docling-studio/frontend/src/features/document/ui/StatusBadge.vue
Pier-Jean Malandrino 59af8acdc6
feat(#211): E3 — Document library (/docs), filters, bulk actions, multi-file import, StatusBadge
- StatusBadge component with 6 lifecycle states, compact/full variants, tooltip (#215)
- DocsLibraryPage: table (Name/Status/Stores/Updated), empty state (#211)
- Filter bar: status pills, store chips, debounced search, URL sync (#212)
- Multi-select with sticky bulk bar: Re-chunk, Push to store modal, Delete (#213)
- DocsNewPage: multi-file drop zone with per-file progress, sequential upload (#214)
- Document.stores?: string[] field, formatRelativeTime(iso, locale) helper
- rechunkDocument / pushDocumentToStore API + store actions (rechunk / pushToStore)
- i18n keys status.*, docs.*, docsNew.* in FR + EN

Closes #211, Closes #212, Closes #213, Closes #214, Closes #215
2026-04-30 09:30:29 +02:00

91 lines
1.9 KiB
Vue

<template>
<span
class="status-badge"
:class="[`status-badge--${state}`, { 'status-badge--compact': compact }]"
:title="tooltip"
:aria-label="label"
>
<span aria-hidden="true" class="status-symbol">{{ symbol }}</span>
<span v-if="!compact" class="status-text">{{ label }}</span>
</span>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from '../../../shared/i18n'
import type { DocumentLifecycleState } from '../../../shared/types'
const props = withDefaults(
defineProps<{
state: DocumentLifecycleState
compact?: boolean
}>(),
{ compact: false },
)
const { t } = useI18n()
const SYMBOLS: Record<DocumentLifecycleState, string> = {
Uploaded: '○',
Parsed: '◐',
Chunked: '◑',
Ingested: '●',
Stale: '⚠',
Failed: '✗',
}
const symbol = computed(() => SYMBOLS[props.state] ?? '?')
const label = computed(() => t(`status.${props.state}`))
const tooltip = computed(() => t(`status.tooltip.${props.state}`))
</script>
<style scoped>
.status-badge {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
font-weight: 500;
padding: 2px 8px;
border-radius: 999px;
white-space: nowrap;
cursor: default;
}
.status-badge--Uploaded {
background: rgba(99, 102, 241, 0.12);
color: #818cf8;
}
.status-badge--Parsed {
background: rgba(59, 130, 246, 0.12);
color: var(--info);
}
.status-badge--Chunked {
background: rgba(249, 115, 22, 0.12);
color: var(--accent);
}
.status-badge--Ingested {
background: rgba(34, 197, 94, 0.12);
color: var(--success);
}
.status-badge--Stale {
background: rgba(234, 179, 8, 0.12);
color: var(--warning);
}
.status-badge--Failed {
background: rgba(239, 68, 68, 0.12);
color: var(--error);
}
.status-badge--compact {
padding: 0;
background: transparent;
gap: 0;
}
.status-symbol {
font-size: 1em;
line-height: 1;
}
</style>