Remodel of Profile System
Added isCompany to Customers changes in workingtimes.vue
This commit is contained in:
29
spaces/components/ProfileDropdown.vue
Normal file
29
spaces/components/ProfileDropdown.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup>
|
||||
const dataStore = useDataStore()
|
||||
const supabase = useSupabaseClient()
|
||||
//const tenants = ref(dataStore.getOwnProfile ? dataStore.getOwnProfile.tenants : [])
|
||||
//const tenant = ref(dataStore.currentTenant)
|
||||
|
||||
const selectedProfile = ref(dataStore.activeProfile.id)
|
||||
console.log(dataStore.ownProfiles)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
:options="dataStore.ownProfiles"
|
||||
value-attribute="id"
|
||||
class="w-40"
|
||||
@change="dataStore.changeProfile(selectedProfile)"
|
||||
v-model="selectedProfile"
|
||||
>
|
||||
<UButton color="gray" variant="ghost" :class="[open && 'bg-gray-50 dark:bg-gray-800']" class="w-full">
|
||||
<UAvatar :alt="dataStore.tenants.find(i => dataStore.getProfileById(selectedProfile).tenant === i.id).name" size="md" />
|
||||
|
||||
<span class="truncate text-gray-900 dark:text-white font-semibold">{{dataStore.tenants.find(i => dataStore.getProfileById(selectedProfile).tenant === i.id).name}}</span>
|
||||
</UButton>
|
||||
|
||||
<template #option="{option}">
|
||||
{{dataStore.tenants.find(i => i.id === option.tenant).name}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
@@ -1,25 +0,0 @@
|
||||
<script setup>
|
||||
const dataStore = useDataStore()
|
||||
|
||||
const tenants = ref(dataStore.getOwnProfile ? dataStore.getOwnProfile.tenants : [])
|
||||
const tenant = ref(dataStore.currentTenant)
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
:options="tenants"
|
||||
value-attribute="id"
|
||||
option-attribute="name"
|
||||
class="w-40"
|
||||
@change="dataStore.changeTenant"
|
||||
v-model="dataStore.currentTenant"
|
||||
>
|
||||
<UButton color="gray" variant="ghost" :class="[open && 'bg-gray-50 dark:bg-gray-800']" class="w-full">
|
||||
<UAvatar :alt="tenants.find(i => i.id === dataStore.currentTenant).name" size="md" />
|
||||
|
||||
<span class="truncate text-gray-900 dark:text-white font-semibold">{{ tenants.find(i => i.id === dataStore.currentTenant).name }}</span>
|
||||
</UButton>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
@@ -59,9 +59,9 @@ const items = computed(() => [
|
||||
<template>
|
||||
<UDropdown mode="hover" :items="items" :ui="{ width: 'w-full', item: { disabled: 'cursor-text select-text' } }" :popper="{ strategy: 'absolute', placement: 'top' }" class="w-full">
|
||||
<template #default="{ open }">
|
||||
<UButton color="gray" variant="ghost" class="w-full" :label="dataStore.getProfileById(user.id).fullName" :class="[open && 'bg-gray-50 dark:bg-gray-800']">
|
||||
<UButton color="gray" variant="ghost" class="w-full" :label="dataStore.activeProfile.fullName" :class="[open && 'bg-gray-50 dark:bg-gray-800']">
|
||||
<template #leading>
|
||||
<UAvatar :alt="dataStore.getProfileById(user.id) ? dataStore.getProfileById(user.id).fullName : ''" size="xs" />
|
||||
<UAvatar :alt="dataStore.activeProfile ? dataStore.activeProfile.fullName : ''" size="xs" />
|
||||
</template>
|
||||
|
||||
<template #trailing>
|
||||
@@ -76,7 +76,7 @@ const items = computed(() => [
|
||||
Angemeldet als
|
||||
</p>
|
||||
<p class="truncate font-medium text-gray-900 dark:text-white">
|
||||
{{dataStore.getProfileById(user.id).email}}
|
||||
{{dataStore.activeProfile.email}}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
31
spaces/composables/useSearch.js
Normal file
31
spaces/composables/useSearch.js
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
|
||||
export const useSearch = (searchString,items) => {
|
||||
const dataStore = useDataStore()
|
||||
|
||||
if(!searchString) {
|
||||
return items
|
||||
}
|
||||
|
||||
items = items.map(item => {
|
||||
|
||||
return {
|
||||
...item,
|
||||
customer: dataStore.getCustomerById(item.customer)
|
||||
}
|
||||
})
|
||||
|
||||
console.log(items)
|
||||
|
||||
|
||||
|
||||
return items.filter(i => JSON.stringify(i).includes(searchString))
|
||||
|
||||
/*return items.filter(item => {
|
||||
return Object.values(item).some((value) => {
|
||||
return String(value).toLowerCase().includes(searchString.toLowerCase())
|
||||
})
|
||||
})*/
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
|
||||
import TenantDropdown from "~/components/TenantDropdown.vue";
|
||||
import TenantDropdown from "~/components/ProfileDropdown.vue";
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const colorMode = useColorMode()
|
||||
@@ -435,7 +435,7 @@ const footerLinks = [/*{
|
||||
<UDashboardPanel :width="250" :resizable="{ min: 200, max: 300 }" collapsible>
|
||||
<UDashboardNavbar class="!border-transparent" :ui="{ left: 'flex-1' }">
|
||||
<template #left>
|
||||
<TenantDropdown class="w-full" />
|
||||
<ProfileDropdown class="w-full" />
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
|
||||
@@ -9,6 +9,19 @@ const itemInfo = ref({
|
||||
resources: []
|
||||
})
|
||||
|
||||
const mapResources = () => {
|
||||
itemInfo.value.resources.map(resource => {
|
||||
|
||||
|
||||
return {
|
||||
id: resource.id,
|
||||
type: resource.type
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const setupPage = () => {
|
||||
if(route.query.start) itemInfo.value.start = route.query.start.replace(" ", "+")
|
||||
@@ -47,17 +60,18 @@ setupPage()
|
||||
>
|
||||
<USelectMenu
|
||||
v-model="itemInfo.resources"
|
||||
:options="dataStore.getResources"
|
||||
:options="dataStore.getResourcesList"
|
||||
option-attribute="title"
|
||||
value-attribute="id"
|
||||
multiple
|
||||
@change=""
|
||||
onChange="mapResources"
|
||||
>
|
||||
<template #label>
|
||||
<span v-if="itemInfo.resources.length == 0">Keine Ressourcen ausgewählt</span>
|
||||
<span v-else >{{ itemInfo.resources.length }} ausgewählt</span>
|
||||
</template>
|
||||
</USelectMenu>
|
||||
{{dataStore.getResourcesList}}
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="Titel:"
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
|
||||
<script setup>
|
||||
|
||||
import {useSearch} from "~/composables/useSearch.js";
|
||||
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
@@ -124,7 +126,7 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
|
||||
|
||||
const searchString = ref('')
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
/*const filteredRows = computed(() => {
|
||||
if(!searchString.value) {
|
||||
return dataStore.contacts
|
||||
}
|
||||
@@ -134,7 +136,12 @@ const filteredRows = computed(() => {
|
||||
return String(value).toLowerCase().includes(searchString.value.toLowerCase())
|
||||
})
|
||||
})
|
||||
})*/
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
return useSearch(searchString.value, dataStore.contacts)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -54,7 +54,7 @@ const tabItems = computed(() => {
|
||||
},
|
||||
{
|
||||
label: "Vorschau",
|
||||
disabled: !itemInfo.value.customer && !itemInfo.value.contact
|
||||
disabled: !itemInfo.value.customer
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -259,7 +259,10 @@ const getDocumentData = () => {
|
||||
//Compile Start & EndText
|
||||
const templateStartText = Handlebars.compile(itemInfo.value.startText);
|
||||
const templateEndText = Handlebars.compile(itemInfo.value.endText);
|
||||
console.log(templateStartText({vorname: contactData.firstName, nachname: contactData.lastName}))
|
||||
console.log(templateStartText({
|
||||
vorname: contactData ? contactData.firstName : "",
|
||||
nachname: contactData ? contactData.lastName : ""
|
||||
}))
|
||||
console.log(templateEndText({zahlungsziel_in_tagen: 14}))
|
||||
|
||||
|
||||
@@ -289,7 +292,10 @@ const getDocumentData = () => {
|
||||
title: itemInfo.value.title,
|
||||
description: itemInfo.value.description,
|
||||
endText: templateEndText({zahlungsziel_in_tagen: itemInfo.value.paymentDays}),
|
||||
startText: templateStartText({vorname: contactData.firstName, nachname: contactData.lastName}),
|
||||
startText: templateStartText({
|
||||
vorname: contactData ? contactData.firstName : "",
|
||||
nachname: contactData ? contactData.lastName : ""
|
||||
}),
|
||||
rows: rows,
|
||||
total: documentTotal.value
|
||||
}
|
||||
@@ -504,9 +510,11 @@ setupPage()
|
||||
class="flex-auto"
|
||||
>
|
||||
<UButton
|
||||
:color="itemInfo.contact ? 'primary' : 'rose'"
|
||||
color="none"
|
||||
variant="outline"
|
||||
class="flex-1 justify-between">
|
||||
class="flex-1 justify-between"
|
||||
:disabled="!itemInfo.customer"
|
||||
>
|
||||
{{dataStore.getContactById(itemInfo.contact) ? dataStore.getContactById(itemInfo.contact).fullName : "Kein Kontakt 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']" />
|
||||
|
||||
@@ -20,7 +20,8 @@ const itemInfo = ref({
|
||||
infoData: {
|
||||
country: "Deutschland"
|
||||
},
|
||||
active: true
|
||||
active: true,
|
||||
isCompany: true
|
||||
})
|
||||
|
||||
//Functions
|
||||
@@ -225,6 +226,13 @@ setupPage()
|
||||
/>
|
||||
</UFormGroup>
|
||||
</UTooltip>
|
||||
<UFormGroup
|
||||
label="Firmenkunde:"
|
||||
>
|
||||
<UCheckbox
|
||||
v-model="itemInfo.isCompany"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="Notizen:"
|
||||
>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<UDashboardNavbar title="Kunden" :badge="filteredRows.length">
|
||||
<template #right>
|
||||
<UInput
|
||||
ref="searchinput"
|
||||
id="searchinput"
|
||||
v-model="searchString"
|
||||
icon="i-heroicons-funnel"
|
||||
autocomplete="off"
|
||||
@@ -45,6 +45,10 @@
|
||||
@select="(i) => router.push(`/customers/show/${i.id}`) "
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Kunden anzuzeigen' }"
|
||||
>
|
||||
<template #isCompany-data="{row}">
|
||||
<span v-if="row.isCompany">Firmenkunden</span>
|
||||
<span v-else>Privatkunde</span>
|
||||
</template>
|
||||
<template #active-data="{row}">
|
||||
<span v-if="row.active" class="text-primary-500">Aktiv</span>
|
||||
<span v-else class="text-rose-500">Gesperrt</span>
|
||||
@@ -85,6 +89,11 @@ const templateColumns = [
|
||||
label: "Name",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "isCompany",
|
||||
label: "Typ",
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: "notes",
|
||||
label: "Notizen",
|
||||
|
||||
@@ -81,8 +81,12 @@ setupPage()
|
||||
<div
|
||||
v-if="item.label === 'Informationen'"
|
||||
>
|
||||
<div class="truncate">
|
||||
<p v-if="currentItem.sellingPrice">Verkaufspreis: {{String(Number(currentItem.sellingPrice).toFixed(2)).replace(".",",")}} €</p>
|
||||
<p>Beschreibung:</p>
|
||||
<pre>{{currentItem.description}}</pre>
|
||||
</div>
|
||||
|
||||
<span v-if="currentItem.sellingPrice">Verkaufspreis: {{String(Number(currentItem.sellingPrice).toFixed(2)).replace(".",",")}} €<br></span>
|
||||
|
||||
</div>
|
||||
<div
|
||||
|
||||
2
spaces/pages/vendors/index.vue
vendored
2
spaces/pages/vendors/index.vue
vendored
@@ -2,7 +2,7 @@
|
||||
<UDashboardNavbar title="Lieferanten" :badge="filteredRows.length">
|
||||
<template #right>
|
||||
<UInput
|
||||
ref="searchinput"
|
||||
id="searchinput"
|
||||
v-model="searchString"
|
||||
icon="i-heroicons-funnel"
|
||||
autocomplete="off"
|
||||
|
||||
@@ -445,10 +445,10 @@ const setState = async (newState) => {
|
||||
</template>
|
||||
|
||||
<template #start-data="{row}">
|
||||
{{dayjs(row.start, "HH:mm:ssZ").format("HH:mm")}} Uhr
|
||||
{{dayjs(row.start, "HH:mm:ss").format("HH:mm")}} Uhr
|
||||
</template>
|
||||
<template #end-data="{row}">
|
||||
{{dayjs(row.end, "HH:mm:ssZ").format("HH:mm")}} Uhr
|
||||
{{dayjs(row.end, "HH:mm:ss").format("HH:mm")}} Uhr
|
||||
</template>
|
||||
<template #duration-data="{row}">
|
||||
{{getDuration(row).composed}}
|
||||
|
||||
@@ -143,6 +143,9 @@ export const useDataStore = defineStore('data', () => {
|
||||
|
||||
|
||||
const profiles = ref([])
|
||||
const ownProfiles = ref([])
|
||||
const activeProfile = ref([])
|
||||
const tenants = ref([])
|
||||
const currentTenant = ref(null)
|
||||
const events = ref([])
|
||||
const customers = ref([])
|
||||
@@ -180,6 +183,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
const texttemplates =ref([])
|
||||
const services =ref([])
|
||||
const serviceCategories =ref([])
|
||||
const resources =ref([])
|
||||
|
||||
|
||||
const rights = ref({
|
||||
@@ -241,26 +245,54 @@ export const useDataStore = defineStore('data', () => {
|
||||
])
|
||||
|
||||
async function initializeData (userId) {
|
||||
let profile = (await supabase.from("profiles").select().eq("user",userId).single()).data
|
||||
|
||||
currentTenant.value = profile.tenant
|
||||
let profileconnections = (await supabase.from("profileconnections").select()).data
|
||||
let profiles = (await supabase.from("profiles").select()).data
|
||||
let profileId = profileconnections.find(i => i.active).profile_id
|
||||
activeProfile.value = profiles.find(i => i.id === profileId)
|
||||
currentTenant.value = activeProfile.value.tenant
|
||||
|
||||
await fetchData()
|
||||
|
||||
}
|
||||
|
||||
async function changeTenant() {
|
||||
async function changeProfile(newActiveProfileId) {
|
||||
loaded.value = false
|
||||
await clearStore()
|
||||
await fetchData()
|
||||
router.push("/")
|
||||
loaded.value = true
|
||||
|
||||
let profileconnections = (await supabase.from("profileconnections").select()).data
|
||||
|
||||
let oldActiveProfileId = profileconnections.find(i => i.active).profile_id
|
||||
|
||||
const {error} = await supabase.from("profileconnections").update({active: true}).eq("profile_id", newActiveProfileId)
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
} else {
|
||||
const {error} = await supabase.from("profileconnections").update({active: false}).eq("profile_id", oldActiveProfileId)
|
||||
|
||||
if(error) {
|
||||
|
||||
} else {
|
||||
reloadNuxtApp({
|
||||
path:"/",
|
||||
ttl: 10000
|
||||
})
|
||||
}
|
||||
|
||||
/*await clearStore()
|
||||
await fetchData()
|
||||
router.push("/")
|
||||
loaded.value = true*/
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchData () {
|
||||
await fetchOwnProfiles()
|
||||
await fetchProfiles()
|
||||
await fetchDocuments()
|
||||
await fetchTenants()
|
||||
await fetchOwnTenant()
|
||||
await fetchEvents()
|
||||
await fetchTasks()
|
||||
@@ -297,6 +329,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
await fetchTextTemplates()
|
||||
await fetchServices()
|
||||
await fetchServiceCategories()
|
||||
await fetchResources()
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
@@ -305,6 +338,8 @@ export const useDataStore = defineStore('data', () => {
|
||||
loaded.value = false
|
||||
ownTenant.value = {}
|
||||
profiles.value = []
|
||||
ownProfiles.value = []
|
||||
tenants.value = []
|
||||
events.value= []
|
||||
customers.value= []
|
||||
tasks.value= []
|
||||
@@ -341,6 +376,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
texttemplates.value = []
|
||||
services.value = []
|
||||
serviceCategories.value = []
|
||||
resources.value = []
|
||||
}
|
||||
|
||||
function hasRight (right) {
|
||||
@@ -395,7 +431,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
if(dataTypes[dataType].numberRangeHolder) {
|
||||
|
||||
const numberRange = useNumberRange(dataType)
|
||||
if(!dataTypes[dataType].numberRangeHolder) {
|
||||
if(!data[dataTypes[dataType].numberRangeHolder]) {
|
||||
data[dataTypes[dataType].numberRangeHolder] = await numberRange.useNextNumber()
|
||||
}
|
||||
|
||||
@@ -517,12 +553,25 @@ export const useDataStore = defineStore('data', () => {
|
||||
}
|
||||
|
||||
async function fetchOwnTenant () {
|
||||
ownTenant.value = (await supabase.from("tenants").select().eq('id', currentTenant.value)).data[0]
|
||||
ownTenant.value = (await supabase.from("tenants").select().eq('id', currentTenant.value).single()).data
|
||||
}
|
||||
|
||||
async function fetchProfiles () {
|
||||
profiles.value = (await supabase.from("profiles").select('* , tenants (id, name)').eq("tenant", currentTenant.value).order("fullName")).data
|
||||
profiles.value = (await supabase.from("profiles").select().eq("tenant",currentTenant.value).order("fullName")).data
|
||||
}
|
||||
|
||||
async function fetchOwnProfiles () {
|
||||
let profiles = (await supabase.from("profiles").select().order("fullName")).data
|
||||
let conns = (await supabase.from("profileconnections").select()).data.map(i => i.profile_id)
|
||||
console.log(conns)
|
||||
console.log(profiles.filter(i => conns.includes(i.id)))
|
||||
ownProfiles.value = profiles.filter(i => conns.includes(i.id))
|
||||
}
|
||||
|
||||
async function fetchTenants () {
|
||||
tenants.value = (await supabase.from("tenants").select()).data
|
||||
}
|
||||
|
||||
async function fetchBankAccounts () {
|
||||
bankAccounts.value = (await supabase.from("bankaccounts").select().eq('tenant', currentTenant.value)).data
|
||||
}
|
||||
@@ -636,6 +685,10 @@ export const useDataStore = defineStore('data', () => {
|
||||
serviceCategories.value = (await supabase.from("serviceCategories").select().eq('tenant', currentTenant.value)).data
|
||||
}
|
||||
|
||||
async function fetchResources() {
|
||||
resources.value = (await supabase.from("resources").select().eq('tenant', currentTenant.value)).data
|
||||
}
|
||||
|
||||
async function fetchDocuments () {
|
||||
let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data
|
||||
|
||||
@@ -844,6 +897,32 @@ export const useDataStore = defineStore('data', () => {
|
||||
]
|
||||
})
|
||||
|
||||
const getResourcesList = computed(() => {
|
||||
return [
|
||||
...profiles.value.filter(i => i.tenant === currentTenant.value).map(profile => {
|
||||
return {
|
||||
type: 'Mitarbeiter',
|
||||
title: profile.fullName,
|
||||
id: profile.id
|
||||
}
|
||||
}),
|
||||
...vehicles.value.map(vehicle => {
|
||||
return {
|
||||
type: 'Fahrzeug',
|
||||
title: vehicle.licensePlate,
|
||||
id: vehicle.id
|
||||
}
|
||||
}),
|
||||
...inventoryitems.value.filter(i=> i.usePlanning).map(item => {
|
||||
return {
|
||||
type: 'Inventar',
|
||||
title: item.name,
|
||||
id: item.id
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
const getEvents = computed(() => {
|
||||
return [
|
||||
...events.value.map(event => {
|
||||
@@ -880,6 +959,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
const getEventsByResource = computed(() => {
|
||||
let tempEvents = []
|
||||
events.value.forEach(event => {
|
||||
console.log(event)
|
||||
event.resources.forEach(resource => {
|
||||
let eventColor = ownTenant.value.calendarConfig.eventTypes.find(type => type.label === event.type).color
|
||||
|
||||
@@ -894,8 +974,8 @@ export const useDataStore = defineStore('data', () => {
|
||||
|
||||
tempEvents.push({
|
||||
...event,
|
||||
resourceId: resource.type !== 'Mitarbeiter' ? `${resource.type[0]}-${resource.id}`: resource.id,
|
||||
resourceType: resource.type,
|
||||
resourceId: /*resource.type !== 'Mitarbeiter' ? `${resource.type[0]}-${resource.id}`:*/ resource.id,
|
||||
resourceType: "Mitarbeiter",
|
||||
title: title,
|
||||
borderColor: eventColor,
|
||||
textColor: eventColor,
|
||||
@@ -1049,12 +1129,15 @@ export const useDataStore = defineStore('data', () => {
|
||||
loaded,
|
||||
ownTenant,
|
||||
initializeData,
|
||||
changeTenant,
|
||||
changeProfile,
|
||||
uploadFiles,
|
||||
hasRight,
|
||||
|
||||
//Data
|
||||
profiles,
|
||||
ownProfiles,
|
||||
activeProfile,
|
||||
tenants,
|
||||
events,
|
||||
customers,
|
||||
tasks,
|
||||
@@ -1100,6 +1183,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
clearStore,
|
||||
fetchOwnTenant,
|
||||
fetchProfiles,
|
||||
fetchOwnProfiles,
|
||||
fetchBankAccounts,
|
||||
fetchBankStatements,
|
||||
fetchEvents,
|
||||
@@ -1161,6 +1245,7 @@ export const useDataStore = defineStore('data', () => {
|
||||
getDocumentTags,
|
||||
getMeasures,
|
||||
getResources,
|
||||
getResourcesList,
|
||||
getEvents,
|
||||
getEventsByResource,
|
||||
getCostCentresComposed,
|
||||
|
||||
Reference in New Issue
Block a user