1
- import { Checkbox , InputGroup , Label , Switch } from "@blueprintjs/core" ;
2
- import { TimePicker } from "@blueprintjs/datetime" ;
3
1
import React , { useMemo , useState , useEffect } from "react" ;
2
+ import {
3
+ Checkbox ,
4
+ FormGroup ,
5
+ InputGroup ,
6
+ Label ,
7
+ Switch ,
8
+ Tab ,
9
+ Tabs ,
10
+ Text ,
11
+ } from "@blueprintjs/core" ;
12
+ import { TimePicker } from "@blueprintjs/datetime" ;
4
13
import getDailyConfig from "../utils/getDailyConfig" ;
5
14
import saveDailyConfig from "../utils/saveDailyConfig" ;
6
15
import scheduleNextDailyRun from "../utils/scheduleNextDailyRun" ;
@@ -9,40 +18,48 @@ import localStorageSet from "roamjs-components/util/localStorageSet";
9
18
import nanoid from "nanoid" ;
10
19
11
20
const DailyConfig = ( ) => {
12
- const config = useMemo ( getDailyConfig , [ ] ) ;
13
- const [ disabled , setDisabled ] = useState ( ! config . enabled ) ;
14
- const [ onlyOnThisDevice , setOnlyOnThisDevice ] = useState (
15
- ! ! config . device && config . device === localStorageGet ( "device" )
16
- ) ;
17
- const [ workflowName , setWorkflowName ] = useState ( config [ "workflow name" ] ) ;
18
- const defaultTime = useMemo ( ( ) => {
21
+ const initialConfig = useMemo ( getDailyConfig , [ ] ) ;
22
+ const [ localConfig , setLocalConfig ] = useState ( initialConfig ) ;
23
+ const setConfig = async ( newConfig : { [ key : string ] : any } ) => {
24
+ setLocalConfig ( ( prev ) => ( { ...prev , ...newConfig } ) ) ;
25
+ await saveDailyConfig ( newConfig ) ;
26
+ } ;
27
+ const {
28
+ enabled,
29
+ device,
30
+ time : timeToRun ,
31
+ "workflow name" : workflowName ,
32
+ "last-run" : lastRun ,
33
+ "next-run" : configNextRun ,
34
+ } = localConfig ;
35
+
36
+ const currentDevice = useMemo ( ( ) => localStorageGet ( "device" ) , [ ] ) ;
37
+ const timePicker = useMemo ( ( ) => {
19
38
const date = new Date ( ) ;
20
- if ( config && config [ "time" ] ) {
21
- const [ h , m ] = config [ "time" ] . split ( ":" ) . map ( Number ) ;
39
+ if ( localConfig && timeToRun ) {
40
+ const [ h , m ] = timeToRun . split ( ":" ) . map ( Number ) ;
22
41
date . setHours ( h ) ;
23
42
date . setMinutes ( m ) ;
24
43
} else {
25
44
date . setHours ( 0 ) ;
26
45
date . setMinutes ( 0 ) ;
27
46
}
28
47
return date ;
29
- } , [ config ] ) ;
30
- const lastRun = config ?. [ "last-run" ] ;
48
+ } , [ localConfig ] ) ;
31
49
const [ now , setNow ] = useState ( new Date ( ) ) ;
32
50
const nextRun = useMemo ( ( ) => {
33
- if ( ! config . enabled ) return 0 ;
34
- return config [ "next-run" ] - now . valueOf ( ) ;
35
- } , [ now , config ] ) ;
51
+ if ( ! localConfig . enabled ) return 0 ;
52
+ return configNextRun - now . valueOf ( ) ;
53
+ } , [ now , localConfig ] ) ;
36
54
37
55
// migrate old config
38
56
useEffect ( ( ) => {
39
- if ( config [ "workflow name" ] && ! config [ "enabled" ] ) {
40
- saveDailyConfig ( {
41
- enabled : true ,
42
- } ) ;
43
- setDisabled ( false ) ;
57
+ if ( workflowName && ! enabled ) {
58
+ setConfig ( { enabled : true } ) ;
44
59
}
45
- } , [ config ] ) ;
60
+ } , [ initialConfig ] ) ;
61
+
62
+ // Set up an interval to periodically update the current time
46
63
useEffect ( ( ) => {
47
64
const int = window . setInterval ( ( ) => {
48
65
setNow ( new Date ( ) ) ;
@@ -51,91 +68,158 @@ const DailyConfig = () => {
51
68
window . clearInterval ( int ) ;
52
69
} ;
53
70
} , [ setNow ] ) ;
71
+
54
72
return (
55
- < div
56
- className = "flex items-start gap-2 flex-col"
57
- style = { {
58
- width : "100%" ,
59
- minWidth : 256 ,
60
- } }
61
- >
62
- < Switch
63
- defaultChecked = { config . enabled }
64
- onChange = { ( e ) => {
65
- const enabled = ( e . target as HTMLInputElement ) . checked ;
66
- if ( enabled ) {
67
- saveDailyConfig ( {
68
- "workflow name" : workflowName || "Daily" ,
69
- } ) ;
70
- scheduleNextDailyRun ( { tomorrow : true } ) ;
71
- } else {
72
- window . clearTimeout ( getDailyConfig ( ) [ "next-run-timeout" ] ) ;
73
- saveDailyConfig ( { "workflow name" : "" } ) ;
74
- setWorkflowName ( "" ) ;
75
- }
76
- setDisabled ( ! enabled ) ;
77
- } }
78
- label = { disabled ? "Disabled" : "Enabled" }
79
- />
80
- < Label >
81
- Workflow Name
82
- < InputGroup
83
- value = { workflowName }
84
- onChange = { ( e ) => {
85
- saveDailyConfig ( {
86
- "workflow name" : e . target . value ,
87
- } ) ;
88
- setWorkflowName ( e . target . value ) ;
73
+ < div >
74
+ < Tabs className = "roamjs-daily-config-tabs" defaultSelectedTabId = "dct" >
75
+ { enabled && (
76
+ < Tab
77
+ className = "text-white"
78
+ id = "dct"
79
+ title = "Daily Config"
80
+ panel = {
81
+ < div className = "flex items-start gap-2 flex-col" >
82
+ < FormGroup
83
+ label = "Workflow Name"
84
+ labelFor = "roamjs-workflow-name"
85
+ className = "my-4"
86
+ >
87
+ < InputGroup
88
+ id = "roamjs-workflow-name"
89
+ value = { workflowName }
90
+ onChange = { ( e ) => {
91
+ setConfig ( { "workflow name" : e . target . value } ) ;
92
+ } }
93
+ style = { { minWidth : "initial" } }
94
+ placeholder = { "Enter workflow name" }
95
+ />
96
+ </ FormGroup >
97
+
98
+ < FormGroup
99
+ label = "Time To Run"
100
+ labelFor = "roamjs-time-picker"
101
+ className = "mb-4 flex"
102
+ style = { { alignItems : "center" } }
103
+ inline = { true }
104
+ >
105
+ < div className = "flex items-center" >
106
+ < TimePicker
107
+ value = { timePicker }
108
+ onChange = { async ( e ) => {
109
+ const newTime = `${ e . getHours ( ) } :${ e . getMinutes ( ) } ` ;
110
+ await setConfig ( { time : newTime } ) ;
111
+ await scheduleNextDailyRun ( { tomorrow : true } ) ;
112
+ setLocalConfig ( getDailyConfig ( ) ) ;
113
+ } }
114
+ showArrowButtons
115
+ className = { "user-select-none flex-1 text-center" }
116
+ />
117
+ </ div >
118
+ </ FormGroup >
119
+
120
+ < FormGroup
121
+ label = "Only Run On This Device"
122
+ labelFor = "roam-js-only-on-this-device"
123
+ inline = { true }
124
+ >
125
+ < Checkbox
126
+ id = "roam-js-only-on-this-device"
127
+ defaultChecked = { ! ! device && device === currentDevice }
128
+ onChange = { ( e ) => {
129
+ const enabled = ( e . target as HTMLInputElement ) . checked ;
130
+ if ( enabled ) {
131
+ const deviceId = currentDevice || nanoid ( ) ;
132
+ setConfig ( { device : deviceId } ) ;
133
+ localStorageSet ( "device" , deviceId ) ;
134
+ } else {
135
+ setConfig ( { device : "" } ) ;
136
+ }
137
+ } }
138
+ disabled = { ! enabled }
139
+ />
140
+ </ FormGroup >
141
+ </ div >
142
+ }
143
+ disabled = { ! enabled }
144
+ />
145
+ ) }
146
+ { enabled && (
147
+ < Tab
148
+ className = "text-white"
149
+ id = "rdt"
150
+ title = "Run Details"
151
+ panel = {
152
+ < div className = "flex items-start gap-2 flex-col" >
153
+ < Label >
154
+ Last Run
155
+ < Text style = { { color : "#8A9BA8" } } >
156
+ { lastRun && lastRun !== "01-01-1970"
157
+ ? `Last ran on page ${ lastRun } `
158
+ : "Last run data not available" }
159
+ </ Text >
160
+ </ Label >
161
+ < Label >
162
+ Next Run
163
+ < Text style = { { color : "#8A9BA8" } } >
164
+ { ! ! nextRun
165
+ ? `${ Math . floor (
166
+ nextRun / ( 60 * 60 * 1000 )
167
+ ) } hours, ${ Math . floor (
168
+ ( nextRun % ( 60 * 60 * 1000 ) ) / ( 60 * 1000 )
169
+ ) } minutes, ${ Math . floor (
170
+ ( nextRun % ( 60 * 1000 ) ) / 1000
171
+ ) } seconds`
172
+ : "Next run data not available" }
173
+ </ Text >
174
+ </ Label >
175
+ < Label >
176
+ Current Date and Time
177
+ < Text style = { { color : "#8A9BA8" } } >
178
+ { new Date ( ) . toLocaleString ( ) }
179
+ </ Text >
180
+ </ Label >
181
+ < Label >
182
+ Next Run Scheduled At
183
+ < Text style = { { color : "#8A9BA8" , maxWidth : "200px" } } >
184
+ { new Date ( configNextRun ) . toLocaleString ( ) }
185
+ </ Text >
186
+ </ Label >
187
+ < Label >
188
+ Set "Time To Run"
189
+ < Text style = { { color : "#8A9BA8" , maxWidth : "200px" } } >
190
+ { timeToRun
191
+ . split ( ":" )
192
+ . map ( ( val , i ) => ( i === 0 ? `${ val } HR` : `${ val } M` ) )
193
+ . join ( " " ) }
194
+ </ Text >
195
+ </ Label >
196
+ </ div >
197
+ }
198
+ />
199
+ ) }
200
+ < Tabs . Expander />
201
+ < Switch
202
+ large = { true }
203
+ className = "w-full text-right"
204
+ checked = { enabled }
205
+ onChange = { async ( e ) => {
206
+ const enabled = ( e . target as HTMLInputElement ) . checked ;
207
+ if ( enabled ) {
208
+ await setConfig ( {
209
+ enabled : true ,
210
+ "workflow name" : workflowName || "Daily" ,
211
+ } ) ;
212
+ scheduleNextDailyRun ( { tomorrow : true } ) ;
213
+ } else {
214
+ window . clearTimeout ( getDailyConfig ( ) [ "next-run-timeout" ] ) ;
215
+ setConfig ( {
216
+ "workflow name" : "" ,
217
+ enabled : false ,
218
+ } ) ;
219
+ }
89
220
} }
90
- disabled = { disabled }
91
- placeholder = { "Daily" }
92
- className = { "w-full" }
93
- />
94
- </ Label >
95
- < Label >
96
- Time To Run
97
- < TimePicker
98
- defaultValue = { defaultTime }
99
- onChange = { ( e ) =>
100
- saveDailyConfig ( { time : `${ e . getHours ( ) } :${ e . getMinutes ( ) } ` } )
101
- }
102
- showArrowButtons
103
- disabled = { disabled }
104
- className = { "w-full user-select-none" }
105
221
/>
106
- </ Label >
107
- < span >
108
- { lastRun &&
109
- lastRun !== "01-01-1970" &&
110
- `Last ran daily workflow on page ${ lastRun } .` }
111
- </ span >
112
- < span >
113
- { ! ! nextRun &&
114
- ! disabled &&
115
- `Next run is in ${ Math . floor (
116
- nextRun / ( 60 * 60 * 1000 )
117
- ) } hours, ${ Math . floor (
118
- ( nextRun % ( 60 * 60 * 1000 ) ) / ( 60 * 1000 )
119
- ) } minutes, ${ Math . floor ( ( nextRun % ( 60 * 1000 ) ) / 1000 ) } seconds.`}
120
- </ span >
121
- < Checkbox
122
- defaultChecked = { onlyOnThisDevice }
123
- onChange = { ( e ) => {
124
- const enabled = ( e . target as HTMLInputElement ) . checked ;
125
- if ( enabled ) {
126
- const deviceId = localStorageGet ( "device" ) || nanoid ( ) ;
127
- saveDailyConfig ( {
128
- device : deviceId ,
129
- } ) ;
130
- localStorageSet ( "device" , deviceId ) ;
131
- } else {
132
- saveDailyConfig ( { device : "" } ) ;
133
- }
134
- setOnlyOnThisDevice ( enabled ) ;
135
- } }
136
- label = { "Only run on this device" }
137
- disabled = { disabled }
138
- />
222
+ </ Tabs >
139
223
</ div >
140
224
) ;
141
225
} ;
0 commit comments