@shipfox/client-auth 17.0.0 → 21.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +19 -0
- package/dist/pages/workspace-onboarding-page.d.ts.map +1 -1
- package/dist/pages/workspace-onboarding-page.js +82 -75
- package/dist/pages/workspace-onboarding-page.js.map +1 -1
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +3 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/login.d.ts +3 -0
- package/dist/routes/login.js +3 -0
- package/dist/routes/login.js.map +1 -1
- package/dist/routes/logout.d.ts +3 -0
- package/dist/routes/logout.js +3 -0
- package/dist/routes/logout.js.map +1 -1
- package/dist/routes/reset.d.ts +3 -0
- package/dist/routes/reset.js +3 -0
- package/dist/routes/reset.js.map +1 -1
- package/dist/routes/signup.d.ts +3 -0
- package/dist/routes/signup.js +3 -0
- package/dist/routes/signup.js.map +1 -1
- package/dist/routes/workspace-onboarding.d.ts +3 -0
- package/dist/routes/workspace-onboarding.d.ts.map +1 -1
- package/dist/routes/workspace-onboarding.js +3 -0
- package/dist/routes/workspace-onboarding.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/pages/workspace-onboarding-page.test.tsx +16 -6
- package/src/pages/workspace-onboarding-page.tsx +100 -92
- package/src/routes/index.tsx +1 -0
- package/src/routes/login.tsx +1 -0
- package/src/routes/logout.tsx +5 -1
- package/src/routes/reset.tsx +1 -0
- package/src/routes/signup.tsx +1 -0
- package/src/routes/workspace-onboarding.tsx +1 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/client-auth",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "21.0.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"@shipfox/api-auth-dto": "12.0.0",
|
|
40
40
|
"@shipfox/api-workspaces-dto": "12.0.0",
|
|
41
41
|
"@shipfox/client-api": "6.0.1",
|
|
42
|
-
"@shipfox/client-invitations": "
|
|
43
|
-
"@shipfox/client-
|
|
44
|
-
"@shipfox/
|
|
45
|
-
"@shipfox/
|
|
42
|
+
"@shipfox/client-invitations": "21.0.0",
|
|
43
|
+
"@shipfox/client-shell": "21.0.0",
|
|
44
|
+
"@shipfox/client-ui": "21.0.0",
|
|
45
|
+
"@shipfox/react-ui": "2.0.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@tanstack/react-query": "^5.101.0",
|
|
@@ -66,7 +66,7 @@ describe('WorkspaceOnboardingPage', () => {
|
|
|
66
66
|
});
|
|
67
67
|
configureApiClient({fetchImpl});
|
|
68
68
|
|
|
69
|
-
renderAuthPage(
|
|
69
|
+
const {container} = renderAuthPage(
|
|
70
70
|
'/',
|
|
71
71
|
<AuthGuard>
|
|
72
72
|
<WorkspaceGuard>
|
|
@@ -74,7 +74,13 @@ describe('WorkspaceOnboardingPage', () => {
|
|
|
74
74
|
</WorkspaceGuard>
|
|
75
75
|
</AuthGuard>,
|
|
76
76
|
);
|
|
77
|
-
|
|
77
|
+
const workspaceName = await screen.findByLabelText('Workspace name');
|
|
78
|
+
expect(container.querySelector('[data-slot="panel-header"]')).toHaveAttribute(
|
|
79
|
+
'data-variant',
|
|
80
|
+
'plain',
|
|
81
|
+
);
|
|
82
|
+
expect(container.querySelector('[data-slot="panel-body"]')).toBeInTheDocument();
|
|
83
|
+
fireEvent.change(workspaceName, {
|
|
78
84
|
target: {value: ' Acme '},
|
|
79
85
|
});
|
|
80
86
|
fireEvent.click(screen.getByRole('button', {name: 'Create workspace'}));
|
|
@@ -111,13 +117,17 @@ describe('WorkspaceOnboardingPage', () => {
|
|
|
111
117
|
const slug = screen.getByLabelText('Workspace slug');
|
|
112
118
|
expect(screen.getByText(`${window.location.origin}/w/acme`)).toBeInTheDocument();
|
|
113
119
|
fireEvent.change(name, {target: {value: 'Acme Labs'}});
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
await waitFor(() => {
|
|
121
|
+
expect(slug).toHaveValue('acme-labs');
|
|
122
|
+
expect(screen.getByText(`${window.location.origin}/w/acme-labs`)).toBeInTheDocument();
|
|
123
|
+
});
|
|
116
124
|
|
|
117
125
|
fireEvent.change(slug, {target: {value: 'custom-workspace'}});
|
|
118
126
|
fireEvent.change(name, {target: {value: 'Renamed Labs'}});
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(slug).toHaveValue('custom-workspace');
|
|
129
|
+
expect(screen.getByText(`${window.location.origin}/w/custom-workspace`)).toBeInTheDocument();
|
|
130
|
+
});
|
|
121
131
|
});
|
|
122
132
|
|
|
123
133
|
test('checks a manually edited workspace slug for availability', async () => {
|
|
@@ -3,9 +3,9 @@ import {createWorkspaceBodySchema} from '@shipfox/api-workspaces-dto';
|
|
|
3
3
|
import {displayNameFieldError, SlugField} from '@shipfox/client-ui';
|
|
4
4
|
import {Button} from '@shipfox/react-ui/button';
|
|
5
5
|
import {Callout} from '@shipfox/react-ui/callout';
|
|
6
|
-
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@shipfox/react-ui/card';
|
|
7
6
|
import {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';
|
|
8
7
|
import {Icon} from '@shipfox/react-ui/icon';
|
|
8
|
+
import {Panel, PanelBody, PanelHeader, PanelTitle} from '@shipfox/react-ui/panel';
|
|
9
9
|
import {toast} from '@shipfox/react-ui/toast';
|
|
10
10
|
import {Text} from '@shipfox/react-ui/typography';
|
|
11
11
|
import {useForm} from '@tanstack/react-form';
|
|
@@ -78,8 +78,8 @@ export function WorkspaceOnboardingPage() {
|
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
return (
|
|
81
|
-
<main className="min-h-screen
|
|
82
|
-
<div className="mx-auto flex min-h-[calc(100vh-64px)] w-full
|
|
81
|
+
<main className="min-h-screen px-frame py-frame max-[520px]:px-row">
|
|
82
|
+
<div className="mx-auto flex min-h-[calc(100vh-64px)] w-full flex-col gap-section">
|
|
83
83
|
<header className="flex items-center justify-between">
|
|
84
84
|
<div className="flex items-center gap-inline">
|
|
85
85
|
<div className="flex size-36 items-center justify-center rounded-8 border border-border-neutral-base bg-background-neutral-base shadow-button-neutral">
|
|
@@ -102,103 +102,111 @@ export function WorkspaceOnboardingPage() {
|
|
|
102
102
|
void form.handleSubmit();
|
|
103
103
|
}}
|
|
104
104
|
>
|
|
105
|
-
<
|
|
106
|
-
<
|
|
107
|
-
<
|
|
105
|
+
<Panel>
|
|
106
|
+
<PanelHeader variant="plain" className="flex-col items-start gap-inline">
|
|
107
|
+
<PanelTitle id="workspace-onboarding-title" variant="h1">
|
|
108
108
|
Create your workspace
|
|
109
|
-
</
|
|
110
|
-
<
|
|
111
|
-
|
|
109
|
+
</PanelTitle>
|
|
110
|
+
<Text size="sm" className="text-foreground-neutral-muted">
|
|
111
|
+
Give your team a place to collaborate.
|
|
112
|
+
</Text>
|
|
113
|
+
</PanelHeader>
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
<PanelBody className="flex flex-col gap-section p-panel">
|
|
116
|
+
{formError ? (
|
|
117
|
+
<Callout role="alert" type="error">
|
|
118
|
+
{formError}
|
|
119
|
+
</Callout>
|
|
120
|
+
) : null}
|
|
118
121
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
122
|
+
<div className="flex flex-col gap-inline">
|
|
123
|
+
<form.Field
|
|
124
|
+
name="name"
|
|
125
|
+
validators={{
|
|
126
|
+
onBlur: ({value}) =>
|
|
127
|
+
displayNameFieldError(
|
|
128
|
+
value,
|
|
129
|
+
'Workspace name',
|
|
130
|
+
createWorkspaceBodySchema.shape.name,
|
|
131
|
+
),
|
|
132
|
+
onSubmit: ({value}) =>
|
|
133
|
+
displayNameFieldError(
|
|
134
|
+
value,
|
|
135
|
+
'Workspace name',
|
|
136
|
+
createWorkspaceBodySchema.shape.name,
|
|
137
|
+
),
|
|
138
|
+
}}
|
|
139
|
+
>
|
|
140
|
+
{(field) => (
|
|
141
|
+
<FormField
|
|
142
|
+
label="Workspace name"
|
|
143
|
+
id="workspace-name"
|
|
144
|
+
error={fieldError(field)}
|
|
145
|
+
>
|
|
146
|
+
<FormFieldInput
|
|
147
|
+
autoComplete="organization"
|
|
148
|
+
name="name"
|
|
149
|
+
placeholder="Acme"
|
|
150
|
+
type="text"
|
|
151
|
+
value={field.state.value}
|
|
152
|
+
onChange={(event) => {
|
|
153
|
+
const name = event.target.value;
|
|
154
|
+
field.handleChange(name);
|
|
155
|
+
if (!slugTouched) {
|
|
156
|
+
form.setFieldValue(
|
|
157
|
+
'slug',
|
|
158
|
+
name ? slugifyName(name, {fallback: 'workspace'}) : '',
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}}
|
|
162
|
+
onBlur={field.handleBlur}
|
|
163
|
+
/>
|
|
164
|
+
</FormField>
|
|
165
|
+
)}
|
|
166
|
+
</form.Field>
|
|
167
|
+
<form.Field
|
|
168
|
+
name="slug"
|
|
169
|
+
validators={{
|
|
170
|
+
onBlur: createWorkspaceBodySchema.shape.slug,
|
|
171
|
+
onSubmit: createWorkspaceBodySchema.shape.slug,
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
{(field) => (
|
|
175
|
+
<SlugField
|
|
176
|
+
id="workspace-slug"
|
|
177
|
+
label="Workspace slug"
|
|
178
|
+
name="slug"
|
|
144
179
|
value={field.state.value}
|
|
145
|
-
onChange={(
|
|
146
|
-
|
|
147
|
-
field.handleChange(
|
|
148
|
-
if (!slugTouched) {
|
|
149
|
-
form.setFieldValue(
|
|
150
|
-
'slug',
|
|
151
|
-
name ? slugifyName(name, {fallback: 'workspace'}) : '',
|
|
152
|
-
);
|
|
153
|
-
}
|
|
180
|
+
onChange={(value) => {
|
|
181
|
+
setSlugTouched(true);
|
|
182
|
+
field.handleChange(value);
|
|
154
183
|
}}
|
|
155
184
|
onBlur={field.handleBlur}
|
|
185
|
+
error={fieldError(field)}
|
|
186
|
+
description={
|
|
187
|
+
<span className="break-all font-code">
|
|
188
|
+
{`${window.location.origin}/w/${field.state.value || 'acme'}`}
|
|
189
|
+
</span>
|
|
190
|
+
}
|
|
191
|
+
placeholder="acme"
|
|
192
|
+
checkEnabled={slugTouched}
|
|
193
|
+
isValid={isSlugValid}
|
|
194
|
+
checkAvailability={checkWorkspaceSlugAvailability}
|
|
156
195
|
/>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
</
|
|
160
|
-
<form.Field
|
|
161
|
-
name="slug"
|
|
162
|
-
validators={{
|
|
163
|
-
onBlur: createWorkspaceBodySchema.shape.slug,
|
|
164
|
-
onSubmit: createWorkspaceBodySchema.shape.slug,
|
|
165
|
-
}}
|
|
166
|
-
>
|
|
167
|
-
{(field) => (
|
|
168
|
-
<SlugField
|
|
169
|
-
id="workspace-slug"
|
|
170
|
-
label="Workspace slug"
|
|
171
|
-
name="slug"
|
|
172
|
-
value={field.state.value}
|
|
173
|
-
onChange={(value) => {
|
|
174
|
-
setSlugTouched(true);
|
|
175
|
-
field.handleChange(value);
|
|
176
|
-
}}
|
|
177
|
-
onBlur={field.handleBlur}
|
|
178
|
-
error={fieldError(field)}
|
|
179
|
-
description={
|
|
180
|
-
<span className="break-all font-code">
|
|
181
|
-
{`${window.location.origin}/w/${field.state.value || 'acme'}`}
|
|
182
|
-
</span>
|
|
183
|
-
}
|
|
184
|
-
placeholder="acme"
|
|
185
|
-
checkEnabled={slugTouched}
|
|
186
|
-
isValid={isSlugValid}
|
|
187
|
-
checkAvailability={checkWorkspaceSlugAvailability}
|
|
188
|
-
/>
|
|
189
|
-
)}
|
|
190
|
-
</form.Field>
|
|
191
|
-
</CardContent>
|
|
196
|
+
)}
|
|
197
|
+
</form.Field>
|
|
198
|
+
</div>
|
|
192
199
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
<Button
|
|
201
|
+
className="w-full"
|
|
202
|
+
iconRight="chevronRight"
|
|
203
|
+
isLoading={createWorkspace.isPending}
|
|
204
|
+
type="submit"
|
|
205
|
+
>
|
|
206
|
+
{createWorkspace.isPending ? 'Creating workspace...' : 'Create workspace'}
|
|
207
|
+
</Button>
|
|
208
|
+
</PanelBody>
|
|
209
|
+
</Panel>
|
|
202
210
|
</form>
|
|
203
211
|
|
|
204
212
|
<div className="hidden flex-col gap-group lg:flex" aria-hidden="true">
|
package/src/routes/index.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import {FullPageLoader} from '@shipfox/react-ui/loader';
|
|
|
4
4
|
import {redirect} from '@tanstack/react-router';
|
|
5
5
|
|
|
6
6
|
export default defineRoute({
|
|
7
|
+
staticData: {frame: 'focused'},
|
|
7
8
|
beforeLoad: ({context}: {context: RouterContext}) => {
|
|
8
9
|
const auth = context.auth;
|
|
9
10
|
if (!auth || auth.isLoading) return;
|
package/src/routes/login.tsx
CHANGED
package/src/routes/logout.tsx
CHANGED
|
@@ -2,4 +2,8 @@ import {defineRoute} from '@shipfox/client-shell/runtime';
|
|
|
2
2
|
import {LogoutPage} from '#pages/logout-page.js';
|
|
3
3
|
import {validateRedirectSearch} from './inputs.js';
|
|
4
4
|
|
|
5
|
-
export default defineRoute({
|
|
5
|
+
export default defineRoute({
|
|
6
|
+
staticData: {frame: 'focused'},
|
|
7
|
+
validateSearch: validateRedirectSearch,
|
|
8
|
+
component: LogoutPage,
|
|
9
|
+
});
|
package/src/routes/reset.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import {PasswordResetPage} from '#pages/password-reset-page.js';
|
|
|
4
4
|
import {validatePasswordResetSearch} from './inputs.js';
|
|
5
5
|
|
|
6
6
|
export default defineRoute({
|
|
7
|
+
staticData: {frame: 'focused'},
|
|
7
8
|
validateSearch: validatePasswordResetSearch,
|
|
8
9
|
component: () => (
|
|
9
10
|
<GuestGuard>
|
package/src/routes/signup.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import {redirect} from '@tanstack/react-router';
|
|
|
4
4
|
import {WorkspaceOnboardingPage} from '#pages/workspace-onboarding-page.js';
|
|
5
5
|
|
|
6
6
|
export default defineRoute({
|
|
7
|
+
staticData: {frame: 'focused'},
|
|
7
8
|
beforeLoad: ({context, location}: {context: RouterContext; location: {href: string}}) => {
|
|
8
9
|
const auth = context.auth;
|
|
9
10
|
if (!auth || auth.isLoading) return;
|