diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/components/dialogs/ApiKeyDialog/ApiKeyDialog.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/components/dialogs/ApiKeyDialog/ApiKeyDialog.tsx index c1fc93f883..b3043c33b1 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/components/dialogs/ApiKeyDialog/ApiKeyDialog.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/components/dialogs/ApiKeyDialog/ApiKeyDialog.tsx @@ -21,7 +21,12 @@ type APIKeyCustomEventDetails = { id: string; }; -export const ApiKeyDialog = () => { +/** + * API Key Dialog + * @param isVaultDelivery - boolean - Allows skipping the save request when a form is already saving to the vault -- example a live form swapping to API mode + * @returns JSX.Element + */ +export const ApiKeyDialog = ({ isVaultDelivery = false }: { isVaultDelivery?: boolean }) => { const dialog = useDialogRef(); const { Event } = useCustomEvent(); const { t } = useTranslation("form-builder"); @@ -73,15 +78,21 @@ export const ApiKeyDialog = () => { setHasError(false); setGenerating(true); try { - // First ensure all responses are sent to vault - const result = await sendResponsesToVault({ - id: id, - }); - - if (result.error) { - // Throw the generic key creation error - // Handling as generic as we're in the process of creating a key - throw new Error(result.error); + /* + Allows skipping the save request + if it's determined that the form responses + are already being delivered to the vault + */ + if (!isVaultDelivery) { + const result = await sendResponsesToVault({ + id: id, + }); + + if (result.error) { + // Throw the generic key creation error + // Handling as generic as we're in the process of creating a key + throw new Error(result.error); + } } const key = await _createKey(id); diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/components/ApiKeyButton.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/components/ApiKeyButton.tsx index 4f187a1525..304820d4d4 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/components/ApiKeyButton.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/components/ApiKeyButton.tsx @@ -5,17 +5,22 @@ import { useTranslation } from "@i18n/client"; import { EventKeys, useCustomEvent } from "@lib/hooks/useCustomEvent"; import { DeleteKeyButton } from "./DeleteKeyButton"; import { SubmitButton as GenerateApiKeyButton } from "@clientComponents/globals/Buttons/SubmitButton"; +import { Theme } from "@clientComponents/globals/Buttons/themes"; import { useFormBuilderConfig } from "@lib/hooks/useFormBuilderConfig"; import { ResponseDeliveryHelpButtonWithApi } from "./dialogs/ResponseDeliveryHelpDialogApiWithApi"; type ApiKeyButtonProps = { showDelete?: boolean; i18nKey?: string; + theme?: Theme; + showHelp?: boolean; }; export const ApiKeyButton = ({ showDelete = false, i18nKey = "settings.api.generateKey", + theme = "primary", + showHelp = true, }: ApiKeyButtonProps) => { const { t } = useTranslation("form-builder"); const { id } = useParams(); @@ -36,13 +41,13 @@ export const ApiKeyButton = ({ {showDelete && apiKeyId ? ( <> - + {showHelp && } ) : ( <> { openDialog(); @@ -50,7 +55,7 @@ export const ApiKeyButton = ({ > {t(i18nKey)} - + {showHelp && } )} diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/FormOwnership.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/FormOwnership.tsx index 249937a1f0..d880088c05 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/FormOwnership.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/FormOwnership.tsx @@ -74,7 +74,7 @@ export const FormOwnership = ({ return ( <> -
+

{t("Manage ownership")}

{message && message}

{t("assignUsersToTemplate")}

diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageApiKey.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageApiKey.tsx new file mode 100644 index 0000000000..283882f532 --- /dev/null +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageApiKey.tsx @@ -0,0 +1,22 @@ +"use client"; +import { useTranslation } from "@i18n/client"; +import { ApiKeyButton } from "../components/ApiKeyButton"; +import { SettingsApplicationsIcon } from "@serverComponents/icons"; +export const ManageApiKey = () => { + const { t } = useTranslation("form-builder"); + return ( +
+

+ {" "} + {t("switchToApiMode.title")}{" "} +

+

{t("switchToApiMode.description")}

+ +
+ ); +}; diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageForm.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageForm.tsx index ac71b2909e..3ed217a271 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageForm.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ManageForm.tsx @@ -6,6 +6,7 @@ import { SetClosingDate } from "./close/SetClosingDate"; import { FormOwnership } from "./FormOwnership"; import { ErrorPanel } from "@clientComponents/globals/ErrorPanel"; import { updateTemplateUsers } from "@formBuilder/actions"; +import { ManageApiKey } from "./ManageApiKey"; import { ThrottlingRate } from "./ThrottlingRate"; interface User { @@ -16,7 +17,7 @@ interface User { interface ManageFormProps { nonce: string | null; - canManageOwnership: boolean; + canManageAllForms: boolean; canSetClosingDate: boolean; formRecord?: FormRecord; usersAssignedToFormRecord?: User[]; @@ -31,13 +32,13 @@ export const ManageForm = (props: ManageFormProps) => { formRecord, usersAssignedToFormRecord, allUsers, - canManageOwnership, + canManageAllForms, canSetClosingDate, id, closedDetails, } = props; - if (!canManageOwnership) { + if (!canManageAllForms) { return ( <> {canSetClosingDate && } @@ -60,7 +61,8 @@ export const ManageForm = (props: ManageFormProps) => { allUsers={allUsers} updateTemplateUsers={updateTemplateUsers} /> - {canManageOwnership && } + {canManageAllForms && } + {canManageAllForms && formRecord.isPublished && } ); diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ThrottlingRate.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ThrottlingRate.tsx index c7a3e2eb64..f9520d0516 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ThrottlingRate.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/ThrottlingRate.tsx @@ -122,7 +122,7 @@ export const ThrottlingRate = ({ formId }: { formId: string }) => { }, [formId, throttlingErrorString]); return ( -
+

{t("throttling.title")}

diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/page.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/page.tsx index b47f3d7232..326658d37a 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/page.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/manage/page.tsx @@ -9,6 +9,8 @@ import { UserAbility } from "@lib/types"; import { Session } from "next-auth"; import { getNonce } from "./actions"; import { checkIfClosed } from "@lib/actions/checkIfClosed"; +import { ApiKeyDialog } from "../../components/dialogs/ApiKeyDialog/ApiKeyDialog"; +import { DeleteApiKeyDialog } from "../../components/dialogs/DeleteApiKeyDialog/DeleteApiKeyDialog"; export async function generateMetadata({ params: { locale }, @@ -22,7 +24,7 @@ export async function generateMetadata({ }; } -const getCanManageOwnership = (formId: string, ability: UserAbility | null) => { +const canManageAllForms = (formId: string, ability: UserAbility | null) => { if (!ability || formId === "0000") { return false; } @@ -68,7 +70,7 @@ export default async function Page({ params: { id } }: { params: { id: string } let closedDetails; - const canManageOwnership = getCanManageOwnership(id, ability); + const manageAllForms = canManageAllForms(id, ability); const canSetClosingDate = getCanSetClosingDate(id, ability, session); const nonce = await getNonce(); @@ -77,12 +79,12 @@ export default async function Page({ params: { id } }: { params: { id: string } closedDetails = closedData?.closedDetails; } - if (!canManageOwnership || id === "0000") { + if (!manageAllForms || id === "0000") { return ( @@ -98,16 +100,34 @@ export default async function Page({ params: { id } }: { params: { id: string } const allUsers = await getAllUsers(ability); + const isPublished = templateWithAssociatedUsers.formRecord.isPublished; + const isVaultDelivery = !templateWithAssociatedUsers.formRecord.deliveryMethod; + return ( - + <> + + {/* + - Only show for users with manage all forms privileges + - we do an additional check here in case the code above to reach this point changes later + - Only show for forms with vault delivery already set + - Only show for live forms + - draft forms should use Response Delivery page + */} + {isPublished && manageAllForms && isVaultDelivery && ( + <> + + + + )} + ); } diff --git a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/page.tsx b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/page.tsx index b1e55e391c..dbc70cecc0 100644 --- a/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/page.tsx +++ b/app/(gcforms)/[locale]/(form administration)/form-builder/[id]/settings/page.tsx @@ -1,10 +1,10 @@ import { serverTranslation } from "@i18n"; import { Metadata } from "next"; import { ResponseDelivery } from "./components/ResponseDelivery"; -import { ApiKeyDialog } from "../components/dialogs/ApiKeyDialog/ApiKeyDialog"; -import { DeleteApiKeyDialog } from "../components/dialogs/DeleteApiKeyDialog/DeleteApiKeyDialog"; import { authCheckAndRedirect } from "@lib/actions"; import { checkPrivilegesAsBoolean } from "@lib/privileges"; +import { ApiKeyDialog } from "../components/dialogs/ApiKeyDialog/ApiKeyDialog"; +import { DeleteApiKeyDialog } from "../components/dialogs/DeleteApiKeyDialog/DeleteApiKeyDialog"; export async function generateMetadata({ params: { locale }, @@ -18,7 +18,6 @@ export async function generateMetadata({ } export default async function Page() { - const { ability } = await authCheckAndRedirect(); const isFormsAdmin = checkPrivilegesAsBoolean(ability, [ @@ -27,7 +26,7 @@ export default async function Page() { subject: "FormRecord", }, ]); - + return ( <> diff --git a/i18n/translations/en/form-builder.json b/i18n/translations/en/form-builder.json index 4639820b27..ec249d31ff 100644 --- a/i18n/translations/en/form-builder.json +++ b/i18n/translations/en/form-builder.json @@ -455,6 +455,11 @@ "downloadBtnText": "Download form file", "title": "Download form file" }, + "switchToApiMode": { + "title": "Switch to API delivery", + "description": "New responses will be available through the API endpoint", + "btnText": "Switch to API delivery" + }, "formIntroduction": "Form introduction", "formInvalidProperty": "Invalid: {{property}}", "formMissingProperty": "Missing: {{property}}", diff --git a/i18n/translations/fr/form-builder.json b/i18n/translations/fr/form-builder.json index 078f452255..eb9a229614 100644 --- a/i18n/translations/fr/form-builder.json +++ b/i18n/translations/fr/form-builder.json @@ -455,6 +455,11 @@ "downloadBtnText": "Télécharger le fichier du formulaire", "title": "Télécharger le fichier du formulaire" }, + "switchToApiMode": { + "title": "Switch to API delivery [FR]", + "description": "New responses will be available through the API endpoint [FR]", + "btnText": "Switch to API delivery [FR]" + }, "formIntroduction": "Introduction du formulaire ", "formInvalidProperty": "Invalide : {{property}}", "formMissingProperty": "Il manque : {{property}}",