Fix people pages permissions handling

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2026-01-02 10:28:49 +01:00
committed by Bryan Frimin
parent 2dd7d7800b
commit cbf338fd14
15 changed files with 300 additions and 69 deletions

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<9acf6a96c0398ea5ae6fec887e8d01b1>>
* @generated SignedSource<<c70fdb86a6f2cb61e35c8231c79db02a>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -29,6 +29,8 @@ export type CreatePeopleDialogMutation$data = {
readonly peopleEdge: {
readonly node: {
readonly additionalEmailAddresses: ReadonlyArray<any>;
readonly canDelete: boolean;
readonly canUpdate: boolean;
readonly fullName: string;
readonly id: string;
readonly kind: PeopleKind;
@@ -118,6 +120,32 @@ v3 = {
"kind": "ScalarField",
"name": "additionalEmailAddresses",
"storageKey": null
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:delete\")"
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:update\")"
}
],
"storageKey": null
@@ -191,16 +219,16 @@ return {
]
},
"params": {
"cacheID": "4065779551f13f5555fa8a0f1b1ae54c",
"cacheID": "a37ebdda62d99a7583f4082b1fe19c96",
"id": null,
"metadata": {},
"name": "CreatePeopleDialogMutation",
"operationKind": "mutation",
"text": "mutation CreatePeopleDialogMutation(\n $input: CreatePeopleInput!\n) {\n createPeople(input: $input) {\n peopleEdge {\n node {\n id\n fullName\n primaryEmailAddress\n position\n kind\n additionalEmailAddresses\n }\n }\n }\n}\n"
"text": "mutation CreatePeopleDialogMutation(\n $input: CreatePeopleInput!\n) {\n createPeople(input: $input) {\n peopleEdge {\n node {\n id\n fullName\n primaryEmailAddress\n position\n kind\n additionalEmailAddresses\n canDelete: permission(action: \"core:people:delete\")\n canUpdate: permission(action: \"core:people:update\")\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "1fbca12cb827104dc700c70a677f92aa";
(node as any).hash = "d0ba45c21175b69c272a4bf9ff3c4039";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<5175c19e84ee71ec4a3e9e35e515991e>>
* @generated SignedSource<<547fca558bc3b4667355cef5d830c9ca>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -16,6 +16,8 @@ export type PeopleGraphNodeQuery$variables = {
export type PeopleGraphNodeQuery$data = {
readonly node: {
readonly additionalEmailAddresses?: ReadonlyArray<any>;
readonly canDelete?: boolean;
readonly canUpdate?: boolean;
readonly contractEndDate?: any | null | undefined;
readonly contractStartDate?: any | null | undefined;
readonly fullName?: string;
@@ -100,6 +102,32 @@ v9 = {
"kind": "ScalarField",
"name": "contractEndDate",
"storageKey": null
},
v10 = {
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:update\")"
},
v11 = {
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:delete\")"
};
return {
"fragment": {
@@ -126,7 +154,9 @@ return {
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/)
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/)
],
"type": "People",
"abstractKey": null
@@ -169,7 +199,9 @@ return {
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/)
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/)
],
"type": "People",
"abstractKey": null
@@ -180,16 +212,16 @@ return {
]
},
"params": {
"cacheID": "096d011a1e9a7374a13d037738b46fc6",
"cacheID": "b770515fd005b877138eaddfa7c1bd2f",
"id": null,
"metadata": {},
"name": "PeopleGraphNodeQuery",
"operationKind": "query",
"text": "query PeopleGraphNodeQuery(\n $peopleId: ID!\n) {\n node(id: $peopleId) {\n __typename\n ... on People {\n id\n fullName\n primaryEmailAddress\n position\n kind\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n }\n id\n }\n}\n"
"text": "query PeopleGraphNodeQuery(\n $peopleId: ID!\n) {\n node(id: $peopleId) {\n __typename\n ... on People {\n id\n fullName\n primaryEmailAddress\n position\n kind\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n canUpdate: permission(action: \"core:people:update\")\n canDelete: permission(action: \"core:people:delete\")\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "af18ca63be219f85baa39bf99294b4f6";
(node as any).hash = "a2bbe9f5064287c6a6e193c948a2c0cc";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<336b3e8036d321c95981b2d15c0b41b9>>
* @generated SignedSource<<2f4336da58b8ec9db40d3b90a75a750f>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -12,12 +12,15 @@ import { ReaderFragment } from 'relay-runtime';
export type PeopleKind = "CONTRACTOR" | "EMPLOYEE" | "SERVICE_ACCOUNT";
import { FragmentRefs } from "relay-runtime";
export type PeopleGraphPaginatedFragment$data = {
readonly canCreatePeople: boolean;
readonly id: string;
readonly peoples: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly additionalEmailAddresses: ReadonlyArray<any>;
readonly canDelete: boolean;
readonly canUpdate: boolean;
readonly contractEndDate: any | null | undefined;
readonly contractStartDate: any | null | undefined;
readonly fullName: string;
@@ -118,6 +121,19 @@ return {
},
"name": "PeopleGraphPaginatedFragment",
"selections": [
{
"alias": "canCreatePeople",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:create\")"
},
{
"alias": "peoples",
"args": [
@@ -203,6 +219,32 @@ return {
"name": "contractEndDate",
"storageKey": null
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:delete\")"
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:update\")"
},
{
"alias": null,
"args": null,
@@ -284,6 +326,6 @@ return {
};
})();
(node as any).hash = "c658d1fc05ce8d1c12e6ba4fd3cf8c52";
(node as any).hash = "199e1751362979bcc7e86e1a90a449d4";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<c6717878cc2ffa24d0d56aab35c431c7>>
* @generated SignedSource<<91fb3430f209ed2c0c83b111ca7b3d86>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -15,7 +15,7 @@ export type PeopleGraphPaginatedQuery$variables = {
};
export type PeopleGraphPaginatedQuery$data = {
readonly organization: {
readonly id?: string;
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"PeopleGraphPaginatedFragment">;
};
};
@@ -83,10 +83,10 @@ return {
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
@@ -122,6 +122,19 @@ return {
{
"kind": "InlineFragment",
"selections": [
{
"alias": "canCreatePeople",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:create\")"
},
{
"alias": null,
"args": (v4/*: any*/),
@@ -196,6 +209,32 @@ return {
"name": "contractEndDate",
"storageKey": null
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:delete\")"
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:update\")"
},
(v3/*: any*/)
],
"storageKey": null
@@ -286,16 +325,16 @@ return {
]
},
"params": {
"cacheID": "dca6a1202b168afd54cac8484cf6fadd",
"cacheID": "caa828b21b4d035ff5543e6d08355aad",
"id": null,
"metadata": {},
"name": "PeopleGraphPaginatedQuery",
"operationKind": "query",
"text": "query PeopleGraphPaginatedQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n ...PeopleGraphPaginatedFragment\n }\n id\n }\n}\n\nfragment PeopleGraphPaginatedFragment on Organization {\n peoples(first: 50, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n kind\n position\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
"text": "query PeopleGraphPaginatedQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n ...PeopleGraphPaginatedFragment\n }\n }\n}\n\nfragment PeopleGraphPaginatedFragment on Organization {\n canCreatePeople: permission(action: \"core:people:create\")\n peoples(first: 50, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n kind\n position\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n canDelete: permission(action: \"core:people:delete\")\n canUpdate: permission(action: \"core:people:update\")\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "2d5f8ae64618a57eeb623b0ade941486";
(node as any).hash = "b041fe4775cf12f965d81f243549cab0";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e4afda2e1cb4e3fcfccfca64b086ad35>>
* @generated SignedSource<<9f37a0466d956646c36ab3afe67a4664>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -208,6 +208,19 @@ return {
{
"kind": "InlineFragment",
"selections": [
{
"alias": "canCreatePeople",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:create"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:create\")"
},
{
"alias": null,
"args": (v15/*: any*/),
@@ -282,6 +295,32 @@ return {
"name": "contractEndDate",
"storageKey": null
},
{
"alias": "canDelete",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:delete"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:delete\")"
},
{
"alias": "canUpdate",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:people:update"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:people:update\")"
},
(v13/*: any*/)
],
"storageKey": null
@@ -372,16 +411,16 @@ return {
]
},
"params": {
"cacheID": "7df8a360f24224a73dc98c9b8f6da287",
"cacheID": "0ebad3a1b3f8943f1fdc170021089dc8",
"id": null,
"metadata": {},
"name": "PeopleListQuery",
"operationKind": "query",
"text": "query PeopleListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $filter: PeopleFilter = null\n $first: Int = 50\n $last: Int = null\n $order: PeopleOrder = {direction: ASC, field: FULL_NAME}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...PeopleGraphPaginatedFragment_4cFWzS\n id\n }\n}\n\nfragment PeopleGraphPaginatedFragment_4cFWzS on Organization {\n peoples(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: $filter) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n kind\n position\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
"text": "query PeopleListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $filter: PeopleFilter = null\n $first: Int = 50\n $last: Int = null\n $order: PeopleOrder = {direction: ASC, field: FULL_NAME}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...PeopleGraphPaginatedFragment_4cFWzS\n id\n }\n}\n\nfragment PeopleGraphPaginatedFragment_4cFWzS on Organization {\n canCreatePeople: permission(action: \"core:people:create\")\n peoples(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: $filter) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n kind\n position\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n canDelete: permission(action: \"core:people:delete\")\n canUpdate: permission(action: \"core:people:update\")\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "c658d1fc05ce8d1c12e6ba4fd3cf8c52";
(node as any).hash = "199e1751362979bcc7e86e1a90a449d4";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<bbaeba32a81d742b0aac7fb505843d5f>>
* @generated SignedSource<<57b1d454985b710fd8d5ccecfa90f97d>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -436,17 +436,17 @@ return {
"storageKey": "permission(action:\"core:processing-activity:list\")"
},
{
"alias": "canListStatesOfApplicability",
"alias": "canListRightsRequests",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:state-of-applicability:list"
"value": "core:rights-request:list"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:state-of-applicability:list\")"
"storageKey": "permission(action:\"core:rights-request:list\")"
},
{
"alias": "canListSnapshots",
@@ -486,6 +486,19 @@ return {
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"iam:organization:update\")"
},
{
"alias": "canListStatesOfApplicability",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:state-of-applicability:list"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:state-of-applicability:list\")"
}
],
"type": "Organization",
@@ -522,12 +535,12 @@ return {
]
},
"params": {
"cacheID": "34a53202cb35bb4f38588dabe5063f6c",
"cacheID": "7a430121b08c549781c5340bacd630c9",
"id": null,
"metadata": {},
"name": "MembershipLayoutQuery",
"operationKind": "query",
"text": "query MembershipLayoutQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...MembershipsDropdown_organizationFragment\n ...SessionDropdownFragment\n ...SidebarFragment\n }\n id\n }\n viewer {\n ...MembershipsDropdown_viewerFragment\n pendingInvitations {\n totalCount\n }\n id\n }\n}\n\nfragment MembershipsDropdown_organizationFragment on Organization {\n name\n}\n\nfragment MembershipsDropdown_viewerFragment on Identity {\n pendingInvitations {\n totalCount\n }\n}\n\nfragment SessionDropdownFragment on Organization {\n canDelete: permission(action: \"iam:organization:delete\")\n viewerMembership {\n identity {\n email\n id\n }\n profile {\n fullName\n id\n }\n id\n }\n}\n\nfragment SidebarFragment on Organization {\n canListMeetings: permission(action: \"core:meeting:list\")\n canListTasks: permission(action: \"core:task:list\")\n canListMeasures: permission(action: \"core:measures:list\")\n canListRisks: permission(action: \"core:risk:list\")\n canListFrameworks: permission(action: \"core:frameworks:list\")\n canListPeople: permission(action: \"core:people:list\")\n canListVendors: permission(action: \"core:vendor:list\")\n canListDocuments: permission(action: \"core:document:list\")\n canListAssets: permission(action: \"core:asset:list\")\n canListData: permission(action: \"core:datum:list\")\n canListAudits: permission(action: \"core:audit:list\")\n canListNonconformities: permission(action: \"core:nonconformity:list\")\n canListObligations: permission(action: \"core:obligation:list\")\n canListContinualImprovements: permission(action: \"core:continual-improvement:list\")\n canListProcessingActivities: permission(action: \"core:processing-activity:list\")\n canListStatesOfApplicability: permission(action: \"core:state-of-applicability:list\")\n canListSnapshots: permission(action: \"core:snapshot:list\")\n canGetTrustCenter: permission(action: \"core:trust-center:get\")\n canUpdateOrganization: permission(action: \"iam:organization:update\")\n}\n"
"text": "query MembershipLayoutQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...MembershipsDropdown_organizationFragment\n ...SessionDropdownFragment\n ...SidebarFragment\n }\n id\n }\n viewer {\n ...MembershipsDropdown_viewerFragment\n pendingInvitations {\n totalCount\n }\n id\n }\n}\n\nfragment MembershipsDropdown_organizationFragment on Organization {\n name\n}\n\nfragment MembershipsDropdown_viewerFragment on Identity {\n pendingInvitations {\n totalCount\n }\n}\n\nfragment SessionDropdownFragment on Organization {\n canDelete: permission(action: \"iam:organization:delete\")\n viewerMembership {\n identity {\n email\n id\n }\n profile {\n fullName\n id\n }\n id\n }\n}\n\nfragment SidebarFragment on Organization {\n canListMeetings: permission(action: \"core:meeting:list\")\n canListTasks: permission(action: \"core:task:list\")\n canListMeasures: permission(action: \"core:measures:list\")\n canListRisks: permission(action: \"core:risk:list\")\n canListFrameworks: permission(action: \"core:frameworks:list\")\n canListPeople: permission(action: \"core:people:list\")\n canListVendors: permission(action: \"core:vendor:list\")\n canListDocuments: permission(action: \"core:document:list\")\n canListAssets: permission(action: \"core:asset:list\")\n canListData: permission(action: \"core:datum:list\")\n canListAudits: permission(action: \"core:audit:list\")\n canListNonconformities: permission(action: \"core:nonconformity:list\")\n canListObligations: permission(action: \"core:obligation:list\")\n canListContinualImprovements: permission(action: \"core:continual-improvement:list\")\n canListProcessingActivities: permission(action: \"core:processing-activity:list\")\n canListRightsRequests: permission(action: \"core:rights-request:list\")\n canListSnapshots: permission(action: \"core:snapshot:list\")\n canGetTrustCenter: permission(action: \"core:trust-center:get\")\n canUpdateOrganization: permission(action: \"iam:organization:update\")\n canListStatesOfApplicability: permission(action: \"core:state-of-applicability:list\")\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e98eac6c530fd62defd06d5978d9724b>>
* @generated SignedSource<<c1333ad749a9c6aaf8f6f671bc578c04>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -24,6 +24,7 @@ export type SidebarFragment$data = {
readonly canListObligations: boolean;
readonly canListPeople: boolean;
readonly canListProcessingActivities: boolean;
readonly canListRightsRequests: boolean;
readonly canListRisks: boolean;
readonly canListSnapshots: boolean;
readonly canListStatesOfApplicability: boolean;
@@ -239,17 +240,17 @@ const node: ReaderFragment = {
"storageKey": "permission(action:\"core:processing-activity:list\")"
},
{
"alias": "canListStatesOfApplicability",
"alias": "canListRightsRequests",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:state-of-applicability:list"
"value": "core:rights-request:list"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:state-of-applicability:list\")"
"storageKey": "permission(action:\"core:rights-request:list\")"
},
{
"alias": "canListSnapshots",
@@ -289,12 +290,25 @@ const node: ReaderFragment = {
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"iam:organization:update\")"
},
{
"alias": "canListStatesOfApplicability",
"args": [
{
"kind": "Literal",
"name": "action",
"value": "core:state-of-applicability:list"
}
],
"kind": "ScalarField",
"name": "permission",
"storageKey": "permission(action:\"core:state-of-applicability:list\")"
}
],
"type": "Organization",
"abstractKey": null
};
(node as any).hash = "2baad6a78a98c3e9458cdb1ada294d76";
(node as any).hash = "3a7071a1d9ed4ffc115f5bc22e283a50";
export default node;

View File

@@ -65,8 +65,8 @@ export function usePeople(
export const paginatedPeopleQuery = graphql`
query PeopleGraphPaginatedQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
id
... on Organization {
id
...PeopleGraphPaginatedFragment
}
}
@@ -87,6 +87,7 @@ export const paginatedPeopleFragment = graphql`
before: { type: "CursorKey", defaultValue: null }
last: { type: "Int", defaultValue: null }
) {
canCreatePeople: permission(action: "core:people:create")
peoples(
first: $first
after: $after
@@ -106,6 +107,8 @@ export const paginatedPeopleFragment = graphql`
additionalEmailAddresses
contractStartDate
contractEndDate
canDelete: permission(action: "core:people:delete")
canUpdate: permission(action: "core:people:update")
}
}
}
@@ -197,6 +200,8 @@ export const peopleNodeQuery = graphql`
additionalEmailAddresses
contractStartDate
contractEndDate
canUpdate: permission(action: "core:people:update")
canDelete: permission(action: "core:people:delete")
}
}
}

View File

@@ -10,6 +10,7 @@ import {
IconGroup1,
IconInboxEmpty,
IconListStack,
IconLock,
IconMedal,
IconPageCheck,
IconPageTextLine,
@@ -47,12 +48,13 @@ const fragment = graphql`
canListProcessingActivities: permission(
action: "core:processing-activity:list"
)
canListStatesOfApplicability: permission(
action: "core:state-of-applicability:list"
)
canListRightsRequests: permission(action: "core:rights-request:list")
canListSnapshots: permission(action: "core:snapshot:list")
canGetTrustCenter: permission(action: "core:trust-center:get")
canUpdateOrganization: permission(action: "iam:organization:update")
canListStatesOfApplicability: permission(
action: "core:state-of-applicability:list"
)
}
`;
@@ -180,6 +182,13 @@ export function Sidebar(props: { fKey: SidebarFragment$key }) {
to={`${prefix}/states-of-applicability`}
/>
)}
{organization.canListRightsRequests && (
<SidebarItem
label={__("Rights Requests")}
icon={IconLock}
to={`${prefix}/rights-requests`}
/>
)}
{organization.canListSnapshots && (
<SidebarItem
label={__("Snapshots")}

View File

@@ -21,8 +21,6 @@ import {
import { useTranslate } from "@probo/i18n";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { Outlet } from "react-router";
import { use } from "react";
import { PermissionsContext } from "/providers/PermissionsContext";
type Props = {
queryRef: PreloadedQuery<PeopleGraphNodeQuery>;
@@ -33,7 +31,6 @@ export default function PeopleDetailPage(props: Props) {
const people = data.node;
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { isAuthorized } = use(PermissionsContext);
const deletePeople = useDeletePeople(
people,
ConnectionHandler.getConnectionID(organizationId, PeopleConnectionKey),
@@ -57,7 +54,7 @@ export default function PeopleDetailPage(props: Props) {
<Avatar name={people.fullName ?? ""} size="xl" />
<div className="text-2xl">{people.fullName}</div>
</div>
{isAuthorized("People", "deletePeople") && (
{data.node.canDelete && (
<ActionDropdown variant="secondary">
<DropdownItem
variant="danger"

View File

@@ -23,10 +23,12 @@ import type { NodeOf } from "/types";
import { usePageTitle } from "@probo/hooks";
import { getRole } from "@probo/helpers";
import { CreatePeopleDialog } from "./dialogs/CreatePeopleDialog";
import { SetEndOfContractDialog, type SetEndOfContractDialogRef } from "./dialogs/SetEndOfContractDialog";
import {
SetEndOfContractDialog,
type SetEndOfContractDialogRef,
} from "./dialogs/SetEndOfContractDialog";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { PermissionsContext } from "/providers/PermissionsContext";
import { use, useRef } from "react";
import { useRef } from "react";
type People = NodeOf<PeopleGraphPaginatedFragment$data["peoples"]>;
@@ -44,25 +46,31 @@ export default function PeopleListPage({
queryRef: PreloadedQuery<PeopleGraphPaginatedQuery>;
}) {
const { __ } = useTranslate();
const { isAuthorized } = use(PermissionsContext);
const { people, refetch, connectionId, hasNext, loadNext, isLoadingNext } =
usePeopleQuery(queryRef);
const {
data,
people,
refetch,
connectionId,
hasNext,
loadNext,
isLoadingNext,
} = usePeopleQuery(queryRef);
usePageTitle(__("Members"));
const hasAnyAction =
isAuthorized("People", "updatePeople") ||
isAuthorized("People", "deletePeople");
const hasAnyAction = people.some(
({ canDelete, canUpdate }) => canDelete || canUpdate
);
return (
<div className="space-y-6">
<PageHeader
title={__("Members")}
description={__(
"Keep track of your company's workforce and their progress towards completing tasks assigned to them.",
"Keep track of your company's workforce and their progress towards completing tasks assigned to them."
)}
>
{isAuthorized("Organization", "createPeople") && (
{data.canCreatePeople && (
<CreatePeopleDialog connectionId={connectionId}>
<Button icon={IconPlusLarge}>{__("Add member")}</Button>
</CreatePeopleDialog>
@@ -110,7 +118,6 @@ function PeopleRow({
const { __ } = useTranslate();
const deletePeople = useDeletePeople(people, connectionId);
const contractEnded = isContractEnded(people);
const { isAuthorized } = use(PermissionsContext);
const dialogRef = useRef<SetEndOfContractDialogRef>(null);
return (
@@ -140,7 +147,7 @@ function PeopleRow({
{hasAnyAction && (
<Td noLink width={50} className="text-end">
<ActionDropdown>
{isAuthorized("People", "updatePeople") && (
{people.canUpdate && (
<DropdownItem
icon={IconCalendar2}
onClick={() => dialogRef.current?.open()}
@@ -148,7 +155,7 @@ function PeopleRow({
{__("Set end of contract")}
</DropdownItem>
)}
{isAuthorized("People", "deletePeople") && (
{people.canDelete && (
<DropdownItem
icon={IconTrashCan}
variant="danger"

View File

@@ -31,7 +31,7 @@ const schema = z.object({
additionalEmailAddresses: z.preprocess(
// Empty additional emails are skipped
(v) => (v as string[]).filter((v) => !!v),
z.array(z.string().email())
z.array(z.string().email()),
),
kind: z.enum(peopleRoles),
});
@@ -50,6 +50,8 @@ export const createPeopleMutation = graphql`
position
kind
additionalEmailAddresses
canDelete: permission(action: "core:people:delete")
canUpdate: permission(action: "core:people:update")
}
}
}

View File

@@ -9,8 +9,6 @@ import type { PeopleGraphUpdateMutation } from "/__generated__/core/PeopleGraphU
import { updatePeopleMutation } from "/hooks/graph/PeopleGraph";
import { Button, Card, Field, Input } from "@probo/ui";
import { EmailsField } from "/components/form/EmailsField";
import { PermissionsContext } from "/providers/PermissionsContext";
import { use } from "react";
const schema = z.object({
fullName: z.string().min(1),
@@ -50,7 +48,6 @@ export default function PeopleProfileTab() {
errorMessage: __("Failed to update member"),
},
);
const { isAuthorized } = use(PermissionsContext);
const onSubmit = handleSubmit((data) => {
const input = {
id: people.id!,
@@ -80,22 +77,32 @@ export default function PeopleProfileTab() {
{...register("position")}
type="text"
placeholder={__("e.g. CEO, CFO, etc.")}
disabled={!people.canUpdate}
/>
<Field
label={__("Primary email")}
{...register("primaryEmailAddress")}
type="email"
disabled={!people.canUpdate}
/>
<EmailsField control={control} register={register} />
<Field label={__("Contract start date")}>
<Input {...register("contractStartDate")} type="date" />
<Input
{...register("contractStartDate")}
type="date"
disabled={!people.canUpdate}
/>
</Field>
<Field label={__("Contract end date")}>
<Input {...register("contractEndDate")} type="date" />
<Input
{...register("contractEndDate")}
type="date"
disabled={!people.canUpdate}
/>
</Field>
</Card>
<div className="flex justify-end">
{formState.isDirty && isAuthorized("People", "updatePeople") && (
{formState.isDirty && people.canUpdate && (
<Button type="submit" disabled={isMutating}>
{__("Update")}
</Button>

View File

@@ -1,6 +1,6 @@
import { useTranslate } from "@probo/i18n";
import { Button, Card, IconCheckmark1 } from "@probo/ui";
import { use, type PropsWithChildren } from "react";
import { type PropsWithChildren } from "react";
import z from "zod";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { ControlledField } from "/components/form/ControlledField";
@@ -11,7 +11,6 @@ import { useOutletContext } from "react-router";
import { updatePeopleMutation } from "/hooks/graph/PeopleGraph";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import type { PeopleGraphUpdateMutation } from "/__generated__/core/PeopleGraphUpdateMutation.graphql";
import { PermissionsContext } from "/providers/PermissionsContext";
const schema = z.object({
kind: z.enum(peopleRoles),
@@ -22,8 +21,6 @@ export default function PeopleRoleTab() {
people: PeopleGraphNodeQuery$data["node"];
}>();
const { __ } = useTranslate();
const { isAuthorized } = use(PermissionsContext);
const canUpdatePeople = isAuthorized("People", "updatePeople");
const { control, formState, handleSubmit, reset } = useFormWithSchema(
schema,
{
@@ -68,7 +65,7 @@ export default function PeopleRoleTab() {
name="kind"
type="select"
label={__("Role")}
disabled={!canUpdatePeople}
disabled={!people.canUpdate}
>
{getRoles(__).map((role) => (
<Option key={role.value} value={role.value}>
@@ -97,7 +94,7 @@ export default function PeopleRoleTab() {
</ul>
</div>
</Card>
{canUpdatePeople && (
{people.canUpdate && (
<div className="flex justify-end">
{formState.isDirty && (
<Button type="submit" disabled={isMutating}>

View File

@@ -1,3 +1,3 @@
module.exports = {
tabWidth: 4,
tabWidth: 2,
};