Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[INNO] -Deleting the subscription when clicking on the Disconnect button. #2607

Merged
merged 25 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
be99c17
- Modal added for backfilling and disconnecting subscription
krazziekay Dec 5, 2023
150023e
- Fixing eslint in a test case
krazziekay Dec 5, 2023
4dd1eed
- WIP - backfill modal
krazziekay Dec 5, 2023
7377807
- WIP - backfill modal
krazziekay Dec 5, 2023
e5d872b
Merge branch 'main' of github.com:atlassian/github-for-jira into ARC-…
krazziekay Dec 5, 2023
9379076
Merge branch 'main' into ARC-adding-modals-for-backfill-page
krazziekay Dec 5, 2023
e940786
Merge branch 'main' of github.com:atlassian/github-for-jira into ARC-…
krazziekay Dec 5, 2023
54747ff
- WIP - backfill modal
krazziekay Dec 5, 2023
ef67e5a
Merge branch 'main' into ARC-adding-modals-for-backfill-page
krazziekay Dec 6, 2023
0b4d49f
- Using the corrected datepicker
krazziekay Dec 7, 2023
2cebe4d
Merge remote-tracking branch 'origin' into ARC-adding-modals-for-back…
krazziekay Dec 7, 2023
f3c4998
Merge branch 'main' into ARC-adding-modals-for-backfill-page
krazziekay Dec 7, 2023
a3b96bf
- Fixing the delete subscription endpoint
krazziekay Dec 7, 2023
f455983
- Test cases added
krazziekay Dec 7, 2023
31caf4a
Merge remote-tracking branch 'origin' into ARC-adding-modals-for-back…
krazziekay Dec 7, 2023
d3934ee
- Fixing test cases
krazziekay Dec 7, 2023
18c04ec
- Added delete subscription function on modal button click
krazziekay Dec 7, 2023
ba947ab
- Fixing types
krazziekay Dec 7, 2023
4e5a822
- Minor fixing
krazziekay Dec 7, 2023
1de5bb6
- Adding test case
krazziekay Dec 7, 2023
5cf2caa
- Refetching added
krazziekay Dec 7, 2023
ec6ef6b
- Cleanup
krazziekay Dec 8, 2023
5b10a31
- Fixing conflicts
krazziekay Dec 8, 2023
ca346b0
Merge branch 'ARC-adding-modals-for-backfill-page' into ARC-delete-su…
krazziekay Dec 8, 2023
c7d339c
- Fixing conflicts
krazziekay Dec 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions spa/src/pages/Connections/GHCloudConnections/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,30 @@ const containerStyles = xcss({

type GitHubCloudConnectionsProps = {
ghCloudSubscriptions: GhCloudSubscriptions;
refetch: () => void;
};

const GitHubCloudConnections = ({
ghCloudSubscriptions,
refetch,
}: GitHubCloudConnectionsProps) => {
const [isModalOpened, setIsModalOpened] = useState(false);
const [subscriptionForModal, setSubscriptionForModal] = useState<SuccessfulConnection | undefined>(undefined);
const [selectedModal, setSelectedModal] = useState<BackfillPageModalTypes>("BACKFILL");

const openedModal = () => {
const openedModal = (refetch: () => void) => {
switch (selectedModal) {
case "BACKFILL":
return (<RestartBackfillModal
subscription={subscriptionForModal as SuccessfulConnection}
setIsModalOpened={setIsModalOpened}
refetch={refetch}
/>);
case "DISCONNECT_SUBSCRIPTION":
return <DisconnectSubscriptionModal
subscription={subscriptionForModal as SuccessfulConnection}
setIsModalOpened={setIsModalOpened}
refetch={refetch}
/>;
// TODO: Create modals for GHE later
case "DISCONNECT_SERVER":
Expand All @@ -64,7 +68,7 @@ const GitHubCloudConnections = ({

<ModalTransition>
{
isModalOpened && subscriptionForModal && openedModal()
isModalOpened && subscriptionForModal && openedModal(refetch)
}
</ModalTransition>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { render, screen } from "@testing-library/react";
import { BrowserRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event";
import DisconnectSubscriptionModal from "./DisconnectSubscriptionModal";
import SubscriptionManager from "../../../services/subscription-manager";

jest.mock("../../../services/subscription-manager");

const sampleSubscription = {
app_slug: "string",
Expand All @@ -29,11 +32,12 @@ const sampleSubscription = {
html_url: "html_url"
};
const isModalOpened = jest.fn();
const refetch = jest.fn();

test("Disconnect subscription Modal", async () => {
test("Clicking cancel in disconnect subscription Modal", async () => {
render(
<BrowserRouter>
<DisconnectSubscriptionModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} />
<DisconnectSubscriptionModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} refetch={refetch} />
</BrowserRouter>
);

Expand All @@ -43,4 +47,27 @@ test("Disconnect subscription Modal", async () => {

await userEvent.click(screen.getByText("Cancel"));
expect(isModalOpened).toBeCalled();
expect(refetch).not.toBeCalled();
});

test("Clicking Disconnect in disconnect subscription Modal", async () => {
jest.mocked(SubscriptionManager).deleteSubscription = jest.fn().mockReturnValue(Promise.resolve(true));

render(
<BrowserRouter>
<DisconnectSubscriptionModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} refetch={refetch} />
</BrowserRouter>
);

expect(screen.getByText("Disconnect sample?")).toBeInTheDocument();
const text = screen.getByTestId("disconnect-content");
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");

await userEvent.click(screen.getByText("Disconnect"));
/**
* Called twice, once when the loading is set to true,
* and later after getting the response from the API request
*/
expect(isModalOpened).toBeCalledTimes(2);
expect(refetch).toBeCalled();
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import { useState } from "react";
import { AxiosError } from "axios";
import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from "@atlaskit/modal-dialog";
import Button from "@atlaskit/button";
import Button, { LoadingButton } from "@atlaskit/button";
import { SuccessfulConnection } from "../../../../../src/rest-interfaces";
import SubscriptionManager from "../../../services/subscription-manager";

/**
* NOTE: While testing in dev mode, please disable the React.StrictMode first,
* otherwise this modal won't show up.
*/
const DisconnectSubscriptionModal = ({ subscription, setIsModalOpened }: {
const DisconnectSubscriptionModal = ({ subscription, setIsModalOpened, refetch }: {
subscription: SuccessfulConnection,
setIsModalOpened: (x: boolean) => void
setIsModalOpened: (x: boolean) => void,
refetch: () => void
}) => {
const disconnect = () => {
// TODO: API call to disconnect this subscription
console.log("Disconnect", subscription.account.login);
const [isLoading, setIsLoading] = useState<boolean>(false);

const disconnect = async () => {
setIsLoading(true);
const response: boolean | AxiosError = await SubscriptionManager.deleteSubscription(subscription.subscriptionId);
if (response instanceof AxiosError) {
// TODO: Handle the error once we have the designs
console.error("Error", response);
} else {
await refetch();
}
setIsModalOpened(false);
};

Expand All @@ -31,10 +43,20 @@ const DisconnectSubscriptionModal = ({ subscription, setIsModalOpened }: {
</p>
</ModalBody>
<ModalFooter>
<Button appearance="subtle" onClick={() => setIsModalOpened(false)}>Cancel</Button>
<Button appearance="danger" onClick={disconnect}>
Disconnect
<Button
isDisabled={isLoading}
appearance="subtle"
onClick={() => setIsModalOpened(false)}
>
Cancel
</Button>
{
isLoading ? <LoadingButton style={{ width: 80 }} isLoading>
Loading button
</LoadingButton> : <Button appearance="danger" onClick={disconnect}>
Disconnect
</Button>
}
</ModalFooter>
</Modal>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ const sampleSubscription = {
html_url: "html_url"
};
const isModalOpened = jest.fn();
const refetch = jest.fn();

test("Restart backfill Modal", async () => {
render(
<BrowserRouter>
<RestartBackfillModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} />
<RestartBackfillModal subscription={sampleSubscription} setIsModalOpened={isModalOpened} refetch={refetch} />
</BrowserRouter>
);

Expand Down
8 changes: 5 additions & 3 deletions spa/src/pages/Connections/Modals/RestartBackfillModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import { DatePicker } from "@atlaskit/datetime-picker";
* NOTE: While testing in dev mode, please disable the React.StrictMode first,
* otherwise this modal won't show up.
*/
const RestartBackfillModal = ({ subscription, setIsModalOpened }: {
const RestartBackfillModal = ({ subscription, setIsModalOpened, refetch }: {
subscription: SuccessfulConnection,
setIsModalOpened: (x: boolean) => void
setIsModalOpened: (x: boolean) => void,
refetch: () => void,
}) => {
const [restartFromDateCheck, setRestartFromDateCheck] = useState(false);
const [backfillDate, setBackfillDate] = useState("");
Expand All @@ -30,9 +31,10 @@ const RestartBackfillModal = ({ subscription, setIsModalOpened }: {
setTimeout(() => setIsDisabled(false), 10);
}, []);

const backfill = () => {
const backfill = async () => {
// TODO: API call to disconnect this subscription
console.log("Backfill for", subscription.account.login, restartFromDateCheck, backfillDate);
await refetch();
setIsModalOpened(false);
};

Expand Down
33 changes: 16 additions & 17 deletions spa/src/pages/Connections/index.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,54 @@
import { useEffect, useState } from "react";
import ApiRequest from "../../api";
import SyncHeader from "../../components/SyncHeader";
import Step from "../../components/Step";
import { Wrapper } from "../../common/Wrapper";
import GitHubCloudConnections from "./GHCloudConnections";
import GitHubEnterpriseConnections from "./GHEnterpriseConnections";
import { GHSubscriptions } from "../../rest-interfaces";
import { reportError } from "../../utils";
import SkeletonForLoading from "./SkeletonForLoading";
import { useNavigate } from "react-router-dom";
import SubscriptionManager from "../../services/subscription-manager";
import { AxiosError } from "axios";

const Connections = () => {
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [ghSubscriptions, setSubscriptions] = useState<GHSubscriptions | null>(null);
const [subscriptions, setSubscriptions] = useState<GHSubscriptions | null>(null);
const fetchGHSubscriptions = async () => {
try {
setIsLoading(true);
const { data } = await ApiRequest.subscriptions.getSubscriptions();
setSubscriptions(data);
} catch (e) {
reportError(e, { path: "Fetching subscriptions" });
} finally {
setIsLoading(false);
setIsLoading(true);
const response = await SubscriptionManager.getSubscriptions();
if (response instanceof AxiosError) {
// TODO: Handle the error once we have the designs
console.error("Error", response);
}
setSubscriptions(response as GHSubscriptions);
setIsLoading(false);
krazziekay marked this conversation as resolved.
Show resolved Hide resolved
};
useEffect(() => {
fetchGHSubscriptions();
}, []);

// If there are no connections then go back to the start page
useEffect(() => {
if (!ghSubscriptions?.ghCloudSubscriptions && ghSubscriptions?.ghEnterpriseServers && ghSubscriptions.ghEnterpriseServers?.length === 0) {
if (!subscriptions?.ghCloudSubscriptions && subscriptions?.ghEnterpriseServers && subscriptions.ghEnterpriseServers?.length === 0) {
navigate("/spa");
}
}, [ghSubscriptions, navigate]);
}, [subscriptions, navigate]);

return (
<Wrapper>
<SyncHeader />
{
isLoading ? <SkeletonForLoading /> : <>
{
ghSubscriptions?.ghCloudSubscriptions && <Step title="GitHub Cloud">
<GitHubCloudConnections ghCloudSubscriptions={ghSubscriptions.ghCloudSubscriptions} />
subscriptions?.ghCloudSubscriptions && <Step title="GitHub Cloud">
<GitHubCloudConnections ghCloudSubscriptions={subscriptions.ghCloudSubscriptions} refetch={fetchGHSubscriptions} />
</Step>
}

{
ghSubscriptions?.ghEnterpriseServers && ghSubscriptions.ghEnterpriseServers?.length > 0 && <Step title="GitHub Enterprise Server">
<GitHubEnterpriseConnections ghEnterpriseServers={ghSubscriptions.ghEnterpriseServers} />
subscriptions?.ghEnterpriseServers && subscriptions.ghEnterpriseServers?.length > 0 && <Step title="GitHub Enterprise Server">
<GitHubEnterpriseConnections ghEnterpriseServers={subscriptions.ghEnterpriseServers} />
</Step>
}
</>
Expand Down
47 changes: 47 additions & 0 deletions spa/src/services/subscription-manager/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Api from "../../api";
import { AxiosError } from "axios";
import { reportError } from "../../utils";
import { GHSubscriptions } from "../../../../src/rest-interfaces";

async function getSubscriptions(): Promise<GHSubscriptions | AxiosError> {
try {
const response= await Api.subscriptions.getSubscriptions();
const status = response.status === 200;
if(!status) {
reportError(
{ message: "Response status for getting subscriptions is not 204", status: response.status },
{ path: "getSubscriptions" }
);
}

return response.data;
} catch (e: unknown) {
reportError(new Error("Unable to delete subscription", { cause: e }), { path: "getSubscriptions" });
return e as AxiosError;
}
}

async function deleteSubscription(subscriptionId: number): Promise<boolean | AxiosError> {
try {
const response= await Api.subscriptions.deleteSubscription(subscriptionId);
const ret = response.status === 204;
if(!ret) {
reportError(
{ message: "Response status for deleting subscription is not 204", status: response.status },
{ path: "deleteSubscription" }
);
}

return ret;
} catch (e: unknown) {
reportError(new Error("Unable to delete subscription", { cause: e }), { path: "deleteSubscription" });
return e as AxiosError;
}
}

export default {
getSubscriptions,
deleteSubscription,
};


Loading