dsh-apis-plugin 0.1.3 → 0.1.5
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/client.js +24 -61
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
// 浏览器半侧:在「插件配置」标签页为 dsh-apis-plugin
|
|
2
|
-
//
|
|
1
|
+
// 浏览器半侧:在「插件配置」标签页为 dsh-apis-plugin 命名空间注册一张展示卡片
|
|
2
|
+
// 接口的增删以 api.cfg 为唯一来源:这里只读展示列表,编辑请改 api.cfg 后点「加载API」重扫
|
|
3
|
+
// API 目录失焦或点「加载API」时自动保存,无页脚按钮
|
|
4
|
+
// 样式与 DOM 结构对齐原生 PluginCard(li 卡片 + SVG 箭头)
|
|
3
5
|
window.__ModuleLoader__.load({
|
|
4
6
|
id: "dsh-apis-plugin",
|
|
5
7
|
factory: (require) => {
|
|
@@ -25,22 +27,19 @@ window.__ModuleLoader__.load({
|
|
|
25
27
|
.apis-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
|
|
26
28
|
.apis-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}
|
|
27
29
|
.apis-body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:12px 0 8px;display:grid;gap:10px}
|
|
28
|
-
.apis-
|
|
29
|
-
.apis-saved{color:var(--dsw-alias-label-tertiary);margin-right:auto;font-size:12px}
|
|
30
|
+
.apis-saved{color:var(--dsw-alias-label-tertiary);font-size:12px;white-space:nowrap}
|
|
30
31
|
.apis-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}
|
|
31
32
|
.apis-btn:disabled{opacity:.4;cursor:default}
|
|
32
33
|
.apis-discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}
|
|
33
34
|
.apis-discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}
|
|
34
|
-
.apis-save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
|
|
35
35
|
.apis-row{display:flex;align-items:center;gap:8px}
|
|
36
36
|
.apis-rowLabel{width:44px;flex-shrink:0;font-size:13px;color:var(--dsw-alias-label-primary)}
|
|
37
37
|
.apis-rowLabelWide{width:auto;white-space:nowrap}
|
|
38
38
|
.apis-hr{width:100%;height:0;border:0;border-top:.5px solid var(--dsw-alias-border-l2);margin:0}
|
|
39
39
|
.apis-input{box-sizing:border-box;flex:1;min-width:0;font:inherit;color:var(--dsw-alias-label-primary);background:transparent;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;padding:6px 10px}
|
|
40
|
-
.apis-
|
|
41
|
-
.apis-
|
|
42
|
-
.apis-
|
|
43
|
-
.apis-add:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
40
|
+
.apis-item{display:flex;align-items:center;gap:8px;min-width:0}
|
|
41
|
+
.apis-itemText{flex:1;min-width:0;font-size:13px;color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:6px 10px;border:.5px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3)}
|
|
42
|
+
.apis-empty{color:var(--dsw-alias-label-tertiary);font-size:13px;padding:4px 0}
|
|
44
43
|
`;
|
|
45
44
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=dsh-apis-plugin]") === null) {
|
|
46
45
|
const tag = document.createElement("style");
|
|
@@ -81,33 +80,23 @@ window.__ModuleLoader__.load({
|
|
|
81
80
|
|
|
82
81
|
function ApisCard(props) {
|
|
83
82
|
const state = props.useApisCard((s) => s);
|
|
84
|
-
const [draft, setDraft] = react.useState(null); // string[],null 表示未编辑
|
|
85
83
|
const [dirDraft, setDirDraft] = react.useState(null); // 文档目录,null 表示未编辑
|
|
86
|
-
const [saving, setSaving] = react.useState(false);
|
|
87
84
|
const [loading, setLoading] = react.useState(false); // 加载API 扫描中
|
|
88
|
-
const [saved, setSaved] = react.useState(false); // 保存成功后短暂提示
|
|
89
85
|
const [loaded, setLoaded] = react.useState(false); // 加载API 完成后短暂提示
|
|
90
86
|
const [open, setOpen] = react.useState(false); // 折叠态只显示标题行
|
|
91
87
|
const ready = state.status === "ready" && state.writable;
|
|
92
88
|
|
|
93
|
-
/**
|
|
94
|
-
const list =
|
|
95
|
-
const dirty = draft !== null;
|
|
89
|
+
/** 只读展示的接口列表:来自 api.cfg(服务端扫描回写) */
|
|
90
|
+
const list = (state.value?.endpoints ?? []).map(String);
|
|
96
91
|
/** 当前展示的文档目录:编辑中取 dirDraft,否则取已保存值 */
|
|
97
92
|
const savedDir = state.value?.apiDir ?? "";
|
|
98
93
|
const shownDir = dirDraft ?? savedDir;
|
|
99
94
|
const dirDirty = dirDraft !== null && dirDraft !== savedDir;
|
|
100
95
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (dirDirty) await scope.set("apiDir", dirDraft); // 只存配置,扫描交给「加载API」
|
|
105
|
-
if (dirty) await scope.set("endpoints", draft);
|
|
106
|
-
setSaving(false);
|
|
107
|
-
setDraft(null);
|
|
96
|
+
/** 目录失焦时自动保存(点「加载API」也会先写入目录) */
|
|
97
|
+
function commitDir() {
|
|
98
|
+
if (dirDirty && ready) scope.set("apiDir", dirDraft);
|
|
108
99
|
setDirDraft(null);
|
|
109
|
-
setSaved(true); // 显示「已保存」提示,2 秒后消失
|
|
110
|
-
setTimeout(() => setSaved(false), 2000);
|
|
111
100
|
}
|
|
112
101
|
|
|
113
102
|
/** 加载API:把目录写入配置并翻转 scanToken,服务端 watch 重扫 apis.txt 后回写接口列表 */
|
|
@@ -125,21 +114,12 @@ window.__ModuleLoader__.load({
|
|
|
125
114
|
}
|
|
126
115
|
}
|
|
127
116
|
|
|
128
|
-
//
|
|
117
|
+
// 只读单行:接口N 标签 + 路径文本
|
|
129
118
|
const row = (v, i) => react_jsx_runtime.jsxs("div", {
|
|
130
|
-
className: "apis-
|
|
119
|
+
className: "apis-item",
|
|
131
120
|
children: [
|
|
132
121
|
react_jsx_runtime.jsx("div", { className: "apis-rowLabel", children: `接口${i + 1}` }),
|
|
133
|
-
react_jsx_runtime.jsx("
|
|
134
|
-
value: v, disabled: !ready || saving,
|
|
135
|
-
onChange: (e) => setDraft(list.map((x, j) => (j === i ? e.target.value : x))),
|
|
136
|
-
className: "apis-input",
|
|
137
|
-
}),
|
|
138
|
-
react_jsx_runtime.jsx("button", {
|
|
139
|
-
type: "button", disabled: !ready || saving, "aria-label": `删除接口${i + 1}`,
|
|
140
|
-
onClick: () => setDraft(list.filter((_, j) => j !== i)),
|
|
141
|
-
className: "apis-remove", children: "✕",
|
|
142
|
-
}),
|
|
122
|
+
react_jsx_runtime.jsx("span", { className: "apis-itemText", title: v, children: v }),
|
|
143
123
|
],
|
|
144
124
|
});
|
|
145
125
|
|
|
@@ -156,24 +136,26 @@ window.__ModuleLoader__.load({
|
|
|
156
136
|
children: [
|
|
157
137
|
react_jsx_runtime.jsxs("div", { className: "apis-headText", children: [
|
|
158
138
|
react_jsx_runtime.jsx("span", { className: "apis-name", children: "通用接口管理插件" }),
|
|
159
|
-
react_jsx_runtime.jsx("span", { className: "apis-description", children: "
|
|
139
|
+
react_jsx_runtime.jsx("span", { className: "apis-description", children: "接口列表(来源:api.cfg)" }),
|
|
160
140
|
] }),
|
|
161
141
|
react_jsx_runtime.jsx(Chevron, { open }),
|
|
162
142
|
],
|
|
163
143
|
}),
|
|
164
|
-
// 展开体:API配置目录行 + 分隔线 +
|
|
144
|
+
// 展开体:API配置目录行 + 分隔线 + 接口行列表(只读)
|
|
165
145
|
open && react_jsx_runtime.jsxs("div", { className: "apis-body", children: [
|
|
166
|
-
// API配置:文档目录(
|
|
146
|
+
// API配置:文档目录(api.cfg / api_doc.md 所在目录,失焦自动保存)+ 加载API 重扫按钮
|
|
167
147
|
react_jsx_runtime.jsxs("div", { className: "apis-row", children: [
|
|
168
148
|
react_jsx_runtime.jsx("div", { className: "apis-rowLabel apis-rowLabelWide", children: "API配置" }),
|
|
169
149
|
react_jsx_runtime.jsx("input", {
|
|
170
|
-
value: shownDir, disabled: !ready ||
|
|
150
|
+
value: shownDir, disabled: !ready || loading,
|
|
171
151
|
onChange: (e) => setDirDraft(e.target.value),
|
|
152
|
+
onBlur: commitDir,
|
|
153
|
+
onKeyDown: (e) => { if (e.key === "Enter") e.currentTarget.blur(); },
|
|
172
154
|
placeholder: "api.cfg / api_doc.md 所在目录",
|
|
173
155
|
className: "apis-input",
|
|
174
156
|
}),
|
|
175
157
|
react_jsx_runtime.jsx("button", {
|
|
176
|
-
type: "button", disabled: !ready ||
|
|
158
|
+
type: "button", disabled: !ready || loading || !shownDir.trim(),
|
|
177
159
|
onClick: loadApis,
|
|
178
160
|
className: "apis-btn apis-discard", children: loading ? "扫描中…" : "加载API",
|
|
179
161
|
}),
|
|
@@ -181,26 +163,7 @@ window.__ModuleLoader__.load({
|
|
|
181
163
|
] }),
|
|
182
164
|
react_jsx_runtime.jsx("hr", { className: "apis-hr" }),
|
|
183
165
|
!state.writable && react_jsx_runtime.jsx("span", { className: "apis-description", children: "只读" }),
|
|
184
|
-
list.map(row),
|
|
185
|
-
react_jsx_runtime.jsx("button", {
|
|
186
|
-
type: "button", disabled: !ready || saving,
|
|
187
|
-
onClick: () => setDraft([...list, ""]),
|
|
188
|
-
className: "apis-add", children: "+ 添加接口",
|
|
189
|
-
}),
|
|
190
|
-
react_jsx_runtime.jsxs("div", { className: "apis-footer", children: [
|
|
191
|
-
// 保存成功后的短暂提示(占按钮行左侧)
|
|
192
|
-
react_jsx_runtime.jsx("span", { className: "apis-saved", children: saved ? "已保存" : "" }),
|
|
193
|
-
react_jsx_runtime.jsx("button", {
|
|
194
|
-
type: "button", disabled: (!dirty && !dirDirty) || saving,
|
|
195
|
-
onClick: () => { setDraft(null); setDirDraft(null); },
|
|
196
|
-
className: "apis-btn apis-discard", children: "放弃修改",
|
|
197
|
-
}),
|
|
198
|
-
react_jsx_runtime.jsx("button", {
|
|
199
|
-
type: "button", disabled: !ready || (!dirty && !dirDirty) || saving,
|
|
200
|
-
onClick: save, children: saving ? "保存中…" : "保存",
|
|
201
|
-
className: "apis-btn apis-save",
|
|
202
|
-
}),
|
|
203
|
-
] }),
|
|
166
|
+
list.length ? list.map(row) : react_jsx_runtime.jsx("span", { className: "apis-empty", children: "暂无接口:请在 API 目录下的 api.cfg 中配置 apis,然后点击「加载API」" }),
|
|
204
167
|
] }),
|
|
205
168
|
],
|
|
206
169
|
});
|