From d27f79c25055274c5641ebb5c07d3fe0628fc9de Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Mon, 6 Jun 2022 11:41:58 +0800 Subject: [PATCH] Add get api keys UI --- .../networking/queries/useGetApiKeysQuery.tsx | 75 ++++++++++ packages/web/pages/settings/api-keys.tsx | 130 ++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 packages/web/lib/networking/queries/useGetApiKeysQuery.tsx create mode 100644 packages/web/pages/settings/api-keys.tsx diff --git a/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx b/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx new file mode 100644 index 000000000..b13422427 --- /dev/null +++ b/packages/web/lib/networking/queries/useGetApiKeysQuery.tsx @@ -0,0 +1,75 @@ +import { gql } from 'graphql-request' +import useSWR from 'swr' +import { publicGqlFetcher } from '../networkHelpers' + +export interface ApiKey { + id: string + name: string + key?: string + scopes: string[] + createdAt: Date + expiresAt: Date + usedAt?: Date +} + +interface ApiKeysQueryResponse { + isValidating: boolean + apiKeys: ApiKey[] + revalidate: () => void +} + +interface ApiKeysQueryResponseData { + apiKeys: ApiKeysData +} + +interface ApiKeysData { + apiKeys: unknown +} + +export function useGetApiKeysQuery(): ApiKeysQueryResponse { + const query = gql` + query GetApiKeys { + apiKeys { + ... on ApiKeysSuccess { + apiKeys { + id + name + key + scopes + createdAt + expiresAt + usedAt + } + } + ... on ApiKeysError { + errorCodes + } + } + } + ` + + const { data, mutate, error, isValidating } = useSWR(query, publicGqlFetcher) + console.log('api keys data', data) + + try { + if (data) { + const result = data as ApiKeysQueryResponseData + const apiKeys = result.apiKeys.apiKeys as ApiKey[] + return { + isValidating, + apiKeys, + revalidate: () => { + mutate() + }, + } + } + } catch (error) { + console.log('error', error) + } + return { + isValidating: false, + apiKeys: [], + // eslint-disable-next-line @typescript-eslint/no-empty-function + revalidate: () => {}, + } +} diff --git a/packages/web/pages/settings/api-keys.tsx b/packages/web/pages/settings/api-keys.tsx new file mode 100644 index 000000000..a46ed0352 --- /dev/null +++ b/packages/web/pages/settings/api-keys.tsx @@ -0,0 +1,130 @@ +import { PrimaryLayout } from '../../components/templates/PrimaryLayout' +import { Toaster } from 'react-hot-toast' +import { Table } from '../../components/elements/Table' +import { applyStoredTheme } from '../../lib/themeUpdater' +import { useMemo } from 'react' +import { useGetApiKeysQuery } from '../../lib/networking/queries/useGetApiKeysQuery' + +interface ApiKey { + name: string + scopes: string + expiresAt: string + usedAt: string +} + +export default function ApiKeys(): JSX.Element { + const { apiKeys, revalidate } = useGetApiKeysQuery() + // const [onDeleteId, setOnDeleteId] = useState(null) + // const [addModelOpen, setAddModelOpen] = useState(false) + // const [url, setUrl] = useState('') + // const [formInputs, setFormInputs] = useState([]) + + const headers = ['Name', 'Scopes', 'Used at', 'Expires at'] + const rows = useMemo(() => { + const rows = new Map() + apiKeys.forEach((apiKey) => + rows.set(apiKey.id, { + name: apiKey.name, + scopes: apiKey.scopes.join(', '), + usedAt: apiKey.usedAt?.toISOString() || 'Never', + expiresAt: apiKey.expiresAt.toISOString(), + }) + ) + return rows + }, [apiKeys]) + + applyStoredTheme(false) + + // async function onDelete(id: string): Promise { + // const result = await deleteWebhookMutation(id) + // if (result) { + // showSuccessToast('Webhook deleted', { position: 'bottom-right' }) + // } else { + // showErrorToast('Failed to delete', { position: 'bottom-right' }) + // } + // revalidate() + // } + // + // async function onCreate(): Promise { + // const result = await setWebhookMutation({ url, eventTypes }) + // if (result) { + // showSuccessToast('Webhook created', { position: 'bottom-right' }) + // } else { + // showErrorToast('Failed to add', { position: 'bottom-right' }) + // } + // revalidate() + // } + + return ( + + + + {/*{addModelOpen && (*/} + {/* */} + {/*)}*/} + + {/*{onDeleteId && (*/} + {/* {*/} + {/* await onDelete(onDeleteId)*/} + {/* setOnDeleteId(null)*/} + {/* }}*/} + {/* onOpenChange={() => setOnDeleteId(null)}*/} + {/* />*/} + {/*)}*/} + { + // setFormInputs([ + // { + // label: 'URL', + // onChange: setUrl, + // name: 'url', + // placeholder: 'https://example.com/webhook', + // required: true, + // }, + // { + // label: 'Event Types', + // name: 'eventTypes', + // value: [true, true], + // onChange: setEventTypes, + // options: eventTypeOptions, + // type: 'checkbox', + // }, + // { + // label: 'Method', + // name: 'method', + // value: method, + // disabled: true, + // }, + // { + // label: 'Content Type', + // name: 'contentType', + // value: contentType, + // disabled: true, + // }, + // ]) + // setUrl('') + // setEventTypes(eventTypeOptions as WebhookEvent[]) + // setAddModelOpen(true) + // }} + /> + + ) +}