Add new dropdown search
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
:piece-types="availablePieceTypes"
|
:piece-types="availablePieceTypes"
|
||||||
:lock-type="lockRootType"
|
:lock-type="lockRootType"
|
||||||
:locked-type-label="displayedRootTypeLabel"
|
:locked-type-label="displayedRootTypeLabel"
|
||||||
|
:allow-subcomponents="allowSubcomponents"
|
||||||
is-root
|
is-root
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,6 +44,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
allowSubcomponents: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
@@ -55,6 +60,7 @@ const { componentTypes, loadComponentTypes } = useComponentTypes()
|
|||||||
|
|
||||||
const availablePieceTypes = computed(() => pieceTypes.value ?? [])
|
const availablePieceTypes = computed(() => pieceTypes.value ?? [])
|
||||||
const availableComponentTypes = computed(() => componentTypes.value ?? [])
|
const availableComponentTypes = computed(() => componentTypes.value ?? [])
|
||||||
|
const allowSubcomponents = computed(() => props.allowSubcomponents !== false)
|
||||||
|
|
||||||
const fallbackRootTypeLabel = computed(() => {
|
const fallbackRootTypeLabel = computed(() => {
|
||||||
if (!props.rootTypeId) {
|
if (!props.rootTypeId) {
|
||||||
@@ -156,4 +162,14 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
syncRootType()
|
syncRootType()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
allowSubcomponents,
|
||||||
|
(allowed) => {
|
||||||
|
if (!allowed && Array.isArray(localStructure.subcomponents) && localStructure.subcomponents.length) {
|
||||||
|
localStructure.subcomponents = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -14,21 +14,17 @@
|
|||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text text-xs">Sélectionner un composant</span>
|
<span class="label-text text-xs">Sélectionner un composant</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<SearchSelect
|
||||||
v-model="assignment.selectedComponentId"
|
:model-value="assignment.selectedComponentId || ''"
|
||||||
class="select select-bordered select-sm"
|
:options="componentOptions"
|
||||||
>
|
:loading="componentsLoading"
|
||||||
<option value="">
|
size="sm"
|
||||||
{{ componentOptions.length ? 'Choisir un composant compatible' : 'Aucun composant disponible' }}
|
placeholder="Rechercher un composant..."
|
||||||
</option>
|
:empty-text="componentOptions.length ? 'Aucun résultat' : 'Aucun composant disponible'"
|
||||||
<option
|
:option-label="componentOptionLabel"
|
||||||
v-for="component in componentOptions"
|
:option-description="componentOptionDescription"
|
||||||
:key="component.id"
|
@update:modelValue="(value) => { assignment.selectedComponentId = normalizeSelectionValue(value); }"
|
||||||
:value="component.id"
|
/>
|
||||||
>
|
|
||||||
{{ formatComponentOption(component) }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -56,21 +52,17 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<select
|
<SearchSelect
|
||||||
v-model="pieceAssignment.selectedPieceId"
|
:model-value="pieceAssignment.selectedPieceId || ''"
|
||||||
class="select select-bordered select-xs"
|
:options="getPieceOptions(pieceAssignment.definition)"
|
||||||
>
|
:loading="piecesLoading"
|
||||||
<option value="">
|
size="xs"
|
||||||
{{ getPieceOptions(pieceAssignment.definition).length ? 'Choisir une pièce' : 'Sélection impossible' }}
|
placeholder="Rechercher une pièce..."
|
||||||
</option>
|
:empty-text="getPieceOptions(pieceAssignment.definition).length ? 'Aucun résultat' : 'Aucune pièce disponible'"
|
||||||
<option
|
:option-label="pieceOptionLabel"
|
||||||
v-for="piece in getPieceOptions(pieceAssignment.definition)"
|
:option-description="pieceOptionDescription"
|
||||||
:key="piece.id"
|
@update:modelValue="(value) => { pieceAssignment.selectedPieceId = normalizeSelectionValue(value); }"
|
||||||
:value="piece.id"
|
/>
|
||||||
>
|
|
||||||
{{ formatPieceOption(piece) }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -90,6 +82,8 @@
|
|||||||
:assignment="subAssignment"
|
:assignment="subAssignment"
|
||||||
:pieces="pieces"
|
:pieces="pieces"
|
||||||
:components="components"
|
:components="components"
|
||||||
|
:components-loading="componentsLoading"
|
||||||
|
:pieces-loading="piecesLoading"
|
||||||
:depth="depth + 1"
|
:depth="depth + 1"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
@@ -98,6 +92,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, watch } from 'vue';
|
import { computed, watch } from 'vue';
|
||||||
|
import SearchSelect from '~/components/common/SearchSelect.vue';
|
||||||
import type {
|
import type {
|
||||||
ComponentModelPiece,
|
ComponentModelPiece,
|
||||||
ComponentModelStructureNode,
|
ComponentModelStructureNode,
|
||||||
@@ -147,11 +142,15 @@ const props = withDefaults(
|
|||||||
pieces: PieceOption[] | null;
|
pieces: PieceOption[] | null;
|
||||||
components: ComponentOption[] | null;
|
components: ComponentOption[] | null;
|
||||||
depth?: number;
|
depth?: number;
|
||||||
|
componentsLoading?: boolean;
|
||||||
|
piecesLoading?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
depth: 0,
|
depth: 0,
|
||||||
pieces: () => [],
|
pieces: () => [],
|
||||||
components: () => [],
|
components: () => [],
|
||||||
|
componentsLoading: false,
|
||||||
|
piecesLoading: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -188,6 +187,29 @@ const componentOptions = computed(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const componentOptionLabel = (component?: ComponentOption | null) => {
|
||||||
|
if (!component) {
|
||||||
|
return 'Composant sans nom';
|
||||||
|
}
|
||||||
|
return component.name || 'Composant sans nom';
|
||||||
|
};
|
||||||
|
|
||||||
|
const componentOptionDescription = (component?: ComponentOption | null) => {
|
||||||
|
if (!component) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const parts: string[] = [];
|
||||||
|
const typeLabel =
|
||||||
|
component.typeComposant?.name || component.typeComposant?.code || null;
|
||||||
|
if (typeLabel) {
|
||||||
|
parts.push(typeLabel);
|
||||||
|
}
|
||||||
|
if (component.reference) {
|
||||||
|
parts.push(`Ref. ${component.reference}`);
|
||||||
|
}
|
||||||
|
return parts.join(' • ');
|
||||||
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
componentOptions,
|
componentOptions,
|
||||||
(options) => {
|
(options) => {
|
||||||
@@ -204,18 +226,6 @@ watch(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
const formatComponentOption = (component: ComponentOption) => {
|
|
||||||
const name = component.name || 'Composant sans nom';
|
|
||||||
const reference = component.reference ? ` • Ref. ${component.reference}` : '';
|
|
||||||
const typeLabel =
|
|
||||||
component.typeComposant?.name || component.typeComposant?.code || '';
|
|
||||||
const typed =
|
|
||||||
typeLabel && component.typeComposant?.name !== name
|
|
||||||
? ` (${typeLabel})`
|
|
||||||
: '';
|
|
||||||
return `${name}${typed}${reference}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const describePieceRequirement = (definition: ComponentModelPiece) => {
|
const describePieceRequirement = (definition: ComponentModelPiece) => {
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
if (definition.role) {
|
if (definition.role) {
|
||||||
@@ -288,10 +298,40 @@ const getPieceOptions = (definition: ComponentModelPiece) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatPieceOption = (piece: PieceOption) => {
|
const pieceOptionLabel = (piece?: PieceOption | null) => {
|
||||||
const name = piece.name || 'Pièce';
|
if (!piece) {
|
||||||
const reference = piece.reference ? ` • Ref. ${piece.reference}` : '';
|
return 'Pièce';
|
||||||
return `${name}${reference}`;
|
}
|
||||||
|
return piece.name || 'Pièce';
|
||||||
|
};
|
||||||
|
|
||||||
|
const pieceOptionDescription = (piece?: PieceOption | null) => {
|
||||||
|
if (!piece) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const parts: string[] = [];
|
||||||
|
const typeLabel =
|
||||||
|
piece.typePiece?.name || piece.typePiece?.code || null;
|
||||||
|
if (typeLabel) {
|
||||||
|
parts.push(typeLabel);
|
||||||
|
}
|
||||||
|
if (piece.reference) {
|
||||||
|
parts.push(`Ref. ${piece.reference}`);
|
||||||
|
}
|
||||||
|
return parts.join(' • ');
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeSelectionValue = (value: unknown) => {
|
||||||
|
if (value === null || value === undefined || value === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|||||||
@@ -175,7 +175,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="space-y-3">
|
<section v-if="allowSubcomponents" class="space-y-3">
|
||||||
<div class="flex items-center justify-between gap-2">
|
<div class="flex items-center justify-between gap-2">
|
||||||
<h4 :class="headingClass">Sous-composants</h4>
|
<h4 :class="headingClass">Sous-composants</h4>
|
||||||
<button type="button" class="btn btn-outline btn-xs" @click="addSubComponent">
|
<button type="button" class="btn btn-outline btn-xs" @click="addSubComponent">
|
||||||
@@ -197,6 +197,7 @@
|
|||||||
:depth="depth + 1"
|
:depth="depth + 1"
|
||||||
:component-types="componentTypes"
|
:component-types="componentTypes"
|
||||||
:piece-types="pieceTypes"
|
:piece-types="pieceTypes"
|
||||||
|
:allow-subcomponents="allowSubcomponents"
|
||||||
@remove="removeSubComponent(index)"
|
@remove="removeSubComponent(index)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -233,6 +234,7 @@ const props = withDefaults(defineProps<{
|
|||||||
isRoot?: boolean
|
isRoot?: boolean
|
||||||
lockType?: boolean
|
lockType?: boolean
|
||||||
lockedTypeLabel?: string
|
lockedTypeLabel?: string
|
||||||
|
allowSubcomponents?: boolean
|
||||||
}>(), {
|
}>(), {
|
||||||
depth: 0,
|
depth: 0,
|
||||||
componentTypes: () => [],
|
componentTypes: () => [],
|
||||||
@@ -240,12 +242,14 @@ const props = withDefaults(defineProps<{
|
|||||||
isRoot: false,
|
isRoot: false,
|
||||||
lockType: false,
|
lockType: false,
|
||||||
lockedTypeLabel: '',
|
lockedTypeLabel: '',
|
||||||
|
allowSubcomponents: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['remove'])
|
const emit = defineEmits(['remove'])
|
||||||
|
|
||||||
const componentTypes = computed(() => props.componentTypes ?? [])
|
const componentTypes = computed(() => props.componentTypes ?? [])
|
||||||
const pieceTypes = computed(() => props.pieceTypes ?? [])
|
const pieceTypes = computed(() => props.pieceTypes ?? [])
|
||||||
|
const allowSubcomponents = computed(() => props.allowSubcomponents !== false)
|
||||||
|
|
||||||
const depthClasses = ['', 'ml-4', 'ml-8', 'ml-12', 'ml-16', 'ml-20']
|
const depthClasses = ['', 'ml-4', 'ml-8', 'ml-12', 'ml-16', 'ml-20']
|
||||||
const containerClass = computed(() => {
|
const containerClass = computed(() => {
|
||||||
@@ -454,6 +458,9 @@ const removePiece = (index: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addSubComponent = () => {
|
const addSubComponent = () => {
|
||||||
|
if (!allowSubcomponents.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
ensureArray('subcomponents')
|
ensureArray('subcomponents')
|
||||||
props.node.subcomponents.push({
|
props.node.subcomponents.push({
|
||||||
typeComposantId: '',
|
typeComposantId: '',
|
||||||
@@ -470,6 +477,16 @@ const removeSubComponent = (index: number) => {
|
|||||||
props.node.subcomponents.splice(index, 1)
|
props.node.subcomponents.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
allowSubcomponents,
|
||||||
|
(allowed) => {
|
||||||
|
if (!allowed && Array.isArray(props.node.subcomponents) && props.node.subcomponents.length) {
|
||||||
|
props.node.subcomponents.splice(0, props.node.subcomponents.length)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
watch(componentTypes, () => {
|
watch(componentTypes, () => {
|
||||||
syncComponentType(props.node)
|
syncComponentType(props.node)
|
||||||
}, { deep: true, immediate: true })
|
}, { deep: true, immediate: true })
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
:default-requirement="createDefaultRequirement"
|
:default-requirement="createDefaultRequirement"
|
||||||
:required-fallback="true"
|
:required-fallback="true"
|
||||||
:min-fallback="1"
|
:min-fallback="1"
|
||||||
|
:type-loading="loadingComponentTypes"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
const { componentTypes, loadComponentTypes } = useComponentTypes()
|
const { componentTypes, loadComponentTypes, loadingComponentTypes } = useComponentTypes()
|
||||||
|
|
||||||
const requirements = computed({
|
const requirements = computed({
|
||||||
get: () => props.modelValue,
|
get: () => props.modelValue,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
:default-requirement="createDefaultRequirement"
|
:default-requirement="createDefaultRequirement"
|
||||||
:required-fallback="false"
|
:required-fallback="false"
|
||||||
:min-fallback="0"
|
:min-fallback="0"
|
||||||
|
:type-loading="loadingPieceTypes"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
const { pieceTypes, loadPieceTypes } = usePieceTypes()
|
const { pieceTypes, loadPieceTypes, loadingPieceTypes } = usePieceTypes()
|
||||||
|
|
||||||
const requirements = computed({
|
const requirements = computed({
|
||||||
get: () => props.modelValue,
|
get: () => props.modelValue,
|
||||||
|
|||||||
@@ -29,21 +29,17 @@
|
|||||||
<span class="label-text">{{ labels.typeSelectLabel }}</span>
|
<span class="label-text">{{ labels.typeSelectLabel }}</span>
|
||||||
<span class="label-text-alt text-error">*</span>
|
<span class="label-text-alt text-error">*</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<SearchSelect
|
||||||
:value="requirement[typeField] ?? ''"
|
:model-value="normalizeTypeModel(requirement[typeField])"
|
||||||
class="select select-bordered select-sm"
|
:options="typeOptions"
|
||||||
required
|
:loading="typeLoading"
|
||||||
@change="updateRequirement(index, { [typeField]: normalizeTypeValue($event.target.value) })"
|
size="sm"
|
||||||
>
|
:placeholder="labels.typePlaceholder"
|
||||||
<option value="">{{ labels.typePlaceholder }}</option>
|
:empty-text="typeOptions.length ? 'Aucun résultat' : 'Aucune option disponible'"
|
||||||
<option
|
:option-label="optionLabel"
|
||||||
v-for="type in typeOptions"
|
:option-description="optionDescription"
|
||||||
:key="type.id"
|
@update:modelValue="(value) => updateRequirement(index, { [typeField]: normalizeTypeValue(value) })"
|
||||||
:value="type.id"
|
/>
|
||||||
>
|
|
||||||
{{ type.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
@@ -128,10 +124,12 @@ import { computed } from 'vue'
|
|||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import IconLucidePlus from '~icons/lucide/plus'
|
import IconLucidePlus from '~icons/lucide/plus'
|
||||||
import IconLucideTrash2 from '~icons/lucide/trash-2'
|
import IconLucideTrash2 from '~icons/lucide/trash-2'
|
||||||
|
import SearchSelect from '~/components/common/SearchSelect.vue'
|
||||||
|
|
||||||
type Option = {
|
type Option = {
|
||||||
id: string | number
|
id: string | number
|
||||||
name: string
|
name: string
|
||||||
|
description?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
type Requirement = Record<string, unknown> & {
|
type Requirement = Record<string, unknown> & {
|
||||||
@@ -193,6 +191,10 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
typeLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
@@ -202,6 +204,23 @@ const requirements = computed({
|
|||||||
set: (value) => emit('update:modelValue', value),
|
set: (value) => emit('update:modelValue', value),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const optionLabel = (option: Option) => {
|
||||||
|
if (!option) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return option.name || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const optionDescription = (option: Option) => {
|
||||||
|
if (!option) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (typeof option.description === 'string' && option.description.trim()) {
|
||||||
|
return option.description.trim()
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
const addRequirement = () => {
|
const addRequirement = () => {
|
||||||
requirements.value = [
|
requirements.value = [
|
||||||
...requirements.value,
|
...requirements.value,
|
||||||
@@ -232,8 +251,18 @@ const parseOptionalNumber = (value: string) => {
|
|||||||
return Number.isFinite(parsed) ? parsed : null
|
return Number.isFinite(parsed) ? parsed : null
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeTypeValue = (value: string) => {
|
const normalizeTypeModel = (value: unknown) => {
|
||||||
if (!value) {
|
if (value === null || value === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (typeof value === 'string' || typeof value === 'number') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizeTypeValue = (value: string | number | null | undefined) => {
|
||||||
|
if (value === '' || value === null || value === undefined) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -96,7 +96,10 @@
|
|||||||
Aperçu :
|
Aperçu :
|
||||||
<span class="font-medium text-base-content">{{ componentStructurePreview }}</span>
|
<span class="font-medium text-base-content">{{ componentStructurePreview }}</span>
|
||||||
</p>
|
</p>
|
||||||
<ComponentModelStructureEditor v-model="componentStructure" />
|
<ComponentModelStructureEditor
|
||||||
|
v-model="componentStructure"
|
||||||
|
:allow-subcomponents="allowComponentSubcomponents"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -147,11 +150,13 @@ const props = withDefaults(defineProps<{
|
|||||||
saving?: boolean
|
saving?: boolean
|
||||||
lockCategory?: boolean
|
lockCategory?: boolean
|
||||||
structureLoading?: boolean
|
structureLoading?: boolean
|
||||||
|
allowComponentSubcomponents?: boolean
|
||||||
}>(), {
|
}>(), {
|
||||||
initialData: null,
|
initialData: null,
|
||||||
saving: false,
|
saving: false,
|
||||||
lockCategory: false,
|
lockCategory: false,
|
||||||
structureLoading: false,
|
structureLoading: false,
|
||||||
|
allowComponentSubcomponents: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -162,6 +167,7 @@ const emit = defineEmits<{
|
|||||||
const lockCategory = computed(() => props.lockCategory ?? false)
|
const lockCategory = computed(() => props.lockCategory ?? false)
|
||||||
const structureLoading = computed(() => props.structureLoading ?? false)
|
const structureLoading = computed(() => props.structureLoading ?? false)
|
||||||
const saving = computed(() => props.saving ?? false)
|
const saving = computed(() => props.saving ?? false)
|
||||||
|
const allowComponentSubcomponents = computed(() => props.allowComponentSubcomponents !== false)
|
||||||
|
|
||||||
const form = reactive<ModelTypePayload>({
|
const form = reactive<ModelTypePayload>({
|
||||||
name: '',
|
name: '',
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
initial-category="COMPONENT"
|
initial-category="COMPONENT"
|
||||||
:initial-data="initialData"
|
:initial-data="initialData"
|
||||||
:lock-category="true"
|
:lock-category="true"
|
||||||
|
:allow-component-subcomponents="false"
|
||||||
:saving="saving"
|
:saving="saving"
|
||||||
@submit="handleSubmit"
|
@submit="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
mode="create"
|
mode="create"
|
||||||
initial-category="COMPONENT"
|
initial-category="COMPONENT"
|
||||||
:lock-category="true"
|
:lock-category="true"
|
||||||
|
:allow-component-subcomponents="false"
|
||||||
:saving="saving"
|
:saving="saving"
|
||||||
@submit="handleSubmit"
|
@submit="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
|
|||||||
@@ -19,21 +19,17 @@
|
|||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text">Catégorie de composant</span>
|
<span class="label-text">Catégorie de composant</span>
|
||||||
</label>
|
</label>
|
||||||
<select
|
<SearchSelect
|
||||||
v-model="selectedTypeId"
|
v-model="selectedTypeId"
|
||||||
class="select select-bordered select-sm md:select-md"
|
:options="componentTypeList"
|
||||||
|
:loading="loadingTypes"
|
||||||
|
size="sm"
|
||||||
|
placeholder="Rechercher une catégorie..."
|
||||||
|
empty-text="Aucune catégorie disponible"
|
||||||
|
:option-label="typeOptionLabel"
|
||||||
|
:option-description="typeOptionDescription"
|
||||||
:disabled="loadingTypes || submitting"
|
:disabled="loadingTypes || submitting"
|
||||||
required
|
/>
|
||||||
>
|
|
||||||
<option value="">Sélectionner une catégorie</option>
|
|
||||||
<option
|
|
||||||
v-for="type in componentTypeList"
|
|
||||||
:key="type.id"
|
|
||||||
:value="type.id"
|
|
||||||
>
|
|
||||||
{{ type.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<p v-if="loadingTypes" class="text-xs text-gray-500 mt-1">
|
<p v-if="loadingTypes" class="text-xs text-gray-500 mt-1">
|
||||||
Chargement des catégories…
|
Chargement des catégories…
|
||||||
</p>
|
</p>
|
||||||
@@ -189,6 +185,8 @@
|
|||||||
:assignment="structureAssignments"
|
:assignment="structureAssignments"
|
||||||
:pieces="availablePieces"
|
:pieces="availablePieces"
|
||||||
:components="availableComponents"
|
:components="availableComponents"
|
||||||
|
:pieces-loading="piecesLoading"
|
||||||
|
:components-loading="componentsLoading"
|
||||||
/>
|
/>
|
||||||
<p v-else class="text-xs text-error">
|
<p v-else class="text-xs text-error">
|
||||||
Impossible de générer les emplacements définis par le squelette.
|
Impossible de générer les emplacements définis par le squelette.
|
||||||
@@ -297,6 +295,7 @@ import ConstructeurSelect from '~/components/ConstructeurSelect.vue'
|
|||||||
import ComponentStructureAssignmentNode, {
|
import ComponentStructureAssignmentNode, {
|
||||||
type StructureAssignmentNode,
|
type StructureAssignmentNode,
|
||||||
} from '~/components/ComponentStructureAssignmentNode.vue'
|
} from '~/components/ComponentStructureAssignmentNode.vue'
|
||||||
|
import SearchSelect from '~/components/common/SearchSelect.vue'
|
||||||
import { useComponentTypes } from '~/composables/useComponentTypes'
|
import { useComponentTypes } from '~/composables/useComponentTypes'
|
||||||
import { useComposants } from '~/composables/useComposants'
|
import { useComposants } from '~/composables/useComposants'
|
||||||
import { usePieces } from '~/composables/usePieces'
|
import { usePieces } from '~/composables/usePieces'
|
||||||
@@ -381,6 +380,12 @@ const componentTypeList = computed<ComponentCatalogType[]>(() =>
|
|||||||
.filter((item: any) => item?.category === 'COMPONENT') as ComponentCatalogType[],
|
.filter((item: any) => item?.category === 'COMPONENT') as ComponentCatalogType[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const typeOptionLabel = (type?: ComponentCatalogType) =>
|
||||||
|
type?.name || 'Catégorie'
|
||||||
|
|
||||||
|
const typeOptionDescription = (type?: ComponentCatalogType) =>
|
||||||
|
type?.description ? String(type.description) : ''
|
||||||
|
|
||||||
const selectedType = computed(() => {
|
const selectedType = computed(() => {
|
||||||
if (!selectedTypeId.value) {
|
if (!selectedTypeId.value) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
Reference in New Issue
Block a user