Skip to content

Commit

Permalink
feat(sdk): add pages to delete service account and token (#825)
Browse files Browse the repository at this point in the history
* feat: add page to delete service account

* feat: add page to revoke service account key

* fix: delete loading state

* chore: update css variables
  • Loading branch information
rsbh authored and anujk14 committed Dec 2, 2024
1 parent 0d25548 commit 4bf5ec5
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const AddServiceAccount = () => {
}
});
}
} catch ({ error }: any) {
} catch (error: any) {
toast.error('Something went wrong', {
description: error.message
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TrashIcon } from '@radix-ui/react-icons';
import { ApsaraColumnDef } from '@raystack/apsara';
import { Button, Flex, Text } from '@raystack/apsara/v1';
import { Link } from '@tanstack/react-router';
import { Link, useNavigate } from '@tanstack/react-router';
import dayjs from 'dayjs';
import { V1Beta1ServiceUser } from '~/api-client';

Expand Down Expand Up @@ -53,16 +53,26 @@ export const getColumns = ({
}
},
cell: ({ row, getValue }) => {
return (
<Button
variant="text"
size="small"
data-test-id="frontier-sdk-delete-service-account-btn"
>
<TrashIcon />
</Button>
);
return <ServiceAccountDeleteAction id={getValue()} />;
}
}
];
};

