Many Changes
This commit is contained in:
128
spaces/app.vue
128
spaces/app.vue
@@ -1,50 +1,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import GlobalSearch from "~/components/GlobalSearch.vue";
|
|
||||||
const supabase = useSupabaseClient()
|
const supabase = useSupabaseClient()
|
||||||
const user = useSupabaseUser()
|
const user = useSupabaseUser()
|
||||||
//console.log(user.value)
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const tenants = (await supabase.from("tenants").select()).data
|
const tenants = (await supabase.from("tenants").select()).data
|
||||||
|
|
||||||
|
|
||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//console.log(userProfile)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const viewport = useViewport()
|
const viewport = useViewport()
|
||||||
|
|
||||||
watch(viewport.breakpoint, (newBreakpoint, oldBreakpoint) => {
|
/*watch(viewport.breakpoint, (newBreakpoint, oldBreakpoint) => {
|
||||||
console.log('Breakpoint updated:', oldBreakpoint, '->', newBreakpoint)
|
console.log('Breakpoint updated:', oldBreakpoint, '->', newBreakpoint)
|
||||||
})
|
})*/
|
||||||
|
|
||||||
|
|
||||||
dataStore.initializeData()
|
dataStore.initializeData()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const linksForBreadcrumbs = ref([])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//const userTenant = ref({})
|
|
||||||
//if(user) userTenant.value = tenants.find(tenant => tenant.id === user.value.app_metadata.tenant)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
meta: [
|
meta: [
|
||||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
||||||
@@ -62,47 +31,6 @@ useSeoMeta({
|
|||||||
twitterCard: 'summary_large_image'
|
twitterCard: 'summary_large_image'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
[{
|
|
||||||
label: user.value ? user.value.email : "",
|
|
||||||
slot: 'account',
|
|
||||||
disabled: true
|
|
||||||
}], [{
|
|
||||||
label: 'Externe Geräte',
|
|
||||||
icon: 'i-heroicons-cog-8-tooth',
|
|
||||||
to: "/settings/externalDevices"
|
|
||||||
},{
|
|
||||||
label: 'Nummernkreise',
|
|
||||||
icon: 'i-heroicons-cog-8-tooth',
|
|
||||||
to: "/settings/numberRanges"
|
|
||||||
},{
|
|
||||||
label: 'Benutzer',
|
|
||||||
icon: 'i-heroicons-user-group',
|
|
||||||
to: "/settings/users"
|
|
||||||
}], /*[{
|
|
||||||
label: 'Documentation',
|
|
||||||
icon: 'i-heroicons-book-open'
|
|
||||||
}, {
|
|
||||||
label: 'Changelog',
|
|
||||||
icon: 'i-heroicons-megaphone'
|
|
||||||
}, {
|
|
||||||
label: 'Status',
|
|
||||||
icon: 'i-heroicons-signal'
|
|
||||||
}],*/ [{
|
|
||||||
label: 'Ausloggen',
|
|
||||||
icon: 'i-heroicons-arrow-left-on-rectangle',
|
|
||||||
click: async () => {
|
|
||||||
await supabase.auth.signOut()
|
|
||||||
await dataStore.clearStore()
|
|
||||||
await router.push("/login")
|
|
||||||
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
]
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -110,62 +38,10 @@ const items = [
|
|||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage/>
|
<NuxtPage/>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
<!-- <UFooter>
|
|
||||||
<template #left>
|
|
||||||
<p class="text-gray-500 dark:text-gray-400 text-sm">
|
|
||||||
Copyright © 2023-{{ new Date().getFullYear() }} <NuxtLink class="hover:underline" to="https://federspiel.tech" target="_blank">
|
|
||||||
Federspiel Technolog UG haftungsbeschränkt
|
|
||||||
</NuxtLink>
|
|
||||||
</p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #right>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
</UFooter>-->
|
|
||||||
|
|
||||||
<UNotifications/>
|
<UNotifications/>
|
||||||
<VitePwaManifest/>
|
<VitePwaManifest/>
|
||||||
|
|
||||||
<!-- <UCard id="page">
|
|
||||||
<template #header>
|
|
||||||
<div id="menu">
|
|
||||||
<router-link
|
|
||||||
v-for="link in navLinks"
|
|
||||||
:to="link.to"
|
|
||||||
class="mr-2"
|
|
||||||
>
|
|
||||||
<UButton>{{link.label}}</UButton>
|
|
||||||
</router-link>
|
|
||||||
<!–<router-link to="/customers" class="mr-2"><UButton>Kunden</UButton></router-link>
|
|
||||||
<router-link to="/projects" class="mr-2"><UButton>Projekte</UButton></router-link>
|
|
||||||
-
|
|
||||||
<router-link to="/receipts" class="mr-2"><UButton>Eingangsrechnungen</UButton></router-link>
|
|
||||||
|
|
||||||
<router-link to="/timetracking" class="mr-2"><UButton>Zeiterfassung</UButton></router-link>
|
|
||||||
<router-link to="/products" class="mr-2"><UButton>Artikel</UButton></router-link>
|
|
||||||
<router-link to="/documents" class="mr-2"><UButton>Dokumente</UButton></router-link>
|
|
||||||
<router-link to="/inventory" class="mr-2"><UButton>Inventar</UButton></router-link>–>
|
|
||||||
<UDropdown :items="userDropdownItems" :popper="{placement: 'bottom-start'}">
|
|
||||||
<UButton color="white" label="Benutzer" trailing-icon="i-heroicons-chevron-down-20-solid" />
|
|
||||||
</UDropdown>
|
|
||||||
</div>
|
|
||||||
<UBreadcrumb
|
|
||||||
class="my-3"
|
|
||||||
:links="linksForBreadcrumbs"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<NuxtPage
|
|
||||||
v-if="loaded"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
>
|
|
||||||
<UProgress animation="carousel" />
|
|
||||||
</div>
|
|
||||||
</UCard>-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const supabase = useSupabaseClient()
|
|||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
document: {
|
documentData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
@@ -13,9 +13,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const {document, openShowModal:openShowModalProp } = props;
|
let {documentData, openShowModal:openShowModalProp } = props;
|
||||||
const tags = dataStore.getDocumentTags
|
const tags = dataStore.getDocumentTags
|
||||||
const openShowModal = ref(false)
|
const openShowModal = ref(false)
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ const openDocument = async () => {
|
|||||||
|
|
||||||
const updateDocument = async () => {
|
const updateDocument = async () => {
|
||||||
|
|
||||||
const {url, ...objData} = document
|
const {url, ...objData} = documentData
|
||||||
delete objData.url
|
delete objData.url
|
||||||
|
|
||||||
const {data,error} = await supabase
|
const {data,error} = await supabase
|
||||||
@@ -50,7 +51,7 @@ const createVendorInvoice = async () => {
|
|||||||
const {data:vendorInvoiceData,error:vendorInvoiceError} = await supabase
|
const {data:vendorInvoiceData,error:vendorInvoiceError} = await supabase
|
||||||
.from("incomingInvoices")
|
.from("incomingInvoices")
|
||||||
.insert([{
|
.insert([{
|
||||||
document: document.id,
|
document: documentData.id,
|
||||||
}])
|
}])
|
||||||
.select()
|
.select()
|
||||||
if(vendorInvoiceError) {
|
if(vendorInvoiceError) {
|
||||||
@@ -62,7 +63,7 @@ const createVendorInvoice = async () => {
|
|||||||
.update({
|
.update({
|
||||||
vendorInvoice: vendorInvoiceData[0].id
|
vendorInvoice: vendorInvoiceData[0].id
|
||||||
})
|
})
|
||||||
.eq('id',document.id)
|
.eq('id',documentData.id)
|
||||||
.select()
|
.select()
|
||||||
|
|
||||||
if(documentError) {
|
if(documentError) {
|
||||||
@@ -84,16 +85,18 @@ const createVendorInvoice = async () => {
|
|||||||
|
|
||||||
|
|
||||||
const archiveDocument = () => {
|
const archiveDocument = () => {
|
||||||
document.tags = ["Archiviert"]
|
documentData.tags = ["Archiviert"]
|
||||||
updateDocument()
|
updateDocument()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="documentListItem">
|
<div class="documentListItem">
|
||||||
<object
|
<object
|
||||||
:data="document.url"
|
:data="documentData.url"
|
||||||
class="previewEmbed"
|
class="previewEmbed"
|
||||||
type="application/pdf"
|
type="application/pdf"
|
||||||
/>
|
/>
|
||||||
@@ -104,22 +107,21 @@ const archiveDocument = () => {
|
|||||||
<UIcon name="i-heroicons-eye-solid" />
|
<UIcon name="i-heroicons-eye-solid" />
|
||||||
</UButton>
|
</UButton>
|
||||||
<UToggle
|
<UToggle
|
||||||
v-model="document.selected"
|
v-model="documentData.selected"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
/>
|
/>
|
||||||
<br>
|
<br>
|
||||||
<UBadge
|
<UBadge
|
||||||
v-if="document.vendorInvoice"
|
v-if="documentData.vendorInvoice"
|
||||||
>{{dataStore.incomingInvoices.find(item => item.id === document.vendorInvoice) ? dataStore.incomingInvoices.find(item => item.id === document.vendorInvoice).reference : ''}}</UBadge>
|
>{{dataStore.incomingInvoices.find(item => item.id === documentData.vendorInvoice) ? dataStore.incomingInvoices.find(item => item.id === documentData.vendorInvoice).reference : ''}}</UBadge>
|
||||||
<UBadge
|
<UBadge
|
||||||
v-if="document.inDatev"
|
v-if="documentData.inDatev"
|
||||||
>DATEV</UBadge>
|
>DATEV</UBadge>
|
||||||
|
{{documentData}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Slideovers -->
|
|
||||||
|
|
||||||
<USlideover
|
<USlideover
|
||||||
v-model="openShowModal"
|
v-model="openShowModal"
|
||||||
fullscreen
|
fullscreen
|
||||||
@@ -128,7 +130,7 @@ const archiveDocument = () => {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<UBadge
|
<UBadge
|
||||||
v-for="tag in document.tags"
|
v-for="tag in documentData.tags"
|
||||||
>
|
>
|
||||||
{{tag}}
|
{{tag}}
|
||||||
</UBadge>
|
</UBadge>
|
||||||
@@ -138,12 +140,13 @@ const archiveDocument = () => {
|
|||||||
<UContainer class="h-full" :ui="{padding: 'px-1 sm:px-1 lg:px-1'}">
|
<UContainer class="h-full" :ui="{padding: 'px-1 sm:px-1 lg:px-1'}">
|
||||||
<object
|
<object
|
||||||
class="h-full w-full"
|
class="h-full w-full"
|
||||||
:data="document.url"
|
:data="documentData.url"
|
||||||
type="application/pdf"
|
type="application/pdf"
|
||||||
/>
|
/>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|
||||||
<UButtonGroup>
|
<UButtonGroup>
|
||||||
<UButton
|
<UButton
|
||||||
@click="archiveDocument"
|
@click="archiveDocument"
|
||||||
@@ -151,7 +154,7 @@ const archiveDocument = () => {
|
|||||||
Archivieren
|
Archivieren
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="document.tags.includes('Eingangsrechnung')"
|
v-if="documentData.tags.includes('Eingangsrechnung')"
|
||||||
@click="createVendorInvoice"
|
@click="createVendorInvoice"
|
||||||
>
|
>
|
||||||
Eingangsrechnung erstellen
|
Eingangsrechnung erstellen
|
||||||
@@ -164,12 +167,12 @@ const archiveDocument = () => {
|
|||||||
>
|
>
|
||||||
<USelectMenu
|
<USelectMenu
|
||||||
:options="tags"
|
:options="tags"
|
||||||
v-model="document.tags"
|
v-model="documentData.tags"
|
||||||
@close="updateDocument"
|
@close="updateDocument"
|
||||||
multiple
|
multiple
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
{{document.tags.length}} ausgewählt
|
{{documentData.tags.length}} ausgewählt
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
@@ -181,13 +184,13 @@ const archiveDocument = () => {
|
|||||||
:options="dataStore.projects"
|
:options="dataStore.projects"
|
||||||
option-attribute="name"
|
option-attribute="name"
|
||||||
value-attribute="id"
|
value-attribute="id"
|
||||||
v-model="document.project"
|
v-model="documentData.project"
|
||||||
@change="updateDocument"
|
@change="updateDocument"
|
||||||
searchable
|
searchable
|
||||||
:search-attributes="['name']"
|
:search-attributes="['name']"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
{{dataStore.projects.find(item => item.id === document.project) ? dataStore.projects.find(item => item.id === document.project).name : "Kein Projekt ausgewählt" }}
|
{{dataStore.projects.find(item => item.id === documentData.project) ? dataStore.projects.find(item => item.id === documentData.project).name : "Kein Projekt ausgewählt" }}
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
@@ -199,13 +202,13 @@ const archiveDocument = () => {
|
|||||||
:options="dataStore.customers"
|
:options="dataStore.customers"
|
||||||
option-attribute="name"
|
option-attribute="name"
|
||||||
value-attribute="id"
|
value-attribute="id"
|
||||||
v-model="document.customer"
|
v-model="documentData.customer"
|
||||||
@change="updateDocument"
|
@change="updateDocument"
|
||||||
searchable
|
searchable
|
||||||
:search-attributes="['name']"
|
:search-attributes="['name']"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
{{dataStore.customers.find(item => item.id === document.customer) ? dataStore.customers.find(item => item.id === document.customer).name : "Kein Kunde ausgewählt" }}
|
{{dataStore.customers.find(item => item.id === documentData.customer) ? dataStore.customers.find(item => item.id === documentData.customer).name : "Kein Kunde ausgewählt" }}
|
||||||
</template>
|
</template>
|
||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
|||||||
37
spaces/components/DocumentList.vue
Normal file
37
spaces/components/DocumentList.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
documents: {
|
||||||
|
type: Array,
|
||||||
|
required:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const dataStore = useDataStore()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="documentList">
|
||||||
|
<DocumentDisplay
|
||||||
|
v-for="item in documents"
|
||||||
|
:document-data="item"
|
||||||
|
:key="item.id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.documentList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
overflow-y: scroll;
|
||||||
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.documentList::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
103
spaces/components/DocumentUpload.vue
Normal file
103
spaces/components/DocumentUpload.vue
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<script setup >
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
elementId: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {type, elementId} = props
|
||||||
|
|
||||||
|
const dataStore = useDataStore()
|
||||||
|
const tags = dataStore.getDocumentTags
|
||||||
|
|
||||||
|
const uploadModalOpen = ref(false)
|
||||||
|
const uploadInProgress = ref(false)
|
||||||
|
const fileUploadFormData = ref({
|
||||||
|
tags: ["Dokument"],
|
||||||
|
project: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const openModal = () => {
|
||||||
|
console.log("Oepn")
|
||||||
|
uploadModalOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFiles = async () => {
|
||||||
|
uploadInProgress.value = true;
|
||||||
|
|
||||||
|
let fileData = fileUploadFormData.value
|
||||||
|
fileData[type] = elementId
|
||||||
|
|
||||||
|
await dataStore.uploadFiles(fileData, document.getElementById("fileUploadInput").files)
|
||||||
|
|
||||||
|
uploadModalOpen.value = false;
|
||||||
|
uploadInProgress.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UModal
|
||||||
|
v-model="uploadModalOpen"
|
||||||
|
>
|
||||||
|
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||||
|
Datei hochladen
|
||||||
|
</h3>
|
||||||
|
<UButton
|
||||||
|
color="gray"
|
||||||
|
variant="ghost"
|
||||||
|
icon="i-heroicons-x-mark-20-solid"
|
||||||
|
class="-my-1"
|
||||||
|
@click="uploadModalOpen = false"
|
||||||
|
:disabled="uploadInProgress"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Datei:"
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
type="file"
|
||||||
|
id="fileUploadInput"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
<UFormGroup
|
||||||
|
label="Tags:"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
multiple
|
||||||
|
searchable
|
||||||
|
searchable-placeholder="Suchen..."
|
||||||
|
:options="tags"
|
||||||
|
v-model="fileUploadFormData.tags"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<UButton
|
||||||
|
@click="uploadFiles"
|
||||||
|
:loading="uploadInProgress"
|
||||||
|
>Hochladen</UButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</UCard>
|
||||||
|
</UModal>
|
||||||
|
|
||||||
|
<UButton
|
||||||
|
@click="openModal"
|
||||||
|
>
|
||||||
|
Hochladen
|
||||||
|
</UButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -36,7 +36,7 @@ const historyItems = computed(() => {
|
|||||||
items = dataStore.historyItems.filter(i => i.document === elementId)
|
items = dataStore.historyItems.filter(i => i.document === elementId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items.reverse()
|
return items
|
||||||
|
|
||||||
})
|
})
|
||||||
const addHistoryItemData = ref({
|
const addHistoryItemData = ref({
|
||||||
@@ -63,7 +63,7 @@ const addHistoryItem = async () => {
|
|||||||
|
|
||||||
|
|
||||||
const {data,error} = await supabase
|
const {data,error} = await supabase
|
||||||
.from("historyItems")
|
.from("historyitems")
|
||||||
.insert([addHistoryItemData.value])
|
.insert([addHistoryItemData.value])
|
||||||
.select()
|
.select()
|
||||||
|
|
||||||
@@ -139,10 +139,10 @@ const renderText = (text) => {
|
|||||||
v-else
|
v-else
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h3 v-if="item.user">{{dataStore.profiles.find(profile => profile.id === item.user) ? dataStore.profiles.find(profile => profile.id === item.user).fullName : ""}}</h3>
|
<h3 v-if="item.user">{{dataStore.getProfileById(item.user) ? dataStore.getProfileById(item.user).fullName : ""}}</h3>
|
||||||
<h3 v-else>Spaces Bot</h3>
|
<h3 v-else>Spaces Bot</h3>
|
||||||
<span v-html="renderText(item.text)"/><br>
|
<span v-html="renderText(item.text)"/><br>
|
||||||
<span class="text-gray-500">{{dayjs(item.created_at).format("DD:MM:YY HH:mm")}}</span>
|
<span class="text-gray-500">{{dayjs(item.created_at).format("DD.MM.YY HH:mm")}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -201,60 +201,8 @@ const userMenuItems = ref([
|
|||||||
|
|
||||||
<template #right>
|
<template #right>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <ClientOnly>
|
|
||||||
<UButton
|
|
||||||
:icon="!isLight ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
|
|
||||||
color="gray"
|
|
||||||
variant="ghost"
|
|
||||||
aria-label="Theme"
|
|
||||||
@click="isLight = !isLight"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template #fallback>
|
|
||||||
<div class="w-8 h-8" />
|
|
||||||
</template>
|
|
||||||
</ClientOnly>-->
|
|
||||||
<GlobalSearch/>
|
<GlobalSearch/>
|
||||||
|
|
||||||
|
|
||||||
<!-- <UPopover :popper="{placement: 'bottom-start'}">
|
|
||||||
<ClientOnly>
|
|
||||||
<UChip
|
|
||||||
:show="dataStore.notifications.filter(notification => !notification.read).length > 0"
|
|
||||||
inset
|
|
||||||
>
|
|
||||||
<UButton
|
|
||||||
icon="i-heroicons-envelope-20-solid"
|
|
||||||
variant="ghost"
|
|
||||||
color="gray"
|
|
||||||
class="mx-2"
|
|
||||||
/>
|
|
||||||
</UChip>
|
|
||||||
|
|
||||||
<template #fallback>
|
|
||||||
<div class="w-8 h-8" />
|
|
||||||
</template>
|
|
||||||
</ClientOnly>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<template #panel>
|
|
||||||
<div class="w-60 p-3">
|
|
||||||
|
|
||||||
<UAlert
|
|
||||||
class="mb-3"
|
|
||||||
v-for="(notification,index) in dataStore.notifications"
|
|
||||||
:color="!notification.read ? 'primary' : 'grey'"
|
|
||||||
variant="outline"
|
|
||||||
:description="notification.text"
|
|
||||||
:title="notification.title"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</UPopover>-->
|
|
||||||
<UButton
|
<UButton
|
||||||
@click="showUserMenu = true"
|
@click="showUserMenu = true"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -347,29 +295,7 @@ const userMenuItems = ref([
|
|||||||
|
|
||||||
</UCard>
|
</UCard>
|
||||||
</USlideover>
|
</USlideover>
|
||||||
<!-- <UDropdown :items="items" :ui="{ item: { disabled: 'cursor-text select-text' } }" :popper="{ placement: 'bottom-start' }">
|
|
||||||
<UAvatar
|
|
||||||
:alt="userProfile ? userProfile.firstName + ' ' + userProfile.lastName : '' "
|
|
||||||
icon="i-heroicons-user-20-solid"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template #account="{ item }">
|
|
||||||
<div class="text-left">
|
|
||||||
<p>
|
|
||||||
Eingeloggt als
|
|
||||||
</p>
|
|
||||||
<p class="truncate font-medium text-gray-900 dark:text-white">
|
|
||||||
{{ item.label }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #item="{ item }">
|
|
||||||
<span class="truncate">{{ item.label }}</span>
|
|
||||||
|
|
||||||
<UIcon :name="item.icon" class="flex-shrink-0 h-4 w-4 text-gray-400 dark:text-gray-500 ms-auto" />
|
|
||||||
</template>
|
|
||||||
</UDropdown>-->
|
|
||||||
</template>
|
</template>
|
||||||
</UHeader>
|
</UHeader>
|
||||||
<UDivider />
|
<UDivider />
|
||||||
@@ -381,8 +307,12 @@ const userMenuItems = ref([
|
|||||||
v-else
|
v-else
|
||||||
class="flex-col mx-auto my-auto mt-10 w-3/4"
|
class="flex-col mx-auto my-auto mt-10 w-3/4"
|
||||||
>
|
>
|
||||||
<img src="/spaces.svg" class="w-1/3 mx-auto"/>
|
<img
|
||||||
<UProgress animation="carousel" class=" " />
|
:src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'"
|
||||||
|
alt="Logo"
|
||||||
|
class="w-1/3 mx-auto"
|
||||||
|
/>
|
||||||
|
<UProgress animation="carousel"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
"@vuepic/vue-datepicker": "^7.4.0",
|
"@vuepic/vue-datepicker": "^7.4.0",
|
||||||
"@zip.js/zip.js": "^2.7.32",
|
"@zip.js/zip.js": "^2.7.32",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
|
"base64-arraybuffer": "^1.0.2",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"client-oauth2": "^4.3.3",
|
"client-oauth2": "^4.3.3",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import dayjs from "dayjs"
|
|||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
const user = useSupabaseUser()
|
const user = useSupabaseUser()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const supabase = useSupabaseClient()
|
||||||
|
import {decode} from 'base64-arraybuffer'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -35,10 +37,8 @@ const itemInfo = ref({
|
|||||||
createdBy: user.value.id,
|
createdBy: user.value.id,
|
||||||
title: null,
|
title: null,
|
||||||
description: null,
|
description: null,
|
||||||
startText: "Sehr geehrte Frau Sindern,\n" +
|
startText: null,
|
||||||
"wir bedanken uns für Ihr entgegengebrachtes Vertrauen und Ihren Auftrag und stellen Ihnen\n" +
|
endText: null,
|
||||||
"folgende Positionen in Rechnung: ",
|
|
||||||
endText: "Bitte überweisen Sie den Rechnungsbetrag unter Angabe der Rechnungsnummer im Verwendungszweck innerhalb von 10 Tagen auf das unten angegebene Konto. Wir bedanken uns für das entgegengebrachte Vertrauen und freuen uns auf eine weitere gute Zusammenarbeit.",
|
|
||||||
rows: [
|
rows: [
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -257,19 +257,58 @@ const saveDocument = async () => {
|
|||||||
rows: itemInfo.value.rows
|
rows: itemInfo.value.rows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let data = null
|
||||||
|
|
||||||
if(route.params.id) {
|
if(route.params.id) {
|
||||||
await dataStore.updateItem("createdDocuments", {...createData, id: itemInfo.value.id})
|
data = await dataStore.updateItem("createddocuments", {...createData, id: itemInfo.value.id})
|
||||||
} else {
|
} else {
|
||||||
await dataStore.createNewItem("createdDocuments", createData)
|
data = await dataStore.createNewItem("createddocuments", createData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await router.push(`/createDocument/edit/${data[0].id}`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeDocument = () => {
|
const closeDocument = async () => {
|
||||||
generateDocument()
|
|
||||||
console.log(uri)
|
await saveDocument()
|
||||||
|
|
||||||
|
await generateDocument()
|
||||||
|
|
||||||
|
|
||||||
|
let fileData = {
|
||||||
|
tags: [],
|
||||||
|
project: null
|
||||||
|
}
|
||||||
|
|
||||||
|
fileData.project = itemInfo.value.project
|
||||||
|
fileData.createdDocument = itemInfo.value.id
|
||||||
|
fileData.tags.push(dataStore.documentTypesForCreation[itemInfo.value.type].labelSingle)
|
||||||
|
|
||||||
|
function dataURLtoFile(dataurl, filename) {
|
||||||
|
var arr = dataurl.split(","),
|
||||||
|
mime = arr[0].match(/:(.*?);/)[1],
|
||||||
|
bstr = atob(arr[arr.length - 1]),
|
||||||
|
n = bstr.length,
|
||||||
|
u8arr = new Uint8Array(n);
|
||||||
|
while (n--) {
|
||||||
|
u8arr[n] = bstr.charCodeAt(n);
|
||||||
|
}
|
||||||
|
return new File([u8arr], filename, { type: mime });
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = dataURLtoFile(uri.value, `${itemInfo.value.documentNumber}.pdf`)
|
||||||
|
|
||||||
|
await dataStore.uploadFiles(fileData, [file], true)
|
||||||
|
|
||||||
|
|
||||||
|
//console.log(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,55 +38,12 @@ const filteredDocuments = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const uploadFiles = async () => {
|
const uploadFiles = async () => {
|
||||||
const uploadSingleFile = async (file) => {
|
uploadInProgress.value = true;
|
||||||
|
|
||||||
const {data, error} = await supabase
|
await dataStore.uploadFiles(fileUploadFormData.value, document.getElementById("fileUploadInput").files)
|
||||||
.storage
|
|
||||||
.from("files")
|
|
||||||
.upload(`${user.value.app_metadata.tenant}/${file.name}`, file)
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.log(error)
|
|
||||||
} else if (data) {
|
|
||||||
const returnPath = data.path
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const files = (await supabase.storage.from('files').list(`${user.value.app_metadata.tenant}/`, {
|
|
||||||
limit: 100,
|
|
||||||
offset: 0,
|
|
||||||
sortBy: {column: 'name', order: 'asc'}
|
|
||||||
})).data
|
|
||||||
|
|
||||||
fileUploadFormData.value.path = returnPath
|
|
||||||
|
|
||||||
const {data, error} = await supabase
|
|
||||||
.from("documents")
|
|
||||||
.insert([fileUploadFormData.value])
|
|
||||||
.select()
|
|
||||||
if(error) console.log(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadInProgress.value = true
|
|
||||||
|
|
||||||
let files = document.getElementById("fileUploadInput").files
|
|
||||||
|
|
||||||
if(files.length === 1) {
|
|
||||||
await uploadSingleFile(files[0])
|
|
||||||
} else if( files.length > 1) {
|
|
||||||
|
|
||||||
for(let i = 0; i < files.length; i++){
|
|
||||||
uploadSingleFile(files[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadModalOpen.value = false;
|
uploadModalOpen.value = false;
|
||||||
uploadInProgress.value = false;
|
uploadInProgress.value = false;
|
||||||
dataStore.fetchDocuments()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadSelected = async () => {
|
const downloadSelected = async () => {
|
||||||
@@ -152,7 +109,7 @@ const downloadSelected = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2">
|
<InputGroup>
|
||||||
<UButton @click="uploadModalOpen = true">Hochladen</UButton>
|
<UButton @click="uploadModalOpen = true">Hochladen</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
@click="downloadSelected"
|
@click="downloadSelected"
|
||||||
@@ -170,7 +127,7 @@ const downloadSelected = async () => {
|
|||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</InputGroup>
|
||||||
<div >
|
<div >
|
||||||
<USlideover
|
<USlideover
|
||||||
v-model="uploadModalOpen"
|
v-model="uploadModalOpen"
|
||||||
@@ -219,15 +176,11 @@ const downloadSelected = async () => {
|
|||||||
</template>
|
</template>
|
||||||
</UCard>
|
</UCard>
|
||||||
</USlideover>
|
</USlideover>
|
||||||
<div class="documentList" >
|
<DocumentList
|
||||||
<DocumentDisplay
|
:documents="filteredDocuments"
|
||||||
:document="i"
|
|
||||||
:key="i.id"
|
|
||||||
v-for="i in filteredDocuments"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,18 @@ definePageMeta({
|
|||||||
const supabase = useSupabaseClient()
|
const supabase = useSupabaseClient()
|
||||||
const user = useSupabaseUser()
|
const user = useSupabaseUser()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const {fetchData} = useDataStore()
|
const colorMode = useColorMode()
|
||||||
|
const dataStore = useDataStore()
|
||||||
|
|
||||||
|
const isLight = computed({
|
||||||
|
get () {
|
||||||
|
return colorMode.value !== 'dark'
|
||||||
|
},
|
||||||
|
set () {
|
||||||
|
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const email = ref("")
|
const email = ref("")
|
||||||
const password = ref("")
|
const password = ref("")
|
||||||
@@ -36,7 +47,7 @@ const onSubmit = async (data) => {
|
|||||||
alert(error.toString())
|
alert(error.toString())
|
||||||
} else {
|
} else {
|
||||||
console.log("Login Successful")
|
console.log("Login Successful")
|
||||||
fetchData()
|
dataStore.changeTenant()
|
||||||
router.push("/")
|
router.push("/")
|
||||||
|
|
||||||
|
|
||||||
@@ -74,11 +85,16 @@ const onSubmit = async (data) => {
|
|||||||
|
|
||||||
</div>-->
|
</div>-->
|
||||||
<UCard class="max-w-sm w-full mx-auto mt-5">
|
<UCard class="max-w-sm w-full mx-auto mt-5">
|
||||||
|
<img
|
||||||
|
:src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'"
|
||||||
|
alt="Logo"
|
||||||
|
class="w-full mx-auto"
|
||||||
|
/>
|
||||||
|
|
||||||
<UAuthForm
|
<UAuthForm
|
||||||
title="Login"
|
title="Login"
|
||||||
description="Geben Sie Ihre Anmeldedaten ein um Zugriff auf Ihren Account zu bekommen"
|
description="Geben Sie Ihre Anmeldedaten ein um Zugriff auf Ihren Account zu bekommen"
|
||||||
align="bottom"
|
align="bottom"
|
||||||
icon="i-heroicons-user-circle"
|
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
:loading="false"
|
:loading="false"
|
||||||
@submit="onSubmit"
|
@submit="onSubmit"
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import HistoryDisplay from "~/components/HistoryDisplay.vue";
|
import HistoryDisplay from "~/components/HistoryDisplay.vue";
|
||||||
|
import DocumentList from "~/components/DocumentList.vue";
|
||||||
|
import DocumentUpload from "~/components/DocumentUpload.vue";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
@@ -17,7 +19,7 @@ const editor = useEditor({
|
|||||||
extensions: [TiptapStarterKit],
|
extensions: [TiptapStarterKit],
|
||||||
});
|
});
|
||||||
|
|
||||||
let currentItem = null
|
let currentItem = ref(null)
|
||||||
|
|
||||||
//Working
|
//Working
|
||||||
const mode = ref(route.params.mode || "show")
|
const mode = ref(route.params.mode || "show")
|
||||||
@@ -30,6 +32,8 @@ const tabItems = [
|
|||||||
label: "Projekte"
|
label: "Projekte"
|
||||||
},{
|
},{
|
||||||
label: "Aufgaben"
|
label: "Aufgaben"
|
||||||
|
},{
|
||||||
|
label: "Dokumente"
|
||||||
},{
|
},{
|
||||||
label: "Dokumentation"
|
label: "Dokumentation"
|
||||||
}
|
}
|
||||||
@@ -38,10 +42,10 @@ const tabItems = [
|
|||||||
//Functions
|
//Functions
|
||||||
const setupPage = () => {
|
const setupPage = () => {
|
||||||
if(mode.value === "show" || mode.value === "edit"){
|
if(mode.value === "show" || mode.value === "edit"){
|
||||||
currentItem = dataStore.getPlantById(Number(useRoute().params.id))
|
currentItem.value = dataStore.getPlantById(Number(useRoute().params.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode.value === "edit") itemInfo.value = currentItem
|
if(mode.value === "edit") itemInfo.value = currentItem.value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +54,7 @@ const setupPage = () => {
|
|||||||
|
|
||||||
|
|
||||||
const editItem = async () => {
|
const editItem = async () => {
|
||||||
router.push(`/plants/edit/${currentItem.id}`)
|
await router.push(`/plants/edit/${currentItem.value.id}`)
|
||||||
setupPage()
|
setupPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +104,78 @@ setupPage()
|
|||||||
|
|
||||||
</UTable>
|
</UTable>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="item.label === 'Dokumente'" class="space-y-3">
|
||||||
|
<InputGroup>
|
||||||
|
<DocumentUpload
|
||||||
|
type="plant"
|
||||||
|
:element-id="currentItem.id"
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
|
||||||
|
<!-- <UModal
|
||||||
|
v-model="uploadModalOpen"
|
||||||
|
>
|
||||||
|
<UCard class="p-4">
|
||||||
|
|
||||||
|
<template #header>
|
||||||
|
Datei hochladen
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Datei:"
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
type="file"
|
||||||
|
id="fileUploadInput"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
<!– <UFormGroup
|
||||||
|
label="Name:"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
v-model="fileUploadFormData.name"
|
||||||
|
/>
|
||||||
|
</UFormGroup>–>
|
||||||
|
<UFormGroup
|
||||||
|
label="Tags:"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
multiple
|
||||||
|
searchable
|
||||||
|
searchable-placeholder="Suchen..."
|
||||||
|
:options="tags"
|
||||||
|
v-model="fileUploadFormData.tags"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
<!–<UFormGroup
|
||||||
|
label="Ordner:"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
:options="folders"
|
||||||
|
v-model="fileUploadFormData.folder"
|
||||||
|
value-attribute="label"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</UFormGroup>–>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<UButton
|
||||||
|
class="mt-3"
|
||||||
|
@click="uploadFiles"
|
||||||
|
>Hochladen</UButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
</UCard>
|
||||||
|
|
||||||
|
</UModal>-->
|
||||||
|
|
||||||
|
<DocumentList :documents="dataStore.getDocumentsByPlantId(currentItem.id)"/>
|
||||||
|
|
||||||
|
</div>
|
||||||
<div v-if="item.label === 'Dokumentation'">
|
<div v-if="item.label === 'Dokumentation'">
|
||||||
|
|
||||||
<Editor/>
|
<Editor/>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import HistoryDisplay from "~/components/HistoryDisplay.vue";
|
import HistoryDisplay from "~/components/HistoryDisplay.vue";
|
||||||
|
import DocumentUpload from "~/components/DocumentUpload.vue";
|
||||||
|
import DocumentList from "~/components/DocumentList.vue";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
@@ -94,10 +96,7 @@ const itemInfo = ref({
|
|||||||
const uploadModalOpen = ref(false)
|
const uploadModalOpen = ref(false)
|
||||||
const fileUploadFormData = ref({
|
const fileUploadFormData = ref({
|
||||||
tags: ["Dokument"],
|
tags: ["Dokument"],
|
||||||
folder: "Projekte",
|
project: null
|
||||||
usedInResource: {
|
|
||||||
type: "Projekt",
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
const tags = dataStore.getDocumentTags
|
const tags = dataStore.getDocumentTags
|
||||||
|
|
||||||
@@ -153,39 +152,13 @@ const updateItem = async () => {
|
|||||||
dataStore.fetchProjects()
|
dataStore.fetchProjects()
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadFile = async () => {
|
const uploadFiles = async () => {
|
||||||
const file = document.getElementById("fileUploadInput").files[0]
|
//uploadInProgress.value = true;
|
||||||
|
|
||||||
const {data,error} = await supabase
|
await dataStore.uploadFiles({...fileUploadFormData.value, project: currentItem.value.id}, document.getElementById("fileUploadInput").files)
|
||||||
.storage
|
|
||||||
.from("documents")
|
|
||||||
.upload(`${user.value.app_metadata.tenant}/${fileUploadFormData.value.folder}/${currentProject.id}/${file.name}`,file)
|
|
||||||
|
|
||||||
console.log(data)
|
|
||||||
const returnPath = data.path
|
|
||||||
|
|
||||||
if(error) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log(returnPath)
|
|
||||||
const files = (await supabase.storage.from('documents').list(`${user.value.app_metadata.tenant}/${fileUploadFormData.value.folder}/${currentProject.id}/`, {limit: 100, offset: 0, sortBy: { column: 'name', order: 'asc' }})).data
|
|
||||||
console.log(files)
|
|
||||||
const fileId = files.find(temp => returnPath.includes(temp.name)).id
|
|
||||||
|
|
||||||
fileUploadFormData.value.object = fileId
|
|
||||||
fileUploadFormData.value.path = returnPath
|
|
||||||
fileUploadFormData.value.usedInResource.id = currentProject.id
|
|
||||||
console.log(fileUploadFormData.value)
|
|
||||||
|
|
||||||
const {data,error} = await supabase
|
|
||||||
.from("documents")
|
|
||||||
.insert([fileUploadFormData.value])
|
|
||||||
.select()
|
|
||||||
console.log(data)
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadModalOpen.value = false;
|
uploadModalOpen.value = false;
|
||||||
|
//uploadInProgress.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +168,7 @@ const projectHours = () => {
|
|||||||
hours += Number(dayjs(item.end).diff(item.start,'hour',true).toFixed(2))
|
hours += Number(dayjs(item.end).diff(item.start,'hour',true).toFixed(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
return hours
|
return hours.toFixed(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -256,6 +229,7 @@ setupPage()
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
<div v-else-if="item.key === 'forms'" class="space-y-3">
|
<div v-else-if="item.key === 'forms'" class="space-y-3">
|
||||||
<UButton
|
<UButton
|
||||||
@click="formModalOpen = true"
|
@click="formModalOpen = true"
|
||||||
@@ -308,13 +282,13 @@ setupPage()
|
|||||||
</template>
|
</template>
|
||||||
</UAccordion>
|
</UAccordion>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
<div v-else-if="item.key === 'documents'" class="space-y-3">
|
<div v-else-if="item.key === 'documents'" class="space-y-3">
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<UButton
|
<DocumentUpload
|
||||||
@click="uploadModalOpen = true"
|
type="project"
|
||||||
>
|
:element-id="currentItem.id"
|
||||||
Hochladen
|
/>
|
||||||
</UButton>
|
|
||||||
<UButton
|
<UButton
|
||||||
@click="router.push(`/createDocument/edit?project=${currentItem.id}&type=quotes&customer=${currentItem.customer}`)"
|
@click="router.push(`/createDocument/edit?project=${currentItem.id}&type=quotes&customer=${currentItem.customer}`)"
|
||||||
>
|
>
|
||||||
@@ -327,7 +301,7 @@ setupPage()
|
|||||||
</UButton>
|
</UButton>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
|
|
||||||
<UModal
|
<!-- <UModal
|
||||||
v-model="uploadModalOpen"
|
v-model="uploadModalOpen"
|
||||||
>
|
>
|
||||||
<UCard class="p-4">
|
<UCard class="p-4">
|
||||||
@@ -344,14 +318,14 @@ setupPage()
|
|||||||
id="fileUploadInput"
|
id="fileUploadInput"
|
||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
<!-- <UFormGroup
|
<!– <UFormGroup
|
||||||
label="Name:"
|
label="Name:"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
>
|
>
|
||||||
<UInput
|
<UInput
|
||||||
v-model="fileUploadFormData.name"
|
v-model="fileUploadFormData.name"
|
||||||
/>
|
/>
|
||||||
</UFormGroup>-->
|
</UFormGroup>–>
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
label="Tags:"
|
label="Tags:"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
@@ -364,7 +338,7 @@ setupPage()
|
|||||||
v-model="fileUploadFormData.tags"
|
v-model="fileUploadFormData.tags"
|
||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
<!--<UFormGroup
|
<!–<UFormGroup
|
||||||
label="Ordner:"
|
label="Ordner:"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
>
|
>
|
||||||
@@ -374,27 +348,22 @@ setupPage()
|
|||||||
value-attribute="label"
|
value-attribute="label"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</UFormGroup>-->
|
</UFormGroup>–>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<UButton
|
<UButton
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
@click="uploadFile"
|
@click="uploadFiles"
|
||||||
>Hochladen</UButton>
|
>Hochladen</UButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
</UCard>
|
</UCard>
|
||||||
|
|
||||||
</UModal>
|
</UModal>-->
|
||||||
|
|
||||||
|
<DocumentList :documents="dataStore.getDocumentsByProjectId(currentItem.id)"/>
|
||||||
|
|
||||||
<div class="documentList">
|
|
||||||
<DocumentDisplay
|
|
||||||
v-for="document in dataStore.getDocumentsByProjectId(currentItem.id)"
|
|
||||||
:document="document"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="item.key === 'timetracking'" class="space-y-3">
|
<div v-else-if="item.key === 'timetracking'" class="space-y-3">
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="main">
|
<div id="main">
|
||||||
|
|
||||||
<div class="flex items-center gap-1">
|
<InputGroup>
|
||||||
<UButton @click="router.push(`/incominginvoices/create/`)">+ Eingangsrechnung</UButton>
|
<UButton @click="router.push(`/incominginvoices/create/`)">+ Eingangsrechnung</UButton>
|
||||||
|
<UButton
|
||||||
|
@click="router.push(`/createDocument/edit?type=quotes`)"
|
||||||
|
>
|
||||||
|
+ Angebot
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
@click="router.push(`/createDocument/edit?type=invoices`)"
|
||||||
|
>
|
||||||
|
+ Rechnung
|
||||||
|
</UButton>
|
||||||
|
|
||||||
<UInput
|
<UInput
|
||||||
v-model="searchString"
|
v-model="searchString"
|
||||||
@@ -13,7 +23,7 @@
|
|||||||
v-model="showDrafts"
|
v-model="showDrafts"
|
||||||
label="Entwürfe Anzeigen"
|
label="Entwürfe Anzeigen"
|
||||||
/>
|
/>
|
||||||
</div>
|
</InputGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -172,9 +182,9 @@ const searchString = ref('')
|
|||||||
const showDrafts = ref(false)
|
const showDrafts = ref(false)
|
||||||
|
|
||||||
const filteredRows = computed(() => {
|
const filteredRows = computed(() => {
|
||||||
let items = [...dataStore.incomingInvoices.map(i => {return {...i, type: "incomingInvoice"}}),...dataStore.createdDocuments]
|
let items = [...dataStore.incomingInvoices.map(i => {return {...i, type: "incomingInvoice"}}),...dataStore.createddocuments]
|
||||||
|
|
||||||
console.log(dataStore.createdDocuments)
|
console.log(dataStore.createddocuments)
|
||||||
|
|
||||||
if(showDrafts.value === true) {
|
if(showDrafts.value === true) {
|
||||||
items = items.filter(i => i.state === "Entwurf")
|
items = items.filter(i => i.state === "Entwurf")
|
||||||
|
|||||||
@@ -19,11 +19,10 @@ let currentItem = ref(null)
|
|||||||
//Working
|
//Working
|
||||||
const mode = ref(route.params.mode || "show")
|
const mode = ref(route.params.mode || "show")
|
||||||
const itemInfo = ref({
|
const itemInfo = ref({
|
||||||
id: 0,
|
|
||||||
name: "",
|
name: "",
|
||||||
licensePlate: "",
|
licensePlate: "",
|
||||||
type: "",
|
type: "",
|
||||||
driver: ""
|
driver: null
|
||||||
})
|
})
|
||||||
|
|
||||||
const tabItems = [{
|
const tabItems = [{
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
label: "Benutzer",
|
label: "Benutzer",
|
||||||
labelSingle: "Benutzer"
|
labelSingle: "Benutzer"
|
||||||
},
|
},
|
||||||
createdDocuments: {
|
createddocuments: {
|
||||||
label: "Dokumente",
|
label: "Dokumente",
|
||||||
labelSingle: "Dokument"
|
labelSingle: "Dokument"
|
||||||
},
|
},
|
||||||
@@ -154,7 +154,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
const inventoryItems = ref([])
|
const inventoryItems = ref([])
|
||||||
const chats = ref([])
|
const chats = ref([])
|
||||||
const messages = ref([])
|
const messages = ref([])
|
||||||
const createdDocuments = ref([])
|
const createddocuments = ref([])
|
||||||
|
|
||||||
async function initializeData () {
|
async function initializeData () {
|
||||||
await fetchProfiles()
|
await fetchProfiles()
|
||||||
@@ -176,7 +176,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
async function fetchData () {
|
async function fetchData () {
|
||||||
await fetchProfiles()
|
await fetchProfiles()
|
||||||
|
|
||||||
fetchDocuments()
|
await fetchDocuments()
|
||||||
await fetchOwnTenant()
|
await fetchOwnTenant()
|
||||||
await fetchEvents()
|
await fetchEvents()
|
||||||
await fetchTasks()
|
await fetchTasks()
|
||||||
@@ -189,7 +189,6 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
await fetchFormSubmits()
|
await fetchFormSubmits()
|
||||||
await fetchProducts()
|
await fetchProducts()
|
||||||
await fetchUnits()
|
await fetchUnits()
|
||||||
//await fetchDocuments()
|
|
||||||
await fetchMovements()
|
await fetchMovements()
|
||||||
await fetchSpaces()
|
await fetchSpaces()
|
||||||
await fetchVehicles()
|
await fetchVehicles()
|
||||||
@@ -245,7 +244,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
inventoryItems.value = []
|
inventoryItems.value = []
|
||||||
chats.value = []
|
chats.value = []
|
||||||
messages.value = []
|
messages.value = []
|
||||||
createdDocuments.value = []
|
createddocuments.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
//Realtime Update
|
//Realtime Update
|
||||||
@@ -278,7 +277,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
const numberRange = useNumberRange(dataType)
|
const numberRange = useNumberRange(dataType)
|
||||||
data[dataTypes[dataType].numberRangeHolder] = await numberRange.useNextNumber()
|
data[dataTypes[dataType].numberRangeHolder] = await numberRange.useNextNumber()
|
||||||
|
|
||||||
} else if(dataType === "createdDocuments") {
|
} else if(dataType === "createddocuments") {
|
||||||
console.log(data.type)
|
console.log(data.type)
|
||||||
const numberRange = useNumberRange(data.type)
|
const numberRange = useNumberRange(data.type)
|
||||||
data.documentNumber = await numberRange.useNextNumber()
|
data.documentNumber = await numberRange.useNextNumber()
|
||||||
@@ -296,6 +295,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')')
|
await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')')
|
||||||
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
|
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
|
||||||
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
|
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
|
||||||
|
return supabaseData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,8 +312,72 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0]))
|
await eval(dataType + '.value[' + dataType + '.value.findIndex(i => i.id === ' + JSON.stringify(data.id) + ')] = ' + JSON.stringify(supabaseData[0]))
|
||||||
toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`})
|
toast.add({title: `${dataTypes[dataType].labelSingle} gespeichert`})
|
||||||
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
|
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
|
||||||
|
return supabaseData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFiles = async (formData, files, upsert) => {
|
||||||
|
|
||||||
|
let documentsToInsert = []
|
||||||
|
|
||||||
|
const uploadSingleFile = async (file) => {
|
||||||
|
|
||||||
|
const {data, error} = await supabase
|
||||||
|
.storage
|
||||||
|
.from("files")
|
||||||
|
.upload(`${currentTenant.value}/${file.name}`, file, {upsert})
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.log(error)
|
||||||
|
console.log(error.statusCode)
|
||||||
|
|
||||||
|
if(error.statusCode === '400') {
|
||||||
|
console.log("is 400")
|
||||||
|
toast.add({title: "Hochladen fehlgeschlagen", description: "Die Datei enthält ungültige Zeichen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000})
|
||||||
|
} else if(error.statusCode === '409') {
|
||||||
|
console.log("is 409")
|
||||||
|
toast.add({title: "Hochladen fehlgeschlagen", description: "Es existiert bereits eine Datei mit diesem Namen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000})
|
||||||
|
} else {
|
||||||
|
toast.add({title: "Hochladen fehlgeschlagen", icon: "i-heroicons-x-circle", color: "rose", timeout: 10000})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (data) {
|
||||||
|
const returnPath = data.path
|
||||||
|
|
||||||
|
documentsToInsert.push({...formData, path: returnPath})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//uploadInProgress.value = true
|
||||||
|
|
||||||
|
|
||||||
|
if(files.length === 1) {
|
||||||
|
await uploadSingleFile(files[0])
|
||||||
|
} else if( files.length > 1) {
|
||||||
|
|
||||||
|
for(let i = 0; i < files.length; i++){
|
||||||
|
uploadSingleFile(files[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data, error} = await supabase
|
||||||
|
.from("documents")
|
||||||
|
.insert(documentsToInsert)
|
||||||
|
.select()
|
||||||
|
if(error) console.log(error)
|
||||||
|
else {
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
|
fetchDocuments()
|
||||||
|
|
||||||
|
//documents.value.push(...data)
|
||||||
|
}
|
||||||
|
//uploadModalOpen.value = false;
|
||||||
|
//uploadInProgress.value = false;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchOwnTenant () {
|
async function fetchOwnTenant () {
|
||||||
@@ -409,21 +473,28 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
messages.value = (await supabase.from("messages").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
|
messages.value = (await supabase.from("messages").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
|
||||||
}
|
}
|
||||||
async function fetchCreatedDocuments() {
|
async function fetchCreatedDocuments() {
|
||||||
createdDocuments.value = (await supabase.from("createddocuments").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
|
createddocuments.value = (await supabase.from("createddocuments").select().eq('tenant', currentTenant.value).order('created_at', {ascending:true})).data
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchDocuments () {
|
async function fetchDocuments () {
|
||||||
let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data
|
let tempDocuments = (await supabase.from("documents").select().eq('tenant', currentTenant.value)).data
|
||||||
|
|
||||||
if(tempDocuments.length > 0) {
|
let paths = []
|
||||||
for(const [index,doc] of tempDocuments.entries()){
|
tempDocuments.forEach(doc => {
|
||||||
// @ts-ignore
|
paths.push(doc.path)
|
||||||
tempDocuments[index].url = (await supabase.storage.from('files').createSignedUrl(doc.path, 60 * 60)).data.signedUrl
|
})
|
||||||
}
|
|
||||||
|
const {data,error} = await supabase.storage.from('files').createSignedUrls(paths,3600)
|
||||||
|
|
||||||
|
tempDocuments = tempDocuments.map((doc,index) => {
|
||||||
|
|
||||||
|
return {
|
||||||
|
...doc,
|
||||||
|
url: data[index].signedUrl
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
documents.value = tempDocuments
|
documents.value = tempDocuments
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addHistoryItem(text, user, elementId, resourceType) {
|
async function addHistoryItem(text, user, elementId, resourceType) {
|
||||||
@@ -473,7 +544,11 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const getDocumentsByProjectId = computed(() => (projectId) => {
|
const getDocumentsByProjectId = computed(() => (projectId) => {
|
||||||
return documents.value.filter(item => item.project === projectId)
|
return documents.value.filter(item => item.project === projectId && !item.tags.includes("Archiviert"))
|
||||||
|
})
|
||||||
|
|
||||||
|
const getDocumentsByPlantId = computed(() => (itemId) => {
|
||||||
|
return documents.value.filter(item => item.plant === itemId && !item.tags.includes("Archiviert"))
|
||||||
})
|
})
|
||||||
|
|
||||||
const getEventsByProjectId = computed(() => (projectId) => {
|
const getEventsByProjectId = computed(() => (projectId) => {
|
||||||
@@ -730,7 +805,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const getCreatedDocumentById = computed(() => (documentId) => {
|
const getCreatedDocumentById = computed(() => (documentId) => {
|
||||||
return createdDocuments.value.find(item => item.id === documentId)
|
return createddocuments.value.find(item => item.id === documentId)
|
||||||
})
|
})
|
||||||
|
|
||||||
const getProjectById = computed(() => (itemId) => {
|
const getProjectById = computed(() => (itemId) => {
|
||||||
@@ -760,6 +835,8 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
ownTenant,
|
ownTenant,
|
||||||
initializeData,
|
initializeData,
|
||||||
changeTenant,
|
changeTenant,
|
||||||
|
uploadFiles,
|
||||||
|
|
||||||
|
|
||||||
//Data
|
//Data
|
||||||
profiles,
|
profiles,
|
||||||
@@ -792,7 +869,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
inventoryItems,
|
inventoryItems,
|
||||||
chats,
|
chats,
|
||||||
messages,
|
messages,
|
||||||
createdDocuments,
|
createddocuments,
|
||||||
documentTypesForCreation,
|
documentTypesForCreation,
|
||||||
//Functions
|
//Functions
|
||||||
createNewItem,
|
createNewItem,
|
||||||
@@ -836,6 +913,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
getContactsByCustomerId,
|
getContactsByCustomerId,
|
||||||
getContactsByVendorId,
|
getContactsByVendorId,
|
||||||
getDocumentsByProjectId,
|
getDocumentsByProjectId,
|
||||||
|
getDocumentsByPlantId,
|
||||||
getEventsByProjectId,
|
getEventsByProjectId,
|
||||||
getTimesByProjectId,
|
getTimesByProjectId,
|
||||||
getTasksByProjectId,
|
getTasksByProjectId,
|
||||||
|
|||||||
6
supabase/functions/import_map.json
Normal file
6
supabase/functions/import_map.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"@supabase/supabase-js": "npm:@supabase/supabase-js@2.39.1",
|
||||||
|
"axios": "npm:axios@1.6.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
test/supabasestorage/AN.pdf
Normal file
BIN
test/supabasestorage/AN.pdf
Normal file
Binary file not shown.
23
test/supabasestorage/index.mjs
Normal file
23
test/supabasestorage/index.mjs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import {createClient} from "@supabase/supabase-js";
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import * as fs from "fs";
|
||||||
|
const supabase = createClient("http://localhost:54321", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0")
|
||||||
|
|
||||||
|
|
||||||
|
const currentTenant = 1
|
||||||
|
|
||||||
|
console.log(await supabase.storage.listBuckets())
|
||||||
|
|
||||||
|
let files = (await supabase.storage.from('files').list(currentTenant)).data
|
||||||
|
|
||||||
|
files.forEach(async (file) => {
|
||||||
|
console.log(await supabase.storage.from('files').getPublicUrl(file.name))
|
||||||
|
})
|
||||||
|
|
||||||
|
const file = fs.readFileSync('AN.pdf','utf8')
|
||||||
|
const fileId = uuidv4()
|
||||||
|
|
||||||
|
const {data,error} = await supabase.storage.from('files').upload(`${currentTenant}/${fileId}/AN.pdf`,file, {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
Reference in New Issue
Block a user