resetbutton & almanach edit start

This commit is contained in:
Simon Martens
2025-05-30 19:30:50 +02:00
parent d8e50b27b0
commit 8ea36da40f
28 changed files with 1789 additions and 763 deletions

View File

@@ -9,23 +9,70 @@ type AlmanachResult struct {
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
EntriesAgents []*dbmodels.REntriesAgents
ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
User *dbmodels.User
Types []string
HasScans bool
}
-->
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
<div class="flex-col w-full">
{{ if $model.redirect_url }}
<a href="{{ $model.redirect_url }}" class="text-gray-700 hover:text-slate-950">
<i class="ri-arrow-left-s-line"></i> Zurück
</a>
{{ else }}
<a href="/" class="text-gray-700 hover:text-slate-950">
<i class="ri-arrow-left-s-line"></i> Startseite
</a>
{{ end }}
<h1 class="text-2xl self-baseline w-full my-6 font-bold text-slate-900">Almanach bearbeiten</h1>
<div class="flex container-normal bg-slate-100 mx-auto px-8">
<div class="flex flex-row w-full justify-between pb-6">
<div class="flex flex-col justify-end-safe pt-36 flex-2/5">
<a href="/almanach/{{ $model.result.Entry.MusenalmID }}" class="text-gray-700 hover:text-slate-950 block mb-2"><i class="ri-arrow-left-s-line"></i>Anschauen</a>
<h1 class="text-2xl w-full font-bold text-slate-900">Almanach bearbeiten</h1>
<!--
<div class="mt-1">
{{ $model.result.Entry.PreferredTitle }}
</div>
-->
</div>
<div class="flex flex-row" id="almanach-header-data">
<div class="flex flex-col justify-end gap-y-6 pr-20">
<div class="">
<div class="font-bold text-sm">
<i class="ri-database-2-line"></i> Datenbank-ID
<tool-tip position="right" class="!inline">
<div class="data-tip">Die Datenbank-ID kann zur Fehlerdiagnose hilfreich sein.</div>
<i class="ri-information-line"></i>
</tool-tip>
</div>
<div class="">{{ $model.result.Entry.Id }}</div>
</div>
</div>
<div class="flex flex-col justify-end gap-y-6 pr-4">
<div class="">
<div class="font-bold text-sm mb-1">
<i class="ri-hashtag"></i> Alm-Nummer
<tool-tip position="right" class="!inline">
<div class="data-tip">Die Alm-Nr ist Teil der URL und wird automatisch vergeben.</div>
<i class="ri-information-line"></i>
</tool-tip>
</div>
<div class="px-1.5 py-0.5 rounded-xs bg-gray-200 w-fit font-bold">{{ $model.result.Entry.MusenalmID }}</div>
</div>
<div class="">
<div class="font-bold text-sm mb-1"><i class="ri-calendar-line"></i> Zuletzt bearbeitet</div>
<div>
<div class="px-1.5 py-0.5 rounded-xs bg-gray-200 w-fit">
{{ GermanDate $model.result.Entry.Updated }};
{{ GermanTime
$model.result.Entry.Updated
}}
</div>
{{- if $model.result.User -}}
<div class="px-1.5 py-0.5 rounded-xs mt-1.5 bg-gray-200 w-fit">
<i class="ri-user-line mr-1"></i> {{- $model.result.User.Name -}}
</div>
{{- end -}}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container-normal mx-auto px-8 mt-4">
{{ template "_usermessage" $model }}
<form class="w-full grid grid-cols-12 gap-4" id="changealmanachform" x-target="changealmanachform user-message almanach-header-data" hx-boost="false" method="POST"></form>
</div>

View File

