citrascope 0.1.0__py3-none-any.whl → 0.4.0__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.
- citrascope/__main__.py +13 -13
- citrascope/api/abstract_api_client.py +7 -0
- citrascope/api/citra_api_client.py +43 -2
- citrascope/citra_scope_daemon.py +205 -61
- citrascope/constants.py +23 -0
- citrascope/hardware/abstract_astro_hardware_adapter.py +70 -2
- citrascope/hardware/adapter_registry.py +94 -0
- citrascope/hardware/indi_adapter.py +456 -16
- citrascope/hardware/kstars_dbus_adapter.py +179 -0
- citrascope/hardware/nina_adv_http_adapter.py +593 -0
- citrascope/hardware/nina_adv_http_survey_template.json +328 -0
- citrascope/logging/__init__.py +2 -1
- citrascope/logging/_citrascope_logger.py +80 -1
- citrascope/logging/web_log_handler.py +75 -0
- citrascope/settings/citrascope_settings.py +140 -0
- citrascope/settings/settings_file_manager.py +126 -0
- citrascope/tasks/runner.py +129 -29
- citrascope/tasks/scope/base_telescope_task.py +25 -10
- citrascope/tasks/scope/static_telescope_task.py +11 -3
- citrascope/web/__init__.py +1 -0
- citrascope/web/app.py +479 -0
- citrascope/web/server.py +132 -0
- citrascope/web/static/api.js +82 -0
- citrascope/web/static/app.js +502 -0
- citrascope/web/static/config.js +438 -0
- citrascope/web/static/img/citra.png +0 -0
- citrascope/web/static/img/favicon.png +0 -0
- citrascope/web/static/style.css +152 -0
- citrascope/web/static/websocket.js +127 -0
- citrascope/web/templates/dashboard.html +407 -0
- {citrascope-0.1.0.dist-info → citrascope-0.4.0.dist-info}/METADATA +87 -47
- citrascope-0.4.0.dist-info/RECORD +38 -0
- {citrascope-0.1.0.dist-info → citrascope-0.4.0.dist-info}/WHEEL +1 -1
- citrascope/settings/_citrascope_settings.py +0 -42
- citrascope-0.1.0.dist-info/RECORD +0 -21
- docs/index.md +0 -47
- {citrascope-0.1.0.dist-info → citrascope-0.4.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// WebSocket connection management for CitraScope
|
|
2
|
+
|
|
3
|
+
let ws = null;
|
|
4
|
+
let reconnectAttempts = 0;
|
|
5
|
+
let reconnectTimer = null;
|
|
6
|
+
let connectionTimer = null;
|
|
7
|
+
const reconnectDelay = 5000; // Fixed 5 second delay between reconnect attempts
|
|
8
|
+
const connectionTimeout = 5000; // 5 second timeout for connection attempts
|
|
9
|
+
|
|
10
|
+
// Callbacks for handling messages
|
|
11
|
+
let onStatusUpdate = null;
|
|
12
|
+
let onLogMessage = null;
|
|
13
|
+
let onTasksUpdate = null;
|
|
14
|
+
let onConnectionChange = null;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize WebSocket connection
|
|
18
|
+
* @param {object} handlers - Event handlers {onStatus, onLog, onTasks, onConnectionChange}
|
|
19
|
+
*/
|
|
20
|
+
export function connectWebSocket(handlers = {}) {
|
|
21
|
+
onStatusUpdate = handlers.onStatus || null;
|
|
22
|
+
onLogMessage = handlers.onLog || null;
|
|
23
|
+
onTasksUpdate = handlers.onTasks || null;
|
|
24
|
+
onConnectionChange = handlers.onConnectionChange || null;
|
|
25
|
+
|
|
26
|
+
connect();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function connect() {
|
|
30
|
+
// Clear any existing reconnect timer
|
|
31
|
+
if (reconnectTimer) {
|
|
32
|
+
clearTimeout(reconnectTimer);
|
|
33
|
+
reconnectTimer = null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Clear any existing connection timeout
|
|
37
|
+
if (connectionTimer) {
|
|
38
|
+
clearTimeout(connectionTimer);
|
|
39
|
+
connectionTimer = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
43
|
+
const wsUrl = `${protocol}//${window.location.host}/ws`;
|
|
44
|
+
|
|
45
|
+
console.log('Attempting WebSocket connection to:', wsUrl);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
// Close existing connection if any
|
|
49
|
+
if (ws && ws.readyState !== WebSocket.CLOSED) {
|
|
50
|
+
ws.close();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ws = new WebSocket(wsUrl);
|
|
54
|
+
|
|
55
|
+
// Set a timeout for connection attempt
|
|
56
|
+
connectionTimer = setTimeout(() => {
|
|
57
|
+
console.log('WebSocket connection timeout');
|
|
58
|
+
if (ws && ws.readyState !== WebSocket.OPEN) {
|
|
59
|
+
ws.close();
|
|
60
|
+
scheduleReconnect();
|
|
61
|
+
}
|
|
62
|
+
}, connectionTimeout);
|
|
63
|
+
|
|
64
|
+
ws.onopen = () => {
|
|
65
|
+
console.log('WebSocket connected successfully');
|
|
66
|
+
if (connectionTimer) {
|
|
67
|
+
clearTimeout(connectionTimer);
|
|
68
|
+
connectionTimer = null;
|
|
69
|
+
}
|
|
70
|
+
reconnectAttempts = 0;
|
|
71
|
+
notifyConnectionChange(true);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
ws.onmessage = (event) => {
|
|
75
|
+
const message = JSON.parse(event.data);
|
|
76
|
+
if (message.type === 'status' && onStatusUpdate) {
|
|
77
|
+
onStatusUpdate(message.data);
|
|
78
|
+
} else if (message.type === 'log' && onLogMessage) {
|
|
79
|
+
onLogMessage(message.data);
|
|
80
|
+
} else if (message.type === 'tasks' && onTasksUpdate) {
|
|
81
|
+
onTasksUpdate(message.data);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
ws.onclose = (event) => {
|
|
86
|
+
console.log('WebSocket closed', event.code, event.reason);
|
|
87
|
+
if (connectionTimer) {
|
|
88
|
+
clearTimeout(connectionTimer);
|
|
89
|
+
connectionTimer = null;
|
|
90
|
+
}
|
|
91
|
+
ws = null;
|
|
92
|
+
scheduleReconnect();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
ws.onerror = (error) => {
|
|
96
|
+
console.error('WebSocket error:', error);
|
|
97
|
+
console.log('WebSocket readyState:', ws?.readyState);
|
|
98
|
+
// Close will be called automatically after error
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('Failed to create WebSocket:', error);
|
|
102
|
+
if (connectionTimer) {
|
|
103
|
+
clearTimeout(connectionTimer);
|
|
104
|
+
connectionTimer = null;
|
|
105
|
+
}
|
|
106
|
+
ws = null;
|
|
107
|
+
scheduleReconnect();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function scheduleReconnect() {
|
|
112
|
+
// Fixed 5 second delay between reconnect attempts
|
|
113
|
+
const delay = reconnectDelay;
|
|
114
|
+
|
|
115
|
+
notifyConnectionChange(false, 'reconnecting');
|
|
116
|
+
|
|
117
|
+
console.log(`Scheduling reconnect in ${delay/1000}s... (attempt ${reconnectAttempts + 1})`);
|
|
118
|
+
|
|
119
|
+
reconnectAttempts++;
|
|
120
|
+
reconnectTimer = setTimeout(connect, delay);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function notifyConnectionChange(connected, reconnectInfo = '') {
|
|
124
|
+
if (onConnectionChange) {
|
|
125
|
+
onConnectionChange(connected, reconnectInfo);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>CitraScope Dashboard</title>
|
|
8
|
+
<link rel="icon" type="image/png" href="/static/img/favicon.png">
|
|
9
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
10
|
+
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
|
11
|
+
<link href="/static/style.css" rel="stylesheet">
|
|
12
|
+
</head>
|
|
13
|
+
|
|
14
|
+
<body data-bs-theme="dark">
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
|
16
|
+
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
|
|
17
|
+
crossorigin="anonymous"></script>
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
<div class="container">
|
|
21
|
+
<header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom align-items-center">
|
|
22
|
+
<span class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-body-emphasis text-decoration-none">
|
|
23
|
+
<span class="fs-4 d-flex align-items-center gap-2">
|
|
24
|
+
<img src="/static/img/citra.png" alt="CitraScope Logo" class="logo-img" />
|
|
25
|
+
CitraScope
|
|
26
|
+
|
|
27
|
+
</span>
|
|
28
|
+
<span class="ms-2 me-3 d-flex align-items-center status-badge-container">
|
|
29
|
+
<span id="wsStatus"><span class="badge rounded-pill bg-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Dashboard connection status">Connecting...</span></span>
|
|
30
|
+
</span>
|
|
31
|
+
</span>
|
|
32
|
+
|
|
33
|
+
<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>
|
|
37
|
+
<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>
|
|
40
|
+
</ul>
|
|
41
|
+
</header>
|
|
42
|
+
|
|
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
|
+
</div>
|
|
50
|
+
|
|
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">Hardware</div>
|
|
62
|
+
<div class="col-6" id="hardwareAdapter">-</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" id="cameraConnected"><span class="badge rounded-pill bg-secondary">Unknown</span></div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="col-12 col-md-6">
|
|
76
|
+
<div class="card bg-dark text-light border-secondary h-100">
|
|
77
|
+
<div class="card-header">
|
|
78
|
+
Telescope
|
|
79
|
+
</div>
|
|
80
|
+
<div class="card-body">
|
|
81
|
+
<div class="row mb-2">
|
|
82
|
+
<div class="col-6 fw-semibold">Right Ascension</div>
|
|
83
|
+
<div class="col-6" id="telescopeRA">-</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="row mb-2">
|
|
86
|
+
<div class="col-6 fw-semibold">Declination</div>
|
|
87
|
+
<div class="col-6" id="telescopeDEC">-</div>
|
|
88
|
+
</div>
|
|
89
|
+
<div class="row">
|
|
90
|
+
<div class="col-6 fw-semibold">Ground Station</div>
|
|
91
|
+
<div class="col-6" id="groundStationName">-</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="container">
|
|
100
|
+
<div class="row g-3 mb-3">
|
|
101
|
+
<div class="col-12">
|
|
102
|
+
<div class="card bg-dark text-light border-secondary">
|
|
103
|
+
<div class="card-header">
|
|
104
|
+
Current Task
|
|
105
|
+
</div>
|
|
106
|
+
<div class="card-body">
|
|
107
|
+
<div id="currentTaskDisplay">
|
|
108
|
+
<p class="text-muted-dark">No active task</p>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- Template for active task display -->
|
|
114
|
+
<template id="activeTaskTemplate">
|
|
115
|
+
<div class="d-flex align-items-center gap-2 mb-2">
|
|
116
|
+
<div class="spinner-border spinner-border-sm text-success" role="status">
|
|
117
|
+
<span class="visually-hidden">Loading...</span>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="fw-bold task-target-name" style="font-size: 1.3em;"></div>
|
|
120
|
+
</div>
|
|
121
|
+
<div class="text-secondary small">
|
|
122
|
+
<span class="task-id-text"></span>
|
|
123
|
+
</div>
|
|
124
|
+
</template>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="row g-3 mb-3">
|
|
128
|
+
<div class="col-12">
|
|
129
|
+
<div class="card bg-dark text-light border-secondary">
|
|
130
|
+
<div class="card-header d-flex align-items-center justify-content-between">
|
|
131
|
+
<span>Task Queue</span>
|
|
132
|
+
<span class="small text-secondary"><span id="tasksPending">0</span> pending</span>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="card-body p-0">
|
|
135
|
+
<div id="taskList" class="table-responsive">
|
|
136
|
+
<p class="p-3 text-muted-dark">Loading tasks...</p>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- Template for task queue rows -->
|
|
142
|
+
<template id="taskRowTemplate">
|
|
143
|
+
<tr class="task-row">
|
|
144
|
+
<td class="fw-semibold task-target"></td>
|
|
145
|
+
<td class="text-secondary small task-start"></td>
|
|
146
|
+
<td class="text-secondary small task-end"></td>
|
|
147
|
+
<td><span class="badge rounded-pill task-status"></span></td>
|
|
148
|
+
</tr>
|
|
149
|
+
</template>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div class="container my-4" id="configSection" style="display: none;">
|
|
156
|
+
<div id="configError" class="alert alert-danger" style="display: none;" role="alert"></div>
|
|
157
|
+
<div id="configSuccess" class="alert alert-success" style="display: none;" role="alert"></div>
|
|
158
|
+
|
|
159
|
+
<form id="configForm">
|
|
160
|
+
<div class="row g-3 mb-3">
|
|
161
|
+
<!-- API Configuration Card -->
|
|
162
|
+
<div class="col-12">
|
|
163
|
+
<div class="card bg-dark text-light border-secondary">
|
|
164
|
+
<div class="card-header">
|
|
165
|
+
<h5 class="mb-0">API Configuration</h5>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="card-body">
|
|
168
|
+
<div class="row g-3">
|
|
169
|
+
<div class="col-12">
|
|
170
|
+
<label for="apiEndpoint" class="form-label">API Endpoint</label>
|
|
171
|
+
<select id="apiEndpoint" class="form-select">
|
|
172
|
+
<option value="production">Production (api.citra.space)</option>
|
|
173
|
+
<option value="development">Development (dev.api.citra.space)</option>
|
|
174
|
+
<option value="custom">Custom</option>
|
|
175
|
+
</select>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="col-12" id="customHostContainer" style="display: none;">
|
|
178
|
+
<label for="customHost" class="form-label">Custom API Host</label>
|
|
179
|
+
<input type="text" id="customHost" class="form-control" placeholder="api.example.com">
|
|
180
|
+
<div class="row g-2 mt-2">
|
|
181
|
+
<div class="col-6">
|
|
182
|
+
<label for="customPort" class="form-label small">Port</label>
|
|
183
|
+
<input type="number" id="customPort" class="form-control" value="443" placeholder="443">
|
|
184
|
+
</div>
|
|
185
|
+
<div class="col-6 d-flex align-items-end">
|
|
186
|
+
<div class="form-check">
|
|
187
|
+
<input class="form-check-input" type="checkbox" id="customUseSsl" checked>
|
|
188
|
+
<label class="form-check-label" for="customUseSsl">
|
|
189
|
+
Use SSL
|
|
190
|
+
</label>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
<div class="col-12 col-md-6">
|
|
196
|
+
<label for="personal_access_token" class="form-label">Personal Access Token <span class="text-danger">*</span></label>
|
|
197
|
+
<input type="password" id="personal_access_token" class="form-control" placeholder="Enter your Citra API token" required>
|
|
198
|
+
<small class="text-muted">Get your token and telescope ID from <a href="" id="appUrlLink" target="_blank"></a></small>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="col-12 col-md-6">
|
|
201
|
+
<label for="telescopeId" class="form-label">Telescope ID <span class="text-danger">*</span></label>
|
|
202
|
+
<input type="text" id="telescopeId" class="form-control" placeholder="Enter telescope ID" required>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<!-- Hardware Configuration Card -->
|
|
210
|
+
<div class="col-12">
|
|
211
|
+
<div class="card bg-dark text-light border-secondary">
|
|
212
|
+
<div class="card-header">
|
|
213
|
+
<h5 class="mb-0">Hardware Configuration</h5>
|
|
214
|
+
</div>
|
|
215
|
+
<div class="card-body">
|
|
216
|
+
<div class="row g-3 mb-3">
|
|
217
|
+
<div class="col-12">
|
|
218
|
+
<label for="hardwareAdapterSelect" class="form-label">Hardware Adapter <span class="text-danger">*</span></label>
|
|
219
|
+
<select id="hardwareAdapterSelect" class="form-select" required>
|
|
220
|
+
<option value="">-- Select Hardware Adapter --</option>
|
|
221
|
+
<!-- Options populated dynamically from API -->
|
|
222
|
+
</select>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<!-- Dynamic Adapter Settings Container -->
|
|
227
|
+
<div id="adapter-settings-container"></div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<!-- Logging Settings Card -->
|
|
233
|
+
<div class="col-12">
|
|
234
|
+
<div class="card bg-dark text-light border-secondary">
|
|
235
|
+
<div class="card-header">
|
|
236
|
+
<h5 class="mb-0">Logging Settings</h5>
|
|
237
|
+
</div>
|
|
238
|
+
<div class="card-body">
|
|
239
|
+
<div class="row g-3">
|
|
240
|
+
<div class="col-12 col-md-6">
|
|
241
|
+
<label for="logLevel" class="form-label">Log Level</label>
|
|
242
|
+
<select id="logLevel" class="form-select">
|
|
243
|
+
<option value="DEBUG">DEBUG</option>
|
|
244
|
+
<option value="INFO">INFO</option>
|
|
245
|
+
<option value="WARNING">WARNING</option>
|
|
246
|
+
<option value="ERROR">ERROR</option>
|
|
247
|
+
</select>
|
|
248
|
+
</div>
|
|
249
|
+
<div class="col-12 col-md-6">
|
|
250
|
+
<div class="form-check mt-4">
|
|
251
|
+
<input class="form-check-input" type="checkbox" id="file_logging_enabled">
|
|
252
|
+
<label class="form-check-label" for="file_logging_enabled">
|
|
253
|
+
Enable file logging
|
|
254
|
+
</label>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
<div class="col-12">
|
|
258
|
+
<small class="text-muted">
|
|
259
|
+
Log file: <span id="logFilePath" class="text-secondary">Loading...</span>
|
|
260
|
+
</small>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<!-- Task Settings Card -->
|
|
268
|
+
<div class="col-12">
|
|
269
|
+
<div class="card bg-dark text-light border-secondary">
|
|
270
|
+
<div class="card-header">
|
|
271
|
+
<h5 class="mb-0">Task Settings</h5>
|
|
272
|
+
</div>
|
|
273
|
+
<div class="card-body">
|
|
274
|
+
<div class="row g-3">
|
|
275
|
+
<div class="col-12 col-md-6">
|
|
276
|
+
<div class="form-check mt-2">
|
|
277
|
+
<input class="form-check-input" type="checkbox" id="keep_images">
|
|
278
|
+
<label class="form-check-label" for="keep_images">
|
|
279
|
+
Keep captured images
|
|
280
|
+
</label>
|
|
281
|
+
</div>
|
|
282
|
+
<small class="text-muted ms-4">By default, images are deleted after upload unless this is enabled</small>
|
|
283
|
+
</div>
|
|
284
|
+
<div class="col-12">
|
|
285
|
+
<small class="text-muted">
|
|
286
|
+
Images directory: <span id="imagesDirPath" class="text-secondary">Loading...</span>
|
|
287
|
+
</small>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<!-- Save Button -->
|
|
296
|
+
<div class="row">
|
|
297
|
+
<div class="col">
|
|
298
|
+
<button type="submit" class="btn btn-primary" id="saveConfigButton">
|
|
299
|
+
<span id="saveButtonText">Save Configuration</span>
|
|
300
|
+
<span id="saveButtonSpinner" class="spinner-border spinner-border-sm ms-2" style="display: none;" role="status"></span>
|
|
301
|
+
</button>
|
|
302
|
+
<small class="text-muted ms-3">
|
|
303
|
+
Config file: <span id="configFilePath" class="text-secondary">Loading...</span>
|
|
304
|
+
</small>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
|
|
308
|
+
<!-- Version Info -->
|
|
309
|
+
<div class="row mt-3">
|
|
310
|
+
<div class="col">
|
|
311
|
+
<small class="text-muted">
|
|
312
|
+
CitraScope Version: <span id="citraScopeVersion" class="text-secondary">Loading...</span>
|
|
313
|
+
</small>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
</form>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<!-- Setup Wizard Modal -->
|
|
320
|
+
<div class="modal fade" id="setupWizard" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">
|
|
321
|
+
<div class="modal-dialog modal-lg modal-dialog-centered">
|
|
322
|
+
<div class="modal-content bg-dark text-light border-secondary">
|
|
323
|
+
<div class="modal-header border-secondary">
|
|
324
|
+
<h5 class="modal-title">Welcome to CitraScope Setup</h5>
|
|
325
|
+
</div>
|
|
326
|
+
<div class="modal-body">
|
|
327
|
+
<p class="lead">Let's configure your telescope system.</p>
|
|
328
|
+
<p>You'll need:</p>
|
|
329
|
+
<ul>
|
|
330
|
+
<li>Your Citra API personal access token from <a href="" id="setupAppUrlLink" target="_blank"></a></li>
|
|
331
|
+
<li>Your telescope ID</li>
|
|
332
|
+
<li>Information about your hardware adapter (INDI, N.I.N.A., or KStars)</li>
|
|
333
|
+
</ul>
|
|
334
|
+
<div class="alert alert-info">
|
|
335
|
+
<strong>Note:</strong> The configuration screen is available in the "Config" tab at the top of the page.
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
<div class="modal-footer border-secondary">
|
|
339
|
+
<button type="button" class="btn btn-primary" onclick="showConfigSection()">Configure Now</button>
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
</div>
|
|
343
|
+
</div>
|
|
344
|
+
|
|
345
|
+
<!-- Roll-up Terminal Overlay as Bootstrap Accordion -->
|
|
346
|
+
<div class="position-fixed bottom-0 start-0 w-100 z-3" style="max-width: 100vw;">
|
|
347
|
+
<div class="accordion" id="logAccordion">
|
|
348
|
+
<div class="accordion-item bg-dark text-light border-secondary">
|
|
349
|
+
<h2 class="accordion-header" id="logAccordionHeader">
|
|
350
|
+
<button class="accordion-button collapsed bg-secondary text-light log-accordion-button" type="button"
|
|
351
|
+
data-bs-toggle="collapse" data-bs-target="#logAccordionCollapse" aria-expanded="false"
|
|
352
|
+
aria-controls="logAccordionCollapse">
|
|
353
|
+
<span id="latestLogLine" class="log-latest-line">Log Terminal</span>
|
|
354
|
+
<div class="accordion-social-links">
|
|
355
|
+
<a href="https://github.com/citra-space/citrascope/issues/new" target="_blank" class="social-link" title="Report an Issue" onclick="event.stopPropagation();">
|
|
356
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
|
|
357
|
+
<path d="M16 8c0 3.866-3.582 7-8 7a9 9 0 0 1-2.347-.306c-.584.296-1.925.864-4.181 1.234-.2.032-.352-.176-.273-.362.354-.836.674-1.95.77-2.966C.744 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7M5 8a1 1 0 1 0-2 0 1 1 0 0 0 2 0m4 0a1 1 0 1 0-2 0 1 1 0 0 0 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/>
|
|
358
|
+
</svg>
|
|
359
|
+
</a>
|
|
360
|
+
<a href="https://discord.gg/STgJQkWe9y" target="_blank" class="social-link" title="Join Discord" onclick="event.stopPropagation();">
|
|
361
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
|
|
362
|
+
<path d="M13.545 2.907a13.227 13.227 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 0 0-3.658 0 8.258 8.258 0 0 0-.412-.833.051.051 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019c.308-.42.582-.863.818-1.329a.05.05 0 0 0-.01-.059.051.051 0 0 0-.018-.011 8.875 8.875 0 0 1-1.248-.595.05.05 0 0 1-.02-.066.051.051 0 0 1 .015-.019c.084-.063.168-.129.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 0 1 .053.007c.08.066.164.132.248.195a.051.051 0 0 1-.004.085 8.254 8.254 0 0 1-1.249.594.05.05 0 0 0-.03.03.052.052 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.235 13.235 0 0 0 4.001-2.02.049.049 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 0 0-.02-.019Zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612Zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612Z"/>
|
|
363
|
+
</svg>
|
|
364
|
+
</a>
|
|
365
|
+
<a href="https://github.com/citra-space/citrascope" target="_blank" class="social-link" title="View on GitHub" onclick="event.stopPropagation();">
|
|
366
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
|
|
367
|
+
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
|
|
368
|
+
</svg>
|
|
369
|
+
</a>
|
|
370
|
+
</div>
|
|
371
|
+
</button>
|
|
372
|
+
</h2>
|
|
373
|
+
<div id="logAccordionCollapse" class="accordion-collapse collapse" aria-labelledby="logAccordionHeader"
|
|
374
|
+
data-bs-parent="#logAccordion">
|
|
375
|
+
<div class="accordion-body p-0 log-accordion-body">
|
|
376
|
+
<div class="log-container p-3" id="logContainer">
|
|
377
|
+
<p class="text-muted-dark">Loading logs...</p>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
|
|
384
|
+
<!-- Templates for log display -->
|
|
385
|
+
<template id="logEntryTemplate">
|
|
386
|
+
<div class="log-entry">
|
|
387
|
+
<span class="log-timestamp"></span>
|
|
388
|
+
<span class="log-level"></span>
|
|
389
|
+
<span class="log-message"></span>
|
|
390
|
+
</div>
|
|
391
|
+
</template>
|
|
392
|
+
|
|
393
|
+
<template id="latestLogLineTemplate">
|
|
394
|
+
<span class="log-timestamp"></span>
|
|
395
|
+
<span class="log-level"></span>
|
|
396
|
+
<span class="log-message"></span>
|
|
397
|
+
</template>
|
|
398
|
+
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
<script type="module" src="/static/app.js"></script>
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
</body>
|
|
406
|
+
|
|
407
|
+
</html>
|