diff --git a/src/auth/actions.ts b/src/auth/actions.ts
index 9f26b610..72c04dea 100644
--- a/src/auth/actions.ts
+++ b/src/auth/actions.ts
@@ -6,6 +6,7 @@ import {
KEY_CREDENTIALS_SIGN_IN_ERROR,
KEY_CREDENTIALS_SIGN_IN_ERROR_URL,
auth,
+ generateAuthSecret,
signIn,
signOut,
} from '@/auth';
@@ -47,3 +48,5 @@ export const getAuthAction = async () => auth();
export const logClientAuthUpdate = async (data: Session | null | undefined) =>
console.log('Client auth update', data);
+
+export const generateAuthSecretAction = async () => generateAuthSecret();
diff --git a/src/components/CopyButton.tsx b/src/components/CopyButton.tsx
new file mode 100644
index 00000000..7c4fa939
--- /dev/null
+++ b/src/components/CopyButton.tsx
@@ -0,0 +1,32 @@
+import { BiCopy } from 'react-icons/bi';
+import LoaderButton from './primitives/LoaderButton';
+import clsx from 'clsx/lite';
+import { toastSuccess } from '@/toast';
+
+export default function CopyButton({
+ label,
+ text,
+ subtle,
+}: {
+ label: string
+ text?: string,
+ subtle?: boolean
+}) {
+ return (
+ }
+ className={clsx(
+ 'translate-y-[2px]',
+ subtle && 'text-gray-300 dark:text-gray-700',
+ )}
+ onClick={text
+ ? () => {
+ navigator.clipboard.writeText(text);
+ toastSuccess(`${label} copied to clipboard`);
+ }
+ : undefined}
+ styleAs="link"
+ disabled={!text}
+ />
+ );
+}
diff --git a/src/site/SecretGenerator.tsx b/src/site/SecretGenerator.tsx
new file mode 100644
index 00000000..c85452d6
--- /dev/null
+++ b/src/site/SecretGenerator.tsx
@@ -0,0 +1,51 @@
+'use client';
+
+import { clsx } from 'clsx/lite';
+import Container from '@/components/Container';
+import Spinner from '@/components/Spinner';
+import CopyButton from '@/components/CopyButton';
+import { useCallback, useEffect, useState } from 'react';
+import { generateAuthSecretAction } from '@/auth/actions';
+import { BiRefresh } from 'react-icons/bi';
+
+export default function SecretGenerator() {
+ const [isLoading, setIsLoading] = useState(false);
+ const [secret, setSecret] = useState('');
+
+ const getSecret = useCallback(async () => {
+ setIsLoading(true);
+ await generateAuthSecretAction()
+ .then(setSecret)
+ .finally(() => setIsLoading(false));
+ }, []);
+
+ useEffect(() => {
+ getSecret();
+ }, [getSecret]);
+
+ return (
+
+
+
+ {secret ?
{secret} :
}
+
+
+
+
+
+ {secret &&
+ {isLoading
+ ?
+ : }
+
}
+
+ );
+}
diff --git a/src/site/SiteChecklistClient.tsx b/src/site/SiteChecklistClient.tsx
index 803d6add..3b2ee2c9 100644
--- a/src/site/SiteChecklistClient.tsx
+++ b/src/site/SiteChecklistClient.tsx
@@ -9,26 +9,23 @@ import ChecklistRow from '../components/ChecklistRow';
import { FiExternalLink } from 'react-icons/fi';
import {
BiCog,
- BiCopy,
BiData,
BiHide,
BiLockAlt,
BiPencil,
} from 'react-icons/bi';
-import Container from '@/components/Container';
import Checklist from '@/components/Checklist';
-import { toastSuccess } from '@/toast';
import { ConfigChecklistStatus } from './config';
import StatusIcon from '@/components/StatusIcon';
import { labelForStorage } from '@/services/storage';
import { HiSparkles } from 'react-icons/hi';
-import LoaderButton from '@/components/primitives/LoaderButton';
import { testConnectionsAction } from '@/admin/actions';
import ErrorNote from '@/components/ErrorNote';
-import Spinner from '@/components/Spinner';
import WarningNote from '@/components/WarningNote';
import { RiSpeedMiniLine } from 'react-icons/ri';
import Link from 'next/link';
+import SecretGenerator from './SecretGenerator';
+import CopyButton from '@/components/CopyButton';
export default function SiteChecklistClient({
// Storage
@@ -94,12 +91,10 @@ export default function SiteChecklistClient({
// Component props
simplifiedView,
isTestingConnections,
- secret,
}: ConfigChecklistStatus &
Partial>> & {
simplifiedView?: boolean
isTestingConnections?: boolean
- secret?: string
}) {
const renderLink = (href: string, text: string, external = true) =>
<>
@@ -122,23 +117,6 @@ export default function SiteChecklistClient({
>}
>;
- const renderCopyButton = (label: string, text?: string, subtle?: boolean) =>
- }
- className={clsx(
- 'translate-y-[2px]',
- subtle && 'text-gray-300 dark:text-gray-700',
- )}
- onClick={text
- ? () => {
- navigator.clipboard.writeText(text);
- toastSuccess(`${label} copied to clipboard`);
- }
- : undefined}
- styleAs="link"
- disabled={!text}
- />;
-
const renderEnvVar = (
variable: string,
minimal?: boolean,
@@ -159,7 +137,7 @@ export default function SiteChecklistClient({
)}>
`{variable}`
- {!minimal && renderCopyButton(variable, variable, true)}
+ {!minimal && }
;
@@ -321,20 +299,9 @@ export default function SiteChecklistClient({
isPending={!hasAuthSecret && isTestingConnections}
>
Store auth secret in environment variable:
- {!hasAuthSecret || true &&
+ {!hasAuthSecret &&
-
-
- {secret ?
{secret} :
}
-
- {renderCopyButton('Secret', secret)}
-
-
-
+
}
{renderEnvVars(['AUTH_SECRET'])}
diff --git a/src/site/SiteChecklistServer.tsx b/src/site/SiteChecklistServer.tsx
index 1d264d19..af73d43b 100644
--- a/src/site/SiteChecklistServer.tsx
+++ b/src/site/SiteChecklistServer.tsx
@@ -1,4 +1,3 @@
-import { generateAuthSecret } from '@/auth';
import SiteChecklistClient from './SiteChecklistClient';
import { CONFIG_CHECKLIST_STATUS } from '@/site/config';
import { testConnectionsAction } from '@/admin/actions';
@@ -8,14 +7,12 @@ export default async function SiteChecklistServer({
}: {
simplifiedView?: boolean
}) {
- const secret = await generateAuthSecret().catch(() => 'TRY AGAIN');
const connectionErrors = await testConnectionsAction().catch(() => ({}));
return (
);
}