citrascope 0.8.0__py3-none-any.whl → 0.9.1__py3-none-any.whl

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.
@@ -8,14 +8,17 @@
8
8
  <link rel="icon" type="image/png" href="/static/img/favicon.png">
9
9
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
10
10
  integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
11
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
11
12
  <link href="/static/style.css" rel="stylesheet">
12
13
  </head>
13
14
 
14
- <body data-bs-theme="dark">
15
+ <body data-bs-theme="dark" x-data>
15
16
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
16
17
  integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
17
18
  crossorigin="anonymous"></script>
18
-
19
+ <script type="module" src="/static/store-init.js"></script>
20
+ <script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
21
+ <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script>
19
22
 
20
23
  <div class="container">
21
24
  <header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom align-items-center">
@@ -24,429 +27,46 @@
24
27
  <img src="/static/img/citra.png" alt="CitraScope Logo" class="logo-img" />
25
28
  CitraScope
26
29
  <small class="text-muted" style="font-size: 0.875rem;">
27
- <span id="headerVersion" style="cursor: pointer; user-select: none;" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Click to check for updates">v...</span>
28
- <span id="updateIndicator" class="badge bg-info text-dark ms-1" style="display: none; font-size: 0.7rem;"></span>
30
+ <span style="cursor: pointer; user-select: none;" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Click to check for updates"
31
+ @click="$store.citrascope.showVersionModal()" x-text="$store.citrascope.version || 'v...'"></span>
32
+ <span class="badge bg-info text-dark ms-1" style="font-size: 0.7rem;"
33
+ x-show="$store.citrascope.updateIndicator"
34
+ x-text="$store.citrascope.updateIndicator"
35
+ @click="$store.citrascope.showVersionModal()"></span>
29
36
  </small>
30
37
  </span>
31
38
  </span>
32
39
 
33
40
  <ul class="nav" id="mainNav">
34
- <li class="nav-item"><a href="#" class="nav-link px-2 text-white" data-section="monitoring"
35
- aria-current="page">Monitoring</a></li>
36
- <li class="nav-item"><a href="#" class="nav-link px-2" data-section="config">Config</a></li>
41
+ <li class="nav-item"><a href="#monitoring" class="nav-link px-2" :class="$store.citrascope.currentSection === 'monitoring' ? 'text-white' : ''"
42
+ :aria-current="$store.citrascope.currentSection === 'monitoring' ? 'page' : null"
43
+ data-section="monitoring" @click.prevent="$store.citrascope.currentSection = 'monitoring'; window.location.hash = 'monitoring'">Monitoring</a></li>
44
+ <li class="nav-item"><a href="#config" class="nav-link px-2" :class="$store.citrascope.currentSection === 'config' ? 'text-white' : ''"
45
+ :aria-current="$store.citrascope.currentSection === 'config' ? 'page' : null"
46
+ data-section="config" @click.prevent="$store.citrascope.currentSection = 'config'; window.location.hash = 'config'">Config</a></li>
37
47
  <li class="nav-item"><a href="https://docs.citra.space/citrascope/" class="nav-link px-2" target="_blank">Docs</a></li>
38
- <li class="nav-item"><a href="#" class="nav-link bg-success text-white btn" style="display: none;"
39
- id="taskScopeButton" target="_blank">Task my Scope</a></li>
48
+ <li class="nav-item"><a href="#" class="nav-link bg-success text-white btn"
49
+ id="taskScopeButton" target="_blank"
50
+ x-show="$store.citrascope.status?.ground_station_url"
51
+ :href="$store.citrascope.status?.ground_station_url || '#'">Task my Scope</a></li>
40
52
  </ul>
41
53
  </header>
42
54
 
43
- <!-- Template for connection status badge -->
44
- <template id="connectionStatusTemplate">
45
- <span class="badge rounded-pill connection-status-badge" data-bs-toggle="tooltip" data-bs-placement="bottom">
46
- <span class="status-text"></span>
47
- </span>
48
- </template>
49
55
  </div>
