Phase 3: Unify controls across shot/asset/task toolbars and detail panels
Extracts duplication that built up as shot/asset/task features reached parity: CheckableCommandItem/ColumnToggleList replace 14+ hand-rolled checkbox-list blocks, shared toolbar pieces (debounced search, detail-panel toggle, clear-filters, segmented view/context toggle) replace copy-pasted markup in the three table toolbars, icon-only buttons standardize on the icon-sm size, TaskBulkActionsMenu's Assign To submenu matches Set Status, and a shared DetailPanelOverlay/Header/Loading/Error shell backs all three detail panels (adding a previously-missing error state to the task panel).
This commit is contained in:
@@ -1,29 +1,21 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Loading State -->
|
||||
<div v-if="loading" class="flex items-center justify-center py-12">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
|
||||
<span class="text-muted-foreground">Loading task details...</span>
|
||||
</div>
|
||||
</div>
|
||||
<DetailPanelLoading v-if="loading" label="Loading task details..." />
|
||||
|
||||
<DetailPanelError
|
||||
v-else-if="error"
|
||||
title="Failed to load task"
|
||||
:message="error"
|
||||
@retry="loadTask"
|
||||
/>
|
||||
|
||||
<!-- Task Details -->
|
||||
<div v-else-if="task" class="flex-1 flex flex-col min-h-0">
|
||||
<!-- Header (Fixed) -->
|
||||
<div class="flex-shrink-0 p-6 border-b">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||
<h2 class="text-xl font-bold truncate">{{ task.name }}</h2>
|
||||
<TaskStatusBadge :status="task.status" class="flex-shrink-0" />
|
||||
</div>
|
||||
|
||||
<!-- Close Button -->
|
||||
<Button variant="ghost" size="sm" class="h-8 w-8 p-0 flex-shrink-0" @click="emit('close')">
|
||||
<X class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<DetailPanelHeader class="flex-shrink-0" :title="task.name" @close="emit('close')">
|
||||
<template #badges>
|
||||
<TaskStatusBadge :status="task.status" class="flex-shrink-0" />
|
||||
</template>
|
||||
</DetailPanelHeader>
|
||||
|
||||
<!-- Tabbed Content -->
|
||||
<Tabs :default-value="initialTab || 'infos'" class="flex-1 flex flex-col min-h-0">
|
||||
@@ -270,11 +262,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { X, Play, Upload, UserPlus, Calendar, User } from 'lucide-vue-next'
|
||||
import { Play, Upload, UserPlus, Calendar, User } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import DetailPanelLoading from '@/components/shared/DetailPanelLoading.vue'
|
||||
import DetailPanelError from '@/components/shared/DetailPanelError.vue'
|
||||
import DetailPanelHeader from '@/components/shared/DetailPanelHeader.vue'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -328,6 +323,7 @@ const authStore = useAuthStore()
|
||||
|
||||
const task = ref<Task | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
const localStatus = ref('')
|
||||
const notes = ref<ProductionNote[]>([])
|
||||
const attachments = ref<TaskAttachment[]>([])
|
||||
@@ -361,14 +357,16 @@ const canReassign = computed(() => {
|
||||
|
||||
async function loadTask() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
task.value = await taskService.getTask(props.taskId)
|
||||
localStatus.value = task.value.status
|
||||
} catch (error: any) {
|
||||
console.error('Error loading task:', error)
|
||||
} catch (err: any) {
|
||||
console.error('Error loading task:', err)
|
||||
error.value = err.response?.data?.detail || 'Failed to load task'
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: error.response?.data?.detail || 'Failed to load task',
|
||||
description: error.value,
|
||||
variant: 'destructive'
|
||||
})
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user