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";
|
"use client";
|
||||||
|
|
||||||
import RegenerateCredentialsModal from "@app/components/RegenerateCredentialsModal";
|
import { useState } from "react";
|
||||||
import { SecurityFeaturesAlert } from "@app/components/SecurityFeaturesAlert";
|
|
||||||
import {
|
import {
|
||||||
SettingsContainer,
|
SettingsContainer,
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
SettingsSectionDescription,
|
SettingsSectionDescription,
|
||||||
|
SettingsSectionFooter,
|
||||||
SettingsSectionHeader,
|
SettingsSectionHeader,
|
||||||
SettingsSectionTitle
|
SettingsSectionTitle
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { Button } from "@app/components/ui/button";
|
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 { 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 { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
|
||||||
import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusContext";
|
import { useSubscriptionStatusContext } from "@app/hooks/useSubscriptionStatusContext";
|
||||||
import { toast } from "@app/hooks/useToast";
|
|
||||||
import { createApiClient } from "@app/lib/api";
|
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { PickClientDefaultsResponse } from "@server/routers/client";
|
import { SecurityFeaturesAlert } from "@app/components/SecurityFeaturesAlert";
|
||||||
import { useTranslations } from "next-intl";
|
import {
|
||||||
import { useParams, useRouter } from "next/navigation";
|
InfoSection,
|
||||||
import { useState } from "react";
|
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() {
|
export default function CredentialsPage() {
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
@@ -34,6 +44,11 @@ export default function CredentialsPage() {
|
|||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const [clientDefaults, setClientDefaults] =
|
const [clientDefaults, setClientDefaults] =
|
||||||
useState<PickClientDefaultsResponse | null>(null);
|
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 { licenseStatus, isUnlocked } = useLicenseStatusContext();
|
||||||
const subscription = useSubscriptionStatusContext();
|
const subscription = useSubscriptionStatusContext();
|
||||||
@@ -46,76 +61,150 @@ export default function CredentialsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirmRegenerate = async () => {
|
const handleConfirmRegenerate = async () => {
|
||||||
const res = await api.get(`/org/${orgId}/pick-client-defaults`);
|
try {
|
||||||
if (res && res.status === 200) {
|
const res = await api.get(`/org/${orgId}/pick-client-defaults`);
|
||||||
const data = res.data.data;
|
if (res && res.status === 200) {
|
||||||
|
const data = res.data.data;
|
||||||
|
|
||||||
const rekeyRes = await api.post(
|
const rekeyRes = await api.post(
|
||||||
`/re-key/${client?.clientId}/regenerate-client-secret`,
|
`/re-key/${client?.clientId}/regenerate-client-secret`,
|
||||||
{
|
{
|
||||||
secret: data.olmSecret
|
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) {
|
toast({
|
||||||
const rekeyData = rekeyRes.data.data;
|
title: t("credentialsSaved"),
|
||||||
setClientDefaults({
|
description: t("credentialsSavedDescription")
|
||||||
...data,
|
|
||||||
olmId: rekeyData.olmId,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
title: t("credentialsSaved"),
|
variant: "destructive",
|
||||||
description: t("credentialsSavedDescription")
|
title: t("error") || "Error",
|
||||||
|
description:
|
||||||
|
formatAxiosError(error) ||
|
||||||
|
t("credentialsRegenerateError") ||
|
||||||
|
"Failed to regenerate credentials"
|
||||||
});
|
});
|
||||||
|
|
||||||
router.refresh();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCredentials = () => {
|
const getConfirmationString = () => {
|
||||||
if (clientDefaults) {
|
return client?.name || client?.clientId?.toString() || "My client";
|
||||||
return {
|
|
||||||
Id: clientDefaults.olmId,
|
|
||||||
Secret: clientDefaults.olmSecret
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const displayOlmId = currentOlmId || clientDefaults?.olmId || null;
|
||||||
|
const displaySecret = regeneratedSecret || null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsContainer>
|
<SettingsContainer>
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<SettingsSectionHeader>
|
<SettingsSectionHeader>
|
||||||
<SettingsSectionTitle>
|
<SettingsSectionTitle>
|
||||||
{t("generatedcredentials")}
|
{t("clientOlmCredentials")}
|
||||||
</SettingsSectionTitle>
|
</SettingsSectionTitle>
|
||||||
<SettingsSectionDescription>
|
<SettingsSectionDescription>
|
||||||
{t("regenerateCredentials")}
|
{t("clientOlmCredentialsDescription")}
|
||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
|
|
||||||
<SettingsSectionBody>
|
<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
|
<Button
|
||||||
onClick={() => setModalOpen(true)}
|
onClick={() => setModalOpen(true)}
|
||||||
disabled={isSecurityFeatureDisabled()}
|
disabled={isSecurityFeatureDisabled()}
|
||||||
>
|
>
|
||||||
{t("regeneratecredentials")}
|
{t("regenerateCredentialsButton")}
|
||||||
</Button>
|
</Button>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
</SettingsContainer>
|
</SettingsContainer>
|
||||||
|
|
||||||
<RegenerateCredentialsModal
|
<ConfirmDeleteDialog
|
||||||
open={modalOpen}
|
open={modalOpen}
|
||||||
onOpenChange={setModalOpen}
|
setOpen={(val) => {
|
||||||
type="client-olm"
|
setModalOpen(val);
|
||||||
onConfirmRegenerate={handleConfirmRegenerate}
|
// Prevent modal from reopening during refresh
|
||||||
dashboardUrl={env.app.dashboardUrl}
|
if (!val) {
|
||||||
credentials={getCredentials()}
|
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