dsh-prompt-customizer 0.2.7 → 0.3.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/LICENSE +21 -21
- package/README.en.md +13 -32
- package/README.i18n.yaml +2 -2
- package/README.md +45 -38
- package/client/client.js +42 -25
- package/client/client.js.map +1 -1
- package/cordis.patch.yml +8 -8
- package/lib/index.js +270 -339
- package/lib/schema.js +51 -69
- package/package.json +61 -61
- package/src/client/PresetsTab.tsx +110 -110
- package/src/client/PreviewTab.tsx +61 -66
- package/src/client/PreviewTools.tsx +31 -31
- package/src/client/SectionsTab.tsx +202 -201
- package/src/client/ToolsTab.tsx +48 -48
- package/src/client/index.ts +116 -115
- package/src/client/locales.ts +101 -97
- package/src/client/presets.ts +268 -268
- package/src/client/styles.ts +41 -41
- package/src/client/types.ts +50 -75
- package/lib/client.js +0 -344
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 DreamsTOF
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DreamsTOF
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) plugin that lets you control the **system prompt** and the **tool catalog** from a settings-panel UI.
|
|
6
6
|
|
|
7
|
-
Plugin-injected prompt sections
|
|
7
|
+
Plugin-injected prompt sections can pollute your system prompt. This plugin lets you **block**, **replace**, **inject**, and **reorder** prompt sections by name, and **hide tools** from the model catalog — all live, without touching the other plugins.
|
|
8
|
+
|
|
9
|
+

|
|
8
10
|
|
|
9
11
|
## Features
|
|
10
12
|
|
|
@@ -13,10 +15,18 @@ Plugin-injected prompt sections (from other plugins) can pollute your system pro
|
|
|
13
15
|
- **Replace** a section's text (the original text is echoed for editing, including dynamically generated sections).
|
|
14
16
|
- **Inject** brand-new sections.
|
|
15
17
|
- **Reorder** sections with ↑/↓ arrows or **drag & drop** (HTML5). Order is stored as a virtual 0-based index, so there are never duplicate or fractional orders.
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
16
21
|
- **Tools**
|
|
17
22
|
- **Blacklist** (`exclude`): hide the listed tools.
|
|
18
23
|
- **Whitelist** (`include`): keep only the listed tools (wins over exclude).
|
|
19
24
|
- Only the model-facing catalog is affected — tools and routes keep working.
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+

|
|
28
|
+

|
|
29
|
+
|
|
20
30
|
- **Presets**
|
|
21
31
|
- **Save** the current customization as a preset (full snapshot).
|
|
22
32
|
- **Apply** a preset: same-name sections are overridden, preset-only sections are added, and current sections outside the preset list are disabled by default.
|
|
@@ -24,6 +34,8 @@ Plugin-injected prompt sections (from other plugins) can pollute your system pro
|
|
|
24
34
|
- Presets store **relative order** (each section records the section it follows), so they stay portable across prompts with different section sets.
|
|
25
35
|
- Multiple presets can be stored locally; only one is active at a time.
|
|
26
36
|
|
|
37
|
+

|
|
38
|
+
|
|
27
39
|
## Installation
|
|
28
40
|
|
|
29
41
|
Install from npm (replace `web` with your profile name):
|
|
@@ -64,37 +76,6 @@ Toggle tools to hide them (blacklist), or switch to whitelist mode to keep only
|
|
|
64
76
|
- **Export** — download the preset as JSON.
|
|
65
77
|
- **Import** — load a preset JSON file (same-name presets are skipped).
|
|
66
78
|
|
|
67
|
-
## Configuration
|
|
68
|
-
|
|
69
|
-
The plugin stores its config in the dsh settings document under the `prompt-customizer` namespace (`~/.dsh/settings.yaml`). You can edit it directly:
|
|
70
|
-
|
|
71
|
-
```yaml
|
|
72
|
-
prompt-customizer:
|
|
73
|
-
# Block these prompt sections by name.
|
|
74
|
-
sections:
|
|
75
|
-
- plugin:some-plugin
|
|
76
|
-
# Replace a section's text by name (original order kept).
|
|
77
|
-
replace:
|
|
78
|
-
system: 'You are a helpful coding assistant.'
|
|
79
|
-
# Inject / override sections (name + order + text).
|
|
80
|
-
inject:
|
|
81
|
-
- name: tool:read
|
|
82
|
-
order: 0
|
|
83
|
-
text: ''
|
|
84
|
-
# Tool catalog filtering.
|
|
85
|
-
tools:
|
|
86
|
-
exclude: []
|
|
87
|
-
include: []
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
| Field | Type | Description |
|
|
91
|
-
| --- | --- | --- |
|
|
92
|
-
| `sections` | `string[]` | Prompt section names to block. |
|
|
93
|
-
| `replace` | `Record<string, string>` | Replacement text per section name. |
|
|
94
|
-
| `inject` | `{name, order, text}[]` | Sections to inject or override (order controls splice position). |
|
|
95
|
-
| `tools.exclude` | `string[]` | Tool names to hide. |
|
|
96
|
-
| `tools.include` | `string[]` | When non-empty, keep only these tools (wins over `exclude`). |
|
|
97
|
-
|
|
98
79
|
## Development
|
|
99
80
|
|
|
100
81
|
```bash
|
package/README.i18n.yaml
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
en: README.en.md
|
|
2
|
-
zh-CN: README.md
|
|
1
|
+
en: README.en.md
|
|
2
|
+
zh-CN: README.md
|
package/README.md
CHANGED
|
@@ -6,37 +6,44 @@
|
|
|
6
6
|
|
|
7
7
|
其他插件注入的提示词段可能会污染你的系统提示词。本插件让你可以按名称**屏蔽**、**替换**、**注入**和**排序**提示词段,并从模型目录中**隐藏工具**——全部实时生效,无需改动其他插件。
|
|
8
8
|
|
|
9
|
+

