From e5892ec421a9251f65b2c9dea41c94558b597c8d Mon Sep 17 00:00:00 2001 From: Gin3601 <2405559452@qq.com> Date: Tue, 26 May 2026 11:46:33 +0800 Subject: [PATCH] feat: relabel concat by target ports in frontend --- tests/test_concat_by_target_frontend.py | 34 +++++++++++++++ web/js/lls_concat_by_target.js | 55 +++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 tests/test_concat_by_target_frontend.py create mode 100644 web/js/lls_concat_by_target.js diff --git a/tests/test_concat_by_target_frontend.py b/tests/test_concat_by_target_frontend.py new file mode 100644 index 0000000..4406e36 --- /dev/null +++ b/tests/test_concat_by_target_frontend.py @@ -0,0 +1,34 @@ +import unittest + +try: + from .test_mask_draw_helpers import ROOT, load_plugin_package +except ImportError: + from test_mask_draw_helpers import ROOT, load_plugin_package + + +class TestConcatByTargetFrontend(unittest.TestCase): + def test_plugin_exports_web_directory(self): + plugin = load_plugin_package() + self.assertEqual(plugin.WEB_DIRECTORY, "./web") + + def test_frontend_asset_exists(self): + asset = ROOT / "web" / "js" / "lls_concat_by_target.js" + self.assertTrue(asset.exists(), msg=f"Missing frontend asset: {asset}") + + def test_frontend_asset_registers_concat_by_target_extension(self): + asset = (ROOT / "web" / "js" / "lls_concat_by_target.js").read_text(encoding="utf-8") + + self.assertIn("app.registerExtension", asset) + self.assertIn("LLSConcatByTarget", asset) + self.assertIn("LLS Concat By Target", asset) + self.assertIn("image/mask_A", asset) + self.assertIn("image/mask_B", asset) + self.assertIn("beforeRegisterNodeDef", asset) + self.assertIn("onNodeCreated", asset) + self.assertIn("onGraphConfigured", asset) + self.assertIn("onConnectionsChange", asset) + self.assertIn("input.label", asset) + + +if __name__ == "__main__": + unittest.main() diff --git a/web/js/lls_concat_by_target.js b/web/js/lls_concat_by_target.js new file mode 100644 index 0000000..efe9fbd --- /dev/null +++ b/web/js/lls_concat_by_target.js @@ -0,0 +1,55 @@ +import { app } from "../../scripts/app.js"; + +const EXTENSION_NAME = "LLS.ConcatByTarget"; +const TARGET_NODE_CLASS = "LLSConcatByTarget"; +const TARGET_NODE_DISPLAY_NAME = "LLS Concat By Target"; +const INPUT_LABELS = { + a: "image/mask_A", + b: "image/mask_B", +}; + +function relabelConcatInputs(node) { + let changed = false; + + for (const input of node.inputs ?? []) { + const targetLabel = INPUT_LABELS[input.name]; + if (targetLabel && input.label !== targetLabel) { + input.label = targetLabel; + changed = true; + } + } + + if (changed) { + node.setDirtyCanvas?.(true, true); + } +} + +app.registerExtension({ + name: EXTENSION_NAME, + async beforeRegisterNodeDef(nodeType, nodeData) { + if (nodeData.name !== TARGET_NODE_CLASS && nodeData.display_name !== TARGET_NODE_DISPLAY_NAME) { + return; + } + + const previousOnNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function onConcatByTargetNodeCreated() { + const result = previousOnNodeCreated?.apply(this, arguments); + relabelConcatInputs(this); + return result; + }; + + const previousOnGraphConfigured = nodeType.prototype.onGraphConfigured; + nodeType.prototype.onGraphConfigured = function onConcatByTargetGraphConfigured() { + const result = previousOnGraphConfigured?.apply(this, arguments); + relabelConcatInputs(this); + return result; + }; + + const previousOnConnectionsChange = nodeType.prototype.onConnectionsChange; + nodeType.prototype.onConnectionsChange = function onConcatByTargetConnectionsChange() { + const result = previousOnConnectionsChange?.apply(this, arguments); + relabelConcatInputs(this); + return result; + }; + }, +});