Tag upload auf den Buzzer, Sync-Status in der Webapp
This commit is contained in:
@@ -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}
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -28,3 +28,16 @@ export interface BuzzerFile {
|
|||||||
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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user