feat(plan): Start planning button on project view
This commit is contained in:
@@ -3,6 +3,7 @@ import { ref, computed, onMounted, watch } from "vue";
|
|||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { apiGet, apiPatch, apiDelete, apiPost } from "@/api/client";
|
import { apiGet, apiPatch, apiDelete, apiPost } from "@/api/client";
|
||||||
import { useToastStore } from "@/stores/toast";
|
import { useToastStore } from "@/stores/toast";
|
||||||
|
import { useTasksStore } from "@/stores/tasks";
|
||||||
import { relativeTime } from "@/composables/useRelativeTime";
|
import { relativeTime } from "@/composables/useRelativeTime";
|
||||||
import ShareDialog from "@/components/ShareDialog.vue";
|
import ShareDialog from "@/components/ShareDialog.vue";
|
||||||
import ProjectRulesTab from "@/components/rules/ProjectRulesTab.vue";
|
import ProjectRulesTab from "@/components/rules/ProjectRulesTab.vue";
|
||||||
@@ -62,9 +63,28 @@ interface NoteItem {
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToastStore();
|
const toast = useToastStore();
|
||||||
|
const tasksStore = useTasksStore();
|
||||||
|
|
||||||
const project = ref<Project | null>(null);
|
const project = ref<Project | null>(null);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const showStartPlanning = ref(false);
|
||||||
|
const planTitle = ref("");
|
||||||
|
const planningBusy = ref(false);
|
||||||
|
|
||||||
|
async function confirmStartPlanning() {
|
||||||
|
const title = planTitle.value.trim();
|
||||||
|
if (!title || !project.value) return;
|
||||||
|
planningBusy.value = true;
|
||||||
|
try {
|
||||||
|
const result = await tasksStore.startPlanning(project.value.id, title);
|
||||||
|
planTitle.value = "";
|
||||||
|
showStartPlanning.value = false;
|
||||||
|
router.push(`/tasks/${result.task.id}`);
|
||||||
|
} finally {
|
||||||
|
planningBusy.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
const saving = ref(false);
|
const saving = ref(false);
|
||||||
const error = ref<string | null>(null);
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
@@ -340,12 +360,35 @@ async function confirmDelete() {
|
|||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<router-link to="/projects" class="btn-back">← Projects</router-link>
|
<router-link to="/projects" class="btn-back">← Projects</router-link>
|
||||||
<div class="page-header-actions">
|
<div class="page-header-actions">
|
||||||
<router-link v-if="project" :to="`/workspace/${project.id}`" class="btn-workspace">
|
<template v-if="showStartPlanning">
|
||||||
|
<input
|
||||||
|
v-model="planTitle"
|
||||||
|
class="plan-title-input"
|
||||||
|
placeholder="Plan title…"
|
||||||
|
@keyup.enter="confirmStartPlanning"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="btn-workspace"
|
||||||
|
:disabled="!planTitle.trim() || planningBusy"
|
||||||
|
@click="confirmStartPlanning"
|
||||||
|
>
|
||||||
|
Create plan
|
||||||
|
</button>
|
||||||
|
<button class="btn-share" @click="showStartPlanning = false; planTitle = ''">Cancel</button>
|
||||||
|
</template>
|
||||||
|
<button
|
||||||
|
v-else-if="project"
|
||||||
|
class="btn-workspace"
|
||||||
|
@click="showStartPlanning = true"
|
||||||
|
>
|
||||||
|
Start planning
|
||||||
|
</button>
|
||||||
|
<router-link v-if="project && !showStartPlanning" :to="`/workspace/${project.id}`" class="btn-workspace">
|
||||||
<LayoutGrid :size="16" />
|
<LayoutGrid :size="16" />
|
||||||
Workspace
|
Workspace
|
||||||
</router-link>
|
</router-link>
|
||||||
<button v-if="project" class="btn-share" @click="showShare = true">Share</button>
|
<button v-if="project && !showStartPlanning" class="btn-share" @click="showShare = true">Share</button>
|
||||||
<button v-if="project" class="btn-danger-outline" @click="showDeleteConfirm = true">Delete</button>
|
<button v-if="project && !showStartPlanning" class="btn-danger-outline" @click="showDeleteConfirm = true">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -685,6 +728,15 @@ async function confirmDelete() {
|
|||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
.page-header-actions { display: flex; gap: 0.5rem; align-items: center; }
|
.page-header-actions { display: flex; gap: 0.5rem; align-items: center; }
|
||||||
|
.plan-title-input {
|
||||||
|
background: var(--color-bg, #111113);
|
||||||
|
color: inherit;
|
||||||
|
border: 1px solid var(--color-border, #2a2a2e);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0.4rem 0.6rem;
|
||||||
|
font: inherit;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-back {
|
.btn-back {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|||||||
Reference in New Issue
Block a user