mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
restyle client regen credentials
This commit is contained in:
@@ -1,27 +1,37 @@
|
||||
"use client";
|
||||
|
||||
import RegenerateCredentialsModal from "@app/components/RegenerateCredentialsModal";
|
||||
import { SecurityFeaturesAlert } from "@app/components/SecurityFeaturesAlert";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
SettingsContainer,
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionFooter,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import { useClientContext } from "@app/hooks/useClientContext";
|
||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { PickClientDefaultsResponse } from "@server/routers/client";
|
||||
import { useClientContext } from "@app/hooks/useClientContext";
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
|
||||
import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusContext";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { createApiClient } from "@app/lib/api";
|
||||
import { build } from "@server/build";
|
||||
import { PickClientDefaultsResponse } from "@server/routers/client";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { SecurityFeaturesAlert } from "@app/components/SecurityFeaturesAlert";
|
||||
import {
|
||||
InfoSection,
|
||||
InfoSectionContent,
|
||||
InfoSections,
|
||||
InfoSectionTitle
|
||||
} from "@app/components/InfoSection";
|
||||
import CopyToClipboard from "@app/components/CopyToClipboard";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
|
||||
export default function CredentialsPage() {
|
||||
const { env } = useEnvContext();
|
||||
@@ -34,6 +44,11 @@ export default function CredentialsPage() {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [clientDefaults, setClientDefaults] =
|
||||
useState<PickClientDefaultsResponse | null>(null);
|
||||
const [currentOlmId, setCurrentOlmId] = useState<string | null>(null);
|
||||
const [regeneratedSecret, setRegeneratedSecret] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
const [showCredentialsAlert, setShowCredentialsAlert] = useState(false);
|
||||
|
||||
const { licenseStatus, isUnlocked } = useLicenseStatusContext();
|
||||
const subscription = useSubscriptionStatusContext();
|
||||
@@ -46,76 +61,150 @@ export default function CredentialsPage() {
|
||||
};
|
||||
|
||||
const handleConfirmRegenerate = async () => {
|
||||
const res = await api.get(`/org/${orgId}/pick-client-defaults`);
|
||||
if (res && res.status === 200) {
|
||||
const data = res.data.data;
|
||||
try {
|
||||
const res = await api.get(`/org/${orgId}/pick-client-defaults`);
|
||||
if (res && res.status === 200) {
|
||||
const data = res.data.data;
|
||||
|
||||
const rekeyRes = await api.post(
|
||||
`/re-key/${client?.clientId}/regenerate-client-secret`,
|
||||
{
|
||||
secret: data.olmSecret
|
||||
const rekeyRes = await api.post(
|
||||
`/re-key/${client?.clientId}/regenerate-client-secret`,
|
||||
{
|
||||
secret: data.olmSecret
|
||||
}
|
||||
);
|
||||
|
||||
if (rekeyRes && rekeyRes.status === 200) {
|
||||
const rekeyData = rekeyRes.data.data;
|
||||
if (rekeyData && rekeyData.olmId) {
|
||||
setCurrentOlmId(rekeyData.olmId);
|
||||
setRegeneratedSecret(data.olmSecret);
|
||||
setClientDefaults({
|
||||
...data,
|
||||
olmId: rekeyData.olmId
|
||||
});
|
||||
setShowCredentialsAlert(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (rekeyRes && rekeyRes.status === 200) {
|
||||
const rekeyData = rekeyRes.data.data;
|
||||
setClientDefaults({
|
||||
...data,
|
||||
olmId: rekeyData.olmId,
|
||||
toast({
|
||||
title: t("credentialsSaved"),
|
||||
description: t("credentialsSavedDescription")
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: t("credentialsSaved"),
|
||||
description: t("credentialsSavedDescription")
|
||||
variant: "destructive",
|
||||
title: t("error") || "Error",
|
||||
description:
|
||||
formatAxiosError(error) ||
|
||||
t("credentialsRegenerateError") ||
|
||||
"Failed to regenerate credentials"
|
||||
});
|
||||
|
||||
router.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
const getCredentials = () => {
|
||||
if (clientDefaults) {
|
||||
return {
|
||||
Id: clientDefaults.olmId,
|
||||
Secret: clientDefaults.olmSecret
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
const getConfirmationString = () => {
|
||||
return client?.name || client?.clientId?.toString() || "My client";
|
||||
};
|
||||
|
||||
const displayOlmId = currentOlmId || clientDefaults?.olmId || null;
|
||||
const displaySecret = regeneratedSecret || null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsContainer>
|
||||
<SettingsSection>
|
||||
<SettingsSectionHeader>
|
||||
<SettingsSectionTitle>
|
||||
{t("generatedcredentials")}
|
||||
{t("clientOlmCredentials")}
|
||||
</SettingsSectionTitle>
|
||||
<SettingsSectionDescription>
|
||||
{t("regenerateCredentials")}
|
||||
{t("clientOlmCredentialsDescription")}
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
|
||||
<SettingsSectionBody>
|
||||
<SecurityFeaturesAlert />
|
||||
<InfoSections cols={3}>
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("olmEndpoint")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<CopyToClipboard
|
||||
text={env.app.dashboardUrl}
|
||||
/>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("olmId")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{displayOlmId ? (
|
||||
<CopyToClipboard text={displayOlmId} />
|
||||
) : (
|
||||
<span>{"••••••••••••••••"}</span>
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("olmSecretKey")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{displaySecret ? (
|
||||
<CopyToClipboard text={displaySecret} />
|
||||
) : (
|
||||
<span>{"••••••••••••••••"}</span>
|
||||
)}
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
</InfoSections>
|
||||
|
||||
{showCredentialsAlert && displaySecret && (
|
||||
<Alert variant="neutral" className="mt-4">
|
||||
<InfoIcon className="h-4 w-4" />
|
||||
<AlertTitle className="font-semibold">
|
||||
{t("clientCredentialsSave")}
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
{t("clientCredentialsSaveDescription")}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
</SettingsSectionBody>
|
||||
<SettingsSectionFooter>
|
||||
<Button
|
||||
onClick={() => setModalOpen(true)}
|
||||
disabled={isSecurityFeatureDisabled()}
|
||||
>
|
||||
{t("regeneratecredentials")}
|
||||
{t("regenerateCredentialsButton")}
|
||||
</Button>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSectionFooter>
|
||||
</SettingsSection>
|
||||
</SettingsContainer>
|
||||
|
||||
<RegenerateCredentialsModal
|
||||
<ConfirmDeleteDialog
|
||||
open={modalOpen}
|
||||
onOpenChange={setModalOpen}
|
||||
type="client-olm"
|
||||
onConfirmRegenerate={handleConfirmRegenerate}
|
||||
dashboardUrl={env.app.dashboardUrl}
|
||||
credentials={getCredentials()}
|
||||
setOpen={(val) => {
|
||||
setModalOpen(val);
|
||||
// Prevent modal from reopening during refresh
|
||||
if (!val) {
|
||||
setTimeout(() => {
|
||||
router.refresh();
|
||||
}, 150);
|
||||
}
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-2">
|
||||
<p>{t("regenerateCredentialsConfirmation")}</p>
|
||||
<p>{t("regenerateCredentialsWarning")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("regenerateCredentialsButton")}
|
||||
onConfirm={handleConfirmRegenerate}
|
||||
string={getConfirmationString()}
|
||||
title={t("regenerateCredentials")}
|
||||
warningText={t("cannotbeUndone")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user