@shipfox/client-workspace-settings 12.0.1 → 13.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 (40) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +37 -0
  3. package/dist/components/general/form-errors.d.ts +11 -0
  4. package/dist/components/general/form-errors.d.ts.map +1 -0
  5. package/dist/components/general/form-errors.js +16 -0
  6. package/dist/components/general/form-errors.js.map +1 -0
  7. package/dist/components/members/workspace-members-section.js +2 -2
  8. package/dist/components/members/workspace-members-section.js.map +1 -1
  9. package/dist/components/workspace-settings-shell.d.ts +3 -3
  10. package/dist/components/workspace-settings-shell.d.ts.map +1 -1
  11. package/dist/components/workspace-settings-shell.js +5 -2
  12. package/dist/components/workspace-settings-shell.js.map +1 -1
  13. package/dist/feature.d.ts +20 -4
  14. package/dist/feature.d.ts.map +1 -1
  15. package/dist/feature.js +15 -3
  16. package/dist/feature.js.map +1 -1
  17. package/dist/pages/general-settings-page.d.ts +2 -0
  18. package/dist/pages/general-settings-page.d.ts.map +1 -0
  19. package/dist/pages/general-settings-page.js +191 -0
  20. package/dist/pages/general-settings-page.js.map +1 -0
  21. package/dist/routes/general.d.ts +6 -0
  22. package/dist/routes/general.d.ts.map +1 -0
  23. package/dist/routes/general.js +7 -0
  24. package/dist/routes/general.js.map +1 -0
  25. package/dist/routes/index.d.ts +1 -1
  26. package/dist/routes/index.d.ts.map +1 -1
  27. package/dist/routes/index.js +2 -2
  28. package/dist/routes/index.js.map +1 -1
  29. package/dist/tsconfig.test.tsbuildinfo +1 -1
  30. package/package.json +7 -7
  31. package/src/components/general/form-errors.ts +17 -0
  32. package/src/components/members/workspace-members-section.tsx +2 -2
  33. package/src/components/workspace-settings-shell.tsx +5 -3
  34. package/src/feature.ts +15 -3
  35. package/src/pages/general-settings-page.test.tsx +91 -0
  36. package/src/pages/general-settings-page.tsx +198 -0
  37. package/src/routes/general.tsx +4 -0
  38. package/src/routes/index.tsx +5 -2
  39. package/test/pages.tsx +11 -5
  40. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pages/general-settings-page.tsx"],"sourcesContent":["import {createWorkspaceBodySchema} from '@shipfox/api-workspaces-dto';\nimport {\n checkWorkspaceSlugAvailability,\n type useActiveWorkspace,\n useUpdateWorkspaceMutation,\n} from '@shipfox/client-auth';\nimport {displayNameFieldError, SlugChangeWarning, SlugField} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useNavigate} from '@tanstack/react-router';\nimport {useState} from 'react';\nimport {workspaceGeneralErrorToFormError} from '#components/general/form-errors.js';\nimport {WorkspaceSettingsShell} from '#components/workspace-settings-shell.js';\n\ninterface WorkspaceGeneralValues {\n name: string;\n slug: string;\n}\n\nfunction isSlugValid(value: string): boolean {\n return createWorkspaceBodySchema.shape.slug.safeParse(value).success;\n}\n\nexport function GeneralSettingsPage() {\n return (\n <WorkspaceSettingsShell>\n {(workspace) => (\n <WorkspaceGeneralForm\n key={`${workspace.id}:${workspace.name}:${workspace.slug}`}\n workspace={workspace}\n />\n )}\n </WorkspaceSettingsShell>\n );\n}\n\nfunction WorkspaceGeneralForm({workspace}: {workspace: ReturnType<typeof useActiveWorkspace>}) {\n const updateWorkspace = useUpdateWorkspaceMutation();\n const navigate = useNavigate();\n const [warningOpen, setWarningOpen] = useState(false);\n const [pendingValues, setPendingValues] = useState<WorkspaceGeneralValues>();\n const [formError, setFormError] = useState<string>();\n\n const form = useForm({\n defaultValues: {name: workspace.name, slug: workspace.slug},\n onSubmit: async ({value}) => {\n if (value.slug !== workspace.slug) {\n setPendingValues(value);\n setWarningOpen(true);\n return;\n }\n await save(value);\n },\n });\n\n async function save(values: WorkspaceGeneralValues) {\n setFormError(undefined);\n const nameChanged = values.name !== workspace.name;\n const slugChanged = values.slug !== workspace.slug;\n if (!nameChanged && !slugChanged) return;\n const command = {\n workspaceId: workspace.id,\n ...(nameChanged ? {name: values.name} : {}),\n ...(slugChanged ? {slug: values.slug} : {}),\n };\n\n try {\n const updated = await updateWorkspace.mutateAsync(command);\n setPendingValues(undefined);\n setWarningOpen(false);\n toast.success('Workspace settings saved.');\n await navigate({\n to: '/w/$workspaceSlug/settings/general',\n params: {workspaceSlug: updated.slug},\n });\n } catch (error) {\n setPendingValues(undefined);\n setWarningOpen(false);\n const mapped = workspaceGeneralErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (previous) => ({\n ...previous,\n errorMap: {...previous.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n }\n\n return (\n <>\n <div className=\"flex min-w-0 flex-col gap-24\">\n <header className=\"flex flex-col gap-6\">\n <Header variant=\"h1\">General</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Update the workspace name and the slug used in its URLs.\n </Text>\n </header>\n\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n\n <form\n className=\"flex max-w-[560px] 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=\"name\"\n validators={{\n onBlur: ({value}) =>\n displayNameFieldError(\n value,\n 'Workspace name',\n createWorkspaceBodySchema.shape.name,\n ),\n onSubmit: ({value}) =>\n displayNameFieldError(\n value,\n 'Workspace name',\n createWorkspaceBodySchema.shape.name,\n ),\n }}\n >\n {(field) => (\n <FormField\n label=\"Workspace name\"\n id=\"workspace-settings-name\"\n error={fieldError(field)}\n >\n <FormFieldInput\n name=\"name\"\n type=\"text\"\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\n <form.Field\n name=\"slug\"\n validators={{\n onBlur: createWorkspaceBodySchema.shape.slug,\n onSubmit: createWorkspaceBodySchema.shape.slug,\n }}\n >\n {(field) => (\n <SlugField\n id=\"workspace-settings-slug\"\n label=\"Workspace slug\"\n name=\"slug\"\n value={field.state.value}\n onChange={(value) => field.handleChange(value)}\n onBlur={field.handleBlur}\n error={fieldError(field)}\n description={<span className=\"break-all font-code\">/w/{field.state.value}</span>}\n placeholder=\"acme\"\n className=\"font-code\"\n currentSlug={workspace.slug}\n checkEnabled\n isValid={isSlugValid}\n checkAvailability={checkWorkspaceSlugAvailability}\n />\n )}\n </form.Field>\n\n <Button type=\"submit\" isLoading={updateWorkspace.isPending} className=\"self-start\">\n Save changes\n </Button>\n </form>\n </div>\n\n <SlugChangeWarning\n open={warningOpen}\n onOpenChange={setWarningOpen}\n entityLabel=\"workspace\"\n isLoading={updateWorkspace.isPending}\n onConfirm={() => {\n if (pendingValues) void save(pendingValues);\n }}\n />\n </>\n );\n}\n"],"names":["createWorkspaceBodySchema","checkWorkspaceSlugAvailability","useUpdateWorkspaceMutation","displayNameFieldError","SlugChangeWarning","SlugField","Button","Callout","FormField","FormFieldInput","fieldError","toast","Header","Text","useForm","useNavigate","useState","workspaceGeneralErrorToFormError","WorkspaceSettingsShell","isSlugValid","value","shape","slug","safeParse","success","GeneralSettingsPage","workspace","WorkspaceGeneralForm","id","name","updateWorkspace","navigate","warningOpen","setWarningOpen","pendingValues","setPendingValues","formError","setFormError","form","defaultValues","onSubmit","save","values","undefined","nameChanged","slugChanged","command","workspaceId","updated","mutateAsync","to","params","workspaceSlug","error","mapped","kind","setFieldMeta","field","previous","errorMap","onServer","message","div","className","header","variant","size","role","type","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","validators","onBlur","label","state","onChange","handleChange","target","handleBlur","description","span","placeholder","currentSlug","checkEnabled","isValid","checkAvailability","isLoading","isPending","open","onOpenChange","entityLabel","onConfirm"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { GeneralSettingsPage } from '#pages/general-settings-page.js';
2
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly component: typeof GeneralSettingsPage;
4
+ }>;
5
+ export default _default;
6
+ //# sourceMappingURL=general.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"general.d.ts","sourceRoot":"","sources":["../../src/routes/general.tsx"],"names":[],"mappings":"AACA,OAAO,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;;;;AAEpE,wBAA6D"}
@@ -0,0 +1,7 @@
1
+ import { defineRoute } from '@shipfox/client-shell/runtime';
2
+ import { GeneralSettingsPage } from '#pages/general-settings-page.js';
3
+ export default defineRoute({
4
+ component: GeneralSettingsPage
5
+ });
6
+
7
+ //# sourceMappingURL=general.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/general.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GeneralSettingsPage} from '#pages/general-settings-page.js';\n\nexport default defineRoute({component: GeneralSettingsPage});\n"],"names":["defineRoute","GeneralSettingsPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,mBAAmB,QAAO,kCAAkC;AAEpE,eAAeD,YAAY;IAACE,WAAWD;AAAmB,GAAG"}
@@ -1,7 +1,7 @@
1
1
  declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
2
2
  readonly beforeLoad: ({ params }: {
3
3
  params: {
4
- wid: string;
4
+ workspaceSlug: string;
5
5
  };
6
6
  }) => never;
7
7
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.tsx"],"names":[],"mappings":";sCAIyB;QAAC,MAAM,EAAE;YAAC,GAAG,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC;;AADhD,wBAIG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.tsx"],"names":[],"mappings":";sCAIyB;QAAC,MAAM,EAAE;YAAC,aAAa,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC;;AAD1D,wBAOG"}
@@ -3,9 +3,9 @@ import { redirect } from '@tanstack/react-router';
3
3
  export default defineRoute({
4
4
  beforeLoad: ({ params })=>{
5
5
  throw redirect({
6
- to: '/workspaces/$wid/settings/members',
6
+ to: '/w/$workspaceSlug/settings/members',
7
7
  params: {
8
- wid: params.wid
8
+ workspaceSlug: params.workspaceSlug
9
9
  }
10
10
  });
11
11
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/index.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {redirect} from '@tanstack/react-router';\n\nexport default defineRoute({\n beforeLoad: ({params}: {params: {wid: string}}) => {\n throw redirect({to: '/workspaces/$wid/settings/members', params: {wid: params.wid}});\n },\n});\n"],"names":["defineRoute","redirect","beforeLoad","params","to","wid"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,QAAQ,QAAO,yBAAyB;AAEhD,eAAeD,YAAY;IACzBE,YAAY,CAAC,EAACC,MAAM,EAA0B;QAC5C,MAAMF,SAAS;YAACG,IAAI;YAAqCD,QAAQ;gBAACE,KAAKF,OAAOE,GAAG;YAAA;QAAC;IACpF;AACF,GAAG"}
1
+ {"version":3,"sources":["../../src/routes/index.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {redirect} from '@tanstack/react-router';\n\nexport default defineRoute({\n beforeLoad: ({params}: {params: {workspaceSlug: string}}) => {\n throw redirect({\n to: '/w/$workspaceSlug/settings/members',\n params: {workspaceSlug: params.workspaceSlug},\n });\n },\n});\n"],"names":["defineRoute","redirect","beforeLoad","params","to","workspaceSlug"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,QAAQ,QAAO,yBAAyB;AAEhD,eAAeD,YAAY;IACzBE,YAAY,CAAC,EAACC,MAAM,EAAoC;QACtD,MAAMF,SAAS;YACbG,IAAI;YACJD,QAAQ;gBAACE,eAAeF,OAAOE,aAAa;YAAA;QAC9C;IACF;AACF,GAAG"}