50
56
 
51
- <div id="monitoringSection">
52
- <div class="container">
53
- <div class="row g-3 mb-3">
54
- <div class="col-12 col-md-6">
55
- <div class="card bg-dark text-light border-secondary h-100">
56
- <div class="card-header">
57
- System Status
58
- </div>
59
- <div class="card-body">
60
- <div class="row mb-2">
61
- <div class="col-6 fw-semibold">Daemon</div>
62
- <div class="col-6" id="wsStatus"><span class="badge rounded-pill bg-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Dashboard connection status">Connecting...</span></div>
63
- </div>
64
- <div class="row mb-2">
65
- <div class="col-6 fw-semibold">Telescope</div>
66
- <div class="col-6" id="telescopeConnected"><span class="badge rounded-pill bg-secondary">Unknown</span></div>
67
- </div>
68
- <div class="row mb-2">
69
- <div class="col-6 fw-semibold">Camera</div>
70
- <div class="col-6 d-flex align-items-center gap-2" id="cameraConnected"><span class="badge rounded-pill bg-secondary">Unknown</span></div>
71
- </div>
72
- <div class="row mb-2">
73
- <div class="col-6 fw-semibold">
74
- <span data-bs-toggle="tooltip" data-bs-theme="dark" data-bs-placement="top" title="Controls whether the Citra.space server will automatically assign new observation tasks to this telescope">
75
- Automated Scheduling
76
- </span>
77
- </div>
78
- <div class="col-6 d-flex align-items-center gap-2">
79
- <span id="automatedSchedulingStatus"><span class="badge rounded-pill bg-secondary">Unknown</span></span>
80
- <div class="form-check form-switch">
81
- <input class="form-check-input" type="checkbox" id="toggleAutomatedSchedulingSwitch" title="Toggle automated scheduling">
82
- <label class="form-check-label visually-hidden" for="toggleAutomatedSchedulingSwitch">Automated Scheduling</label>
83
- </div>
84
- </div>
85
- </div>
86
- <div class="row">
87
- <div class="col-6 fw-semibold">
88
- <span data-bs-toggle="tooltip" data-bs-theme="dark" data-bs-placement="top" title="Controls whether this local daemon will execute tasks from its queue. Pause to safely stop observations without canceling scheduled tasks">
89
- Task Processing
90
- </span>
91
- </div>
92
- <div class="col-6 d-flex align-items-center gap-2">
93
- <span id="processingStatus"><span class="badge rounded-pill bg-success">Active</span></span>
94
- <div class="form-check form-switch">
95
- <input class="form-check-input" type="checkbox" id="toggleProcessingSwitch" checked title="Toggle task processing">
96
- <label class="form-check-label visually-hidden" for="toggleProcessingSwitch">Task Processing</label>
97
- </div>
98
- </div>
99
- </div>
100
- <div class="row">
101
- <div class="col-6 fw-semibold">
102
- <span data-bs-toggle="tooltip" data-bs-theme="dark" data-bs-placement="top" title="System clock synchronization status. Accurate time is critical for astronomical observations">
103
- Time Sync
104
- </span>
105
- </div>
106
- <div class="col-6 d-flex align-items-center gap-2">
107
- <span id="timeSyncStatus"><span class="badge rounded-pill bg-secondary">Unknown</span></span>
108
- <small class="text-muted" id="timeOffsetDisplay">-</small>
109
- </div>
110
- </div>
111
- <!-- Missing Dependencies Alert -->
112
- <div id="missingDependenciesAlert" class="alert alert-warning mt-3 mb-0" role="alert" style="display: none;">
113
- <!-- Populated by JavaScript -->
114
- </div>
115
- </div>
116
- </div>
117
- </div>
118
- <div class="col-12 col-md-6">
119
- <div class="card bg-dark text-light border-secondary h-100">
120
- <div class="card-header">
121
- Telescope
122
- </div>
123
- <div class="card-body">
124
- <div class="row mb-2">
125
- <div class="col-6 fw-semibold">Adapter</div>
126
- <div class="col-6" id="hardwareAdapter">-</div>
127
- </div>
128
- <div class="row mb-2">
129
- <div class="col-6 fw-semibold">RA / DEC</div>
130
- <div class="col-6" id="telescopeCoords">-</div>
131
- </div>
132
- <div class="row mb-2">
133
- <div class="col-6 fw-semibold">Enabled Filters</div>
134
- <div class="col-6" id="enabledFilters">-</div>
135
- </div>
136
- <div class="row">
137
- <div class="col-6 fw-semibold">Ground Station</div>
138
- <div class="col-6" id="groundStationName">-</div>
139
- </div>
140
- </div>
141
- </div>
142
- </div>
143
57
 
