@shipfox/client-onboarding 24.0.0 → 25.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/.turbo/turbo-type.log +0 -1
- package/CHANGELOG.md +18 -0
- package/README.md +26 -7
- package/dist/components/setup-checklist-body.d.ts +3 -0
- package/dist/components/setup-checklist-body.d.ts.map +1 -0
- package/dist/components/setup-checklist-body.js +25 -0
- package/dist/components/setup-checklist-body.js.map +1 -0
- package/dist/components/setup-checklist-completion.d.ts +6 -0
- package/dist/components/setup-checklist-completion.d.ts.map +1 -0
- package/dist/components/setup-checklist-completion.js +156 -0
- package/dist/components/setup-checklist-completion.js.map +1 -0
- package/dist/components/setup-checklist-confetti.d.ts +13 -0
- package/dist/components/setup-checklist-confetti.d.ts.map +1 -0
- package/dist/components/setup-checklist-confetti.js +24 -0
- package/dist/components/setup-checklist-confetti.js.map +1 -0
- package/dist/components/setup-checklist-host-primitives.d.ts +11 -0
- package/dist/components/setup-checklist-host-primitives.d.ts.map +1 -0
- package/dist/components/setup-checklist-host-primitives.js +71 -0
- package/dist/components/setup-checklist-host-primitives.js.map +1 -0
- package/dist/components/setup-checklist-row.d.ts +7 -0
- package/dist/components/setup-checklist-row.d.ts.map +1 -0
- package/dist/components/setup-checklist-row.js +177 -0
- package/dist/components/setup-checklist-row.js.map +1 -0
- package/dist/components/setup-checklist-types.d.ts +19 -0
- package/dist/components/setup-checklist-types.d.ts.map +1 -0
- package/dist/components/setup-checklist-types.js +3 -0
- package/dist/components/setup-checklist-types.js.map +1 -0
- package/dist/components/setup-checklist.d.ts +5 -0
- package/dist/components/setup-checklist.d.ts.map +1 -0
- package/dist/components/setup-checklist.js +5 -0
- package/dist/components/setup-checklist.js.map +1 -0
- package/dist/components/setup-checklist.stories.d.ts +19 -0
- package/dist/components/setup-checklist.stories.d.ts.map +1 -0
- package/dist/components/setup-checklist.stories.js +305 -0
- package/dist/components/setup-checklist.stories.js.map +1 -0
- package/dist/components/workspace-setup-checklist.d.ts +3 -0
- package/dist/components/workspace-setup-checklist.d.ts.map +1 -0
- package/dist/components/workspace-setup-checklist.js +80 -0
- package/dist/components/workspace-setup-checklist.js.map +1 -0
- package/dist/components/workspace-setup-indicator.d.ts +3 -0
- package/dist/components/workspace-setup-indicator.d.ts.map +1 -0
- package/dist/components/workspace-setup-indicator.js +133 -0
- package/dist/components/workspace-setup-indicator.js.map +1 -0
- package/dist/core/setup-checklist.d.ts +2 -0
- package/dist/core/setup-checklist.d.ts.map +1 -1
- package/dist/core/setup-checklist.js +11 -6
- package/dist/core/setup-checklist.js.map +1 -1
- package/dist/feature.d.ts +6 -0
- package/dist/feature.d.ts.map +1 -0
- package/dist/feature.js +19 -0
- package/dist/feature.js.map +1 -0
- package/dist/hooks/api/setup-checklist.d.ts +13 -0
- package/dist/hooks/api/setup-checklist.d.ts.map +1 -0
- package/dist/hooks/api/setup-checklist.js +103 -0
- package/dist/hooks/api/setup-checklist.js.map +1 -0
- package/dist/hooks/use-checklist-analytics.d.ts +6 -0
- package/dist/hooks/use-checklist-analytics.d.ts.map +1 -0
- package/dist/hooks/use-checklist-analytics.js +51 -0
- package/dist/hooks/use-checklist-analytics.js.map +1 -0
- package/dist/hooks/use-checklist-dismissal.d.ts +5 -0
- package/dist/hooks/use-checklist-dismissal.d.ts.map +1 -0
- package/dist/hooks/use-checklist-dismissal.js +31 -0
- package/dist/hooks/use-checklist-dismissal.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +12 -5
- package/src/components/setup-checklist-body.tsx +35 -0
- package/src/components/setup-checklist-completion.test.tsx +124 -0
- package/src/components/setup-checklist-completion.tsx +165 -0
- package/src/components/setup-checklist-confetti.test.ts +19 -0
- package/src/components/setup-checklist-confetti.ts +39 -0
- package/src/components/setup-checklist-host-primitives.tsx +65 -0
- package/src/components/setup-checklist-row.tsx +189 -0
- package/src/components/setup-checklist-types.ts +21 -0
- package/src/components/setup-checklist.stories.tsx +281 -0
- package/src/components/setup-checklist.test.tsx +564 -0
- package/src/components/setup-checklist.tsx +8 -0
- package/src/components/workspace-setup-checklist.tsx +91 -0
- package/src/components/workspace-setup-indicator.tsx +126 -0
- package/src/core/setup-checklist.test.ts +2 -2
- package/src/core/setup-checklist.ts +19 -10
- package/src/feature.ts +16 -0
- package/src/hooks/api/setup-checklist.ts +144 -0
- package/src/hooks/use-checklist-analytics.ts +60 -0
- package/src/hooks/use-checklist-dismissal.ts +30 -0
- package/src/index.ts +8 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import {modelProviderQueryKeys} from '@shipfox/client-agent';
|
|
2
|
+
import {
|
|
3
|
+
type IntegrationConnection,
|
|
4
|
+
type IntegrationProvider,
|
|
5
|
+
integrationConnectionsQueryOptions,
|
|
6
|
+
integrationProvidersQueryOptions,
|
|
7
|
+
} from '@shipfox/client-integrations';
|
|
8
|
+
import {provisionerTokenQueryKeys} from '@shipfox/client-runners';
|
|
9
|
+
import {
|
|
10
|
+
clearWorkspaceSetupChecklistDismissal,
|
|
11
|
+
dismissWorkspaceSetupChecklist,
|
|
12
|
+
} from '@shipfox/client-shell/runtime';
|
|
13
|
+
import {listInvitationsQueryKey, listMembersQueryKey} from '@shipfox/client-workspace-settings';
|
|
14
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
15
|
+
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
|
|
16
|
+
import {
|
|
17
|
+
createMemoryHistory,
|
|
18
|
+
createRootRoute,
|
|
19
|
+
createRoute,
|
|
20
|
+
createRouter,
|
|
21
|
+
Outlet,
|
|
22
|
+
RouterProvider,
|
|
23
|
+
} from '@tanstack/react-router';
|
|
24
|
+
import type {ReactNode} from 'react';
|
|
25
|
+
import {useEffect, useMemo, useState} from 'react';
|
|
26
|
+
import {deriveSetupChecklist} from '#core/setup-checklist.js';
|
|
27
|
+
import {
|
|
28
|
+
SetupChecklistBody,
|
|
29
|
+
type WorkspaceReference,
|
|
30
|
+
WorkspaceSetupChecklist,
|
|
31
|
+
WorkspaceSetupIndicator,
|
|
32
|
+
} from './setup-checklist.js';
|
|
33
|
+
|
|
34
|
+
const WORKSPACE: WorkspaceReference = {id: 'story-workspace', slug: 'acme'};
|
|
35
|
+
const DISMISSED_WORKSPACE: WorkspaceReference = {
|
|
36
|
+
id: 'dismissed-story-workspace',
|
|
37
|
+
slug: WORKSPACE.slug,
|
|
38
|
+
};
|
|
39
|
+
const now = new Date().toISOString();
|
|
40
|
+
|
|
41
|
+
const githubProvider: IntegrationProvider = {
|
|
42
|
+
provider: 'github',
|
|
43
|
+
displayName: 'GitHub',
|
|
44
|
+
capabilities: ['source_control'],
|
|
45
|
+
};
|
|
46
|
+
const linearProvider: IntegrationProvider = {
|
|
47
|
+
provider: 'linear',
|
|
48
|
+
displayName: 'Linear',
|
|
49
|
+
capabilities: ['agent_tools'],
|
|
50
|
+
};
|
|
51
|
+
const githubConnection: IntegrationConnection = {
|
|
52
|
+
id: 'github-connection',
|
|
53
|
+
workspaceId: WORKSPACE.id,
|
|
54
|
+
provider: 'github',
|
|
55
|
+
externalAccountId: 'github-account',
|
|
56
|
+
slug: 'github-account',
|
|
57
|
+
displayName: 'GitHub',
|
|
58
|
+
lifecycleStatus: 'active',
|
|
59
|
+
capabilities: ['source_control'],
|
|
60
|
+
createdAt: now,
|
|
61
|
+
updatedAt: now,
|
|
62
|
+
};
|
|
63
|
+
const disabledLinearConnection: IntegrationConnection = {
|
|
64
|
+
id: 'linear-connection',
|
|
65
|
+
workspaceId: WORKSPACE.id,
|
|
66
|
+
provider: 'linear',
|
|
67
|
+
externalAccountId: 'linear-account',
|
|
68
|
+
slug: 'linear-account',
|
|
69
|
+
displayName: 'Linear',
|
|
70
|
+
lifecycleStatus: 'error',
|
|
71
|
+
capabilities: ['agent_tools'],
|
|
72
|
+
createdAt: now,
|
|
73
|
+
updatedAt: now,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const completeChecklist = deriveSetupChecklist({
|
|
77
|
+
readiness: {
|
|
78
|
+
providers: [
|
|
79
|
+
{
|
|
80
|
+
provider: 'github',
|
|
81
|
+
displayName: 'GitHub',
|
|
82
|
+
capabilities: ['source_control'],
|
|
83
|
+
connected: true,
|
|
84
|
+
attention: false,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
provider: 'linear',
|
|
88
|
+
displayName: 'Linear',
|
|
89
|
+
capabilities: ['agent_tools'],
|
|
90
|
+
connected: true,
|
|
91
|
+
attention: false,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
attentionProviders: [],
|
|
95
|
+
hasSourceControl: true,
|
|
96
|
+
hasToolIntegration: true,
|
|
97
|
+
},
|
|
98
|
+
installationRunners: 'managed',
|
|
99
|
+
workspaceRunnerCapacity: false,
|
|
100
|
+
modelProvider: {installationProvided: true, configured: false},
|
|
101
|
+
membership: {memberCount: 2, pendingInvitationCount: 0},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const meta = {
|
|
105
|
+
title: 'Client onboarding/Setup checklist',
|
|
106
|
+
parameters: {
|
|
107
|
+
layout: 'fullscreen',
|
|
108
|
+
},
|
|
109
|
+
} satisfies Meta;
|
|
110
|
+
|
|
111
|
+
export default meta;
|
|
112
|
+
type Story = StoryObj<typeof meta>;
|
|
113
|
+
|
|
114
|
+
export const CloudPanel: Story = {
|
|
115
|
+
render: () => <HostStory scenario="cloud" host="panel" />,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const CloudIndicator: Story = {
|
|
119
|
+
render: () => <HostStory scenario="cloud" host="indicator" />,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const SelfHostedPanel: Story = {
|
|
123
|
+
render: () => <HostStory scenario="self-hosted" host="panel" />,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const SelfHostedIndicator: Story = {
|
|
127
|
+
render: () => <HostStory scenario="self-hosted" host="indicator" />,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const NeedsAttentionPanel: Story = {
|
|
131
|
+
render: () => <HostStory scenario="attention" host="panel" />,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const NeedsAttentionIndicator: Story = {
|
|
135
|
+
render: () => <HostStory scenario="attention" host="indicator" />,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const Dismissed: Story = {
|
|
139
|
+
render: () => <DismissedStory />,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const CompletedWithBurst: Story = {
|
|
143
|
+
render: () => <CompletedStory showBurst />,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export const CompletedWithoutBurst: Story = {
|
|
147
|
+
render: () => <CompletedStory />,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
function HostStory({scenario, host}: {scenario: Scenario; host: 'panel' | 'indicator'}) {
|
|
151
|
+
return (
|
|
152
|
+
<StoryProviders scenario={scenario}>
|
|
153
|
+
<div className="min-h-[240px] bg-background-subtle-base p-frame">
|
|
154
|
+
<div className="mx-auto flex w-full max-w-[480px] flex-col gap-group">
|
|
155
|
+
{host === 'panel' ? (
|
|
156
|
+
<WorkspaceSetupChecklist workspace={WORKSPACE} />
|
|
157
|
+
) : (
|
|
158
|
+
<div className="flex justify-end border-b border-border-neutral-base bg-background-neutral-base p-row">
|
|
159
|
+
<WorkspaceSetupIndicator workspace={WORKSPACE} />
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</StoryProviders>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function CompletedStory({showBurst = false}: {showBurst?: boolean}) {
|
|
169
|
+
return (
|
|
170
|
+
<StoryProviders scenario="complete">
|
|
171
|
+
<div className="min-h-[240px] bg-background-subtle-base p-frame">
|
|
172
|
+
<div className="mx-auto w-full max-w-[480px]">
|
|
173
|
+
<div className="overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base">
|
|
174
|
+
<SetupChecklistBody
|
|
175
|
+
checklist={completeChecklist}
|
|
176
|
+
workspaceSlug={WORKSPACE.slug}
|
|
177
|
+
completion
|
|
178
|
+
showBurst={showBurst}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</StoryProviders>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function DismissedStory() {
|
|
188
|
+
const [initialized, setInitialized] = useState(false);
|
|
189
|
+
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
dismissWorkspaceSetupChecklist(DISMISSED_WORKSPACE.id);
|
|
192
|
+
setInitialized(true);
|
|
193
|
+
return () => clearWorkspaceSetupChecklistDismissal(DISMISSED_WORKSPACE.id);
|
|
194
|
+
}, []);
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<StoryProviders scenario="cloud">
|
|
198
|
+
<div className="min-h-[240px] bg-background-subtle-base p-frame">
|
|
199
|
+
{initialized ? <WorkspaceSetupChecklist workspace={DISMISSED_WORKSPACE} /> : null}
|
|
200
|
+
</div>
|
|
201
|
+
</StoryProviders>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
type Scenario = 'attention' | 'cloud' | 'complete' | 'self-hosted';
|
|
206
|
+
|
|
207
|
+
function StoryProviders({scenario, children}: {scenario: Scenario; children: ReactNode}) {
|
|
208
|
+
const queryClient = useMemo(() => createScenarioQueryClient(scenario), [scenario]);
|
|
209
|
+
const router = useMemo(() => createStoryRouter(children), [children]);
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<QueryClientProvider client={queryClient}>
|
|
213
|
+
<RouterProvider router={router} />
|
|
214
|
+
</QueryClientProvider>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function createScenarioQueryClient(scenario: Scenario) {
|
|
219
|
+
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}});
|
|
220
|
+
const cloud = scenario === 'cloud' || scenario === 'complete';
|
|
221
|
+
const attention = scenario === 'attention';
|
|
222
|
+
const providers = attention ? [githubProvider, linearProvider] : [githubProvider];
|
|
223
|
+
const connections = attention ? [githubConnection, disabledLinearConnection] : [githubConnection];
|
|
224
|
+
const runnerResponse = {
|
|
225
|
+
provisioners: [],
|
|
226
|
+
installationRunners: cloud ? ('managed' as const) : ('none' as const),
|
|
227
|
+
};
|
|
228
|
+
const catalog = {
|
|
229
|
+
providers: [],
|
|
230
|
+
workspaceProviders: 'enabled' as const,
|
|
231
|
+
managedProviderId: cloud ? 'managed-default' : null,
|
|
232
|
+
instanceDefaultProviderId: null,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
queryClient.setQueryData(integrationProvidersQueryOptions().queryKey, providers);
|
|
236
|
+
queryClient.setQueryData(integrationConnectionsQueryOptions(WORKSPACE.id).queryKey, connections);
|
|
237
|
+
queryClient.setQueryData(provisionerTokenQueryKeys.active(WORKSPACE.id), runnerResponse);
|
|
238
|
+
queryClient.setQueryData(modelProviderQueryKeys.catalog(), catalog);
|
|
239
|
+
queryClient.setQueryData(modelProviderQueryKeys.configs(WORKSPACE.id), {
|
|
240
|
+
configs: [],
|
|
241
|
+
defaultHarnessId: null,
|
|
242
|
+
defaultProviderId: null,
|
|
243
|
+
});
|
|
244
|
+
queryClient.setQueryData(listMembersQueryKey(WORKSPACE.id), [
|
|
245
|
+
{
|
|
246
|
+
id: 'member-1',
|
|
247
|
+
userId: 'user-1',
|
|
248
|
+
workspaceId: WORKSPACE.id,
|
|
249
|
+
email: 'you@example.com',
|
|
250
|
+
name: 'You',
|
|
251
|
+
role: 'admin' as const,
|
|
252
|
+
joinedAt: now,
|
|
253
|
+
updatedAt: now,
|
|
254
|
+
},
|
|
255
|
+
]);
|
|
256
|
+
queryClient.setQueryData(listInvitationsQueryKey(WORKSPACE.id), []);
|
|
257
|
+
|
|
258
|
+
return queryClient;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function createStoryRouter(children: ReactNode) {
|
|
262
|
+
const rootRoute = createRootRoute({component: Outlet});
|
|
263
|
+
const routes = [
|
|
264
|
+
'/w/$workspaceSlug',
|
|
265
|
+
'/w/$workspaceSlug/settings/integrations',
|
|
266
|
+
'/w/$workspaceSlug/settings/runners',
|
|
267
|
+
'/w/$workspaceSlug/settings/agents',
|
|
268
|
+
'/w/$workspaceSlug/settings/members',
|
|
269
|
+
].map((path) =>
|
|
270
|
+
createRoute({
|
|
271
|
+
getParentRoute: () => rootRoute,
|
|
272
|
+
path,
|
|
273
|
+
component: () => children,
|
|
274
|
+
}),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
return createRouter({
|
|
278
|
+
routeTree: rootRoute.addChildren(routes),
|
|
279
|
+
history: createMemoryHistory({initialEntries: ['/w/acme']}),
|
|
280
|
+
});
|
|
281
|
+
}
|