popilot 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +204 -2
- package/lib/doctor.mjs +38 -1
- package/lib/hydrate.mjs +15 -0
- package/lib/scaffold.mjs +5 -0
- package/lib/setup-wizard.mjs +35 -2
- package/package.json +1 -1
- package/scaffold/.context/project.yaml.example +19 -0
- package/scaffold/mcp-notification-server/package.json +18 -0
- package/scaffold/mcp-notification-server/src/index.ts +275 -0
- package/scaffold/mcp-notification-server/src/turso-client.ts +142 -0
- package/scaffold/mcp-notification-server/tsconfig.json +14 -0
- package/scaffold/mcp-pm/package.json +19 -0
- package/scaffold/mcp-pm/src/api-client.ts +69 -0
- package/scaffold/mcp-pm/src/index.ts +660 -0
- package/scaffold/mcp-pm/tsconfig.json +14 -0
- package/scaffold/pm-api/package.json +21 -0
- package/scaffold/pm-api/sql/001-memo-v2.sql +49 -0
- package/scaffold/pm-api/sql/002-notifications.sql +18 -0
- package/scaffold/pm-api/sql/003-content.sql +66 -0
- package/scaffold/pm-api/sql/004-agent-events.sql +21 -0
- package/scaffold/pm-api/sql/005-epic-sprint-decoupling.sql +6 -0
- package/scaffold/pm-api/sql/schema-core.sql +331 -0
- package/scaffold/pm-api/sql/schema-docs.sql +25 -0
- package/scaffold/pm-api/sql/schema-meetings.sql +17 -0
- package/scaffold/pm-api/sql/schema-rewards.sql +16 -0
- package/scaffold/pm-api/src/auth.ts +28 -0
- package/scaffold/pm-api/src/blockchain/adapter.ts +20 -0
- package/scaffold/pm-api/src/blockchain/tron.ts +62 -0
- package/scaffold/pm-api/src/db/adapter.ts +36 -0
- package/scaffold/pm-api/src/db/turso.ts +147 -0
- package/scaffold/pm-api/src/index.ts +114 -0
- package/scaffold/pm-api/src/mcp-tools/dashboard.ts +40 -0
- package/scaffold/pm-api/src/mcp-tools/epic.ts +67 -0
- package/scaffold/pm-api/src/mcp-tools/event.ts +89 -0
- package/scaffold/pm-api/src/mcp-tools/index.ts +11 -0
- package/scaffold/pm-api/src/mcp-tools/initiative.ts +51 -0
- package/scaffold/pm-api/src/mcp-tools/memo.ts +164 -0
- package/scaffold/pm-api/src/mcp-tools/notification.ts +37 -0
- package/scaffold/pm-api/src/mcp-tools/retro.ts +183 -0
- package/scaffold/pm-api/src/mcp-tools/sprint.ts +204 -0
- package/scaffold/pm-api/src/mcp-tools/standup.ts +136 -0
- package/scaffold/pm-api/src/mcp-tools/story.ts +230 -0
- package/scaffold/pm-api/src/mcp-tools/task.ts +187 -0
- package/scaffold/pm-api/src/mcp-tools/utils.ts +83 -0
- package/scaffold/pm-api/src/mcp.ts +871 -0
- package/scaffold/pm-api/src/nudge.ts +283 -0
- package/scaffold/pm-api/src/routes/auth.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-activity.ts +27 -0
- package/scaffold/pm-api/src/routes/v2-admin.ts +165 -0
- package/scaffold/pm-api/src/routes/v2-dashboard.ts +189 -0
- package/scaffold/pm-api/src/routes/v2-docs.ts +34 -0
- package/scaffold/pm-api/src/routes/v2-initiatives.ts +118 -0
- package/scaffold/pm-api/src/routes/v2-kickoff.ts +265 -0
- package/scaffold/pm-api/src/routes/v2-meetings.ts +324 -0
- package/scaffold/pm-api/src/routes/v2-memos.ts +257 -0
- package/scaffold/pm-api/src/routes/v2-nav.ts +260 -0
- package/scaffold/pm-api/src/routes/v2-notifications.ts +79 -0
- package/scaffold/pm-api/src/routes/v2-page-content.ts +35 -0
- package/scaffold/pm-api/src/routes/v2-pm.ts +380 -0
- package/scaffold/pm-api/src/routes/v2-policy.ts +58 -0
- package/scaffold/pm-api/src/routes/v2-retro.ts +221 -0
- package/scaffold/pm-api/src/routes/v2-rewards.ts +132 -0
- package/scaffold/pm-api/src/routes/v2-scenarios.ts +48 -0
- package/scaffold/pm-api/src/routes/v2-search.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-standup.ts +127 -0
- package/scaffold/pm-api/src/routes/v2-user.ts +38 -0
- package/scaffold/pm-api/src/types.ts +11 -0
- package/scaffold/pm-api/src/utils/activity.ts +22 -0
- package/scaffold/pm-api/src/utils/admin.ts +9 -0
- package/scaffold/pm-api/src/utils/agent-notify.ts +62 -0
- package/scaffold/pm-api/src/utils/assignee.ts +69 -0
- package/scaffold/pm-api/src/utils/db.ts +45 -0
- package/scaffold/pm-api/src/utils/initiative.ts +23 -0
- package/scaffold/pm-api/src/utils/retro-link.ts +32 -0
- package/scaffold/pm-api/src/utils/sprint-lifecycle.ts +96 -0
- package/scaffold/pm-api/tsconfig.json +15 -0
- package/scaffold/pm-api/wrangler.toml.hbs +11 -0
- package/scaffold/spec-site/package-lock.json +892 -0
- package/scaffold/spec-site/package.json +15 -1
- package/scaffold/spec-site/src/api/types.ts +6 -0
- package/scaffold/spec-site/src/components/AppHeader.vue +429 -55
- package/scaffold/spec-site/src/components/AuthGate.vue +117 -0
- package/scaffold/spec-site/src/components/BurndownChart.vue +78 -0
- package/scaffold/spec-site/src/components/DocComments.vue +137 -0
- package/scaffold/spec-site/src/components/DocEditor.vue +118 -0
- package/scaffold/spec-site/src/components/DocExportBar.vue +110 -0
- package/scaffold/spec-site/src/components/DocsSidebar.vue +309 -0
- package/scaffold/spec-site/src/components/EmptyState.vue +30 -0
- package/scaffold/spec-site/src/components/ErrorBanner.vue +38 -0
- package/scaffold/spec-site/src/components/Icon.vue +58 -0
- package/scaffold/spec-site/src/components/MemberSelect.vue +48 -0
- package/scaffold/spec-site/src/components/MemoChecklist.vue +88 -0
- package/scaffold/spec-site/src/components/MemoGraph.vue +75 -0
- package/scaffold/spec-site/src/components/MemoItem.vue +353 -0
- package/scaffold/spec-site/src/components/MemoRelations.vue +101 -0
- package/scaffold/spec-site/src/components/MemoTimeline.vue +53 -0
- package/scaffold/spec-site/src/components/MentionInput.vue +174 -0
- package/scaffold/spec-site/src/components/NotificationDropdown.vue +116 -0
- package/scaffold/spec-site/src/components/PriorityBadge.vue +23 -0
- package/scaffold/spec-site/src/components/SearchModal.vue +102 -0
- package/scaffold/spec-site/src/components/SlashCommand.ts +123 -0
- package/scaffold/spec-site/src/components/StateDisplay.vue +54 -0
- package/scaffold/spec-site/src/components/TreeNode.vue +82 -0
- package/scaffold/spec-site/src/components/UserAvatar.vue +24 -0
- package/scaffold/spec-site/src/components/VelocityChart.vue +77 -0
- package/scaffold/spec-site/src/composables/navTypes.ts +3 -0
- package/scaffold/spec-site/src/composables/pmTypes.ts +15 -2
- package/scaffold/spec-site/src/composables/useBottomSheet.ts +103 -0
- package/scaffold/spec-site/src/composables/useDashboard.ts +221 -0
- package/scaffold/spec-site/src/composables/useMediaQuery.ts +28 -0
- package/scaffold/spec-site/src/composables/useMemo.ts +39 -0
- package/scaffold/spec-site/src/composables/useNotification.ts +200 -0
- package/scaffold/spec-site/src/composables/usePmStore.ts +48 -1
- package/scaffold/spec-site/src/composables/useRetro.ts +6 -0
- package/scaffold/spec-site/src/composables/useStandup.ts +201 -0
- package/scaffold/spec-site/src/composables/useTheme.ts +37 -0
- package/scaffold/spec-site/src/composables/useTurso.ts +17 -0
- package/scaffold/spec-site/src/composables/useUser.ts +19 -1
- package/scaffold/spec-site/src/composables/useViewport.ts +26 -0
- package/scaffold/spec-site/src/features.ts +108 -0
- package/scaffold/spec-site/src/mockup/ComponentPalette.vue +61 -0
- package/scaffold/spec-site/src/mockup/MockupCanvas.vue +459 -0
- package/scaffold/spec-site/src/mockup/PropertyPanel.vue +217 -0
- package/scaffold/spec-site/src/mockup/componentCatalog.ts +68 -0
- package/scaffold/spec-site/src/mockup/useScenarios.ts +67 -0
- package/scaffold/spec-site/src/pages/AdminPage.vue +299 -0
- package/scaffold/spec-site/src/pages/DashboardPage.vue +650 -0
- package/scaffold/spec-site/src/pages/DocsEditor.vue +119 -0
- package/scaffold/spec-site/src/pages/DocsHub.vue +157 -0
- package/scaffold/spec-site/src/pages/DocsPage.vue +444 -0
- package/scaffold/spec-site/src/pages/InboxPage.vue +156 -0
- package/scaffold/spec-site/src/pages/MeetingsPage.vue +294 -0
- package/scaffold/spec-site/src/pages/MemosPage.vue +857 -0
- package/scaffold/spec-site/src/pages/MockupEditorPage.vue +611 -0
- package/scaffold/spec-site/src/pages/MockupListPage.vue +121 -0
- package/scaffold/spec-site/src/pages/MockupViewerPage.vue +199 -0
- package/scaffold/spec-site/src/pages/MyPage.vue +343 -0
- package/scaffold/spec-site/src/pages/NotificationSettingsPage.vue +59 -0
- package/scaffold/spec-site/src/pages/RewardsPage.vue +266 -0
- package/scaffold/spec-site/src/pages/SprintAdmin.vue +521 -0
- package/scaffold/spec-site/src/pages/SprintTimeline.vue +159 -0
- package/scaffold/spec-site/src/pages/board/BoardAdmin.vue +422 -0
- package/scaffold/spec-site/src/pages/board/BoardEpicSection.vue +54 -0
- package/scaffold/spec-site/src/pages/board/BoardPage.vue +884 -0
- package/scaffold/spec-site/src/pages/board/BoardStoryCard.vue +67 -0
- package/scaffold/spec-site/src/pages/board/BoardTaskItem.vue +52 -0
- package/scaffold/spec-site/src/pages/board/KanbanBoard.vue +93 -0
- package/scaffold/spec-site/src/pages/board/MyTasksPage.vue +202 -0
- package/scaffold/spec-site/src/pages/board/SprintClose.vue +167 -0
- package/scaffold/spec-site/src/pages/board/SprintColumn.vue +49 -0
- package/scaffold/spec-site/src/pages/board/SprintKickoff.vue +389 -0
- package/scaffold/spec-site/src/pages/board/StatusBadge.vue +52 -0
- package/scaffold/spec-site/src/pages/board/StoryDetailPanel.vue +495 -0
- package/scaffold/spec-site/src/pages/board/TaskCard.vue +42 -0
- package/scaffold/spec-site/src/pages/retro/RetroCard.vue +36 -2
- package/scaffold/spec-site/src/pages/retro/RetroHeader.vue +82 -66
- package/scaffold/spec-site/src/pages/retro/RetroPage.vue +47 -18
- package/scaffold/spec-site/src/pages/standup/StandupEntryCard.vue +551 -0
- package/scaffold/spec-site/src/pages/standup/StandupForm.vue +68 -0
- package/scaffold/spec-site/src/pages/standup/StandupList.vue +71 -0
- package/scaffold/spec-site/src/pages/standup/StandupPage.vue +225 -0
- package/scaffold/spec-site/src/router.ts +141 -0
- package/scaffold/spec-site/src/styles/buttons.css +124 -0
- package/scaffold/spec-site/src/utils/parseMentions.ts +56 -0
- package/scaffold/spec-site/src/utils/timezone.ts +18 -0
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
3
|
import type { RetroSession, RetroPhase } from '@/composables/useRetro'
|
|
4
4
|
import { VOTES_PER_PERSON } from '@/composables/useRetro'
|
|
5
|
+
|
|
6
|
+
const AUTHOR_COLORS = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#14b8a6', '#f97316']
|
|
7
|
+
|
|
5
8
|
const props = defineProps<{
|
|
6
9
|
session: RetroSession | null
|
|
7
10
|
sprintId: string
|
|
8
|
-
currentUser: string
|
|
11
|
+
currentUser: string
|
|
9
12
|
votesRemaining: number
|
|
10
13
|
teamMembers: string[]
|
|
14
|
+
participants: string[]
|
|
15
|
+
itemCount?: number
|
|
11
16
|
}>()
|
|
12
17
|
|
|
13
18
|
const emit = defineEmits<{
|
|
14
19
|
(e: 'phase-change', phase: RetroPhase): void
|
|
15
|
-
(e: 'select-user', name: string): void
|
|
16
20
|
(e: 'reset'): void
|
|
17
21
|
(e: 'export'): void
|
|
18
22
|
}>()
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
function authorColor(name: string): string {
|
|
25
|
+
let hash = 0
|
|
26
|
+
for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash)
|
|
27
|
+
return AUTHOR_COLORS[Math.abs(hash) % AUTHOR_COLORS.length]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const participantList = computed(() =>
|
|
31
|
+
props.participants.map(name => ({
|
|
32
|
+
name,
|
|
33
|
+
initial: name.charAt(0),
|
|
34
|
+
color: authorColor(name),
|
|
35
|
+
isMe: name === props.currentUser,
|
|
36
|
+
}))
|
|
37
|
+
)
|
|
21
38
|
|
|
22
39
|
const PHASE_META: Record<RetroPhase, { label: string; next: string }> = {
|
|
23
40
|
write: { label: 'Writing', next: 'Start Voting' },
|
|
@@ -36,6 +53,11 @@ function prevPhase() {
|
|
|
36
53
|
|
|
37
54
|
function nextPhase() {
|
|
38
55
|
if (!props.session) return
|
|
56
|
+
// write -> vote: require at least 1 card
|
|
57
|
+
if (props.session.phase === 'write' && (props.itemCount ?? 0) === 0) {
|
|
58
|
+
alert('Add at least one card before starting the vote.')
|
|
59
|
+
return
|
|
60
|
+
}
|
|
39
61
|
const idx = PHASE_ORDER.indexOf(props.session.phase)
|
|
40
62
|
if (idx < PHASE_ORDER.length - 1) emit('phase-change', PHASE_ORDER[idx + 1])
|
|
41
63
|
}
|
|
@@ -44,11 +66,6 @@ function phase(): RetroPhase {
|
|
|
44
66
|
return props.session?.phase ?? 'write'
|
|
45
67
|
}
|
|
46
68
|
|
|
47
|
-
function selectMember(name: string) {
|
|
48
|
-
emit('select-user', name)
|
|
49
|
-
userOpen.value = false
|
|
50
|
-
}
|
|
51
|
-
|
|
52
69
|
const menuOpen = ref(false)
|
|
53
70
|
|
|
54
71
|
function handleReset() {
|
|
@@ -76,30 +93,33 @@ function handleExport() {
|
|
|
76
93
|
</span>
|
|
77
94
|
</div>
|
|
78
95
|
<div class="rh-right">
|
|
79
|
-
<!--
|
|
80
|
-
<div class="rh-
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
:class="{ active: m === currentUser }"
|
|
91
|
-
@click="selectMember(m)"
|
|
92
|
-
>
|
|
93
|
-
{{ m }}
|
|
94
|
-
</div>
|
|
96
|
+
<!-- Participants -->
|
|
97
|
+
<div class="rh-participants">
|
|
98
|
+
<div
|
|
99
|
+
v-for="p in participantList"
|
|
100
|
+
:key="p.name"
|
|
101
|
+
class="rh-avatar"
|
|
102
|
+
:class="{ 'rh-avatar--me': p.isMe }"
|
|
103
|
+
:style="{ background: p.color }"
|
|
104
|
+
:title="p.name + (p.isMe ? ' (me)' : '')"
|
|
105
|
+
>
|
|
106
|
+
{{ p.initial }}
|
|
95
107
|
</div>
|
|
108
|
+
<span v-if="participantList.length === 0" class="rh-no-participants">No participants yet</span>
|
|
109
|
+
<span v-else class="rh-participant-count">{{ participantList.length }} joined</span>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Current user badge -->
|
|
113
|
+
<div v-if="currentUser" class="rh-me-badge">
|
|
114
|
+
<span class="rh-me-dot" :style="{ background: authorColor(currentUser) }" />
|
|
115
|
+
{{ currentUser }}
|
|
96
116
|
</div>
|
|
97
117
|
|
|
98
118
|
<!-- Phase controls -->
|
|
99
119
|
<button v-if="phase() !== 'write'" class="rh-prev" @click="prevPhase">
|
|
100
120
|
← Prev
|
|
101
121
|
</button>
|
|
102
|
-
<button v-if="phase() !== 'done'" class="rh-next" @click="nextPhase">
|
|
122
|
+
<button v-if="phase() !== 'done'" class="rh-next" :disabled="phase() === 'write' && (itemCount ?? 0) === 0" @click="nextPhase">
|
|
103
123
|
{{ PHASE_META[phase()].next }} →
|
|
104
124
|
</button>
|
|
105
125
|
|
|
@@ -159,54 +179,51 @@ function handleExport() {
|
|
|
159
179
|
gap: 8px;
|
|
160
180
|
}
|
|
161
181
|
|
|
162
|
-
/* --
|
|
163
|
-
.rh-
|
|
164
|
-
|
|
165
|
-
.rh-user-btn {
|
|
182
|
+
/* -- Participants -- */
|
|
183
|
+
.rh-participants {
|
|
166
184
|
display: flex;
|
|
167
185
|
align-items: center;
|
|
168
186
|
gap: 4px;
|
|
169
|
-
padding: 6px 12px;
|
|
170
|
-
border: 1px solid var(--border);
|
|
171
|
-
border-radius: 6px;
|
|
172
|
-
background: #fff;
|
|
173
|
-
font-size: 13px;
|
|
174
|
-
font-weight: 500;
|
|
175
|
-
font-family: var(--font-sans);
|
|
176
|
-
cursor: pointer;
|
|
177
|
-
color: var(--text-primary);
|
|
178
|
-
transition: all 0.15s;
|
|
179
187
|
}
|
|
180
|
-
.rh-user-btn:hover { background: var(--bg); }
|
|
181
188
|
|
|
182
|
-
.rh-
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
.rh-avatar {
|
|
190
|
+
width: 26px;
|
|
191
|
+
height: 26px;
|
|
192
|
+
border-radius: 50%;
|
|
193
|
+
display: flex;
|
|
194
|
+
align-items: center;
|
|
195
|
+
justify-content: center;
|
|
196
|
+
color: #fff;
|
|
197
|
+
font-size: 11px;
|
|
198
|
+
font-weight: 700;
|
|
199
|
+
flex-shrink: 0;
|
|
200
|
+
border: 2px solid transparent;
|
|
201
|
+
transition: transform 0.15s;
|
|
185
202
|
}
|
|
203
|
+
.rh-avatar:hover { transform: scale(1.15); }
|
|
204
|
+
.rh-avatar--me { border-color: var(--primary); box-shadow: 0 0 0 1px #fff; }
|
|
186
205
|
|
|
187
|
-
.rh-
|
|
188
|
-
|
|
189
|
-
top: calc(100% + 4px);
|
|
190
|
-
right: 0;
|
|
191
|
-
min-width: 120px;
|
|
192
|
-
background: #fff;
|
|
193
|
-
border: 1px solid var(--border);
|
|
194
|
-
border-radius: 8px;
|
|
195
|
-
box-shadow: var(--shadow-md);
|
|
196
|
-
padding: 4px;
|
|
197
|
-
z-index: 100;
|
|
198
|
-
}
|
|
206
|
+
.rh-no-participants { font-size: 12px; color: var(--text-muted); }
|
|
207
|
+
.rh-participant-count { font-size: 11px; color: var(--text-muted); margin-left: 2px; }
|
|
199
208
|
|
|
200
|
-
.rh-
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
.rh-me-badge {
|
|
210
|
+
display: flex;
|
|
211
|
+
align-items: center;
|
|
212
|
+
gap: 6px;
|
|
213
|
+
padding: 4px 10px;
|
|
214
|
+
background: var(--bg);
|
|
215
|
+
border: 1px solid var(--border);
|
|
203
216
|
border-radius: 6px;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
font-size: 12px;
|
|
218
|
+
font-weight: 600;
|
|
219
|
+
color: var(--text-primary);
|
|
220
|
+
}
|
|
221
|
+
.rh-me-dot {
|
|
222
|
+
width: 8px;
|
|
223
|
+
height: 8px;
|
|
224
|
+
border-radius: 50%;
|
|
225
|
+
flex-shrink: 0;
|
|
207
226
|
}
|
|
208
|
-
.rh-user-item:hover { background: var(--bg); color: var(--text-primary); }
|
|
209
|
-
.rh-user-item.active { color: var(--primary); font-weight: 600; }
|
|
210
227
|
|
|
211
228
|
/* -- Phase buttons -- */
|
|
212
229
|
.rh-prev {
|
|
@@ -217,7 +234,6 @@ function handleExport() {
|
|
|
217
234
|
border-radius: 6px;
|
|
218
235
|
font-size: 13px;
|
|
219
236
|
font-weight: 500;
|
|
220
|
-
font-family: var(--font-sans);
|
|
221
237
|
cursor: pointer;
|
|
222
238
|
transition: all 0.15s;
|
|
223
239
|
}
|
|
@@ -231,11 +247,11 @@ function handleExport() {
|
|
|
231
247
|
border-radius: 6px;
|
|
232
248
|
font-size: 13px;
|
|
233
249
|
font-weight: 600;
|
|
234
|
-
font-family: var(--font-sans);
|
|
235
250
|
cursor: pointer;
|
|
236
251
|
transition: opacity 0.15s;
|
|
237
252
|
}
|
|
238
253
|
.rh-next:hover { opacity: 0.9; }
|
|
254
|
+
.rh-next:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
239
255
|
|
|
240
256
|
/* -- More menu -- */
|
|
241
257
|
.rh-menu-wrap { position: relative; }
|
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { onMounted,
|
|
3
|
-
import { useRoute } from 'vue-router'
|
|
2
|
+
import { onMounted, computed } from 'vue'
|
|
3
|
+
import { useRoute, useRouter } from 'vue-router'
|
|
4
4
|
import { useUser } from '@/composables/useUser'
|
|
5
5
|
import { useRetro } from '@/composables/useRetro'
|
|
6
6
|
import { getActiveSprint } from '@/composables/useNavStore'
|
|
7
|
+
import { apiPost } from '@/api/client'
|
|
7
8
|
import RetroHeader from './RetroHeader.vue'
|
|
8
9
|
import RetroBoard from './RetroBoard.vue'
|
|
9
10
|
import RetroActions from './RetroActions.vue'
|
|
10
11
|
|
|
11
12
|
const route = useRoute()
|
|
13
|
+
const router = useRouter()
|
|
12
14
|
const sprintId = (route.params.sprint as string) || getActiveSprint().id
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
async function completeAndKickoff() {
|
|
17
|
+
await apiPost(`/api/v2/retro/${sprintId}/complete`, {})
|
|
18
|
+
router.push('/kickoff/new')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { currentUser, dynamicMembers, loadMembers } = useUser()
|
|
15
22
|
const retro = useRetro(sprintId)
|
|
16
23
|
|
|
24
|
+
const userName = computed(() => currentUser.value ?? localStorage.getItem('retro-user-name') ?? '')
|
|
25
|
+
|
|
17
26
|
onMounted(async () => {
|
|
27
|
+
loadMembers()
|
|
18
28
|
await retro.loadOrCreateSession()
|
|
19
|
-
retro.startPolling(
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
watch(currentUser, (nextUser) => {
|
|
23
|
-
retro.startPolling(nextUser ?? '')
|
|
29
|
+
retro.startPolling(userName.value)
|
|
24
30
|
})
|
|
25
31
|
|
|
26
32
|
function handleExport() {
|
|
@@ -37,11 +43,12 @@ function handleExport() {
|
|
|
37
43
|
<RetroHeader
|
|
38
44
|
:session="retro.session.value"
|
|
39
45
|
:sprint-id="sprintId"
|
|
40
|
-
:current-user="
|
|
46
|
+
:current-user="userName"
|
|
41
47
|
:votes-remaining="retro.votesRemaining.value"
|
|
42
|
-
:team-members="
|
|
48
|
+
:team-members="dynamicMembers"
|
|
49
|
+
:participants="retro.participants.value"
|
|
50
|
+
:item-count="retro.items.value.length"
|
|
43
51
|
@phase-change="retro.setPhase"
|
|
44
|
-
@select-user="setUser"
|
|
45
52
|
@reset="retro.resetSession"
|
|
46
53
|
@export="handleExport"
|
|
47
54
|
/>
|
|
@@ -64,21 +71,28 @@ function handleExport() {
|
|
|
64
71
|
:problem-items="retro.problemItems.value"
|
|
65
72
|
:try-items="retro.tryItems.value"
|
|
66
73
|
:phase="retro.session.value.phase"
|
|
67
|
-
:current-user="
|
|
74
|
+
:current-user="userName"
|
|
68
75
|
:votes-remaining="retro.votesRemaining.value"
|
|
69
76
|
@add-item="retro.addItem"
|
|
70
|
-
@delete-item="(id) => retro.deleteItem(id,
|
|
71
|
-
@toggle-vote="(id, hasVoted) => retro.toggleVote(id,
|
|
77
|
+
@delete-item="(id) => retro.deleteItem(id, userName)"
|
|
78
|
+
@toggle-vote="(id, hasVoted) => retro.toggleVote(id, userName, hasVoted)"
|
|
72
79
|
/>
|
|
73
80
|
|
|
74
81
|
<div v-if="retro.session.value?.phase === 'done'" class="retro-done">
|
|
75
|
-
<div class="done-banner">
|
|
82
|
+
<div class="done-banner">
|
|
83
|
+
Retrospective completed
|
|
84
|
+
<div class="done-actions">
|
|
85
|
+
<button class="btn btn--primary" @click="completeAndKickoff">
|
|
86
|
+
Next Sprint Kickoff →
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
76
90
|
<RetroBoard
|
|
77
91
|
:keep-items="retro.keepItems.value"
|
|
78
92
|
:problem-items="retro.problemItems.value"
|
|
79
93
|
:try-items="retro.tryItems.value"
|
|
80
94
|
phase="discuss"
|
|
81
|
-
:current-user="
|
|
95
|
+
:current-user="userName"
|
|
82
96
|
:votes-remaining="0"
|
|
83
97
|
@add-item="() => {}"
|
|
84
98
|
@delete-item="() => {}"
|
|
@@ -92,7 +106,7 @@ function handleExport() {
|
|
|
92
106
|
retro.session.value?.phase === 'done'
|
|
93
107
|
"
|
|
94
108
|
:actions="retro.actions.value"
|
|
95
|
-
:team-members="
|
|
109
|
+
:team-members="dynamicMembers"
|
|
96
110
|
:readonly="retro.session.value?.phase === 'done'"
|
|
97
111
|
@add-action="retro.addAction"
|
|
98
112
|
@toggle-status="retro.toggleActionStatus"
|
|
@@ -155,7 +169,6 @@ function handleExport() {
|
|
|
155
169
|
border-radius: 6px;
|
|
156
170
|
font-size: 13px;
|
|
157
171
|
font-weight: 600;
|
|
158
|
-
font-family: var(--font-sans);
|
|
159
172
|
cursor: pointer;
|
|
160
173
|
}
|
|
161
174
|
|
|
@@ -175,4 +188,20 @@ function handleExport() {
|
|
|
175
188
|
font-size: 14px;
|
|
176
189
|
border-bottom: 1px solid var(--green-border);
|
|
177
190
|
}
|
|
191
|
+
.done-actions {
|
|
192
|
+
margin-top: 8px;
|
|
193
|
+
}
|
|
194
|
+
.btn {
|
|
195
|
+
padding: 8px 16px;
|
|
196
|
+
border: none;
|
|
197
|
+
border-radius: 6px;
|
|
198
|
+
font-size: 13px;
|
|
199
|
+
font-weight: 600;
|
|
200
|
+
cursor: pointer;
|
|
201
|
+
}
|
|
202
|
+
.btn--primary {
|
|
203
|
+
background: var(--primary);
|
|
204
|
+
color: #fff;
|
|
205
|
+
}
|
|
206
|
+
.btn--primary:hover { opacity: 0.9; }
|
|
178
207
|
</style>
|