Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8d7499f

Browse files
authored
feat: ui alert <= 30mins from deadline (#1825)
Summary:When a workspace build is <= 30 minutes from auto-scheduled shutdown,then an alert banner is displayed on the workspace page.
1 parentff542af commit8d7499f

File tree

5 files changed

+204
-1
lines changed

5 files changed

+204
-1
lines changed

‎site/src/components/Workspace/Workspace.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Resources } from "../Resources/Resources"
88
import{Stack}from"../Stack/Stack"
99
import{WorkspaceActions}from"../WorkspaceActions/WorkspaceActions"
1010
import{WorkspaceSchedule}from"../WorkspaceSchedule/WorkspaceSchedule"
11+
import{WorkspaceScheduleBanner}from"../WorkspaceScheduleBanner/WorkspaceScheduleBanner"
1112
import{WorkspaceSection}from"../WorkspaceSection/WorkspaceSection"
1213
import{WorkspaceStats}from"../WorkspaceStats/WorkspaceStats"
1314

@@ -63,8 +64,12 @@ export const Workspace: React.FC<WorkspaceProps> = ({
6364

6465
<Stackdirection="row"spacing={3}className={styles.layout}>
6566
<Stackspacing={3}className={styles.main}>
67+
<WorkspaceScheduleBannerworkspace={workspace}/>
68+
6669
<WorkspaceStatsworkspace={workspace}/>
70+
6771
<Resourcesresources={resources}getResourcesError={getResourcesError}workspace={workspace}/>
72+
6873
<WorkspaceSectiontitle="Timeline"contentsProps={{className:styles.timelineContents}}>
6974
<BuildsTablebuilds={builds}className={styles.timelineTable}/>
7075
</WorkspaceSection>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import{Story}from"@storybook/react"
2+
importdayjsfrom"dayjs"
3+
importutcfrom"dayjs/plugin/utc"
4+
importReactfrom"react"
5+
import*asMocksfrom"../../testHelpers/entities"
6+
import{WorkspaceScheduleBanner,WorkspaceScheduleBannerProps}from"./WorkspaceScheduleBanner"
7+
8+
dayjs.extend(utc)
9+
10+
exportdefault{
11+
title:"components/WorkspaceScheduleBanner",
12+
component:WorkspaceScheduleBanner,
13+
}
14+
15+
constTemplate:Story<WorkspaceScheduleBannerProps>=(args)=><WorkspaceScheduleBanner{...args}/>
16+
17+
exportconstExample=Template.bind({})
18+
Example.args={
19+
workspace:{
20+
...Mocks.MockWorkspace,
21+
latest_build:{
22+
...Mocks.MockWorkspaceBuild,
23+
deadline:dayjs().utc().format(),
24+
job:{
25+
...Mocks.MockProvisionerJob,
26+
status:"succeeded",
27+
},
28+
transition:"start",
29+
},
30+
ttl:2*60*60*1000*1_000_000,// 2 hours
31+
},
32+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
importdayjsfrom"dayjs"
2+
importutcfrom"dayjs/plugin/utc"
3+
import*asTypesGenfrom"../../api/typesGenerated"
4+
import*asMocksfrom"../../testHelpers/entities"
5+
import{shouldDisplay}from"./WorkspaceScheduleBanner"
6+
7+
dayjs.extend(utc)
8+
9+
describe("WorkspaceScheduleBanner",()=>{
10+
describe("shouldDisplay",()=>{
11+
// Manual TTL case
12+
it("should not display if the build does not have a deadline",()=>{
13+
// Given: a workspace with deadline of '"0001-01-01T00:00:00Z"'
14+
constworkspace:TypesGen.Workspace={
15+
...Mocks.MockWorkspace,
16+
latest_build:{
17+
...Mocks.MockWorkspaceBuild,
18+
deadline:"0001-01-01T00:00:00Z",
19+
transition:"start",
20+
},
21+
}
22+
23+
// Then: shouldDisplay is false
24+
expect(shouldDisplay(workspace)).toBeFalsy()
25+
})
26+
27+
// Transition Checks
28+
it("should not display if the latest build is not transition=start",()=>{
29+
// Given: a workspace with latest build as "stop"
30+
constworkspace:TypesGen.Workspace={
31+
...Mocks.MockWorkspace,
32+
latest_build:{
33+
...Mocks.MockWorkspaceBuild,
34+
transition:"stop",
35+
},
36+
}
37+
38+
// Then: shouldDisplay is false
39+
expect(shouldDisplay(workspace)).toBeFalsy()
40+
})
41+
42+
// Provisioner Job Checks
43+
it("should not display if the latest build is canceling",()=>{
44+
// Given: a workspace with latest build as "canceling"
45+
constworkspace:TypesGen.Workspace={
46+
...Mocks.MockWorkspace,
47+
latest_build:{
48+
...Mocks.MockWorkspaceBuild,
49+
job:Mocks.MockCancelingProvisionerJob,
50+
transition:"start",
51+
},
52+
}
53+
54+
// Then: shouldDisplay is false
55+
expect(shouldDisplay(workspace)).toBeFalsy()
56+
})
57+
it("should not display if the latest build is canceled",()=>{
58+
// Given: a workspace with latest build as "canceled"
59+
constworkspace:TypesGen.Workspace={
60+
...Mocks.MockWorkspace,
61+
latest_build:{
62+
...Mocks.MockWorkspaceBuild,
63+
job:Mocks.MockCanceledProvisionerJob,
64+
transition:"start",
65+
},
66+
}
67+
68+
// Then: shouldDisplay is false
69+
expect(shouldDisplay(workspace)).toBeFalsy()
70+
})
71+
it("should not display if the latest build failed",()=>{
72+
// Given: a workspace with latest build as "failed"
73+
constworkspace:TypesGen.Workspace={
74+
...Mocks.MockWorkspace,
75+
latest_build:{
76+
...Mocks.MockWorkspaceBuild,
77+
job:Mocks.MockFailedProvisionerJob,
78+
transition:"start",
79+
},
80+
}
81+
82+
// Then: shouldDisplay is false
83+
expect(shouldDisplay(workspace)).toBeFalsy()
84+
})
85+
86+
// Deadline Checks
87+
it("should display if deadline is within 30 minutes",()=>{
88+
// Given: a workspace with latest build as start and deadline in ~30 mins
89+
constworkspace:TypesGen.Workspace={
90+
...Mocks.MockWorkspace,
91+
latest_build:{
92+
...Mocks.MockWorkspaceBuild,
93+
deadline:dayjs().add(27,"minutes").utc().format(),
94+
job:Mocks.MockRunningProvisionerJob,
95+
transition:"start",
96+
},
97+
}
98+
99+
// Then: shouldDisplay is true
100+
expect(shouldDisplay(workspace)).toBeTruthy()
101+
})
102+
it("should not display if deadline is 45 minutes",()=>{
103+
// Given: a workspace with latest build as start and deadline in 45 mins
104+
constworkspace:TypesGen.Workspace={
105+
...Mocks.MockWorkspace,
106+
latest_build:{
107+
...Mocks.MockWorkspaceBuild,
108+
deadline:dayjs().add(45,"minutes").utc().format(),
109+
transition:"start",
110+
},
111+
}
112+
113+
// Then: shouldDisplay is false
114+
expect(shouldDisplay(workspace)).toBeFalsy()
115+
})
116+
})
117+
})
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
importAlertfrom"@material-ui/lab/Alert"
2+
importAlertTitlefrom"@material-ui/lab/AlertTitle"
3+
importdayjsfrom"dayjs"
4+
importisSameOrBeforefrom"dayjs/plugin/isSameOrBefore"
5+
importutcfrom"dayjs/plugin/utc"
6+
importReactfrom"react"
7+
import*asTypesGenfrom"../../api/typesGenerated"
8+
9+
dayjs.extend(utc)
10+
dayjs.extend(isSameOrBefore)
11+
12+
exportconstLanguage={
13+
bannerTitle:"Your workspace is scheduled to automatically shut down soon.",
14+
}
15+
16+
exportinterfaceWorkspaceScheduleBannerProps{
17+
workspace:TypesGen.Workspace
18+
}
19+
20+
exportconstshouldDisplay=(workspace:TypesGen.Workspace):boolean=>{
21+
consttransition=workspace.latest_build.transition
22+
conststatus=workspace.latest_build.job.status
23+
24+
if(transition!=="start"){
25+
returnfalse
26+
}elseif(status==="canceled"||status==="canceling"||status==="failed"){
27+
returnfalse
28+
}else{
29+
// a mannual shutdown has a deadline of '"0001-01-01T00:00:00Z"'
30+
// SEE: #1834
31+
constdeadline=dayjs(workspace.latest_build.deadline).utc()
32+
consthasDeadline=deadline.year()>1
33+
constthirtyMinutesFromNow=dayjs().add(30,"minutes").utc()
34+
returnhasDeadline&&deadline.isSameOrBefore(thirtyMinutesFromNow)
35+
}
36+
}
37+
38+
exportconstWorkspaceScheduleBanner:React.FC<WorkspaceScheduleBannerProps>=({ workspace})=>{
39+
if(!shouldDisplay(workspace)){
40+
returnnull
41+
}else{
42+
return(
43+
<Alertseverity="warning">
44+
<AlertTitle>{Language.bannerTitle}</AlertTitle>
45+
</Alert>
46+
)
47+
}
48+
}

‎site/src/xServices/workspace/workspaceXService.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ export const workspaceMachine = createMachine(
370370
constoldBuilds=context.builds
371371

372372
if(!oldBuilds){
373-
thrownewError("Builds not loaded")
373+
// This state is theoretically impossible, but helps TS
374+
thrownewError("workspaceXService: failed to load workspace builds")
374375
}
375376

376377
return[...oldBuilds, ...event.data]

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp