v0.7.98-beta - het heet nu gewoon een app
Some checks failed
Deploy server-up (dev) / deploy (push) Failing after 15m46s

- "stack" heet in de interface voortaan "app": 24 teksten per taal plus de
  terugvalteksten in de pagina. Je installeerde een app uit de App Store en
  kreeg een stack; dat moest je maar net weten
- code, API-paden, mapnamen en .serverup.json houden `stack` — dat leest
  niemand, en hernoemen zou opgeslagen gegevens en URL's breken
- de aparte sectie "Overige containers" is verdwenen. Handmatig gestarte
  containers staan nu tussen de rest met het label "Handmatig gestart", met
  starten, stoppen en logs. De zoekterm geldt voor allebei; een
  categoriefilter laat ze vallen, want ze hebben geen categorie
- de waarschuwing bij backups zei nog dat appdata er niet in zit; sinds
  v0.7.88 zit die er juist wel in, met een databasedump erbij

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
This commit is contained in:
Ramon 2026-08-03 19:42:41 +02:00
parent 842615a562
commit 299ccf507c
6 changed files with 164 additions and 92 deletions

View file

@ -1,3 +1,25 @@
# v0.7.98-beta — Het heet nu gewoon een app
Je installeerde een **app** uit de **App Store** en kreeg een **stack**. Dat
moest je maar net weten. In de interface heet alles nu een app: 24 teksten per
taal plus de terugvalteksten in de pagina zelf.
De code, de API-paden (`/api/stacks/…`), de mapnamen en `.serverup.json` houden
`stack`. Dat zijn geen woorden die iemand leest, en ze hernoemen zou opgeslagen
gegevens en URL's breken zonder dat er iets duidelijker van wordt.
**De tweede lijst is verdwenen.** "Overige containers" stond als aparte sectie
onderaan, met een eigen kop, een eigen uitleg en een eigen vormgeving. Wie zijn
apps kwijt was moest weten dat die lijst bestond. Handmatig gestarte containers
staan nu gewoon tussen de rest, als kaart, met het label **Handmatig gestart**.
Er is minder mee te doen — starten, stoppen, logs — maar ze zijn wel te vinden.
De zoekterm werkt op allebei; een categoriefilter laat ze vallen, want ze hébben
geen categorie.
Onderweg gevonden: de waarschuwing bij backups zei nog dat een backup *"niet de
Docker-volumes met de eigenlijke appdata"* bevat. Sinds v0.7.88 zit de appdata er
juist wél in, met een dump van elke database erbij. Die tekst klopt nu.
# v0.7.97-beta — Repo's bijwerken werkte niet meer # v0.7.97-beta — Repo's bijwerken werkte niet meer
**`fatal: Cannot rebase onto multiple branches.`** Het bijwerken van een **`fatal: Cannot rebase onto multiple branches.`** Het bijwerken van een

View file

@ -1 +1 @@
0.7.97-beta 0.7.98-beta

View file

