anywork-library-plugin 0.0.0-stage → 0.1.0

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 CHANGED
@@ -1,3 +1,36 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # library-plugin
2
+
3
+ 资料库:文件 + 笔记。DSH Web 客户端插件。侧栏文案是「资料库」,槽位 id 是 `ziliaoku`,和 desk-panel 自带的 `desk-hub` 分开,可以同时装着,以后也可以只留这一份。
4
+
5
+ 界面跟工作台里的资料库一致:标题「资料库」,副标题「文件 + 笔记 · 放进来 = 全员可见」,页签「📁 文件 / 📝 笔记」。文件走公司盘(上传、文件夹、下载、移动、删除),笔记走知识库(搜索、记一条、查看;删除只给管理员)。
6
+
7
+ ## 安装和卸下
8
+
9
+ 在这个目录:
10
+
11
+ ```sh
12
+ npm pack anywork-library-plugin --registry https://registry.npmjs.org
13
+ dsh plugin --profile web add ./anywork-library-plugin-0.1.0.tgz
14
+ ```
15
+
16
+ `--profile` 写在子命令前面。`add` 会把本包写进该 profile 的 `dsh.profile.bundles`。浏览器入口是导出的 `./client`(`dsh.client.platform` 为 `web`,并依赖 `@deepseek-ai/dsh-client-ui-slots` 和 `@deepseek-ai/dsh-client-ui-sidebar`)。
17
+
18
+ 卸下:
19
+
20
+ ```sh
21
+ dsh plugin --profile web remove anywork-library-plugin
22
+ ```
23
+
24
+ 装上或卸下之后重启那个实例。`file:` 或 tgz 装进去的是副本,改源码不会自动更新。
25
+
26
+ 需要 Anywork 门户已经提供 `/portal/api/drive/*` 和 `/portal/api/kb/*`,并且浏览器带着登录会话打开工作台。没登录时面板会提示从门户再进。本包不自带盘和知识库服务。
27
+
28
+ 本地 Docker / 工作台安装先不做。
29
+
30
+ ## 开发
31
+
32
+ ```sh
33
+ npm test
34
+ ```
35
+
36
+ 改 `lib/api.js` 或 `lib/panel.js` 之后执行 `npm run assemble`,再提交生成的 `lib/client.js`。
@@ -0,0 +1,7 @@
1
+ # 资料库:向 Web profile 插入侧栏面板(客户端插件,不改 dsh 源码)。
2
+ # 行 id 用 ziliaoku,避开工作台 desk-panel 自带的侧栏 id desk-hub。
3
+ # 安装:dsh plugin --profile web add ./anywork-library-plugin-0.1.0.tgz
4
+ # `--profile` 写在子命令前面。
5
+ - insert:
6
+ - id: ziliaoku
7
+ name: 'anywork-library-plugin'
package/icon.svg ADDED
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round">
2
+ <path d="M3.5 7.5A1.5 1.5 0 0 1 5 6h4l2 2h8a1.5 1.5 0 0 1 1.5 1.5v8A1.5 1.5 0 0 1 19 19H5a1.5 1.5 0 0 1-1.5-1.5v-10z"/>
3
+ </svg>
package/lib/api.js ADDED
@@ -0,0 +1,110 @@
1
+ // Portal client for 资料库. Drive and notes stay on the Anywork host.
2
+
3
+ export const MAX_UPLOAD = 50 * 1024 * 1024;
4
+
5
+ export function canDeleteNote(role) {
6
+ return role === "admin";
7
+ }
8
+
9
+ export function portalErrorText(err) {
10
+ var msg = err && err.message ? String(err.message) : String(err || "");
11
+ var status = err && err.status;
12
+ if (status === 401 || /login required/i.test(msg)) {
13
+ return "读不到资料库(需要门户登录)。请从门户地址打开工作台后再试。";
14
+ }
15
+ return msg || "读取失败";
16
+ }
17
+
18
+ function readBody(response) {
19
+ return response.text().then(function (text) {
20
+ var data = null;
21
+ if (text) {
22
+ try { data = JSON.parse(text); } catch (e) { data = null; }
23
+ }
24
+ if (!response.ok) {
25
+ var err = new Error((data && data.error) || text || ("HTTP " + response.status));
26
+ err.status = response.status;
27
+ throw err;
28
+ }
29
+ return data == null ? {} : data;
30
+ });
31
+ }
32
+
33
+ export function createPortalApi(getFetch) {
34
+ function doFetch(url, options) {
35
+ var fetchImpl = typeof getFetch === "function" ? getFetch() : getFetch;
36
+ if (typeof fetchImpl !== "function") {
37
+ var err = new Error("fetch 不可用");
38
+ err.status = 0;
39
+ return Promise.reject(err);
40
+ }
41
+ var opts = options || {};
42
+ opts.credentials = opts.credentials || "same-origin";
43
+ return Promise.resolve(fetchImpl(url, opts)).then(readBody);
44
+ }
45
+
46
+ return {
47
+ listDrive: function (path) {
48
+ return doFetch("/portal/api/drive/list?path=" + encodeURIComponent(path || ""), {
49
+ headers: { accept: "application/json" },
50
+ });
51
+ },
52
+ upload: function (path, file) {
53
+ return doFetch(
54
+ "/portal/api/drive/upload?path=" + encodeURIComponent(path || "") + "&name=" + encodeURIComponent(file.name),
55
+ { method: "POST", body: file, headers: { accept: "application/json" } }
56
+ );
57
+ },
58
+ mkdir: function (path, name) {
59
+ return doFetch("/portal/api/drive/mkdir", {
60
+ method: "POST",
61
+ headers: { "content-type": "application/json", accept: "application/json" },
62
+ body: JSON.stringify({ path: path || "", name: name }),
63
+ });
64
+ },
65
+ rm: function (path) {
66
+ return doFetch("/portal/api/drive/rm", {
67
+ method: "POST",
68
+ headers: { "content-type": "application/json", accept: "application/json" },
69
+ body: JSON.stringify({ path: path }),
70
+ });
71
+ },
72
+ mv: function (from, to) {
73
+ return doFetch("/portal/api/drive/mv", {
74
+ method: "POST",
75
+ headers: { "content-type": "application/json", accept: "application/json" },
76
+ body: JSON.stringify({ from: from, to: to || "" }),
77
+ });
78
+ },
79
+ downloadUrl: function (path) {
80
+ return "/portal/api/drive/download?path=" + encodeURIComponent(path);
81
+ },
82
+ listNotes: function () {
83
+ return doFetch("/portal/api/kb/list", { headers: { accept: "application/json" } });
84
+ },
85
+ searchNotes: function (q) {
86
+ return doFetch("/portal/api/kb/search?q=" + encodeURIComponent(q), { headers: { accept: "application/json" } });
87
+ },
88
+ readNote: function (name) {
89
+ return doFetch("/portal/api/kb/note?name=" + encodeURIComponent(name), { headers: { accept: "application/json" } });
90
+ },
91
+ saveNote: function (input, lang) {
92
+ return doFetch("/portal/api/kb/save?lang=" + encodeURIComponent(lang || "zh"), {
93
+ method: "POST",
94
+ headers: { "content-type": "application/json", accept: "application/json" },
95
+ body: JSON.stringify({
96
+ title: input.title || "",
97
+ tags: input.tags || "",
98
+ content: input.content || "",
99
+ }),
100
+ });
101
+ },
102
+ removeNote: function (name, lang) {
103
+ return doFetch("/portal/api/kb/rm?lang=" + encodeURIComponent(lang || "zh"), {
104
+ method: "POST",
105
+ headers: { "content-type": "application/json", accept: "application/json" },
106
+ body: JSON.stringify({ name: name }),
107
+ });
108
+ },
109
+ };
110
+ }