From cf16d25a678c6129bda7a8cb115baca83f112662 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Wed, 5 Jun 2024 07:13:35 -0400 Subject: [PATCH] chore: Tidy API key settings page --- app/actions/definitions/apiKeys.tsx | 25 +++++++++++++++++ app/hooks/useSettingsConfig.ts | 2 +- app/scenes/{APITokenNew.tsx => APIKeyNew.tsx} | 19 ++++++++----- app/scenes/Settings/ApiKeys.tsx | 27 +++++++------------ server/models/ApiKey.ts | 7 ++--- shared/i18n/locales/en_US/translation.json | 12 ++++----- shared/validations.ts | 7 +++++ 7 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 app/actions/definitions/apiKeys.tsx rename app/scenes/{APITokenNew.tsx => APIKeyNew.tsx} (69%) diff --git a/app/actions/definitions/apiKeys.tsx b/app/actions/definitions/apiKeys.tsx new file mode 100644 index 000000000..0252f1086 --- /dev/null +++ b/app/actions/definitions/apiKeys.tsx @@ -0,0 +1,25 @@ +import { PlusIcon } from "outline-icons"; +import * as React from "react"; +import stores from "~/stores"; +import APIKeyNew from "~/scenes/APIKeyNew"; +import { createAction } from ".."; +import { SettingsSection } from "../sections"; + +export const createApiKey = createAction({ + name: ({ t }) => t("New API key"), + analyticsName: "New API key", + section: SettingsSection, + icon: , + keywords: "create", + visible: () => + stores.policies.abilities(stores.auth.team?.id || "").createApiKey, + perform: ({ t, event }) => { + event?.preventDefault(); + event?.stopPropagation(); + + stores.dialogs.openModal({ + title: t("New API key"), + content: , + }); + }, +}); diff --git a/app/hooks/useSettingsConfig.ts b/app/hooks/useSettingsConfig.ts index 1183acd95..482a100f1 100644 --- a/app/hooks/useSettingsConfig.ts +++ b/app/hooks/useSettingsConfig.ts @@ -88,7 +88,7 @@ const useSettingsConfig = () => { icon: EmailIcon, }, { - name: t("API Tokens"), + name: t("API"), path: settingsPath("tokens"), component: ApiKeys, enabled: can.createApiKey, diff --git a/app/scenes/APITokenNew.tsx b/app/scenes/APIKeyNew.tsx similarity index 69% rename from app/scenes/APITokenNew.tsx rename to app/scenes/APIKeyNew.tsx index 96967eae0..68125cc69 100644 --- a/app/scenes/APITokenNew.tsx +++ b/app/scenes/APIKeyNew.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; +import { ApiKeyValidation } from "@shared/validations"; import Button from "~/components/Button"; import Flex from "~/components/Flex"; import Input from "~/components/Input"; @@ -11,7 +12,7 @@ type Props = { onSubmit: () => void; }; -function APITokenNew({ onSubmit }: Props) { +function APIKeyNew({ onSubmit }: Props) { const [name, setName] = React.useState(""); const [isSaving, setIsSaving] = React.useState(false); const { apiKeys } = useStores(); @@ -26,7 +27,7 @@ function APITokenNew({ onSubmit }: Props) { await apiKeys.create({ name, }); - toast.success(t("API token created")); + toast.success(t("API Key created")); onSubmit(); } catch (err) { toast.error(err.message); @@ -45,7 +46,7 @@ function APITokenNew({ onSubmit }: Props) {
{t( - `Name your token something that will help you to remember it's use in the future, for example "local development", "production", or "continuous integration".` + `Name your key something that will help you to remember it's use in the future, for example "local development" or "continuous integration".` )} @@ -54,16 +55,20 @@ function APITokenNew({ onSubmit }: Props) { label={t("Name")} onChange={handleNameChange} value={name} + minLength={ApiKeyValidation.minNameLength} + maxLength={ApiKeyValidation.maxNameLength} required autoFocus flex /> - + + +
); } -export default APITokenNew; +export default APIKeyNew; diff --git a/app/scenes/Settings/ApiKeys.tsx b/app/scenes/Settings/ApiKeys.tsx index 52e30694f..000a3faa2 100644 --- a/app/scenes/Settings/ApiKeys.tsx +++ b/app/scenes/Settings/ApiKeys.tsx @@ -3,15 +3,14 @@ import { CodeIcon } from "outline-icons"; import * as React from "react"; import { useTranslation, Trans } from "react-i18next"; import ApiKey from "~/models/ApiKey"; -import APITokenNew from "~/scenes/APITokenNew"; import { Action } from "~/components/Actions"; import Button from "~/components/Button"; import Heading from "~/components/Heading"; -import Modal from "~/components/Modal"; import PaginatedList from "~/components/PaginatedList"; import Scene from "~/components/Scene"; import Text from "~/components/Text"; -import useBoolean from "~/hooks/useBoolean"; +import { createApiKey } from "~/actions/definitions/apiKeys"; +import useActionContext from "~/hooks/useActionContext"; import useCurrentTeam from "~/hooks/useCurrentTeam"; import usePolicy from "~/hooks/usePolicy"; import useStores from "~/hooks/useStores"; @@ -21,12 +20,12 @@ function ApiKeys() { const team = useCurrentTeam(); const { t } = useTranslation(); const { apiKeys } = useStores(); - const [newModalOpen, handleNewModalOpen, handleNewModalClose] = useBoolean(); const can = usePolicy(team); + const context = useActionContext(); return ( } actions={ <> @@ -34,19 +33,20 @@ function ApiKeys() {