Add people position

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-07-11 09:05:00 +02:00
parent 452c1b5381
commit 6fda84e5c7
10 changed files with 95 additions and 25 deletions

View File

@@ -80,6 +80,7 @@ const paginatedPeopleFragment = graphql`
fullName
primaryEmailAddress
kind
position
additionalEmailAddresses
}
}
@@ -157,6 +158,7 @@ export const peopleNodeQuery = graphql`
id
fullName
primaryEmailAddress
position
kind
additionalEmailAddresses
}
@@ -171,6 +173,7 @@ export const updatePeopleMutation = graphql`
id
fullName
primaryEmailAddress
position
kind
additionalEmailAddresses
}

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<006f8f3dc3c4d41a23cc71a870aa571c>>
* @generated SignedSource<<71df408810680ded020fb0e1cc93ff79>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -19,6 +19,7 @@ export type PeopleGraphNodeQuery$data = {
readonly fullName?: string;
readonly id?: string;
readonly kind?: PeopleKind;
readonly position?: string | null | undefined;
readonly primaryEmailAddress?: string;
};
};
@@ -67,10 +68,17 @@ v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "kind",
"name": "position",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "kind",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
@@ -99,7 +107,8 @@ return {
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/)
(v6/*: any*/),
(v7/*: any*/)
],
"type": "People",
"abstractKey": null
@@ -139,7 +148,8 @@ return {
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/)
(v6/*: any*/),
(v7/*: any*/)
],
"type": "People",
"abstractKey": null
@@ -150,16 +160,16 @@ return {
]
},
"params": {
"cacheID": "319f5f4ff11db061920a25bbfda43244",
"cacheID": "850de97d42fdda9d2335c0e5219fd067",
"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 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 }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "b4e6fe403e30fbc27ae638d464ad7543";
(node as any).hash = "f39d45664dba2b3bcdad07ef8baebfe9";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e4fcd65491a7570cf56382a3f977e06d>>
* @generated SignedSource<<5eba326084bfab4966727af60e2aa85c>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -21,6 +21,7 @@ export type PeopleGraphPaginatedFragment$data = {
readonly fullName: string;
readonly id: string;
readonly kind: PeopleKind;
readonly position: string | null | undefined;
readonly primaryEmailAddress: string;
};
}>;
@@ -159,6 +160,13 @@ return {
"name": "kind",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "position",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -247,6 +255,6 @@ return {
};
})();
(node as any).hash = "c163b7909a337efd22088852b9908045";
(node as any).hash = "5e095baf6a65e7cdbaa804d4658cbb6b";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<43878b22fe8a689f41bcd506711ddb5f>>
* @generated SignedSource<<1ec11120f71d4bc3040bcdd2665904c0>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -160,6 +160,13 @@ return {
"name": "kind",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "position",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -256,12 +263,12 @@ return {
]
},
"params": {
"cacheID": "b154e94ac7e783a492bc5aed7d44229d",
"cacheID": "1139d090f54b12e62e08f0a1970c9af0",
"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 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) {\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"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<b798b75c1d930af818109fd819d5cef3>>
* @generated SignedSource<<18d62863109c347d5fcf7b5701a9c57b>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -30,6 +30,7 @@ export type PeopleGraphUpdateMutation$data = {
readonly fullName: string;
readonly id: string;
readonly kind: PeopleKind;
readonly position: string | null | undefined;
readonly primaryEmailAddress: string;
};
};
@@ -91,6 +92,13 @@ v1 = [
"name": "primaryEmailAddress",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "position",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -130,16 +138,16 @@ return {
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "c61ca0a6b20067ce5e0c708fc55509d8",
"cacheID": "814551d1fb24548c41d417342625071f",
"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 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 }\n }\n}\n"
}
};
})();
(node as any).hash = "48c2618963704a8cd3b1f0a68817cdad";
(node as any).hash = "ecc5666046434d5c8e80eaab0e508c11";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e7dfc0de7524eaa22ca235ac0b6e3011>>
* @generated SignedSource<<4cfc7218bc48a818eedc2ea87ac521e6>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -233,6 +233,13 @@ return {
"name": "kind",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "position",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -329,16 +336,16 @@ return {
]
},
"params": {
"cacheID": "a17ff68897dbcf3daa33b073bc83f1bb",
"cacheID": "8134caa0eab10c19236a49728f1f77b6",
"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 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 $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"
}
};
})();
(node as any).hash = "c163b7909a337efd22088852b9908045";
(node as any).hash = "5e095baf6a65e7cdbaa804d4658cbb6b";
export default node;

View File

@@ -59,6 +59,7 @@ export default function PeopleListPage({
<Tr>
<SortableTh field="FULL_NAME">{__("Name")}</SortableTh>
<SortableTh field="KIND">{__("Role")}</SortableTh>
<Th>{__("Position")}</Th>
<Th>{__("Actions")}</Th>
</Tr>
</Thead>
@@ -101,6 +102,7 @@ function PeopleRow({
</div>
</Td>
<Td className="text-sm">{getRole(__, people.kind)}</Td>
<Td className="text-sm">{people.position}</Td>
<Td noLink width={50} className="text-end">
<ActionDropdown>
<DropdownItem

View File

@@ -26,11 +26,12 @@ type Props = {
const schema = z.object({
fullName: z.string().min(1),
position: z.string().min(1),
primaryEmailAddress: z.string().email(),
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),
});
@@ -46,6 +47,7 @@ export const createPeopleMutation = graphql`
id
fullName
primaryEmailAddress
position
kind
additionalEmailAddresses
}
@@ -103,6 +105,12 @@ export function CreatePeopleDialog({ children, connectionId }: Props) {
{...register("primaryEmailAddress")}
type="email"
/>
<Field
label={__("Position")}
{...register("position")}
type="text"
placeholder={__("e.g. CEO, CFO, etc.")}
/>
<ControlledField
control={control}
name="kind"

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<fce211be2cfe7f4b313cf2db7f4f127c>>
* @generated SignedSource<<cf446d4f8991b5ff332b3d81174c3247>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -32,6 +32,7 @@ export type CreatePeopleDialogMutation$data = {
readonly fullName: string;
readonly id: string;
readonly kind: PeopleKind;
readonly position: string | null | undefined;
readonly primaryEmailAddress: string;
};
};
@@ -97,6 +98,13 @@ v3 = {
"name": "primaryEmailAddress",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "position",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -183,16 +191,16 @@ return {
]
},
"params": {
"cacheID": "634c2845825a02a0343c3211b41c90a0",
"cacheID": "4065779551f13f5555fa8a0f1b1ae54c",
"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 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 }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "867aad1276c26bd787ddf80c6f166abe";
(node as any).hash = "1fbca12cb827104dc700c70a677f92aa";
export default node;

View File

@@ -13,6 +13,7 @@ import { EmailsField } from "/components/form/EmailsField";
const schema = z.object({
fullName: z.string().min(1),
primaryEmailAddress: z.string().email(),
position: z.string().min(1).nullable(),
additionalEmailAddresses: z.preprocess(
// Empty additional emails are skipped
(v) => (v as string[]).filter((v) => !!v),
@@ -32,6 +33,7 @@ export default function PeopleProfileTab() {
kind: people.kind,
fullName: people.fullName,
primaryEmailAddress: people.primaryEmailAddress,
position: people.position,
additionalEmailAddresses: [...(people.additionalEmailAddresses ?? [])],
},
});
@@ -50,6 +52,7 @@ export default function PeopleProfileTab() {
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,
@@ -65,6 +68,12 @@ export default function PeopleProfileTab() {
<form onSubmit={onSubmit} className="space-y-4">
<Card padded className="space-y-4">
<Field label={__("Full name")} {...register("fullName")} type="text" />
<Field
label={__("Position")}
{...register("position")}
type="text"
placeholder={__("e.g. CEO, CFO, etc.")}
/>
<Field
label={__("Primary email")}
{...register("primaryEmailAddress")}