@ -221,12 +221,12 @@ tailwind.config = {
</button> </button>
<button class="stat-card text-left hover:shadow-soft2 transition" @click="goto('stacks')"> <button class="stat-card text-left hover:shadow-soft2 transition" @click="goto('stacks')">
<div class="stat-icon bg-ac/10 text-ac dark:text-ac-dark"><span class="mdi mdi-folder-multiple-outline"></span></div> <div class="stat-icon bg-ac/10 text-ac dark:text-ac-dark"><span class="mdi mdi-folder-multiple-outline"></span></div>
<div class="min-w-0"><div class="stat-value" x-text="stacks.length"></div><div class="stat-label">Stacks</div></div> <div class="min-w-0"><div class="stat-value" x-text="stacks.length"></div><div class="stat-label">Apps</div></div>
</button> </button>
</div> </div>
<div class="flex items-center gap-3 mb-3"> <div class="flex items-center gap-3 mb-3">
<h2 class="text-sm font-bold text-wh dark:text-wh-dark uppercase tracking-wide" x-text="t('stacks')">Stacks</h2> <h2 class="text-sm font-bold text-wh dark:text-wh-dark uppercase tracking-wide" x-text="t('stacks')">Apps</h2>
<button @click="loadDashboard()" class="btn-icon ml-auto w-9 h-9"><span class="mdi mdi-refresh"></span></button> <button @click="loadDashboard()" class="btn-icon ml-auto w-9 h-9"><span class="mdi mdi-refresh"></span></button>
</div> </div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4" x-show="stacks.length > 0"> <div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4" x-show="stacks.length > 0">
@ -240,7 +240,7 @@ tailwind.config = {
</button> </button>
</template> </template>
</div> </div>
<div x-show="stacks.length === 0" class="empty"><span class="mdi mdi-server-network"></span><p x-text="t('no_stacks')">Geen stacks</p></div> <div x-show="stacks.length === 0" class="empty"><span class="mdi mdi-server-network"></span><p x-text="t('no_stacks')">Geen apps</p></div>
</section> </section>
<!-- ══ Stacks ══ --> <!-- ══ Stacks ══ -->
@ -296,7 +296,8 @@ tailwind.config = {
</button> </button>
</div> </div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4" x-show="filteredStacks.length > 0"> <div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4"
x-show="filteredStacks.length || filteredLos.length">
<template x-for="s in filteredStacks" :key="s.name"> <template x-for="s in filteredStacks" :key="s.name">
<div class="card card-hover flex flex-col border-l-4" <div class="card card-hover flex flex-col border-l-4"
:style="'border-left-color:' + cat((s.categories || [])[0] || 'overig').color"> :style="'border-left-color:' + cat((s.categories || [])[0] || 'overig').color">
@ -437,48 +438,52 @@ tailwind.config = {
</div> </div>
</div> </div>
</template> </template>
</div>
<div x-show="filteredStacks.length === 0" class="empty"><span class="mdi mdi-server-network"></span><p x-text="t('no_stacks')">Geen stacks gevonden</p></div>
<!-- Containers die niet bij een door Server Up beheerde stack horen. <!-- Handmatig gestarte containers staan in dezelfde lijst. Ze horen
Zonder dit blok tellen ze wel mee op het dashboard maar zijn ze niet bij een app die Server Up heeft aangemaakt, dus er is minder
nergens terug te vinden. --> mee te doen — maar ze apart onderaan zetten maakte ze onvindbaar
<div x-show="unmanaged.length" class="mt-8"> en gaf ze een tweederangs plek die niemand hielp. -->
<div class="flex items-center gap-2 mb-2"> <template x-for="c in filteredLos" :key="c.id">
<span class="mdi mdi-cube-outline text-t2 dark:text-t2-dark"></span> <div class="card card-hover flex flex-col border-l-4 border-l-bd dark:border-l-bd-dark">
<h3 class="text-sm font-bold text-wh dark:text-wh-dark" x-text="t('other_containers')">Overige containers</h3> <div class="px-4 py-3.5 flex items-center gap-2.5 border-b border-bd dark:border-bd-dark">
<span class="badge badge-dim" x-text="unmanaged.length"></span> <span class="w-8 h-8 rounded-lg bg-s2 dark:bg-s2-dark grid place-items-center text-base shrink-0">📦</span>
<button class="btn-icon ml-auto w-9 h-9" @click="loadHostContainers()"><span class="mdi mdi-refresh"></span></button> <span class="w-2.5 h-2.5 rounded-full shrink-0"
:class="c.running ? 'bg-ok shadow-[0_0_8px_#22c55e]' : 'bg-dm dark:bg-dm-dark'"></span>
<span class="font-semibold text-wh dark:text-wh-dark text-sm flex-1 truncate" x-text="c.name"></span>
<span x-show="c.self" class="badge badge-info" x-text="t('this_app')">deze app</span>
<span class="badge" :class="c.running ? 'badge-ok' : 'badge-dim'"
x-text="c.running ? t('running') : t('stopped')"></span>
</div> </div>
<p class="text-xs text-t2 dark:text-t2-dark mb-3" x-text="t('other_containers_hint')"></p> <div class="p-4 flex flex-col gap-3 flex-1">
<div class="card divide-y divide-bd dark:divide-bd-dark"> <div class="flex flex-wrap gap-1 items-center">
<template x-for="c in unmanaged" :key="c.id"> <span class="badge badge-dim" x-text="t('manual_started')">Handmatig gestart</span>
<div class="px-4 py-3 flex flex-wrap items-center gap-2"> <span x-show="c.project" class="badge badge-dim" x-text="c.project"></span>
<span class="w-2.5 h-2.5 rounded-full shrink-0" :class="c.running ? 'bg-ok' : 'bg-dm dark:bg-dm-dark'"></span>
<div class="min-w-0 flex-1">
<div class="text-sm font-semibold text-wh dark:text-wh-dark truncate" x-text="c.name"></div>
<div class="text-[10px] font-mono text-dm dark:text-dm-dark truncate">
<span x-text="c.image"></span><span x-show="c.ports"> · </span><span x-text="c.ports"></span>
</div> </div>
<div class="text-[11px] font-mono text-dm dark:text-dm-dark break-all">
<span x-text="c.image"></span>
<template x-if="c.ports"><span> · <span x-text="c.ports"></span></span></template>
</div> </div>
<span class="badge badge-dim" x-show="c.project" x-text="c.project"></span>
<span class="badge badge-info" x-show="c.self" x-text="t('this_app')">deze app</span>
<template x-if="!c.self"> <template x-if="!c.self">
<div class="flex gap-1.5"> <div class="flex flex-wrap gap-1.5 mt-auto">
<button class="btn-sm !h-8 !px-2" :title="c.running ? t('stop') : t('start')" <button class="btn-sm flex-1 min-w-[84px]" :class="c.running ? 'btn-danger' : 'btn-primary'"
@click="hostContainerAction(c.name, c.running ? 'stop' : 'start')"> @click="hostContainerAction(c.name, c.running ? 'stop' : 'start')">
<span class="mdi" :class="c.running ? 'mdi-stop' : 'mdi-play'"></span> <span class="mdi" :class="c.running ? 'mdi-stop' : 'mdi-play'"></span>
<span x-text="c.running ? t('stop') : t('start')"></span>
</button> </button>
<button class="btn-sm !h-8 !px-2" :title="t('restart')" <button class="btn-sm" :title="t('restart')"
@click="hostContainerAction(c.name, 'restart')"><span class="mdi mdi-restart"></span></button> @click="hostContainerAction(c.name, 'restart')"><span class="mdi mdi-restart"></span></button>
<button class="btn-sm !h-8 !px-2" :title="t('logs')" <button class="btn-sm" :title="t('logs')"
@click="openHostLogs(c.name)"><span class="mdi mdi-text-box-outline"></span></button> @click="openHostLogs(c.name)"><span class="mdi mdi-text-box-outline"></span></button>
</div> </div>
</template> </template>
</div> </div>
</div>
</template> </template>
</div> </div>
</div> <div x-show="!filteredStacks.length && !filteredLos.length" class="empty"><span class="mdi mdi-server-network"></span><p x-text="t('no_stacks')">Geen apps gevonden</p></div>
<p x-show="filteredLos.length" class="text-xs text-t2 dark:text-t2-dark mt-4"
x-text="t('manual_hint')"></p>
</section> </section>
<!-- ══ App Store ══ --> <!-- ══ App Store ══ -->
@ -920,7 +925,7 @@ tailwind.config = {
</p> </p>
<div class="grid sm:grid-cols-2 gap-3"> <div class="grid sm:grid-cols-2 gap-3">
<div> <div>
<label class="form-label" x-text="t('backup_keep')">Aantal per stack</label> <label class="form-label" x-text="t('backup_keep')">Aantal per app</label>
<input type="number" min="0" class="form-input" x-model.number="settings.BACKUP_KEEP" @change="autoSave()"> <input type="number" min="0" class="form-input" x-model.number="settings.BACKUP_KEEP" @change="autoSave()">
</div> </div>
<div> <div>
@ -1679,7 +1684,7 @@ tailwind.config = {
sm:h-auto sm:max-h-[88vh] sm:rounded-2xl"> sm:h-auto sm:max-h-[88vh] sm:rounded-2xl">
<div class="modal-head"> <div class="modal-head">
<span class="mdi mdi-download-outline text-ac dark:text-ac-dark shrink-0"></span> <span class="mdi mdi-download-outline text-ac dark:text-ac-dark shrink-0"></span>
<span class="min-w-0 truncate" x-text="install.mode === 'edit' ? t('stack_settings') : t('install_stack')">Stack installeren</span> <span class="min-w-0 truncate" x-text="install.mode === 'edit' ? t('stack_settings') : t('install_stack')">App installeren</span>
<span x-show="install.format === 'boilerplate'" class="badge badge-info hidden sm:inline-flex">Boilerplate</span> <span x-show="install.format === 'boilerplate'" class="badge badge-info hidden sm:inline-flex">Boilerplate</span>
<!-- Op een telefoon vult deze modal het scherm, dus er is geen <!-- Op een telefoon vult deze modal het scherm, dus er is geen
achtergrond meer om op te tikken. Zonder deze knop kom je er niet uit. --> achtergrond meer om op te tikken. Zonder deze knop kom je er niet uit. -->
@ -2090,7 +2095,7 @@ tailwind.config = {
<!-- Legacy fields --> <!-- Legacy fields -->
<template x-if="install.format === 'compose' && !install.loading"> <template x-if="install.format === 'compose' && !install.loading">
<div class="space-y-4"> <div class="space-y-4">
<div><label class="form-label">Stack</label><input class="form-input" :value="install.stack" readonly></div> <div><label class="form-label">App</label><input class="form-input" :value="install.stack" readonly></div>
<div x-show="install.mode !== 'edit'"> <div x-show="install.mode !== 'edit'">
<label class="form-label" x-text="t('instance_name')">Instantie naam</label> <label class="form-label" x-text="t('instance_name')">Instantie naam</label>
<input class="form-input" x-model="install.instance"> <input class="form-input" x-model="install.instance">
@ -2166,7 +2171,7 @@ tailwind.config = {
<div x-show="modal==='remove'" class="modal max-w-md"> <div x-show="modal==='remove'" class="modal max-w-md">
<div class="modal-head"><span class="mdi mdi-delete-alert-outline text-er"></span> <span x-text="t('remove_stack')">Verwijderen</span></div> <div class="modal-head"><span class="mdi mdi-delete-alert-outline text-er"></span> <span x-text="t('remove_stack')">Verwijderen</span></div>
<div class="modal-body"> <div class="modal-body">
<p class="text-sm mb-4 text-t2 dark:text-t2-dark">Stack: <strong class="text-wh dark:text-wh-dark" x-text="install.stack"></strong></p> <p class="text-sm mb-4 text-t2 dark:text-t2-dark">App: <strong class="text-wh dark:text-wh-dark" x-text="install.stack"></strong></p>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<button class="btn" @click="doRemove('stack')"><span class="mdi mdi-stop-circle-outline"></span> <span x-text="t('remove_stack_only')">Stop + volumes</span></button> <button class="btn" @click="doRemove('stack')"><span class="mdi mdi-stop-circle-outline"></span> <span x-text="t('remove_stack_only')">Stop + volumes</span></button>
<button class="btn btn-danger" @click="doRemove('all')"><span class="mdi mdi-delete-outline"></span> <span x-text="t('remove_all')">Verwijder alles</span></button> <button class="btn btn-danger" @click="doRemove('all')"><span class="mdi mdi-delete-outline"></span> <span x-text="t('remove_all')">Verwijder alles</span></button>
@ -2310,7 +2315,7 @@ tailwind.config = {
<div x-show="wizardStapId() === 'welkom'"> <div x-show="wizardStapId() === 'welkom'">
<p class="text-sm">Doorloop deze korte wizard om Server Up te configureren.</p> <p class="text-sm">Doorloop deze korte wizard om Server Up te configureren.</p>
<ul class="text-sm mt-4 space-y-2 text-t2 dark:text-t2-dark"> <ul class="text-sm mt-4 space-y-2 text-t2 dark:text-t2-dark">
<li class="flex gap-2"><span class="mdi mdi-check-circle text-ok"></span> Beheer Docker stacks via één UI</li> <li class="flex gap-2"><span class="mdi mdi-check-circle text-ok"></span> Beheer je Docker-apps via één UI</li>
<li class="flex gap-2"><span class="mdi mdi-check-circle text-ok"></span> Installeer apps uit je eigen repo of de Boilerplates</li> <li class="flex gap-2"><span class="mdi mdi-check-circle text-ok"></span> Installeer apps uit je eigen repo of de Boilerplates</li>
<li class="flex gap-2"><span class="mdi mdi-check-circle text-ok"></span> Modules toevoegen voor MQTT, Home Assistant, etc.</li> <li class="flex gap-2"><span class="mdi mdi-check-circle text-ok"></span> Modules toevoegen voor MQTT, Home Assistant, etc.</li>
</ul> </ul>
@ -2323,7 +2328,7 @@ tailwind.config = {
<div x-show="wizardStapId() === 'repos'"> <div x-show="wizardStapId() === 'repos'">
<p class="text-sm mb-3">Server Up start met deze repos. Je kunt later meer toevoegen via Instellingen → Git Repositories.</p> <p class="text-sm mb-3">Server Up start met deze repos. Je kunt later meer toevoegen via Instellingen → Git Repositories.</p>
<ul class="text-sm space-y-2.5"> <ul class="text-sm space-y-2.5">
<li class="flex items-start gap-2"><span class="mdi mdi-check-circle text-ok mt-0.5"></span><span><strong>bes-r/server-up</strong> — eigen stacks &amp; modules <span class="text-dm dark:text-dm-dark">(submap: apps / modules)</span></span></li> <li class="flex items-start gap-2"><span class="mdi mdi-check-circle text-ok mt-0.5"></span><span><strong>bes-r/server-up</strong> — eigen apps &amp; modules <span class="text-dm dark:text-dm-dark">(submap: apps / modules)</span></span></li>
<li class="flex items-start gap-2"><span class="mdi mdi-check-circle text-ok mt-0.5"></span><span><strong>ChristianLempa/boilerplates-library</strong> — community templates <span class="text-dm dark:text-dm-dark">(submap: compose)</span></span></li> <li class="flex items-start gap-2"><span class="mdi mdi-check-circle text-ok mt-0.5"></span><span><strong>ChristianLempa/boilerplates-library</strong> — community templates <span class="text-dm dark:text-dm-dark">(submap: compose)</span></span></li>
</ul> </ul>
</div> </div>
@ -2333,7 +2338,7 @@ tailwind.config = {
<span class="mdi mdi-server text-2xl"></span><span class="font-semibold">Al een server</span><span class="text-[10px] text-center opacity-70">Gitea / Forgejo of andere git</span> <span class="mdi mdi-server text-2xl"></span><span class="font-semibold">Al een server</span><span class="text-[10px] text-center opacity-70">Gitea / Forgejo of andere git</span>
</button> </button>
<button @click="wizard.git.choice = 'install'" :class="wizard.git.choice === 'install' ? 'border-ac text-ac dark:text-ac-dark bg-ac/5' : 'border-bd dark:border-bd-dark text-t2 dark:text-t2-dark'" class="flex flex-col items-center gap-1.5 rounded-xl border p-3 text-xs transition cursor-pointer hover:border-ac"> <button @click="wizard.git.choice = 'install'" :class="wizard.git.choice === 'install' ? 'border-ac text-ac dark:text-ac-dark bg-ac/5' : 'border-bd dark:border-bd-dark text-t2 dark:text-t2-dark'" class="flex flex-col items-center gap-1.5 rounded-xl border p-3 text-xs transition cursor-pointer hover:border-ac">
<span class="mdi mdi-download-circle-outline text-2xl"></span><span class="font-semibold">Installeer Forgejo</span><span class="text-[10px] text-center opacity-70">Forgejo als stack</span> <span class="mdi mdi-download-circle-outline text-2xl"></span><span class="font-semibold">Installeer Forgejo</span><span class="text-[10px] text-center opacity-70">Forgejo als app</span>
</button> </button>
<button @click="wizard.git.choice = 'skip'" :class="wizard.git.choice === 'skip' ? 'border-ac text-ac dark:text-ac-dark bg-ac/5' : 'border-bd dark:border-bd-dark text-t2 dark:text-t2-dark'" class="flex flex-col items-center gap-1.5 rounded-xl border p-3 text-xs transition cursor-pointer hover:border-ac"> <button @click="wizard.git.choice = 'skip'" :class="wizard.git.choice === 'skip' ? 'border-ac text-ac dark:text-ac-dark bg-ac/5' : 'border-bd dark:border-bd-dark text-t2 dark:text-t2-dark'" class="flex flex-col items-center gap-1.5 rounded-xl border p-3 text-xs transition cursor-pointer hover:border-ac">
<span class="mdi mdi-skip-next-circle-outline text-2xl"></span><span class="font-semibold">Overslaan</span><span class="text-[10px] text-center opacity-70">Later toe te voegen</span> <span class="mdi mdi-skip-next-circle-outline text-2xl"></span><span class="font-semibold">Overslaan</span><span class="text-[10px] text-center opacity-70">Later toe te voegen</span>
@ -3011,6 +3016,17 @@ function app() {
return !q || (s.name || '').toLowerCase().includes(q); return !q || (s.name || '').toLowerCase().includes(q);
}); });
}, },
// Containers die niet bij een app horen die Server Up heeft aangemaakt.
// Ze staan in dezelfde lijst en volgen dus dezelfde zoekterm. Een
// categoriefilter laat ze wél vallen: ze hebben geen categorieën, dus ze
// horen niet bij "alleen Media" te blijven staan.
get filteredLos() {
if (this.stackCat) return [];
const q = this.stackQuery.toLowerCase();
return this.unmanaged.filter(c =>
!q || (c.name || '').toLowerCase().includes(q)
|| (c.image || '').toLowerCase().includes(q));
},
// Categorieën van de geïnstalleerde stacks, met hun aantal. // Categorieën van de geïnstalleerde stacks, met hun aantal.
get stackCategories() { get stackCategories() {
const telling = {}; const telling = {};

View file

@ -5,7 +5,7 @@
"flag": "🇬🇧" "flag": "🇬🇧"
}, },
"dashboard": "Dashboard", "dashboard": "Dashboard",
"stacks": "Stacks", "stacks": "Apps",
"app_store": "App Store", "app_store": "App Store",
"images": "Docker Images", "images": "Docker Images",
"audit": "Audit Log", "audit": "Audit Log",
@ -47,7 +47,7 @@
"language": "Language", "language": "Language",
"git": "Git", "git": "Git",
"docker": "Docker", "docker": "Docker",
"no_stacks": "No stacks found", "no_stacks": "No apps found",
"no_images": "No images found", "no_images": "No images found",
"no_repos": "No repositories", "no_repos": "No repositories",
"add_repo": "Add repository", "add_repo": "Add repository",
@ -55,10 +55,10 @@
"repo_url": "Git URL", "repo_url": "Git URL",
"repo_branch": "Branch", "repo_branch": "Branch",
"repo_subdir": "Subdirectory", "repo_subdir": "Subdirectory",
"install_stack": "Install stack", "install_stack": "Install app",
"instance_name": "Instance name", "instance_name": "Instance name",
"instance_hint": "Change for multiple installations", "instance_hint": "Change for multiple installations",
"remove_stack": "Remove stack", "remove_stack": "Remove app",
"remove_stack_only": "Stop containers + volumes", "remove_stack_only": "Stop containers + volumes",
"remove_all": "Stop + remove all files", "remove_all": "Stop + remove all files",
"prune_images": "Remove all unused images?", "prune_images": "Remove all unused images?",
@ -75,7 +75,7 @@
"wizard_paths": "Set paths", "wizard_paths": "Set paths",
"wizard_paths_sub": "Where should your Docker projects be stored?", "wizard_paths_sub": "Where should your Docker projects be stored?",
"wizard_git": "Git repositories", "wizard_git": "Git repositories",
"wizard_git_sub": "Synchronise your stacks and modules.", "wizard_git_sub": "Synchronise your apps and modules.",
"wizard_done": "All done!", "wizard_done": "All done!",
"wizard_done_sub": "Setup complete. Change anything later in Settings.", "wizard_done_sub": "Setup complete. Change anything later in Settings.",
"prev": "Previous", "prev": "Previous",
@ -152,7 +152,7 @@
"trusted_proxies_hint": "One per line, IP or CIDR. The header is only trusted from these addresses — without this list anyone could impersonate an administrator.", "trusted_proxies_hint": "One per line, IP or CIDR. The header is only trusted from these addresses — without this list anyone could impersonate an administrator.",
"proxy_lockout_confirm": "In 'Reverse proxy' mode the local login is disabled. Are you sure your proxy works?", "proxy_lockout_confirm": "In 'Reverse proxy' mode the local login is disabled. Are you sure your proxy works?",
"networks": "Networks", "networks": "Networks",
"networks_hint": "A macvlan or ipvlan network gives a stack its own IP address on your LAN instead of ports on the host. No more port conflicts, and you can firewall per app. Note: the Docker host itself cannot reach macvlan containers without a shim interface.", "networks_hint": "A macvlan or ipvlan network gives a app its own IP address on your LAN instead of ports on the host. No more port conflicts, and you can firewall per app. Note: the Docker host itself cannot reach macvlan containers without a shim interface.",
"add_network": "Add network", "add_network": "Add network",
"network": "Network", "network": "Network",
"no_networks": "No networks yet.", "no_networks": "No networks yet.",
@ -167,8 +167,8 @@
"ports_on_host": "Ports on the host (default)", "ports_on_host": "Ports on the host (default)",
"own_ip": "own IP", "own_ip": "own IP",
"ip_address": "IP address", "ip_address": "IP address",
"own_ip_hint": "The stack gets this address on your LAN. Port mappings are dropped — the app is reachable on its own port. The Docker host itself cannot reach a macvlan container without a shim interface (see docs/netwerken.md).", "own_ip_hint": "The app gets this address on your LAN. Port mappings are dropped — the app is reachable on its own port. The Docker host itself cannot reach a macvlan container without a shim interface (see docs/netwerken.md).",
"no_networks_hint": "Want to give stacks their own IP? Add a network first under Settings → Networks.", "no_networks_hint": "Want to give apps their own IP? Add a network first under Settings → Networks.",
"generate_value": "Generate a random value", "generate_value": "Generate a random value",
"port_taken": "Port {port} is already in use — {suggested} suggested.", "port_taken": "Port {port} is already in use — {suggested} suggested.",
"channel": "Channel", "channel": "Channel",
@ -196,25 +196,25 @@
"backups": "Backups", "backups": "Backups",
"no_backups": "No backups yet", "no_backups": "No backups yet",
"restore": "Restore", "restore": "Restore",
"restore_confirm": "Restore backup {file}?\n\nThe current files of this stack will be replaced and the stack restarted.", "restore_confirm": "Restore backup {file}?\n\nThe current files of this app will be replaced and the app restarted.",
"delete_backup_confirm": "Delete this backup?", "delete_backup_confirm": "Delete this backup?",
"backup_scope_warning": "A backup contains the stack's compose and .env files, not the Docker volumes holding the actual app data. See docs/backups.md.", "backup_scope_warning": "A backup contains the app's compose and .env files, the appdata next to them, and a dump of every database it uses. Docker volumes the app creates itself are not included. See docs/backups.md.",
"backup_retention": "Retention", "backup_retention": "Retention",
"backup_keep": "Backups to keep per stack", "backup_keep": "Backups to keep per app",
"backup_max_age": "Maximum age (days, 0 = no limit)", "backup_max_age": "Maximum age (days, 0 = no limit)",
"backup_schedule": "Scheduled backups", "backup_schedule": "Scheduled backups",
"backup_schedule_off": "Off", "backup_schedule_off": "Off",
"backup_schedule_daily": "Daily", "backup_schedule_daily": "Daily",
"backup_schedule_weekly": "Weekly", "backup_schedule_weekly": "Weekly",
"backup_schedule_hour": "Around which hour", "backup_schedule_hour": "Around which hour",
"backup_before_update": "Automatically back up before updating a stack", "backup_before_update": "Automatically back up before updating a app",
"backup_before_remove": "Automatically back up before removing a stack", "backup_before_remove": "Automatically back up before removing a app",
"check_updates": "Check for updates", "check_updates": "Check for updates",
"stack_update_check": "Check daily whether newer images are available", "stack_update_check": "Check daily whether newer images are available",
"role_admin": "Administrator", "role_admin": "Administrator",
"role_operator": "Operator", "role_operator": "Operator",
"role_viewer": "Read-only", "role_viewer": "Read-only",
"roles_hint": "An administrator may do everything. An operator manages stacks, containers and backups, but not settings, users, repositories or networks. Read-only cannot change anything.", "roles_hint": "An administrator may do everything. An operator manages apps, containers and backups, but not settings, users, repositories or networks. Read-only cannot change anything.",
"proxy_role": "Role for proxy users", "proxy_role": "Role for proxy users",
"proxy_role_hint": "Anyone signing in through the reverse proxy without their own account gets this role.", "proxy_role_hint": "Anyone signing in through the reverse proxy without their own account gets this role.",
"no_permission": "Your role does not allow this action", "no_permission": "Your role does not allow this action",
@ -241,10 +241,8 @@
"range_count": "{count} addresses", "range_count": "{count} addresses",
"already_added": "already added", "already_added": "already added",
"detect_empty": "No network with a default route was found on this server. Fill in the details below manually.", "detect_empty": "No network with a default route was found on this server. Fill in the details below manually.",
"wizard_hint": "Run the wizard again to adjust paths and repositories. Your existing stacks are left untouched.", "wizard_hint": "Run the wizard again to adjust paths and repositories. Your existing apps are left untouched.",
"of_which_managed": "of which {n} via Server Up", "of_which_managed": "of which {n} via Server Up",
"other_containers": "Other containers",
"other_containers_hint": "These containers run on this host but do not belong to a stack managed by Server Up — started manually, for example, or from before you began using Server Up. They do count towards the dashboard figures.",
"this_app": "this app", "this_app": "this app",
"advanced_options": "Advanced options", "advanced_options": "Advanced options",
"what_does_this_do": "What does this setting do?", "what_does_this_do": "What does this setting do?",
@ -252,15 +250,15 @@
"enter_manually": "Enter manually…", "enter_manually": "Enter manually…",
"no_connectable_app": "No {app} is installed yet. Install it first, or enter the address manually.", "no_connectable_app": "No {app} is installed yet. Install it first, or enter the address manually.",
"connect_apps": "Connect to other apps", "connect_apps": "Connect to other apps",
"connect_apps_hint": "Put this stack on the shared network '{net}' so it can reach other apps by name and vice versa. Without this, every stack stands alone.", "connect_apps_hint": "Put this app on the shared network '{net}' so it can reach other apps by name and vice versa. Without this, every app stands alone.",
"filter_on_category": "Filter by this category", "filter_on_category": "Filter by this category",
"categories": "Categories", "categories": "Categories",
"stack_settings": "Settings", "stack_settings": "Settings",
"reconfigure_warning": "The stack is rebuilt from its template. Manual changes to the compose file will be lost — a backup is made first automatically.", "reconfigure_warning": "The app is rebuilt from its template. Manual changes to the compose file will be lost — a backup is made first automatically.",
"reconfigure_confirm": "Save settings for {stack}?\n\nA backup is made first, then the stack is rebuilt and restarted.", "reconfigure_confirm": "Save settings for {stack}?\n\nA backup is made first, then the app is rebuilt and restarted.",
"connect_to_apps": "Connect to other apps", "connect_to_apps": "Connect to other apps",
"connected_to_apps": "Already connected to other apps", "connected_to_apps": "Already connected to other apps",
"connect_stack_confirm": "Put {stack} on the shared network '{net}'?\n\nThe stack will be restarted.", "connect_stack_confirm": "Put {stack} on the shared network '{net}'?\n\nThe app will be restarted.",
"all_time": "All time", "all_time": "All time",
"last_day": "24 hours", "last_day": "24 hours",
"last_week": "7 days", "last_week": "7 days",
@ -371,7 +369,7 @@
"audit_cat_notify": "Notifications", "audit_cat_notify": "Notifications",
"audit_cat_pangolin": "Pangolin", "audit_cat_pangolin": "Pangolin",
"audit_cat_repos": "Repositories", "audit_cat_repos": "Repositories",
"audit_cat_stacks": "Stacks", "audit_cat_stacks": "Apps",
"audit_cat_store": "App store", "audit_cat_store": "App store",
"audit_cat_update": "Updates", "audit_cat_update": "Updates",
"audit_cat_wizard": "Wizard", "audit_cat_wizard": "Wizard",
@ -429,7 +427,7 @@
"col_action": "Action", "col_action": "Action",
"col_status": "Status", "col_status": "Status",
"col_ref": "Subject", "col_ref": "Subject",
"open_stack": "Go to stack", "open_stack": "Go to app",
"more": "More", "more": "More",
"ok": "OK", "ok": "OK",
"failed": "Failed", "failed": "Failed",
@ -462,7 +460,10 @@
"apply_all": "Apply to all", "apply_all": "Apply to all",
"path_unusable": "This path cannot be used", "path_unusable": "This path cannot be used",
"paths_changed": "The folders have changed", "paths_changed": "The folders have changed",
"paths_move_hint": "The setting is saved, but your data is still in the old place and every stack still points there. Moving copies everything first, updates the stacks, and only then clears out the old folders.", "paths_move_hint": "The setting is saved, but your data is still in the old place and every app still points there. Moving copies everything first, updates the apps, and only then clears out the old folders.",
"move_data": "Move data", "move_data": "Move data",
"move_data_confirm": "Move {n} folder(s)? Stacks are stopped, data is copied and verified, and only then is the old cleared out." "move_data_confirm": "Move {n} folder(s)? Apps are stopped, data is copied and verified, and only then is the old cleared out.",
"manual_started": "Started manually",
"manual_hint": "These apps run on this host but were not created by Server Up — started manually, or from before you began using Server Up. You can start, stop and view their logs here.",
"containers_n": "{n} containers"
} }

View file

@ -5,7 +5,7 @@
"flag": "🇳🇱" "flag": "🇳🇱"
}, },
"dashboard": "Dashboard", "dashboard": "Dashboard",
"stacks": "Stacks", "stacks": "Apps",
"app_store": "App Store", "app_store": "App Store",
"images": "Docker Images", "images": "Docker Images",
"audit": "Audit Log", "audit": "Audit Log",
@ -47,7 +47,7 @@
"language": "Taal", "language": "Taal",
"git": "Git", "git": "Git",
"docker": "Docker", "docker": "Docker",
"no_stacks": "Geen stacks gevonden", "no_stacks": "Geen apps gevonden",
"no_images": "Geen images gevonden", "no_images": "Geen images gevonden",
"no_repos": "Geen repositories", "no_repos": "Geen repositories",
"add_repo": "Repository toevoegen", "add_repo": "Repository toevoegen",
@ -55,10 +55,10 @@
"repo_url": "Git URL", "repo_url": "Git URL",
"repo_branch": "Branch", "repo_branch": "Branch",
"repo_subdir": "Submap", "repo_subdir": "Submap",
"install_stack": "Stack installeren", "install_stack": "App installeren",
"instance_name": "Instantie naam", "instance_name": "Instantie naam",
"instance_hint": "Wijzig voor meerdere installaties", "instance_hint": "Wijzig voor meerdere installaties",
"remove_stack": "Stack verwijderen", "remove_stack": "App verwijderen",
"remove_stack_only": "Stop containers + volumes", "remove_stack_only": "Stop containers + volumes",
"remove_all": "Stop + verwijder alle bestanden", "remove_all": "Stop + verwijder alle bestanden",
"prune_images": "Alle ongebruikte images verwijderen?", "prune_images": "Alle ongebruikte images verwijderen?",
@ -75,7 +75,7 @@
"wizard_paths": "Mappen instellen", "wizard_paths": "Mappen instellen",
"wizard_paths_sub": "Waar worden je Docker-projecten opgeslagen?", "wizard_paths_sub": "Waar worden je Docker-projecten opgeslagen?",
"wizard_git": "Git repositories", "wizard_git": "Git repositories",
"wizard_git_sub": "Synchroniseer je stacks en modules.", "wizard_git_sub": "Synchroniseer je apps en modules.",
"wizard_done": "Klaar!", "wizard_done": "Klaar!",
"wizard_done_sub": "Setup is voltooid. Wijzig alles later via Instellingen.", "wizard_done_sub": "Setup is voltooid. Wijzig alles later via Instellingen.",
"prev": "Vorige", "prev": "Vorige",
@ -152,7 +152,7 @@
"trusted_proxies_hint": "Eén per regel, IP of CIDR. Alleen vanaf deze adressen wordt de header vertrouwd — zonder deze lijst kan iedereen zich voordoen als beheerder.", "trusted_proxies_hint": "Eén per regel, IP of CIDR. Alleen vanaf deze adressen wordt de header vertrouwd — zonder deze lijst kan iedereen zich voordoen als beheerder.",
"proxy_lockout_confirm": "In modus 'Reverse proxy' vervalt de lokale login. Weet je zeker dat je proxy werkt?", "proxy_lockout_confirm": "In modus 'Reverse proxy' vervalt de lokale login. Weet je zeker dat je proxy werkt?",
"networks": "Netwerken", "networks": "Netwerken",
"networks_hint": "Met een macvlan- of ipvlan-netwerk krijgt een stack een eigen IP-adres in je LAN in plaats van poorten op de host. Geen poortconflicten meer, en je kunt per app firewallen. Let op: de Docker-host zelf bereikt macvlan-containers niet zonder shim-interface.", "networks_hint": "Met een macvlan- of ipvlan-netwerk krijgt een app een eigen IP-adres in je LAN in plaats van poorten op de host. Geen poortconflicten meer, en je kunt per app firewallen. Let op: de Docker-host zelf bereikt macvlan-containers niet zonder shim-interface.",
"add_network": "Netwerk toevoegen", "add_network": "Netwerk toevoegen",
"network": "Netwerk", "network": "Netwerk",
"no_networks": "Nog geen netwerken.", "no_networks": "Nog geen netwerken.",
@ -167,8 +167,8 @@
"ports_on_host": "Poorten op de host (standaard)", "ports_on_host": "Poorten op de host (standaard)",
"own_ip": "eigen IP", "own_ip": "eigen IP",
"ip_address": "IP-adres", "ip_address": "IP-adres",
"own_ip_hint": "De stack krijgt dit adres in het LAN. Poortmappings vervallen — de app is bereikbaar op zijn eigen poort. De Docker-host zelf kan een macvlan-container niet bereiken zonder shim-interface (zie docs/netwerken.md).", "own_ip_hint": "De app krijgt dit adres in het LAN. Poortmappings vervallen — de app is bereikbaar op zijn eigen poort. De Docker-host zelf kan een macvlan-container niet bereiken zonder shim-interface (zie docs/netwerken.md).",
"no_networks_hint": "Wil je stacks een eigen IP geven? Voeg eerst een netwerk toe bij Instellingen → Netwerken.", "no_networks_hint": "Wil je apps een eigen IP geven? Voeg eerst een netwerk toe bij Instellingen → Netwerken.",
"generate_value": "Genereer een willekeurige waarde", "generate_value": "Genereer een willekeurige waarde",
"port_taken": "Poort {port} is al in gebruik — {suggested} voorgesteld.", "port_taken": "Poort {port} is al in gebruik — {suggested} voorgesteld.",
"channel": "Kanaal", "channel": "Kanaal",
@ -196,25 +196,25 @@
"backups": "Backups", "backups": "Backups",
"no_backups": "Nog geen backups", "no_backups": "Nog geen backups",
"restore": "Terugzetten", "restore": "Terugzetten",
"restore_confirm": "Backup {file} terugzetten?\n\nDe huidige bestanden van deze stack worden vervangen en de stack wordt herstart.", "restore_confirm": "Backup {file} terugzetten?\n\nDe huidige bestanden van deze app worden vervangen en de app wordt herstart.",
"delete_backup_confirm": "Deze backup verwijderen?", "delete_backup_confirm": "Deze backup verwijderen?",
"backup_scope_warning": "Een backup bevat de compose- en .env-bestanden van de stack, niet de Docker-volumes met de eigenlijke appdata. Zie docs/backups.md.", "backup_scope_warning": "Een backup bevat de compose- en .env-bestanden van de app, de appdata ernaast, en een dump van elke database die erbij hoort. Docker-volumes die de app zelf aanmaakt gaan niet mee. Zie docs/backups.md.",
"backup_retention": "Bewaarbeleid", "backup_retention": "Bewaarbeleid",
"backup_keep": "Aantal backups per stack", "backup_keep": "Aantal backups per app",
"backup_max_age": "Maximale leeftijd (dagen, 0 = geen limiet)", "backup_max_age": "Maximale leeftijd (dagen, 0 = geen limiet)",
"backup_schedule": "Geplande backups", "backup_schedule": "Geplande backups",
"backup_schedule_off": "Uit", "backup_schedule_off": "Uit",
"backup_schedule_daily": "Dagelijks", "backup_schedule_daily": "Dagelijks",
"backup_schedule_weekly": "Wekelijks", "backup_schedule_weekly": "Wekelijks",
"backup_schedule_hour": "Rond welk uur", "backup_schedule_hour": "Rond welk uur",
"backup_before_update": "Automatisch een backup vóór het bijwerken van een stack", "backup_before_update": "Automatisch een backup vóór het bijwerken van een app",
"backup_before_remove": "Automatisch een backup vóór het verwijderen van een stack", "backup_before_remove": "Automatisch een backup vóór het verwijderen van een app",
"check_updates": "Updates controleren", "check_updates": "Updates controleren",
"stack_update_check": "Dagelijks controleren of er nieuwere images zijn", "stack_update_check": "Dagelijks controleren of er nieuwere images zijn",
"role_admin": "Beheerder", "role_admin": "Beheerder",
"role_operator": "Operator", "role_operator": "Operator",
"role_viewer": "Alleen lezen", "role_viewer": "Alleen lezen",
"roles_hint": "Beheerder mag alles. Operator beheert stacks, containers en backups, maar niet de instellingen, gebruikers, repo's of netwerken. Alleen lezen kan niets wijzigen.", "roles_hint": "Beheerder mag alles. Operator beheert apps, containers en backups, maar niet de instellingen, gebruikers, repo's of netwerken. Alleen lezen kan niets wijzigen.",
"proxy_role": "Rol voor proxy-gebruikers", "proxy_role": "Rol voor proxy-gebruikers",
"proxy_role_hint": "Iedereen die via de reverse proxy binnenkomt en geen eigen account heeft, krijgt deze rol.", "proxy_role_hint": "Iedereen die via de reverse proxy binnenkomt en geen eigen account heeft, krijgt deze rol.",
"no_permission": "Je rol geeft geen toegang tot deze actie", "no_permission": "Je rol geeft geen toegang tot deze actie",
@ -241,10 +241,8 @@
"range_count": "{count} adressen", "range_count": "{count} adressen",
"already_added": "al toegevoegd", "already_added": "al toegevoegd",
"detect_empty": "Er is geen netwerk met een default route gevonden op deze server. Vul de gegevens hieronder handmatig in.", "detect_empty": "Er is geen netwerk met een default route gevonden op deze server. Vul de gegevens hieronder handmatig in.",
"wizard_hint": "Doorloop de wizard opnieuw om paden en repositories aan te passen. Je bestaande stacks blijven staan.", "wizard_hint": "Doorloop de wizard opnieuw om paden en repositories aan te passen. Je bestaande apps blijven staan.",
"of_which_managed": "waarvan {n} via Server Up", "of_which_managed": "waarvan {n} via Server Up",
"other_containers": "Overige containers",
"other_containers_hint": "Deze containers draaien op deze host maar horen niet bij een stack die Server Up beheert — bijvoorbeeld handmatig gestart of van vóór je Server Up ging gebruiken. Ze tellen wel mee in de cijfers op het dashboard.",
"this_app": "deze app", "this_app": "deze app",
"advanced_options": "Geavanceerde opties", "advanced_options": "Geavanceerde opties",
"what_does_this_do": "Wat doet deze instelling?", "what_does_this_do": "Wat doet deze instelling?",
@ -252,15 +250,15 @@
"enter_manually": "Handmatig invullen…", "enter_manually": "Handmatig invullen…",
"no_connectable_app": "Er is nog geen {app} geïnstalleerd. Installeer die eerst, of vul het adres handmatig in.", "no_connectable_app": "Er is nog geen {app} geïnstalleerd. Installeer die eerst, of vul het adres handmatig in.",
"connect_apps": "Verbinden met andere apps", "connect_apps": "Verbinden met andere apps",
"connect_apps_hint": "Zet deze stack op het gedeelde netwerk '{net}', zodat hij andere apps op hun naam kan bereiken en andersom. Zonder dit staat elke stack op zichzelf.", "connect_apps_hint": "Zet deze app op het gedeelde netwerk '{net}', zodat hij andere apps op hun naam kan bereiken en andersom. Zonder dit staat elke app op zichzelf.",
"filter_on_category": "Filter op deze categorie", "filter_on_category": "Filter op deze categorie",
"categories": "Categorieën", "categories": "Categorieën",
"stack_settings": "Instellingen", "stack_settings": "Instellingen",
"reconfigure_warning": "De stack wordt opnieuw opgebouwd uit het sjabloon. Handmatige wijzigingen in het compose-bestand gaan daarbij verloren — er wordt eerst automatisch een backup gemaakt.", "reconfigure_warning": "De app wordt opnieuw opgebouwd uit het sjabloon. Handmatige wijzigingen in het compose-bestand gaan daarbij verloren — er wordt eerst automatisch een backup gemaakt.",
"reconfigure_confirm": "Instellingen van {stack} opslaan?\n\nEr wordt eerst een backup gemaakt; daarna wordt de stack opnieuw opgebouwd en herstart.", "reconfigure_confirm": "Instellingen van {stack} opslaan?\n\nEr wordt eerst een backup gemaakt; daarna wordt de app opnieuw opgebouwd en herstart.",
"connect_to_apps": "Koppelen aan andere apps", "connect_to_apps": "Koppelen aan andere apps",
"connected_to_apps": "Al gekoppeld aan andere apps", "connected_to_apps": "Al gekoppeld aan andere apps",
"connect_stack_confirm": "{stack} op het gedeelde netwerk '{net}' zetten?\n\nDe stack wordt daarna herstart.", "connect_stack_confirm": "{stack} op het gedeelde netwerk '{net}' zetten?\n\nDe app wordt daarna herstart.",
"all_time": "Altijd", "all_time": "Altijd",
"last_day": "24 uur", "last_day": "24 uur",
"last_week": "7 dagen", "last_week": "7 dagen",
@ -371,7 +369,7 @@
"audit_cat_notify": "Meldingen", "audit_cat_notify": "Meldingen",
"audit_cat_pangolin": "Pangolin", "audit_cat_pangolin": "Pangolin",
"audit_cat_repos": "Repositories", "audit_cat_repos": "Repositories",
"audit_cat_stacks": "Stacks", "audit_cat_stacks": "Apps",
"audit_cat_store": "App Store", "audit_cat_store": "App Store",
"audit_cat_update": "Bijwerken", "audit_cat_update": "Bijwerken",
"audit_cat_wizard": "Wizard", "audit_cat_wizard": "Wizard",
@ -429,7 +427,7 @@
"col_action": "Actie", "col_action": "Actie",
"col_status": "Status", "col_status": "Status",
"col_ref": "Betreft", "col_ref": "Betreft",
"open_stack": "Naar de stack", "open_stack": "Naar de app",
"more": "Meer", "more": "Meer",
"ok": "Gelukt", "ok": "Gelukt",
"failed": "Mislukt", "failed": "Mislukt",
@ -462,7 +460,10 @@
"apply_all": "Alles overnemen", "apply_all": "Alles overnemen",
"path_unusable": "Dit pad is niet bruikbaar", "path_unusable": "Dit pad is niet bruikbaar",
"paths_changed": "De mappen zijn gewijzigd", "paths_changed": "De mappen zijn gewijzigd",
"paths_move_hint": "De instelling is opgeslagen, maar je data staat nog op de oude plek en elke stack wijst daar nog naartoe. Verplaatsen kopieert eerst alles, werkt de stacks bij, en ruimt de oude mappen pas daarna op.", "paths_move_hint": "De instelling is opgeslagen, maar je data staat nog op de oude plek en elke app wijst daar nog naartoe. Verplaatsen kopieert eerst alles, werkt de apps bij, en ruimt de oude mappen pas daarna op.",
"move_data": "Data verplaatsen", "move_data": "Data verplaatsen",
"move_data_confirm": "{n} map(pen) verplaatsen? De stacks worden gestopt, de data wordt gekopieerd en gecontroleerd, en pas daarna wordt het oude opgeruimd." "move_data_confirm": "{n} map(pen) verplaatsen? De apps worden gestopt, de data wordt gekopieerd en gecontroleerd, en pas daarna wordt het oude opgeruimd.",
"manual_started": "Handmatig gestart",
"manual_hint": "Deze apps draaien op deze host maar zijn niet door Server Up aangemaakt — handmatig gestart, of van vóór je Server Up ging gebruiken. Je kunt ze hier starten, stoppen en hun logs bekijken.",
"containers_n": "{n} containers"
} }

