Add console useMutation and rename compliance graphs

Introduce the app-bound useMutation primitive and rename the trust center
graph and reference hooks to compliance page, moving the shared reference
dialogs alongside them. Sweep the compliance page subpages onto the new
mutation hook and the compliance-portal permission strings, and strip the
profile fields from the organization settings form.

Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
Bryan Frimin
2026-07-10 15:16:16 +02:00
parent ebe6192a0c
commit db24d17455
31 changed files with 391 additions and 383 deletions

View File

@@ -36,9 +36,9 @@ import { z } from "zod";
import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql"; import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql";
import { import {
useCreateTrustCenterReferenceMutation, useCreateCompliancePageReferenceMutation,
useUpdateTrustCenterReferenceMutation, useUpdateCompliancePageReferenceMutation,
} from "#/hooks/graph/TrustCenterReferenceGraph"; } from "#/hooks/graph/CompliancePageReferenceGraph";
import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { useFormWithSchema } from "#/hooks/useFormWithSchema";
const referenceSchema = z.object({ const referenceSchema = z.object({
@@ -50,23 +50,23 @@ const referenceSchema = z.object({
type ReferenceFormData = z.infer<typeof referenceSchema>; type ReferenceFormData = z.infer<typeof referenceSchema>;
export type TrustCenterReferenceDialogRef = { export type CompliancePageReferenceDialogRef = {
openCreate: (trustCenterId: string, connectionId: string) => void; openCreate: (compliancePageId: string, connectionId: string) => void;
openEdit: (reference: CompliancePageReferenceListItemFragment$data, rank: number) => void; openEdit: (reference: CompliancePageReferenceListItemFragment$data, rank: number) => void;
}; };
export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogRef, { children?: ReactNode }>( export const CompliancePageReferenceDialog = forwardRef<CompliancePageReferenceDialogRef, { children?: ReactNode }>(
function TrustCenterReferenceDialog({ children }, ref) { function CompliancePageReferenceDialog({ children }, ref) {
const { __ } = useTranslate(); const { __ } = useTranslate();
const dialogRef = useDialogRef(); const dialogRef = useDialogRef();
const [mode, setMode] = useState<"create" | "edit">("create"); const [mode, setMode] = useState<"create" | "edit">("create");
const [trustCenterId, setTrustCenterId] = useState<string>(""); const [compliancePageId, setCompliancePageId] = useState<string>("");
const [connectionId, setConnectionId] = useState<string>(""); const [connectionId, setConnectionId] = useState<string>("");
const [editReference, setEditReference] = useState<CompliancePageReferenceListItemFragment$data | null>(null); const [editReference, setEditReference] = useState<CompliancePageReferenceListItemFragment$data | null>(null);
const [uploadedFile, setUploadedFile] = useState<File | null>(null); const [uploadedFile, setUploadedFile] = useState<File | null>(null);
const [createReference, isCreating] = useCreateTrustCenterReferenceMutation(); const [createReference, isCreating] = useCreateCompliancePageReferenceMutation();
const [updateReference, isUpdating] = useUpdateTrustCenterReferenceMutation(); const [updateReference, isUpdating] = useUpdateCompliancePageReferenceMutation();
const { register, handleSubmit, formState: { errors }, reset } = useFormWithSchema( const { register, handleSubmit, formState: { errors }, reset } = useFormWithSchema(
referenceSchema, referenceSchema,
@@ -80,9 +80,9 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
); );
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
openCreate: (tId: string, cId: string) => { openCreate: (pageId: string, cId: string) => {
setMode("create"); setMode("create");
setTrustCenterId(tId); setCompliancePageId(pageId);
setConnectionId(cId); setConnectionId(cId);
setEditReference(null); setEditReference(null);
setUploadedFile(null); setUploadedFile(null);
@@ -123,7 +123,7 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
await createReference({ await createReference({
variables: { variables: {
input: { input: {
trustCenterId, trustCenterId: compliancePageId,
name: data.name, name: data.name,
description: data.description || null, description: data.description || null,
websiteUrl: data.websiteUrl, websiteUrl: data.websiteUrl,
@@ -134,12 +134,11 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
uploadables: { uploadables: {
"input.logoFile": uploadedFile, "input.logoFile": uploadedFile,
}, },
onSuccess: () => {
reset();
setUploadedFile(null);
dialogRef.current?.close();
},
}); });
reset();
setUploadedFile(null);
dialogRef.current?.close();
} else if (editReference) { } else if (editReference) {
const input: { const input: {
id: string; id: string;
@@ -169,12 +168,11 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
await updateReference({ await updateReference({
variables: { input }, variables: { input },
uploadables: Object.keys(uploadables).length > 0 ? uploadables : undefined, uploadables: Object.keys(uploadables).length > 0 ? uploadables : undefined,
onSuccess: () => {
reset();
setUploadedFile(null);
dialogRef.current?.close();
},
}); });
reset();
setUploadedFile(null);
dialogRef.current?.close();
} }
}; };

View File

@@ -30,8 +30,9 @@ import {
useDialogRef, useDialogRef,
} from "@probo/ui"; } from "@probo/ui";
import { deleteTrustCenterReferenceMutation } from "#/hooks/graph/TrustCenterReferenceGraph"; import type { CompliancePageReferenceGraphDeleteMutation } from "#/__generated__/core/CompliancePageReferenceGraphDeleteMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { deleteCompliancePageReferenceMutation } from "#/hooks/graph/CompliancePageReferenceGraph";
import { useMutation } from "#/lib/relay/useMutation";
type Props = { type Props = {
children: React.ReactNode; children: React.ReactNode;
@@ -41,7 +42,7 @@ type Props = {
onSuccess?: () => void; onSuccess?: () => void;
}; };
export function DeleteTrustCenterReferenceDialog({ export function DeleteCompliancePageReferenceDialog({
children, children,
referenceId, referenceId,
referenceName, referenceName,
@@ -51,10 +52,13 @@ export function DeleteTrustCenterReferenceDialog({
const { __ } = useTranslate(); const { __ } = useTranslate();
const ref = useDialogRef(); const ref = useDialogRef();
const [mutate, isDeleting] = useMutationWithToasts(deleteTrustCenterReferenceMutation, { const [mutate, isDeleting] = useMutation<CompliancePageReferenceGraphDeleteMutation>(
successMessage: __("Reference deleted successfully"), deleteCompliancePageReferenceMutation,
errorMessage: __("Failed to delete reference"), {
}); successMessage: __("Reference deleted successfully"),
errorToast: __("Failed to delete reference"),
},
);
const handleDelete = async () => { const handleDelete = async () => {
await mutate({ await mutate({

View File

@@ -20,34 +20,40 @@
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import type { TrustCenterGraphUpdateMutation } from "#/__generated__/core/TrustCenterGraphUpdateMutation.graphql"; import type { CompliancePageGraphDeleteNDAMutation } from "#/__generated__/core/CompliancePageGraphDeleteNDAMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import type { CompliancePageGraphUpdateMutation } from "#/__generated__/core/CompliancePageGraphUpdateMutation.graphql";
import type { CompliancePageGraphUploadNDAMutation } from "#/__generated__/core/CompliancePageGraphUploadNDAMutation.graphql";
import { useMutation } from "#/lib/relay/useMutation";
const updateTrustCenterMutation = graphql` const updateCompliancePageMutation = graphql`
mutation TrustCenterGraphUpdateMutation($input: UpdateTrustCenterInput!) { mutation CompliancePageGraphUpdateMutation($input: UpdateTrustCenterInput!) {
updateTrustCenter(input: $input) { updateTrustCenter(input: $input) {
trustCenter { trustCenter {
id id
active active
searchEngineIndexing searchEngineIndexing
description
websiteUrl
email
headquarterAddress
updatedAt updatedAt
} }
} }
} }
`; `;
export function useUpdateTrustCenterMutation() { export function useUpdateCompliancePageMutation() {
return useMutationWithToasts<TrustCenterGraphUpdateMutation>( return useMutation<CompliancePageGraphUpdateMutation>(
updateTrustCenterMutation, updateCompliancePageMutation,
{ {
successMessage: "Compliance Page updated successfully", successMessage: "Compliance Page updated successfully",
errorMessage: "Failed to update compliance page", errorToast: "Failed to update compliance page",
}, },
); );
} }
const uploadTrustCenterNDAMutation = graphql` const uploadCompliancePageNDAMutation = graphql`
mutation TrustCenterGraphUploadNDAMutation( mutation CompliancePageGraphUploadNDAMutation(
$input: UploadTrustCenterNDAInput! $input: UploadTrustCenterNDAInput!
) { ) {
uploadTrustCenterNDA(input: $input) { uploadTrustCenterNDA(input: $input) {
@@ -63,15 +69,15 @@ const uploadTrustCenterNDAMutation = graphql`
} }
`; `;
export function useUploadTrustCenterNDAMutation() { export function useUploadCompliancePageNDAMutation() {
return useMutationWithToasts(uploadTrustCenterNDAMutation, { return useMutation<CompliancePageGraphUploadNDAMutation>(uploadCompliancePageNDAMutation, {
successMessage: "NDA uploaded successfully", successMessage: "NDA uploaded successfully",
errorMessage: "Failed to upload NDA", errorToast: "Failed to upload NDA",
}); });
} }
const deleteTrustCenterNDAMutation = graphql` const deleteCompliancePageNDAMutation = graphql`
mutation TrustCenterGraphDeleteNDAMutation( mutation CompliancePageGraphDeleteNDAMutation(
$input: DeleteTrustCenterNDAInput! $input: DeleteTrustCenterNDAInput!
) { ) {
deleteTrustCenterNDA(input: $input) { deleteTrustCenterNDA(input: $input) {
@@ -87,9 +93,9 @@ const deleteTrustCenterNDAMutation = graphql`
} }
`; `;
export function useDeleteTrustCenterNDAMutation() { export function useDeleteCompliancePageNDAMutation() {
return useMutationWithToasts(deleteTrustCenterNDAMutation, { return useMutation<CompliancePageGraphDeleteNDAMutation>(deleteCompliancePageNDAMutation, {
successMessage: "NDA deleted successfully", successMessage: "NDA deleted successfully",
errorMessage: "Failed to delete NDA", errorToast: "Failed to delete NDA",
}); });
} }

View File

@@ -0,0 +1,135 @@
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import { graphql } from "react-relay";
import type { CompliancePageReferenceGraphCreateMutation } from "#/__generated__/core/CompliancePageReferenceGraphCreateMutation.graphql";
import type { CompliancePageReferenceGraphDeleteMutation } from "#/__generated__/core/CompliancePageReferenceGraphDeleteMutation.graphql";
import type { CompliancePageReferenceGraphUpdateMutation } from "#/__generated__/core/CompliancePageReferenceGraphUpdateMutation.graphql";
import type { CompliancePageReferenceGraphUpdateRankMutation } from "#/__generated__/core/CompliancePageReferenceGraphUpdateRankMutation.graphql";
import { useMutation } from "#/lib/relay/useMutation";
export const createCompliancePageReferenceMutation = graphql`
mutation CompliancePageReferenceGraphCreateMutation(
$input: CreateTrustCenterReferenceInput!
$connections: [ID!]!
) {
createTrustCenterReference(input: $input) {
trustCenterReferenceEdge @appendEdge(connections: $connections) {
cursor
node {
id
name
description
websiteUrl
logo {
downloadUrl
}
rank
createdAt
updatedAt
canUpdate: permission(action: "compliance-portal:portal-reference:update")
canDelete: permission(action: "compliance-portal:portal-reference:delete")
}
}
}
}
`;
export const updateCompliancePageReferenceMutation = graphql`
mutation CompliancePageReferenceGraphUpdateMutation(
$input: UpdateTrustCenterReferenceInput!
) {
updateTrustCenterReference(input: $input) {
trustCenterReference {
id
name
description
websiteUrl
logo {
downloadUrl
}
rank
createdAt
updatedAt
canUpdate: permission(action: "compliance-portal:portal-reference:update")
canDelete: permission(action: "compliance-portal:portal-reference:delete")
}
}
}
`;
export const deleteCompliancePageReferenceMutation = graphql`
mutation CompliancePageReferenceGraphDeleteMutation(
$input: DeleteTrustCenterReferenceInput!
$connections: [ID!]!
) {
deleteTrustCenterReference(input: $input) {
deletedTrustCenterReferenceId @deleteEdge(connections: $connections)
}
}
`;
export function useCreateCompliancePageReferenceMutation() {
return useMutation<CompliancePageReferenceGraphCreateMutation>(
createCompliancePageReferenceMutation,
{
successMessage: "Reference created successfully",
errorToast: "Failed to create reference",
},
);
}
export function useUpdateCompliancePageReferenceMutation() {
return useMutation<CompliancePageReferenceGraphUpdateMutation>(
updateCompliancePageReferenceMutation,
{
successMessage: "Reference updated successfully",
errorToast: "Failed to update reference",
},
);
}
export const updateCompliancePageReferenceRankMutation = graphql`
mutation CompliancePageReferenceGraphUpdateRankMutation(
$input: UpdateTrustCenterReferenceInput!
) {
updateTrustCenterReference(input: $input) {
trustCenterReference {
id
rank
}
}
}
`;
export function useUpdateCompliancePageReferenceRankMutation() {
return useMutation<CompliancePageReferenceGraphUpdateRankMutation>(
updateCompliancePageReferenceRankMutation,
{
successMessage: "Order updated successfully",
errorToast: "Failed to update order",
},
);
}
export function useDeleteCompliancePageReferenceMutation() {
return useMutation<CompliancePageReferenceGraphDeleteMutation>(
deleteCompliancePageReferenceMutation,
{
successMessage: "Reference deleted successfully",
errorToast: "Failed to delete reference",
},
);
}

View File

@@ -1,141 +0,0 @@
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import { graphql } from "react-relay";
import type { TrustCenterReferenceGraphCreateMutation } from "#/__generated__/core/TrustCenterReferenceGraphCreateMutation.graphql";
import type { TrustCenterReferenceGraphDeleteMutation } from "#/__generated__/core/TrustCenterReferenceGraphDeleteMutation.graphql";
import type { TrustCenterReferenceGraphUpdateMutation } from "#/__generated__/core/TrustCenterReferenceGraphUpdateMutation.graphql";
import type { TrustCenterReferenceGraphUpdateRankMutation } from "#/__generated__/core/TrustCenterReferenceGraphUpdateRankMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
export const createTrustCenterReferenceMutation = graphql`
mutation TrustCenterReferenceGraphCreateMutation(
$input: CreateTrustCenterReferenceInput!
$connections: [ID!]!
) {
createTrustCenterReference(input: $input) {
trustCenterReferenceEdge @appendEdge(connections: $connections) {
cursor
node {
id
name
description
websiteUrl
logo {
downloadUrl
}
rank
createdAt
updatedAt
canUpdate: permission(action: "core:trust-center-reference:update")
canDelete: permission(action: "core:trust-center-reference:delete")
}
}
}
}
`;
export const updateTrustCenterReferenceMutation = graphql`
mutation TrustCenterReferenceGraphUpdateMutation(
$input: UpdateTrustCenterReferenceInput!
) {
updateTrustCenterReference(input: $input) {
trustCenterReference {
id
name
description
websiteUrl
logo {
downloadUrl
}
rank
createdAt
updatedAt
canUpdate: permission(action: "core:trust-center-reference:update")
canDelete: permission(action: "core:trust-center-reference:delete")
}
}
}
`;
export const deleteTrustCenterReferenceMutation = graphql`
mutation TrustCenterReferenceGraphDeleteMutation(
$input: DeleteTrustCenterReferenceInput!
$connections: [ID!]!
) {
deleteTrustCenterReference(input: $input) {
deletedTrustCenterReferenceId @deleteEdge(connections: $connections)
}
}
`;
export function useCreateTrustCenterReferenceMutation() {
return useMutationWithToasts<TrustCenterReferenceGraphCreateMutation>(
createTrustCenterReferenceMutation,
{
successMessage: "Reference created successfully",
errorMessage: "Failed to create reference",
},
);
}
export function useUpdateTrustCenterReferenceMutation() {
return useMutationWithToasts<TrustCenterReferenceGraphUpdateMutation>(
updateTrustCenterReferenceMutation,
{
successMessage: "Reference updated successfully",
errorMessage: "Failed to update reference",
},
);
}
export const updateTrustCenterReferenceRankMutation = graphql`
mutation TrustCenterReferenceGraphUpdateRankMutation(
$input: UpdateTrustCenterReferenceInput!
) {
updateTrustCenterReference(input: $input) {
trustCenterReference {
id
rank
}
}
}
`;
export function useUpdateTrustCenterReferenceRankMutation() {
return useMutationWithToasts<TrustCenterReferenceGraphUpdateRankMutation>(
updateTrustCenterReferenceRankMutation,
{
successMessage: "Order updated successfully",
errorMessage: "Failed to update order",
},
);
}
export function useDeleteTrustCenterReferenceMutation() {
return useMutationWithToasts<TrustCenterReferenceGraphDeleteMutation>(
deleteTrustCenterReferenceMutation,
{
successMessage: "Reference deleted successfully",
errorMessage: "Failed to delete reference",
},
);
}

View File

@@ -0,0 +1,53 @@
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import { formatError } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { createUseMutation, type MutationNotifier } from "@probo/relay";
import { useToast } from "@probo/ui";
import { useMemo } from "react";
/**
* Binds the shared awaitable useMutation (`@probo/relay`) to this app's
* feedback stack: `@probo/ui` toasts, i18n titles, and `formatError`
* descriptions. This is the only place those opinions are wired.
*
* Always import useMutation from `#/lib/relay/useMutation` — never useMutation
* from react-relay.
*/
function useMutationNotifier(): MutationNotifier {
const { toast } = useToast();
const { __ } = useTranslate();
return useMemo<MutationNotifier>(
() => ({
notifySuccess: (title) => {
toast({ title, description: "", variant: "success" });
},
notifyError: (error, title) => {
const finalTitle = title ?? __("Error");
toast({
title: finalTitle,
description: formatError(finalTitle, error),
variant: "error",
});
},
}),
[toast, __],
);
}
export type { MutationFeedback } from "@probo/relay";
export const useMutation = createUseMutation(useMutationNotifier);

View File

@@ -68,7 +68,7 @@ const fragment = graphql`
action: "core:processing-activity:list" action: "core:processing-activity:list"
) )
canListRightsRequests: permission(action: "core:rights-request:list") canListRightsRequests: permission(action: "core:rights-request:list")
canGetTrustCenter: permission(action: "core:trust-center:get") canGetCompliancePage: permission(action: "compliance-portal:portal:get")
canListCookieBanners: permission(action: "core:cookie-banner:list") canListCookieBanners: permission(action: "core:cookie-banner:list")
canUpdateOrganization: permission(action: "iam:organization:update") canUpdateOrganization: permission(action: "iam:organization:update")
canListStatementsOfApplicability: permission( canListStatementsOfApplicability: permission(
@@ -212,7 +212,7 @@ export function Sidebar(props: { fKey: SidebarFragment$key }) {
to={`${prefix}/access-reviews`} to={`${prefix}/access-reviews`}
/> />
)} )}
{organization.canGetTrustCenter && ( {organization.canGetCompliancePage && (
<SidebarItem <SidebarItem
label={__("Compliance Page")} label={__("Compliance Page")}
icon={IconShield} icon={IconShield}

View File

@@ -31,7 +31,6 @@ import {
IconTrashCan, IconTrashCan,
Label, Label,
Spinner, Spinner,
Textarea,
useDialogRef, useDialogRef,
} from "@probo/ui"; } from "@probo/ui";
import { type ChangeEventHandler, useState } from "react"; import { type ChangeEventHandler, useState } from "react";
@@ -53,10 +52,6 @@ const fragment = graphql`
horizontalLogo { horizontalLogo {
downloadUrl downloadUrl
} }
description
websiteUrl
email
headquarterAddress
canUpdate: permission(action: "iam:organization:update") canUpdate: permission(action: "iam:organization:update")
} }
`; `;
@@ -73,10 +68,6 @@ const updateOrganizationMutation = graphql`
horizontalLogo { horizontalLogo {
downloadUrl downloadUrl
} }
description
websiteUrl
email
headquarterAddress
} }
} }
} }
@@ -99,10 +90,6 @@ const deleteHorizontalLogoMutation = graphql`
const organizationSchema = z.object({ const organizationSchema = z.object({
name: z.string().min(1, "Organization name is required"), name: z.string().min(1, "Organization name is required"),
description: z.string().optional(),
websiteUrl: z.string().optional(),
email: z.string().optional(),
headquarterAddress: z.string().optional(),
}); });
type OrganizationFormData = z.infer<typeof organizationSchema>; type OrganizationFormData = z.infer<typeof organizationSchema>;
@@ -140,10 +127,6 @@ export function OrganizationForm(props: {
{ {
defaultValues: { defaultValues: {
name: organization.name, name: organization.name,
description: organization.description || "",
websiteUrl: organization.websiteUrl || "",
email: organization.email || "",
headquarterAddress: organization.headquarterAddress || "",
}, },
}, },
); );
@@ -221,10 +204,6 @@ export function OrganizationForm(props: {
input: { input: {
organizationId: organization.id, organizationId: organization.id,
name: data.name, name: data.name,
description: data.description || null,
websiteUrl: data.websiteUrl || null,
email: data.email || null,
headquarterAddress: data.headquarterAddress || null,
}, },
}, },
}); });
@@ -344,43 +323,6 @@ export function OrganizationForm(props: {
label={__("Organization name")} label={__("Organization name")}
placeholder={__("Organization name")} placeholder={__("Organization name")}
/> />
<div>
<Label>{__("Description")}</Label>
<Textarea
{...register("description")}
readOnly={formState.isSubmitting || !canUpdate}
name="description"
placeholder={__("Brief description of your organization")}
rows={3}
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Field
{...register("websiteUrl")}
readOnly={formState.isSubmitting || !canUpdate}
name="websiteUrl"
type="url"
label={__("Website URL")}
placeholder={__("https://example.com")}
/>
<Field
{...register("email")}
readOnly={formState.isSubmitting || !canUpdate}
name="email"
type="email"
label={__("Email")}
placeholder={__("contact@example.com")}
/>
</div>
<div>
<Label>{__("Headquarter Address")}</Label>
<Textarea
{...register("headquarterAddress")}
readOnly={formState.isSubmitting || !canUpdate}
name="headquarterAddress"
placeholder={__("123 Main St, City, Country")}
/>
</div>
{formState.isDirty && canUpdate && ( {formState.isDirty && canUpdate && (
<div className="flex justify-end pt-6"> <div className="flex justify-end pt-6">

View File

@@ -23,7 +23,9 @@ import { Field } from "@probo/ui";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import type { CompliancePageAliasField_removeResourceAliasMutation } from "#/__generated__/core/CompliancePageAliasField_removeResourceAliasMutation.graphql";
import type { CompliancePageAliasField_setResourceAliasMutation } from "#/__generated__/core/CompliancePageAliasField_setResourceAliasMutation.graphql";
import { useMutation } from "#/lib/relay/useMutation";
const setResourceAliasMutation = graphql` const setResourceAliasMutation = graphql`
mutation CompliancePageAliasField_setResourceAliasMutation( mutation CompliancePageAliasField_setResourceAliasMutation(
@@ -65,18 +67,18 @@ export function CompliancePageAliasField(props: {
setValue(alias ?? ""); setValue(alias ?? "");
} }
const [setResourceAlias, isSettingAlias] = useMutationWithToasts( const [setResourceAlias, isSettingAlias] = useMutation<CompliancePageAliasField_setResourceAliasMutation>(
setResourceAliasMutation, setResourceAliasMutation,
{ {
successMessage: __("Alias updated successfully."), successMessage: __("Alias updated successfully."),
errorMessage: __("Failed to update alias"), errorToast: __("Failed to update alias"),
}, },
); );
const [removeResourceAlias, isRemovingAlias] = useMutationWithToasts( const [removeResourceAlias, isRemovingAlias] = useMutation<CompliancePageAliasField_removeResourceAliasMutation>(
removeResourceAliasMutation, removeResourceAliasMutation,
{ {
successMessage: __("Alias removed successfully."), successMessage: __("Alias removed successfully."),
errorMessage: __("Failed to remove alias"), errorToast: __("Failed to remove alias"),
}, },
); );
@@ -117,7 +119,7 @@ export function CompliancePageAliasField(props: {
}, },
}); });
} catch { } catch {
// useMutationWithToasts already shows an error toast. // useMutation already shows an error toast.
} }
}, [alias, canRemoveAlias, canSetAlias, removeResourceAlias, resourceId, setResourceAlias, value]); }, [alias, canRemoveAlias, canSetAlias, removeResourceAlias, resourceId, setResourceAlias, value]);

View File

@@ -19,7 +19,7 @@
// SOFTWARE. // SOFTWARE.
import type { TrustCenterDocumentAccessStatus } from "@probo/coredata"; import type { TrustCenterDocumentAccessStatus } from "@probo/coredata";
import type { TrustCenterDocumentAccessInfo } from "@probo/helpers"; import type { CompliancePageDocumentAccessInfo } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { import {
Button, Button,
@@ -40,7 +40,7 @@ import type { CompliancePageAccessEditDialogDocumentAccessFragment$data, Complia
import type { CompliancePageAccessEditDialogQuery as CompliancePageAccessEditDialogQueryType } from "#/__generated__/core/CompliancePageAccessEditDialogQuery.graphql"; import type { CompliancePageAccessEditDialogQuery as CompliancePageAccessEditDialogQueryType } from "#/__generated__/core/CompliancePageAccessEditDialogQuery.graphql";
import type { CompliancePageAccessEditDialogUpdateMutation } from "#/__generated__/core/CompliancePageAccessEditDialogUpdateMutation.graphql"; import type { CompliancePageAccessEditDialogUpdateMutation } from "#/__generated__/core/CompliancePageAccessEditDialogUpdateMutation.graphql";
import type { CompliancePageAccessListItemFragment$data } from "#/__generated__/core/CompliancePageAccessListItemFragment.graphql"; import type { CompliancePageAccessListItemFragment$data } from "#/__generated__/core/CompliancePageAccessListItemFragment.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
import { CompliancePageDocumentAccessList } from "#/pages/organizations/compliance-page/access/_components/CompliancePageDocumentAccessList"; import { CompliancePageDocumentAccessList } from "#/pages/organizations/compliance-page/access/_components/CompliancePageDocumentAccessList";
import { ElectronicSignatureSection } from "#/pages/organizations/compliance-page/access/_components/ElectronicSignatureSection"; import { ElectronicSignatureSection } from "#/pages/organizations/compliance-page/access/_components/ElectronicSignatureSection";
@@ -76,10 +76,10 @@ const documentAccessFragment = graphql`
} }
`; `;
function getTrustCenterDocumentAccessInfo( function getCompliancePageDocumentAccessInfo(
fragmentRef: CompliancePageAccessEditDialogDocumentAccessFragment$key, fragmentRef: CompliancePageAccessEditDialogDocumentAccessFragment$key,
__: (key: string) => string, __: (key: string) => string,
): TrustCenterDocumentAccessInfo { ): CompliancePageDocumentAccessInfo {
const node = readInlineData(documentAccessFragment, fragmentRef); const node = readInlineData(documentAccessFragment, fragmentRef);
return toDocumentAccessInfo(node, __); return toDocumentAccessInfo(node, __);
} }
@@ -87,7 +87,7 @@ function getTrustCenterDocumentAccessInfo(
function toDocumentAccessInfo( function toDocumentAccessInfo(
node: CompliancePageAccessEditDialogDocumentAccessFragment$data, node: CompliancePageAccessEditDialogDocumentAccessFragment$data,
__: (key: string) => string, __: (key: string) => string,
): TrustCenterDocumentAccessInfo { ): CompliancePageDocumentAccessInfo {
if (node.document) { if (node.document) {
return { return {
persisted: node.id !== node.document.id, persisted: node.id !== node.document.id,
@@ -124,7 +124,7 @@ function toDocumentAccessInfo(
status: node.status, status: node.status,
}; };
} }
throw new Error("Unknown trust center access document type"); throw new Error("Unknown compliance page access document type");
} }
const compliancePageAccessEditDialogQuery = graphql` const compliancePageAccessEditDialogQuery = graphql`
@@ -221,7 +221,7 @@ function CompliancePageAccessEditForm(props: {
const initialDocumentAccesses const initialDocumentAccesses
= data.node.availableDocumentAccesses?.edges.map(edge => = data.node.availableDocumentAccesses?.edges.map(edge =>
getTrustCenterDocumentAccessInfo(edge.node, __), getCompliancePageDocumentAccessInfo(edge.node, __),
) ?? []; ) ?? [];
const initialStatusByID = initialDocumentAccesses.reduce< const initialStatusByID = initialDocumentAccesses.reduce<
Record<string, TrustCenterDocumentAccessStatus> Record<string, TrustCenterDocumentAccessStatus>
@@ -230,12 +230,12 @@ function CompliancePageAccessEditForm(props: {
return acc; return acc;
}, {}); }, {});
const [documentAccesses, setDocumentAccesses] = useState< const [documentAccesses, setDocumentAccesses] = useState<
TrustCenterDocumentAccessInfo[] CompliancePageDocumentAccessInfo[]
>(initialDocumentAccesses); >(initialDocumentAccesses);
const handleUpdateDocumentAccessStatus = useCallback( const handleUpdateDocumentAccessStatus = useCallback(
( (
documentAccess: TrustCenterDocumentAccessInfo, documentAccess: CompliancePageDocumentAccessInfo,
status: TrustCenterDocumentAccessStatus, status: TrustCenterDocumentAccessStatus,
) => { ) => {
setDocumentAccesses((prev) => { setDocumentAccesses((prev) => {
@@ -269,11 +269,11 @@ function CompliancePageAccessEditForm(props: {
); );
}, [initialStatusByID]); }, [initialStatusByID]);
const [updateTrustCenterAccess, isUpdating] = useMutationWithToasts<CompliancePageAccessEditDialogUpdateMutation>( const [updateCompliancePageAccess, isUpdating] = useMutation<CompliancePageAccessEditDialogUpdateMutation>(
updateAccessMutation, updateAccessMutation,
{ {
successMessage: __("Access updated successfully"), successMessage: __("Access updated successfully"),
errorMessage: __("Failed to update access"), errorToast: __("Failed to update access"),
}, },
); );
@@ -282,7 +282,7 @@ function CompliancePageAccessEditForm(props: {
= []; = [];
const reports: { id: string; status: TrustCenterDocumentAccessStatus }[] const reports: { id: string; status: TrustCenterDocumentAccessStatus }[]
= []; = [];
const trustCenterFiles: { const compliancePageFiles: {
id: string; id: string;
status: TrustCenterDocumentAccessStatus; status: TrustCenterDocumentAccessStatus;
}[] = []; }[] = [];
@@ -297,7 +297,7 @@ function CompliancePageAccessEditForm(props: {
reports.push({ id: docAccess.id, status: docAccess.status }); reports.push({ id: docAccess.id, status: docAccess.status });
break; break;
case "file": case "file":
trustCenterFiles.push({ compliancePageFiles.push({
id: docAccess.id, id: docAccess.id,
status: docAccess.status, status: docAccess.status,
}); });
@@ -306,17 +306,18 @@ function CompliancePageAccessEditForm(props: {
} }
} }
await updateTrustCenterAccess({ await updateCompliancePageAccess({
variables: { variables: {
input: { input: {
id: access.id, id: access.id,
documents, documents,
reports, reports,
trustCenterFiles, trustCenterFiles: compliancePageFiles,
}, },
}, },
onSuccess: onSubmit,
}); });
onSubmit();
}; };
return ( return (

View File

@@ -44,7 +44,7 @@ const fragment = graphql`
ndaSignature { ndaSignature {
status status
} }
canUpdate: permission(action: "core:trust-center-access:update") canUpdate: permission(action: "compliance-portal:portal-access:update")
} }
`; `;

View File

@@ -19,16 +19,17 @@
// SOFTWARE. // SOFTWARE.
import type { TrustCenterDocumentAccessStatus } from "@probo/coredata"; import type { TrustCenterDocumentAccessStatus } from "@probo/coredata";
import { getTrustCenterDocumentAccessStatusBadgeVariant, getTrustCenterDocumentAccessStatusLabel, type TrustCenterDocumentAccessInfo } from "@probo/helpers"; import type { CompliancePageDocumentAccessInfo } from "@probo/helpers";
import { getCompliancePageDocumentAccessStatusBadgeVariant, getCompliancePageDocumentAccessStatusLabel } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Badge, Button, Table, Tbody, Td, Th, Thead, Tr } from "@probo/ui"; import { Badge, Button, Table, Tbody, Td, Th, Thead, Tr } from "@probo/ui";
interface CompliancePageDocumentAccessListProps { interface CompliancePageDocumentAccessListProps {
documentAccesses: TrustCenterDocumentAccessInfo[]; documentAccesses: CompliancePageDocumentAccessInfo[];
initialStatusByID: Record<string, TrustCenterDocumentAccessStatus>; initialStatusByID: Record<string, TrustCenterDocumentAccessStatus>;
onGrantAll: () => void; onGrantAll: () => void;
onRejectOrRevokeAll: () => void; onRejectOrRevokeAll: () => void;
onUpdateStatus: (docAccess: TrustCenterDocumentAccessInfo, status: TrustCenterDocumentAccessStatus) => void; onUpdateStatus: (docAccess: CompliancePageDocumentAccessInfo, status: TrustCenterDocumentAccessStatus) => void;
} }
export function CompliancePageDocumentAccessList(props: CompliancePageDocumentAccessListProps) { export function CompliancePageDocumentAccessList(props: CompliancePageDocumentAccessListProps) {
@@ -108,8 +109,8 @@ export function CompliancePageDocumentAccessList(props: CompliancePageDocumentAc
<Td> <Td>
{(docAccess.persisted || docAccess.status !== "REQUESTED") {(docAccess.persisted || docAccess.status !== "REQUESTED")
&& ( && (
<Badge variant={getTrustCenterDocumentAccessStatusBadgeVariant(docAccess.status)}> <Badge variant={getCompliancePageDocumentAccessStatusBadgeVariant(docAccess.status)}>
{getTrustCenterDocumentAccessStatusLabel(docAccess.status, __)} {getCompliancePageDocumentAccessStatusLabel(docAccess.status, __)}
</Badge> </Badge>
)} )}
</Td> </Td>

View File

@@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
import { formatDate, getAuditStateLabel, getAuditStateVariant, getTrustCenterVisibilityOptions } from "@probo/helpers"; import { formatDate, getAuditStateLabel, getAuditStateVariant, getCompliancePageVisibilityOptions } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Badge, Field, Option, Td, Tr } from "@probo/ui"; import { Badge, Field, Option, Td, Tr } from "@probo/ui";
import { useCallback } from "react"; import { useCallback } from "react";
@@ -28,12 +28,12 @@ import { graphql } from "relay-runtime";
import type { CompliancePageAuditListItem_auditFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_auditFragment.graphql"; import type { CompliancePageAuditListItem_auditFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_auditFragment.graphql";
import type { CompliancePageAuditListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql"; import type { CompliancePageAuditListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql";
import type { CompliancePageAuditListItem_updateAuditVisibilityMutation } from "#/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql"; import type { CompliancePageAuditListItem_updateAuditVisibilityMutation } from "#/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId"; import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
const compliancePageFragment = graphql` const compliancePageFragment = graphql`
fragment CompliancePageAuditListItem_compliancePageFragment on TrustCenter { fragment CompliancePageAuditListItem_compliancePageFragment on TrustCenter {
canUpdate: permission(action: "core:trust-center:update") canUpdate: permission(action: "compliance-portal:portal:update")
} }
`; `;
@@ -46,7 +46,7 @@ const auditFragment = graphql`
} }
validUntil validUntil
state state
trustCenterVisibility compliancePageVisibility: trustCenterVisibility
} }
`; `;
@@ -75,13 +75,13 @@ export function CompliancePageAuditListItem(props: {
); );
const audit = useFragment<CompliancePageAuditListItem_auditFragment$key>(auditFragment, auditFragmentRef); const audit = useFragment<CompliancePageAuditListItem_auditFragment$key>(auditFragment, auditFragmentRef);
const [updateAuditVisibility, isUpdatingAuditVisibility] = useMutationWithToasts< const [updateAuditVisibility, isUpdatingAuditVisibility] = useMutation<
CompliancePageAuditListItem_updateAuditVisibilityMutation CompliancePageAuditListItem_updateAuditVisibilityMutation
>( >(
updateAuditVisibilityMutation, updateAuditVisibilityMutation,
{ {
successMessage: __("Audit visibility updated successfully."), successMessage: __("Audit visibility updated successfully."),
errorMessage: __("Failed to update audit visibility"), errorToast: __("Failed to update audit visibility"),
}, },
); );
const handleVisibilityChange = useCallback( const handleVisibilityChange = useCallback(
@@ -100,7 +100,7 @@ export function CompliancePageAuditListItem(props: {
[audit.id, updateAuditVisibility], [audit.id, updateAuditVisibility],
); );
const visibilityOptions = getTrustCenterVisibilityOptions(__); const visibilityOptions = getCompliancePageVisibilityOptions(__);
const validUntilFormatted = audit.validUntil const validUntilFormatted = audit.validUntil
? formatDate(audit.validUntil) ? formatDate(audit.validUntil)
: __("No expiry"); : __("No expiry");
@@ -120,7 +120,7 @@ export function CompliancePageAuditListItem(props: {
<Td noLink width={130} className="pr-0"> <Td noLink width={130} className="pr-0">
<Field <Field
type="select" type="select"
value={audit.trustCenterVisibility} value={audit.compliancePageVisibility}
onValueChange={value => void handleVisibilityChange(value)} onValueChange={value => void handleVisibilityChange(value)}
disabled={isUpdatingAuditVisibility || !compliancePage.canUpdate} disabled={isUpdatingAuditVisibility || !compliancePage.canUpdate}
className="w-[105px]" className="w-[105px]"

View File

@@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
import { getTrustCenterVisibilityOptions } from "@probo/helpers"; import { getCompliancePageVisibilityOptions } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Badge, DocumentTypeBadge, Field, Option, Td, Tr } from "@probo/ui"; import { Badge, DocumentTypeBadge, Field, Option, Td, Tr } from "@probo/ui";
import { useCallback } from "react"; import { useCallback } from "react";
@@ -27,14 +27,15 @@ import { graphql } from "relay-runtime";
import type { CompliancePageDocumentListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageDocumentListItem_compliancePageFragment.graphql"; import type { CompliancePageDocumentListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageDocumentListItem_compliancePageFragment.graphql";
import type { CompliancePageDocumentListItem_documentFragment$key } from "#/__generated__/core/CompliancePageDocumentListItem_documentFragment.graphql"; import type { CompliancePageDocumentListItem_documentFragment$key } from "#/__generated__/core/CompliancePageDocumentListItem_documentFragment.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import type { CompliancePageDocumentListItem_updateVisibilityMutation } from "#/__generated__/core/CompliancePageDocumentListItem_updateVisibilityMutation.graphql";
import { useOrganizationId } from "#/hooks/useOrganizationId"; import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
import { CompliancePageAliasField } from "../../_components/CompliancePageAliasField"; import { CompliancePageAliasField } from "../../_components/CompliancePageAliasField";
const compliancePageFragment = graphql` const compliancePageFragment = graphql`
fragment CompliancePageDocumentListItem_compliancePageFragment on TrustCenter { fragment CompliancePageDocumentListItem_compliancePageFragment on TrustCenter {
canUpdate: permission(action: "core:trust-center:update") canUpdate: permission(action: "compliance-portal:portal:update")
} }
`; `;
@@ -44,7 +45,7 @@ const documentFragment = graphql`
alias alias
canSetAlias: permission(action: "resourcealias:alias:set") canSetAlias: permission(action: "resourcealias:alias:set")
canRemoveAlias: permission(action: "resourcealias:alias:remove") canRemoveAlias: permission(action: "resourcealias:alias:remove")
trustCenterVisibility compliancePageVisibility: trustCenterVisibility
latestPublishedVersion: versions( latestPublishedVersion: versions(
first: 1 first: 1
orderBy: { field: CREATED_AT, direction: DESC } orderBy: { field: CREATED_AT, direction: DESC }
@@ -80,7 +81,7 @@ export function CompliancePageDocumentListItem(props: {
const organizationId = useOrganizationId(); const organizationId = useOrganizationId();
const { __ } = useTranslate(); const { __ } = useTranslate();
const visibilityOptions = getTrustCenterVisibilityOptions(__); const visibilityOptions = getCompliancePageVisibilityOptions(__);
const compliancePage = useFragment<CompliancePageDocumentListItem_compliancePageFragment$key>( const compliancePage = useFragment<CompliancePageDocumentListItem_compliancePageFragment$key>(
compliancePageFragment, compliancePageFragment,
@@ -90,13 +91,14 @@ export function CompliancePageDocumentListItem(props: {
documentFragment, documentFragment,
documentFragmentRef, documentFragmentRef,
); );
const [updateDocumentVisibility, isUpdatingDocumentVisibility] = useMutationWithToasts( const [updateDocumentVisibility, isUpdatingDocumentVisibility]
updateDocumentVisibilityMutation, = useMutation<CompliancePageDocumentListItem_updateVisibilityMutation>(
{ updateDocumentVisibilityMutation,
successMessage: __("Document visibility updated successfully."), {
errorMessage: __("Failed to update document visibility"), successMessage: __("Document visibility updated successfully."),
}, errorToast: __("Failed to update document visibility"),
); },
);
const handleVsibilityChange = useCallback( const handleVsibilityChange = useCallback(
async (value: string) => { async (value: string) => {
const stringValue = typeof value === "string" ? value : ""; const stringValue = typeof value === "string" ? value : "";
@@ -135,7 +137,7 @@ export function CompliancePageDocumentListItem(props: {
<Td noLink width={130} className="pr-0"> <Td noLink width={130} className="pr-0">
<Field <Field
type="select" type="select"
value={document.trustCenterVisibility} value={document.compliancePageVisibility}
onValueChange={value => void handleVsibilityChange(value)} onValueChange={value => void handleVsibilityChange(value)}
disabled={isUpdatingDocumentVisibility || !compliancePage.canUpdate} disabled={isUpdatingDocumentVisibility || !compliancePage.canUpdate}
className="w-[105px]" className="w-[105px]"

View File

@@ -32,7 +32,7 @@ export const compliancePageFilesPageQuery = graphql`
query CompliancePageFilesPageQuery($organizationId: ID!) { query CompliancePageFilesPageQuery($organizationId: ID!) {
organization: node(id: $organizationId) { organization: node(id: $organizationId) {
... on Organization { ... on Organization {
canCreateTrustCenterFile: permission(action: "core:trust-center-file:create") canCreateCompliancePageFile: permission(action: "compliance-portal:portal-file:create")
} }
...CompliancePageFileListFragment ...CompliancePageFileListFragment
} }
@@ -52,7 +52,7 @@ export function CompliancePageFilesPage(props: {
const filesConnectionId = ConnectionHandler.getConnectionID( const filesConnectionId = ConnectionHandler.getConnectionID(
organizationId, organizationId,
"CompliancePageFileList_trustCenterFiles", "CompliancePageFileList_compliancePageFiles",
); );
return ( return (
@@ -64,7 +64,7 @@ export function CompliancePageFilesPage(props: {
{__("Upload and manage files for your compliance page")} {__("Upload and manage files for your compliance page")}
</p> </p>
</div> </div>
{organization.canCreateTrustCenterFile && ( {organization.canCreateCompliancePageFile && (
<Button <Button
icon={IconPlusLarge} icon={IconPlusLarge}
onClick={() => createDialogRef.current?.open()} onClick={() => createDialogRef.current?.open()}

View File

@@ -36,8 +36,8 @@ const fragment = graphql`
compliancePage: trustCenter @required(action: THROW) { compliancePage: trustCenter @required(action: THROW) {
...CompliancePageFileListItem_compliancePageFragment ...CompliancePageFileListItem_compliancePageFragment
} }
trustCenterFiles(first: 100) compliancePageFiles: trustCenterFiles(first: 100)
@connection(key: "CompliancePageFileList_trustCenterFiles") { @connection(key: "CompliancePageFileList_compliancePageFiles") {
__id __id
edges { edges {
node { node {
@@ -57,7 +57,7 @@ export function CompliancePageFileList(props: { fragmentRef: CompliancePageFileL
const { const {
compliancePage, compliancePage,
trustCenterFiles: files, compliancePageFiles: files,
} = useFragment<CompliancePageFileListFragment$key>(fragment, fragmentRef); } = useFragment<CompliancePageFileListFragment$key>(fragment, fragmentRef);
const [editingFile, setEditingFile] = useState< const [editingFile, setEditingFile] = useState<

View File

@@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
import { formatDate, getTrustCenterVisibilityOptions } from "@probo/helpers"; import { formatDate, getCompliancePageVisibilityOptions } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Badge, Button, Field, IconArrowLink, IconPencil, IconTrashCan, Option, Td, Tr } from "@probo/ui"; import { Badge, Button, Field, IconArrowLink, IconPencil, IconTrashCan, Option, Td, Tr } from "@probo/ui";
import { useCallback } from "react"; import { useCallback } from "react";
@@ -28,13 +28,13 @@ import { graphql } from "relay-runtime";
import type { CompliancePageFileListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageFileListItem_compliancePageFragment.graphql"; import type { CompliancePageFileListItem_compliancePageFragment$key } from "#/__generated__/core/CompliancePageFileListItem_compliancePageFragment.graphql";
import type { CompliancePageFileListItem_fileFragment$data, CompliancePageFileListItem_fileFragment$key } from "#/__generated__/core/CompliancePageFileListItem_fileFragment.graphql"; import type { CompliancePageFileListItem_fileFragment$data, CompliancePageFileListItem_fileFragment$key } from "#/__generated__/core/CompliancePageFileListItem_fileFragment.graphql";
import type { CompliancePageFileListItemMutation } from "#/__generated__/core/CompliancePageFileListItemMutation.graphql"; import type { CompliancePageFileListItemMutation } from "#/__generated__/core/CompliancePageFileListItemMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
import { CompliancePageAliasField } from "../../_components/CompliancePageAliasField"; import { CompliancePageAliasField } from "../../_components/CompliancePageAliasField";
const compliancePageFragment = graphql` const compliancePageFragment = graphql`
fragment CompliancePageFileListItem_compliancePageFragment on TrustCenter { fragment CompliancePageFileListItem_compliancePageFragment on TrustCenter {
canUpdate: permission(action: "core:trust-center:update") canUpdate: permission(action: "compliance-portal:portal:update")
} }
`; `;
@@ -49,10 +49,10 @@ const fileFragment = graphql`
file { file {
downloadUrl downloadUrl
} }
trustCenterVisibility compliancePageVisibility: trustCenterVisibility
createdAt createdAt
canUpdate: permission(action: "core:trust-center-file:update") canUpdate: permission(action: "compliance-portal:portal-file:update")
canDelete: permission(action: "core:trust-center-file:delete") canDelete: permission(action: "compliance-portal:portal-file:delete")
} }
`; `;
@@ -75,7 +75,7 @@ export function CompliancePageFileListItem(props: {
const { compliancePageFragmentRef, fileFragmentRef, onEdit, onDelete } = props; const { compliancePageFragmentRef, fileFragmentRef, onEdit, onDelete } = props;
const { __ } = useTranslate(); const { __ } = useTranslate();
const visibilityOptions = getTrustCenterVisibilityOptions(__); const visibilityOptions = getCompliancePageVisibilityOptions(__);
const compliancePage = useFragment<CompliancePageFileListItem_compliancePageFragment$key>( const compliancePage = useFragment<CompliancePageFileListItem_compliancePageFragment$key>(
compliancePageFragment, compliancePageFragment,
@@ -83,11 +83,11 @@ export function CompliancePageFileListItem(props: {
); );
const file = useFragment<CompliancePageFileListItem_fileFragment$key>(fileFragment, fileFragmentRef); const file = useFragment<CompliancePageFileListItem_fileFragment$key>(fileFragment, fileFragmentRef);
const [updateFile, isUpdating] = useMutationWithToasts<CompliancePageFileListItemMutation>( const [updateFile, isUpdating] = useMutation<CompliancePageFileListItemMutation>(
updateCompliancePageFileMutation, updateCompliancePageFileMutation,
{ {
successMessage: "File updated successfully", successMessage: "File updated successfully",
errorMessage: "Failed to update file", errorToast: "Failed to update file",
}, },
); );
@@ -125,7 +125,7 @@ export function CompliancePageFileListItem(props: {
<Td noLink width={130} className="pr-0"> <Td noLink width={130} className="pr-0">
<Field <Field
type="select" type="select"
value={file.trustCenterVisibility} value={file.compliancePageVisibility}
onValueChange={value => void handleValueChange(value)} onValueChange={value => void handleValueChange(value)}
disabled={isUpdating || !compliancePage.canUpdate} disabled={isUpdating || !compliancePage.canUpdate}
className="w-[105px]" className="w-[105px]"

View File

@@ -24,7 +24,7 @@ import { useCallback } from "react";
import { type DataID, graphql } from "relay-runtime"; import { type DataID, graphql } from "relay-runtime";
import type { DeleteCompliancePageFileDialogMutation } from "#/__generated__/core/DeleteCompliancePageFileDialogMutation.graphql"; import type { DeleteCompliancePageFileDialogMutation } from "#/__generated__/core/DeleteCompliancePageFileDialogMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
const deleteCompliancePageFileMutation = graphql` const deleteCompliancePageFileMutation = graphql`
mutation DeleteCompliancePageFileDialogMutation( mutation DeleteCompliancePageFileDialogMutation(
@@ -47,11 +47,11 @@ export function DeleteCompliancePageFileDialog(props: {
const { __ } = useTranslate(); const { __ } = useTranslate();
const [deleteFile, isDeleting] = useMutationWithToasts<DeleteCompliancePageFileDialogMutation>( const [deleteFile, isDeleting] = useMutation<DeleteCompliancePageFileDialogMutation>(
deleteCompliancePageFileMutation, deleteCompliancePageFileMutation,
{ {
successMessage: "File deleted successfully", successMessage: "File deleted successfully",
errorMessage: "Failed to delete file", errorToast: "Failed to delete file",
}, },
); );
@@ -65,11 +65,10 @@ export function DeleteCompliancePageFileDialog(props: {
input: { id: fileId }, input: { id: fileId },
connections: connectionId ? [connectionId] : [], connections: connectionId ? [connectionId] : [],
}, },
onSuccess: () => {
ref.current?.close();
onDelete();
},
}); });
ref.current?.close();
onDelete();
}, [fileId, deleteFile, ref, connectionId, onDelete]); }, [fileId, deleteFile, ref, connectionId, onDelete]);
return ( return (

View File

@@ -26,7 +26,7 @@ import { z } from "zod";
import type { CompliancePageFileListItem_fileFragment$data } from "#/__generated__/core/CompliancePageFileListItem_fileFragment.graphql"; import type { CompliancePageFileListItem_fileFragment$data } from "#/__generated__/core/CompliancePageFileListItem_fileFragment.graphql";
import type { EditCompliancePageFileDialogMutation } from "#/__generated__/core/EditCompliancePageFileDialogMutation.graphql"; import type { EditCompliancePageFileDialogMutation } from "#/__generated__/core/EditCompliancePageFileDialogMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
const updateCompliancePageFileMutation = graphql` const updateCompliancePageFileMutation = graphql`
mutation EditCompliancePageFileDialogMutation($input: UpdateTrustCenterFileInput!) { mutation EditCompliancePageFileDialogMutation($input: UpdateTrustCenterFileInput!) {
@@ -54,11 +54,11 @@ export function EditCompliancePageFileDialog(props: {
defaultValues: { name: file.name, category: file.category }, defaultValues: { name: file.name, category: file.category },
}); });
const [updateFile, isUpdating] = useMutationWithToasts<EditCompliancePageFileDialogMutation>( const [updateFile, isUpdating] = useMutation<EditCompliancePageFileDialogMutation>(
updateCompliancePageFileMutation, updateCompliancePageFileMutation,
{ {
successMessage: "File updated successfully", successMessage: "File updated successfully",
errorMessage: "Failed to update file", errorToast: "Failed to update file",
}, },
); );
@@ -71,10 +71,9 @@ export function EditCompliancePageFileDialog(props: {
category: data.category, category: data.category,
}, },
}, },
onSuccess: () => {
onClose();
},
}); });
onClose();
}; };
return ( return (

View File

@@ -25,7 +25,7 @@ import {
acceptPresentation, acceptPresentation,
acceptSpreadsheet, acceptSpreadsheet,
acceptText, acceptText,
getTrustCenterVisibilityOptions, getCompliancePageVisibilityOptions,
} from "@probo/helpers"; } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Badge, Button, Dialog, DialogContent, DialogFooter, type DialogRef, Dropzone, Field, Option, Spinner } from "@probo/ui"; import { Badge, Button, Dialog, DialogContent, DialogFooter, type DialogRef, Dropzone, Field, Option, Spinner } from "@probo/ui";
@@ -35,8 +35,8 @@ import { z } from "zod";
import type { NewCompliancePageFileDialog_createMutation } from "#/__generated__/core/NewCompliancePageFileDialog_createMutation.graphql"; import type { NewCompliancePageFileDialog_createMutation } from "#/__generated__/core/NewCompliancePageFileDialog_createMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId"; import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
const acceptedFileTypes = { const acceptedFileTypes = {
...acceptDocument, ...acceptDocument,
@@ -76,10 +76,10 @@ export function NewCompliancePageFileDialog(props: {
const createSchema = z.object({ const createSchema = z.object({
name: z.string().min(1, __("Name is required")), name: z.string().min(1, __("Name is required")),
category: z.string().min(1, __("Category is required")), category: z.string().min(1, __("Category is required")),
trustCenterVisibility: z.enum(["NONE", "PRIVATE", "PUBLIC"]), compliancePageVisibility: z.enum(["NONE", "PRIVATE", "PUBLIC"]),
}); });
const createForm = useFormWithSchema(createSchema, { const createForm = useFormWithSchema(createSchema, {
defaultValues: { name: "", category: "", trustCenterVisibility: "NONE" }, defaultValues: { name: "", category: "", compliancePageVisibility: "NONE" },
}); });
const handleFileUpload = useCallback( const handleFileUpload = useCallback(
@@ -105,10 +105,10 @@ export function NewCompliancePageFileDialog(props: {
[createForm, __], [createForm, __],
); );
const [createFile, isCreating] = useMutationWithToasts<NewCompliancePageFileDialog_createMutation>( const [createFile, isCreating] = useMutation<NewCompliancePageFileDialog_createMutation>(
createCompliancePageFileMutation, { createCompliancePageFileMutation, {
successMessage: "File uploaded successfully", successMessage: "File uploaded successfully",
errorMessage: "Failed to upload file", errorToast: "Failed to upload file",
}, },
); );
const handleCreate = async (data: z.infer<typeof createSchema>) => { const handleCreate = async (data: z.infer<typeof createSchema>) => {
@@ -122,7 +122,7 @@ export function NewCompliancePageFileDialog(props: {
organizationId, organizationId,
name: data.name, name: data.name,
category: data.category, category: data.category,
trustCenterVisibility: data.trustCenterVisibility, trustCenterVisibility: data.compliancePageVisibility,
file: null, file: null,
}, },
connections: connectionId ? [connectionId] : [], connections: connectionId ? [connectionId] : [],
@@ -130,12 +130,11 @@ export function NewCompliancePageFileDialog(props: {
uploadables: { uploadables: {
"input.file": uploadedFile, "input.file": uploadedFile,
}, },
onSuccess: () => {
ref.current?.close();
createForm.reset();
setUploadedFile(null);
},
}); });
ref.current?.close();
createForm.reset();
setUploadedFile(null);
}; };
return ( return (
@@ -176,15 +175,15 @@ export function NewCompliancePageFileDialog(props: {
<Field <Field
label={__("Visibility")} label={__("Visibility")}
type="select" type="select"
value={createForm.watch("trustCenterVisibility")} value={createForm.watch("compliancePageVisibility")}
onValueChange={value => onValueChange={value =>
createForm.setValue( createForm.setValue(
"trustCenterVisibility", "compliancePageVisibility",
value as "NONE" | "PRIVATE" | "PUBLIC", value as "NONE" | "PRIVATE" | "PUBLIC",
)} )}
error={createForm.formState.errors.trustCenterVisibility?.message} error={createForm.formState.errors.compliancePageVisibility?.message}
> >
{getTrustCenterVisibilityOptions(__).map(option => ( {getCompliancePageVisibilityOptions(__).map(option => (
<Option key={option.value} value={option.value}> <Option key={option.value} value={option.value}>
<div className="flex items-center justify-between w-full"> <div className="flex items-center justify-between w-full">
<Badge variant={option.variant}>{option.label}</Badge> <Badge variant={option.variant}>{option.label}</Badge>

View File

@@ -26,7 +26,7 @@ import { ConnectionHandler, graphql } from "relay-runtime";
import type { CompliancePageMailingListPage_updateMailingListMutation } from "#/__generated__/core/CompliancePageMailingListPage_updateMailingListMutation.graphql"; import type { CompliancePageMailingListPage_updateMailingListMutation } from "#/__generated__/core/CompliancePageMailingListPage_updateMailingListMutation.graphql";
import type { CompliancePageMailingListPageQuery } from "#/__generated__/core/CompliancePageMailingListPageQuery.graphql"; import type { CompliancePageMailingListPageQuery } from "#/__generated__/core/CompliancePageMailingListPageQuery.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
import { CompliancePageMailingList } from "./_components/CompliancePageMailingList"; import { CompliancePageMailingList } from "./_components/CompliancePageMailingList";
import { CompliancePageUpdatesList, type UpdateNode } from "./_components/CompliancePageUpdatesList"; import { CompliancePageUpdatesList, type UpdateNode } from "./_components/CompliancePageUpdatesList";
@@ -101,11 +101,11 @@ export function CompliancePageMailingListPage(props: {
const [replyTo, setReplyTo] = useState(mailingList?.replyTo ?? ""); const [replyTo, setReplyTo] = useState(mailingList?.replyTo ?? "");
const [updateMailingList, isUpdating] const [updateMailingList, isUpdating]
= useMutationWithToasts<CompliancePageMailingListPage_updateMailingListMutation>( = useMutation<CompliancePageMailingListPage_updateMailingListMutation>(
updateMailingListMutation, updateMailingListMutation,
{ {
successMessage: __("Mailing list updated successfully"), successMessage: __("Mailing list updated successfully"),
errorMessage: __("Failed to update mailing list"), errorToast: __("Failed to update mailing list"),
}, },
); );

View File

@@ -26,7 +26,7 @@ import { graphql } from "relay-runtime";
import type { CompliancePageMailingListDeleteMutation } from "#/__generated__/core/CompliancePageMailingListDeleteMutation.graphql"; import type { CompliancePageMailingListDeleteMutation } from "#/__generated__/core/CompliancePageMailingListDeleteMutation.graphql";
import type { CompliancePageMailingListFragment$key } from "#/__generated__/core/CompliancePageMailingListFragment.graphql"; import type { CompliancePageMailingListFragment$key } from "#/__generated__/core/CompliancePageMailingListFragment.graphql";
import type { CompliancePageMailingListQuery } from "#/__generated__/core/CompliancePageMailingListQuery.graphql"; import type { CompliancePageMailingListQuery } from "#/__generated__/core/CompliancePageMailingListQuery.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
const deleteMutation = graphql` const deleteMutation = graphql`
mutation CompliancePageMailingListDeleteMutation( mutation CompliancePageMailingListDeleteMutation(
@@ -89,11 +89,11 @@ export function CompliancePageMailingList(props: {
const subscribers = data.mailingList?.subscribers; const subscribers = data.mailingList?.subscribers;
const [deleteSubscriber, isDeleting] = useMutationWithToasts<CompliancePageMailingListDeleteMutation>( const [deleteSubscriber, isDeleting] = useMutation<CompliancePageMailingListDeleteMutation>(
deleteMutation, deleteMutation,
{ {
successMessage: __("Subscriber removed successfully"), successMessage: __("Subscriber removed successfully"),
errorMessage: __("Failed to delete subscriber"), errorToast: __("Failed to delete subscriber"),
}, },
); );

View File

@@ -27,7 +27,7 @@ import { graphql } from "relay-runtime";
import type { CompliancePageUpdatesListDeleteMutation } from "#/__generated__/core/CompliancePageUpdatesListDeleteMutation.graphql"; import type { CompliancePageUpdatesListDeleteMutation } from "#/__generated__/core/CompliancePageUpdatesListDeleteMutation.graphql";
import type { CompliancePageUpdatesListFragment$data, CompliancePageUpdatesListFragment$key } from "#/__generated__/core/CompliancePageUpdatesListFragment.graphql"; import type { CompliancePageUpdatesListFragment$data, CompliancePageUpdatesListFragment$key } from "#/__generated__/core/CompliancePageUpdatesListFragment.graphql";
import type { CompliancePageUpdatesListQuery } from "#/__generated__/core/CompliancePageUpdatesListQuery.graphql"; import type { CompliancePageUpdatesListQuery } from "#/__generated__/core/CompliancePageUpdatesListQuery.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
import { SendUpdateDialog } from "./SendUpdateDialog"; import { SendUpdateDialog } from "./SendUpdateDialog";
@@ -92,9 +92,9 @@ export function CompliancePageUpdatesList(props: {
const connection = data.updates; const connection = data.updates;
const [deleteUpdate, isDeleting] const [deleteUpdate, isDeleting]
= useMutationWithToasts<CompliancePageUpdatesListDeleteMutation>(deleteMutation, { = useMutation<CompliancePageUpdatesListDeleteMutation>(deleteMutation, {
successMessage: __("Update deleted successfully"), successMessage: __("Update deleted successfully"),
errorMessage: __("Failed to delete update"), errorToast: __("Failed to delete update"),
}); });
const handleDelete = (id: string) => { const handleDelete = (id: string) => {

View File

@@ -27,7 +27,7 @@ import { z } from "zod";
import type { ComplianceUpdateFormDialogCreateMutation } from "#/__generated__/core/ComplianceUpdateFormDialogCreateMutation.graphql"; import type { ComplianceUpdateFormDialogCreateMutation } from "#/__generated__/core/ComplianceUpdateFormDialogCreateMutation.graphql";
import type { ComplianceUpdateFormDialogUpdateMutation } from "#/__generated__/core/ComplianceUpdateFormDialogUpdateMutation.graphql"; import type { ComplianceUpdateFormDialogUpdateMutation } from "#/__generated__/core/ComplianceUpdateFormDialogUpdateMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
import type { UpdateNode } from "./CompliancePageUpdatesList"; import type { UpdateNode } from "./CompliancePageUpdatesList";
@@ -104,19 +104,19 @@ export function ComplianceUpdateFormDialog(props: Props) {
} }
}, [update, form]); }, [update, form]);
const [createUpdate, isCreating] = useMutationWithToasts<ComplianceUpdateFormDialogCreateMutation>( const [createUpdate, isCreating] = useMutation<ComplianceUpdateFormDialogCreateMutation>(
createMutation, createMutation,
{ {
successMessage: __("Update created successfully"), successMessage: __("Update created successfully"),
errorMessage: __("Failed to create update"), errorToast: __("Failed to create update"),
}, },
); );
const [saveUpdate, isSaving] = useMutationWithToasts<ComplianceUpdateFormDialogUpdateMutation>( const [saveUpdate, isSaving] = useMutation<ComplianceUpdateFormDialogUpdateMutation>(
updateMutation, updateMutation,
{ {
successMessage: __("Update saved successfully"), successMessage: __("Update saved successfully"),
errorMessage: __("Failed to save update"), errorToast: __("Failed to save update"),
}, },
); );

View File

@@ -25,7 +25,7 @@ import { z } from "zod";
import type { NewCompliancePageSubscriberDialogMutation } from "#/__generated__/core/NewCompliancePageSubscriberDialogMutation.graphql"; import type { NewCompliancePageSubscriberDialogMutation } from "#/__generated__/core/NewCompliancePageSubscriberDialogMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
const createSubscriberMutation = graphql` const createSubscriberMutation = graphql`
mutation NewCompliancePageSubscriberDialogMutation( mutation NewCompliancePageSubscriberDialogMutation(
@@ -69,11 +69,11 @@ export function NewCompliancePageSubscriberDialog(props: {
defaultValues: { fullName: "", email: "", confirmed: false }, defaultValues: { fullName: "", email: "", confirmed: false },
}); });
const [createSubscriber, isCreating] = useMutationWithToasts<NewCompliancePageSubscriberDialogMutation>( const [createSubscriber, isCreating] = useMutation<NewCompliancePageSubscriberDialogMutation>(
createSubscriberMutation, createSubscriberMutation,
{ {
successMessage: __("Subscriber added successfully"), successMessage: __("Subscriber added successfully"),
errorMessage: __("Failed to add subscriber"), errorToast: __("Failed to add subscriber"),
}, },
); );

View File

@@ -23,7 +23,7 @@ import { Button, Dialog, DialogContent, DialogFooter, type DialogRef, IconSend,
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import type { SendUpdateDialogMutation } from "#/__generated__/core/SendUpdateDialogMutation.graphql"; import type { SendUpdateDialogMutation } from "#/__generated__/core/SendUpdateDialogMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useMutation } from "#/lib/relay/useMutation";
import type { UpdateNode } from "./CompliancePageUpdatesList"; import type { UpdateNode } from "./CompliancePageUpdatesList";
@@ -50,9 +50,9 @@ type Props = {
export function SendUpdateDialog({ ref, update, onSent }: Props) { export function SendUpdateDialog({ ref, update, onSent }: Props) {
const { __ } = useTranslate(); const { __ } = useTranslate();
const [sendUpdate, isSending] = useMutationWithToasts<SendUpdateDialogMutation>(sendMutation, { const [sendUpdate, isSending] = useMutation<SendUpdateDialogMutation>(sendMutation, {
successMessage: __("Update enqueued for delivery"), successMessage: __("Update enqueued for delivery"),
errorMessage: __("Failed to enqueue update for delivery"), errorToast: __("Failed to enqueue update for delivery"),
}); });
const handleSend = async () => { const handleSend = async () => {

View File

@@ -25,7 +25,7 @@ import { ConnectionHandler, graphql, type PreloadedQuery, usePreloadedQuery } fr
import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql"; import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql";
import type { CompliancePageReferencesPageQuery } from "#/__generated__/core/CompliancePageReferencesPageQuery.graphql"; import type { CompliancePageReferencesPageQuery } from "#/__generated__/core/CompliancePageReferencesPageQuery.graphql";
import { TrustCenterReferenceDialog, type TrustCenterReferenceDialogRef } from "#/components/trustCenter/TrustCenterReferenceDialog"; import { CompliancePageReferenceDialog, type CompliancePageReferenceDialogRef } from "#/components/compliancePage/CompliancePageReferenceDialog";
import { CompliancePageReferenceList } from "./_components/CompliancePageReferenceList"; import { CompliancePageReferenceList } from "./_components/CompliancePageReferenceList";
@@ -36,7 +36,7 @@ export const compliancePageReferencesPageQuery = graphql`
... on Organization { ... on Organization {
compliancePage: trustCenter @required(action: THROW) { compliancePage: trustCenter @required(action: THROW) {
id id
canCreateReference: permission(action: "core:trust-center-reference:create") canCreateReference: permission(action: "compliance-portal:portal-reference:create")
...CompliancePageReferenceListFragment ...CompliancePageReferenceListFragment
} }
} }
@@ -48,7 +48,7 @@ export function CompliancePageReferencesPage(props: { queryRef: PreloadedQuery<C
const { queryRef } = props; const { queryRef } = props;
const { __ } = useTranslate(); const { __ } = useTranslate();
const dialogRef = useRef<TrustCenterReferenceDialogRef>(null); const dialogRef = useRef<CompliancePageReferenceDialogRef>(null);
const { organization } = usePreloadedQuery<CompliancePageReferencesPageQuery>( const { organization } = usePreloadedQuery<CompliancePageReferencesPageQuery>(
compliancePageReferencesPageQuery, compliancePageReferencesPageQuery,
@@ -94,7 +94,7 @@ export function CompliancePageReferencesPage(props: { queryRef: PreloadedQuery<C
<CompliancePageReferenceList fragmentRef={organization.compliancePage} onEdit={handleEdit} /> <CompliancePageReferenceList fragmentRef={organization.compliancePage} onEdit={handleEdit} />
<TrustCenterReferenceDialog ref={dialogRef} /> <CompliancePageReferenceDialog ref={dialogRef} />
</div> </div>
)} )}
</div> </div>

View File

@@ -27,7 +27,7 @@ import { graphql } from "relay-runtime";
import type { CompliancePageReferenceListFragment$key } from "#/__generated__/core/CompliancePageReferenceListFragment.graphql"; import type { CompliancePageReferenceListFragment$key } from "#/__generated__/core/CompliancePageReferenceListFragment.graphql";
import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql"; import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql";
import type { CompliancePageReferenceListQuery } from "#/__generated__/core/CompliancePageReferenceListQuery.graphql"; import type { CompliancePageReferenceListQuery } from "#/__generated__/core/CompliancePageReferenceListQuery.graphql";
import { useUpdateTrustCenterReferenceRankMutation } from "#/hooks/graph/TrustCenterReferenceGraph"; import { useUpdateCompliancePageReferenceRankMutation } from "#/hooks/graph/CompliancePageReferenceGraph";
import { CompliancePageReferenceListItem } from "./CompliancePageReferenceListItem"; import { CompliancePageReferenceListItem } from "./CompliancePageReferenceListItem";
@@ -65,7 +65,7 @@ export function CompliancePageReferenceList(props: {
CompliancePageReferenceListQuery, CompliancePageReferenceListQuery,
CompliancePageReferenceListFragment$key CompliancePageReferenceListFragment$key
>(fragment, fragmentRef); >(fragment, fragmentRef);
const [updateRank] = useUpdateTrustCenterReferenceRankMutation(); const [updateRank] = useUpdateCompliancePageReferenceRankMutation();
const [draggedIndex, setDraggedIndex] = useState<number | null>(null); const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null); const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);

View File

@@ -25,7 +25,7 @@ import { useFragment } from "react-relay";
import { type DataID, graphql } from "relay-runtime"; import { type DataID, graphql } from "relay-runtime";
import type { CompliancePageReferenceListItemFragment$data, CompliancePageReferenceListItemFragment$key } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql"; import type { CompliancePageReferenceListItemFragment$data, CompliancePageReferenceListItemFragment$key } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql";
import { DeleteTrustCenterReferenceDialog } from "#/components/trustCenter/DeleteTrustCenterReferenceDialog"; import { DeleteCompliancePageReferenceDialog } from "#/components/compliancePage/DeleteCompliancePageReferenceDialog";
const fragment = graphql` const fragment = graphql`
fragment CompliancePageReferenceListItemFragment on TrustCenterReference { fragment CompliancePageReferenceListItemFragment on TrustCenterReference {
@@ -36,8 +36,8 @@ const fragment = graphql`
name name
description description
websiteUrl websiteUrl
canUpdate: permission(action: "core:trust-center-reference:update") canUpdate: permission(action: "compliance-portal:portal-reference:update")
canDelete: permission(action: "core:trust-center-reference:delete") canDelete: permission(action: "compliance-portal:portal-reference:delete")
} }
`; `;
@@ -109,13 +109,13 @@ export function CompliancePageReferenceListItem(props: {
<Button variant="secondary" icon={IconPencil} onClick={() => onEdit(reference)} /> <Button variant="secondary" icon={IconPencil} onClick={() => onEdit(reference)} />
)} )}
{reference.canDelete && ( {reference.canDelete && (
<DeleteTrustCenterReferenceDialog <DeleteCompliancePageReferenceDialog
referenceId={reference.id} referenceId={reference.id}
referenceName={reference.name} referenceName={reference.name}
connectionId={connectionId} connectionId={connectionId}
> >
<Button variant="danger" icon={IconTrashCan} /> <Button variant="danger" icon={IconTrashCan} />
</DeleteTrustCenterReferenceDialog> </DeleteCompliancePageReferenceDialog>
)} )}
</div> </div>
</Td> </Td>

View File

@@ -25,15 +25,15 @@ import { graphql } from "relay-runtime";
import type { CompliancePageThirdPartyListItem_thirdPartyFragment$key } from "#/__generated__/core/CompliancePageThirdPartyListItem_thirdPartyFragment.graphql"; import type { CompliancePageThirdPartyListItem_thirdPartyFragment$key } from "#/__generated__/core/CompliancePageThirdPartyListItem_thirdPartyFragment.graphql";
import type { CompliancePageThirdPartyListItemMutation } from "#/__generated__/core/CompliancePageThirdPartyListItemMutation.graphql"; import type { CompliancePageThirdPartyListItemMutation } from "#/__generated__/core/CompliancePageThirdPartyListItemMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId"; import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
const thirdPartyFragment = graphql` const thirdPartyFragment = graphql`
fragment CompliancePageThirdPartyListItem_thirdPartyFragment on ThirdParty { fragment CompliancePageThirdPartyListItem_thirdPartyFragment on ThirdParty {
id id
category category
name name
showOnTrustCenter showOnCompliancePage: showOnTrustCenter
canUpdate: permission(action: "core:thirdParty:update") canUpdate: permission(action: "core:thirdParty:update")
} }
`; `;
@@ -62,13 +62,13 @@ export function CompliancePageThirdPartyListItem(props: {
thirdPartyFragment, thirdPartyFragment,
thirdPartyFragmentRef, thirdPartyFragmentRef,
); );
const [updateThirdPartyVisibility, isUpadtingThirdPartyVisibility] = useMutationWithToasts< const [updateThirdPartyVisibility, isUpadtingThirdPartyVisibility] = useMutation<
CompliancePageThirdPartyListItemMutation CompliancePageThirdPartyListItemMutation
>( >(
updateThirdPartyVisibilityMutation, updateThirdPartyVisibilityMutation,
{ {
successMessage: __("Subprocessor visibility updated successfully."), successMessage: __("Subprocessor visibility updated successfully."),
errorMessage: __("Failed to update subprocessor visibility"), errorToast: __("Failed to update subprocessor visibility"),
}, },
); );
@@ -81,8 +81,8 @@ export function CompliancePageThirdPartyListItem(props: {
<Badge variant="neutral">{thirdParty.category}</Badge> <Badge variant="neutral">{thirdParty.category}</Badge>
</Td> </Td>
<Td> <Td>
<Badge variant={thirdParty.showOnTrustCenter ? "success" : "danger"}> <Badge variant={thirdParty.showOnCompliancePage ? "success" : "danger"}>
{thirdParty.showOnTrustCenter ? __("Visible") : __("None")} {thirdParty.showOnCompliancePage ? __("Visible") : __("None")}
</Badge> </Badge>
</Td> </Td>
<Td noLink width={100} className="text-end"> <Td noLink width={100} className="text-end">
@@ -94,14 +94,14 @@ export function CompliancePageThirdPartyListItem(props: {
variables: { variables: {
input: { input: {
id: thirdParty.id, id: thirdParty.id,
showOnTrustCenter: !thirdParty.showOnTrustCenter, showOnTrustCenter: !thirdParty.showOnCompliancePage,
}, },
}, },
})} })}
icon={thirdParty.showOnTrustCenter ? IconCrossLargeX : IconCheckmark1} icon={thirdParty.showOnCompliancePage ? IconCrossLargeX : IconCheckmark1}
disabled={isUpadtingThirdPartyVisibility} disabled={isUpadtingThirdPartyVisibility}
> >
{thirdParty.showOnTrustCenter ? __("Hide") : __("Show")} {thirdParty.showOnCompliancePage ? __("Hide") : __("Show")}
</Button> </Button>
)} )}
</Td> </Td>

View File

@@ -86,8 +86,13 @@ export {
getTrustCenterVisibilityVariant, getTrustCenterVisibilityVariant,
getTrustCenterVisibilityLabel, getTrustCenterVisibilityLabel,
getTrustCenterVisibilityOptions, getTrustCenterVisibilityOptions,
getTrustCenterVisibilityVariant as getCompliancePageVisibilityVariant,
getTrustCenterVisibilityLabel as getCompliancePageVisibilityLabel,
getTrustCenterVisibilityOptions as getCompliancePageVisibilityOptions,
trustCenterVisibilities, trustCenterVisibilities,
trustCenterVisibilities as compliancePageVisibilities,
type TrustCenterVisibility, type TrustCenterVisibility,
type TrustCenterVisibility as CompliancePageVisibility,
} from "./trustCenterVisibility"; } from "./trustCenterVisibility";
export { promisifyMutation } from "./relay"; export { promisifyMutation } from "./relay";
export { fileType, fileSize } from "./file"; export { fileType, fileSize } from "./file";
@@ -123,7 +128,10 @@ export { Role, roles, getAssignableRoles } from "./roles";
export { export {
getTrustCenterDocumentAccessStatusBadgeVariant, getTrustCenterDocumentAccessStatusBadgeVariant,
getTrustCenterDocumentAccessStatusLabel, getTrustCenterDocumentAccessStatusLabel,
getTrustCenterDocumentAccessStatusBadgeVariant as getCompliancePageDocumentAccessStatusBadgeVariant,
getTrustCenterDocumentAccessStatusLabel as getCompliancePageDocumentAccessStatusLabel,
type TrustCenterDocumentAccessInfo, type TrustCenterDocumentAccessInfo,
type TrustCenterDocumentAccessInfo as CompliancePageDocumentAccessInfo,
} from "./trustCenterDocumentAccess"; } from "./trustCenterDocumentAccess";
export { export {
getRightsRequestTypeLabel, getRightsRequestTypeLabel,