dsh-calendar 0.10.3 → 0.10.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  [历史英文记录](docs/CHANGELOG.en.md)
6
6
 
7
+ ## 0.10.4 (2026-10-17)
8
+
9
+ - 日程与连接表单采用每个实例独立的字段标识,点击标签可聚焦输入框,并提供正确的可访问名称。
10
+ - 修复英文服务商选项残留中文;首次连接摘要尚在加载时暂缓打开连接编辑器,避免快速点击看到空白配置。
11
+ - 在官方 DSH 0.2.1-alpha.5 的隔离网页版检查本机 CalDAV 新建日程、连接测试、中英文表单及 390px 布局。
12
+
7
13
  ## 0.10.3 (2026-10-05)
8
14
 
9
15
  - 修复窄窗口中日历悬浮按钮遮挡聊天发送按钮的问题;浮层宽度计入内边距,并限制在视口内,避免左侧内容被裁切。
package/README.en.md CHANGED
@@ -8,6 +8,11 @@ View, create and reschedule CalDAV events from DSH.
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/dsh-calendar)](https://www.npmjs.com/package/dsh-calendar) [![downloads](https://raw.githubusercontent.com/STARDUSTLC666/dsh-suite/npm-downloads/assets/dsh-calendar-downloads.svg)](https://www.npmjs.com/package/dsh-calendar)
10
10
 
11
+ Feedback and contributions are welcome: report [issues](https://github.com/STARDUSTLC666/dsh-calendar/issues) or submit [pull requests](https://github.com/STARDUSTLC666/dsh-calendar/pulls).
12
+
13
+
14
+ See the [0.10.4 validation record](docs/validation/0.10.4.md) for DSH `0.2.1-alpha.5` browser checks and the remaining limits.
15
+
11
16
  ## What it does
12
17
 
13
18
  - Month, week and agenda views with drag and keyboard rescheduling.
package/README.md CHANGED
@@ -8,6 +8,11 @@
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/dsh-calendar)](https://www.npmjs.com/package/dsh-calendar) [![downloads](https://raw.githubusercontent.com/STARDUSTLC666/dsh-suite/npm-downloads/assets/dsh-calendar-downloads.svg)](https://www.npmjs.com/package/dsh-calendar)
10
10
 
11
+ 欢迎使用,遇到问题或有改进建议,请提交 [issues](https://github.com/STARDUSTLC666/dsh-calendar/issues) 和 [PR](https://github.com/STARDUSTLC666/dsh-calendar/pulls)。
12
+
13
+
14
+ DSH `0.2.1-alpha.5` 的本轮检查与未验收范围见 [0.10.4 验收记录](docs/validation/0.10.4.md)。
15
+
11
16
  ## 功能
12
17
 
13
18
  - 月、周与议程视图,支持拖拽和键盘改期。
@@ -1,5 +1,7 @@
1
1
  # dsh-calendar 验证记录
2
2
 
3
+ [0.10.4 · DSH 0.2.1-alpha.5 浏览器操作验收](validation/0.10.4.md)。
4
+
3
5
  [0.10.1 中英文界面验收](validation-language-2026-10-03.md)。
4
6
 
5
7
  本页整理原 README 的历史验证说明,保留当时的版本、日期与范围。自动测试、启动检查、浏览器操作和真实服务验收分别记录,不能相互替代。更详细的版本验收文件仍保留在仓库中。
@@ -0,0 +1,11 @@
1
+ # 0.10.4 · DSH alpha.5 网页验收
2
+
3
+ 宿主为公开 npm `@deepseek-ai/dsh@0.2.1-alpha.5`,Windows Node 24,系统 Chrome 无头浏览器。测试数据与 DSH profile 均位于 E 盘的隔离目录。
4
+
5
+ - 194 项 Windows 自动测试通过。
6
+ - 日程标题、日期、起止时间、重复、地点及备注可通过标签定位;实际点击日期标签后输入框获得焦点。
7
+ - 新建日程经真实 HTTP CalDAV 客户端写入本机合成服务并重新读取;连接设置可测试该服务。
8
+ - 英文服务商显示 Custom CalDAV,表单字段有英文名称;390px 英文弹窗保持在视口内。
9
+ - 连接摘要请求完成前,连接入口保持禁用,避免编辑器以空配置初始化。
10
+
11
+ 未使用外部 CalDAV 账号,未操作桌面原生窗口;本机合成服务通过不等于云端账号验收。
package/lib/client.js CHANGED
@@ -10,7 +10,7 @@ var module = { exports: {} }; var exports = module.exports;
10
10
  "use strict";
11
11
 
12
12
  const React = require("react");
13
- const { useState, useEffect, useMemo, useRef, useCallback } = React;
13
+ const { useState, useEffect, useMemo, useRef, useCallback, useId } = React;
14
14
  const h = React.createElement;
15
15
 
16
16
  // Resolve against the Harness document base, including any reverse-proxy prefix.
@@ -183,6 +183,7 @@ const UI = {
183
183
  "conn.title": "CalDAV 连接设置",
184
184
  "conn.intro": "测试连接不会修改日历。连接成功后,点击“保存并启用”。",
185
185
  "conn.provider": "服务商",
186
+ "provider.custom": "自建 CalDAV",
186
187
  "conn.caldavUrl": "日历集合 URL",
187
188
  "conn.username": "账号",
188
189
  "conn.password": "密码 / 应用专用密码",
@@ -278,6 +279,7 @@ const UI = {
278
279
  "conn.title": "CalDAV connection",
279
280
  "conn.intro": "Testing the connection does not change your calendar. Once it succeeds, click Save and enable.",
280
281
  "conn.provider": "Provider",
282
+ "provider.custom": "Custom CalDAV",
281
283
  "conn.caldavUrl": "Calendar collection URL",
282
284
  "conn.username": "Account",
283
285
  "conn.password": "Password / app-specific password",
@@ -1310,6 +1312,7 @@ function asPseudoEvent(draft) {
1310
1312
 
1311
1313
  function EventForm(props) {
1312
1314
  const { draft, events, onCancel, onSubmit, busy, error } = props;
1315
+ const formId = useId();
1313
1316
  const [form, setForm] = useState(draft);
1314
1317
  useEffect(() => { setForm(draft); }, [draft.uid, draft.date, draft.startTime, draft.summary]);
1315
1318
  const patch = (fields) => setForm((prev) => Object.assign({}, prev, fields));
@@ -1321,21 +1324,21 @@ function EventForm(props) {
1321
1324
  const body = h("div", null, [
1322
1325
  error ? h("div", { className: "dshc-alert error" }, error) : null,
1323
1326
  h("div", { className: "dshc-field" }, [
1324
- h("label", null, t("field.summary")),
1325
- h(Txt, { value: form.summary, autoFocus: true, onChange: (e) => patch({ summary: e.target.value }), placeholder: t("form.newTitle") })
1327
+ h("label", { htmlFor: formId + "-summary" }, t("field.summary")),
1328
+ h(Txt, { id: formId + "-summary", value: form.summary, autoFocus: true, onChange: (e) => patch({ summary: e.target.value }), placeholder: t("form.newTitle") })
1326
1329
  ]),
1327
1330
  h("div", { className: "dshc-field" }, [
1328
- h("label", null, t("field.date")),
1329
- h(Txt, { type: "date", value: form.date, onChange: (e) => patch({ date: e.target.value }) })
1331
+ h("label", { htmlFor: formId + "-date" }, t("field.date")),
1332
+ h(Txt, { id: formId + "-date", type: "date", value: form.date, onChange: (e) => patch({ date: e.target.value }) })
1330
1333
  ]),
1331
1334
  form.allDay === true ? null : h("div", { className: "dshc-two" }, [
1332
- h("div", { className: "dshc-field" }, [h("label", null, t("field.start")), h(Txt, { type: "time", value: form.startTime, onChange: (e) => patch({ startTime: e.target.value }) })]),
1333
- h("div", { className: "dshc-field" }, [h("label", null, t("field.end")), h(Txt, { type: "time", value: form.endTime, onChange: (e) => patch({ endTime: e.target.value }) })])
1335
+ h("div", { className: "dshc-field" }, [h("label", { htmlFor: formId + "-start" }, t("field.start")), h(Txt, { id: formId + "-start", type: "time", value: form.startTime, onChange: (e) => patch({ startTime: e.target.value }) })]),
1336
+ h("div", { className: "dshc-field" }, [h("label", { htmlFor: formId + "-end" }, t("field.end")), h(Txt, { id: formId + "-end", type: "time", value: form.endTime, onChange: (e) => patch({ endTime: e.target.value }) })])
1334
1337
  ]),
1335
1338
  h("div", { className: "dshc-field" }, [h(Chk, { checked: form.allDay === true, label: t("field.allDay"), onChange: (next) => patch({ allDay: next }) })]),
1336
1339
  h("div", { className: "dshc-field" }, [
1337
- h("label", null, t("field.repeat")),
1338
- h("select", { className: "dshc-input", value: form.repeat, onChange: (e) => patch({ repeat: e.target.value }) }, [
1340
+ h("label", { htmlFor: formId + "-repeat" }, t("field.repeat")),
1341
+ h("select", { id: formId + "-repeat", className: "dshc-input", value: form.repeat, onChange: (e) => patch({ repeat: e.target.value }) }, [
1339
1342
  h("option", { value: "", key: "none" }, t("repeat.none")),
1340
1343
  h("option", { value: "daily", key: "d" }, t("repeat.daily")),
1341
1344
  h("option", { value: "weekly", key: "w" }, t("repeat.weekly")),
@@ -1345,13 +1348,13 @@ function EventForm(props) {
1345
1348
  ])
1346
1349
  ]),
1347
1350
  form.repeat === "custom" ? h("div", { className: "dshc-field" }, [
1348
- h("label", null, "RRULE"),
1349
- h(Txt, { value: form.rrule, placeholder: "FREQ=WEEKLY;COUNT=10", onChange: (e) => patch({ rrule: e.target.value }) })
1351
+ h("label", { htmlFor: formId + "-rrule" }, "RRULE"),
1352
+ h(Txt, { id: formId + "-rrule", value: form.rrule, placeholder: "FREQ=WEEKLY;COUNT=10", onChange: (e) => patch({ rrule: e.target.value }) })
1350
1353
  ]) : null,
1351
- h("div", { className: "dshc-field" }, [h("label", null, t("field.location")), h(Txt, { value: form.location, onChange: (e) => patch({ location: e.target.value }) })]),
1354
+ h("div", { className: "dshc-field" }, [h("label", { htmlFor: formId + "-location" }, t("field.location")), h(Txt, { id: formId + "-location", value: form.location, onChange: (e) => patch({ location: e.target.value }) })]),
1352
1355
  h("div", { className: "dshc-field" }, [
1353
- h("label", null, t("field.description")),
1354
- h("textarea", { className: "dshc-input", value: form.description, onChange: (e) => patch({ description: e.target.value }) })
1356
+ h("label", { htmlFor: formId + "-description" }, t("field.description")),
1357
+ h("textarea", { id: formId + "-description", className: "dshc-input", value: form.description, onChange: (e) => patch({ description: e.target.value }) })
1355
1358
  ]),
1356
1359
  conflicts.length > 0 ? h("div", { className: "dshc-alert warn" }, [
1357
1360
  h("div", null, [
@@ -1479,6 +1482,7 @@ function connectionSummary(connection) {
1479
1482
  */
1480
1483
  function ConnectionForm(props) {
1481
1484
  const { connection, onClose, onSaved } = props;
1485
+ const formId = useId();
1482
1486
  const [form, setForm] = useState(() => connectionDraftOf(connection));
1483
1487
  const [busy, setBusy] = useState("");
1484
1488
  const [result, setResult] = useState(null);
@@ -1533,10 +1537,10 @@ function ConnectionForm(props) {
1533
1537
  ? h("div", { className: "dshc-alert warn" }, t("conn.noSettings"))
1534
1538
  : null,
1535
1539
  h("div", { className: "dshc-field" }, [
1536
- h("label", null, t("conn.provider")),
1537
- h("select", { className: "dshc-input", "aria-label": t("conn.provider"), value: form.provider, onChange: (e) => patch({ provider: e.target.value }) },
1540
+ h("label", { htmlFor: formId + "-provider" }, t("conn.provider")),
1541
+ h("select", { id: formId + "-provider", className: "dshc-input", "aria-label": t("conn.provider"), value: form.provider, onChange: (e) => patch({ provider: e.target.value }) },
1538
1542
  [h("option", { value: "", key: "__none" }, "— " + t("conn.needProvider") + " —")].concat(
1539
- PROVIDER_NAMES.map((name) => h("option", { value: name, key: name }, name === "custom" ? "自建 CalDAV" : name === "icloud" ? "iCloud" : name === "nextcloud" ? "Nextcloud" : "Google"))
1543
+ PROVIDER_NAMES.map((name) => h("option", { value: name, key: name }, name === "custom" ? t("provider.custom") : name === "icloud" ? "iCloud" : name === "nextcloud" ? "Nextcloud" : "Google"))
1540
1544
  ))
1541
1545
  ]),
1542
1546
  PROVIDER_HINT[form.provider] ? h("div", { className: "dshc-sub", style: { marginBottom: "8px" } }, t(PROVIDER_HINT[form.provider])) : null,
@@ -1554,8 +1558,9 @@ function ConnectionForm(props) {
1554
1558
  || (key === "refreshToken" && connection.hasRefreshToken === true));
1555
1559
  const hintKey = FIELD_HINT[form.provider] ? FIELD_HINT[form.provider][key] : undefined;
1556
1560
  return h("div", { className: "dshc-field", key }, [
1557
- h("label", null, t(FIELD_LABEL[key])),
1561
+ h("label", { htmlFor: formId + "-" + key }, t(FIELD_LABEL[key])),
1558
1562
  h(Txt, {
1563
+ id: formId + "-" + key,
1559
1564
  type: secret ? "password" : "text",
1560
1565
  "aria-label": t(FIELD_LABEL[key]),
1561
1566
  value: form[key] || "",
@@ -2016,7 +2021,7 @@ function CalendarPanel(props) {
2016
2021
  h(Btn, { key: "prev", onClick: () => step(-1), "aria-label": t("action.prev") }, "\u2039"),
2017
2022
  h(Btn, { key: "today", onClick: () => setAnchor(new Date()) }, t("action.today")),
2018
2023
  h(Btn, { key: "next", onClick: () => step(1), "aria-label": t("action.next") }, "\u203a"),
2019
- h(Btn, { key: "conn", onClick: () => setConnOpen(true) }, t("conn.button")),
2024
+ h(Btn, { key: "conn", disabled: configured === null, onClick: () => setConnOpen(true) }, t("conn.button")),
2020
2025
  h(Btn, { key: "import", disabled: demo === true || importBusy, onClick: () => setImportOpen(value => !value) }, t("import.open")),
2021
2026
  demo === true
2022
2027
  ? h(Btn, { key: "exitdemo", onClick: () => setDemo(false) }, t("action.exitDemo"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-calendar",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "description": "连接 CalDAV 日历,在 DSH 中查看、创建和调整日程。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",