From c1414507ae2295078b3d43b103ca926bc4b7da15 Mon Sep 17 00:00:00 2001 From: gakshita Date: Mon, 14 Oct 2024 15:53:28 +0530 Subject: [PATCH 1/3] fix: moved dropdowns to chart component + added pending icon --- packages/ui/src/icons/index.ts | 1 + packages/ui/src/icons/pending-icon.tsx | 27 +++++ .../cycles/analytics-sidebar/base.tsx | 103 +++++++++++++----- .../analytics-sidebar/issue-progress.tsx | 76 ++----------- .../cycles/list/cycle-list-item-action.tsx | 2 +- 5 files changed, 112 insertions(+), 97 deletions(-) create mode 100644 packages/ui/src/icons/pending-icon.tsx diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts index 69436c2e836..e857dc1a493 100644 --- a/packages/ui/src/icons/index.ts +++ b/packages/ui/src/icons/index.ts @@ -31,3 +31,4 @@ export * from "./favorite-folder-icon"; export * from "./planned-icon"; export * from "./in-progress-icon"; export * from "./done-icon"; +export * from "./pending-icon"; diff --git a/packages/ui/src/icons/pending-icon.tsx b/packages/ui/src/icons/pending-icon.tsx new file mode 100644 index 00000000000..14ba234d318 --- /dev/null +++ b/packages/ui/src/icons/pending-icon.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; + +import { ISvgIcons } from "./type"; + +export const PendingState: React.FC = ({ width = "10", height = "11", className, color }) => ( + + + + +); diff --git a/web/ce/components/cycles/analytics-sidebar/base.tsx b/web/ce/components/cycles/analytics-sidebar/base.tsx index 94609bc1f63..ce181ea5d92 100644 --- a/web/ce/components/cycles/analytics-sidebar/base.tsx +++ b/web/ce/components/cycles/analytics-sidebar/base.tsx @@ -2,14 +2,16 @@ import { FC, Fragment } from "react"; import { observer } from "mobx-react"; // plane ui -import { Loader } from "@plane/ui"; +import { TCycleEstimateType } from "@plane/types"; +import { EEstimateSystem } from "@plane/types/src/enums"; +import { CustomSelect, Loader } from "@plane/ui"; // components import ProgressChart from "@/components/core/sidebar/progress-chart"; -import { validateCycleSnapshot } from "@/components/cycles"; +import { cycleEstimateOptions, validateCycleSnapshot } from "@/components/cycles"; // helpers import { getDate } from "@/helpers/date-time.helper"; // hooks -import { useCycle } from "@/hooks/store"; +import { useCycle, useProjectEstimates } from "@/hooks/store"; type ProgressChartProps = { workspaceSlug: string; @@ -20,7 +22,9 @@ export const SidebarChart: FC = observer((props) => { const { workspaceSlug, projectId, cycleId } = props; // hooks - const { getEstimateTypeByCycleId, getCycleById } = useCycle(); + const { getEstimateTypeByCycleId, getCycleById, fetchCycleDetails, fetchArchivedCycleDetails, setEstimateType } = + useCycle(); + const { currentActiveEstimateId, areEstimateEnabledByProjectId, estimateById } = useProjectEstimates(); // derived data const cycleDetails = validateCycleSnapshot(getCycleById(cycleId)); @@ -29,7 +33,10 @@ export const SidebarChart: FC = observer((props) => { const totalEstimatePoints = cycleDetails?.total_estimate_points || 0; const totalIssues = cycleDetails?.total_issues || 0; const estimateType = getEstimateTypeByCycleId(cycleId); - + const isCurrentProjectEstimateEnabled = projectId && areEstimateEnabledByProjectId(projectId) ? true : false; + const estimateDetails = + isCurrentProjectEstimateEnabled && currentActiveEstimateId && estimateById(currentActiveEstimateId); + const isCurrentEstimateTypeIsPoints = estimateDetails && estimateDetails?.type === EEstimateSystem.POINTS; const chartDistributionData = estimateType === "points" ? cycleDetails?.estimate_distribution : cycleDetails?.distribution || undefined; @@ -37,33 +44,71 @@ export const SidebarChart: FC = observer((props) => { if (!workspaceSlug || !projectId || !cycleId) return null; + const isArchived = !!cycleDetails?.archived_at; + + // handlers + const onChange = async (value: TCycleEstimateType) => { + setEstimateType(cycleId, value); + if (!workspaceSlug || !projectId || !cycleId) return; + try { + if (isArchived) { + await fetchArchivedCycleDetails(workspaceSlug, projectId, cycleId); + } else { + await fetchCycleDetails(workspaceSlug, projectId, cycleId); + } + } catch (err) { + console.error(err); + setEstimateType(cycleId, estimateType); + } + }; return ( -
-
-
- - Ideal + <> + {isCurrentEstimateTypeIsPoints && ( +
+ {cycleEstimateOptions.find((v) => v.value === estimateType)?.label ?? "None"}} + onChange={onChange} + maxHeight="lg" + buttonClassName="border-none rounded text-sm font-medium capitalize" + > + {cycleEstimateOptions.map((item) => ( + + {item.label} + + ))} +
-
- - Current + )} +
+
+
+
+ + Ideal +
+
+ + Current +
+
+ {cycleStartDate && cycleEndDate && completionChartDistributionData ? ( + + + + ) : ( + + + + )}
- {cycleStartDate && cycleEndDate && completionChartDistributionData ? ( - - - - ) : ( - - - - )} -
+ ); }); diff --git a/web/core/components/cycles/analytics-sidebar/issue-progress.tsx b/web/core/components/cycles/analytics-sidebar/issue-progress.tsx index 55178ed2171..927346aa71a 100644 --- a/web/core/components/cycles/analytics-sidebar/issue-progress.tsx +++ b/web/core/components/cycles/analytics-sidebar/issue-progress.tsx @@ -7,8 +7,7 @@ import { observer } from "mobx-react"; import { useSearchParams } from "next/navigation"; import { ChevronUp, ChevronDown } from "lucide-react"; import { Disclosure, Transition } from "@headlessui/react"; -import { ICycle, IIssueFilterOptions, TCycleEstimateType, TCyclePlotType, TProgressSnapshot } from "@plane/types"; -import { CustomSelect } from "@plane/ui"; +import { ICycle, IIssueFilterOptions, TCyclePlotType, TProgressSnapshot } from "@plane/types"; // components import { CycleProgressStats } from "@/components/cycles"; // constants @@ -26,6 +25,11 @@ type TCycleAnalyticsProgress = { cycleId: string; }; +export const cycleEstimateOptions: options[] = [ + { value: "issues", label: "issues" }, + { value: "points", label: "points" }, +]; + export const validateCycleSnapshot = (cycleDetails: ICycle | null): ICycle | null => { if (!cycleDetails || cycleDetails === null) return cycleDetails; @@ -49,24 +53,14 @@ export const cycleChartOptions: options[] = [ { value: "burndown", label: "Burn-down" }, { value: "burnup", label: "Burn-up" }, ]; -export const cycleEstimateOptions: options[] = [ - { value: "issues", label: "issues" }, - { value: "points", label: "points" }, -]; + export const CycleAnalyticsProgress: FC = observer((props) => { // props const { workspaceSlug, projectId, cycleId } = props; // router const searchParams = useSearchParams(); const peekCycle = searchParams.get("peekCycle") || undefined; - const { - getPlotTypeByCycleId, - getEstimateTypeByCycleId, - getCycleById, - fetchCycleDetails, - fetchArchivedCycleDetails, - setEstimateType, - } = useCycle(); + const { getPlotTypeByCycleId, getEstimateTypeByCycleId, getCycleById } = useCycle(); const { issuesFilter: { issueFilters, updateFilters }, } = useIssues(EIssuesStoreType.CYCLE); @@ -76,21 +70,9 @@ export const CycleAnalyticsProgress: FC = observer((pro const plotType: TCyclePlotType = getPlotTypeByCycleId(cycleId); const estimateType = getEstimateTypeByCycleId(cycleId); - const completedIssues = cycleDetails?.completed_issues || 0; const totalIssues = cycleDetails?.total_issues || 0; - const completedEstimatePoints = cycleDetails?.completed_estimate_points || 0; const totalEstimatePoints = cycleDetails?.total_estimate_points || 0; - const progressHeaderPercentage = cycleDetails - ? estimateType === "points" - ? completedEstimatePoints != 0 && totalEstimatePoints != 0 - ? Math.round((completedEstimatePoints / totalEstimatePoints) * 100) - : 0 - : completedIssues != 0 && completedIssues != 0 - ? Math.round((completedIssues / totalIssues) * 100) - : 0 - : 0; - const chartDistributionData = estimateType === "points" ? cycleDetails?.estimate_distribution : cycleDetails?.distribution || undefined; @@ -115,23 +97,6 @@ export const CycleAnalyticsProgress: FC = observer((pro const isCycleStartDateValid = cycleStartDate && cycleStartDate <= new Date(); const isCycleEndDateValid = cycleStartDate && cycleEndDate && cycleEndDate >= cycleStartDate; const isCycleDateValid = isCycleStartDateValid && isCycleEndDateValid; - const isArchived = !!cycleDetails?.archived_at; - - // handlers - const onChange = async (value: TCycleEstimateType) => { - setEstimateType(cycleId, value); - if (!workspaceSlug || !projectId || !cycleId) return; - try { - if (isArchived) { - await fetchArchivedCycleDetails(workspaceSlug, projectId, cycleId); - } else { - await fetchCycleDetails(workspaceSlug, projectId, cycleId); - } - } catch (err) { - console.error(err); - setEstimateType(cycleId, estimateType); - } - }; const handleFiltersUpdate = useCallback( (key: keyof IIssueFilterOptions, value: string | string[]) => { @@ -192,30 +157,7 @@ export const CycleAnalyticsProgress: FC = observer((pro -
- {cycleEstimateOptions.find((v) => v.value === estimateType)?.label ?? "None"}} - onChange={onChange} - maxHeight="lg" - buttonClassName="border-none rounded text-sm font-medium" - > - {cycleEstimateOptions.map((item) => ( - - {item.label} - - ))} - -
-
- Done - {progressHeaderPercentage}% -
-
-
-
- -
+ {/* progress detailed view */} {chartDistributionData && (
diff --git a/web/core/components/cycles/list/cycle-list-item-action.tsx b/web/core/components/cycles/list/cycle-list-item-action.tsx index eab9c501898..989e0436e36 100644 --- a/web/core/components/cycles/list/cycle-list-item-action.tsx +++ b/web/core/components/cycles/list/cycle-list-item-action.tsx @@ -211,7 +211,7 @@ export const CycleListItemAction: FC = observer((props) => { <>
diff --git a/web/core/components/cycles/quick-actions.tsx b/web/core/components/cycles/quick-actions.tsx index 6d6e9ed1507..49f78cb5c0a 100644 --- a/web/core/components/cycles/quick-actions.tsx +++ b/web/core/components/cycles/quick-actions.tsx @@ -115,7 +115,7 @@ export const CycleQuickActions: React.FC = observer((props) => { key: "archive", action: handleArchiveCycle, title: "Archive", - description: isCompleted ? undefined : "Only completed cycle can\nbe archived.", + description: isCompleted ? undefined : "Only completed cycles can\nbe archived.", icon: ArchiveIcon, className: "items-start", iconClassName: "mt-1", diff --git a/yarn.lock b/yarn.lock index 73129dbc834..99246b4d462 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1389,9 +1389,9 @@ "@floating-ui/dom" "^1.0.0" "@floating-ui/react@^0.26.4": - version "0.26.24" - resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.24.tgz#072b9dfeca4e79ef4e3000ef1c28e0ffc86f4ed4" - integrity sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw== + version "0.26.25" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.25.tgz#cf4c8a2b89fab1a71712d15e6551df3bfbd2ea1d" + integrity sha512-hZOmgN0NTOzOuZxI1oIrDu3Gcl8WViIkvPMpB4xdd4QD6xAMtwgwr3VPoiyH/bLtRcS1cDnhxLSD1NsMJmwh/A== dependencies: "@floating-ui/react-dom" "^2.1.2" "@floating-ui/utils" "^0.2.8" @@ -6373,7 +6373,7 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== -entities@^4.2.0, entities@^4.4.0: +entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -8382,7 +8382,7 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lib0@^0.2.42, lib0@^0.2.47, lib0@^0.2.74, lib0@^0.2.85, lib0@^0.2.86, lib0@^0.2.87: +lib0@^0.2.42, lib0@^0.2.47, lib0@^0.2.74, lib0@^0.2.85, lib0@^0.2.87, lib0@^0.2.98: version "0.2.98" resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.98.tgz#fe55203b8586512c1837248d5f309d7dfd566f5d" integrity sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA== @@ -9491,11 +9491,11 @@ parse-svg-path@^0.1.2: integrity sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ== parse5@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + version "7.2.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.0.tgz#8a0591ce9b7c5e2027173ab737d4d3fc3d826fab" + integrity sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA== dependencies: - entities "^4.4.0" + entities "^4.5.0" parseurl@~1.3.3: version "1.3.3" @@ -9922,9 +9922,9 @@ posthog-js@^1.131.3: web-vitals "^4.0.1" preact@^10.19.3: - version "10.24.2" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.24.2.tgz#42179771d3b06e7adb884e3f8127ddd3d99b78f6" - integrity sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q== + version "10.24.3" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.24.3.tgz#086386bd47071e3b45410ef20844c21e23828f64" + integrity sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA== prebuild-install@^7.1.1: version "7.1.2" @@ -11790,17 +11790,17 @@ tiptap-markdown@^0.8.9: markdown-it-task-lists "^2.1.1" prosemirror-markdown "^1.11.1" -tldts-core@^6.1.50: - version "6.1.50" - resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.50.tgz#8f8f87928adde862b8bc8ce6954c463e2dded790" - integrity sha512-na2EcZqmdA2iV9zHV7OHQDxxdciEpxrjbkp+aHmZgnZKHzoElLajP59np5/4+sare9fQBfixgvXKx8ev1d7ytw== +tldts-core@^6.1.51: + version "6.1.51" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.51.tgz#abbb005cccc1c469ed7ddf1ec472acd91efda4d0" + integrity sha512-bu9oCYYWC1iRjx+3UnAjqCsfrWNZV1ghNQf49b3w5xE8J/tNShHTzp5syWJfwGH+pxUgTTLUnzHnfuydW7wmbg== tldts@^6.1.32: - version "6.1.50" - resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.50.tgz#3b259a65bb11978a2a3d1b3c37660e542dbf9896" - integrity sha512-q9GOap6q3KCsLMdOjXhWU5jVZ8/1dIib898JBRLsN+tBhENpBDcAVQbE0epADOjw11FhQQy9AcbqKGBQPUfTQA== + version "6.1.51" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.51.tgz#ee5b35a939e733515f8cbfc882791ec87962e12c" + integrity sha512-33lfQoL0JsDogIbZ8fgRyvv77GnRtwkNE/MOKocwUgPO1WrSfsq7+vQRKxRQZai5zd+zg97Iv9fpFQSzHyWdLA== dependencies: - tldts-core "^6.1.50" + tldts-core "^6.1.51" to-fast-properties@^2.0.0: version "2.0.0" @@ -12756,9 +12756,9 @@ yaml@^1.10.0: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@^2.3.4, yaml@^2.4.2: - version "2.5.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" - integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== + version "2.6.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.0.tgz#14059ad9d0b1680d0f04d3a60fe00f3a857303c3" + integrity sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ== yargs-parser@^21.1.1: version "21.1.1" @@ -12779,11 +12779,11 @@ yargs@^17.0.0, yargs@^17.7.2: yargs-parser "^21.1.1" yjs@^13.6.14, yjs@^13.6.15: - version "13.6.19" - resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.19.tgz#66999f41254ab65be8c8e71bd767d124ad600909" - integrity sha512-GNKw4mEUn5yWU2QPHRx8jppxmCm9KzbBhB4qJLUJFiiYD0g/tDVgXQ7aPkyh01YO28kbs2J/BEbWBagjuWyejw== + version "13.6.20" + resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.20.tgz#da878412688f107dc03faa4fc3cff37736fe5dfa" + integrity sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ== dependencies: - lib0 "^0.2.86" + lib0 "^0.2.98" yn@3.1.1: version "3.1.1" From e10c8316397b6bdbbe8550d1f73a99fe0a829eb4 Mon Sep 17 00:00:00 2001 From: gakshita Date: Mon, 14 Oct 2024 16:51:14 +0530 Subject: [PATCH 3/3] fix: review changes --- packages/ui/src/icons/pending-icon.tsx | 6 +++--- .../cycles/analytics-sidebar/base.tsx | 2 +- .../analytics-sidebar/issue-progress.tsx | 19 +++++++++---------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/ui/src/icons/pending-icon.tsx b/packages/ui/src/icons/pending-icon.tsx index 14ba234d318..5269a22e2b0 100644 --- a/packages/ui/src/icons/pending-icon.tsx +++ b/packages/ui/src/icons/pending-icon.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { ISvgIcons } from "./type"; -export const PendingState: React.FC = ({ width = "10", height = "11", className, color }) => ( +export const PendingState: React.FC = ({ width = "10", height = "11", className, color = "#455068" }) => ( = ({ width = "10", height = "11", fill-rule="evenodd" clip-rule="evenodd" d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12Z" - fill="#455068" + fill={color} /> ); diff --git a/web/ce/components/cycles/analytics-sidebar/base.tsx b/web/ce/components/cycles/analytics-sidebar/base.tsx index ce181ea5d92..34d61efaa5d 100644 --- a/web/ce/components/cycles/analytics-sidebar/base.tsx +++ b/web/ce/components/cycles/analytics-sidebar/base.tsx @@ -33,7 +33,7 @@ export const SidebarChart: FC = observer((props) => { const totalEstimatePoints = cycleDetails?.total_estimate_points || 0; const totalIssues = cycleDetails?.total_issues || 0; const estimateType = getEstimateTypeByCycleId(cycleId); - const isCurrentProjectEstimateEnabled = projectId && areEstimateEnabledByProjectId(projectId) ? true : false; + const isCurrentProjectEstimateEnabled = Boolean(projectId && areEstimateEnabledByProjectId(projectId)); const estimateDetails = isCurrentProjectEstimateEnabled && currentActiveEstimateId && estimateById(currentActiveEstimateId); const isCurrentEstimateTypeIsPoints = estimateDetails && estimateDetails?.type === EEstimateSystem.POINTS; diff --git a/web/core/components/cycles/analytics-sidebar/issue-progress.tsx b/web/core/components/cycles/analytics-sidebar/issue-progress.tsx index 302887b0ad5..d9725d1d66d 100644 --- a/web/core/components/cycles/analytics-sidebar/issue-progress.tsx +++ b/web/core/components/cycles/analytics-sidebar/issue-progress.tsx @@ -24,11 +24,19 @@ type TCycleAnalyticsProgress = { projectId: string; cycleId: string; }; +type Options = { + value: string; + label: string; +}; -export const cycleEstimateOptions: options[] = [ +export const cycleEstimateOptions: Options[] = [ { value: "issues", label: "Issues" }, { value: "points", label: "Points" }, ]; +export const cycleChartOptions: Options[] = [ + { value: "burndown", label: "Burn-down" }, + { value: "burnup", label: "Burn-up" }, +]; export const validateCycleSnapshot = (cycleDetails: ICycle | null): ICycle | null => { if (!cycleDetails || cycleDetails === null) return cycleDetails; @@ -45,15 +53,6 @@ export const validateCycleSnapshot = (cycleDetails: ICycle | null): ICycle | nul return updatedCycleDetails; }; -type options = { - value: string; - label: string; -}; -export const cycleChartOptions: options[] = [ - { value: "burndown", label: "Burn-down" }, - { value: "burnup", label: "Burn-up" }, -]; - export const CycleAnalyticsProgress: FC = observer((props) => { // props const { workspaceSlug, projectId, cycleId } = props;