144
- </div>
145
- </div>
146
- <div class="container">
147
- <div class="row g-3 mb-3">
148
- <div class="col-12">
149
- <div class="card bg-dark text-light border-secondary">
150
- <div class="card-header">
151
- Current Task
152
- </div>
153
- <div class="card-body">
154
- <div id="currentTaskDisplay">
155
- <p class="text-muted-dark">No active task</p>
156
- </div>
157
- </div>
158
- </div>
58
+ {% include '_monitoring.html' %}
159
59
 
160
- <!-- Template for active task display -->
161
- <template id="activeTaskTemplate">
162
- <div class="d-flex align-items-center gap-2 mb-2">
163
- <div class="spinner-border spinner-border-sm text-success" role="status">
164
- <span class="visually-hidden">Loading...</span>
165
- </div>
166
- <div class="fw-bold task-target-name" style="font-size: 1.3em;"></div>
167
- </div>
168
- <div class="text-secondary small">
169
- <span class="task-id-text"></span>
170
- </div>
171
- </template>
172
- </div>
173
- </div>
174
- <div class="row g-3 mb-3">
175
- <div class="col-12">
176
- <div class="card bg-dark text-light border-secondary">
177
- <div class="card-header d-flex align-items-center justify-content-between">
178
- <span>Task Queue</span>
179
- <span class="small text-secondary"><span id="tasksPending">0</span> pending</span>
180
- </div>
181
- <div class="card-body p-0">
182
- <div id="taskList" class="table-responsive">
183
- <p class="p-3 text-muted-dark">Loading tasks...</p>
184
- </div>
185
- </div>
186
- </div>
187
-
188
- <!-- Template for task queue rows -->
189
- <template id="taskRowTemplate">
190
- <tr class="task-row">
191
- <td class="fw-semibold task-target"></td>
192
- <td class="text-secondary small task-start"></td>
193
- <td class="text-secondary small task-end"></td>
194
- <td><span class="badge rounded-pill task-status"></span></td>
195
- </tr>
196
- </template>
197
- </div>
198
- </div>
199
- </div>
200
- </div>
201
-
202
- <div class="container my-4" id="configSection" style="display: none;">
203
- <form id="configForm">
204
- <div class="row g-3 mb-3">
205
- <!-- API Configuration Card -->
206
- <div class="col-12">
207
- <div class="card bg-dark text-light border-secondary">
208
- <div class="card-header">
209
- <h5 class="mb-0">API Configuration</h5>
210
- </div>
211
- <div class="card-body">
212
- <div class="row g-3">
213
- <div class="col-12">
214
- <label for="apiEndpoint" class="form-label">API Endpoint</label>
215
- <select id="apiEndpoint" class="form-select">
216
- <option value="production">Production (api.citra.space)</option>
217
- <option value="development">Development (dev.api.citra.space)</option>
218
- <option value="custom">Custom</option>
219
- </select>
220
- </div>
221
- <div class="col-12" id="customHostContainer" style="display: none;">
222
- <label for="customHost" class="form-label">Custom API Host</label>
223
- <input type="text" id="customHost" class="form-control" placeholder="api.example.com">
224
- <div class="row g-2 mt-2">
225
- <div class="col-6">
226
- <label for="customPort" class="form-label small">Port</label>
227
- <input type="number" id="customPort" class="form-control" value="443" placeholder="443">
228
- </div>
229
- <div class="col-6 d-flex align-items-end">
230
- <div class="form-check">
231
- <input class="form-check-input" type="checkbox" id="customUseSsl" checked>
232
- <label class="form-check-label" for="customUseSsl">
233
- Use SSL
234
- </label>
235
- </div>
236
- </div>
237
- </div>
238
- </div>
239
- <div class="col-12 col-md-6">
240
- <label for="personal_access_token" class="form-label">Personal Access Token <span class="text-danger">*</span></label>
241
- <input type="password" id="personal_access_token" class="form-control" placeholder="Enter your Citra API token" required>
242
- <small class="text-muted">Get your token and telescope ID from <a href="" id="appUrlLink" target="_blank"></a></small>
243
- </div>
244
- <div class="col-12 col-md-6">
245
- <label for="telescopeId" class="form-label">Telescope ID <span class="text-danger">*</span></label>
246
- <input type="text" id="telescopeId" class="form-control" placeholder="Enter telescope ID" required>
247
- </div>
248
- </div>
249
- </div>
250
- </div>
251
- </div>
252
-
253
- <!-- Hardware Configuration Card -->
254
- <div class="col-12">
255
- <div class="card bg-dark text-light border-secondary">
256
- <div class="card-header">
257
- <h5 class="mb-0">Hardware Configuration</h5>
258
- </div>
259
- <div class="card-body">
260
- <div class="row g-3 mb-3">
261
- <div class="col-12">
262
- <label for="hardwareAdapterSelect" class="form-label">Hardware Adapter <span class="text-danger">*</span></label>
263
- <select id="hardwareAdapterSelect" class="form-select" required>
264
- <option value="">-- Select Hardware Adapter --</option>
265
- <!-- Options populated dynamically from API -->
266
- </select>
267
- </div>
268
- </div>
60
+ {% include '_config.html' %}
269
61
 
