feat: allow creating a new project directly as a child project from another one
This commit is contained in:
parent
9c3259c660
commit
b34118485c
@ -42,7 +42,12 @@
|
|||||||
>
|
>
|
||||||
<icon :icon="project.isFavorite ? 'star' : ['far', 'star']"/>
|
<icon :icon="project.isFavorite ? 'star' : ['far', 'star']"/>
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
<ProjectSettingsDropdown class="menu-list-dropdown" :project="project" v-if="project.id > 0">
|
<ProjectSettingsDropdown
|
||||||
|
v-if="project.id > 0"
|
||||||
|
class="menu-list-dropdown"
|
||||||
|
:project="project"
|
||||||
|
:level="level"
|
||||||
|
>
|
||||||
<template #trigger="{toggleOpen}">
|
<template #trigger="{toggleOpen}">
|
||||||
<BaseButton class="menu-list-dropdown-trigger" @click="toggleOpen">
|
<BaseButton class="menu-list-dropdown-trigger" @click="toggleOpen">
|
||||||
<icon icon="ellipsis-h" class="icon"/>
|
<icon icon="ellipsis-h" class="icon"/>
|
||||||
@ -73,6 +78,7 @@ import ProjectSettingsDropdown from '@/components/project/project-settings-dropd
|
|||||||
import {getProjectTitle} from '@/helpers/getProjectTitle'
|
import {getProjectTitle} from '@/helpers/getProjectTitle'
|
||||||
import ColorBubble from '@/components/misc/colorBubble.vue'
|
import ColorBubble from '@/components/misc/colorBubble.vue'
|
||||||
import ProjectsNavigation from '@/components/home/ProjectsNavigation.vue'
|
import ProjectsNavigation from '@/components/home/ProjectsNavigation.vue'
|
||||||
|
import {canNestProjectDeeper} from '@/helpers/canNestProjectDeeper'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
project: IProject,
|
project: IProject,
|
||||||
@ -98,13 +104,7 @@ const childProjects = computed(() => {
|
|||||||
.sort((a, b) => a.position - b.position)
|
.sort((a, b) => a.position - b.position)
|
||||||
})
|
})
|
||||||
|
|
||||||
const canNestDeeper = computed(() => {
|
const canNestDeeper = computed(() => canNestProjectDeeper(props.level))
|
||||||
if (props.level < 2) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return props.level >= 2 && window.PROJECT_INFINITE_NESTING_ENABLED
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -72,6 +72,13 @@
|
|||||||
@update:model-value="setSubscriptionInStore"
|
@update:model-value="setSubscriptionInStore"
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
/>
|
/>
|
||||||
|
<dropdown-item
|
||||||
|
v-if="level < 2"
|
||||||
|
:to="{ name: 'project.createFromParent', params: { parentProjectId: project.id } }"
|
||||||
|
icon="layer-group"
|
||||||
|
>
|
||||||
|
{{ $t('menu.createProject') }}
|
||||||
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'project.settings.delete', params: { projectId: project.id } }"
|
:to="{ name: 'project.settings.delete', params: { projectId: project.id } }"
|
||||||
icon="trash-alt"
|
icon="trash-alt"
|
||||||
@ -102,6 +109,9 @@ const props = defineProps({
|
|||||||
type: Object as PropType<IProject>,
|
type: Object as PropType<IProject>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
level: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const projectStore = useProjectStore()
|
const projectStore = useProjectStore()
|
||||||
|
7
src/helpers/canNestProjectDeeper.ts
Normal file
7
src/helpers/canNestProjectDeeper.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export function canNestProjectDeeper(level: number) {
|
||||||
|
if (level < 2) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return level >= 2 && window.PROJECT_INFINITE_NESTING_ENABLED
|
||||||
|
}
|
@ -864,7 +864,8 @@
|
|||||||
"unarchive": "Un-Archive",
|
"unarchive": "Un-Archive",
|
||||||
"setBackground": "Set background",
|
"setBackground": "Set background",
|
||||||
"share": "Share",
|
"share": "Share",
|
||||||
"newProject": "New project"
|
"newProject": "New project",
|
||||||
|
"createProject": "Create project"
|
||||||
},
|
},
|
||||||
"apiConfig": {
|
"apiConfig": {
|
||||||
"url": "Vikunja URL",
|
"url": "Vikunja URL",
|
||||||
|
@ -237,6 +237,15 @@ const router = createRouter({
|
|||||||
showAsModal: true,
|
showAsModal: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/projects/:parentProjectId/new',
|
||||||
|
name: 'project.createFromParent',
|
||||||
|
component: NewProjectComponent,
|
||||||
|
props: route => ({ parentProjectId: Number(route.params.parentProjectId as string) }),
|
||||||
|
meta: {
|
||||||
|
showAsModal: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/projects/:projectId/settings/edit',
|
path: '/projects/:projectId/settings/edit',
|
||||||
name: 'project.settings.edit',
|
name: 'project.settings.edit',
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<create-edit :title="$t('project.create.header')" @create="createNewProject()" :primary-disabled="project.title === ''">
|
<create-edit
|
||||||
|
:title="$t('project.create.header')"
|
||||||
|
@create="createNewProject()"
|
||||||
|
:primary-disabled="project.title === ''"
|
||||||
|
>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="projectTitle">{{ $t('project.title') }}</label>
|
<label class="label" for="projectTitle">{{ $t('project.title') }}</label>
|
||||||
<div
|
<div
|
||||||
@ -31,14 +35,14 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('project.color') }}</label>
|
<label class="label">{{ $t('project.color') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<color-picker v-model="project.hexColor" />
|
<color-picker v-model="project.hexColor"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</create-edit>
|
</create-edit>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, reactive, shallowReactive} from 'vue'
|
import {ref, reactive, shallowReactive, watch} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import {useRouter, useRoute} from 'vue-router'
|
import {useRouter, useRoute} from 'vue-router'
|
||||||
|
|
||||||
@ -65,18 +69,28 @@ const projectService = shallowReactive(new ProjectService())
|
|||||||
const projectStore = useProjectStore()
|
const projectStore = useProjectStore()
|
||||||
const parentProject = ref<IProject | null>(null)
|
const parentProject = ref<IProject | null>(null)
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
parentProjectId?: number,
|
||||||
|
}>()
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.parentProjectId,
|
||||||
|
() => parentProject.value = projectStore.projects[props.parentProjectId],
|
||||||
|
{immediate: true},
|
||||||
|
)
|
||||||
|
|
||||||
async function createNewProject() {
|
async function createNewProject() {
|
||||||
if (project.title === '') {
|
if (project.title === '') {
|
||||||
showError.value = true
|
showError.value = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
showError.value = false
|
showError.value = false
|
||||||
|
|
||||||
if (parentProject.value) {
|
if (parentProject.value) {
|
||||||
project.parentProjectId = parentProject.value.id
|
project.parentProjectId = parentProject.value.id
|
||||||
}
|
}
|
||||||
|
|
||||||
await projectStore.createProject(project)
|
await projectStore.createProject(project)
|
||||||
success({message: t('project.create.createdSuccess') })
|
success({message: t('project.create.createdSuccess')})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
Loading…
x
Reference in New Issue
Block a user