From 7a0b69c1c161e45838483cdfef6939af1c8fc576 Mon Sep 17 00:00:00 2001 From: Lightling Date: Tue, 4 Mar 2025 22:32:28 -0500 Subject: [PATCH] support dropdown field option --- src/components/InputChips.vue | 67 ++++++++++++++++++++++++++++++++ src/types/data.ts | 28 ++++++++++++- src/views/Editor/DataEditor.vue | 28 ++++++++++--- src/views/Editor/FieldEditor.vue | 27 +++++++++++-- 4 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 src/components/InputChips.vue diff --git a/src/components/InputChips.vue b/src/components/InputChips.vue new file mode 100644 index 0000000..a061c22 --- /dev/null +++ b/src/components/InputChips.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/src/types/data.ts b/src/types/data.ts index 3f55efd..f4cc68f 100644 --- a/src/types/data.ts +++ b/src/types/data.ts @@ -1,3 +1,7 @@ +/** + * Defines the available types of fields that can be edited by the data editor, + * set by a column's field type. + */ export const FieldTypes = [ 'text', 'image', @@ -6,6 +10,9 @@ export const FieldTypes = [ 'toggle', ] as const +/** + * Specifies the type of field for editing in the data editor. + */ export type FieldType = typeof FieldTypes[number] export interface Image { @@ -13,18 +20,35 @@ export interface Image { alt?: string } +/** + * The structure of a column. Columns define the available fields to edit for every row + * and control how they are edited. + */ export interface Column { + /** the name of the field; this represents the key in the columns record */ name: string + /** the type of the field; this controls how it is edited in the data editor */ type: FieldType + /** whether the field is secondary or not; if it is, it is hidden from the quick editing view in the data editor */ secondary?: boolean + /** options for the field; applies only to certain field types such as dropdowns */ + options?: any } -export type Columns = Column[] - +/** + * The structure of a Row. All rows at minimum should have a private _id field; + * beyond that, it is simply a record of key-value pairs + * where the key corresponds to a column by name + */ export type Row = { _id: string } & Record +/** + * The structure of an inventory. An inventory is simply a set of columns (fields) and rows (data), + * where each row has key-value pairs where the keys correspond to a column by name, + * and the columns define how the rows can be edited + */ export interface Inventory { columns: Column[] rows: Row[] diff --git a/src/views/Editor/DataEditor.vue b/src/views/Editor/DataEditor.vue index 2930ff8..e75cbc1 100644 --- a/src/views/Editor/DataEditor.vue +++ b/src/views/Editor/DataEditor.vue @@ -3,10 +3,11 @@ import { computed, ref } from 'vue' import { v7 as uuidv7 } from 'uuid' import Button from 'primevue/button' import Checkbox from 'primevue/checkbox' -import DataTable from 'primevue/datatable' import Column from 'primevue/column' +import DataTable from 'primevue/datatable' import Image from 'primevue/image' import InputText from 'primevue/inputtext' +import Select from 'primevue/select' import { type Row as DataRow, @@ -143,7 +144,12 @@ DataTable.data-editor( div( v-else ) - span {{ slotProps.data[col.name] }} + span( + v-if='slotProps.data[col.name]' + ) {{ slotProps.data[col.name] }} + span.empty( + v-else + ) not set template( #editor='slotProps' ) @@ -168,6 +174,17 @@ DataTable.data-editor( :name='`toggle for ${slotProps.data.name || slotProps.data._id} ${col.name}`' binary ) + div( + v-else-if='col.type === "dropdown"' + ) + Select( + v-model='slotProps.data[slotProps.field]' + :options='col.options' + placeholder='Select from Options' + filter + showClear + fluid + ) div( v-else ) @@ -228,7 +245,7 @@ DataTable.data-editor( ) p.empty( v-if='!slotProps.data[field]' - ) {{ field }} is empty + ) {{ field }} is not set .info-image( v-else-if='column.type === "image"' ) @@ -262,13 +279,14 @@ Button( img max-width: 100% max-height: 8rem -:deep(td:last-of-type) +:deep(tr:not(.p-datatable-row-expansion) td:last-of-type) padding-left: 0 button:first-of-type margin-left: -16px .info :deep(.p-image) img max-width: 16rem max-height: 16rem -p.empty +p.empty, +span.empty font-style: italic diff --git a/src/views/Editor/FieldEditor.vue b/src/views/Editor/FieldEditor.vue index 7c5797c..d7ebb4b 100644 --- a/src/views/Editor/FieldEditor.vue +++ b/src/views/Editor/FieldEditor.vue @@ -12,12 +12,14 @@ import { FieldTypes, type Column as DataColumn, } from 'src/types/data' +import InputChips from 'src/components/InputChips.vue' const emits = defineEmits<{ (e: 'dirty'): void }>() const model = defineModel({ required: true }) const editingFields = ref([]) +const expandedRows = ref([]) const onFieldEditSave = (event: { newData: any, index: number }) => { let { newData, index } = event @@ -49,10 +51,15 @@ const onDeleteField = (event: Event, slotProps: { index: number }) => { DataTable.field-editor( @row-edit-save='onFieldEditSave' v-model:editingRows='editingFields' + v-model:expandedRows='expandedRows' :value='model' editMode='row' tableStyle='min-width: 50rem' ) + Column( + expander + style='width:5rem;' + ) Column( field='name' header='Name' @@ -156,6 +163,19 @@ DataTable.field-editor( slotProps.editorCancelCallback(e) }` ) + template( + #expansion='slotProps' + ) + div( + v-if='slotProps.data.type === "dropdown"' + ) + InputChips( + v-model='slotProps.data.options' + @dirty='$emit("dirty")' + ) + p( + v-else + ) there are no additional properties for this field type Button( icon='pi pi-plus' aria-label='Add New Field' @@ -165,7 +185,8 @@ Button(