Fix console app graphQL queries
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<beba83081139a0721dd1ca6e169c56f2>>
|
* @generated SignedSource<<dcdbded62e85b824993721946b5e5e2e>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -19,7 +19,7 @@ export type MembershipsDropdownMenuQuery$data = {
|
|||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly membership: {
|
readonly membership: {
|
||||||
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdownMenuItemFragment">;
|
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdownMenuItemFragment">;
|
||||||
} | null | undefined;
|
};
|
||||||
readonly organization: {
|
readonly organization: {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdownMenuItem_organizationFragment">;
|
readonly " $fragmentSpreads": FragmentRefs<"MembershipsDropdownMenuItem_organizationFragment">;
|
||||||
@@ -134,6 +134,8 @@ return {
|
|||||||
"action": "THROW"
|
"action": "THROW"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"kind": "RequiredField",
|
||||||
|
"field": {
|
||||||
"alias": null,
|
"alias": null,
|
||||||
"args": null,
|
"args": null,
|
||||||
"concreteType": "Membership",
|
"concreteType": "Membership",
|
||||||
@@ -148,6 +150,8 @@ return {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
|
},
|
||||||
|
"action": "THROW"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -289,6 +293,6 @@ return {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "14dbd79243ffb6104ff7315b78aa7990";
|
(node as any).hash = "11d7ec7c24e0e539fd42e428d71998e1";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<5916f4df5b8113a300774131759cb218>>
|
* @generated SignedSource<<b6eef6dfea77fdf5e4e151eef11f4484>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -285,6 +285,19 @@ return {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "permission",
|
"name": "permission",
|
||||||
"storageKey": "permission(action:\"iam:membership:update\")"
|
"storageKey": "permission(action:\"iam:membership:update\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "canDelete",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:membership-profile:delete"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:membership-profile:delete\")"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -328,19 +341,6 @@ return {
|
|||||||
"name": "permission",
|
"name": "permission",
|
||||||
"storageKey": "permission(action:\"iam:membership-profile:update\")"
|
"storageKey": "permission(action:\"iam:membership-profile:update\")"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"alias": "canDelete",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "iam:membership-profile:delete"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"iam:membership-profile:delete\")"
|
|
||||||
},
|
|
||||||
(v11/*: any*/)
|
(v11/*: any*/)
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -430,12 +430,12 @@ return {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "3ed525921615d7910d784222c189566a",
|
"cacheID": "25aa17e466fdec627ba3d24d5230301b",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "PeopleListFragment_RefetchQuery",
|
"name": "PeopleListFragment_RefetchQuery",
|
||||||
"operationKind": "query",
|
"operationKind": "query",
|
||||||
"text": "query PeopleListFragment_RefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: ProfileOrder = {direction: ASC, field: FULL_NAME}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...PeopleListFragment_16fISc\n id\n }\n}\n\nfragment PeopleListFragment_16fISc on Organization {\n profiles(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n ...PeopleListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment PeopleListItemFragment on Profile {\n id\n fullName\n kind\n position\n membership {\n id\n role\n source\n state\n canUpdate: permission(action: \"iam:membership:update\")\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership-profile:update\")\n canDelete: permission(action: \"iam:membership-profile:delete\")\n}\n"
|
"text": "query PeopleListFragment_RefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: ProfileOrder = {direction: ASC, field: FULL_NAME}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...PeopleListFragment_16fISc\n id\n }\n}\n\nfragment PeopleListFragment_16fISc on Organization {\n profiles(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n ...PeopleListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment PeopleListItemFragment on Profile {\n id\n fullName\n kind\n position\n membership {\n id\n role\n source\n state\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership-profile:delete\")\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership-profile:update\")\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<b56389d57c3d4cb31dd873feaeff2bb3>>
|
* @generated SignedSource<<6e9b0a4fbf6ce65f11f2367f2ec5b6d4>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -15,7 +15,6 @@ export type MembershipState = "ACTIVE" | "INACTIVE";
|
|||||||
export type ProfileKind = "CONTRACTOR" | "EMPLOYEE" | "SERVICE_ACCOUNT";
|
export type ProfileKind = "CONTRACTOR" | "EMPLOYEE" | "SERVICE_ACCOUNT";
|
||||||
import { FragmentRefs } from "relay-runtime";
|
import { FragmentRefs } from "relay-runtime";
|
||||||
export type PeopleListItemFragment$data = {
|
export type PeopleListItemFragment$data = {
|
||||||
readonly canDelete: boolean;
|
|
||||||
readonly canUpdate: boolean;
|
readonly canUpdate: boolean;
|
||||||
readonly createdAt: string;
|
readonly createdAt: string;
|
||||||
readonly fullName: string;
|
readonly fullName: string;
|
||||||
@@ -25,6 +24,7 @@ export type PeopleListItemFragment$data = {
|
|||||||
};
|
};
|
||||||
readonly kind: ProfileKind;
|
readonly kind: ProfileKind;
|
||||||
readonly membership: {
|
readonly membership: {
|
||||||
|
readonly canDelete: boolean;
|
||||||
readonly canUpdate: boolean;
|
readonly canUpdate: boolean;
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly role: MembershipRole;
|
readonly role: MembershipRole;
|
||||||
@@ -119,6 +119,19 @@ return {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "permission",
|
"name": "permission",
|
||||||
"storageKey": "permission(action:\"iam:membership:update\")"
|
"storageKey": "permission(action:\"iam:membership:update\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "canDelete",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:membership-profile:delete"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:membership-profile:delete\")"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -166,19 +179,6 @@ return {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "permission",
|
"name": "permission",
|
||||||
"storageKey": "permission(action:\"iam:membership-profile:update\")"
|
"storageKey": "permission(action:\"iam:membership-profile:update\")"
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": "canDelete",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "iam:membership-profile:delete"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"iam:membership-profile:delete\")"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"type": "Profile",
|
"type": "Profile",
|
||||||
@@ -186,6 +186,6 @@ return {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "5f45ee7c58d50b0a6569c3bd22ffc83f";
|
(node as any).hash = "89702fbdf02294212269adb22efb65fe";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<53070e63046901877444d5de41cc8624>>
|
* @generated SignedSource<<e628337d33e88ca5cfe6e45a55eebe32>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -396,6 +396,19 @@ return {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "permission",
|
"name": "permission",
|
||||||
"storageKey": "permission(action:\"iam:membership:update\")"
|
"storageKey": "permission(action:\"iam:membership:update\")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "canDelete",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "action",
|
||||||
|
"value": "iam:membership-profile:delete"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "permission",
|
||||||
|
"storageKey": "permission(action:\"iam:membership-profile:delete\")"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -427,19 +440,6 @@ return {
|
|||||||
"name": "permission",
|
"name": "permission",
|
||||||
"storageKey": "permission(action:\"iam:membership-profile:update\")"
|
"storageKey": "permission(action:\"iam:membership-profile:update\")"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"alias": "canDelete",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "iam:membership-profile:delete"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"iam:membership-profile:delete\")"
|
|
||||||
},
|
|
||||||
(v2/*: any*/)
|
(v2/*: any*/)
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -552,12 +552,12 @@ return {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "d13993ce884669894f65925a714aeaa6",
|
"cacheID": "4303ec6c2fa72181d747bb9053446aaa",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "PeoplePageQuery",
|
"name": "PeoplePageQuery",
|
||||||
"operationKind": "query",
|
"operationKind": "query",
|
||||||
"text": "query PeoplePageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n canInviteUser: permission(action: \"iam:invitation:create\")\n profiles(first: 20, orderBy: {direction: ASC, field: FULL_NAME}) {\n totalCount\n }\n ...PeopleListFragment_8lnpd\n invitations(first: 20, orderBy: {direction: DESC, field: CREATED_AT}) {\n totalCount\n __typename\n }\n ...InvitationListFragment_1PypFi\n }\n id\n }\n}\n\nfragment InvitationListFragment_1PypFi on Organization {\n invitations(first: 20, orderBy: {direction: DESC, field: CREATED_AT}) {\n edges {\n node {\n id\n ...InvitationListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment InvitationListItemFragment on Invitation {\n id\n fullName\n email\n role\n status\n createdAt\n acceptedAt\n canDelete: permission(action: \"iam:invitation:delete\")\n}\n\nfragment PeopleListFragment_8lnpd on Organization {\n profiles(first: 20, orderBy: {direction: ASC, field: FULL_NAME}) {\n totalCount\n edges {\n node {\n id\n ...PeopleListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment PeopleListItemFragment on Profile {\n id\n fullName\n kind\n position\n membership {\n id\n role\n source\n state\n canUpdate: permission(action: \"iam:membership:update\")\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership-profile:update\")\n canDelete: permission(action: \"iam:membership-profile:delete\")\n}\n"
|
"text": "query PeoplePageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n canInviteUser: permission(action: \"iam:invitation:create\")\n profiles(first: 20, orderBy: {direction: ASC, field: FULL_NAME}) {\n totalCount\n }\n ...PeopleListFragment_8lnpd\n invitations(first: 20, orderBy: {direction: DESC, field: CREATED_AT}) {\n totalCount\n __typename\n }\n ...InvitationListFragment_1PypFi\n }\n id\n }\n}\n\nfragment InvitationListFragment_1PypFi on Organization {\n invitations(first: 20, orderBy: {direction: DESC, field: CREATED_AT}) {\n edges {\n node {\n id\n ...InvitationListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment InvitationListItemFragment on Invitation {\n id\n fullName\n email\n role\n status\n createdAt\n acceptedAt\n canDelete: permission(action: \"iam:invitation:delete\")\n}\n\nfragment PeopleListFragment_8lnpd on Organization {\n profiles(first: 20, orderBy: {direction: ASC, field: FULL_NAME}) {\n totalCount\n edges {\n node {\n id\n ...PeopleListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment PeopleListItemFragment on Profile {\n id\n fullName\n kind\n position\n membership {\n id\n role\n source\n state\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership-profile:delete\")\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership-profile:update\")\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<405fdde1b279cf7336ca395457041b93>>
|
* @generated SignedSource<<2e75f19fcdaf2b78a187c33458c9cfe0>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -23,7 +23,7 @@ export type PersonPageQuery$data = {
|
|||||||
};
|
};
|
||||||
readonly membership: {
|
readonly membership: {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
} | null | undefined;
|
};
|
||||||
readonly " $fragmentSpreads": FragmentRefs<"PersonFormFragment">;
|
readonly " $fragmentSpreads": FragmentRefs<"PersonFormFragment">;
|
||||||
} | {
|
} | {
|
||||||
// This will never be '%other', but we need some
|
// This will never be '%other', but we need some
|
||||||
@@ -126,7 +126,11 @@ return {
|
|||||||
"kind": "InlineFragment",
|
"kind": "InlineFragment",
|
||||||
"selections": [
|
"selections": [
|
||||||
(v3/*: any*/),
|
(v3/*: any*/),
|
||||||
(v5/*: any*/),
|
{
|
||||||
|
"kind": "RequiredField",
|
||||||
|
"field": (v5/*: any*/),
|
||||||
|
"action": "THROW"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "RequiredField",
|
"kind": "RequiredField",
|
||||||
"field": {
|
"field": {
|
||||||
@@ -265,6 +269,6 @@ return {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "24863216f5484c1fae7ff6ad002a7f8c";
|
(node as any).hash = "5dce91fda9224f6f3928d4549485d3bd";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -18,19 +18,22 @@ import { MembershipCard } from "./_components/MembershipCard";
|
|||||||
export const membershipsPageQuery = graphql`
|
export const membershipsPageQuery = graphql`
|
||||||
query MembershipsPageQuery {
|
query MembershipsPageQuery {
|
||||||
viewer @required(action: THROW) {
|
viewer @required(action: THROW) {
|
||||||
memberships(
|
profiles(
|
||||||
first: 1000
|
first: 1000
|
||||||
orderBy: { direction: ASC, field: ORGANIZATION_NAME }
|
orderBy: { direction: ASC, field: ORGANIZATION_NAME }
|
||||||
)
|
)
|
||||||
@connection(key: "MembershipsPage_memberships")
|
@connection(key: "MembershipsPage_profiles")
|
||||||
@required(action: THROW) {
|
@required(action: THROW) {
|
||||||
__id
|
__id
|
||||||
edges @required(action: THROW) {
|
edges @required(action: THROW) {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
|
membership @required(action: THROW) {
|
||||||
...MembershipCardFragment
|
...MembershipCardFragment
|
||||||
|
}
|
||||||
organization @required(action: THROW) {
|
organization @required(action: THROW) {
|
||||||
name
|
name
|
||||||
|
...MembershipCard_organizationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +67,7 @@ export function MembershipsPage(props: {
|
|||||||
const { queryRef } = props;
|
const { queryRef } = props;
|
||||||
const {
|
const {
|
||||||
viewer: {
|
viewer: {
|
||||||
memberships: { __id: membershipConnectionId, edges: initialMemberships },
|
profiles: { edges: initialProfiles },
|
||||||
pendingInvitations: {
|
pendingInvitations: {
|
||||||
__id: pendingInvitationsConnectionId,
|
__id: pendingInvitationsConnectionId,
|
||||||
edges: invitations,
|
edges: invitations,
|
||||||
@@ -72,14 +75,14 @@ export function MembershipsPage(props: {
|
|||||||
},
|
},
|
||||||
} = usePreloadedQuery<MembershipsPageQuery>(membershipsPageQuery, queryRef);
|
} = usePreloadedQuery<MembershipsPageQuery>(membershipsPageQuery, queryRef);
|
||||||
|
|
||||||
const memberships = useMemo(() => {
|
const profiles = useMemo(() => {
|
||||||
if (!search.trim()) {
|
if (!search.trim()) {
|
||||||
return initialMemberships;
|
return initialProfiles;
|
||||||
}
|
}
|
||||||
return initialMemberships.filter(({ node }) =>
|
return initialProfiles.filter(({ node }) =>
|
||||||
node.organization.name.toLowerCase().includes(search.toLowerCase()),
|
node.organization.name.toLowerCase().includes(search.toLowerCase()),
|
||||||
);
|
);
|
||||||
}, [initialMemberships, search]);
|
}, [initialProfiles, search]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -98,14 +101,13 @@ export function MembershipsPage(props: {
|
|||||||
pendingInvitationsConnectionId={
|
pendingInvitationsConnectionId={
|
||||||
pendingInvitationsConnectionId
|
pendingInvitationsConnectionId
|
||||||
}
|
}
|
||||||
membershipConnectionId={membershipConnectionId}
|
|
||||||
key={node.id}
|
key={node.id}
|
||||||
fKey={node}
|
fKey={node}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{initialMemberships.length > 0 && (
|
{initialProfiles.length > 0 && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<h2 className="text-xl font-semibold">
|
<h2 className="text-xl font-semibold">
|
||||||
{__("Your organizations")}
|
{__("Your organizations")}
|
||||||
@@ -118,15 +120,19 @@ export function MembershipsPage(props: {
|
|||||||
onValueChange={setSearch}
|
onValueChange={setSearch}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{memberships.length === 0
|
{profiles.length === 0
|
||||||
? (
|
? (
|
||||||
<div className="text-center text-txt-secondary py-4">
|
<div className="text-center text-txt-secondary py-4">
|
||||||
{__("No organizations found")}
|
{__("No organizations found")}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
memberships.map(({ node }) => (
|
profiles.map(({ node }) => (
|
||||||
<MembershipCard key={node.id} fKey={node} />
|
<MembershipCard
|
||||||
|
key={node.id}
|
||||||
|
fKey={node.membership}
|
||||||
|
organizationFragmentRef={node.organization}
|
||||||
|
/>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,21 +22,17 @@ const fragment = graphql`
|
|||||||
const acceptMutation = graphql`
|
const acceptMutation = graphql`
|
||||||
mutation InvitationCardMutation(
|
mutation InvitationCardMutation(
|
||||||
$input: AcceptInvitationInput!
|
$input: AcceptInvitationInput!
|
||||||
$membershipConnections: [ID!]!
|
# FIXME: profiles
|
||||||
|
# $membershipConnections: [ID!]!
|
||||||
$pendingInvitationConnections: [ID!]!
|
$pendingInvitationConnections: [ID!]!
|
||||||
) {
|
) {
|
||||||
acceptInvitation(input: $input) {
|
acceptInvitation(input: $input) {
|
||||||
invitation {
|
invitation {
|
||||||
id @deleteEdge(connections: $pendingInvitationConnections)
|
id @deleteEdge(connections: $pendingInvitationConnections)
|
||||||
}
|
}
|
||||||
membershipEdge @prependEdge(connections: $membershipConnections) {
|
membership {
|
||||||
node {
|
|
||||||
id
|
id
|
||||||
...MembershipCardFragment
|
...MembershipCardFragment
|
||||||
organization {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,12 +40,11 @@ const acceptMutation = graphql`
|
|||||||
|
|
||||||
interface InvitationCardProps {
|
interface InvitationCardProps {
|
||||||
pendingInvitationsConnectionId: DataID;
|
pendingInvitationsConnectionId: DataID;
|
||||||
membershipConnectionId: DataID;
|
|
||||||
fKey: InvitationCardFragment$key;
|
fKey: InvitationCardFragment$key;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InvitationCard(props: InvitationCardProps) {
|
export function InvitationCard(props: InvitationCardProps) {
|
||||||
const { pendingInvitationsConnectionId, membershipConnectionId, fKey }
|
const { pendingInvitationsConnectionId, fKey }
|
||||||
= props;
|
= props;
|
||||||
|
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
@@ -67,7 +62,6 @@ export function InvitationCard(props: InvitationCardProps) {
|
|||||||
invitationId: invitation.id,
|
invitationId: invitation.id,
|
||||||
},
|
},
|
||||||
pendingInvitationConnections: [pendingInvitationsConnectionId],
|
pendingInvitationConnections: [pendingInvitationsConnectionId],
|
||||||
membershipConnections: [membershipConnectionId],
|
|
||||||
},
|
},
|
||||||
onCompleted: (_, e) => {
|
onCompleted: (_, e) => {
|
||||||
if (e) {
|
if (e) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useFragment } from "react-relay";
|
|||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
|
import type { MembershipCard_organizationFragment$key } from "#/__generated__/iam/MembershipCard_organizationFragment.graphql";
|
||||||
import type { MembershipCardFragment$key } from "#/__generated__/iam/MembershipCardFragment.graphql";
|
import type { MembershipCardFragment$key } from "#/__generated__/iam/MembershipCardFragment.graphql";
|
||||||
|
|
||||||
const fragment = graphql`
|
const fragment = graphql`
|
||||||
@@ -21,26 +22,34 @@ const fragment = graphql`
|
|||||||
id
|
id
|
||||||
expiresAt
|
expiresAt
|
||||||
}
|
}
|
||||||
organization @required(action: THROW) {
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const organizationFragment = graphql`
|
||||||
|
fragment MembershipCard_organizationFragment on Organization {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
logoUrl
|
logoUrl
|
||||||
}
|
}
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface MembershipCardProps {
|
interface MembershipCardProps {
|
||||||
fKey: MembershipCardFragment$key;
|
fKey: MembershipCardFragment$key;
|
||||||
|
organizationFragmentRef: MembershipCard_organizationFragment$key;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MembershipCard(props: MembershipCardProps) {
|
export function MembershipCard(props: MembershipCardProps) {
|
||||||
const { fKey } = props;
|
const { fKey, organizationFragmentRef } = props;
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
|
|
||||||
const { lastSession, organization } = useFragment<MembershipCardFragment$key>(
|
const { lastSession } = useFragment<MembershipCardFragment$key>(
|
||||||
fragment,
|
fragment,
|
||||||
fKey,
|
fKey,
|
||||||
);
|
);
|
||||||
|
const organization = useFragment<MembershipCard_organizationFragment$key>(
|
||||||
|
organizationFragment,
|
||||||
|
organizationFragmentRef,
|
||||||
|
);
|
||||||
const isExpired
|
const isExpired
|
||||||
= lastSession && parseDate(lastSession.expiresAt) < new Date();
|
= lastSession && parseDate(lastSession.expiresAt) < new Date();
|
||||||
const isAssuming = !!lastSession && !isExpired;
|
const isAssuming = !!lastSession && !isExpired;
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ export const viewerMembershipLayoutQuery = graphql`
|
|||||||
...MembershipsDropdown_organizationFragment
|
...MembershipsDropdown_organizationFragment
|
||||||
...ViewerMembershipDropdownFragment
|
...ViewerMembershipDropdownFragment
|
||||||
...SidebarFragment @skip(if: $hideSidebar)
|
...SidebarFragment @skip(if: $hideSidebar)
|
||||||
viewerMembership @required(action: THROW) {
|
viewer @required(action: THROW) {
|
||||||
role
|
|
||||||
profile @required(action: THROW) {
|
|
||||||
fullName
|
fullName
|
||||||
|
membership @required(action: THROW) {
|
||||||
|
role
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,11 +91,11 @@ export function ViewerMembershipLayout(props: {
|
|||||||
<CurrentUser
|
<CurrentUser
|
||||||
value={{
|
value={{
|
||||||
email: viewer.email,
|
email: viewer.email,
|
||||||
fullName: organization.viewerMembership.profile.fullName,
|
fullName: organization.viewer.fullName,
|
||||||
role: organization.viewerMembership.role,
|
role: organization.viewer.membership.role,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Outlet context={organization.viewerMembership.role} />
|
<Outlet context={organization.viewer.membership.role} />
|
||||||
</CurrentUser>
|
</CurrentUser>
|
||||||
</CoreRelayProvider>
|
</CoreRelayProvider>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MembershipsDropdownMenuItem } from "./MembershipsDropdownMenuItem";
|
|||||||
export const membershipsDropdownMenuQuery = graphql`
|
export const membershipsDropdownMenuQuery = graphql`
|
||||||
query MembershipsDropdownMenuQuery {
|
query MembershipsDropdownMenuQuery {
|
||||||
viewer @required(action: THROW) {
|
viewer @required(action: THROW) {
|
||||||
memberships(
|
profiles(
|
||||||
first: 1000
|
first: 1000
|
||||||
orderBy: { direction: ASC, field: ORGANIZATION_NAME }
|
orderBy: { direction: ASC, field: ORGANIZATION_NAME }
|
||||||
) @required(action: THROW) {
|
) @required(action: THROW) {
|
||||||
@@ -17,13 +17,16 @@ export const membershipsDropdownMenuQuery = graphql`
|
|||||||
id
|
id
|
||||||
organization @required(action: THROW) {
|
organization @required(action: THROW) {
|
||||||
name
|
name
|
||||||
|
...MembershipsDropdownMenuItem_organizationFragment
|
||||||
}
|
}
|
||||||
|
membership @required(action: THROW) {
|
||||||
...MembershipsDropdownMenuItemFragment
|
...MembershipsDropdownMenuItemFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface MembershipsDropdownMenuProps {
|
interface MembershipsDropdownMenuProps {
|
||||||
@@ -36,27 +39,27 @@ export function MembershipsDropdownMenu(props: MembershipsDropdownMenuProps) {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
viewer: {
|
viewer: {
|
||||||
memberships: { edges: initialMemberships },
|
profiles: { edges: initialProfiles },
|
||||||
},
|
},
|
||||||
} = usePreloadedQuery<MembershipsDropdownMenuQuery>(
|
} = usePreloadedQuery<MembershipsDropdownMenuQuery>(
|
||||||
membershipsDropdownMenuQuery,
|
membershipsDropdownMenuQuery,
|
||||||
queryRef,
|
queryRef,
|
||||||
);
|
);
|
||||||
|
|
||||||
const memberships = useMemo(() => {
|
const profiles = useMemo(() => {
|
||||||
if (!search) {
|
if (!search) {
|
||||||
return initialMemberships;
|
return initialProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
return initialMemberships.filter(({ node: { organization } }) =>
|
return initialProfiles.filter(({ node: { organization } }) =>
|
||||||
organization.name.toLowerCase().includes(search.toLowerCase()),
|
organization.name.toLowerCase().includes(search.toLowerCase()),
|
||||||
);
|
);
|
||||||
}, [initialMemberships, search]);
|
}, [initialProfiles, search]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{memberships.map(({ node }) => (
|
{profiles.map(({ node }) => (
|
||||||
<MembershipsDropdownMenuItem fKey={node} key={node.id} />
|
<MembershipsDropdownMenuItem fKey={node.membership} organizationFragmentRef={node.organization} key={node.id} />
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useFragment } from "react-relay";
|
|||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
|
import type { MembershipsDropdownMenuItem_organizationFragment$key } from "#/__generated__/iam/MembershipsDropdownMenuItem_organizationFragment.graphql";
|
||||||
import type { MembershipsDropdownMenuItemFragment$key } from "#/__generated__/iam/MembershipsDropdownMenuItemFragment.graphql";
|
import type { MembershipsDropdownMenuItemFragment$key } from "#/__generated__/iam/MembershipsDropdownMenuItemFragment.graphql";
|
||||||
|
|
||||||
const fragment = graphql`
|
const fragment = graphql`
|
||||||
@@ -19,21 +20,27 @@ const fragment = graphql`
|
|||||||
id
|
id
|
||||||
expiresAt
|
expiresAt
|
||||||
}
|
}
|
||||||
organization @required(action: THROW) {
|
|
||||||
id
|
|
||||||
logoUrl
|
|
||||||
name
|
|
||||||
}
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const organizationFragment = graphql`
|
||||||
|
fragment MembershipsDropdownMenuItem_organizationFragment on Organization {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
logoUrl
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function MembershipsDropdownMenuItem(props: {
|
export function MembershipsDropdownMenuItem(props: {
|
||||||
fKey: MembershipsDropdownMenuItemFragment$key;
|
fKey: MembershipsDropdownMenuItemFragment$key;
|
||||||
|
organizationFragmentRef: MembershipsDropdownMenuItem_organizationFragment$key;
|
||||||
}) {
|
}) {
|
||||||
const { fKey } = props;
|
const { fKey, organizationFragmentRef } = props;
|
||||||
|
|
||||||
const { id, lastSession, organization }
|
const { id, lastSession }
|
||||||
= useFragment<MembershipsDropdownMenuItemFragment$key>(fragment, fKey);
|
= useFragment<MembershipsDropdownMenuItemFragment$key>(fragment, fKey);
|
||||||
|
const organization
|
||||||
|
= useFragment<MembershipsDropdownMenuItem_organizationFragment$key>(organizationFragment, organizationFragmentRef);
|
||||||
|
|
||||||
const isAssuming = !!lastSession;
|
const isAssuming = !!lastSession;
|
||||||
const isExpired
|
const isExpired
|
||||||
|
|||||||
@@ -14,18 +14,17 @@ import { useFragment, useMutation } from "react-relay";
|
|||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { ViewerMembershipDropdownFragment$key } from "#/__generated__/iam/ViewerMembershipDropdownFragment.graphql";
|
import type { ViewerMembershipDropdownFragment$key } from "#/__generated__/iam/ViewerMembershipDropdownFragment.graphql";
|
||||||
|
import type { ViewerMembershipDropdownSignOutMutation } from "#/__generated__/iam/ViewerMembershipDropdownSignOutMutation.graphql";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
export const fragment = graphql`
|
export const fragment = graphql`
|
||||||
fragment ViewerMembershipDropdownFragment on Organization {
|
fragment ViewerMembershipDropdownFragment on Organization {
|
||||||
viewerMembership @required(action: THROW) {
|
viewer @required(action: THROW) {
|
||||||
|
fullName
|
||||||
identity @required(action: THROW) {
|
identity @required(action: THROW) {
|
||||||
email
|
email
|
||||||
canListAPIKeys: permission(action: "iam:personal-api-key:list")
|
canListAPIKeys: permission(action: "iam:personal-api-key:list")
|
||||||
}
|
}
|
||||||
profile @required(action: THROW) {
|
|
||||||
fullName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@@ -48,12 +47,12 @@ export function ViewerMembershipDropdown(props: {
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
viewerMembership: {
|
viewer: {
|
||||||
|
fullName,
|
||||||
identity: { canListAPIKeys, email },
|
identity: { canListAPIKeys, email },
|
||||||
profile: { fullName },
|
|
||||||
},
|
},
|
||||||
} = useFragment<ViewerMembershipDropdownFragment$key>(fragment, fKey);
|
} = useFragment<ViewerMembershipDropdownFragment$key>(fragment, fKey);
|
||||||
const [signOut] = useMutation(signOutMutation);
|
const [signOut] = useMutation<ViewerMembershipDropdownSignOutMutation>(signOutMutation);
|
||||||
|
|
||||||
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const peoplePageQuery = graphql`
|
|||||||
__typename
|
__typename
|
||||||
... on Organization {
|
... on Organization {
|
||||||
canInviteUser: permission(action: "iam:invitation:create")
|
canInviteUser: permission(action: "iam:invitation:create")
|
||||||
members(first: 20, orderBy: { direction: ASC, field: FULL_NAME })
|
profiles(first: 20, orderBy: { direction: ASC, field: FULL_NAME })
|
||||||
@required(action: THROW) {
|
@required(action: THROW) {
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
@@ -50,8 +50,8 @@ export function PeoplePage(props: {
|
|||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<"memberships" | "invitations">(
|
const [activeTab, setActiveTab] = useState<"people" | "invitations">(
|
||||||
"memberships",
|
"people",
|
||||||
);
|
);
|
||||||
|
|
||||||
const { organization } = usePreloadedQuery<PeoplePageQuery>(
|
const { organization } = usePreloadedQuery<PeoplePageQuery>(
|
||||||
@@ -85,12 +85,12 @@ export function PeoplePage(props: {
|
|||||||
|
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabItem
|
<TabItem
|
||||||
active={activeTab === "memberships"}
|
active={activeTab === "people"}
|
||||||
onClick={() => setActiveTab("memberships")}
|
onClick={() => setActiveTab("people")}
|
||||||
>
|
>
|
||||||
{__("Members")}
|
{__("People")}
|
||||||
{(organization.members.totalCount ?? 0) > 0 && (
|
{(organization.profiles.totalCount ?? 0) > 0 && (
|
||||||
<TabBadge>{organization.members.totalCount}</TabBadge>
|
<TabBadge>{organization.profiles.totalCount}</TabBadge>
|
||||||
)}
|
)}
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem
|
<TabItem
|
||||||
@@ -105,7 +105,7 @@ export function PeoplePage(props: {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<div className="pb-6 pt-6">
|
<div className="pb-6 pt-6">
|
||||||
{activeTab === "memberships" && <PeopleList fKey={organization} />}
|
{activeTab === "people" && <PeopleList fKey={organization} />}
|
||||||
|
|
||||||
{activeTab === "invitations" && (
|
{activeTab === "invitations" && (
|
||||||
<InvitationList
|
<InvitationList
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ export const personPageQuery = graphql`
|
|||||||
query PersonPageQuery($personId: ID!) {
|
query PersonPageQuery($personId: ID!) {
|
||||||
person: node(id: $personId) @required(action: THROW) {
|
person: node(id: $personId) @required(action: THROW) {
|
||||||
__typename
|
__typename
|
||||||
... on MembershipProfile {
|
... on Profile {
|
||||||
fullName
|
fullName
|
||||||
membershipId
|
membership @required(action: THROW) {
|
||||||
|
id
|
||||||
|
}
|
||||||
identity @required(action: THROW) {
|
identity @required(action: THROW) {
|
||||||
email
|
email
|
||||||
}
|
}
|
||||||
@@ -47,7 +49,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery<PersonPageQuery> })
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { person } = usePreloadedQuery<PersonPageQuery>(personPageQuery, queryRef);
|
const { person } = usePreloadedQuery<PersonPageQuery>(personPageQuery, queryRef);
|
||||||
if (person.__typename !== "MembershipProfile") {
|
if (person.__typename !== "Profile") {
|
||||||
throw new Error("invalid type for node");
|
throw new Error("invalid type for node");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery<PersonPageQuery> })
|
|||||||
return removeMembership({
|
return removeMembership({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
membershipId: person.membershipId,
|
membershipId: person.membership.id,
|
||||||
organizationId: organizationId,
|
organizationId: organizationId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,20 +15,20 @@ const fragment = graphql`
|
|||||||
@argumentDefinitions(
|
@argumentDefinitions(
|
||||||
first: { type: "Int", defaultValue: 20 }
|
first: { type: "Int", defaultValue: 20 }
|
||||||
order: {
|
order: {
|
||||||
type: "MembershipOrder"
|
type: "ProfileOrder"
|
||||||
defaultValue: { direction: ASC, field: FULL_NAME }
|
defaultValue: { direction: ASC, field: FULL_NAME }
|
||||||
}
|
}
|
||||||
after: { type: "CursorKey", defaultValue: null }
|
after: { type: "CursorKey", defaultValue: null }
|
||||||
before: { type: "CursorKey", defaultValue: null }
|
before: { type: "CursorKey", defaultValue: null }
|
||||||
last: { type: "Int", defaultValue: null }
|
last: { type: "Int", defaultValue: null }
|
||||||
) {
|
) {
|
||||||
members(
|
profiles(
|
||||||
first: $first
|
first: $first
|
||||||
after: $after
|
after: $after
|
||||||
last: $last
|
last: $last
|
||||||
before: $before
|
before: $before
|
||||||
orderBy: $order
|
orderBy: $order
|
||||||
) @connection(key: "PeopleListFragment_members", filters: ["orderBy"]) @required(action: THROW) {
|
) @connection(key: "PeopleListFragment_profiles", filters: ["orderBy"]) @required(action: THROW) {
|
||||||
__id
|
__id
|
||||||
totalCount
|
totalCount
|
||||||
edges @required(action: THROW) {
|
edges @required(action: THROW) {
|
||||||
@@ -51,7 +51,7 @@ export function PeopleList(props: { fKey: PeopleListFragment$key }) {
|
|||||||
PeopleListFragment$key
|
PeopleListFragment$key
|
||||||
>(fragment, fKey);
|
>(fragment, fKey);
|
||||||
|
|
||||||
const refetchMemberships = () => {
|
const refetchPeople = () => {
|
||||||
peoplePagination.refetch({}, { fetchPolicy: "network-only" });
|
peoplePagination.refetch({}, { fetchPolicy: "network-only" });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,21 +77,21 @@ export function PeopleList(props: { fKey: PeopleListFragment$key }) {
|
|||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{peoplePagination.data.members.totalCount === 0
|
{peoplePagination.data.profiles.totalCount === 0
|
||||||
? (
|
? (
|
||||||
<Tr>
|
<Tr>
|
||||||
<Td colSpan={7} className="text-center text-txt-secondary">
|
<Td colSpan={7} className="text-center text-txt-secondary">
|
||||||
{__("No members")}
|
{__("No people")}
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
peoplePagination.data.members.edges.map(({ node: membership }) => (
|
peoplePagination.data.profiles.edges.map(({ node: profile }) => (
|
||||||
<MemberListItem
|
<MemberListItem
|
||||||
connectionId={peoplePagination.data.members.__id}
|
connectionId={peoplePagination.data.profiles.__id}
|
||||||
key={membership.id}
|
key={profile.id}
|
||||||
fKey={membership}
|
fKey={profile}
|
||||||
onRefetch={refetchMemberships}
|
onRefetch={refetchPeople}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -22,23 +22,24 @@ import { useOrganizationId } from "#/hooks/useOrganizationId";
|
|||||||
import { EditMemberDialog } from "../../settings/_components/EditMemberDialog";
|
import { EditMemberDialog } from "../../settings/_components/EditMemberDialog";
|
||||||
|
|
||||||
const fragment = graphql`
|
const fragment = graphql`
|
||||||
fragment PeopleListItemFragment on Membership {
|
fragment PeopleListItemFragment on Profile {
|
||||||
id
|
|
||||||
role
|
|
||||||
source
|
|
||||||
state
|
|
||||||
profile @required(action: THROW) {
|
|
||||||
id
|
id
|
||||||
fullName
|
fullName
|
||||||
kind
|
kind
|
||||||
position
|
position
|
||||||
|
membership @required(action: THROW) {
|
||||||
|
id
|
||||||
|
role
|
||||||
|
source
|
||||||
|
state
|
||||||
|
canUpdate: permission(action: "iam:membership:update")
|
||||||
|
canDelete: permission(action: "iam:membership-profile:delete")
|
||||||
}
|
}
|
||||||
identity @required(action: THROW) {
|
identity @required(action: THROW) {
|
||||||
email
|
email
|
||||||
}
|
}
|
||||||
createdAt
|
createdAt
|
||||||
canUpdate: permission(action: "iam:membership:update")
|
canUpdate: permission(action: "iam:membership-profile:update")
|
||||||
canDelete: permission(action: "iam:membership:delete")
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -65,9 +66,9 @@ export function MemberListItem(props: {
|
|||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
|
||||||
const membership = useFragment<PeopleListItemFragment$key>(fragment, fKey);
|
const profile = useFragment<PeopleListItemFragment$key>(fragment, fKey);
|
||||||
|
|
||||||
const isInactive = membership.state === "INACTIVE";
|
const isInactive = profile.membership.state === "INACTIVE";
|
||||||
|
|
||||||
const [removeMembership, isRemoving] = useMutationWithToasts(
|
const [removeMembership, isRemoving] = useMutationWithToasts(
|
||||||
removeMemberMutation,
|
removeMemberMutation,
|
||||||
@@ -83,7 +84,7 @@ export function MemberListItem(props: {
|
|||||||
return removeMembership({
|
return removeMembership({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
membershipId: membership.id,
|
membershipId: profile.membership.id,
|
||||||
organizationId: organizationId,
|
organizationId: organizationId,
|
||||||
},
|
},
|
||||||
connections: [connectionId],
|
connections: [connectionId],
|
||||||
@@ -93,7 +94,7 @@ export function MemberListItem(props: {
|
|||||||
{
|
{
|
||||||
message: sprintf(
|
message: sprintf(
|
||||||
__("Are you sure you want to remove %s?"),
|
__("Are you sure you want to remove %s?"),
|
||||||
membership.profile.fullName,
|
profile.fullName,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -106,33 +107,33 @@ export function MemberListItem(props: {
|
|||||||
isRemoving && "opacity-60 pointer-events-none",
|
isRemoving && "opacity-60 pointer-events-none",
|
||||||
isInactive && "opacity-50",
|
isInactive && "opacity-50",
|
||||||
)}
|
)}
|
||||||
to={`/organizations/${organizationId}/people/${membership.profile.id}`}
|
to={`/organizations/${organizationId}/people/${profile.id}`}
|
||||||
>
|
>
|
||||||
<Td>
|
<Td>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="font-semibold">{membership.profile.fullName}</span>
|
<span className="font-semibold">{profile.fullName}</span>
|
||||||
{isInactive && <Badge variant="neutral">{__("Inactive")}</Badge>}
|
{isInactive && <Badge variant="neutral">{__("Inactive")}</Badge>}
|
||||||
</div>
|
</div>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{membership.identity.email}
|
{profile.identity.email}
|
||||||
<Badge variant="info">{membership.source}</Badge>
|
<Badge variant="info">{profile.membership.source}</Badge>
|
||||||
</div>
|
</div>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{membership.profile.kind}</Td>
|
<Td>{profile.kind}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<Badge>{membership.role}</Badge>
|
<Badge>{profile.membership.role}</Badge>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{new Date(membership.createdAt).toLocaleDateString()}</Td>
|
<Td>{new Date(profile.createdAt).toLocaleDateString()}</Td>
|
||||||
<Td>{membership.profile.position}</Td>
|
<Td>{profile.position}</Td>
|
||||||
<Td noLink width={160} className="text-end">
|
<Td noLink width={160} className="text-end">
|
||||||
{!isInactive && (
|
{!isInactive && (
|
||||||
<div
|
<div
|
||||||
className="flex gap-2 justify-end"
|
className="flex gap-2 justify-end"
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{membership.canUpdate && (
|
{profile.membership.canUpdate && (
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => setDialogOpen(true)}
|
onClick={() => setDialogOpen(true)}
|
||||||
@@ -146,7 +147,7 @@ export function MemberListItem(props: {
|
|||||||
<Spinner size={16} />
|
<Spinner size={16} />
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
membership.canDelete && (
|
profile.membership.canDelete && (
|
||||||
<Button
|
<Button
|
||||||
variant="danger"
|
variant="danger"
|
||||||
onClick={handleRemove}
|
onClick={handleRemove}
|
||||||
@@ -164,7 +165,7 @@ export function MemberListItem(props: {
|
|||||||
{dialogOpen && (
|
{dialogOpen && (
|
||||||
<EditMemberDialog
|
<EditMemberDialog
|
||||||
onClose={() => setDialogOpen(false)}
|
onClose={() => setDialogOpen(false)}
|
||||||
membership={membership}
|
profile={profile}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
|||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
|
|
||||||
const fragment = graphql`
|
const fragment = graphql`
|
||||||
fragment PersonFormFragment on MembershipProfile {
|
fragment PersonFormFragment on Profile {
|
||||||
id
|
id
|
||||||
fullName
|
fullName
|
||||||
kind
|
kind
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ const updateMembershipMutation = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export function EditMemberDialog(props: {
|
export function EditMemberDialog(props: {
|
||||||
membership: PeopleListItemFragment$data;
|
profile: PeopleListItemFragment$data;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { membership, onClose } = props;
|
const { profile, onClose } = props;
|
||||||
|
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
@@ -41,7 +41,7 @@ export function EditMemberDialog(props: {
|
|||||||
const { role } = use(CurrentUser);
|
const { role } = use(CurrentUser);
|
||||||
const availableRoles = getAssignableRoles(role);
|
const availableRoles = getAssignableRoles(role);
|
||||||
|
|
||||||
const [selectedRole, setSelectedRole] = useState<string>(membership.role);
|
const [selectedRole, setSelectedRole] = useState<string>(profile.membership.role);
|
||||||
|
|
||||||
const [updateMembership, isUpdating] = useMutationWithToasts(
|
const [updateMembership, isUpdating] = useMutationWithToasts(
|
||||||
updateMembershipMutation,
|
updateMembershipMutation,
|
||||||
@@ -56,7 +56,7 @@ export function EditMemberDialog(props: {
|
|||||||
await updateMembership({
|
await updateMembership({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
membershipId: membership.id,
|
membershipId: profile.membership.id,
|
||||||
organizationId: organizationId,
|
organizationId: organizationId,
|
||||||
role: selectedRole,
|
role: selectedRole,
|
||||||
},
|
},
|
||||||
@@ -73,7 +73,7 @@ export function EditMemberDialog(props: {
|
|||||||
<p className="text-txt-secondary text-sm mb-4">
|
<p className="text-txt-secondary text-sm mb-4">
|
||||||
{sprintf(
|
{sprintf(
|
||||||
__("Update the role for %s"),
|
__("Update the role for %s"),
|
||||||
membership.profile.fullName,
|
profile.fullName,
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ export function EditMemberDialog(props: {
|
|||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isUpdating || selectedRole === membership.role}
|
disabled={isUpdating || selectedRole === profile.membership.role}
|
||||||
>
|
>
|
||||||
{isUpdating && <Spinner />}
|
{isUpdating && <Spinner />}
|
||||||
{__("Update Role")}
|
{__("Update Role")}
|
||||||
|
|||||||
@@ -8,20 +8,16 @@ import type { SCIMEventListItemFragment$key } from "#/__generated__/iam/SCIMEven
|
|||||||
|
|
||||||
const SCIMEventListItemFragment = graphql`
|
const SCIMEventListItemFragment = graphql`
|
||||||
fragment SCIMEventListItemFragment on SCIMEvent {
|
fragment SCIMEventListItemFragment on SCIMEvent {
|
||||||
id
|
|
||||||
method
|
method
|
||||||
path
|
path
|
||||||
statusCode
|
statusCode
|
||||||
errorMessage
|
errorMessage
|
||||||
ipAddress
|
ipAddress
|
||||||
createdAt
|
createdAt
|
||||||
membership {
|
|
||||||
id
|
|
||||||
profile {
|
profile {
|
||||||
fullName
|
fullName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const getResultBadge = (statusCode: number) => {
|
const getResultBadge = (statusCode: number) => {
|
||||||
@@ -93,7 +89,8 @@ export function SCIMEventListItem(props: {
|
|||||||
<div className="flex gap-8 text-sm">
|
<div className="flex gap-8 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<span className="text-txt-secondary">User: </span>
|
<span className="text-txt-secondary">User: </span>
|
||||||
<span>{event.membership?.profile?.fullName || "-"}</span>
|
{/* FIXME */}
|
||||||
|
{/* <span>{event.membership?.profile?.fullName || "-"}</span> */}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="text-txt-secondary">IP Address: </span>
|
<span className="text-txt-secondary">IP Address: </span>
|
||||||
|
|||||||
@@ -736,13 +736,10 @@ WHERE
|
|||||||
args := pgx.StrictNamedArgs{"identity_id": identityID}
|
args := pgx.StrictNamedArgs{"identity_id": identityID}
|
||||||
maps.Copy(args, filter.SQLArguments())
|
maps.Copy(args, filter.SQLArguments())
|
||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
row := conn.QueryRow(ctx, q, args)
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("cannot query iam_membership_profiles: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
err = rows.Scan(&count)
|
err := row.Scan(&count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("cannot collect count: %w", err)
|
return 0, fmt.Errorf("cannot collect count: %w", err)
|
||||||
}
|
}
|
||||||
@@ -774,13 +771,10 @@ WHERE
|
|||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
maps.Copy(args, filter.SQLArguments())
|
maps.Copy(args, filter.SQLArguments())
|
||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
row := conn.QueryRow(ctx, q, args)
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("cannot query iam_membership_profiles: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
err = rows.Scan(&count)
|
err := row.Scan(&count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("cannot collect count: %w", err)
|
return 0, fmt.Errorf("cannot collect count: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, fi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter := coredata.NewMembershipProfileFilter(nil)
|
||||||
|
|
||||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||||
return &types.ProfileConnection{
|
return &types.ProfileConnection{
|
||||||
Resolver: r,
|
Resolver: r,
|
||||||
@@ -45,8 +47,6 @@ func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, fi
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := coredata.NewMembershipProfileFilter(nil)
|
|
||||||
|
|
||||||
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||||
Field: coredata.MembershipProfileOrderFieldFullName,
|
Field: coredata.MembershipProfileOrderFieldFullName,
|
||||||
Direction: page.OrderDirectionAsc,
|
Direction: page.OrderDirectionAsc,
|
||||||
@@ -1247,6 +1247,8 @@ func (r *organizationResolver) Profiles(ctx context.Context, obj *types.Organiza
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter := coredata.NewMembershipProfileFilter(nil)
|
||||||
|
|
||||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||||
return &types.ProfileConnection{
|
return &types.ProfileConnection{
|
||||||
Resolver: r,
|
Resolver: r,
|
||||||
@@ -1254,8 +1256,6 @@ func (r *organizationResolver) Profiles(ctx context.Context, obj *types.Organiza
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := coredata.NewMembershipProfileFilter(nil)
|
|
||||||
|
|
||||||
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
||||||
Field: coredata.MembershipProfileOrderFieldFullName,
|
Field: coredata.MembershipProfileOrderFieldFullName,
|
||||||
Direction: page.OrderDirectionAsc,
|
Direction: page.OrderDirectionAsc,
|
||||||
@@ -1514,7 +1514,7 @@ func (r *profileConnectionResolver) TotalCount(ctx context.Context, obj *types.P
|
|||||||
case *identityResolver:
|
case *identityResolver:
|
||||||
count, err := r.iam.AccountService.CountProfiles(ctx, obj.ParentID, coredata.NewMembershipProfileFilter(nil))
|
count, err := r.iam.AccountService.CountProfiles(ctx, obj.ParentID, coredata.NewMembershipProfileFilter(nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot count sprofiles", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot count profiles", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
return &count, nil
|
return &count, nil
|
||||||
|
|||||||
@@ -6576,7 +6576,7 @@ func (r *profileConnectionResolver) TotalCount(ctx context.Context, obj *types.P
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch obj.Resolver.(type) {
|
switch obj.Resolver.(type) {
|
||||||
case *stateOfApplicabilityResolver:
|
case *organizationResolver:
|
||||||
count, err := r.iam.OrganizationService.CountProfiles(ctx, obj.ParentID, obj.Filters)
|
count, err := r.iam.OrganizationService.CountProfiles(ctx, obj.ParentID, obj.Filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("cannot count profiles: %w", err))
|
panic(fmt.Errorf("cannot count profiles: %w", err))
|
||||||
|
|||||||
Reference in New Issue
Block a user