@goodandready/dsh-kanban 0.1.20 → 0.1.21
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 +19 -1
- package/lib/client.js +34 -0
- package/lib/filters.js +307 -288
- package/lib/gitea.js +28 -0
- package/lib/import.js +23 -0
- package/lib/index.js +25 -2
- package/lib/outbound.js +22 -0
- package/lib/routes.js +355 -331
- package/lib/store.js +392 -389
- package/lib/sync.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -127,7 +127,25 @@ A due date can be set on any card. Overdue cards are highlighted, and a switch i
|
|
|
127
127
|
the board header narrows the board to them alone — the answer to "what is already
|
|
128
128
|
late" is one click, not a scan.
|
|
129
129
|
|
|
130
|
-
### 6.
|
|
130
|
+
### 6. Ownership: Who Took the Task
|
|
131
|
+
|
|
132
|
+
The board carries two different people per task and never confuses them: the
|
|
133
|
+
**author** who filed the issue and the **assignee** who took it. Both arrive
|
|
134
|
+
from Gitea, both are filter dimensions, and the assignee is shown on the card
|
|
135
|
+
itself — "who is doing this" is asked more often than "who wrote it".
|
|
136
|
+
|
|
137
|
+
A single button in the task window takes the task or drops it. Taking assigns
|
|
138
|
+
the account whose token the board uses: the harness has no user of its own, so
|
|
139
|
+
"me" is resolved by asking Gitea rather than by guessing. The change travels
|
|
140
|
+
back to the issue through the outbound queue, so the board keeps working while
|
|
141
|
+
Gitea is down; dropping sends an empty assignee list, because Gitea reads a
|
|
142
|
+
missing field as "leave it alone".
|
|
143
|
+
|
|
144
|
+
Assignment made in Gitea arrives on the next sync — in both directions,
|
|
145
|
+
including removal. Filtering by "nobody" answers the question the board is
|
|
146
|
+
opened for most often: what is free to pick up.
|
|
147
|
+
|
|
148
|
+
### 7. Board Snapshot: Export and Import
|
|
131
149
|
|
|
132
150
|
`GET /dsh-kanban/snapshot` returns the whole board as JSON; `POST` to the same
|
|
133
151
|
route restores it. Import is idempotent: a task whose id is already on the board
|
package/lib/client.js
CHANGED
|
@@ -682,6 +682,7 @@ window.__ModuleLoader__.load({
|
|
|
682
682
|
'.dkb-archiveRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;align-items:center;gap:12px;padding:8px 12px;display:flex}' +
|
|
683
683
|
'.dkb-start{display:contents}' +
|
|
684
684
|
'.dkb-pack{color:var(--dsw-alias-label-secondary)}' +
|
|
685
|
+
'.dkb-who{color:var(--dsw-alias-label-secondary)}' +
|
|
685
686
|
'.dkb-sameSession{outline:1px solid var(--dsw-alias-label-secondary);outline-offset:1px}' +
|
|
686
687
|
'.dkb-waitCount{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:0 10px;height:30px;cursor:pointer;color:var(--dsw-alias-label-primary)}' +
|
|
687
688
|
'.dkb-archiveOpen{background:none;border:0;padding:0;text-align:left;cursor:pointer;font:inherit}' +
|
|
@@ -946,6 +947,12 @@ window.__ModuleLoader__.load({
|
|
|
946
947
|
'sync.neverSeen': 'no successful check since the harness started',
|
|
947
948
|
'facet.repo': 'Repository',
|
|
948
949
|
'facet.author': 'Author',
|
|
950
|
+
'facet.assignee': 'Assignee',
|
|
951
|
+
'card.assigneeHint': 'Who took the task',
|
|
952
|
+
'panel.assignee': 'taken by {who}',
|
|
953
|
+
'panel.assignMe': 'Take it',
|
|
954
|
+
'panel.assignDrop': 'Drop it',
|
|
955
|
+
'error.gitea-unreachable': 'Gitea did not answer, so there is nobody to take the task as.',
|
|
949
956
|
'board.pickArchive': 'To the archive',
|
|
950
957
|
'board.pickUnqueue': 'Out of the queue',
|
|
951
958
|
'board.pickMove': 'Move to…',
|
|
@@ -1191,6 +1198,12 @@ window.__ModuleLoader__.load({
|
|
|
1191
1198
|
'sync.neverSeen': '自 harness 启动以来没有一次成功的核对',
|
|
1192
1199
|
'facet.repo': '仓库',
|
|
1193
1200
|
'facet.author': '创建者',
|
|
1201
|
+
'facet.assignee': '负责人',
|
|
1202
|
+
'card.assigneeHint': '谁接下了这个任务',
|
|
1203
|
+
'panel.assignee': '由 {who} 接手',
|
|
1204
|
+
'panel.assignMe': '我来接',
|
|
1205
|
+
'panel.assignDrop': '放手',
|
|
1206
|
+
'error.gitea-unreachable': 'Gitea 没有响应,无从得知以谁的身份接手。',
|
|
1194
1207
|
'board.pickArchive': '移入归档',
|
|
1195
1208
|
'board.pickUnqueue': '移出队列',
|
|
1196
1209
|
'board.pickMove': '移动到…',
|
|
@@ -1623,6 +1636,10 @@ window.__ModuleLoader__.load({
|
|
|
1623
1636
|
title: exactAt(task.dueAt),
|
|
1624
1637
|
}, t('card.due', { date: shortDate(task.dueAt) }))
|
|
1625
1638
|
: null,
|
|
1639
|
+
task.assignee
|
|
1640
|
+
? React.createElement('span', { className: 'dkb-who', title: t('card.assigneeHint') },
|
|
1641
|
+
'@' + task.assignee)
|
|
1642
|
+
: null,
|
|
1626
1643
|
pack
|
|
1627
1644
|
? React.createElement('span', {
|
|
1628
1645
|
className: 'dkb-pack', title: t('card.packHint'),
|
|
@@ -2355,6 +2372,7 @@ window.__ModuleLoader__.load({
|
|
|
2355
2372
|
React.createElement('div', { className: 'dkb-title' }, openTask.title),
|
|
2356
2373
|
React.createElement('div', { className: 'dkb-note' },
|
|
2357
2374
|
t('panel.created', { ago: agoText(state.now, openTask.createdAt, t) })
|
|
2375
|
+
+ (openTask.assignee ? ' · ' + t('panel.assignee', { who: openTask.assignee }) : '')
|
|
2358
2376
|
// Автор стоит рядом с датой заведения: это одно событие — кто и
|
|
2359
2377
|
// когда завёл, — и разносить его по разным углам незачем.
|
|
2360
2378
|
+ (openTask.author ? ' · ' + t('panel.author', { who: openTask.author }) : ''),
|
|
@@ -2420,6 +2438,22 @@ window.__ModuleLoader__.load({
|
|
|
2420
2438
|
},
|
|
2421
2439
|
}, t('panel.saveEdit')),
|
|
2422
2440
|
),
|
|
2441
|
+
// Взять и отдать — одна кнопка в двух состояниях: держать рядом
|
|
2442
|
+
// «взять» и «отказаться» значит предлагать бессмысленное действие.
|
|
2443
|
+
React.createElement('button', {
|
|
2444
|
+
type: 'button', className: 'dkb-discard', style: { alignSelf: 'flex-start' },
|
|
2445
|
+
onClick: async () => {
|
|
2446
|
+
const mine = openTask.assignee !== '' && openTask.assignee !== undefined
|
|
2447
|
+
try {
|
|
2448
|
+
const out = await api('/task/' + encodeURIComponent(openTask.id) + '/assign', {
|
|
2449
|
+
method: 'POST',
|
|
2450
|
+
body: JSON.stringify({ login: mine ? '' : 'me' }),
|
|
2451
|
+
})
|
|
2452
|
+
if (out && out.task) setOpenTask(out.task)
|
|
2453
|
+
await load(board)
|
|
2454
|
+
} catch (e) { setError(t(e.key || 'error.unknown')) }
|
|
2455
|
+
},
|
|
2456
|
+
}, openTask.assignee ? t('panel.assignDrop') : t('panel.assignMe')),
|
|
2423
2457
|
openTask.sessionId
|
|
2424
2458
|
? React.createElement('button', {
|
|
2425
2459
|
type: 'button', className: 'dkb-discard', style: { alignSelf: 'flex-start' },
|