Tag upload auf den Buzzer, Sync-Status in der Webapp

This commit is contained in:
2026-03-17 15:53:34 +01:00
parent 574ab9fa30
commit 735129d83d
3 changed files with 72 additions and 8 deletions

View File

@@ -10,6 +10,9 @@
QuestionIcon, QuestionIcon,
TagIcon, TagIcon,
UserIcon, UserIcon,
CheckCircleIcon,
WarningIcon,
WarningCircleIcon,
} from "phosphor-svelte"; } from "phosphor-svelte";
import { import {
isFetchingRemote, isFetchingRemote,
@@ -43,6 +46,52 @@
$: syncStatus = $syncStateMap[type][file.name] || { state: SyncState.UNKNOWN, linkedFiles: [] }; $: syncStatus = $syncStateMap[type][file.name] || { state: SyncState.UNKNOWN, linkedFiles: [] };
$: statusConfig = (() => {
switch (syncStatus.state) {
case SyncState.UNKNOWN:
return {
icon: QuestionIcon,
color: "text-amber-500",
variant: "warning",
text: "Prüfsumme fehlt. Bitte Metadaten aktualisieren.",
};
case SyncState.SINGLE_SIDED:
return {
icon: CircleIcon,
color: "text-green-600",
variant: "info",
text: `Datei existiert nur ${type === "buzzer" ? "auf dem Buzzer" : "lokal"}.`,
};
case SyncState.SYNCED:
return {
icon: CheckCircleIcon,
color: "text-green-600",
variant: "info",
text: "Datei ist synchronisiert.",
};
case SyncState.CONFLICT:
return {
icon: WarningIcon,
color: "text-amber-600",
variant: "warning",
text: `Konflikt: Name/Tags weichen ab. Vergleiche mit <span class="text-medium text-on-surface bg-white rounded px-1">${syncStatus.linkedFiles[0]}</span> ${type === "buzzer" ? "lokal" : "auf dem Buzzer"}`,
};
case SyncState.DUPLICATE:
const duplicateText =
syncStatus.linkedFiles.length === 0
? `Diese Datei ist hier ok, aber ${type === "buzzer" ? "lokal" : "auf dem Buzzer"} existieren mehrere identische Versionen.`
: `Mehrfach vorhanden: Gleicher Inhalt auch in <span class="text-medium text-on-surface bg-white rounded px-1">${syncStatus.linkedFiles.join("</span> <span class='text-medium text-on-surface bg-white rounded px-1'>")}</span>`;
return {
icon: WarningCircleIcon,
color: "text-red-600",
variant: "danger",
text: duplicateText,
};
default:
return null;
}
})();
function toggleSelection() { function toggleSelection() {
if ($isFetchingRemote) return; if ($isFetchingRemote) return;
@@ -102,16 +151,19 @@
</div> </div>
<div class="flex items-center gap-0 text-xs text-text-muted mt-0.5 min-w-0"> <div class="flex items-center gap-0 text-xs text-text-muted mt-0.5 min-w-0">
{#if syncStatus.state === SyncState.UNKNOWN} {#if statusConfig}
<span <span
use:tooltip={{ use:tooltip={{
text: text: statusConfig.text,
"Dieser Datei fehlt der CRC32-Tag. Bitte aktualisiere über das Menu die Metadaten.", pos: "right",
pos: "right", variant: statusConfig.variant,
variant: "warning",
}} }}
> >
<CircleIcon weight="fill" class="mr-1 shrink-0 text-emerald-600 w-3.5 h-3.5" /> <svelte:component
this={statusConfig.icon}
weight="fill"
class="mr-1 shrink-0 w-3.5 h-3.5 {statusConfig.color}"
/>
</span> </span>
{/if} {/if}

View File

@@ -1,7 +1,6 @@
import { writable, derived } from 'svelte/store'; import { writable, derived } from 'svelte/store';
import type { BuzzerFile } from './types'; import{ type BuzzerFile, SyncState, type SyncStatus } from './types';
import { SETTINGS } from './settings'; import { SETTINGS } from './settings';
import { syncState, type SyncStatus } from './sync';
const CONNECTION_STATE_KEY = 'buzzer_connection_state'; const CONNECTION_STATE_KEY = 'buzzer_connection_state';

View File

@@ -27,4 +27,17 @@ export interface BuzzerFile {
sysTags: SystemTags; sysTags: SystemTags;
metaTags: MetadataTags; metaTags: MetadataTags;
selected: boolean; selected: boolean;
}
export enum SyncState {
UNKNOWN = "UNKNOWN", // Amber Question (Keine CRC32)
SINGLE_SIDED = "SINGLE_SIDED", // Green Circle (Nur lokal oder nur remote)
SYNCED = "SYNCED", // Green CheckCircle (Beidseitig, identisch)
CONFLICT = "CONFLICT", // Amber Warning (Beidseitig, abweichender Name/Tags)
DUPLICATE = "DUPLICATE" // Red Warning (Mehrfach gleiche CRC32 auf einer Seite)
}
export interface SyncStatus {
state: SyncState;
linkedFiles: string[]; // Referenzen auf die Dateinamen der Gegenseite (für Tooltips)
} }