From e5d98b0180a6bd8cad6fb9790c0d2db8726d2ad2 Mon Sep 17 00:00:00 2001
From: David Nicholas
Date: Thu, 6 Feb 2025 09:45:43 -0800
Subject: [PATCH] pull out to hooks
---
public/canjs/routing/route-data/route-data.js | 4 +
.../components/IssueSource/IssueSource.tsx | 141 +++++-------------
.../StatusSelect/ExcludedStatusSelect.tsx | 6 +-
.../components/StatusSelect/index.ts | 1 +
.../IssueSource/hooks/useJQL/index.ts | 1 +
.../IssueSource/hooks/useJQL/useJQL.ts | 47 ++++++
.../hooks/useRawIssueRequestData/index.ts | 1 +
.../useRawIssueRequestData.ts | 38 +++++
public/timeline-report.js | 2 +-
9 files changed, 134 insertions(+), 107 deletions(-)
create mode 100644 public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/index.ts
create mode 100644 public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/useJQL.ts
create mode 100644 public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/index.ts
create mode 100644 public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/useRawIssueRequestData.ts
diff --git a/public/canjs/routing/route-data/route-data.js b/public/canjs/routing/route-data/route-data.js
index d422647c..eb158e59 100644
--- a/public/canjs/routing/route-data/route-data.js
+++ b/public/canjs/routing/route-data/route-data.js
@@ -35,6 +35,10 @@ import {
makeAsyncFromObservableButStillSettableProperty,
toSelectedParts,
} from "../data-utils.js";
+import {
+ calculationsForLevel,
+ createBaseLevels,
+} from "../../../react/SettingsSidebar/components/TimingCalculation/hooks/useTimingCalculations/helpers.js";
export function getTimingLevels(issueHierarchy, timingCalculations) {
const baseLevels = createBaseLevels(issueHierarchy);
diff --git a/public/react/SettingsSidebar/components/IssueSource/IssueSource.tsx b/public/react/SettingsSidebar/components/IssueSource/IssueSource.tsx
index 3387797c..92e4e8d8 100644
--- a/public/react/SettingsSidebar/components/IssueSource/IssueSource.tsx
+++ b/public/react/SettingsSidebar/components/IssueSource/IssueSource.tsx
@@ -1,111 +1,39 @@
-import React, { useCallback, useMemo, useState, FC } from "react";
-import Button from "@atlaskit/button/new";
-import { useCanObservable, CanPromise } from "../../../hooks/useCanObservable/useCanObservable";
-import type { JiraIssue } from "../../../../jira/shared/types";
-import type { OidcJiraIssue } from "../../../../jira-oidc-helpers/types";
-import { value } from "../../../../can";
-import routeData from "../../../../canjs/routing/route-data";
-import type { MultiValue } from "react-select";
-import ExcludedStatusSelect, {
- ExcludedStatusSelectOption,
-} from "./components/StatusSelect/ExcludedStatusSelect";
-interface IssueSourceProps {}
+import type { ExcludedStatusSelectOption } from "./components/StatusSelect";
-const useRawIssuesRequestData = () => {
- const issuesPromise = useCanObservable>(
- value.from(routeData, "rawIssuesRequestData.issuesPromise")
- );
+import React, { useMemo, FC } from "react";
+import Button from "@atlaskit/button/new";
- const issuesPromisePending = useCanObservable(
- value.from(routeData, "rawIssuesRequestData.issuesPromise.isPending")
- );
- const issuesPromiseResolved = useCanObservable(
- value.from(routeData, "rawIssuesRequestData.issuesPromise.isResolved")
- );
- const issuesPromiseValueLength = useCanObservable(
- value.from(routeData, "rawIssuesRequestData.issuesPromise.value.length")
- );
- const issuesReceived = useCanObservable(
- value.from(routeData, "rawIssuesRequestData.progressData.issuesReceived")
- );
- const issuesRequested = useCanObservable(
- value.from(routeData, "rawIssuesRequestData.progressData.issuesRequested")
- );
+import routeData from "../../../../canjs/routing/route-data";
+import ExcludedStatusSelect from "./components/StatusSelect";
+import { useRawIssuesRequestData } from "./hooks/useRawIssueRequestData";
+import { useJQL } from "./hooks/useJQL";
- return {
- issuesPromise,
- issuesPromisePending,
- issuesPromiseResolved,
- issuesPromiseValueLength,
- issuesReceived,
- issuesRequested,
- };
-};
+interface IssueSourceProps {}
const IssueSource: FC = () => {
- const {
- issuesPromise,
- issuesPromisePending,
- issuesPromiseResolved,
- issuesPromiseValueLength,
- issuesReceived,
- issuesRequested,
- } = useRawIssuesRequestData();
+ const { issuesPromise, isLoading, isSuccess, numberOfIssues, receivedChunks, totalChunks } =
+ useRawIssuesRequestData();
- const loadChildren = useCanObservable(value.from(routeData, "loadChildren"));
- const jqlFromRouteData = useCanObservable(value.from(routeData, "jql"));
- const childJQLFromRouteData = useCanObservable(value.from(routeData, "childJQL"));
- const statusesToExcludeFromRouteData = useCanObservable(
- value.from(routeData, "statusesToExclude")
- );
-
- const [jql, setJql] = useState(jqlFromRouteData);
- const [childJQL, setChildJQL] = useState(childJQLFromRouteData);
- const [statusesToExclude, setStatusesToExclude] = useState(
- statusesToExcludeFromRouteData
- );
-
- const statusesToExcludeOptions = useMemo(
- () =>
- statusesToExclude.map((status) => ({
- label: status,
- value: status,
- })),
- [statusesToExclude]
- );
- const applyJql = useCallback(() => {
- routeData.assign({
- jql,
- childJQL,
- statusesToExclude,
- });
- }, [jql, childJQL, statusesToExclude]);
-
- const enableApply = useMemo(() => {
- return (
- !loadChildren &&
- (jql !== jqlFromRouteData ||
- childJQL !== childJQLFromRouteData ||
- statusesToExclude.some((filter) => !statusesToExcludeFromRouteData.includes(filter)) ||
- statusesToExcludeFromRouteData.some((filter) => !statusesToExclude.includes(filter)))
- );
- }, [
- loadChildren,
+ const {
jql,
- jqlFromRouteData,
+ setJql,
childJQL,
- childJQLFromRouteData,
+ setChildJQL,
+ applyJql,
statusesToExclude,
- statusesToExcludeFromRouteData,
- ]);
+ loadChildren,
+ setStatusesToExclude,
+ applyButtonEnabled,
+ } = useJQL();
- const handleExcludedStatusChange = useCallback(
- (statusesToExcludeOptions: MultiValue) => {
- const statusesToExclude = statusesToExcludeOptions.map((option) => option.value);
- setStatusesToExclude(statusesToExclude);
- },
- []
- );
+ const statusesToExcludeOptions = useMemo(() => toOptions(statusesToExclude), []);
+
+ const handleExcludedStatusChange = (
+ statusesToExcludeOptions: Readonly
+ ) => {
+ const statusesToExclude = statusesToExcludeOptions.map((option) => option.value);
+ setStatusesToExclude(statusesToExclude);
+ };
return (
<>
@@ -161,15 +89,15 @@ const IssueSource: FC = () => {
- {issuesPromisePending &&
- (issuesRequested ? (
+ {isLoading &&
+ (totalChunks ? (
<>
- Loaded {issuesReceived} of {issuesRequested} issues
+ Loaded {receivedChunks} of {totalChunks} issues
>
) : (
<>Loading issues ...>
))}
- {issuesPromiseResolved && <>Loaded {issuesPromiseValueLength} issues>}
+ {isSuccess && <>Loaded {numberOfIssues} issues>}
= () => {
/>
-
@@ -189,3 +117,10 @@ const IssueSource: FC = () => {
};
export default IssueSource;
+
+const toOptions = (statuses: string[]) => {
+ return statuses.map((status) => ({
+ label: status,
+ value: status,
+ }));
+};
diff --git a/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/ExcludedStatusSelect.tsx b/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/ExcludedStatusSelect.tsx
index cbfc91e3..a1109a4d 100644
--- a/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/ExcludedStatusSelect.tsx
+++ b/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/ExcludedStatusSelect.tsx
@@ -2,7 +2,6 @@ import React, { FC, useId } from "react";
import Select from "@atlaskit/select";
import { Label } from "@atlaskit/form";
import useExcludedStatusSelect from "./hooks/useExcludedStatusSelect";
-import type { MultiValue } from "react-select";
export interface ExcludedStatusSelectOption {
label: string;
@@ -12,8 +11,8 @@ export interface ExcludedStatusSelectOption {
export interface ExcludedStatusSelectProps {
label: string;
placeholder: string;
- value: MultiValue;
- onChange?: (value: MultiValue) => void;
+ value: ExcludedStatusSelectOption[];
+ onChange?: (value: Readonly) => void;
}
const ExcludedStatusSelect: FC = ({
label,
@@ -28,6 +27,7 @@ const ExcludedStatusSelect: FC = ({
if (allStatusesOptions.length === 0) {
return null;
}
+
return (
<>
diff --git a/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/index.ts b/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/index.ts
index 44462169..9434bd21 100644
--- a/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/index.ts
+++ b/public/react/SettingsSidebar/components/IssueSource/components/StatusSelect/index.ts
@@ -1 +1,2 @@
export { default } from "./ExcludedStatusSelect";
+export * from "./ExcludedStatusSelect";
diff --git a/public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/index.ts b/public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/index.ts
new file mode 100644
index 00000000..33001cad
--- /dev/null
+++ b/public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/index.ts
@@ -0,0 +1 @@
+export * from "./useJQL";
diff --git a/public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/useJQL.ts b/public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/useJQL.ts
new file mode 100644
index 00000000..f4536836
--- /dev/null
+++ b/public/react/SettingsSidebar/components/IssueSource/hooks/useJQL/useJQL.ts
@@ -0,0 +1,47 @@
+import { useState } from "react";
+import { value } from "../../../../../../can";
+import routeData from "../../../../../../canjs/routing/route-data";
+import { useCanObservable } from "../../../../../hooks/useCanObservable";
+
+export const useJQL = () => {
+ const jqlFromRouteData = useCanObservable(value.from(routeData, "jql"));
+ const childJQLFromRouteData = useCanObservable(value.from(routeData, "childJQL"));
+ const loadChildren = useCanObservable(value.from(routeData, "loadChildren"));
+ const statusesToExcludeFromRouteData = useCanObservable(
+ value.from(routeData, "statusesToExclude")
+ );
+
+ const [statusesToExclude, setStatusesToExclude] = useState(
+ statusesToExcludeFromRouteData
+ );
+ const [jql, setJql] = useState(jqlFromRouteData);
+ const [childJQL, setChildJQL] = useState(childJQLFromRouteData);
+
+ console.log({ jql, loadChildren, childJQL, statusesToExclude });
+
+ const applyJql = () => {
+ routeData.assign({
+ jql,
+ childJQL,
+ statusesToExclude,
+ });
+ };
+
+ const statusesDiffer =
+ statusesToExclude.some((filter) => !statusesToExcludeFromRouteData.includes(filter)) ||
+ statusesToExcludeFromRouteData.some((filter) => !statusesToExclude.includes(filter));
+
+ return {
+ loadChildren,
+ jql,
+ setJql,
+ childJQL,
+ setChildJQL,
+ applyJql,
+ statusesToExclude,
+ setStatusesToExclude,
+ applyButtonEnabled:
+ !loadChildren &&
+ (jql !== jqlFromRouteData || childJQL !== childJQLFromRouteData || statusesDiffer),
+ };
+};
diff --git a/public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/index.ts b/public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/index.ts
new file mode 100644
index 00000000..19b099e8
--- /dev/null
+++ b/public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/index.ts
@@ -0,0 +1 @@
+export * from "./useRawIssueRequestData";
diff --git a/public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/useRawIssueRequestData.ts b/public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/useRawIssueRequestData.ts
new file mode 100644
index 00000000..75533f4a
--- /dev/null
+++ b/public/react/SettingsSidebar/components/IssueSource/hooks/useRawIssueRequestData/useRawIssueRequestData.ts
@@ -0,0 +1,38 @@
+import type { CanPromise } from "../../../../../hooks/useCanObservable";
+import type { JiraIssue } from "../../../../../../jira/shared/types";
+import type { OidcJiraIssue } from "../../../../../../jira-oidc-helpers/types";
+
+import { value } from "../../../../../../can";
+import routeData from "../../../../../../canjs/routing/route-data";
+import { useCanObservable } from "../../../../../hooks/useCanObservable";
+
+export const useRawIssuesRequestData = () => {
+ const issuesPromise = useCanObservable>(
+ value.from(routeData, "rawIssuesRequestData.issuesPromise")
+ );
+
+ const issuesPromisePending = useCanObservable(
+ value.from(routeData, "rawIssuesRequestData.issuesPromise.isPending")
+ );
+ const issuesPromiseResolved = useCanObservable(
+ value.from(routeData, "rawIssuesRequestData.issuesPromise.isResolved")
+ );
+ const issuesPromiseValueLength = useCanObservable(
+ value.from(routeData, "rawIssuesRequestData.issuesPromise.value.length")
+ );
+ const issuesReceived = useCanObservable(
+ value.from(routeData, "rawIssuesRequestData.progressData.issuesReceived")
+ );
+ const issuesRequested = useCanObservable(
+ value.from(routeData, "rawIssuesRequestData.progressData.issuesRequested")
+ );
+
+ return {
+ issuesPromise,
+ isLoading: issuesPromisePending,
+ isSuccess: issuesPromiseResolved,
+ numberOfIssues: issuesPromiseValueLength,
+ receivedChunks: issuesReceived,
+ totalChunks: issuesRequested,
+ };
+};
diff --git a/public/timeline-report.js b/public/timeline-report.js
index 8b32ea53..ca7d447b 100644
--- a/public/timeline-report.js
+++ b/public/timeline-report.js
@@ -26,7 +26,7 @@ import SavedReports from "./react/SaveReports";
import SettingsSidebar from "./react/SettingsSidebar";
import SampleDataNotice from "./react/SampleDataNotice";
-import { getTheme } from "./jira/theme";
+import { getTheme, applyThemeToCssVars } from "./jira/theme";
export class TimelineReport extends StacheElement {
static view = `