Skip to content

Commit 908ad7f

Browse files
committed
more
1 parent 6daf004 commit 908ad7f

File tree

12 files changed

+180
-82
lines changed

12 files changed

+180
-82
lines changed

integration-tests/testkit/flow.ts

+25-13
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ export function createOrganization(input: CreateOrganizationInput, authToken: st
5656
}
5757
}
5858
memberRoles {
59-
id
60-
name
61-
locked
59+
edges {
60+
node {
61+
id
62+
name
63+
locked
64+
}
65+
}
6266
}
6367
rateLimit {
6468
retentionInDays
@@ -655,11 +659,15 @@ export function createMemberRole(input: CreateMemberRoleInput, authToken: string
655659
id
656660
slug
657661
memberRoles {
658-
id
659-
name
660-
description
661-
locked
662-
permissions
662+
edges {
663+
node {
664+
id
665+
name
666+
description
667+
locked
668+
permissions
669+
}
670+
}
663671
}
664672
}
665673
}
@@ -713,11 +721,15 @@ export function deleteMemberRole(input: DeleteMemberRoleInput, authToken: string
713721
id
714722
slug
715723
memberRoles {
716-
id
717-
name
718-
description
719-
locked
720-
permissions
724+
edges {
725+
node {
726+
id
727+
name
728+
description
729+
locked
730+
permissions
731+
}
732+
}
721733
}
722734
}
723735
}

