main
html 506 lines 30.3 KB
Raw
1 <html>
2 <head>
3 <script type="module">
4 import { store } from "/components/modals/scheduler/scheduler-store.js";
5 </script>
6 </head>
7 <body>
8 <div x-data>
9 <template x-if="$store.schedulerStore">
10 <div>
11 <!-- Create Task Form -->
12 <div class="scheduler-form" x-show="$store.schedulerStore.isCreating">
13 <div class="scheduler-form-header">
14 <div class="scheduler-form-title">Create New Task</div>
15 </div>
16 <div class="buttons-container scheduler-editor-actions scheduler-editor-actions-top">
17 <div class="buttons-left"></div>
18 <div class="buttons-right">
19 <button type="button" class="button confirm"
20 @click="$store.schedulerStore.saveTask()">Save</button>
21 <button type="button" class="button cancel"
22 @click="$store.schedulerStore.cancelEdit()">Cancel</button>
23 </div>
24 </div>
25
26 <div class="scheduler-form-grid">
27 <div class="scheduler-form-field">
28 <div class="label-help-wrapper">
29 <label class="scheduler-form-label">Task Name</label>
30 <div class="scheduler-form-help">A unique name to identify this task</div>
31 </div>
32 <input type="text" x-model="$store.schedulerStore.editingTask.name" placeholder="Enter task name">
33 </div>
34
35 <div class="scheduler-form-field">
36 <div class="label-help-wrapper">
37 <label class="scheduler-form-label">Type</label>
38 <div class="scheduler-form-help">Task execution method</div>
39 </div>
40 <select x-model="$store.schedulerStore.editingTask.type">
41 <option value="scheduled">Scheduled (Cron)</option>
42 <option value="adhoc">Ad-hoc (Manual)</option>
43 <option value="planned">Planned (Specific Times)</option>
44 </select>
45 </div>
46
47 <div class="scheduler-form-field">
48 <div class="label-help-wrapper">
49 <label class="scheduler-form-label">Project</label>
50 <div class="scheduler-form-help"
51 x-text="$store.schedulerStore.editingTask.dedicated_context ? 'Inherited from the active chat project.' : 'Mirrors the shared context project.'"></div>
52 </div>
53 <div class="project-selector">
54 <select class="scheduler-project-select"
55 x-model="$store.schedulerStore.selectedProjectSlug"
56 @change="$store.schedulerStore.onProjectSelect($event.target.value)">
57 <option value="">No project</option>
58 <template x-for="proj in $store.schedulerStore.projectOptions" :key="proj.name">
59 <option :value="proj.name" x-text="proj.title"></option>
60 </template>
61 </select>
62 </div>
63 </div>
64
65 <div class="scheduler-form-field" x-show="$store.schedulerStore.isCreating">
66 <div class="label-help-wrapper">
67 <label class="scheduler-form-label">State</label>
68 <div class="scheduler-form-help">Select the initial state of the task</div>
69 </div>
70 <div>
71 <div class="scheduler-state-selector">
72 <span class="scheduler-status-badge scheduler-status-idle"
73 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'idle'}"
74 @click="$store.schedulerStore.editingTask.state = 'idle'">Idle</span>
75 <span class="scheduler-status-badge scheduler-status-running"
76 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'running'}"
77 @click="$store.schedulerStore.editingTask.state = 'running'">Running</span>
78 <span class="scheduler-status-badge scheduler-status-disabled"
79 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'disabled'}"
80 @click="$store.schedulerStore.editingTask.state = 'disabled'">Disabled</span>
81 <span class="scheduler-status-badge scheduler-status-error"
82 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'error'}"
83 @click="$store.schedulerStore.editingTask.state = 'error'">Error</span>
84 </div>
85 <div class="scheduler-state-explanation">
86 <span x-show="$store.schedulerStore.editingTask.state === 'idle'"><strong>Idle</strong>: Ready to run</span>
87 <span x-show="$store.schedulerStore.editingTask.state === 'running'"><strong>Running</strong>: Currently executing</span>
88 <span x-show="$store.schedulerStore.editingTask.state === 'disabled'"><strong>Disabled</strong>: Won't execute automatically</span>
89 <span x-show="$store.schedulerStore.editingTask.state === 'error'"><strong>Error</strong>: Task encountered an error</span>
90 </div>
91 </div>
92 </div>
93
94 <div class="scheduler-form-field full-width"
95 x-show="$store.schedulerStore.editingTask.type === 'scheduled'">
96 <div class="label-help-wrapper">
97 <label class="scheduler-form-label">Schedule</label>
98 <div class="scheduler-form-help">Cron schedule for automated execution (minute hour day month weekday)</div>
99 </div>
100 <div class="scheduler-schedule-builder">
101 <div class="scheduler-schedule-field">
102 <span class="scheduler-schedule-label">Minute</span>
103 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.minute"
104 placeholder="*" maxlength="9">
105 </div>
106 <div class="scheduler-schedule-field">
107 <span class="scheduler-schedule-label">Hour</span>
108 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.hour"
109 placeholder="*" maxlength="9">
110 </div>
111 <div class="scheduler-schedule-field">
112 <span class="scheduler-schedule-label">Day</span>
113 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.day"
114 placeholder="*" maxlength="9">
115 </div>
116 <div class="scheduler-schedule-field">
117 <span class="scheduler-schedule-label">Month</span>
118 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.month"
119 placeholder="*" maxlength="9">
120 </div>
121 <div class="scheduler-schedule-field">
122 <span class="scheduler-schedule-label">Weekday</span>
123 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.weekday"
124 placeholder="*" maxlength="9">
125 </div>
126 </div>
127 </div>
128
129 <div class="scheduler-form-field full-width"
130 x-show="$store.schedulerStore.editingTask.type === 'planned'"
131 x-effect="if ($store.schedulerStore.isCreating && $store.schedulerStore.editingTask.type === 'planned') { $store.schedulerStore.initFlatpickr('create') }">
132 <div class="label-help-wrapper">
133 <label class="scheduler-form-label">Plan</label>
134 <div class="scheduler-form-help">Specific execution times for this task</div>
135 </div>
136 <div class="scheduler-plan-builder">
137 <div class="scheduler-plan-todo">
138 <span class="scheduler-plan-label">Upcoming Executions</span>
139 <div class="scheduler-todo-list">
140 <template x-if="$store.schedulerStore.editingTask.plan && Array.isArray($store.schedulerStore.editingTask.plan.todo) && $store.schedulerStore.editingTask.plan.todo.length > 0">
141 <template x-for="(time, index) in $store.schedulerStore.editingTask.plan.todo" :key="index">
142 <div class="scheduler-todo-item">
143 <span x-text="$store.schedulerStore.formatDate(time)"></span>
144 <button @click.prevent="$store.schedulerStore.editingTask.plan.todo.splice(index, 1)"
145 class="scheduler-todo-remove">
146 <x-icon name="close"></x-icon>
147 </button>
148 </div>
149 </template>
150 </template>
151 <template x-if="!$store.schedulerStore.editingTask.plan || !$store.schedulerStore.editingTask.plan.todo || $store.schedulerStore.editingTask.plan.todo.length === 0">
152 <div class="scheduler-empty-plan">
153 No scheduled execution times yet. Add one below.
154 </div>
155 </template>
156 <div class="scheduler-add-todo">
157 <input type="text" id="newPlannedTime-create"
158 class="scheduler-flatpickr-input"
159 placeholder="Select date and time">
160 <button @click.prevent="$store.schedulerStore.addPlannedTime('create')"
161 class="btn btn-ok scheduler-add-todo-button">
162 <x-icon name="add"></x-icon>
163 Add Time
164 </button>
165 </div>
166 </div>
167 </div>
168 </div>
169 </div>
170
171 <div class="scheduler-form-field full-width"
172 x-show="$store.schedulerStore.editingTask.type === 'adhoc'">
173 <div class="label-help-wrapper">
174 <label class="scheduler-form-label">Token</label>
175 <div class="scheduler-form-help">Token used to trigger this task externally</div>
176 </div>
177 <div class="input-group">
178 <input type="text" x-model="$store.schedulerStore.editingTask.token"
179 placeholder="Token for ad-hoc task">
180 <button class="btn btn-action generate-token"
181 @click="$store.schedulerStore.editingTask.token = $store.schedulerStore.generateRandomToken()"
182 title="Generate Token">
183 <x-icon name="refresh"></x-icon>
184 Generate
185 </button>
186 </div>
187 </div>
188
189 <div class="scheduler-form-field full-width">
190 <div class="label-help-wrapper">
191 <label class="scheduler-form-label">System Prompt</label>
192 <div class="scheduler-form-help">System-level instructions for the assistant</div>
193 </div>
194 <textarea x-model="$store.schedulerStore.editingTask.system_prompt"
195 placeholder="System instructions for the AI"></textarea>
196 </div>
197
198 <div class="scheduler-form-field full-width">
199 <div class="label-help-wrapper">
200 <label class="scheduler-form-label">User Prompt</label>
201 <div class="scheduler-form-help">The main task prompt that will be executed</div>
202 </div>
203 <textarea x-model="$store.schedulerStore.editingTask.prompt"
204 placeholder="User message for the AI"></textarea>
205 </div>
206
207 <div class="scheduler-form-field full-width">
208 <div class="label-help-wrapper">
209 <label class="scheduler-form-label">Attachments</label>
210 <div class="scheduler-form-help">Container file paths or URLs, one per line</div>
211 </div>
212 <textarea x-model="$store.schedulerStore.attachmentsText"
213 placeholder="Enter file paths or URLs, one per line"></textarea>
214 </div>
215 </div>
216 </div>
217
218 <!-- Edit Task Form -->
219 <div class="scheduler-form" x-show="$store.schedulerStore.isEditing">
220 <div class="scheduler-form-header">
221 <div class="scheduler-form-title">Edit Task</div>
222 </div>
223 <div class="buttons-container scheduler-editor-actions scheduler-editor-actions-top">
224 <div class="buttons-left">
225 <button type="button" class="button cancel"
226 @click="$confirmClick($event, () => $store.schedulerStore.deleteTask($store.schedulerStore.editingTask.uuid))">Delete</button>
227 </div>
228 <div class="buttons-right">
229 <button type="button" class="button confirm"
230 @click="$store.schedulerStore.saveTask()">Save</button>
231 <button type="button" class="button cancel"
232 @click="$store.schedulerStore.cancelEdit()">Cancel</button>
233 </div>
234 </div>
235
236 <div class="scheduler-form-grid">
237 <div class="scheduler-form-field">
238 <div class="label-help-wrapper">
239 <label class="scheduler-form-label">Task Name</label>
240 <div class="scheduler-form-help">A unique name to identify this task</div>
241 </div>
242 <input type="text" x-model="$store.schedulerStore.editingTask.name" placeholder="Enter task name">
243 </div>
244
245 <div class="scheduler-form-field">
246 <div class="label-help-wrapper">
247 <label class="scheduler-form-label">Task Type</label>
248 <div class="scheduler-form-help">Task type cannot be changed after creation</div>
249 </div>
250 <select x-model="$store.schedulerStore.editingTask.type" disabled>
251 <option value="scheduled">Scheduled Task</option>
252 <option value="adhoc">Ad-hoc Task</option>
253 <option value="planned">Planned Task</option>
254 </select>
255 </div>
256
257 <div class="scheduler-form-field">
258 <div class="label-help-wrapper">
259 <label class="scheduler-form-label">Project</label>
260 <div class="scheduler-form-help"
261 x-text="$store.schedulerStore.editingTask.dedicated_context ? 'Dedicated tasks inherit the active chat project.' : 'Shared tasks mirror the project assigned to their context.'"></div>
262 </div>
263 <div class="project-display">
264 <span class="project-color-ball"
265 :style="$store.schedulerStore.editingTask.project?.color ? { backgroundColor: $store.schedulerStore.editingTask.project.color } : { border: '1px solid var(--color-border)' }"></span>
266 <span x-text="$store.schedulerStore.formatProjectLabel($store.schedulerStore.editingTask.project)"></span>
267 </div>
268 </div>
269
270 <div class="scheduler-form-field" x-show="$store.schedulerStore.isEditing">
271 <div class="label-help-wrapper">
272 <label class="scheduler-form-label">State</label>
273 <div class="scheduler-form-help">Change the task's state</div>
274 </div>
275 <div>
276 <div class="scheduler-state-selector">
277 <span class="scheduler-status-badge scheduler-status-idle"
278 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'idle'}"
279 @click="$store.schedulerStore.editingTask.state = 'idle'">Idle</span>
280 <span class="scheduler-status-badge scheduler-status-running"
281 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'running'}"
282 @click="$store.schedulerStore.editingTask.state = 'running'">Running</span>
283 <span class="scheduler-status-badge scheduler-status-disabled"
284 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'disabled'}"
285 @click="$store.schedulerStore.editingTask.state = 'disabled'">Disabled</span>
286 <span class="scheduler-status-badge scheduler-status-error"
287 :class="{'scheduler-status-selected': $store.schedulerStore.editingTask.state === 'error'}"
288 @click="$store.schedulerStore.editingTask.state = 'error'">Error</span>
289 </div>
290 <div class="scheduler-state-explanation">
291 <span x-show="$store.schedulerStore.editingTask.state === 'idle'"><strong>Idle</strong>: Ready to run</span>
292 <span x-show="$store.schedulerStore.editingTask.state === 'running'"><strong>Running</strong>: Currently executing</span>
293 <span x-show="$store.schedulerStore.editingTask.state === 'disabled'"><strong>Disabled</strong>: Won't execute automatically</span>
294 <span x-show="$store.schedulerStore.editingTask.state === 'error'"><strong>Error</strong>: Task encountered an error</span>
295 </div>
296 </div>
297 </div>
298
299 <div class="scheduler-form-field full-width"
300 x-show="$store.schedulerStore.editingTask && $store.schedulerStore.editingTask.type === 'scheduled'">
301 <div class="label-help-wrapper">
302 <label class="scheduler-form-label">Schedule (Cron Expression)</label>
303 <div class="scheduler-form-help">Format: minute hour day month weekday (e.g., "* * * * *" for every minute)</div>
304 </div>
305 <div class="scheduler-schedule-builder">
306 <div class="scheduler-schedule-field">
307 <span class="scheduler-schedule-label">Minute</span>
308 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.minute"
309 placeholder="*" maxlength="9">
310 </div>
311 <div class="scheduler-schedule-field">
312 <span class="scheduler-schedule-label">Hour</span>
313 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.hour"
314 placeholder="*" maxlength="9">
315 </div>
316 <div class="scheduler-schedule-field">
317 <span class="scheduler-schedule-label">Day</span>
318 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.day"
319 placeholder="*" maxlength="9">
320 </div>
321 <div class="scheduler-schedule-field">
322 <span class="scheduler-schedule-label">Month</span>
323 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.month"
324 placeholder="*" maxlength="9">
325 </div>
326 <div class="scheduler-schedule-field">
327 <span class="scheduler-schedule-label">Weekday</span>
328 <input type="text" x-model="$store.schedulerStore.editingTask.schedule.weekday"
329 placeholder="*" maxlength="9">
330 </div>
331 </div>
332 </div>
333
334 <div class="scheduler-form-field full-width"
335 x-show="$store.schedulerStore.editingTask.type === 'planned'"
336 x-effect="if ($store.schedulerStore.isEditing && $store.schedulerStore.editingTask.type === 'planned') { $store.schedulerStore.initFlatpickr('edit') }">
337 <div class="label-help-wrapper">
338 <label class="scheduler-form-label">Plan</label>
339 <div class="scheduler-form-help">Specific execution times for this task</div>
340 </div>
341 <div class="scheduler-plan-builder">
342 <div class="scheduler-plan-todo">
343 <span class="scheduler-plan-label">Upcoming Executions</span>
344 <div class="scheduler-todo-list">
345 <template x-if="$store.schedulerStore.editingTask.plan && Array.isArray($store.schedulerStore.editingTask.plan.todo) && $store.schedulerStore.editingTask.plan.todo.length > 0">
346 <template x-for="(time, index) in $store.schedulerStore.editingTask.plan.todo" :key="index">
347 <div class="scheduler-todo-item">
348 <span x-text="$store.schedulerStore.formatDate(time)"></span>
349 <button @click.prevent="$store.schedulerStore.editingTask.plan.todo.splice(index, 1)"
350 class="scheduler-todo-remove">
351 <x-icon name="close"></x-icon>
352 </button>
353 </div>
354 </template>
355 </template>
356 <template x-if="!$store.schedulerStore.editingTask.plan || !$store.schedulerStore.editingTask.plan.todo || $store.schedulerStore.editingTask.plan.todo.length === 0">
357 <div class="scheduler-empty-plan">
358 No scheduled execution times yet. Add one below.
359 </div>
360 </template>
361 <div class="scheduler-add-todo">
362 <input type="text" id="newPlannedTime-edit"
363 class="scheduler-flatpickr-input"
364 placeholder="Select date and time">
365 <button @click.prevent="$store.schedulerStore.addPlannedTime('edit')"
366 class="btn btn-ok scheduler-add-todo-button">
367 <x-icon name="add"></x-icon>
368 Add Time
369 </button>
370 </div>
371 </div>
372 </div>
373 </div>
374 </div>
375
376 <div class="scheduler-form-field full-width"
377 x-show="$store.schedulerStore.editingTask.type === 'adhoc'">
378 <div class="label-help-wrapper">
379 <label class="scheduler-form-label">Token</label>
380 <div class="scheduler-form-help">Token used to trigger this task externally</div>
381 </div>
382 <div class="input-group">
383 <input type="text" x-model="$store.schedulerStore.editingTask.token"
384 placeholder="Token for ad-hoc task">
385 <button class="btn btn-action generate-token"
386 @click="$store.schedulerStore.editingTask.token = $store.schedulerStore.generateRandomToken()"
387 title="Generate Token">
388 <x-icon name="refresh"></x-icon>
389 Generate
390 </button>
391 </div>
392 </div>
393
394 <div class="scheduler-form-field full-width">
395 <div class="label-help-wrapper">
396 <label class="scheduler-form-label">System Prompt</label>
397 <div class="scheduler-form-help">System-level instructions for the assistant</div>
398 </div>
399 <textarea x-model="$store.schedulerStore.editingTask.system_prompt"
400 placeholder="System instructions for the AI"></textarea>
401 </div>
402
403 <div class="scheduler-form-field full-width">
404 <div class="label-help-wrapper">
405 <label class="scheduler-form-label">User Prompt</label>
406 <div class="scheduler-form-help">The main task prompt that will be executed</div>
407 </div>
408 <textarea x-model="$store.schedulerStore.editingTask.prompt"
409 placeholder="User message for the AI"></textarea>
410 </div>
411
412 <div class="scheduler-form-field full-width">
413 <div class="label-help-wrapper">
414 <label class="scheduler-form-label">Attachments</label>
415 <div class="scheduler-form-help">Container file paths or URLs, one per line</div>
416 </div>
417 <textarea x-model="$store.schedulerStore.attachmentsText"
418 placeholder="Enter file paths or URLs, one per line"></textarea>
419 </div>
420 </div>
421 </div>
422 </div>
423 </template>
424 </div>
425
426 <style>
427 /* Form header with Save/Cancel buttons - aligns with Projects pattern */
428
429 .scheduler-form-title {
430 font-size: 1.2rem;
431 font-weight: 600;
432 color: var(--color-primary);
433 }
434
435 .scheduler-form-actions {
436 display: flex;
437 gap: 0.5rem;
438 }
439
440 .scheduler-editor-actions {
441 margin: 0 0 1rem 0;
442 }
443
444 /* Generate token button - extends .btn-action from buttons.css */
445 .btn-action.generate-token {
446 padding: 0.4rem 0.75rem;
447 white-space: nowrap;
448 }
449
450 /* Todo remove button with Material Symbol */
451 .scheduler-todo-remove {
452 background: none;
453 border: 1px solid var(--color-border);
454 padding: 0.15rem;
455 color: var(--color-text);
456 opacity: 0.7;
457 display: inline-flex;
458 align-items: center;
459 justify-content: center;
460 border-radius: 4px;
461 cursor: pointer;
462 }
463
464 .scheduler-todo-remove .material-symbols-outlined {
465 font-size: 16px;
466 }
467
468 .scheduler-todo-remove:hover {
469 opacity: 1;
470 border-color: var(--color-accent);
471 color: var(--color-accent);
472 }
473
474 /* Add todo button styling */
475 .scheduler-add-todo-button {
476 display: inline-flex;
477 align-items: center;
478 gap: 0.25rem;
479 }
480
481 .scheduler-add-todo-button .material-symbols-outlined {
482 font-size: 18px;
483 }
484
485 /* Project color ball */
486 .project-color-ball {
487 display: inline-block;
488 width: 10px;
489 height: 10px;
490 border-radius: 50%;
491 margin-right: 6px;
492 vertical-align: middle;
493 }
494
495 .project-display {
496 display: flex;
497 align-items: center;
498 padding: 0.5rem;
499 background: var(--color-background);
500 border: 1px solid var(--color-border);
501 border-radius: 4px;
502 }
503 </style>
504 </body>
505 </html>
506