From 6e4fbb7104fe9ac97315261cf8b474a032173b22 Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Sun, 22 Sep 2024 00:28:36 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ghostchu/peerbanhelper/Main.java | 17 ++- .../peerbanhelper/PeerBanHelperServer.java | 1 + .../ghostchu/peerbanhelper/btn/BtnConfig.java | 10 +- .../impl/webapi/WebConfigController.java | 142 ++++++++++++++++++ 4 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/WebConfigController.java diff --git a/src/main/java/com/ghostchu/peerbanhelper/Main.java b/src/main/java/com/ghostchu/peerbanhelper/Main.java index ec38ce0b8b..628338ed5c 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/Main.java +++ b/src/main/java/com/ghostchu/peerbanhelper/Main.java @@ -13,11 +13,12 @@ import com.ghostchu.peerbanhelper.util.PBHLibrariesLoader; import com.ghostchu.peerbanhelper.util.Slf4jLogAppender; import com.ghostchu.simplereloadlib.ReloadManager; +import com.ghostchu.simplereloadlib.ReloadResult; +import com.ghostchu.simplereloadlib.ReloadableContainer; import com.google.common.eventbus.EventBus; import com.google.common.io.ByteStreams; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.apache.logging.log4j.core.config.plugins.util.PluginManager; import org.bspfsystems.yamlconfiguration.configuration.InvalidConfigurationException; import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; import org.jetbrains.annotations.Nullable; @@ -103,7 +104,7 @@ public static void main(String[] args) { DEF_LOCALE = mainConfig.getString("language"); if (DEF_LOCALE == null || DEF_LOCALE.equalsIgnoreCase("default")) { DEF_LOCALE = System.getenv("PBH_USER_LOCALE"); - if(DEF_LOCALE == null) { + if (DEF_LOCALE == null) { DEF_LOCALE = Locale.getDefault().toLanguageTag(); } } @@ -165,9 +166,9 @@ private static void setupConfDirectory(String[] args) { root = new File(System.getenv("LOCALAPPDATA"), "PeerBanHelper").getAbsolutePath(); } else { var dataDirectory = new File(System.getProperty("user.home")).toPath(); - if(osName.contains("mac")){ + if (osName.contains("mac")) { dataDirectory = dataDirectory.resolve("/Library/Application Support"); - }else{ + } else { dataDirectory = dataDirectory.resolve(".config"); } root = dataDirectory.resolve("PeerBanHelper").toAbsolutePath().toString(); @@ -342,7 +343,7 @@ public static String decapitalize(String name) { return name; } if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && - Character.isUpperCase(name.charAt(0))) { + Character.isUpperCase(name.charAt(0))) { return name; } char chars[] = name.toCharArray(); @@ -391,4 +392,10 @@ public static void unregisterBean(String beanName) { defaultListableBeanFactory.removeBeanDefinition(beanName); } + public static Map reloadConfig() { + mainConfig = loadConfiguration(mainConfigFile); + profileConfig = loadConfiguration(profileConfigFile); + setupProxySettings(); + return reloadManager.reload(); + } } \ No newline at end of file diff --git a/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java b/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java index 1413e05302..01a4c42f72 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java +++ b/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java @@ -654,6 +654,7 @@ private void registerModules() { moduleManager.register(PBHGeneralController.class); moduleManager.register(PBHTorrentController.class); moduleManager.register(PBHPeerController.class); + moduleManager.register(WebConfigController.class); } public Map>> collectPeers() { diff --git a/src/main/java/com/ghostchu/peerbanhelper/btn/BtnConfig.java b/src/main/java/com/ghostchu/peerbanhelper/btn/BtnConfig.java index be3f950bb8..bdf910b670 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/btn/BtnConfig.java +++ b/src/main/java/com/ghostchu/peerbanhelper/btn/BtnConfig.java @@ -2,6 +2,9 @@ import com.ghostchu.peerbanhelper.PeerBanHelperServer; import com.ghostchu.peerbanhelper.text.Lang; +import com.ghostchu.simplereloadlib.ReloadResult; +import com.ghostchu.simplereloadlib.ReloadStatus; +import com.ghostchu.simplereloadlib.Reloadable; import lombok.extern.slf4j.Slf4j; import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection; import org.springframework.beans.factory.annotation.Autowired; @@ -13,7 +16,7 @@ @Configuration @Slf4j -public class BtnConfig { +public class BtnConfig implements Reloadable { @Autowired private PeerBanHelperServer server; @Autowired @@ -37,4 +40,9 @@ public BtnNetwork btnNetwork() { return null; } } + + @Override + public ReloadResult reloadModule() throws Exception { + return ReloadResult.builder().status(ReloadStatus.REQUIRE_RESTART).build(); + } } diff --git a/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/WebConfigController.java b/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/WebConfigController.java new file mode 100644 index 0000000000..f5d073d60f --- /dev/null +++ b/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/WebConfigController.java @@ -0,0 +1,142 @@ +package com.ghostchu.peerbanhelper.module.impl.webapi; + +import com.ghostchu.peerbanhelper.Main; +import com.ghostchu.peerbanhelper.module.AbstractFeatureModule; +import com.ghostchu.peerbanhelper.util.context.IgnoreScan; +import com.ghostchu.peerbanhelper.web.JavalinWebContainer; +import com.ghostchu.peerbanhelper.web.Role; +import com.ghostchu.peerbanhelper.web.wrapper.StdResp; +import com.ghostchu.simplereloadlib.ReloadResult; +import com.ghostchu.simplereloadlib.ReloadableContainer; +import io.javalin.http.Context; +import org.bspfsystems.yamlconfiguration.configuration.InvalidConfigurationException; +import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +@IgnoreScan +public class WebConfigController extends AbstractFeatureModule { + private final JavalinWebContainer javalinWebContainer; + + public WebConfigController(JavalinWebContainer javalinWebContainer) { + super(); + this.javalinWebContainer = javalinWebContainer; + } + + @Override + public boolean isConfigurable() { + return false; + } + + @Override + public @NotNull String getName() { + return "Web Config Editor"; + } + + @Override + public @NotNull String getConfigName() { + return "web-config-editor"; + } + + @Override + public void onEnable() { + javalinWebContainer.javalin() + .get("/api/config", this::listConfig, Role.USER_READ) + .get("/api/config/{configId}", this::retrieveConfigContent, Role.USER_WRITE) + .put("/api/config/{configId}", this::editConfig, Role.USER_WRITE); + } + + private void editConfig(Context ctx) throws IOException { + ConfigSaveRequest configSaveRequest = ctx.bodyAsClass(ConfigSaveRequest.class); + var test = new YamlConfiguration(); + try { + test.loadFromString(configSaveRequest.content()); + } catch (InvalidConfigurationException e) { + ctx.json(new StdResp(false, "Invalid configuration: " + e.getMessage(), null)); + return; + } + switch (ctx.pathParam("configId")) { + case "config.yml" -> { + Files.writeString(Main.getMainConfigFile().toPath(), configSaveRequest.content(), StandardCharsets.UTF_8); + ctx.json(new StdResp(true, "Configuration saved", processConfigReloading())); + } + case "profile.yml" -> { + Files.writeString(Main.getProfileConfigFile().toPath(), configSaveRequest.content(), StandardCharsets.UTF_8); + ctx.json(new StdResp(true, "Configuration saved", processConfigReloading())); + } + default -> { + throw new IllegalArgumentException("Invalid configId"); + } + } + } + + private void retrieveConfigContent(Context ctx) throws IOException { + switch (ctx.pathParam("configId")) { + case "config.yml" -> { + ctx.json(new StdResp(true, null, Files.readString(Main.getMainConfigFile().toPath(), StandardCharsets.UTF_8))); + } + case "profile.yml" -> { + ctx.json(new StdResp(true, null, Files.readString(Main.getProfileConfigFile().toPath(), StandardCharsets.UTF_8))); + } + default -> { + throw new IllegalArgumentException("Invalid configId"); + } + } + } + + + private void listConfig(Context ctx) { + ctx.json(new StdResp(true, null, new String[]{"config.yml", "profile.yml"})); + } + + @Override + public void onDisable() { + + } + + private List processConfigReloading() { + List list = new ArrayList<>(); + for (Map.Entry entry : Main.reloadConfig().entrySet()) { + String name = "???"; + var ref = entry.getKey().getReloadable(); + if (ref != null) { + var obj = ref.get(); + if (obj != null) { + name = obj.getClass().getName(); + } + } else { + if (entry.getKey().getReloadableMethod() != null) { + name = entry.getKey().getReloadableMethod().getName(); + } + } + list.add(new ConfigReloadEntryContainer( + name, + entry.getValue().getStatus().name(), + entry.getValue().getReason(), + entry.getValue().getException() == null ? null : entry.getValue().getException().getMessage() + )); + } + return list; + } + + record ConfigReloadEntryContainer( + String name, + String result, + String reason, + String errorMsg + ) { + + } + + record ConfigSaveRequest(String content) { + + } +} From b8f4b9316efdff997ff16788a15a58a60ffff4ae Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Sun, 22 Sep 2024 02:07:59 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=94=AF=E6=8C=81=20WebUI=20=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/impl/rule/IPBlackRuleList.java | 5 +- webui/package.json | 5 + webui/pnpm-lock.yaml | 283 ++++++++++++++---- webui/src/api/model/config.ts | 30 ++ webui/src/components/codeEditor.vue | 58 ++++ webui/src/locale/en-US.ts | 6 +- webui/src/locale/zh-CN.ts | 9 +- webui/src/main.ts | 2 + webui/src/router/index.ts | 19 ++ webui/src/service/config.ts | 51 ++++ webui/src/views/config/index.vue | 141 +++++++++ webui/src/views/config/locale/en-US.ts | 6 + webui/src/views/config/locale/zh-CN.ts | 6 + 13 files changed, 562 insertions(+), 59 deletions(-) create mode 100644 webui/src/api/model/config.ts create mode 100644 webui/src/components/codeEditor.vue create mode 100644 webui/src/service/config.ts create mode 100644 webui/src/views/config/index.vue create mode 100644 webui/src/views/config/locale/en-US.ts create mode 100644 webui/src/views/config/locale/zh-CN.ts diff --git a/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/IPBlackRuleList.java b/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/IPBlackRuleList.java index af355fafad..b5149e22f8 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/IPBlackRuleList.java +++ b/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/IPBlackRuleList.java @@ -23,6 +23,7 @@ import com.ghostchu.peerbanhelper.util.rule.matcher.IPMatcher; import com.ghostchu.peerbanhelper.web.wrapper.StdResp; import com.ghostchu.simplereloadlib.ReloadResult; +import com.ghostchu.simplereloadlib.ReloadStatus; import com.ghostchu.simplereloadlib.Reloadable; import com.github.mizosoft.methanol.MutableRequest; import com.google.common.hash.HashCode; @@ -108,8 +109,8 @@ public void onDisable() { @Override public ReloadResult reloadModule() throws Exception { - reloadConfig(); - return Reloadable.super.reloadModule(); + Thread.ofVirtual().start(this::reloadConfig); + return ReloadResult.builder().status(ReloadStatus.SCHEDULED).build(); } @Override diff --git a/webui/package.json b/webui/package.json index c0ffa18fab..ec524dcb4c 100644 --- a/webui/package.json +++ b/webui/package.json @@ -15,10 +15,14 @@ }, "dependencies": { "@arco-design/web-vue": "^2.56.2", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/lang-yaml": "github:codemirror/lang-yaml", "@dzangolab/flag-icon-css": "^3.4.5", "@octokit/core": "^6.1.2", "@octokit/request-error": "^6.1.4", "@vueuse/core": "^11.1.0", + "codemirror": "^5", + "codemirror-editor-vue3": "^2.8.0", "compare-versions": "^6.1.1", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.13", @@ -41,6 +45,7 @@ "@eslint/js": "^9.10.0", "@rushstack/eslint-patch": "^1.10.4", "@tsconfig/node20": "^20.1.4", + "@types/codemirror": "^5.60.15", "@types/eslint__js": "^8.42.3", "@types/lodash": "^4.17.7", "@types/mockjs": "^1.0.10", diff --git a/webui/pnpm-lock.yaml b/webui/pnpm-lock.yaml index 71371145e6..db5aaf8a55 100644 --- a/webui/pnpm-lock.yaml +++ b/webui/pnpm-lock.yaml @@ -16,6 +16,12 @@ importers: '@arco-design/web-vue': specifier: ^2.56.2 version: 2.56.2(vue@3.5.6(typescript@5.6.2)) + '@codemirror/lang-json': + specifier: ^6.0.1 + version: 6.0.1 + '@codemirror/lang-yaml': + specifier: github:codemirror/lang-yaml + version: https://codeload.github.com/codemirror/lang-yaml/tar.gz/4746470e7948943e9a88af677719bddfdf6d5a4e(@codemirror/view@6.33.0) '@dzangolab/flag-icon-css': specifier: ^3.4.5 version: 3.4.5 @@ -28,6 +34,12 @@ importers: '@vueuse/core': specifier: ^11.1.0 version: 11.1.0(vue@3.5.6(typescript@5.6.2)) + codemirror: + specifier: ^5 + version: 5.65.18 + codemirror-editor-vue3: + specifier: ^2.8.0 + version: 2.8.0(codemirror@5.65.18)(diff-match-patch@1.0.5)(vue@3.5.6(typescript@5.6.2)) compare-versions: specifier: ^6.1.1 version: 6.1.1 @@ -89,6 +101,9 @@ importers: '@tsconfig/node20': specifier: ^20.1.4 version: 20.1.4 + '@types/codemirror': + specifier: ^5.60.15 + version: 5.60.15 '@types/eslint__js': specifier: ^8.42.3 version: 8.42.3 @@ -384,143 +399,167 @@ packages: resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==} engines: {node: '>=6.9.0'} + '@codemirror/autocomplete@6.18.1': + resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + + '@codemirror/lang-json@6.0.1': + resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==} + + '@codemirror/lang-yaml@https://codeload.github.com/codemirror/lang-yaml/tar.gz/4746470e7948943e9a88af677719bddfdf6d5a4e': + resolution: {tarball: https://codeload.github.com/codemirror/lang-yaml/tar.gz/4746470e7948943e9a88af677719bddfdf6d5a4e} + version: 6.1.1 + + '@codemirror/language@6.10.3': + resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} + + '@codemirror/state@6.4.1': + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + + '@codemirror/view@6.33.0': + resolution: {integrity: sha512-AroaR3BvnjRW8fiZBalAaK+ZzB5usGgI014YKElYZvQdNH5ZIidHlO+cyf/2rWzyBFRkvG6VhiXeAEbC53P2YQ==} + '@dzangolab/flag-icon-css@3.4.5': resolution: {integrity: sha512-XqVAi0O/KITtznpMK5TP4D+rWfwst5lrsbPbes5c5SPMGjwK7fuvlTdEmG2XUrxzYqDTIPshywyzdVYKooGdGA==} '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==, tarball: https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz} + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==, tarball: https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz} + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==, tarball: https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz} + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==, tarball: https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz} + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==, tarball: https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz} + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==, tarball: https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz} + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==, tarball: https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz} + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==, tarball: https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz} + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==, tarball: https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz} + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==, tarball: https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz} + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==, tarball: https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz} + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==, tarball: https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz} + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==, tarball: https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz} + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==, tarball: https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz} + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==, tarball: https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz} + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==, tarball: https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz} + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==, tarball: https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz} + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==, tarball: https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz} + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==, tarball: https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz} + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==, tarball: https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz} + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==, tarball: https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz} + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==, tarball: https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz} + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==, tarball: https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz} + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -596,6 +635,21 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@lezer/common@1.2.1': + resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} + + '@lezer/highlight@1.2.1': + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + + '@lezer/json@1.0.2': + resolution: {integrity: sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==} + + '@lezer/lr@1.4.2': + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + + '@lezer/yaml@1.0.3': + resolution: {integrity: sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -660,82 +714,91 @@ packages: optional: true '@rollup/rollup-android-arm-eabi@4.21.3': - resolution: {integrity: sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz} + resolution: {integrity: sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==} cpu: [arm] os: [android] '@rollup/rollup-android-arm64@4.21.3': - resolution: {integrity: sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz} + resolution: {integrity: sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==} cpu: [arm64] os: [android] '@rollup/rollup-darwin-arm64@4.21.3': - resolution: {integrity: sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz} + resolution: {integrity: sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==} cpu: [arm64] os: [darwin] '@rollup/rollup-darwin-x64@4.21.3': - resolution: {integrity: sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz} + resolution: {integrity: sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==} cpu: [x64] os: [darwin] '@rollup/rollup-linux-arm-gnueabihf@4.21.3': - resolution: {integrity: sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz} + resolution: {integrity: sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.21.3': - resolution: {integrity: sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz} + resolution: {integrity: sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.21.3': - resolution: {integrity: sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz} + resolution: {integrity: sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.21.3': - resolution: {integrity: sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz} + resolution: {integrity: sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.21.3': - resolution: {integrity: sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz} + resolution: {integrity: sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.21.3': - resolution: {integrity: sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz} + resolution: {integrity: sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.21.3': - resolution: {integrity: sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz} + resolution: {integrity: sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.21.3': - resolution: {integrity: sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz} + resolution: {integrity: sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.21.3': - resolution: {integrity: sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz} + resolution: {integrity: sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.21.3': - resolution: {integrity: sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz} + resolution: {integrity: sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==} cpu: [arm64] os: [win32] '@rollup/rollup-win32-ia32-msvc@4.21.3': - resolution: {integrity: sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz} + resolution: {integrity: sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==} cpu: [ia32] os: [win32] '@rollup/rollup-win32-x64-msvc@4.21.3': - resolution: {integrity: sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==, tarball: https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz} + resolution: {integrity: sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==} cpu: [x64] os: [win32] @@ -745,6 +808,9 @@ packages: '@tsconfig/node20@20.1.4': resolution: {integrity: sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==} + '@types/codemirror@5.60.15': + resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==} + '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} @@ -769,6 +835,9 @@ packages: '@types/node@22.5.5': resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} + '@types/tern@0.23.9': + resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==} + '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} @@ -987,7 +1056,7 @@ packages: engines: {node: '>=12'} anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, tarball: https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz} + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} argparse@2.0.1: @@ -1019,7 +1088,7 @@ packages: resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==} binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, tarball: https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz} + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} birpc@0.2.17: @@ -1111,12 +1180,22 @@ packages: engines: {node: '>=10'} chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, tarball: https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz} + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} cipher-base@1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + codemirror-editor-vue3@2.8.0: + resolution: {integrity: sha512-ebYGNhBpLmQNLguXzNyMMkn6K8v3lcS5/Ncvdn6YS4bLGEHE67MfsJIS/WV0L7I6WavUuFlY/Rs/AJKChIwSwg==} + peerDependencies: + codemirror: ^5 + diff-match-patch: ^1.0.5 + vue: ^3.x + + codemirror@5.65.18: + resolution: {integrity: sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA==} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -1251,6 +1330,9 @@ packages: des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} @@ -1272,7 +1354,7 @@ packages: engines: {node: '>=0.12'} errno@0.1.8: - resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==, tarball: https://registry.npmjs.org/errno/-/errno-0.1.8.tgz} + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true error-stack-parser-es@0.1.5: @@ -1422,7 +1504,7 @@ packages: engines: {node: '>=14.14'} fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz} + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] @@ -1465,7 +1547,7 @@ packages: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, tarball: https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz} + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, tarball: https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz} @@ -1541,12 +1623,12 @@ packages: engines: {node: '>= 4'} image-size@0.5.5: - resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==, tarball: https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz} + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} engines: {node: '>=0.10.0'} hasBin: true immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==, tarball: https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz} + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -1567,7 +1649,7 @@ packages: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, tarball: https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz} + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} is-callable@1.2.7: @@ -1709,7 +1791,7 @@ packages: engines: {node: '>=12'} make-dir@2.1.0: - resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==, tarball: https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz} + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} md5.js@1.3.5: @@ -1735,7 +1817,7 @@ packages: hasBin: true mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, tarball: https://registry.npmjs.org/mime/-/mime-1.6.0.tgz} + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true @@ -1785,7 +1867,7 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} needle@3.3.1: - resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==, tarball: https://registry.npmjs.org/needle/-/needle-3.3.1.tgz} + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} engines: {node: '>= 4.4.x'} hasBin: true @@ -1797,7 +1879,7 @@ packages: engines: {node: '>=10'} normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, tarball: https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz} + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} normalize.css@8.0.1: @@ -2015,7 +2097,7 @@ packages: engines: {node: '>= 6'} readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, tarball: https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz} + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} resize-observer-polyfill@1.5.1: @@ -2061,7 +2143,7 @@ packages: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} sass@1.77.8: - resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==, tarball: https://registry.npmjs.org/sass/-/sass-1.77.8.tgz} + resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -2135,7 +2217,7 @@ packages: engines: {node: '>=0.10.0'} source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, tarball: https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz} + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} speakingurl@14.0.1: @@ -2166,6 +2248,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} engines: {node: '>=16'} @@ -2427,6 +2512,9 @@ packages: typescript: optional: true + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -2774,6 +2862,47 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.33.0)(@lezer/common@1.2.1)': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.33.0 + '@lezer/common': 1.2.1 + + '@codemirror/lang-json@6.0.1': + dependencies: + '@codemirror/language': 6.10.3 + '@lezer/json': 1.0.2 + + '@codemirror/lang-yaml@https://codeload.github.com/codemirror/lang-yaml/tar.gz/4746470e7948943e9a88af677719bddfdf6d5a4e(@codemirror/view@6.33.0)': + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.33.0)(@lezer/common@1.2.1) + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + '@lezer/yaml': 1.0.3 + transitivePeerDependencies: + - '@codemirror/view' + + '@codemirror/language@6.10.3': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.33.0 + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + style-mod: 4.1.2 + + '@codemirror/state@6.4.1': {} + + '@codemirror/view@6.33.0': + dependencies: + '@codemirror/state': 6.4.1 + style-mod: 4.1.2 + w3c-keyname: 2.2.8 + '@dzangolab/flag-icon-css@3.4.5': {} '@esbuild/aix-ppc64@0.21.5': @@ -2917,6 +3046,28 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@lezer/common@1.2.1': {} + + '@lezer/highlight@1.2.1': + dependencies: + '@lezer/common': 1.2.1 + + '@lezer/json@1.0.2': + dependencies: + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/lr@1.4.2': + dependencies: + '@lezer/common': 1.2.1 + + '@lezer/yaml@1.0.3': + dependencies: + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3039,6 +3190,10 @@ snapshots: '@tsconfig/node20@20.1.4': {} + '@types/codemirror@5.60.15': + dependencies: + '@types/tern': 0.23.9 + '@types/eslint@9.6.1': dependencies: '@types/estree': 1.0.5 @@ -3062,6 +3217,10 @@ snapshots: dependencies: undici-types: 6.19.6 + '@types/tern@0.23.9': + dependencies: + '@types/estree': 1.0.5 + '@types/uuid@10.0.0': {} '@types/web-bluetooth@0.0.20': {} @@ -3561,6 +3720,14 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 + codemirror-editor-vue3@2.8.0(codemirror@5.65.18)(diff-match-patch@1.0.5)(vue@3.5.6(typescript@5.6.2)): + dependencies: + codemirror: 5.65.18 + diff-match-patch: 1.0.5 + vue: 3.5.6(typescript@5.6.2) + + codemirror@5.65.18: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -3701,6 +3868,8 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 + diff-match-patch@1.0.5: {} + diffie-hellman@5.0.3: dependencies: bn.js: 4.12.0 @@ -4667,6 +4836,8 @@ snapshots: strip-json-comments@3.1.1: {} + style-mod@4.1.2: {} + superjson@2.2.1: dependencies: copy-anything: 3.0.5 @@ -4912,6 +5083,8 @@ snapshots: optionalDependencies: typescript: 5.6.2 + w3c-keyname@2.2.8: {} + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 diff --git a/webui/src/api/model/config.ts b/webui/src/api/model/config.ts new file mode 100644 index 0000000000..5f5a9742bd --- /dev/null +++ b/webui/src/api/model/config.ts @@ -0,0 +1,30 @@ + +export interface ConfigSaveResult { + /** + * 重载异常信息 + */ + errorMsg: string; + /** + * 重载项名称 + */ + name: string; + /** + * 产生此重载结果的原因 + */ + reason: string; + /** + * 重载结果 + */ + result: Result; +} + +/** + * 重载结果 + */ +export enum Result { + Exception = "EXCEPTION", + Outdated = "OUTDATED", + RequireRestart = "REQUIRE_RESTART", + Scheduled = "SCHEDULED", + Success = "SUCCESS", +} \ No newline at end of file diff --git a/webui/src/components/codeEditor.vue b/webui/src/components/codeEditor.vue new file mode 100644 index 0000000000..ffe7a41b92 --- /dev/null +++ b/webui/src/components/codeEditor.vue @@ -0,0 +1,58 @@ + + \ No newline at end of file diff --git a/webui/src/locale/en-US.ts b/webui/src/locale/en-US.ts index 05792ed719..541f1172de 100644 --- a/webui/src/locale/en-US.ts +++ b/webui/src/locale/en-US.ts @@ -10,6 +10,7 @@ import loginLocale from '@/views/login/locale/en-US' import oobeLocale from '@/views/oobe/locale/en-US' import ruleManageMentLocale from '@/views/rule-management/locale/en-US' import chartsLocale from '@/views/charts/locale/en-US' +import configLocale from '@/views/config/locale/en-US' export default { 'navbar.action.locale': 'Switch to English', 'navbar.action.autoUpdate': 'Auto Update', @@ -30,6 +31,8 @@ export default { 'router.metrics.ruleMetrics': 'Rule Metrics', 'router.metrics.charts': 'Charts', 'router.rule_management': 'Rule Management', + 'router.settings': "Settings", + 'router.settings.config': "Config", 'router.moduleNotEnable': '{moduleName} is not enabled', 'router.moduleNotEnable.tips': 'Please enable the feature in the configuration file', @@ -52,5 +55,6 @@ export default { ...loginLocale, ...oobeLocale, ...ruleManageMentLocale, - ...chartsLocale + ...chartsLocale, + ...configLocale } diff --git a/webui/src/locale/zh-CN.ts b/webui/src/locale/zh-CN.ts index 69bdf2b23d..f2a697fe92 100644 --- a/webui/src/locale/zh-CN.ts +++ b/webui/src/locale/zh-CN.ts @@ -10,6 +10,7 @@ import loginLocale from '@/views/login/locale/zh-CN' import oobeLocale from '@/views/oobe/locale/zh-CN' import ruleManageMentLocale from '@/views/rule-management/locale/zh-CN' import chartsLocale from '@/views/charts/locale/zh-CN' +import configLocale from '@/views/config/locale/zh-CN' export default { 'navbar.action.locale': '切换为中文', 'navbar.action.autoUpdate': '自动刷新', @@ -29,6 +30,9 @@ export default { 'router.metrics.ruleMetrics': '规则统计', 'router.metrics.charts': '图表', 'router.rule_management': '规则管理', + 'router.settings': "设置", + 'router.settings.config': "配置文件", + 'router.moduleNotEnable': '{moduleName}功能未启用', 'router.moduleNotEnable.tips': '请在配置文件中开启相关功能', @@ -40,6 +44,8 @@ export default { 'service.networkErrorRetry.cancel': '取消重试', 'service.networkErrorRetry.retry': '重试', + + ...settingsLocale, ...plusLocale, ...dashboardPageLocale, @@ -51,5 +57,6 @@ export default { ...loginLocale, ...oobeLocale, ...ruleManageMentLocale, - ...chartsLocale + ...chartsLocale, + ...configLocale } diff --git a/webui/src/main.ts b/webui/src/main.ts index 83c5aad0ca..64706e1099 100644 --- a/webui/src/main.ts +++ b/webui/src/main.ts @@ -8,6 +8,7 @@ import App from './App.vue' import router from './router' import i18n from './locale' import { setGlobalOptions } from 'vue-request' +import {InstallCodeMirror} from "codemirror-editor-vue3"; const app = createApp(App) Message._context = app._context @@ -22,5 +23,6 @@ setGlobalOptions({ app.use(createPinia()) app.use(i18n) app.use(router) +app.use(InstallCodeMirror) app.mount('#app') diff --git a/webui/src/router/index.ts b/webui/src/router/index.ts index 5bf6e56156..13e723878f 100644 --- a/webui/src/router/index.ts +++ b/webui/src/router/index.ts @@ -166,6 +166,25 @@ export const routerOptions: RouteRecordRaw[] = [ } ] }, + { + path: '/settings', + name: 'settings', + meta: { + label: 'router.settings', + needLogin: true + }, + children: [ + { + path: '/config', + name: 'settings_config', + meta: { + label: 'router.settings.config', + needLogin: true + }, + component: () => import('@/views/config/index.vue') + } + ] + }, { path: '/init', name: 'init', diff --git a/webui/src/service/config.ts b/webui/src/service/config.ts new file mode 100644 index 0000000000..10e37db820 --- /dev/null +++ b/webui/src/service/config.ts @@ -0,0 +1,51 @@ +import { useEndpointStore } from '@/stores/endpoint' +import { type CommonResponse } from '@/api/model/common' +import urlJoin from 'url-join' +import { getCommonHeader } from './utils' +import type {ConfigSaveResult} from "@/api/model/config"; + +export async function getConfigYamlList(): Promise> { + const endpointStore = useEndpointStore() + await endpointStore.serverAvailable + + const url = new URL(urlJoin(endpointStore.endpoint, 'api/config'), location.href) + return fetch(url, { + headers: getCommonHeader() + }).then((res) => { + endpointStore.assertResponseLogin(res) + return res.json() + }) +} + +export async function getConfigYamlContent( + configId: string, +): Promise> { + const endpointStore = useEndpointStore() + await endpointStore.serverAvailable + + const url = new URL(urlJoin(endpointStore.endpoint, `api/config/${configId}`), location.href) + return fetch(url, { + headers: getCommonHeader() + }).then((res) => { + endpointStore.assertResponseLogin(res) + return res.json() + }) +} + +export async function setConfigYamlContent( + configId: string, + content: string +): Promise> { + const endpointStore = useEndpointStore() + await endpointStore.serverAvailable + + const url = new URL(urlJoin(endpointStore.endpoint, `api/config/${configId}`), location.href) + return fetch(url, { + headers: getCommonHeader(), + method: 'PUT', + body: JSON.stringify({ content }) + }).then((res) => { + endpointStore.assertResponseLogin(res) + return res.json() + }) +} diff --git a/webui/src/views/config/index.vue b/webui/src/views/config/index.vue new file mode 100644 index 0000000000..86b70b98cd --- /dev/null +++ b/webui/src/views/config/index.vue @@ -0,0 +1,141 @@ + + diff --git a/webui/src/views/config/locale/en-US.ts b/webui/src/views/config/locale/en-US.ts new file mode 100644 index 0000000000..8e0a24f39e --- /dev/null +++ b/webui/src/views/config/locale/en-US.ts @@ -0,0 +1,6 @@ +export default { + 'page.config.save': 'Save', + 'page.config.saveFailed': 'Error while saving {name}: {errorMsg}', + 'page.config.saveSuccess': 'Successfully saved configuration and reloaded', + 'page.config.saveRequireRestart': 'Successfully saved and reloaded, but some changes require restart to take effect' +} diff --git a/webui/src/views/config/locale/zh-CN.ts b/webui/src/views/config/locale/zh-CN.ts new file mode 100644 index 0000000000..e4c6241263 --- /dev/null +++ b/webui/src/views/config/locale/zh-CN.ts @@ -0,0 +1,6 @@ +export default { + 'page.config.save': '保存', + 'page.config.saveFailed': '保存 {name} 时出错: {errorMsg}', + 'page.config.saveSuccess': '已成功保存并重载配置文件', + 'page.config.saveRequireRestart': '已成功保存并重载,但部分配置更改需要重启应用' +} From 8dd6e405fdb19c6fe581f66a2546a5d2594d8e0b Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Sun, 22 Sep 2024 02:15:19 +0800 Subject: [PATCH 3/6] lint --- webui/src/api/model/config.ts | 45 +++++---- webui/src/service/config.ts | 68 +++++++------ webui/src/views/config/index.vue | 129 ++++++++++++------------- webui/src/views/config/locale/en-US.ts | 3 +- 4 files changed, 121 insertions(+), 124 deletions(-) diff --git a/webui/src/api/model/config.ts b/webui/src/api/model/config.ts index 5f5a9742bd..cbacf6451d 100644 --- a/webui/src/api/model/config.ts +++ b/webui/src/api/model/config.ts @@ -1,30 +1,29 @@ - export interface ConfigSaveResult { - /** - * 重载异常信息 - */ - errorMsg: string; - /** - * 重载项名称 - */ - name: string; - /** - * 产生此重载结果的原因 - */ - reason: string; - /** - * 重载结果 - */ - result: Result; + /** + * 重载异常信息 + */ + errorMsg: string + /** + * 重载项名称 + */ + name: string + /** + * 产生此重载结果的原因 + */ + reason: string + /** + * 重载结果 + */ + result: Result } /** * 重载结果 */ export enum Result { - Exception = "EXCEPTION", - Outdated = "OUTDATED", - RequireRestart = "REQUIRE_RESTART", - Scheduled = "SCHEDULED", - Success = "SUCCESS", -} \ No newline at end of file + Exception = 'EXCEPTION', + Outdated = 'OUTDATED', + RequireRestart = 'REQUIRE_RESTART', + Scheduled = 'SCHEDULED', + Success = 'SUCCESS' +} diff --git a/webui/src/service/config.ts b/webui/src/service/config.ts index 10e37db820..47ca4ab20a 100644 --- a/webui/src/service/config.ts +++ b/webui/src/service/config.ts @@ -2,50 +2,48 @@ import { useEndpointStore } from '@/stores/endpoint' import { type CommonResponse } from '@/api/model/common' import urlJoin from 'url-join' import { getCommonHeader } from './utils' -import type {ConfigSaveResult} from "@/api/model/config"; +import type { ConfigSaveResult } from '@/api/model/config' export async function getConfigYamlList(): Promise> { - const endpointStore = useEndpointStore() - await endpointStore.serverAvailable + const endpointStore = useEndpointStore() + await endpointStore.serverAvailable - const url = new URL(urlJoin(endpointStore.endpoint, 'api/config'), location.href) - return fetch(url, { - headers: getCommonHeader() - }).then((res) => { - endpointStore.assertResponseLogin(res) - return res.json() - }) + const url = new URL(urlJoin(endpointStore.endpoint, 'api/config'), location.href) + return fetch(url, { + headers: getCommonHeader() + }).then((res) => { + endpointStore.assertResponseLogin(res) + return res.json() + }) } -export async function getConfigYamlContent( - configId: string, -): Promise> { - const endpointStore = useEndpointStore() - await endpointStore.serverAvailable +export async function getConfigYamlContent(configId: string): Promise> { + const endpointStore = useEndpointStore() + await endpointStore.serverAvailable - const url = new URL(urlJoin(endpointStore.endpoint, `api/config/${configId}`), location.href) - return fetch(url, { - headers: getCommonHeader() - }).then((res) => { - endpointStore.assertResponseLogin(res) - return res.json() - }) + const url = new URL(urlJoin(endpointStore.endpoint, `api/config/${configId}`), location.href) + return fetch(url, { + headers: getCommonHeader() + }).then((res) => { + endpointStore.assertResponseLogin(res) + return res.json() + }) } export async function setConfigYamlContent( - configId: string, - content: string + configId: string, + content: string ): Promise> { - const endpointStore = useEndpointStore() - await endpointStore.serverAvailable + const endpointStore = useEndpointStore() + await endpointStore.serverAvailable - const url = new URL(urlJoin(endpointStore.endpoint, `api/config/${configId}`), location.href) - return fetch(url, { - headers: getCommonHeader(), - method: 'PUT', - body: JSON.stringify({ content }) - }).then((res) => { - endpointStore.assertResponseLogin(res) - return res.json() - }) + const url = new URL(urlJoin(endpointStore.endpoint, `api/config/${configId}`), location.href) + return fetch(url, { + headers: getCommonHeader(), + method: 'PUT', + body: JSON.stringify({ content }) + }).then((res) => { + endpointStore.assertResponseLogin(res) + return res.json() + }) } diff --git a/webui/src/views/config/index.vue b/webui/src/views/config/index.vue index 86b70b98cd..16a153691a 100644 --- a/webui/src/views/config/index.vue +++ b/webui/src/views/config/index.vue @@ -1,19 +1,15 @@ diff --git a/webui/src/views/config/locale/en-US.ts b/webui/src/views/config/locale/en-US.ts index 8e0a24f39e..388436f57c 100644 --- a/webui/src/views/config/locale/en-US.ts +++ b/webui/src/views/config/locale/en-US.ts @@ -2,5 +2,6 @@ export default { 'page.config.save': 'Save', 'page.config.saveFailed': 'Error while saving {name}: {errorMsg}', 'page.config.saveSuccess': 'Successfully saved configuration and reloaded', - 'page.config.saveRequireRestart': 'Successfully saved and reloaded, but some changes require restart to take effect' + 'page.config.saveRequireRestart': + 'Successfully saved and reloaded, but some changes require restart to take effect' } From e69bd700b47c7f3638b1478dd5fb706e3475cc29 Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Sun, 22 Sep 2024 02:17:17 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20eslint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webui/src/views/config/index.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/webui/src/views/config/index.vue b/webui/src/views/config/index.vue index 16a153691a..e823dedb44 100644 --- a/webui/src/views/config/index.vue +++ b/webui/src/views/config/index.vue @@ -54,15 +54,15 @@ export default defineComponent({ }) // Load YAML content for the selected tab - const loadTabContent = async (configId: string) => { + const loadTabContent = async (key: string | number) => { + const configId = key.toString(); // 确保 configId 是 string 类型 if (!yamlContents.value[configId]) { - // Lazy load content if not already loaded - const response = await getConfigYamlContent(configId) + const response = await getConfigYamlContent(configId); if (response.success) { - yamlContents.value[configId] = response.data + yamlContents.value[configId] = response.data; } } - } + }; const saveConfig = async (configId: string) => { const content = yamlContents.value[configId] From 89bbd13703ebd6c2aa8c93e36b60cec68b709271 Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Sun, 22 Sep 2024 02:21:34 +0800 Subject: [PATCH 5/6] fix lint --- webui/src/components/codeEditor.vue | 58 ----------------------------- webui/src/locale/en-US.ts | 4 +- webui/src/locale/zh-CN.ts | 7 +--- webui/src/main.ts | 2 +- webui/src/views/config/index.vue | 8 ++-- 5 files changed, 9 insertions(+), 70 deletions(-) delete mode 100644 webui/src/components/codeEditor.vue diff --git a/webui/src/components/codeEditor.vue b/webui/src/components/codeEditor.vue deleted file mode 100644 index ffe7a41b92..0000000000 --- a/webui/src/components/codeEditor.vue +++ /dev/null @@ -1,58 +0,0 @@ - - \ No newline at end of file diff --git a/webui/src/locale/en-US.ts b/webui/src/locale/en-US.ts index 541f1172de..97dc05687c 100644 --- a/webui/src/locale/en-US.ts +++ b/webui/src/locale/en-US.ts @@ -31,8 +31,8 @@ export default { 'router.metrics.ruleMetrics': 'Rule Metrics', 'router.metrics.charts': 'Charts', 'router.rule_management': 'Rule Management', - 'router.settings': "Settings", - 'router.settings.config': "Config", + 'router.settings': 'Settings', + 'router.settings.config': 'Config', 'router.moduleNotEnable': '{moduleName} is not enabled', 'router.moduleNotEnable.tips': 'Please enable the feature in the configuration file', diff --git a/webui/src/locale/zh-CN.ts b/webui/src/locale/zh-CN.ts index f2a697fe92..d23c940886 100644 --- a/webui/src/locale/zh-CN.ts +++ b/webui/src/locale/zh-CN.ts @@ -30,9 +30,8 @@ export default { 'router.metrics.ruleMetrics': '规则统计', 'router.metrics.charts': '图表', 'router.rule_management': '规则管理', - 'router.settings': "设置", - 'router.settings.config': "配置文件", - + 'router.settings': '设置', + 'router.settings.config': '配置文件', 'router.moduleNotEnable': '{moduleName}功能未启用', 'router.moduleNotEnable.tips': '请在配置文件中开启相关功能', @@ -44,8 +43,6 @@ export default { 'service.networkErrorRetry.cancel': '取消重试', 'service.networkErrorRetry.retry': '重试', - - ...settingsLocale, ...plusLocale, ...dashboardPageLocale, diff --git a/webui/src/main.ts b/webui/src/main.ts index 64706e1099..9839089c0f 100644 --- a/webui/src/main.ts +++ b/webui/src/main.ts @@ -8,7 +8,7 @@ import App from './App.vue' import router from './router' import i18n from './locale' import { setGlobalOptions } from 'vue-request' -import {InstallCodeMirror} from "codemirror-editor-vue3"; +import { InstallCodeMirror } from 'codemirror-editor-vue3' const app = createApp(App) Message._context = app._context diff --git a/webui/src/views/config/index.vue b/webui/src/views/config/index.vue index e823dedb44..01a12fccc8 100644 --- a/webui/src/views/config/index.vue +++ b/webui/src/views/config/index.vue @@ -55,14 +55,14 @@ export default defineComponent({ // Load YAML content for the selected tab const loadTabContent = async (key: string | number) => { - const configId = key.toString(); // 确保 configId 是 string 类型 + const configId = key.toString() // 确保 configId 是 string 类型 if (!yamlContents.value[configId]) { - const response = await getConfigYamlContent(configId); + const response = await getConfigYamlContent(configId) if (response.success) { - yamlContents.value[configId] = response.data; + yamlContents.value[configId] = response.data } } - }; + } const saveConfig = async (configId: string) => { const content = yamlContents.value[configId] From e25018c1dd60b2d1aa0a02da5726766dda98e70b Mon Sep 17 00:00:00 2001 From: Ghost_chu Date: Sun, 22 Sep 2024 13:45:21 +0800 Subject: [PATCH 6/6] fix lint --- webui/src/views/config/index.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webui/src/views/config/index.vue b/webui/src/views/config/index.vue index 01a12fccc8..d567debad9 100644 --- a/webui/src/views/config/index.vue +++ b/webui/src/views/config/index.vue @@ -11,7 +11,6 @@ @ready="onReady(configId)" @focus="onFocus" /> - {{ t('page.config.save') }} @@ -125,7 +124,7 @@ export default defineComponent({ cmOptions, loadTabContent, saveConfig, - onReady: (configId: string) => (cm: Editor) => { + onReady: (configId: string) => () => { console.log(`Codemirror instance ready for ${configId}`) }, onChange: (configId: string) => (value: string) => {