Skip to content

Commit f9420af

Browse files
authored
ui update, add debug panel (#100)
* ui update, add debug panel * add local state, edit setTime, multiple others * PR Feedback * force update on scheduleNextDailyRun via timepicker * PR Review * 1.6.9
1 parent bb1662f commit f9420af

8 files changed

+209
-119
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The following steps dive into all the features SmartBlocks has to offer in incre
2626

2727
## Demo
2828

29-
[![](docs/media/vargas-smartblocks-demo-thumbnail.gif)](https://www.loom.com/share/954d916643754027a3889fd5bf7f24dd)
29+
[![](https://raw.githubusercontent.com/RoamJs/smartblocks/main/docs/media/vargas-smartblocks-demo-thumbnail.gif)](https://www.loom.com/share/954d916643754027a3889fd5bf7f24dd)
3030

3131
<!-- <div style="position: relative; padding-bottom: 66.66666666666666%; height: 0;"><iframe src="https://www.loom.com/embed/954d916643754027a3889fd5bf7f24dd" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div> -->
3232

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "smartblocks",
3-
"version": "1.6.11",
3+
"version": "1.6.12",
44
"description": "Create custom and programmable templates from within Roam!",
55
"main": "./build/main.js",
66
"scripts": {

src/components/DailyConfigComponent.tsx

+188-104
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
import { Checkbox, InputGroup, Label, Switch } from "@blueprintjs/core";
2-
import { TimePicker } from "@blueprintjs/datetime";
31
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";
413
import getDailyConfig from "../utils/getDailyConfig";
514
import saveDailyConfig from "../utils/saveDailyConfig";
615
import scheduleNextDailyRun from "../utils/scheduleNextDailyRun";
@@ -9,40 +18,48 @@ import localStorageSet from "roamjs-components/util/localStorageSet";
918
import nanoid from "nanoid";
1019

1120
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(() => {
1938
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);
2241
date.setHours(h);
2342
date.setMinutes(m);
2443
} else {
2544
date.setHours(0);
2645
date.setMinutes(0);
2746
}
2847
return date;
29-
}, [config]);
30-
const lastRun = config?.["last-run"];
48+
}, [localConfig]);
3149
const [now, setNow] = useState(new Date());
3250
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]);
3654

3755
// migrate old config
3856
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 });
4459
}
45-
}, [config]);
60+
}, [initialConfig]);
61+
62+
// Set up an interval to periodically update the current time
4663
useEffect(() => {
4764
const int = window.setInterval(() => {
4865
setNow(new Date());
@@ -51,91 +68,158 @@ const DailyConfig = () => {
5168
window.clearInterval(int);
5269
};
5370
}, [setNow]);
71+
5472
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+
}
89220
}}
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"}
105221
/>
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>
139223
</div>
140224
);
141225
};

src/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ export default runExtension(async ({ extensionAPI }) => {
104104
105105
.roamjs-smartblock-menu {
106106
width: 300px;
107+
}
108+
.rm-settings-tabs .roamjs-daily-config-tabs .bp3-tab-list {
109+
padding: 2px;
110+
background: none;
111+
}
112+
.rm-settings-tabs .roamjs-daily-config-tabs .bp3-timepicker.bp3-disabled .bp3-timepicker-input{
113+
color: #4b5563;
107114
}`);
108115

109116
const toggleCommandPalette = (flag: boolean) => {

src/utils/getDailyConfig.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { z } from "zod";
22
import getExtensionApi from "roamjs-components/util/extensionApiContext";
3+
import localStorageGet from "roamjs-components/util/localStorageGet";
34

45
const zDailyConfig = z
56
.object({
@@ -9,7 +10,7 @@ const zDailyConfig = z
910
"next-run": z.number().optional().default(0),
1011
"next-run-timeout": z.number().optional().default(0),
1112
enabled: z.boolean().optional().default(false),
12-
device: z.string().optional().default(""),
13+
device: z.string().optional().default(localStorageGet("device")),
1314
})
1415
.or(
1516
z.null().transform(() => ({
@@ -19,7 +20,7 @@ const zDailyConfig = z
1920
"next-run": 0,
2021
"next-run-timeout": 0,
2122
enabled: false,
22-
device: "",
23+
device: localStorageGet("device"),
2324
}))
2425
)
2526
.optional()

0 commit comments

Comments
 (0)