Merge branch 'refs/heads/dev' into beta
This commit is contained in:
@@ -7,12 +7,20 @@ const props = defineProps({
|
||||
required: true,
|
||||
type: String
|
||||
},
|
||||
createQuery: {
|
||||
type: Object
|
||||
},
|
||||
item: {
|
||||
required: true,
|
||||
type: Object
|
||||
},
|
||||
inModal: {
|
||||
type: Boolean,
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(["returnData"])
|
||||
|
||||
|
||||
const {type} = props
|
||||
|
||||
@@ -38,6 +46,7 @@ const route = useRoute()
|
||||
const dataStore = useDataStore()
|
||||
const profileStore = useProfileStore()
|
||||
const supabase = useSupabaseClient()
|
||||
const modal = useModal()
|
||||
|
||||
const dataType = dataStore.dataTypes[type]
|
||||
const openTab = ref(0)
|
||||
@@ -73,17 +82,20 @@ const setupCreate = () => {
|
||||
setupCreate()
|
||||
|
||||
const setupQuery = () => {
|
||||
if(route.query) {
|
||||
Object.keys(route.query).forEach(key => {
|
||||
if(props.mode === "create" && (route.query || props.createQuery)) {
|
||||
|
||||
let data = !props.inModal ? route.query : props.createQuery
|
||||
|
||||
Object.keys(data).forEach(key => {
|
||||
if(dataType.templateColumns.find(i => i.key === key)) {
|
||||
if (["customer", "contract", "plant", "contact", "project"].includes(key)) {
|
||||
item.value[key] = Number(route.query[key])
|
||||
item.value[key] = Number(data[key])
|
||||
} else {
|
||||
item.value[key] = route.query[key]
|
||||
item.value[key] = data[key]
|
||||
}
|
||||
} else if(key === "resources") {
|
||||
/*item.value[key] = route.query[key]*/
|
||||
JSON.parse(route.query[key]).forEach(async (i) => {
|
||||
/*item.value[key] = data[key]*/
|
||||
JSON.parse(data[key]).forEach(async (i) => {
|
||||
console.log(i)
|
||||
let type = i.substring(0,1)
|
||||
let id = i.substring(2,i.length)
|
||||
@@ -180,10 +192,37 @@ const calcSaveAllowed = (item) => {
|
||||
watch(item.value, async (newItem, oldItem) => {
|
||||
calcSaveAllowed(newItem)
|
||||
})
|
||||
|
||||
const createItem = async () => {
|
||||
let ret = null
|
||||
|
||||
if(props.inModal) {
|
||||
ret = await dataStore.createNewItem(type,item.value,true)
|
||||
} else {
|
||||
ret = dataStore.createNewItem(type,item.value)
|
||||
}
|
||||
|
||||
emit('returnData', ret)
|
||||
}
|
||||
|
||||
const updateItem = async () => {
|
||||
let ret = null
|
||||
|
||||
if(props.inModal) {
|
||||
ret = await dataStore.updateItem(type,item.value, oldItem.value,true)
|
||||
} else {
|
||||
ret = await dataStore.updateItem(type,item.value, oldItem.value)
|
||||
}
|
||||
|
||||
emit('returnData', ret)
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UDashboardNavbar
|
||||
v-if="!props.inModal"
|
||||
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
|
||||
>
|
||||
<template #left>
|
||||
@@ -217,14 +256,14 @@ watch(item.value, async (newItem, oldItem) => {
|
||||
</ButtonWithConfirm>
|
||||
<UButton
|
||||
v-if="item.id"
|
||||
@click="dataStore.updateItem(type,item, oldItem)"
|
||||
@click="updateItem"
|
||||
:disabled="!saveAllowed"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
<UButton
|
||||
v-else
|
||||
@click="dataStore.createNewItem(type,item)"
|
||||
@click="createItem"
|
||||
:disabled="!saveAllowed"
|
||||
>
|
||||
Erstellen
|
||||
@@ -238,6 +277,40 @@ watch(item.value, async (newItem, oldItem) => {
|
||||
</UButton>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UDashboardNavbar
|
||||
v-else
|
||||
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
|
||||
>
|
||||
<template #center>
|
||||
<h1
|
||||
v-if="item"
|
||||
:class="['text-xl','font-medium']"
|
||||
>{{item.id ? `${dataType.labelSingle} bearbeiten` : `${dataType.labelSingle} erstellen` }}</h1>
|
||||
</template>
|
||||
<template #right>
|
||||
<UButton
|
||||
v-if="item.id"
|
||||
@click="updateItem"
|
||||
:disabled="!saveAllowed"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
<UButton
|
||||
v-else
|
||||
@click="createItem"
|
||||
:disabled="!saveAllowed"
|
||||
>
|
||||
Erstellen
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="modal.close()"
|
||||
color="red"
|
||||
class="ml-2"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
/>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UDashboardPanelContent>
|
||||
<UForm
|
||||
class="p-5"
|
||||
|
||||
82
components/EntityModalButtons.vue
Normal file
82
components/EntityModalButtons.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<script setup>
|
||||
import StandardEntityModal from "~/components/StandardEntityModal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
},
|
||||
createQuery: {
|
||||
type: Object,
|
||||
},
|
||||
buttonShow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
buttonEdit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
buttonCreate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(["returnData"])
|
||||
|
||||
|
||||
const modal = useModal()
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UButton
|
||||
variant="outline"
|
||||
class="w-25 ml-2"
|
||||
v-if="props.id && props.buttonShow"
|
||||
icon="i-heroicons-eye"
|
||||
@click="modal.open(StandardEntityModal, {
|
||||
id: props.id,
|
||||
type: props.type,
|
||||
mode: 'show',
|
||||
})"
|
||||
/>
|
||||
<UButton
|
||||
variant="outline"
|
||||
class="w-25 ml-2"
|
||||
v-if="props.id && props.buttonEdit"
|
||||
icon="i-heroicons-pencil-solid"
|
||||
@click="modal.open(StandardEntityModal, {
|
||||
id: props.id,
|
||||
type: props.type,
|
||||
mode: 'edit',
|
||||
onReturnData(data) {
|
||||
emit('returnData', data)
|
||||
}
|
||||
})"
|
||||
/>
|
||||
<UButton
|
||||
variant="outline"
|
||||
class="w-25 ml-2"
|
||||
v-if="!props.id && props.buttonCreate"
|
||||
icon="i-heroicons-plus"
|
||||
@click="modal.open(StandardEntityModal, {
|
||||
type: props.type,
|
||||
mode: 'create',
|
||||
createQuery: props.createQuery,
|
||||
onReturnData(data) {
|
||||
emit('returnData', data)
|
||||
}
|
||||
})"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -9,6 +9,9 @@ const props = defineProps({
|
||||
item: {
|
||||
required: true,
|
||||
type: Object
|
||||
},
|
||||
inModal: {
|
||||
type: Boolean,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -37,6 +40,7 @@ const dataStore = useDataStore()
|
||||
const profileStore = useProfileStore()
|
||||
const supabase = useSupabaseClient()
|
||||
const files = useFiles()
|
||||
const modal = useModal()
|
||||
|
||||
const dataType = dataStore.dataTypes[type]
|
||||
|
||||
@@ -168,6 +172,7 @@ const getAvailableQueryStringData = (keys) => {
|
||||
|
||||
<template>
|
||||
<UDashboardNavbar
|
||||
v-if="!props.inModal"
|
||||
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
|
||||
>
|
||||
<template #left>
|
||||
@@ -200,6 +205,26 @@ const getAvailableQueryStringData = (keys) => {
|
||||
</UButton>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UDashboardNavbar
|
||||
v-else
|
||||
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
|
||||
>
|
||||
<template #center>
|
||||
<h1
|
||||
v-if="item"
|
||||
:class="['text-xl','font-medium']"
|
||||
>{{item ? `${dataType.labelSingle}${props.item[dataType.templateColumns.find(i => i.title).key] ? ': ' + props.item[dataType.templateColumns.find(i => i.title).key] : ''}`: '' }}</h1>
|
||||
</template>
|
||||
<template #right>
|
||||
<UButton
|
||||
@click="modal.close()"
|
||||
color="red"
|
||||
class="ml-2"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
/>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UTabs
|
||||
:items="dataType.showTabs"
|
||||
v-if="props.item.id"
|
||||
|
||||
97
components/StandardEntityModal.vue
Normal file
97
components/StandardEntityModal.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<script setup>
|
||||
|
||||
const toast = useToast()
|
||||
const dataStore = useDataStore()
|
||||
const supabase = useSupabaseClient()
|
||||
const modal = useModal()
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "show"
|
||||
},
|
||||
createQuery: {
|
||||
type: Object
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
const emit = defineEmits(["updateNeeded","returnData"])
|
||||
|
||||
const dataType = dataStore.dataTypes[props.type]
|
||||
|
||||
const loaded = ref(false)
|
||||
const items = ref([])
|
||||
const item = ref({})
|
||||
|
||||
const setupPage = async () => {
|
||||
if(props.mode === "show") {
|
||||
//Load Data for Show
|
||||
item.value = await useSupabaseSelectSingle(props.type, props.id, dataType.supabaseSelectWithInformation || "*")
|
||||
} else if(props.mode === "edit") {
|
||||
//Load Data for Edit
|
||||
const data = JSON.stringify((await supabase.from(props.type).select().eq("id", props.id).single()).data)
|
||||
//await useSupabaseSelectSingle(type, route.params.id)
|
||||
item.value = data
|
||||
|
||||
} else if(props.mode === "create") {
|
||||
//Load Data for Create
|
||||
item.value = JSON.stringify({})
|
||||
|
||||
} else if(props.mode === "list") {
|
||||
//Load Data for List
|
||||
items.value = await useSupabaseSelect(props.type, dataType.supabaseSelectWithInformation || "*", dataType.supabaseSortColumn,dataType.supabaseSortAscending || false)
|
||||
}
|
||||
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
setupPage()
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :fullscreen="props.mode === 'show'">
|
||||
<EntityShow
|
||||
v-if="loaded && props.mode === 'show'"
|
||||
:type="props.type"
|
||||
:item="item"
|
||||
@updateNeeded="setupPage"
|
||||
:key="item"
|
||||
:in-modal="true"
|
||||
/>
|
||||
<EntityEdit
|
||||
v-else-if="loaded && (props.mode === 'edit' || props.mode === 'create')"
|
||||
:type="props.type"
|
||||
:item="item"
|
||||
:inModal="true"
|
||||
@return-data="(data) => emit('return-data',data)"
|
||||
:createQuery="props.createQuery"
|
||||
/>
|
||||
<!-- <EntityList
|
||||
v-else-if="loaded && props.mode === 'list'"
|
||||
:type="props.type"
|
||||
:items="items"
|
||||
/>-->
|
||||
<UProgress
|
||||
v-else
|
||||
animation="carousel"
|
||||
class="p-5 mt-10"
|
||||
/>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -3,12 +3,15 @@ import dayjs from "dayjs"
|
||||
import Handlebars from "handlebars"
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {useFunctions} from "~/composables/useFunctions.js";
|
||||
import StandardEntityModal from "~/components/StandardEntityModal.vue";
|
||||
import EntityModalButtons from "~/components/EntityModalButtons.vue";
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const profileStore = useProfileStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const supabase = useSupabaseClient()
|
||||
const modal = useModal()
|
||||
|
||||
|
||||
definePageMeta({
|
||||
@@ -326,7 +329,14 @@ const setTaxType = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const setCustomerData = () => {
|
||||
const setCustomerData = async (customerId) => {
|
||||
|
||||
if(customerId){
|
||||
itemInfo.value.customer = customerId
|
||||
}
|
||||
|
||||
customers.value = await useSupabaseSelect("customers")
|
||||
|
||||
|
||||
let customer = customers.value.find(i => i.id === itemInfo.value.customer)
|
||||
console.log(customer)
|
||||
@@ -1363,31 +1373,67 @@ const setRowData = (row) => {
|
||||
searchable-placeholder="Suche..."
|
||||
v-model="itemInfo.customer"
|
||||
@change="setCustomerData"
|
||||
class="flex-auto mr-2"
|
||||
class="flex-auto"
|
||||
>
|
||||
<UButton
|
||||
:color="itemInfo.customer ? 'primary' : 'rose'"
|
||||
variant="outline"
|
||||
class="w-full"
|
||||
>
|
||||
{{itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).name : "Kein Kunde ausgewählt"}}
|
||||
{{customers.find(i => i.id === itemInfo.customer) ? customers.find(i => i.id === itemInfo.customer).name : "Kein Kunde ausgewählt"}}
|
||||
|
||||
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform text-gray-400 dark:text-gray-500" :class="['transform rotate-90']" />
|
||||
</UButton>
|
||||
</USelectMenu>
|
||||
<EntityModalButtons
|
||||
type="customers"
|
||||
:id="itemInfo.customer"
|
||||
@return-data="(data) => setCustomerData(data.id)"
|
||||
/>
|
||||
<!-- <UButton
|
||||
variant="outline"
|
||||
class="w-25 ml-2"
|
||||
v-if="itemInfo.customer"
|
||||
icon="i-heroicons-eye"
|
||||
@click="modal.open(StandardEntityModal, {
|
||||
id: itemInfo.customer,
|
||||
type: 'customers',
|
||||
mode: 'show',
|
||||
})"
|
||||
/>
|
||||
<UButton
|
||||
variant="outline"
|
||||
class="w-25"
|
||||
class="w-25 ml-2"
|
||||
v-if="itemInfo.customer"
|
||||
icon="i-heroicons-arrow-right-end-on-rectangle"
|
||||
@click="router.push(`/standardEntity/customers/show/${itemInfo.customer}`)"
|
||||
>Kunde</UButton>
|
||||
icon="i-heroicons-pencil-solid"
|
||||
@click="modal.open(StandardEntityModal, {
|
||||
id: itemInfo.customer,
|
||||
type: 'customers',
|
||||
mode: 'edit',
|
||||
onReturnData(data) {
|
||||
setCustomerData()
|
||||
}
|
||||
})"
|
||||
/>
|
||||
<UButton
|
||||
variant="outline"
|
||||
class="w-25 ml-2"
|
||||
v-if="!itemInfo.customer"
|
||||
icon="i-heroicons-plus"
|
||||
@click="modal.open(StandardEntityModal, {
|
||||
type: 'customers',
|
||||
mode: 'create',
|
||||
onReturnData(data) {
|
||||
setCustomerData(data.id)
|
||||
}
|
||||
})"
|
||||
/>-->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<UAlert
|
||||
v-if="itemInfo.customer"
|
||||
v-if="customers.find(i => i.id === itemInfo.customer)"
|
||||
class="mt-2"
|
||||
variant="solid"
|
||||
color="white"
|
||||
@@ -1432,12 +1478,18 @@ const setRowData = (row) => {
|
||||
{{dataStore.getContactById(itemInfo.contact) ? dataStore.getContactById(itemInfo.contact).fullName : "Kein Kontakt ausgewählt"}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
<!-- <UButton
|
||||
variant="outline"
|
||||
v-if="itemInfo.contact"
|
||||
icon="i-heroicons-arrow-right-end-on-rectangle"
|
||||
@click="router.push(`/standardEntity/contacts/show/${itemInfo.contact}`)"
|
||||
>Kontakt</UButton>
|
||||
>Kontakt</UButton>-->
|
||||
<EntityModalButtons
|
||||
type="contacts"
|
||||
:id="itemInfo.contact"
|
||||
:create-query="{customerId: itemInfo.customer}"
|
||||
@return-data="(data) => itemInfo.contact = data.id"
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
</UFormGroup>
|
||||
@@ -1634,12 +1686,12 @@ const setRowData = (row) => {
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.plant = null"
|
||||
/>
|
||||
<UButton
|
||||
variant="outline"
|
||||
v-if="itemInfo.plant"
|
||||
icon="i-heroicons-arrow-right-end-on-rectangle"
|
||||
@click="router.push(`/standardEntity/plants/show/${itemInfo.plant}`)"
|
||||
>Objekt</UButton>
|
||||
<EntityModalButtons
|
||||
type="plants"
|
||||
:id="itemInfo.plant"
|
||||
:create-query="{customer: itemInfo.customer}"
|
||||
@return-data="(data) => itemInfo.plant = data.id"
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
</UFormGroup>
|
||||
@@ -1673,12 +1725,12 @@ const setRowData = (row) => {
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.project = null"
|
||||
/>
|
||||
<UButton
|
||||
variant="outline"
|
||||
v-if="itemInfo.project"
|
||||
icon="i-heroicons-arrow-right-end-on-rectangle"
|
||||
@click="router.push(`/standardEntity/projects/show/${itemInfo.project}`)"
|
||||
>Projekt</UButton>
|
||||
<EntityModalButtons
|
||||
type="projects"
|
||||
:id="itemInfo.project"
|
||||
:create-query="{customer: itemInfo.customer, plant: itemInfo.plant}"
|
||||
@return-data="(data) => itemInfo.project = data.id"
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
</UFormGroup>
|
||||
|
||||
@@ -51,6 +51,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
const profileStore = useProfileStore()
|
||||
const toast = useToast()
|
||||
const router = useRouter()
|
||||
const modal = useModal()
|
||||
|
||||
const dataTypes = {
|
||||
tasks: {
|
||||
@@ -2417,7 +2418,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function createNewItem (dataType,data){
|
||||
async function createNewItem (dataType,data,noRedirect=false){
|
||||
if(typeof(data) === 'object') {
|
||||
data = {...data, tenant: profileStore.currentTenant}
|
||||
} else if(typeof(data) === 'array') {
|
||||
@@ -2476,19 +2477,19 @@ export const useDataStore = defineStore('data', () => {
|
||||
|
||||
|
||||
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
|
||||
if(dataTypes[dataType].redirect) {
|
||||
if(dataTypes[dataType].redirect && !noRedirect) {
|
||||
if(dataTypes[dataType].isStandardEntity) {
|
||||
await router.push(dataTypes[dataType].redirectToList ? `/standardEntity/${dataType}` : `/standardEntity/${dataType}/show/${returnData.id}`)
|
||||
} else {
|
||||
await router.push(dataTypes[dataType].redirectToList ? `/${dataType}` : `/${dataType}/show/${returnData.id}`)
|
||||
}
|
||||
}
|
||||
|
||||
return supabaseData
|
||||
modal.close()
|
||||
return supabaseData[0]
|
||||
}
|
||||
}
|
||||
|
||||
async function updateItem (dataType, data, oldData = null) {
|
||||
async function updateItem (dataType, data, oldData = null, noRedirect = false) {
|
||||
//console.log(dataType, data)
|
||||
//Temporary Fix TODO: Remove and build Solution
|
||||
data = JSON.parse(JSON.stringify(data))
|
||||
@@ -2536,14 +2537,15 @@ export const useDataStore = defineStore('data', () => {
|
||||
//await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0]))
|
||||
//if(dataType === 'profiles') await fetchProfiles()
|
||||
toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`})
|
||||
if(dataTypes[dataType].redirect) {
|
||||
if(dataTypes[dataType].redirect && !noRedirect) {
|
||||
if(dataTypes[dataType].isStandardEntity) {
|
||||
await router.push(dataTypes[dataType].redirectToList ? `/standardEntity/${dataType}` : `/standardEntity/${dataType}/show/${data.id}`)
|
||||
} else {
|
||||
await router.push(dataTypes[dataType].redirectToList ? `/${dataType}` : `/${dataType}/show/${data.id}`)
|
||||
}
|
||||
}
|
||||
return supabaseData
|
||||
modal.close()
|
||||
return supabaseData[0]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user