Rebuild General Layout to Nuxt UI PRO Dashboard
This commit is contained in:
@@ -3,9 +3,7 @@ const supabase = useSupabaseClient()
|
|||||||
const user = useSupabaseUser()
|
const user = useSupabaseUser()
|
||||||
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()
|
||||||
|
|
||||||
const viewport = useViewport()
|
const viewport = useViewport()
|
||||||
|
|
||||||
/*watch(viewport.breakpoint, (newBreakpoint, oldBreakpoint) => {
|
/*watch(viewport.breakpoint, (newBreakpoint, oldBreakpoint) => {
|
||||||
@@ -13,6 +11,10 @@ const viewport = useViewport()
|
|||||||
})*/
|
})*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
meta: [
|
meta: [
|
||||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
||||||
@@ -45,6 +47,28 @@ useSeoMeta({
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
/* width */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Track */
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: rgb(2,6,23);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle */
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: grey;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle on hover */
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #69c350;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#logo img{
|
#logo img{
|
||||||
height: 15vh;
|
height: 15vh;
|
||||||
@@ -58,24 +82,12 @@ useSeoMeta({
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
.documentList::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollList {
|
.scrollList {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
height: 85vh;
|
height: 85vh;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollList::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -101,16 +113,4 @@ useSeoMeta({
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.table > div {
|
|
||||||
width: 78vw;
|
|
||||||
height: 90vh;
|
|
||||||
overflow: scroll !important;
|
|
||||||
-ms-overflow-style: none; /*!* IE and Edge *!*/
|
|
||||||
scrollbar-width: none; /*!* Firefox *!*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.table > div::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
107
spaces/components/HelpSlideover.vue
Normal file
107
spaces/components/HelpSlideover.vue
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { isHelpSlideoverOpen } = useDashboard()
|
||||||
|
const { metaSymbol } = useShortcuts()
|
||||||
|
|
||||||
|
const shortcuts = ref(false)
|
||||||
|
const query = ref('')
|
||||||
|
|
||||||
|
const links = [{
|
||||||
|
label: 'Shortcuts',
|
||||||
|
icon: 'i-heroicons-key',
|
||||||
|
trailingIcon: 'i-heroicons-arrow-right-20-solid',
|
||||||
|
color: 'gray',
|
||||||
|
onClick: () => {
|
||||||
|
shortcuts.value = true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Documentation',
|
||||||
|
icon: 'i-heroicons-book-open',
|
||||||
|
to: 'https://ui.nuxt.com/pro/guide',
|
||||||
|
target: '_blank'
|
||||||
|
}, {
|
||||||
|
label: 'GitHub repository',
|
||||||
|
icon: 'i-simple-icons-github',
|
||||||
|
to: 'https://github.com/nuxt/ui-pro',
|
||||||
|
target: '_blank'
|
||||||
|
}, {
|
||||||
|
label: 'Buy Nuxt UI Pro',
|
||||||
|
icon: 'i-heroicons-credit-card',
|
||||||
|
to: 'https://ui.nuxt.com/pro/purchase',
|
||||||
|
target: '_blank'
|
||||||
|
}]
|
||||||
|
|
||||||
|
const categories = computed(() => [{
|
||||||
|
title: 'General',
|
||||||
|
items: [
|
||||||
|
{ shortcuts: [metaSymbol.value, 'K'], name: 'Command menu' },
|
||||||
|
{ shortcuts: ['N'], name: 'Notifications' },
|
||||||
|
{ shortcuts: ['?'], name: 'Help & Support' },
|
||||||
|
{ shortcuts: ['/'], name: 'Search' }
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
title: 'Navigation',
|
||||||
|
items: [
|
||||||
|
{ shortcuts: ['G', 'H'], name: 'Go to Home' },
|
||||||
|
{ shortcuts: ['G', 'I'], name: 'Go to Inbox' },
|
||||||
|
{ shortcuts: ['G', 'U'], name: 'Go to Users' },
|
||||||
|
{ shortcuts: ['G', 'S'], name: 'Go to Settings' }
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
title: 'Inbox',
|
||||||
|
items: [
|
||||||
|
{ shortcuts: ['↑'], name: 'Prev notification' },
|
||||||
|
{ shortcuts: ['↓'], name: 'Next notification' }
|
||||||
|
]
|
||||||
|
}])
|
||||||
|
|
||||||
|
const filteredCategories = computed(() => {
|
||||||
|
return categories.value.map(category => ({
|
||||||
|
title: category.title,
|
||||||
|
items: category.items.filter(item => {
|
||||||
|
return item.name.search(new RegExp(query.value, 'i')) !== -1
|
||||||
|
})
|
||||||
|
})).filter(category => !!category.items.length)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UDashboardSlideover v-model="isHelpSlideoverOpen">
|
||||||
|
<template #title>
|
||||||
|
<UButton
|
||||||
|
v-if="shortcuts"
|
||||||
|
color="gray"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
icon="i-heroicons-arrow-left-20-solid"
|
||||||
|
@click="shortcuts = false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{ shortcuts ? 'Shortcuts' : 'Hilfe & Support' }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-if="shortcuts" class="space-y-6">
|
||||||
|
<UInput v-model="query" icon="i-heroicons-magnifying-glass" placeholder="Search..." autofocus color="gray" />
|
||||||
|
|
||||||
|
<div v-for="(category, index) in filteredCategories" :key="index">
|
||||||
|
<p class="mb-3 text-sm text-gray-900 dark:text-white font-semibold">
|
||||||
|
{{ category.title }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div v-for="(item, i) in category.items" :key="i" class="flex items-center justify-between">
|
||||||
|
<span class="text-sm text-gray-500 dark:text-gray-400">{{ item.name }}</span>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-end flex-shrink-0 gap-0.5">
|
||||||
|
<UKbd v-for="(shortcut, j) in item.shortcuts" :key="j">
|
||||||
|
{{ shortcut }}
|
||||||
|
</UKbd>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex flex-col gap-y-3">
|
||||||
|
<UButton v-for="(link, index) in links" :key="index" color="white" v-bind="link" />
|
||||||
|
</div>
|
||||||
|
</UDashboardSlideover>
|
||||||
|
</template>
|
||||||
29
spaces/components/NotificationsSlideover.vue
Normal file
29
spaces/components/NotificationsSlideover.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { formatTimeAgo } from '@vueuse/core'
|
||||||
|
import type { Notification } from '~/types'
|
||||||
|
|
||||||
|
const { isNotificationsSlideoverOpen } = useDashboard()
|
||||||
|
|
||||||
|
const { data: notifications } = await useFetch<Notification[]>('/api/notifications')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UDashboardSlideover v-model="isNotificationsSlideoverOpen" title="Notifications">
|
||||||
|
<NuxtLink v-for="notification in notifications" :key="notification.id" :to="`/inbox?id=${notification.id}`" class="p-3 rounded-md hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer flex items-center gap-3 relative">
|
||||||
|
<UChip color="red" :show="!!notification.unread" inset>
|
||||||
|
<UAvatar v-bind="notification.sender.avatar" :alt="notification.sender.name" size="md" />
|
||||||
|
</UChip>
|
||||||
|
|
||||||
|
<div class="text-sm flex-1">
|
||||||
|
<p class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-900 dark:text-white font-medium">{{ notification.sender.name }}</span>
|
||||||
|
|
||||||
|
<time :datetime="notification.date" class="text-gray-500 dark:text-gray-400 text-xs" v-text="formatTimeAgo(new Date(notification.date))" />
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-500 dark:text-gray-400">
|
||||||
|
{{ notification.body }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</NuxtLink>
|
||||||
|
</UDashboardSlideover>
|
||||||
|
</template>
|
||||||
46
spaces/components/TeamsDropdown.vue
Normal file
46
spaces/components/TeamsDropdown.vue
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const teams = [{
|
||||||
|
label: 'Nuxt',
|
||||||
|
/*avatar: {
|
||||||
|
src: 'https://avatars.githubusercontent.com/u/23360933?s=200&v=4'
|
||||||
|
},*/
|
||||||
|
click: () => {
|
||||||
|
team.value = teams[0]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'NuxtLabs',
|
||||||
|
/*avatar: {
|
||||||
|
src: 'https://avatars.githubusercontent.com/u/62017400?s=200&v=4'
|
||||||
|
},*/
|
||||||
|
click: () => {
|
||||||
|
team.value = teams[1]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
||||||
|
const actions = [{
|
||||||
|
label: 'Create team',
|
||||||
|
icon: 'i-heroicons-plus-circle'
|
||||||
|
}, {
|
||||||
|
label: 'Manage teams',
|
||||||
|
icon: 'i-heroicons-cog-8-tooth'
|
||||||
|
}]
|
||||||
|
|
||||||
|
const team = ref(teams[0])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UDropdown
|
||||||
|
v-slot="{ open }"
|
||||||
|
mode="hover"
|
||||||
|
:items="[teams]"
|
||||||
|
class="w-full"
|
||||||
|
:ui="{ width: 'w-full' }"
|
||||||
|
:popper="{ strategy: 'absolute' }"
|
||||||
|
>
|
||||||
|
<UButton color="gray" variant="ghost" :class="[open && 'bg-gray-50 dark:bg-gray-800']" class="w-full">
|
||||||
|
<UAvatar v-if="team.avatar" :src="team.avatar.src" size="2xs" />
|
||||||
|
|
||||||
|
<span class="truncate text-gray-900 dark:text-white font-semibold">{{ team.label }}</span>
|
||||||
|
</UButton>
|
||||||
|
</UDropdown>
|
||||||
|
</template>
|
||||||
84
spaces/components/UserDropdown.vue
Normal file
84
spaces/components/UserDropdown.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { isHelpSlideoverOpen } = useDashboard()
|
||||||
|
const { isDashboardSearchModalOpen } = useUIState()
|
||||||
|
const { metaSymbol } = useShortcuts()
|
||||||
|
const user = useSupabaseUser()
|
||||||
|
const dataStore = useDataStore()
|
||||||
|
const supabase = useSupabaseClient()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const items = computed(() => [
|
||||||
|
[{
|
||||||
|
slot: 'account',
|
||||||
|
label: '',
|
||||||
|
disabled: true
|
||||||
|
}], [{
|
||||||
|
label: 'Settings',
|
||||||
|
icon: 'i-heroicons-cog-8-tooth',
|
||||||
|
to: '/settings'
|
||||||
|
}, {
|
||||||
|
label: 'Command menu',
|
||||||
|
icon: 'i-heroicons-command-line',
|
||||||
|
shortcuts: [metaSymbol.value, 'K'],
|
||||||
|
click: () => {
|
||||||
|
isDashboardSearchModalOpen.value = true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Help & Support',
|
||||||
|
icon: 'i-heroicons-question-mark-circle',
|
||||||
|
shortcuts: ['?'],
|
||||||
|
click: () => isHelpSlideoverOpen.value = true
|
||||||
|
}], [{
|
||||||
|
label: 'Documentation',
|
||||||
|
icon: 'i-heroicons-book-open',
|
||||||
|
to: 'https://ui.nuxt.com/pro/guide',
|
||||||
|
target: '_blank'
|
||||||
|
},/* {
|
||||||
|
label: 'GitHub repository',
|
||||||
|
icon: 'i-simple-icons-github',
|
||||||
|
to: 'https://github.com/nuxt/ui-pro',
|
||||||
|
target: '_blank'
|
||||||
|
}, {
|
||||||
|
label: 'Buy Nuxt UI Pro',
|
||||||
|
icon: 'i-heroicons-credit-card',
|
||||||
|
to: 'https://ui.nuxt.com/pro/purchase',
|
||||||
|
target: '_blank'
|
||||||
|
}*/], [{
|
||||||
|
label: 'Abmelden',
|
||||||
|
icon: 'i-heroicons-arrow-left-on-rectangle',
|
||||||
|
click: async () => {
|
||||||
|
await supabase.auth.signOut()
|
||||||
|
await dataStore.clearStore()
|
||||||
|
await router.push('/login')
|
||||||
|
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<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']">
|
||||||
|
<template #leading>
|
||||||
|
<UAvatar :alt="dataStore.getProfileById(user.id) ? dataStore.getProfileById(user.id).fullName : ''" size="xs" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #trailing>
|
||||||
|
<UIcon name="i-heroicons-ellipsis-vertical" class="w-5 h-5 ml-auto" />
|
||||||
|
</template>
|
||||||
|
</UButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #account>
|
||||||
|
<div class="text-left">
|
||||||
|
<p>
|
||||||
|
Angemeldet als
|
||||||
|
</p>
|
||||||
|
<p class="truncate font-medium text-gray-900 dark:text-white">
|
||||||
|
{{dataStore.getProfileById(user.id).email}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UDropdown>
|
||||||
|
</template>
|
||||||
29
spaces/composables/useDashboard.ts
Normal file
29
spaces/composables/useDashboard.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { createSharedComposable } from '@vueuse/core'
|
||||||
|
|
||||||
|
const _useDashboard = () => {
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const isHelpSlideoverOpen = ref(false)
|
||||||
|
const isNotificationsSlideoverOpen = ref(false)
|
||||||
|
|
||||||
|
defineShortcuts({
|
||||||
|
'g-h': () => router.push('/'),
|
||||||
|
'g-i': () => router.push('/inbox'),
|
||||||
|
'g-u': () => router.push('/users'),
|
||||||
|
'g-s': () => router.push('/settings'),
|
||||||
|
'?': () => isHelpSlideoverOpen.value = true,
|
||||||
|
n: () => isNotificationsSlideoverOpen.value = true
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => route.fullPath, () => {
|
||||||
|
isHelpSlideoverOpen.value = false
|
||||||
|
isNotificationsSlideoverOpen.value = false
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
isHelpSlideoverOpen,
|
||||||
|
isNotificationsSlideoverOpen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDashboard = createSharedComposable(_useDashboard)
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
const colorMode = useColorMode()
|
const colorMode = useColorMode()
|
||||||
|
const { isHelpSlideoverOpen } = useDashboard()
|
||||||
const userProfile = dataStore.getOwnProfile
|
const userProfile = dataStore.getOwnProfile
|
||||||
const supabase = useSupabaseClient()
|
const supabase = useSupabaseClient()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -10,6 +10,7 @@ const route = useRoute()
|
|||||||
|
|
||||||
dataStore.initializeData((await supabase.auth.getUser()).data.user.id)
|
dataStore.initializeData((await supabase.auth.getUser()).data.user.id)
|
||||||
|
|
||||||
|
|
||||||
const isLight = computed({
|
const isLight = computed({
|
||||||
get() {
|
get() {
|
||||||
return colorMode.value !== 'dark'
|
return colorMode.value !== 'dark'
|
||||||
@@ -196,21 +197,16 @@ const userMenuItems = ref([
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const links = [[{
|
const linksold = [[{
|
||||||
label: 'Profil',
|
|
||||||
avatar: {
|
|
||||||
alt: userProfile ? userProfile.fullName : "XY"
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
label: "Dashboard",
|
label: "Dashboard",
|
||||||
to: "/",
|
to: "/",
|
||||||
icon: "i-heroicons-home"
|
icon: "i-heroicons-home"
|
||||||
}], [{
|
}],
|
||||||
|
[{
|
||||||
label: "Aufgaben",
|
label: "Aufgaben",
|
||||||
to: "/tasks",
|
to: "/tasks",
|
||||||
icon: "i-heroicons-rectangle-stack"
|
icon: "i-heroicons-rectangle-stack"
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
label: "Plantafel",
|
label: "Plantafel",
|
||||||
to: "/calendar/timeline",
|
to: "/calendar/timeline",
|
||||||
icon: "i-heroicons-calendar-days"
|
icon: "i-heroicons-calendar-days"
|
||||||
@@ -314,147 +310,227 @@ const links = [[{
|
|||||||
}]
|
}]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let links = [
|
||||||
|
{
|
||||||
|
id: 'dashboard',
|
||||||
|
label: "Dashboard",
|
||||||
|
to: "/",
|
||||||
|
icon: "i-heroicons-home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Organisation",
|
||||||
|
icon: "i-heroicons-rectangle-stack",
|
||||||
|
defaultOpen: false,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Aufgaben",
|
||||||
|
to: "/tasks",
|
||||||
|
icon: "i-heroicons-rectangle-stack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Plantafel",
|
||||||
|
to: "/calendar/timeline",
|
||||||
|
icon: "i-heroicons-calendar-days"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Kalender",
|
||||||
|
to: "/calendar/grid",
|
||||||
|
icon: "i-heroicons-calendar-days"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Dokumente",
|
||||||
|
to: "/documents",
|
||||||
|
icon: "i-heroicons-document"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "E-Mail",
|
||||||
|
to: "/email",
|
||||||
|
icon: "i-heroicons-envelope"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Kontakte",
|
||||||
|
defaultOpen: false,
|
||||||
|
icon: "i-heroicons-user-group",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Kunden",
|
||||||
|
to: "/customers",
|
||||||
|
icon: "i-heroicons-user-group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Lieferanten",
|
||||||
|
to: "/vendors",
|
||||||
|
icon: "i-heroicons-truck"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Ansprechpartner",
|
||||||
|
to: "/contacts",
|
||||||
|
icon: "i-heroicons-user-group"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Mitarbeiter",
|
||||||
|
defaultOpen:false,
|
||||||
|
icon: "i-heroicons-user-group",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Zeiterfassung",
|
||||||
|
to: "/employees/timetracking",
|
||||||
|
icon: "i-heroicons-clock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Anwesenheiten",
|
||||||
|
to: "/workingtimes",
|
||||||
|
icon: "i-heroicons-clock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Abwesenheiten",
|
||||||
|
to: "/absenceRequests",
|
||||||
|
icon: "i-heroicons-document-text"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Lager",
|
||||||
|
icon: "i-heroicons-puzzle-piece",
|
||||||
|
defaultOpen: false,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Steuerung",
|
||||||
|
to: "/inventory",
|
||||||
|
icon: "i-heroicons-square-3-stack-3d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Lagerplätze",
|
||||||
|
to: "/spaces",
|
||||||
|
icon: "i-heroicons-square-3-stack-3d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Inventar",
|
||||||
|
to: "/inventoryitems",
|
||||||
|
icon: "i-heroicons-puzzle-piece"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Stammdaten",
|
||||||
|
defaultOpen: false,
|
||||||
|
icon: "i-heroicons-clipboard-document",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Artikelstamm",
|
||||||
|
to: "/products",
|
||||||
|
icon: "i-heroicons-puzzle-piece"
|
||||||
|
},{
|
||||||
|
label: "Leistungsstamm",
|
||||||
|
to: "/services",
|
||||||
|
icon: "i-heroicons-puzzle-piece"
|
||||||
|
},{
|
||||||
|
label: "Fahrzeuge",
|
||||||
|
to: "/vehicles",
|
||||||
|
icon: "i-heroicons-truck"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Belege",
|
||||||
|
to: "/receipts",
|
||||||
|
icon: "i-heroicons-document-text"
|
||||||
|
},{
|
||||||
|
label: "Projekte",
|
||||||
|
to: "/projects",
|
||||||
|
icon: "i-heroicons-clipboard-document-check"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Verträge",
|
||||||
|
to: "/contracts",
|
||||||
|
icon: "i-heroicons-clipboard-document"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Objekte",
|
||||||
|
to: "/plants",
|
||||||
|
icon: "i-heroicons-clipboard-document"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const groups = [{
|
||||||
|
key: 'links',
|
||||||
|
label: 'Go to',
|
||||||
|
commands: links.map(link => ({ ...link, shortcuts: link.tooltip?.shortcuts }))
|
||||||
|
}, {
|
||||||
|
key: 'code',
|
||||||
|
label: 'Code',
|
||||||
|
commands: [{
|
||||||
|
id: 'source',
|
||||||
|
label: 'View page source',
|
||||||
|
icon: 'i-simple-icons-github',
|
||||||
|
click: () => {
|
||||||
|
window.open(`https://github.com/nuxt-ui-pro/dashboard/blob/main/pages${route.path === '/' ? '/index' : route.path}.vue`, '_blank')
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
const footerLinks = [/*{
|
||||||
|
label: 'Invite people',
|
||||||
|
icon: 'i-heroicons-plus',
|
||||||
|
to: '/settings/members'
|
||||||
|
}, */{
|
||||||
|
label: 'Hilfe & Support',
|
||||||
|
icon: 'i-heroicons-question-mark-circle',
|
||||||
|
click: () => isHelpSlideoverOpen.value = true
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="dataStore.loaded" class="flex justify-center flex-row">
|
<UDashboardLayout v-if="dataStore.loaded">
|
||||||
<!-- <UHeader :links="navLinks" :to="null">
|
|
||||||
<template #logo>
|
|
||||||
<div id="logo">
|
|
||||||
<img
|
|
||||||
:src="!isLight ? '/spaces.svg' : '/spaces_hell.svg'"
|
|
||||||
alt="Logo"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
<UDashboardPanel :width="250" :resizable="{ min: 200, max: 300 }" collapsible>
|
||||||
|
<UDashboardNavbar class="!border-transparent" :ui="{ left: 'flex-1' }">
|
||||||
<template #panel>
|
<template #left>
|
||||||
<UNavigationTree :links="navLinks"/>
|
<TeamsDropdown />
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #right>
|
|
||||||
|
|
||||||
<GlobalSearch/>
|
|
||||||
|
|
||||||
<UButton
|
|
||||||
@click="showUserMenu = true"
|
|
||||||
variant="ghost"
|
|
||||||
color="gray"
|
|
||||||
>
|
|
||||||
<UAvatar
|
|
||||||
:alt="userProfile ? userProfile.firstName + ' ' + userProfile.lastName : '' "
|
|
||||||
icon="i-heroicons-user-20-solid"
|
|
||||||
:chip-color="dataStore.notifications.filter(item => !item.read).length > 0 ? 'primary' : null"
|
|
||||||
|
|
||||||
/>
|
|
||||||
</UButton>
|
|
||||||
|
|
||||||
<USlideover
|
|
||||||
v-model="showUserMenu"
|
|
||||||
>
|
|
||||||
<UCard
|
|
||||||
class="h-full"
|
|
||||||
>
|
|
||||||
|
|
||||||
<div v-if="dataStore.getOwnProfile.tenants.length > 1">
|
|
||||||
<UDivider
|
|
||||||
class="my-3"
|
|
||||||
label="Tenant"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<USelectMenu
|
|
||||||
:options="dataStore.getOwnProfile.tenants"
|
|
||||||
option-attribute="name"
|
|
||||||
value-attribute="id"
|
|
||||||
v-model="dataStore.currentTenant"
|
|
||||||
@change="dataStore.changeTenant()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<UDivider
|
|
||||||
class="my-3"
|
|
||||||
label="Menü"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<UVerticalNavigation
|
|
||||||
:links="userMenuItems"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!– <UDivider
|
|
||||||
class="my-3"
|
|
||||||
label="Benachrichtigungen"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<UAlert
|
|
||||||
class="mb-3"
|
|
||||||
v-for="(notification) in dataStore.notifications"
|
|
||||||
:color="!notification.read ? 'primary' : 'white'"
|
|
||||||
:variant="!notification.read ? 'outline' : 'soft'"
|
|
||||||
:description="notification.text"
|
|
||||||
:title="notification.title"
|
|
||||||
:close-button="!notification.read ? { icon: 'i-heroicons-x-mark-20-solid', color: 'gray', variant: 'link', padded: false } : null"
|
|
||||||
@close="async () => {
|
|
||||||
const {error} = await supabase.from('notifications').update({read:true}).eq('id', notification.id)
|
|
||||||
if(error) console.log(error)
|
|
||||||
dataStore.fetchNotifications()
|
|
||||||
}"
|
|
||||||
/>–>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<InputGroup>
|
|
||||||
<UButton
|
|
||||||
:icon="!isLight ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
|
|
||||||
color="white"
|
|
||||||
variant="outline"
|
|
||||||
aria-label="Theme"
|
|
||||||
@click="isLight = !isLight"
|
|
||||||
/>
|
|
||||||
<UButton
|
|
||||||
color="rose"
|
|
||||||
variant="outline"
|
|
||||||
@click="async () => {
|
|
||||||
showUserMenu = false
|
|
||||||
await supabase.auth.signOut()
|
|
||||||
await dataStore.clearStore()
|
|
||||||
await router.push('/login')
|
|
||||||
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
Ausloggen
|
|
||||||
</UButton>
|
|
||||||
</InputGroup>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</UCard>
|
|
||||||
</USlideover>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
</UHeader>
|
|
||||||
<UDivider />-->
|
|
||||||
<div class="ml-2 mt-3" id="menuLeft">
|
|
||||||
|
|
||||||
<UVerticalNavigation
|
|
||||||
:links="links"
|
|
||||||
>
|
|
||||||
<template #avatar="{link}">
|
|
||||||
<UAvatar
|
|
||||||
v-if="link.avatar"
|
|
||||||
v-bind="link.avatar"
|
|
||||||
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</UVerticalNavigation>
|
</UDashboardNavbar>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pl-3 pr-3 mt-3" id="contentContainer">
|
<UDashboardSidebar id="sidebar">
|
||||||
<slot id="content"/>
|
<template #header>
|
||||||
</div>
|
<UDashboardSearchButton />
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
|
<UDashboardSidebarLinks :links="links" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<UDivider />
|
||||||
|
|
||||||
|
<UDashboardSidebarLinks :links="[{ label: 'Colors', draggable: true, children: colors }]" @update:links="colors => defaultColors = colors" />
|
||||||
|
|
||||||
|
-->
|
||||||
|
<div class="flex-1" />
|
||||||
|
|
||||||
|
<UDashboardSidebarLinks :links="footerLinks" />
|
||||||
|
|
||||||
|
<UDivider class="sticky bottom-0" />
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<!-- ~/components/UserDropdown.vue -->
|
||||||
|
<UserDropdown />
|
||||||
|
</template>
|
||||||
|
</UDashboardSidebar>
|
||||||
|
</UDashboardPanel>
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<!-- ~/components/HelpSlideover.vue -->
|
||||||
|
<HelpSlideover />
|
||||||
|
<!-- ~/components/NotificationsSlideover.vue -->
|
||||||
|
<NotificationsSlideover />
|
||||||
|
|
||||||
|
<ClientOnly>
|
||||||
|
<LazyUDashboardSearch :groups="groups" />
|
||||||
|
</ClientOnly>
|
||||||
|
</UDashboardLayout>
|
||||||
<div
|
<div
|
||||||
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"
|
||||||
@@ -466,31 +542,9 @@ const links = [[{
|
|||||||
/>
|
/>
|
||||||
<UProgress animation="carousel"/>
|
<UProgress animation="carousel"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
#menuLeft {
|
|
||||||
height: 95vh;
|
|
||||||
width: 20vw;
|
|
||||||
overflow-y: scroll;
|
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
#menuLeft::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#contentContainer {
|
|
||||||
width: 77vw;
|
|
||||||
height: 95vh;
|
|
||||||
overflow-y: scroll;
|
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
#contentContainer::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -287,19 +287,28 @@ const calendarOptionsTimeline = reactive({
|
|||||||
|
|
||||||
</UModal>
|
</UModal>
|
||||||
|
|
||||||
<div v-if="mode === 'grid'">
|
<UDashboardPage>
|
||||||
<FullCalendar
|
<UDashboardPanel grow>
|
||||||
:options="calendarOptionsGrid"
|
<UDashboardNavbar :title="currentItem ? currentItem.name : ''">
|
||||||
/>
|
<template #right>
|
||||||
</div>
|
|
||||||
<div v-else-if="mode === 'timeline'">
|
</template>
|
||||||
<FullCalendar
|
</UDashboardNavbar>
|
||||||
:options="calendarOptionsTimeline"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
<div v-if="mode === 'grid'" class="p-5">
|
||||||
|
<FullCalendar
|
||||||
|
:options="calendarOptionsGrid"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="mode === 'timeline'" class="p-5">
|
||||||
|
<FullCalendar
|
||||||
|
:options="calendarOptionsTimeline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</UDashboardPanel>
|
||||||
|
</UDashboardPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,26 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="cardHolder">
|
<UDashboardPage>
|
||||||
<div class="card">
|
<UDashboardPanel grow>
|
||||||
<h1 class="text-center text-4xl">Aufgaben</h1>
|
<UDashboardNavbar title="Home">
|
||||||
<p class="text-center text-6xl mt-5">{{openTasks}}</p>
|
<template #right>
|
||||||
</div><div class="card">
|
<UTooltip text="Notifications" :shortcuts="['N']">
|
||||||
|
<UButton color="gray" variant="ghost" square @click="isNotificationsSlideoverOpen = true">
|
||||||
|
<UChip color="red" inset>
|
||||||
|
<UIcon name="i-heroicons-bell" class="w-5 h-5" />
|
||||||
|
</UChip>
|
||||||
|
</UButton>
|
||||||
|
</UTooltip>
|
||||||
|
|
||||||
</div><div class="card">
|
<UDropdown :items="items">
|
||||||
|
<UButton icon="i-heroicons-plus" size="md" class="ml-1.5 rounded-full" />
|
||||||
|
</UDropdown>
|
||||||
|
</template>
|
||||||
|
</UDashboardNavbar>
|
||||||
|
|
||||||
</div><div class="card">
|
<!-- <UDashboardToolbar>
|
||||||
|
<template #left>
|
||||||
|
<!– ~/components/home/HomeDateRangePicker.vue –>
|
||||||
|
<!– <HomeDateRangePicker v-model="range" class="-ml-2.5" />–>
|
||||||
|
|
||||||
</div><div class="card">
|
<!– ~/components/home/HomePeriodSelect.vue –>
|
||||||
|
<!– <HomePeriodSelect v-model="period" :range="range" />–>
|
||||||
|
</template>
|
||||||
|
</UDashboardToolbar>-->
|
||||||
|
|
||||||
</div><div class="card">
|
<UDashboardPanelContent>
|
||||||
|
<!-- ~/components/home/HomeChart.vue -->
|
||||||
|
<!-- <HomeChart :period="period" :range="range" />
|
||||||
|
|
||||||
</div>
|
<div class="grid lg:grid-cols-2 lg:items-start gap-8 mt-8">
|
||||||
|
<!– ~/components/home/HomeSales.vue –>
|
||||||
|
<HomeSales />
|
||||||
|
<!– ~/components/home/HomeCountries.vue –>
|
||||||
|
<HomeCountries />
|
||||||
<br>
|
</div>-->
|
||||||
|
</UDashboardPanelContent>
|
||||||
</div>
|
</UDashboardPanel>
|
||||||
|
</UDashboardPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -28,6 +47,18 @@ definePageMeta({
|
|||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { isNotificationsSlideoverOpen } = useDashboard()
|
||||||
|
const items = [[{
|
||||||
|
label: 'Aufgabe',
|
||||||
|
icon: 'i-heroicons-paper-airplane',
|
||||||
|
to: '/tasks/create'
|
||||||
|
}, {
|
||||||
|
label: 'Kunde',
|
||||||
|
icon: 'i-heroicons-user-plus',
|
||||||
|
to: '/customers/create'
|
||||||
|
}]]
|
||||||
|
|
||||||
|
|
||||||
const {getOpenTasksCount} = useDataStore()
|
const {getOpenTasksCount} = useDataStore()
|
||||||
const openTasks = getOpenTasksCount
|
const openTasks = getOpenTasksCount
|
||||||
|
|
||||||
@@ -38,7 +69,7 @@ const user = useSupabaseUser()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.cardHolder {
|
/*.cardHolder {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -49,5 +80,5 @@ const user = useSupabaseUser()
|
|||||||
width: 22vw;
|
width: 22vw;
|
||||||
height: 40vh;
|
height: 40vh;
|
||||||
border: 1px solid white
|
border: 1px solid white
|
||||||
}
|
}*/
|
||||||
</style>
|
</style>
|
||||||
@@ -122,6 +122,28 @@ const calendarOptionsTimeline = reactive({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<UDashboardPage>
|
||||||
|
<UDashboardPanel grow>
|
||||||
|
<UDashboardNavbar :title="currentItem ? currentItem.name : ''">
|
||||||
|
<template #right>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</UDashboardNavbar>
|
||||||
|
<div v-if="viewport.isLessThan('tablet')">
|
||||||
|
<FullCalendar
|
||||||
|
:options="calendarOptionsList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<FullCalendar
|
||||||
|
:options="calendarOptionsTimeline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</UDashboardPanel>
|
||||||
|
</UDashboardPage>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<UModal
|
<UModal
|
||||||
v-model="openNewEventModal"
|
v-model="openNewEventModal"
|
||||||
@@ -229,16 +251,7 @@ const calendarOptionsTimeline = reactive({
|
|||||||
|
|
||||||
|
|
||||||
</UModal>
|
</UModal>
|
||||||
<div v-if="viewport.isLessThan('tablet')">
|
|
||||||
<FullCalendar
|
|
||||||
:options="calendarOptionsList"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<FullCalendar
|
|
||||||
:options="calendarOptionsTimeline"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
})
|
})
|
||||||
@@ -75,7 +77,177 @@ setupPage()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1
|
<UDashboardPage>
|
||||||
|
<UDashboardPanel grow>
|
||||||
|
<UDashboardNavbar :title="currentItem ? currentItem.name : ''">
|
||||||
|
<template #right>
|
||||||
|
<UButton
|
||||||
|
v-if="mode === 'edit'"
|
||||||
|
@click="dataStore.updateItem('tasks',itemInfo)"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
v-else-if="mode === 'create'"
|
||||||
|
@click="dataStore.createNewItem('tasks',itemInfo)"
|
||||||
|
>
|
||||||
|
Erstellen
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
@click="cancelEditorCreate"
|
||||||
|
color="red"
|
||||||
|
class="ml-2"
|
||||||
|
v-if="mode === 'edit' || mode === 'create'"
|
||||||
|
>
|
||||||
|
Abbrechen
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
v-if="mode === 'show' && currentItem.id"
|
||||||
|
@click="editItem"
|
||||||
|
>
|
||||||
|
Bearbeiten
|
||||||
|
</UButton>
|
||||||
|
</template>
|
||||||
|
</UDashboardNavbar>
|
||||||
|
|
||||||
|
<!-- <UDashboardToolbar>
|
||||||
|
<template #left>
|
||||||
|
<!– <UButton @click="router.push(`/tasks/create`)">+ Aufgabe</UButton>
|
||||||
|
|
||||||
|
<UInput
|
||||||
|
v-model="searchString"
|
||||||
|
placeholder="Suche..."
|
||||||
|
/>–>
|
||||||
|
|
||||||
|
<UCheckbox
|
||||||
|
label="Erledigte Anzeigen"
|
||||||
|
v-model="showDone"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #right>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="selectedColumns"
|
||||||
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
|
:options="templateColumns"
|
||||||
|
multiple
|
||||||
|
class="hidden lg:block"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
Spalten
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</template>
|
||||||
|
</UDashboardToolbar>-->
|
||||||
|
|
||||||
|
|
||||||
|
<UTabs
|
||||||
|
:items="[{label: 'Informationen'},{label: 'Logbuch'}]"
|
||||||
|
v-if="currentItem && mode === 'show'"
|
||||||
|
class="p-5"
|
||||||
|
>
|
||||||
|
<template #item="{item}">
|
||||||
|
<UCard class="mt-5">
|
||||||
|
<div v-if="item.label === 'Informationen'">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="truncate">
|
||||||
|
<p>Kategorie: {{currentItem.categorie}}</p>
|
||||||
|
<p v-if="currentItem.project">Projekt: <nuxt-link :to="`/projects/show/${currentItem.project}`">{{dataStore.getProjectById(currentItem.project).name}}</nuxt-link></p>
|
||||||
|
<p>Beschreibung: {{currentItem.description}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- TODO: Logbuch Tasks -->
|
||||||
|
</UCard>
|
||||||
|
</template>
|
||||||
|
</UTabs>
|
||||||
|
|
||||||
|
<UForm v-else-if="mode === 'edit' || mode === 'create' " class="p-5">
|
||||||
|
<UFormGroup
|
||||||
|
label="Name:"
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
v-model="itemInfo.name"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Kategorie:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.categorie"
|
||||||
|
:options="categories"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Benutzer:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.user"
|
||||||
|
:options="dataStore.profiles"
|
||||||
|
option-attribute="fullName"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable-placeholder="Suche..."
|
||||||
|
searchable
|
||||||
|
:search-attributes="['fullName']"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
{{dataStore.getProfileById(itemInfo.user) ? dataStore.getProfileById(itemInfo.user).fullName : "Kein Benutzer ausgewählt"}}
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
<UFormGroup
|
||||||
|
label="Projekt:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.project"
|
||||||
|
:options="dataStore.projects"
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable-placeholder="Suche..."
|
||||||
|
searchable
|
||||||
|
:search-attributes="['name']"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
{{dataStore.getProjectById(itemInfo.project) ? dataStore.getProjectById(itemInfo.project).name : "Kein Projekt ausgewählt"}}
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
<UFormGroup
|
||||||
|
label="Objekt:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.plant"
|
||||||
|
:options="dataStore.plants"
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable-placeholder="Suche..."
|
||||||
|
searchable
|
||||||
|
:search-attributes="['name']"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
{{dataStore.getPlantById(itemInfo.plant) ? dataStore.getPlantById(itemInfo.plant).name : "Kein Objekt ausgewählt"}}
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Beschreibung:"
|
||||||
|
>
|
||||||
|
<UTextarea
|
||||||
|
v-model="itemInfo.description"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
</UForm>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</UDashboardPanel>
|
||||||
|
</UDashboardPage>
|
||||||
|
|
||||||
|
<!-- <h1
|
||||||
class="mb-3 truncate font-bold text-2xl"
|
class="mb-3 truncate font-bold text-2xl"
|
||||||
v-if="currentItem"
|
v-if="currentItem"
|
||||||
>Aufgabe: {{currentItem.name}}</h1>
|
>Aufgabe: {{currentItem.name}}</h1>
|
||||||
@@ -108,7 +280,7 @@ setupPage()
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- TODO: Logbuch Tasks -->
|
<!– TODO: Logbuch Tasks –>
|
||||||
</UCard>
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
</UTabs>
|
</UTabs>
|
||||||
@@ -220,7 +392,7 @@ setupPage()
|
|||||||
</UButton>
|
</UButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</UCard>
|
</UCard>-->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,25 +1,64 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<UDashboardPage>
|
||||||
|
<UDashboardPanel grow>
|
||||||
|
<UDashboardNavbar title="Aufgaben" :badge="filteredRows.length">
|
||||||
|
<template #right>
|
||||||
|
<UInput
|
||||||
|
ref="input"
|
||||||
|
v-model="searchString"
|
||||||
|
icon="i-heroicons-funnel"
|
||||||
|
autocomplete="off"
|
||||||
|
placeholder="Suche..."
|
||||||
|
class="hidden lg:block"
|
||||||
|
@keydown.esc="$event.target.blur()"
|
||||||
|
>
|
||||||
|
<template #trailing>
|
||||||
|
<UKbd value="/" />
|
||||||
|
</template>
|
||||||
|
</UInput>
|
||||||
|
|
||||||
<div>
|
<UButton @click="router.push(`/tasks/create`)">+ Aufgabe</UButton>
|
||||||
<Toolbar>
|
</template>
|
||||||
<UButton @click="router.push(`/tasks/create`)">+ Aufgabe</UButton>
|
</UDashboardNavbar>
|
||||||
|
|
||||||
<UInput
|
<UDashboardToolbar>
|
||||||
v-model="searchString"
|
<template #left>
|
||||||
placeholder="Suche..."
|
<!-- <UButton @click="router.push(`/tasks/create`)">+ Aufgabe</UButton>
|
||||||
/>
|
|
||||||
|
<UInput
|
||||||
|
v-model="searchString"
|
||||||
|
placeholder="Suche..."
|
||||||
|
/>-->
|
||||||
|
|
||||||
|
<UCheckbox
|
||||||
|
label="Erledigte Anzeigen"
|
||||||
|
v-model="showDone"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #right>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="selectedColumns"
|
||||||
|
icon="i-heroicons-adjustments-horizontal-solid"
|
||||||
|
:options="templateColumns"
|
||||||
|
multiple
|
||||||
|
class="hidden lg:block"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
Spalten
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</template>
|
||||||
|
</UDashboardToolbar>
|
||||||
|
|
||||||
<UCheckbox
|
|
||||||
label="Erledigte Anzeigen"
|
|
||||||
v-model="showDone"
|
|
||||||
/>
|
|
||||||
</Toolbar>
|
|
||||||
<div class="table">
|
|
||||||
<UTable
|
<UTable
|
||||||
|
v-model:sort="sort"
|
||||||
:rows="filteredRows"
|
:rows="filteredRows"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
@select="selectItem"
|
sort-mode="manual"
|
||||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
|
class="w-full"
|
||||||
|
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||||
|
@select="(i) => router.push(`/tasks/show/${i.id}`) "
|
||||||
>
|
>
|
||||||
<template #finish-data="{row}">
|
<template #finish-data="{row}">
|
||||||
<UButton
|
<UButton
|
||||||
@@ -44,27 +83,37 @@
|
|||||||
{{dataStore.getPlantById(row.plant) ? dataStore.getPlantById(row.plant).name : "" }}
|
{{dataStore.getPlantById(row.plant) ? dataStore.getPlantById(row.plant).name : "" }}
|
||||||
</template>
|
</template>
|
||||||
</UTable>
|
</UTable>
|
||||||
</div>
|
</UDashboardPanel>
|
||||||
|
</UDashboardPage>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script lang="ts" setup>
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
})
|
})
|
||||||
|
const input = ref<{ input: HTMLInputElement }>()
|
||||||
|
|
||||||
const dataStore = useDataStore()
|
const dataStore = useDataStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const mode = ref("show")
|
const mode = ref("show")
|
||||||
|
|
||||||
const columns = [
|
|
||||||
|
|
||||||
{
|
defineShortcuts({
|
||||||
|
'/': () => {
|
||||||
|
input.value?.input?.focus()
|
||||||
|
},
|
||||||
|
'+': () => {
|
||||||
|
router.push("/tasks/create")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const templateColumns = [
|
||||||
|
|
||||||
|
/*{
|
||||||
key:"finish"
|
key:"finish"
|
||||||
},{
|
},*/{
|
||||||
key: "created_at",
|
key: "created_at",
|
||||||
label: "Erstellt am:",
|
label: "Erstellt am:",
|
||||||
sortable: true
|
sortable: true
|
||||||
@@ -95,6 +144,10 @@ const columns = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const selectedColumns = ref(templateColumns)
|
||||||
|
const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column)))
|
||||||
|
|
||||||
|
|
||||||
const searchString = ref('')
|
const searchString = ref('')
|
||||||
const showDone = ref(false)
|
const showDone = ref(false)
|
||||||
|
|
||||||
|
|||||||
11
spaces/pages/test.vue
Normal file
11
spaces/pages/test.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
test
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -795,7 +795,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
|
|
||||||
const getResources = computed(() => {
|
const getResources = computed(() => {
|
||||||
return [
|
return [
|
||||||
...profiles.value.map(profile => {
|
...profiles.value.filter(i => i.tenant === currentTenant.value).map(profile => {
|
||||||
return {
|
return {
|
||||||
type: 'Mitarbeiter',
|
type: 'Mitarbeiter',
|
||||||
title: profile.fullName,
|
title: profile.fullName,
|
||||||
|
|||||||
Reference in New Issue
Block a user