file saving & exiting
This commit is contained in:
parent
0a55fc8c88
commit
61a8f56d13
8 changed files with 151 additions and 24 deletions
|
@ -9,6 +9,7 @@
|
|||
"core:default",
|
||||
"opener:default",
|
||||
"dialog:default",
|
||||
"fs:allow-write-text-file",
|
||||
"fs:default"
|
||||
]
|
||||
}
|
|
@ -36,4 +36,9 @@ main
|
|||
<style lang="sass">
|
||||
header
|
||||
margin-bottom: 1rem
|
||||
.ellipsis
|
||||
display: inline-block
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
</style>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { definePreset } from '@primeuix/themes'
|
|||
import Aura from '@primeuix/themes/aura'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import ToastService from 'primevue/toastservice'
|
||||
import Tooltip from 'primevue/tooltip'
|
||||
import 'primeicons/primeicons.css'
|
||||
|
||||
import { router } from './router'
|
||||
|
@ -12,7 +13,6 @@ import App from './App.vue'
|
|||
const pinia = createPinia()
|
||||
const app = createApp(App)
|
||||
|
||||
|
||||
const themePreset = definePreset(Aura, {
|
||||
semantic: {
|
||||
primary: {
|
||||
|
@ -44,4 +44,5 @@ app
|
|||
},
|
||||
})
|
||||
.use(ToastService)
|
||||
.directive('tooltip', Tooltip)
|
||||
.mount('#app')
|
||||
|
|
|
@ -17,12 +17,14 @@ export const useAppStore = defineStore('appStore', {
|
|||
} as InventoryState,
|
||||
}),
|
||||
getters: {
|
||||
fileTree: (state) => fileTree(state.currentInventory),
|
||||
fileDirectory: (state) => {
|
||||
fileTree(state) {
|
||||
return fileTree(state.currentInventory)
|
||||
},
|
||||
fileDirectory(state) {
|
||||
const split = fileTree(state.currentInventory)
|
||||
return state.currentInventory.filePath.replace(split[split.length - 1], '')
|
||||
},
|
||||
fileName: (state) => {
|
||||
fileName(state) {
|
||||
const split = fileTree(state.currentInventory)
|
||||
return split[split.length - 1]
|
||||
},
|
||||
|
|
|
@ -15,35 +15,40 @@ import {
|
|||
const props = defineProps<{
|
||||
columns: DataColumn[],
|
||||
}>()
|
||||
const model = defineModel<DataRow[]>()
|
||||
const emits = defineEmits<{
|
||||
(e: 'dirty'): void
|
||||
}>()
|
||||
const model = defineModel<DataRow[]>({ required: true })
|
||||
const editingRows = ref([])
|
||||
|
||||
const onRowEditSave = (event: { newData: any, index: number }) => {
|
||||
let { newData, index } = event
|
||||
model.value![index] = newData
|
||||
model.value[index] = newData
|
||||
emits('dirty')
|
||||
}
|
||||
|
||||
const onAddRow = (event: Event) => {
|
||||
event.preventDefault()
|
||||
model.value!.push({ _id: uuidv7() })
|
||||
console.log(model.value)
|
||||
model.value.push({ _id: uuidv7() })
|
||||
emits('dirty')
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
(document.querySelector('tr:last-of-type button.edit') as HTMLButtonElement).click()
|
||||
(document.querySelector('.data-editor tr:last-of-type button.edit') as HTMLButtonElement).click()
|
||||
requestAnimationFrame(() => {
|
||||
(document.querySelector('tr:last-of-type input') as HTMLInputElement | undefined)?.focus()
|
||||
(document.querySelector('.data-editor tr:last-of-type input') as HTMLInputElement | undefined)?.select()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const onDeleteRow = (event: Event, slotProps: { index: number }) => {
|
||||
event.preventDefault()
|
||||
model.value!.splice(slotProps.index, 1)
|
||||
model.value.splice(slotProps.index, 1)
|
||||
emits('dirty')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
DataTable(
|
||||
DataTable.data-editor(
|
||||
@row-edit-save='onRowEditSave'
|
||||
v-model:editingRows='editingRows'
|
||||
:value='model'
|
||||
|
@ -93,6 +98,7 @@ DataTable(
|
|||
)
|
||||
Column(
|
||||
rowEditor
|
||||
header='Actions'
|
||||
style='width:10%;min-width:8rem;'
|
||||
bodyStyle='text-align:center;'
|
||||
)
|
||||
|
@ -157,4 +163,7 @@ Button(
|
|||
:deep(.p-image)
|
||||
img
|
||||
max-width: 16rem
|
||||
:deep(td:last-of-type)
|
||||
display: flex
|
||||
padding-left: 8px
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
computed,
|
||||
ref,
|
||||
} from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useToast } from 'primevue'
|
||||
import { writeTextFile } from '@tauri-apps/plugin-fs'
|
||||
import Menubar from 'primevue/menubar'
|
||||
import Tabs from 'primevue/tabs'
|
||||
import TabList from 'primevue/tablist'
|
||||
import Tab from 'primevue/tab'
|
||||
|
@ -14,13 +21,71 @@ import DataEditor from './DataEditor.vue'
|
|||
import FieldEditor from './FieldEditor.vue'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
const data = ref([...appStore.currentInventory.data?.rows || []])
|
||||
const fields = ref([...appStore.currentInventory.data?.columns || []])
|
||||
const data = ref(appStore.currentInventory.data?.rows)
|
||||
const fields = ref(appStore.currentInventory.data?.columns)
|
||||
const dirty = ref(false)
|
||||
const fileDirectory = ref(appStore.fileDirectory)
|
||||
const fileName = ref(appStore.fileName)
|
||||
|
||||
const onSave = async () => {
|
||||
try {
|
||||
await writeTextFile(appStore.currentInventory.filePath, JSON.stringify({
|
||||
rows: data.value,
|
||||
columns: fields.value,
|
||||
}, null, 2))
|
||||
} catch (err) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'The file could not be saved (permission issue?)',
|
||||
detail: err,
|
||||
})
|
||||
}
|
||||
dirty.value = false
|
||||
}
|
||||
|
||||
const onQuit = () => {
|
||||
// todo: should prompt to confirm
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
const menu = computed(() => ([
|
||||
{
|
||||
label: 'Save',
|
||||
icon: 'pi pi-save',
|
||||
command: onSave,
|
||||
disabled: !dirty.value,
|
||||
},
|
||||
{
|
||||
label: 'Exit',
|
||||
icon: 'pi pi-sign-out',
|
||||
command: onQuit,
|
||||
},
|
||||
]))
|
||||
|
||||
const onDirty = () => {
|
||||
dirty.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
Tabs(value='data-editor')
|
||||
Menubar(
|
||||
:model='menu'
|
||||
)
|
||||
template(#end)
|
||||
.context
|
||||
span Editing for
|
||||
span.ellipsis(
|
||||
v-tooltip.bottom='fileDirectory'
|
||||
)
|
||||
span {{ fileDirectory }}
|
||||
span.ellipsis(
|
||||
v-tooltip.bottom='fileName'
|
||||
)
|
||||
span {{ fileName }}
|
||||
Tabs.tabs(value='data-editor')
|
||||
TabList
|
||||
Tab(value='data-editor') Data Editor
|
||||
Tab(value='field-editor') Field Editor
|
||||
|
@ -28,14 +93,22 @@ Tabs(value='data-editor')
|
|||
TabPanel(value='field-editor')
|
||||
FieldEditor(
|
||||
v-model='fields'
|
||||
@dirty='onDirty'
|
||||
)
|
||||
TabPanel(value='data-editor')
|
||||
DataEditor(
|
||||
v-model='data'
|
||||
:columns='fields'
|
||||
@dirty='onDirty'
|
||||
)
|
||||
</template>
|
||||
|
||||
<style scoped lang="sass">
|
||||
|
||||
.tabs
|
||||
margin-top: 1rem
|
||||
.context
|
||||
display: flex
|
||||
gap: 1rem
|
||||
.ellipsis
|
||||
max-width: 8rem
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { v1 as uuidv1 } from 'uuid'
|
||||
import Button from 'primevue/button'
|
||||
import DataTable from 'primevue/datatable'
|
||||
import Column from 'primevue/column'
|
||||
|
@ -11,18 +12,40 @@ import {
|
|||
type Column as DataColumn,
|
||||
} from 'src/types/data'
|
||||
|
||||
const model = defineModel<DataColumn[]>()
|
||||
const emits = defineEmits<{
|
||||
(e: 'dirty'): void
|
||||
}>()
|
||||
const model = defineModel<DataColumn[]>({ required: true })
|
||||
const editingFields = ref([])
|
||||
|
||||
const onFieldEditSave = (event: { newData: any, index: number }) => {
|
||||
let { newData, index } = event
|
||||
model.value![index] = newData
|
||||
console.log(model.value)
|
||||
model.value[index] = newData
|
||||
emits('dirty')
|
||||
}
|
||||
|
||||
const onAddField = (event: Event) => {
|
||||
event.preventDefault()
|
||||
model.value.push({ name: uuidv1().split('-')[0], type: 'text' })
|
||||
emits('dirty')
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
(document.querySelector('.field-editor tr:last-of-type button.edit') as HTMLButtonElement).click()
|
||||
requestAnimationFrame(() => {
|
||||
(document.querySelector('.field-editor tr:last-of-type input') as HTMLInputElement | undefined)?.select()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const onDeleteField = (event: Event, slotProps: { index: number }) => {
|
||||
event.preventDefault()
|
||||
model.value.splice(slotProps.index, 1)
|
||||
emits('dirty')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
DataTable(
|
||||
DataTable.field-editor(
|
||||
@row-edit-save='onFieldEditSave'
|
||||
v-model:editingRows='editingFields'
|
||||
:value='model'
|
||||
|
@ -61,13 +84,14 @@ DataTable(
|
|||
)
|
||||
Column(
|
||||
rowEditor
|
||||
header='Actions'
|
||||
style='width:10%;min-width:8rem;'
|
||||
bodyStyle='text-align:center;'
|
||||
)
|
||||
template(
|
||||
#body='slotProps'
|
||||
)
|
||||
Button(
|
||||
Button.edit(
|
||||
icon='pi pi-pencil'
|
||||
aria-label='Row Edit'
|
||||
rounded
|
||||
|
@ -83,6 +107,9 @@ DataTable(
|
|||
rounded
|
||||
severity='danger'
|
||||
variant='text'
|
||||
:onClick=`(e) => {
|
||||
onDeleteField(e, slotProps)
|
||||
}`
|
||||
)
|
||||
template(
|
||||
#editor='slotProps'
|
||||
|
@ -107,7 +134,16 @@ DataTable(
|
|||
slotProps.editorCancelCallback(e)
|
||||
}`
|
||||
)
|
||||
Button(
|
||||
icon='pi pi-plus'
|
||||
aria-label='Add New Field'
|
||||
label='Add New Field'
|
||||
@click='onAddField'
|
||||
)
|
||||
</template>
|
||||
|
||||
<style scoped lang="sass">
|
||||
:deep(td:last-of-type)
|
||||
display: flex
|
||||
padding-left: 8px
|
||||
</style>
|
||||
|
|
|
@ -38,7 +38,7 @@ const onBrowse = async (e: Event) => {
|
|||
|
||||
const onCreate = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
appStore.currentInventory.filePath = `${filePath}/${fileName}.json`
|
||||
appStore.currentInventory.filePath = `${filePath.value}/${fileName.value}.json`
|
||||
appStore.currentInventory.data = {
|
||||
columns: [
|
||||
{ name: 'name', type: 'text' },
|
||||
|
|
Loading…
Add table
Reference in a new issue