@@ -20,15 +20,11 @@
<div id="breadcrumbs">
<div>
<div>
<a href="/personen?letter={{- First $model.result.Agent.Name -}}"
>Personen &amp; Körperschaften</a
>
<a href="/personen?letter={{- First $model.result.Agent.Name -}}">Personen &amp; Körperschaften</a>
<i class="ri-arrow-right-wide-line"></i> <b>{{ $model.result.Agent.Name }}</b>
</div>
<div class="backbutton">
<a href="/personen/" class="no-underline">
<i class="ri-arrow-left-long-line"></i> Alle Personen &amp; Körperschaften
</a>
<a href="/personen/" class="no-underline"> <i class="ri-arrow-left-long-line"></i> Alle Personen &amp; Körperschaften </a>
</div>
</div>
</div>
@@ -155,32 +151,17 @@
<input type="checkbox" id="showall" autocomplete="off" />
<label for="showall" class="cursor-pointer select-none ml-1">Alle anzeigen</label>
<script type="module">
const tablist = document.getElementById("entries-tabs");
const checkbox = document.getElementById("showall");
entriestabs?.hookupShowAll(showall);
{{- if eq (len $model.result.CResult) 1 -}}
if (checkbox) {
if (tablist) {
tablist.showAll();
}
checkbox.checked = true;
checkbox.disabled = true;
}
{{- else -}}
if (tablist && checkbox) {
checkbox.addEventListener("change", () => {
if (checkbox && checkbox.checked) {
tablist.showAll();
} else {
tablist.default();
}
});
}
entriestabs?.showAll();
showall?.checked = true;
showall?.disabled = true;
{{- end -}}
</script>
</div>
</div>
<div class="mt-8">
<tab-list id="entries-tabs">
<tab-list id="entriestabs">
{{- range $_, $e := $model.result.CResult -}}
{{- $contents := index $model.result.Contents $e.Id -}}
<div
@@ -191,8 +172,7 @@
<i class="ri-arrow-right-s-fill show-closed"></i>
<i class="ri-arrow-down-s-fill show-opened"></i>
</div>
<div
class="inline-block font-sans bg-slate-800 text-white h-max text-sm px-1.5 rounded">
<div class="inline-block font-sans bg-slate-800 text-white h-max text-sm px-1.5 rounded">
{{- len $contents -}}
</div>
</div>

View File

