fix : code review — correct 15 issues across UX overhaul (phases 1-4)
Critical fixes: - Make MigrateConstructeurLinks migration no-op (legacy tables already dropped) - Add explicit ON CONFLICT (id) target in RestoreConstructeurLinks migration - Replace N+1 queries with 4 bulk GROUP BY in ConstructeurStatsController - Declare missing versionListRef template ref in machine detail page - Add missing await on removeMachineDocument, cast activeTab as string Important fixes: - Add lang="ts" to ToastContainer and constructeurs page - Type entityType as union in UsedInSection/useUsedIn - Remove dead duration param from showError - Update back-link props to new /catalogues/* URLs (3 pages) - Replace raw error blocks with EmptyState in component/piece detail pages - Type handleFillEntity params and machineInfoCardRef Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { useToast } from '~/composables/useToast'
|
||||
import IconLucideCheck from '~icons/lucide/check'
|
||||
import IconLucideX from '~icons/lucide/x'
|
||||
@@ -77,7 +77,7 @@ import IconLucideInfo from '~icons/lucide/info'
|
||||
|
||||
const { toasts, removeToast } = useToast()
|
||||
|
||||
const getToastClasses = (type) => {
|
||||
const getToastClasses = (type: ToastType) => {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
return 'alert-success text-success-content'
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
entityType: string
|
||||
entityType: 'composants' | 'pieces' | 'products'
|
||||
entityId: string | null
|
||||
}>()
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ export function useToast() {
|
||||
return showToast(message, 'success', duration)
|
||||
}
|
||||
|
||||
const showError = (message: string, duration = 5000): number => {
|
||||
return showToast(message, 'error', duration)
|
||||
const showError = (message: string): number => {
|
||||
return showToast(message, 'error', 0)
|
||||
}
|
||||
|
||||
const showWarning = (message: string, duration = 6000): number => {
|
||||
|
||||
@@ -17,7 +17,7 @@ interface UsedInData {
|
||||
pieces: UsedInEntity[]
|
||||
}
|
||||
|
||||
export function useUsedIn(entityType: Ref<string>, entityId: Ref<string | null>) {
|
||||
export function useUsedIn(entityType: Ref<'composants' | 'pieces' | 'products'>, entityId: Ref<string | null>) {
|
||||
const data = ref<UsedInData>({ machines: [], composants: [], pieces: [] })
|
||||
const loading = ref(false)
|
||||
|
||||
|
||||
@@ -18,19 +18,13 @@
|
||||
<p class="text-sm text-base-content/70">Chargement du composant…</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="!component" class="max-w-xl mx-auto">
|
||||
<div class="alert alert-error shadow-lg">
|
||||
<div>
|
||||
<h2 class="font-semibold text-lg">Composant introuvable</h2>
|
||||
<p class="text-sm text-base-content/80">
|
||||
Nous n'avons pas pu retrouver le composant demandé. Il a peut-être été supprimé.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary mt-6" @click="$router.back()">
|
||||
Retour au catalogue
|
||||
</button>
|
||||
</div>
|
||||
<EmptyState
|
||||
v-else-if="!component"
|
||||
title="Composant introuvable"
|
||||
description="Nous n'avons pas pu retrouver le composant demandé. Il a peut-être été supprimé."
|
||||
action-label="Retour au catalogue"
|
||||
action-to="/catalogues/composants"
|
||||
/>
|
||||
|
||||
<section v-else class="card border border-base-200 bg-base-100 shadow-sm max-w-5xl mx-auto">
|
||||
<div class="card-body space-y-6">
|
||||
@@ -39,7 +33,7 @@
|
||||
:subtitle="isEditMode ? 'Ajustez les informations du composant et ses champs personnalisés.' : undefined"
|
||||
:is-edit-mode="isEditMode"
|
||||
:can-edit="canEdit"
|
||||
back-link="/component-catalog"
|
||||
back-link="/catalogues/composants"
|
||||
@toggle-edit="isEditMode = !isEditMode"
|
||||
/>
|
||||
|
||||
@@ -129,6 +123,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Référence auto (read-only, shown only if computed) -->
|
||||
<div v-if="component.referenceAuto" class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Référence auto</span>
|
||||
</label>
|
||||
<p class="text-sm font-medium text-base-content py-1 flex items-center gap-2">
|
||||
<span class="font-mono font-semibold">{{ component.referenceAuto }}</span>
|
||||
<span class="badge badge-sm badge-ghost">auto</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Référence + Fournisseurs (if value or edit mode) -->
|
||||
<div
|
||||
v-if="isEditMode || component.reference || constructeurLinks.length"
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import DataTable from '~/components/common/DataTable.vue'
|
||||
import FieldEmail from '~/components/form/FieldEmail.vue'
|
||||
|
||||
@@ -223,12 +223,13 @@ if (!machineId) {
|
||||
}
|
||||
|
||||
const d = useMachineDetailData(machineId)
|
||||
const machineInfoCardRef = ref(null)
|
||||
const machineInfoCardRef = ref<{ saveFieldDefinitions?: () => Promise<void> } | null>(null)
|
||||
const versionRefreshKey = ref(0)
|
||||
const refreshVersions = () => { versionRefreshKey.value++ }
|
||||
const { confirm: confirmDialog } = useConfirm()
|
||||
|
||||
const activeTab = ref(route.query.tab || 'general')
|
||||
const versionListRef = ref<InstanceType<typeof EntityVersionList> | null>(null)
|
||||
const activeTab = ref((route.query.tab as string) || 'general')
|
||||
watch(activeTab, (val) => {
|
||||
navigateTo({ query: { ...route.query, tab: val } }, { replace: true })
|
||||
})
|
||||
@@ -306,7 +307,7 @@ const handleAddEntity = async (payload) => {
|
||||
refreshVersions()
|
||||
}
|
||||
|
||||
const handleFillEntity = (linkId, entityKind, modelTypeId) => {
|
||||
const handleFillEntity = (linkId: string, entityKind: string, modelTypeId: string) => {
|
||||
fillLinkId.value = linkId
|
||||
fillTypeId.value = modelTypeId
|
||||
addModalKind.value = entityKind
|
||||
@@ -341,7 +342,7 @@ const confirmRemovePiece = async (id: string) => {
|
||||
|
||||
const confirmRemoveDocument = async (id: string) => {
|
||||
if (!await confirmDialog({ title: 'Supprimer ce document ?', message: 'Le fichier sera supprimé définitivement.', confirmText: 'Supprimer', dangerous: true })) return
|
||||
d.removeMachineDocument(id)
|
||||
await d.removeMachineDocument(id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -18,19 +18,13 @@
|
||||
<p class="text-sm text-base-content/70">Chargement de la pièce…</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="!piece" class="max-w-xl mx-auto">
|
||||
<div class="alert alert-error shadow-lg">
|
||||
<div>
|
||||
<h2 class="font-semibold text-lg">Pièce introuvable</h2>
|
||||
<p class="text-sm text-base-content/80">
|
||||
Nous n'avons pas pu retrouver la pièce demandée. Elle a peut-être été supprimée.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary mt-6" @click="$router.back()">
|
||||
Retour au catalogue
|
||||
</button>
|
||||
</div>
|
||||
<EmptyState
|
||||
v-else-if="!piece"
|
||||
title="Pièce introuvable"
|
||||
description="Nous n'avons pas pu retrouver la pièce demandée. Elle a peut-être été supprimée."
|
||||
action-label="Retour au catalogue"
|
||||
action-to="/catalogues/pieces"
|
||||
/>
|
||||
|
||||
<section v-else class="card border border-base-200 bg-base-100 shadow-sm max-w-5xl mx-auto">
|
||||
<div class="card-body space-y-6">
|
||||
@@ -39,7 +33,7 @@
|
||||
:subtitle="isEditMode ? 'Ajustez les informations de la pièce et ses champs personnalisés.' : undefined"
|
||||
:is-edit-mode="isEditMode"
|
||||
:can-edit="canEdit"
|
||||
back-link="/pieces-catalog"
|
||||
back-link="/catalogues/pieces"
|
||||
@toggle-edit="isEditMode = !isEditMode"
|
||||
/>
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
:subtitle="isEditMode ? 'Ajustez les informations du produit et ses champs personnalisés.' : undefined"
|
||||
:is-edit-mode="isEditMode"
|
||||
:can-edit="canEdit"
|
||||
back-link="/product-catalog"
|
||||
back-link="/catalogues/produits"
|
||||
@toggle-edit="isEditMode = !isEditMode"
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user