1
1
import type { Meta , StoryObj } from "@storybook/react" ;
2
2
import { expect , spyOn , within } from "@storybook/test" ;
3
- import type { Workspace , WorkspaceApp } from "api/typesGenerated" ;
3
+ import type {
4
+ Workspace ,
5
+ WorkspaceApp ,
6
+ WorkspaceResource ,
7
+ } from "api/typesGenerated" ;
4
8
import {
5
9
MockFailedWorkspace ,
6
10
MockStartingWorkspace ,
@@ -13,11 +17,12 @@ import {
13
17
mockApiError ,
14
18
} from "testHelpers/entities" ;
15
19
import { withProxyProvider } from "testHelpers/storybook" ;
16
- import TaskPage , { data } from "./TaskPage" ;
20
+ import TaskPage , { data , WorkspaceDoesNotHaveAITaskError } from "./TaskPage" ;
17
21
18
22
const meta : Meta < typeof TaskPage > = {
19
23
title : "pages/TaskPage" ,
20
24
component : TaskPage ,
25
+ decorators : [ withProxyProvider ( ) ] ,
21
26
parameters : {
22
27
layout : "fullscreen" ,
23
28
} ,
@@ -96,61 +101,142 @@ export const TerminatedBuildWithStatus: Story = {
96
101
} ,
97
102
} ;
98
103
99
- function activeWorkspace ( apps : WorkspaceApp [ ] ) : Workspace {
104
+ export const SidebarAppDisabled : Story = {
105
+ beforeEach : ( ) => {
106
+ spyOn ( data , "fetchTask" ) . mockResolvedValue ( {
107
+ prompt : "Create competitors page" ,
108
+ workspace : {
109
+ ...MockWorkspace ,
110
+ latest_build : {
111
+ ...MockWorkspace . latest_build ,
112
+ has_ai_task : true ,
113
+ ai_task_sidebar_app_id : "claude-code" ,
114
+ resources : mockResources ( {
115
+ claudeCodeAppOverrides : {
116
+ health : "disabled" ,
117
+ } ,
118
+ } ) ,
119
+ } ,
120
+ } ,
121
+ } ) ;
122
+ } ,
123
+ } ;
124
+
125
+ export const SidebarAppLoading : Story = {
126
+ beforeEach : ( ) => {
127
+ spyOn ( data , "fetchTask" ) . mockResolvedValue ( {
128
+ prompt : "Create competitors page" ,
129
+ workspace : {
130
+ ...MockWorkspace ,
131
+ latest_build : {
132
+ ...MockWorkspace . latest_build ,
133
+ has_ai_task : true ,
134
+ ai_task_sidebar_app_id : "claude-code" ,
135
+ resources : mockResources ( {
136
+ claudeCodeAppOverrides : {
137
+ health : "initializing" ,
138
+ } ,
139
+ } ) ,
140
+ } ,
141
+ } ,
142
+ } ) ;
143
+ } ,
144
+ } ;
145
+
146
+ export const SidebarAppHealthy : Story = {
147
+ beforeEach : ( ) => {
148
+ spyOn ( data , "fetchTask" ) . mockResolvedValue ( {
149
+ prompt : "Create competitors page" ,
150
+ workspace : {
151
+ ...MockWorkspace ,
152
+ latest_build : {
153
+ ...MockWorkspace . latest_build ,
154
+ has_ai_task : true ,
155
+ ai_task_sidebar_app_id : "claude-code" ,
156
+ resources : mockResources ( {
157
+ claudeCodeAppOverrides : {
158
+ health : "healthy" ,
159
+ } ,
160
+ } ) ,
161
+ } ,
162
+ } ,
163
+ } ) ;
164
+ } ,
165
+ } ;
166
+
167
+ export const BuildNoAITask : Story = {
168
+ beforeEach : ( ) => {
169
+ spyOn ( data , "fetchTask" ) . mockImplementation ( ( ) => {
170
+ throw new WorkspaceDoesNotHaveAITaskError ( MockWorkspace ) ;
171
+ } ) ;
172
+ } ,
173
+ } ;
174
+
175
+ interface MockResourcesProps {
176
+ apps ?: WorkspaceApp [ ] ;
177
+ claudeCodeAppOverrides ?: Partial < WorkspaceApp > ;
178
+ }
179
+
180
+ const mockResources = (
181
+ props ?: MockResourcesProps ,
182
+ ) : readonly WorkspaceResource [ ] => [
183
+ {
184
+ ...MockWorkspaceResource ,
185
+ agents : [
186
+ {
187
+ ...MockWorkspaceAgent ,
188
+ apps : [
189
+ ...( props ?. apps ?? [ ] ) ,
190
+ {
191
+ ...MockWorkspaceApp ,
192
+ id : "claude-code" ,
193
+ display_name : "Claude Code" ,
194
+ slug : "claude-code" ,
195
+ icon : "/icon/claude.svg" ,
196
+ statuses : [
197
+ MockWorkspaceAppStatus ,
198
+ {
199
+ ...MockWorkspaceAppStatus ,
200
+ id : "2" ,
201
+ message : "Planning changes" ,
202
+ state : "working" ,
203
+ } ,
204
+ ] ,
205
+ ...( props ?. claudeCodeAppOverrides ?? { } ) ,
206
+ } ,
207
+ {
208
+ ...MockWorkspaceApp ,
209
+ id : "vscode" ,
210
+ slug : "vscode" ,
211
+ display_name : "VS Code Web" ,
212
+ icon : "/icon/code.svg" ,
213
+ } ,
214
+ {
215
+ ...MockWorkspaceApp ,
216
+ slug : "zed" ,
217
+ id : "zed" ,
218
+ display_name : "Zed" ,
219
+ icon : "/icon/zed.svg" ,
220
+ } ,
221
+ ] ,
222
+ } ,
223
+ ] ,
224
+ } ,
225
+ ] ;
226
+
227
+ const activeWorkspace = ( apps : WorkspaceApp [ ] ) : Workspace => {
100
228
return {
101
229
...MockWorkspace ,
102
230
latest_build : {
103
231
...MockWorkspace . latest_build ,
104
- resources : [
105
- {
106
- ...MockWorkspaceResource ,
107
- agents : [
108
- {
109
- ...MockWorkspaceAgent ,
110
- apps : [
111
- ...apps ,
112
- {
113
- ...MockWorkspaceApp ,
114
- id : "claude-code" ,
115
- display_name : "Claude Code" ,
116
- slug : "claude-code" ,
117
- icon : "/icon/claude.svg" ,
118
- statuses : [
119
- MockWorkspaceAppStatus ,
120
- {
121
- ...MockWorkspaceAppStatus ,
122
- id : "2" ,
123
- message : "Planning changes" ,
124
- state : "working" ,
125
- } ,
126
- ] ,
127
- } ,
128
- {
129
- ...MockWorkspaceApp ,
130
- id : "vscode" ,
131
- slug : "vscode" ,
132
- display_name : "VS Code Web" ,
133
- icon : "/icon/code.svg" ,
134
- } ,
135
- {
136
- ...MockWorkspaceApp ,
137
- slug : "zed" ,
138
- id : "zed" ,
139
- display_name : "Zed" ,
140
- icon : "/icon/zed.svg" ,
141
- } ,
142
- ] ,
143
- } ,
144
- ] ,
145
- } ,
146
- ] ,
232
+ resources : mockResources ( { apps } ) ,
147
233
} ,
148
234
latest_app_status : {
149
235
...MockWorkspaceAppStatus ,
150
236
app_id : "claude-code" ,
151
237
} ,
152
238
} ;
153
- }
239
+ } ;
154
240
155
241
export const Active : Story = {
156
242
decorators : [ withProxyProvider ( ) ] ,
0 commit comments