dsh-task-ledger 0.0.56 → 0.0.57

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/dist/client.js CHANGED
@@ -202,11 +202,12 @@ window.__ModuleLoader__.load({
202
202
  finish: false,
203
203
  release: false
204
204
  };
205
- /** 状态档命中(停滞由 host 标记,前端不判阈值)——只作用于第二区。 */
205
+ /** 状态档命中(积压 / 超期 / 停滞由 host 标记,前端不判阈值)——只作用于第二区。 */
206
206
  function statusHit(task, status) {
207
207
  if (status === "all") return true;
208
208
  if (status === "active") return task.status === "doing" || task.status === "blocked";
209
209
  if (status === "open") return task.status === "open";
210
+ if (status === "backlog") return task.backlog === true;
210
211
  if (status === "overdue") return task.overdue === true;
211
212
  return task.stale === true;
212
213
  }
@@ -235,7 +236,8 @@ window.__ModuleLoader__.load({
235
236
  doing: 0,
236
237
  open: 0,
237
238
  overdue: 0,
238
- stale: 0
239
+ stale: 0,
240
+ backlog: 0
239
241
  }
240
242
  };
241
243
  const allTasks = board.tasks;
@@ -244,7 +246,8 @@ window.__ModuleLoader__.load({
244
246
  doing: allTasks.filter((task) => task.status === "doing").length,
245
247
  open: allTasks.filter((task) => task.status === "open").length,
246
248
  overdue: allTasks.filter((task) => task.overdue === true).length,
247
- stale: allTasks.filter((task) => task.stale === true).length
249
+ stale: allTasks.filter((task) => task.stale === true).length,
250
+ backlog: allTasks.filter((task) => task.backlog === true).length
248
251
  };
249
252
  const mineRows = board.tasks.filter((task) => isMine(task, board)).filter((task) => query.workspace === "" || task.workspace.id === query.workspace).filter((task) => hitKeyword(query.keyword, [
250
253
  task.title,
@@ -280,6 +283,7 @@ window.__ModuleLoader__.load({
280
283
  doingCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "doing").length,
281
284
  overdueCount: entry.rows.filter((row) => row.kind === "task" && row.task.overdue === true).length,
282
285
  staleCount: entry.rows.filter((row) => row.kind === "task" && row.task.stale === true).length,
286
+ backlogCount: entry.rows.filter((row) => row.kind === "task" && row.task.backlog === true).length,
283
287
  openCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "open").length,
284
288
  total: entry.rows.length,
285
289
  rows: entry.rows.sort(inGroupOrder)
@@ -374,6 +378,9 @@ body{
374
378
  /* ⚠️ 宿主是 state-warn(不是 state-warning,后者无此定义) */
375
379
  --dtl-warning:var(--dsw-alias-state-warn-primary,#f59e0b);
376
380
  --dtl-danger:var(--dsw-alias-state-error-primary,#ec1313);
381
+ /* 超期橙:在「积压黄」与「停滞红」之间再取一档(语义阶梯 灰→黄→橙→红),
382
+ 宿主没有现成的橙 token ⇒ 用 warn + error 两色现算,主题一换自动跟随 */
383
+ --dtl-overdue:color-mix(in srgb,var(--dtl-warning) 55%,var(--dtl-danger));
377
384
  --dtl-link:var(--dsw-alias-link,#3b5bdb);
378
385
  /* 语义色实面上的字(角标 / 实心提示):红绿黄都是中调 ⇒ 白字两个主题都可读 */
379
386
  --dtl-on-signal:#fff;
@@ -660,11 +667,12 @@ body[data-ds-dark-theme]{
660
667
  /* 「查看」钮在表格行里也要常驻布局(display:none 会不算宽度 ⇒ hover 一出就又把行撑开) */
661
668
  .dtl-orow .dtl-viewbtn{display:inline-flex;visibility:hidden;}
662
669
  .dtl-orow:hover .dtl-viewbtn{visibility:visible;}
663
- /* 行首状态圆点:灰=待认领 / 浅蓝=进行中(比「我的」蓝灰一档)/ 黄=阻塞 / 红=停滞;
670
+ /* 行首状态圆点:灰=待认领 / 浅蓝=进行中(比「我的」蓝灰一档)/ 黄=积压 / 橙=超期 / 红=停滞;
664
671
  6px(用户 2026-10-18:8px 太大) */
665
672
  .dtl-dot{display:inline-block;width:6px;height:6px;flex:none;border-radius:50%;}
666
673
  .dtl-dot--doing{background:var(--dtl-business-dim);}
667
- .dtl-dot--blocked{background:var(--dtl-warning);}
674
+ .dtl-dot--backlog{background:var(--dtl-warning);}
675
+ .dtl-dot--overdue{background:var(--dtl-overdue);}
668
676
  .dtl-dot--stale{background:var(--dtl-danger);}
669
677
  .dtl-dot--open,.dtl-dot--closed{background:var(--dtl-fg-3);}
670
678
 
@@ -693,7 +701,8 @@ body[data-ds-dark-theme]{
693
701
  /* 状态条:贴卡片左缘、与正文两行等高的竖向色条(dispatch StatusRail 同款 6×36) */
694
702
  .dtl-rail{display:inline-block;width:6px;height:36px;flex:none;border-radius:var(--dtl-radius-xs);}
695
703
  .dtl-rail--doing{background:var(--dtl-business);}
696
- .dtl-rail--blocked{background:var(--dtl-warning);}
704
+ .dtl-rail--backlog{background:var(--dtl-warning);}
705
+ .dtl-rail--overdue{background:var(--dtl-overdue);}
697
706
  .dtl-rail--stale{background:var(--dtl-danger);}
698
707
  .dtl-rail--open,.dtl-rail--closed{background:var(--dtl-fg-3);}
699
708
 
@@ -720,11 +729,12 @@ body[data-ds-dark-theme]{
720
729
  background:var(--dtl-chip-bg);color:var(--dtl-fg-3);font-size:10px;line-height:16px;
721
730
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;}
722
731
  /* 状态四色 = **实心色块**(用户 2026-10-18:彩色字看不清 ⇒ 改色块 + 反色字):
723
- 待认领灰 / 进行中蓝 / 阻塞黄 / 停滞红(与行首圆点同色系)。
732
+ 待认领灰 / 进行中蓝 / 积压黄 / 超期橙 / 停滞红(与行首圆点同色系)。
724
733
  红黄蓝都是中调 ⇒ 白字两个主题都可读;灰块用「字色底 + 面色字」⇒ 明暗自动反过来 */
725
734
  .dtl-tag--open{background:var(--dtl-fg-3);color:var(--dtl-surface-1);font-weight:600;}
726
735
  .dtl-tag--doing{background:var(--dtl-business);color:var(--dtl-on-signal);font-weight:600;}
727
- .dtl-tag--blocked{background:var(--dtl-warning);color:var(--dtl-on-signal);font-weight:600;}
736
+ .dtl-tag--backlog{background:var(--dtl-warning);color:var(--dtl-on-signal);font-weight:600;}
737
+ .dtl-tag--overdue{background:var(--dtl-overdue);color:var(--dtl-on-signal);font-weight:600;}
728
738
  .dtl-tag--stale{background:var(--dtl-danger);color:var(--dtl-on-signal);font-weight:600;}
729
739
  /* 执行人:浅蓝底(与状态色区分:状态是「事怎么样」,人是「谁在做」) */
730
740
  .dtl-tag--person{background:var(--dtl-open-bg-soft);color:var(--dtl-fg-2);}
@@ -1082,44 +1092,63 @@ body[data-ds-dark-theme]{
1082
1092
  * 行 = 一条淡分隔线格:上下居中的状态圆点 + 任务(标题行 + 标签行;**标签行最前是状态标签**)
1083
1093
  * + **执行人列**(原状态位,有执行人才摆 `@名字` 标签)+ 最右「@创建人 创建于 年-月-日 时:分:秒」
1084
1094
  * (悬停掉时分秒并让位给操作钮)+ 查看。
1085
- * 状态一律**标签型、四色**(用户 2026-10-18:原来是一排素字 / pill,现在与人员**位置互换**):
1086
- * 灰=待认领 / 蓝=进行中 / 黄=阻塞 / 红=停滞;停滞标签悬停给**配置出来的**阈值解释
1087
- * (staleDays 由 host 下发)。圆点颜色同色系。
1095
+ * 状态一律**标签型、五色**(用户 2026-10-18:原来是一排素字 / pill,现在与人员**位置互换**):
1096
+ * 灰=待认领 / 蓝=进行中 / 黄=积压 / 橙=超期 / 红=停滞;三个异常标签悬停给**配置出来的**
1097
+ * 阈值解释(staleDays / overdueDays / backlogDays 由 host 下发)。圆点颜色同色系。
1088
1098
  *
1089
1099
  * 按钮(含查看)**不各判各的**:权限一律问 `resolveActions()`(rows.ts),本文件只按返回值画。
1090
1100
  *
1091
1101
  * 按钮点击行为(含查看)归「任务按钮与会话交接」任务,本文件只做样子与提示。
1092
1102
  */
1103
+ /**
1104
+ * ⚠️ 调试态(用户 2026-10-19):第二区**第一条**把全部状态标签一次摆出来,看全五枚色块。
1105
+ * 定稿后:删掉本常量与 `debugAllTones` 这一路,标签行回到按 `tone` 取一枚。
1106
+ */
1107
+ const DEBUG_TONES = [
1108
+ "open",
1109
+ "backlog",
1110
+ "doing",
1111
+ "overdue",
1112
+ "stale"
1113
+ ];
1093
1114
  /** 行标题:在办 = 任务名(缺则任务号);已结案 = 任务包名(缺则「完成了什么」首句)。 */
1094
1115
  function titleOf(row) {
1095
1116
  if (row.kind === "task") return row.task.title ?? row.task.id;
1096
1117
  const title = row.record.workpackage ?? row.record.summary;
1097
1118
  return title !== void 0 && title !== "" ? title : row.record.src ?? "—";
1098
1119
  }
1099
- /** 状态语义(异常优先:stale 盖过 blocked;blocked 是 host 按 7 天算出来的,不是状态)。 */
1120
+ /** 状态语义(异常优先:停滞 > 超期 > 积压;三者都是 host 按时间算出来的,不是状态)。 */
1100
1121
  function toneOf(row) {
1101
1122
  if (row.kind !== "task") return "closed";
1102
1123
  if (row.task.stale === true) return "stale";
1103
- if (row.task.overdue === true) return "blocked";
1124
+ if (row.task.overdue === true) return "overdue";
1125
+ if (row.task.backlog === true) return "backlog";
1104
1126
  if (row.task.status === "open") return "open";
1105
1127
  return "doing";
1106
1128
  }
1107
1129
  /** 状态文案(已结案没有在办状态 ⇒ 不给标签)。 */
1108
1130
  function statusLabel(tone, t) {
1109
1131
  if (tone === "stale") return t("statusStale");
1110
- if (tone === "blocked") return t("statusBlocked");
1132
+ if (tone === "overdue") return t("statusOverdue");
1133
+ if (tone === "backlog") return t("statusBacklog");
1111
1134
  if (tone === "open") return t("statusOpen");
1112
1135
  if (tone === "doing") return t("statusActive");
1113
1136
  return null;
1114
1137
  }
1115
1138
  function TaskRowView(props) {
1116
- const { t, row, variant, staleDays, board } = props;
1139
+ const { t, row, variant, board, debugAllTones } = props;
1117
1140
  const tone = toneOf(row);
1118
1141
  const isTask = row.kind === "task";
1119
1142
  const tags = (row.kind === "task" ? row.task.tags : row.record.tags) ?? [];
1120
1143
  const created = row.kind === "task" ? row.task.created ?? null : row.record.created ?? null;
1121
1144
  const createdDay = created !== null && created !== void 0 && Date.parse(created) >= 0 ? formatDateTime(created).slice(0, 10) : null;
1122
- const staleTip = staleDays === null || staleDays === void 0 ? void 0 : t("statStaleTitle", { n: staleDays });
1145
+ const stats = board?.stats;
1146
+ const tipOf = (tone) => {
1147
+ if (stats === void 0) return void 0;
1148
+ if (tone === "stale") return t("statStaleTitle", { n: stats.staleDays });
1149
+ if (tone === "overdue") return t("statOverdueTitle", { n: stats.overdueDays });
1150
+ if (tone === "backlog") return t("statBacklogTitle", { n: stats.backlogDays });
1151
+ };
1123
1152
  const actions = isTask ? resolveActions(row.task, board) : CLOSED_ACTIONS;
1124
1153
  const viewButton = (0, react.createElement)("button", {
1125
1154
  type: "button",
@@ -1147,17 +1176,17 @@ body[data-ds-dark-theme]{
1147
1176
  className: "dtl-minibtn",
1148
1177
  "data-tip": t("tipRelease")
1149
1178
  }, t("actionRelease"));
1150
- const statusText = statusLabel(tone, t);
1151
- const statusTag = statusText === null || tone === "closed" ? null : (0, react.createElement)(Tag, {
1152
- text: statusText,
1153
- tone,
1154
- title: tone === "stale" ? staleTip ?? statusText : statusText
1155
- });
1156
- const alarmTag = tone === "blocked" || tone === "stale" ? (0, react.createElement)(Tag, {
1157
- text: statusLabel(tone, t) ?? "",
1158
- tone,
1159
- title: tone === "stale" ? staleTip : void 0
1160
- }) : null;
1179
+ const tagOf = (which) => {
1180
+ const text = statusLabel(which, t) ?? "";
1181
+ return (0, react.createElement)(Tag, {
1182
+ key: which,
1183
+ text,
1184
+ tone: which,
1185
+ title: tipOf(which) ?? text
1186
+ });
1187
+ };
1188
+ const statusTag = tone === "closed" ? null : tagOf(tone);
1189
+ const alarmTag = tone === "backlog" || tone === "overdue" || tone === "stale" ? tagOf(tone) : null;
1161
1190
  const titleLine = (0, react.createElement)("div", { className: "dtl-taskrow__l1" }, (0, react.createElement)("span", {
1162
1191
  className: "dtl-taskrow__title dtl-ellipsis",
1163
1192
  title: titleOf(row)
@@ -1177,7 +1206,7 @@ body[data-ds-dark-theme]{
1177
1206
  who: String(owner),
1178
1207
  when: startedOk ? formatDateTime(String(row.task.started)) : t("timeUnknown")
1179
1208
  });
1180
- const tagLine = (0, react.createElement)("div", { className: "dtl-orow__tags" }, statusTag, tags.map((tag) => (0, react.createElement)(Tag, {
1209
+ const tagLine = (0, react.createElement)("div", { className: "dtl-orow__tags" }, debugAllTones === true ? DEBUG_TONES.map(tagOf) : statusTag, tags.map((tag) => (0, react.createElement)(Tag, {
1181
1210
  key: tag,
1182
1211
  text: `#${tag}`
1183
1212
  })));
@@ -1375,13 +1404,18 @@ body[data-ds-dark-theme]{
1375
1404
  className: "dtl-stats",
1376
1405
  style: statsRowStyle
1377
1406
  }, (0, react.createElement)("div", { className: "dtl-stats__cards" }, card("statMyActive", stats.myActive, t("statMyActiveHint", { n: stats.myOverdue })), card("statOpen", stats.open, t("statOpenHint", { n: days(stats.oldestOpenDays) })), card("statDoing", stats.doing, t("statDoingHint", { n: stats.doing - stats.myActive })), (0, react.createElement)(StatCard, {
1378
- label: t("statBlockedStale"),
1379
- value: stats.overdue + stats.stale,
1380
- hint: t("statBlockedSplit", {
1381
- blocked: stats.overdue,
1407
+ label: t("statAlarm"),
1408
+ value: stats.backlog + stats.overdue + stats.stale,
1409
+ hint: t("statAlarmSplit", {
1410
+ backlog: stats.backlog,
1411
+ overdue: stats.overdue,
1382
1412
  stale: stats.stale
1383
1413
  }),
1384
- title: t("statStaleTitle", { n: stats.staleDays }),
1414
+ title: [
1415
+ t("statBacklogTitle", { n: stats.backlogDays }),
1416
+ t("statOverdueTitle", { n: stats.overdueDays }),
1417
+ t("statStaleTitle", { n: stats.staleDays })
1418
+ ].join(";"),
1385
1419
  interactive: false
1386
1420
  }), periodCard("statWeekDone", periods?.thisWeek), periodCard("statLastWeekDone", periods?.lastWeek), periodCard("statMonthDone", periods?.thisMonth), periodCard("statLastMonthDone", periods?.lastMonth)), (0, react.createElement)("div", {
1387
1421
  className: "dtl-card",
@@ -1482,7 +1516,6 @@ body[data-ds-dark-theme]{
1482
1516
  t,
1483
1517
  row,
1484
1518
  variant: "mine",
1485
- staleDays: board?.stats.staleDays ?? null,
1486
1519
  board
1487
1520
  })), (0, react.createElement)("div", null, (0, react.createElement)("div", { style: regionHeadRowStyle }, (0, react.createElement)("span", { style: {
1488
1521
  color: "var(--dtl-fg-3)",
@@ -1511,9 +1544,14 @@ body[data-ds-dark-theme]{
1511
1544
  label: t("statusOpen"),
1512
1545
  badge: orZero(view.allCounts.open)
1513
1546
  },
1547
+ {
1548
+ value: "backlog",
1549
+ label: t("statusBacklog"),
1550
+ badge: orZero(view.allCounts.backlog)
1551
+ },
1514
1552
  {
1515
1553
  value: "overdue",
1516
- label: t("statusBlocked"),
1554
+ label: t("statusOverdue"),
1517
1555
  badge: orZero(view.allCounts.overdue)
1518
1556
  },
1519
1557
  {
@@ -1550,12 +1588,12 @@ body[data-ds-dark-theme]{
1550
1588
  variant: "primary",
1551
1589
  size: "md",
1552
1590
  onClick: onBack
1553
- }, t("allEmptyAction"))) : (0, react.createElement)("div", { style: { marginTop: "var(--dtl-space-2)" } }, view.groups.map((group) => (0, react.createElement)(WorkspaceGroupView, {
1591
+ }, t("allEmptyAction"))) : (0, react.createElement)("div", { style: { marginTop: "var(--dtl-space-2)" } }, view.groups.map((group, index) => (0, react.createElement)(WorkspaceGroupView, {
1554
1592
  key: group.workspaceId,
1555
1593
  t,
1556
1594
  group,
1557
- staleDays: board?.stats.staleDays ?? null,
1558
- board
1595
+ board,
1596
+ debugFirstRow: index === 0
1559
1597
  })))))))));
1560
1598
  }
1561
1599
  /** 角标:>0 才给数字,0 = undefined(不标)。 */
@@ -1564,15 +1602,16 @@ body[data-ds-dark-theme]{
1564
1602
  }
1565
1603
  /** 一个工作区分组(全部待办表格段):段头(点+名+统计)→ 列头行 → 任务行。
1566
1604
  * 统计口径(用户 2026-10-18):共 N|待办 N|进行中 N 常显(0 也显);
1567
- * 阻塞 / 停滞**只在 >0 时出现**。 */
1605
+ * 积压 / 超期 / 停滞**只在 >0 时出现**。 */
1568
1606
  function WorkspaceGroupView(props) {
1569
- const { t, group, staleDays, board } = props;
1607
+ const { t, group, board, debugFirstRow } = props;
1570
1608
  const [open, setOpen] = (0, react.useState)(group.rows.length <= GROUP_COLLAPSE_OVER);
1571
1609
  const stats = [
1572
1610
  t("groupTotal", { n: group.total }),
1573
1611
  t("groupOpen", { n: group.openCount }),
1574
1612
  t("groupDoing", { n: group.doingCount }),
1575
- ...group.overdueCount > 0 ? [t("groupBlocked", { n: group.overdueCount })] : [],
1613
+ ...group.backlogCount > 0 ? [t("groupBacklog", { n: group.backlogCount })] : [],
1614
+ ...group.overdueCount > 0 ? [t("groupOverdue", { n: group.overdueCount })] : [],
1576
1615
  ...group.staleCount > 0 ? [t("groupStale", { n: group.staleCount })] : []
1577
1616
  ].join(" | ");
1578
1617
  return (0, react.createElement)("div", { className: "dtl-group" }, (0, react.createElement)("button", {
@@ -1587,13 +1626,13 @@ body[data-ds-dark-theme]{
1587
1626
  display: "inline-flex",
1588
1627
  flex: "none",
1589
1628
  color: "var(--dtl-fg-3)"
1590
- } }, (0, react.createElement)(open ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular : _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 14 })), (0, react.createElement)("span", { className: "dtl-group__name dtl-ellipsis" }, group.title), (0, react.createElement)("span", { style: { flex: "1 1 auto" } }), (0, react.createElement)("span", { className: "dtl-group__stats" }, stats)), open ? (0, react.createElement)("div", null, group.rows.map((row) => (0, react.createElement)(TaskRowView, {
1629
+ } }, (0, react.createElement)(open ? _deepseek_ai_dsh_client_ui_primitives.IconFolderOpenRegular : _deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 14 })), (0, react.createElement)("span", { className: "dtl-group__name dtl-ellipsis" }, group.title), (0, react.createElement)("span", { style: { flex: "1 1 auto" } }), (0, react.createElement)("span", { className: "dtl-group__stats" }, stats)), open ? (0, react.createElement)("div", null, group.rows.map((row, index) => (0, react.createElement)(TaskRowView, {
1591
1630
  key: row.key,
1592
1631
  t,
1593
1632
  row,
1594
1633
  variant: "others",
1595
- staleDays,
1596
- board
1634
+ board,
1635
+ debugAllTones: debugFirstRow === true && index === 0
1597
1636
  }))) : null);
1598
1637
  }
1599
1638
  //#endregion
@@ -1613,16 +1652,18 @@ body[data-ds-dark-theme]{
1613
1652
  degradedItem: "{title}:{message}",
1614
1653
  statsPlaceholder: "统计报表尚未开建(另立任务):这里以后放分类分布、按人完成数、时间线。",
1615
1654
  statMyActive: "我的待办",
1616
- statMyActiveHint: "阻塞 {n} 条",
1655
+ statMyActiveHint: "超期 {n} 条",
1617
1656
  statOpen: "待认领",
1618
1657
  statOpenHint: "最长未认领 {n}",
1619
1658
  statDoing: "进行中",
1620
1659
  statDoingHint: "其他成员负责 {n} 条",
1621
- statBlockedStale: "阻塞 · 停滞",
1660
+ statAlarm: "积压 · 超期 · 停滞",
1622
1661
  statStaleWord: "停滞",
1623
1662
  statStaleHint: "{n} 条",
1624
- statBlockedSplit: "阻塞 {blocked} | 停滞 {stale}",
1625
- statStaleTitle: "停滞 = 进行中或阻塞超过 {n} 天未更新",
1663
+ statAlarmSplit: "积压 {backlog} | 超期 {overdue} | 停滞 {stale}",
1664
+ statStaleTitle: "停滞 = 进行中满 {n} 天没更新",
1665
+ statOverdueTitle: "超期 = 认领后满 {n} 天还没结案",
1666
+ statBacklogTitle: "积压 = 待认领满 {n} 天没人接",
1626
1667
  statWeekDone: "本周完成",
1627
1668
  statLastWeekDone: "上周完成",
1628
1669
  statMonthDone: "本月完成",
@@ -1651,7 +1692,8 @@ body[data-ds-dark-theme]{
1651
1692
  statusAll: "全部",
1652
1693
  statusActive: "进行中",
1653
1694
  statusOpen: "待认领",
1654
- statusBlocked: "阻塞",
1695
+ statusBacklog: "积压",
1696
+ statusOverdue: "超期",
1655
1697
  statusStale: "停滞",
1656
1698
  workspaceLabel: "工作区",
1657
1699
  workspaceAll: "全部工作区",
@@ -1662,7 +1704,8 @@ body[data-ds-dark-theme]{
1662
1704
  groupTotal: "共 {n} 条",
1663
1705
  groupOpen: "待办 {n} 条",
1664
1706
  groupDoing: "进行中 {n} 条",
1665
- groupBlocked: "阻塞 {n} 条",
1707
+ groupBacklog: "积压 {n} 条",
1708
+ groupOverdue: "超期 {n} 条",
1666
1709
  groupStale: "停滞 {n} 条",
1667
1710
  colTask: "任务",
1668
1711
  colCreator: "创建人",
@@ -1727,16 +1770,18 @@ body[data-ds-dark-theme]{
1727
1770
  degradedItem: "{title}: {message}",
1728
1771
  statsPlaceholder: "Stats reports are not built yet (separate task): category breakdown, completions by person, timeline.",
1729
1772
  statMyActive: "My todos",
1730
- statMyActiveHint: "blocked {n}",
1773
+ statMyActiveHint: "overdue {n}",
1731
1774
  statOpen: "Unclaimed",
1732
1775
  statOpenHint: "longest unclaimed {n}",
1733
1776
  statDoing: "In progress",
1734
1777
  statDoingHint: "owned by other members: {n}",
1735
- statBlockedStale: "Blocked · Stale",
1778
+ statAlarm: "Backlog · Overdue · Stale",
1736
1779
  statStaleWord: "Stale",
1737
1780
  statStaleHint: "{n}",
1738
- statBlockedSplit: "{blocked} blocked | {stale} stale",
1739
- statStaleTitle: "stale = active or blocked with no update for {n}+ days",
1781
+ statAlarmSplit: "{backlog} backlog | {overdue} overdue | {stale} stale",
1782
+ statStaleTitle: "stale = active with no update for {n}+ days",
1783
+ statOverdueTitle: "overdue = claimed {n}+ days ago and still open",
1784
+ statBacklogTitle: "backlog = unclaimed for {n}+ days",
1740
1785
  statWeekDone: "Done this week",
1741
1786
  statLastWeekDone: "Done last week",
1742
1787
  statMonthDone: "Done this month",
@@ -1765,7 +1810,8 @@ body[data-ds-dark-theme]{
1765
1810
  statusAll: "All",
1766
1811
  statusActive: "Active",
1767
1812
  statusOpen: "Unclaimed",
1768
- statusBlocked: "Blocked",
1813
+ statusBacklog: "Backlog",
1814
+ statusOverdue: "Overdue",
1769
1815
  statusStale: "Stale",
1770
1816
  workspaceLabel: "Workspace",
1771
1817
  workspaceAll: "All workspaces",
@@ -1776,7 +1822,8 @@ body[data-ds-dark-theme]{
1776
1822
  groupTotal: "{n} total",
1777
1823
  groupOpen: "{n} open",
1778
1824
  groupDoing: "{n} active",
1779
- groupBlocked: "{n} blocked",
1825
+ groupBacklog: "{n} backlog",
1826
+ groupOverdue: "{n} overdue",
1780
1827
  groupStale: "{n} stale",
1781
1828
  colTask: "Task",
1782
1829
  colCreator: "Created by",