@shipfox/client-workspace-settings 21.0.0 → 22.0.1
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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +24 -0
- package/dist/components/members/workspace-members-section.d.ts.map +1 -1
- package/dist/components/members/workspace-members-section.js +39 -41
- package/dist/components/members/workspace-members-section.js.map +1 -1
- package/dist/components/workspace-settings-shell.d.ts.map +1 -1
- package/dist/components/workspace-settings-shell.js +9 -2
- package/dist/components/workspace-settings-shell.js.map +1 -1
- package/dist/pages/general-settings-page.d.ts.map +1 -1
- package/dist/pages/general-settings-page.js +79 -81
- package/dist/pages/general-settings-page.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/components/members/workspace-members-section.tsx +23 -22
- package/src/components/workspace-settings-shell.tsx +10 -2
- package/src/pages/general-settings-page.tsx +84 -82
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/client-workspace-settings",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "22.0.1",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"@swc/helpers": "^0.5.17",
|
|
29
29
|
"@tanstack/react-form": "^1.32.0",
|
|
30
30
|
"@shipfox/api-workspaces-dto": "12.0.0",
|
|
31
|
+
"@shipfox/client-auth": "22.0.1",
|
|
31
32
|
"@shipfox/client-api": "6.0.1",
|
|
32
|
-
"@shipfox/client-
|
|
33
|
-
"@shipfox/
|
|
34
|
-
"@shipfox/
|
|
35
|
-
"@shipfox/client-ui": "21.0.0"
|
|
33
|
+
"@shipfox/client-shell": "22.0.1",
|
|
34
|
+
"@shipfox/react-ui": "2.1.0",
|
|
35
|
+
"@shipfox/client-ui": "22.0.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@tanstack/react-query": "^5.101.0",
|
|
@@ -34,7 +34,6 @@ import {useState} from 'react';
|
|
|
34
34
|
import {
|
|
35
35
|
getInvitationExpiry,
|
|
36
36
|
getMemberRemovalRestriction,
|
|
37
|
-
memberCount,
|
|
38
37
|
type PendingInvitation,
|
|
39
38
|
type WorkspaceMember,
|
|
40
39
|
} from '#core/membership.js';
|
|
@@ -74,18 +73,15 @@ function MembersSection({
|
|
|
74
73
|
return (
|
|
75
74
|
<section className="flex flex-col gap-group">
|
|
76
75
|
<div className="flex flex-col gap-tight">
|
|
77
|
-
<Header variant="
|
|
78
|
-
<Text size="sm" className="text-foreground-neutral-muted">
|
|
79
|
-
{query.isPending
|
|
80
|
-
? 'Loading members…'
|
|
81
|
-
: `${memberCount(members)} ${memberCount(members) === 1 ? 'member' : 'members'}`}
|
|
82
|
-
</Text>
|
|
76
|
+
<Header variant="h1">Members</Header>
|
|
83
77
|
</div>
|
|
84
78
|
|
|
85
|
-
{query.isPending ? <TableSkeleton rows={3} cols={3} /> : null}
|
|
79
|
+
{query.isPending ? <TableSkeleton rows={3} cols={3} label="Loading members" /> : null}
|
|
86
80
|
|
|
87
81
|
{query.isError && query.data === undefined ? (
|
|
88
|
-
<
|
|
82
|
+
<Panel>
|
|
83
|
+
<QueryLoadError query={query} subject="members" variant="panel" />
|
|
84
|
+
</Panel>
|
|
89
85
|
) : null}
|
|
90
86
|
|
|
91
87
|
{members.length > 0 ? (
|
|
@@ -213,11 +209,6 @@ function PendingInvitationsSection({
|
|
|
213
209
|
<div className="flex items-center justify-between gap-group">
|
|
214
210
|
<div className="flex flex-col gap-tight">
|
|
215
211
|
<Header variant="h3">Pending invitations</Header>
|
|
216
|
-
<Text size="sm" className="text-foreground-neutral-muted">
|
|
217
|
-
{query.isPending
|
|
218
|
-
? 'Loading invitations…'
|
|
219
|
-
: `${invitations.length} ${invitations.length === 1 ? 'invitation' : 'invitations'}`}
|
|
220
|
-
</Text>
|
|
221
212
|
</div>
|
|
222
213
|
<InviteMemberModal
|
|
223
214
|
open={inviteOpen}
|
|
@@ -227,13 +218,19 @@ function PendingInvitationsSection({
|
|
|
227
218
|
/>
|
|
228
219
|
</div>
|
|
229
220
|
|
|
230
|
-
{query.isPending ? <TableSkeleton rows={2} cols={3} /> : null}
|
|
221
|
+
{query.isPending ? <TableSkeleton rows={2} cols={3} label="Loading invitations" /> : null}
|
|
231
222
|
|
|
232
223
|
{query.isError && query.data === undefined ? (
|
|
233
|
-
<
|
|
224
|
+
<Panel>
|
|
225
|
+
<QueryLoadError query={query} subject="invitations" variant="panel" />
|
|
226
|
+
</Panel>
|
|
234
227
|
) : null}
|
|
235
228
|
|
|
236
|
-
{query.data !== undefined && invitations.length === 0 ?
|
|
229
|
+
{query.data !== undefined && invitations.length === 0 ? (
|
|
230
|
+
<Panel>
|
|
231
|
+
<EmptyInvitations />
|
|
232
|
+
</Panel>
|
|
233
|
+
) : null}
|
|
237
234
|
|
|
238
235
|
{invitations.length > 0 ? (
|
|
239
236
|
<Panel>
|
|
@@ -458,22 +455,26 @@ function EmptyInvitations() {
|
|
|
458
455
|
icon="mailLine"
|
|
459
456
|
title="No pending invitations."
|
|
460
457
|
description="Invite someone above to grow your workspace."
|
|
458
|
+
variant="panel"
|
|
461
459
|
/>
|
|
462
460
|
);
|
|
463
461
|
}
|
|
464
462
|
|
|
465
|
-
function TableSkeleton({rows, cols}: {rows: number; cols: number}) {
|
|
463
|
+
function TableSkeleton({rows, cols, label}: {rows: number; cols: number; label: string}) {
|
|
466
464
|
return (
|
|
467
|
-
<
|
|
465
|
+
<Panel role="status" aria-label={label} className="divide-y">
|
|
468
466
|
{Array.from({length: rows}).map((_, rowIdx) => (
|
|
469
|
-
|
|
470
|
-
|
|
467
|
+
<div
|
|
468
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable placeholder rows
|
|
469
|
+
key={rowIdx}
|
|
470
|
+
className="grid min-h-44 grid-cols-3 gap-group px-row py-row"
|
|
471
|
+
>
|
|
471
472
|
{Array.from({length: cols}).map((__, colIdx) => (
|
|
472
473
|
// biome-ignore lint/suspicious/noArrayIndexKey: stable placeholder cells
|
|
473
474
|
<Skeleton key={colIdx} className="h-20" />
|
|
474
475
|
))}
|
|
475
476
|
</div>
|
|
476
477
|
))}
|
|
477
|
-
</
|
|
478
|
+
</Panel>
|
|
478
479
|
);
|
|
479
480
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useAuthState,
|
|
3
|
+
useMaybeActiveWorkspace,
|
|
4
|
+
WorkspaceUnavailablePage,
|
|
5
|
+
} from '@shipfox/client-shell/runtime';
|
|
2
6
|
import {FullPageLoader} from '@shipfox/react-ui/loader';
|
|
7
|
+
import {Navigate} from '@tanstack/react-router';
|
|
3
8
|
import type {ReactNode} from 'react';
|
|
4
9
|
|
|
5
10
|
interface WorkspaceSettingsShellProps {
|
|
@@ -7,8 +12,11 @@ interface WorkspaceSettingsShellProps {
|
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
export function WorkspaceSettingsShell({children}: WorkspaceSettingsShellProps) {
|
|
15
|
+
const auth = useAuthState();
|
|
10
16
|
const workspace = useMaybeActiveWorkspace();
|
|
11
|
-
if (
|
|
17
|
+
if (auth.isLoading) return <FullPageLoader />;
|
|
18
|
+
if (!auth.isAuthenticated) return <Navigate to={'/auth/login' as never} replace />;
|
|
19
|
+
if (!workspace) return <WorkspaceUnavailablePage />;
|
|
12
20
|
|
|
13
21
|
return children(workspace);
|
|
14
22
|
}
|
|
@@ -8,8 +8,9 @@ import {displayNameFieldError, SlugChangeWarning, SlugField} from '@shipfox/clie
|
|
|
8
8
|
import {Button} from '@shipfox/react-ui/button';
|
|
9
9
|
import {Callout} from '@shipfox/react-ui/callout';
|
|
10
10
|
import {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';
|
|
11
|
+
import {Panel, PanelBody} from '@shipfox/react-ui/panel';
|
|
11
12
|
import {toast} from '@shipfox/react-ui/toast';
|
|
12
|
-
import {Header
|
|
13
|
+
import {Header} from '@shipfox/react-ui/typography';
|
|
13
14
|
import {useForm} from '@tanstack/react-form';
|
|
14
15
|
import {useNavigate} from '@tanstack/react-router';
|
|
15
16
|
import {useState} from 'react';
|
|
@@ -95,93 +96,94 @@ function WorkspaceGeneralForm({workspace}: {workspace: ReturnType<typeof useActi
|
|
|
95
96
|
return (
|
|
96
97
|
<>
|
|
97
98
|
<div className="flex min-w-0 flex-col gap-section">
|
|
98
|
-
<
|
|
99
|
-
<Header variant="h1">General</Header>
|
|
100
|
-
<Text size="sm" className="text-foreground-neutral-muted">
|
|
101
|
-
Update the workspace name and the slug used in its URLs.
|
|
102
|
-
</Text>
|
|
103
|
-
</header>
|
|
99
|
+
<Header variant="h1">General</Header>
|
|
104
100
|
|
|
105
|
-
|
|
106
|
-
<
|
|
107
|
-
{formError
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
<Panel>
|
|
102
|
+
<PanelBody className="gap-group p-panel">
|
|
103
|
+
{formError ? (
|
|
104
|
+
<Callout role="alert" type="error">
|
|
105
|
+
{formError}
|
|
106
|
+
</Callout>
|
|
107
|
+
) : null}
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
>
|
|
137
|
-
{(field) => (
|
|
138
|
-
<FormField
|
|
139
|
-
label="Workspace name"
|
|
140
|
-
id="workspace-settings-name"
|
|
141
|
-
error={fieldError(field)}
|
|
109
|
+
<form
|
|
110
|
+
className="flex w-full max-w-[560px] flex-col gap-group"
|
|
111
|
+
noValidate
|
|
112
|
+
onSubmit={(event) => {
|
|
113
|
+
event.preventDefault();
|
|
114
|
+
event.stopPropagation();
|
|
115
|
+
void form.handleSubmit();
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
<form.Field
|
|
119
|
+
name="name"
|
|
120
|
+
validators={{
|
|
121
|
+
onBlur: ({value}) =>
|
|
122
|
+
displayNameFieldError(
|
|
123
|
+
value,
|
|
124
|
+
'Workspace name',
|
|
125
|
+
createWorkspaceBodySchema.shape.name,
|
|
126
|
+
),
|
|
127
|
+
onSubmit: ({value}) =>
|
|
128
|
+
displayNameFieldError(
|
|
129
|
+
value,
|
|
130
|
+
'Workspace name',
|
|
131
|
+
createWorkspaceBodySchema.shape.name,
|
|
132
|
+
),
|
|
133
|
+
}}
|
|
142
134
|
>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
135
|
+
{(field) => (
|
|
136
|
+
<FormField
|
|
137
|
+
label="Workspace name"
|
|
138
|
+
id="workspace-settings-name"
|
|
139
|
+
error={fieldError(field)}
|
|
140
|
+
>
|
|
141
|
+
<FormFieldInput
|
|
142
|
+
name="name"
|
|
143
|
+
type="text"
|
|
144
|
+
value={field.state.value}
|
|
145
|
+
onChange={(event) => field.handleChange(event.target.value)}
|
|
146
|
+
onBlur={field.handleBlur}
|
|
147
|
+
/>
|
|
148
|
+
</FormField>
|
|
149
|
+
)}
|
|
150
|
+
</form.Field>
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
name="slug"
|
|
156
|
-
validators={{
|
|
157
|
-
onBlur: createWorkspaceBodySchema.shape.slug,
|
|
158
|
-
onSubmit: createWorkspaceBodySchema.shape.slug,
|
|
159
|
-
}}
|
|
160
|
-
>
|
|
161
|
-
{(field) => (
|
|
162
|
-
<SlugField
|
|
163
|
-
id="workspace-settings-slug"
|
|
164
|
-
label="Workspace slug"
|
|
152
|
+
<form.Field
|
|
165
153
|
name="slug"
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
154
|
+
validators={{
|
|
155
|
+
onBlur: createWorkspaceBodySchema.shape.slug,
|
|
156
|
+
onSubmit: createWorkspaceBodySchema.shape.slug,
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
{(field) => (
|
|
160
|
+
<SlugField
|
|
161
|
+
id="workspace-settings-slug"
|
|
162
|
+
label="Workspace slug"
|
|
163
|
+
name="slug"
|
|
164
|
+
value={field.state.value}
|
|
165
|
+
onChange={(value) => field.handleChange(value)}
|
|
166
|
+
onBlur={field.handleBlur}
|
|
167
|
+
error={fieldError(field)}
|
|
168
|
+
description={
|
|
169
|
+
<span className="break-all font-code">/w/{field.state.value}</span>
|
|
170
|
+
}
|
|
171
|
+
placeholder="acme"
|
|
172
|
+
className="font-code"
|
|
173
|
+
currentSlug={workspace.slug}
|
|
174
|
+
checkEnabled
|
|
175
|
+
isValid={isSlugValid}
|
|
176
|
+
checkAvailability={checkWorkspaceSlugAvailability}
|
|
177
|
+
/>
|
|
178
|
+
)}
|
|
179
|
+
</form.Field>
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
181
|
+
<Button type="submit" isLoading={updateWorkspace.isPending} className="self-start">
|
|
182
|
+
Save changes
|
|
183
|
+
</Button>
|
|
184
|
+
</form>
|
|
185
|
+
</PanelBody>
|
|
186
|
+
</Panel>
|
|
185
187
|
</div>
|
|
186
188
|
|
|
187
189
|
<SlugChangeWarning
|