From fdef19eb0db250f7e90f147bacedec93a129ca11 Mon Sep 17 00:00:00 2001 From: rookiestar28 Date: Fri, 20 Mar 2026 05:15:51 +0800 Subject: [PATCH] refactor: centralize legacy class aliases and node image helpers --- nodes/image_to_prompt.py | 14 +++--- nodes/prompt_refiner.py | 13 +++--- web/openclaw_tabs.js | 8 +++- web/openclaw_ui.js | 7 ++- web/openclaw_utils.js | 48 +++++++++++++++++++ web/tabs/packs_tab.js | 26 +++++------ web/tabs/planner_tab.js | 60 ++++++++++++------------ web/tabs/refiner_tab.js | 66 +++++++++++++-------------- web/tabs/variants_tab.js | 42 ++++++++--------- web/tests/unit/openclaw_utils.test.js | 22 +++++++++ 10 files changed, 192 insertions(+), 114 deletions(-) diff --git a/nodes/image_to_prompt.py b/nodes/image_to_prompt.py index 75c9b87..bc4682c 100644 --- a/nodes/image_to_prompt.py +++ b/nodes/image_to_prompt.py @@ -1,4 +1,5 @@ import logging +from functools import partial from typing import Any, Tuple try: @@ -64,14 +65,11 @@ class OpenClawImageToPrompt: FUNCTION = "generate_prompt" CATEGORY = "moltbot" - def _tensor_to_base64_png(self, tensor_image: Any, max_side: int) -> str: - """ - Convert ComfyUI tensor (Batch, H, W, C) to base64 PNG. - Uses the first image in batch. - """ - return tensor_to_base64_png( - tensor_image=tensor_image, max_side=max_side, context="ImageToPrompt" - ) + # R154: keep the compatibility method name, but bind the shared helper + # directly so node wrappers do not duplicate image conversion logic. + _tensor_to_base64_png = staticmethod( + partial(tensor_to_base64_png, context="ImageToPrompt") + ) def generate_prompt( self, image: Any, goal: str, detail_level: str, max_image_side: int diff --git a/nodes/prompt_refiner.py b/nodes/prompt_refiner.py index e7468eb..2252381 100644 --- a/nodes/prompt_refiner.py +++ b/nodes/prompt_refiner.py @@ -1,5 +1,6 @@ import json import logging +from functools import partial from typing import Any, Tuple try: @@ -76,13 +77,11 @@ class OpenClawPromptRefiner: FUNCTION = "refine_prompt" CATEGORY = "moltbot" - def _tensor_to_base64_png(self, tensor_image: Any, max_side: int) -> str: - """ - Convert ComfyUI tensor (Batch, H, W, C) to base64 PNG. - """ - return tensor_to_base64_png( - tensor_image=tensor_image, max_side=max_side, context="PromptRefiner" - ) + # R154: keep the compatibility method name, but bind the shared helper + # directly so node wrappers do not duplicate image conversion logic. + _tensor_to_base64_png = staticmethod( + partial(tensor_to_base64_png, context="PromptRefiner") + ) def refine_prompt( self, diff --git a/web/openclaw_tabs.js b/web/openclaw_tabs.js index dd04048..ca8282f 100644 --- a/web/openclaw_tabs.js +++ b/web/openclaw_tabs.js @@ -4,7 +4,10 @@ */ import { ErrorBoundary } from "./ErrorBoundary.js"; import { STORAGE_KEYS, getMirroredStorageValue, setMirroredStorageValue } from "./openclaw_compat.js"; -import { normalizeLegacyClassNames } from "./openclaw_utils.js"; +import { + applyLegacyClassAliases, + normalizeLegacyClassNames, +} from "./openclaw_utils.js"; export class TabManager { constructor() { @@ -79,6 +82,8 @@ export class TabManager { normalizeLegacyClassNames(this.tabsEl); normalizeLegacyClassNames(this.contentEl); + applyLegacyClassAliases(this.tabsEl); + applyLegacyClassAliases(this.contentEl); } activateTab(id) { @@ -119,6 +124,7 @@ export class TabManager { if (pane) { normalizeLegacyClassNames(pane); + applyLegacyClassAliases(pane); } } diff --git a/web/openclaw_ui.js b/web/openclaw_ui.js index f5de42d..bf44a29 100644 --- a/web/openclaw_ui.js +++ b/web/openclaw_ui.js @@ -5,7 +5,10 @@ import { tabManager } from "./openclaw_tabs.js"; import { ErrorBoundary } from "./ErrorBoundary.js"; import { openclawApi } from "./openclaw_api.js"; -import { normalizeLegacyClassNames } from "./openclaw_utils.js"; +import { + applyLegacyClassAliases, + normalizeLegacyClassNames, +} from "./openclaw_utils.js"; import { OpenClawActions } from "./openclaw_actions.js"; import { QueueMonitor } from "./openclaw_queue_monitor.js"; import { OpenClawNotificationCenter } from "./openclaw_notification_center.js"; @@ -204,6 +207,7 @@ export class OpenClawUI { tabManager.init(tabBar, contentArea); normalizeLegacyClassNames(container); + applyLegacyClassAliases(container); this.bannerManager.bind(container, (action) => this.handleAction(action)); this.notificationCenter.render(); } @@ -301,6 +305,7 @@ export class OpenClawUI { this.container.appendChild(overlay); normalizeLegacyClassNames(overlay); + applyLegacyClassAliases(overlay); } } diff --git a/web/openclaw_utils.js b/web/openclaw_utils.js index cbab1b3..2ad7e36 100644 --- a/web/openclaw_utils.js +++ b/web/openclaw_utils.js @@ -72,6 +72,54 @@ export function normalizeLegacyClassNames(root) { return root; } +/** + * R154: derive runtime legacy aliases from canonical class tokens so templates + * do not need to hand-author duplicate `openclaw-*` + `moltbot-*` markup. + */ +export function buildLegacyAliasClassTokens(className = "") { + const canonicalTokens = normalizeLegacyClassTokens(className) + .split(/\s+/) + .map((token) => token.trim()) + .filter(Boolean); + const seen = new Set(canonicalTokens); + const combined = [...canonicalTokens]; + + canonicalTokens.forEach((token) => { + if (!token.startsWith("openclaw-")) { + return; + } + const legacy = `moltbot-${token.slice("openclaw-".length)}`; + if (seen.has(legacy)) { + return; + } + seen.add(legacy); + combined.push(legacy); + }); + + return combined.join(" "); +} + +export function applyLegacyClassAliases(root) { + if (!root) return root; + const nodes = []; + if (typeof root.className === "string") { + nodes.push(root); + } + if (typeof root.querySelectorAll === "function") { + nodes.push(...root.querySelectorAll("[class]")); + } + + nodes.forEach((node) => { + if (typeof node.className !== "string") return; + const withAliases = buildLegacyAliasClassTokens(node.className); + if (withAliases !== node.className) { + node.className = withAliases; + } + }); + + return root; +} + /** * Lightweight toast helper for UI feedback. * @param {string} message diff --git a/web/tabs/packs_tab.js b/web/tabs/packs_tab.js index 4fb515e..27a67a0 100644 --- a/web/tabs/packs_tab.js +++ b/web/tabs/packs_tab.js @@ -20,21 +20,21 @@ export const PacksTab = { render(container) { // --- 1. Static Layout --- container.innerHTML = ` -
-
-
Asset Packs
- -
+
+
+
Asset Packs
+ +
- - +
-
-
Loading...
+
+
Loading...
`; @@ -51,7 +51,7 @@ export const PacksTab = { const renderListItem = (pack) => { return ` -
+
${escapeHtml(pack.name)} v${escapeHtml(pack.version)} @@ -64,8 +64,8 @@ export const PacksTab = {
- - + +
`; @@ -73,7 +73,7 @@ export const PacksTab = { const renderList = (packs) => { if (!packs || packs.length === 0) { - ui.list.innerHTML = '
No packs installed.
'; + ui.list.innerHTML = '
No packs installed.
'; return; } ui.list.innerHTML = packs.map(renderListItem).join(""); diff --git a/web/tabs/planner_tab.js b/web/tabs/planner_tab.js index 539fae6..e3fd0ee 100644 --- a/web/tabs/planner_tab.js +++ b/web/tabs/planner_tab.js @@ -8,30 +8,30 @@ export const PlannerTab = { render(container) { container.innerHTML = ` -
-
-
-
Generation Goal
+
+
+
+
Generation Goal
- + -
-
- -
-
- - +
+ +
-
- - +
+ +
@@ -45,28 +45,28 @@ export const PlannerTab = {
Live Preview (best effort)
- +
- +
- +
-