Fix organization members order and filtering

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-01-19 18:33:36 +04:00
parent 887d39144b
commit 8559a11be5
6 changed files with 118 additions and 104 deletions

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<d0098f8499fc70b98d7264cb756b2c6b>> * @generated SignedSource<<81b275e4cf4b88d7d9e797f5ae20a163>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -67,7 +67,7 @@ return {
{ {
"defaultValue": { "defaultValue": {
"direction": "ASC", "direction": "ASC",
"field": "CREATED_AT" "field": "FULL_NAME"
}, },
"kind": "LocalArgument", "kind": "LocalArgument",
"name": "order" "name": "order"
@@ -239,6 +239,6 @@ return {
}; };
})(); })();
(node as any).hash = "763331f25e735e2645b0c6949ecad362"; (node as any).hash = "c1af7d267ca5d53454869cc8fbf4420c";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<ccb5c8952aaa41ddee0df7e7e3abb2b0>> * @generated SignedSource<<6205161c89403b10363ea54bbb10ccea>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -63,7 +63,7 @@ v4 = {
v5 = { v5 = {
"defaultValue": { "defaultValue": {
"direction": "ASC", "direction": "ASC",
"field": "CREATED_AT" "field": "FULL_NAME"
}, },
"kind": "LocalArgument", "kind": "LocalArgument",
"name": "order" "name": "order"
@@ -403,16 +403,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "bb44371bed2eb3032b52ea5bbb3109c1", "cacheID": "8089993871afc0b3d2c0defd9182c31a",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "MemberListFragment_RefetchQuery", "name": "MemberListFragment_RefetchQuery",
"operationKind": "query", "operationKind": "query",
"text": "query MemberListFragment_RefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: MembershipOrder = {direction: ASC, field: CREATED_AT}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MemberListFragment_16fISc\n id\n }\n}\n\nfragment MemberListFragment_16fISc on Organization {\n members(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n source\n state\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n" "text": "query MemberListFragment_RefetchQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: MembershipOrder = {direction: ASC, field: FULL_NAME}\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...MemberListFragment_16fISc\n id\n }\n}\n\nfragment MemberListFragment_16fISc on Organization {\n members(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n source\n state\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n"
} }
}; };
})(); })();
(node as any).hash = "763331f25e735e2645b0c6949ecad362"; (node as any).hash = "c1af7d267ca5d53454869cc8fbf4420c";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<4d9333564d383b3af80a4d6c2ce68277>> * @generated SignedSource<<11a6b18e62a7a93fa6c2365a7e3a86f6>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -78,17 +78,9 @@ v4 = {
}, },
v5 = { v5 = {
"direction": "ASC", "direction": "ASC",
"field": "CREATED_AT" "field": "FULL_NAME"
}, },
v6 = [ v6 = [
(v4/*: any*/),
{
"kind": "Literal",
"name": "order",
"value": (v5/*: any*/)
}
],
v7 = [
(v4/*: any*/), (v4/*: any*/),
{ {
"kind": "Literal", "kind": "Literal",
@@ -96,56 +88,68 @@ v7 = [
"value": (v5/*: any*/) "value": (v5/*: any*/)
} }
], ],
v8 = { v7 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "totalCount", "name": "totalCount",
"storageKey": null "storageKey": null
}, },
v9 = { v8 = {
"direction": "DESC",
"field": "CREATED_AT"
},
v9 = [
(v4/*: any*/),
{
"kind": "Literal",
"name": "orderBy",
"value": (v8/*: any*/)
}
],
v10 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "id", "name": "id",
"storageKey": null "storageKey": null
}, },
v10 = { v11 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "role", "name": "role",
"storageKey": null "storageKey": null
}, },
v11 = { v12 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "fullName", "name": "fullName",
"storageKey": null "storageKey": null
}, },
v12 = { v13 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "email", "name": "email",
"storageKey": null "storageKey": null
}, },
v13 = { v14 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "createdAt", "name": "createdAt",
"storageKey": null "storageKey": null
}, },
v14 = { v15 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "cursor", "name": "cursor",
"storageKey": null "storageKey": null
}, },
v15 = { v16 = {
"alias": null, "alias": null,
"args": null, "args": null,
"concreteType": "PageInfo", "concreteType": "PageInfo",
@@ -184,7 +188,7 @@ v15 = {
], ],
"storageKey": null "storageKey": null
}, },
v16 = { v17 = {
"kind": "ClientExtension", "kind": "ClientExtension",
"selections": [ "selections": [
{ {
@@ -196,7 +200,7 @@ v16 = {
} }
] ]
}, },
v17 = [ v18 = [
"orderBy" "orderBy"
]; ];
return { return {
@@ -222,7 +226,14 @@ return {
"selections": [ "selections": [
(v3/*: any*/), (v3/*: any*/),
{ {
"args": (v6/*: any*/), "args": [
(v4/*: any*/),
{
"kind": "Literal",
"name": "order",
"value": (v5/*: any*/)
}
],
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "MemberListFragment" "name": "MemberListFragment"
}, },
@@ -230,20 +241,27 @@ return {
"kind": "RequiredField", "kind": "RequiredField",
"field": { "field": {
"alias": null, "alias": null,
"args": (v7/*: any*/), "args": (v6/*: any*/),
"concreteType": "MembershipConnection", "concreteType": "MembershipConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "members", "name": "members",
"plural": false, "plural": false,
"selections": [ "selections": [
(v8/*: any*/) (v7/*: any*/)
], ],
"storageKey": "members(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})" "storageKey": "members(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})"
}, },
"action": "THROW" "action": "THROW"
}, },
{ {
"args": (v6/*: any*/), "args": [
(v4/*: any*/),
{
"kind": "Literal",
"name": "order",
"value": (v8/*: any*/)
}
],
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "InvitationListFragment" "name": "InvitationListFragment"
}, },
@@ -251,20 +269,20 @@ return {
"kind": "RequiredField", "kind": "RequiredField",
"field": { "field": {
"alias": null, "alias": null,
"args": (v7/*: any*/), "args": (v9/*: any*/),
"concreteType": "InvitationConnection", "concreteType": "InvitationConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "invitations", "name": "invitations",
"plural": false, "plural": false,
"selections": [ "selections": [
(v8/*: any*/), (v7/*: any*/),
{ {
"args": null, "args": null,
"kind": "FragmentSpread", "kind": "FragmentSpread",
"name": "MembersPage_invitationsTotalCountFragment" "name": "MembersPage_invitationsTotalCountFragment"
} }
], ],
"storageKey": "invitations(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})" "storageKey": "invitations(first:20,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}, },
"action": "THROW" "action": "THROW"
} }
@@ -296,20 +314,20 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
(v9/*: any*/), (v10/*: any*/),
{ {
"kind": "InlineFragment", "kind": "InlineFragment",
"selections": [ "selections": [
(v3/*: any*/), (v3/*: any*/),
{ {
"alias": null, "alias": null,
"args": (v7/*: any*/), "args": (v6/*: any*/),
"concreteType": "MembershipConnection", "concreteType": "MembershipConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "members", "name": "members",
"plural": false, "plural": false,
"selections": [ "selections": [
(v8/*: any*/), (v7/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -326,8 +344,8 @@ return {
"name": "node", "name": "node",
"plural": false, "plural": false,
"selections": [ "selections": [
(v9/*: any*/),
(v10/*: any*/), (v10/*: any*/),
(v11/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -350,8 +368,8 @@ return {
"name": "profile", "name": "profile",
"plural": false, "plural": false,
"selections": [ "selections": [
(v11/*: any*/), (v12/*: any*/),
(v9/*: any*/) (v10/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
@@ -363,12 +381,12 @@ return {
"name": "identity", "name": "identity",
"plural": false, "plural": false,
"selections": [ "selections": [
(v12/*: any*/), (v13/*: any*/),
(v9/*: any*/) (v10/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v13/*: any*/), (v14/*: any*/),
{ {
"alias": "canUpdate", "alias": "canUpdate",
"args": [ "args": [
@@ -399,19 +417,19 @@ return {
], ],
"storageKey": null "storageKey": null
}, },
(v14/*: any*/) (v15/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v15/*: any*/), (v16/*: any*/),
(v16/*: any*/) (v17/*: any*/)
], ],
"storageKey": "members(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})" "storageKey": "members(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})"
}, },
{ {
"alias": null, "alias": null,
"args": (v7/*: any*/), "args": (v6/*: any*/),
"filters": (v17/*: any*/), "filters": (v18/*: any*/),
"handle": "connection", "handle": "connection",
"key": "MemberListFragment_members", "key": "MemberListFragment_members",
"kind": "LinkedHandle", "kind": "LinkedHandle",
@@ -419,7 +437,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v7/*: any*/), "args": (v9/*: any*/),
"concreteType": "InvitationConnection", "concreteType": "InvitationConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "invitations", "name": "invitations",
@@ -441,10 +459,10 @@ return {
"name": "node", "name": "node",
"plural": false, "plural": false,
"selections": [ "selections": [
(v9/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
(v10/*: any*/), (v10/*: any*/),
(v12/*: any*/),
(v13/*: any*/),
(v11/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -452,7 +470,7 @@ return {
"name": "status", "name": "status",
"storageKey": null "storageKey": null
}, },
(v13/*: any*/), (v14/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -484,21 +502,21 @@ return {
], ],
"storageKey": null "storageKey": null
}, },
(v14/*: any*/) (v15/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
(v15/*: any*/),
(v16/*: any*/), (v16/*: any*/),
(v8/*: any*/), (v17/*: any*/),
(v7/*: any*/),
(v2/*: any*/) (v2/*: any*/)
], ],
"storageKey": "invitations(first:20,orderBy:{\"direction\":\"ASC\",\"field\":\"CREATED_AT\"})" "storageKey": "invitations(first:20,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}, },
{ {
"alias": null, "alias": null,
"args": (v7/*: any*/), "args": (v9/*: any*/),
"filters": (v17/*: any*/), "filters": (v18/*: any*/),
"handle": "connection", "handle": "connection",
"key": "InvitationListFragment_invitations", "key": "InvitationListFragment_invitations",
"kind": "LinkedHandle", "kind": "LinkedHandle",
@@ -514,16 +532,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "bff4e08ce3b3a6923bfb9d24fc609b18", "cacheID": "438ac1a112e204b2a9ff30e3b36ec3ae",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "MembersPageQuery", "name": "MembersPageQuery",
"operationKind": "query", "operationKind": "query",
"text": "query MembersPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n canInviteUser: permission(action: \"iam:invitation:create\")\n ...MemberListFragment_1jRT0c\n members(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n }\n ...InvitationListFragment_1jRT0c\n invitations(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n __typename\n }\n }\n id\n }\n}\n\nfragment InvitationListFragment_1jRT0c on Organization {\n invitations(first: 20, orderBy: {direction: ASC, 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 expiresAt\n acceptedAt\n canDelete: permission(action: \"iam:invitation:delete\")\n}\n\nfragment MemberListFragment_1jRT0c on Organization {\n members(first: 20, orderBy: {direction: ASC, field: CREATED_AT}) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n source\n state\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n" "text": "query MembersPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n canInviteUser: permission(action: \"iam:invitation:create\")\n ...MemberListFragment_8lnpd\n members(first: 20, orderBy: {direction: ASC, field: FULL_NAME}) {\n totalCount\n }\n ...InvitationListFragment_1PypFi\n invitations(first: 20, orderBy: {direction: DESC, field: CREATED_AT}) {\n totalCount\n __typename\n }\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 expiresAt\n acceptedAt\n canDelete: permission(action: \"iam:invitation:delete\")\n}\n\nfragment MemberListFragment_8lnpd on Organization {\n members(first: 20, orderBy: {direction: ASC, field: FULL_NAME}) {\n totalCount\n edges {\n node {\n id\n ...MemberListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment MemberListItemFragment on Membership {\n id\n role\n source\n state\n profile {\n fullName\n id\n }\n identity {\n email\n id\n }\n createdAt\n canUpdate: permission(action: \"iam:membership:update\")\n canDelete: permission(action: \"iam:membership:delete\")\n}\n"
} }
}; };
})(); })();
(node as any).hash = "96c00bf5db547e829eaefb042658be73"; (node as any).hash = "0e24cf08536ed857c6ab8f8ded76947e";
export default node; export default node;

View File

@@ -16,14 +16,14 @@ export const membersPageQuery = graphql`
... on Organization { ... on Organization {
canInviteUser: permission(action: "iam:invitation:create") canInviteUser: permission(action: "iam:invitation:create")
...MemberListFragment ...MemberListFragment
@arguments(first: 20, order: { direction: ASC, field: CREATED_AT }) @arguments(first: 20, order: { direction: ASC, field: FULL_NAME })
members(first: 20, orderBy: { direction: ASC, field: CREATED_AT }) members(first: 20, orderBy: { direction: ASC, field: FULL_NAME })
@required(action: THROW) { @required(action: THROW) {
totalCount totalCount
} }
...InvitationListFragment ...InvitationListFragment
@arguments(first: 20, order: { direction: ASC, field: CREATED_AT }) @arguments(first: 20, order: { direction: DESC, field: CREATED_AT })
invitations(first: 20, orderBy: { direction: ASC, field: CREATED_AT }) invitations(first: 20, orderBy: { direction: DESC, field: CREATED_AT })
@required(action: THROW) { @required(action: THROW) {
totalCount totalCount
...MembersPage_invitationsTotalCountFragment ...MembersPage_invitationsTotalCountFragment

View File

@@ -14,7 +14,7 @@ const fragment = graphql`
first: { type: "Int", defaultValue: 20 } first: { type: "Int", defaultValue: 20 }
order: { order: {
type: "MembershipOrder" type: "MembershipOrder"
defaultValue: { direction: ASC, field: CREATED_AT } 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 }

View File

@@ -450,8 +450,6 @@ WITH mbr AS (
identity_id = @identity_id identity_id = @identity_id
AND state = 'ACTIVE' AND state = 'ACTIVE'
AND %s AND %s
ORDER BY
created_at DESC
) )
SELECT SELECT
mbr.id, mbr.id,
@@ -508,47 +506,45 @@ func (m *Memberships) LoadByOrganizationID(
filter *MembershipFilter, filter *MembershipFilter,
) error { ) error {
query := ` query := `
WITH membership_with_profile AS ( WITH m AS (
SELECT SELECT
m.id,
m.identity_id,
m.organization_id,
m.role,
m.source,
m.state,
COALESCE(mp.full_name, i.full_name, '') AS full_name,
i.email_address,
o.name as organization_name,
m.created_at,
m.updated_at
FROM
iam_memberships m
JOIN
identities i ON m.identity_id = i.id
JOIN
organizations o ON mbr.organization_id = o.id
LEFT JOIN
iam_membership_profiles mp ON mp.membership_id = m.id
WHERE
m.organization_id = @organization_id
AND m.%s
AND %s
)
SELECT
id, id,
identity_id, identity_id,
organization_id, organization_id,
role, role,
source, source,
state, state,
full_name,
email_address,
created_at, created_at,
updated_at updated_at
FROM
iam_memberships
WHERE
organization_id = @organization_id
AND %s
)
SELECT
m.id,
m.identity_id,
m.organization_id,
m.role,
m.source,
m.state,
COALESCE(mp.full_name, i.full_name, '') as full_name,
o.name as organization_name,
i.email_address,
m.created_at,
m.updated_at
FROM FROM
membership_with_profile m
JOIN
identities i ON m.identity_id = i.id
JOIN
organizations o ON m.organization_id = o.id
LEFT JOIN
iam_membership_profiles mp ON mp.membership_id = m.id
WHERE WHERE
%s %s
AND %s
` `
query = fmt.Sprintf(query, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment()) query = fmt.Sprintf(query, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment())