Harden compliance portal auth and TLS
Align console references and OAuth branding with the compliance-page model, and fix certificate cache eviction, portal OAuth handlers, and magic-link edge cases left after the trust-center rename. Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
@@ -35,11 +35,11 @@ import { forwardRef, type ReactNode, useImperativeHandle, useState } from "react
|
||||
import { z } from "zod";
|
||||
|
||||
import type { CompliancePageReferenceListItemFragment$data } from "#/__generated__/core/CompliancePageReferenceListItemFragment.graphql";
|
||||
import {
|
||||
useCreateTrustCenterReferenceMutation,
|
||||
useUpdateTrustCenterReferenceMutation,
|
||||
} from "#/hooks/graph/TrustCenterReferenceGraph";
|
||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||
import {
|
||||
useCreateCompliancePageReferenceMutation,
|
||||
useUpdateCompliancePageReferenceMutation,
|
||||
} from "#/pages/organizations/compliance-page/_lib/compliancePageReferenceMutations";
|
||||
|
||||
const referenceSchema = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
@@ -65,8 +65,8 @@ export const CompliancePageReferenceDialog = forwardRef<CompliancePageReferenceD
|
||||
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,
|
||||
|
||||
@@ -30,9 +30,9 @@ import {
|
||||
useDialogRef,
|
||||
} from "@probo/ui";
|
||||
|
||||
import type { TrustCenterReferenceGraphDeleteMutation } from "#/__generated__/core/TrustCenterReferenceGraphDeleteMutation.graphql";
|
||||
import { deleteTrustCenterReferenceMutation } from "#/hooks/graph/TrustCenterReferenceGraph";
|
||||
import type { compliancePageReferenceMutationsDeleteMutation } from "#/__generated__/core/compliancePageReferenceMutationsDeleteMutation.graphql";
|
||||
import { useMutation } from "#/lib/relay/useMutation";
|
||||
import { deleteCompliancePageReferenceMutation } from "#/pages/organizations/compliance-page/_lib/compliancePageReferenceMutations";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
@@ -52,8 +52,8 @@ export function DeleteCompliancePageReferenceDialog({
|
||||
const { __ } = useTranslate();
|
||||
const ref = useDialogRef();
|
||||
|
||||
const [mutate, isDeleting] = useMutation<TrustCenterReferenceGraphDeleteMutation>(
|
||||
deleteTrustCenterReferenceMutation,
|
||||
const [mutate, isDeleting] = useMutation<compliancePageReferenceMutationsDeleteMutation>(
|
||||
deleteCompliancePageReferenceMutation,
|
||||
{
|
||||
successMessage: __("Reference deleted successfully"),
|
||||
errorToast: __("Failed to delete reference"),
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
// 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 { 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 { useMutation } from "#/lib/relay/useMutation";
|
||||
|
||||
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: "compliance-portal:portal-reference:update")
|
||||
canDelete: permission(action: "compliance-portal:portal-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: "compliance-portal:portal-reference:update")
|
||||
canDelete: permission(action: "compliance-portal:portal-reference:delete")
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const deleteTrustCenterReferenceMutation = graphql`
|
||||
mutation TrustCenterReferenceGraphDeleteMutation(
|
||||
$input: DeleteTrustCenterReferenceInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
deleteTrustCenterReference(input: $input) {
|
||||
deletedTrustCenterReferenceId @deleteEdge(connections: $connections)
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function useCreateTrustCenterReferenceMutation() {
|
||||
return useMutation<TrustCenterReferenceGraphCreateMutation>(
|
||||
createTrustCenterReferenceMutation,
|
||||
{
|
||||
successMessage: "Reference created successfully",
|
||||
errorToast: "Failed to create reference",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function useUpdateTrustCenterReferenceMutation() {
|
||||
return useMutation<TrustCenterReferenceGraphUpdateMutation>(
|
||||
updateTrustCenterReferenceMutation,
|
||||
{
|
||||
successMessage: "Reference updated successfully",
|
||||
errorToast: "Failed to update reference",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export const updateTrustCenterReferenceRankMutation = graphql`
|
||||
mutation TrustCenterReferenceGraphUpdateRankMutation(
|
||||
$input: UpdateTrustCenterReferenceInput!
|
||||
) {
|
||||
updateTrustCenterReference(input: $input) {
|
||||
trustCenterReference {
|
||||
id
|
||||
rank
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function useUpdateTrustCenterReferenceRankMutation() {
|
||||
return useMutation<TrustCenterReferenceGraphUpdateRankMutation>(
|
||||
updateTrustCenterReferenceRankMutation,
|
||||
{
|
||||
successMessage: "Order updated successfully",
|
||||
errorToast: "Failed to update order",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function useDeleteTrustCenterReferenceMutation() {
|
||||
return useMutation<TrustCenterReferenceGraphDeleteMutation>(
|
||||
deleteTrustCenterReferenceMutation,
|
||||
{
|
||||
successMessage: "Reference deleted successfully",
|
||||
errorToast: "Failed to delete reference",
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,25 +1,29 @@
|
||||
// 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.
|
||||
// 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 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.
|
||||
// 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 { usePageTitle } from "@probo/hooks";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { Button } from "@probo/ui";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
export default function MagicLinkAlreadyUsedPage() {
|
||||
const { __ } = useTranslate();
|
||||
const navigate = useNavigate();
|
||||
|
||||
usePageTitle(__("Link Already Used"));
|
||||
|
||||
@@ -33,10 +37,7 @@ export default function MagicLinkAlreadyUsedPage() {
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full h-10"
|
||||
onClick={() => void navigate("/auth/login")}
|
||||
>
|
||||
<Button className="w-full h-10" to="/auth/login">
|
||||
{__("Sign in")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
// 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.
|
||||
// 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 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.
|
||||
// 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 { usePageTitle } from "@probo/hooks";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { Button } from "@probo/ui";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
export default function MagicLinkExpiredPage() {
|
||||
const { __ } = useTranslate();
|
||||
const navigate = useNavigate();
|
||||
|
||||
usePageTitle(__("Link Expired"));
|
||||
|
||||
@@ -33,10 +37,7 @@ export default function MagicLinkExpiredPage() {
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
className="w-full h-10"
|
||||
onClick={() => void navigate("/auth/login")}
|
||||
>
|
||||
<Button className="w-full h-10" to="/auth/login">
|
||||
{__("Sign in")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -42,9 +42,7 @@ export const signInPageQuery = graphql`
|
||||
oauthClientBranding(clientId: $clientId) {
|
||||
name
|
||||
clientURL
|
||||
logo {
|
||||
downloadUrl
|
||||
}
|
||||
logoUrl
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -85,7 +83,7 @@ export default function SignInPage(props: Props) {
|
||||
<>
|
||||
<OAuthClientBrandingSection
|
||||
name={clientBranding.name}
|
||||
logoDownloadUrl={clientBranding.logo?.downloadUrl}
|
||||
logoDownloadUrl={clientBranding.logoUrl}
|
||||
clientURL={clientBranding.clientURL}
|
||||
/>
|
||||
<div className="w-full border-t border-t-border-mid" />
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
// 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.
|
||||
// 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 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.
|
||||
// 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 { useTranslate } from "@probo/i18n";
|
||||
import { Button, Field, useToast } from "@probo/ui";
|
||||
@@ -67,12 +73,22 @@ export function MagicLinkForm() {
|
||||
body.set("email", email);
|
||||
body.set("continue", postAuthRedirectUrl);
|
||||
|
||||
const response = await fetch("/api/connect/v1/magic-link/send", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/x-www-form-urlencoded" },
|
||||
credentials: "include",
|
||||
body,
|
||||
});
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch("/api/connect/v1/magic-link/send", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/x-www-form-urlencoded" },
|
||||
credentials: "include",
|
||||
body,
|
||||
});
|
||||
} catch {
|
||||
toast({
|
||||
title: __("Error"),
|
||||
description: __("Cannot send magic link"),
|
||||
variant: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
toast({
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// 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 { compliancePageReferenceMutationsCreateMutation } from "#/__generated__/core/compliancePageReferenceMutationsCreateMutation.graphql";
|
||||
import type { compliancePageReferenceMutationsDeleteMutation } from "#/__generated__/core/compliancePageReferenceMutationsDeleteMutation.graphql";
|
||||
import type { compliancePageReferenceMutationsUpdateMutation } from "#/__generated__/core/compliancePageReferenceMutationsUpdateMutation.graphql";
|
||||
import type { compliancePageReferenceMutationsUpdateRankMutation } from "#/__generated__/core/compliancePageReferenceMutationsUpdateRankMutation.graphql";
|
||||
import { useMutation } from "#/lib/relay/useMutation";
|
||||
|
||||
export const createCompliancePageReferenceMutation = graphql`
|
||||
mutation compliancePageReferenceMutationsCreateMutation(
|
||||
$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 compliancePageReferenceMutationsUpdateMutation(
|
||||
$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 compliancePageReferenceMutationsDeleteMutation(
|
||||
$input: DeleteTrustCenterReferenceInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
deleteTrustCenterReference(input: $input) {
|
||||
deletedTrustCenterReferenceId @deleteEdge(connections: $connections)
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function useCreateCompliancePageReferenceMutation() {
|
||||
return useMutation<compliancePageReferenceMutationsCreateMutation>(
|
||||
createCompliancePageReferenceMutation,
|
||||
{
|
||||
successMessage: "Reference created successfully",
|
||||
errorToast: "Failed to create reference",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function useUpdateCompliancePageReferenceMutation() {
|
||||
return useMutation<compliancePageReferenceMutationsUpdateMutation>(
|
||||
updateCompliancePageReferenceMutation,
|
||||
{
|
||||
successMessage: "Reference updated successfully",
|
||||
errorToast: "Failed to update reference",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export const updateCompliancePageReferenceRankMutation = graphql`
|
||||
mutation compliancePageReferenceMutationsUpdateRankMutation(
|
||||
$input: UpdateTrustCenterReferenceInput!
|
||||
) {
|
||||
updateTrustCenterReference(input: $input) {
|
||||
trustCenterReference {
|
||||
id
|
||||
rank
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function useUpdateCompliancePageReferenceRankMutation() {
|
||||
return useMutation<compliancePageReferenceMutationsUpdateRankMutation>(
|
||||
updateCompliancePageReferenceRankMutation,
|
||||
{
|
||||
successMessage: "Order updated successfully",
|
||||
errorToast: "Failed to update order",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function useDeleteCompliancePageReferenceMutation() {
|
||||
return useMutation<compliancePageReferenceMutationsDeleteMutation>(
|
||||
deleteCompliancePageReferenceMutation,
|
||||
{
|
||||
successMessage: "Reference deleted successfully",
|
||||
errorToast: "Failed to delete reference",
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -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 "#/pages/organizations/compliance-page/_lib/compliancePageReferenceMutations";
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user