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 {
useCreateTrustCenterReferenceMutation,
useUpdateTrustCenterReferenceMutation,
} from "#/hooks/graph/TrustCenterReferenceGraph";
useCreateCompliancePageReferenceMutation,
useUpdateCompliancePageReferenceMutation,
} from "#/hooks/graph/CompliancePageReferenceGraph";
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
const referenceSchema = z.object({
@@ -50,23 +50,23 @@ const referenceSchema = z.object({
type ReferenceFormData = z.infer<typeof referenceSchema>;
export type TrustCenterReferenceDialogRef = {
openCreate: (trustCenterId: string, connectionId: string) => void;
export type CompliancePageReferenceDialogRef = {
openCreate: (compliancePageId: string, connectionId: string) => void;
openEdit: (reference: CompliancePageReferenceListItemFragment$data, rank: number) => void;
};
export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogRef, { children?: ReactNode }>(
function TrustCenterReferenceDialog({ children }, ref) {
export const CompliancePageReferenceDialog = forwardRef<CompliancePageReferenceDialogRef, { children?: ReactNode }>(
function CompliancePageReferenceDialog({ children }, ref) {
const { __ } = useTranslate();
const dialogRef = useDialogRef();
const [mode, setMode] = useState<"create" | "edit">("create");
const [trustCenterId, setTrustCenterId] = useState<string>("");
const [compliancePageId, setCompliancePageId] = useState<string>("");
const [connectionId, setConnectionId] = useState<string>("");
const [editReference, setEditReference] = useState<CompliancePageReferenceListItemFragment$data | null>(null);
const [uploadedFile, setUploadedFile] = useState<File | null>(null);
const [createReference, isCreating] = useCreateTrustCenterReferenceMutation();
const [updateReference, isUpdating] = useUpdateTrustCenterReferenceMutation();
const [createReference, isCreating] = useCreateCompliancePageReferenceMutation();
const [updateReference, isUpdating] = useUpdateCompliancePageReferenceMutation();
const { register, handleSubmit, formState: { errors }, reset } = useFormWithSchema(
referenceSchema,
@@ -80,9 +80,9 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
);
useImperativeHandle(ref, () => ({
openCreate: (tId: string, cId: string) => {
openCreate: (pageId: string, cId: string) => {
setMode("create");
setTrustCenterId(tId);
setCompliancePageId(pageId);
setConnectionId(cId);
setEditReference(null);
setUploadedFile(null);
@@ -123,7 +123,7 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
await createReference({
variables: {
input: {
trustCenterId,
trustCenterId: compliancePageId,
name: data.name,
description: data.description || null,
websiteUrl: data.websiteUrl,
@@ -134,12 +134,11 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
uploadables: {
"input.logoFile": uploadedFile,
},
onSuccess: () => {
reset();
setUploadedFile(null);
dialogRef.current?.close();
},
});
reset();
setUploadedFile(null);
dialogRef.current?.close();
} else if (editReference) {
const input: {
id: string;
@@ -169,12 +168,11 @@ export const TrustCenterReferenceDialog = forwardRef<TrustCenterReferenceDialogR
await updateReference({
variables: { input },
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,
} from "@probo/ui";
import { deleteTrustCenterReferenceMutation } from "#/hooks/graph/TrustCenterReferenceGraph";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import type { CompliancePageReferenceGraphDeleteMutation } from "#/__generated__/core/CompliancePageReferenceGraphDeleteMutation.graphql";
import { deleteCompliancePageReferenceMutation } from "#/hooks/graph/CompliancePageReferenceGraph";
import { useMutation } from "#/lib/relay/useMutation";
type Props = {
children: React.ReactNode;
@@ -41,7 +42,7 @@ type Props = {
onSuccess?: () => void;
};
export function DeleteTrustCenterReferenceDialog({
export function DeleteCompliancePageReferenceDialog({
children,
referenceId,
referenceName,
@@ -51,10 +52,13 @@ export function DeleteTrustCenterReferenceDialog({
const { __ } = useTranslate();
const ref = useDialogRef();
const [mutate, isDeleting] = useMutationWithToasts(deleteTrustCenterReferenceMutation, {
successMessage: __("Reference deleted successfully"),
errorMessage: __("Failed to delete reference"),
});
const [mutate, isDeleting] = useMutation<CompliancePageReferenceGraphDeleteMutation>(
deleteCompliancePageReferenceMutation,
{
successMessage: __("Reference deleted successfully"),
errorToast: __("Failed to delete reference"),
},
);
const handleDelete = async () => {
await mutate({

View File

@@ -20,34 +20,40 @@
import { graphql } from "relay-runtime";
import type { TrustCenterGraphUpdateMutation } from "#/__generated__/core/TrustCenterGraphUpdateMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import type { CompliancePageGraphDeleteNDAMutation } from "#/__generated__/core/CompliancePageGraphDeleteNDAMutation.graphql";
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`
mutation TrustCenterGraphUpdateMutation($input: UpdateTrustCenterInput!) {
const updateCompliancePageMutation = graphql`
mutation CompliancePageGraphUpdateMutation($input: UpdateTrustCenterInput!) {
updateTrustCenter(input: $input) {
trustCenter {
id
active
searchEngineIndexing
description
websiteUrl
email
headquarterAddress
updatedAt
}
}
}
`;
export function useUpdateTrustCenterMutation() {
return useMutationWithToasts<TrustCenterGraphUpdateMutation>(
updateTrustCenterMutation,
export function useUpdateCompliancePageMutation() {
return useMutation<CompliancePageGraphUpdateMutation>(
updateCompliancePageMutation,
{
successMessage: "Compliance Page updated successfully",
errorMessage: "Failed to update compliance page",
errorToast: "Failed to update compliance page",
},
);
}
const uploadTrustCenterNDAMutation = graphql`
mutation TrustCenterGraphUploadNDAMutation(
const uploadCompliancePageNDAMutation = graphql`
mutation CompliancePageGraphUploadNDAMutation(
$input: UploadTrustCenterNDAInput!
) {
uploadTrustCenterNDA(input: $input) {
@@ -63,15 +69,15 @@ const uploadTrustCenterNDAMutation = graphql`
}
`;
export function useUploadTrustCenterNDAMutation() {
return useMutationWithToasts(uploadTrustCenterNDAMutation, {
export function useUploadCompliancePageNDAMutation() {
return useMutation<CompliancePageGraphUploadNDAMutation>(uploadCompliancePageNDAMutation, {
successMessage: "NDA uploaded successfully",
errorMessage: "Failed to upload NDA",
errorToast: "Failed to upload NDA",
});
}
const deleteTrustCenterNDAMutation = graphql`
mutation TrustCenterGraphDeleteNDAMutation(
const deleteCompliancePageNDAMutation = graphql`
mutation CompliancePageGraphDeleteNDAMutation(
$input: DeleteTrustCenterNDAInput!
) {
deleteTrustCenterNDA(input: $input) {
@@ -87,9 +93,9 @@ const deleteTrustCenterNDAMutation = graphql`
}
`;
export function useDeleteTrustCenterNDAMutation() {
return useMutationWithToasts(deleteTrustCenterNDAMutation, {
export function useDeleteCompliancePageNDAMutation() {
return useMutation<CompliancePageGraphDeleteNDAMutation>(deleteCompliancePageNDAMutation, {
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"
)
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")
canUpdateOrganization: permission(action: "iam:organization:update")
canListStatementsOfApplicability: permission(
@@ -212,7 +212,7 @@ export function Sidebar(props: { fKey: SidebarFragment$key }) {
to={`${prefix}/access-reviews`}
/>
)}
{organization.canGetTrustCenter && (
{organization.canGetCompliancePage && (
<SidebarItem
label={__("Compliance Page")}
icon={IconShield}

View File

@@ -31,7 +31,6 @@ import {
IconTrashCan,
Label,
Spinner,
Textarea,
useDialogRef,
} from "@probo/ui";
import { type ChangeEventHandler, useState } from "react";
@@ -53,10 +52,6 @@ const fragment = graphql`
horizontalLogo {
downloadUrl
}
description
websiteUrl
email
headquarterAddress
canUpdate: permission(action: "iam:organization:update")
}
`;
@@ -73,10 +68,6 @@ const updateOrganizationMutation = graphql`
horizontalLogo {
downloadUrl
}
description
websiteUrl
email
headquarterAddress
}
}
}
@@ -99,10 +90,6 @@ const deleteHorizontalLogoMutation = graphql`
const organizationSchema = z.object({
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>;
@@ -140,10 +127,6 @@ export function OrganizationForm(props: {
{
defaultValues: {
name: organization.name,
description: organization.description || "",
websiteUrl: organization.websiteUrl || "",
email: organization.email || "",
headquarterAddress: organization.headquarterAddress || "",
},
},
);
@@ -221,10 +204,6 @@ export function OrganizationForm(props: {
input: {
organizationId: organization.id,
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")}
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 && (
<div className="flex justify-end pt-6">

View File

@@ -23,7 +23,9 @@ import { Field } from "@probo/ui";
import { useCallback, useState } from "react";
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`
mutation CompliancePageAliasField_setResourceAliasMutation(
@@ -65,18 +67,18 @@ export function CompliancePageAliasField(props: {
setValue(alias ?? "");
}
const [setResourceAlias, isSettingAlias] = useMutationWithToasts(
const [setResourceAlias, isSettingAlias] = useMutation<CompliancePageAliasField_setResourceAliasMutation>(
setResourceAliasMutation,
{
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,
{
successMessage: __("Alias removed successfully."),
errorMessage: __("Failed to remove alias"),
errorToast: __("Failed to remove alias"),
},
);
@@ -117,7 +119,7 @@ export function CompliancePageAliasField(props: {
},
});
} catch {
// useMutationWithToasts already shows an error toast.
// useMutation already shows an error toast.
}
}, [alias, canRemoveAlias, canSetAlias, removeResourceAlias, resourceId, setResourceAlias, value]);

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import { formatDate, getAuditStateLabel, getAuditStateVariant, getTrustCenterVisibilityOptions } from "@probo/helpers";
import { formatDate, getAuditStateLabel, getAuditStateVariant, getCompliancePageVisibilityOptions } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { Badge, Field, Option, Td, Tr } from "@probo/ui";
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_compliancePageFragment$key } from "#/__generated__/core/CompliancePageAuditListItem_compliancePageFragment.graphql";
import type { CompliancePageAuditListItem_updateAuditVisibilityMutation } from "#/__generated__/core/CompliancePageAuditListItem_updateAuditVisibilityMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
const compliancePageFragment = graphql`
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
state
trustCenterVisibility
compliancePageVisibility: trustCenterVisibility
}
`;
@@ -75,13 +75,13 @@ export function CompliancePageAuditListItem(props: {
);
const audit = useFragment<CompliancePageAuditListItem_auditFragment$key>(auditFragment, auditFragmentRef);
const [updateAuditVisibility, isUpdatingAuditVisibility] = useMutationWithToasts<
const [updateAuditVisibility, isUpdatingAuditVisibility] = useMutation<
CompliancePageAuditListItem_updateAuditVisibilityMutation
>(
updateAuditVisibilityMutation,
{
successMessage: __("Audit visibility updated successfully."),
errorMessage: __("Failed to update audit visibility"),
errorToast: __("Failed to update audit visibility"),
},
);
const handleVisibilityChange = useCallback(
@@ -100,7 +100,7 @@ export function CompliancePageAuditListItem(props: {
[audit.id, updateAuditVisibility],
);
const visibilityOptions = getTrustCenterVisibilityOptions(__);
const visibilityOptions = getCompliancePageVisibilityOptions(__);
const validUntilFormatted = audit.validUntil
? formatDate(audit.validUntil)
: __("No expiry");
@@ -120,7 +120,7 @@ export function CompliancePageAuditListItem(props: {
<Td noLink width={130} className="pr-0">
<Field
type="select"
value={audit.trustCenterVisibility}
value={audit.compliancePageVisibility}
onValueChange={value => void handleVisibilityChange(value)}
disabled={isUpdatingAuditVisibility || !compliancePage.canUpdate}
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
// SOFTWARE.
import { getTrustCenterVisibilityOptions } from "@probo/helpers";
import { getCompliancePageVisibilityOptions } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { Badge, DocumentTypeBadge, Field, Option, Td, Tr } from "@probo/ui";
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_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 { useMutation } from "#/lib/relay/useMutation";
import { CompliancePageAliasField } from "../../_components/CompliancePageAliasField";
const compliancePageFragment = graphql`
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
canSetAlias: permission(action: "resourcealias:alias:set")
canRemoveAlias: permission(action: "resourcealias:alias:remove")
trustCenterVisibility
compliancePageVisibility: trustCenterVisibility
latestPublishedVersion: versions(
first: 1
orderBy: { field: CREATED_AT, direction: DESC }
@@ -80,7 +81,7 @@ export function CompliancePageDocumentListItem(props: {
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const visibilityOptions = getTrustCenterVisibilityOptions(__);
const visibilityOptions = getCompliancePageVisibilityOptions(__);
const compliancePage = useFragment<CompliancePageDocumentListItem_compliancePageFragment$key>(
compliancePageFragment,
@@ -90,13 +91,14 @@ export function CompliancePageDocumentListItem(props: {
documentFragment,
documentFragmentRef,
);
const [updateDocumentVisibility, isUpdatingDocumentVisibility] = useMutationWithToasts(
updateDocumentVisibilityMutation,
{
successMessage: __("Document visibility updated successfully."),
errorMessage: __("Failed to update document visibility"),
},
);
const [updateDocumentVisibility, isUpdatingDocumentVisibility]
= useMutation<CompliancePageDocumentListItem_updateVisibilityMutation>(
updateDocumentVisibilityMutation,
{
successMessage: __("Document visibility updated successfully."),
errorToast: __("Failed to update document visibility"),
},
);
const handleVsibilityChange = useCallback(
async (value: string) => {
const stringValue = typeof value === "string" ? value : "";
@@ -135,7 +137,7 @@ export function CompliancePageDocumentListItem(props: {
<Td noLink width={130} className="pr-0">
<Field
type="select"
value={document.trustCenterVisibility}
value={document.compliancePageVisibility}
onValueChange={value => void handleVsibilityChange(value)}
disabled={isUpdatingDocumentVisibility || !compliancePage.canUpdate}
className="w-[105px]"

View File

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

View File

@@ -36,8 +36,8 @@ const fragment = graphql`
compliancePage: trustCenter @required(action: THROW) {
...CompliancePageFileListItem_compliancePageFragment
}
trustCenterFiles(first: 100)
@connection(key: "CompliancePageFileList_trustCenterFiles") {
compliancePageFiles: trustCenterFiles(first: 100)
@connection(key: "CompliancePageFileList_compliancePageFiles") {
__id
edges {
node {
@@ -57,7 +57,7 @@ export function CompliancePageFileList(props: { fragmentRef: CompliancePageFileL
const {
compliancePage,
trustCenterFiles: files,
compliancePageFiles: files,
} = useFragment<CompliancePageFileListFragment$key>(fragment, fragmentRef);
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
// SOFTWARE.
import { formatDate, getTrustCenterVisibilityOptions } from "@probo/helpers";
import { formatDate, getCompliancePageVisibilityOptions } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { Badge, Button, Field, IconArrowLink, IconPencil, IconTrashCan, Option, Td, Tr } from "@probo/ui";
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_fileFragment$data, CompliancePageFileListItem_fileFragment$key } from "#/__generated__/core/CompliancePageFileListItem_fileFragment.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";
const compliancePageFragment = graphql`
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 {
downloadUrl
}
trustCenterVisibility
compliancePageVisibility: trustCenterVisibility
createdAt
canUpdate: permission(action: "core:trust-center-file:update")
canDelete: permission(action: "core:trust-center-file:delete")
canUpdate: permission(action: "compliance-portal:portal-file:update")
canDelete: permission(action: "compliance-portal:portal-file:delete")
}
`;
@@ -75,7 +75,7 @@ export function CompliancePageFileListItem(props: {
const { compliancePageFragmentRef, fileFragmentRef, onEdit, onDelete } = props;
const { __ } = useTranslate();
const visibilityOptions = getTrustCenterVisibilityOptions(__);
const visibilityOptions = getCompliancePageVisibilityOptions(__);
const compliancePage = useFragment<CompliancePageFileListItem_compliancePageFragment$key>(
compliancePageFragment,
@@ -83,11 +83,11 @@ export function CompliancePageFileListItem(props: {
);
const file = useFragment<CompliancePageFileListItem_fileFragment$key>(fileFragment, fileFragmentRef);
const [updateFile, isUpdating] = useMutationWithToasts<CompliancePageFileListItemMutation>(
const [updateFile, isUpdating] = useMutation<CompliancePageFileListItemMutation>(
updateCompliancePageFileMutation,
{
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">
<Field
type="select"
value={file.trustCenterVisibility}
value={file.compliancePageVisibility}
onValueChange={value => void handleValueChange(value)}
disabled={isUpdating || !compliancePage.canUpdate}
className="w-[105px]"

View File

@@ -24,7 +24,7 @@ import { useCallback } from "react";
import { type DataID, graphql } from "relay-runtime";
import type { DeleteCompliancePageFileDialogMutation } from "#/__generated__/core/DeleteCompliancePageFileDialogMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
const deleteCompliancePageFileMutation = graphql`
mutation DeleteCompliancePageFileDialogMutation(
@@ -47,11 +47,11 @@ export function DeleteCompliancePageFileDialog(props: {
const { __ } = useTranslate();
const [deleteFile, isDeleting] = useMutationWithToasts<DeleteCompliancePageFileDialogMutation>(
const [deleteFile, isDeleting] = useMutation<DeleteCompliancePageFileDialogMutation>(
deleteCompliancePageFileMutation,
{
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 },
connections: connectionId ? [connectionId] : [],
},
onSuccess: () => {
ref.current?.close();
onDelete();
},
});
ref.current?.close();
onDelete();
}, [fileId, deleteFile, ref, connectionId, onDelete]);
return (

View File

@@ -26,7 +26,7 @@ import { z } from "zod";
import type { CompliancePageFileListItem_fileFragment$data } from "#/__generated__/core/CompliancePageFileListItem_fileFragment.graphql";
import type { EditCompliancePageFileDialogMutation } from "#/__generated__/core/EditCompliancePageFileDialogMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
const updateCompliancePageFileMutation = graphql`
mutation EditCompliancePageFileDialogMutation($input: UpdateTrustCenterFileInput!) {
@@ -54,11 +54,11 @@ export function EditCompliancePageFileDialog(props: {
defaultValues: { name: file.name, category: file.category },
});
const [updateFile, isUpdating] = useMutationWithToasts<EditCompliancePageFileDialogMutation>(
const [updateFile, isUpdating] = useMutation<EditCompliancePageFileDialogMutation>(
updateCompliancePageFileMutation,
{
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,
},
},
onSuccess: () => {
onClose();
},
});
onClose();
};
return (

View File

@@ -25,7 +25,7 @@ import {
acceptPresentation,
acceptSpreadsheet,
acceptText,
getTrustCenterVisibilityOptions,
getCompliancePageVisibilityOptions,
} from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
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 { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
const acceptedFileTypes = {
...acceptDocument,
@@ -76,10 +76,10 @@ export function NewCompliancePageFileDialog(props: {
const createSchema = z.object({
name: z.string().min(1, __("Name 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, {
defaultValues: { name: "", category: "", trustCenterVisibility: "NONE" },
defaultValues: { name: "", category: "", compliancePageVisibility: "NONE" },
});
const handleFileUpload = useCallback(
@@ -105,10 +105,10 @@ export function NewCompliancePageFileDialog(props: {
[createForm, __],
);
const [createFile, isCreating] = useMutationWithToasts<NewCompliancePageFileDialog_createMutation>(
const [createFile, isCreating] = useMutation<NewCompliancePageFileDialog_createMutation>(
createCompliancePageFileMutation, {
successMessage: "File uploaded successfully",
errorMessage: "Failed to upload file",
errorToast: "Failed to upload file",
},
);
const handleCreate = async (data: z.infer<typeof createSchema>) => {
@@ -122,7 +122,7 @@ export function NewCompliancePageFileDialog(props: {
organizationId,
name: data.name,
category: data.category,
trustCenterVisibility: data.trustCenterVisibility,
trustCenterVisibility: data.compliancePageVisibility,
file: null,
},
connections: connectionId ? [connectionId] : [],
@@ -130,12 +130,11 @@ export function NewCompliancePageFileDialog(props: {
uploadables: {
"input.file": uploadedFile,
},
onSuccess: () => {
ref.current?.close();
createForm.reset();
setUploadedFile(null);
},
});
ref.current?.close();
createForm.reset();
setUploadedFile(null);
};
return (
@@ -176,15 +175,15 @@ export function NewCompliancePageFileDialog(props: {
<Field
label={__("Visibility")}
type="select"
value={createForm.watch("trustCenterVisibility")}
value={createForm.watch("compliancePageVisibility")}
onValueChange={value =>
createForm.setValue(
"trustCenterVisibility",
"compliancePageVisibility",
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}>
<div className="flex items-center justify-between w-full">
<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 { CompliancePageMailingListPageQuery } from "#/__generated__/core/CompliancePageMailingListPageQuery.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
import { CompliancePageMailingList } from "./_components/CompliancePageMailingList";
import { CompliancePageUpdatesList, type UpdateNode } from "./_components/CompliancePageUpdatesList";
@@ -101,11 +101,11 @@ export function CompliancePageMailingListPage(props: {
const [replyTo, setReplyTo] = useState(mailingList?.replyTo ?? "");
const [updateMailingList, isUpdating]
= useMutationWithToasts<CompliancePageMailingListPage_updateMailingListMutation>(
= useMutation<CompliancePageMailingListPage_updateMailingListMutation>(
updateMailingListMutation,
{
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 { CompliancePageMailingListFragment$key } from "#/__generated__/core/CompliancePageMailingListFragment.graphql";
import type { CompliancePageMailingListQuery } from "#/__generated__/core/CompliancePageMailingListQuery.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
const deleteMutation = graphql`
mutation CompliancePageMailingListDeleteMutation(
@@ -89,11 +89,11 @@ export function CompliancePageMailingList(props: {
const subscribers = data.mailingList?.subscribers;
const [deleteSubscriber, isDeleting] = useMutationWithToasts<CompliancePageMailingListDeleteMutation>(
const [deleteSubscriber, isDeleting] = useMutation<CompliancePageMailingListDeleteMutation>(
deleteMutation,
{
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 { CompliancePageUpdatesListFragment$data, CompliancePageUpdatesListFragment$key } from "#/__generated__/core/CompliancePageUpdatesListFragment.graphql";
import type { CompliancePageUpdatesListQuery } from "#/__generated__/core/CompliancePageUpdatesListQuery.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
import { SendUpdateDialog } from "./SendUpdateDialog";
@@ -92,9 +92,9 @@ export function CompliancePageUpdatesList(props: {
const connection = data.updates;
const [deleteUpdate, isDeleting]
= useMutationWithToasts<CompliancePageUpdatesListDeleteMutation>(deleteMutation, {
= useMutation<CompliancePageUpdatesListDeleteMutation>(deleteMutation, {
successMessage: __("Update deleted successfully"),
errorMessage: __("Failed to delete update"),
errorToast: __("Failed to delete update"),
});
const handleDelete = (id: string) => {

View File

@@ -27,7 +27,7 @@ import { z } from "zod";
import type { ComplianceUpdateFormDialogCreateMutation } from "#/__generated__/core/ComplianceUpdateFormDialogCreateMutation.graphql";
import type { ComplianceUpdateFormDialogUpdateMutation } from "#/__generated__/core/ComplianceUpdateFormDialogUpdateMutation.graphql";
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
import type { UpdateNode } from "./CompliancePageUpdatesList";
@@ -104,19 +104,19 @@ export function ComplianceUpdateFormDialog(props: Props) {
}
}, [update, form]);
const [createUpdate, isCreating] = useMutationWithToasts<ComplianceUpdateFormDialogCreateMutation>(
const [createUpdate, isCreating] = useMutation<ComplianceUpdateFormDialogCreateMutation>(
createMutation,
{
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,
{
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 { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
const createSubscriberMutation = graphql`
mutation NewCompliancePageSubscriberDialogMutation(
@@ -69,11 +69,11 @@ export function NewCompliancePageSubscriberDialog(props: {
defaultValues: { fullName: "", email: "", confirmed: false },
});
const [createSubscriber, isCreating] = useMutationWithToasts<NewCompliancePageSubscriberDialogMutation>(
const [createSubscriber, isCreating] = useMutation<NewCompliancePageSubscriberDialogMutation>(
createSubscriberMutation,
{
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 type { SendUpdateDialogMutation } from "#/__generated__/core/SendUpdateDialogMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useMutation } from "#/lib/relay/useMutation";
import type { UpdateNode } from "./CompliancePageUpdatesList";
@@ -50,9 +50,9 @@ type Props = {
export function SendUpdateDialog({ ref, update, onSent }: Props) {
const { __ } = useTranslate();
const [sendUpdate, isSending] = useMutationWithToasts<SendUpdateDialogMutation>(sendMutation, {
const [sendUpdate, isSending] = useMutation<SendUpdateDialogMutation>(sendMutation, {
successMessage: __("Update enqueued for delivery"),
errorMessage: __("Failed to enqueue update for delivery"),
errorToast: __("Failed to enqueue update for delivery"),
});
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 { 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";
@@ -36,7 +36,7 @@ export const compliancePageReferencesPageQuery = graphql`
... on Organization {
compliancePage: trustCenter @required(action: THROW) {
id
canCreateReference: permission(action: "core:trust-center-reference:create")
canCreateReference: permission(action: "compliance-portal:portal-reference:create")
...CompliancePageReferenceListFragment
}
}
@@ -48,7 +48,7 @@ export function CompliancePageReferencesPage(props: { queryRef: PreloadedQuery<C
const { queryRef } = props;
const { __ } = useTranslate();
const dialogRef = useRef<TrustCenterReferenceDialogRef>(null);
const dialogRef = useRef<CompliancePageReferenceDialogRef>(null);
const { organization } = usePreloadedQuery<CompliancePageReferencesPageQuery>(
compliancePageReferencesPageQuery,
@@ -94,7 +94,7 @@ export function CompliancePageReferencesPage(props: { queryRef: PreloadedQuery<C
<CompliancePageReferenceList fragmentRef={organization.compliancePage} onEdit={handleEdit} />
<TrustCenterReferenceDialog ref={dialogRef} />
<CompliancePageReferenceDialog ref={dialogRef} />
</div>
)}
</div>

View File

@@ -27,7 +27,7 @@ import { graphql } from "relay-runtime";
import type { CompliancePageReferenceListFragment$key } from "#/__generated__/core/CompliancePageReferenceListFragment.graphql";
import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.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";
@@ -65,7 +65,7 @@ export function CompliancePageReferenceList(props: {
CompliancePageReferenceListQuery,
CompliancePageReferenceListFragment$key
>(fragment, fragmentRef);
const [updateRank] = useUpdateTrustCenterReferenceRankMutation();
const [updateRank] = useUpdateCompliancePageReferenceRankMutation();
const [draggedIndex, setDraggedIndex] = 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 { CompliancePageReferenceListItemFragment$data, CompliancePageReferenceListItemFragment$key } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql";
import { DeleteTrustCenterReferenceDialog } from "#/components/trustCenter/DeleteTrustCenterReferenceDialog";
import { DeleteCompliancePageReferenceDialog } from "#/components/compliancePage/DeleteCompliancePageReferenceDialog";
const fragment = graphql`
fragment CompliancePageReferenceListItemFragment on TrustCenterReference {
@@ -36,8 +36,8 @@ const fragment = graphql`
name
description
websiteUrl
canUpdate: permission(action: "core:trust-center-reference:update")
canDelete: permission(action: "core:trust-center-reference:delete")
canUpdate: permission(action: "compliance-portal:portal-reference:update")
canDelete: permission(action: "compliance-portal:portal-reference:delete")
}
`;
@@ -109,13 +109,13 @@ export function CompliancePageReferenceListItem(props: {
<Button variant="secondary" icon={IconPencil} onClick={() => onEdit(reference)} />
)}
{reference.canDelete && (
<DeleteTrustCenterReferenceDialog
<DeleteCompliancePageReferenceDialog
referenceId={reference.id}
referenceName={reference.name}
connectionId={connectionId}
>
<Button variant="danger" icon={IconTrashCan} />
</DeleteTrustCenterReferenceDialog>
</DeleteCompliancePageReferenceDialog>
)}
</div>
</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 { CompliancePageThirdPartyListItemMutation } from "#/__generated__/core/CompliancePageThirdPartyListItemMutation.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId";
import { useMutation } from "#/lib/relay/useMutation";
const thirdPartyFragment = graphql`
fragment CompliancePageThirdPartyListItem_thirdPartyFragment on ThirdParty {
id
category
name
showOnTrustCenter
showOnCompliancePage: showOnTrustCenter
canUpdate: permission(action: "core:thirdParty:update")
}
`;
@@ -62,13 +62,13 @@ export function CompliancePageThirdPartyListItem(props: {
thirdPartyFragment,
thirdPartyFragmentRef,
);
const [updateThirdPartyVisibility, isUpadtingThirdPartyVisibility] = useMutationWithToasts<
const [updateThirdPartyVisibility, isUpadtingThirdPartyVisibility] = useMutation<
CompliancePageThirdPartyListItemMutation
>(
updateThirdPartyVisibilityMutation,
{
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>
</Td>
<Td>
<Badge variant={thirdParty.showOnTrustCenter ? "success" : "danger"}>
{thirdParty.showOnTrustCenter ? __("Visible") : __("None")}
<Badge variant={thirdParty.showOnCompliancePage ? "success" : "danger"}>
{thirdParty.showOnCompliancePage ? __("Visible") : __("None")}
</Badge>
</Td>
<Td noLink width={100} className="text-end">
@@ -94,14 +94,14 @@ export function CompliancePageThirdPartyListItem(props: {
variables: {
input: {
id: thirdParty.id,
showOnTrustCenter: !thirdParty.showOnTrustCenter,
showOnTrustCenter: !thirdParty.showOnCompliancePage,
},
},
})}
icon={thirdParty.showOnTrustCenter ? IconCrossLargeX : IconCheckmark1}
icon={thirdParty.showOnCompliancePage ? IconCrossLargeX : IconCheckmark1}
disabled={isUpadtingThirdPartyVisibility}
>
{thirdParty.showOnTrustCenter ? __("Hide") : __("Show")}
{thirdParty.showOnCompliancePage ? __("Hide") : __("Show")}
</Button>
)}
</Td>

View File

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