|
|
10
|
+
|
|
9
11
|
## 功能特性
|
|
10
12
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- 通过 **↑/↓ 箭头**或**拖拽**(HTML5)排序。顺序以虚拟的 0 起始下标存储,因此不会出现重复或小数 order
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
- **提示词段管理**
|
|
14
|
+
- **屏蔽**指定名称的段(从组装后的系统提示词中移除)
|
|
15
|
+
- **替换**某段的文本(编辑时会回显原始文本,包括动态生成的段)
|
|
16
|
+
- **注入**全新的段
|
|
17
|
+
- 通过 **↑/↓ 箭头**或**拖拽**(HTML5)排序。顺序以虚拟的 0 起始下标存储,因此不会出现重复或小数 order
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
- **工具过滤**
|
|
22
|
+
- 隐藏列出的工具
|
|
23
|
+
- 只影响面向模型的目录,工具与路由仍正常工作
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+

|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
- **预设系统**
|
|
30
|
+
- **保存**当前定制为预设(完整快照)
|
|
31
|
+
- **应用**预设:同名段被覆盖、预设独有段被添加、预设名单之外的当前段默认被屏蔽
|
|
32
|
+
- **导出 / 导入**预设为 JSON(完整快照)
|
|
33
|
+
- 预设存储**相对顺序**(每段记录它跟在哪个段之后),因此可跨不同段集合的提示词移植
|
|
34
|
+
- 本地可保存多个预设,同一时间只能激活一个
|
|
35
|
+
|
|
36
|
+

