1
1
import Button from "@material-ui/core/Button"
2
2
import IconButton from "@material-ui/core/IconButton"
3
3
import Popover from "@material-ui/core/Popover"
4
- import { makeStyles } from "@material-ui/core/styles"
4
+ import { makeStyles , Theme } from "@material-ui/core/styles"
5
5
import Tooltip from "@material-ui/core/Tooltip"
6
6
import AddIcon from "@material-ui/icons/Add"
7
7
import RemoveIcon from "@material-ui/icons/Remove"
8
8
import ScheduleIcon from "@material-ui/icons/Schedule"
9
+ import { Maybe } from "components/Conditionals/Maybe"
10
+ import { Stack } from "components/Stack/Stack"
9
11
import dayjs from "dayjs"
10
12
import advancedFormat from "dayjs/plugin/advancedFormat"
11
13
import duration from "dayjs/plugin/duration"
@@ -17,6 +19,7 @@ import { useTranslation } from "react-i18next"
17
19
import { Workspace } from "../../api/typesGenerated"
18
20
import { isWorkspaceOn } from "../../util/workspace"
19
21
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule"
22
+ import { EditHours } from "./EditHours"
20
23
import { WorkspaceScheduleLabel } from "./WorkspaceScheduleLabel"
21
24
22
25
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
@@ -27,12 +30,12 @@ dayjs.extend(duration)
27
30
dayjs . extend ( relativeTime )
28
31
dayjs . extend ( timezone )
29
32
30
- export const shouldDisplayPlusMinus = ( workspace : Workspace ) : boolean => {
33
+ export const canEditDeadline = ( workspace : Workspace ) : boolean => {
31
34
return isWorkspaceOn ( workspace ) && Boolean ( workspace . latest_build . deadline )
32
35
}
33
36
34
37
export const shouldDisplayScheduleLabel = ( workspace : Workspace ) : boolean => {
35
- if ( shouldDisplayPlusMinus ( workspace ) ) {
38
+ if ( canEditDeadline ( workspace ) ) {
36
39
return true
37
40
}
38
41
if ( isWorkspaceOn ( workspace ) ) {
@@ -43,13 +46,17 @@ export const shouldDisplayScheduleLabel = (workspace: Workspace): boolean => {
43
46
44
47
export interface WorkspaceScheduleButtonProps {
45
48
workspace : Workspace
46
- onDeadlinePlus : ( ) => void
47
- onDeadlineMinus : ( ) => void
49
+ onDeadlinePlus : ( hours : number ) => void
50
+ onDeadlineMinus : ( hours : number ) => void
48
51
deadlineMinusEnabled : ( ) => boolean
49
52
deadlinePlusEnabled : ( ) => boolean
53
+ maxDeadlineIncrease : number
54
+ maxDeadlineDecrease : number
50
55
canUpdateWorkspace : boolean
51
56
}
52
57
58
+ export type EditMode = "add" | "subtract" | "off"
59
+
53
60
export const WorkspaceScheduleButton : React . FC <
54
61
WorkspaceScheduleButtonProps
55
62
> = ( {
@@ -58,49 +65,93 @@ export const WorkspaceScheduleButton: React.FC<
58
65
onDeadlineMinus,
59
66
deadlinePlusEnabled,
60
67
deadlineMinusEnabled,
68
+ maxDeadlineDecrease,
69
+ maxDeadlineIncrease,
61
70
canUpdateWorkspace,
62
71
} ) => {
63
72
const { t } = useTranslation ( "workspacePage" )
64
73
const anchorRef = useRef < HTMLButtonElement > ( null )
65
74
const [ isOpen , setIsOpen ] = useState ( false )
75
+ const [ editMode , setEditMode ] = useState < EditMode > ( "off" )
66
76
const id = isOpen ? "schedule-popover" : undefined
67
- const styles = useStyles ( )
77
+ const styles = useStyles ( { editMode } )
68
78
69
79
const onClose = ( ) => {
70
80
setIsOpen ( false )
71
81
}
72
82
83
+ const handleSubmitHours = ( hours : number ) => {
84
+ if ( hours !== 0 ) {
85
+ if ( editMode === "add" ) {
86
+ onDeadlinePlus ( hours )
87
+ }
88
+ if ( editMode === "subtract" ) {
89
+ onDeadlineMinus ( hours )
90
+ }
91
+ }
92
+ setEditMode ( "off" )
93
+ }
94
+
73
95
return (
74
96
< span className = { styles . wrapper } >
75
- { shouldDisplayScheduleLabel ( workspace ) && (
76
- < span className = { styles . label } >
77
- < WorkspaceScheduleLabel workspace = { workspace } />
78
- { canUpdateWorkspace && shouldDisplayPlusMinus ( workspace ) && (
79
- < span className = { styles . actions } >
80
- < IconButton
81
- className = { styles . iconButton }
82
- size = "small"
83
- disabled = { ! deadlineMinusEnabled ( ) }
84
- onClick = { onDeadlineMinus }
85
- >
86
- < Tooltip title = { t ( "workspaceScheduleButton.editDeadlineMinus" ) } >
87
- < RemoveIcon />
88
- </ Tooltip >
89
- </ IconButton >
90
- < IconButton
91
- className = { styles . iconButton }
92
- size = "small"
93
- disabled = { ! deadlinePlusEnabled ( ) }
94
- onClick = { onDeadlinePlus }
95
- >
96
- < Tooltip title = { t ( "workspaceScheduleButton.editDeadlinePlus" ) } >
97
- < AddIcon />
98
- </ Tooltip >
99
- </ IconButton >
100
- </ span >
101
- ) }
102
- </ span >
103
- ) }
97
+ < Maybe condition = { shouldDisplayScheduleLabel ( workspace ) } >
98
+ < Stack
99
+ className = { styles . label }
100
+ spacing = { 1 }
101
+ direction = "row"
102
+ alignItems = "center"
103
+ >
104
+ < Stack spacing = { 1 } direction = "row" alignItems = "center" >
105
+ < WorkspaceScheduleLabel workspace = { workspace } />
106
+ < Maybe condition = { canUpdateWorkspace && canEditDeadline ( workspace ) } >
107
+ < span className = { styles . actions } >
108
+ < IconButton
109
+ className = { styles . subtractButton }
110
+ size = "small"
111
+ disabled = { ! deadlineMinusEnabled ( ) }
112
+ onClick = { ( ) => {
113
+ setEditMode ( "subtract" )
114
+ } }
115
+ >
116
+ < Tooltip
117
+ title = { t ( "workspaceScheduleButton.editDeadlineMinus" ) }
118
+ >
119
+ < RemoveIcon />
120
+ </ Tooltip >
121
+ </ IconButton >
122
+ < IconButton
123
+ className = { styles . addButton }
124
+ size = "small"
125
+ disabled = { ! deadlinePlusEnabled ( ) }
126
+ onClick = { ( ) => {
127
+ setEditMode ( "add" )
128
+ } }
129
+ >
130
+ < Tooltip
131
+ title = { t ( "workspaceScheduleButton.editDeadlinePlus" ) }
132
+ >
133
+ < AddIcon />
134
+ </ Tooltip >
135
+ </ IconButton >
136
+ </ span >
137
+ </ Maybe >
138
+ </ Stack >
139
+ < Maybe
140
+ condition = {
141
+ canUpdateWorkspace &&
142
+ canEditDeadline ( workspace ) &&
143
+ editMode !== "off"
144
+ }
145
+ >
146
+ < EditHours
147
+ handleSubmit = { handleSubmitHours }
148
+ max = {
149
+ editMode === "add" ? maxDeadlineIncrease : maxDeadlineDecrease
150
+ }
151
+ />
152
+ </ Maybe >
153
+ </ Stack >
154
+ </ Maybe >
104
155
< >
105
156
< Button
106
157
ref = { anchorRef }
@@ -139,7 +190,11 @@ export const WorkspaceScheduleButton: React.FC<
139
190
)
140
191
}
141
192
142
- const useStyles = makeStyles ( ( theme ) => ( {
193
+ interface StyleProps {
194
+ editMode : EditMode
195
+ }
196
+
197
+ const useStyles = makeStyles < Theme , StyleProps > ( ( theme ) => ( {
143
198
wrapper : {
144
199
display : "inline-flex" ,
145
200
alignItems : "center" ,
@@ -151,15 +206,13 @@ const useStyles = makeStyles((theme) => ({
151
206
} ,
152
207
} ,
153
208
label : {
154
- borderRight : 0 ,
155
- padding : "0 8px 0 16px" ,
209
+ padding : theme . spacing ( 0 , 2 ) ,
156
210
color : theme . palette . text . secondary ,
157
211
158
212
[ theme . breakpoints . down ( "sm" ) ] : {
159
213
width : "100%" ,
160
- display : "flex" ,
161
- alignItems : "center" ,
162
214
padding : theme . spacing ( 1.5 , 2 ) ,
215
+ flexDirection : "column" ,
163
216
} ,
164
217
} ,
165
218
actions : {
@@ -190,8 +243,19 @@ const useStyles = makeStyles((theme) => ({
190
243
} ,
191
244
} ,
192
245
} ,
193
- iconButton : {
246
+ addButton : {
247
+ borderRadius : theme . shape . borderRadius ,
248
+ border : ( { editMode } ) =>
249
+ editMode === "add"
250
+ ? `2px solid ${ theme . palette . primary . main } `
251
+ : "2px solid transparent" ,
252
+ } ,
253
+ subtractButton : {
194
254
borderRadius : theme . shape . borderRadius ,
255
+ border : ( { editMode } ) =>
256
+ editMode === "subtract"
257
+ ? `2px solid ${ theme . palette . primary . main } `
258
+ : "2px solid transparent" ,
195
259
} ,
196
260
popoverPaper : {
197
261
padding : `${ theme . spacing ( 2 ) } px ${ theme . spacing ( 3 ) } px ${ theme . spacing (
0 commit comments