Skip to content

Commit a5ebf21

Browse files
authored
[INNO] ARC-2714 - Adding modals for backfill page (#2598)
* - Modal added for backfilling and disconnecting subscription * - Fixing eslint in a test case * - WIP - backfill modal * - WIP - backfill modal * - WIP - backfill modal * - Using the corrected datepicker * - Fixing the delete subscription endpoint * - Test cases added - TODO updated * - Fixing test cases
1 parent c6020bb commit a5ebf21

File tree

10 files changed

+445
-19
lines changed

10 files changed

+445
-19
lines changed

spa/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
"@atlaskit/avatar": "^21.3.9",
2626
"@atlaskit/badge": "^15.1.14",
2727
"@atlaskit/button": "^16.8.0",
28+
"@atlaskit/checkbox": "^13.0.1",
2829
"@atlaskit/css-reset": "^6.5.2",
2930
"@atlaskit/dropdown-menu": "^12.1.8",
31+
"@atlaskit/datetime-picker": "^13.0.3",
3032
"@atlaskit/dynamic-table": "^14.11.5",
3133
"@atlaskit/form": "^8.11.8",
3234
"@atlaskit/heading": "^1.3.7",

spa/src/common/Wrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const wrapperStyle = css`
1111
`;
1212
const wrapperCenterStyle = css`
1313
margin: 0 auto;
14-
max-width: 800px;
14+
max-width: 580px;
1515
height: calc(100vh - ${navHeight * 2}px);
1616
display: flex;
1717
flex-direction: column;

spa/src/pages/Connections/GHCloudConnections/index.tsx

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
/** @jsxImportSource @emotion/react */
2+
import { useState } from "react";
23
import { DynamicTableStateless } from "@atlaskit/dynamic-table";
34
import {
45
head,
56
getGHSubscriptionsRows,
67
} from "../../../utils/dynamicTableHelper";
7-
import { GhCloudSubscriptions } from "../../../rest-interfaces";
8+
import { BackfillPageModalTypes, GhCloudSubscriptions } from "../../../rest-interfaces";
89
import { Box, xcss } from "@atlaskit/primitives";
10+
import { SuccessfulConnection } from "rest-interfaces";
11+
import DisconnectSubscriptionModal from "../Modals/DisconnectSubscriptionModal";
12+
import RestartBackfillModal from "../Modals/RestartBackfillModal";
13+
import { ModalTransition } from "@atlaskit/modal-dialog";
914

1015
const containerStyles = xcss({
1116
display: "flex",
@@ -15,18 +20,54 @@ const containerStyles = xcss({
1520
type GitHubCloudConnectionsProps = {
1621
ghCloudSubscriptions: GhCloudSubscriptions;
1722
};
23+
1824
const GitHubCloudConnections = ({
1925
ghCloudSubscriptions,
2026
}: GitHubCloudConnectionsProps) => {
27+
const [isModalOpened, setIsModalOpened] = useState(false);
28+
const [subscriptionForModal, setSubscriptionForModal] = useState<SuccessfulConnection | undefined>(undefined);
29+
const [selectedModal, setSelectedModal] = useState<BackfillPageModalTypes>("BACKFILL");
30+
31+
const openedModal = () => {
32+
switch (selectedModal) {
33+
case "BACKFILL":
34+
return (<RestartBackfillModal
35+
subscription={subscriptionForModal as SuccessfulConnection}
36+
setIsModalOpened={setIsModalOpened}
37+
/>);
38+
case "DISCONNECT_SUBSCRIPTION":
39+
return <DisconnectSubscriptionModal
40+
subscription={subscriptionForModal as SuccessfulConnection}
41+
setIsModalOpened={setIsModalOpened}
42+
/>;
43+
// TODO: Create modals for GHE later
44+
case "DISCONNECT_SERVER":
45+
case "DISCONNECT_SERVER_APP":
46+
default:
47+
return <></>;
48+
}
49+
};
50+
2151
return (
22-
<Box xcss={containerStyles}>
23-
<DynamicTableStateless
24-
head={head}
25-
rows={getGHSubscriptionsRows(ghCloudSubscriptions.successfulCloudConnections)}
26-
rowsPerPage={5}
27-
page={1}
28-
/>
29-
</Box>
52+
<>
53+
<Box xcss={containerStyles}>
54+
<DynamicTableStateless
55+
head={head}
56+
rows={getGHSubscriptionsRows(
57+
ghCloudSubscriptions.successfulCloudConnections,
58+
{ setIsModalOpened, setSubscriptionForModal, setSelectedModal }
59+
)}
60+
rowsPerPage={5}
61+
page={1}
62+
/>
63+
</Box>
64+
65+
<ModalTransition>
66+
{
67+
isModalOpened && subscriptionForModal && openedModal()
68+
}
69+
</ModalTransition>
70+
</>
3071
);
3172
};
3273

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import "@testing-library/jest-dom";
2+
import { render, screen } from "@testing-library/react";
3+
import { BrowserRouter } from "react-router-dom";
4+
import userEvent from "@testing-library/user-event";
5+
import DisconnectSubscriptionModal from "./DisconnectSubscriptionModal";
6+
7+
const sampleSubscription = {
8+
app_slug: "string",
9+
syncWarning: "warning",
10+
id: 1,
11+
account: {
12+
login: "sample",
13+
id: 1,
14+
avatar_url: "string",
15+
},
16+
repository_selection: "string",
17+
app_id: 1,
18+
target_id: 1,
19+
target_type: "string",
20+
created_at: "string",
21+
updated_at: "string",
22+
syncStatus: "string",
23+
totalNumberOfRepos: 2,
24+
numberOfSyncedRepos: 2,
25+
jiraHost: "https://test-jira.atlassian.net",
26+
isGlobalInstall: true,
27+
backfillSince: null,
28+
subscriptionId: 1,
29+
html_url: "html_url"
30+
};
31+
const isModalOpened = jest.fn();
32+
33+
test("Disconnect subscription Modal", async () => {
34+
render(
35+
<BrowserRouter>
36+
<DisconnectSubscriptionModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} />
37+
</BrowserRouter>
38+
);
39+
40+
expect(screen.getByText("Disconnect sample?")).toBeInTheDocument();
41+
const text = screen.getByTestId("disconnect-content");
42+
expect(text.textContent).toBe("Are you sure you want to disconnect your organization sample? This means that you will have to redo the backfill of historical data if you ever want to reconnect");
43+
44+
await userEvent.click(screen.getByText("Cancel"));
45+
expect(isModalOpened).toBeCalled();
46+
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from "@atlaskit/modal-dialog";
2+
import Button from "@atlaskit/button";
3+
import { SuccessfulConnection } from "../../../../../src/rest-interfaces";
4+
5+
/**
6+
* NOTE: While testing in dev mode, please disable the React.StrictMode first,
7+
* otherwise this modal won't show up.
8+
*/
9+
const DisconnectSubscriptionModal = ({ subscription, setIsModalOpened }: {
10+
subscription: SuccessfulConnection,
11+
setIsModalOpened: (x: boolean) => void
12+
}) => {
13+
const disconnect = () => {
14+
// TODO: API call to disconnect this subscription
15+
console.log("Disconnect", subscription.account.login);
16+
setIsModalOpened(false);
17+
};
18+
19+
return (
20+
<>
21+
<Modal onClose={() => setIsModalOpened(false)}>
22+
<ModalHeader>
23+
<ModalTitle appearance="warning">
24+
<>Disconnect {subscription.account.login}?</>
25+
</ModalTitle>
26+
</ModalHeader>
27+
<ModalBody>
28+
<p data-testid="disconnect-content">
29+
Are you sure you want to disconnect your organization <b>{subscription.account.login}</b>?
30+
This means that you will have to redo the backfill of historical data if you ever want to reconnect
31+
</p>
32+
</ModalBody>
33+
<ModalFooter>
34+
<Button appearance="subtle" onClick={() => setIsModalOpened(false)}>Cancel</Button>
35+
<Button appearance="danger" onClick={disconnect}>
36+
Disconnect
37+
</Button>
38+
</ModalFooter>
39+
</Modal>
40+
</>
41+
);
42+
};
43+
44+
export default DisconnectSubscriptionModal;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import "@testing-library/jest-dom";
2+
import { render, screen } from "@testing-library/react";
3+
import { BrowserRouter } from "react-router-dom";
4+
import userEvent from "@testing-library/user-event";
5+
import RestartBackfillModal from "./RestartBackfillModal";
6+
7+
const sampleSubscription = {
8+
app_slug: "string",
9+
syncWarning: "warning",
10+
id: 1,
11+
account: {
12+
login: "sample",
13+
id: 1,
14+
avatar_url: "string",
15+
},
16+
repository_selection: "string",
17+
app_id: 1,
18+
target_id: 1,
19+
target_type: "string",
20+
created_at: "string",
21+
updated_at: "string",
22+
syncStatus: "string",
23+
totalNumberOfRepos: 2,
24+
numberOfSyncedRepos: 2,
25+
jiraHost: "https://test-jira.atlassian.net",
26+
isGlobalInstall: true,
27+
backfillSince: null,
28+
subscriptionId: 1,
29+
html_url: "html_url"
30+
};
31+
const isModalOpened = jest.fn();
32+
33+
test("Restart backfill Modal", async () => {
34+
render(
35+
<BrowserRouter>
36+
<RestartBackfillModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} />
37+
</BrowserRouter>
38+
);
39+
40+
expect(screen.getByText("Backfill your data")).toBeInTheDocument();
41+
// expect(screen.queryByTestId("backfill-datepicker")).toBeInTheDocument();
42+
expect(screen.getByRole("checkbox", {name: "Restart the backfill from today to this date"})).toBeInTheDocument();
43+
44+
await userEvent.click(screen.getByText("Cancel"));
45+
expect(isModalOpened).toBeCalled();
46+
});
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { useEffect, useState } from "react";
2+
import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from "@atlaskit/modal-dialog";
3+
import Button from "@atlaskit/button";
4+
import { SuccessfulConnection } from "../../../../../src/rest-interfaces";
5+
import { Checkbox } from "@atlaskit/checkbox";
6+
import { Label } from "@atlaskit/form";
7+
import { DatePicker } from "@atlaskit/datetime-picker";
8+
9+
/**
10+
* NOTE: While testing in dev mode, please disable the React.StrictMode first,
11+
* otherwise this modal won't show up.
12+
*/
13+
const RestartBackfillModal = ({ subscription, setIsModalOpened }: {
14+
subscription: SuccessfulConnection,
15+
setIsModalOpened: (x: boolean) => void
16+
}) => {
17+
const [restartFromDateCheck, setRestartFromDateCheck] = useState(false);
18+
const [backfillDate, setBackfillDate] = useState("");
19+
20+
/**
21+
* TODO: Remove this later once the issue within datepicker is identified and fixed
22+
* Thread: https://atlassian.slack.com/archives/CFJ9DU39U/p1701912243843529
23+
*
24+
* The datepicker jumps around when rendered inside a modal,
25+
* Until that is fixed, adding a short disable for the datepicker,
26+
* which is then enabled to avoid having the jumpy effect.
27+
*/
28+
const [isDisabled, setIsDisabled] = useState(true);
29+
useEffect(() => {
30+
setTimeout(() => setIsDisabled(false), 10);
31+
}, []);
32+
33+
const backfill = () => {
34+
// TODO: API call to disconnect this subscription
35+
console.log("Backfill for", subscription.account.login, restartFromDateCheck, backfillDate);
36+
setIsModalOpened(false);
37+
};
38+
39+
return (
40+
<>
41+
<Modal onClose={() => setIsModalOpened(false)}>
42+
<ModalHeader>
43+
<ModalTitle>Backfill your data</ModalTitle>
44+
</ModalHeader>
45+
<ModalBody>
46+
<p>
47+
Backfilling data can take a long time, so we’ll only backfill your data from the last 6 months.
48+
If you want to backfill more data, choose a date below. Branches will be backfilled regardless of their age.
49+
</p>
50+
<p>
51+
<Label htmlFor="backfill-date-picker">Choose date</Label>
52+
<DatePicker
53+
testId="backfill-datepicker"
54+
selectProps={{
55+
inputId: "backfill-date-picker",
56+
}}
57+
placeholder="Select date"
58+
isDisabled={isDisabled} // TODO: remove this later
59+
onChange={setBackfillDate}
60+
/>
61+
</p>
62+
<p>
63+
<Checkbox
64+
onChange={() => setRestartFromDateCheck(!restartFromDateCheck)}
65+
label={`Restart the backfill from today to this date`}
66+
name="restart-from-selected-date"
67+
/>
68+
</p>
69+
</ModalBody>
70+
<ModalFooter>
71+
<Button appearance="subtle" onClick={() => setIsModalOpened(false)}>Cancel</Button>
72+
<Button appearance="danger" onClick={backfill}>
73+
Backfill data
74+
</Button>
75+
</ModalFooter>
76+
</Modal>
77+
</>
78+
);
79+
};
80+
81+
export default RestartBackfillModal;

spa/src/utils/dynamicTableHelper.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Avatar from "@atlaskit/avatar";
33
import Badge from "@atlaskit/badge";
44
import { token } from "@atlaskit/tokens";
55
import Lozenge from "@atlaskit/lozenge";
6-
import { SuccessfulConnection } from "../rest-interfaces";
6+
import { BackfillPageModalTypes, SuccessfulConnection } from "../rest-interfaces";
77
import { ThemeAppearance } from "@atlaskit/lozenge/dist/types/Lozenge";
88
import { css } from "@emotion/react";
99
import EditIcon from "@atlaskit/icon/glyph/edit";
@@ -17,6 +17,12 @@ type Row = {
1717
cells: { key: string | number; content: React.JSX.Element | string | number }[];
1818
};
1919

20+
type ConnectionsActionsCallback = {
21+
setIsModalOpened: (x: boolean) => void;
22+
setSubscriptionForModal: (sub: SuccessfulConnection) => void;
23+
setSelectedModal: (x: BackfillPageModalTypes) => void;
24+
};
25+
2026
const rowWrapperStyle = css`
2127
display: flex;
2228
align-items: center;
@@ -82,7 +88,8 @@ const createHead = (withWidth: boolean) => {
8288
export const head = createHead(true);
8389

8490
export const getGHSubscriptionsRows = (
85-
SuccessfulConnections: SuccessfulConnection[]
91+
SuccessfulConnections: SuccessfulConnection[],
92+
callbacks?: ConnectionsActionsCallback
8693
): Row[] => {
8794
if (!SuccessfulConnections) {
8895
return [];
@@ -194,6 +201,24 @@ export const getGHSubscriptionsRows = (
194201
>
195202
Configure
196203
</DropdownItem>
204+
<DropdownItem
205+
onClick={() => {
206+
callbacks?.setIsModalOpened(true);
207+
callbacks?.setSubscriptionForModal(cloudConnection);
208+
callbacks?.setSelectedModal("BACKFILL");
209+
}}
210+
>
211+
Backfill
212+
</DropdownItem>
213+
<DropdownItem
214+
onClick={() => {
215+
callbacks?.setIsModalOpened(true);
216+
callbacks?.setSubscriptionForModal(cloudConnection);
217+
callbacks?.setSelectedModal("DISCONNECT_SUBSCRIPTION");
218+
}}
219+
>
220+
Disconnect
221+
</DropdownItem>
197222
</DropdownItemGroup>
198223
</DropdownMenu>
199224
</div>

0 commit comments

Comments
 (0)