270
- <!-- Dynamic Adapter Settings Container -->
271
- <div id="adapter-settings-container"></div>
272
-
273
- <!-- Missing Dependencies Alert (Config Page) -->
274
- <div id="configMissingDependenciesAlert" class="alert alert-warning mt-3" role="alert" style="display: none;">
275
- <!-- Populated by JavaScript -->
276
- </div>
277
-
278
- <!-- Filter Configuration Section (shown when adapter supports filters) -->
279
- <div id="filterConfigSection" style="display: none; margin-top: 1.5rem;">
280
- <hr class="border-secondary">
281
- <h5 class="mb-3">Filter Configuration</h5>
282
- <p id="filterAdapterChangeMessage" class="text-muted mb-3" style="display: none;">
283
- Save configuration to edit filter settings for this adapter
284
- </p>
285
- <div class="row">
286
- <!-- Filter List Column -->
287
- <div class="col-12 col-md-6">
288
- <h6 class="mb-2">Filters</h6>
289
- <div id="filterTableContainer">
290
- <table class="table table-dark table-sm">
291
- <thead>
292
- <tr>
293
- <th>Enabled</th>
294
- <th>Name</th>
295
- <th>Focus Position</th>
296
- </tr>
297
- </thead>
298
- <tbody id="filterTableBody">
299
- <!-- Filter rows will be populated by JavaScript -->
300
- </tbody>
301
- </table>
302
- <div id="noFiltersMessage" class="text-muted small" style="display: none;">
303
- No filters configured. Connect to hardware to discover filters.
304
- </div>
305
- </div>
306
- </div>
307
-
308
- <!-- Autofocus Column -->
309
- <div class="col-12 col-md-6">
310
- <h6 class="mb-2">Autofocus</h6>
311
- <div class="mb-3">
312
- <button type="button" class="btn btn-sm btn-outline-primary w-100" id="runAutofocusButton">
313
- <span id="autofocusButtonText">Run Autofocus</span>
314
- <span id="autofocusButtonSpinner" class="spinner-border spinner-border-sm ms-2" style="display: none;" role="status"></span>
315
- </button>
316
- </div>
317
- <div class="mb-3">
318
- <label class="form-label small text-muted">Last Autofocus</label>
319
- <div id="lastAutofocusDisplay" class="text-light">Never</div>
320
- </div>
321
- <div class="mb-3">
322
- <div class="form-check">
323
- <input class="form-check-input" type="checkbox" id="scheduled_autofocus_enabled">
324
- <label class="form-check-label" for="scheduled_autofocus_enabled">
325
- Enable Scheduled Autofocus
326
- </label>
327
- </div>
328
- </div>
329
- <div class="mb-3">
330
- <label for="autofocus_interval_minutes" class="form-label small">Autofocus Interval</label>
331
- <select id="autofocus_interval_minutes" class="form-select form-select-sm">
332
- <option value="30">30 minutes</option>
333
- <option value="60" selected>60 minutes</option>
334
- <option value="120">120 minutes (2 hours)</option>
335
- <option value="180">180 minutes (3 hours)</option>
336
- </select>
337
- </div>
338
- <div id="nextAutofocusDisplay" class="small text-muted" style="display: none;">
339
- Next autofocus in: <span id="nextAutofocusTime">--</span>
340
- </div>
341
- </div>
342
- </div>
343
- </div>
344
- </div>
345
- </div>
346
- </div>
347
-
348
- <!-- Time Synchronization Settings Card -->
349
- <div class="col-12">
350
- <div class="card bg-dark text-light border-secondary">
351
- <div class="card-header">
352
- <h5 class="mb-0">Time Synchronization</h5>
353
- </div>
354
- <div class="card-body">
355
- <div class="row g-3">
356
- <div class="col-12 col-md-6">
357
- <label for="time_offset_pause_ms" class="form-label">Pause Threshold (ms)</label>
358
- <input type="number" class="form-control form-control-sm" id="time_offset_pause_ms" min="1" max="10000" step="1" value="500">
359
- <small class="text-muted">Clock drift that triggers task pause (NTP-based monitoring)</small>
360
- </div>
361
- </div>
362
- </div>
363
- </div>
364
- </div>
365
-
366
- <!-- Logging Settings Card -->
367
- <div class="col-12">
368
- <div class="card bg-dark text-light border-secondary">
369
- <div class="card-header">
370
- <h5 class="mb-0">Logging Settings</h5>
371
- </div>
372
- <div class="card-body">
373
- <div class="row g-3">
374
- <div class="col-12 col-md-6">
375
- <label for="logLevel" class="form-label">Log Level</label>
376
- <select id="logLevel" class="form-select">
377
- <option value="DEBUG">DEBUG</option>
378
- <option value="INFO">INFO</option>
379
- <option value="WARNING">WARNING</option>
380
- <option value="ERROR">ERROR</option>
381
- </select>
382
- </div>
383
- <div class="col-12 col-md-6">
384
- <div class="form-check mt-4">
385
- <input class="form-check-input" type="checkbox" id="file_logging_enabled">
386
- <label class="form-check-label" for="file_logging_enabled">
387
- Enable file logging
388
- </label>
389
- </div>
390
- </div>
391
- <div class="col-12">
392
- <small class="text-muted">
393
- Log file: <span id="logFilePath" class="text-secondary">Loading...</span>
394
- </small>
395
- </div>
396
- </div>
397
- </div>
398
- </div>
399
- </div>
400
-
401
- <!-- Task Settings Card -->
402
- <div class="col-12">
403
- <div class="card bg-dark text-light border-secondary">
404
- <div class="card-header">
405
- <h5 class="mb-0">Task Settings</h5>
406
- </div>
407
- <div class="card-body">
408
- <div class="row g-3">
409
- <div class="col-12 col-md-6">
410
- <div class="form-check mt-2">
411
- <input class="form-check-input" type="checkbox" id="keep_images">
412
- <label class="form-check-label" for="keep_images">
413
- Keep captured images
414
- </label>
415
- </div>
416
- <small class="text-muted ms-4">By default, images are deleted after upload unless this is enabled</small>
417
- </div>
418
- <div class="col-12">
419
- <small class="text-muted">
420
- Images directory: <span id="imagesDirPath" class="text-secondary">Loading...</span>
421
- </small>
422
- </div>
423
- </div>
424
- </div>
425
- </div>
426
- </div>
427
- </div>
428
-
429
- <!-- Save Button -->
430
- <div class="row">
431
- <div class="col">
432
- <button type="submit" class="btn btn-primary" id="saveConfigButton">
433
- <span id="saveButtonText">Save Configuration</span>
434
- <span id="saveButtonSpinner" class="spinner-border spinner-border-sm ms-2" style="display: none;" role="status"></span>
435
- </button>
436
- <small class="text-muted ms-3">
437
- Config file: <span id="configFilePath" class="text-secondary">Loading...</span>
438
- </small>
439
- </div>
440
- </div>
441
- </form>
442
- </div>
443
62
 
