1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00

feat(instances): the Snapshots tab shows the VM's history as a line

The tab opened on "Snapshots · Active" above the form, and listed the
snapshots below it as rows of "name · description · external, current
· date" with a solid red Delete on each. Which snapshot the VM goes on
from was the word "current" among the others.

Now a line runs down the tab, newest first. On top is Now, the VM in
its state's color, with the form that takes a snapshot there. Below it
each snapshot is a point: its name and date, its description on a line
of its own, its kind under them. The one the VM goes on from is filled
and says so; the others are rings. Revert and Delete are small outlined
buttons. Forms, confirmations and the rules that disable them are
unchanged.
This commit is contained in:
catborise 2026-11-04 08:51:01 +03:00
parent 07ca42dcdf
commit 0b2604f151
7 changed files with 246 additions and 210 deletions

View file

@ -8,115 +8,126 @@
{% vm_state instance.status as state %}
<div class="card">
<div class="card-body">
<p class="small text-body-secondary mb-2">{% trans "Snapshots" %} · {{ state.0 }}</p>
{# the VM's history, newest first: now, where a new snapshot is taken, then each snapshot; the VM goes on from the filled one #}
{% if busy %}
<div class="alert alert-warning" role="status">{% trans "A disk job is running on this VM; snapshot actions are unavailable until it ends." %}</div>
{% endif %}
{# an external snapshot is the way: each disk goes on in a new file, the VM keeps running #}
<form action="{% url 'instances:create_external_snapshot' instance.id %}" method="post" aria-label="{% trans "Take a snapshot" %}">{% csrf_token %}{% submission_key %}
<div class="row g-2">
<div class="col-12 col-md">
<label class="visually-hidden" for="snapshot-name">{% trans "Snapshot name" %}</label>
<input type="text" class="form-control" id="snapshot-name" name="name" placeholder="{% trans "Snapshot name" %}" maxlength="64" pattern="[A-Za-z0-9_\-][A-Za-z0-9._\-]{0,63}" title="{% trans "Letters, digits, '.', '_' or '-'; not starting with '.'" %}" required>
</div>
<div class="col-12 col-md">
<label class="visually-hidden" for="snapshot-description">{% trans "Description" %}</label>
<input type="text" class="form-control" id="snapshot-description" name="description" placeholder="{% trans "Description (optional)" %}">
</div>
<div class="col-12 col-md-auto d-grid">
<button type="submit" class="btn btn-primary" name="snapshot"{% if instance.internal_snapshots or instance.newer_than_current_snapshot or busy or held %} disabled{% endif %}>{% trans "Take a snapshot" %}</button>
</div>
<div class="snap-line">
<div class="snap-node">
<span class="snap-dot{% if instance.status == 1 %} bg-success{% elif instance.status == 3 or instance.status == 7 %} bg-warning{% elif instance.status == 5 %} bg-secondary{% endif %}" aria-hidden="true"></span>
<p class="mb-2"><span class="fw-semibold">{% trans "Now" %}</span> <span class="small text-body-secondary">{{ state.0 }}</span></p>
{# an external snapshot is the way: each disk goes on in a new file, the VM keeps running #}
<form action="{% url 'instances:create_external_snapshot' instance.id %}" method="post" aria-label="{% trans "Take a snapshot" %}">{% csrf_token %}{% submission_key %}
<div class="row g-2">
<div class="col-12 col-md">
<label class="visually-hidden" for="snapshot-name">{% trans "Snapshot name" %}</label>
<input type="text" class="form-control" id="snapshot-name" name="name" placeholder="{% trans "Snapshot name" %}" maxlength="64" pattern="[A-Za-z0-9_\-][A-Za-z0-9._\-]{0,63}" title="{% trans "Letters, digits, '.', '_' or '-'; not starting with '.'" %}" required>
</div>
<div class="col-12 col-md">
<label class="visually-hidden" for="snapshot-description">{% trans "Description" %}</label>
<input type="text" class="form-control" id="snapshot-description" name="description" placeholder="{% trans "Description (optional)" %}">
</div>
<div class="col-12 col-md-auto d-grid">
<button type="submit" class="btn btn-primary" name="snapshot"{% if instance.internal_snapshots or instance.newer_than_current_snapshot or busy or held %} disabled{% endif %}>{% trans "Take a snapshot" %}</button>
</div>
</div>
<div class="d-flex flex-wrap column-gap-4 mt-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="memory" id="snapshot-memory"{% if instance.status != 1 %} disabled{% endif %}
>
<label class="form-check-label" for="snapshot-memory">{% trans "Save memory too" %}</label>
</div>
<div class="form-check">
{% if instance.status == 1 and instance.guest_agent_ready %}
<input class="form-check-input" type="checkbox" name="quiesce" id="snapshot-quiesce" data-offered="1" checked>
{% else %}
<input class="form-check-input" type="checkbox" name="quiesce" id="snapshot-quiesce" disabled>
{% endif %}
<label class="form-check-label" for="snapshot-quiesce">{% trans "Freeze the guest's file systems" %}</label>
</div>
</div>
<p class="small text-body-secondary mt-1 mb-0">
{% if instance.internal_snapshots %}{% trans "The VM has internal snapshots: delete them before taking an external one." %}
{% elif instance.newer_than_current_snapshot %}{% trans "Snapshots newer than the one reverted to exist: delete them before taking a new one." %}
{% else %}{% trans "Each disk goes on in a new file next to it; the VM keeps running." %}
{% if instance.status == 1 %}{% trans "With memory, the VM pauses while its memory is saved." %}{% endif %}
{% if instance.status != 1 %}{% trans "Memory and frozen file systems are for a running VM." %}{% elif not instance.guest_agent_ready %}{% trans "Freezing needs the guest agent, which is not connected." %}{% endif %}{% endif %}
</p>
</form>
<details class="mt-3">
<summary class="small text-body-secondary">{% trans "Internal snapshot: a fallback for a VM that cannot take an external one" %}</summary>
<form class="mt-2" action="{% url 'instances:snapshot' instance.id %}" method="post" aria-label="{% trans "Take an internal snapshot" %}">{% csrf_token %}{% submission_key %}
<p class="small mb-2">
{% if instance.status == 1 %}{% trans "The disks and memory go into the disk files. The VM does not respond while its memory is saved, which can take long: avoid it in production." %}
{% elif instance.status == 3 %}{% trans "The disks and memory go into the disk files; the paused VM stays paused." %}
{% else %}{% trans "The disks go into their files." %}{% endif %}
</p>
<div class="row g-2">
<div class="col-12 col-md">
<label class="visually-hidden" for="internal-snapshot-name">{% trans "Snapshot name" %}</label>
<input type="text" class="form-control" id="internal-snapshot-name" name="name" placeholder="{% trans "Snapshot name" %}" maxlength="64" pattern="[A-Za-z0-9_\-][A-Za-z0-9._\-]{0,63}" title="{% trans "Letters, digits, '.', '_' or '-'; not starting with '.'" %}" required>
</div>
<div class="col-12 col-md">
<label class="visually-hidden" for="internal-snapshot-description">{% trans "Description" %}</label>
<input type="text" class="form-control" id="internal-snapshot-description" name="description" placeholder="{% trans "Description (optional)" %}">
</div>
<div class="col-12 col-md-auto d-grid">
<button type="submit" class="btn btn-secondary" name="snapshot"{% if instance.external_snapshots or busy or held %} disabled{% endif %}>{% trans "Take an internal snapshot" %}</button>
</div>
</div>
{% if instance.external_snapshots %}<p class="small text-body-secondary mt-1 mb-0">{% trans "The VM has external snapshots: the two kinds do not mix." %}</p>{% endif %}
</form>
</details>
</div>
<div class="d-flex flex-wrap column-gap-4 mt-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="memory" id="snapshot-memory"{% if instance.status != 1 %} disabled{% endif %}
>
<label class="form-check-label" for="snapshot-memory">{% trans "Save memory too" %}</label>
</div>
<div class="form-check">
{% if instance.status == 1 and instance.guest_agent_ready %}
<input class="form-check-input" type="checkbox" name="quiesce" id="snapshot-quiesce" data-offered="1" checked>
{% if instance.snapshots %}
<ol class="list-unstyled mb-0" id="snapshot-list">
{% for snap in instance.snapshots %}
<li class="snap-node d-flex flex-wrap align-items-start gap-2">
<span class="snap-dot{% if snap.current %} snap-current{% endif %}" aria-hidden="true"></span>
<div class="me-auto text-break">
<strong>{{ snap.name }}</strong> <span class="small text-body-secondary text-nowrap ms-1">{{ snap.date|date:"Y-m-d H:i" }}</span>
{% if snap.description %}<div>{{ snap.description }}</div>{% endif %}
<div class="small text-body-secondary">{% if snap.external %}{% trans "external" %}{% if snap.memory %}, {% trans "with memory" %}{% endif %}{% else %}{% trans "internal" %}{% endif %}{% if snap.current %}; <span class="text-body">{% trans "the VM goes on from this one" %}</span>{% endif %}</div>
</div>
{% if snap.external %}
<form action="{% url 'instances:revert_external_snapshot' instance.id %}" method="post">{% csrf_token %}{% submission_key %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-outline-secondary" name="revert_external_snapshot"
data-confirm="{% blocktrans with name=snap.name %}Revert to snapshot {{ name }}? Changes made since it are lost.{% endblocktrans %}{% if not snap.memory %}{% if instance.status == 1 %} {% trans "The VM is powered off and starts again from the snapshot's disks, as after a power cut." %}{% elif instance.status == 3 %} {% trans "The VM is powered off and comes back paused on the snapshot's disks." %}{% endif %}{% endif %}{% if snap.detaches %} {% trans 'These disks are detached; their writes since the current snapshot are discarded and their files are kept:' %} {% for d in snap.detaches %}{{ d.dev }} ({{ d.path }}){% if not forloop.last %}, {% endif %}{% endfor %}.{% endif %}{% if instance.nvram %} {% trans 'Firmware variables (NVRAM) are not restored.' %}{% endif %}"
{% if busy or held %} disabled{% endif %}>{% trans "Revert" %}</button>
</form>
<form action="{% url 'instances:delete_external_snapshot' instance.id %}" method="post">{% csrf_token %}{% submission_key %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-outline-danger" name="delete_external_snapshot"
data-confirm="{% blocktrans with name=snap.name %}Delete snapshot {{ name }}? Its files are merged with the disks; the VM's data is kept.{% endblocktrans %}"
{% if busy or held %} disabled{% endif %}>{% trans "Delete" %}</button>
</form>
{% else %}
<input class="form-check-input" type="checkbox" name="quiesce" id="snapshot-quiesce" disabled>
<form action="{% url 'instances:revert_snapshot' instance.id %}" method="post">{% csrf_token %}{% submission_key %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-outline-secondary" name="revert_snapshot"
data-confirm="{% blocktrans with name=snap.name %}Revert to snapshot {{ name }}? Disk changes made since it are lost; a snapshot of a running VM starts it again as it was then.{% endblocktrans %}"
{% if instance.status != 5 or busy or held %} disabled{% endif %}
{% if instance.status != 5 %}title="{% trans "Shut the VM down to revert to an internal snapshot." %}"{% endif %}>{% trans "Revert" %}</button>
</form>
<form action="{% url 'instances:delete_snapshot' instance.id %}" method="post">{% csrf_token %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-outline-danger"
data-confirm="{% blocktrans with name=snap.name %}Delete snapshot {{ name }}? The VM's current disks are not changed.{% endblocktrans %}"
{% if busy or held %} disabled{% endif %}>{% trans "Delete" %}</button>
</form>
{% endif %}
<label class="form-check-label" for="snapshot-quiesce">{% trans "Freeze the guest's file systems" %}</label>
</div>
</li>
{% endfor %}
</ol>
{% else %}
<div class="snap-node">
<span class="snap-dot snap-none" aria-hidden="true"></span>
<p class="small text-body-secondary mb-0">{% trans "The VM has no snapshot." %}</p>
</div>
<p class="small text-body-secondary mt-1 mb-0">
{% if instance.internal_snapshots %}{% trans "The VM has internal snapshots: delete them before taking an external one." %}
{% elif instance.newer_than_current_snapshot %}{% trans "Snapshots newer than the one reverted to exist: delete them before taking a new one." %}
{% else %}{% trans "Each disk goes on in a new file next to it; the VM keeps running." %}
{% if instance.status == 1 %}{% trans "With memory, the VM pauses while its memory is saved." %}{% endif %}
{% if instance.status != 1 %}{% trans "Memory and frozen file systems are for a running VM." %}{% elif not instance.guest_agent_ready %}{% trans "Freezing needs the guest agent, which is not connected." %}{% endif %}{% endif %}
</p>
</form>
<details class="mt-3">
<summary class="small text-body-secondary">{% trans "Internal snapshot: a fallback for a VM that cannot take an external one" %}</summary>
<form class="mt-2" action="{% url 'instances:snapshot' instance.id %}" method="post" aria-label="{% trans "Take an internal snapshot" %}">{% csrf_token %}{% submission_key %}
<p class="small mb-2">
{% if instance.status == 1 %}{% trans "The disks and memory go into the disk files. The VM does not respond while its memory is saved, which can take long: avoid it in production." %}
{% elif instance.status == 3 %}{% trans "The disks and memory go into the disk files; the paused VM stays paused." %}
{% else %}{% trans "The disks go into their files." %}{% endif %}
</p>
<div class="row g-2">
<div class="col-12 col-md">
<label class="visually-hidden" for="internal-snapshot-name">{% trans "Snapshot name" %}</label>
<input type="text" class="form-control" id="internal-snapshot-name" name="name" placeholder="{% trans "Snapshot name" %}" maxlength="64" pattern="[A-Za-z0-9_\-][A-Za-z0-9._\-]{0,63}" title="{% trans "Letters, digits, '.', '_' or '-'; not starting with '.'" %}" required>
</div>
<div class="col-12 col-md">
<label class="visually-hidden" for="internal-snapshot-description">{% trans "Description" %}</label>
<input type="text" class="form-control" id="internal-snapshot-description" name="description" placeholder="{% trans "Description (optional)" %}">
</div>
<div class="col-12 col-md-auto d-grid">
<button type="submit" class="btn btn-secondary" name="snapshot"{% if instance.external_snapshots or busy or held %} disabled{% endif %}>{% trans "Take an internal snapshot" %}</button>
</div>
</div>
{% if instance.external_snapshots %}<p class="small text-body-secondary mt-1 mb-0">{% trans "The VM has external snapshots: the two kinds do not mix." %}</p>{% endif %}
</form>
</details>
{% if instance.snapshots %}
<ul class="list-group mt-3" id="snapshot-list">
{% for snap in instance.snapshots %}
<li class="list-group-item d-flex flex-wrap align-items-center gap-2">
<div class="me-auto text-break">
<strong>{{ snap.name }}</strong>{% if snap.description %} <span>· {{ snap.description }}</span>{% endif %}
<span class="small text-body-secondary">· {% if snap.external %}{% trans "external" %}{% if snap.memory %}, {% trans "with memory" %}{% endif %}{% else %}{% trans "internal" %}{% endif %}{% if snap.current %}, {% trans "current" %}{% endif %} · {{ snap.date|date:"Y-m-d H:i" }}</span>
</div>
{% if snap.external %}
<form action="{% url 'instances:revert_external_snapshot' instance.id %}" method="post">{% csrf_token %}{% submission_key %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-secondary" name="revert_external_snapshot"
data-confirm="{% blocktrans with name=snap.name %}Revert to snapshot {{ name }}? Changes made since it are lost.{% endblocktrans %}{% if not snap.memory %}{% if instance.status == 1 %} {% trans "The VM is powered off and starts again from the snapshot's disks, as after a power cut." %}{% elif instance.status == 3 %} {% trans "The VM is powered off and comes back paused on the snapshot's disks." %}{% endif %}{% endif %}{% if snap.detaches %} {% trans 'These disks are detached; their writes since the current snapshot are discarded and their files are kept:' %} {% for d in snap.detaches %}{{ d.dev }} ({{ d.path }}){% if not forloop.last %}, {% endif %}{% endfor %}.{% endif %}{% if instance.nvram %} {% trans 'Firmware variables (NVRAM) are not restored.' %}{% endif %}"
{% if busy or held %} disabled{% endif %}>{% trans "Revert" %}</button>
</form>
<form action="{% url 'instances:delete_external_snapshot' instance.id %}" method="post">{% csrf_token %}{% submission_key %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-danger" name="delete_external_snapshot"
data-confirm="{% blocktrans with name=snap.name %}Delete snapshot {{ name }}? Its files are merged with the disks; the VM's data is kept.{% endblocktrans %}"
{% if busy or held %} disabled{% endif %}>{% trans "Delete" %}</button>
</form>
{% else %}
<form action="{% url 'instances:revert_snapshot' instance.id %}" method="post">{% csrf_token %}{% submission_key %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-secondary" name="revert_snapshot"
data-confirm="{% blocktrans with name=snap.name %}Revert to snapshot {{ name }}? Disk changes made since it are lost; a snapshot of a running VM starts it again as it was then.{% endblocktrans %}"
{% if instance.status != 5 or busy or held %} disabled{% endif %}
{% if instance.status != 5 %}title="{% trans "Shut the VM down to revert to an internal snapshot." %}"{% endif %}>{% trans "Revert" %}</button>
</form>
<form action="{% url 'instances:delete_snapshot' instance.id %}" method="post">{% csrf_token %}
<input type="hidden" name="name" value="{{ snap.name }}">
<button type="submit" class="btn btn-sm btn-danger"
data-confirm="{% blocktrans with name=snap.name %}Delete snapshot {{ name }}? The VM's current disks are not changed.{% endblocktrans %}"
{% if busy or held %} disabled{% endif %}>{% trans "Delete" %}</button>
</form>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% if instance.internal_snapshots and instance.status != 5 %}<p class="small text-body-secondary mt-1 mb-0">{% trans "Shut the VM down to revert to an internal snapshot." %}</p>{% endif %}
{% else %}
<p class="small text-body-secondary mt-3 mb-0">{% trans "The VM has no snapshot." %}</p>
{% endif %}
<p class="small text-body-secondary mt-2 mb-0">{% blocktrans %}Times in {{ TIME_ZONE }}. A VM with snapshots cannot be migrated.{% endblocktrans %}</p>
</div>
</div>

View file

@ -219,7 +219,7 @@ class SnapshotTabTestCase(TestCase):
def test_one_list_newest_first_each_with_its_kind(self):
doc = self.page(internal=[self.snap("i")], external=[self.snap("e", date=datetime(2026, 2, 1), memory=True)])
rows = [" ".join(li.text_content().split()) for li in doc.xpath("//ul[@id='snapshot-list']/li")]
rows = [" ".join(li.text_content().split()) for li in doc.xpath("//ol[@id='snapshot-list']/li")]
self.assertEqual([row.split(" ")[0] for row in rows], ["e", "i"])
self.assertIn("external, with memory", rows[0])
self.assertIn("internal", rows[1])

Binary file not shown.

View file

@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-11-04 04:57+0000\n"
"POT-Creation-Date: 2026-11-04 05:47+0000\n"
"PO-Revision-Date: 2020-11-04 12:00+0000\n"
"Last-Translator: catborise <muhammetalisag@gmail.com>, 2020\n"
"Language-Team: Turkish (https://www.transifex.com/catborise/teams/110663/tr/)\n"
@ -436,8 +436,8 @@ msgstr "%(name)s API anahtarı için işlemler"
#: instances/templates/create_flavors.html:11
#: instances/templates/instances/settings_tab.html:251
#: instances/templates/instances/settings_tab.html:325
#: instances/templates/instances/snapshots_tab.html:96
#: instances/templates/instances/snapshots_tab.html:110
#: instances/templates/instances/snapshots_tab.html:103
#: instances/templates/instances/snapshots_tab.html:117
#: networks/templates/network.html:168 storages/templates/storage.html:152
#: templates/common/confirm_delete.html:5
#: templates/common/confirm_delete.html:9
@ -1728,8 +1728,8 @@ msgstr "Kayıtlı, korumak için boş bırakın"
#: computes/forms.py:28 computes/templates/computes/instances.html:45
#: instances/templates/instances/settings_tab.html:858
#: instances/templates/instances/settings_tab.html:890
#: instances/templates/instances/snapshots_tab.html:23
#: instances/templates/instances/snapshots_tab.html:67
#: instances/templates/instances/snapshots_tab.html:27
#: instances/templates/instances/snapshots_tab.html:71
msgid "Description"
msgstr "Tanım"
@ -5468,10 +5468,6 @@ msgstr ""
msgid "%(action)s: change it in the XML editor."
msgstr "%(action)s: XML düzenleyicide değiştirin."
#: instances/templates/instances/snapshots_tab.html:11
msgid "Snapshots"
msgstr "Anlık görüntüler"
#: instances/templates/instances/snapshots_tab.html:13
msgid ""
"A disk job is running on this VM; snapshot actions are unavailable until it "
@ -5480,44 +5476,48 @@ msgstr ""
"Bu sanal makinede bir disk işi çalışıyor; bitene kadar anlık görüntü "
"işlemleri kullanılamaz."
#: instances/templates/instances/snapshots_tab.html:16
#: instances/templates/instances/snapshots_tab.html:27
#: instances/templates/instances/snapshots_tab.html:18
msgid "Now"
msgstr "Şimdi"
#: instances/templates/instances/snapshots_tab.html:20
#: instances/templates/instances/snapshots_tab.html:31
msgid "Take a snapshot"
msgstr "Anlık görüntü al"
#: instances/templates/instances/snapshots_tab.html:19
#: instances/templates/instances/snapshots_tab.html:20
#: instances/templates/instances/snapshots_tab.html:63
#: instances/templates/instances/snapshots_tab.html:64
#: instances/templates/instances/snapshots_tab.html:23
#: instances/templates/instances/snapshots_tab.html:24
#: instances/templates/instances/snapshots_tab.html:67
#: instances/templates/instances/snapshots_tab.html:68
msgid "Snapshot name"
msgstr "Anlık görüntü adı"
#: instances/templates/instances/snapshots_tab.html:20
#: instances/templates/instances/snapshots_tab.html:64
#: instances/templates/instances/snapshots_tab.html:24
#: instances/templates/instances/snapshots_tab.html:68
msgid "Letters, digits, '.', '_' or '-'; not starting with '.'"
msgstr "Harfler, rakamlar, '.', '_' veya '-'; '.' ile başlamaz"
#: instances/templates/instances/snapshots_tab.html:24
#: instances/templates/instances/snapshots_tab.html:68
#: instances/templates/instances/snapshots_tab.html:28
#: instances/templates/instances/snapshots_tab.html:72
msgid "Description (optional)"
msgstr "Açıklama (isteğe bağlı)"
#: instances/templates/instances/snapshots_tab.html:34
#: instances/templates/instances/snapshots_tab.html:38
msgid "Save memory too"
msgstr "Belleği de kaydet"
#: instances/templates/instances/snapshots_tab.html:42
#: instances/templates/instances/snapshots_tab.html:46
msgid "Freeze the guest's file systems"
msgstr "Konuk sistemin dosya sistemlerini dondur"
#: instances/templates/instances/snapshots_tab.html:46
#: instances/templates/instances/snapshots_tab.html:50
msgid ""
"The VM has internal snapshots: delete them before taking an external one."
msgstr ""
"Sanal makinenin dahili anlık görüntüleri var: harici bir tane almadan önce "
"onları silin."
#: instances/templates/instances/snapshots_tab.html:47
#: instances/templates/instances/snapshots_tab.html:51
msgid ""
"Snapshots newer than the one reverted to exist: delete them before taking a "
"new one."
@ -5525,38 +5525,38 @@ msgstr ""
"Geri dönülen anlık görüntüden daha yeni anlık görüntüler var: yenisini "
"almadan önce onları silin."
#: instances/templates/instances/snapshots_tab.html:48
#: instances/templates/instances/snapshots_tab.html:52
msgid "Each disk goes on in a new file next to it; the VM keeps running."
msgstr ""
"Her disk yanındaki yeni bir dosyada devam eder; sanal makine çalışmaya devam "
"eder."
#: instances/templates/instances/snapshots_tab.html:49
#: instances/templates/instances/snapshots_tab.html:53
msgid "With memory, the VM pauses while its memory is saved."
msgstr ""
"Bellekle birlikte alınırsa sanal makine, belleği kaydedilirken duraklatılır."
#: instances/templates/instances/snapshots_tab.html:50
#: instances/templates/instances/snapshots_tab.html:54
msgid "Memory and frozen file systems are for a running VM."
msgstr ""
"Bellek ve dondurulmuş dosya sistemleri çalışan bir sanal makine içindir."
#: instances/templates/instances/snapshots_tab.html:50
#: instances/templates/instances/snapshots_tab.html:54
msgid "Freezing needs the guest agent, which is not connected."
msgstr "Dondurma için konuk ajanı gerekir, ancak bağlı değil."
#: instances/templates/instances/snapshots_tab.html:54
#: instances/templates/instances/snapshots_tab.html:58
msgid "Internal snapshot: a fallback for a VM that cannot take an external one"
msgstr ""
"Dahili anlık görüntü: harici anlık görüntü alamayan bir sanal makine için "
"yedek yol"
#: instances/templates/instances/snapshots_tab.html:55
#: instances/templates/instances/snapshots_tab.html:71
#: instances/templates/instances/snapshots_tab.html:59
#: instances/templates/instances/snapshots_tab.html:75
msgid "Take an internal snapshot"
msgstr "Dahili anlık görüntü al"
#: instances/templates/instances/snapshots_tab.html:57
#: instances/templates/instances/snapshots_tab.html:61
msgid ""
"The disks and memory go into the disk files. The VM does not respond while "
"its memory is saved, which can take long: avoid it in production."
@ -5564,46 +5564,46 @@ msgstr ""
"Diskler ve bellek disk dosyalarına yazılır. Belleği kaydedilirken sanal "
"makine yanıt vermez ve bu uzun sürebilir: üretim ortamında kaçının."
#: instances/templates/instances/snapshots_tab.html:58
#: instances/templates/instances/snapshots_tab.html:62
msgid ""
"The disks and memory go into the disk files; the paused VM stays paused."
msgstr ""
"Diskler ve bellek disk dosyalarına yazılır; duraklatılmış sanal makine "
"duraklatılmış kalır."
#: instances/templates/instances/snapshots_tab.html:59
#: instances/templates/instances/snapshots_tab.html:63
msgid "The disks go into their files."
msgstr "Diskler kendi dosyalarına yazılır."
#: instances/templates/instances/snapshots_tab.html:74
#: instances/templates/instances/snapshots_tab.html:78
msgid "The VM has external snapshots: the two kinds do not mix."
msgstr ""
"Sanal makinenin harici anlık görüntüleri var: iki tür bir arada kullanılamaz."
#: instances/templates/instances/snapshots_tab.html:83
#: instances/templates/instances/snapshots_tab.html:90
msgid "external"
msgstr "harici"
#: instances/templates/instances/snapshots_tab.html:83
#: instances/templates/instances/snapshots_tab.html:90
msgid "with memory"
msgstr "bellekle"
#: instances/templates/instances/snapshots_tab.html:83
#: instances/templates/instances/snapshots_tab.html:90
msgid "internal"
msgstr "dahili"
#: instances/templates/instances/snapshots_tab.html:83
msgid "current"
msgstr "geçerli"
#: instances/templates/instances/snapshots_tab.html:90
msgid "the VM goes on from this one"
msgstr "sanal makine bundan devam ediyor"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
#, python-format
msgid "Revert to snapshot %(name)s? Changes made since it are lost."
msgstr ""
"%(name)s anlık görüntüsüne dönülsün mü? O zamandan beri yapılan değişiklikler"
" kaybolur."
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid ""
"The VM is powered off and starts again from the snapshot's disks, as after a "
"power cut."
@ -5611,13 +5611,13 @@ msgstr ""
"Sanal makine kapatılır ve bir elektrik kesintisinden sonraki gibi anlık "
"görüntünün diskleriyle yeniden başlar."
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid "The VM is powered off and comes back paused on the snapshot's disks."
msgstr ""
"Sanal makine kapatılır ve anlık görüntünün diskleriyle duraklatılmış olarak "
"geri gelir."
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid ""
"These disks are detached; their writes since the current snapshot are "
"discarded and their files are kept:"
@ -5625,16 +5625,16 @@ msgstr ""
"Bu diskler ayrılır; geçerli anlık görüntüden beri yapılan yazmaları atılır ve"
" dosyaları korunur:"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid "Firmware variables (NVRAM) are not restored."
msgstr "Üretici yazılımı değişkenleri (NVRAM) geri yüklenmez."
#: instances/templates/instances/snapshots_tab.html:90
#: instances/templates/instances/snapshots_tab.html:104
#: instances/templates/instances/snapshots_tab.html:97
#: instances/templates/instances/snapshots_tab.html:111
msgid "Revert"
msgstr "Geri dön"
#: instances/templates/instances/snapshots_tab.html:95
#: instances/templates/instances/snapshots_tab.html:102
#, python-format
msgid ""
"Delete snapshot %(name)s? Its files are merged with the disks; the VM's data "
@ -5643,7 +5643,7 @@ msgstr ""
"%(name)s anlık görüntüsü silinsin mi? Dosyaları disklerle birleştirilir; "
"sanal makinenin verileri korunur."
#: instances/templates/instances/snapshots_tab.html:102
#: instances/templates/instances/snapshots_tab.html:109
#, python-format
msgid ""
"Revert to snapshot %(name)s? Disk changes made since it are lost; a snapshot "
@ -5653,23 +5653,23 @@ msgstr ""
"değişiklikleri kaybolur; çalışan bir sanal makinenin anlık görüntüsü onu o "
"anki hâliyle yeniden başlatır."
#: instances/templates/instances/snapshots_tab.html:104
#: instances/templates/instances/snapshots_tab.html:116
#: instances/templates/instances/snapshots_tab.html:111
#: instances/templates/instances/snapshots_tab.html:130
msgid "Shut the VM down to revert to an internal snapshot."
msgstr "Dahili bir anlık görüntüye dönmek için sanal makineyi kapatın."
#: instances/templates/instances/snapshots_tab.html:109
#: instances/templates/instances/snapshots_tab.html:116
#, python-format
msgid "Delete snapshot %(name)s? The VM's current disks are not changed."
msgstr ""
"%(name)s anlık görüntüsü silinsin mi? Sanal makinenin geçerli diskleri "
"değişmez."
#: instances/templates/instances/snapshots_tab.html:118
#: instances/templates/instances/snapshots_tab.html:126
msgid "The VM has no snapshot."
msgstr "Sanal makinenin anlık görüntüsü yok."
#: instances/templates/instances/snapshots_tab.html:120
#: instances/templates/instances/snapshots_tab.html:131
#, python-format
msgid "Times in %(TIME_ZONE)s. A VM with snapshots cannot be migrated."
msgstr ""

Binary file not shown.

View file

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-11-04 04:57+0000\n"
"POT-Creation-Date: 2026-11-04 05:47+0000\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@ -431,8 +431,8 @@ msgstr "API 令牌 %(name)s 的操作"
#: instances/templates/create_flavors.html:11
#: instances/templates/instances/settings_tab.html:251
#: instances/templates/instances/settings_tab.html:325
#: instances/templates/instances/snapshots_tab.html:96
#: instances/templates/instances/snapshots_tab.html:110
#: instances/templates/instances/snapshots_tab.html:103
#: instances/templates/instances/snapshots_tab.html:117
#: networks/templates/network.html:168 storages/templates/storage.html:152
#: templates/common/confirm_delete.html:5
#: templates/common/confirm_delete.html:9
@ -1674,8 +1674,8 @@ msgstr "已保存,留空则保持不变"
#: computes/forms.py:28 computes/templates/computes/instances.html:45
#: instances/templates/instances/settings_tab.html:858
#: instances/templates/instances/settings_tab.html:890
#: instances/templates/instances/snapshots_tab.html:23
#: instances/templates/instances/snapshots_tab.html:67
#: instances/templates/instances/snapshots_tab.html:27
#: instances/templates/instances/snapshots_tab.html:71
msgid "Description"
msgstr "描述"
@ -5212,176 +5212,176 @@ msgstr "适用于客户机报告的崩溃,而非挂起。“停止”会让反
msgid "%(action)s: change it in the XML editor."
msgstr "%(action)s:请在 XML 编辑器中更改。"
#: instances/templates/instances/snapshots_tab.html:11
msgid "Snapshots"
msgstr "快照"
#: instances/templates/instances/snapshots_tab.html:13
msgid ""
"A disk job is running on this VM; snapshot actions are unavailable until it "
"ends."
msgstr "此虚拟机正在运行磁盘任务;任务结束前快照操作不可用。"
#: instances/templates/instances/snapshots_tab.html:16
#: instances/templates/instances/snapshots_tab.html:27
#: instances/templates/instances/snapshots_tab.html:18
msgid "Now"
msgstr "现在"
#: instances/templates/instances/snapshots_tab.html:20
#: instances/templates/instances/snapshots_tab.html:31
msgid "Take a snapshot"
msgstr "创建快照"
#: instances/templates/instances/snapshots_tab.html:19
#: instances/templates/instances/snapshots_tab.html:20
#: instances/templates/instances/snapshots_tab.html:63
#: instances/templates/instances/snapshots_tab.html:64
#: instances/templates/instances/snapshots_tab.html:23
#: instances/templates/instances/snapshots_tab.html:24
#: instances/templates/instances/snapshots_tab.html:67
#: instances/templates/instances/snapshots_tab.html:68
msgid "Snapshot name"
msgstr "快照名称"
#: instances/templates/instances/snapshots_tab.html:20
#: instances/templates/instances/snapshots_tab.html:64
#: instances/templates/instances/snapshots_tab.html:24
#: instances/templates/instances/snapshots_tab.html:68
msgid "Letters, digits, '.', '_' or '-'; not starting with '.'"
msgstr "字母、数字、“.”、“_”或“-”;不能以“.”开头"
#: instances/templates/instances/snapshots_tab.html:24
#: instances/templates/instances/snapshots_tab.html:68
#: instances/templates/instances/snapshots_tab.html:28
#: instances/templates/instances/snapshots_tab.html:72
msgid "Description (optional)"
msgstr "描述(可选)"
#: instances/templates/instances/snapshots_tab.html:34
#: instances/templates/instances/snapshots_tab.html:38
msgid "Save memory too"
msgstr "同时保存内存"
#: instances/templates/instances/snapshots_tab.html:42
#: instances/templates/instances/snapshots_tab.html:46
msgid "Freeze the guest's file systems"
msgstr "冻结客户机的文件系统"
#: instances/templates/instances/snapshots_tab.html:46
#: instances/templates/instances/snapshots_tab.html:50
msgid ""
"The VM has internal snapshots: delete them before taking an external one."
msgstr "该虚拟机有内部快照:请先删除它们再创建外部快照。"
#: instances/templates/instances/snapshots_tab.html:47
#: instances/templates/instances/snapshots_tab.html:51
msgid ""
"Snapshots newer than the one reverted to exist: delete them before taking a "
"new one."
msgstr "存在比所恢复快照更新的快照:请先删除它们再创建新快照。"
#: instances/templates/instances/snapshots_tab.html:48
#: instances/templates/instances/snapshots_tab.html:52
msgid "Each disk goes on in a new file next to it; the VM keeps running."
msgstr "每个磁盘在其旁边的新文件中继续写入;虚拟机保持运行。"
#: instances/templates/instances/snapshots_tab.html:49
#: instances/templates/instances/snapshots_tab.html:53
msgid "With memory, the VM pauses while its memory is saved."
msgstr "包含内存时,虚拟机在保存内存期间暂停。"
#: instances/templates/instances/snapshots_tab.html:50
#: instances/templates/instances/snapshots_tab.html:54
msgid "Memory and frozen file systems are for a running VM."
msgstr "内存和冻结文件系统仅适用于运行中的虚拟机。"
#: instances/templates/instances/snapshots_tab.html:50
#: instances/templates/instances/snapshots_tab.html:54
msgid "Freezing needs the guest agent, which is not connected."
msgstr "冻结需要客户机代理,但它未连接。"
#: instances/templates/instances/snapshots_tab.html:54
#: instances/templates/instances/snapshots_tab.html:58
msgid "Internal snapshot: a fallback for a VM that cannot take an external one"
msgstr "内部快照:用于无法创建外部快照的虚拟机的备用方案"
#: instances/templates/instances/snapshots_tab.html:55
#: instances/templates/instances/snapshots_tab.html:71
#: instances/templates/instances/snapshots_tab.html:59
#: instances/templates/instances/snapshots_tab.html:75
msgid "Take an internal snapshot"
msgstr "创建内部快照"
#: instances/templates/instances/snapshots_tab.html:57
#: instances/templates/instances/snapshots_tab.html:61
msgid ""
"The disks and memory go into the disk files. The VM does not respond while "
"its memory is saved, which can take long: avoid it in production."
msgstr "磁盘和内存保存到磁盘文件中。保存内存期间虚拟机不响应,可能耗时较长:生产环境中请避免使用。"
#: instances/templates/instances/snapshots_tab.html:58
#: instances/templates/instances/snapshots_tab.html:62
msgid ""
"The disks and memory go into the disk files; the paused VM stays paused."
msgstr "磁盘和内存保存到磁盘文件中;已暂停的虚拟机保持暂停。"
#: instances/templates/instances/snapshots_tab.html:59
#: instances/templates/instances/snapshots_tab.html:63
msgid "The disks go into their files."
msgstr "磁盘保存到各自的文件中。"
#: instances/templates/instances/snapshots_tab.html:74
#: instances/templates/instances/snapshots_tab.html:78
msgid "The VM has external snapshots: the two kinds do not mix."
msgstr "该虚拟机已有外部快照:两种快照不能混用。"
#: instances/templates/instances/snapshots_tab.html:83
#: instances/templates/instances/snapshots_tab.html:90
msgid "external"
msgstr "外部"
#: instances/templates/instances/snapshots_tab.html:83
#: instances/templates/instances/snapshots_tab.html:90
msgid "with memory"
msgstr "含内存"
#: instances/templates/instances/snapshots_tab.html:83
#: instances/templates/instances/snapshots_tab.html:90
msgid "internal"
msgstr "内部"
#: instances/templates/instances/snapshots_tab.html:83
msgid "current"
msgstr "当前"
#: instances/templates/instances/snapshots_tab.html:90
msgid "the VM goes on from this one"
msgstr "虚拟机从此快照继续"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
#, python-format
msgid "Revert to snapshot %(name)s? Changes made since it are lost."
msgstr "恢复到快照 %(name)s?此后所做的更改将丢失。"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid ""
"The VM is powered off and starts again from the snapshot's disks, as after a "
"power cut."
msgstr "虚拟机将关机,并从快照的磁盘重新启动,如同断电后一样。"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid "The VM is powered off and comes back paused on the snapshot's disks."
msgstr "虚拟机将关机,并在快照的磁盘上以暂停状态恢复。"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid ""
"These disks are detached; their writes since the current snapshot are "
"discarded and their files are kept:"
msgstr "以下磁盘将被分离;它们自当前快照以来的写入将被丢弃,文件会保留:"
#: instances/templates/instances/snapshots_tab.html:89
#: instances/templates/instances/snapshots_tab.html:96
msgid "Firmware variables (NVRAM) are not restored."
msgstr "固件变量(NVRAM)不会恢复。"
#: instances/templates/instances/snapshots_tab.html:90
#: instances/templates/instances/snapshots_tab.html:104
#: instances/templates/instances/snapshots_tab.html:97
#: instances/templates/instances/snapshots_tab.html:111
msgid "Revert"
msgstr "恢复"
#: instances/templates/instances/snapshots_tab.html:95
#: instances/templates/instances/snapshots_tab.html:102
#, python-format
msgid ""
"Delete snapshot %(name)s? Its files are merged with the disks; the VM's data "
"is kept."
msgstr "删除快照 %(name)s?其文件将合并到磁盘中;虚拟机的数据会保留。"
#: instances/templates/instances/snapshots_tab.html:102
#: instances/templates/instances/snapshots_tab.html:109
#, python-format
msgid ""
"Revert to snapshot %(name)s? Disk changes made since it are lost; a snapshot "
"of a running VM starts it again as it was then."
msgstr "恢复到快照 %(name)s?此后的磁盘更改将丢失;运行中虚拟机的快照会使其以当时的状态重新启动。"
#: instances/templates/instances/snapshots_tab.html:104
#: instances/templates/instances/snapshots_tab.html:116
#: instances/templates/instances/snapshots_tab.html:111
#: instances/templates/instances/snapshots_tab.html:130
msgid "Shut the VM down to revert to an internal snapshot."
msgstr "请先关闭虚拟机,再恢复到内部快照。"
#: instances/templates/instances/snapshots_tab.html:109
#: instances/templates/instances/snapshots_tab.html:116
#, python-format
msgid "Delete snapshot %(name)s? The VM's current disks are not changed."
msgstr "删除快照 %(name)s?虚拟机的当前磁盘不会改变。"
#: instances/templates/instances/snapshots_tab.html:118
#: instances/templates/instances/snapshots_tab.html:126
msgid "The VM has no snapshot."
msgstr "该虚拟机没有快照。"
#: instances/templates/instances/snapshots_tab.html:120
#: instances/templates/instances/snapshots_tab.html:131
#, python-format
msgid "Times in %(TIME_ZONE)s. A VM with snapshots cannot be migrated."
msgstr "时间以 %(TIME_ZONE)s 显示。有快照的虚拟机无法迁移。"

View file

@ -205,6 +205,31 @@ button.vcpu-cell:disabled { opacity: .65; }
.boot-text { min-width: 10rem; flex-basis: 10rem; }
.boot-chain .boot-spare-only, .boot-spare .boot-chain-only { display: none !important; }
/* the snapshots tab: the VM's history as a line, newest first; now on top, the snapshot the VM goes on from filled */
.snap-line { position: relative; padding-left: 1.75rem; }
.snap-line::before {
content: "";
position: absolute;
left: calc(.5rem - 1px);
top: .75rem;
bottom: .75rem;
border-left: 2px solid var(--bs-border-color);
}
.snap-node { position: relative; padding: .5rem 0; }
.snap-dot {
position: absolute;
left: -1.75rem;
top: .75rem;
width: 1rem;
height: 1rem;
border-radius: 50%;
border: 2px solid var(--bs-primary);
background: var(--bs-body-bg);
}
.snap-dot.bg-success, .snap-dot.bg-warning, .snap-dot.bg-secondary { border-color: transparent; }
.snap-dot.snap-current { background: var(--bs-primary); }
.snap-dot.snap-none { border-color: var(--bs-border-color); }
/* a log message keeps a readable width when its table scrolls on a phone */
.log-message {
min-width: 16rem;