feat: Implement infinite scroll for generation history and enhance the display of generation statuses (failed, processing).
This commit is contained in:
@@ -43,6 +43,7 @@ const generationStatus = ref('')
|
|||||||
const generationProgress = ref(0)
|
const generationProgress = ref(0)
|
||||||
const generationError = ref(null)
|
const generationError = ref(null)
|
||||||
const generatedResult = ref(null) // For immediate feedback if needed
|
const generatedResult = ref(null) // For immediate feedback if needed
|
||||||
|
const isLoadingMore = ref(false)
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
const qualityOptions = ref([
|
const qualityOptions = ref([
|
||||||
@@ -159,7 +160,29 @@ const loadData = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadMoreHistory = async () => {
|
const loadMoreHistory = async () => {
|
||||||
// Implement pagination/infinite scroll logic here
|
if (isLoadingMore.value || historyGenerations.value.length >= historyTotal.value) return
|
||||||
|
|
||||||
|
isLoadingMore.value = true
|
||||||
|
historyFirst.value += historyRows.value
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await aiService.getGenerations(historyRows.value, historyFirst.value)
|
||||||
|
if (response && response.generations) {
|
||||||
|
historyGenerations.value = [...historyGenerations.value, ...response.generations]
|
||||||
|
historyTotal.value = response.total_count || historyTotal.value
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load more history', e)
|
||||||
|
} finally {
|
||||||
|
isLoadingMore.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onScroll = (event) => {
|
||||||
|
const { scrollTop, clientHeight, scrollHeight } = event.target
|
||||||
|
if (scrollTop + clientHeight >= scrollHeight - 50) {
|
||||||
|
loadMoreHistory()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Generation ---
|
// --- Generation ---
|
||||||
@@ -370,20 +393,41 @@ const deleteGeneration = async (gen) => {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Gallery Grid -->
|
<!-- Gallery Grid -->
|
||||||
<div class="flex-1 overflow-y-auto p-4 pb-32 md:pb-32"> <!-- pb-32 to allow space for bottom panel -->
|
<div class="flex-1 overflow-y-auto p-4 pb-32 md:pb-32" @scroll="onScroll">
|
||||||
|
<!-- pb-32 to allow space for bottom panel -->
|
||||||
|
|
||||||
<div v-if="historyGenerations.length > 0"
|
<div v-if="historyGenerations.length > 0"
|
||||||
class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-2 md:gap-1">
|
class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-2 md:gap-1">
|
||||||
<div v-for="gen in historyGenerations" :key="gen.id"
|
<div v-for="gen in historyGenerations" :key="gen.id"
|
||||||
class="aspect-[9/16] relative group overflow-hidden bg-slate-800 transition-all duration-300">
|
class="aspect-[9/16] relative group overflow-hidden bg-slate-800 transition-all duration-300">
|
||||||
|
|
||||||
|
<!-- Image -->
|
||||||
<!-- Image -->
|
<!-- Image -->
|
||||||
<img v-if="gen.result_list && gen.result_list.length > 0"
|
<img v-if="gen.result_list && gen.result_list.length > 0"
|
||||||
:src="API_URL + '/assets/' + gen.result_list[0] + '?thumbnail=true'"
|
:src="API_URL + '/assets/' + gen.result_list[0] + '?thumbnail=true'"
|
||||||
class="w-full h-full object-cover"
|
class="w-full h-full object-cover cursor-pointer"
|
||||||
@click="openImagePreview(API_URL + '/assets/' + gen.result_list[0])" />
|
@click="openImagePreview(API_URL + '/assets/' + gen.result_list[0])" />
|
||||||
<div v-else class="w-full h-full flex items-center justify-center text-slate-600">
|
|
||||||
<i class="pi pi-image text-4xl"></i>
|
<!-- Failed State -->
|
||||||
|
<div v-else-if="gen.status === 'failed'"
|
||||||
|
class="w-full h-full flex flex-col items-center justify-center p-2 text-center bg-red-500/10 border border-red-500/20">
|
||||||
|
<i class="pi pi-times-circle text-red-500 text-2xl mb-1"></i>
|
||||||
|
<span class="text-[10px] font-bold text-red-400 uppercase tracking-wide">Failed</span>
|
||||||
|
<span v-if="gen.failed_reason"
|
||||||
|
class="text-[8px] text-red-300/70 mt-1 line-clamp-2 leading-tight"
|
||||||
|
v-tooltip.top="gen.failed_reason">{{ gen.failed_reason }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Processing State -->
|
||||||
|
<div v-else-if="gen.status === 'processing' || gen.status === 'starting'"
|
||||||
|
class="w-full h-full flex flex-col items-center justify-center bg-slate-800/50 border border-violet-500/20">
|
||||||
|
<i class="pi pi-spin pi-spinner text-violet-500 text-xl mb-2"></i>
|
||||||
|
<span class="text-[10px] text-violet-300/70">Creating...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Placeholder -->
|
||||||
|
<div v-else class="w-full h-full flex items-center justify-center text-slate-600 bg-slate-800">
|
||||||
|
<i class="pi pi-image text-4xl opacity-20"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Overlay Info -->
|
<!-- Overlay Info -->
|
||||||
@@ -392,15 +436,23 @@ const deleteGeneration = async (gen) => {
|
|||||||
|
|
||||||
<!-- Top Actions -->
|
<!-- Top Actions -->
|
||||||
<div
|
<div
|
||||||
class="flex justify-between items-start translate-y-[-10px] group-hover:translate-y-0 transition-transform duration-200">
|
class="flex justify-between items-start translate-y-[-10px] group-hover:translate-y-0 transition-transform duration-200 w-full">
|
||||||
<Button icon="pi pi-trash" v-tooltip.right="'Delete'"
|
<Button icon="pi pi-trash" v-tooltip.right="'Delete'"
|
||||||
class="!w-6 !h-6 !rounded-full !bg-red-500/20 !border-none !text-red-400 text-[10px] hover:!bg-red-500 hover:!text-white"
|
class="!w-6 !h-6 !rounded-full !bg-red-500/20 !border-none !text-red-400 text-[10px] hover:!bg-red-500 hover:!text-white"
|
||||||
@click.stop="deleteGeneration(gen)" />
|
@click.stop="deleteGeneration(gen)" />
|
||||||
|
|
||||||
<Button icon="pi pi-pencil" v-tooltip.left="'Edit (Use Result)'"
|
<div class="flex gap-1">
|
||||||
|
<Button v-if="gen.result_list && gen.result_list.length > 0" icon="pi pi-eye"
|
||||||
|
v-tooltip.left="'View Full'"
|
||||||
|
class="!w-6 !h-6 !rounded-full !bg-white/20 !border-none !text-white text-[10px] hover:!bg-blue-500"
|
||||||
|
@click.stop="openImagePreview(API_URL + '/assets/' + gen.result_list[0])" />
|
||||||
|
|
||||||
|
<Button v-if="gen.result_list && gen.result_list.length > 0" icon="pi pi-pencil"
|
||||||
|
v-tooltip.left="'Edit (Use Result)'"
|
||||||
class="!w-6 !h-6 !rounded-full !bg-white/20 !border-none !text-white text-[10px] hover:!bg-violet-500"
|
class="!w-6 !h-6 !rounded-full !bg-white/20 !border-none !text-white text-[10px] hover:!bg-violet-500"
|
||||||
@click.stop="useResultAsAsset(gen)" />
|
@click.stop="useResultAsAsset(gen)" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Bottom Actions -->
|
<!-- Bottom Actions -->
|
||||||
<div class="translate-y-[10px] group-hover:translate-y-0 transition-transform duration-200">
|
<div class="translate-y-[10px] group-hover:translate-y-0 transition-transform duration-200">
|
||||||
|
|||||||
Reference in New Issue
Block a user