444
63
  <!-- Setup Wizard Modal -->
445
- <div class="modal fade" id="setupWizard" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">
64
+ <div class="modal fade" id="setupWizard" tabindex="-1" aria-hidden="true">
446
65
  <div class="modal-dialog modal-lg modal-dialog-centered">
447
66
  <div class="modal-content bg-dark text-light border-secondary">
448
67
  <div class="modal-header border-secondary">
449
68
  <h5 class="modal-title">Welcome to CitraScope Setup</h5>
69
+ <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
450
70
  </div>
451
71
  <div class="modal-body">
452
72
  <p class="lead">Let's configure your telescope system.</p>
@@ -456,12 +76,9 @@
456
76
  <li>Your telescope ID</li>
457
77
  <li>Information about your hardware adapter (INDI, N.I.N.A., or KStars)</li>
458
78
  </ul>
459
- <div class="alert alert-info">
460
- <strong>Note:</strong> The configuration screen is available in the "Config" tab at the top of the page.
461
- </div>
462
79
  </div>
463
80
  <div class="modal-footer border-secondary">
464
- <button type="button" class="btn btn-primary" onclick="showConfigSection()">Configure Now</button>
81
+ <button type="button" class="btn btn-primary" @click="$store.citrascope.showConfigSection()">Configure Now</button>
465
82
  </div>
