dsh-calendar 0.9.2 → 0.9.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/lib/client.js CHANGED
@@ -152,7 +152,7 @@ const UI = {
152
152
  "state.notConfigured": "还没配置 CalDAV 账号",
153
153
  "state.notConfiguredHint": "点击“连接设置”,选择日历服务并填写账号信息,测试连接后保存即可。也可以先查看示例,了解日历的用法。",
154
154
  "state.readonly": "只读",
155
- "demo.banner": "示例日历为只读,可以切换视图和查看详情。点击「退出示例」后连接自己的日历,即可创建和修改日程。",
155
+ "demo.banner": "示例日历为只读,可以切换视图和查看详情。点击「退出示例」后连接自己的日历,即可创建和修改日程。",
156
156
  "field.summary": "标题", "field.date": "日期", "field.start": "开始", "field.end": "结束",
157
157
  "field.allDay": "全天", "field.location": "地点", "field.description": "备注",
158
158
  "field.repeat": "重复", "field.uid": "事件 uid", "field.when": "时间", "field.duration": "时长",
@@ -194,7 +194,7 @@ const UI = {
194
194
  "conn.refreshToken": "refreshToken",
195
195
  "conn.tokenUrl": "令牌地址(可留空)",
196
196
  "conn.proxyUrl": "代理地址(可留空)",
197
- "conn.keep": "已保存,留空不改",
197
+ "conn.keep": "已配置,留空不改",
198
198
  "conn.test": "测试连接",
199
199
  "conn.testing": "正在连接…",
200
200
  "conn.save": "保存并启用",
@@ -247,7 +247,7 @@ const UI = {
247
247
  "state.notConfigured": "No CalDAV account configured yet",
248
248
  "state.notConfiguredHint": "Open Connection settings, choose your calendar service and enter your account details, then test and save the connection. You can also explore the sample calendar first.",
249
249
  "state.readonly": "read-only",
250
- "demo.banner": "This sample calendar is read-only. Switch views and open event details. Exit the sample and connect your calendar to create or edit events.",
250
+ "demo.banner": "This sample calendar is read-only. Switch views and open event details. Exit the sample and connect your calendar to create or edit events.",
251
251
  "field.summary": "Title", "field.date": "Date", "field.start": "Start", "field.end": "End",
252
252
  "field.allDay": "All day", "field.location": "Location", "field.description": "Notes",
253
253
  "field.repeat": "Repeats", "field.uid": "Event uid", "field.when": "When", "field.duration": "Duration",
@@ -289,7 +289,7 @@ const UI = {
289
289
  "conn.refreshToken": "refreshToken",
290
290
  "conn.tokenUrl": "Token URL (optional)",
291
291
  "conn.proxyUrl": "Proxy URL (optional)",
292
- "conn.keep": "saved — leave blank to keep",
292
+ "conn.keep": "configured — leave blank to keep",
293
293
  "conn.test": "Test connection",
294
294
  "conn.testing": "Connecting…",
295
295
  "conn.save": "Save and enable",
@@ -1119,12 +1119,12 @@ function demoEvents() {
1119
1119
  const at = (offset, hour, minute) => { const d = addDays(base, offset); d.setHours(hour, minute || 0, 0, 0); return isoOf(d); };
1120
1120
  const dateOnly = (offset) => { const d = addDays(base, offset); return dayKey(d); };
1121
1121
  return [
1122
- { uid: "demo://allday", summary: "📦 项目上线日", start: dateOnly(0), end: dateOnly(1), allDay: true, description: "确认发布说明并完成上线检查", location: "线上", isOccurrence: false },
1123
- { uid: "demo://review", summary: "产品评审会", start: at(0, 10, 0), end: at(0, 11, 0), allDay: false, location: "会议室 A", description: "议程:体验反馈与本周计划", isOccurrence: false },
1122
+ { uid: "demo://allday", summary: "📦 项目上线日", start: dateOnly(0), end: dateOnly(1), allDay: true, description: "确认发布说明并完成上线检查", location: "线上", isOccurrence: false },
1123
+ { uid: "demo://review", summary: "产品评审会", start: at(0, 10, 0), end: at(0, 11, 0), allDay: false, location: "会议室 A", description: "议程:体验反馈与本周计划", isOccurrence: false },
1124
1124
  { uid: "demo://one-on-one", summary: "1:1 同步", start: at(0, 15, 0), end: at(0, 15, 30), allDay: false, location: "线上", isOccurrence: false },
1125
1125
  { uid: "demo://standup", summary: "每周站会", start: at(1, 9, 30), end: at(1, 9, 50), allDay: false, rrule: "FREQ=WEEKLY;COUNT=6", location: "线上", isOccurrence: false },
1126
1126
  { uid: "demo://standup@2", summary: "每周站会", start: at(8, 9, 30), end: at(8, 9, 50), allDay: false, location: "线上", isOccurrence: true, seriesStart: at(1, 9, 30) },
1127
- { uid: "demo://sync", summary: "与同事同步", start: at(2, 16, 0), end: at(2, 16, 30), allDay: false, location: "线上", description: "同步进度与下一步安排", isOccurrence: false }
1127
+ { uid: "demo://sync", summary: "与同事同步", start: at(2, 16, 0), end: at(2, 16, 30), allDay: false, location: "线上", description: "同步进度与下一步安排", isOccurrence: false }
1128
1128
  ];
1129
1129
  }
1130
1130
 
@@ -1305,8 +1305,8 @@ function EventForm(props) {
1305
1305
 
1306
1306
  // ───────────────────────────── 详情抽屉 ─────────────────────────────
1307
1307
 
1308
- function EventDrawer(props) {
1309
- const { event, onClose, onEdit, onDelete, busy, confirmDelete, setConfirmDelete, events, readOnly } = props;
1308
+ function EventDrawer(props) {
1309
+ const { event, onClose, onEdit, onDelete, busy, confirmDelete, setConfirmDelete, events, readOnly } = props;
1310
1310
  const [copied, setCopied] = useState(false);
1311
1311
  const seriesCount = event.isOccurrence ? events.filter((e) => e.seriesStart === event.seriesStart).length : 0;
1312
1312
  return h("div", { className: "dshc-overlay", onMouseDown: (e) => { if (e.target === e.currentTarget) onClose(); } }, [
@@ -1333,9 +1333,9 @@ function EventDrawer(props) {
1333
1333
  h(Btn, { key: "copy", onClick: async () => { const ok = await copyText(event.uid); if (ok) { setCopied(true); setTimeout(() => setCopied(false), 1600); } } }, copied ? t("action.copied") : t("action.copy")),
1334
1334
  h("span", { className: "dshc-spacer" }),
1335
1335
  confirmDelete
1336
- ? h(Btn, { key: "confirm", variant: "primary", disabled: busy === true || readOnly === true, onClick: () => onDelete(event) }, t("action.confirmDelete"))
1337
- : h(Btn, { key: "delete", variant: "danger", onClick: () => setConfirmDelete(true), disabled: busy === true || readOnly === true }, t("action.delete")),
1338
- h(Btn, { key: "edit", variant: "outline", onClick: () => onEdit(event), disabled: busy === true || readOnly === true }, t("action.edit"))
1336
+ ? h(Btn, { key: "confirm", variant: "primary", disabled: busy === true || readOnly === true, onClick: () => onDelete(event) }, t("action.confirmDelete"))
1337
+ : h(Btn, { key: "delete", variant: "danger", onClick: () => setConfirmDelete(true), disabled: busy === true || readOnly === true }, t("action.delete")),
1338
+ h(Btn, { key: "edit", variant: "outline", onClick: () => onEdit(event), disabled: busy === true || readOnly === true }, t("action.edit"))
1339
1339
  ]),
1340
1340
  confirmDelete ? h("div", { className: "dshc-sub", style: { textAlign: "right", marginTop: "6px" } }, t("confirm.delete", { name: event.summary })) : null
1341
1341
  ])
@@ -1410,7 +1410,10 @@ function ConnectionForm(props) {
1410
1410
  const [busy, setBusy] = useState("");
1411
1411
  const [result, setResult] = useState(null);
1412
1412
  const maySave = connection === null || connection.settingsAvailable !== false;
1413
- const patch = (fields) => setForm((prev) => Object.assign({}, prev, fields));
1413
+ const patch = (fields) => {
1414
+ setForm((prev) => Object.assign({}, prev, fields));
1415
+ setResult(null);
1416
+ };
1414
1417
  const visible = PROVIDER_FIELDS[form.provider] || [];
1415
1418
  const payload = () => {
1416
1419
  const out = {};
@@ -1423,6 +1426,7 @@ function ConnectionForm(props) {
1423
1426
  }
1424
1427
  if (form.provider !== "") out.provider = form.provider;
1425
1428
  if (form.provider === "google") out.authMethod = "oauth";
1429
+ else if (form.provider !== "" && connection && form.provider !== connection.provider) out.authMethod = "basic";
1426
1430
  return out;
1427
1431
  };
1428
1432
  const test = async () => {
@@ -1756,8 +1760,8 @@ function CalendarPanel(props) {
1756
1760
  };
1757
1761
 
1758
1762
  /** 改期入口:重复日程先问一句(拖动会移动整个系列,这是语义雷区,不能悄悄做)。 */
1759
- const reschedule = (event, range) => {
1760
- if (demo === true) { notify(t("demo.banner")); return; }
1763
+ const reschedule = (event, range) => {
1764
+ if (demo === true) { notify(t("demo.banner")); return; }
1761
1765
  // 重复日程暂不支持拖动改期:CalDAV 里整个系列是一个对象,而 update 只能改 master 的
1762
1766
  // DTSTART —— 把「这次实例的目标时间」发过去等于**重锚系列起点**(早于它的实例全丢、
1763
1767
  // COUNT/UNTIL 语义被改,撤销也回不到原系列)。评审实测过,这里必须先挡住。
@@ -1789,8 +1793,8 @@ function CalendarPanel(props) {
1789
1793
  const title = view === "week" ? formatWeekTitle(anchor) : view === "agenda" ? t("view.agenda") : formatMonthTitle(anchor);
1790
1794
  const step = (delta) => setAnchor((current) => (view === "week" ? addDays(current, delta * 7) : addMonthShift(current, delta)));
1791
1795
 
1792
- const submit = async (form) => {
1793
- if (demo === true) { setFormError(t("demo.banner")); return; }
1796
+ const submit = async (form) => {
1797
+ if (demo === true) { setFormError(t("demo.banner")); return; }
1794
1798
  setBusy(true);
1795
1799
  setFormError(null);
1796
1800
  try {
@@ -1808,8 +1812,8 @@ function CalendarPanel(props) {
1808
1812
  }
1809
1813
  };
1810
1814
 
1811
- const remove = async (event) => {
1812
- if (demo === true) { notify(t("demo.banner")); return; }
1815
+ const remove = async (event) => {
1816
+ if (demo === true) { notify(t("demo.banner")); return; }
1813
1817
  setBusy(true);
1814
1818
  try {
1815
1819
  await api("delete", { uid: event.uid });
@@ -1839,7 +1843,7 @@ function CalendarPanel(props) {
1839
1843
  demo === true
1840
1844
  ? h(Btn, { key: "exitdemo", onClick: () => setDemo(false) }, t("action.exitDemo"))
1841
1845
  : h(Btn, { key: "reload", onClick: reload }, t("action.refresh")),
1842
- h(Btn, { key: "new", variant: "primary", disabled: demo === true, onClick: () => setDraft(draftAt(anchor)) }, t("action.new"))
1846
+ h(Btn, { key: "new", variant: "primary", disabled: demo === true, onClick: () => setDraft(draftAt(anchor)) }, t("action.new"))
1843
1847
  ]);
1844
1848
 
1845
1849
  const body = () => {
@@ -1857,16 +1861,16 @@ function CalendarPanel(props) {
1857
1861
  if (data.loading === true && data.events.length === 0) {
1858
1862
  return h("div", { className: "dshc-grid" }, Array.from({ length: 14 }, (_, i) => h("div", { className: "dshc-skel", key: i })));
1859
1863
  }
1860
- if (view === "week") return h(WeekView, { anchor, events: visibleEvents, onPick: openEvent, onCreateAt: createAt, onReschedule: demo === true ? undefined : reschedule });
1864
+ if (view === "week") return h(WeekView, { anchor, events: visibleEvents, onPick: openEvent, onCreateAt: createAt, onReschedule: demo === true ? undefined : reschedule });
1861
1865
  if (view === "agenda") return h(AgendaView, { events: visibleEvents, onPick: openEvent, onCreateAt: createAt });
1862
1866
  return h(MonthView, { anchor, events: visibleEvents, onPick: openEvent, onCreateAt: createAt });
1863
1867
  };
1864
1868
 
1865
1869
  const openEvent = (event) => { setConfirmDelete(false); setSelected(event); };
1866
- const createAt = (day, hour) => {
1867
- if (demo === true) { notify(t("demo.banner")); return; }
1868
- setDraft(draftAt(day, hour));
1869
- };
1870
+ const createAt = (day, hour) => {
1871
+ if (demo === true) { notify(t("demo.banner")); return; }
1872
+ setDraft(draftAt(day, hour));
1873
+ };
1870
1874
 
1871
1875
  return h("div", { ref: rootRef, className: "dshc-root" }, [
1872
1876
  h("div", { className: "dshc-shell" }, [
@@ -1893,8 +1897,8 @@ function CalendarPanel(props) {
1893
1897
  ])
1894
1898
  ]),
1895
1899
  selected !== null
1896
- ? h(EventDrawer, {
1897
- readOnly: demo === true,
1900
+ ? h(EventDrawer, {
1901
+ readOnly: demo === true,
1898
1902
  event: selected,
1899
1903
  events: data.events,
1900
1904
  busy,
package/lib/config.d.ts CHANGED
@@ -44,8 +44,8 @@ export interface CalendarConfig {
44
44
  calendar?: string;
45
45
  /**
46
46
  * HTTP 代理地址,如 http://127.0.0.1:7890。
47
- * 中国用户访问 Google / iCloud 需经代理:填你本地代理客户端的端口即可,
48
- * 插件会把所有 CalDAV 请求路由到该代理,不影响其他插件。
47
+ * 当前网络无法直连时可填本地代理客户端的端口;可直连时留空即可。
48
+ * 插件只把本插件的请求路由到该代理,不影响其他插件。
49
49
  */
50
50
  proxyUrl?: string;
51
51
  }
package/lib/web.js CHANGED
@@ -248,6 +248,8 @@ export class CalendarSettingsBackend {
248
248
  const resolved = effective[key];
249
249
  return typeof resolved === 'string' ? resolved : '';
250
250
  };
251
+ const env = this.options.env ?? process.env;
252
+ const hasCredential = (key, envKey) => text(key).trim() !== '' || (typeof env[envKey] === 'string' && env[envKey].trim() !== '');
251
253
  return {
252
254
  configured,
253
255
  ...(reason !== undefined ? { reason } : {}),
@@ -266,9 +268,9 @@ export class CalendarSettingsBackend {
266
268
  clientId: text('clientId'),
267
269
  tokenUrl: text('tokenUrl'),
268
270
  proxyUrl: text('proxyUrl'),
269
- hasPassword: text('password') !== '' || (effective.password ?? '') !== '',
270
- hasClientSecret: text('clientSecret') !== '' || (effective.clientSecret ?? '') !== '',
271
- hasRefreshToken: text('refreshToken') !== '' || (effective.refreshToken ?? '') !== '',
271
+ hasPassword: hasCredential('password', 'DSH_CALENDAR_PASSWORD'),
272
+ hasClientSecret: hasCredential('clientSecret', 'DSH_CALENDAR_CLIENT_SECRET'),
273
+ hasRefreshToken: hasCredential('refreshToken', 'DSH_CALENDAR_REFRESH_TOKEN'),
272
274
  };
273
275
  }
274
276
  /** 兼容旧动作名:status 就是连接摘要。 */
package/package.json CHANGED
@@ -1,80 +1,80 @@
1
- {
2
- "name": "dsh-calendar",
3
- "version": "0.9.2",
4
- "description": "DSH 日历插件:可视化周/月视图、拖拽改期与 CalDAV 日程管理,支持 Google OAuth2、iCloud、Nextcloud。",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "types": "lib/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./lib/index.d.ts",
11
- "default": "./lib/index.js"
12
- },
13
- "./client": "./lib/client.js",
14
- "./cordis.patch.yml": "./cordis.patch.yml",
15
- "./package.json": "./package.json"
16
- },
17
- "files": [
18
- "lib",
19
- "scripts",
20
- "cordis.patch.yml",
21
- "README.md",
22
- "README.en.md",
23
- "CHANGELOG.md"
24
- ],
25
- "scripts": {
26
- "build": "tsc -p tsconfig.json",
27
- "typecheck": "tsc -p tsconfig.json --noEmit",
28
- "test": "pnpm run build && node --test \"test/*.test.mjs\"",
29
- "prepublishOnly": "pnpm run build"
30
- },
31
- "dsh": {
32
- "bundle": {
33
- "patch": "./cordis.patch.yml"
34
- },
35
- "client": {
36
- "inject": [
37
- "@deepseek-ai/dsh-client-ui-settings"
38
- ],
39
- "platform": "web"
40
- }
41
- },
42
- "keywords": [
43
- "dsh",
44
- "deepseek-harness",
45
- "dsh-plugin",
46
- "plugin",
47
- "calendar",
48
- "caldav",
49
- "ical"
50
- ],
51
- "license": "MIT",
52
- "engines": {
53
- "node": "^22.19.0 || >=24.0.0"
54
- },
55
- "dependencies": {
56
- "@deepseek-ai/schemastery": "^3.18.3",
57
- "ical.js": "^2.1.0",
58
- "schemastery": "^3.18.0",
59
- "tsdav": "^2.3.1",
60
- "undici": "^8.10.0",
61
- "yaml": "^2.9.1"
62
- },
63
- "devDependencies": {
64
- "@types/node": "^24.0.0",
65
- "jsdom": "^30.1.0",
66
- "react": "^19.3.0",
67
- "react-dom": "^19.3.0",
68
- "typescript": "^5.6.0"
69
- },
70
- "repository": {
71
- "type": "git",
72
- "url": "git+https://github.com/STARDUSTLC666/dsh-calendar.git"
73
- },
74
- "bugs": {
75
- "url": "https://github.com/STARDUSTLC666/dsh-calendar/issues"
76
- },
77
- "homepage": "https://github.com/STARDUSTLC666/dsh-calendar#readme",
78
- "author": "stardustlc",
79
- "packageManager": "pnpm@11.7.0"
80
- }
1
+ {
2
+ "name": "dsh-calendar",
3
+ "version": "0.9.4",
4
+ "description": "DSH 日历插件:可视化周/月视图、拖拽改期与 CalDAV 日程管理,支持 Google OAuth2、iCloud、Nextcloud。",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ },
13
+ "./client": "./lib/client.js",
14
+ "./cordis.patch.yml": "./cordis.patch.yml",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "lib",
19
+ "scripts",
20
+ "cordis.patch.yml",
21
+ "README.md",
22
+ "README.en.md",
23
+ "CHANGELOG.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit",
28
+ "test": "pnpm run build && node --test \"test/*.test.mjs\"",
29
+ "prepublishOnly": "pnpm run build"
30
+ },
31
+ "dsh": {
32
+ "bundle": {
33
+ "patch": "./cordis.patch.yml"
34
+ },
35
+ "client": {
36
+ "inject": [
37
+ "@deepseek-ai/dsh-client-ui-settings"
38
+ ],
39
+ "platform": "web"
40
+ }
41
+ },
42
+ "keywords": [
43
+ "dsh",
44
+ "deepseek-harness",
45
+ "dsh-plugin",
46
+ "plugin",
47
+ "calendar",
48
+ "caldav",
49
+ "ical"
50
+ ],
51
+ "license": "MIT",
52
+ "engines": {
53
+ "node": "^22.19.0 || >=24.0.0"
54
+ },
55
+ "dependencies": {
56
+ "@deepseek-ai/schemastery": "^3.18.3",
57
+ "ical.js": "^2.1.0",
58
+ "schemastery": "^3.18.0",
59
+ "tsdav": "^2.3.1",
60
+ "undici": "^8.11.2",
61
+ "yaml": "^2.9.1"
62
+ },
63
+ "devDependencies": {
64
+ "@types/node": "^24.0.0",
65
+ "jsdom": "^30.1.0",
66
+ "react": "^19.3.0",
67
+ "react-dom": "^19.3.0",
68
+ "typescript": "^5.6.0"
69
+ },
70
+ "repository": {
71
+ "type": "git",
72
+ "url": "git+https://github.com/STARDUSTLC666/dsh-calendar.git"
73
+ },
74
+ "bugs": {
75
+ "url": "https://github.com/STARDUSTLC666/dsh-calendar/issues"
76
+ },
77
+ "homepage": "https://github.com/STARDUSTLC666/dsh-calendar#readme",
78
+ "author": "stardustlc",
79
+ "packageManager": "pnpm@11.7.0"
80
+ }