View file

@ -397,6 +397,38 @@ check('balk staat halverwege', c.job.progress.pct === 50);
c.rpc = poortRpc; c.rpc = poortRpc;
// ── Eén lijst voor beheerde en handmatig gestarte apps ────────────────────
// Ze stonden in twee lijsten onder elkaar, waarvan de tweede een kop, een
// uitleg en een eigen vormgeving had. Wie zijn apps kwijt was, moest weten
// dat er een tweede lijst bestond.
c.stacks = [{name: 'sonarr', categories: ['media']},
{name: 'vaultwarden', categories: ['tools']}];
c.hostContainers = {containers: [
{id: '1', name: 'oude-nginx', image: 'nginx:alpine', managed: false},
{id: '2', name: 'sonarr', image: 'lscr.io/sonarr', managed: true},
]};
c.stackQuery = ''; c.stackCat = '';
check('beheerde apps staan in de lijst', c.filteredStacks.length === 2);
check('handmatig gestarte apps ook', c.filteredLos.length === 1);
check('en niet dubbel', c.filteredLos[0].name === 'oude-nginx');
c.stackQuery = 'nginx';
check('de zoekterm geldt voor allebei',
c.filteredStacks.length === 0 && c.filteredLos.length === 1);
c.stackQuery = 'sonarr';
check('een beheerde app blijft over', c.filteredStacks.length === 1);
check('en de handmatige valt af', c.filteredLos.length === 0);
c.stackQuery = 'lscr';
check('zoeken kan ook op image', c.filteredLos.length === 0);
c.stackQuery = 'alpine';
check('van een handmatig gestarte app', c.filteredLos.length === 1);
// Een categoriefilter hoort ze te laten vallen: ze hébben geen categorie.
c.stackQuery = ''; c.stackCat = 'media';
check('categoriefilter laat handmatige apps vallen', c.filteredLos.length === 0);
check('en houdt de beheerde over', c.filteredStacks.length === 1);
// Een leeg of onzinnig veld hoort geen verzoek te sturen. // Een leeg of onzinnig veld hoort geen verzoek te sturen.
c.install.values.port = 0; c.install.values.port = 0;
gevraagd = []; gevraagd = [];