Spaces:
Build error
Build error
import { useQueryClient } from "@tanstack/react-query"; | |
import React from "react"; | |
import { Link } from "react-router"; | |
import { useTranslation } from "react-i18next"; | |
import { useGetSecrets } from "#/hooks/query/use-get-secrets"; | |
import { useDeleteSecret } from "#/hooks/mutation/use-delete-secret"; | |
import { SecretForm } from "#/components/features/settings/secrets-settings/secret-form"; | |
import { | |
SecretListItem, | |
SecretListItemSkeleton, | |
} from "#/components/features/settings/secrets-settings/secret-list-item"; | |
import { BrandButton } from "#/components/features/settings/brand-button"; | |
import { ConfirmationModal } from "#/components/shared/modals/confirmation-modal"; | |
import { GetSecretsResponse } from "#/api/secrets-service.types"; | |
import { useUserProviders } from "#/hooks/use-user-providers"; | |
import { useConfig } from "#/hooks/query/use-config"; | |
function SecretsSettingsScreen() { | |
const queryClient = useQueryClient(); | |
const { t } = useTranslation(); | |
const { data: config } = useConfig(); | |
const { data: secrets, isLoading: isLoadingSecrets } = useGetSecrets(); | |
const { mutate: deleteSecret } = useDeleteSecret(); | |
const { providers } = useUserProviders(); | |
const isSaas = config?.APP_MODE === "saas"; | |
const hasProviderSet = providers.length > 0; | |
const [view, setView] = React.useState< | |
"list" | "add-secret-form" | "edit-secret-form" | |
>("list"); | |
const [selectedSecret, setSelectedSecret] = React.useState<string | null>( | |
null, | |
); | |
const [confirmationModalIsVisible, setConfirmationModalIsVisible] = | |
React.useState(false); | |
const deleteSecretOptimistically = (secret: string) => { | |
queryClient.setQueryData<GetSecretsResponse["custom_secrets"]>( | |
["secrets"], | |
(oldSecrets) => { | |
if (!oldSecrets) return []; | |
return oldSecrets.filter((s) => s.name !== secret); | |
}, | |
); | |
}; | |
const revertOptimisticUpdate = () => { | |
queryClient.invalidateQueries({ queryKey: ["secrets"] }); | |
}; | |
const handleDeleteSecret = (secret: string) => { | |
deleteSecretOptimistically(secret); | |
deleteSecret(secret, { | |
onSettled: () => { | |
setConfirmationModalIsVisible(false); | |
}, | |
onError: revertOptimisticUpdate, | |
}); | |
}; | |
const onConfirmDeleteSecret = () => { | |
if (selectedSecret) handleDeleteSecret(selectedSecret); | |
}; | |
const onCancelDeleteSecret = () => { | |
setConfirmationModalIsVisible(false); | |
}; | |
const shouldRenderConnectToGitButton = isSaas && !hasProviderSet; | |
return ( | |
<div | |
data-testid="secrets-settings-screen" | |
className="px-11 py-9 flex flex-col gap-5" | |
> | |
{isLoadingSecrets && view === "list" && ( | |
<ul> | |
<SecretListItemSkeleton /> | |
<SecretListItemSkeleton /> | |
<SecretListItemSkeleton /> | |
</ul> | |
)} | |
{shouldRenderConnectToGitButton && ( | |
<Link to="/settings/git" data-testid="connect-git-button" type="button"> | |
<BrandButton type="button" variant="secondary"> | |
Connect a Git provider to manage secrets | |
</BrandButton> | |
</Link> | |
)} | |
{secrets?.length === 0 && view === "list" && ( | |
<p data-testid="no-secrets-message">{t("SECRETS$NO_SECRETS_FOUND")}</p> | |
)} | |
{view === "list" && ( | |
<table className="w-full"> | |
<tbody> | |
{secrets?.map((secret) => ( | |
<SecretListItem | |
key={secret.name} | |
title={secret.name} | |
description={secret.description} | |
onEdit={() => { | |
setView("edit-secret-form"); | |
setSelectedSecret(secret.name); | |
}} | |
onDelete={() => { | |
setConfirmationModalIsVisible(true); | |
setSelectedSecret(secret.name); | |
}} | |
/> | |
))} | |
</tbody> | |
</table> | |
)} | |
{!shouldRenderConnectToGitButton && view === "list" && ( | |
<BrandButton | |
testId="add-secret-button" | |
type="button" | |
variant="primary" | |
onClick={() => setView("add-secret-form")} | |
isDisabled={isLoadingSecrets} | |
> | |
{t("SECRETS$ADD_NEW_SECRET")} | |
</BrandButton> | |
)} | |
{(view === "add-secret-form" || view === "edit-secret-form") && ( | |
<SecretForm | |
mode={view === "add-secret-form" ? "add" : "edit"} | |
selectedSecret={selectedSecret} | |
onCancel={() => setView("list")} | |
/> | |
)} | |
{confirmationModalIsVisible && ( | |
<ConfirmationModal | |
text={t("SECRETS$CONFIRM_DELETE_KEY")} | |
onConfirm={onConfirmDeleteSecret} | |
onCancel={onCancelDeleteSecret} | |
/> | |
)} | |
</div> | |
); | |
} | |
export default SecretsSettingsScreen; | |