Fix permissions handling with react context
Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
@@ -6,7 +6,8 @@ import type { CustomDomainManagerDeleteMutation } from "./__generated__/CustomDo
|
||||
import { CreateCustomDomainDialog } from "./CreateCustomDomainDialog";
|
||||
import { DeleteCustomDomainDialog } from "./DeleteCustomDomainDialog";
|
||||
import { DomainDetailsDialog } from "./DomainDetailsDialog";
|
||||
import { Authorized } from "/permissions";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
import { use } from "react";
|
||||
|
||||
const deleteCustomDomainMutation = graphql`
|
||||
mutation CustomDomainManagerDeleteMutation($input: DeleteCustomDomainInput!) {
|
||||
@@ -45,7 +46,7 @@ export function CustomDomainManager({
|
||||
customDomain,
|
||||
}: CustomDomainManagerProps) {
|
||||
const { __ } = useTranslate();
|
||||
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const [deleteCustomDomain] =
|
||||
useMutationWithToasts<CustomDomainManagerDeleteMutation>(
|
||||
deleteCustomDomainMutation,
|
||||
@@ -107,11 +108,11 @@ export function CustomDomainManager({
|
||||
)}
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
<Authorized entity="Organization" action="createCustomDomain">
|
||||
{isAuthorized("Organization", "createCustomDomain") && (
|
||||
<CreateCustomDomainDialog organizationId={organizationId}>
|
||||
<Button icon={IconPlusLarge}>{__("Add Domain")}</Button>
|
||||
</CreateCustomDomainDialog>
|
||||
</Authorized>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -139,14 +140,14 @@ export function CustomDomainManager({
|
||||
<Button variant="secondary">{__("View Details")}</Button>
|
||||
</DomainDetailsDialog>
|
||||
|
||||
<Authorized entity="CustomDomain" action="deleteCustomDomain">
|
||||
{isAuthorized("CustomDomain", "deleteCustomDomain") && (
|
||||
<DeleteCustomDomainDialog
|
||||
domainName={domain.domain}
|
||||
onConfirm={handleDeleteDomain}
|
||||
>
|
||||
<Button variant="danger">{__("Delete")}</Button>
|
||||
</DeleteCustomDomainDialog>
|
||||
</Authorized>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,8 +17,9 @@ import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
|
||||
import { z } from "zod";
|
||||
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
||||
import { Controller } from "react-hook-form";
|
||||
import { Suspense } from "react";
|
||||
import { getAssignableRoles } from "/permissions";
|
||||
import { Suspense, use } from "react";
|
||||
import { getAssignableRoles } from "@probo/helpers";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
const inviteMutation = graphql`
|
||||
mutation InviteUserDialogMutation(
|
||||
@@ -56,7 +57,8 @@ type Props = PropsWithChildren & {
|
||||
function InviteUserDialogContent({ children, connectionId, onRefetch }: Props) {
|
||||
const { __ } = useTranslate();
|
||||
const organizationId = useOrganizationId();
|
||||
const assignableRoles = getAssignableRoles(organizationId);
|
||||
const { role: currentUserRole } = use(PermissionsContext);
|
||||
const assignableRoles = getAssignableRoles(currentUserRole);
|
||||
const [inviteUser, isInviting] = useMutationWithToasts(inviteMutation, {
|
||||
successMessage: __("Invitation sent successfully"),
|
||||
errorMessage: __("Failed to send invitation"),
|
||||
|
||||
@@ -2,7 +2,8 @@ import { Badge, Button, Card } from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { sprintf } from "@probo/helpers";
|
||||
import type { TrustCenterGraphQuery$data } from "/hooks/graph/__generated__/TrustCenterGraphQuery.graphql";
|
||||
import { Authorized } from "/permissions";
|
||||
import { use } from "react";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
type Props = {
|
||||
organizationId: string;
|
||||
@@ -11,7 +12,7 @@ type Props = {
|
||||
|
||||
export function SlackConnections({ organizationId, slackConnections: connectedSlackConnections }: Props) {
|
||||
const { __, dateTimeFormat } = useTranslate();
|
||||
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const slackConnectionDefinitions = [
|
||||
{
|
||||
id: "SLACK",
|
||||
@@ -77,11 +78,11 @@ export function SlackConnections({ organizationId, slackConnections: connectedSl
|
||||
</Badge>
|
||||
</div>
|
||||
) : (
|
||||
<Authorized entity="TrustCenter" action="updateTrustCenter">
|
||||
isAuthorized("TrustCenter", "updateTrustCenter") && (
|
||||
<Button variant="secondary" asChild>
|
||||
<a href={getUrl(slackConnection.id)}>{__("Connect")}</a>
|
||||
</Button>
|
||||
</Authorized>
|
||||
)
|
||||
)}
|
||||
</Card>
|
||||
))}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { promisifyMutation } from "@probo/helpers";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
ActionDropdown,
|
||||
Avatar,
|
||||
@@ -15,21 +18,17 @@ import {
|
||||
useConfirm,
|
||||
useDialogRef,
|
||||
} from "@probo/ui";
|
||||
import { Fragment } from "react";
|
||||
import { Fragment, use } from "react";
|
||||
import { graphql, useMutation, useRelayEnvironment } from "react-relay";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import type { ItemOf } from "/types";
|
||||
import { Link, useLocation, useParams } from "react-router";
|
||||
import type { TaskFormDialogFragment$key } from "./__generated__/TaskFormDialogFragment.graphql";
|
||||
import TaskFormDialog, {
|
||||
taskUpdateMutation,
|
||||
} from "/components/tasks/TaskFormDialog";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { Link, useLocation, useParams } from "react-router";
|
||||
import { promisifyMutation } from "@probo/helpers";
|
||||
import { Authorized } from "/permissions";
|
||||
import { isAuthorized } from "/permissions";
|
||||
import type { TaskFormDialogFragment$key } from "./__generated__/TaskFormDialogFragment.graphql";
|
||||
import { updateStoreCounter } from "/hooks/useMutationWithIncrement";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
import type { ItemOf } from "/types";
|
||||
|
||||
type Props = {
|
||||
tasks: ({
|
||||
@@ -51,7 +50,6 @@ type Props = {
|
||||
|
||||
export default function TasksCard({ tasks, connectionId }: Props) {
|
||||
const { __ } = useTranslate();
|
||||
const organizationId = useOrganizationId();
|
||||
const hash = useLocation().hash.replace("#", "");
|
||||
|
||||
const hashes = [
|
||||
@@ -70,8 +68,10 @@ export default function TasksCard({ tasks, connectionId }: Props) {
|
||||
|
||||
usePageTitle(__("Tasks"));
|
||||
|
||||
const hasAnyAction = isAuthorized(organizationId, "Task", "updateTask") ||
|
||||
isAuthorized(organizationId, "Task", "deleteTask");
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
|
||||
const hasAnyAction = isAuthorized("Task", "updateTask") ||
|
||||
isAuthorized("Task", "deleteTask");
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -151,6 +151,7 @@ function TaskRow(props: TaskRowProps) {
|
||||
const confirm = useConfirm();
|
||||
const [deleteTask] = useMutation(deleteMutation);
|
||||
const params = useParams<{ measureId?: string }>();
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
|
||||
const relayEnv = useRelayEnvironment();
|
||||
const [updateTask, isUpdating] = useMutation(taskUpdateMutation);
|
||||
@@ -232,15 +233,15 @@ function TaskRow(props: TaskRowProps) {
|
||||
)}
|
||||
{props.hasAnyAction && (
|
||||
<ActionDropdown>
|
||||
<Authorized entity="Task" action="updateTask">
|
||||
{isAuthorized("Task", "updateTask") && (
|
||||
<DropdownItem
|
||||
icon={IconPencil}
|
||||
onClick={() => dialogRef.current?.open()}
|
||||
>
|
||||
{__("Edit")}
|
||||
</DropdownItem>
|
||||
</Authorized>
|
||||
<Authorized entity="Task" action="deleteTask">
|
||||
)}
|
||||
{isAuthorized("Task", "deleteTask") && (
|
||||
<DropdownItem
|
||||
variant="danger"
|
||||
icon={IconTrashCan}
|
||||
@@ -248,7 +249,7 @@ function TaskRow(props: TaskRowProps) {
|
||||
>
|
||||
{__("Delete")}
|
||||
</DropdownItem>
|
||||
</Authorized>
|
||||
)}
|
||||
</ActionDropdown>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -14,11 +14,11 @@ import {
|
||||
} from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { useFragment } from "react-relay";
|
||||
import { useMemo, useState, useCallback, useEffect } from "react";
|
||||
import { useMemo, useState, useCallback, useEffect, use } from "react";
|
||||
import { sprintf, getAuditStateVariant, getAuditStateLabel, formatDate, getTrustCenterVisibilityOptions } from "@probo/helpers";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import type { TrustCenterAuditsCardFragment$key } from "./__generated__/TrustCenterAuditsCardFragment.graphql";
|
||||
import { isAuthorized } from "/permissions";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
const trustCenterAuditFragment = graphql`
|
||||
fragment TrustCenterAuditsCardFragment on Audit {
|
||||
@@ -124,8 +124,8 @@ function AuditRow(props: {
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
const [optimisticValue, setOptimisticValue] = useState<string | null>(null);
|
||||
|
||||
const canUpdate = organizationId ? isAuthorized(organizationId, "TrustCenter", "updateTrustCenter") : false;
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const canUpdate = organizationId ? isAuthorized("TrustCenter", "updateTrustCenter") : false;
|
||||
|
||||
const handleValueChange = useCallback((value: string | {}) => {
|
||||
const stringValue = typeof value === 'string' ? value : '';
|
||||
|
||||
@@ -17,10 +17,10 @@ import {
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import type { TrustCenterDocumentsCardFragment$key } from "./__generated__/TrustCenterDocumentsCardFragment.graphql";
|
||||
import { useFragment } from "react-relay";
|
||||
import { useMemo, useState, useCallback, useEffect } from "react";
|
||||
import { useMemo, useState, useCallback, useEffect, use } from "react";
|
||||
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { isAuthorized } from "/permissions";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
const trustCenterDocumentFragment = graphql`
|
||||
fragment TrustCenterDocumentsCardFragment on Document {
|
||||
@@ -129,8 +129,8 @@ function DocumentRow(props: {
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
const [optimisticValue, setOptimisticValue] = useState<string | null>(null);
|
||||
|
||||
const canUpdate = organizationId ? isAuthorized(organizationId, "TrustCenter", "updateTrustCenter") : false;
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const canUpdate = isAuthorized("TrustCenter", "updateTrustCenter");
|
||||
|
||||
const handleValueChange = useCallback((value: string | {}) => {
|
||||
const stringValue = typeof value === 'string' ? value : '';
|
||||
|
||||
@@ -18,12 +18,10 @@ import {
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import type { TrustCenterFilesCardFragment$key, TrustCenterFilesCardFragment$data } from "./__generated__/TrustCenterFilesCardFragment.graphql";
|
||||
import { useFragment } from "react-relay";
|
||||
import { useMemo, useState, useCallback, useEffect } from "react";
|
||||
import { useMemo, useState, useCallback, useEffect, use } from "react";
|
||||
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
|
||||
import { formatDate } from "@probo/helpers";
|
||||
import { Authorized } from "/permissions";
|
||||
import { isAuthorized } from "/permissions";
|
||||
import { useParams } from "react-router";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
const trustCenterFileFragment = graphql`
|
||||
fragment TrustCenterFilesCardFragment on TrustCenterFile {
|
||||
@@ -150,9 +148,8 @@ function FileRow(props: {
|
||||
const file = props.file;
|
||||
const { __ } = useTranslate();
|
||||
const [optimisticValue, setOptimisticValue] = useState<string | null>(null);
|
||||
const { organizationId } = useParams();
|
||||
|
||||
const canUpdate = organizationId ? isAuthorized(organizationId, "TrustCenter", "updateTrustCenter") : false;
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const canUpdate = isAuthorized("TrustCenter", "updateTrustCenter");
|
||||
|
||||
const handleValueChange = useCallback((value: string | {}) => {
|
||||
const stringValue = typeof value === 'string' ? value : '';
|
||||
@@ -207,7 +204,7 @@ function FileRow(props: {
|
||||
onClick={() => window.open(file.fileUrl, '_blank', 'noopener,noreferrer')}
|
||||
title={__("Download")}
|
||||
/>
|
||||
<Authorized entity="TrustCenterFile" action="updateTrustCenterFile">
|
||||
{isAuthorized("TrustCenterFile", "updateTrustCenterFile") && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={IconPencil}
|
||||
@@ -215,8 +212,8 @@ function FileRow(props: {
|
||||
disabled={props.disabled}
|
||||
title={__("Edit")}
|
||||
/>
|
||||
</Authorized>
|
||||
<Authorized entity="TrustCenterFile" action="deleteTrustCenterFile">
|
||||
)}
|
||||
{isAuthorized("TrustCenterFile", "deleteTrustCenterFile") && (
|
||||
<Button
|
||||
variant="danger"
|
||||
icon={IconTrashCan}
|
||||
@@ -224,7 +221,7 @@ function FileRow(props: {
|
||||
disabled={props.disabled}
|
||||
title={__("Delete")}
|
||||
/>
|
||||
</Authorized>
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
</Tr>
|
||||
|
||||
@@ -14,14 +14,14 @@ import {
|
||||
IconPencil,
|
||||
IconArrowLink,
|
||||
} from "@probo/ui";
|
||||
import { type ReactNode, useRef, useState } from "react";
|
||||
import { type ReactNode, useRef, useState, use } from "react";
|
||||
import {
|
||||
useTrustCenterReferences,
|
||||
useUpdateTrustCenterReferenceRankMutation,
|
||||
} from "/hooks/graph/TrustCenterReferenceGraph";
|
||||
import { TrustCenterReferenceDialog, type TrustCenterReferenceDialogRef } from "./TrustCenterReferenceDialog";
|
||||
import { DeleteTrustCenterReferenceDialog } from "./DeleteTrustCenterReferenceDialog";
|
||||
import { Authorized } from "/permissions";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
type Props = {
|
||||
trustCenterId: string;
|
||||
@@ -41,6 +41,7 @@ type Reference = {
|
||||
|
||||
export function TrustCenterReferencesSection({ trustCenterId }: Props) {
|
||||
const { __ } = useTranslate();
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const dialogRef = useRef<TrustCenterReferenceDialogRef>(null);
|
||||
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
|
||||
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
|
||||
@@ -112,14 +113,14 @@ export function TrustCenterReferencesSection({ trustCenterId }: Props) {
|
||||
{__("Showcase your customers and partners on your trust center")}
|
||||
</p>
|
||||
</div>
|
||||
<Authorized entity="TrustCenter" action="createTrustCenterReference">
|
||||
{isAuthorized("TrustCenter", "createTrustCenterReference") && (
|
||||
<Button
|
||||
icon={IconPlusLarge}
|
||||
onClick={handleCreate}
|
||||
>
|
||||
{__("Add Reference")}
|
||||
</Button>
|
||||
</Authorized>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
@@ -190,6 +191,7 @@ function ReferenceRow({
|
||||
onDrop,
|
||||
}: ReferenceRowProps) {
|
||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
|
||||
const className = [
|
||||
isDragging && "opacity-50 cursor-grabbing",
|
||||
@@ -231,14 +233,14 @@ function ReferenceRow({
|
||||
icon={IconArrowLink}
|
||||
onClick={onVisitWebsite}
|
||||
/>
|
||||
<Authorized entity="TrustCenterReference" action="updateTrustCenterReference">
|
||||
{isAuthorized("TrustCenterReference", "updateTrustCenterReference") && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={IconPencil}
|
||||
onClick={onEdit}
|
||||
/>
|
||||
</Authorized>
|
||||
<Authorized entity="TrustCenterReference" action="deleteTrustCenterReference">
|
||||
)}
|
||||
{isAuthorized("TrustCenterReference", "deleteTrustCenterReference") && (
|
||||
<DeleteTrustCenterReferenceDialog
|
||||
referenceId={reference.id}
|
||||
referenceName={reference.name}
|
||||
@@ -249,7 +251,7 @@ function ReferenceRow({
|
||||
icon={IconTrashCan}
|
||||
/>
|
||||
</DeleteTrustCenterReferenceDialog>
|
||||
</Authorized>
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
</Tr>
|
||||
|
||||
@@ -14,11 +14,11 @@ import {
|
||||
} from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { useFragment } from "react-relay";
|
||||
import { useMemo, useState, useEffect } from "react";
|
||||
import { useMemo, useState, use } from "react";
|
||||
import { sprintf } from "@probo/helpers";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { isAuthorized } from "/permissions/permissions";
|
||||
import type { TrustCenterVendorsCardFragment$key } from "./__generated__/TrustCenterVendorsCardFragment.graphql";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
const trustCenterVendorFragment = graphql`
|
||||
fragment TrustCenterVendorsCardFragment on Vendor {
|
||||
@@ -49,44 +49,14 @@ type Props<Params> = {
|
||||
|
||||
export function TrustCenterVendorsCard<Params>(props: Props<Params>) {
|
||||
const { __ } = useTranslate();
|
||||
const organizationId = useOrganizationId();
|
||||
const [limit, setLimit] = useState<number | null>(100);
|
||||
const [canUpdate, setCanUpdate] = useState<boolean>(false);
|
||||
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const canUpdate = isAuthorized("Vendor", "updateVendor");
|
||||
const vendors = useMemo(() => {
|
||||
return limit ? props.vendors.slice(0, limit) : props.vendors;
|
||||
}, [props.vendors, limit]);
|
||||
const showMoreButton = limit !== null && props.vendors.length > limit;
|
||||
|
||||
useEffect(() => {
|
||||
if (!organizationId) {
|
||||
setCanUpdate(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const authorized = isAuthorized(organizationId, "Vendor", "updateVendor");
|
||||
setCanUpdate(authorized);
|
||||
} catch (promise) {
|
||||
if (promise instanceof Promise) {
|
||||
promise
|
||||
.then(() => {
|
||||
try {
|
||||
const authorized = isAuthorized(organizationId, "Vendor", "updateVendor");
|
||||
setCanUpdate(authorized);
|
||||
} catch {
|
||||
setCanUpdate(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setCanUpdate(false);
|
||||
});
|
||||
} else {
|
||||
setCanUpdate(false);
|
||||
}
|
||||
}
|
||||
}, [organizationId]);
|
||||
|
||||
const onToggleVisibility = (vendorId: string, showOnTrustCenter: boolean) => {
|
||||
props.onToggleVisibility({
|
||||
variables: {
|
||||
|
||||
Reference in New Issue
Block a user