main
html 263 lines 12.6 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 class="scheduler-list-container"
11 x-show="!$store.schedulerStore.isCreating && !$store.schedulerStore.isEditing">
12
13 <!-- Filter Header -->
14 <div class="filters-header">
15 <div class="filter-group-inline filter-type">
16 <label>Type</label>
17 <select x-model="$store.schedulerStore.filterType">
18 <option value="all">All Types</option>
19 <option value="scheduled">Scheduled</option>
20 <option value="adhoc">Ad-hoc</option>
21 <option value="planned">Planned</option>
22 </select>
23 </div>
24
25 <div class="filter-group-inline filter-state">
26 <label>State</label>
27 <select x-model="$store.schedulerStore.filterState">
28 <option value="all">All States</option>
29 <option value="idle">Idle</option>
30 <option value="running">Running</option>
31 <option value="disabled">Disabled</option>
32 <option value="error">Error</option>
33 </select>
34 </div>
35
36 <button class="btn btn-ok btn-new-task" @click="$store.schedulerStore.startCreateTask()">
37 <x-icon name="add"></x-icon>
38 New Task
39 </button>
40 </div>
41
42 <!-- Status Bar -->
43 <div class="data-status-bar" x-show="!$store.schedulerStore.isLoading">
44 <div class="status-info">
45 <span class="status-item">
46 <x-icon name="schedule"></x-icon>
47 Total: <strong x-text="$store.schedulerStore.tasks.length"></strong>
48 </span>
49 <span class="status-separator"></span>
50 <span class="status-item">
51 Filtered: <strong x-text="$store.schedulerStore.filteredTasks.length"></strong>
52 </span>
53 </div>
54
55 <!-- Pagination -->
56 <div class="status-pagination" x-show="$store.schedulerStore.totalPages > 1">
57 <button class="btn btn-icon" @click="$store.schedulerStore.prevPage()"
58 :disabled="$store.schedulerStore.currentPage === 1" title="Previous Page">
59 <x-icon name="chevron_left"></x-icon>
60 </button>
61 <div class="page-input-group">
62 <label>Page</label>
63 <input type="number" class="page-input"
64 x-model.number="$store.schedulerStore.currentPage"
65 @change="$store.schedulerStore.goToPage($store.schedulerStore.currentPage)"
66 @keyup.enter="$store.schedulerStore.goToPage($store.schedulerStore.currentPage)"
67 :min="1" :max="$store.schedulerStore.totalPages" />
68 <span class="page-total">of <strong
69 x-text="$store.schedulerStore.totalPages"></strong></span>
70 </div>
71 <button class="btn btn-icon" @click="$store.schedulerStore.nextPage()"
72 :disabled="$store.schedulerStore.currentPage === $store.schedulerStore.totalPages"
73 title="Next Page">
74 <x-icon name="chevron_right"></x-icon>
75 </button>
76 </div>
77 </div>
78
79 <!-- Empty State -->
80 <div class="data-empty-state"
81 x-show="!$store.schedulerStore.isLoading && $store.schedulerStore.filteredTasks.length === 0">
82 <div>No tasks found</div>
83 <button class="btn btn-ok" @click="$store.schedulerStore.startCreateTask()">
84 <x-icon name="add"></x-icon>
85 Create your first task
86 </button>
87 </div>
88
89 <!-- Task Table -->
90 <div class="data-table-container"
91 x-show="!$store.schedulerStore.isLoading && $store.schedulerStore.paginatedTasks.length > 0">
92 <table class="data-table scheduler-task-table">
93 <thead>
94 <tr>
95 <th class="col-name sortable" @click="$store.schedulerStore.changeSort('name')">
96 Name
97 <span class="sort-indicator"
98 x-show="$store.schedulerStore.sortField === 'name'"
99 :class="{'desc': $store.schedulerStore.sortDirection === 'desc'}"></span>
100 </th>
101 <th class="col-state sortable" @click="$store.schedulerStore.changeSort('state')">
102 State
103 <span class="sort-indicator"
104 x-show="$store.schedulerStore.sortField === 'state'"
105 :class="{'desc': $store.schedulerStore.sortDirection === 'desc'}"></span>
106 </th>
107 <th class="col-project">Project</th>
108 <th class="col-lastrun sortable" @click="$store.schedulerStore.changeSort('last_run')">
109 Last Run
110 <span class="sort-indicator"
111 x-show="$store.schedulerStore.sortField === 'last_run'"
112 :class="{'desc': $store.schedulerStore.sortDirection === 'desc'}"></span>
113 </th>
114 <th class="col-actions">Actions</th>
115 </tr>
116 </thead>
117 <tbody>
118 <template x-for="task in $store.schedulerStore.paginatedTasks" :key="task.uuid">
119 <tr @click="$store.schedulerStore.showTaskDetail(task.uuid)">
120 <td class="col-name">
121 <span x-text="task.name"></span>
122 </td>
123 <td class="col-state">
124 <span class="scheduler-status-badge"
125 :class="$store.schedulerStore.getStateBadgeClass(task.state)"
126 x-text="task.state"></span>
127 </td>
128 <td class="col-project">
129 <span class="project-color-ball"
130 :style="$store.schedulerStore.extractTaskProject(task)?.color ? { backgroundColor: $store.schedulerStore.extractTaskProject(task).color } : { border: '1px solid var(--color-border)' }"></span>
131 <span x-text="$store.schedulerStore.formatTaskProject(task)"></span>
132 </td>
133 <td class="col-lastrun" x-text="$store.schedulerStore.formatDate(task.last_run)"></td>
134 <td class="col-actions" @click.stop>
135 <div class="actions-wrapper">
136 <button class="btn btn-action"
137 @click="$store.schedulerStore.runTask(task.uuid)" title="Run Task">
138 <x-icon name="play_arrow"></x-icon>
139 </button>
140 <button class="btn btn-action"
141 @click="$store.schedulerStore.resetTaskState(task.uuid)" title="Reset State">
142 <x-icon name="refresh"></x-icon>
143 </button>
144 <button class="btn btn-action"
145 @click="$store.schedulerStore.startEditTask(task.uuid)" title="Edit Task">
146 <x-icon name="edit"></x-icon>
147 </button>
148 <button class="btn btn-action delete"
149 @click="$confirmClick($event, () => $store.schedulerStore.deleteTask(task.uuid))" title="Delete Task">
150 <x-icon name="delete"></x-icon>
151 </button>
152 </div>
153 </td>
154 </tr>
155 </template>
156 </tbody>
157 </table>
158 </div>
159
160 <!-- Bottom Status Bar (for pagination when table is long) -->
161 <div class="data-status-bar data-status-bar-bottom"
162 x-show="!$store.schedulerStore.isLoading && $store.schedulerStore.paginatedTasks.length > 5 && $store.schedulerStore.totalPages > 1">
163 <div class="status-info">
164 <span class="status-item">
165 <x-icon name="schedule"></x-icon>
166 Total: <strong x-text="$store.schedulerStore.tasks.length"></strong>
167 </span>
168 <span class="status-separator"></span>
169 <span class="status-item">
170 Filtered: <strong x-text="$store.schedulerStore.filteredTasks.length"></strong>
171 </span>
172 </div>
173
174 <div class="status-pagination">
175 <button class="btn btn-icon" @click="$store.schedulerStore.prevPage()"
176 :disabled="$store.schedulerStore.currentPage === 1" title="Previous Page">
177 <x-icon name="chevron_left"></x-icon>
178 </button>
179 <div class="page-input-group">
180 <label>Page</label>
181 <input type="number" class="page-input"
182 x-model.number="$store.schedulerStore.currentPage"
183 @change="$store.schedulerStore.goToPage($store.schedulerStore.currentPage)"
184 @keyup.enter="$store.schedulerStore.goToPage($store.schedulerStore.currentPage)"
185 :min="1" :max="$store.schedulerStore.totalPages" />
186 <span class="page-total">of <strong
187 x-text="$store.schedulerStore.totalPages"></strong></span>
188 </div>
189 <button class="btn btn-icon" @click="$store.schedulerStore.nextPage()"
190 :disabled="$store.schedulerStore.currentPage === $store.schedulerStore.totalPages"
191 title="Next Page">
192 <x-icon name="chevron_right"></x-icon>
193 </button>
194 </div>
195 </div>
196 </div>
197 </template>
198 </div>
199
200 <style>
201 /* Scheduler-specific: Container layout */
202 .scheduler-list-container {
203 display: flex;
204 flex-direction: column;
205 gap: 0;
206 }
207
208 /* Scheduler-specific: New task button positioning */
209 .btn-new-task {
210 margin-left: auto;
211 display: inline-flex;
212 align-items: center;
213 gap: 0.5rem;
214 }
215
216 .btn-new-task .material-symbols-outlined {
217 font-size: 20px;
218 }
219
220 /* Scheduler-specific: Filter select min-width */
221 .scheduler-list-container .filter-group-inline select {
222 min-width: 120px;
223 }
224
225 /* Scheduler-specific: Column widths */
226 .scheduler-task-table .col-name { width: 25%; }
227 .scheduler-task-table .col-state { width: 12%; }
228 .scheduler-task-table .col-project { width: 20%; }
229 .scheduler-task-table .col-lastrun { width: 23%; }
230 .scheduler-task-table .col-actions { width: 20%; }
231
232 /* Scheduler-specific: Project color ball */
233 .project-color-ball {
234 display: inline-block;
235 width: 10px;
236 height: 10px;
237 border-radius: 50%;
238 margin-right: 6px;
239 vertical-align: middle;
240 }
241
242 /* Responsive - Scheduler-specific */
243 @media (max-width: 870px) {
244 .btn-new-task {
245 margin-left: 0;
246 justify-content: center;
247 }
248
249 /* Hide less important columns on mobile */
250 .scheduler-task-table .col-project,
251 .scheduler-task-table .col-lastrun {
252 display: none;
253 }
254
255 /* Adjust remaining column widths */
256 .scheduler-task-table .col-name { width: 45%; }
257 .scheduler-task-table .col-state { width: 20%; }
258 .scheduler-task-table .col-actions { width: 35%; }
259 }
260 </style>
261 </body>
262 </html>
263