@@ -14,42 +14,54 @@
<div class="flex container-normal mx-auto px-8 mt-4">
<div class="flex-col max-w-2xl w-full">
<form class="w-full grid grid-cols-3 gap-4" id="changeuserform" x-target="changeuserform footer" hx-boost="false" method="POST" x-data="{ openpw: false }">
<form
class="w-full flex flex-col gap-4 dbform"
id="changeuserform"
x-target="changeuserform
footer"
hx-boost="false"
method="POST"
x-data="{ openpw: false }"
@rbichange="FormHasChanged($el) ? resetb.classList.add('hidden') : resetb.classList.remove('hidden')">
<!-- INFO: MESSAGES -->
<div class="col-span-3">
{{ template "_usermessage" $model }}
</div>
<div
class="rounded-xs col-span-3 border-2 border-transparent px-3
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
<label for="username" class="text-sm text-gray-700 font-bold"> Name <i class="ri-text"></i> </label>
<input type="text" name="name" id="name" class="mt-1 block w-full focus:border-none focus:outline-none" placeholder="" required autocomplete="off" value="{{ $model.user.Name }}" autofocus />
<!-- INFO: BASIC FELDER -->
<div class="inputwrapper">
<label for="username" class="inputlabel"> Name <i class="ri-text"></i> </label>
<div class="flex flex-row">
<input type="text" name="name" id="name" class="inputinput" placeholder="" required autocomplete="off" value="{{ $model.user.Name }}" autofocus />
<reset-button controls="name" wrapper-class="inputwrapper" modified-class-suffix="modified"></reset-button>
</div>
</div>
<div
class="rounded-xs col-span-3 border-2 border-transparent px-3
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
<label for="username" class="text-sm text-gray-700 font-bold"> E-Mail <i class="ri-at-line"></i> </label>
<input type="email" name="username" id="username" autocomplete="off" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required value="{{ $model.user.Email }}" />
<div class="inputwrapper">
<label for="username" class="inputlabel"> E-Mail <i class="ri-at-line"></i> </label>
<div class="flex flex-row">
<input type="email" name="username" id="username" autocomplete="off" class="inputinput" placeholder="" required value="{{ $model.user.Email }}" />
<reset-button controls="username" wrapper-class="inputwrapper" modified-class-suffix="modified"></reset-button>
</div>
</div>
<div
class="rounded-xs col-span-3 border-2 border-transparent px-3
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
<label for="role" class="text-sm text-gray-700 font-bold"> Rolle <i class="ri-user-3-line"></i> </label>
<select
{{ if not (eq $model.request.user.Role "Admin") -}}
disabled
{{- end }}
name="role"
id="role"
autocomplete="off"
class="mt-1 block w-full rounded-md focus:border-none focus:outline-none
disabled:opacity-50">
<option value="User" {{ if eq $model.user.Role "User" }}selected{{ end }}>Benutzer</option>
<option value="Editor" {{ if eq $model.user.Role "Editor" }}selected{{ end }}>Redakteur</option>
<option value="Admin" {{ if eq $model.user.Role "Admin" }}selected{{ end }}>Administrator</option>
</select>
<!-- INFO: ROLLE -->
<div class="inputwrapper">
<label for="role" class="inputlabel"> Rolle <i class="ri-user-3-line"></i> </label>
<div class="flex flex-row">
<select
{{ if not (eq $model.request.user.Role "Admin") -}}
disabled
{{- end }}
name="role"
id="role"
autocomplete="off"
class="inputselect">
<option value="User" {{ if eq $model.user.Role "User" }}selected{{ end }}>Benutzer</option>
<option value="Editor" {{ if eq $model.user.Role "Editor" }}selected{{ end }}>Redakteur</option>
<option value="Admin" {{ if eq $model.user.Role "Admin" }}selected{{ end }}>Administrator</option>
</select>
<reset-button controls="role" wrapper-class="inputwrapper" modified-class-suffix="modified"></reset-button>
</div>
</div>
{{- if and
(eq $model.request.user.Role "Admin")
@@ -70,63 +82,49 @@
<p class="text-sm text-gray-700 max-w-[80ch]">Achtung! Wenn Sie die Rolle eines Benutzers ändern, wird dieser unter Umständen von laufenden Sitzungen abgemeldet und muss sich erneut anmelden.</p>
</div>
{{- end -}}
<!-- INFO: PW ÄNDERN AUSKLAPPEN -->
<div class="col-span-3">
<div class="flex items-center">
<input type="checkbox" name="openpw" id="openpw" x-model="openpw" class="mr-2" />
<label for="openpw" class="text-sm text-gray-700 font-bold"> Passwort ändern <i class="ri-key-2-line"></i> </label>
<label for="openpw" class="inputlabeltext"> Passwort ändern <i class="ri-key-2-line"></i> </label>
</div>
</div>
<!-- INFO: PASSWORT -->
{{- if not (eq $model.request.user.Role "Admin") -}}
<div
x-bind:style="!openpw ? 'display:none' : ''"
class="rounded-xs col-span-3 border-2 border-transparent px-3
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
<label for="password_old" class="text-sm text-gray-700 font-bold"> Altes Passwort </label>
<input x-bind:type="openpw ? 'password' : 'hidden'" name="password_old" id="password_old" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required />
<div x-bind:style="!openpw ? 'display:none' : ''" class="inputwrapper">
<label for="password_old" class="inputlabel"> Altes Passwort </label>
<input x-bind:type="openpw ? 'password' : 'hidden'" name="password_old" id="password_old" class="inputinput" placeholder="" required />
</div>
{{- end -}}
<div
x-bind:style="!openpw ? 'display:none' : ''"
class="rounded-xs col-span-3 border-2 border-transparent px-3
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
<label for="password" class="text-sm text-gray-700 font-bold"> Neues Passwort </label>
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password" id="password" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required />
<div x-bind:style="!openpw ? 'display:none' : ''" class="inputwrapper">
<label for="password" class="inputlabel"> Neues Passwort </label>
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password" id="password" class="inputinput" placeholder="" required />
</div>
<div
x-bind:style="!openpw ? 'display:none' : ''"
class="rounded-xs col-span-3 border-2 border-transparent px-3
py-1 pb-1.5 border-l-2 focus-within:border-l-slate-600
bg-slate-200 focus-within:bg-slate-100 transition-all duration-100">
<label for="password_repeat" class="text-sm text-gray-700 font-bold"> Passwort wiederholen </label>
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password_repeat" id="password_repeat" class="mt-1 block w-full rounded-md focus:border-none focus:outline-none" placeholder="" required />
<div x-bind:style="!openpw ? 'display:none' : ''" class="inputwrapper">
<label for="password_repeat" class="inputlabel"> Passwort wiederholen </label>
<input x-bind:type="openpw ? 'password' : 'hidden'" minlength="10" name="password_repeat" id="password_repeat" class="inputinput" placeholder="" required />
</div>
<div class="col-span-3 flex justify-end" x-bind:style="!openpw ? 'display:none' : ''">
<input type="checkbox" name="logout" id="logout" class="mr-2" x-bind:style="!openpw ? 'display:none' : ''" />
<label for="logout" class="text-sm text-gray-700 font-bold"> überall ausloggen <i class="ri-logout-box-line"></i> </label>
<label for="logout" class="inputlabeltext"><i class="ri-logout-box-line"></i> überall ausloggen</label>
</div>
<div class="col-span-1 col-start-2">
<a
href="/user/{{ $model.user.Id }}/edit?redirectTo={{ $model.redirect_url }}"
type="cancel"
class="w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md text-sm font-medium text-gray-800 bg-stone-200 hover:bg-stone-300 cursor-pointer focus:outline-none
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 no-underline">
Zurücksetzen
</a>
</div>
<div class="col-span-1 col-start-3">
<input type="hidden" name="csrf_token" id="csrf_token" required value="{{ $model.csrf_token }}" />
<button
type="submit"
class="w-full inline-flex justify-center py-2 px-4 border border-transparent rounded-md
shadow-sm text-sm font-medium text-white bg-slate-700 hover:bg-slate-800 cursor-pointer focus:outline-none
focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
Speichern
</button>
<!-- INFO: Buttons -->
<div class="grid grid-cols-3 gap-4 col-span-3 mt-6">
<div id="resetb" class="col-span-1 col-start-2 hidden">
<a href="/user/{{ $model.user.Id }}/edit?redirectTo={{ $model.redirect_url }}" type="cancel" class="resetbutton"> Zurücksetzen </a>
</div>
<div class="col-span-1 col-start-3">
<input type="hidden" name="csrf_token" id="csrf_token" required value="{{ $model.csrf_token }}" />
<button type="submit" class="submitbutton">Speichern</button>
</div>
</div>
</form>
<!-- INFO: Aktivieren/Deaktivieren -->
<div class="col-span-1 mt-12 justify-self-end self-end items-end flex flex-row justify-end">
{{ if not $model.user.Deactivated }}
<form id="actbtn" x-init @ajax:before="confirm('Der Benutzer {{ $model.user.Name }} wird deaktiviert und kann sich nicht mehr einloggen. Sicher?') || $event.preventDefault()" action="/user/{{ $model.user.Id }}/deactivate/" method="POST" hx-boost="false" x-target="user-message footer actbtn" x-target.away="_top">

View File

@@ -4,73 +4,8 @@
<script src="/assets/js/qrcode.min.js"></script>
<script type="module">
/**
* @param {number} timeout - Maximum time to wait in milliseconds.
* @param {number} interval - How often to check in milliseconds.
* @returns {Promise<Function>} Resolves with the QRCode constructor when available.
*/
function getQRCodeWhenAvailable(timeout = 5000, interval = 100) {
return new Promise((resolve, reject) => {
let elapsedTime = 0;
const checkInterval = setInterval(() => {
if (typeof window.QRCode === "function") {
clearInterval(checkInterval);
resolve(window.QRCode); // Resolve with the QRCode object/function
} else {
elapsedTime += interval;
if (elapsedTime >= timeout) {
clearInterval(checkInterval);
console.error("Timed out waiting for QRCode to become available.");
reject(new Error("QRCode not available after " + timeout + "ms. Check if qrcode.min.js is loaded correctly and sets window.QRCode."));
}
}
}, interval);
});
}
// INFO: We have to wait for the QRCode object to be available. It's messy.
async function genQRCode() {
console.debug("Generating QR Code...");
const QRCode = await getQRCodeWhenAvailable();
const tokenElement = document.getElementById("token");
const qrElement = document.getElementById("qr");
if (qrElement) {
// INFO: Clear previous QR code if any
// Also hide it initially to prevent flickering
qrElement.innerHTML = "";
qrElement.classList.add("hidden");
new QRCode(qrElement, {
text: tokenElement.value,
width: 1280,
height: 1280,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H,
});
setTimeout(() => {
qrElement.classList.remove("hidden");
}, 20);
}
// Add event listeners to the token input field to select its content on focus or click
if (tokenElement) {
tokenElement.addEventListener("focus", (ev) => {
ev.preventDefault();
tokenElement.select();
});
tokenElement.addEventListener("mousedown", (ev) => {
ev.preventDefault();
tokenElement.select();
});
tokenElement.addEventListener("mouseup", (ev) => {
ev.preventDefault();
tokenElement.select();
});
}
}
genQRCode();
window.genQRCode = genQRCode;
GenQRCode(token.value);
SelectableInput(token);
</script>
<div class="flex container-normal bg-slate-100 mx-auto !pt-36 px-8">
@@ -135,7 +70,7 @@
<i class="ri-external-link-line"></i>
</a>
</tool-tip>
<form class="" method="POST" hx-boost="false" x-target="token access-link qrinfo" @ajax:after="genQRCode()">
<form class="" method="POST" hx-boost="false" x-target="token access-link qrinfo" @ajax:after="GenQRCode(token.value); SelectableInput(token)">
<input type="hidden" name="csrf_token" id="csrf_token" required value="{{ $model.csrf_token }}" />
<div class="col-span-9 flex flex-row items-center justify-center">
<tool-tip position="top">