Compare commits

...

3 Commits

Author SHA1 Message Date
b3dd46195d Merge remote-tracking branch 'origin/dev' into dev
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 26s
Build and Push Docker Images / build-frontend (push) Successful in 1m17s
Build and Push Docker Images / build-website (push) Successful in 23s
Build and Push Docker Images / build-central-services-api (push) Successful in 22s
Build and Push Docker Images / build-central-services-admin (push) Successful in 22s
Build and Push Docker Images / build-docs (push) Successful in 22s
2026-09-09 12:47:50 +02:00
54294ce7e9 fix: make planning board week start configurable 2026-09-09 12:46:08 +02:00
5141a1f3ac feat: Lieferantenanlage verschiebbar machen 2026-09-09 12:43:39 +02:00
4 changed files with 80 additions and 5 deletions

View File

@@ -22,6 +22,10 @@ const props = defineProps({
inModal: {
type: Boolean,
},
draggable: {
type: Boolean,
default: false,
},
platform: {
type: String,
}
@@ -523,6 +527,8 @@ const updateItem = async () => {
</UDashboardNavbar>
<UDashboardNavbar
v-else
:data-draggable-handle="props.draggable ? '' : undefined"
:class="props.draggable ? 'cursor-move select-none' : undefined"
:ui="{center: 'flex items-stretch gap-1.5 min-w-0'}"
>
<template #center>

View File

@@ -1,4 +1,5 @@
<script setup>
import { useDraggable } from '@vueuse/core'
const toast = useToast()
const dataStore = useDataStore()
@@ -31,6 +32,23 @@ const loaded = ref(false)
const items = ref([])
const item = ref({})
const isDraggableVendorCreate = computed(() => props.type === "vendors" && props.mode === "create")
const draggableWindow = ref(null)
const initialWindowPosition = import.meta.client
? {
x: Math.max(16, (window.innerWidth - Math.min(1024, window.innerWidth - 32)) / 2),
y: Math.max(16, Math.min(96, window.innerHeight * 0.1)),
}
: { x: 16, y: 16 }
const { style: draggableWindowStyle } = useDraggable(draggableWindow, {
initialValue: initialWindowPosition,
onStart: (_position, event) => {
const target = event.target
return target instanceof Element && Boolean(target.closest('[data-draggable-handle]'))
},
})
const setupPage = async () => {
if(props.mode === "show") {
//Load Data for Show
@@ -60,7 +78,30 @@ setupPage()
</script>
<template>
<UModal :fullscreen="props.mode === 'show'">
<div
v-if="isDraggableVendorCreate"
ref="draggableWindow"
:style="draggableWindowStyle"
class="fixed z-[999] flex h-[80vh] max-h-[calc(100vh-2rem)] w-[calc(100vw-2rem)] max-w-5xl flex-col overflow-hidden resize rounded-xl border border-gray-200 bg-white shadow-2xl dark:border-gray-800 dark:bg-gray-900"
>
<EntityEdit
v-if="loaded"
:type="props.type"
:item="item"
:inModal="true"
:draggable="true"
@return-data="(data) => emit('returnData', data)"
:createQuery="props.createQuery"
:mode="props.mode"
/>
<UProgress
v-else
animation="carousel"
class="m-5 mt-10"
/>
</div>
<UModal v-else :fullscreen="props.mode === 'show'">
<template #content>
<EntityShow
v-if="loaded && props.mode === 'show'"

View File

@@ -184,12 +184,16 @@ const resolvedPlanningBoardConfig = computed(() => {
const normalizedStartTime = /^\d{2}:\d{2}$/.test(String(config.startTime || "")) ? String(config.startTime) : "06:00"
const normalizedEndTime = /^\d{2}:\d{2}$/.test(String(config.endTime || "")) ? String(config.endTime) : "21:00"
const normalizedSlotMinutes = Number(config.slotMinutes)
const normalizedWeekStartsOn = Number(config.weekStartsOn)
const allowedSlotMinutes = [15, 30, 60, 120, 180]
return {
startTime: normalizedStartTime,
endTime: normalizedEndTime,
slotMinutes: allowedSlotMinutes.includes(normalizedSlotMinutes) ? normalizedSlotMinutes : 180
slotMinutes: allowedSlotMinutes.includes(normalizedSlotMinutes) ? normalizedSlotMinutes : 180,
weekStartsOn: Number.isInteger(normalizedWeekStartsOn) && normalizedWeekStartsOn >= 1 && normalizedWeekStartsOn <= 5
? normalizedWeekStartsOn
: 1
}
})
@@ -295,6 +299,7 @@ const visibleDraftEventIds = computed(() =>
const calendarOptions = computed(() => ({
schedulerLicenseKey: "CC-Attribution-NonCommercial-NoDerivatives",
locale: deLocale,
firstDay: resolvedPlanningBoardConfig.value.weekStartsOn,
plugins: [resourceTimelinePlugin, interactionPlugin],
initialView: calendarView.value,
initialDate: calendarCurrentDate.value,
@@ -349,6 +354,7 @@ const calendarOptions = computed(() => ({
resourceTimelineWeek: {
type: "resourceTimeline",
duration: { days: 7 },
dateAlignment: "week",
buttonText: "Woche",
slotDuration: { minutes: resolvedPlanningBoardConfig.value.slotMinutes },
snapDuration: { minutes: resolvedPlanningBoardConfig.value.slotMinutes },

View File

@@ -130,10 +130,19 @@ const planningBoardTimeGridOptions = [
{ label: "180 Minuten", value: 180 }
]
const planningBoardWeekStartOptions = [
{ label: "Montag", value: 1 },
{ label: "Dienstag", value: 2 },
{ label: "Mittwoch", value: 3 },
{ label: "Donnerstag", value: 4 },
{ label: "Freitag", value: 5 }
]
const planningBoardConfig = reactive({
startTime: auth.activeTenantData?.calendarConfig?.planningBoard?.startTime || "06:00",
endTime: auth.activeTenantData?.calendarConfig?.planningBoard?.endTime || "21:00",
slotMinutes: auth.activeTenantData?.calendarConfig?.planningBoard?.slotMinutes || 180
slotMinutes: auth.activeTenantData?.calendarConfig?.planningBoard?.slotMinutes || 180,
weekStartsOn: auth.activeTenantData?.calendarConfig?.planningBoard?.weekStartsOn ?? 1
})
const canManageMcpTokens = computed(() => Boolean(auth.user?.is_admin || auth.hasPermission("mcp.tokens.write")))
@@ -238,6 +247,7 @@ const setupPage = async () => {
planningBoardConfig.startTime = auth.activeTenantData?.calendarConfig?.planningBoard?.startTime || "06:00"
planningBoardConfig.endTime = auth.activeTenantData?.calendarConfig?.planningBoard?.endTime || "21:00"
planningBoardConfig.slotMinutes = auth.activeTenantData?.calendarConfig?.planningBoard?.slotMinutes || 180
planningBoardConfig.weekStartsOn = auth.activeTenantData?.calendarConfig?.planningBoard?.weekStartsOn ?? 1
}
const features = ref({ ...defaultFeatures, ...(auth.activeTenantData?.features || {}) })
@@ -571,7 +581,8 @@ const savePlanningBoardConfig = async () => {
planningBoard: {
startTime: planningBoardConfig.startTime || "06:00",
endTime: planningBoardConfig.endTime || "21:00",
slotMinutes: Number(planningBoardConfig.slotMinutes) || 180
slotMinutes: Number(planningBoardConfig.slotMinutes) || 180,
weekStartsOn: Number(planningBoardConfig.weekStartsOn)
}
}
})
@@ -741,7 +752,7 @@ onMounted(() => {
<div class="space-y-4">
<div>
<h3 class="text-base font-semibold text-highlighted">Plantafel</h3>
<p class="text-sm text-muted">Lege hier die Rahmenzeiten und den Rasterabstand für die Plantafel fest.</p>
<p class="text-sm text-muted">Lege hier Rahmenzeiten, Rasterabstand und Wochenbeginn für die Plantafel fest.</p>
</div>
<UFormField
@@ -767,6 +778,17 @@ onMounted(() => {
/>
</UFormField>
<UFormField
label="Wochenbeginn:"
>
<USelectMenu
v-model="planningBoardConfig.weekStartsOn"
:items="planningBoardWeekStartOptions"
label-key="label"
value-key="value"
/>
</UFormField>
<UButton
class="mt-1"
@click="savePlanningBoardConfig"