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

Commit0b15b1b

Browse files
authored
feat: add impending deletion indicators to the workspace page (#7588)
* created WorkspaceDeletion directory* remove commented code* attempting to fix workspace stories* fix lint* fix the rest of the stories* fix right stories* PR comments* fix lint
1 parent8e31ed4 commit0b15b1b

20 files changed

+422
-142
lines changed

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

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { action } from "@storybook/addon-actions"
22
import{Story}from"@storybook/react"
33
import{WatchAgentMetadataContext}from"components/Resources/AgentMetadata"
44
import{ProvisionerJobLog}from"api/typesGenerated"
5-
import*asMocksfrom"../../testHelpers/entities"
5+
import*asMocksfrom"testHelpers/entities"
66
import{Workspace,WorkspaceErrors,WorkspaceProps}from"./Workspace"
77
import{withReactContext}from"storybook-react-context"
88
importEventSourcefrom"eventsourcemock"
99
import{ProxyContext,getPreferredProxy}from"contexts/ProxyContext"
10-
import{MockProxyLatencies}from"../../testHelpers/entities"
10+
import{DashboardProviderContext}from"components/Dashboard/DashboardProvider"
1111

1212
exportdefault{
1313
title:"components/Workspace",
@@ -24,21 +24,37 @@ export default {
2424
],
2525
}
2626

27+
constMockedAppearance={
28+
config:Mocks.MockAppearance,
29+
preview:false,
30+
setPreview:()=>null,
31+
save:()=>null,
32+
}
33+
2734
constTemplate:Story<WorkspaceProps>=(args)=>(
28-
<ProxyContext.Provider
35+
<DashboardProviderContext.Provider
2936
value={{
30-
proxyLatencies:MockProxyLatencies,
31-
proxy:getPreferredProxy([],undefined),
32-
proxies:[],
33-
isLoading:false,
34-
isFetched:true,
35-
setProxy:()=>{
36-
return
37-
},
37+
buildInfo:Mocks.MockBuildInfo,
38+
entitlements:Mocks.MockEntitlementsWithScheduling,
39+
experiments:Mocks.MockExperiments,
40+
appearance:MockedAppearance,
3841
}}
3942
>
40-
<Workspace{...args}/>
41-
</ProxyContext.Provider>
43+
<ProxyContext.Provider
44+
value={{
45+
proxyLatencies:Mocks.MockProxyLatencies,
46+
proxy:getPreferredProxy([],undefined),
47+
proxies:[],
48+
isLoading:false,
49+
isFetched:true,
50+
setProxy:()=>{
51+
return
52+
},
53+
}}
54+
>
55+
<Workspace{...args}/>
56+
</ProxyContext.Provider>
57+
</DashboardProviderContext.Provider>
4258
)
4359

4460
exportconstRunning=Template.bind({})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import{Workspace}from"api/typesGenerated"
2+
import{displayImpendingDeletion}from"./utils"
3+
import{useDashboard}from"components/Dashboard/DashboardProvider"
4+
import{Pill}from"components/Pill/Pill"
5+
importErrorIconfrom"@mui/icons-material/ErrorOutline"
6+
7+
exportconstImpendingDeletionBadge=({
8+
workspace,
9+
}:{
10+
workspace:Workspace
11+
}):JSX.Element|null=>{
12+
const{ entitlements, experiments}=useDashboard()
13+
constallowAdvancedScheduling=
14+
entitlements.features["advanced_template_scheduling"].enabled
15+
// This check can be removed when https://github.com/coder/coder/milestone/19
16+
// is merged up
17+
constallowWorkspaceActions=experiments.includes("workspace_actions")
18+
// return null
19+
20+
if(
21+
!displayImpendingDeletion(
22+
workspace,
23+
allowAdvancedScheduling,
24+
allowWorkspaceActions,
25+
)
26+
){
27+
returnnull
28+
}
29+
30+
return<Pillicon={<ErrorIcon/>}text="Impending deletion"type="error"/>
31+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import{Workspace}from"api/typesGenerated"
2+
import{displayImpendingDeletion}from"./utils"
3+
import{useDashboard}from"components/Dashboard/DashboardProvider"
4+
import{Maybe}from"components/Conditionals/Maybe"
5+
import{Alert}from"components/Alert/Alert"
6+
7+
exportconstImpendingDeletionBanner=({
8+
workspace,
9+
onDismiss,
10+
displayImpendingDeletionBanner,
11+
}:{
12+
workspace?:Workspace
13+
onDismiss:()=>void
14+
displayImpendingDeletionBanner:boolean
15+
}):JSX.Element|null=>{
16+
const{ entitlements, experiments}=useDashboard()
17+
constallowAdvancedScheduling=
18+
entitlements.features["advanced_template_scheduling"].enabled
19+
// This check can be removed when https://github.com/coder/coder/milestone/19
20+
// is merged up
21+
constallowWorkspaceActions=experiments.includes("workspace_actions")
22+
23+
return(
24+
<Maybe
25+
condition={Boolean(
26+
workspace&&
27+
displayImpendingDeletion(
28+
workspace,
29+
allowAdvancedScheduling,
30+
allowWorkspaceActions,
31+
)&&
32+
displayImpendingDeletionBanner,
33+
)}
34+
>
35+
<Alertseverity="info"onDismiss={onDismiss}dismissible>
36+
You have workspaces that will be deleted soon.
37+
</Alert>
38+
</Maybe>
39+
)
40+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import{Maybe}from"components/Conditionals/Maybe"
2+
import{StatsItem}from"components/Stats/Stats"
3+
importLinkfrom"@mui/material/Link"
4+
import{LinkasRouterLink}from"react-router-dom"
5+
importstyledfrom"@emotion/styled"
6+
import{Workspace}from"api/typesGenerated"
7+
import{displayImpendingDeletion}from"./utils"
8+
import{useDashboard}from"components/Dashboard/DashboardProvider"
9+
10+
exportconstImpendingDeletionStat=({
11+
workspace,
12+
}:{
13+
workspace:Workspace
14+
}):JSX.Element=>{
15+
const{ entitlements, experiments}=useDashboard()
16+
constallowAdvancedScheduling=
17+
entitlements.features["advanced_template_scheduling"].enabled
18+
// This check can be removed when https://github.com/coder/coder/milestone/19
19+
// is merged up
20+
constallowWorkspaceActions=experiments.includes("workspace_actions")
21+
22+
return(
23+
<Maybe
24+
condition={displayImpendingDeletion(
25+
workspace,
26+
allowAdvancedScheduling,
27+
allowWorkspaceActions,
28+
)}
29+
>
30+
<StyledStatsItem
31+
label="Deletion on"
32+
className="containerClass"
33+
value={
34+
<Link
35+
component={RouterLink}
36+
to={`/templates/${workspace.template_name}/settings/schedule`}
37+
title="Schedule settings"
38+
>
39+
{/* We check for string existence in the conditional */}
40+
{newDate(workspace.deleting_atasstring).toLocaleString()}
41+
</Link>
42+
}
43+
/>
44+
</Maybe>
45+
)
46+
}
47+
48+
constStyledStatsItem=styled(StatsItem)(()=>({
49+
"&.containerClass":{
50+
flexDirection:"column",
51+
gap:0,
52+
padding:0,
53+
54+
"& > span:first-of-type":{
55+
fontSize:12,
56+
fontWeight:500,
57+
},
58+
},
59+
}))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import{Workspace}from"api/typesGenerated"
2+
import{displayImpendingDeletion}from"./utils"
3+
import{useDashboard}from"components/Dashboard/DashboardProvider"
4+
importstyledfrom"@emotion/styled"
5+
import{ThemeasMaterialUITheme}from"@mui/material/styles"
6+
7+
exportconstImpendingDeletionText=({
8+
workspace,
9+
}:{
10+
workspace:Workspace
11+
}):JSX.Element|null=>{
12+
const{ entitlements, experiments}=useDashboard()
13+
constallowAdvancedScheduling=
14+
entitlements.features["advanced_template_scheduling"].enabled
15+
// This check can be removed when https://github.com/coder/coder/milestone/19
16+
// is merged up
17+
constallowWorkspaceActions=experiments.includes("workspace_actions")
18+
19+
if(
20+
!displayImpendingDeletion(
21+
workspace,
22+
allowAdvancedScheduling,
23+
allowWorkspaceActions,
24+
)
25+
){
26+
returnnull
27+
}
28+
return<StyledSpanrole="status">Impending deletion</StyledSpan>
29+
}
30+
31+
constStyledSpan=styled.span<{theme?:MaterialUITheme}>`
32+
color:${(props)=>props.theme.palette.warning.light};
33+
font-weight: 600;
34+
`
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export*from"./ImpendingDeletionStat"
2+
export*from"./ImpendingDeletionBadge"
3+
export*from"./ImpendingDeletionText"
4+
export*from"./ImpendingDeletionBanner"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import*asTypesGenfrom"api/typesGenerated"
2+
import*asMocksfrom"testHelpers/entities"
3+
import{displayImpendingDeletion}from"./utils"
4+
5+
describe("displayImpendingDeletion",()=>{
6+
consttoday=newDate()
7+
it.each<[string,boolean,boolean,boolean]>([
8+
[
9+
newDate(newDate().setDate(today.getDate()+15)).toISOString(),
10+
true,
11+
true,
12+
false,
13+
],// today + 15 days out
14+
[
15+
newDate(newDate().setDate(today.getDate()+14)).toISOString(),
16+
true,
17+
true,
18+
true,
19+
],// today + 14
20+
[
21+
newDate(newDate().setDate(today.getDate()+13)).toISOString(),
22+
true,
23+
true,
24+
true,
25+
],// today + 13
26+
[
27+
newDate(newDate().setDate(today.getDate()+1)).toISOString(),
28+
true,
29+
true,
30+
true,
31+
],// today + 1
32+
[newDate().toISOString(),true,true,true],// today + 0
33+
[newDate().toISOString(),false,true,false],// Advanced Scheduling off
34+
[newDate().toISOString(),true,false,false],// Workspace Actions off
35+
])(
36+
`deleting_at=%p, allowAdvancedScheduling=%p, AllowWorkspaceActions=%p, shouldDisplay=%p`,
37+
(
38+
deleting_at,
39+
allowAdvancedScheduling,
40+
allowWorkspaceActions,
41+
shouldDisplay,
42+
)=>{
43+
constworkspace:TypesGen.Workspace={
44+
...Mocks.MockWorkspace,
45+
deleting_at,
46+
}
47+
expect(
48+
displayImpendingDeletion(
49+
workspace,
50+
allowAdvancedScheduling,
51+
allowWorkspaceActions,
52+
),
53+
).toBe(shouldDisplay)
54+
},
55+
)
56+
})
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import{Workspace}from"api/typesGenerated"
2+
3+
// This const dictates how far out we alert the user that a workspace
4+
// has an impending deletion (due to template.InactivityTTL being set)
5+
constIMPENDING_DELETION_DISPLAY_THRESHOLD=14// 14 days
6+
7+
/**
8+
* Returns a boolean indicating if an impending deletion indicator should be
9+
* displayed in the UI. Impending deletions are configured by setting the
10+
* Template.InactivityTTL
11+
*@param {TypesGen.Workspace} workspace
12+
*@returns {boolean}
13+
*/
14+
exportconstdisplayImpendingDeletion=(
15+
workspace:Workspace,
16+
allowAdvancedScheduling:boolean,
17+
allowWorkspaceActions:boolean,
18+
)=>{
19+
consttoday=newDate()
20+
if(
21+
!workspace.deleting_at||
22+
!allowAdvancedScheduling||
23+
!allowWorkspaceActions
24+
){
25+
returnfalse
26+
}
27+
return(
28+
newDate(workspace.deleting_at)<=
29+
newDate(
30+
today.setDate(today.getDate()+IMPENDING_DELETION_DISPLAY_THRESHOLD),
31+
)
32+
)
33+
}

‎site/src/components/WorkspaceStats/WorkspaceStats.stories.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
11
import{Story}from"@storybook/react"
2-
import{MockWorkspace}from"testHelpers/entities"
2+
import{
3+
MockWorkspace,
4+
MockAppearance,
5+
MockBuildInfo,
6+
MockEntitlementsWithScheduling,
7+
MockExperiments,
8+
}from"testHelpers/entities"
39
import{
410
WorkspaceStats,
511
WorkspaceStatsProps,
612
}from"../WorkspaceStats/WorkspaceStats"
13+
import{DashboardProviderContext}from"components/Dashboard/DashboardProvider"
714

815
exportdefault{
916
title:"components/WorkspaceStats",
1017
component:WorkspaceStats,
1118
}
1219

20+
constMockedAppearance={
21+
config:MockAppearance,
22+
preview:false,
23+
setPreview:()=>null,
24+
save:()=>null,
25+
}
26+
1327
constTemplate:Story<WorkspaceStatsProps>=(args)=>(
14-
<WorkspaceStats{...args}/>
28+
<DashboardProviderContext.Provider
29+
value={{
30+
buildInfo:MockBuildInfo,
31+
entitlements:MockEntitlementsWithScheduling,
32+
experiments:MockExperiments,
33+
appearance:MockedAppearance,
34+
}}
35+
>
36+
<WorkspaceStats{...args}/>
37+
</DashboardProviderContext.Provider>
1538
)
1639

1740
exportconstExample=Template.bind({})

‎site/src/components/WorkspaceStats/WorkspaceStats.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import Popover from "@mui/material/Popover"
2020
importTextFieldfrom"@mui/material/TextField"
2121
importButtonfrom"@mui/material/Button"
2222
import{WorkspaceStatusText}from"components/WorkspaceStatusBadge/WorkspaceStatusBadge"
23+
import{ImpendingDeletionStat}from"components/WorkspaceDeletion"
2324

2425
constLanguage={
2526
workspaceDetails:"Workspace Details",
@@ -74,6 +75,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
7475
label="Status"
7576
value={<WorkspaceStatusTextworkspace={workspace}/>}
7677
/>
78+
<ImpendingDeletionStatworkspace={workspace}/>
7779
<StatsItem
7880
className={styles.statsItem}
7981
label={Language.templateLabel}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp