OXYGENHUB
# e8fa53694f68 oxygenhub / templates / backups.html
4.8 KiB · HTML · last changed feat: backups for users and organisations, to a directory, with restore (refs #169) 22 days ago source blame history raw
1
{% extends "base.html" %}
2
{% import "settings_tabs.html" as t %}
3
{% block title %}Backups{% if kind == "org" %} · {{ owner }}{% endif %}{% endblock %}
4
{% block tabs %}{% if kind == "user" %}{% call t::tabs("backups") %}{% endif %}{% endblock %}
5
{% block content %}
6
<div class="head"><h1>Backups <small>{% if kind == "org" %}<a href="/orgs/{{ owner }}/settings">{{ owner }}</a>'s repositories{% else %}your repositories{% endif %}, copied to a place you control</small></h1></div>
7
{% if let Some(n) = notice %}<p class="note">{{ n }}</p>{% endif %}
8
{% if let Some(e) = error %}<p class="error">{{ e }}</p>{% endif %}
9
<p class="small mute backup-what">Each run copies every repository {% if kind == "org" %}the organisation{% else %}you{% endif %} own, with its wiki, byte for byte (signatures and all), its issues, proposals, releases and settings (never a secret value){% if kind == "org" %}, and the organisation's members and teams{% endif %}. Only what changed since the last run travels, and any kept run can be restored with <code>oxygenhub admin restore</code>.</p>
10
11
<form class="card wide backup-form" method="post" action="{{ base }}">
12
  <input type="hidden" name="_csrf" value="{{ shell.csrf }}">
13
  <h2>Where and how often</h2>
14
  <fieldset class="choices">
15
    <legend class="small mute">How often</legend>
16
    {% for (v, label) in every() %}<label class="choice"><input type="radio" name="every" value="{{ v }}"{% if setting.every == *v %} checked{% endif %}> {{ label }}</label>{% endfor %}
17
  </fieldset>
18
  <fieldset class="choices">
19
    <legend class="small mute">Where</legend>
20
    {% if !dirs.is_empty() %}<label class="choice"><input type="radio" name="destination" value="dir"{% if setting.destination == "dir" %} checked{% endif %}> A directory on this hub's host</label>{% endif %}
21
    <label class="choice"><input type="radio" name="destination" value="gcs"{% if setting.destination == "gcs" || dirs.is_empty() %} checked{% endif %}> A Google Cloud Storage bucket, with no key</label>
22
  </fieldset>
23
  {% if !dirs.is_empty() %}
24
  <label for="dir">Directory</label>
25
  <select id="dir" name="dir">{% for d in dirs %}<option value="{{ d }}"{% if setting.destination == "dir" && setting.target == *d %} selected{% endif %}>{{ d }}/{{ owner }}</option>{% endfor %}</select>
26
  {% endif %}
27
  <label for="bucket">GCS bucket</label>
28
  <input type="text" id="bucket" name="bucket" placeholder="{{ owner }}-oxygen-backup" value="{% if setting.destination == "gcs" %}{{ setting.target }}{% endif %}">
29
  <label for="provider">Workload identity provider</label>
30
  <input type="text" id="provider" name="provider" placeholder="//iam.googleapis.com/projects/NUMBER/locations/global/workloadIdentityPools/oxygenhub/providers/oxygenhub-io" value="{{ setting.provider }}">
31
  <p class="small mute">The hub signs in as <code>backup:{{ owner }}</code> with a token it issues itself; Google exchanges it for a few minutes' access to this bucket. No key file exists. One-time setup: <a href="/help#backups">Help › Backups</a> (docs/backups.md §6).</p>
32
  <label for="prefix">Prefix (optional)</label>
33
  <input type="text" id="prefix" name="prefix" value="{{ setting.prefix }}" placeholder="oxygenhub">
34
  <label for="keep_days">Keep runs for</label>
35
  <select id="keep_days" name="keep_days">{% for k in keeps() %}<option value="{{ k }}"{% if setting.keep_days == *k %} selected{% endif %}>{{ k }} days</option>{% endfor %}</select>
36
  <button type="submit">SAVE</button>
37
</form>
38
39
<section class="card-box" id="runs">
40
  <div class="card-head"><h2>Runs</h2><span class="count-chip">{{ runs.len() }}</span>
41
    <form class="inline more" method="post" action="{{ base }}/run"><input type="hidden" name="_csrf" value="{{ shell.csrf }}"><button type="submit" class="small primary-btn"{% if setting.updated_ms == 0 %} disabled title="Save where backups go first"{% endif %}>Back up now</button></form>
42
  </div>
43
  {% if runs.is_empty() %}<p class="empty small">No runs yet.{% if setting.every == "off" %} Pick how often and where, then save.{% endif %}</p>
44
  {% else %}
45
  <div class="table"><table class="backup-runs">
46
    <tr><th>Started</th><th>Took</th><th>Outcome</th><th>Repositories</th><th>Files sent</th><th>Size sent</th><th></th></tr>
47
    {% for r in runs %}
48
    <tr>
49
      <td><time title="{{ r.started_ms|when_i }}">{{ r.started_ms|ago_i }}</time>{% if r.trigger == "now" %} <span class="mute small">by hand</span>{% endif %}</td>
50
      <td>{% if let Some(f) = r.finished_ms %}{{ ((f - r.started_ms) / 1000) }} s{% else %}<span class="mute">running</span>{% endif %}</td>
51
      <td><span class="backup-status st-{{ r.status }}">{{ r.status }}</span></td>
52
      <td>{{ r.repos }}</td>
53
      <td>{{ r.sent }} <span class="mute small">of {{ r.files }}</span></td>
54
      <td>{{ (r.bytes / 1024) }} KiB</td>
55
      <td class="small mute">{{ r.detail }}</td>
56
    </tr>
57
    {% endfor %}
58
  </table></div>
59
  {% endif %}
60
</section>
61
{% endblock %}