From c00e8cfa54dacb8b3e1f8d4eee7160a75bf96606 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Tue, 22 Apr 2025 15:20:41 -0300 Subject: [PATCH] perf: Fetch data server-side for Api Keys page (#20677) * server-side fetching for api keys page * refactor billing page * fix --- .../developer/api-keys/actions.ts | 7 ++++ .../developer/api-keys/loading.tsx | 5 +++ .../developer/api-keys/page.tsx | 21 ++++------- apps/web/middleware.ts | 2 ++ .../settings/developer/api-keys-skeleton.tsx | 24 +++++++++++++ .../settings/developer/api-keys-view.tsx | 35 +++++++------------ .../api-keys/components/ApiKeyDialogForm.tsx | 5 ++- .../ee/api-keys/components/ApiKeyListItem.tsx | 8 +++-- 8 files changed, 67 insertions(+), 40 deletions(-) create mode 100644 apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions.ts create mode 100644 apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/loading.tsx create mode 100644 apps/web/modules/settings/developer/api-keys-skeleton.tsx diff --git a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions.ts b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions.ts new file mode 100644 index 0000000000..4351daf7dc --- /dev/null +++ b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions.ts @@ -0,0 +1,7 @@ +"use server"; + +import { revalidatePath } from "next/cache"; + +export async function revalidateApiKeysList() { + revalidatePath("/settings/developer/api-keys"); +} diff --git a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/loading.tsx b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/loading.tsx new file mode 100644 index 0000000000..da4647980d --- /dev/null +++ b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/loading.tsx @@ -0,0 +1,5 @@ +import { SkeletonLoader } from "~/settings/developer/api-keys-skeleton"; + +export default function Loading() { + return ; +} diff --git a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/page.tsx b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/page.tsx index 7d3e7ae798..ec4b1db182 100644 --- a/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/page.tsx +++ b/apps/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/page.tsx @@ -1,9 +1,10 @@ -import { getTranslate, _generateMetadata } from "app/_utils"; +import { createRouterCaller } from "app/_trpc/context"; +import { _generateMetadata } from "app/_utils"; -import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader"; import { APP_NAME } from "@calcom/lib/constants"; +import { apiKeysRouter } from "@calcom/trpc/server/routers/viewer/apiKeys/_router"; -import ApiKeysView, { NewApiKeyButton } from "~/settings/developer/api-keys-view"; +import ApiKeysView from "~/settings/developer/api-keys-view"; export const generateMetadata = async () => await _generateMetadata( @@ -15,17 +16,9 @@ export const generateMetadata = async () => ); const Page = async () => { - const t = await getTranslate(); - - return ( - } - borderInShellHeader={true}> - - - ); + const caller = await createRouterCaller(apiKeysRouter); + const apiKeys = await caller.list(); + return ; }; export default Page; diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts index 576387edfa..b9df41d18c 100644 --- a/apps/web/middleware.ts +++ b/apps/web/middleware.ts @@ -20,6 +20,7 @@ export const POST_METHODS_ALLOWED_API_ROUTES = ["/api/auth/signup", "/api/trpc/" export const POST_METHODS_ALLOWED_APP_ROUTES = [ "/settings/my-account/general", "/settings/developer/webhooks", + "/settings/developer/api-keys", ]; export function checkPostMethod(req: NextRequest) { const pathname = req.nextUrl.pathname; @@ -192,6 +193,7 @@ export const config = { // Routes allowed for POST method (matching `POST_METHODS_ALLOWED_APP_ROUTES` array) "/settings/my-account/general", "/settings/developer/webhooks", + "/settings/developer/api-keys", ], }; diff --git a/apps/web/modules/settings/developer/api-keys-skeleton.tsx b/apps/web/modules/settings/developer/api-keys-skeleton.tsx new file mode 100644 index 0000000000..5b9a5a5b2c --- /dev/null +++ b/apps/web/modules/settings/developer/api-keys-skeleton.tsx @@ -0,0 +1,24 @@ +"use client"; + +import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader"; +import { APP_NAME } from "@calcom/lib/constants"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton"; + +export const SkeletonLoader = () => { + const { t } = useLocale(); + + return ( + + +
+ + +
+
+
+ ); +}; diff --git a/apps/web/modules/settings/developer/api-keys-view.tsx b/apps/web/modules/settings/developer/api-keys-view.tsx index 1be96cc998..81e144b670 100644 --- a/apps/web/modules/settings/developer/api-keys-view.tsx +++ b/apps/web/modules/settings/developer/api-keys-view.tsx @@ -7,24 +7,13 @@ import LicenseRequired from "@calcom/ee/common/components/LicenseRequired"; import { Dialog } from "@calcom/features/components/controlled-dialog"; import ApiKeyDialogForm from "@calcom/features/ee/api-keys/components/ApiKeyDialogForm"; import ApiKeyListItem from "@calcom/features/ee/api-keys/components/ApiKeyListItem"; +import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader"; import { APP_NAME } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { trpc } from "@calcom/trpc/react"; +import type { RouterOutputs } from "@calcom/trpc/react"; import { Button } from "@calcom/ui/components/button"; import { DialogContent } from "@calcom/ui/components/dialog"; import { EmptyScreen } from "@calcom/ui/components/empty-screen"; -import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton"; - -const SkeletonLoader = () => { - return ( - -
- - -
-
- ); -}; export const apiKeyModalRef = { current: null as null | ((show: boolean) => void), @@ -48,10 +37,12 @@ export const NewApiKeyButton = () => { ); }; -const ApiKeysView = () => { - const { t } = useLocale(); +type Props = { + apiKeys: RouterOutputs["viewer"]["apiKeys"]["list"]; +}; - const { data, isPending } = trpc.viewer.apiKeys.list.useQuery(); +const ApiKeysView = ({ apiKeys: data }: Props) => { + const { t } = useLocale(); const [apiKeyModal, setApiKeyModal] = useState(false); const [apiKeyToEdit, setApiKeyToEdit] = useState<(TApiKeys & { neverExpires?: boolean }) | undefined>( @@ -67,12 +58,12 @@ const ApiKeysView = () => { }; }, []); - if (isPending || !data) { - return ; - } - return ( - <> + } + borderInShellHeader={true}>
{data?.length ? ( @@ -108,7 +99,7 @@ const ApiKeysView = () => { setApiKeyModal(false)} defaultValues={apiKeyToEdit} /> - + ); }; diff --git a/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx b/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx index 4340034b6e..1cc97cdcd5 100644 --- a/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx +++ b/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx @@ -6,14 +6,15 @@ import type { TApiKeys } from "@calcom/ee/api-keys/components/ApiKeyListItem"; import LicenseRequired from "@calcom/ee/common/components/LicenseRequired"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { DialogFooter } from "@calcom/ui/components/dialog"; import { Button } from "@calcom/ui/components/button"; +import { DialogFooter } from "@calcom/ui/components/dialog"; import { Form } from "@calcom/ui/components/form"; import { TextField } from "@calcom/ui/components/form"; import { SelectField } from "@calcom/ui/components/form"; import { Switch } from "@calcom/ui/components/form"; import { showToast } from "@calcom/ui/components/toast"; import { Tooltip } from "@calcom/ui/components/tooltip"; +import { revalidateApiKeysList } from "@calcom/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions"; export default function ApiKeyDialogForm({ defaultValues, @@ -28,6 +29,7 @@ export default function ApiKeyDialogForm({ const updateApiKeyMutation = trpc.viewer.apiKeys.edit.useMutation({ onSuccess() { utils.viewer.apiKeys.list.invalidate(); + revalidateApiKeysList(); showToast(t("api_key_updated"), "success"); handleClose(); }, @@ -131,6 +133,7 @@ export default function ApiKeyDialogForm({ setApiKey(apiKey); setApiKeyDetails({ ...event }); await utils.viewer.apiKeys.list.invalidate(); + revalidateApiKeysList(); setSuccessfulNewApiKeyModal(true); } }} diff --git a/packages/features/ee/api-keys/components/ApiKeyListItem.tsx b/packages/features/ee/api-keys/components/ApiKeyListItem.tsx index 6449ca946d..3f7d27f329 100644 --- a/packages/features/ee/api-keys/components/ApiKeyListItem.tsx +++ b/packages/features/ee/api-keys/components/ApiKeyListItem.tsx @@ -2,6 +2,9 @@ import dayjs from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; +import classNames from "@calcom/ui/classNames"; +import { Badge } from "@calcom/ui/components/badge"; +import { Button } from "@calcom/ui/components/button"; import { Dropdown, DropdownItem, @@ -9,10 +12,8 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@calcom/ui/components/dropdown"; -import { Badge } from "@calcom/ui/components/badge"; -import { Button } from "@calcom/ui/components/button"; -import classNames from "@calcom/ui/classNames"; import { showToast } from "@calcom/ui/components/toast"; +import { revalidateApiKeysList } from "@calcom/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/api-keys/actions"; export type TApiKeys = RouterOutputs["viewer"]["apiKeys"]["list"][number]; @@ -34,6 +35,7 @@ const ApiKeyListItem = ({ const deleteApiKey = trpc.viewer.apiKeys.delete.useMutation({ async onSuccess() { await utils.viewer.apiKeys.list.invalidate(); + revalidateApiKeysList(); showToast(t("api_key_deleted"), "success"); }, onError(err) {