139 lines
5.5 KiB
Vue
139 lines
5.5 KiB
Vue
<script setup>
|
|
import { computed, ref } from 'vue'
|
|
import { route } from 'ziggy-js'
|
|
|
|
const props = defineProps({
|
|
labels: { type: Array, default: () => [] },
|
|
last_labels_import: { type: Object, default: () => ({}) },
|
|
})
|
|
|
|
const uploading = ref(false)
|
|
const result = ref(null)
|
|
const error = ref(null)
|
|
|
|
const sortedLabels = computed(() => [...props.labels].sort((a, b) => a.name.localeCompare(b.name)))
|
|
|
|
async function handleFileChange(event) {
|
|
const file = event.target.files[0]
|
|
if (!file) return
|
|
uploading.value = true
|
|
error.value = null
|
|
result.value = null
|
|
|
|
const form = new FormData()
|
|
form.append('file', file)
|
|
|
|
try {
|
|
const res = await fetch(route('settings.labels.import'), {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
'X-XSRF-TOKEN': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? ''),
|
|
},
|
|
body: form,
|
|
})
|
|
if (!res.ok) {
|
|
const data = await res.json()
|
|
error.value = data.message || 'Import fehlgeschlagen'
|
|
return
|
|
}
|
|
result.value = await res.json()
|
|
event.target.value = ''
|
|
window.location.reload()
|
|
} catch {
|
|
error.value = 'Netzwerkfehler beim Upload'
|
|
} finally {
|
|
uploading.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<h3 class="mb-1 text-sm font-semibold text-gray-900">Label-Import</h3>
|
|
|
|
<p class="mb-1 text-xs text-gray-500">
|
|
Diese Datei findest du im ProPresenter-Ordner unter <strong>Configuration</strong>.
|
|
<span class="group relative inline-block">
|
|
<svg
|
|
class="ml-1 inline h-3.5 w-3.5 cursor-help text-gray-400"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
>
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<span class="absolute bottom-full left-0 z-10 mb-2 hidden w-72 rounded-lg border border-gray-200 bg-white p-3 text-xs text-gray-600 shadow-lg group-hover:block">
|
|
<strong>macOS:</strong> ~/Library/Application Support/RenewedVision/ProPresenter/Configuration/Labels<br><br>
|
|
<strong>Windows:</strong> %APPDATA%\RenewedVision\ProPresenter\Configuration\Labels
|
|
</span>
|
|
</span>
|
|
</p>
|
|
|
|
<div v-if="last_labels_import?.at" class="mb-4 text-xs text-gray-400">
|
|
Letzter Import: {{ last_labels_import.at }}
|
|
<span v-if="last_labels_import.filename">({{ last_labels_import.filename }})</span>
|
|
</div>
|
|
|
|
<label
|
|
class="mb-4 flex cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed border-gray-200 bg-gray-50 p-6 transition-colors hover:border-amber-300 hover:bg-amber-50"
|
|
data-testid="labels-upload-area"
|
|
>
|
|
<svg class="mb-2 h-8 w-8 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
|
|
</svg>
|
|
<span class="text-sm text-gray-500">
|
|
{{ uploading ? 'Wird importiert...' : 'Labels-Datei auswählen oder hierher ziehen' }}
|
|
</span>
|
|
<input
|
|
type="file"
|
|
class="hidden"
|
|
:disabled="uploading"
|
|
data-testid="labels-file-input"
|
|
@change="handleFileChange"
|
|
/>
|
|
</label>
|
|
|
|
<div
|
|
v-if="error"
|
|
class="mb-4 rounded-lg bg-red-50 p-3 text-sm text-red-700"
|
|
data-testid="labels-import-error"
|
|
>
|
|
{{ error }}
|
|
</div>
|
|
|
|
<div
|
|
v-if="result"
|
|
class="mb-4 rounded-lg bg-green-50 p-3 text-sm text-green-700"
|
|
data-testid="labels-import-summary"
|
|
>
|
|
<strong>Import abgeschlossen:</strong>
|
|
{{ result.new }} neue Labels importiert, {{ result.updated }} bestehende Labels aktualisiert.
|
|
Insgesamt {{ result.total }} Labels in Datei.
|
|
</div>
|
|
|
|
<div v-if="sortedLabels.length > 0">
|
|
<h4 class="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500">
|
|
Label-Bibliothek ({{ sortedLabels.length }})
|
|
</h4>
|
|
<div class="divide-y divide-gray-100 rounded-lg border border-gray-100">
|
|
<div
|
|
v-for="label in sortedLabels"
|
|
:key="label.id"
|
|
class="flex items-center gap-3 px-3 py-2 text-sm"
|
|
:data-testid="'labels-registry-row-' + label.name"
|
|
>
|
|
<span
|
|
class="h-4 w-4 shrink-0 rounded border border-gray-200"
|
|
:style="label.color ? { backgroundColor: label.color } : { backgroundColor: '#e5e7eb' }"
|
|
/>
|
|
<span class="flex-1 text-gray-700">{{ label.name }}</span>
|
|
<span v-if="label.color" class="font-mono text-xs text-gray-400">{{ label.color }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p v-else class="text-sm text-gray-400">Noch keine Labels importiert.</p>
|
|
</div>
|
|
</template>
|