@@ -3,6 +3,7 @@ package app
3
3
import (
4
4
"bytes"
5
5
"context"
6
+ "embed"
6
7
"errors"
7
8
"fmt"
8
9
"html/template"
@@ -18,6 +19,10 @@ import (
18
19
"github.com/sirupsen/logrus"
19
20
)
20
21
22
+ // Embed the file content as string.
23
+ //go:embed static
24
+ var staticFiles embed.FS
25
+
21
26
// HTTP allows interaction with the zackup webserver.
22
27
type HTTP interface {
23
28
// Start will start the HTTP server.
@@ -198,7 +203,7 @@ func tplPercentUsage(m HostMetrics, val uint64) float64 {
198
203
return math .Floor (r * 100 ) / 100
199
204
}
200
205
201
- var tpl = template .Must (template .New ("index" ).Funcs (template.FuncMap {
206
+ var tpl = template .Must (template .New ("index.html " ).Funcs (template.FuncMap {
202
207
"fmtTime" : tplFmtTime ,
203
208
"fmtDuration" : tplFmtDuration ,
204
209
"statusClass" : tplStatusClass ,
@@ -207,126 +212,4 @@ var tpl = template.Must(template.New("index").Funcs(template.FuncMap{
207
212
"humanBytes" : tplHumanBytes ,
208
213
"usageDetails" : tplUsageDetails ,
209
214
"percentUsage" : tplPercentUsage ,
210
- }).Parse (`<!doctype html>
211
- <html>
212
- <head>
213
- <meta charset="UTF-8">
214
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
215
- <title>zackup overview</title>
216
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected] /dist/css/bootstrap.min.css"
217
- integrity="sha256-YLGeXaapI0/5IgZopewRJcFXomhRMlYYjugPLSyNjTY=" crossorigin="anonymous">
218
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected] /css/all.min.css"
219
- integrity="sha256-7rF6RaSKyh16288E3hVdzQtHyzatA2MQRGu0cf6pqqM=" crossorigin="anonymous">
220
- <script>
221
- function toggleTimes() {
222
- const times = document.querySelectorAll("tbody time")
223
- for (let i = 0, len = times.length; i < len; ++i) {
224
- const el = times[i]
225
- if (!el.dataset.text) {
226
- el.dataset.text = el.innerText
227
- }
228
- if (el.innerText === el.dataset.text) {
229
- el.innerText = el.getAttribute("title")
230
- } else {
231
- el.innerText = el.dataset.text
232
- }
233
- }
234
- }
235
-
236
- document.addEventListener("DOMContentLoaded", () => {
237
- const btn = document.querySelector("button.js-toggle-times")
238
- if (btn) {
239
- btn.addEventListener("click", ev => {
240
- ev.preventDefault()
241
- toggleTimes()
242
- })
243
- }
244
- })
245
- </script>
246
- <style>
247
- .progress {
248
- height: 3px;
249
- width: 150px;
250
- }
251
- </style>
252
- </head>
253
-
254
- <body>
255
- <main class="container-fluid">
256
- <h1>zackup overview</h1>
257
- <table class="table table-sm table-hover table-striped">
258
- <caption class="small">
259
- <button class="btn btn-sm btn-outline-secondary js-toggle-times float-right" type="button">
260
- Toggle times
261
- </button>
262
- Date: {{ fmtTime .Time false }}
263
- <br>
264
- <a href="https://github.com/digineo/zackup">Digineo Zackup</a>
265
- • <a href="https://github.com/digineo/zackup/issues">Issues</a>
266
- </caption>
267
- <thead>
268
- <tr>
269
- <th>Host</th>
270
- <th>Status</th>
271
- <th>last started</th>
272
- <th colspan="2" class="text-center">last succeeded</th>
273
- <th colspan="2" class="text-center">last failed</th>
274
- <th>scheduled for</th>
275
- <th>Space used</th>
276
- <th class="text-right">Compression factor</th>
277
- </tr>
278
- </thead>
279
- <tbody>
280
- {{ range .Hosts }}
281
- <tr>
282
- <td><tt>{{ .Host }}</tt></td>
283
- <td class="{{ statusClass . }}">
284
- <i class="{{ statusIcon . }} fa-fw"></i> {{ .Status }}
285
- </td>
286
- {{ if .StartedAt.IsZero }}
287
- <td>{{ na }}</td>
288
- <td class="text-center" colspan="2">{{ na }}</td>
289
- <td class="text-center" colspan="2">{{ na }}</td>
290
- <td>{{ na }}</td>
291
- <td>{{ na }}</td>
292
- <td class="text-right">{{ na }}</td>
293
- {{ else }}
294
- <td>{{ fmtTime .StartedAt true }}</td>
295
- {{ if .SucceededAt }}
296
- <td class="text-right">{{ fmtTime .SucceededAt true }}</td>
297
- <td><span class="badge badge-secondary">{{ fmtDuration .SuccessDuration }}</span></td>
298
- {{ else }}
299
- <td colspan="2" class="text-center">{{ na }}</td>
300
- {{ end }}
301
- {{ if .FailedAt }}
302
- <td class="text-right">{{ fmtTime .FailedAt true }}</td>
303
- <td><span class="badge badge-secondary">{{ fmtDuration .FailureDuration }}</span></td>
304
- {{ else }}
305
- <td colspan="2" class="text-center">{{ na }}</td>
306
- {{ end }}
307
- <td>
308
- {{ if .ScheduledAt }}
309
- {{ fmtTime .ScheduledAt true }}
310
- {{ else }}
311
- {{ na }}
312
- {{ end }}
313
- </td>
314
- <td title="{{ usageDetails . }}">
315
- <div class="progress">
316
- <div class="progress-bar bg-success" style="width:{{ percentUsage . .SpaceUsedByDataset }}%"></div>
317
- <div class="progress-bar bg-warning" style="width:{{ percentUsage . .SpaceUsedBySnapshots }}%"></div>
318
- <div class="progress-bar bg-info" style="width:{{ percentUsage . .SpaceUsedByChildren }}%"></div>
319
- <div class="progress-bar bg-danger" style="width:{{ percentUsage . .SpaceUsedByRefReservation }}%"></div>
320
- </div>
321
- <small>Total: {{ humanBytes .SpaceUsedTotal }}</small>
322
- </td>
323
- <td class="text-right">{{ printf "%0.2f" .CompressionFactor }}</td>
324
- {{ end }}
325
- </tr>
326
- {{ end }}
327
- </tbody>
328
- </table>
329
- </main>
330
- </body>
331
- </html>
332
- ` ))
215
+ }).ParseFS (staticFiles , "static/index.html" ))
0 commit comments