-
{{ event.subtask.project_code }}
-
{{ event.subtask.master_task?.name || event.subtask.master_task }}
+
+
+
+
{{ event.title }}
+
+
+
+
+
+
+ {{ event.blocker.name }}
+
+
+
+ {{ event.subtask.project_code }}
+ {{ event.subtask.master_task?.name || event.subtask.master_task }}
+
+
{{ event.initials }}
-
{{ event.start.toLocaleDateString('sk-SK') }}
+
{{ event.date.toLocaleDateString('sk-SK') }}
-
+
+
+
+
-
-
-
-
{{ event.title }}
+
+
+
+
+
@@ -196,7 +209,7 @@ export default {
},
taskClicked(subtask) {
- if (subtask.nonWorking) return
+ if (subtask.type == 'non-working-hours') return
// console.log("task", task)
if (subtask.end.getTime() - subtask.start.getTime() <= 3600000) {
// console.log("ShortTask")
@@ -212,13 +225,21 @@ export default {
this.$events.emit('show-complete-task-modal', { subtask })
},
- editTask(subtask, editMode) {
- this.$events.emit('show-subtask-modal', {subtask, editMode})
+ editTask({subtask}) {
+ this.$events.emit('show-subtask-modal', {subtask})
},
- deleteTask(subtask) {
+ deleteTask({ subtask }) {
this.$events.emit('show-delete-task-modal', {subtask})
- }
+ },
+
+ editBlocker({ blocker }) {
+ this.$events.emit('show-blocker-modal', {blocker})
+ },
+
+ deleteBlocker({ blocker }) {
+ this.$events.emit('show-delete-blocker-modal', {blocker})
+ },
}
}
@@ -363,6 +384,17 @@ export default {
.custom-event-body
padding: 20px 10px
+ .event-content
+ &.blocker
+ *
+ color: #ffffff !important
+
+ .event-details .event-initials
+ border: 1px solid white
+
+ .event-footer
+ border-top: 1px solid rgba(255, 255, 255, 0.19)
+
&:has(.completed)
background: rgb(251, 251, 251) !important
border: 1px solid #cccccc !important
@@ -378,12 +410,11 @@ export default {
left: 0 !important
&:not(.vuecal__event--focus)
- &:has(.short-event)
- padding: 10px !important
-
- &:has(.micro-event)
- padding: 5px 10px !important
+ &:has(.micro-event) .custom-event-body
+ padding: 5px !important
+ &:has(.short-event) .custom-event-body:not(.micro-event)
+ padding: 10px 5px !important
.short-event
.project-code
display: none !important
@@ -420,19 +451,6 @@ export default {
.event-footer
display: none !important
- &.event-blocker
- background: #B00020 !important
-
- h3,
- .event-details *
- color: white !important
-
- .event-details .event-initials
- border: 1px solid white
-
- .event-footer
- border-top: 1px solid rgba(255, 255, 255, 0.19)
-
.project-code
margin: 0 0 20px
display: block
diff --git a/app/src/plugins/tm@dashboard/tasks/_utils/timeline.utils.ts b/app/src/plugins/tm@dashboard/tasks/_utils/timeline.utils.ts
index 8f5e220..1a31d8a 100644
--- a/app/src/plugins/tm@dashboard/tasks/_utils/timeline.utils.ts
+++ b/app/src/plugins/tm@dashboard/tasks/_utils/timeline.utils.ts
@@ -21,13 +21,17 @@ export default {
},
generateTimelineEvents(subtasks, employee, date) {
- const events = []
+ let events = []
subtasks.forEach(subtask => {
- subtask.timeblocks?.forEach((timeblock) => {
- events.push(this._composeTimelineEvent(subtask, employee, date, timeblock))
- })
- })
+ if (subtask.type == 'blocker') {
+ events = [...events, ...this._generateEventsFromBlocker(subtask, date)]
+ } else {
+ subtask.timeblocks?.forEach((timeblock) => {
+ events.push(this._composeTimelineEvent(subtask, employee, date, timeblock))
+ })
+ }
+ })
return events
},
@@ -50,30 +54,72 @@ export default {
}
},
+ _generateEventsFromBlocker(blocker, date) {
+ const start = moment(blocker.start)
+ const end = moment(blocker.end)
+
+ const dates = start == end ? [moment(start).format('YYYY-MM-DD')] : this._getDatesInRange(start, end)
+
+ const blockers = dates.map(d => {
+ const diffInDays = differenceInCalendarDays(date, new Date(d))
+ const dStart = new Date(moment(d).set({hours: start.hours(), minutes: start.minutes()}).format('YYYY-MM-DD HH:mm'))
+ const dEnd = new Date(moment(d).set({hours: end.hours(), minutes: end.minutes()}).format('YYYY-MM-DD HH:mm'))
+
+ return {
+ blocker,
+ split: this._getSplitFromDate(date, d),
+ start: addDays(dStart, diffInDays),
+ end: addDays(dEnd, diffInDays),
+ date: new Date(d),
+ type: 'blocker',
+ initials: `${blocker.employee?.name[0]}${blocker.employee?.surname[0]}`,
+ color: '#B00020',
+ draggable: false
+ }
+ })
+
+
+
+ console.log(blockers)
+
+ return blockers
+ },
+
+ _getDatesInRange(start, end) {
+ const dates = []
+
+ while (start <= end) {
+ dates.push(moment(start).format('YYYY-MM-DD'))
+ start.add(1, 'day')
+ }
+
+ return dates
+ },
+
generateTimelineNonWorkingHours(date, employee) {
- const nonWorkingHours = []
+ const events = []
for (let i = 0; i < 7; i++) {
- nonWorkingHours.push({
+ events.push({
title: "Non working hours",
start: setMinutes(setHours(date, 0), 0),
end: setMinutes(setHours(date, employee.work_start), 0),
- nonWorking: true,
+ type: 'non-working-hours',
split: i + 1,
draggable: false
})
- nonWorkingHours.push({
+ events.push({
title: "Non working hours",
start: setMinutes(setHours(date, employee.work_end), 0),
end: setMinutes(setHours(date, 23), 59),
- nonWorking: true,
+ type: 'non-working-hours',
split: i + 1,
draggable: false
})
}
- return nonWorkingHours
+ return events
},
_getSplitFromDate(date, start) {
diff --git a/app/src/plugins/tm@dashboard/tasks/tasks.vue b/app/src/plugins/tm@dashboard/tasks/tasks.vue
index 60998c5..a3a43f1 100644
--- a/app/src/plugins/tm@dashboard/tasks/tasks.vue
+++ b/app/src/plugins/tm@dashboard/tasks/tasks.vue
@@ -43,7 +43,7 @@ export default {
if (!workingHours[task.split])
workingHours[task.split] = 0
- if (task.nonWorking || task.subtask.is_finished)
+ if (task.type == 'non-working-hours' || task.subtask?.is_finished || task.blocker?.is_finished)
return
workingHours[task.split] += timelineUtils._getDifferenceInHours(task.end, task.start)
@@ -88,9 +88,17 @@ export default {
this.onFilterChanged(this.filter)
})
+ this.$events.on('on-blocker-edited', () => {
+ this.onFilterChanged(this.filter)
+ })
+
this.$events.on('on-subtask-deleted', () => {
this.onFilterChanged(this.filter)
})
+
+ this.$events.on('on-blocker-deleted', () => {
+ this.onFilterChanged(this.filter)
+ })
},
unmounted() {
@@ -110,10 +118,10 @@ export default {
const queryParameters = new URLSearchParams(urlQueryObject).toString()
try {
- const { subtasks } = await this.$axios.get_auth(`v1/subtasks?${queryParameters}`)
- this.config.scrollHour = this.filter?.employee.work_start - 1
- this.config.date = this.filter.start
- this.subtasks = subtasks
+ const { subtasks, blockers } = await this.$axios.get_auth(`v1/subtasks?${queryParameters}`)
+ this.config.scrollHour = this.filter?.employee.work_start - 1
+ this.config.date = this.filter.start
+ this.subtasks = [...subtasks, ...blockers.map(blocker => ({...blocker, type: 'blocker'}))]
} catch (error) {
console.log(error)
this.$toast.error('Nepodarilo sa nacitat data!')
diff --git a/app/src/plugins/tm@dashboard/teams/teams.vue b/app/src/plugins/tm@dashboard/teams/teams.vue
index c2b944b..fcb0811 100644
--- a/app/src/plugins/tm@dashboard/teams/teams.vue
+++ b/app/src/plugins/tm@dashboard/teams/teams.vue
@@ -57,15 +57,7 @@ export default {
timelineData() {
if (!this.subtasks)
- return
-
- // let unscheduledTime = 0
- // const tasks = [...this._generateNonWorking(), ...this._generateTasks()]
-
- // tasks.forEach(task => {
- // if (!task.nonWorking)
- // workingHours += timelineUtils._getDifferenceInHours(task.end, task.start)
- // })
+ return
return {
unscheduledTime: 333,
@@ -147,7 +139,7 @@ export default {
start: setMinutes(setHours(date, 0), 0),
end: setMinutes(setHours(date, employee.work_start), 0),
split: index + 1,
- nonWorking: true,
+ type: 'non-working-hours',
draggable: false
})
@@ -156,7 +148,7 @@ export default {
start: setMinutes(setHours(date, employee.work_end), 0),
end: setMinutes(setHours(date, 23), 59),
split: index + 1,
- nonWorking: true,
+ type: 'non-working-hours',
draggable: false
})
})
diff --git a/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue b/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue
index 5495286..4640ab6 100644
--- a/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue
+++ b/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue
@@ -27,18 +27,21 @@
>
+
+
+
{{ blocker.id ? 'UPRAVIŤ' : 'VYTVORIŤ'}}
@@ -55,6 +58,7 @@ import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
import { mapGetters } from 'vuex'
+import moment from 'moment'
export default {
mixins: [VuetifyFixFocusMixin],
@@ -71,7 +75,9 @@ export default {
v$: useVuelidate(),
errorUtils,
blocker: null,
- startEndDate: null
+ datepicker: null,
+ starts_at_time: null,
+ ends_at_time: null
}
},
@@ -92,22 +98,33 @@ export default {
start: { required },
end: { required },
employee_id: { required }
- }
+ },
+
+ starts_at_time: { required },
+ ends_at_time: { required },
+ datepicker: { required }
}
},
methods: {
async showModal({ blocker }) {
- this.visible = true
- this.blocker = null
- this.startEndDate = null
+ this.visible = true
+ this.blocker = null
+ this.datepicker = null
+ this.starts_at_time = null
+ this.ends_at_time = null
+
this.$nextTick(() => this.v$.$reset())
try {
if (blocker?.id) {
blocker = await this.$axios.get_auth_data(`v1/blockers/${blocker.id}`)
blocker.employee_id = blocker.employee.id
- this.startEndDate = [new Date(blocker.start), new Date(blocker.end)]
+
+ this.starts_at_time = moment(blocker.start).format('HH:mm')
+ this.ends_at_time = moment(blocker.end).format('HH:mm')
+ this.datepicker = new Date(blocker.start)
+
this.blocker = blocker
} else {
this.blocker = {start: null}
@@ -122,14 +139,18 @@ export default {
return
try {
- if (this.blocker.id)
- await this.$axios.put_auth(`v1/blockers/${this.blocker.id}`, this.blocker)
- else
- await this.$axios.post_auth('v1/blockers', this.blocker)
+ if (this.blocker.id) {
+ const { blocker } = await this.$axios.put_auth(`v1/blockers/${this.blocker.id}`, this.blocker)
+ this.blocker = blocker
+ } else {
+ const { blocker } = await this.$axios.post_auth('v1/blockers', this.blocker)
+ this.blocker = blocker
+ }
+ this.$events.emit("on-blocker-edited", this.blocker)
this.closeModal()
} catch (error) {
- this.$toast(error)
+ this.$toast.error(error)
}
},
@@ -137,23 +158,31 @@ export default {
this.$refs['datepicker'].clearValue()
this.visible = false
this.$emit('close', this.blocker)
+ },
+
+ _syncDatesTimes() {
+ if (!this.starts_at_time || !this.ends_at_time || !this.datepicker)
+ return
+
+ const splittedStart = this.starts_at_time.split(':')
+ const splittedEnd = this.ends_at_time.split(':')
+
+ this.blocker.start = moment(this.datepicker).set({hours: parseInt(splittedStart[0]), minutes: parseInt(splittedStart[1])}).format('YYYY-MM-DD HH:mm')
+ this.blocker.end = moment(this.datepicker).set({hours: parseInt(splittedEnd[0]), minutes: parseInt(splittedEnd[1])}).format('YYYY-MM-DD HH:mm')
}
},
watch: {
- startEndDate(value) {
- if (!value || !value[1])
- return
+ ends_at_time() {
+ this._syncDatesTimes()
+ },
- this.startEndDate[0] = this.startEndDate[0].setHours(this.user.work_start, 0, 0, 0)
- this.startEndDate[1] = this.startEndDate[1].setHours(this.user.work_end, 0, 0, 0)
+ starts_at_time() {
+ this._syncDatesTimes()
+ },
-
- this.blocker = {
- ...this.blocker,
- start: tmUtils.formatDateTimeForBackend(this.startEndDate[0]),
- end: tmUtils.formatDateTimeForBackend(this.startEndDate[1]),
- }
+ datepicker() {
+ this._syncDatesTimes()
}
}
}
diff --git a/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue b/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue
new file mode 100644
index 0000000..18a6e02
--- /dev/null
+++ b/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
Ste si istý, že chcete zmazať {{ blocker.name }}?
+
+
+
+
+ ÁNO
+ ZRUŠIŤ
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/plugins/tm@modal/task/z-task-modal.vue b/app/src/plugins/tm@modal/task/z-task-modal.vue
index 4e0093b..095e444 100644
--- a/app/src/plugins/tm@modal/task/z-task-modal.vue
+++ b/app/src/plugins/tm@modal/task/z-task-modal.vue
@@ -3,7 +3,7 @@
@@ -28,7 +28,11 @@
-
{{ subtask.project_code }}
+
+
{{ subtask.master_task?.project_code }}
+
{{ subtask.master_task?.name }}
+
+