update
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { fetchGuides, createGuide as apiCreate, deleteGuide, cancelGuide as apiCancel, fetchProjects, deleteProject as apiDeleteProject, fetchProviders } from './api.js'
|
||||
import { fetchGuides, fetchTopics, createGuide as apiCreate, deleteGuide, cancelGuide as apiCancel, fetchBausteineStatus, fetchActiveBausteine, createBausteine as apiCreateBausteine, deleteBausteine as apiDeleteBausteine, fetchProjects, deleteProject as apiDeleteProject, fetchProviders } from './api.js'
|
||||
import TopicSidebar from './components/TopicSidebar.vue'
|
||||
import TopicDetail from './components/TopicDetail.vue'
|
||||
|
||||
const guides = ref([])
|
||||
const projects = ref([])
|
||||
const manualTopics = ref([])
|
||||
const manualTopics = ref(JSON.parse(localStorage.getItem('manualTopics') || '[]'))
|
||||
const backendTopics = ref([])
|
||||
|
||||
function persistManualTopics() {
|
||||
localStorage.setItem('manualTopics', JSON.stringify(manualTopics.value))
|
||||
}
|
||||
const selectedTopic = ref(null)
|
||||
const previewGuide = ref(null)
|
||||
const sidebarPinned = ref(localStorage.getItem('sidebarPinned') !== 'false')
|
||||
@@ -16,6 +21,9 @@ const darkMode = ref(
|
||||
? window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
: localStorage.getItem('darkMode') === 'true',
|
||||
)
|
||||
const EMPTY_BAUSTEINE = { ready: false, generating: false, progress: null, error: null }
|
||||
const bausteine = ref({ ...EMPTY_BAUSTEINE })
|
||||
const activeBausteine = ref([])
|
||||
const provider = ref(localStorage.getItem('provider') || 'claude')
|
||||
const providers = ref([])
|
||||
|
||||
@@ -75,9 +83,9 @@ const topics = computed(() => {
|
||||
topicDates[g.topic] = g.created_at
|
||||
}
|
||||
}
|
||||
for (const t of manualTopics.value) {
|
||||
for (const t of [...backendTopics.value, ...manualTopics.value]) {
|
||||
if (isProject.has(t)) continue
|
||||
if (!topicDates[t]) topicDates[t] = new Date().toISOString()
|
||||
if (!topicDates[t]) topicDates[t] = ''
|
||||
}
|
||||
return Object.keys(topicDates).sort((a, b) => topicDates[b].localeCompare(topicDates[a]))
|
||||
})
|
||||
@@ -109,6 +117,14 @@ const hasActiveGuides = computed(() =>
|
||||
guides.value.some((g) => g.status === 'queued' || g.status === 'generating'),
|
||||
)
|
||||
|
||||
async function loadTopics() {
|
||||
try {
|
||||
backendTopics.value = await fetchTopics()
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Laden der Themen:', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadGuides() {
|
||||
try {
|
||||
guides.value = await fetchGuides()
|
||||
@@ -117,6 +133,20 @@ async function loadGuides() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadBausteine() {
|
||||
try {
|
||||
activeBausteine.value = await fetchActiveBausteine()
|
||||
if (selectedTopic.value) {
|
||||
bausteine.value = await fetchBausteineStatus(selectedTopic.value)
|
||||
} else {
|
||||
bausteine.value = { ...EMPTY_BAUSTEINE }
|
||||
}
|
||||
if (activeBausteine.value.length && !pollTimer) startPolling()
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Laden der Bausteine:', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadProjects() {
|
||||
try {
|
||||
projects.value = await fetchProjects()
|
||||
@@ -125,7 +155,7 @@ async function loadProjects() {
|
||||
}
|
||||
}
|
||||
|
||||
const FORMAT_ORDER = ['OnePager', 'MiniGuide', 'Guide']
|
||||
const FORMAT_ORDER = ['OnePager', 'MiniGuide', 'Guide', 'FullGuide']
|
||||
|
||||
function autoPreview() {
|
||||
const map = doneByFormat.value
|
||||
@@ -142,15 +172,25 @@ function selectTopic(topic) {
|
||||
selectedTopic.value = topic
|
||||
previewGuide.value = null
|
||||
sidebarSticky.value = false
|
||||
loadBausteine()
|
||||
nextTick(autoPreview)
|
||||
}
|
||||
|
||||
function createTopic(topic) {
|
||||
if (!manualTopics.value.includes(topic)) {
|
||||
manualTopics.value.push(topic)
|
||||
persistManualTopics()
|
||||
}
|
||||
selectedTopic.value = topic
|
||||
previewGuide.value = null
|
||||
loadBausteine()
|
||||
}
|
||||
|
||||
async function handleBausteineClick({ instructions }) {
|
||||
if (!selectedTopic.value) return
|
||||
await apiCreateBausteine(selectedTopic.value, instructions, provider.value)
|
||||
await loadBausteine()
|
||||
startPolling()
|
||||
}
|
||||
|
||||
async function handleFormatClick({ format, instructions }) {
|
||||
@@ -184,8 +224,8 @@ async function handleDeleteGuide(guideId) {
|
||||
function startPolling() {
|
||||
stopPolling()
|
||||
pollTimer = setInterval(async () => {
|
||||
await loadGuides()
|
||||
if (!hasActiveGuides.value) stopPolling()
|
||||
await Promise.all([loadGuides(), loadBausteine(), loadTopics()])
|
||||
if (!hasActiveGuides.value && !activeBausteine.value.length) stopPolling()
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
@@ -206,7 +246,10 @@ async function handleDeleteTopic(topic) {
|
||||
for (const g of topicGuides) {
|
||||
await deleteGuide(g.id)
|
||||
}
|
||||
await apiDeleteBausteine(topic)
|
||||
manualTopics.value = manualTopics.value.filter((t) => t !== topic)
|
||||
persistManualTopics()
|
||||
await loadTopics()
|
||||
if (selectedTopic.value === topic) {
|
||||
selectedTopic.value = null
|
||||
previewGuide.value = null
|
||||
@@ -219,12 +262,13 @@ function onVisibility() {
|
||||
stopPolling()
|
||||
} else {
|
||||
loadGuides()
|
||||
if (hasActiveGuides.value) startPolling()
|
||||
loadBausteine()
|
||||
if (hasActiveGuides.value || activeBausteine.value.length) startPolling()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([loadGuides(), loadProjects(), loadProviders()])
|
||||
await Promise.all([loadGuides(), loadTopics(), loadProjects(), loadProviders()])
|
||||
if (!selectedTopic.value && topics.value.length) {
|
||||
selectTopic(topics.value[0])
|
||||
}
|
||||
@@ -248,6 +292,8 @@ onUnmounted(() => {
|
||||
:doneByFormat="doneByFormat"
|
||||
:latestByFormat="latestByFormat"
|
||||
:allGuides="guides"
|
||||
:bausteine="bausteine"
|
||||
:activeBausteine="activeBausteine"
|
||||
:pinned="sidebarPinned"
|
||||
:dark="darkMode"
|
||||
:provider="provider"
|
||||
@@ -257,6 +303,7 @@ onUnmounted(() => {
|
||||
@select="selectTopic"
|
||||
@create="createTopic"
|
||||
@formatClick="handleFormatClick"
|
||||
@bausteineClick="handleBausteineClick"
|
||||
@deleteTopic="handleDeleteTopic"
|
||||
@deleteProject="handleDeleteProject"
|
||||
@cancelGuide="handleCancel"
|
||||
|
||||
Reference in New Issue
Block a user