feat: stabilize admin dashboard, refactor group management, implement PWA, and fix routing

This commit is contained in:
2026-05-03 19:51:18 +05:00
parent 622ca04170
commit 0598e07823
36 changed files with 1387 additions and 467 deletions
+25 -2
View File
@@ -23,7 +23,19 @@
<div class="flex-1 flex flex-col relative min-w-0">
<!-- Toolbar -->
<div class="h-10 bg-slate-900 border-b border-slate-700 flex items-center px-3 gap-2 z-20">
<input v-model="canvasName" @change="saveCanvas" class="text-sm font-semibold text-slate-300 mr-2 bg-transparent border border-transparent hover:border-slate-600 focus:border-blue-500 focus:bg-slate-800 outline-none rounded px-2 py-1 w-64 transition" title="Переименовать карту" />
<input v-model="canvasName" @change="saveCanvas" class="text-sm font-semibold text-slate-300 mr-2 bg-transparent border border-transparent hover:border-slate-600 focus:border-blue-500 focus:bg-slate-800 outline-none rounded px-2 py-1 w-48 transition" title="Переименовать карту" />
<!-- Group Selection -->
<div class="flex items-center gap-1 bg-slate-800 border border-slate-700 rounded px-2 py-1">
<span class="text-[10px] text-slate-500 uppercase font-bold mr-1">Группа:</span>
<select v-model="selectedGroupId" @change="saveCanvas" class="bg-transparent text-xs text-slate-300 outline-none cursor-pointer hover:text-white transition">
<option :value="null">Личная (нет)</option>
<option v-for="g in groupsList" :key="g.id" :value="g.id">
👥 {{ g.name }}
</option>
</select>
</div>
<span v-if="isDirty" class="px-2 py-1 bg-yellow-600 text-yellow-100 rounded text-xs font-medium">
● Несохранено
</span>
@@ -204,6 +216,8 @@ const authHeaders = computed(() => ({ Authorization: `Bearer ${auth.token.value}
const elements = ref([])
const selectedNode = ref(null)
const canvasName = ref(props.canvasId)
const selectedGroupId = ref(null)
const groupsList = ref([])
const nodeTypes = [
{ type: 'text', name: 'Текст', icon: '📝', description: 'Markdown заметка' },
@@ -219,6 +233,7 @@ const loadData = async () => {
const data = await loadCanvas(props.canvasId)
elements.value = transformToFlowElements(data)
canvasName.value = data.name || props.canvasId
selectedGroupId.value = data.groupId || null
// Mark initial state as saved
markAsSaved(data)
}
@@ -639,7 +654,7 @@ const saveCanvas = async () => {
console.log('[DEBUG saveCanvas] Sending PUT request...')
const res = await $fetch(`/api/canvas/${props.canvasId}`, {
method: 'PUT',
body: { ...obsidianCanvas, name: canvasName.value },
body: { ...obsidianCanvas, name: canvasName.value, groupId: selectedGroupId.value },
headers: authHeaders.value
})
console.log('[DEBUG saveCanvas] PUT request successful!', res)
@@ -690,6 +705,14 @@ onMounted(async () => {
} catch (e) {
console.error('Failed to load canvases', e)
}
// Load groups for assignment
try {
const data = await $fetch('/api/groups')
groupsList.value = data.groups || []
} catch (e) {
console.error('Failed to load groups', e)
}
})
</script>