import { LitElement, html, nothing } from 'lit';
|
import { customElement, state } from 'lit/decorators.js';
|
import { event, type EventRef } from '@dh-software/lit-extensions';
|
import type { DhInput } from '@dh-software/dh-components';
|
import type { EinstellungenAnsicht } from 'bibliothek-types';
|
import { ladeEinstellungen, speichereEinstellungen, exportUrl, importiereUmzugsPaket } from '../api-client';
|
|
/** Einstellungen der Anwendung — nur direkt am Server erreichbar. */
|
@customElement('bibliothek-einstellungen')
|
export class BibliothekEinstellungen extends LitElement {
|
@state() private ansicht?: EinstellungenAnsicht;
|
@state() private datenOrdner = '';
|
@state() private port = 3000;
|
@state() private gitBenutzer = '';
|
@state() private gitSchluessel = '';
|
@state() private meldung = '';
|
@state() private fehler = '';
|
@state() private speichert = false;
|
|
@event({ bubbles: true, composed: true }, 'geschlossen')
|
private geschlossen!: EventRef<void>;
|
|
@event({ bubbles: true, composed: true }, 'umzugAbgeschlossen')
|
private umzugAbgeschlossen!: EventRef<void>;
|
|
// Light DOM, damit das globale dh-components-Theme greift.
|
createRenderRoot() {
|
return this;
|
}
|
|
connectedCallback(): void {
|
super.connectedCallback();
|
this.einstellungenLaden();
|
}
|
|
render() {
|
if (!this.ansicht) {
|
return html`<dh-card variant="outlined"><span slot="content">Einstellungen werden geladen …</span></dh-card>`;
|
}
|
const neustartNoetig =
|
this.datenOrdner.trim() !== this.ansicht.einstellungen.datenOrdner || this.port !== this.ansicht.laufenderPort;
|
return html`
|
<dh-card variant="outlined" no-hover-effect no-click-effect>
|
<span slot="header">Einstellungen</span>
|
<div slot="content">
|
<dh-form-grid>
|
<dh-form-field label="Datenordner" span="2">
|
<dh-input
|
type="text"
|
placeholder=${'leer = Standardordner unter ProgramData'}
|
.value=${this.datenOrdner}
|
@input=${this.beiDatenOrdner}
|
></dh-input>
|
<span class="feldhinweis">Hier liegen die Datenbank und alle bereitgestellten Programm-Dateien.</span>
|
</dh-form-field>
|
<dh-form-field label="Port">
|
<dh-input type="number" min="1" max="65535" .value=${String(this.port)} @input=${this.beiPort}></dh-input>
|
</dh-form-field>
|
<dh-form-field label="Git-Benutzer (für interne Tools)">
|
<dh-input
|
type="text"
|
placeholder="leer = SSH-Konfiguration des Dienstbenutzers"
|
.value=${this.gitBenutzer}
|
@input=${this.beiGitBenutzer}
|
></dh-input>
|
<span class="feldhinweis">
|
Gilt für alle Git-Quellen. Dadurch bleiben die Katalog-URLs frei von Konto-Angaben — ein
|
Kontowechsel ist eine Änderung hier statt an jedem Eintrag.
|
</span>
|
</dh-form-field>
|
<dh-form-field label="SSH-Schlüssel (optional)">
|
<dh-input
|
type="text"
|
placeholder="C:\\ProgramData\\Software-Bibliothek\\id_bibliothek"
|
.value=${this.gitSchluessel}
|
@input=${this.beiGitSchluessel}
|
></dh-input>
|
<span class="feldhinweis">
|
Nur nötig, wenn das Konto, unter dem die Bibliothek läuft, keinen eigenen SSH-Schlüssel hat —
|
sonst leer lassen. Wird relevant beim Betrieb als Dienst oder nach einem Serverumzug.
|
</span>
|
</dh-form-field>
|
</dh-form-grid>
|
|
<dl class="einstellungen-infos">
|
<dt>Datenordner (aktuell genutzt)</dt>
|
<dd>${this.ansicht.effektiverDatenOrdner}</dd>
|
<dt>Konfigurationsdatei</dt>
|
<dd>${this.ansicht.konfigurationsDatei}</dd>
|
<dt>Laufender Port</dt>
|
<dd>${this.ansicht.laufenderPort}</dd>
|
</dl>
|
|
<div class="umzug">
|
<h3>Umzug auf einen anderen Rechner</h3>
|
<p class="feldhinweis">
|
Gesichert werden Katalog, Bezugsquellen und Einstellungen — wenige Kilobyte. Die geholten
|
Programm-Dateien kommen nicht mit; die holt der Abgleich auf dem neuen Rechner selbst wieder.
|
</p>
|
<div class="umzug-aktionen">
|
<dh-button buttonText="Exportieren" variant="standard" @click=${this.beiExport}></dh-button>
|
<dh-button buttonText="Mit Schlüsseln exportieren" variant="standard" @click=${this.beiExportMitGeheimnissen}></dh-button>
|
<dh-button buttonText="Paket einlesen" variant="standard" @click=${this.beiImportWaehlen}></dh-button>
|
<input id="import-datei" type="file" accept="application/json,.json" hidden @change=${this.beiImportDatei} />
|
</div>
|
<p class="feldhinweis warnhinweis">
|
„Mit Schlüsseln" schreibt die hinterlegten Werte im Klartext in die Datei — nur bewusst nutzen
|
und die Datei danach sicher aufbewahren bzw. löschen.
|
</p>
|
</div>
|
|
${neustartNoetig ? html`<p class="hinweis">Änderungen an Datenordner oder Port wirken erst nach einem Neustart der Anwendung.</p>` : nothing}
|
${this.meldung ? html`<p class="hinweis">${this.meldung}</p>` : nothing}
|
</div>
|
<div slot="actions">
|
${this.fehler ? html`<span class="fehler">${this.fehler}</span>` : nothing}
|
<dh-button buttonText="Schließen" variant="standard" @click=${this.beiSchliessen}></dh-button>
|
<dh-button
|
buttonText=${this.speichert ? 'Speichert…' : 'Speichern'}
|
variant="filled"
|
?disabled=${this.speichert}
|
@click=${this.beiSpeichern}
|
></dh-button>
|
</div>
|
</dh-card>
|
`;
|
}
|
|
private async einstellungenLaden(): Promise<void> {
|
try {
|
this.ansicht = await ladeEinstellungen();
|
this.datenOrdner = this.ansicht.einstellungen.datenOrdner;
|
this.port = this.ansicht.einstellungen.port;
|
this.gitBenutzer = this.ansicht.einstellungen.gitBenutzer;
|
this.gitSchluessel = this.ansicht.einstellungen.gitSchluessel;
|
} catch (fehler) {
|
this.fehler = fehler instanceof Error ? fehler.message : 'Einstellungen konnten nicht geladen werden.';
|
}
|
}
|
|
private beiDatenOrdner(ereignis: Event): void {
|
this.datenOrdner = (ereignis.target as DhInput).value;
|
}
|
|
private beiPort(ereignis: Event): void {
|
this.port = Number((ereignis.target as DhInput).value) || 0;
|
}
|
|
private beiGitBenutzer(ereignis: Event): void {
|
this.gitBenutzer = (ereignis.target as DhInput).value;
|
}
|
|
private beiGitSchluessel(ereignis: Event): void {
|
this.gitSchluessel = (ereignis.target as DhInput).value;
|
}
|
|
private beiSchliessen(): void {
|
this.geschlossen.dispatch();
|
}
|
|
private beiExport(): void {
|
window.location.href = exportUrl(false);
|
}
|
|
private beiExportMitGeheimnissen(): void {
|
if (confirm('Die Datei enthält dann die hinterlegten Schlüssel im Klartext. Wirklich so exportieren?')) {
|
window.location.href = exportUrl(true);
|
}
|
}
|
|
private beiImportWaehlen(): void {
|
this.querySelector<HTMLInputElement>('#import-datei')?.click();
|
}
|
|
private async beiImportDatei(ereignis: Event): Promise<void> {
|
const feld = ereignis.target as HTMLInputElement;
|
const datei = feld.files?.[0];
|
feld.value = ''; // erlaubt, dieselbe Datei erneut zu wählen
|
if (!datei) {
|
return;
|
}
|
if (!confirm('Der bisherige Katalog wird dabei vollständig ersetzt. Fortfahren?')) {
|
return;
|
}
|
this.fehler = '';
|
this.meldung = '';
|
try {
|
const ergebnis = await importiereUmzugsPaket(JSON.parse(await datei.text()));
|
this.meldung = `${ergebnis.uebernommen} Einträge übernommen${ergebnis.mitGeheimnissen > 0 ? `, davon ${ergebnis.mitGeheimnissen} mit Schlüsseln` : ''}. ${ergebnis.hinweis}`;
|
this.umzugAbgeschlossen.dispatch();
|
} catch (fehler) {
|
this.fehler = fehler instanceof Error ? fehler.message : 'Paket konnte nicht eingelesen werden.';
|
}
|
}
|
|
private async beiSpeichern(): Promise<void> {
|
this.speichert = true;
|
this.fehler = '';
|
this.meldung = '';
|
try {
|
this.ansicht = await speichereEinstellungen({
|
datenOrdner: this.datenOrdner.trim(),
|
port: this.port,
|
gitBenutzer: this.gitBenutzer.trim(),
|
gitSchluessel: this.gitSchluessel.trim(),
|
});
|
this.datenOrdner = this.ansicht.einstellungen.datenOrdner;
|
this.port = this.ansicht.einstellungen.port;
|
this.gitBenutzer = this.ansicht.einstellungen.gitBenutzer;
|
this.gitSchluessel = this.ansicht.einstellungen.gitSchluessel;
|
this.meldung = 'Gespeichert. Datenordner und Port gelten ab dem nächsten Start.';
|
} catch (fehler) {
|
this.fehler = fehler instanceof Error ? fehler.message : 'Speichern fehlgeschlagen.';
|
} finally {
|
this.speichert = false;
|
}
|
}
|
}
|
|
declare global {
|
interface HTMLElementTagNameMap {
|
'bibliothek-einstellungen': BibliothekEinstellungen;
|
}
|
}
|