@shipfox/client-workspace-settings 3.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +30 -0
  3. package/dist/components/members/workspace-members-section.d.ts.map +1 -1
  4. package/dist/components/members/workspace-members-section.js +4 -4
  5. package/dist/components/members/workspace-members-section.js.map +1 -1
  6. package/dist/core/invitation.d.ts +15 -0
  7. package/dist/core/invitation.d.ts.map +1 -0
  8. package/dist/core/invitation.js +3 -0
  9. package/dist/core/invitation.js.map +1 -0
  10. package/dist/feature.d.ts +0 -70
  11. package/dist/feature.d.ts.map +1 -1
  12. package/dist/feature.js +0 -84
  13. package/dist/feature.js.map +1 -1
  14. package/dist/hooks/api/create-invitation.d.ts +2 -13
  15. package/dist/hooks/api/create-invitation.d.ts.map +1 -1
  16. package/dist/hooks/api/create-invitation.js +12 -9
  17. package/dist/hooks/api/create-invitation.js.map +1 -1
  18. package/dist/hooks/api/invitation-mapper.d.ts +4 -0
  19. package/dist/hooks/api/invitation-mapper.d.ts.map +1 -0
  20. package/dist/hooks/api/invitation-mapper.js +15 -0
  21. package/dist/hooks/api/invitation-mapper.js.map +1 -0
  22. package/dist/hooks/api/list-invitations.d.ts +10 -13
  23. package/dist/hooks/api/list-invitations.d.ts.map +1 -1
  24. package/dist/hooks/api/list-invitations.js +11 -5
  25. package/dist/hooks/api/list-invitations.js.map +1 -1
  26. package/dist/hooks/api/revoke-invitation.js +2 -4
  27. package/dist/hooks/api/revoke-invitation.js.map +1 -1
  28. package/dist/index.d.ts +0 -7
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +0 -7
  31. package/dist/index.js.map +1 -1
  32. package/dist/tsconfig.test.tsbuildinfo +1 -1
  33. package/package.json +5 -30
  34. package/src/components/members/workspace-members-section.tsx +6 -11
  35. package/src/core/invitation.ts +15 -0
  36. package/src/feature.ts +0 -84
  37. package/src/hooks/api/create-invitation.ts +20 -10
  38. package/src/hooks/api/invitation-mapper.test.ts +29 -0
  39. package/src/hooks/api/invitation-mapper.ts +16 -0
  40. package/src/hooks/api/list-invitations.ts +17 -7
  41. package/src/hooks/api/revoke-invitation.ts +2 -2
  42. package/src/index.ts +0 -7
  43. package/test/pages.tsx +1 -5
  44. package/tsconfig.build.tsbuildinfo +1 -1
  45. package/dist/pages/events-settings-page.d.ts +0 -2
  46. package/dist/pages/events-settings-page.d.ts.map +0 -1
  47. package/dist/pages/events-settings-page.js +0 -30
  48. package/dist/pages/events-settings-page.js.map +0 -1
  49. package/dist/pages/integrations-settings-page.d.ts +0 -2
  50. package/dist/pages/integrations-settings-page.d.ts.map +0 -1
  51. package/dist/pages/integrations-settings-page.js +0 -10
  52. package/dist/pages/integrations-settings-page.js.map +0 -1
  53. package/dist/pages/model-providers-settings-page.d.ts +0 -2
  54. package/dist/pages/model-providers-settings-page.d.ts.map +0 -1
  55. package/dist/pages/model-providers-settings-page.js +0 -20
  56. package/dist/pages/model-providers-settings-page.js.map +0 -1
  57. package/dist/pages/provisioners-settings-page.d.ts +0 -2
  58. package/dist/pages/provisioners-settings-page.d.ts.map +0 -1
  59. package/dist/pages/provisioners-settings-page.js +0 -14
  60. package/dist/pages/provisioners-settings-page.js.map +0 -1
  61. package/dist/pages/runners-settings-page.d.ts +0 -2
  62. package/dist/pages/runners-settings-page.d.ts.map +0 -1
  63. package/dist/pages/runners-settings-page.js +0 -14
  64. package/dist/pages/runners-settings-page.js.map +0 -1
  65. package/dist/pages/secrets-settings-page.d.ts +0 -2
  66. package/dist/pages/secrets-settings-page.d.ts.map +0 -1
  67. package/dist/pages/secrets-settings-page.js +0 -14
  68. package/dist/pages/secrets-settings-page.js.map +0 -1
  69. package/dist/pages/variables-settings-page.d.ts +0 -2
  70. package/dist/pages/variables-settings-page.d.ts.map +0 -1
  71. package/dist/pages/variables-settings-page.js +0 -14
  72. package/dist/pages/variables-settings-page.js.map +0 -1
  73. package/dist/routes/agents.d.ts +0 -6
  74. package/dist/routes/agents.d.ts.map +0 -1
  75. package/dist/routes/agents.js +0 -7
  76. package/dist/routes/agents.js.map +0 -1
  77. package/dist/routes/events.d.ts +0 -8
  78. package/dist/routes/events.d.ts.map +0 -1
  79. package/dist/routes/events.js +0 -9
  80. package/dist/routes/events.js.map +0 -1
  81. package/dist/routes/integrations.d.ts +0 -6
  82. package/dist/routes/integrations.d.ts.map +0 -1
  83. package/dist/routes/integrations.js +0 -7
  84. package/dist/routes/integrations.js.map +0 -1
  85. package/dist/routes/provisioners.d.ts +0 -6
  86. package/dist/routes/provisioners.d.ts.map +0 -1
  87. package/dist/routes/provisioners.js +0 -7
  88. package/dist/routes/provisioners.js.map +0 -1
  89. package/dist/routes/runners.d.ts +0 -6
  90. package/dist/routes/runners.d.ts.map +0 -1
  91. package/dist/routes/runners.js +0 -7
  92. package/dist/routes/runners.js.map +0 -1
  93. package/dist/routes/secrets.d.ts +0 -6
  94. package/dist/routes/secrets.d.ts.map +0 -1
  95. package/dist/routes/secrets.js +0 -7
  96. package/dist/routes/secrets.js.map +0 -1
  97. package/dist/routes/variables.d.ts +0 -6
  98. package/dist/routes/variables.d.ts.map +0 -1
  99. package/dist/routes/variables.js +0 -7
  100. package/dist/routes/variables.js.map +0 -1
  101. package/src/pages/events-settings-page.tsx +0 -25
  102. package/src/pages/integrations-settings-page.test.tsx +0 -72
  103. package/src/pages/integrations-settings-page.tsx +0 -6
  104. package/src/pages/model-providers-settings-page.test.tsx +0 -48
  105. package/src/pages/model-providers-settings-page.tsx +0 -15
  106. package/src/pages/provisioners-settings-page.test.tsx +0 -29
  107. package/src/pages/provisioners-settings-page.tsx +0 -14
  108. package/src/pages/runners-settings-page.test.tsx +0 -23
  109. package/src/pages/runners-settings-page.tsx +0 -14
  110. package/src/pages/secrets-settings-page.tsx +0 -14
  111. package/src/pages/variables-settings-page.tsx +0 -14
  112. package/src/routes/agents.tsx +0 -3
  113. package/src/routes/events.tsx +0 -7
  114. package/src/routes/integrations.tsx +0 -3
  115. package/src/routes/provisioners.tsx +0 -3
  116. package/src/routes/runners.tsx +0 -3
  117. package/src/routes/secrets.tsx +0 -3
  118. package/src/routes/variables.tsx +0 -3
  119. package/test/typecheck/route-ids.tsx +0 -7
  120. package/test/typecheck/settings-composition.tsx +0 -95
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 27 files with swc (667.09ms)
2
+ Successfully compiled: 15 files with swc (512.33ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @shipfox/client-workspace-settings
2
2
 
3
+ ## 5.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - ffd727b: Converges auth session and invitation state onto shared camelCase domain types validated at the API boundary, replacing the raw snake_case DTOs previously returned by login, signup, password reset, email verification, workspace creation, and invitation preview. `AuthState.user`, `useRefreshAuth()`, and `usePreviewInvitation()` now resolve to `UserIdentity`/`AuthenticatedSession`/`InvitationPreview` shapes (for example `accessToken` instead of `token`, `workspaceName` instead of `workspace_name`). Also moves the shared `AuthShell` component and session mapping helpers into `@shipfox/client-shell`, breaking the former `client-auth` ↔ `client-invitations` circular dependency.
8
+ - f1d6465: Moves workspace-settings and project-workflow route ownership from centralized packages into each feature's own route module, so a feature package declares and ships its own settings pages.
9
+ - Updated dependencies [ffd727b]
10
+ - @shipfox/client-shell@5.0.0
11
+ - @shipfox/client-auth@5.0.0
12
+
13
+ ## 4.0.0
14
+
15
+ ### Patch Changes
16
+
17
+ - 6b4a575: Adds checked client API response boundaries and domain-cached invitation queries.
18
+ - Updated dependencies [2e5b718]
19
+ - Updated dependencies [6b4a575]
20
+ - Updated dependencies [20e4feb]
21
+ - Updated dependencies [11b10f7]
22
+ - Updated dependencies [781a45b]
23
+ - @shipfox/client-ui@4.0.0
24
+ - @shipfox/client-agent@4.0.0
25
+ - @shipfox/client-integrations@4.0.0
26
+ - @shipfox/client-shell@4.0.0
27
+ - @shipfox/client-api@4.0.0
28
+ - @shipfox/client-auth@4.0.0
29
+ - @shipfox/client-runners@4.0.0
30
+ - @shipfox/client-secrets@4.0.0
31
+ - @shipfox/client-triggers@4.0.0
32
+
3
33
  ## 3.0.1
4
34
 
5
35
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-members-section.d.ts","sourceRoot":"","sources":["../../../src/components/members/workspace-members-section.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,+BAA+B,CAAC,EAC9C,WAAW,EACX,aAAa,GACd,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,+BAOA"}
1
+ {"version":3,"file":"workspace-members-section.d.ts","sourceRoot":"","sources":["../../../src/components/members/workspace-members-section.tsx"],"names":[],"mappings":"AA2CA,wBAAgB,+BAA+B,CAAC,EAC9C,WAAW,EACX,aAAa,GACd,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,+BAOA"}
@@ -200,7 +200,7 @@ function MemberRow({ member, isSelf, workspaceId, workspaceName }) {
200
200
  }
201
201
  function PendingInvitationsSection({ workspaceId, workspaceName }) {
202
202
  const query = useListInvitations(workspaceId);
203
- const invitations = query.data?.invitations ?? [];
203
+ const invitations = query.data ?? [];
204
204
  const [inviteOpen, setInviteOpen] = useState(false);
205
205
  return /*#__PURE__*/ _jsxs("section", {
206
206
  className: "flex flex-col gap-16",
@@ -274,7 +274,7 @@ function PendingInvitationsSection({ workspaceId, workspaceName }) {
274
274
  function InvitationRow({ invitation, workspaceId }) {
275
275
  const [open, setOpen] = useState(false);
276
276
  const revoke = useRevokeInvitation(workspaceId);
277
- const expiresAt = new Date(invitation.expires_at);
277
+ const expiresAt = new Date(invitation.expiresAt);
278
278
  const expiresSoon = expiresAt.getTime() - Date.now() < EXPIRES_SOON_MS;
279
279
  async function handleRevoke() {
280
280
  try {
@@ -295,7 +295,7 @@ function InvitationRow({ invitation, workspaceId }) {
295
295
  })
296
296
  }),
297
297
  /*#__PURE__*/ _jsx(TableCell, {
298
- children: invitation.invited_by_display ?? '—'
298
+ children: invitation.invitedByDisplay ?? '—'
299
299
  }),
300
300
  /*#__PURE__*/ _jsx(TableCell, {
301
301
  children: /*#__PURE__*/ _jsxs("div", {
@@ -303,7 +303,7 @@ function InvitationRow({ invitation, workspaceId }) {
303
303
  children: [
304
304
  /*#__PURE__*/ _jsx(Text, {
305
305
  size: "sm",
306
- children: formatDate(invitation.expires_at)
306
+ children: formatDate(invitation.expiresAt)
307
307
  }),
308
308
  expiresSoon ? /*#__PURE__*/ _jsx(Badge, {
309
309
  variant: "warning",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/members/workspace-members-section.tsx"],"sourcesContent":["import {createInvitationBodySchema, type MembershipWithUserDto} from '@shipfox/api-workspaces-dto';\nimport {ApiError} from '@shipfox/client-api';\nimport {useAuthState} from '@shipfox/client-auth';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n ModalTrigger,\n} from '@shipfox/react-ui/modal';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {formatDate} from '@shipfox/react-ui/utils';\nimport {useForm} from '@tanstack/react-form';\nimport {useState} from 'react';\nimport {useCreateInvitation} from '#hooks/api/create-invitation.js';\nimport {useListInvitations} from '#hooks/api/list-invitations.js';\nimport {useListMembers} from '#hooks/api/list-members.js';\nimport {useRemoveMember} from '#hooks/api/remove-member.js';\nimport {useRevokeInvitation} from '#hooks/api/revoke-invitation.js';\nimport {invitationErrorToFormError} from './form-errors.js';\n\nconst EXPIRES_SOON_MS = 24 * 60 * 60 * 1000;\n\nexport function WorkspaceMembersSettingsSection({\n workspaceId,\n workspaceName,\n}: {\n workspaceId: string;\n workspaceName: string;\n}) {\n return (\n <div className=\"flex min-w-0 flex-col gap-32\">\n <MembersSection workspaceId={workspaceId} workspaceName={workspaceName} />\n <PendingInvitationsSection workspaceId={workspaceId} workspaceName={workspaceName} />\n </div>\n );\n}\n\nfunction MembersSection({\n workspaceId,\n workspaceName,\n}: {\n workspaceId: string;\n workspaceName: string;\n}) {\n const auth = useAuthState();\n const query = useListMembers(workspaceId);\n const members = query.data?.members ?? [];\n\n return (\n <section className=\"flex flex-col gap-16\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Members</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {query.isPending\n ? 'Loading members…'\n : `${members.length} ${members.length === 1 ? 'member' : 'members'}`}\n </Text>\n </div>\n\n {query.isPending ? <TableSkeleton rows={3} cols={3} /> : null}\n\n {query.isError && query.data === undefined ? (\n <QueryLoadError query={query} subject=\"members\" />\n ) : null}\n\n {members.length > 0 ? (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Email</TableHead>\n <TableHead>Joined</TableHead>\n <TableHead className=\"w-80 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {members.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n isSelf={member.user_id === auth.user?.id}\n workspaceId={workspaceId}\n workspaceName={workspaceName}\n />\n ))}\n </TableBody>\n </Table>\n ) : null}\n </section>\n );\n}\n\nfunction MemberRow({\n member,\n isSelf,\n workspaceId,\n workspaceName,\n}: {\n member: MembershipWithUserDto;\n isSelf: boolean;\n workspaceId: string;\n workspaceName: string;\n}) {\n const [open, setOpen] = useState(false);\n const remove = useRemoveMember(workspaceId);\n\n async function handleRemove() {\n try {\n await remove.mutateAsync(member.user_id);\n toast.success(`Removed ${member.user_email} from ${workspaceName}.`);\n setOpen(false);\n } catch (error) {\n toast.error(removeMemberErrorMessage(error));\n }\n }\n\n return (\n <TableRow className={remove.isPending ? 'opacity-60' : undefined}>\n <TableCell className=\"font-medium\">{member.user_name ?? '—'}</TableCell>\n <TableCell>\n <Code variant=\"paragraph\">{member.user_email}</Code>\n </TableCell>\n <TableCell>{formatDate(member.created_at)}</TableCell>\n <TableCell className=\"text-right\">\n <Modal open={open} onOpenChange={setOpen}>\n <ModalTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"transparentMuted\"\n aria-label=\"Remove member\"\n disabled={isSelf}\n isLoading={remove.isPending}\n className={\n remove.isPending\n ? 'opacity-100 transition-opacity'\n : 'opacity-0 transition-opacity group-hover/row:opacity-100 focus-visible:opacity-100'\n }\n >\n <Icon name=\"userUnfollowLine\" className=\"size-16\" />\n </Button>\n </ModalTrigger>\n <ModalContent>\n <ModalTitle className=\"sr-only\">Remove member</ModalTitle>\n <ModalHeader>\n <Text size=\"lg\">\n Remove {member.user_name ?? member.user_email} from {workspaceName}?\n </Text>\n </ModalHeader>\n <ModalBody>\n <Text size=\"sm\">\n They will lose access immediately. They can be re-invited later.\n </Text>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={handleRemove} isLoading={remove.isPending}>\n Remove\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </TableCell>\n </TableRow>\n );\n}\n\nfunction PendingInvitationsSection({\n workspaceId,\n workspaceName,\n}: {\n workspaceId: string;\n workspaceName: string;\n}) {\n const query = useListInvitations(workspaceId);\n const invitations = query.data?.invitations ?? [];\n const [inviteOpen, setInviteOpen] = useState(false);\n\n return (\n <section className=\"flex flex-col gap-16\">\n <div className=\"flex items-center justify-between gap-16\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Pending invitations</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {query.isPending\n ? 'Loading invitations…'\n : `${invitations.length} ${invitations.length === 1 ? 'invitation' : 'invitations'}`}\n </Text>\n </div>\n <InviteMemberModal\n open={inviteOpen}\n onOpenChange={setInviteOpen}\n workspaceId={workspaceId}\n workspaceName={workspaceName}\n />\n </div>\n\n {query.isPending ? <TableSkeleton rows={2} cols={3} /> : null}\n\n {query.isError && query.data === undefined ? (\n <QueryLoadError query={query} subject=\"invitations\" />\n ) : null}\n\n {query.data !== undefined && invitations.length === 0 ? <EmptyInvitations /> : null}\n\n {invitations.length > 0 ? (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Email</TableHead>\n <TableHead>Invited by</TableHead>\n <TableHead>Expires</TableHead>\n <TableHead className=\"w-80 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invitations.map((invitation) => (\n <InvitationRow\n key={invitation.id}\n invitation={invitation}\n workspaceId={workspaceId}\n />\n ))}\n </TableBody>\n </Table>\n ) : null}\n </section>\n );\n}\n\nfunction InvitationRow({\n invitation,\n workspaceId,\n}: {\n invitation: import('@shipfox/api-workspaces-dto').InvitationDto;\n workspaceId: string;\n}) {\n const [open, setOpen] = useState(false);\n const revoke = useRevokeInvitation(workspaceId);\n const expiresAt = new Date(invitation.expires_at);\n const expiresSoon = expiresAt.getTime() - Date.now() < EXPIRES_SOON_MS;\n\n async function handleRevoke() {\n try {\n await revoke.mutateAsync(invitation.id);\n toast.success(`Invitation to ${invitation.email} revoked.`);\n setOpen(false);\n } catch {\n toast.error('Could not revoke invitation.');\n }\n }\n\n return (\n <TableRow className={revoke.isPending ? 'opacity-60' : undefined}>\n <TableCell>\n <Code variant=\"paragraph\">{invitation.email}</Code>\n </TableCell>\n <TableCell>{invitation.invited_by_display ?? '—'}</TableCell>\n <TableCell>\n <div className=\"flex items-center gap-8\">\n <Text size=\"sm\">{formatDate(invitation.expires_at)}</Text>\n {expiresSoon ? <Badge variant=\"warning\">Soon</Badge> : null}\n </div>\n </TableCell>\n <TableCell className=\"text-right\">\n <Modal open={open} onOpenChange={setOpen}>\n <ModalTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"transparentMuted\"\n aria-label=\"Revoke invitation\"\n isLoading={revoke.isPending}\n className={\n revoke.isPending\n ? 'opacity-100 transition-opacity'\n : 'opacity-0 transition-opacity group-hover/row:opacity-100 focus-visible:opacity-100'\n }\n >\n <Icon name=\"closeLine\" className=\"size-16\" />\n </Button>\n </ModalTrigger>\n <ModalContent>\n <ModalTitle className=\"sr-only\">Revoke invitation</ModalTitle>\n <ModalHeader>\n <Text size=\"lg\">Revoke invitation to {invitation.email}?</Text>\n </ModalHeader>\n <ModalBody>\n <Text size=\"sm\">They will no longer be able to use the link from their email.</Text>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={handleRevoke} isLoading={revoke.isPending}>\n Revoke\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </TableCell>\n </TableRow>\n );\n}\n\nfunction InviteMemberModal({\n open,\n onOpenChange,\n workspaceId,\n workspaceName,\n}: {\n open: boolean;\n onOpenChange: (next: boolean) => void;\n workspaceId: string;\n workspaceName: string;\n}) {\n const create = useCreateInvitation(workspaceId);\n const [formError, setFormError] = useState<string | undefined>();\n\n const form = useForm({\n defaultValues: {email: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n const result = await create.mutateAsync({email: value.email});\n toast.success(`Invitation sent to ${result.email}.`);\n // Go through handleOpenChange so form.reset() fires and reopening the\n // modal does not show stale form state.\n handleOpenChange(false);\n } catch (error) {\n const mapped = invitationErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n function handleOpenChange(nextOpen: boolean) {\n if (!nextOpen) {\n form.reset();\n setFormError(undefined);\n create.reset();\n }\n onOpenChange(nextOpen);\n }\n\n return (\n <Modal open={open} onOpenChange={handleOpenChange}>\n <ModalTrigger asChild>\n <Button size=\"sm\" variant=\"secondary\">\n Invite member\n </Button>\n </ModalTrigger>\n <ModalContent>\n <ModalTitle className=\"sr-only\">Invite a member</ModalTitle>\n <ModalHeader>\n <Text size=\"lg\">Invite a member</Text>\n </ModalHeader>\n <ModalBody className=\"gap-16\">\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form\n id=\"invite-member-form\"\n className=\"flex flex-col gap-16\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"email\"\n validators={{\n onBlur: createInvitationBodySchema.shape.email,\n onSubmit: createInvitationBodySchema.shape.email,\n }}\n >\n {(field) => (\n <FormField\n label=\"Email\"\n id=\"invite-email\"\n error={fieldError(field)}\n description={`They'll receive an email with a link to join ${workspaceName}.`}\n >\n <FormFieldInput\n autoComplete=\"email\"\n autoFocus\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n </form>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => handleOpenChange(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" form=\"invite-member-form\" isLoading={create.isPending}>\n Send invitation\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n\nfunction EmptyInvitations() {\n return (\n <EmptyState\n icon=\"mailLine\"\n title=\"No pending invitations.\"\n description=\"Invite someone above to grow your workspace.\"\n />\n );\n}\n\nfunction TableSkeleton({rows, cols}: {rows: number; cols: number}) {\n return (\n <div className=\"flex flex-col gap-12\">\n {Array.from({length: rows}).map((_, rowIdx) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: stable placeholder rows\n <div key={rowIdx} className=\"grid grid-cols-3 gap-16\">\n {Array.from({length: cols}).map((__, colIdx) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: stable placeholder cells\n <Skeleton key={colIdx} className=\"h-20\" />\n ))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction removeMemberErrorMessage(error: unknown): string {\n if (error instanceof ApiError) {\n if (error.code === 'self-removal-not-allowed') return \"You can't remove yourself.\";\n if (error.code === 'last-member') return 'Cannot remove the last member.';\n return error.message;\n }\n if (error instanceof Error) return error.message;\n return 'Could not remove member.';\n}\n"],"names":["createInvitationBodySchema","ApiError","useAuthState","QueryLoadError","Badge","Button","Callout","EmptyState","FormField","FormFieldInput","fieldError","Icon","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","ModalTrigger","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","formatDate","useForm","useState","useCreateInvitation","useListInvitations","useListMembers","useRemoveMember","useRevokeInvitation","invitationErrorToFormError","EXPIRES_SOON_MS","WorkspaceMembersSettingsSection","workspaceId","workspaceName","div","className","MembersSection","PendingInvitationsSection","auth","query","members","data","section","variant","size","isPending","length","TableSkeleton","rows","cols","isError","undefined","subject","map","member","MemberRow","isSelf","user_id","user","id","open","setOpen","remove","handleRemove","mutateAsync","success","user_email","error","removeMemberErrorMessage","user_name","created_at","onOpenChange","asChild","aria-label","disabled","isLoading","name","onClick","invitations","inviteOpen","setInviteOpen","InviteMemberModal","EmptyInvitations","invitation","InvitationRow","revoke","expiresAt","Date","expires_at","expiresSoon","getTime","now","handleRevoke","email","invited_by_display","create","formError","setFormError","form","defaultValues","onSubmit","value","result","handleOpenChange","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","nextOpen","reset","role","type","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","validators","onBlur","shape","label","description","autoComplete","autoFocus","state","onChange","handleChange","target","handleBlur","icon","title","Array","from","_","rowIdx","__","colIdx","code","Error"],"mappings":";AAAA,SAAQA,0BAA0B,QAAmC,8BAA8B;AACnG,SAAQC,QAAQ,QAAO,sBAAsB;AAC7C,SAAQC,YAAY,QAAO,uBAAuB;AAClD,SAAQC,cAAc,QAAO,qBAAqB;AAClD,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,SAAS,EAAEC,cAAc,EAAEC,UAAU,QAAO,+BAA+B;AACnF,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SACEC,KAAK,EACLC,SAAS,EACTC,YAAY,EACZC,WAAW,EACXC,WAAW,EACXC,UAAU,EACVC,YAAY,QACP,0BAA0B;AACjC,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SACEC,KAAK,EACLC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,QAAQ,QACH,0BAA0B;AACjC,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,IAAI,EAAEC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAChE,SAAQC,UAAU,QAAO,0BAA0B;AACnD,SAAQC,OAAO,QAAO,uBAAuB;AAC7C,SAAQC,QAAQ,QAAO,QAAQ;AAC/B,SAAQC,mBAAmB,QAAO,kCAAkC;AACpE,SAAQC,kBAAkB,QAAO,iCAAiC;AAClE,SAAQC,cAAc,QAAO,6BAA6B;AAC1D,SAAQC,eAAe,QAAO,8BAA8B;AAC5D,SAAQC,mBAAmB,QAAO,kCAAkC;AACpE,SAAQC,0BAA0B,QAAO,mBAAmB;AAE5D,MAAMC,kBAAkB,KAAK,KAAK,KAAK;AAEvC,OAAO,SAASC,gCAAgC,EAC9CC,WAAW,EACXC,aAAa,EAId;IACC,qBACE,MAACC;QAAIC,WAAU;;0BACb,KAACC;gBAAeJ,aAAaA;gBAAaC,eAAeA;;0BACzD,KAACI;gBAA0BL,aAAaA;gBAAaC,eAAeA;;;;AAG1E;AAEA,SAASG,eAAe,EACtBJ,WAAW,EACXC,aAAa,EAId;IACC,MAAMK,OAAO7C;IACb,MAAM8C,QAAQb,eAAeM;IAC7B,MAAMQ,UAAUD,MAAME,IAAI,EAAED,WAAW,EAAE;IAEzC,qBACE,MAACE;QAAQP,WAAU;;0BACjB,MAACD;gBAAIC,WAAU;;kCACb,KAAChB;wBAAOwB,SAAQ;kCAAK;;kCACrB,KAACvB;wBAAKwB,MAAK;wBAAKT,WAAU;kCACvBI,MAAMM,SAAS,GACZ,qBACA,GAAGL,QAAQM,MAAM,CAAC,CAAC,EAAEN,QAAQM,MAAM,KAAK,IAAI,WAAW,WAAW;;;;YAIzEP,MAAMM,SAAS,iBAAG,KAACE;gBAAcC,MAAM;gBAAGC,MAAM;iBAAQ;YAExDV,MAAMW,OAAO,IAAIX,MAAME,IAAI,KAAKU,0BAC/B,KAACzD;gBAAe6C,OAAOA;gBAAOa,SAAQ;iBACpC;YAEHZ,QAAQM,MAAM,GAAG,kBAChB,MAACnC;;kCACC,KAACI;kCACC,cAAA,MAACC;;8CACC,KAACF;8CAAU;;8CACX,KAACA;8CAAU;;8CACX,KAACA;8CAAU;;8CACX,KAACA;oCAAUqB,WAAU;8CAAkB;;;;;kCAG3C,KAACvB;kCACE4B,QAAQa,GAAG,CAAC,CAACC,uBACZ,KAACC;gCAECD,QAAQA;gCACRE,QAAQF,OAAOG,OAAO,KAAKnB,KAAKoB,IAAI,EAAEC;gCACtC3B,aAAaA;gCACbC,eAAeA;+BAJVqB,OAAOK,EAAE;;;iBASpB;;;AAGV;AAEA,SAASJ,UAAU,EACjBD,MAAM,EACNE,MAAM,EACNxB,WAAW,EACXC,aAAa,EAMd;IACC,MAAM,CAAC2B,MAAMC,QAAQ,GAAGtC,SAAS;IACjC,MAAMuC,SAASnC,gBAAgBK;IAE/B,eAAe+B;QACb,IAAI;YACF,MAAMD,OAAOE,WAAW,CAACV,OAAOG,OAAO;YACvCxC,MAAMgD,OAAO,CAAC,CAAC,QAAQ,EAAEX,OAAOY,UAAU,CAAC,MAAM,EAAEjC,cAAc,CAAC,CAAC;YACnE4B,QAAQ;QACV,EAAE,OAAOM,OAAO;YACdlD,MAAMkD,KAAK,CAACC,yBAAyBD;QACvC;IACF;IAEA,qBACE,MAACnD;QAASmB,WAAW2B,OAAOjB,SAAS,GAAG,eAAeM;;0BACrD,KAACtC;gBAAUsB,WAAU;0BAAemB,OAAOe,SAAS,IAAI;;0BACxD,KAACxD;0BACC,cAAA,KAACK;oBAAKyB,SAAQ;8BAAaW,OAAOY,UAAU;;;0BAE9C,KAACrD;0BAAWQ,WAAWiC,OAAOgB,UAAU;;0BACxC,KAACzD;gBAAUsB,WAAU;0BACnB,cAAA,MAAChC;oBAAMyD,MAAMA;oBAAMW,cAAcV;;sCAC/B,KAACpD;4BAAa+D,OAAO;sCACnB,cAAA,KAAC5E;gCACCgD,MAAK;gCACLD,SAAQ;gCACR8B,cAAW;gCACXC,UAAUlB;gCACVmB,WAAWb,OAAOjB,SAAS;gCAC3BV,WACE2B,OAAOjB,SAAS,GACZ,mCACA;0CAGN,cAAA,KAAC3C;oCAAK0E,MAAK;oCAAmBzC,WAAU;;;;sCAG5C,MAAC9B;;8CACC,KAACG;oCAAW2B,WAAU;8CAAU;;8CAChC,KAAC5B;8CACC,cAAA,MAACa;wCAAKwB,MAAK;;4CAAK;4CACNU,OAAOe,SAAS,IAAIf,OAAOY,UAAU;4CAAC;4CAAOjC;4CAAc;;;;8CAGvE,KAAC7B;8CACC,cAAA,KAACgB;wCAAKwB,MAAK;kDAAK;;;8CAIlB,MAACtC;;sDACC,KAACV;4CAAO+C,SAAQ;4CAAYkC,SAAS,IAAMhB,QAAQ;sDAAQ;;sDAG3D,KAACjE;4CAAO+C,SAAQ;4CAASkC,SAASd;4CAAcY,WAAWb,OAAOjB,SAAS;sDAAE;;;;;;;;;;;AAS3F;AAEA,SAASR,0BAA0B,EACjCL,WAAW,EACXC,aAAa,EAId;IACC,MAAMM,QAAQd,mBAAmBO;IACjC,MAAM8C,cAAcvC,MAAME,IAAI,EAAEqC,eAAe,EAAE;IACjD,MAAM,CAACC,YAAYC,cAAc,GAAGzD,SAAS;IAE7C,qBACE,MAACmB;QAAQP,WAAU;;0BACjB,MAACD;gBAAIC,WAAU;;kCACb,MAACD;wBAAIC,WAAU;;0CACb,KAAChB;gCAAOwB,SAAQ;0CAAK;;0CACrB,KAACvB;gCAAKwB,MAAK;gCAAKT,WAAU;0CACvBI,MAAMM,SAAS,GACZ,yBACA,GAAGiC,YAAYhC,MAAM,CAAC,CAAC,EAAEgC,YAAYhC,MAAM,KAAK,IAAI,eAAe,eAAe;;;;kCAG1F,KAACmC;wBACCrB,MAAMmB;wBACNR,cAAcS;wBACdhD,aAAaA;wBACbC,eAAeA;;;;YAIlBM,MAAMM,SAAS,iBAAG,KAACE;gBAAcC,MAAM;gBAAGC,MAAM;iBAAQ;YAExDV,MAAMW,OAAO,IAAIX,MAAME,IAAI,KAAKU,0BAC/B,KAACzD;gBAAe6C,OAAOA;gBAAOa,SAAQ;iBACpC;YAEHb,MAAME,IAAI,KAAKU,aAAa2B,YAAYhC,MAAM,KAAK,kBAAI,KAACoC,wBAAsB;YAE9EJ,YAAYhC,MAAM,GAAG,kBACpB,MAACnC;;kCACC,KAACI;kCACC,cAAA,MAACC;;8CACC,KAACF;8CAAU;;8CACX,KAACA;8CAAU;;8CACX,KAACA;8CAAU;;8CACX,KAACA;oCAAUqB,WAAU;8CAAkB;;;;;kCAG3C,KAACvB;kCACEkE,YAAYzB,GAAG,CAAC,CAAC8B,2BAChB,KAACC;gCAECD,YAAYA;gCACZnD,aAAaA;+BAFRmD,WAAWxB,EAAE;;;iBAOxB;;;AAGV;AAEA,SAASyB,cAAc,EACrBD,UAAU,EACVnD,WAAW,EAIZ;IACC,MAAM,CAAC4B,MAAMC,QAAQ,GAAGtC,SAAS;IACjC,MAAM8D,SAASzD,oBAAoBI;IACnC,MAAMsD,YAAY,IAAIC,KAAKJ,WAAWK,UAAU;IAChD,MAAMC,cAAcH,UAAUI,OAAO,KAAKH,KAAKI,GAAG,KAAK7D;IAEvD,eAAe8D;QACb,IAAI;YACF,MAAMP,OAAOrB,WAAW,CAACmB,WAAWxB,EAAE;YACtC1C,MAAMgD,OAAO,CAAC,CAAC,cAAc,EAAEkB,WAAWU,KAAK,CAAC,SAAS,CAAC;YAC1DhC,QAAQ;QACV,EAAE,OAAM;YACN5C,MAAMkD,KAAK,CAAC;QACd;IACF;IAEA,qBACE,MAACnD;QAASmB,WAAWkD,OAAOxC,SAAS,GAAG,eAAeM;;0BACrD,KAACtC;0BACC,cAAA,KAACK;oBAAKyB,SAAQ;8BAAawC,WAAWU,KAAK;;;0BAE7C,KAAChF;0BAAWsE,WAAWW,kBAAkB,IAAI;;0BAC7C,KAACjF;0BACC,cAAA,MAACqB;oBAAIC,WAAU;;sCACb,KAACf;4BAAKwB,MAAK;sCAAMvB,WAAW8D,WAAWK,UAAU;;wBAChDC,4BAAc,KAAC9F;4BAAMgD,SAAQ;sCAAU;6BAAe;;;;0BAG3D,KAAC9B;gBAAUsB,WAAU;0BACnB,cAAA,MAAChC;oBAAMyD,MAAMA;oBAAMW,cAAcV;;sCAC/B,KAACpD;4BAAa+D,OAAO;sCACnB,cAAA,KAAC5E;gCACCgD,MAAK;gCACLD,SAAQ;gCACR8B,cAAW;gCACXE,WAAWU,OAAOxC,SAAS;gCAC3BV,WACEkD,OAAOxC,SAAS,GACZ,mCACA;0CAGN,cAAA,KAAC3C;oCAAK0E,MAAK;oCAAYzC,WAAU;;;;sCAGrC,MAAC9B;;8CACC,KAACG;oCAAW2B,WAAU;8CAAU;;8CAChC,KAAC5B;8CACC,cAAA,MAACa;wCAAKwB,MAAK;;4CAAK;4CAAsBuC,WAAWU,KAAK;4CAAC;;;;8CAEzD,KAACzF;8CACC,cAAA,KAACgB;wCAAKwB,MAAK;kDAAK;;;8CAElB,MAACtC;;sDACC,KAACV;4CAAO+C,SAAQ;4CAAYkC,SAAS,IAAMhB,QAAQ;sDAAQ;;sDAG3D,KAACjE;4CAAO+C,SAAQ;4CAASkC,SAASe;4CAAcjB,WAAWU,OAAOxC,SAAS;sDAAE;;;;;;;;;;;AAS3F;AAEA,SAASoC,kBAAkB,EACzBrB,IAAI,EACJW,YAAY,EACZvC,WAAW,EACXC,aAAa,EAMd;IACC,MAAM8D,SAASvE,oBAAoBQ;IACnC,MAAM,CAACgE,WAAWC,aAAa,GAAG1E;IAElC,MAAM2E,OAAO5E,QAAQ;QACnB6E,eAAe;YAACN,OAAO;QAAE;QACzBO,UAAU,OAAO,EAACC,KAAK,EAAC;YACtBJ,aAAa9C;YACb,IAAI;gBACF,MAAMmD,SAAS,MAAMP,OAAO/B,WAAW,CAAC;oBAAC6B,OAAOQ,MAAMR,KAAK;gBAAA;gBAC3D5E,MAAMgD,OAAO,CAAC,CAAC,mBAAmB,EAAEqC,OAAOT,KAAK,CAAC,CAAC,CAAC;gBACnD,sEAAsE;gBACtE,wCAAwC;gBACxCU,iBAAiB;YACnB,EAAE,OAAOpC,OAAO;gBACd,MAAMqC,SAAS3E,2BAA2BsC;gBAC1C,IAAIqC,OAAOC,IAAI,KAAK,SAAS;oBAC3BP,KAAKQ,YAAY,CAACF,OAAOG,KAAK,EAAE,CAACC,OAAU,CAAA;4BACzC,GAAGA,IAAI;4BACPC,UAAU;gCAAC,GAAGD,KAAKC,QAAQ;gCAAEC,UAAUN,OAAOO,OAAO;4BAAA;wBACvD,CAAA;gBACF,OAAO;oBACLd,aAAaO,OAAOO,OAAO;gBAC7B;YACF;QACF;IACF;IAEA,SAASR,iBAAiBS,QAAiB;QACzC,IAAI,CAACA,UAAU;YACbd,KAAKe,KAAK;YACVhB,aAAa9C;YACb4C,OAAOkB,KAAK;QACd;QACA1C,aAAayC;IACf;IAEA,qBACE,MAAC7G;QAAMyD,MAAMA;QAAMW,cAAcgC;;0BAC/B,KAAC9F;gBAAa+D,OAAO;0BACnB,cAAA,KAAC5E;oBAAOgD,MAAK;oBAAKD,SAAQ;8BAAY;;;0BAIxC,MAACtC;;kCACC,KAACG;wBAAW2B,WAAU;kCAAU;;kCAChC,KAAC5B;kCACC,cAAA,KAACa;4BAAKwB,MAAK;sCAAK;;;kCAElB,MAACxC;wBAAU+B,WAAU;;4BAClB6D,0BACC,KAACnG;gCAAQqH,MAAK;gCAAQC,MAAK;0CACxBnB;iCAED;0CACJ,KAACE;gCACCvC,IAAG;gCACHxB,WAAU;gCACViF,UAAU;gCACVhB,UAAU,CAACiB;oCACTA,MAAMC,cAAc;oCACpBD,MAAME,eAAe;oCACrB,KAAKrB,KAAKsB,YAAY;gCACxB;0CAEA,cAAA,KAACtB,KAAKuB,KAAK;oCACT7C,MAAK;oCACL8C,YAAY;wCACVC,QAAQpI,2BAA2BqI,KAAK,CAAC/B,KAAK;wCAC9CO,UAAU7G,2BAA2BqI,KAAK,CAAC/B,KAAK;oCAClD;8CAEC,CAACc,sBACA,KAAC5G;4CACC8H,OAAM;4CACNlE,IAAG;4CACHQ,OAAOlE,WAAW0G;4CAClBmB,aAAa,CAAC,6CAA6C,EAAE7F,cAAc,CAAC,CAAC;sDAE7E,cAAA,KAACjC;gDACC+H,cAAa;gDACbC,SAAS;gDACTpD,MAAK;gDACLuC,MAAK;gDACLd,OAAOM,MAAMsB,KAAK,CAAC5B,KAAK;gDACxB6B,UAAU,CAACb,QAAUV,MAAMwB,YAAY,CAACd,MAAMe,MAAM,CAAC/B,KAAK;gDAC1DsB,QAAQhB,MAAM0B,UAAU;;;;;;;kCAOpC,MAAC/H;;0CACC,KAACV;gCAAO+C,SAAQ;gCAAYkC,SAAS,IAAM0B,iBAAiB;0CAAQ;;0CAGpE,KAAC3G;gCAAOuH,MAAK;gCAASjB,MAAK;gCAAqBvB,WAAWoB,OAAOlD,SAAS;0CAAE;;;;;;;;AAOvF;AAEA,SAASqC;IACP,qBACE,KAACpF;QACCwI,MAAK;QACLC,OAAM;QACNT,aAAY;;AAGlB;AAEA,SAAS/E,cAAc,EAACC,IAAI,EAAEC,IAAI,EAA+B;IAC/D,qBACE,KAACf;QAAIC,WAAU;kBACZqG,MAAMC,IAAI,CAAC;YAAC3F,QAAQE;QAAI,GAAGK,GAAG,CAAC,CAACqF,GAAGC,SAClC,wEAAwE;0BACxE,KAACzG;gBAAiBC,WAAU;0BACzBqG,MAAMC,IAAI,CAAC;oBAAC3F,QAAQG;gBAAI,GAAGI,GAAG,CAAC,CAACuF,IAAIC,SACnC,yEAAyE;kCACzE,KAACnI;wBAAsByB,WAAU;uBAAlB0G;eAHTF;;AASlB;AAEA,SAASvE,yBAAyBD,KAAc;IAC9C,IAAIA,iBAAiB3E,UAAU;QAC7B,IAAI2E,MAAM2E,IAAI,KAAK,4BAA4B,OAAO;QACtD,IAAI3E,MAAM2E,IAAI,KAAK,eAAe,OAAO;QACzC,OAAO3E,MAAM4C,OAAO;IACtB;IACA,IAAI5C,iBAAiB4E,OAAO,OAAO5E,MAAM4C,OAAO;IAChD,OAAO;AACT"}
1
+ {"version":3,"sources":["../../../src/components/members/workspace-members-section.tsx"],"sourcesContent":["import {createInvitationBodySchema, type MembershipWithUserDto} from '@shipfox/api-workspaces-dto';\nimport {ApiError} from '@shipfox/client-api';\nimport {useAuthState} from '@shipfox/client-auth';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n ModalTrigger,\n} from '@shipfox/react-ui/modal';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {formatDate} from '@shipfox/react-ui/utils';\nimport {useForm} from '@tanstack/react-form';\nimport {useState} from 'react';\nimport type {Invitation} from '#core/invitation.js';\nimport {useCreateInvitation} from '#hooks/api/create-invitation.js';\nimport {useListInvitations} from '#hooks/api/list-invitations.js';\nimport {useListMembers} from '#hooks/api/list-members.js';\nimport {useRemoveMember} from '#hooks/api/remove-member.js';\nimport {useRevokeInvitation} from '#hooks/api/revoke-invitation.js';\nimport {invitationErrorToFormError} from './form-errors.js';\n\nconst EXPIRES_SOON_MS = 24 * 60 * 60 * 1000;\n\nexport function WorkspaceMembersSettingsSection({\n workspaceId,\n workspaceName,\n}: {\n workspaceId: string;\n workspaceName: string;\n}) {\n return (\n <div className=\"flex min-w-0 flex-col gap-32\">\n <MembersSection workspaceId={workspaceId} workspaceName={workspaceName} />\n <PendingInvitationsSection workspaceId={workspaceId} workspaceName={workspaceName} />\n </div>\n );\n}\n\nfunction MembersSection({\n workspaceId,\n workspaceName,\n}: {\n workspaceId: string;\n workspaceName: string;\n}) {\n const auth = useAuthState();\n const query = useListMembers(workspaceId);\n const members = query.data?.members ?? [];\n\n return (\n <section className=\"flex flex-col gap-16\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Members</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {query.isPending\n ? 'Loading members…'\n : `${members.length} ${members.length === 1 ? 'member' : 'members'}`}\n </Text>\n </div>\n\n {query.isPending ? <TableSkeleton rows={3} cols={3} /> : null}\n\n {query.isError && query.data === undefined ? (\n <QueryLoadError query={query} subject=\"members\" />\n ) : null}\n\n {members.length > 0 ? (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Email</TableHead>\n <TableHead>Joined</TableHead>\n <TableHead className=\"w-80 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {members.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n isSelf={member.user_id === auth.user?.id}\n workspaceId={workspaceId}\n workspaceName={workspaceName}\n />\n ))}\n </TableBody>\n </Table>\n ) : null}\n </section>\n );\n}\n\nfunction MemberRow({\n member,\n isSelf,\n workspaceId,\n workspaceName,\n}: {\n member: MembershipWithUserDto;\n isSelf: boolean;\n workspaceId: string;\n workspaceName: string;\n}) {\n const [open, setOpen] = useState(false);\n const remove = useRemoveMember(workspaceId);\n\n async function handleRemove() {\n try {\n await remove.mutateAsync(member.user_id);\n toast.success(`Removed ${member.user_email} from ${workspaceName}.`);\n setOpen(false);\n } catch (error) {\n toast.error(removeMemberErrorMessage(error));\n }\n }\n\n return (\n <TableRow className={remove.isPending ? 'opacity-60' : undefined}>\n <TableCell className=\"font-medium\">{member.user_name ?? '—'}</TableCell>\n <TableCell>\n <Code variant=\"paragraph\">{member.user_email}</Code>\n </TableCell>\n <TableCell>{formatDate(member.created_at)}</TableCell>\n <TableCell className=\"text-right\">\n <Modal open={open} onOpenChange={setOpen}>\n <ModalTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"transparentMuted\"\n aria-label=\"Remove member\"\n disabled={isSelf}\n isLoading={remove.isPending}\n className={\n remove.isPending\n ? 'opacity-100 transition-opacity'\n : 'opacity-0 transition-opacity group-hover/row:opacity-100 focus-visible:opacity-100'\n }\n >\n <Icon name=\"userUnfollowLine\" className=\"size-16\" />\n </Button>\n </ModalTrigger>\n <ModalContent>\n <ModalTitle className=\"sr-only\">Remove member</ModalTitle>\n <ModalHeader>\n <Text size=\"lg\">\n Remove {member.user_name ?? member.user_email} from {workspaceName}?\n </Text>\n </ModalHeader>\n <ModalBody>\n <Text size=\"sm\">\n They will lose access immediately. They can be re-invited later.\n </Text>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={handleRemove} isLoading={remove.isPending}>\n Remove\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </TableCell>\n </TableRow>\n );\n}\n\nfunction PendingInvitationsSection({\n workspaceId,\n workspaceName,\n}: {\n workspaceId: string;\n workspaceName: string;\n}) {\n const query = useListInvitations(workspaceId);\n const invitations = query.data ?? [];\n const [inviteOpen, setInviteOpen] = useState(false);\n\n return (\n <section className=\"flex flex-col gap-16\">\n <div className=\"flex items-center justify-between gap-16\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Pending invitations</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {query.isPending\n ? 'Loading invitations…'\n : `${invitations.length} ${invitations.length === 1 ? 'invitation' : 'invitations'}`}\n </Text>\n </div>\n <InviteMemberModal\n open={inviteOpen}\n onOpenChange={setInviteOpen}\n workspaceId={workspaceId}\n workspaceName={workspaceName}\n />\n </div>\n\n {query.isPending ? <TableSkeleton rows={2} cols={3} /> : null}\n\n {query.isError && query.data === undefined ? (\n <QueryLoadError query={query} subject=\"invitations\" />\n ) : null}\n\n {query.data !== undefined && invitations.length === 0 ? <EmptyInvitations /> : null}\n\n {invitations.length > 0 ? (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Email</TableHead>\n <TableHead>Invited by</TableHead>\n <TableHead>Expires</TableHead>\n <TableHead className=\"w-80 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invitations.map((invitation) => (\n <InvitationRow\n key={invitation.id}\n invitation={invitation}\n workspaceId={workspaceId}\n />\n ))}\n </TableBody>\n </Table>\n ) : null}\n </section>\n );\n}\n\nfunction InvitationRow({invitation, workspaceId}: {invitation: Invitation; workspaceId: string}) {\n const [open, setOpen] = useState(false);\n const revoke = useRevokeInvitation(workspaceId);\n const expiresAt = new Date(invitation.expiresAt);\n const expiresSoon = expiresAt.getTime() - Date.now() < EXPIRES_SOON_MS;\n\n async function handleRevoke() {\n try {\n await revoke.mutateAsync(invitation.id);\n toast.success(`Invitation to ${invitation.email} revoked.`);\n setOpen(false);\n } catch {\n toast.error('Could not revoke invitation.');\n }\n }\n\n return (\n <TableRow className={revoke.isPending ? 'opacity-60' : undefined}>\n <TableCell>\n <Code variant=\"paragraph\">{invitation.email}</Code>\n </TableCell>\n <TableCell>{invitation.invitedByDisplay ?? '—'}</TableCell>\n <TableCell>\n <div className=\"flex items-center gap-8\">\n <Text size=\"sm\">{formatDate(invitation.expiresAt)}</Text>\n {expiresSoon ? <Badge variant=\"warning\">Soon</Badge> : null}\n </div>\n </TableCell>\n <TableCell className=\"text-right\">\n <Modal open={open} onOpenChange={setOpen}>\n <ModalTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"transparentMuted\"\n aria-label=\"Revoke invitation\"\n isLoading={revoke.isPending}\n className={\n revoke.isPending\n ? 'opacity-100 transition-opacity'\n : 'opacity-0 transition-opacity group-hover/row:opacity-100 focus-visible:opacity-100'\n }\n >\n <Icon name=\"closeLine\" className=\"size-16\" />\n </Button>\n </ModalTrigger>\n <ModalContent>\n <ModalTitle className=\"sr-only\">Revoke invitation</ModalTitle>\n <ModalHeader>\n <Text size=\"lg\">Revoke invitation to {invitation.email}?</Text>\n </ModalHeader>\n <ModalBody>\n <Text size=\"sm\">They will no longer be able to use the link from their email.</Text>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={handleRevoke} isLoading={revoke.isPending}>\n Revoke\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </TableCell>\n </TableRow>\n );\n}\n\nfunction InviteMemberModal({\n open,\n onOpenChange,\n workspaceId,\n workspaceName,\n}: {\n open: boolean;\n onOpenChange: (next: boolean) => void;\n workspaceId: string;\n workspaceName: string;\n}) {\n const create = useCreateInvitation(workspaceId);\n const [formError, setFormError] = useState<string | undefined>();\n\n const form = useForm({\n defaultValues: {email: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n const result = await create.mutateAsync({email: value.email});\n toast.success(`Invitation sent to ${result.email}.`);\n // Go through handleOpenChange so form.reset() fires and reopening the\n // modal does not show stale form state.\n handleOpenChange(false);\n } catch (error) {\n const mapped = invitationErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n function handleOpenChange(nextOpen: boolean) {\n if (!nextOpen) {\n form.reset();\n setFormError(undefined);\n create.reset();\n }\n onOpenChange(nextOpen);\n }\n\n return (\n <Modal open={open} onOpenChange={handleOpenChange}>\n <ModalTrigger asChild>\n <Button size=\"sm\" variant=\"secondary\">\n Invite member\n </Button>\n </ModalTrigger>\n <ModalContent>\n <ModalTitle className=\"sr-only\">Invite a member</ModalTitle>\n <ModalHeader>\n <Text size=\"lg\">Invite a member</Text>\n </ModalHeader>\n <ModalBody className=\"gap-16\">\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form\n id=\"invite-member-form\"\n className=\"flex flex-col gap-16\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"email\"\n validators={{\n onBlur: createInvitationBodySchema.shape.email,\n onSubmit: createInvitationBodySchema.shape.email,\n }}\n >\n {(field) => (\n <FormField\n label=\"Email\"\n id=\"invite-email\"\n error={fieldError(field)}\n description={`They'll receive an email with a link to join ${workspaceName}.`}\n >\n <FormFieldInput\n autoComplete=\"email\"\n autoFocus\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n </form>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"secondary\" onClick={() => handleOpenChange(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" form=\"invite-member-form\" isLoading={create.isPending}>\n Send invitation\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n\nfunction EmptyInvitations() {\n return (\n <EmptyState\n icon=\"mailLine\"\n title=\"No pending invitations.\"\n description=\"Invite someone above to grow your workspace.\"\n />\n );\n}\n\nfunction TableSkeleton({rows, cols}: {rows: number; cols: number}) {\n return (\n <div className=\"flex flex-col gap-12\">\n {Array.from({length: rows}).map((_, rowIdx) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: stable placeholder rows\n <div key={rowIdx} className=\"grid grid-cols-3 gap-16\">\n {Array.from({length: cols}).map((__, colIdx) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: stable placeholder cells\n <Skeleton key={colIdx} className=\"h-20\" />\n ))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction removeMemberErrorMessage(error: unknown): string {\n if (error instanceof ApiError) {\n if (error.code === 'self-removal-not-allowed') return \"You can't remove yourself.\";\n if (error.code === 'last-member') return 'Cannot remove the last member.';\n return error.message;\n }\n if (error instanceof Error) return error.message;\n return 'Could not remove member.';\n}\n"],"names":["createInvitationBodySchema","ApiError","useAuthState","QueryLoadError","Badge","Button","Callout","EmptyState","FormField","FormFieldInput","fieldError","Icon","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","ModalTrigger","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","formatDate","useForm","useState","useCreateInvitation","useListInvitations","useListMembers","useRemoveMember","useRevokeInvitation","invitationErrorToFormError","EXPIRES_SOON_MS","WorkspaceMembersSettingsSection","workspaceId","workspaceName","div","className","MembersSection","PendingInvitationsSection","auth","query","members","data","section","variant","size","isPending","length","TableSkeleton","rows","cols","isError","undefined","subject","map","member","MemberRow","isSelf","user_id","user","id","open","setOpen","remove","handleRemove","mutateAsync","success","user_email","error","removeMemberErrorMessage","user_name","created_at","onOpenChange","asChild","aria-label","disabled","isLoading","name","onClick","invitations","inviteOpen","setInviteOpen","InviteMemberModal","EmptyInvitations","invitation","InvitationRow","revoke","expiresAt","Date","expiresSoon","getTime","now","handleRevoke","email","invitedByDisplay","create","formError","setFormError","form","defaultValues","onSubmit","value","result","handleOpenChange","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","nextOpen","reset","role","type","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","validators","onBlur","shape","label","description","autoComplete","autoFocus","state","onChange","handleChange","target","handleBlur","icon","title","Array","from","_","rowIdx","__","colIdx","code","Error"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface Invitation {
2
+ id: string;
3
+ workspaceId: string;
4
+ email: string;
5
+ expiresAt: string;
6
+ acceptedAt: string | null;
7
+ invitedByUserId: string;
8
+ invitedByDisplay: string | null;
9
+ createdAt: string;
10
+ updatedAt: string;
11
+ }
12
+ export interface CreateInvitationCommand {
13
+ email: string;
14
+ }
15
+ //# sourceMappingURL=invitation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invitation.d.ts","sourceRoot":"","sources":["../../src/core/invitation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=invitation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/invitation.ts"],"sourcesContent":["export interface Invitation {\n id: string;\n workspaceId: string;\n email: string;\n expiresAt: string;\n acceptedAt: string | null;\n invitedByUserId: string;\n invitedByDisplay: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateInvitationCommand {\n email: string;\n}\n"],"names":[],"mappings":"AAYA,WAEC"}
package/dist/feature.d.ts CHANGED
@@ -9,34 +9,6 @@ export declare const workspaceSettingsFeature: {
9
9
  readonly path: "/workspaces/$wid/settings/members";
10
10
  readonly parent: "workspaceSettings";
11
11
  readonly impl: "@shipfox/client-workspace-settings/routes/members";
12
- }, {
13
- readonly path: "/workspaces/$wid/settings/runners";
14
- readonly parent: "workspaceSettings";
15
- readonly impl: "@shipfox/client-workspace-settings/routes/runners";
16
- }, {
17
- readonly path: "/workspaces/$wid/settings/provisioners";
18
- readonly parent: "workspaceSettings";
19
- readonly impl: "@shipfox/client-workspace-settings/routes/provisioners";
20
- }, {
21
- readonly path: "/workspaces/$wid/settings/agents";
22
- readonly parent: "workspaceSettings";
23
- readonly impl: "@shipfox/client-workspace-settings/routes/agents";
24
- }, {
25
- readonly path: "/workspaces/$wid/settings/secrets";
26
- readonly parent: "workspaceSettings";
27
- readonly impl: "@shipfox/client-workspace-settings/routes/secrets";
28
- }, {
29
- readonly path: "/workspaces/$wid/settings/variables";
30
- readonly parent: "workspaceSettings";
31
- readonly impl: "@shipfox/client-workspace-settings/routes/variables";
32
- }, {
33
- readonly path: "/workspaces/$wid/settings/integrations";
34
- readonly parent: "workspaceSettings";
35
- readonly impl: "@shipfox/client-workspace-settings/routes/integrations";
36
- }, {
37
- readonly path: "/workspaces/$wid/settings/events";
38
- readonly parent: "workspaceSettings";
39
- readonly impl: "@shipfox/client-workspace-settings/routes/events";
40
12
  }];
41
13
  readonly navigation: readonly [{
42
14
  readonly id: "nav.settings";
@@ -51,48 +23,6 @@ export declare const workspaceSettingsFeature: {
51
23
  readonly label: "Members";
52
24
  readonly icon: IconName;
53
25
  readonly order: 100;
54
- }, {
55
- readonly id: "settings.runners";
56
- readonly pathSegment: "runners";
57
- readonly label: "Runners";
58
- readonly icon: IconName;
59
- readonly order: 200;
60
- }, {
61
- readonly id: "settings.provisioners";
62
- readonly pathSegment: "provisioners";
63
- readonly label: "Runner provisioners";
64
- readonly icon: IconName;
65
- readonly order: 300;
66
- }, {
67
- readonly id: "settings.agents";
68
- readonly pathSegment: "agents";
69
- readonly label: "Agents";
70
- readonly icon: IconName;
71
- readonly order: 400;
72
- }, {
73
- readonly id: "settings.secrets";
74
- readonly pathSegment: "secrets";
75
- readonly label: "Secrets";
76
- readonly icon: IconName;
77
- readonly order: 500;
78
- }, {
79
- readonly id: "settings.variables";
80
- readonly pathSegment: "variables";
81
- readonly label: "Variables";
82
- readonly icon: IconName;
83
- readonly order: 600;
84
- }, {
85
- readonly id: "settings.integrations";
86
- readonly pathSegment: "integrations";
87
- readonly label: "Integrations";
88
- readonly icon: IconName;
89
- readonly order: 700;
90
- }, {
91
- readonly id: "settings.events";
92
- readonly pathSegment: "events";
93
- readonly label: "Events";
94
- readonly icon: IconName;
95
- readonly order: 800;
96
26
  }];
97
27
  };
98
28
  //# sourceMappingURL=feature.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAErD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBA+DX,QAAQ;;;;;;uBAOH,QAAQ;;;;;;uBAOX,QAAQ;;;;;;uBAOR,QAAQ;;;;;;uBAOX,QAAQ;;;;;;uBAOL,QAAQ;;;;;;uBAOV,QAAQ;;;;;;uBAOP,QAAQ;;;CAIjC,CAAC"}
1
+ {"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAErD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;uBA4BX,QAAQ;;;CAIhC,CAAC"}
package/dist/feature.js CHANGED
@@ -11,41 +11,6 @@ export const workspaceSettingsFeature = defineClientFeature({
11
11
  path: '/workspaces/$wid/settings/members',
12
12
  parent: 'workspaceSettings',
13
13
  impl: '@shipfox/client-workspace-settings/routes/members'
14
- },
15
- {
16
- path: '/workspaces/$wid/settings/runners',
17
- parent: 'workspaceSettings',
18
- impl: '@shipfox/client-workspace-settings/routes/runners'
19
- },
20
- {
21
- path: '/workspaces/$wid/settings/provisioners',
22
- parent: 'workspaceSettings',
23
- impl: '@shipfox/client-workspace-settings/routes/provisioners'
24
- },
25
- {
26
- path: '/workspaces/$wid/settings/agents',
27
- parent: 'workspaceSettings',
28
- impl: '@shipfox/client-workspace-settings/routes/agents'
29
- },
30
- {
31
- path: '/workspaces/$wid/settings/secrets',
32
- parent: 'workspaceSettings',
33
- impl: '@shipfox/client-workspace-settings/routes/secrets'
34
- },
35
- {
36
- path: '/workspaces/$wid/settings/variables',
37
- parent: 'workspaceSettings',
38
- impl: '@shipfox/client-workspace-settings/routes/variables'
39
- },
40
- {
41
- path: '/workspaces/$wid/settings/integrations',
42
- parent: 'workspaceSettings',
43
- impl: '@shipfox/client-workspace-settings/routes/integrations'
44
- },
45
- {
46
- path: '/workspaces/$wid/settings/events',
47
- parent: 'workspaceSettings',
48
- impl: '@shipfox/client-workspace-settings/routes/events'
49
14
  }
50
15
  ],
51
16
  navigation: [
@@ -64,55 +29,6 @@ export const workspaceSettingsFeature = defineClientFeature({
64
29
  label: 'Members',
65
30
  icon: 'userLine',
66
31
  order: 100
67
- },
68
- {
69
- id: 'settings.runners',
70
- pathSegment: 'runners',
71
- label: 'Runners',
72
- icon: 'settings3Line',
73
- order: 200
74
- },
75
- {
76
- id: 'settings.provisioners',
77
- pathSegment: 'provisioners',
78
- label: 'Runner provisioners',
79
- icon: 'serverLine',
80
- order: 300
81
- },
82
- {
83
- id: 'settings.agents',
84
- pathSegment: 'agents',
85
- label: 'Agents',
86
- icon: 'robot2Line',
87
- order: 400
88
- },
89
- {
90
- id: 'settings.secrets',
91
- pathSegment: 'secrets',
92
- label: 'Secrets',
93
- icon: 'keyLine',
94
- order: 500
95
- },
96
- {
97
- id: 'settings.variables',
98
- pathSegment: 'variables',
99
- label: 'Variables',
100
- icon: 'bracesLine',
101
- order: 600
102
- },
103
- {
104
- id: 'settings.integrations',
105
- pathSegment: 'integrations',
106
- label: 'Integrations',
107
- icon: 'plugLine',
108
- order: 700
109
- },
110
- {
111
- id: 'settings.events',
112
- pathSegment: 'events',
113
- label: 'Events',
114
- icon: 'pulseLine',
115
- order: 800
116
32
  }
117
33
  ]
118
34
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/feature.ts"],"sourcesContent":["import {defineClientFeature} from '@shipfox/client-shell';\nimport type {IconName} from '@shipfox/react-ui/icon';\n\nexport const workspaceSettingsFeature = defineClientFeature({\n id: 'shipfox.workspace-settings',\n routes: [\n {\n path: '/workspaces/$wid/settings',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/index',\n },\n {\n path: '/workspaces/$wid/settings/members',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/members',\n },\n {\n path: '/workspaces/$wid/settings/runners',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/runners',\n },\n {\n path: '/workspaces/$wid/settings/provisioners',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/provisioners',\n },\n {\n path: '/workspaces/$wid/settings/agents',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/agents',\n },\n {\n path: '/workspaces/$wid/settings/secrets',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/secrets',\n },\n {\n path: '/workspaces/$wid/settings/variables',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/variables',\n },\n {\n path: '/workspaces/$wid/settings/integrations',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/integrations',\n },\n {\n path: '/workspaces/$wid/settings/events',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/events',\n },\n ],\n navigation: [\n {\n id: 'nav.settings',\n scope: 'workspace',\n label: 'Settings',\n to: '/workspaces/$wid/settings',\n order: 200,\n },\n ],\n settingsSections: [\n {\n id: 'settings.members',\n pathSegment: 'members',\n label: 'Members',\n icon: 'userLine' as IconName,\n order: 100,\n },\n {\n id: 'settings.runners',\n pathSegment: 'runners',\n label: 'Runners',\n icon: 'settings3Line' as IconName,\n order: 200,\n },\n {\n id: 'settings.provisioners',\n pathSegment: 'provisioners',\n label: 'Runner provisioners',\n icon: 'serverLine' as IconName,\n order: 300,\n },\n {\n id: 'settings.agents',\n pathSegment: 'agents',\n label: 'Agents',\n icon: 'robot2Line' as IconName,\n order: 400,\n },\n {\n id: 'settings.secrets',\n pathSegment: 'secrets',\n label: 'Secrets',\n icon: 'keyLine' as IconName,\n order: 500,\n },\n {\n id: 'settings.variables',\n pathSegment: 'variables',\n label: 'Variables',\n icon: 'bracesLine' as IconName,\n order: 600,\n },\n {\n id: 'settings.integrations',\n pathSegment: 'integrations',\n label: 'Integrations',\n icon: 'plugLine' as IconName,\n order: 700,\n },\n {\n id: 'settings.events',\n pathSegment: 'events',\n label: 'Events',\n icon: 'pulseLine' as IconName,\n order: 800,\n },\n ],\n});\n"],"names":["defineClientFeature","workspaceSettingsFeature","id","routes","path","parent","impl","navigation","scope","label","to","order","settingsSections","pathSegment","icon"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAG1D,OAAO,MAAMC,2BAA2BD,oBAAoB;IAC1DE,IAAI;IACJC,QAAQ;QACN;YACEC,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;KACD;IACDC,YAAY;QACV;YACEL,IAAI;YACJM,OAAO;YACPC,OAAO;YACPC,IAAI;YACJC,OAAO;QACT;KACD;IACDC,kBAAkB;QAChB;YACEV,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;QACA;YACET,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;KACD;AACH,GAAG"}
1
+ {"version":3,"sources":["../src/feature.ts"],"sourcesContent":["import {defineClientFeature} from '@shipfox/client-shell';\nimport type {IconName} from '@shipfox/react-ui/icon';\n\nexport const workspaceSettingsFeature = defineClientFeature({\n id: 'shipfox.workspace-settings',\n routes: [\n {\n path: '/workspaces/$wid/settings',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/index',\n },\n {\n path: '/workspaces/$wid/settings/members',\n parent: 'workspaceSettings',\n impl: '@shipfox/client-workspace-settings/routes/members',\n },\n ],\n navigation: [\n {\n id: 'nav.settings',\n scope: 'workspace',\n label: 'Settings',\n to: '/workspaces/$wid/settings',\n order: 200,\n },\n ],\n settingsSections: [\n {\n id: 'settings.members',\n pathSegment: 'members',\n label: 'Members',\n icon: 'userLine' as IconName,\n order: 100,\n },\n ],\n});\n"],"names":["defineClientFeature","workspaceSettingsFeature","id","routes","path","parent","impl","navigation","scope","label","to","order","settingsSections","pathSegment","icon"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAG1D,OAAO,MAAMC,2BAA2BD,oBAAoB;IAC1DE,IAAI;IACJC,QAAQ;QACN;YACEC,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;QACA;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;KACD;IACDC,YAAY;QACV;YACEL,IAAI;YACJM,OAAO;YACPC,OAAO;YACPC,IAAI;YACJC,OAAO;QACT;KACD;IACDC,kBAAkB;QAChB;YACEV,IAAI;YACJW,aAAa;YACbJ,OAAO;YACPK,MAAM;YACNH,OAAO;QACT;KACD;AACH,GAAG"}
@@ -1,14 +1,3 @@
1
- export declare function useCreateInvitation(workspaceId: string): import("@tanstack/react-query").UseMutationResult<{
2
- id: string;
3
- workspace_id: string;
4
- email: string;
5
- expires_at: string;
6
- accepted_at: string | null;
7
- invited_by_user_id: string;
8
- invited_by_display: string | null;
9
- created_at: string;
10
- updated_at: string;
11
- }, Error, {
12
- email: string;
13
- }, unknown>;
1
+ import type { CreateInvitationCommand, Invitation } from '#core/invitation.js';
2
+ export declare function useCreateInvitation(workspaceId: string): import("@tanstack/react-query").UseMutationResult<Invitation, Error, CreateInvitationCommand, unknown>;
14
3
  //# sourceMappingURL=create-invitation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-invitation.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/create-invitation.ts"],"names":[],"mappings":"AAYA,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM;;;;;;;;;;;;YAQtD"}
1
+ {"version":3,"file":"create-invitation.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/create-invitation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,uBAAuB,EAAE,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAmB7E,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,0GAQtD"}
@@ -1,23 +1,26 @@
1
- import { apiRequest } from '@shipfox/client-api';
1
+ import { invitationDtoSchema } from '@shipfox/api-workspaces-dto';
2
+ import { checkedApiRequest } from '@shipfox/client-api';
2
3
  import { useMutation, useQueryClient } from '@tanstack/react-query';
3
- import { listInvitationsQueryKey } from './list-invitations.js';
4
+ import { toInvitation } from './invitation-mapper.js';
5
+ import { listInvitationsQueryOptions } from './list-invitations.js';
4
6
  async function createInvitation(params) {
5
- return await apiRequest(`/workspaces/${params.workspaceId}/invitations`, {
7
+ const response = await checkedApiRequest(invitationDtoSchema, `/workspaces/${params.workspaceId}/invitations`, {
6
8
  method: 'POST',
7
- body: params.body
9
+ body: {
10
+ email: params.command.email
11
+ }
8
12
  });
13
+ return toInvitation(response);
9
14
  }
10
15
  export function useCreateInvitation(workspaceId) {
11
16
  const queryClient = useQueryClient();
12
17
  return useMutation({
13
- mutationFn: (body)=>createInvitation({
18
+ mutationFn: (command)=>createInvitation({
14
19
  workspaceId,
15
- body
20
+ command
16
21
  }),
17
22
  onSuccess: async ()=>{
18
- await queryClient.invalidateQueries({
19
- queryKey: listInvitationsQueryKey(workspaceId)
20
- });
23
+ await queryClient.invalidateQueries(listInvitationsQueryOptions(workspaceId));
21
24
  }
22
25
  });
23
26
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/create-invitation.ts"],"sourcesContent":["import type {CreateInvitationBodyDto, InvitationDto} from '@shipfox/api-workspaces-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {useMutation, useQueryClient} from '@tanstack/react-query';\nimport {listInvitationsQueryKey} from './list-invitations.js';\n\nasync function createInvitation(params: {workspaceId: string; body: CreateInvitationBodyDto}) {\n return await apiRequest<InvitationDto>(`/workspaces/${params.workspaceId}/invitations`, {\n method: 'POST',\n body: params.body,\n });\n}\n\nexport function useCreateInvitation(workspaceId: string) {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (body: CreateInvitationBodyDto) => createInvitation({workspaceId, body}),\n onSuccess: async () => {\n await queryClient.invalidateQueries({queryKey: listInvitationsQueryKey(workspaceId)});\n },\n });\n}\n"],"names":["apiRequest","useMutation","useQueryClient","listInvitationsQueryKey","createInvitation","params","workspaceId","method","body","useCreateInvitation","queryClient","mutationFn","onSuccess","invalidateQueries","queryKey"],"mappings":"AACA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,WAAW,EAAEC,cAAc,QAAO,wBAAwB;AAClE,SAAQC,uBAAuB,QAAO,wBAAwB;AAE9D,eAAeC,iBAAiBC,MAA4D;IAC1F,OAAO,MAAML,WAA0B,CAAC,YAAY,EAAEK,OAAOC,WAAW,CAAC,YAAY,CAAC,EAAE;QACtFC,QAAQ;QACRC,MAAMH,OAAOG,IAAI;IACnB;AACF;AAEA,OAAO,SAASC,oBAAoBH,WAAmB;IACrD,MAAMI,cAAcR;IACpB,OAAOD,YAAY;QACjBU,YAAY,CAACH,OAAkCJ,iBAAiB;gBAACE;gBAAaE;YAAI;QAClFI,WAAW;YACT,MAAMF,YAAYG,iBAAiB,CAAC;gBAACC,UAAUX,wBAAwBG;YAAY;QACrF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/create-invitation.ts"],"sourcesContent":["import {invitationDtoSchema} from '@shipfox/api-workspaces-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation, useQueryClient} from '@tanstack/react-query';\nimport type {CreateInvitationCommand, Invitation} from '#core/invitation.js';\nimport {toInvitation} from './invitation-mapper.js';\nimport {listInvitationsQueryOptions} from './list-invitations.js';\n\nasync function createInvitation(params: {\n workspaceId: string;\n command: CreateInvitationCommand;\n}): Promise<Invitation> {\n const response = await checkedApiRequest(\n invitationDtoSchema,\n `/workspaces/${params.workspaceId}/invitations`,\n {\n method: 'POST',\n body: {email: params.command.email},\n },\n );\n return toInvitation(response);\n}\n\nexport function useCreateInvitation(workspaceId: string) {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (command: CreateInvitationCommand) => createInvitation({workspaceId, command}),\n onSuccess: async () => {\n await queryClient.invalidateQueries(listInvitationsQueryOptions(workspaceId));\n },\n });\n}\n"],"names":["invitationDtoSchema","checkedApiRequest","useMutation","useQueryClient","toInvitation","listInvitationsQueryOptions","createInvitation","params","response","workspaceId","method","body","email","command","useCreateInvitation","queryClient","mutationFn","onSuccess","invalidateQueries"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,8BAA8B;AAChE,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,EAAEC,cAAc,QAAO,wBAAwB;AAElE,SAAQC,YAAY,QAAO,yBAAyB;AACpD,SAAQC,2BAA2B,QAAO,wBAAwB;AAElE,eAAeC,iBAAiBC,MAG/B;IACC,MAAMC,WAAW,MAAMP,kBACrBD,qBACA,CAAC,YAAY,EAAEO,OAAOE,WAAW,CAAC,YAAY,CAAC,EAC/C;QACEC,QAAQ;QACRC,MAAM;YAACC,OAAOL,OAAOM,OAAO,CAACD,KAAK;QAAA;IACpC;IAEF,OAAOR,aAAaI;AACtB;AAEA,OAAO,SAASM,oBAAoBL,WAAmB;IACrD,MAAMM,cAAcZ;IACpB,OAAOD,YAAY;QACjBc,YAAY,CAACH,UAAqCP,iBAAiB;gBAACG;gBAAaI;YAAO;QACxFI,WAAW;YACT,MAAMF,YAAYG,iBAAiB,CAACb,4BAA4BI;QAClE;IACF;AACF"}
@@ -0,0 +1,4 @@
1
+ import type { InvitationDto } from '@shipfox/api-workspaces-dto';
2
+ import type { Invitation } from '#core/invitation.js';
3
+ export declare function toInvitation(dto: InvitationDto): Invitation;
4
+ //# sourceMappingURL=invitation-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invitation-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/invitation-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAEpD,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAY3D"}
@@ -0,0 +1,15 @@
1
+ export function toInvitation(dto) {
2
+ return {
3
+ id: dto.id,
4
+ workspaceId: dto.workspace_id,
5
+ email: dto.email,
6
+ expiresAt: dto.expires_at,
7
+ acceptedAt: dto.accepted_at,
8
+ invitedByUserId: dto.invited_by_user_id,
9
+ invitedByDisplay: dto.invited_by_display,
10
+ createdAt: dto.created_at,
11
+ updatedAt: dto.updated_at
12
+ };
13
+ }
14
+
15
+ //# sourceMappingURL=invitation-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/api/invitation-mapper.ts"],"sourcesContent":["import type {InvitationDto} from '@shipfox/api-workspaces-dto';\nimport type {Invitation} from '#core/invitation.js';\n\nexport function toInvitation(dto: InvitationDto): Invitation {\n return {\n id: dto.id,\n workspaceId: dto.workspace_id,\n email: dto.email,\n expiresAt: dto.expires_at,\n acceptedAt: dto.accepted_at,\n invitedByUserId: dto.invited_by_user_id,\n invitedByDisplay: dto.invited_by_display,\n createdAt: dto.created_at,\n updatedAt: dto.updated_at,\n };\n}\n"],"names":["toInvitation","dto","id","workspaceId","workspace_id","email","expiresAt","expires_at","acceptedAt","accepted_at","invitedByUserId","invited_by_user_id","invitedByDisplay","invited_by_display","createdAt","created_at","updatedAt","updated_at"],"mappings":"AAGA,OAAO,SAASA,aAAaC,GAAkB;IAC7C,OAAO;QACLC,IAAID,IAAIC,EAAE;QACVC,aAAaF,IAAIG,YAAY;QAC7BC,OAAOJ,IAAII,KAAK;QAChBC,WAAWL,IAAIM,UAAU;QACzBC,YAAYP,IAAIQ,WAAW;QAC3BC,iBAAiBT,IAAIU,kBAAkB;QACvCC,kBAAkBX,IAAIY,kBAAkB;QACxCC,WAAWb,IAAIc,UAAU;QACzBC,WAAWf,IAAIgB,UAAU;IAC3B;AACF"}
@@ -1,15 +1,12 @@
1
+ import type { Invitation } from '#core/invitation.js';
1
2
  export declare const listInvitationsQueryKey: (workspaceId: string) => readonly ["workspaces", string, "invitations"];
2
- export declare function useListInvitations(workspaceId: string): import("@tanstack/react-query").UseQueryResult<NoInfer<{
3
- invitations: {
4
- id: string;
5
- workspace_id: string;
6
- email: string;
7
- expires_at: string;
8
- accepted_at: string | null;
9
- invited_by_user_id: string;
10
- invited_by_display: string | null;
11
- created_at: string;
12
- updated_at: string;
13
- }[];
14
- }>, Error>;
3
+ export declare function listInvitationsQueryOptions(workspaceId: string): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<Invitation[], Error, Invitation[], readonly ["workspaces", string, "invitations"]>, "queryFn"> & {
4
+ queryFn?: import("@tanstack/react-query").QueryFunction<Invitation[], readonly ["workspaces", string, "invitations"], never>;
5
+ } & {
6
+ queryKey: readonly ["workspaces", string, "invitations"] & {
7
+ [dataTagSymbol]: Invitation[];
8
+ [dataTagErrorSymbol]: Error;
9
+ };
10
+ };
11
+ export declare function useListInvitations(workspaceId: string): import("@tanstack/react-query").UseQueryResult<NoInfer<Invitation[]>, Error>;
15
12
  //# sourceMappingURL=list-invitations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-invitations.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/list-invitations.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,uBAAuB,GAAI,aAAa,MAAM,mDACN,CAAC;AAMtD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM;;;;;;;;;;;;WAKrD"}
1
+ {"version":3,"file":"list-invitations.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/list-invitations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAGpD,eAAO,MAAM,uBAAuB,GAAI,aAAa,MAAM,mDACN,CAAC;AAUtD,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM;;;;;;;EAK9D;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,gFAErD"}