466
83
  </div>
467
84
  </div>
@@ -475,7 +92,18 @@
475
92
  <button class="accordion-button collapsed bg-secondary text-light log-accordion-button" type="button"
476
93
  data-bs-toggle="collapse" data-bs-target="#logAccordionCollapse" aria-expanded="false"
477
94
  aria-controls="logAccordionCollapse">
478
- <span id="latestLogLine" class="log-latest-line">Log Terminal</span>
95
+ <span class="log-latest-line">
96
+ <template x-if="!$store.citrascope.latestLog">
97
+ <span>Log Terminal</span>
98
+ </template>
99
+ <template x-if="$store.citrascope.latestLog">
100
+ <span>
101
+ <span class="log-timestamp" x-text="new Date($store.citrascope.latestLog.timestamp).toLocaleTimeString()"></span>
102
+ <span class="log-level" :class="'log-level-' + $store.citrascope.latestLog.level" x-text="$store.citrascope.latestLog.level"></span>
103
+ <span x-text="($store.citrascope.stripAnsiCodes($store.citrascope.latestLog.message) || '').substring(0, 150) + (($store.citrascope.latestLog.message || '').length > 150 ? '...' : '')"></span>
104
+ </span>
105
+ </template>
106
+ </span>
479
107
  <div class="accordion-social-links">
480
108
  <a href="https://github.com/citra-space/citrascope/issues/new" target="_blank" class="social-link" title="Report an Issue" onclick="event.stopPropagation();">
