Skip to content

Commit

Permalink
pull out to hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidNic11 committed Feb 6, 2025
1 parent 84372ba commit e5d98b0
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 107 deletions.
4 changes: 4 additions & 0 deletions public/canjs/routing/route-data/route-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
141 changes: 38 additions & 103 deletions public/react/SettingsSidebar/components/IssueSource/IssueSource.tsx
Original file line number Diff line number Diff line change
@@ -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<CanPromise<JiraIssue[] | OidcJiraIssue[]>>(
value.from(routeData, "rawIssuesRequestData.issuesPromise")
);
import React, { useMemo, FC } from "react";
import Button from "@atlaskit/button/new";

const issuesPromisePending = useCanObservable<boolean>(
value.from(routeData, "rawIssuesRequestData.issuesPromise.isPending")
);
const issuesPromiseResolved = useCanObservable<boolean>(
value.from(routeData, "rawIssuesRequestData.issuesPromise.isResolved")
);
const issuesPromiseValueLength = useCanObservable<number>(
value.from(routeData, "rawIssuesRequestData.issuesPromise.value.length")
);
const issuesReceived = useCanObservable<number>(
value.from(routeData, "rawIssuesRequestData.progressData.issuesReceived")
);
const issuesRequested = useCanObservable<number>(
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<IssueSourceProps> = () => {
const {
issuesPromise,
issuesPromisePending,
issuesPromiseResolved,
issuesPromiseValueLength,
issuesReceived,
issuesRequested,
} = useRawIssuesRequestData();
const { issuesPromise, isLoading, isSuccess, numberOfIssues, receivedChunks, totalChunks } =
useRawIssuesRequestData();

const loadChildren = useCanObservable(value.from<boolean>(routeData, "loadChildren"));
const jqlFromRouteData = useCanObservable(value.from<string>(routeData, "jql"));
const childJQLFromRouteData = useCanObservable(value.from<string>(routeData, "childJQL"));
const statusesToExcludeFromRouteData = useCanObservable(
value.from<string[]>(routeData, "statusesToExclude")
);

const [jql, setJql] = useState(jqlFromRouteData);
const [childJQL, setChildJQL] = useState(childJQLFromRouteData);
const [statusesToExclude, setStatusesToExclude] = useState<string[]>(
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<ExcludedStatusSelectOption>) => {
const statusesToExclude = statusesToExcludeOptions.map((option) => option.value);
setStatusesToExclude(statusesToExclude);
},
[]
);
const statusesToExcludeOptions = useMemo(() => toOptions(statusesToExclude), []);

const handleExcludedStatusChange = (
statusesToExcludeOptions: Readonly<ExcludedStatusSelectOption[]>
) => {
const statusesToExclude = statusesToExcludeOptions.map((option) => option.value);
setStatusesToExclude(statusesToExclude);
};

return (
<>
Expand Down Expand Up @@ -161,15 +89,15 @@ const IssueSource: FC<IssueSourceProps> = () => {
</span>
</p>
<p className="text-xs" style={{ lineHeight: "26px" }}>
{issuesPromisePending &&
(issuesRequested ? (
{isLoading &&
(totalChunks ? (
<>
Loaded {issuesReceived} of {issuesRequested} issues
Loaded {receivedChunks} of {totalChunks} issues
</>
) : (
<>Loading issues ...</>
))}
{issuesPromiseResolved && <>Loaded {issuesPromiseValueLength} issues</>}
{isSuccess && <>Loaded {numberOfIssues} issues</>}
</p>
</div>
<ExcludedStatusSelect
Expand All @@ -180,7 +108,7 @@ const IssueSource: FC<IssueSourceProps> = () => {
/>

<div className="flex flex-row justify-end mt-2">
<Button appearance="primary" isDisabled={!enableApply} onClick={applyJql}>
<Button appearance="primary" isDisabled={!applyButtonEnabled} onClick={applyJql}>
<span className="text-sm">Apply</span>
</Button>
</div>
Expand All @@ -189,3 +117,10 @@ const IssueSource: FC<IssueSourceProps> = () => {
};

export default IssueSource;

const toOptions = (statuses: string[]) => {
return statuses.map((status) => ({
label: status,
value: status,
}));
};
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -12,8 +11,8 @@ export interface ExcludedStatusSelectOption {
export interface ExcludedStatusSelectProps {
label: string;
placeholder: string;
value: MultiValue<ExcludedStatusSelectOption>;
onChange?: (value: MultiValue<ExcludedStatusSelectOption>) => void;
value: ExcludedStatusSelectOption[];
onChange?: (value: Readonly<ExcludedStatusSelectOption[]>) => void;
}
const ExcludedStatusSelect: FC<ExcludedStatusSelectProps> = ({
label,
Expand All @@ -28,6 +27,7 @@ const ExcludedStatusSelect: FC<ExcludedStatusSelectProps> = ({
if (allStatusesOptions.length === 0) {
return null;
}

return (
<>
<Label htmlFor={id}>{label}</Label>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from "./ExcludedStatusSelect";
export * from "./ExcludedStatusSelect";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useJQL";
Original file line number Diff line number Diff line change
@@ -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<string>(routeData, "jql"));
const childJQLFromRouteData = useCanObservable(value.from<string>(routeData, "childJQL"));
const loadChildren = useCanObservable(value.from<boolean>(routeData, "loadChildren"));
const statusesToExcludeFromRouteData = useCanObservable(
value.from<string[]>(routeData, "statusesToExclude")
);

const [statusesToExclude, setStatusesToExclude] = useState<string[]>(
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),
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useRawIssueRequestData";
Original file line number Diff line number Diff line change
@@ -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<CanPromise<JiraIssue[] | OidcJiraIssue[]>>(
value.from(routeData, "rawIssuesRequestData.issuesPromise")
);

const issuesPromisePending = useCanObservable<boolean>(
value.from(routeData, "rawIssuesRequestData.issuesPromise.isPending")
);
const issuesPromiseResolved = useCanObservable<boolean>(
value.from(routeData, "rawIssuesRequestData.issuesPromise.isResolved")
);
const issuesPromiseValueLength = useCanObservable<number>(
value.from(routeData, "rawIssuesRequestData.issuesPromise.value.length")
);
const issuesReceived = useCanObservable<number>(
value.from(routeData, "rawIssuesRequestData.progressData.issuesReceived")
);
const issuesRequested = useCanObservable<number>(
value.from(routeData, "rawIssuesRequestData.progressData.issuesRequested")
);

return {
issuesPromise,
isLoading: issuesPromisePending,
isSuccess: issuesPromiseResolved,
numberOfIssues: issuesPromiseValueLength,
receivedChunks: issuesReceived,
totalChunks: issuesRequested,
};
};
2 changes: 1 addition & 1 deletion public/timeline-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = `
Expand Down

0 comments on commit e5d98b0

Please sign in to comment.