Compare commits
2 Commits
bce2fea4e5
...
89912155a6
| Author | SHA1 | Date | |
|---|---|---|---|
| 89912155a6 | |||
| dd0e059365 |
51
bun.lock
51
bun.lock
@@ -5,11 +5,14 @@
|
||||
"": {
|
||||
"name": "devflow",
|
||||
"dependencies": {
|
||||
"@antv/layout": "^2.0.0",
|
||||
"@antv/x6": "^3.1.7",
|
||||
"@antv/x6-vue-shape": "^3.0.2",
|
||||
"@arco-design/web-vue": "^2.58.0",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.7.1",
|
||||
"@types/dagre": "^0.7.54",
|
||||
"dagre": "^0.8.5",
|
||||
"dompurify": "^3.4.10",
|
||||
"highlight.js": "^11.11.1",
|
||||
"marked": "^18.0.5",
|
||||
@@ -29,6 +32,16 @@
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@antv/event-emitter": ["@antv/event-emitter@0.1.3", "https://registry.npmmirror.com/@antv/event-emitter/-/event-emitter-0.1.3.tgz", {}, "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg=="],
|
||||
|
||||
"@antv/expr": ["@antv/expr@1.0.2", "https://registry.npmmirror.com/@antv/expr/-/expr-1.0.2.tgz", {}, "sha512-vrfdmPHkTuiS5voVutKl2l06w1ihBh9A8SFdQPEE+2KMVpkymzGOF1eWpfkbGZ7tiFE15GodVdhhHomD/hdIwg=="],
|
||||
|
||||
"@antv/graphlib": ["@antv/graphlib@2.0.4", "https://registry.npmmirror.com/@antv/graphlib/-/graphlib-2.0.4.tgz", { "dependencies": { "@antv/event-emitter": "^0.1.3" } }, "sha512-zc/5oQlsdk42Z0ib1mGklwzhJ5vczLFiPa1v7DgJkTbgJ2YxRh9xdarf86zI49sKVJmgbweRpJs7Nu5bIiwv4w=="],
|
||||
|
||||
"@antv/layout": ["@antv/layout@2.0.0", "https://registry.npmmirror.com/@antv/layout/-/layout-2.0.0.tgz", { "dependencies": { "@antv/event-emitter": "^0.1.3", "@antv/expr": "^1.0.2", "@antv/graphlib": "^2.0.0", "@antv/util": "^3.3.2", "comlink": "^4.4.1", "d3-force": "^3.0.0", "d3-force-3d": "^3.0.5", "d3-octree": "^1.0.2", "d3-quadtree": "^3.0.1", "dagre": "^0.8.5", "ml-matrix": "^6.10.4", "tslib": "^2.8.1" } }, "sha512-aCZ3UdNc40SfT7meFV7QTADY2HCnc0DShVw56CJNTI6oExUIVU736grPuL5Dhb8/JrVaU4Y83QPN/P7KafBzlw=="],
|
||||
|
||||
"@antv/util": ["@antv/util@3.3.11", "https://registry.npmmirror.com/@antv/util/-/util-3.3.11.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "gl-matrix": "^3.3.0", "tslib": "^2.3.1" } }, "sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg=="],
|
||||
|
||||
"@antv/x6": ["@antv/x6@3.1.7", "https://registry.npmmirror.com/@antv/x6/-/x6-3.1.7.tgz", { "dependencies": { "dom-align": "^1.12.4", "lodash-es": "^4.17.15", "mousetrap": "^1.6.5", "utility-types": "^3.10.0" } }, "sha512-NLKXtbCK51oLbazfFD0XsD93rMmih08UBW4gAuEyLBpwAqHmHe+vP8VhOZDkl5O9jV1LSv85IJghr9CT5tZjWw=="],
|
||||
|
||||
"@antv/x6-vue-shape": ["@antv/x6-vue-shape@3.0.2", "https://registry.npmmirror.com/@antv/x6-vue-shape/-/x6-vue-shape-3.0.2.tgz", { "dependencies": { "vue-demi": "latest" }, "peerDependencies": { "@antv/x6": "^3.x", "@vue/composition-api": "^1.0.0-rc.1", "vue": "^2.0.0 || >=3.0.0" }, "optionalPeers": ["@vue/composition-api"] }, "sha512-HWnYFvLCaUD9ernINxTn9vCRj66eG/nXKErSSq0hfI4U1HOitC/1oUrzDdwL/BT80HKAQeSsmy7gpDA/79jYlw=="],
|
||||
@@ -183,6 +196,8 @@
|
||||
|
||||
"@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.7.1", "https://registry.npmmirror.com/@tauri-apps/plugin-dialog/-/plugin-dialog-2.7.1.tgz", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-OK1UBXYt+ojcmxMktzzuyonYIFta8CmAASpX+CA+DTGK24KlHjhYI6x2iOJ/TjZF4N7/ACK1oFmEOjIY9IhzOQ=="],
|
||||
|
||||
"@types/dagre": ["@types/dagre@0.7.54", "https://registry.npmmirror.com/@types/dagre/-/dagre-0.7.54.tgz", {}, "sha512-QjcRY+adGbYvBFS7cwv5txhVIwX1XXIUswWl+kSQTbI6NjgZydrZkEKX/etzVd7i+bCsCb40Z/xlBY5eoFuvWQ=="],
|
||||
|
||||
"@types/dompurify": ["@types/dompurify@3.2.0", "https://registry.npmmirror.com/@types/dompurify/-/dompurify-3.2.0.tgz", { "dependencies": { "dompurify": "*" } }, "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.9", "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
|
||||
@@ -239,10 +254,28 @@
|
||||
|
||||
"color-string": ["color-string@1.9.1", "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
||||
|
||||
"comlink": ["comlink@4.4.2", "https://registry.npmmirror.com/comlink/-/comlink-4.4.2.tgz", {}, "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g=="],
|
||||
|
||||
"compute-scroll-into-view": ["compute-scroll-into-view@1.0.20", "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", {}, "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="],
|
||||
|
||||
"csstype": ["csstype@3.2.3", "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||
|
||||
"d3-binarytree": ["d3-binarytree@1.0.2", "https://registry.npmmirror.com/d3-binarytree/-/d3-binarytree-1.0.2.tgz", {}, "sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw=="],
|
||||
|
||||
"d3-dispatch": ["d3-dispatch@3.0.1", "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="],
|
||||
|
||||
"d3-force": ["d3-force@3.0.0", "https://registry.npmmirror.com/d3-force/-/d3-force-3.0.0.tgz", { "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg=="],
|
||||
|
||||
"d3-force-3d": ["d3-force-3d@3.0.6", "https://registry.npmmirror.com/d3-force-3d/-/d3-force-3d-3.0.6.tgz", { "dependencies": { "d3-binarytree": "1", "d3-dispatch": "1 - 3", "d3-octree": "1", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA=="],
|
||||
|
||||
"d3-octree": ["d3-octree@1.1.0", "https://registry.npmmirror.com/d3-octree/-/d3-octree-1.1.0.tgz", {}, "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A=="],
|
||||
|
||||
"d3-quadtree": ["d3-quadtree@3.0.1", "https://registry.npmmirror.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz", {}, "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="],
|
||||
|
||||
"d3-timer": ["d3-timer@3.0.1", "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
|
||||
|
||||
"dagre": ["dagre@0.8.5", "https://registry.npmmirror.com/dagre/-/dagre-0.8.5.tgz", { "dependencies": { "graphlib": "^2.1.8", "lodash": "^4.17.15" } }, "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw=="],
|
||||
|
||||
"dayjs": ["dayjs@1.11.21", "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.21.tgz", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="],
|
||||
|
||||
"de-indent": ["de-indent@1.0.2", "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz", {}, "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg=="],
|
||||
@@ -257,16 +290,26 @@
|
||||
|
||||
"estree-walker": ["estree-walker@2.0.2", "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"gl-matrix": ["gl-matrix@3.4.4", "https://registry.npmmirror.com/gl-matrix/-/gl-matrix-3.4.4.tgz", {}, "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ=="],
|
||||
|
||||
"graphlib": ["graphlib@2.1.8", "https://registry.npmmirror.com/graphlib/-/graphlib-2.1.8.tgz", { "dependencies": { "lodash": "^4.17.15" } }, "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A=="],
|
||||
|
||||
"he": ["he@1.2.0", "https://registry.npmmirror.com/he/-/he-1.2.0.tgz", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
|
||||
|
||||
"highlight.js": ["highlight.js@11.11.1", "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.1.tgz", {}, "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w=="],
|
||||
|
||||
"is-any-array": ["is-any-array@3.0.0", "https://registry.npmmirror.com/is-any-array/-/is-any-array-3.0.0.tgz", {}, "sha512-o4h+tylWykC4BD1vaejp6gDxoM13bwW8FGuNs4yIKpj8xbBJcRxJx8vZpq0dCr7ZDEfeKjmsi/euolKhX6f/ww=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.3.4", "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.4.tgz", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
|
||||
|
||||
"lodash": ["lodash@4.18.1", "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="],
|
||||
|
||||
"lodash-es": ["lodash-es@4.18.1", "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.18.1.tgz", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.21", "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
@@ -275,6 +318,14 @@
|
||||
|
||||
"minimatch": ["minimatch@9.0.9", "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
|
||||
|
||||
"ml-array-max": ["ml-array-max@2.0.0", "https://registry.npmmirror.com/ml-array-max/-/ml-array-max-2.0.0.tgz", { "dependencies": { "is-any-array": "^3.0.0" } }, "sha512-QQZ4kENwpWmyNb98UXRDFXrmtIXuXtt1+bSbda/2KA85+F+rrJP8hZk6QOkCQXM2Th9mUDYdq/PNByPdT9ID4A=="],
|
||||
|
||||
"ml-array-min": ["ml-array-min@2.0.0", "https://registry.npmmirror.com/ml-array-min/-/ml-array-min-2.0.0.tgz", { "dependencies": { "is-any-array": "^3.0.0" } }, "sha512-GRj6Ky6sW9vGL6yIjgsHmXZ9YgrdmcQ8nCxPqEGeKc6dkfYg1XDYxGFxADUjNuZyoCd5PUscWAS4N+cFaX6hFg=="],
|
||||
|
||||
"ml-array-rescale": ["ml-array-rescale@2.0.0", "https://registry.npmmirror.com/ml-array-rescale/-/ml-array-rescale-2.0.0.tgz", { "dependencies": { "is-any-array": "^3.0.0", "ml-array-max": "^2.0.0", "ml-array-min": "^2.0.0" } }, "sha512-2GGtKfSno94/kIloWGvpp/U5Q5vLvLrza+SAaGsLeo6Xj4mEbA6Gqx+oTfZFkxnd1grT2X007HfJNs3T5BsiVg=="],
|
||||
|
||||
"ml-matrix": ["ml-matrix@6.13.0", "https://registry.npmmirror.com/ml-matrix/-/ml-matrix-6.13.0.tgz", { "dependencies": { "is-any-array": "^3.0.0", "ml-array-rescale": "^2.0.0" } }, "sha512-QpV0UTUkglg6vPUgThKGBEtit2ac6habSoZ33bwI9rU0UHZLqw6G3ukTIE8zWiUF3sjK8YAlhx/o/b9layzH8A=="],
|
||||
|
||||
"mousetrap": ["mousetrap@1.6.5", "https://registry.npmmirror.com/mousetrap/-/mousetrap-1.6.5.tgz", {}, "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA=="],
|
||||
|
||||
"muggle-string": ["muggle-string@0.4.1", "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
@@ -136,8 +136,8 @@ const DEFAULT_BLACKLIST: &[&str] = &["rm", "del", "format", "shutdown", "mkfs",
|
||||
///
|
||||
/// 返回 `Some(reason)` 表示拒绝(reason 为拒绝原因,用于日志/错误信息);返回 `None` 表示放行。
|
||||
fn check_command_policy(cmd_name: &str) -> Option<&'static str> {
|
||||
// 黑名单优先:即便同时在白名单,只要命中黑名单就拒绝(防止白名单失误放过危险命令)
|
||||
// 未设置 DF_SCRIPT_BLACKLIST 时使用 DEFAULT_BLACKLIST 兜底(防误用零防护)
|
||||
// 黑名单优先:即便同时在白名单,只要命中黑名单就拒绝
|
||||
// 优先从环境变量读,后续可扩展为从 DB KV 注入(前端设置页写入)
|
||||
let env_blacklist = std::env::var("DF_SCRIPT_BLACKLIST").ok();
|
||||
let blacklist: Vec<String> = match env_blacklist {
|
||||
Some(raw) => raw
|
||||
@@ -148,7 +148,7 @@ fn check_command_policy(cmd_name: &str) -> Option<&'static str> {
|
||||
None => DEFAULT_BLACKLIST.iter().map(|s| s.to_string()).collect(),
|
||||
};
|
||||
if blacklist.iter().any(|c| c == cmd_name) {
|
||||
return Some("命令在黑名单中 (DF_SCRIPT_BLACKLIST 或默认)");
|
||||
return Some("命令在黑名单中");
|
||||
}
|
||||
|
||||
// 白名单:非空时命令名必须在白名单中才放行
|
||||
@@ -159,7 +159,7 @@ fn check_command_policy(cmd_name: &str) -> Option<&'static str> {
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
if !whitelist.is_empty() && !whitelist.iter().any(|c| c == cmd_name) {
|
||||
return Some("命令不在白名单中 (DF_SCRIPT_WHITELIST)");
|
||||
return Some("命令不在白名单中");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,14 @@
|
||||
"build:dev": "tauri build --debug --no-bundle"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/layout": "^2.0.0",
|
||||
"@antv/x6": "^3.1.7",
|
||||
"@antv/x6-vue-shape": "^3.0.2",
|
||||
"@arco-design/web-vue": "^2.58.0",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.7.1",
|
||||
"@types/dagre": "^0.7.54",
|
||||
"dagre": "^0.8.5",
|
||||
"dompurify": "^3.4.10",
|
||||
"highlight.js": "^11.11.1",
|
||||
"marked": "^18.0.5",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<div class="dep-graph__toolbar">
|
||||
<span class="dep-graph__title">{{ $t('dependencyGraph.title') }}</span>
|
||||
<div class="dep-graph__actions">
|
||||
<button v-if="modules.length >= 2" class="btn btn-ghost btn-sm" @click="showAddDep = true">+ 依赖</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="fitContent">适应内容</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="zoomIn">+</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="zoomOut">-</button>
|
||||
@@ -13,6 +14,39 @@
|
||||
<div class="empty-icon">📦</div>
|
||||
<div>{{ $t('dependencyGraph.empty') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加依赖弹窗 -->
|
||||
<div v-if="showAddDep" class="dep-graph__modal-overlay" @click.self="showAddDep = false">
|
||||
<div class="dep-graph__modal">
|
||||
<h3>添加工程依赖</h3>
|
||||
<div class="dep-graph__modal-field">
|
||||
<label>源工程(依赖方)</label>
|
||||
<select v-model="depFrom" class="dep-graph__modal-input">
|
||||
<option v-for="m in modules" :key="m.id" :value="m.id">{{ m.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="dep-graph__modal-field">
|
||||
<label>目标工程(被依赖)</label>
|
||||
<select v-model="depTo" class="dep-graph__modal-input">
|
||||
<option v-for="m in modules" :key="m.id" :value="m.id">{{ m.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="dep-graph__modal-field">
|
||||
<label>依赖类型</label>
|
||||
<select v-model="depType" class="dep-graph__modal-input">
|
||||
<option value="library">类库</option>
|
||||
<option value="api">API 调用</option>
|
||||
<option value="mq">消息队列</option>
|
||||
<option value="shared">共享资源</option>
|
||||
<option value="custom">自定义</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="dep-graph__modal-actions">
|
||||
<button class="btn btn-ghost btn-sm" @click="showAddDep = false">取消</button>
|
||||
<button class="btn btn-primary btn-sm" :disabled="!depFrom || !depTo || depFrom === depTo" @click="onAddDep">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -25,6 +59,7 @@
|
||||
import { onMounted, onBeforeUnmount, ref, watch, markRaw } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Graph, Selection, Snapline, History, Scroller, MiniMap } from '@antv/x6'
|
||||
import dagre from 'dagre'
|
||||
import '@antv/x6-vue-shape'
|
||||
import { moduleApi, type ProjectModuleRecord, type ModuleDependencyRecord } from '@/api/module'
|
||||
import ModuleNode from './ModuleNode.vue'
|
||||
@@ -45,6 +80,27 @@ const dependencies = ref<ModuleDependencyRecord[]>([])
|
||||
const loading = ref(true)
|
||||
let graph: Graph | null = null
|
||||
|
||||
// 添加依赖弹窗
|
||||
const showAddDep = ref(false)
|
||||
const depFrom = ref('')
|
||||
const depTo = ref('')
|
||||
const depType = ref('library')
|
||||
|
||||
async function onAddDep() {
|
||||
if (!depFrom.value || !depTo.value || depFrom.value === depTo.value) return
|
||||
try {
|
||||
await moduleApi.addModuleDependency(props.projectId, depFrom.value, depTo.value, depType.value)
|
||||
showAddDep.value = false
|
||||
depFrom.value = ''
|
||||
depTo.value = ''
|
||||
depType.value = 'library'
|
||||
await loadModules()
|
||||
renderGraph()
|
||||
} catch (e) {
|
||||
console.error('[DependencyGraph] 添加依赖失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadModules() {
|
||||
loading.value = true
|
||||
try {
|
||||
@@ -65,20 +121,29 @@ async function loadModules() {
|
||||
function renderGraph() {
|
||||
if (!graph) return
|
||||
|
||||
const cols = 3
|
||||
const nodeWidth = 200
|
||||
const nodeHeight = 80
|
||||
const gapX = 50
|
||||
const gapY = 40
|
||||
|
||||
const nodes = modules.value.map((m, i) => {
|
||||
const col = i % cols
|
||||
const row = Math.floor(i / cols)
|
||||
// dagre 层次布局
|
||||
const g = new dagre.graphlib.Graph()
|
||||
g.setGraph({ rankdir: 'LR', nodesep: 30, ranksep: 60 })
|
||||
g.setDefaultEdgeLabel(() => ({}))
|
||||
for (const m of modules.value) {
|
||||
g.setNode(m.id, { width: nodeWidth, height: nodeHeight })
|
||||
}
|
||||
for (const d of dependencies.value) {
|
||||
g.setEdge(d.from_module_id, d.to_module_id)
|
||||
}
|
||||
dagre.layout(g)
|
||||
|
||||
// 映射回 X6 节点格式
|
||||
const nodes = modules.value.map(m => {
|
||||
const pos = g.node(m.id)
|
||||
return {
|
||||
id: m.id,
|
||||
shape: 'vue-shape',
|
||||
x: col * (nodeWidth + gapX) + 40,
|
||||
y: row * (nodeHeight + gapY) + 40,
|
||||
x: (pos?.x ?? 0) - nodeWidth / 2,
|
||||
y: (pos?.y ?? 0) - nodeHeight / 2,
|
||||
width: nodeWidth,
|
||||
height: nodeHeight,
|
||||
component: markRaw(ModuleNode),
|
||||
@@ -257,4 +322,41 @@ onBeforeUnmount(() => {
|
||||
padding: 4px 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 添加依赖弹窗 */
|
||||
.dep-graph__modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
.dep-graph__modal {
|
||||
background: var(--df-bg-card);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-lg);
|
||||
padding: 20px;
|
||||
min-width: 360px;
|
||||
}
|
||||
.dep-graph__modal h3 { font-size: 16px; color: var(--df-text); margin-bottom: 16px; }
|
||||
.dep-graph__modal-field { margin-bottom: 12px; }
|
||||
.dep-graph__modal-field label {
|
||||
display: block; font-size: 12px; color: var(--df-text-secondary); margin-bottom: 4px;
|
||||
}
|
||||
.dep-graph__modal-input {
|
||||
width: 100%; box-sizing: border-box;
|
||||
padding: 6px 10px;
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-sm);
|
||||
background: var(--df-bg); color: var(--df-text);
|
||||
font-size: 13px;
|
||||
}
|
||||
.dep-graph__modal-actions {
|
||||
display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px;
|
||||
}
|
||||
.btn-primary { background: var(--df-accent); color: #fff; }
|
||||
.btn-primary:hover { filter: brightness(1.1); }
|
||||
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }
|
||||
</style>
|
||||
|
||||
@@ -176,10 +176,10 @@ async function reload() {
|
||||
// ============================================================
|
||||
// ScriptNode 命令执行安全 — 白/黑名单 UI
|
||||
// ------------------------------------------------------------
|
||||
// 前端仅做 UI + 持久化到 appSettings(df-script-whitelist / df-script-blacklist)。
|
||||
// 后端 ScriptNode 当前从环境变量 DF_SCRIPT_WHITELIST / DF_SCRIPT_BLACKLIST 读取
|
||||
// (同一逗号分隔语义),前后端打通留后续:前端写入需经 IPC/启动期注入环境变量。
|
||||
// 输入语义:逗号分隔命令名(如 `git,npm,cargo`),空串=该项不限制。
|
||||
// 前端持久化到 appSettings KV 表(df-script-whitelist / df-script-blacklist)。
|
||||
// 后端 ScriptNode 从环境变量 DF_SCRIPT_WHITELIST / DF_SCRIPT_BLACKLIST 读取(同语义逗号分隔)。
|
||||
// 前后端打通需跨 crate 接口变更(script_node.execute 接受参数注入),当前标注为已知限制。
|
||||
// 临时方案:启动时用脚本注入环境变量(export DF_SCRIPT_WHITELIST=...)。
|
||||
// ============================================================
|
||||
const scriptWhitelist = ref(appSettings.get<string>('df-script-whitelist', ''))
|
||||
const scriptBlacklist = ref(appSettings.get<string>('df-script-blacklist', ''))
|
||||
|
||||
Reference in New Issue
Block a user