dsh-taskboard 0.5.5 → 0.6.1
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/README.md +26 -2
- package/lib/client.js +2663 -767
- package/lib/host/execution.js +3 -0
- package/lib/host/execution.js.map +1 -1
- package/lib/host/routes.js +31 -1
- package/lib/host/routes.js.map +1 -1
- package/lib/host/session-sync.js +210 -10
- package/lib/host/session-sync.js.map +1 -1
- package/lib/host/store.js +9 -2
- package/lib/host/store.js.map +1 -1
- package/lib/index.js +100 -1
- package/lib/index.js.map +1 -1
- package/lib/shared/api.js.map +1 -1
- package/lib/shared/protocol.js +19 -1
- package/lib/shared/protocol.js.map +1 -1
- package/package.json +75 -75
- package/src/client/api.ts +8 -0
- package/src/client/board/AlertModal.tsx +3 -1
- package/src/client/board/ImportModal.tsx +26 -24
- package/src/client/board/SettingsModal.tsx +66 -26
- package/src/client/board/SlashPromptInput.tsx +340 -0
- package/src/client/board/TaskBoard.tsx +53 -49
- package/src/client/board/TaskCard.tsx +33 -21
- package/src/client/board/TaskDetail.tsx +169 -104
- package/src/client/board/TaskFormModal.tsx +254 -202
- package/src/client/board/TemplateManager.tsx +32 -29
- package/src/client/board/labels.ts +36 -27
- package/src/client/controller.ts +62 -2
- package/src/client/i18n/en.ts +455 -0
- package/src/client/i18n/runtime.ts +155 -0
- package/src/client/i18n/zh.ts +460 -0
- package/src/client/index.ts +182 -42
- package/src/client/sidebar-entry.ts +13 -3
- package/src/client/styles.ts +133 -0
- package/src/host/execution.ts +13 -0
- package/src/host/routes.ts +49 -1
- package/src/host/session-sync.ts +334 -14
- package/src/host/store.ts +15 -1
- package/src/index.ts +115 -1
- package/src/shared/api.ts +47 -0
- package/src/shared/protocol.ts +41 -0
- package/src/shared/version.ts +1 -1
|
@@ -15,7 +15,8 @@ import { useState } from 'react'
|
|
|
15
15
|
import type { BoardController } from '../controller.ts'
|
|
16
16
|
import type { TaskRecord } from '../../shared/protocol.ts'
|
|
17
17
|
import { fmtTime, isStaleClaim } from './format.ts'
|
|
18
|
-
import {
|
|
18
|
+
import { OUTCOME_KEYS, URGENCY_KEYS } from './labels.ts'
|
|
19
|
+
import { useT } from '../i18n/runtime.ts'
|
|
19
20
|
|
|
20
21
|
/** dataTransfer type carrying the dragged task id. */
|
|
21
22
|
export const DRAG_TYPE = 'application/x-dsh-atb-task'
|
|
@@ -35,6 +36,7 @@ function shortId(id: string | undefined): string {
|
|
|
35
36
|
* @param onAlert - show an alert message (replaces native alert).
|
|
36
37
|
*/
|
|
37
38
|
export function TaskCard({ task, controller, draggable = false, now, onAlert }: { task: TaskRecord; controller: BoardController; draggable?: boolean; now?: number; onAlert?: (msg: string) => void }) {
|
|
39
|
+
const t = useT()
|
|
38
40
|
const [rejectOpen, setRejectOpen] = useState(false)
|
|
39
41
|
const [note, setNote] = useState('')
|
|
40
42
|
const last = task.executions.length > 0 ? task.executions[task.executions.length - 1] : undefined
|
|
@@ -63,7 +65,7 @@ export function TaskCard({ task, controller, draggable = false, now, onAlert }:
|
|
|
63
65
|
// Block drag if a session is still executing this task
|
|
64
66
|
if (running !== undefined) {
|
|
65
67
|
e.preventDefault()
|
|
66
|
-
const msg =
|
|
68
|
+
const msg = t('card.drag.running', { title: task.title })
|
|
67
69
|
if (onAlert !== undefined) onAlert(msg)
|
|
68
70
|
else alert(msg)
|
|
69
71
|
return
|
|
@@ -85,53 +87,63 @@ export function TaskCard({ task, controller, draggable = false, now, onAlert }:
|
|
|
85
87
|
>
|
|
86
88
|
<div className="dsh-atb-card-title">{task.title}</div>
|
|
87
89
|
<div className="dsh-atb-card-meta">
|
|
88
|
-
<span className="dsh-atb-badge">{
|
|
89
|
-
{task.blocked && <span className="dsh-atb-badge" data-kind="blocked"
|
|
90
|
-
{stale && <span className="dsh-atb-badge" data-kind="stale"
|
|
90
|
+
<span className="dsh-atb-badge">{t(URGENCY_KEYS[task.urgency])}</span>
|
|
91
|
+
{task.blocked && <span className="dsh-atb-badge" data-kind="blocked">{t('shared.blocked')}</span>}
|
|
92
|
+
{stale && <span className="dsh-atb-badge" data-kind="stale">{t('card.badge.stale')}</span>}
|
|
91
93
|
{task.execution.mode === 'scheduled' && (
|
|
92
94
|
<span className="dsh-atb-badge" data-kind="scheduled">⏰ {fmtTime(task.execution.nextRunAt)}</span>
|
|
93
95
|
)}
|
|
94
96
|
{task.model !== undefined && (
|
|
95
97
|
<span
|
|
96
98
|
className="dsh-atb-badge"
|
|
97
|
-
title={
|
|
99
|
+
title={t('card.badge.modelTitle', { model: task.model.provider + '/' + task.model.model }) + (task.model.reasoningEffort !== undefined ? t('card.badge.modelEffort', { effort: task.model.reasoningEffort }) : '')}
|
|
98
100
|
>
|
|
99
101
|
{task.model.model}{task.model.reasoningEffort !== undefined ? ` (${task.model.reasoningEffort})` : ''}
|
|
100
102
|
</span>
|
|
101
103
|
)}
|
|
104
|
+
{task.permission === 'read-only' && (
|
|
105
|
+
<span className="dsh-atb-badge" data-kind="blocked" title={t('card.badge.permReadOnlyTitle')}>
|
|
106
|
+
{t('card.badge.permReadOnly')}
|
|
107
|
+
</span>
|
|
108
|
+
)}
|
|
109
|
+
{task.permission === 'danger-full-access' && (
|
|
110
|
+
<span className="dsh-atb-badge" data-kind="urgent" title={t('card.badge.permFullTitle')}>
|
|
111
|
+
{t('card.badge.permFull')}
|
|
112
|
+
</span>
|
|
113
|
+
)}
|
|
102
114
|
{task.checklist !== undefined && task.checklist.length > 0 && (
|
|
103
115
|
<span
|
|
104
116
|
className="dsh-atb-badge"
|
|
105
117
|
data-kind={task.status === 'in_review' && task.checklist.some(i => !i.checked) ? 'blocked' : 'checklist'}
|
|
106
|
-
title={task.status === 'in_review' && task.checklist.some(i => !i.checked) ? '
|
|
118
|
+
title={task.status === 'in_review' && task.checklist.some(i => !i.checked) ? t('card.badge.checklistReview') : t('card.badge.checklist')}
|
|
107
119
|
>
|
|
108
120
|
☑ {task.checklist.filter(i => i.checked).length}/{task.checklist.length}
|
|
109
121
|
</span>
|
|
110
122
|
)}
|
|
111
|
-
{task.status === 'done' && <span className="dsh-atb-badge" data-kind="done"
|
|
123
|
+
{task.status === 'done' && <span className="dsh-atb-badge" data-kind="done">{t('status.pill.done')}</span>}
|
|
112
124
|
{last !== undefined && (
|
|
113
125
|
<span className="dsh-atb-badge" data-kind={last.outcome === 'running' ? 'running' : last.outcome}>
|
|
114
|
-
{
|
|
126
|
+
{t(OUTCOME_KEYS[last.outcome] ?? last.outcome)}
|
|
115
127
|
</span>
|
|
116
128
|
)}
|
|
117
129
|
{targetSessionId !== undefined && (
|
|
118
130
|
<button
|
|
119
131
|
type="button"
|
|
120
132
|
className="dsh-atb-card-session"
|
|
121
|
-
title={
|
|
133
|
+
title={t('card.session.jumpTitle', { id: targetSessionId })}
|
|
122
134
|
onClick={(e) => {
|
|
123
135
|
e.stopPropagation()
|
|
124
136
|
void controller.openSession(targetSessionId).then(result => {
|
|
125
137
|
if (result === 'missing') {
|
|
126
|
-
const msg =
|
|
138
|
+
const msg = t('card.session.missing', { id: shortId(targetSessionId) })
|
|
127
139
|
if (onAlert !== undefined) onAlert(msg)
|
|
128
140
|
else alert(msg)
|
|
129
141
|
} else if (result === 'archived') {
|
|
130
|
-
const msg =
|
|
142
|
+
const msg = t('card.session.archived', { id: shortId(targetSessionId) })
|
|
131
143
|
if (onAlert !== undefined) onAlert(msg)
|
|
132
144
|
else alert(msg)
|
|
133
145
|
} else if (result === 'unavailable') {
|
|
134
|
-
const msg =
|
|
146
|
+
const msg = t('card.session.unavailable', { id: targetSessionId })
|
|
135
147
|
if (onAlert !== undefined) onAlert(msg)
|
|
136
148
|
else alert(msg)
|
|
137
149
|
}
|
|
@@ -142,7 +154,7 @@ export function TaskCard({ task, controller, draggable = false, now, onAlert }:
|
|
|
142
154
|
</button>
|
|
143
155
|
)}
|
|
144
156
|
{task.comments.length > 0 && <span>💬 {task.comments.length}</span>}
|
|
145
|
-
{task.trashedAt !== undefined && <span className="dsh-atb-badge" data-kind="trashed"
|
|
157
|
+
{task.trashedAt !== undefined && <span className="dsh-atb-badge" data-kind="trashed">{t('card.badge.pendingPurge')}</span>}
|
|
146
158
|
<span style={{ marginLeft: 'auto' }}>{fmtTime(task.updatedAt)}</span>
|
|
147
159
|
</div>
|
|
148
160
|
{reviewing && (rejectOpen
|
|
@@ -151,7 +163,7 @@ export function TaskCard({ task, controller, draggable = false, now, onAlert }:
|
|
|
151
163
|
<input
|
|
152
164
|
className="dsh-atb-input dsh-atb-quick-note"
|
|
153
165
|
value={note}
|
|
154
|
-
placeholder=
|
|
166
|
+
placeholder={t('card.reject.placeholder')}
|
|
155
167
|
autoFocus
|
|
156
168
|
spellCheck={false}
|
|
157
169
|
onChange={e => setNote(e.target.value)}
|
|
@@ -160,8 +172,8 @@ export function TaskCard({ task, controller, draggable = false, now, onAlert }:
|
|
|
160
172
|
else if (e.key === 'Escape') { setRejectOpen(false); setNote('') }
|
|
161
173
|
}}
|
|
162
174
|
/>
|
|
163
|
-
<button type="button" className="dsh-atb-quickbtn" data-act="reject-confirm" onClick={submitReject}
|
|
164
|
-
<button type="button" className="dsh-atb-quickbtn" data-act="reject-cancel" onClick={() => { setRejectOpen(false); setNote('') }}
|
|
175
|
+
<button type="button" className="dsh-atb-quickbtn" data-act="reject-confirm" onClick={submitReject}>{t('card.reject.confirm')}</button>
|
|
176
|
+
<button type="button" className="dsh-atb-quickbtn" data-act="reject-cancel" onClick={() => { setRejectOpen(false); setNote('') }}>{t('shared.cancel')}</button>
|
|
165
177
|
</div>
|
|
166
178
|
)
|
|
167
179
|
: (
|
|
@@ -170,19 +182,19 @@ export function TaskCard({ task, controller, draggable = false, now, onAlert }:
|
|
|
170
182
|
type="button"
|
|
171
183
|
className="dsh-atb-quickbtn"
|
|
172
184
|
data-act="done"
|
|
173
|
-
title=
|
|
185
|
+
title={t('card.action.doneTitle')}
|
|
174
186
|
onClick={() => void controller.move(task.id, task.version, 'done')}
|
|
175
187
|
>
|
|
176
|
-
|
|
188
|
+
{t('card.action.done')}
|
|
177
189
|
</button>
|
|
178
190
|
<button
|
|
179
191
|
type="button"
|
|
180
192
|
className="dsh-atb-quickbtn"
|
|
181
193
|
data-act="reject"
|
|
182
|
-
title=
|
|
194
|
+
title={t('card.action.rejectTitle')}
|
|
183
195
|
onClick={() => setRejectOpen(true)}
|
|
184
196
|
>
|
|
185
|
-
|
|
197
|
+
{t('card.action.reject')}
|
|
186
198
|
</button>
|
|
187
199
|
</div>
|
|
188
200
|
))}
|