dsh-task-ledger 0.0.52 → 0.0.54

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
@@ -177,7 +177,7 @@ window.__ModuleLoader__.load({
177
177
  if (needle === "") return true;
178
178
  return parts.some((part) => part?.toLowerCase().includes(needle) === true);
179
179
  }
180
- /** 「我的」判定:owner = 该工作区的当前 git 身份,且状态是 doing / blocked(与 host 统计同口径)。 */
180
+ /** 「我的」判定:owner = 该工作区的当前 git 身份,且状态是进行中(blocked 是旧数据,照收;与 host 同口径)。 */
181
181
  function isMine(task, board) {
182
182
  if (board === null) return false;
183
183
  const identity = board.identities[task.workspace.id] ?? null;
@@ -207,10 +207,10 @@ window.__ModuleLoader__.load({
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 === "blocked") return task.status === "blocked";
210
+ if (status === "overdue") return task.overdue === true;
211
211
  return task.stale === true;
212
212
  }
213
- /** 组内排序:别人的 doing/blocked 在前、待认领在后;各自按创建 / 开始时间倒序。 */
213
+ /** 组内排序:别人的进行中在前、待认领在后;各自按创建 / 开始时间倒序。 */
214
214
  function inGroupOrder(a, b) {
215
215
  if (a.kind !== "task" || b.kind !== "task") return 0;
216
216
  const rank = (task) => task.status === "open" ? 1 : 0;
@@ -234,7 +234,7 @@ window.__ModuleLoader__.load({
234
234
  total: 0,
235
235
  doing: 0,
236
236
  open: 0,
237
- blocked: 0,
237
+ overdue: 0,
238
238
  stale: 0
239
239
  }
240
240
  };
@@ -243,7 +243,7 @@ window.__ModuleLoader__.load({
243
243
  total: allTasks.length,
244
244
  doing: allTasks.filter((task) => task.status === "doing").length,
245
245
  open: allTasks.filter((task) => task.status === "open").length,
246
- blocked: allTasks.filter((task) => task.status === "blocked").length,
246
+ overdue: allTasks.filter((task) => task.overdue === true).length,
247
247
  stale: allTasks.filter((task) => task.stale === true).length
248
248
  };
249
249
  const mineRows = board.tasks.filter((task) => isMine(task, board)).filter((task) => query.workspace === "" || task.workspace.id === query.workspace).filter((task) => hitKeyword(query.keyword, [
@@ -278,7 +278,7 @@ window.__ModuleLoader__.load({
278
278
  workspaceId,
279
279
  title: entry.title,
280
280
  doingCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "doing").length,
281
- blockedCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "blocked").length,
281
+ overdueCount: entry.rows.filter((row) => row.kind === "task" && row.task.overdue === true).length,
282
282
  staleCount: entry.rows.filter((row) => row.kind === "task" && row.task.stale === true).length,
283
283
  openCount: entry.rows.filter((row) => row.kind === "task" && row.task.status === "open").length,
284
284
  total: entry.rows.length,
@@ -643,9 +643,9 @@ body[data-ds-dark-theme]{
643
643
  /* 列:任务(弹性)/ 执行人 / 右侧槽(创建信息 ⇄ 操作钮) */
644
644
  .dtl-tcell{min-width:0;}
645
645
  .dtl-tcell--title{flex:1 1 auto;}
646
- /* 执行人列(原状态列,用户 2026-10-18 互换):标签最宽 20ch ⇒ 列宽按它给,标签再自己收到 100%
647
- (名字过长时由标签自己的省略号兜住,不许溢出压到右边的槽) */
648
- .dtl-tcell--status{flex:none;width:110px;}
646
+ /* 执行人列(原状态列,用户 2026-10-18 互换):稍放宽一档(用户 2026-10-19:原来有点挤),
647
+ 20 字的名字能基本摆全;再长由标签自己的省略号兜住,不许溢出压到右边的槽 */
648
+ .dtl-tcell--status{flex:none;width:136px;}
649
649
  .dtl-tcell--status .dtl-tag{max-width:100%;}
650
650
  /* 悬停:**创建信息整条让位给操作钮**(用户 2026-10-18:不要「掉掉时分秒」那种半吊子,
651
651
  要整条换掉)。两个都**常驻布局**(visibility 切换、不用 display),格子宽度 = 两者较宽的
@@ -712,8 +712,10 @@ body[data-ds-dark-theme]{
712
712
  .dtl-taskrow__row:hover .dtl-taskrow__when{display:none;}
713
713
  .dtl-taskrow__row:hover .dtl-taskrow__actions{display:inline-flex;}
714
714
 
715
- /* 标签(用户 2026-10-18):状态 / 执行人 / #标签 **共用一枚件**,只换色调;
716
- 最大宽度 20ch(≈10 个中文或 20 个字符),超出省略号、悬停跑马灯把全文滚出来。 */
715
+ /* 标签(用户 2026-10-18):状态 / 执行人 / #标签 **共用一枚件**,只换色调。
716
+ 最大宽度 20ch(≈10 个中文或 20 个字符)⇒ 名字上限 20 字;超出**省略号(3 个点)**,
717
+ 悬停把全名补出来(用户 2026-10-19:不跑马灯了)。**没被截 ⇒ 悬停无反应**
718
+ (提示由 Tag 元件按实际宽度决定挂不挂,这里只管裁切)。 */
717
719
  .dtl-tag{display:inline-block;flex:none;max-width:20ch;padding:0 6px;border-radius:999px;
718
720
  background:var(--dtl-chip-bg);color:var(--dtl-fg-3);font-size:10px;line-height:16px;
719
721
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;}
@@ -726,13 +728,6 @@ body[data-ds-dark-theme]{
726
728
  .dtl-tag--stale{background:var(--dtl-danger);color:var(--dtl-on-signal);font-weight:600;}
727
729
  /* 执行人:浅蓝底(与状态色区分:状态是「事怎么样」,人是「谁在做」) */
728
730
  .dtl-tag--person{background:var(--dtl-open-bg-soft);color:var(--dtl-fg-2);}
729
- /* 内层撑满真实宽度(inline-block ⇒ transform 才生效),外层负责裁切与省略号 */
730
- .dtl-tag__text{display:inline-block;}
731
- /* 跑马灯只挂在**真溢出**的标签上(短的挂上去会白飘一段) */
732
- .dtl-tag--long:hover{text-overflow:clip;}
733
- .dtl-tag--long:hover .dtl-tag__text{animation:dtl-marquee 6s linear infinite;}
734
- @keyframes dtl-marquee{0%,12%{transform:translateX(0);}
735
- 88%,100%{transform:translateX(calc(-100% + 20ch - 12px));}}
736
731
 
737
732
  /* 分区标题里的计数:与日期徽同款中括号小字(用户 2026-10-17);0 条不渲染 */
738
733
  .dtl-count{font-size:var(--dtl-font-xs);color:var(--dtl-fg-3);font-variant-numeric:tabular-nums;}
@@ -935,16 +930,17 @@ body[data-ds-dark-theme]{
935
930
  }
936
931
  /**
937
932
  * 标签(**唯一**一枚件,用户 2026-10-18):状态 / 执行人 / #标签 都走它,只换 tone。
938
- * 超宽 ⇒ 省略号;悬停 ⇒ 跑马灯滚出全文(溢出时不挂 title,免得原生提示盖住滚动)。
933
+ * 超过 20 个字符宽 ⇒ 省略号,**且只在被截时**挂悬停提示补出全文(用户 2026-10-19:
934
+ * 不跑马灯;没被截 ⇒ 悬停无反应)。
939
935
  */
940
936
  function Tag(props) {
941
937
  ensureUiBase();
942
938
  const { text, tone = "neutral", title } = props;
943
939
  const long = displayWidth(text) > TAG_MAX_WIDTH;
944
940
  return (0, react.createElement)("span", {
945
- className: `dtl-tag dtl-tag--${tone}${long ? " dtl-tag--long" : ""}`,
946
- title: long ? void 0 : title ?? text
947
- }, (0, react.createElement)("span", { className: "dtl-tag__text" }, text));
941
+ className: `dtl-tag dtl-tag--${tone}`,
942
+ title: long ? title ?? text : void 0
943
+ }, text);
948
944
  }
949
945
  /** 空态:`guide` = 真空引导卡(虚线),`filtered` = 筛选空小字。 */
950
946
  function EmptyState(props) {
@@ -1100,24 +1096,14 @@ body[data-ds-dark-theme]{
1100
1096
  const title = row.record.workpackage ?? row.record.summary;
1101
1097
  return title !== void 0 && title !== "" ? title : row.record.src ?? "—";
1102
1098
  }
1103
- /** 状态语义(异常优先:stale 盖过 blocked)。 */
1099
+ /** 状态语义(异常优先:stale 盖过 blocked;blocked 是 host 按 7 天算出来的,不是状态)。 */
1104
1100
  function toneOf(row) {
1105
1101
  if (row.kind !== "task") return "closed";
1106
1102
  if (row.task.stale === true) return "stale";
1107
- if (row.task.status === "blocked") return "blocked";
1103
+ if (row.task.overdue === true) return "blocked";
1108
1104
  if (row.task.status === "open") return "open";
1109
1105
  return "doing";
1110
1106
  }
1111
- /**
1112
- * ⚠️ 调试态(用户 2026-10-19):创建人 / 执行人(GitHub 账号)的名字**补到 20 个字符**,
1113
- * 好看清「满 20 字」时标签的截断 + 悬停跑马灯到底是什么效果。
1114
- * **真实数据一个字没动** —— 只在渲染这一刻把名字补长(mock 仅此一处,用 `-` 当填充,一眼看得出是假的)。
1115
- * 定稿后:删掉本常量与 `debugName()`,两处调用换回原始名字。
1116
- */
1117
- const DEBUG_NAME_CHARS = 20;
1118
- function debugName(name) {
1119
- return name.length >= DEBUG_NAME_CHARS ? name : name + "-".repeat(DEBUG_NAME_CHARS - name.length);
1120
- }
1121
1107
  /** 状态文案(已结案没有在办状态 ⇒ 不给标签)。 */
1122
1108
  function statusLabel(tone, t) {
1123
1109
  if (tone === "stale") return t("statusStale");
@@ -1184,11 +1170,11 @@ body[data-ds-dark-theme]{
1184
1170
  const creator = isTask ? row.task.creator : row.record.owner;
1185
1171
  const owner = isTask ? row.task.owner : null;
1186
1172
  const hasOwner = !(owner === null || owner === void 0 || owner === "");
1187
- const who = creator === null || creator === void 0 || creator === "" ? "—" : `@${debugName(creator)}`;
1173
+ const who = creator === null || creator === void 0 || creator === "" ? "—" : `@${creator}`;
1188
1174
  const createdOk = created !== null && created !== void 0 && Date.parse(created) >= 0;
1189
1175
  const startedOk = isTask && row.task.started !== null && row.task.started !== void 0 && Date.parse(row.task.started) >= 0;
1190
1176
  const ownerTip = t("startedAt", {
1191
- who: debugName(String(owner)),
1177
+ who: String(owner),
1192
1178
  when: startedOk ? formatDateTime(String(row.task.started)) : t("timeUnknown")
1193
1179
  });
1194
1180
  const tagLine = (0, react.createElement)("div", { className: "dtl-orow__tags" }, statusTag, tags.map((tag) => (0, react.createElement)(Tag, {
@@ -1196,7 +1182,7 @@ body[data-ds-dark-theme]{
1196
1182
  text: `#${tag}`
1197
1183
  })));
1198
1184
  return (0, react.createElement)("div", { className: "dtl-orow" }, (0, react.createElement)("div", { className: "dtl-orow__row" }, (0, react.createElement)("span", { className: `dtl-dot dtl-dot--${tone}` }), (0, react.createElement)("div", { className: "dtl-tcell dtl-tcell--title" }, orowTitleLine, tagLine), (0, react.createElement)("span", { className: "dtl-tcell dtl-tcell--status" }, hasOwner ? (0, react.createElement)(Tag, {
1199
- text: `@${debugName(String(owner))}`,
1185
+ text: `@${String(owner)}`,
1200
1186
  tone: "person",
1201
1187
  title: ownerTip
1202
1188
  }) : null), (0, react.createElement)("span", { className: "dtl-orow__slot" }, (0, react.createElement)("span", { className: "dtl-orow__created" }, t("createdAt", {
@@ -1388,11 +1374,11 @@ body[data-ds-dark-theme]{
1388
1374
  }, state.refreshing ? t("refreshing") : t("refresh")))), tab === "stats" ? (0, react.createElement)("div", { style: hintStyle }, t("statsPlaceholder")) : (0, react.createElement)("div", null, stats === void 0 ? null : (0, react.createElement)("div", {
1389
1375
  className: "dtl-stats",
1390
1376
  style: statsRowStyle
1391
- }, (0, react.createElement)("div", { className: "dtl-stats__cards" }, card("statMyActive", stats.myActive, t("statMyActiveHint", { n: stats.myBlocked })), card("statOpen", stats.open, t("statOpenHint", { n: days(stats.oldestOpenDays) })), card("statDoing", stats.doing, t("statDoingHint", { n: stats.doing - stats.myActive + stats.myBlocked })), (0, react.createElement)(StatCard, {
1377
+ }, (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, {
1392
1378
  label: t("statBlockedStale"),
1393
- value: stats.blocked + stats.stale,
1379
+ value: stats.overdue + stats.stale,
1394
1380
  hint: t("statBlockedSplit", {
1395
- blocked: stats.blocked,
1381
+ blocked: stats.overdue,
1396
1382
  stale: stats.stale
1397
1383
  }),
1398
1384
  title: t("statStaleTitle", { n: stats.staleDays }),
@@ -1526,9 +1512,9 @@ body[data-ds-dark-theme]{
1526
1512
  badge: orZero(view.allCounts.open)
1527
1513
  },
1528
1514
  {
1529
- value: "blocked",
1515
+ value: "overdue",
1530
1516
  label: t("statusBlocked"),
1531
- badge: orZero(view.allCounts.blocked)
1517
+ badge: orZero(view.allCounts.overdue)
1532
1518
  },
1533
1519
  {
1534
1520
  value: "stale",
@@ -1586,7 +1572,7 @@ body[data-ds-dark-theme]{
1586
1572
  t("groupTotal", { n: group.total }),
1587
1573
  t("groupOpen", { n: group.openCount }),
1588
1574
  t("groupDoing", { n: group.doingCount }),
1589
- ...group.blockedCount > 0 ? [t("groupBlocked", { n: group.blockedCount })] : [],
1575
+ ...group.overdueCount > 0 ? [t("groupBlocked", { n: group.overdueCount })] : [],
1590
1576
  ...group.staleCount > 0 ? [t("groupStale", { n: group.staleCount })] : []
1591
1577
  ].join(" | ");
1592
1578
  return (0, react.createElement)("div", { className: "dtl-group" }, (0, react.createElement)("button", {
@@ -1859,7 +1845,7 @@ body[data-ds-dark-theme]{
1859
1845
  * 定位用宿主变量 `--dsh-frame-overlay-top`(标题栏净空 + 20px),**不写死 top 值**;
1860
1846
  * 浮层默认 `pointer-events:none`、子元素自动恢复 ⇒ 自绘条目不挡下方应用。
1861
1847
  *
1862
- * 角标 = 我名下 `doing` + `blocked` 计数(host 统计真值,SSE 已否 ⇒ 取自同一份快照,>0 才画);
1848
+ * 角标 = 我名下进行中计数(host 统计真值,SSE 已否 ⇒ 取自同一份快照,>0 才画);
1863
1849
  * 0→n 跳变时一次脉冲动画,不自动消失。宿主**无**通知 API ⇒ 「通知」就是这个角标。
1864
1850
  */
1865
1851
  function OverlayEntry(props) {