function ServiceAccountDeleteAction({ id }: { id: string }) {
const navigate = useNavigate({ from: '/api-keys' });

function onDeleteClick() {
return navigate({ to: '/api-keys/$id/delete', params: { id: id } });
}
return (
<Button
variant="text"
size="small"
data-test-id="frontier-sdk-delete-service-account-btn"
onClick={onDeleteClick}
>
<TrashIcon />
</Button>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Dialog, Separator, Image } from '@raystack/apsara';
import styles from './styles.module.css';
import { Button, Flex, Text, toast } from '@raystack/apsara/v1';
import cross from '~/react/assets/cross.svg';
import { useNavigate, useParams } from '@tanstack/react-router';
import { useFrontier } from '~/react/contexts/FrontierContext';
import { useState } from 'react';

export const DeleteServiceAccount = () => {
const { id } = useParams({ from: '/api-keys/$id/delete' });
const navigate = useNavigate({ from: '/api-keys/$id/delete' });
const { client, activeOrganization: organization } = useFrontier();
const [isLoading, setIsLoading] = useState(false);

const orgId = organization?.id;

async function onDeleteClick() {
try {
setIsLoading(true);
await client?.frontierServiceDeleteServiceUser(id, { org_id: orgId });
navigate({
to: '/api-keys',
state: {
refetch: true
}
});
toast.success('Service account deleted');
} catch (err: any) {
toast.error('Unable to delete service account', {
description: err?.message
});
} finally {
setIsLoading(false);
}
}

function onCancel() {
navigate({ to: '/api-keys' });
}

return (
<Dialog open={true}>
{/* @ts-ignore */}
<Dialog.Content
overlayClassname={styles.overlay}
className={styles.addDialogContent}
>
<Flex justify="between" className={styles.addDialogForm}>
<Text size={6} weight={500}>
Delete Service Account
</Text>

<Image
alt="cross"
style={{ cursor: 'pointer' }}
// @ts-ignore
src={cross}
onClick={() => navigate({ to: '/api-keys' })}
data-test-id="frontier-sdk-delete-service-account-close-btn"
/>
</Flex>
<Separator />

<Flex
direction="column"
gap="medium"
className={styles.addDialogFormContent}
>
<Text>
This is an irreversible and permanent action doing this might result
in deletion of the service account and the keys associated with it.
Do you wish to proceed?
</Text>
</Flex>
<Separator />
<Flex
justify="end"
className={styles.addDialogFormBtnWrapper}
gap={'medium'}
>
<Button
variant="secondary"
size="normal"
data-test-id="frontier-sdk-delete-service-account-cancel-btn"
onClick={onCancel}
>
Cancel
</Button>
<Button
variant="danger"
size="normal"
data-test-id="frontier-sdk-delete-service-account-confirm-btn"
loading={isLoading}
disabled={isLoading}
onClick={onDeleteClick}
loaderText="Deleting..."
>
I Understand and Delete
</Button>
</Flex>
</Dialog.Content>
</Dialog>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ExclamationTriangleIcon } from '@radix-ui/react-icons';
import Skeleton from 'react-loading-skeleton';
import { getColumns } from './columns';
import { V1Beta1ServiceUser } from '~/api-client/dist';
import { Outlet, useNavigate } from '@tanstack/react-router';
import { Outlet, useLocation, useNavigate } from '@tanstack/react-router';

const NoServiceAccounts = ({
config
Expand Down Expand Up @@ -165,6 +165,8 @@ const ServiceAccountsTable = ({
export default function ApiKeys() {
const [serviceUsers, setServiceUsers] = useState<V1Beta1ServiceUser[]>([]);
const [isServiceUsersLoading, setIsServiceUsersLoading] = useState(false);
const location = useLocation();
const refetch = location?.state?.refetch;

const {
activeOrganization: organization,
Expand Down Expand Up @@ -196,7 +198,7 @@ export default function ApiKeys() {
if (organization?.id && canUpdateWorkspace) {
getServiceAccounts(organization?.id);
}
}, [organization?.id, client, canUpdateWorkspace]);
}, [organization?.id, client, canUpdateWorkspace, refetch]);

const isLoading =
isActiveOrganizationLoading ||
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Dialog, Separator, Image } from '@raystack/apsara';
import styles from './styles.module.css';
import { Button, Flex, Text, toast } from '@raystack/apsara/v1';
import cross from '~/react/assets/cross.svg';
import { useNavigate, useParams } from '@tanstack/react-router';
import { useFrontier } from '~/react/contexts/FrontierContext';
import { useState } from 'react';
import { DEFAULT_API_PLATFORM_APP_NAME } from '~/react/utils/constants';

export const DeleteServiceAccountKey = () => {
const { id, tokenId } = useParams({
from: '/api-keys/$id/key/$tokenId/delete'
});
const navigate = useNavigate({ from: '/api-keys/$id/key/$tokenId/delete' });
const { client, config } = useFrontier();
const [isLoading, setIsLoading] = useState(false);

async function onDeleteClick() {
try {
setIsLoading(true);
await client?.frontierServiceDeleteServiceUserToken(id, tokenId);
navigate({
to: '/api-keys/$id',
params: {
id: id
},
state: {
refetch: true
}
});
toast.success('Service account key revoked');
} catch (err: any) {
toast.error('Unable to revoke service account key', {
description: err?.message
});
} finally {
setIsLoading(false);
}
}

function onCancel() {
navigate({
to: '/api-keys/$id',
params: {
id: id
}
});
}
const appName = config?.apiPlatform?.appName || DEFAULT_API_PLATFORM_APP_NAME;

return (
<Dialog open={true}>
{/* @ts-ignore */}
<Dialog.Content
overlayClassname={styles.overlay}
className={styles.addDialogContent}
>
<Flex justify="between" className={styles.addDialogForm}>
<Text size={6} weight={500}>
Revoke API Key
</Text>

<Image
alt="cross"
style={{ cursor: 'pointer' }}
// @ts-ignore
src={cross}
onClick={onCancel}
data-test-id="frontier-sdk-revoke-service-account-key-close-btn"
/>
</Flex>
<Separator />

<Flex
direction="column"
gap="medium"
className={styles.addDialogFormContent}
>
<Text>
This is an irreversible action doing this might lead to
discontinuation of access to the {appName} features. Do you wish to
proceed?
</Text>
</Flex>
<Separator />
<Flex
justify="end"
className={styles.addDialogFormBtnWrapper}
gap={'medium'}
>
<Button
variant="secondary"
size="normal"
data-test-id="frontier-sdk-revoke-service-account-key-cancel-btn"
onClick={onCancel}
>
Cancel
</Button>
<Button
variant="danger"
size="normal"
data-test-id="frontier-sdk-revoke-service-account-key-confirm-btn"
loading={isLoading}
disabled={isLoading}
onClick={onDeleteClick}
loaderText="Revoking..."
>
Revoke
</Button>
</Flex>
</Dialog.Content>
</Dialog>
);
};
Loading

0 comments on commit 4bf5ec5

Please sign in to comment.