2018-09-08 21:33:23 +00:00
|
|
|
<template>
|
2020-05-31 19:17:10 +00:00
|
|
|
<div
|
2022-11-13 21:04:57 +00:00
|
|
|
:class="{ 'is-loading': projectService.loading, 'is-archived': currentProject.isArchived}"
|
2020-09-05 20:35:52 +00:00
|
|
|
class="loader-container"
|
2020-05-31 19:17:10 +00:00
|
|
|
>
|
2021-01-18 21:14:10 +00:00
|
|
|
<div class="switch-view-container">
|
|
|
|
<div class="switch-view">
|
2022-11-12 10:46:00 +00:00
|
|
|
<BaseButton
|
2021-11-13 20:28:29 +00:00
|
|
|
v-shortcut="'g l'"
|
2022-11-13 21:04:57 +00:00
|
|
|
:title="$t('keyboardShortcuts.project.switchToProjectView')"
|
2022-11-12 10:46:00 +00:00
|
|
|
class="switch-view-button"
|
2022-11-13 21:04:57 +00:00
|
|
|
:class="{'is-active': viewName === 'project'}"
|
|
|
|
:to="{ name: 'project.list', params: { projectId } }"
|
2022-11-12 10:46:00 +00:00
|
|
|
>
|
2022-11-13 21:04:57 +00:00
|
|
|
{{ $t('project.list.title') }}
|
2022-11-12 10:46:00 +00:00
|
|
|
</BaseButton>
|
|
|
|
<BaseButton
|
2021-11-13 20:28:29 +00:00
|
|
|
v-shortcut="'g g'"
|
2022-11-13 21:04:57 +00:00
|
|
|
:title="$t('keyboardShortcuts.project.switchToGanttView')"
|
2022-11-12 10:46:00 +00:00
|
|
|
class="switch-view-button"
|
2021-12-10 14:29:28 +00:00
|
|
|
:class="{'is-active': viewName === 'gantt'}"
|
2022-11-13 21:04:57 +00:00
|
|
|
:to="{ name: 'project.gantt', params: { projectId } }"
|
2022-11-12 10:46:00 +00:00
|
|
|
>
|
2022-11-13 21:04:57 +00:00
|
|
|
{{ $t('project.gantt.title') }}
|
2022-11-12 10:46:00 +00:00
|
|
|
</BaseButton>
|
|
|
|
<BaseButton
|
2021-11-13 20:28:29 +00:00
|
|
|
v-shortcut="'g t'"
|
2022-11-13 21:04:57 +00:00
|
|
|
:title="$t('keyboardShortcuts.project.switchToTableView')"
|
2022-11-12 10:46:00 +00:00
|
|
|
class="switch-view-button"
|
2021-12-10 14:29:28 +00:00
|
|
|
:class="{'is-active': viewName === 'table'}"
|
2022-11-13 21:04:57 +00:00
|
|
|
:to="{ name: 'project.table', params: { projectId } }"
|
2022-11-12 10:46:00 +00:00
|
|
|
>
|
2022-11-13 21:04:57 +00:00
|
|
|
{{ $t('project.table.title') }}
|
2022-11-12 10:46:00 +00:00
|
|
|
</BaseButton>
|
|
|
|
<BaseButton
|
2021-11-13 20:28:29 +00:00
|
|
|
v-shortcut="'g k'"
|
2022-11-13 21:04:57 +00:00
|
|
|
:title="$t('keyboardShortcuts.project.switchToKanbanView')"
|
2022-11-12 10:46:00 +00:00
|
|
|
class="switch-view-button"
|
2021-12-10 14:29:28 +00:00
|
|
|
:class="{'is-active': viewName === 'kanban'}"
|
2022-11-13 21:04:57 +00:00
|
|
|
:to="{ name: 'project.kanban', params: { projectId } }"
|
2022-11-12 10:46:00 +00:00
|
|
|
>
|
2022-11-13 21:04:57 +00:00
|
|
|
{{ $t('project.kanban.title') }}
|
2022-11-12 10:46:00 +00:00
|
|
|
</BaseButton>
|
2021-01-18 21:14:10 +00:00
|
|
|
</div>
|
2021-11-14 20:33:53 +00:00
|
|
|
<slot name="header" />
|
2020-05-31 19:17:10 +00:00
|
|
|
</div>
|
2022-11-13 21:04:57 +00:00
|
|
|
<transition name="fade">
|
|
|
|
<Message variant="warning" v-if="currentProject.isArchived" class="mb-4">
|
|
|
|
{{ $t('project.archived') }}
|
2021-11-01 17:19:59 +00:00
|
|
|
</Message>
|
2022-11-13 21:04:57 +00:00
|
|
|
</transition>
|
2019-04-29 21:41:39 +00:00
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
<slot v-if="loadedProjectId"/>
|
2018-09-08 21:33:23 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
2021-12-10 14:29:28 +00:00
|
|
|
<script setup lang="ts">
|
2022-04-18 17:32:21 +00:00
|
|
|
import {ref, computed, watch} from 'vue'
|
2021-11-14 20:33:53 +00:00
|
|
|
import {useRoute} from 'vue-router'
|
2021-11-01 17:19:59 +00:00
|
|
|
|
2022-11-12 10:46:00 +00:00
|
|
|
import BaseButton from '@/components/base/BaseButton.vue'
|
2021-12-10 14:29:28 +00:00
|
|
|
import Message from '@/components/misc/message.vue'
|
2021-11-01 17:19:59 +00:00
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
import ProjectModel from '@/models/project'
|
|
|
|
import ProjectService from '@/services/project'
|
2021-11-01 17:19:59 +00:00
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
import {getProjectTitle} from '@/helpers/getProjectTitle'
|
|
|
|
import {saveProjectToHistory} from '@/modules/projectHistory'
|
2022-03-27 19:56:56 +00:00
|
|
|
import {useTitle} from '@/composables/useTitle'
|
2022-09-24 13:20:40 +00:00
|
|
|
|
|
|
|
import {useBaseStore} from '@/stores/base'
|
2022-11-13 21:04:57 +00:00
|
|
|
import {useProjectStore} from '@/stores/projects'
|
2021-11-01 17:19:59 +00:00
|
|
|
|
2021-12-10 14:29:28 +00:00
|
|
|
const props = defineProps({
|
2022-11-13 21:04:57 +00:00
|
|
|
projectId: {
|
2021-12-10 14:29:28 +00:00
|
|
|
type: Number,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
viewName: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2021-11-01 17:19:59 +00:00
|
|
|
const route = useRoute()
|
|
|
|
|
2022-09-24 13:20:40 +00:00
|
|
|
const baseStore = useBaseStore()
|
2022-11-13 21:04:57 +00:00
|
|
|
const projectStore = useProjectStore()
|
|
|
|
const projectService = ref(new ProjectService())
|
|
|
|
const loadedProjectId = ref(0)
|
2021-11-01 17:19:59 +00:00
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
const currentProject = computed(() => {
|
|
|
|
return typeof baseStore.currentProject === 'undefined' ? {
|
2021-11-01 17:19:59 +00:00
|
|
|
id: 0,
|
|
|
|
title: '',
|
|
|
|
isArchived: false,
|
2022-01-30 15:47:23 +00:00
|
|
|
maxRight: null,
|
2022-11-13 21:04:57 +00:00
|
|
|
} : baseStore.currentProject
|
2021-11-01 17:19:59 +00:00
|
|
|
})
|
2022-11-13 21:04:57 +00:00
|
|
|
useTitle(() => currentProject.value.id ? getProjectTitle(currentProject.value) : '')
|
2021-11-01 17:19:59 +00:00
|
|
|
|
2022-02-27 13:22:54 +00:00
|
|
|
// watchEffect would be called every time the prop would get a value assigned, even if that value was the same as before.
|
2022-11-13 21:04:57 +00:00
|
|
|
// This resulted in loading and setting the project multiple times, even when navigating away from it.
|
|
|
|
// This caused wired bugs where the project background would be set on the home page but only right after setting a new
|
|
|
|
// project background and then navigating to home. It also highlighted the project in the menu and didn't allow changing any
|
2022-02-27 13:22:54 +00:00
|
|
|
// of it, most likely due to the rights not being properly populated.
|
|
|
|
watch(
|
2022-11-13 21:04:57 +00:00
|
|
|
() => props.projectId,
|
|
|
|
// loadProject
|
|
|
|
async (projectIdToLoad: number) => {
|
|
|
|
const projectData = {id: projectIdToLoad}
|
|
|
|
saveProjectToHistory(projectData)
|
|
|
|
|
|
|
|
// Don't load the project if we either already loaded it or aren't dealing with a project at all currently and
|
|
|
|
// the currently loaded project has the right set.
|
2022-10-17 14:11:57 +00:00
|
|
|
if (
|
|
|
|
(
|
2022-11-13 21:04:57 +00:00
|
|
|
projectIdToLoad === loadedProjectId.value ||
|
|
|
|
typeof projectIdToLoad === 'undefined' ||
|
|
|
|
projectIdToLoad === currentProject.value.id
|
2022-10-17 14:11:57 +00:00
|
|
|
)
|
2022-11-13 21:04:57 +00:00
|
|
|
&& typeof currentProject.value !== 'undefined' && currentProject.value.maxRight !== null
|
2022-10-17 14:11:57 +00:00
|
|
|
) {
|
2022-11-13 21:04:57 +00:00
|
|
|
loadedProjectId.value = props.projectId
|
2022-10-17 14:11:57 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
console.debug(`Loading project, props.viewName = ${props.viewName}, $route.params =`, route.params, `, loadedProjectId = ${loadedProjectId.value}, currentProject = `, currentProject.value)
|
2022-10-17 14:11:57 +00:00
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
// Set the current project to the one we're about to load so that the title is already shown at the top
|
|
|
|
loadedProjectId.value = 0
|
|
|
|
const projectFromStore = projectStore.getProjectById(projectData.id)
|
|
|
|
if (projectFromStore !== null) {
|
2022-10-17 14:11:57 +00:00
|
|
|
baseStore.setBackground(null)
|
|
|
|
baseStore.setBlurHash(null)
|
2022-11-13 21:04:57 +00:00
|
|
|
baseStore.handleSetCurrentProject({project: projectFromStore})
|
2022-10-17 14:11:57 +00:00
|
|
|
}
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
// We create an extra project object instead of creating it in project.value because that would trigger a ui update which would result in bad ux.
|
|
|
|
const project = new ProjectModel(projectData)
|
2022-10-17 14:11:57 +00:00
|
|
|
try {
|
2022-11-13 21:04:57 +00:00
|
|
|
const loadedProject = await projectService.value.get(project)
|
|
|
|
baseStore.handleSetCurrentProject({project: loadedProject})
|
2022-10-17 14:11:57 +00:00
|
|
|
} finally {
|
2022-11-13 21:04:57 +00:00
|
|
|
loadedProjectId.value = props.projectId
|
2022-10-17 14:11:57 +00:00
|
|
|
}
|
|
|
|
},
|
2022-04-18 17:32:21 +00:00
|
|
|
{immediate: true},
|
2022-02-27 13:22:54 +00:00
|
|
|
)
|
2021-07-09 08:22:20 +00:00
|
|
|
</script>
|
2021-10-18 12:21:02 +00:00
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2021-10-18 12:21:53 +00:00
|
|
|
.switch-view-container {
|
|
|
|
@media screen and (max-width: $tablet) {
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
2022-02-27 15:36:20 +00:00
|
|
|
flex-direction: column;
|
2021-10-18 12:21:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.switch-view {
|
2021-11-22 21:12:54 +00:00
|
|
|
background: var(--white);
|
2021-10-18 12:21:53 +00:00
|
|
|
display: inline-flex;
|
|
|
|
border-radius: $radius;
|
|
|
|
font-size: .75rem;
|
2021-11-22 21:12:54 +00:00
|
|
|
box-shadow: var(--shadow-sm);
|
2021-10-18 12:21:53 +00:00
|
|
|
height: $switch-view-height;
|
2022-02-27 15:36:20 +00:00
|
|
|
margin: 0 auto 1rem;
|
2021-10-18 12:21:53 +00:00
|
|
|
padding: .5rem;
|
2022-11-12 10:46:00 +00:00
|
|
|
}
|
2021-10-18 12:21:53 +00:00
|
|
|
|
2022-11-12 10:46:00 +00:00
|
|
|
.switch-view-button {
|
|
|
|
padding: .25rem .5rem;
|
|
|
|
display: block;
|
|
|
|
border-radius: $radius;
|
|
|
|
transition: all 100ms;
|
|
|
|
|
|
|
|
&:not(:last-child) {
|
|
|
|
margin-right: .5rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
color: var(--switch-view-color);
|
|
|
|
background: var(--primary);
|
|
|
|
}
|
|
|
|
|
|
|
|
&.is-active {
|
|
|
|
color: var(--switch-view-color);
|
|
|
|
background: var(--primary);
|
|
|
|
font-weight: bold;
|
|
|
|
box-shadow: var(--shadow-xs);
|
|
|
|
}
|
2021-10-18 12:21:53 +00:00
|
|
|
}
|
|
|
|
|
2022-11-12 10:46:00 +00:00
|
|
|
// FIXME: this should be in notification and set via a prop
|
2021-10-18 12:21:02 +00:00
|
|
|
.is-archived .notification.is-warning {
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
}
|
|
|
|
</style>
|