integration-tests/tests/api/organization/members.spec.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,10 @@ const OrganizationInvitationsQuery = graphql(`
150150
organization: organizationBySlug(organizationSlug: $organizationSlug) {
151151
id
152152
invitations {
153-
total
154-
nodes {
155-
id
153+
edges {
154+
node {
155+
id
156+
}
156157
}
157158
}
158159
}

packages/services/api/src/modules/auth/module.graphql.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ export default gql`
4040
}
4141
4242
type User {
43-
id: ID!
44-
email: String!
43+
id: ID! @tag(name: "public")
44+
email: String! @tag(name: "public")
4545
fullName: String!
46-
displayName: String!
47-
provider: AuthProvider!
46+
displayName: String! @tag(name: "public")
47+
provider: AuthProviderType! @tag(name: "public")
4848
isAdmin: Boolean!
4949
}
5050
@@ -53,17 +53,17 @@ export default gql`
5353
total: Int!
5454
}
5555
56-
enum AuthProvider {
57-
GOOGLE
58-
GITHUB
56+
enum AuthProviderType {
57+
GOOGLE @tag(name: "public")
58+
GITHUB @tag(name: "public")
5959
"""
6060
Username-Password-Authentication
6161
"""
62-
USERNAME_PASSWORD
62+
USERNAME_PASSWORD @tag(name: "public")
6363
"""
6464
OpenID Connect
6565
"""
66-
OIDC
66+
OIDC @tag(name: "public")
6767
}
6868
6969
enum OrganizationAccessScope {

packages/services/api/src/modules/organization/module.graphql.ts

+29-14
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,16 @@ export default gql`
274274
organization: Organization!
275275
}
276276
277+
type MemberRoleEdge {
278+
node: MemberRole! @tag(name: "public")
279+
cursor: String!
280+
}
281+
282+
type MemberRoleConnection {
283+
edges: [MemberRoleEdge!]! @tag(name: "public")
284+
pageInfo: PageInfo!
285+
}
286+
277287
type Organization {
278288
"""
279289
Unique UUID of the organization
@@ -285,13 +295,13 @@ export default gql`
285295
slug: String! @tag(name: "public")
286296
cleanId: ID! @deprecated(reason: "Use the 'slug' field instead.")
287297
name: String! @deprecated(reason: "Use the 'slug' field instead.")
288-
owner: Member!
298+
owner: Member! @tag(name: "public")
289299
me: Member!
290300
members(first: Int @tag(name: "public"), after: String @tag(name: "public")): MemberConnection!
291301
@tag(name: "public")
292-
invitations: OrganizationInvitationConnection
302+
invitations: OrganizationInvitationConnection @tag(name: "public")
293303
getStarted: OrganizationGetStarted!
294-
memberRoles: [MemberRole!]
304+
memberRoles: MemberRoleConnection @tag(name: "public")
295305
"""
296306
Whether the viewer should be able to access the settings page within the app
297307
"""
@@ -331,7 +341,7 @@ export default gql`
331341
"""
332342
List of available permission groups that can be assigned to users.
333343
"""
334-
availableMemberPermissionGroups: [PermissionGroup!]!
344+
availableMemberPermissionGroups: [PermissionGroup!]! @tag(name: "public")
335345
"""
336346
List of available permission groups that can be assigned to organization access tokens.
337347
"""
@@ -368,9 +378,14 @@ export default gql`
368378
total: Int!
369379
}
370380
381+
type OrganizationInvitationEdge {
382+
node: OrganizationInvitation! @tag(name: "public")
383+
cursor: String!
384+
}
385+
371386
type OrganizationInvitationConnection {
372-
nodes: [OrganizationInvitation!]!
373-
total: Int!
387+
edges: [OrganizationInvitationEdge!]! @tag(name: "public")
388+
pageInfo: PageInfo!
374389
}
375390
376391
type OrganizationInvitation {
@@ -422,9 +437,9 @@ export default gql`
422437
}
423438
424439
type MemberRole {
425-
id: ID!
426-
name: String!
427-
description: String!
440+
id: ID! @tag(name: "public")
441+
name: String! @tag(name: "public")
442+
description: String! @tag(name: "public")
428443
"""
429444
Whether the role is a built-in role. Built-in roles cannot be deleted or modified.
430445
"""
@@ -448,7 +463,7 @@ export default gql`
448463
"""
449464
List of permissions attached to this member role.
450465
"""
451-
permissions: [String!]!
466+
permissions: [String!]! @tag(name: "public")
452467
}
453468
454469
input CreateMemberRoleInput {
@@ -563,11 +578,11 @@ export default gql`
563578
564579
type Member {
565580
id: ID!
566-
user: User!
567-
isOwner: Boolean!
581+
user: User! @tag(name: "public")
582+
isOwner: Boolean! @tag(name: "public")
568583
canLeaveOrganization: Boolean!
569-
role: MemberRole!
570-
resourceAssignment: ResourceAssignment!
584+
role: MemberRole! @tag(name: "public")
585+
resourceAssignment: ResourceAssignment! @tag(name: "public")
571586
"""
572587
Whether the viewer can remove this member from the organization.
573588
"""

packages/services/api/src/modules/organization/providers/organization-manager.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1191,4 +1191,16 @@ export class OrganizationManager {
11911191

11921192
return this.organizationMemberRoles.findViewerRoleByOrganizationId(selector.organizationId);
11931193
}
1194+
1195+
async findOrganizationOwner(organization: Organization) {
1196+
await this.session.assertPerformAction({
1197+
action: 'member:describe',
1198+
organizationId: organization.id,
1199+
params: {
1200+
organizationId: organization.id,
1201+
},
1202+
});
1203+
1204+
return this.organizationMembers.findOrganizationOwner(organization);
1205+
}
11941206
}

packages/services/api/src/modules/organization/resolvers/Organization.ts

+24-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const Organization: Pick<
3939
return !!organization.id;
4040
},
4141
owner: async (organization, _, { injector }) => {
42-
const owner = await injector.get(OrganizationMembers).findOrganizationOwner(organization);
42+
const owner = await injector.get(OrganizationManager).findOrganizationOwner(organization);
4343
if (!owner) {
4444
throw new Error('Not found.');
4545
}
@@ -78,12 +78,31 @@ export const Organization: Pick<
7878
}
7979

8080
return {
81-
total: invitations.length,
82-
nodes: invitations,
81+
pageInfo: {
82+
hasNextPage: false,
83+
hasPreviousPage: false,
84+
endCursor: '',
85+
startCursor: '',
86+
},
87+
edges: invitations.map(node => ({
88+
node,
89+
cursor: '',
90+
})),
8391
};
8492
},
85-
memberRoles: (organization, _, { injector }) => {
86-
return injector.get(OrganizationMemberRoles).getMemberRolesForOrganizationId(organization.id);
93+
memberRoles: async (organization, _, { injector }) => {
94+
const roles = await injector
95+
.get(OrganizationMemberRoles)
96+
.getMemberRolesForOrganizationId(organization.id);
97+
return {
98+
edges: roles.map(node => ({ node, cursor: node.id })),
99+
pageInfo: {
100+
hasNextPage: false,
101+
hasPreviousPage: false,
102+
endCursor: '',
103+
startCursor: '',
104+
},
105+
};
87106
},
88107
cleanId: organization => organization.slug,
89108
viewerCanDelete: async (organization, _arg, { session }) => {

packages/services/storage/src/db/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ export interface organization_invitations {
180180
export interface organization_member {
181181
assigned_resources: any | null;
182182
connected_to_zendesk: boolean;
183+
created_at: Date;
183184
organization_id: string;
184185
role: user_role;
185186
role_id: string | null;

packages/web/app/src/components/organization/members/invitations.tsx

+24-15
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,15 @@ const MemberInvitationForm_OrganizationFragment = graphql(`
6161
id
6262
slug
6363
memberRoles {
64-
id
65-
name
66-
description
67-
locked
68-
canInvite
64+
edges {
65+
node {
66+
id
67+
name
68+
description
69+
locked
70+
canInvite
71+
}
72+
}
6973
}
7074
}
7175
`);
@@ -94,7 +98,9 @@ function MemberInvitationForm(props: {
9498
const { toast } = useToast();
9599
const organization = useFragment(MemberInvitationForm_OrganizationFragment, props.organization);
96100
const [invitation, invite] = useMutation(MemberInvitationForm_InviteByEmail);
97-
const viewerRole = organization.memberRoles?.find(r => r.name === 'Viewer');
101+
const viewerRole = organization.memberRoles?.edges.find(
102+
edge => edge.node.name === 'Viewer',
103+
)?.node;
98104

99105
const form = useForm<MemberInvitationFormValues>({
100106
resolver: zodResolver(memberInvitationFormSchema),
@@ -204,9 +210,10 @@ function MemberInvitationForm(props: {
204210
<FormItem>
205211
<FormControl>
206212
<RoleSelector
207-
roles={organization.memberRoles ?? []}
213+
roles={organization.memberRoles?.edges.map(edge => edge.node) ?? []}
208214
defaultRole={
209-
organization.memberRoles?.find(r => r.id === field.value) ?? viewerRole
215+
organization.memberRoles?.edges.find(edge => edge.node.id === field.value)
216+
?.node ?? viewerRole
210217
}
211218
isRoleActive={role => ({
212219
active: role.canInvite,
@@ -407,9 +414,11 @@ const OrganizationInvitations_OrganizationFragment = graphql(`
407414
id
408415
slug
409416
invitations {
410-
nodes {
411-
id
412-
...Members_Invitation
417+
edges {
418+
node {
419+
id
420+
...Members_Invitation
421+
}
413422
}
414423
}
415424
...MemberInvitationForm_OrganizationFragment
@@ -440,7 +449,7 @@ export function OrganizationInvitations(props: {
440449
organization={organization}
441450
/>
442451
</SubPageLayoutHeader>
443-
{organization.invitations.nodes.length > 0 ? (
452+
{organization.invitations.edges.length > 0 ? (
444453
<table className="w-full table-auto divide-y-[1px] divide-gray-500/20">
445454
<thead>
446455
<tr>
@@ -451,10 +460,10 @@ export function OrganizationInvitations(props: {
451460
</tr>
452461
</thead>
453462
<tbody className="divide-y-[1px] divide-gray-500/20">
454-
{organization.invitations.nodes.map(node => (
463+
{organization.invitations.edges.map(edge => (
455464
<Invitation
456-
key={node.id}
457-
invitation={node}
465+
key={edge.node.id}
466+
invitation={edge.node}
458467
organizationSlug={organization.slug}
459468
refetchInvitations={props.refetchInvitations}
460469
/>

packages/web/app/src/components/organization/members/member-role-picker.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ const MemberRolePicker_OrganizationFragment = graphql(`
1919
id
2020
slug
2121
memberRoles {
22-
id
23-
permissions
22+
edges {
23+
node {
24+
id
25+
permissions
26+
}
27+
}
2428
}
2529
...ResourceSelector_OrganizationFragment
2630
...MemberRoleSelector_OrganizationFragment
@@ -142,7 +146,8 @@ export function MemberRolePicker(props: {
142146
const [assignRoleState, assignRole] = useMutation(MemberRolePicker_AssignRoleMutation);
143147
const { toast } = useToast();
144148

145-
const selectedRole = organization.memberRoles?.find(role => role.id === selectedRoleId) ?? null;
149+
const selectedRole =
150+
organization.memberRoles?.edges?.find(edge => edge.node.id === selectedRoleId)?.node ?? null;
146151

147152
return (
148153
<Sheet.SheetContent className="flex max-h-screen min-w-[800px] flex-col overflow-y-scroll">

0 commit comments

Comments
 (0)