agent-office 0.4.9 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +259 -228
- package/dist/commands/cron-requests.d.ts +7 -0
- package/dist/commands/cron-requests.d.ts.map +1 -0
- package/dist/commands/cron-requests.js +31 -0
- package/dist/commands/cron-requests.js.map +1 -0
- package/dist/commands/crons.d.ts +10 -0
- package/dist/commands/crons.d.ts.map +1 -0
- package/dist/commands/crons.js +45 -0
- package/dist/commands/crons.js.map +1 -0
- package/dist/commands/hello.d.ts +5 -0
- package/dist/commands/hello.d.ts.map +1 -0
- package/dist/commands/hello.js +4 -0
- package/dist/commands/hello.js.map +1 -0
- package/dist/commands/messages.d.ts +5 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +18 -0
- package/dist/commands/messages.js.map +1 -0
- package/dist/commands/sessions.d.ts +13 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +58 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/task-columns.d.ts +2 -0
- package/dist/commands/task-columns.d.ts.map +1 -0
- package/dist/commands/task-columns.js +13 -0
- package/dist/commands/task-columns.js.map +1 -0
- package/dist/commands/tasks.d.ts +11 -0
- package/dist/commands/tasks.d.ts.map +1 -0
- package/dist/commands/tasks.js +75 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +50 -0
- package/dist/config.test.js.map +1 -0
- package/dist/db/index.d.ts +6 -70
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +4 -11
- package/dist/db/index.js.map +1 -0
- package/dist/db/mock-storage.d.ts +79 -0
- package/dist/db/mock-storage.d.ts.map +1 -0
- package/dist/db/mock-storage.js +381 -0
- package/dist/db/mock-storage.js.map +1 -0
- package/dist/db/mock-storage.test.d.ts +2 -0
- package/dist/db/mock-storage.test.d.ts.map +1 -0
- package/dist/db/mock-storage.test.js +234 -0
- package/dist/db/mock-storage.test.js.map +1 -0
- package/dist/db/postgresql-storage.d.ts +10 -8
- package/dist/db/postgresql-storage.d.ts.map +1 -0
- package/dist/db/postgresql-storage.js +76 -42
- package/dist/db/postgresql-storage.js.map +1 -0
- package/dist/db/sqlite-storage.d.ts +9 -8
- package/dist/db/sqlite-storage.d.ts.map +1 -0
- package/dist/db/sqlite-storage.js +75 -41
- package/dist/db/sqlite-storage.js.map +1 -0
- package/dist/db/storage-base.d.ts +7 -8
- package/dist/db/storage-base.d.ts.map +1 -0
- package/dist/db/storage-base.js +3 -2
- package/dist/db/storage-base.js.map +1 -0
- package/dist/db/storage.d.ts +12 -12
- package/dist/db/storage.d.ts.map +1 -0
- package/dist/db/storage.js +1 -0
- package/dist/db/storage.js.map +1 -0
- package/dist/db/types.d.ts +67 -0
- package/dist/db/types.d.ts.map +1 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +397 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +49 -0
- package/dist/index.test.js.map +1 -0
- package/dist/lib/output.d.ts +2 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +8 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/services/cron-service.constraints.test.d.ts +2 -0
- package/dist/services/cron-service.constraints.test.d.ts.map +1 -0
- package/dist/services/cron-service.constraints.test.js +90 -0
- package/dist/services/cron-service.constraints.test.js.map +1 -0
- package/dist/services/cron-service.d.ts +45 -0
- package/dist/services/cron-service.d.ts.map +1 -0
- package/dist/services/cron-service.js +157 -0
- package/dist/services/cron-service.js.map +1 -0
- package/dist/services/cron-service.test.d.ts +2 -0
- package/dist/services/cron-service.test.d.ts.map +1 -0
- package/dist/services/cron-service.test.js +280 -0
- package/dist/services/cron-service.test.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +5 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/message-service.d.ts +16 -0
- package/dist/services/message-service.d.ts.map +1 -0
- package/dist/services/message-service.js +39 -0
- package/dist/services/message-service.js.map +1 -0
- package/dist/services/message-service.test.d.ts +2 -0
- package/dist/services/message-service.test.d.ts.map +1 -0
- package/dist/services/message-service.test.js +145 -0
- package/dist/services/message-service.test.js.map +1 -0
- package/dist/services/session-service.constraints.test.d.ts +2 -0
- package/dist/services/session-service.constraints.test.d.ts.map +1 -0
- package/dist/services/session-service.constraints.test.js +34 -0
- package/dist/services/session-service.constraints.test.js.map +1 -0
- package/dist/services/session-service.d.ts +27 -0
- package/dist/services/session-service.d.ts.map +1 -0
- package/dist/services/session-service.js +55 -0
- package/dist/services/session-service.js.map +1 -0
- package/dist/services/session-service.test.d.ts +2 -0
- package/dist/services/session-service.test.d.ts.map +1 -0
- package/dist/services/session-service.test.js +87 -0
- package/dist/services/session-service.test.js.map +1 -0
- package/dist/services/task-service.d.ts +25 -0
- package/dist/services/task-service.d.ts.map +1 -0
- package/dist/services/task-service.js +87 -0
- package/dist/services/task-service.js.map +1 -0
- package/dist/services/task-service.test.d.ts +2 -0
- package/dist/services/task-service.test.d.ts.map +1 -0
- package/dist/services/task-service.test.js +180 -0
- package/dist/services/task-service.test.js.map +1 -0
- package/package.json +40 -42
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -317
- package/dist/commands/communicator.d.ts +0 -9
- package/dist/commands/communicator.js +0 -2231
- package/dist/commands/manage.d.ts +0 -5
- package/dist/commands/manage.js +0 -20
- package/dist/commands/notifier.d.ts +0 -11
- package/dist/commands/notifier.js +0 -100
- package/dist/commands/screensaver.d.ts +0 -8
- package/dist/commands/screensaver.js +0 -1280
- package/dist/commands/serve.d.ts +0 -13
- package/dist/commands/serve.js +0 -95
- package/dist/commands/task-board.d.ts +0 -29
- package/dist/commands/task-board.js +0 -251
- package/dist/commands/worker.d.ts +0 -16
- package/dist/commands/worker.js +0 -145
- package/dist/db/migrate.d.ts +0 -2
- package/dist/db/migrate.js +0 -3
- package/dist/lib/agentic-coding-server.d.ts +0 -66
- package/dist/lib/agentic-coding-server.js +0 -7
- package/dist/lib/notifier.d.ts +0 -18
- package/dist/lib/notifier.js +0 -15
- package/dist/lib/opencode-coding-server.d.ts +0 -11
- package/dist/lib/opencode-coding-server.js +0 -66
- package/dist/lib/pi-coding-server.d.ts +0 -20
- package/dist/lib/pi-coding-server.js +0 -162
- package/dist/manage/app.d.ts +0 -6
- package/dist/manage/app.js +0 -128
- package/dist/manage/components/AgentCode.d.ts +0 -8
- package/dist/manage/components/AgentCode.js +0 -73
- package/dist/manage/components/CreateSession.d.ts +0 -8
- package/dist/manage/components/CreateSession.js +0 -37
- package/dist/manage/components/CronList.d.ts +0 -9
- package/dist/manage/components/CronList.js +0 -321
- package/dist/manage/components/CronRequests.d.ts +0 -8
- package/dist/manage/components/CronRequests.js +0 -181
- package/dist/manage/components/DeleteSession.d.ts +0 -7
- package/dist/manage/components/DeleteSession.js +0 -55
- package/dist/manage/components/InjectText.d.ts +0 -8
- package/dist/manage/components/InjectText.js +0 -51
- package/dist/manage/components/ItemSelector.d.ts +0 -7
- package/dist/manage/components/ItemSelector.js +0 -20
- package/dist/manage/components/MenuSelect.d.ts +0 -13
- package/dist/manage/components/MenuSelect.js +0 -22
- package/dist/manage/components/MyMail.d.ts +0 -9
- package/dist/manage/components/MyMail.js +0 -143
- package/dist/manage/components/Profile.d.ts +0 -8
- package/dist/manage/components/Profile.js +0 -60
- package/dist/manage/components/ReadMail.d.ts +0 -8
- package/dist/manage/components/ReadMail.js +0 -110
- package/dist/manage/components/SendMessage.d.ts +0 -9
- package/dist/manage/components/SendMessage.js +0 -79
- package/dist/manage/components/SessionList.d.ts +0 -9
- package/dist/manage/components/SessionList.js +0 -608
- package/dist/manage/components/SessionSidebar.d.ts +0 -6
- package/dist/manage/components/SessionSidebar.js +0 -24
- package/dist/manage/components/TailMessages.d.ts +0 -8
- package/dist/manage/components/TailMessages.js +0 -126
- package/dist/manage/hooks/useApi.d.ts +0 -147
- package/dist/manage/hooks/useApi.js +0 -181
- package/dist/server/cron.d.ts +0 -25
- package/dist/server/cron.js +0 -107
- package/dist/server/index.d.ts +0 -4
- package/dist/server/index.js +0 -22
- package/dist/server/routes.d.ts +0 -13
- package/dist/server/routes.js +0 -1396
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState, useCallback } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { TextInput, Spinner, ConfirmInput } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
const NEXT_RUN_PADDING = 22;
|
|
7
|
-
export function CronList({ serverUrl, password, onBack, contentHeight, sessionName: initialSessionName }) {
|
|
8
|
-
const { listCrons, createCron, deleteCron, enableCron, disableCron, getCronHistory, listSessions } = useApi(serverUrl, password);
|
|
9
|
-
const { data: crons, loading, error: loadError, run } = useAsyncState();
|
|
10
|
-
const { data: sessions, run: runSessions } = useAsyncState();
|
|
11
|
-
const [cursor, setCursor] = useState(0);
|
|
12
|
-
const [mode, setMode] = useState("list");
|
|
13
|
-
const [actionMsg, setActionMsg] = useState(null);
|
|
14
|
-
const [actionError, setActionError] = useState(null);
|
|
15
|
-
const [selectedSession, setSelectedSession] = useState(initialSessionName ?? null);
|
|
16
|
-
const [createData, setCreateData] = useState({
|
|
17
|
-
name: "",
|
|
18
|
-
schedule: "",
|
|
19
|
-
message: "",
|
|
20
|
-
});
|
|
21
|
-
const [selectedSessionCursor, setSelectedSessionCursor] = useState(0);
|
|
22
|
-
const [history, setHistory] = useState([]);
|
|
23
|
-
const [historyLoading, setHistoryLoading] = useState(false);
|
|
24
|
-
const filteredCrons = crons?.filter((c) => (selectedSession ? c.session_name === selectedSession : true)) ?? [];
|
|
25
|
-
const reload = () => {
|
|
26
|
-
void run(listCrons);
|
|
27
|
-
void runSessions(() => listSessions());
|
|
28
|
-
};
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
reload();
|
|
31
|
-
}, []);
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (filteredCrons.length > 0) {
|
|
34
|
-
setCursor((c) => Math.min(c, filteredCrons.length - 1));
|
|
35
|
-
}
|
|
36
|
-
}, [filteredCrons.length]);
|
|
37
|
-
useInput((input, key) => {
|
|
38
|
-
if (key.escape && mode === "list") {
|
|
39
|
-
onBack();
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (key.escape && (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "history" || mode === "view-message")) {
|
|
43
|
-
setMode("list");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (key.escape && (mode === "create-name" || mode === "create-schedule" || mode === "create-message" || mode === "create-timezone")) {
|
|
47
|
-
setMode("list");
|
|
48
|
-
setCreateData({ name: "", schedule: "", message: "" });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (loading)
|
|
52
|
-
return;
|
|
53
|
-
if (mode === "list") {
|
|
54
|
-
if (key.upArrow)
|
|
55
|
-
setCursor((c) => Math.max(0, c - 1));
|
|
56
|
-
if (key.downArrow)
|
|
57
|
-
setCursor((c) => Math.min(filteredCrons.length - 1, c + 1));
|
|
58
|
-
if (input === "c") {
|
|
59
|
-
setActionError(null);
|
|
60
|
-
setActionMsg(null);
|
|
61
|
-
setCreateData({ name: "", schedule: "", message: "", timezone: "" });
|
|
62
|
-
setSelectedSessionCursor(0);
|
|
63
|
-
setMode("create-select-session");
|
|
64
|
-
}
|
|
65
|
-
if (input === "f" && filteredCrons.length > 0) {
|
|
66
|
-
setSelectedSession((prev) => (prev ? null : filteredCrons[0]?.session_name ?? null));
|
|
67
|
-
}
|
|
68
|
-
if (filteredCrons.length > 0) {
|
|
69
|
-
const selected = filteredCrons[cursor];
|
|
70
|
-
if (input === "d") {
|
|
71
|
-
setActionError(null);
|
|
72
|
-
setActionMsg(null);
|
|
73
|
-
setMode("confirm-delete");
|
|
74
|
-
}
|
|
75
|
-
if (input === "e") {
|
|
76
|
-
setActionError(null);
|
|
77
|
-
setActionMsg(null);
|
|
78
|
-
setMode(selected?.enabled ? "confirm-disable" : "confirm-enable");
|
|
79
|
-
}
|
|
80
|
-
if (input === "h") {
|
|
81
|
-
setActionError(null);
|
|
82
|
-
loadHistory(selected.id);
|
|
83
|
-
}
|
|
84
|
-
if (input === "v") {
|
|
85
|
-
setMode("view-message");
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable") {
|
|
90
|
-
if (key.return || input === "y") {
|
|
91
|
-
if (mode === "confirm-delete") {
|
|
92
|
-
handleDelete();
|
|
93
|
-
}
|
|
94
|
-
else if (mode === "confirm-enable") {
|
|
95
|
-
handleEnable();
|
|
96
|
-
}
|
|
97
|
-
else if (mode === "confirm-disable") {
|
|
98
|
-
handleDisable();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (input === "n" || key.escape) {
|
|
102
|
-
setMode("list");
|
|
103
|
-
}
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (mode === "create-select-session") {
|
|
107
|
-
if (key.upArrow)
|
|
108
|
-
setSelectedSessionCursor((c) => Math.max(0, c - 1));
|
|
109
|
-
if (key.downArrow)
|
|
110
|
-
setSelectedSessionCursor((c) => Math.min((sessions ?? []).length - 1, c + 1));
|
|
111
|
-
if (key.return) {
|
|
112
|
-
const selected = sessions?.[selectedSessionCursor];
|
|
113
|
-
if (selected) {
|
|
114
|
-
setSelectedSession(selected.name);
|
|
115
|
-
setMode("create-name");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (key.escape) {
|
|
119
|
-
setCreateData({ name: "", schedule: "", message: "" });
|
|
120
|
-
setSelectedSession(null);
|
|
121
|
-
setMode("list");
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
const loadHistory = useCallback(async (cronId) => {
|
|
126
|
-
setHistoryLoading(true);
|
|
127
|
-
try {
|
|
128
|
-
const entries = await getCronHistory(cronId, 10);
|
|
129
|
-
setHistory(entries);
|
|
130
|
-
setMode("history");
|
|
131
|
-
}
|
|
132
|
-
catch (err) {
|
|
133
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
134
|
-
}
|
|
135
|
-
finally {
|
|
136
|
-
setHistoryLoading(false);
|
|
137
|
-
}
|
|
138
|
-
}, [getCronHistory]);
|
|
139
|
-
const handleDelete = async () => {
|
|
140
|
-
const selected = filteredCrons[cursor];
|
|
141
|
-
if (!selected)
|
|
142
|
-
return;
|
|
143
|
-
setMode("deleting");
|
|
144
|
-
try {
|
|
145
|
-
await deleteCron(selected.id);
|
|
146
|
-
setActionMsg(`Cron job "${selected.name}" deleted.`);
|
|
147
|
-
setMode("list");
|
|
148
|
-
reload();
|
|
149
|
-
}
|
|
150
|
-
catch (err) {
|
|
151
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
152
|
-
setMode("list");
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
const handleEnable = async () => {
|
|
156
|
-
const selected = filteredCrons[cursor];
|
|
157
|
-
if (!selected)
|
|
158
|
-
return;
|
|
159
|
-
setMode("toggling");
|
|
160
|
-
try {
|
|
161
|
-
await enableCron(selected.id);
|
|
162
|
-
setActionMsg(`Cron job "${selected.name}" enabled.`);
|
|
163
|
-
setMode("list");
|
|
164
|
-
reload();
|
|
165
|
-
}
|
|
166
|
-
catch (err) {
|
|
167
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
168
|
-
setMode("list");
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
const handleDisable = async () => {
|
|
172
|
-
const selected = filteredCrons[cursor];
|
|
173
|
-
if (!selected)
|
|
174
|
-
return;
|
|
175
|
-
setMode("toggling");
|
|
176
|
-
try {
|
|
177
|
-
await disableCron(selected.id);
|
|
178
|
-
setActionMsg(`Cron job "${selected.name}" disabled.`);
|
|
179
|
-
setMode("list");
|
|
180
|
-
reload();
|
|
181
|
-
}
|
|
182
|
-
catch (err) {
|
|
183
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
184
|
-
setMode("list");
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
const handleCreate = async () => {
|
|
188
|
-
if (!createData.name.trim() || !createData.schedule.trim() || !createData.message.trim())
|
|
189
|
-
return;
|
|
190
|
-
if (!selectedSession)
|
|
191
|
-
return;
|
|
192
|
-
setMode("creating");
|
|
193
|
-
try {
|
|
194
|
-
await createCron({
|
|
195
|
-
name: createData.name.trim(),
|
|
196
|
-
session_name: selectedSession,
|
|
197
|
-
schedule: createData.schedule.trim(),
|
|
198
|
-
message: createData.message.trim(),
|
|
199
|
-
timezone: createData.timezone,
|
|
200
|
-
});
|
|
201
|
-
setActionMsg(`Cron job "${createData.name.trim()}" created.`);
|
|
202
|
-
setMode("list");
|
|
203
|
-
setCreateData({ name: "", schedule: "", message: "", timezone: "" });
|
|
204
|
-
reload();
|
|
205
|
-
}
|
|
206
|
-
catch (err) {
|
|
207
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
208
|
-
setMode("list");
|
|
209
|
-
setCreateData({ name: "", schedule: "", message: "", timezone: "" });
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
const formatNextRun = (nextRun) => {
|
|
213
|
-
if (!nextRun)
|
|
214
|
-
return "—";
|
|
215
|
-
try {
|
|
216
|
-
const date = new Date(nextRun);
|
|
217
|
-
return date.toLocaleString();
|
|
218
|
-
}
|
|
219
|
-
catch {
|
|
220
|
-
return nextRun;
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
const formatLastRun = (lastRun) => {
|
|
224
|
-
if (!lastRun)
|
|
225
|
-
return "never";
|
|
226
|
-
try {
|
|
227
|
-
const date = new Date(lastRun);
|
|
228
|
-
return date.toLocaleString();
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
return lastRun;
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
if (loading && filteredCrons.length === 0) {
|
|
235
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading cron jobs..." }) }));
|
|
236
|
-
}
|
|
237
|
-
if (loadError) {
|
|
238
|
-
return (_jsxs(Box, { height: contentHeight, flexDirection: "column", gap: 1, children: [_jsx(Text, { color: "red", bold: true, children: "Error" }), _jsx(Text, { children: loadError })] }));
|
|
239
|
-
}
|
|
240
|
-
const renderActionPanel = () => {
|
|
241
|
-
if (mode === "deleting") {
|
|
242
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: `Deleting "${filteredCrons[cursor]?.name}"...` }) }));
|
|
243
|
-
}
|
|
244
|
-
if (mode === "toggling") {
|
|
245
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: "Updating cron job..." }) }));
|
|
246
|
-
}
|
|
247
|
-
if (mode === "confirm-delete" && filteredCrons[cursor]) {
|
|
248
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Delete Cron Job" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Delete ", _jsx(Text, { color: "yellow", bold: true, children: filteredCrons[cursor].name }), "? This cannot be undone."] }) }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleDelete(), onCancel: () => setMode("list") }) })] }));
|
|
249
|
-
}
|
|
250
|
-
if (mode === "confirm-enable" && filteredCrons[cursor]) {
|
|
251
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "Enable Cron Job" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Enable ", _jsx(Text, { color: "cyan", bold: true, children: filteredCrons[cursor].name }), "?"] }) }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleEnable(), onCancel: () => setMode("list") }) })] }));
|
|
252
|
-
}
|
|
253
|
-
if (mode === "confirm-disable" && filteredCrons[cursor]) {
|
|
254
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Disable Cron Job" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Disable ", _jsx(Text, { color: "cyan", bold: true, children: filteredCrons[cursor].name }), "?"] }) }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleDisable(), onCancel: () => setMode("list") }) })] }));
|
|
255
|
-
}
|
|
256
|
-
return null;
|
|
257
|
-
};
|
|
258
|
-
const renderCreateSelectSession = () => {
|
|
259
|
-
if (mode !== "create-select-session")
|
|
260
|
-
return null;
|
|
261
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { gap: 2, children: _jsx(Text, { bold: true, children: "Select Coworker" }) }), (sessions ?? []).map((s, i) => {
|
|
262
|
-
const sel = i === selectedSessionCursor;
|
|
263
|
-
return (_jsxs(Box, { gap: 2, children: [_jsx(Text, { color: sel ? "cyan" : undefined, bold: sel, children: sel ? "▶ " : " " }), _jsx(Text, { color: sel ? "cyan" : undefined, bold: sel, children: s.name })] }, s.id));
|
|
264
|
-
}), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u00B7 Enter select \u00B7 Esc cancel" }) })] }));
|
|
265
|
-
};
|
|
266
|
-
const renderCreateFields = () => {
|
|
267
|
-
if (mode === "create-name") {
|
|
268
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsx(Text, { dimColor: true, children: selectedSession })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Name: " }), _jsx(TextInput, { placeholder: "e.g. daily-standup", onSubmit: (v) => {
|
|
269
|
-
setCreateData({ ...createData, name: v });
|
|
270
|
-
setMode("create-schedule");
|
|
271
|
-
} }, "create-name")] })] }));
|
|
272
|
-
}
|
|
273
|
-
if (mode === "create-schedule") {
|
|
274
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsx(Text, { dimColor: true, children: createData.name ?? "" })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Schedule (cron expr): " }), _jsx(TextInput, { placeholder: "e.g. 0 9 * * *", onSubmit: (v) => {
|
|
275
|
-
setCreateData({ ...createData, schedule: v });
|
|
276
|
-
setMode("create-message");
|
|
277
|
-
} }, "create-schedule")] }), _jsx(Text, { dimColor: true, children: "Example: \"0 9 * * *\" = daily at 9am, \"*/30 * * * *\" = every 30 minutes" })] }));
|
|
278
|
-
}
|
|
279
|
-
if (mode === "create-message") {
|
|
280
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsx(Text, { dimColor: true, children: createData.schedule ?? "" })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Message: " }), _jsx(TextInput, { placeholder: "Message to inject", onSubmit: (v) => {
|
|
281
|
-
setCreateData({ ...createData, message: v });
|
|
282
|
-
setMode("create-timezone");
|
|
283
|
-
} }, "create-message")] })] }));
|
|
284
|
-
}
|
|
285
|
-
if (mode === "create-timezone") {
|
|
286
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsxs(Text, { dimColor: true, children: [createData.message.slice(0, 40), "..."] })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Timezone (optional, ENTER to skip): " }), _jsx(TextInput, { placeholder: "e.g. America/New_York", onSubmit: (v) => {
|
|
287
|
-
setCreateData({ ...createData, timezone: v || "" });
|
|
288
|
-
handleCreate();
|
|
289
|
-
} }, "create-timezone")] }), _jsx(Text, { dimColor: true, children: "Leave empty for system timezone" })] }));
|
|
290
|
-
}
|
|
291
|
-
if (mode === "creating") {
|
|
292
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Creating cron job..." }) }));
|
|
293
|
-
}
|
|
294
|
-
return null;
|
|
295
|
-
};
|
|
296
|
-
const renderViewMessage = () => {
|
|
297
|
-
if (mode !== "view-message")
|
|
298
|
-
return null;
|
|
299
|
-
const selected = filteredCrons[cursor];
|
|
300
|
-
if (!selected)
|
|
301
|
-
return null;
|
|
302
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Message Preview" }), _jsx(Text, { dimColor: true, children: selected.name })] }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 0, flexDirection: "column", children: _jsx(Text, { wrap: "wrap", children: selected.message }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc back" }) })] }));
|
|
303
|
-
};
|
|
304
|
-
const renderHistory = () => {
|
|
305
|
-
if (mode !== "history")
|
|
306
|
-
return null;
|
|
307
|
-
if (historyLoading) {
|
|
308
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading history..." }) }));
|
|
309
|
-
}
|
|
310
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "History" }), _jsx(Text, { dimColor: true, children: "Press any key to go back" })] }), history.length === 0 ? (_jsx(Text, { dimColor: true, children: "No execution history yet." })) : (_jsx(Box, { flexDirection: "column", children: history.map((entry) => (_jsxs(Box, { gap: 2, children: [_jsx(Text, { color: entry.success ? "green" : "red", children: entry.success ? "✓" : "✗" }), _jsx(Text, { children: new Date(entry.executed_at).toLocaleString() }), !entry.success && entry.error_message && (_jsx(Text, { color: "red", children: entry.error_message }))] }, entry.id))) }))] }));
|
|
311
|
-
};
|
|
312
|
-
const actionPanel = renderActionPanel();
|
|
313
|
-
const panelHeight = actionPanel ? 5 : 0;
|
|
314
|
-
const tableHeight = contentHeight - panelHeight - 5;
|
|
315
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [renderCreateSelectSession(), renderCreateFields(), renderViewMessage(), renderHistory(), (mode === "list" || mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "deleting" || mode === "toggling" || mode === "view-message") && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Cron Jobs" }), selectedSession ? (_jsxs(Text, { color: "cyan", dimColor: true, children: ["[", filteredCrons.length, " jobs for ", selectedSession, "]"] })) : (_jsxs(Text, { dimColor: true, children: ["[", filteredCrons.length, " total]"] })), loading && _jsx(Spinner, {})] }), actionPanel, filteredCrons.length === 0 ? (_jsx(Box, { height: tableHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: selectedSession
|
|
316
|
-
? `No cron jobs for ${selectedSession}. Press c to create one.`
|
|
317
|
-
: "No cron jobs yet. Press c to create one." }) })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " NAME".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "COWORKER".padEnd(15) }), _jsx(Text, { bold: true, color: "cyan", children: "SCHEDULE".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "NEXT RUN".padEnd(NEXT_RUN_PADDING) }), _jsx(Text, { bold: true, color: "cyan", children: "STATUS" })] }), filteredCrons.map((job, idx) => {
|
|
318
|
-
const selected = idx === cursor;
|
|
319
|
-
return (_jsxs(Box, { gap: 2, children: [_jsxs(Box, { width: 20, children: [_jsx(Text, { color: selected ? "cyan" : undefined, children: selected ? "▶ " : " " }), _jsx(Text, { color: selected ? "cyan" : "green", bold: selected, children: job.name })] }), _jsx(Box, { width: 15, children: _jsx(Text, { color: selected ? "magenta" : undefined, dimColor: !selected, children: job.session_name.padEnd(15) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { dimColor: !selected, children: job.schedule.padEnd(20) }) }), _jsx(Box, { width: NEXT_RUN_PADDING, children: _jsx(Text, { color: job.enabled ? (selected ? "cyan" : "green") : "gray", dimColor: !selected, children: job.enabled ? formatNextRun(job.next_run).padEnd(NEXT_RUN_PADDING) : "DISABLED".padEnd(NEXT_RUN_PADDING) }) }), _jsx(Text, { color: job.enabled ? "green" : "gray", dimColor: !selected, children: job.enabled ? "enabled" : "disabled" })] }, job.id));
|
|
320
|
-
})] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["c create \u00B7 d delete \u00B7 e enable/disable \u00B7 h history \u00B7 v view message \u00B7 f", " ", selectedSession ? "show all" : "filter by coworker", " \u00B7 Esc back"] }) })] }))] }));
|
|
321
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface CronRequestsProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function CronRequests({ serverUrl, password, onBack, contentHeight }: CronRequestsProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState, useCallback } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { TextInput, Spinner, ConfirmInput } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
export function CronRequests({ serverUrl, password, onBack, contentHeight }) {
|
|
7
|
-
const { listCronRequests, approveCronRequest, rejectCronRequest } = useApi(serverUrl, password);
|
|
8
|
-
const { data: requests, loading, error: loadError, run } = useAsyncState();
|
|
9
|
-
const [cursor, setCursor] = useState(0);
|
|
10
|
-
const [mode, setMode] = useState("list");
|
|
11
|
-
const [actionMsg, setActionMsg] = useState(null);
|
|
12
|
-
const [actionError, setActionError] = useState(null);
|
|
13
|
-
const [rejectNotes, setRejectNotes] = useState("");
|
|
14
|
-
const [showAll, setShowAll] = useState(false);
|
|
15
|
-
const filteredRequests = (requests ?? []).filter((r) => showAll || r.status === "pending");
|
|
16
|
-
const reload = useCallback(() => {
|
|
17
|
-
void run(() => listCronRequests(showAll ? undefined : { status: "pending" }));
|
|
18
|
-
}, [showAll]);
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
reload();
|
|
21
|
-
}, [showAll]);
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (filteredRequests.length > 0) {
|
|
24
|
-
setCursor((c) => Math.min(c, filteredRequests.length - 1));
|
|
25
|
-
}
|
|
26
|
-
}, [filteredRequests.length]);
|
|
27
|
-
useInput((input, key) => {
|
|
28
|
-
if (key.escape && mode === "list") {
|
|
29
|
-
onBack();
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
if (key.escape && (mode === "confirm-approve" || mode === "confirm-reject" || mode === "reject-notes" || mode === "view-message")) {
|
|
33
|
-
setMode("list");
|
|
34
|
-
setRejectNotes("");
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (loading)
|
|
38
|
-
return;
|
|
39
|
-
if (mode === "list") {
|
|
40
|
-
if (key.upArrow)
|
|
41
|
-
setCursor((c) => Math.max(0, c - 1));
|
|
42
|
-
if (key.downArrow)
|
|
43
|
-
setCursor((c) => Math.min(filteredRequests.length - 1, c + 1));
|
|
44
|
-
if (filteredRequests.length > 0) {
|
|
45
|
-
const selected = filteredRequests[cursor];
|
|
46
|
-
if (input === "a" && selected?.status === "pending") {
|
|
47
|
-
setActionError(null);
|
|
48
|
-
setActionMsg(null);
|
|
49
|
-
setMode("confirm-approve");
|
|
50
|
-
}
|
|
51
|
-
if (input === "r" && selected?.status === "pending") {
|
|
52
|
-
setActionError(null);
|
|
53
|
-
setActionMsg(null);
|
|
54
|
-
setRejectNotes("");
|
|
55
|
-
setMode("reject-notes");
|
|
56
|
-
}
|
|
57
|
-
if (input === "v") {
|
|
58
|
-
setMode("view-message");
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (input === "f") {
|
|
62
|
-
setShowAll((prev) => !prev);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (mode === "confirm-approve") {
|
|
66
|
-
if (key.return || input === "y") {
|
|
67
|
-
handleApprove();
|
|
68
|
-
}
|
|
69
|
-
if (input === "n" || key.escape) {
|
|
70
|
-
setMode("list");
|
|
71
|
-
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
if (mode === "confirm-reject") {
|
|
75
|
-
if (key.return || input === "y") {
|
|
76
|
-
handleReject();
|
|
77
|
-
}
|
|
78
|
-
if (input === "n" || key.escape) {
|
|
79
|
-
setMode("list");
|
|
80
|
-
setRejectNotes("");
|
|
81
|
-
}
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
const handleApprove = async () => {
|
|
86
|
-
const selected = filteredRequests[cursor];
|
|
87
|
-
if (!selected)
|
|
88
|
-
return;
|
|
89
|
-
setMode("approving");
|
|
90
|
-
try {
|
|
91
|
-
await approveCronRequest(selected.id);
|
|
92
|
-
setActionMsg(`Cron request "${selected.name}" approved and scheduled.`);
|
|
93
|
-
setMode("list");
|
|
94
|
-
reload();
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
98
|
-
setMode("list");
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
const handleReject = async () => {
|
|
102
|
-
const selected = filteredRequests[cursor];
|
|
103
|
-
if (!selected)
|
|
104
|
-
return;
|
|
105
|
-
setMode("rejecting");
|
|
106
|
-
try {
|
|
107
|
-
await rejectCronRequest(selected.id, rejectNotes || undefined);
|
|
108
|
-
setActionMsg(`Cron request "${selected.name}" rejected.`);
|
|
109
|
-
setMode("list");
|
|
110
|
-
setRejectNotes("");
|
|
111
|
-
reload();
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
setActionError(err instanceof Error ? err.message : String(err));
|
|
115
|
-
setMode("list");
|
|
116
|
-
setRejectNotes("");
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
const formatDate = (dateStr) => {
|
|
120
|
-
try {
|
|
121
|
-
return new Date(dateStr).toLocaleString();
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
return dateStr;
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
const statusColor = (status) => {
|
|
128
|
-
switch (status) {
|
|
129
|
-
case "pending": return "yellow";
|
|
130
|
-
case "approved": return "green";
|
|
131
|
-
case "rejected": return "red";
|
|
132
|
-
default: return "white";
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
if (loading && filteredRequests.length === 0) {
|
|
136
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading cron requests..." }) }));
|
|
137
|
-
}
|
|
138
|
-
if (loadError) {
|
|
139
|
-
return (_jsxs(Box, { height: contentHeight, flexDirection: "column", gap: 1, children: [_jsx(Text, { color: "red", bold: true, children: "Error" }), _jsx(Text, { children: loadError })] }));
|
|
140
|
-
}
|
|
141
|
-
const renderActionPanel = () => {
|
|
142
|
-
if (mode === "approving") {
|
|
143
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: "green", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: `Approving "${filteredRequests[cursor]?.name}"...` }) }));
|
|
144
|
-
}
|
|
145
|
-
if (mode === "rejecting") {
|
|
146
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: `Rejecting "${filteredRequests[cursor]?.name}"...` }) }));
|
|
147
|
-
}
|
|
148
|
-
if (mode === "confirm-approve" && filteredRequests[cursor]) {
|
|
149
|
-
const req = filteredRequests[cursor];
|
|
150
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "Approve Cron Request" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: ["Approve ", _jsx(Text, { color: "cyan", bold: true, children: req.name }), " from ", _jsx(Text, { color: "magenta", children: req.session_name }), "?"] }), _jsxs(Text, { dimColor: true, children: ["Schedule: ", req.schedule] })] }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleApprove(), onCancel: () => setMode("list") }) })] }));
|
|
151
|
-
}
|
|
152
|
-
if (mode === "confirm-reject" && filteredRequests[cursor]) {
|
|
153
|
-
const req = filteredRequests[cursor];
|
|
154
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Reject Cron Request" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: ["Reject ", _jsx(Text, { color: "cyan", bold: true, children: req.name }), " from ", _jsx(Text, { color: "magenta", children: req.session_name }), "?"] }), rejectNotes && _jsxs(Text, { dimColor: true, children: ["Notes: ", rejectNotes] })] }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleReject(), onCancel: () => { setMode("list"); setRejectNotes(""); } }) })] }));
|
|
155
|
-
}
|
|
156
|
-
return null;
|
|
157
|
-
};
|
|
158
|
-
const renderRejectNotes = () => {
|
|
159
|
-
if (mode !== "reject-notes")
|
|
160
|
-
return null;
|
|
161
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, color: "red", children: "Reject Cron Request" }), _jsx(Text, { dimColor: true, children: filteredRequests[cursor]?.name })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Reason (optional, Enter to skip): " }), _jsx(TextInput, { placeholder: "e.g. Schedule too frequent", onSubmit: (v) => {
|
|
162
|
-
setRejectNotes(v);
|
|
163
|
-
setMode("confirm-reject");
|
|
164
|
-
} }, "reject-notes")] }), _jsx(Text, { dimColor: true, children: "Esc cancel" })] }));
|
|
165
|
-
};
|
|
166
|
-
const renderViewMessage = () => {
|
|
167
|
-
if (mode !== "view-message")
|
|
168
|
-
return null;
|
|
169
|
-
const selected = filteredRequests[cursor];
|
|
170
|
-
if (!selected)
|
|
171
|
-
return null;
|
|
172
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Request Details" }), _jsx(Text, { dimColor: true, children: selected.name })] }), _jsxs(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 0, flexDirection: "column", children: [_jsxs(Text, { children: ["From: ", _jsx(Text, { color: "magenta", bold: true, children: selected.session_name })] }), _jsxs(Text, { children: ["Schedule: ", _jsx(Text, { bold: true, children: selected.schedule })] }), selected.timezone && _jsxs(Text, { children: ["Timezone: ", selected.timezone] }), _jsxs(Text, { children: ["Status: ", _jsx(Text, { color: statusColor(selected.status), bold: true, children: selected.status })] }), _jsxs(Text, { children: ["Requested: ", formatDate(selected.requested_at)] }), selected.reviewed_at && _jsxs(Text, { children: ["Reviewed: ", formatDate(selected.reviewed_at), " by ", selected.reviewed_by] }), selected.reviewer_notes && _jsxs(Text, { children: ["Notes: ", selected.reviewer_notes] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { bold: true, children: "Message:" }) }), _jsx(Text, { wrap: "wrap", children: selected.message })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc back" }) })] }));
|
|
173
|
-
};
|
|
174
|
-
const actionPanel = renderActionPanel();
|
|
175
|
-
const panelHeight = actionPanel ? 5 : 0;
|
|
176
|
-
const tableHeight = contentHeight - panelHeight - 5;
|
|
177
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [renderRejectNotes(), renderViewMessage(), (mode === "list" || mode === "confirm-approve" || mode === "confirm-reject" || mode === "approving" || mode === "rejecting") && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Cron Requests" }), _jsxs(Text, { dimColor: true, children: ["[", filteredRequests.length, " ", showAll ? "total" : "pending", "]"] }), loading && _jsx(Spinner, {})] }), actionMsg && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: actionMsg }) })), actionError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: actionError }) })), actionPanel, filteredRequests.length === 0 ? (_jsx(Box, { height: tableHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: showAll ? "No cron requests found." : "No pending cron requests. Press f to show all." }) })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " NAME".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "COWORKER".padEnd(15) }), _jsx(Text, { bold: true, color: "cyan", children: "SCHEDULE".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "REQUESTED".padEnd(22) }), _jsx(Text, { bold: true, color: "cyan", children: "STATUS" })] }), filteredRequests.map((req, idx) => {
|
|
178
|
-
const selected = idx === cursor;
|
|
179
|
-
return (_jsxs(Box, { gap: 2, children: [_jsxs(Box, { width: 20, children: [_jsx(Text, { color: selected ? "cyan" : undefined, children: selected ? "▶ " : " " }), _jsx(Text, { color: selected ? "cyan" : "green", bold: selected, children: req.name })] }), _jsx(Box, { width: 15, children: _jsx(Text, { color: selected ? "magenta" : undefined, dimColor: !selected, children: req.session_name.padEnd(15) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { dimColor: !selected, children: req.schedule.padEnd(20) }) }), _jsx(Box, { width: 22, children: _jsx(Text, { dimColor: !selected, children: formatDate(req.requested_at).padEnd(22) }) }), _jsx(Text, { color: statusColor(req.status), bold: selected, children: req.status })] }, req.id));
|
|
180
|
-
})] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["a approve \u00B7 r reject \u00B7 v view details \u00B7 f ", showAll ? "show pending only" : "show all", " \u00B7 Esc back"] }) })] }))] }));
|
|
181
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { Select, Spinner, ConfirmInput } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
export function DeleteSession({ serverUrl, password, onBack }) {
|
|
7
|
-
const { listSessions, deleteSession } = useApi(serverUrl, password);
|
|
8
|
-
const { run } = useAsyncState();
|
|
9
|
-
const [sessions, setSessions] = useState([]);
|
|
10
|
-
const [stage, setStage] = useState("loading");
|
|
11
|
-
const [selected, setSelected] = useState(null);
|
|
12
|
-
const [error, setError] = useState(null);
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
void run(listSessions).then((rows) => {
|
|
15
|
-
if (rows && rows.length > 0) {
|
|
16
|
-
setSessions(rows);
|
|
17
|
-
setStage("select");
|
|
18
|
-
}
|
|
19
|
-
else if (rows) {
|
|
20
|
-
setError("No sessions to delete.");
|
|
21
|
-
setStage("error");
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
}, []);
|
|
25
|
-
// Auto-return to menu 1.5s after done or error
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
if (stage === "done" || stage === "error") {
|
|
28
|
-
const timer = setTimeout(onBack, 1500);
|
|
29
|
-
return () => clearTimeout(timer);
|
|
30
|
-
}
|
|
31
|
-
}, [stage, onBack]);
|
|
32
|
-
const handleSelect = (name) => {
|
|
33
|
-
setSelected(name);
|
|
34
|
-
setStage("confirm");
|
|
35
|
-
};
|
|
36
|
-
const handleConfirm = async (confirmed) => {
|
|
37
|
-
if (!confirmed || !selected) {
|
|
38
|
-
onBack();
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
setStage("deleting");
|
|
42
|
-
try {
|
|
43
|
-
await deleteSession(selected);
|
|
44
|
-
setStage("done");
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
48
|
-
setStage("error");
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Delete Session" }), stage === "loading" && (_jsx(Spinner, { label: "Loading sessions..." })), stage === "select" && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Select a session to delete:" }), _jsx(Select, { options: sessions.map((s) => ({
|
|
52
|
-
label: `${s.name} ${s.session_id.slice(0, 8)}...`,
|
|
53
|
-
value: s.name,
|
|
54
|
-
})), onChange: handleSelect })] })), stage === "confirm" && selected && (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["Delete ", _jsx(Text, { color: "yellow", bold: true, children: selected }), "?", " ", _jsx(Text, { dimColor: true, children: "This also deletes the OpenCode session." })] }), _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleConfirm(true), onCancel: () => void handleConfirm(false) })] })), stage === "deleting" && (_jsx(Spinner, { label: `Deleting "${selected}"...` })), stage === "done" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", children: ["Session \"", selected, "\" deleted."] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] })), stage === "error" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }))] }));
|
|
55
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface InjectTextProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function InjectText({ serverUrl, password, onBack, contentHeight }: InjectTextProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { Select, Spinner, TextInput } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
export function InjectText({ serverUrl, password, onBack, contentHeight }) {
|
|
7
|
-
const { listSessions, injectText } = useApi(serverUrl, password);
|
|
8
|
-
const { run: runList } = useAsyncState();
|
|
9
|
-
const [sessions, setSessions] = useState([]);
|
|
10
|
-
const [sessionsLoading, setSessionsLoading] = useState(true);
|
|
11
|
-
const [stage, setStage] = useState("select");
|
|
12
|
-
const [selectedName, setSelectedName] = useState(null);
|
|
13
|
-
const [error, setError] = useState(null);
|
|
14
|
-
const [submitted, setSubmitted] = useState(false);
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
runList(listSessions).then((rows) => {
|
|
17
|
-
setSessions(rows ?? []);
|
|
18
|
-
setSessionsLoading(false);
|
|
19
|
-
});
|
|
20
|
-
}, []);
|
|
21
|
-
// Auto-return after done or error
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (stage === "done" || stage === "error") {
|
|
24
|
-
const timer = setTimeout(onBack, 2000);
|
|
25
|
-
return () => clearTimeout(timer);
|
|
26
|
-
}
|
|
27
|
-
}, [stage, onBack]);
|
|
28
|
-
const handleSessionSelect = (name) => {
|
|
29
|
-
setSelectedName(name);
|
|
30
|
-
setStage("input");
|
|
31
|
-
};
|
|
32
|
-
const handleTextSubmit = async (text) => {
|
|
33
|
-
const trimmed = text.trim();
|
|
34
|
-
if (!trimmed || !selectedName)
|
|
35
|
-
return;
|
|
36
|
-
setSubmitted(true);
|
|
37
|
-
setStage("submitting");
|
|
38
|
-
try {
|
|
39
|
-
await injectText(selectedName, trimmed);
|
|
40
|
-
setStage("done");
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
44
|
-
setStage("error");
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
if (sessionsLoading) {
|
|
48
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading sessions..." }) }));
|
|
49
|
-
}
|
|
50
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Inject Text" }), stage === "select" && sessions.length === 0 && (_jsx(Box, { height: contentHeight - 2, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "No sessions yet. Create one first." }) })), stage === "select" && sessions.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Select a session to inject into:" }), _jsx(Select, { options: sessions.map((s) => ({ label: s.name, value: s.name })), onChange: handleSessionSelect })] })), stage === "input" && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Session: " }), _jsx(Text, { color: "cyan", children: selectedName })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Text: " }), !submitted && (_jsx(TextInput, { placeholder: "Type your message...", onSubmit: handleTextSubmit }))] })] })), stage === "submitting" && (_jsx(Spinner, { label: `Injecting into "${selectedName}"...` })), stage === "done" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", children: ["Message injected into \"", selectedName, "\"."] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] })), stage === "error" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }))] }));
|
|
51
|
-
}
|