481
109
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
@@ -498,29 +126,21 @@
498
126
  <div id="logAccordionCollapse" class="accordion-collapse collapse" aria-labelledby="logAccordionHeader"
499
127
  data-bs-parent="#logAccordion">
500
128
  <div class="accordion-body p-0 log-accordion-body">
501
- <div class="log-container p-3" id="logContainer">
502
- <p class="text-muted-dark">Loading logs...</p>
129
+ <div class="log-container p-3" id="logContainer" x-ref="logContainer">
130
+ <p class="text-muted-dark" x-show="$store.citrascope.logs.length === 0">No logs available</p>
131
+ <template x-for="(log, index) in $store.citrascope.logs" :key="index">
132
+ <div x-data="logEntry(log)" class="log-entry">
133
+ <span class="log-timestamp" x-text="timestamp"></span>
134
+ <span class="log-level" :class="levelClass" x-text="log.level"></span>
135
+ <span class="log-message" x-text="strippedMessage"></span>
136
+ </div>
137
+ </template>
503
138
  </div>
504
139
  </div>
505
140
  </div>
506
141
  </div>
507
142
  </div>
508
143
 
509
- <!-- Templates for log display -->
510
- <template id="logEntryTemplate">
511
- <div class="log-entry">
512
- <span class="log-timestamp"></span>
513
- <span class="log-level"></span>
514
- <span class="log-message"></span>
515
- </div>
516
- </template>
517
-
518
- <template id="latestLogLineTemplate">
519
- <span class="log-timestamp"></span>
520
- <span class="log-level"></span>
521
- <span class="log-message"></span>
522
- </template>
523
-
524
144
  </div>
525
145
 
526
146
 
@@ -533,34 +153,34 @@
533
153
  <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
534
154
  </div>
535
155
  <div class="modal-body">
536
- <div id="versionCheckLoading" style="text-align: center;">
156
+ <div x-show="$store.citrascope.versionCheckState === 'loading'" style="text-align: center;">
537
157
  <div class="spinner-border text-primary" role="status">
538
158
  <span class="visually-hidden">Checking...</span>
539
159
  </div>
540
160
  <p class="mt-2">Checking for updates...</p>
541
161
  </div>
542
- <div id="versionCheckUpToDate" style="display: none;">
162
+ <div x-show="$store.citrascope.versionCheckState === 'up-to-date'">
543
163
  <p class="text-success">✓ You're up to date!</p>
544
164
  <p>
545
- <strong>Current version:</strong> <span id="modalCurrentVersionUpToDate">-</span>
165
+ <strong>Current version:</strong> <span x-text="$store.citrascope.versionCheckResult?.currentVersion === 'development' ? 'development' : 'v' + ($store.citrascope.versionCheckResult?.currentVersion || '-')"></span>
546
166
  </p>
547
167
  </div>
548
- <div id="versionCheckUpdateAvailable" style="display: none;">
168
+ <div x-show="$store.citrascope.versionCheckState === 'update-available'">
549
169
  <p class="text-warning">A new version of CitraScope is available!</p>
550
170
  <p class="mb-3">
551
- <strong>Current:</strong> <span id="modalCurrentVersion">-</span><br>
552
- <strong>Latest:</strong> <span id="modalLatestVersion">-</span>
171
+ <strong>Current:</strong> <span x-text="'v' + ($store.citrascope.versionCheckResult?.currentVersion || '-')"></span><br>
172
+ <strong>Latest:</strong> <span x-text="$store.citrascope.versionCheckResult?.latestVersion || '-'"></span>
553
173
  </p>
554
174
  <p class="mb-2">To upgrade, run:</p>
555
175
  <pre class="bg-secondary p-2 rounded"><code>pip install -U citrascope</code></pre>
556
176
  <p class="mb-0">
557
- <a href="#" id="releaseNotesLink" target="_blank" class="text-info">View release notes on GitHub →</a>
177
+ <a :href="$store.citrascope.versionCheckResult?.releaseUrl || '#'" target="_blank" class="text-info">View release notes on GitHub →</a>
558
178
  </p>
