Fix iam pages permissions handling
Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
@@ -4,7 +4,6 @@ import { Badge, Button, IconPeopleAdd, Layout, Skeleton } from "@probo/ui";
|
||||
import { Sidebar } from "./_components/Sidebar";
|
||||
import { MembershipsDropdown } from "./MembershipsDropdown";
|
||||
import type { MembershipLayoutQuery } from "/__generated__/iam/MembershipLayoutQuery.graphql";
|
||||
import { PermissionsProvider } from "/providers/PermissionsProvider";
|
||||
import { SessionDropdown } from "./_components/SessionDropdown";
|
||||
import { Suspense } from "react";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
@@ -16,10 +15,10 @@ export const membershipLayoutQuery = graphql`
|
||||
... on Organization {
|
||||
...MembershipsDropdown_organizationFragment
|
||||
...SessionDropdownFragment
|
||||
...SidebarFragment
|
||||
}
|
||||
}
|
||||
viewer @required(action: THROW) {
|
||||
...SidebarFragment @arguments(organizationId: $organizationId)
|
||||
...MembershipsDropdown_viewerFragment
|
||||
pendingInvitations @required(action: THROW) {
|
||||
totalCount @required(action: THROW)
|
||||
@@ -41,39 +40,37 @@ export function MembershipLayout(props: {
|
||||
);
|
||||
|
||||
return (
|
||||
<PermissionsProvider>
|
||||
<Layout
|
||||
header={
|
||||
<>
|
||||
<div className="mr-auto">
|
||||
<MembershipsDropdown
|
||||
organizationFKey={organization}
|
||||
viewerFKey={viewer}
|
||||
/>
|
||||
{viewer.pendingInvitations.totalCount > 0 && (
|
||||
<Link to="/" className="relative" title={__("Invitations")}>
|
||||
<Button variant="tertiary" icon={IconPeopleAdd} />
|
||||
<Badge
|
||||
variant="info"
|
||||
size="sm"
|
||||
className="absolute -top-1 -right-1 min-w-[20px] h-5 flex items-center justify-center"
|
||||
>
|
||||
{viewer.pendingInvitations.totalCount}
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||
<SessionDropdown fKey={organization} />
|
||||
</Suspense>
|
||||
</>
|
||||
}
|
||||
sidebar={<Sidebar fKey={viewer} />}
|
||||
>
|
||||
<CoreRelayProvider>
|
||||
<Outlet />
|
||||
</CoreRelayProvider>
|
||||
</Layout>
|
||||
</PermissionsProvider>
|
||||
<Layout
|
||||
header={
|
||||
<>
|
||||
<div className="mr-auto">
|
||||
<MembershipsDropdown
|
||||
organizationFKey={organization}
|
||||
viewerFKey={viewer}
|
||||
/>
|
||||
{viewer.pendingInvitations.totalCount > 0 && (
|
||||
<Link to="/" className="relative" title={__("Invitations")}>
|
||||
<Button variant="tertiary" icon={IconPeopleAdd} />
|
||||
<Badge
|
||||
variant="info"
|
||||
size="sm"
|
||||
className="absolute -top-1 -right-1 min-w-[20px] h-5 flex items-center justify-center"
|
||||
>
|
||||
{viewer.pendingInvitations.totalCount}
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||
<SessionDropdown fKey={organization} />
|
||||
</Suspense>
|
||||
</>
|
||||
}
|
||||
sidebar={<Sidebar fKey={organization} />}
|
||||
>
|
||||
<CoreRelayProvider>
|
||||
<Outlet />
|
||||
</CoreRelayProvider>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import {
|
||||
UserDropdownItem,
|
||||
useToast,
|
||||
} from "@probo/ui";
|
||||
import { use } from "react";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
import { graphql } from "relay-runtime";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { useFragment, useMutation } from "react-relay";
|
||||
@@ -18,6 +16,7 @@ import type { SessionDropdownFragment$key } from "/__generated__/iam/SessionDrop
|
||||
|
||||
export const fragment = graphql`
|
||||
fragment SessionDropdownFragment on Organization {
|
||||
canDelete: permission(action: "iam:organization:delete")
|
||||
viewerMembership @required(action: THROW) {
|
||||
identity @required(action: THROW) {
|
||||
email
|
||||
@@ -42,10 +41,10 @@ export function SessionDropdown(props: { fKey: SessionDropdownFragment$key }) {
|
||||
|
||||
const { __ } = useTranslate();
|
||||
const organizationId = useOrganizationId();
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const { toast } = useToast();
|
||||
|
||||
const {
|
||||
canDelete,
|
||||
viewerMembership: {
|
||||
identity: { email },
|
||||
profile: { fullName },
|
||||
@@ -73,20 +72,18 @@ export function SessionDropdown(props: { fKey: SessionDropdownFragment$key }) {
|
||||
|
||||
return (
|
||||
<UserDropdown fullName={fullName} email={email}>
|
||||
{isAuthorized("Organization", "deleteOrganization") && (
|
||||
{canDelete && (
|
||||
<UserDropdownItem
|
||||
to="/me/api-keys"
|
||||
icon={IconKey}
|
||||
label={__("API Keys")}
|
||||
/>
|
||||
)}
|
||||
{isAuthorized("Organization", "listSignableDocuments") && (
|
||||
<UserDropdownItem
|
||||
to={`/organizations/${organizationId}/employee`}
|
||||
icon={IconPageTextLine}
|
||||
label={__("My Signatures")}
|
||||
/>
|
||||
)}
|
||||
<UserDropdownItem
|
||||
to={`/organizations/${organizationId}/employee`}
|
||||
icon={IconPageTextLine}
|
||||
label={__("My Signatures")}
|
||||
/>
|
||||
<UserDropdownItem
|
||||
to="mailto:support@getprobo.com"
|
||||
icon={IconCircleQuestionmark}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import {
|
||||
IconBank,
|
||||
IconBook,
|
||||
IconBox,
|
||||
IconCalendar1,
|
||||
IconCircleProgress,
|
||||
IconClock,
|
||||
IconCrossLargeX,
|
||||
IconFire3,
|
||||
IconGroup1,
|
||||
IconInboxEmpty,
|
||||
IconListStack,
|
||||
IconMedal,
|
||||
IconPageCheck,
|
||||
IconPageTextLine,
|
||||
IconRotateCw,
|
||||
IconSettingsGear2,
|
||||
IconShield,
|
||||
IconStore,
|
||||
IconTodo,
|
||||
SidebarItem,
|
||||
IconBank,
|
||||
IconBook,
|
||||
IconBox,
|
||||
IconCalendar1,
|
||||
IconCircleProgress,
|
||||
IconClock,
|
||||
IconCrossLargeX,
|
||||
IconFire3,
|
||||
IconGroup1,
|
||||
IconInboxEmpty,
|
||||
IconListStack,
|
||||
IconMedal,
|
||||
IconPageCheck,
|
||||
IconPageTextLine,
|
||||
IconRotateCw,
|
||||
IconSettingsGear2,
|
||||
IconShield,
|
||||
IconStore,
|
||||
IconTodo,
|
||||
SidebarItem,
|
||||
} from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
@@ -27,211 +27,180 @@ import { useFragment } from "react-relay";
|
||||
import type { SidebarFragment$key } from "/__generated__/iam/SidebarFragment.graphql";
|
||||
|
||||
const fragment = graphql`
|
||||
fragment SidebarFragment on Identity
|
||||
@argumentDefinitions(organizationId: { type: "ID!" }) {
|
||||
canListMeetings: permission(
|
||||
action: "core:meeting:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListTasks: permission(action: "core:task:list", id: $organizationId)
|
||||
canListMeasures: permission(
|
||||
action: "core:measures:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListRisks: permission(action: "core:risk:list", id: $organizationId)
|
||||
canListFrameworks: permission(
|
||||
action: "core:frameworks:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListPeople: permission(action: "core:people:list", id: $organizationId)
|
||||
canListVendors: permission(action: "core:vendor:list", id: $organizationId)
|
||||
canListDocuments: permission(
|
||||
action: "core:document:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListAssets: permission(action: "core:asset:list", id: $organizationId)
|
||||
canListData: permission(action: "core:datum:list", id: $organizationId)
|
||||
canListAudits: permission(action: "core:audit:list", id: $organizationId)
|
||||
canListNonconformities: permission(
|
||||
action: "core:nonconformity:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListObligations: permission(
|
||||
action: "core:obligation:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListContinualImprovements: permission(
|
||||
action: "core:continual-improvement:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListProcessingActivities: permission(
|
||||
action: "core:processing-activity:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListStatesOfApplicability: permission(
|
||||
action: "core:state-of-applicability:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canListSnapshots: permission(
|
||||
action: "core:snapshot:list"
|
||||
id: $organizationId
|
||||
)
|
||||
canGetTrustCenter: permission(
|
||||
action: "core:trust-center:get"
|
||||
id: $organizationId
|
||||
)
|
||||
canUpdateOrganization: permission(
|
||||
action: "iam:organization:update"
|
||||
id: $organizationId
|
||||
)
|
||||
}
|
||||
fragment SidebarFragment on Organization {
|
||||
canListMeetings: permission(action: "core:meeting:list")
|
||||
canListTasks: permission(action: "core:task:list")
|
||||
canListMeasures: permission(action: "core:measures:list")
|
||||
canListRisks: permission(action: "core:risk:list")
|
||||
canListFrameworks: permission(action: "core:frameworks:list")
|
||||
canListPeople: permission(action: "core:people:list")
|
||||
canListVendors: permission(action: "core:vendor:list")
|
||||
canListDocuments: permission(action: "core:document:list")
|
||||
canListAssets: permission(action: "core:asset:list")
|
||||
canListData: permission(action: "core:datum:list")
|
||||
canListAudits: permission(action: "core:audit:list")
|
||||
canListNonconformities: permission(action: "core:nonconformity:list")
|
||||
canListObligations: permission(action: "core:obligation:list")
|
||||
canListContinualImprovements: permission(
|
||||
action: "core:continual-improvement:list"
|
||||
)
|
||||
canListProcessingActivities: permission(
|
||||
action: "core:processing-activity:list"
|
||||
)
|
||||
canListStatesOfApplicability: permission(
|
||||
action: "core:state-of-applicability:list"
|
||||
)
|
||||
canListSnapshots: permission(action: "core:snapshot:list")
|
||||
canGetTrustCenter: permission(action: "core:trust-center:get")
|
||||
canUpdateOrganization: permission(action: "iam:organization:update")
|
||||
}
|
||||
`;
|
||||
|
||||
export function Sidebar(props: { fKey: SidebarFragment$key }) {
|
||||
const { fKey } = props;
|
||||
const { fKey } = props;
|
||||
|
||||
const { __ } = useTranslate();
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
const organizationId = useOrganizationId();
|
||||
|
||||
const permissions = useFragment<SidebarFragment$key>(fragment, fKey);
|
||||
const organization = useFragment<SidebarFragment$key>(fragment, fKey);
|
||||
|
||||
const prefix = `/organizations/${organizationId}`;
|
||||
const prefix = `/organizations/${organizationId}`;
|
||||
|
||||
return (
|
||||
<ul className="space-y-[2px]">
|
||||
{permissions.canListMeetings && (
|
||||
<SidebarItem
|
||||
label={__("Meetings")}
|
||||
icon={IconCalendar1}
|
||||
to={`${prefix}/meetings`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListTasks && (
|
||||
<SidebarItem
|
||||
label={__("Tasks")}
|
||||
icon={IconInboxEmpty}
|
||||
to={`${prefix}/tasks`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListMeasures && (
|
||||
<SidebarItem
|
||||
label={__("Measures")}
|
||||
icon={IconTodo}
|
||||
to={`${prefix}/measures`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListRisks && (
|
||||
<SidebarItem
|
||||
label={__("Risks")}
|
||||
icon={IconFire3}
|
||||
to={`${prefix}/risks`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListFrameworks && (
|
||||
<SidebarItem
|
||||
label={__("Frameworks")}
|
||||
icon={IconBank}
|
||||
to={`${prefix}/frameworks`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListPeople && (
|
||||
<SidebarItem
|
||||
label={__("People")}
|
||||
icon={IconGroup1}
|
||||
to={`${prefix}/people`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListVendors && (
|
||||
<SidebarItem
|
||||
label={__("Vendors")}
|
||||
icon={IconStore}
|
||||
to={`${prefix}/vendors`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListDocuments && (
|
||||
<SidebarItem
|
||||
label={__("Documents")}
|
||||
icon={IconPageTextLine}
|
||||
to={`${prefix}/documents`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListAssets && (
|
||||
<SidebarItem
|
||||
label={__("Assets")}
|
||||
icon={IconBox}
|
||||
to={`${prefix}/assets`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListData && (
|
||||
<SidebarItem
|
||||
label={__("Data")}
|
||||
icon={IconListStack}
|
||||
to={`${prefix}/data`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListAudits && (
|
||||
<SidebarItem
|
||||
label={__("Audits")}
|
||||
icon={IconMedal}
|
||||
to={`${prefix}/audits`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListNonconformities && (
|
||||
<SidebarItem
|
||||
label={__("Nonconformities")}
|
||||
icon={IconCrossLargeX}
|
||||
to={`${prefix}/nonconformities`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListObligations && (
|
||||
<SidebarItem
|
||||
label={__("Obligations")}
|
||||
icon={IconBook}
|
||||
to={`${prefix}/obligations`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListContinualImprovements && (
|
||||
<SidebarItem
|
||||
label={__("Continual Improvements")}
|
||||
icon={IconRotateCw}
|
||||
to={`${prefix}/continual-improvements`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListProcessingActivities && (
|
||||
<SidebarItem
|
||||
label={__("Processing Activities")}
|
||||
icon={IconCircleProgress}
|
||||
to={`${prefix}/processing-activities`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListStatesOfApplicability && (
|
||||
<SidebarItem
|
||||
label={__("States of Applicability")}
|
||||
icon={IconPageCheck}
|
||||
to={`${prefix}/states-of-applicability`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canListSnapshots && (
|
||||
<SidebarItem
|
||||
label={__("Snapshots")}
|
||||
icon={IconClock}
|
||||
to={`${prefix}/snapshots`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canGetTrustCenter && (
|
||||
<SidebarItem
|
||||
label={__("Trust Center")}
|
||||
icon={IconShield}
|
||||
to={`${prefix}/trust-center`}
|
||||
/>
|
||||
)}
|
||||
{permissions.canUpdateOrganization && (
|
||||
<SidebarItem
|
||||
label={__("Settings")}
|
||||
icon={IconSettingsGear2}
|
||||
to={`${prefix}/settings`}
|
||||
/>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
return (
|
||||
<ul className="space-y-[2px]">
|
||||
{organization.canListMeetings && (
|
||||
<SidebarItem
|
||||
label={__("Meetings")}
|
||||
icon={IconCalendar1}
|
||||
to={`${prefix}/meetings`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListTasks && (
|
||||
<SidebarItem
|
||||
label={__("Tasks")}
|
||||
icon={IconInboxEmpty}
|
||||
to={`${prefix}/tasks`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListMeasures && (
|
||||
<SidebarItem
|
||||
label={__("Measures")}
|
||||
icon={IconTodo}
|
||||
to={`${prefix}/measures`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListRisks && (
|
||||
<SidebarItem
|
||||
label={__("Risks")}
|
||||
icon={IconFire3}
|
||||
to={`${prefix}/risks`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListFrameworks && (
|
||||
<SidebarItem
|
||||
label={__("Frameworks")}
|
||||
icon={IconBank}
|
||||
to={`${prefix}/frameworks`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListPeople && (
|
||||
<SidebarItem
|
||||
label={__("People")}
|
||||
icon={IconGroup1}
|
||||
to={`${prefix}/people`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListVendors && (
|
||||
<SidebarItem
|
||||
label={__("Vendors")}
|
||||
icon={IconStore}
|
||||
to={`${prefix}/vendors`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListDocuments && (
|
||||
<SidebarItem
|
||||
label={__("Documents")}
|
||||
icon={IconPageTextLine}
|
||||
to={`${prefix}/documents`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListAssets && (
|
||||
<SidebarItem
|
||||
label={__("Assets")}
|
||||
icon={IconBox}
|
||||
to={`${prefix}/assets`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListData && (
|
||||
<SidebarItem
|
||||
label={__("Data")}
|
||||
icon={IconListStack}
|
||||
to={`${prefix}/data`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListAudits && (
|
||||
<SidebarItem
|
||||
label={__("Audits")}
|
||||
icon={IconMedal}
|
||||
to={`${prefix}/audits`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListNonconformities && (
|
||||
<SidebarItem
|
||||
label={__("Nonconformities")}
|
||||
icon={IconCrossLargeX}
|
||||
to={`${prefix}/nonconformities`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListObligations && (
|
||||
<SidebarItem
|
||||
label={__("Obligations")}
|
||||
icon={IconBook}
|
||||
to={`${prefix}/obligations`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListContinualImprovements && (
|
||||
<SidebarItem
|
||||
label={__("Continual Improvements")}
|
||||
icon={IconRotateCw}
|
||||
to={`${prefix}/continual-improvements`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListProcessingActivities && (
|
||||
<SidebarItem
|
||||
label={__("Processing Activities")}
|
||||
icon={IconCircleProgress}
|
||||
to={`${prefix}/processing-activities`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListStatesOfApplicability && (
|
||||
<SidebarItem
|
||||
label={__("States of Applicability")}
|
||||
icon={IconPageCheck}
|
||||
to={`${prefix}/states-of-applicability`}
|
||||
/>
|
||||
)}
|
||||
{organization.canListSnapshots && (
|
||||
<SidebarItem
|
||||
label={__("Snapshots")}
|
||||
icon={IconClock}
|
||||
to={`${prefix}/snapshots`}
|
||||
/>
|
||||
)}
|
||||
{organization.canGetTrustCenter && (
|
||||
<SidebarItem
|
||||
label={__("Trust Center")}
|
||||
icon={IconShield}
|
||||
to={`${prefix}/trust-center`}
|
||||
/>
|
||||
)}
|
||||
{organization.canUpdateOrganization && (
|
||||
<SidebarItem
|
||||
label={__("Settings")}
|
||||
icon={IconSettingsGear2}
|
||||
to={`${prefix}/settings`}
|
||||
/>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,16 +10,6 @@ import { InviteUserDialog } from "./_components/InviteUserDialog";
|
||||
|
||||
export const membersPageQuery = graphql`
|
||||
query MembersPageQuery($organizationId: ID!) {
|
||||
viewer @required(action: THROW) {
|
||||
canInviteUser: permission(
|
||||
action: "iam:membership:create"
|
||||
id: $organizationId
|
||||
)
|
||||
...InvitationListItem_permissionsFragment
|
||||
@arguments(organizationId: $organizationId)
|
||||
...MemberListItem_permissionsFragment
|
||||
@arguments(organizationId: $organizationId)
|
||||
}
|
||||
organization: node(id: $organizationId) @required(action: THROW) {
|
||||
__typename
|
||||
... on Organization {
|
||||
@@ -36,6 +26,7 @@ export const membersPageQuery = graphql`
|
||||
@required(action: THROW) {
|
||||
totalCount
|
||||
}
|
||||
canInviteUser: permission(action: "iam:invitation:create")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +43,7 @@ export function MembersPage(props: {
|
||||
"memberships",
|
||||
);
|
||||
|
||||
const { organization, viewer } = usePreloadedQuery<MembersPageQuery>(
|
||||
const { organization } = usePreloadedQuery<MembersPageQuery>(
|
||||
membersPageQuery,
|
||||
queryRef,
|
||||
);
|
||||
@@ -64,7 +55,7 @@ export function MembersPage(props: {
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-base font-medium">{__("Workspace members")}</h2>
|
||||
{viewer.canInviteUser && (
|
||||
{organization.canInviteUser && (
|
||||
<InviteUserDialog viewerMembershipFKey={organization}>
|
||||
<Button variant="secondary">{__("Invite member")}</Button>
|
||||
</InviteUserDialog>
|
||||
@@ -94,12 +85,10 @@ export function MembersPage(props: {
|
||||
|
||||
<Card>
|
||||
<div className="px-6 pb-6 pt-6">
|
||||
{activeTab === "memberships" && (
|
||||
<MemberList fKey={organization} permissionsFKey={viewer} />
|
||||
)}
|
||||
{activeTab === "memberships" && <MemberList fKey={organization} />}
|
||||
|
||||
{activeTab === "invitations" && (
|
||||
<InvitationList fKey={organization} permissionsFKey={viewer} />
|
||||
<InvitationList fKey={organization} />
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useTranslate } from "@probo/i18n";
|
||||
import { graphql, usePaginationFragment } from "react-relay";
|
||||
import { InvitationListItem } from "./InvitationListItem";
|
||||
import type { InvitationListFragment$key } from "/__generated__/iam/InvitationListFragment.graphql";
|
||||
import type { InvitationListItem_permissionsFragment$key } from "/__generated__/iam/InvitationListItem_permissionsFragment.graphql";
|
||||
import type { InvitationListFragment_RefetchQuery } from "/__generated__/iam/InvitationListFragment_RefetchQuery.graphql";
|
||||
|
||||
const fragment = graphql`
|
||||
@@ -41,11 +40,8 @@ const fragment = graphql`
|
||||
}
|
||||
`;
|
||||
|
||||
export function InvitationList(props: {
|
||||
fKey: InvitationListFragment$key;
|
||||
permissionsFKey: InvitationListItem_permissionsFragment$key;
|
||||
}) {
|
||||
const { fKey, permissionsFKey } = props;
|
||||
export function InvitationList(props: { fKey: InvitationListFragment$key }) {
|
||||
const { fKey } = props;
|
||||
|
||||
const { __ } = useTranslate();
|
||||
|
||||
@@ -106,7 +102,6 @@ export function InvitationList(props: {
|
||||
key={invitation.id}
|
||||
fKey={invitation}
|
||||
onRefetch={refetchInvitations}
|
||||
permissionsFKey={permissionsFKey}
|
||||
/>
|
||||
),
|
||||
)
|
||||
|
||||
@@ -15,7 +15,6 @@ import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
|
||||
import { sprintf } from "@probo/helpers";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import type { InvitationListItemFragment$key } from "/__generated__/iam/InvitationListItemFragment.graphql";
|
||||
import type { InvitationListItem_permissionsFragment$key } from "/__generated__/iam/InvitationListItem_permissionsFragment.graphql";
|
||||
|
||||
const fragment = graphql`
|
||||
fragment InvitationListItemFragment on Invitation {
|
||||
@@ -27,16 +26,7 @@ const fragment = graphql`
|
||||
createdAt
|
||||
expiresAt
|
||||
acceptedAt
|
||||
}
|
||||
`;
|
||||
|
||||
const permissionsFragment = graphql`
|
||||
fragment InvitationListItem_permissionsFragment on Identity
|
||||
@argumentDefinitions(organizationId: { type: "ID!" }) {
|
||||
canDeleteInvitation: permission(
|
||||
action: "iam:invitation:delete"
|
||||
id: $organizationId
|
||||
)
|
||||
canDelete: permission(action: "iam:invitation:delete")
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -54,10 +44,9 @@ const deleteInvitationMutation = graphql`
|
||||
export function InvitationListItem(props: {
|
||||
connectionId: string;
|
||||
fKey: InvitationListItemFragment$key;
|
||||
permissionsFKey: InvitationListItem_permissionsFragment$key;
|
||||
onRefetch: () => void;
|
||||
}) {
|
||||
const { connectionId, fKey, permissionsFKey } = props;
|
||||
const { connectionId, fKey } = props;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
@@ -67,10 +56,6 @@ export function InvitationListItem(props: {
|
||||
fragment,
|
||||
fKey,
|
||||
);
|
||||
const permissions = useFragment<InvitationListItem_permissionsFragment$key>(
|
||||
permissionsFragment,
|
||||
permissionsFKey,
|
||||
);
|
||||
|
||||
const [deleteInvitation, isDeleting] = useMutationWithToasts(
|
||||
deleteInvitationMutation,
|
||||
@@ -134,7 +119,7 @@ export function InvitationListItem(props: {
|
||||
{isDeleting ? (
|
||||
<Spinner size={16} />
|
||||
) : (
|
||||
permissions.canDeleteInvitation && (
|
||||
invitation.canDelete && (
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={handleDelete}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { SortableTable, SortableTh } from "/components/SortableTable";
|
||||
import type { MemberListFragment_RefetchQuery } from "/__generated__/iam/MemberListFragment_RefetchQuery.graphql";
|
||||
import { MemberListItem } from "./MemberListItem";
|
||||
import type { MemberListFragment$key } from "/__generated__/iam/MemberListFragment.graphql";
|
||||
import type { MemberListItem_permissionsFragment$key } from "/__generated__/iam/MemberListItem_permissionsFragment.graphql";
|
||||
|
||||
const fragment = graphql`
|
||||
fragment MemberListFragment on Organization
|
||||
@@ -40,11 +39,8 @@ const fragment = graphql`
|
||||
}
|
||||
`;
|
||||
|
||||
export function MemberList(props: {
|
||||
fKey: MemberListFragment$key;
|
||||
permissionsFKey: MemberListItem_permissionsFragment$key;
|
||||
}) {
|
||||
const { fKey, permissionsFKey } = props;
|
||||
export function MemberList(props: { fKey: MemberListFragment$key }) {
|
||||
const { fKey } = props;
|
||||
|
||||
const { __ } = useTranslate();
|
||||
|
||||
@@ -98,7 +94,6 @@ export function MemberList(props: {
|
||||
key={membership.id}
|
||||
fKey={membership}
|
||||
onRefetch={refetchMemberships}
|
||||
permissionsFKey={permissionsFKey}
|
||||
viewerFKey={membersPagination.data}
|
||||
/>
|
||||
))
|
||||
|
||||
@@ -14,7 +14,6 @@ import { useState } from "react";
|
||||
import { useFragment } from "react-relay";
|
||||
import { graphql } from "relay-runtime";
|
||||
import type { MemberListItemFragment$key } from "/__generated__/iam/MemberListItemFragment.graphql";
|
||||
import type { MemberListItem_permissionsFragment$key } from "/__generated__/iam/MemberListItem_permissionsFragment.graphql";
|
||||
import type { MemberListItem_currentRoleFragment$key } from "/__generated__/iam/MemberListItem_currentRoleFragment.graphql";
|
||||
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
@@ -32,6 +31,8 @@ const fragment = graphql`
|
||||
email
|
||||
}
|
||||
createdAt
|
||||
canUpdate: permission(action: "iam:membership:update")
|
||||
canDelete: permission(action: "iam:membership:delete")
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -43,20 +44,6 @@ const currentRoleFragment = graphql`
|
||||
}
|
||||
`;
|
||||
|
||||
const permissionsFragment = graphql`
|
||||
fragment MemberListItem_permissionsFragment on Identity
|
||||
@argumentDefinitions(organizationId: { type: "ID!" }) {
|
||||
canUpdateMembership: permission(
|
||||
action: "iam:membership:update"
|
||||
id: $organizationId
|
||||
)
|
||||
canDeleteMembership: permission(
|
||||
action: "iam:membership:delete"
|
||||
id: $organizationId
|
||||
)
|
||||
}
|
||||
`;
|
||||
|
||||
const removeMemberMutation = graphql`
|
||||
mutation MemberListItem_removeMutation(
|
||||
$input: RemoveMemberInput!
|
||||
@@ -71,11 +58,10 @@ const removeMemberMutation = graphql`
|
||||
export function MemberListItem(props: {
|
||||
connectionId: string;
|
||||
fKey: MemberListItemFragment$key;
|
||||
permissionsFKey: MemberListItem_permissionsFragment$key;
|
||||
viewerFKey: MemberListItem_currentRoleFragment$key;
|
||||
onRefetch: () => void;
|
||||
}) {
|
||||
const { fKey, connectionId, permissionsFKey, viewerFKey } = props;
|
||||
const { fKey, connectionId, viewerFKey } = props;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
@@ -88,10 +74,6 @@ export function MemberListItem(props: {
|
||||
currentRoleFragment,
|
||||
viewerFKey,
|
||||
);
|
||||
const permissions = useFragment<MemberListItem_permissionsFragment$key>(
|
||||
permissionsFragment,
|
||||
permissionsFKey,
|
||||
);
|
||||
|
||||
// Only OWNER can edit OWNER members
|
||||
const canEditThisRole =
|
||||
@@ -151,7 +133,7 @@ export function MemberListItem(props: {
|
||||
className="flex gap-2 justify-end"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{permissions.canUpdateMembership && canEditThisRole && (
|
||||
{membership.canUpdate && canEditThisRole && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => setDialogOpen(true)}
|
||||
@@ -163,7 +145,7 @@ export function MemberListItem(props: {
|
||||
{isRemoving ? (
|
||||
<Spinner size={16} />
|
||||
) : (
|
||||
permissions.canDeleteMembership &&
|
||||
membership.canDelete &&
|
||||
canEditThisRole && (
|
||||
<Button
|
||||
variant="danger"
|
||||
|
||||
Reference in New Issue
Block a user