diff --git a/src/main.ts b/src/main.ts index 0b7e33d..c4702f5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,8 @@ import { createPinia } from 'pinia' import PrimeVue from 'primevue/config' import Aura from '@primevue/themes/aura'; import Tooltip from 'primevue/tooltip'; +import ConfirmationService from 'primevue/confirmationservice'; +import ToastService from 'primevue/toastservice'; import 'primeicons/primeicons.css' import App from './App.vue' import router from './router' @@ -36,5 +38,7 @@ app.config.globalProperties.$primevue.config.locale = { }; app.directive('tooltip', Tooltip); +app.use(ConfirmationService); +app.use(ToastService); app.mount('#app') diff --git a/src/services/dataService.js b/src/services/dataService.js index fdabca3..5afc964 100644 --- a/src/services/dataService.js +++ b/src/services/dataService.js @@ -43,6 +43,11 @@ export const dataService = { return response.data }, + deleteAsset: async (id) => { + const response = await api.delete(`/assets/${id}`) + return response.data + }, + generatePromptFromImage: async (files, prompt) => { const formData = new FormData() diff --git a/src/views/AssetsView.vue b/src/views/AssetsView.vue index 373a099..f9eaf42 100644 --- a/src/views/AssetsView.vue +++ b/src/views/AssetsView.vue @@ -7,8 +7,14 @@ import Button from 'primevue/button' import Skeleton from 'primevue/skeleton' import Dialog from 'primevue/dialog' import Paginator from 'primevue/paginator' +import ConfirmDialog from 'primevue/confirmdialog' +import { useConfirm } from "primevue/useconfirm" +import Toast from 'primevue/toast' +import { useToast } from "primevue/usetoast" const router = useRouter() +const confirm = useConfirm() +const toast = useToast() const assets = ref([]) const loading = ref(true) const activeFilter = ref('all') @@ -57,6 +63,30 @@ const paginatedAssets = computed(() => { return assets.value }) + + +const confirmDelete = (asset: Asset) => { + confirm.require({ + message: 'Do you want to delete this asset?', + header: 'Delete Confirmation', + icon: 'pi pi-info-circle', + rejectLabel: 'Cancel', + acceptLabel: 'Delete', + rejectClass: 'p-button-secondary p-button-outlined', + acceptClass: 'p-button-danger', + accept: async () => { + try { + await dataService.deleteAsset(asset.id) + toast.add({ severity: 'success', summary: 'Confirmed', detail: 'Asset deleted', life: 3000 }) + loadAssets() + } catch (e) { + console.error('Failed to delete asset', e) + toast.add({ severity: 'error', summary: 'Error', detail: 'Failed to delete asset', life: 3000 }) + } + } + }) +} + const onPage = (event: any) => { first.value = event.first rows.value = event.rows @@ -183,6 +213,11 @@ const handleLogout = () => { class="absolute top-2.5 right-2.5 bg-black/60 backdrop-blur-sm px-3 py-1 rounded-full text-xs uppercase font-semibold text-white z-10"> {{ asset.type }} +
+ +
@@ -238,6 +273,8 @@ const handleLogout = () => { + + diff --git a/src/views/CharacterDetailView.vue b/src/views/CharacterDetailView.vue index 3a1efdd..98a555a 100644 --- a/src/views/CharacterDetailView.vue +++ b/src/views/CharacterDetailView.vue @@ -190,6 +190,7 @@ const saveTelegramId = () => { } } const generationSuccess = ref(false) +const generationError = ref(null) const generatedResult = ref(null) // Prompt Assistant state @@ -336,7 +337,8 @@ const pollStatus = async (id) => { loadHistory() } else if (response.status === 'failed') { completed = true - throw new Error('Generation failed on server') + generationError.value = response.failed_reason || 'Generation failed on server' + throw new Error(generationError.value) } else { // Wait before next poll await new Promise(resolve => setTimeout(resolve, 2000)) @@ -434,6 +436,7 @@ const handleGenerate = async () => { isGenerating.value = true generationSuccess.value = false + generationError.value = null generationStatus.value = 'starting' generationProgress.value = 0 generatedResult.value = null @@ -728,6 +731,21 @@ const handleLogout = () => { {{ generationProgress }}% +
+
+ +
+

Generation Failed

+

+ {{ generationError }} +

+
+
@@ -792,8 +810,8 @@ const handleLogout = () => {
- -

Ready

+ +

Ready

diff --git a/src/views/ImageGenerationView.vue b/src/views/ImageGenerationView.vue index 851820e..52495dd 100644 --- a/src/views/ImageGenerationView.vue +++ b/src/views/ImageGenerationView.vue @@ -23,6 +23,7 @@ const isGenerating = ref(false) const generationStatus = ref('') const generationProgress = ref(0) const generationSuccess = ref(false) +const generationError = ref(null) const generatedResult = ref(null) // History State @@ -193,6 +194,7 @@ const handleGenerate = async () => { isGenerating.value = true generationSuccess.value = false + generationError.value = null generationStatus.value = 'starting' generationProgress.value = 0 generatedResult.value = null @@ -262,7 +264,8 @@ const pollStatus = async (id) => { } else if (response.status === 'failed') { completed = true - throw new Error('Generation failed on server') + generationError.value = response.failed_reason || 'Generation failed on server' + throw new Error(generationError.value) } else { await new Promise(resolve => setTimeout(resolve, 2000)) } @@ -546,7 +549,22 @@ onMounted(() => { {{ generationProgress }}%
-
+
+
+ +
+

Generation Failed

+

+ {{ generationError }} +

+
+ +

Result

@@ -601,7 +619,7 @@ onMounted(() => {
-

Ready to generate

@@ -651,7 +669,7 @@ onMounted(() => { gen.api_execution_time_seconds.toFixed(1) }}s {{ gen.token_usage - }} + }}