559
179
  </div>
560
- <div id="versionCheckError" style="display: none;">
180
+ <div x-show="$store.citrascope.versionCheckState === 'error'">
561
181
  <p class="text-muted">Unable to check for updates. You may be offline or GitHub is unreachable.</p>
562
182
  <p>
563
- <strong>Current version:</strong> <span id="modalCurrentVersionError">-</span>
183
+ <strong>Current version:</strong> <span x-text="$store.citrascope.versionCheckResult?.currentVersion === 'development' ? 'development' : ($store.citrascope.versionCheckResult?.currentVersion || '-')"></span>
564
184
  </p>
565
185
  </div>
566
186
  </div>
@@ -583,18 +203,26 @@
583
203
  <div class="row g-3">
584
204
  <div class="col-12">
585
205
  <label for="exposureDuration" class="form-label">Exposure Duration (seconds)</label>
586
- <input type="number" id="exposureDuration" class="form-control" value="0.1" min="0.001" max="300" step="0.001">
206
+ <input type="number" class="form-control" x-model.number="$store.citrascope.exposureDuration" min="0.001" max="300" step="0.001">
587
207
  <small class="text-muted">Range: 0.001 to 300 seconds</small>
588
208
  </div>
589
209
  </div>
590
210
 
591
211
  <!-- Capture Result Area -->
592
- <div id="captureResult" class="mt-3" style="display: none;">
212
+ <div x-show="$store.citrascope.captureResult" class="mt-3">
593
213
  <hr class="border-secondary">
594
214
  <h6>Latest Capture</h6>
595
215
  <div class="alert alert-success mb-2">
596
- <strong>Filename:</strong> <span id="captureFilename"></span><br>
597
- <strong>Format:</strong> <span id="captureFormat"></span>
216
+ <strong>Filename:</strong> <span x-text="$store.citrascope.captureResult?.filename"></span><br>
217
+ <strong>Format:</strong> <span x-text="$store.citrascope.captureResult?.format || 'Unknown'"></span>
218
+ </div>
219
+
220
+ <!-- Image Preview (only for PNG/JPG) -->
221
+ <div x-show="$store.citrascope.captureResult && ['PNG', 'JPG', 'JPEG'].includes($store.citrascope.captureResult.format)" class="mt-3">
222
+ <img :src="'/images/' + $store.citrascope.captureResult?.filename"
223
+ alt="Captured image"
224
+ class="img-fluid rounded border border-secondary"
225
+ style="max-height: 400px; width: auto; display: block; margin: 0 auto;">
598
226
  </div>
599
227
  </div>
600
228
 
@@ -603,14 +231,14 @@
603
231
  <hr class="border-secondary">
604
232
  <h6>Images Directory</h6>
605
233
  <p class="text-muted small mb-1">All captured images are saved to:</p>
606
- <p><a href="#" id="imagesDirLink" class="text-break"></a></p>
234
+ <p><a :href="'file://' + ($store.citrascope.config?.images_dir_path || '#')" x-text="$store.citrascope.config?.images_dir_path || 'Not set'" class="text-break"></a></p>
607
235
  </div>
608
236
  </div>
609
237
  <div class="modal-footer border-secondary">
610
238
  <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
611
- <button type="button" class="btn btn-primary" id="captureButton" onclick="captureImage()">
612
- <span id="captureButtonText">Capture</span>
613
- <span id="captureButtonSpinner" class="spinner-border spinner-border-sm ms-2" role="status" style="display: none;">
239
+ <button type="button" class="btn btn-primary" :disabled="$store.citrascope.isCapturing" @click="$store.citrascope.captureImage()">
240
+ <span x-text="$store.citrascope.isCapturing ? 'Capturing...' : 'Capture'"></span>
241
+ <span x-show="$store.citrascope.isCapturing" class="spinner-border spinner-border-sm ms-2" role="status">
614
242
  <span class="visually-hidden">Capturing...</span>
615
243
  </span>
616
244
  </button>