diff --git a/apps/console/src/components/form/PeopleSelectField.tsx b/apps/console/src/components/form/PeopleSelectField.tsx index ef607181b..a72a75cfb 100644 --- a/apps/console/src/components/form/PeopleSelectField.tsx +++ b/apps/console/src/components/form/PeopleSelectField.tsx @@ -38,7 +38,7 @@ function PeopleSelectWithQuery( ) { const { __ } = useTranslate(); const { name, organizationId, control } = props; - const people = usePeople(organizationId); + const people = usePeople(organizationId, { excludeContractEnded: true }); return ( <> diff --git a/apps/console/src/hooks/graph/PeopleGraph.ts b/apps/console/src/hooks/graph/PeopleGraph.ts index 531e2e6fb..2341f22e1 100644 --- a/apps/console/src/hooks/graph/PeopleGraph.ts +++ b/apps/console/src/hooks/graph/PeopleGraph.ts @@ -16,10 +16,10 @@ import { promisifyMutation, sprintf } from "@probo/helpers"; import { useTranslate } from "@probo/i18n"; const peopleQuery = graphql` - query PeopleGraphQuery($organizationId: ID!) { + query PeopleGraphQuery($organizationId: ID!, $filter: PeopleFilter) { organization: node(id: $organizationId) { ... on Organization { - peoples(first: 100, orderBy: { direction: ASC, field: CREATED_AT }) { + peoples(first: 100, orderBy: { direction: ASC, field: FULL_NAME }, filter: $filter) { edges { node { id @@ -36,10 +36,15 @@ const peopleQuery = graphql` /** * Return a list of people (used for people selectors) */ -export function usePeople(organizationId: string) { - const data = useLazyLoadQuery(peopleQuery, { - organizationId: organizationId, - }); +export function usePeople(organizationId: string, { excludeContractEnded }: { excludeContractEnded?: boolean } = {}) { + const data = useLazyLoadQuery( + peopleQuery, + { + organizationId: organizationId, + filter: excludeContractEnded ? { excludeContractEnded: true } : null, + }, + { fetchPolicy: "network-only" } + ); return useMemo(() => { return data.organization?.peoples?.edges.map((edge) => edge.node) ?? []; }, [data]); @@ -61,7 +66,8 @@ export const paginatedPeopleFragment = graphql` @refetchable(queryName: "PeopleListQuery") @argumentDefinitions( first: { type: "Int", defaultValue: 50 } - order: { type: "PeopleOrder", defaultValue: null } + order: { type: "PeopleOrder", defaultValue: { direction: ASC, field: FULL_NAME } } + filter: { type: "PeopleFilter", defaultValue: null } after: { type: "CursorKey", defaultValue: null } before: { type: "CursorKey", defaultValue: null } last: { type: "Int", defaultValue: null } @@ -72,6 +78,7 @@ export const paginatedPeopleFragment = graphql` last: $last before: $before orderBy: $order + filter: $filter ) @connection(key: "PeopleGraphPaginatedQuery_peoples") { __id edges { @@ -82,6 +89,8 @@ export const paginatedPeopleFragment = graphql` kind position additionalEmailAddresses + contractStartDate + contractEndDate } } } @@ -161,6 +170,8 @@ export const peopleNodeQuery = graphql` position kind additionalEmailAddresses + contractStartDate + contractEndDate } } } @@ -176,6 +187,8 @@ export const updatePeopleMutation = graphql` position kind additionalEmailAddresses + contractStartDate + contractEndDate } } } diff --git a/apps/console/src/hooks/graph/__generated__/PeopleGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/PeopleGraphNodeQuery.graphql.ts index e7a967322..c7b553bcf 100644 --- a/apps/console/src/hooks/graph/__generated__/PeopleGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/PeopleGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<71df408810680ded020fb0e1cc93ff79>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -16,6 +16,8 @@ export type PeopleGraphNodeQuery$variables = { export type PeopleGraphNodeQuery$data = { readonly node: { readonly additionalEmailAddresses?: ReadonlyArray; + readonly contractEndDate?: any | null | undefined; + readonly contractStartDate?: any | null | undefined; readonly fullName?: string; readonly id?: string; readonly kind?: PeopleKind; @@ -84,6 +86,20 @@ v7 = { "kind": "ScalarField", "name": "additionalEmailAddresses", "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractStartDate", + "storageKey": null +}, +v9 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractEndDate", + "storageKey": null }; return { "fragment": { @@ -108,7 +124,9 @@ return { (v4/*: any*/), (v5/*: any*/), (v6/*: any*/), - (v7/*: any*/) + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/) ], "type": "People", "abstractKey": null @@ -149,7 +167,9 @@ return { (v4/*: any*/), (v5/*: any*/), (v6/*: any*/), - (v7/*: any*/) + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/) ], "type": "People", "abstractKey": null @@ -160,16 +180,16 @@ return { ] }, "params": { - "cacheID": "850de97d42fdda9d2335c0e5219fd067", + "cacheID": "096d011a1e9a7374a13d037738b46fc6", "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 }\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 }\n id\n }\n}\n" } }; })(); -(node as any).hash = "f39d45664dba2b3bcdad07ef8baebfe9"; +(node as any).hash = "af18ca63be219f85baa39bf99294b4f6"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedFragment.graphql.ts b/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedFragment.graphql.ts index 804e60eaa..4ff1ba3c6 100644 --- a/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedFragment.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<5eba326084bfab4966727af60e2aa85c>> + * @generated SignedSource<<940911e0b7ae1ffe53a31f98216dcfe6>> * @lightSyntaxTransform * @nogrep */ @@ -18,6 +18,8 @@ export type PeopleGraphPaginatedFragment$data = { readonly edges: ReadonlyArray<{ readonly node: { readonly additionalEmailAddresses: ReadonlyArray; + readonly contractEndDate: any | null | undefined; + readonly contractStartDate: any | null | undefined; readonly fullName: string; readonly id: string; readonly kind: PeopleKind; @@ -58,6 +60,11 @@ return { "kind": "LocalArgument", "name": "before" }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filter" + }, { "defaultValue": 50, "kind": "LocalArgument", @@ -69,7 +76,10 @@ return { "name": "last" }, { - "defaultValue": null, + "defaultValue": { + "direction": "ASC", + "field": "FULL_NAME" + }, "kind": "LocalArgument", "name": "order" } @@ -111,6 +121,11 @@ return { { "alias": "peoples", "args": [ + { + "kind": "Variable", + "name": "filter", + "variableName": "filter" + }, { "kind": "Variable", "name": "orderBy", @@ -174,6 +189,20 @@ return { "name": "additionalEmailAddresses", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractStartDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractEndDate", + "storageKey": null + }, { "alias": null, "args": null, @@ -255,6 +284,6 @@ return { }; })(); -(node as any).hash = "5e095baf6a65e7cdbaa804d4658cbb6b"; +(node as any).hash = "c658d1fc05ce8d1c12e6ba4fd3cf8c52"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedQuery.graphql.ts index a90a61e12..73f07ac7b 100644 --- a/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/PeopleGraphPaginatedQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<1ec11120f71d4bc3040bcdd2665904c0>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -58,6 +58,14 @@ v4 = [ "kind": "Literal", "name": "first", "value": 50 + }, + { + "kind": "Literal", + "name": "orderBy", + "value": { + "direction": "ASC", + "field": "FULL_NAME" + } } ]; return { @@ -174,6 +182,20 @@ return { "name": "additionalEmailAddresses", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractStartDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractEndDate", + "storageKey": null + }, (v3/*: any*/) ], "storageKey": null @@ -240,13 +262,14 @@ return { ] } ], - "storageKey": "peoples(first:50)" + "storageKey": "peoples(first:50,orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})" }, { "alias": null, "args": (v4/*: any*/), "filters": [ - "orderBy" + "orderBy", + "filter" ], "handle": "connection", "key": "PeopleGraphPaginatedQuery_peoples", @@ -263,12 +286,12 @@ return { ] }, "params": { - "cacheID": "1139d090f54b12e62e08f0a1970c9af0", + "cacheID": "dca6a1202b168afd54cac8484cf6fadd", "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) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n kind\n position\n additionalEmailAddresses\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 ... 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" } }; })(); diff --git a/apps/console/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts index e48d43d05..465fe4159 100644 --- a/apps/console/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,7 +9,11 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; +export type PeopleFilter = { + excludeContractEnded?: boolean | null | undefined; +}; export type PeopleGraphQuery$variables = { + filter?: PeopleFilter | null | undefined; organizationId: string; }; export type PeopleGraphQuery$data = { @@ -31,33 +35,41 @@ export type PeopleGraphQuery = { }; const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "organizationId" - } -], -v1 = [ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filter" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "organizationId" +}, +v2 = [ { "kind": "Variable", "name": "id", "variableName": "organizationId" } ], -v2 = { +v3 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v3 = { +v4 = { "kind": "InlineFragment", "selections": [ { "alias": null, "args": [ + { + "kind": "Variable", + "name": "filter", + "variableName": "filter" + }, { "kind": "Literal", "name": "first", @@ -68,7 +80,7 @@ v3 = { "name": "orderBy", "value": { "direction": "ASC", - "field": "CREATED_AT" + "field": "FULL_NAME" } } ], @@ -93,7 +105,7 @@ v3 = { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), + (v3/*: any*/), { "alias": null, "args": null, @@ -115,7 +127,7 @@ v3 = { "storageKey": null } ], - "storageKey": "peoples(first:100,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})" + "storageKey": null } ], "type": "Organization", @@ -123,20 +135,23 @@ v3 = { }; return { "fragment": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], "kind": "Fragment", "metadata": null, "name": "PeopleGraphQuery", "selections": [ { "alias": "organization", - "args": (v1/*: any*/), + "args": (v2/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - (v3/*: any*/) + (v4/*: any*/) ], "storageKey": null } @@ -146,13 +161,16 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], "kind": "Operation", "name": "PeopleGraphQuery", "selections": [ { "alias": "organization", - "args": (v1/*: any*/), + "args": (v2/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", @@ -165,24 +183,24 @@ return { "name": "__typename", "storageKey": null }, - (v3/*: any*/), - (v2/*: any*/) + (v4/*: any*/), + (v3/*: any*/) ], "storageKey": null } ] }, "params": { - "cacheID": "cf76244f6aaa0c573bdeb7bf118ad2a3", + "cacheID": "cfb5be60bd39783154a815d178a8fa51", "id": null, "metadata": {}, "name": "PeopleGraphQuery", "operationKind": "query", - "text": "query PeopleGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n peoples(first: 100, orderBy: {direction: ASC, field: CREATED_AT}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n }\n id\n }\n}\n" + "text": "query PeopleGraphQuery(\n $organizationId: ID!\n $filter: PeopleFilter\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}, filter: $filter) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n }\n id\n }\n}\n" } }; })(); -(node as any).hash = "11220f45320400c451abeaf7479a8e47"; +(node as any).hash = "79f4d511be3c7cfa63a774ac017a6f41"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/PeopleGraphUpdateMutation.graphql.ts b/apps/console/src/hooks/graph/__generated__/PeopleGraphUpdateMutation.graphql.ts index f3646f368..74feea799 100644 --- a/apps/console/src/hooks/graph/__generated__/PeopleGraphUpdateMutation.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/PeopleGraphUpdateMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<18d62863109c347d5fcf7b5701a9c57b>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -27,6 +27,8 @@ export type PeopleGraphUpdateMutation$data = { readonly updatePeople: { readonly people: { readonly additionalEmailAddresses: ReadonlyArray; + readonly contractEndDate: any | null | undefined; + readonly contractStartDate: any | null | undefined; readonly fullName: string; readonly id: string; readonly kind: PeopleKind; @@ -112,6 +114,20 @@ v1 = [ "kind": "ScalarField", "name": "additionalEmailAddresses", "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractStartDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractEndDate", + "storageKey": null } ], "storageKey": null @@ -138,16 +154,16 @@ return { "selections": (v1/*: any*/) }, "params": { - "cacheID": "814551d1fb24548c41d417342625071f", + "cacheID": "23c51259f3ff117441f9c6e11de5ba5a", "id": null, "metadata": {}, "name": "PeopleGraphUpdateMutation", "operationKind": "mutation", - "text": "mutation PeopleGraphUpdateMutation(\n $input: UpdatePeopleInput!\n) {\n updatePeople(input: $input) {\n people {\n id\n fullName\n primaryEmailAddress\n position\n kind\n additionalEmailAddresses\n }\n }\n}\n" + "text": "mutation PeopleGraphUpdateMutation(\n $input: UpdatePeopleInput!\n) {\n updatePeople(input: $input) {\n people {\n id\n fullName\n primaryEmailAddress\n position\n kind\n additionalEmailAddresses\n contractStartDate\n contractEndDate\n }\n }\n}\n" } }; })(); -(node as any).hash = "ecc5666046434d5c8e80eaab0e508c11"; +(node as any).hash = "fc0946729d6a2729aa1b7c9b2dfbdf7a"; export default node; diff --git a/apps/console/src/hooks/graph/__generated__/PeopleListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/PeopleListQuery.graphql.ts index 73b2df62e..007804cc6 100644 --- a/apps/console/src/hooks/graph/__generated__/PeopleListQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/PeopleListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<4cfc7218bc48a818eedc2ea87ac521e6>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,9 @@ import { ConcreteRequest } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; export type OrderDirection = "ASC" | "DESC"; export type PeopleOrderField = "CREATED_AT" | "FULL_NAME" | "KIND"; +export type PeopleFilter = { + excludeContractEnded?: boolean | null | undefined; +}; export type PeopleOrder = { direction: OrderDirection; field: PeopleOrderField; @@ -19,6 +22,7 @@ export type PeopleOrder = { export type PeopleListQuery$variables = { after?: any | null | undefined; before?: any | null | undefined; + filter?: PeopleFilter | null | undefined; first?: number | null | undefined; id: string; last?: number | null | undefined; @@ -46,71 +50,85 @@ v1 = { "name": "before" }, v2 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filter" +}, +v3 = { "defaultValue": 50, "kind": "LocalArgument", "name": "first" }, -v3 = { +v4 = { "defaultValue": null, "kind": "LocalArgument", "name": "id" }, -v4 = { +v5 = { "defaultValue": null, "kind": "LocalArgument", "name": "last" }, -v5 = { - "defaultValue": null, +v6 = { + "defaultValue": { + "direction": "ASC", + "field": "FULL_NAME" + }, "kind": "LocalArgument", "name": "order" }, -v6 = [ +v7 = [ { "kind": "Variable", "name": "id", "variableName": "id" } ], -v7 = { +v8 = { "kind": "Variable", "name": "after", "variableName": "after" }, -v8 = { +v9 = { "kind": "Variable", "name": "before", "variableName": "before" }, -v9 = { +v10 = { + "kind": "Variable", + "name": "filter", + "variableName": "filter" +}, +v11 = { "kind": "Variable", "name": "first", "variableName": "first" }, -v10 = { +v12 = { "kind": "Variable", "name": "last", "variableName": "last" }, -v11 = { +v13 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v12 = { +v14 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v13 = [ - (v7/*: any*/), +v15 = [ (v8/*: any*/), (v9/*: any*/), (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), { "kind": "Variable", "name": "orderBy", @@ -125,7 +143,8 @@ return { (v2/*: any*/), (v3/*: any*/), (v4/*: any*/), - (v5/*: any*/) + (v5/*: any*/), + (v6/*: any*/) ], "kind": "Fragment", "metadata": null, @@ -133,7 +152,7 @@ return { "selections": [ { "alias": null, - "args": (v6/*: any*/), + "args": (v7/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", @@ -141,10 +160,11 @@ return { "selections": [ { "args": [ - (v7/*: any*/), (v8/*: any*/), (v9/*: any*/), (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), { "kind": "Variable", "name": "order", @@ -167,29 +187,30 @@ return { (v0/*: any*/), (v1/*: any*/), (v2/*: any*/), - (v4/*: any*/), + (v3/*: any*/), (v5/*: any*/), - (v3/*: any*/) + (v6/*: any*/), + (v4/*: any*/) ], "kind": "Operation", "name": "PeopleListQuery", "selections": [ { "alias": null, - "args": (v6/*: any*/), + "args": (v7/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - (v11/*: any*/), - (v12/*: any*/), + (v13/*: any*/), + (v14/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v13/*: any*/), + "args": (v15/*: any*/), "concreteType": "PeopleConnection", "kind": "LinkedField", "name": "peoples", @@ -211,7 +232,7 @@ return { "name": "node", "plural": false, "selections": [ - (v12/*: any*/), + (v14/*: any*/), { "alias": null, "args": null, @@ -247,7 +268,21 @@ return { "name": "additionalEmailAddresses", "storageKey": null }, - (v11/*: any*/) + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractStartDate", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contractEndDate", + "storageKey": null + }, + (v13/*: any*/) ], "storageKey": null }, @@ -317,9 +352,10 @@ return { }, { "alias": null, - "args": (v13/*: any*/), + "args": (v15/*: any*/), "filters": [ - "orderBy" + "orderBy", + "filter" ], "handle": "connection", "key": "PeopleGraphPaginatedQuery_peoples", @@ -336,16 +372,16 @@ return { ] }, "params": { - "cacheID": "8134caa0eab10c19236a49728f1f77b6", + "cacheID": "7df8a360f24224a73dc98c9b8f6da287", "id": null, "metadata": {}, "name": "PeopleListQuery", "operationKind": "query", - "text": "query PeopleListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 50\n $last: Int = null\n $order: PeopleOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...PeopleGraphPaginatedFragment_16fISc\n id\n }\n}\n\nfragment PeopleGraphPaginatedFragment_16fISc on Organization {\n peoples(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n kind\n position\n additionalEmailAddresses\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 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" } }; })(); -(node as any).hash = "5e095baf6a65e7cdbaa804d4658cbb6b"; +(node as any).hash = "c658d1fc05ce8d1c12e6ba4fd3cf8c52"; export default node; diff --git a/apps/console/src/pages/organizations/audits/AuditDetailsPage.tsx b/apps/console/src/pages/organizations/audits/AuditDetailsPage.tsx index 5f38cdf20..da47e7869 100644 --- a/apps/console/src/pages/organizations/audits/AuditDetailsPage.tsx +++ b/apps/console/src/pages/organizations/audits/AuditDetailsPage.tsx @@ -31,7 +31,7 @@ import { useOrganizationId } from "/hooks/useOrganizationId"; import { ControlledField } from "/components/form/ControlledField"; import { useFormWithSchema } from "/hooks/useFormWithSchema"; import z from "zod"; -import { getAuditStateLabel, getAuditStateVariant, auditStates, fileSize, sprintf } from "@probo/helpers"; +import { getAuditStateLabel, getAuditStateVariant, auditStates, fileSize, sprintf, formatDatetime } from "@probo/helpers"; import type { AuditGraphNodeQuery } from "/hooks/graph/__generated__/AuditGraphNodeQuery.graphql"; const updateAuditSchema = z.object({ @@ -77,11 +77,6 @@ export default function AuditDetailsPage(props: Props) { if (!auditEntry.id) return; try { - const formatDatetime = (dateString?: string) => { - if (!dateString) return undefined; - return `${dateString}T00:00:00Z`; - }; - await updateAudit({ id: auditEntry.id, validFrom: formatDatetime(formData.validFrom), diff --git a/apps/console/src/pages/organizations/audits/dialogs/CreateAuditDialog.tsx b/apps/console/src/pages/organizations/audits/dialogs/CreateAuditDialog.tsx index 827bd9339..10d6cf1b4 100644 --- a/apps/console/src/pages/organizations/audits/dialogs/CreateAuditDialog.tsx +++ b/apps/console/src/pages/organizations/audits/dialogs/CreateAuditDialog.tsx @@ -16,7 +16,7 @@ import z from "zod"; import { useFormWithSchema } from "/hooks/useFormWithSchema"; import { ControlledField } from "/components/form/ControlledField"; import { useCreateAudit } from "/hooks/graph/AuditGraph"; -import { auditStates, getAuditStateLabel } from "@probo/helpers"; +import { auditStates, getAuditStateLabel, formatDatetime } from "@probo/helpers"; import { useLazyLoadQuery } from "react-relay"; import { graphql } from "relay-runtime"; import { Suspense } from "react"; @@ -74,12 +74,6 @@ export function CreateAuditDialog({ const onSubmit = handleSubmit(async (data) => { try { - // Convert date strings to datetime format - const formatDatetime = (dateString?: string) => { - if (!dateString) return undefined; - return `${dateString}T00:00:00Z`; - }; - await createAudit({ organizationId, frameworkId: data.frameworkId, diff --git a/apps/console/src/pages/organizations/people/PeopleListPage.tsx b/apps/console/src/pages/organizations/people/PeopleListPage.tsx index 8dec52697..78612792a 100644 --- a/apps/console/src/pages/organizations/people/PeopleListPage.tsx +++ b/apps/console/src/pages/organizations/people/PeopleListPage.tsx @@ -26,6 +26,14 @@ import { useOrganizationId } from "/hooks/useOrganizationId"; type People = NodeOf; +const isContractEnded = (person: People): boolean => { + if (!person.contractEndDate) return false; + const endDate = new Date(person.contractEndDate); + const today = new Date(); + today.setHours(0, 0, 0, 0); + return endDate < today; +}; + export default function PeopleListPage({ queryRef, }: { @@ -87,9 +95,13 @@ function PeopleRow({ const organizationId = useOrganizationId(); const { __ } = useTranslate(); const deletePeople = useDeletePeople(people, connectionId); + const contractEnded = isContractEnded(people); return ( - +
diff --git a/apps/console/src/pages/organizations/people/tabs/PeopleProfileTab.tsx b/apps/console/src/pages/organizations/people/tabs/PeopleProfileTab.tsx index cacc417b0..212fc6727 100644 --- a/apps/console/src/pages/organizations/people/tabs/PeopleProfileTab.tsx +++ b/apps/console/src/pages/organizations/people/tabs/PeopleProfileTab.tsx @@ -1,5 +1,5 @@ import z from "zod"; -import { peopleRoles } from "@probo/helpers"; +import { peopleRoles, formatDatetime } from "@probo/helpers"; import { useOutletContext } from "react-router"; import type { PeopleGraphNodeQuery$data } from "/hooks/graph/__generated__/PeopleGraphNodeQuery.graphql"; import { useTranslate } from "@probo/i18n"; @@ -7,7 +7,7 @@ import { useFormWithSchema } from "/hooks/useFormWithSchema"; import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; import type { PeopleGraphUpdateMutation } from "/hooks/graph/__generated__/PeopleGraphUpdateMutation.graphql"; import { updatePeopleMutation } from "/hooks/graph/PeopleGraph"; -import { Button, Card, Field } from "@probo/ui"; +import { Button, Card, Field, Input } from "@probo/ui"; import { EmailsField } from "/components/form/EmailsField"; const schema = z.object({ @@ -20,6 +20,8 @@ const schema = z.object({ z.array(z.string().email()) ), kind: z.enum(peopleRoles), + contractStartDate: z.string().optional().nullable(), + contractEndDate: z.string().optional().nullable(), }); export default function PeopleProfileTab() { @@ -35,6 +37,8 @@ export default function PeopleProfileTab() { primaryEmailAddress: people.primaryEmailAddress, position: people.position, additionalEmailAddresses: [...(people.additionalEmailAddresses ?? [])], + contractStartDate: people.contractStartDate?.split('T')[0] || "", + contractEndDate: people.contractEndDate?.split('T')[0] || "", }, }); const [mutate, isMutating] = useMutationWithToasts( @@ -46,18 +50,19 @@ export default function PeopleProfileTab() { ); const onSubmit = handleSubmit((data) => { + const input = { + id: people.id!, + fullName: data.fullName, + primaryEmailAddress: data.primaryEmailAddress, + position: data.position, + additionalEmailAddresses: data.additionalEmailAddresses, + kind: people.kind, + contractStartDate: formatDatetime(data.contractStartDate) ?? null, + contractEndDate: formatDatetime(data.contractEndDate) ?? null, + }; + mutate({ - variables: { - input: { - id: people.id!, - fullName: data.fullName, - primaryEmailAddress: data.primaryEmailAddress, - position: data.position, - additionalEmailAddresses: data.additionalEmailAddresses, - // TODO : make these field optional in the query (server side) - kind: people.kind, - }, - }, + variables: { input }, onCompleted: () => { reset(data); }, @@ -80,6 +85,12 @@ export default function PeopleProfileTab() { type="email" /> + + + + + +
{formState.isDirty && ( diff --git a/apps/console/src/pages/organizations/people/tabs/PeopleRoleTab.tsx b/apps/console/src/pages/organizations/people/tabs/PeopleRoleTab.tsx index 6f25bad5f..33d00edda 100644 --- a/apps/console/src/pages/organizations/people/tabs/PeopleRoleTab.tsx +++ b/apps/console/src/pages/organizations/people/tabs/PeopleRoleTab.tsx @@ -47,6 +47,8 @@ export default function PeopleRoleTab() { fullName: people.fullName!, primaryEmailAddress: people.primaryEmailAddress!, additionalEmailAddresses: people.additionalEmailAddresses ?? [], + contractStartDate: people.contractStartDate, + contractEndDate: people.contractEndDate, }, }, onCompleted: () => { diff --git a/packages/helpers/src/date.ts b/packages/helpers/src/date.ts new file mode 100644 index 000000000..3bd8eea30 --- /dev/null +++ b/packages/helpers/src/date.ts @@ -0,0 +1,4 @@ +export function formatDatetime(dateString?: string | null): string | undefined { + if (!dateString) return undefined; + return `${dateString}T00:00:00Z`; +} diff --git a/packages/helpers/src/index.ts b/packages/helpers/src/index.ts index b96d20145..08e6e1dc8 100644 --- a/packages/helpers/src/index.ts +++ b/packages/helpers/src/index.ts @@ -18,3 +18,4 @@ export { getAssetTypeVariant, getCriticityVariant } from "./assets"; export { getAuditStateLabel, getAuditStateVariant, auditStates } from "./audits"; export { promisifyMutation } from "./relay"; export { fileType, fileSize } from "./file"; +export { formatDatetime } from "./date"; diff --git a/pkg/coredata/people.go b/pkg/coredata/people.go index 1b8848f4d..d7466b4cc 100644 --- a/pkg/coredata/people.go +++ b/pkg/coredata/people.go @@ -300,6 +300,7 @@ func (p *Peoples) CountByOrganizationID( conn pg.Conn, scope Scoper, organizationID gid.GID, + filter *PeopleFilter, ) (int, error) { q := ` SELECT @@ -309,12 +310,14 @@ FROM WHERE %s AND organization_id = @organization_id + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) row := conn.QueryRow(ctx, q, args) @@ -333,6 +336,7 @@ func (p *Peoples) LoadByOrganizationID( scope Scoper, organizationID gid.GID, cursor *page.Cursor[PeopleOrderField], + filter *PeopleFilter, ) error { q := ` SELECT @@ -354,13 +358,15 @@ WHERE %s AND organization_id = @organization_id AND %s + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, cursor.SQLArguments()) maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) rows, err := conn.Query(ctx, q, args) if err != nil { diff --git a/pkg/coredata/people_filter.go b/pkg/coredata/people_filter.go new file mode 100644 index 000000000..36a656d2f --- /dev/null +++ b/pkg/coredata/people_filter.go @@ -0,0 +1,53 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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. + +package coredata + +import ( + "time" + + "github.com/jackc/pgx/v5" +) + +type ( + PeopleFilter struct { + excludeContractEnded *bool + currentDate time.Time + } +) + +func NewPeopleFilter(excludeContractEnded *bool) *PeopleFilter { + return &PeopleFilter{ + excludeContractEnded: excludeContractEnded, + currentDate: time.Now(), + } +} + +func (f *PeopleFilter) SQLArguments() pgx.StrictNamedArgs { + return pgx.StrictNamedArgs{ + "exclude_contract_ended": f.excludeContractEnded, + "current_date": f.currentDate, + } +} + +func (f *PeopleFilter) SQLFragment() string { + return ` +( + CASE + WHEN @exclude_contract_ended::boolean IS NOT NULL AND @exclude_contract_ended::boolean = true THEN + (contract_end_date IS NULL OR contract_end_date >= @current_date::date) + ELSE TRUE + END +)` +} diff --git a/pkg/probo/people_service.go b/pkg/probo/people_service.go index c8cc6ca26..1a9d00755 100644 --- a/pkg/probo/people_service.go +++ b/pkg/probo/people_service.go @@ -98,6 +98,7 @@ func (s PeopleService) GetByUserID( func (s PeopleService) CountForOrganizationID( ctx context.Context, organizationID gid.GID, + filter *coredata.PeopleFilter, ) (int, error) { var count int @@ -105,7 +106,7 @@ func (s PeopleService) CountForOrganizationID( ctx, func(conn pg.Conn) (err error) { peoples := coredata.Peoples{} - count, err = peoples.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID) + count, err = peoples.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter) if err != nil { return fmt.Errorf("cannot count peoples: %w", err) } @@ -125,6 +126,7 @@ func (s PeopleService) ListForOrganizationID( ctx context.Context, organizationID gid.GID, cursor *page.Cursor[coredata.PeopleOrderField], + filter *coredata.PeopleFilter, ) (*page.Page[*coredata.People, coredata.PeopleOrderField], error) { var peoples coredata.Peoples @@ -137,6 +139,7 @@ func (s PeopleService) ListForOrganizationID( s.svc.scope, organizationID, cursor, + filter, ) }, ) diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index e951ccf8f..5e1ac6d72 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -718,6 +718,10 @@ input RiskFilter { query: String } +input PeopleFilter { + excludeContractEnded: Boolean +} + input OrganizationFilter { trustCenterSlug: String } @@ -796,6 +800,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: PeopleOrder + filter: PeopleFilter ): PeopleConnection! @goField(forceResolver: true) documents( diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 84529a5e7..71f4a1c6a 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -665,7 +665,7 @@ type ComplexityRoot struct { LogoURL func(childComplexity int) int Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) int Name func(childComplexity int) int - Peoples func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy) int + Peoples func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy, filter *types.PeopleFilter) int Risks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) int Tasks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) int TrustCenter func(childComplexity int) int @@ -1212,7 +1212,7 @@ type OrganizationResolver interface { Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FrameworkOrderBy) (*types.FrameworkConnection, error) Controls(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) Vendors(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) - Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy) (*types.PeopleConnection, error) + Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy, filter *types.PeopleFilter) (*types.PeopleConnection, error) Documents(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) Measures(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) Risks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) @@ -4009,7 +4009,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Organization.Peoples(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.PeopleOrderBy)), true + return e.complexity.Organization.Peoples(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.PeopleOrderBy), args["filter"].(*types.PeopleFilter)), true case "Organization.risks": if e.complexity.Organization.Risks == nil { @@ -5551,6 +5551,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputMeasureOrder, ec.unmarshalInputOrganizationFilter, ec.unmarshalInputOrganizationOrder, + ec.unmarshalInputPeopleFilter, ec.unmarshalInputPeopleOrder, ec.unmarshalInputPublishDocumentVersionInput, ec.unmarshalInputRemoveUserInput, @@ -6402,6 +6403,10 @@ input RiskFilter { query: String } +input PeopleFilter { + excludeContractEnded: Boolean +} + input OrganizationFilter { trustCenterSlug: String } @@ -6480,6 +6485,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: PeopleOrder + filter: PeopleFilter ): PeopleConnection! @goField(forceResolver: true) documents( @@ -12229,6 +12235,11 @@ func (ec *executionContext) field_Organization_peoples_args(ctx context.Context, return nil, err } args["orderBy"] = arg4 + arg5, err := ec.field_Organization_peoples_argsFilter(ctx, rawArgs) + if err != nil { + return nil, err + } + args["filter"] = arg5 return args, nil } func (ec *executionContext) field_Organization_peoples_argsFirst( @@ -12296,6 +12307,19 @@ func (ec *executionContext) field_Organization_peoples_argsOrderBy( return zeroVal, nil } +func (ec *executionContext) field_Organization_peoples_argsFilter( + ctx context.Context, + rawArgs map[string]any, +) (*types.PeopleFilter, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + if tmp, ok := rawArgs["filter"]; ok { + return ec.unmarshalOPeopleFilter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeopleFilter(ctx, tmp) + } + + var zeroVal *types.PeopleFilter + return zeroVal, nil +} + func (ec *executionContext) field_Organization_risks_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -30201,7 +30225,7 @@ func (ec *executionContext) _Organization_peoples(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Organization().Peoples(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.PeopleOrderBy)) + return ec.resolvers.Organization().Peoples(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.PeopleOrderBy), fc.Args["filter"].(*types.PeopleFilter)) }) if err != nil { ec.Error(ctx, err) @@ -45554,6 +45578,33 @@ func (ec *executionContext) unmarshalInputOrganizationOrder(ctx context.Context, return it, nil } +func (ec *executionContext) unmarshalInputPeopleFilter(ctx context.Context, obj any) (types.PeopleFilter, error) { + var it types.PeopleFilter + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"excludeContractEnded"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "excludeContractEnded": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("excludeContractEnded")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + it.ExcludeContractEnded = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputPeopleOrder(ctx context.Context, obj any) (types.PeopleOrderBy, error) { var it types.PeopleOrderBy asMap := map[string]any{} @@ -63240,6 +63291,14 @@ func (ec *executionContext) marshalOPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋ return ec._People(ctx, sel, v) } +func (ec *executionContext) unmarshalOPeopleFilter2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeopleFilter(ctx context.Context, v any) (*types.PeopleFilter, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputPeopleFilter(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, v any) (*coredata.PeopleKind, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/people.go b/pkg/server/api/console/v1/types/people.go index c41dba7d5..9fef8a9fc 100644 --- a/pkg/server/api/console/v1/types/people.go +++ b/pkg/server/api/console/v1/types/people.go @@ -30,6 +30,7 @@ type ( Resolver any ParentID gid.GID + Filters *coredata.PeopleFilter } ) @@ -37,6 +38,7 @@ func NewPeopleConnection( p *page.Page[*coredata.People, coredata.PeopleOrderField], parentType any, parentID gid.GID, + filters *coredata.PeopleFilter, ) *PeopleConnection { var edges = make([]*PeopleEdge, len(p.Data)) @@ -50,6 +52,7 @@ func NewPeopleConnection( Resolver: parentType, ParentID: parentID, + Filters: filters, } } diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index f0e9d599f..e77b622b3 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -907,6 +907,10 @@ type PeopleEdge struct { Node *People `json:"node"` } +type PeopleFilter struct { + ExcludeContractEnded *bool `json:"excludeContractEnded,omitempty"` +} + type PublishDocumentVersionInput struct { DocumentID gid.GID `json:"documentId"` Changelog *string `json:"changelog,omitempty"` diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index cb3695841..2e5c3497a 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -2587,7 +2587,7 @@ func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organizat } // Peoples is the resolver for the peoples field. -func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy) (*types.PeopleConnection, error) { +func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy, filter *types.PeopleFilter) (*types.PeopleConnection, error) { prb := r.ProboService(ctx, obj.ID.TenantID()) pageOrderBy := page.OrderBy[coredata.PeopleOrderField]{ @@ -2603,12 +2603,17 @@ func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organizat cursor := types.NewCursor(first, after, last, before, pageOrderBy) - page, err := prb.Peoples.ListForOrganizationID(ctx, obj.ID, cursor) + var peopleFilter = coredata.NewPeopleFilter(nil) + if filter != nil { + peopleFilter = coredata.NewPeopleFilter(filter.ExcludeContractEnded) + } + + page, err := prb.Peoples.ListForOrganizationID(ctx, obj.ID, cursor, peopleFilter) if err != nil { panic(fmt.Errorf("cannot list organization peoples: %w", err)) } - return types.NewPeopleConnection(page, r, obj.ID), nil + return types.NewPeopleConnection(page, r, obj.ID, peopleFilter), nil } // Documents is the resolver for the documents field. @@ -2819,7 +2824,7 @@ func (r *peopleConnectionResolver) TotalCount(ctx context.Context, obj *types.Pe switch obj.Resolver.(type) { case *organizationResolver: - count, err := prb.Peoples.CountForOrganizationID(ctx, obj.ParentID) + count, err := prb.Peoples.CountForOrganizationID(ctx, obj.ParentID, obj.Filters) if err != nil { return 0, fmt.Errorf("cannot count peoples: %w", err) }