From a523c3cf2d01115a49f18f3754415759b2787186 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 18 Jan 2023 16:35:24 +0800 Subject: [PATCH 1/8] Use the same SettingsTable for the API keys --- .../networking/queries/useGetApiKeysQuery.tsx | 8 +- packages/web/pages/settings/api.tsx | 166 ++++++++++-------- 2 files changed, 99 insertions(+), 75 deletions(-) diff --git a/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx b/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx index 9b3c9e79c..c1b6b0fa8 100644 --- a/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx +++ b/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx @@ -7,9 +7,9 @@ export interface ApiKey { name: string key?: string scopes: string[] - createdAt: Date - expiresAt: Date - usedAt?: Date + createdAt: string + expiresAt: string + usedAt?: string } interface ApiKeysQueryResponse { @@ -66,7 +66,7 @@ export function useGetApiKeysQuery(): ApiKeysQueryResponse { console.log('error', error) } return { - isValidating: false, + isValidating: true, apiKeys: [], // eslint-disable-next-line @typescript-eslint/no-empty-function revalidate: () => {}, diff --git a/packages/web/pages/settings/api.tsx b/packages/web/pages/settings/api.tsx index a78b2b285..aa6401a32 100644 --- a/packages/web/pages/settings/api.tsx +++ b/packages/web/pages/settings/api.tsx @@ -14,6 +14,14 @@ import { Table } from '../../components/elements/Table' import { FormInputProps } from '../../components/elements/FormElements' import { FormModal } from '../../components/patterns/FormModal' import { ConfirmationModal } from '../../components/patterns/ConfirmationModal' +import { + EmptySettingsRow, + SettingsTable, + SettingsTableRow, +} from '../../components/templates/settings/SettingsTable' +import { StyledText } from '../../components/elements/StyledText' +import { formattedShortDate } from '../../lib/dateFormatting' +import Link from 'next/link' interface ApiKey { name: string @@ -23,7 +31,7 @@ interface ApiKey { } export default function Api(): JSX.Element { - const { apiKeys, revalidate } = useGetApiKeysQuery() + const { apiKeys, revalidate, isValidating } = useGetApiKeysQuery() const [onDeleteId, setOnDeleteId] = useState('') const [addModalOpen, setAddModalOpen] = useState(false) const [name, setName] = useState('') @@ -48,25 +56,6 @@ export default function Api(): JSX.Element { } }, [router.query]) - const headers = ['Name', 'Scopes', 'Used at', 'Expires on'] - const rows = useMemo(() => { - const rows = new Map() - apiKeys.forEach((apiKey) => - rows.set(apiKey.id, { - name: apiKey.name, - scopes: apiKey.scopes.join(', ') || 'All', - usedAt: apiKey.usedAt - ? new Date(apiKey.usedAt).toISOString() - : 'Never used', - expiresAt: - new Date(apiKey.expiresAt).getTime() != neverExpiresDate.getTime() - ? new Date(apiKey.expiresAt).toDateString() - : 'Never', - }) - ) - return rows - }, [apiKeys]) - applyStoredTheme(false) async function onDelete(id: string): Promise { @@ -135,66 +124,101 @@ export default function Api(): JSX.Element { 'in 1 year', 'Never', ], - value: defaultExpiresAt, + value: neverExpiresDate, }, ]) } return ( - - + { + onAdd() + setName('') + setExpiresAt(new Date(neverExpiresDate)) + setAddModalOpen(true) + }} + children={ + <> + {apiKeys.length > 0 ? ( + apiKeys.map((apiKey, i) => { + return ( + setOnDeleteId(apiKey.id)} + deleteTitle="Delete" + sublineElement={ + + {`Last used: ${ + apiKey.usedAt + ? formattedShortDate(apiKey.usedAt) + : 'Never' + }, `} + {apiKey.expiresAt && + apiKey.expiresAt != neverExpiresDate.toISOString() + ? `expires: ${formattedShortDate(apiKey.expiresAt)}` + : 'never expires'} + + } + titleElement={<>} + extraElement={<>} + /> + ) + }) + ) : ( + + )} - {addModalOpen && ( - - )} + {addModalOpen && ( + + )} - {apiKeyGenerated && ( - { - await navigator.clipboard.writeText(apiKeyGenerated) - setApiKeyGenerated('') - }} - onOpenChange={() => setApiKeyGenerated('')} - /> - )} + acceptButtonLabel={'Copy'} + onAccept={async () => { + await navigator.clipboard.writeText(apiKeyGenerated) + setApiKeyGenerated('') + }} + onOpenChange={() => setApiKeyGenerated('')} + /> + )} - {onDeleteId && ( - { - await onDelete(onDeleteId) - setOnDeleteId('') - }} - onOpenChange={() => setOnDeleteId('')} - /> - )} - - { - onAdd() - setName('') - setExpiresAt(new Date(defaultExpiresAt)) - setAddModalOpen(true) - }} - /> - + {onDeleteId && ( + { + await onDelete(onDeleteId) + setOnDeleteId('') + }} + onOpenChange={() => setOnDeleteId('')} + /> + )} + + } + /> ) } From 7b885aeb348d011673e3f24657ae253453a86d11 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 18 Jan 2023 16:57:21 +0800 Subject: [PATCH 2/8] Dont use children= --- packages/web/pages/settings/api.tsx | 141 ++++++++++++++-------------- 1 file changed, 68 insertions(+), 73 deletions(-) diff --git a/packages/web/pages/settings/api.tsx b/packages/web/pages/settings/api.tsx index aa6401a32..c4010b50c 100644 --- a/packages/web/pages/settings/api.tsx +++ b/packages/web/pages/settings/api.tsx @@ -142,83 +142,78 @@ export default function Api(): JSX.Element { setExpiresAt(new Date(neverExpiresDate)) setAddModalOpen(true) }} - children={ - <> - {apiKeys.length > 0 ? ( - apiKeys.map((apiKey, i) => { - return ( - setOnDeleteId(apiKey.id)} - deleteTitle="Delete" - sublineElement={ - - {`Last used: ${ - apiKey.usedAt - ? formattedShortDate(apiKey.usedAt) - : 'Never' - }, `} - {apiKey.expiresAt && - apiKey.expiresAt != neverExpiresDate.toISOString() - ? `expires: ${formattedShortDate(apiKey.expiresAt)}` - : 'never expires'} - - } - titleElement={<>} - extraElement={<>} - /> - ) - }) - ) : ( - - )} - - {addModalOpen && ( - + {apiKeys.length > 0 ? ( + apiKeys.map((apiKey, i) => { + return ( + setOnDeleteId(apiKey.id)} + deleteTitle="Delete" + sublineElement={ + + {`Last used: ${ + apiKey.usedAt ? formattedShortDate(apiKey.usedAt) : 'Never' + }, `} + {apiKey.expiresAt && + apiKey.expiresAt != neverExpiresDate.toISOString() + ? `expires: ${formattedShortDate(apiKey.expiresAt)}` + : 'never expires'} + + } + titleElement={<>} + extraElement={<>} /> - )} + ) + }) + ) : ( + + )} - {apiKeyGenerated && ( - + )} + + {apiKeyGenerated && ( + { - await navigator.clipboard.writeText(apiKeyGenerated) - setApiKeyGenerated('') - }} - onOpenChange={() => setApiKeyGenerated('')} - /> - )} + acceptButtonLabel={'Copy'} + onAccept={async () => { + await navigator.clipboard.writeText(apiKeyGenerated) + setApiKeyGenerated('') + }} + onOpenChange={() => setApiKeyGenerated('')} + /> + )} - {onDeleteId && ( - { - await onDelete(onDeleteId) - setOnDeleteId('') - }} - onOpenChange={() => setOnDeleteId('')} - /> - )} - - } - /> + {onDeleteId && ( + { + await onDelete(onDeleteId) + setOnDeleteId('') + }} + onOpenChange={() => setOnDeleteId('')} + /> + )} + ) } From cab2e7ba0d9f82f528181765278e81cd5211b498 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 18 Jan 2023 17:47:13 +0800 Subject: [PATCH 3/8] Continue to use 7 days for default expires at --- packages/web/pages/settings/api.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web/pages/settings/api.tsx b/packages/web/pages/settings/api.tsx index c4010b50c..93664d1ab 100644 --- a/packages/web/pages/settings/api.tsx +++ b/packages/web/pages/settings/api.tsx @@ -124,7 +124,7 @@ export default function Api(): JSX.Element { 'in 1 year', 'Never', ], - value: neverExpiresDate, + value: defaultExpiresAt, }, ]) } @@ -139,7 +139,7 @@ export default function Api(): JSX.Element { createAction={() => { onAdd() setName('') - setExpiresAt(new Date(neverExpiresDate)) + setExpiresAt(new Date(defaultExpiresAt)) setAddModalOpen(true) }} > From 4e2197331c809999aabf8feec2b59ee67ff6b946 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 18 Jan 2023 18:01:34 +0800 Subject: [PATCH 4/8] Fix default expiration to match form --- .../components/patterns/ConfirmationModal.tsx | 5 ++--- packages/web/pages/settings/api.tsx | 20 ++++--------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/packages/web/components/patterns/ConfirmationModal.tsx b/packages/web/components/patterns/ConfirmationModal.tsx index a05d7524f..7ff120c77 100644 --- a/packages/web/components/patterns/ConfirmationModal.tsx +++ b/packages/web/components/patterns/ConfirmationModal.tsx @@ -6,14 +6,13 @@ import { import { VStack, HStack } from '../elements/LayoutPrimitives' import { Button } from '../elements/Button' import { StyledText } from '../elements/StyledText' -import { useConfirmListener } from '../../lib/keyboardShortcuts/useKeyboardShortcuts' -import { useEffect, useRef } from 'react' type ConfirmationModalProps = { message?: string richMessage?: React.ReactNode icon?: React.ReactNode acceptButtonLabel?: string + cancelButtonLabel?: string onAccept: () => void onOpenChange: (open: boolean) => void } @@ -42,7 +41,7 @@ export function ConfirmationModal(props: ConfirmationModalProps): JSX.Element { } }} > - Cancel + {props.cancelButtonLabel ? props.cancelButtonLabel : 'Cancel'} + From d08763c12651b6abd20b5619f2c46f3620a22706 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 18 Jan 2023 18:46:03 +0800 Subject: [PATCH 7/8] Fix default values when creating API keys, sort keys by createdAt --- .../web/components/elements/FormElements.tsx | 1 + packages/web/pages/settings/api.tsx | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/web/components/elements/FormElements.tsx b/packages/web/components/elements/FormElements.tsx index 1e5caa098..cdb98a1ca 100644 --- a/packages/web/components/elements/FormElements.tsx +++ b/packages/web/components/elements/FormElements.tsx @@ -92,6 +92,7 @@ export function GeneralFormInput(props: FormInputProps): JSX.Element { return (