add editor modal + fix image not sending dirty

This commit is contained in:
lightling 2025-03-21 17:46:01 -04:00
parent acaa9a18ae
commit 1eee6c0b4b
Signed by: lightling
GPG key ID: F1F29650D537C773
2 changed files with 150 additions and 1 deletions

View file

@ -22,6 +22,7 @@ import {
type Row as DataRow,
type Column as DataColumn,
} from 'src/types/data'
import DataEditorModal from './DataEditorModal.vue'
import ImageEditor from './ImageEditor.vue'
import { type EditingRow } from './types'
@ -37,6 +38,8 @@ const editingRows = ref<DataRow[]>([])
const expandedRows = ref<DataRow[]>([])
const editingImage = ref(false)
const editingImageRow = ref(null as EditingRow | null)
const editingRow = ref(false)
const editingRowData = ref(null as EditingRow | null)
const columnsByKey = computed(() => Object.assign({}, ...props.columns.map(c => ({[c.name]: c}))))
const columnsPrimary = computed(() => props.columns.filter(column => !column.secondary))
const selectedTemplate = ref(null as DataRow | null) // simply used to reset dropdown when selected
@ -86,6 +89,12 @@ const onEditImage = (event: Event, slotProps: EditingRow) => {
editingImageRow.value = slotProps
}
const onEditRow = (event: Event, slotProps: EditingRow) => {
event.preventDefault()
editingRow.value = true
editingRowData.value = slotProps
}
const onRemoveImage = (event: Event, slotProps: EditingRow) => {
event.preventDefault()
const row = { ...model.value[slotProps.index] } as any
@ -96,6 +105,7 @@ const onRemoveImage = (event: Event, slotProps: EditingRow) => {
let rows = editingRows.value
rows.splice(indexOfEditing, 1)
editingRows.value = rows
emits('dirty')
}
}
@ -110,8 +120,14 @@ const onSaveImage = (image: string) => {
let rows = editingRows.value
rows.splice(indexOfEditing, 1)
editingRows.value = rows
emits('dirty')
}
}
const onSaveRow = (row: DataRow, editingRow: EditingRow) => {
model.value[editingRow.index] = row
emits('dirty')
}
</script>
<template lang="pug">
@ -120,6 +136,12 @@ ImageEditor(
v-model:row='editingImageRow'
@saved='onSaveImage'
)
DataEditorModal(
v-model:visible='editingRow'
:row='editingRowData'
:fields='columns'
@saved='onSaveRow'
)
DataTable.data-editor(
@row-edit-save='onRowEditSave'
v-model:editingRows='editingRows'
@ -258,6 +280,14 @@ DataTable.data-editor(
variant='text'
@click='slotProps.editorInitCallback'
)
Button.edit(
icon='pi pi-pen-to-square'
aria-label='Row Edit Details'
rounded
severity='secondary'
variant='text'
@click='(e) => onEditRow(e, slotProps)'
)
Button(
icon='pi pi-trash'
aria-label='Delete'
@ -283,7 +313,7 @@ DataTable.data-editor(
rounded
severity='secondary'
variant='text'
@click'slotProps.editorCancelCallback(e)'
@click='slotProps.editorCancelCallback(e)'
)
template(
#expansion='slotProps'

View file

@ -0,0 +1,119 @@
<script setup lang="ts">
import {
ref,
watch
} from 'vue'
import Button from 'primevue/button'
import Checkbox from 'primevue/checkbox'
import Dialog from 'primevue/dialog'
import ImageComponent from 'primevue/image'
import InputGroup from 'primevue/inputgroup'
import InputGroupAddon from 'primevue/inputgroupaddon'
import InputText from 'primevue/inputtext'
import MultiSelect from 'primevue/multiselect'
import Select from 'primevue/select'
import { useAppStore } from 'src/store'
import { type EditingRow } from './types'
import type { Row as DataRow, Column as DataColumn } from 'src/types/data'
const store = useAppStore()
const props = defineProps<{
fields: DataColumn[],
row: EditingRow,
}>()
const visible = defineModel<boolean>('visible', { default: false })
const emit = defineEmits<{
(e: 'saved', val: DataRow, editingRow: EditingRow): void
}>()
const editing = ref<DataRow>({} as any)
watch(() => props.row, async (newRow, oldRow) => {
editing.value = JSON.parse(JSON.stringify(props.row.data || {}))
})
const onCancel = (e: Event) => {
e.preventDefault()
visible.value = false
}
const onSave = async (e: Event) => {
e.preventDefault()
emit('saved', JSON.parse(JSON.stringify(editing.value || {})), props.row)
visible.value = false
}
</script>
<template lang="pug">
ImageEditor(
v-model:visible='editingImage'
v-model:row='editingImageRow'
@saved='onSaveImage'
)
Dialog(
v-model:visible='visible'
modal
header='Edit Data'
)
.content
InputGroup(
v-for='field in fields'
)
InputGroupAddon
label
span {{ field.name }}
InputGroupAddon(
v-if='field.type === "image"'
)
p Image editing in data modal not yet supported
InputGroupAddon(
v-else-if='field.type === "toggle"'
)
Checkbox(
v-model='editing[field.name]'
:name='`toggle for ${editing.name || editing._id} ${field.name}`'
binary
)
InputGroupAddon(
v-else-if='field.type === "dropdown"'
)
Select(
v-model='editing[field.name]'
:options='field.options'
placeholder='Select from Options'
filter
showClear
fluid
)
InputGroupAddon(
v-else-if='field.type === "multiselect"'
)
MultiSelect(
v-model='editing[field.name]'
:options='field.options'
placeholder='Select from Options'
filter
showClear
fluid
display='chip'
)
InputGroupAddon(
v-else
)
InputText(
v-model='editing[field.name]'
)
template(#footer)
Button(
label='Save'
@click='onSave'
)
Button(
label='Cancel'
@click='onCancel'
)
</template>
<style scoped lang="sass">
</style>