|
|
26
37
|
|
|
27
38
|
## 安装
|
|
28
39
|
|
|
29
|
-
从 npm
|
|
40
|
+
从 npm 安装:
|
|
30
41
|
|
|
31
42
|
```bash
|
|
32
43
|
dsh plugin --profile web add dsh-prompt-customizer
|
|
33
44
|
```
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
dsh plugin --profile web add /path/to/dsh-prompt-customizer
|
|
39
|
-
```
|
|
46
|
+
<br />
|
|
40
47
|
|
|
41
48
|
安装后,打开 dsh Web UI → **设置** → 侧边栏中的 **提示词定制**。
|
|
42
49
|
|
|
@@ -46,10 +53,10 @@ dsh plugin --profile web add /path/to/dsh-prompt-customizer
|
|
|
46
53
|
|
|
47
54
|
每一行代表一个提示词段,包含:
|
|
48
55
|
|
|
49
|
-
- **复选框**:屏蔽 /
|
|
50
|
-
-
|
|
51
|
-
- **↑/↓
|
|
52
|
-
- `#N` 徽标显示该段的虚拟顺序(0
|
|
56
|
+
- **复选框**:屏蔽 / 取消屏蔽
|
|
57
|
+
- **替换**按钮:编辑该段文本(默认回显原始文本)
|
|
58
|
+
- **↑/↓ 箭头**和**拖拽手柄**:调整顺序
|
|
59
|
+
- `#N` 徽标显示该段的虚拟顺序(0 起始的位置)
|
|
53
60
|
|
|
54
61
|
底部的 **注入新段** 区域可按名称、顺序和文本添加全新段。
|
|
55
62
|
|
|
@@ -59,10 +66,10 @@ dsh plugin --profile web add /path/to/dsh-prompt-customizer
|
|
|
59
66
|
|
|
60
67
|
### 预设 Tab
|
|
61
68
|
|
|
62
|
-
- **保存当前为预设**:捕获当前的提示词 /
|
|
63
|
-
-
|
|
64
|
-
- **导出**:将预设下载为 JSON
|
|
65
|
-
- **导入**:加载预设 JSON
|
|
69
|
+
- **保存当前为预设**:捕获当前的提示词 / 工具定制
|
|
70
|
+
- **应用**:激活某个预设(覆盖同名段、添加预设独有段、屏蔽预设名单之外的当前段)
|
|
71
|
+
- **导出**:将预设下载为 JSON
|
|
72
|
+
- **导入**:加载预设 JSON 文件(同名预设会被跳过)
|
|
66
73
|
|
|
67
74
|
## 配置
|
|
68
75
|
|
|
@@ -75,25 +82,25 @@ prompt-customizer:
|
|
|
75
82
|
- plugin:some-plugin
|
|
76
83
|
# 按名称替换某段文本(保留原始顺序)。
|
|
77
84
|
replace:
|
|
78
|
-
system:
|
|
85
|
+
system: "You are a helpful coding assistant."
|
|
79
86
|
# 注入 / 覆盖段(名称 + 顺序 + 文本)。
|
|
80
87
|
inject:
|
|
81
88
|
- name: tool:read
|
|
82
89
|
order: 0
|
|
83
|
-
text:
|
|
90
|
+
text: ""
|
|
84
91
|
# 工具目录过滤。
|
|
85
92
|
tools:
|
|
86
93
|
exclude: []
|
|
87
94
|
include: []
|
|
88
95
|
```
|
|
89
96
|
|
|
90
|
-
| 字段
|
|
91
|
-
|
|
|
92
|
-
| `sections`
|
|
93
|
-
| `replace`
|
|
94
|
-
| `inject`
|
|
95
|
-
| `tools.exclude` | `string[]`
|
|
96
|
-
| `tools.include` | `string[]`
|
|
97
|
+
| 字段 | 类型 | 说明 |
|
|
98
|
+
| --------------- | ------------------------ | ------------------------------------------ |
|
|
99
|
+
| `sections` | `string[]` | 要屏蔽的提示词段名称。 |
|
|
100
|
+
| `replace` | `Record<string, string>` | 每个段名称对应的替换文本。 |
|
|
101
|
+
| `inject` | `{name, order, text}[]` | 要注入或覆盖的段(order 控制拼接位置)。 |
|
|
102
|
+
| `tools.exclude` | `string[]` | 要隐藏的工具名称。 |
|
|
103
|
+
| `tools.include` | `string[]` | 非空时仅保留这些工具(优先于 `exclude`)。 |
|
|
97
104
|
|
|
98
105
|
## 开发
|
|
99
106
|
|
package/client/client.js
CHANGED
|
@@ -24,6 +24,7 @@ window.__ModuleLoader__.load({
|
|
|
24
24
|
system: "系统",
|
|
25
25
|
replace: "编辑",
|
|
26
26
|
clearReplace: "清除",
|
|
27
|
+
clearInput: "清空",
|
|
27
28
|
injectNew: "注入新段",
|
|
28
29
|
name: "名称",
|
|
29
30
|
order: "顺序",
|
|
@@ -51,6 +52,7 @@ window.__ModuleLoader__.load({
|
|
|
51
52
|
apply: "应用",
|
|
52
53
|
export: "导出",
|
|
53
54
|
delete: "删除",
|
|
55
|
+
restore: "还原",
|
|
54
56
|
active: "使用中",
|
|
55
57
|
preset: "预设"
|
|
56
58
|
},
|
|
@@ -70,6 +72,7 @@ window.__ModuleLoader__.load({
|
|
|
70
72
|
system: "System",
|
|
71
73
|
replace: "Replace",
|
|
72
74
|
clearReplace: "Clear",
|
|
75
|
+
clearInput: "Clear",
|
|
73
76
|
injectNew: "Inject section",
|
|
74
77
|
name: "Name",
|
|
75
78
|
order: "Order",
|
|
@@ -97,6 +100,7 @@ window.__ModuleLoader__.load({
|
|
|
97
100
|
apply: "Apply",
|
|
98
101
|
export: "Export",
|
|
99
102
|
delete: "Delete",
|
|
103
|
+
restore: "Restore",
|
|
100
104
|
active: "Active",
|
|
101
105
|
preset: "Preset"
|
|
102
106
|
}
|
|
@@ -377,7 +381,10 @@ window.__ModuleLoader__.load({
|
|
|
377
381
|
source: isCustom ? "custom" : "system"
|
|
378
382
|
});
|
|
379
383
|
}
|
|
380
|
-
return [...map.values()].sort((a, b) => a.order - b.order)
|
|
384
|
+
return [...map.values()].sort((a, b) => a.order - b.order).map((sec, i) => ({
|
|
385
|
+
...sec,
|
|
386
|
+
order: i
|
|
387
|
+
}));
|
|
381
388
|
}
|
|
382
389
|
/**
|
|
383
390
|
* Resolve a preset's relative order into an absolute ordered list (0..n-1).
|
|
@@ -576,7 +583,7 @@ window.__ModuleLoader__.load({
|
|
|
576
583
|
scope.set("replace", next);
|
|
577
584
|
setEditing(null);
|
|
578
585
|
};
|
|
579
|
-
const
|
|
586
|
+
const restoreReplace = (name) => {
|
|
580
587
|
const next = { ...replace };
|
|
581
588
|
delete next[name];
|
|
582
589
|
scope.set("replace", next);
|
|
@@ -705,19 +712,26 @@ window.__ModuleLoader__.load({
|
|
|
705
712
|
(0, react.createElement)("span", { style: s.code }, sec.name),
|
|
706
713
|
(0, react.createElement)("span", { style: s.orderTag }, "#" + index),
|
|
707
714
|
(0, react.createElement)("span", { style: sec.source === "custom" ? s.badgeCustom : s.badgeSystem }, sec.source === "custom" ? t("manual") : t("system")),
|
|
708
|
-
sec.
|
|
715
|
+
replace[sec.name] ? (0, react.createElement)("span", { style: s.badgeReplaced }, t("replaced")) : null
|
|
709
716
|
]), isEditing ? (0, react.createElement)("div", { style: s.editBox }, [(0, react.createElement)("textarea", {
|
|
710
717
|
style: s.editInput,
|
|
711
718
|
value: draft,
|
|
712
719
|
onChange: (e) => setDraft(e.target.value),
|
|
713
720
|
rows: 3
|
|
714
|
-
}), (0, react.createElement)("div", { style: s.injectRow }, [
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
+
}), (0, react.createElement)("div", { style: s.injectRow }, [
|
|
722
|
+
(0, react.createElement)("button", {
|
|
723
|
+
style: s.mini,
|
|
724
|
+
onClick: () => commitReplace(sec.name)
|
|
725
|
+
}, t("save")),
|
|
726
|
+
(0, react.createElement)("button", {
|
|
727
|
+
style: s.mini,
|
|
728
|
+
onClick: () => setEditing(null)
|
|
729
|
+
}, t("clearInput")),
|
|
730
|
+
sec.source !== "custom" && replace[sec.name] ? (0, react.createElement)("button", {
|
|
731
|
+
style: s.mini,
|
|
732
|
+
onClick: () => restoreReplace(sec.name)
|
|
733
|
+
}, t("restore")) : null
|
|
734
|
+
])]) : (0, react.createElement)("div", { style: s.preview }, String(replace[sec.name] ?? sec.text ?? "").slice(0, 140) || (sec.source === "custom" ? t("empty") : t("dynamic")))]),
|
|
721
735
|
(0, react.createElement)("div", { style: s.arrowCol }, [(0, react.createElement)("button", {
|
|
722
736
|
style: s.arrow,
|
|
723
737
|
disabled: index === 0,
|
|
@@ -729,10 +743,14 @@ window.__ModuleLoader__.load({
|
|
|
729
743
|
onClick: () => moveOrder(index, 1),
|
|
730
744
|
title: t("moveDown")
|
|
731
745
|
}, "↓")]),
|
|
732
|
-
(0, react.createElement)("button", {
|
|
746
|
+
isEditing ? null : (0, react.createElement)("button", {
|
|
733
747
|
style: s.mini,
|
|
734
|
-
onClick: () =>
|
|
735
|
-
},
|
|
748
|
+
onClick: () => startReplace(sec.name, String(sec.text ?? ""))
|
|
749
|
+
}, t("replace")),
|
|
750
|
+
!isEditing && sec.source !== "custom" && replace[sec.name] ? (0, react.createElement)("button", {
|
|
751
|
+
style: s.mini,
|
|
752
|
+
onClick: () => restoreReplace(sec.name)
|
|
753
|
+
}, t("restore")) : null,
|
|
736
754
|
sec.source === "custom" ? (0, react.createElement)("button", {
|
|
737
755
|
style: s.mini,
|
|
738
756
|
onClick: () => removeCustom(sec.name),
|
|
@@ -966,33 +984,28 @@ window.__ModuleLoader__.load({
|
|
|
966
984
|
* after every plugin's filter, and the tools the current preset will inject
|
|
967
985
|
* (whitelist-style, after include/exclude). Neither view edits config. */
|
|
968
986
|
const PREVIEW_URL = "/api/prompt-customizer/preview";
|
|
969
|
-
function PreviewTab({ scope, t }) {
|
|
987
|
+
function PreviewTab({ scope, t, active, refreshId }) {
|
|
970
988
|
const [sub, setSub] = (0, react.useState)("prompt");
|
|
971
989
|
const [data, setData] = (0, react.useState)(null);
|
|
972
990
|
const [error, setError] = (0, react.useState)(null);
|
|
973
991
|
const inFlight = (0, react.useRef)(false);
|
|
974
|
-
const pending = (0, react.useRef)(false);
|
|
975
992
|
const load = () => {
|
|
976
|
-
if (inFlight.current)
|
|
977
|
-
pending.current = true;
|
|
978
|
-
return;
|
|
979
|
-
}
|
|
993
|
+
if (inFlight.current) return;
|
|
980
994
|
inFlight.current = true;
|
|
981
995
|
setData(null);
|
|
982
|
-
fetch(PREVIEW_URL
|
|
996
|
+
fetch(`${PREVIEW_URL}?t=${Date.now()}`).then((r) => r.json()).then((body) => {
|
|
983
997
|
if (body && body.ok === false) throw new Error(body.error ?? "preview failed");
|
|
984
998
|
setData(body);
|
|
985
999
|
setError(null);
|
|
986
1000
|
}).catch((e) => setError(String(e instanceof Error ? e.message : e))).finally(() => {
|
|
987
1001
|
inFlight.current = false;
|
|
988
|
-
if (pending.current) {
|
|
989
|
-
pending.current = false;
|
|
990
|
-
load();
|
|
991
|
-
}
|
|
992
1002
|
});
|
|
993
1003
|
};
|
|
994
1004
|
(0, react.useEffect)(load, []);
|
|
995
1005
|
(0, react.useEffect)(() => scope.subscribe(load), [scope]);
|
|
1006
|
+
(0, react.useEffect)(() => {
|
|
1007
|
+
if (active) load();
|
|
1008
|
+
}, [active, refreshId]);
|
|
996
1009
|
return (0, react.createElement)("div", { style: s.list }, [
|
|
997
1010
|
(0, react.createElement)("div", { style: s.bar }, [(0, react.createElement)("button", {
|
|
998
1011
|
style: sub === "prompt" ? s.tabActive : s.tab,
|
|
@@ -1050,11 +1063,13 @@ window.__ModuleLoader__.load({
|
|
|
1050
1063
|
const [inv, setInv] = (0, react.useState)(null);
|
|
1051
1064
|
const [tab, setTab] = (0, react.useState)("sections");
|
|
1052
1065
|
const [error, setError] = (0, react.useState)(null);
|
|
1066
|
+
const [refreshId, setRefreshId] = (0, react.useState)(0);
|
|
1053
1067
|
(0, react.useEffect)(() => scope.subscribe(() => setSnap(scope.getSnapshot())), [scope]);
|
|
1054
1068
|
const refresh = () => {
|
|
1055
1069
|
fetch(INVENTORY_URL).then((r) => r.json()).then((data) => {
|
|
1056
1070
|
setInv(data);
|
|
1057
1071
|
setError(null);
|
|
1072
|
+
setRefreshId((n) => n + 1);
|
|
1058
1073
|
}).catch((e) => setError(String(e instanceof Error ? e.message : e)));
|
|
1059
1074
|
};
|
|
1060
1075
|
(0, react.useEffect)(refresh, []);
|
|
@@ -1109,7 +1124,9 @@ window.__ModuleLoader__.load({
|
|
|
1109
1124
|
t
|
|
1110
1125
|
}) : (0, react.createElement)(PreviewTab, {
|
|
1111
1126
|
scope,
|
|
1112
|
-
t
|
|
1127
|
+
t,
|
|
1128
|
+
active: tab === "preview",
|
|
1129
|
+
refreshId
|
|
1113
1130
|
})
|
|
1114
1131
|
]);
|
|
1115
1132
|
}
|