diff --git a/README.md b/README.md index d1af6ff..5497904 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,17 @@ Deployment profiles and hardening checklists:
+Frontend quality baseline for Library and Approvals surfaces + +- Canonicalized active frontend styling ownership around `openclaw-*`, including shell/tab-manager cleanup and a deterministic split of `web/openclaw.css` into core and legacy-alias modules. +- Added a frontend unit-test lane with Vitest + jsdom plus baseline coverage for shared UI helpers and extracted Library tab state logic. +- Expanded Playwright coverage for `Library` and `Approvals`, including success/degraded paths and approvals parity between the sidebar and the Remote Admin Console. +- Completed full verification gate pass (detect-secrets, pre-commit, backend unit suites, adversarial/retry/real-backend lanes, and frontend Playwright E2E). + +
+ +
+ Audit event clarity and connector ingress fail-closed hardening - Normalized audit helper behavior so config/secret/LLM-test convenience wrappers now emit one canonical audit event per action, reducing duplicate noise while preserving legacy compatibility paths. diff --git a/package-lock.json b/package-lock.json index 5b22ff7..7a28058 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,12 +6,592 @@ "": { "name": "comfyui-openclaw", "devDependencies": { - "@playwright/test": "^1.50.0" + "@playwright/test": "^1.50.0", + "jsdom": "^26.0.0", + "vitest": "^3.2.4" }, "engines": { "node": ">=18.0.0" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, "node_modules/@playwright/test": { "version": "1.58.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.1.tgz", @@ -27,6 +607,716 @@ "node": ">=18" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -41,6 +1331,221 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/playwright": { "version": "1.58.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.1.tgz", @@ -70,6 +1575,578 @@ "engines": { "node": ">=18" } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index 400e3ed..9d2d482 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,14 @@ "node": ">=18.0.0" }, "devDependencies": { - "@playwright/test": "^1.50.0" + "@playwright/test": "^1.50.0", + "jsdom": "^26.0.0", + "vitest": "^3.2.4" }, "scripts": { "test": "node scripts/run-playwright.mjs", + "test:unit": "vitest run", + "test:unit:watch": "vitest", "test:ui": "npx playwright test --ui", "test:headed": "npx playwright test --headed", "test:debug": "npx playwright test --debug", diff --git a/tests/e2e/specs/approvals.spec.js b/tests/e2e/specs/approvals.spec.js new file mode 100644 index 0000000..5b5be6b --- /dev/null +++ b/tests/e2e/specs/approvals.spec.js @@ -0,0 +1,124 @@ +import { expect, test } from '@playwright/test'; +import { clickTab, mockComfyUiCore, waitForOpenClawReady } from '../utils/helpers.js'; + +const pendingApproval = { + approval_id: 'apr-001', + template_id: 'render_portrait', + status: 'pending', + requested_at: '2026-03-05T10:00:00Z', + source: 'telegram', + inputs: { prompt: 'portrait', style: 'studio' }, +}; + +async function mockApprovalApis(page, { listStatus = 200, listData = [pendingApproval], approveStatus = 200 } = {}) { + let approvals = [...listData]; + + await page.route('**/openclaw/approvals**', async (route) => { + const request = route.request(); + const url = new URL(request.url()); + + if (request.method() === 'GET' && /\/approvals\/[^/]+$/.test(url.pathname)) { + const id = decodeURIComponent(url.pathname.split('/').pop()); + const match = approvals.find((item) => item.approval_id === id); + await route.fulfill({ + status: match ? 200 : 404, + contentType: 'application/json', + body: JSON.stringify(match ? { approval: match } : { error: 'not_found' }), + }); + return; + } + + if (request.method() === 'GET') { + await route.fulfill({ + status: listStatus, + contentType: 'application/json', + body: JSON.stringify( + listStatus === 200 ? { approvals } : { error: 'approval_list_failed' } + ), + }); + return; + } + + if (request.method() === 'POST' && url.pathname.endsWith('/approve')) { + if (approveStatus === 200) { + approvals = approvals.map((item) => + item.approval_id === pendingApproval.approval_id + ? { ...item, status: 'approved' } + : item + ); + } + await route.fulfill({ + status: approveStatus, + contentType: 'application/json', + body: JSON.stringify( + approveStatus === 200 + ? { executed: true, prompt_id: 'prompt-42' } + : { error: 'approve_failed' } + ), + }); + return; + } + + if (request.method() === 'POST' && url.pathname.endsWith('/reject')) { + approvals = approvals.map((item) => + item.approval_id === pendingApproval.approval_id + ? { ...item, status: 'rejected' } + : item + ); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ ok: true }), + }); + return; + } + + await route.fulfill({ status: 404, contentType: 'application/json', body: JSON.stringify({ error: 'not_found' }) }); + }); +} + +test.describe('Approvals surfaces', () => { + test.beforeEach(async ({ page }) => { + await mockComfyUiCore(page); + await page.addInitScript(() => { + window.confirm = () => true; + window.alert = () => {}; + }); + }); + + test('loads pending approvals and allows approve action', async ({ page }) => { + await mockApprovalApis(page); + await page.goto('test-harness.html'); + await waitForOpenClawReady(page); + await clickTab(page, 'Approvals'); + + await expect(page.locator('#apr-list .openclaw-list-item')).toHaveCount(1); + await expect(page.locator('#apr-list')).toContainText('render_portrait'); + + await page.locator('#apr-list button[data-action="approve"]').click(); + await expect(page.locator('#apr-list')).toContainText('APPROVED'); + }); + + test('shows approval list fetch failures inside the sidebar', async ({ page }) => { + await mockApprovalApis(page, { listStatus: 500, listData: [] }); + await page.goto('test-harness.html'); + await waitForOpenClawReady(page); + await clickTab(page, 'Approvals'); + + await expect(page.locator('.openclaw-error-box')).toContainText('approval_list_failed'); + }); + + test('keeps admin console pending approvals aligned with sidebar data', async ({ page }) => { + await mockApprovalApis(page); + await page.goto('test-harness.html'); + await waitForOpenClawReady(page); + await clickTab(page, 'Approvals'); + await expect(page.locator('#apr-list')).toContainText('apr-001'); + + await page.goto('http://127.0.0.1:3000/web/admin_console.html'); + await page.locator('#refreshApprovals').click(); + + await expect(page.locator('#approvalsList')).toContainText('apr-001'); + await expect(page.locator('#approvalsList')).toContainText('render_portrait'); + }); +}); diff --git a/tests/e2e/specs/library.spec.js b/tests/e2e/specs/library.spec.js new file mode 100644 index 0000000..d3835dc --- /dev/null +++ b/tests/e2e/specs/library.spec.js @@ -0,0 +1,120 @@ +import { expect, test } from '@playwright/test'; +import { clickTab, mockComfyUiCore, waitForOpenClawReady } from '../utils/helpers.js'; + +const presets = [ + { + id: 'prompt-1', + name: 'Portrait Prompt', + category: 'prompt', + content: { positive: 'portrait lighting', negative: 'blurry' }, + }, + { + id: 'params-1', + name: 'Landscape Params', + category: 'params', + content: { params: { width: 1280, height: 720, seed: 99 } }, + }, +]; + +test.describe('Library Tab', () => { + test.beforeEach(async ({ page }) => { + await mockComfyUiCore(page); + await page.addInitScript(() => { + window.confirm = () => true; + window.alert = () => {}; + }); + + await page.route('**/openclaw/presets**', async (route) => { + const request = route.request(); + const url = new URL(request.url()); + + if (request.method() === 'GET' && /\/presets\/[^/]+$/.test(url.pathname)) { + const id = decodeURIComponent(url.pathname.split('/').pop()); + const preset = presets.find((item) => item.id === id); + await route.fulfill({ + status: preset ? 200 : 404, + contentType: 'application/json', + body: JSON.stringify(preset || { error: 'not_found' }), + }); + return; + } + + if (request.method() === 'GET') { + const category = url.searchParams.get('category'); + const items = category ? presets.filter((item) => item.category === category) : presets; + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(items), + }); + return; + } + + if (request.method() === 'POST') { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ ok: true, id: 'new-preset' }), + }); + return; + } + + await route.fulfill({ status: 204, body: '' }); + }); + + await page.route('**/openclaw/packs**', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ packs: [] }), + }); + }); + + await page.goto('test-harness.html'); + await waitForOpenClawReady(page); + }); + + test('loads presets and applies prompt presets into Planner', async ({ page }) => { + await clickTab(page, 'Library'); + + await expect(page.locator('#lib-list .openclaw-list-item')).toHaveCount(2); + await expect(page.locator('#lib-list')).toContainText('Portrait Prompt'); + + await page.locator('#lib-list button[data-action="apply"]').first().click(); + + await expect(page.locator('#openclaw-tab-planner')).toHaveClass(/active/); + await expect(page.locator('#planner-out-pos')).toHaveValue('portrait lighting'); + await expect(page.locator('#planner-out-neg')).toHaveValue('blurry'); + }); + + test('filters presets and routes params presets into Variants', async ({ page }) => { + await clickTab(page, 'Library'); + + await page.locator('#lib-search').fill('landscape'); + await expect(page.locator('#lib-list .openclaw-list-item')).toHaveCount(1); + await expect(page.locator('#lib-list')).toContainText('Landscape Params'); + + await page.locator('#lib-list button[data-action="apply"]').click(); + + await expect(page.locator('#openclaw-tab-variants')).toHaveClass(/active/); + await expect(page.locator('#var-base-params')).toHaveValue(/1280/); + await expect(page.locator('#var-base-params')).toHaveValue(/99/); + }); + + test('shows a deterministic error state when presets fail to load', async ({ page }) => { + await page.unroute('**/openclaw/presets**'); + await page.route('**/openclaw/presets**', async (route) => { + await route.fulfill({ + status: 500, + contentType: 'application/json', + body: JSON.stringify({ error: 'preset_list_failed' }), + }); + }); + + await page.goto('test-harness.html'); + await waitForOpenClawReady(page); + await clickTab(page, 'Library'); + + await expect(page.locator('.openclaw-error-box')).toContainText('preset_list_failed'); + }); +}); diff --git a/vitest.config.mjs b/vitest.config.mjs new file mode 100644 index 0000000..c318474 --- /dev/null +++ b/vitest.config.mjs @@ -0,0 +1,11 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "jsdom", + setupFiles: ["./web/tests/unit/setup.js"], + include: ["web/tests/unit/**/*.test.js"], + restoreMocks: true, + clearMocks: true, + }, +}); diff --git a/web/openclaw.css b/web/openclaw.css index 3a6791f..d78038a 100644 --- a/web/openclaw.css +++ b/web/openclaw.css @@ -1,1854 +1,3 @@ -/* Moltbot Design System */ - -:root { - /* Spacing Scale */ - --openclaw-space-xs: 4px; - --openclaw-space-sm: 8px; - --openclaw-space-md: 12px; - --openclaw-space-lg: 16px; - --openclaw-space-xl: 24px; - - /* Typography */ - --openclaw-font-xs: 11px; - --openclaw-font-sm: 12px; - --openclaw-font-md: 13px; - --openclaw-font-lg: 14px; - --openclaw-font-mono: 'Consolas', 'Monaco', 'Courier New', monospace; - - /* Colors (inheriting from ComfyUI variable names where possible, fallbacks provided) */ - --openclaw-color-bg: var(--comfy-menu-bg, #222); - --openclaw-color-bg-light: var(--comfy-input-bg, #333); - --openclaw-color-fg: var(--fg-color, #eee); - --openclaw-color-fg-muted: #aaa; - --openclaw-color-border: var(--border-color, #444); - --openclaw-color-primary: var(--primary-color, #2a2); - --openclaw-color-danger: #d44; - --openclaw-color-warning: #ea0; - --openclaw-color-success: #2a2; -} - -/* Layout Primitives */ - -.openclaw-sidebar-container { - display: flex; - flex-direction: column; - height: 100%; - min-width: 560px; /* Keep sidebar readable: header tabs + Parameter Lab controls */ - min-height: 0; /* allow children to shrink for overflow handling */ - background: var(--openclaw-color-bg); - color: var(--openclaw-color-fg); - font-family: Arial, sans-serif; - font-size: var(--openclaw-font-md); -} - -/* CRITICAL: Keep this rule + !important; SplitterPanel inline sizing can override inner container min-width. */ -.side-bar-panel:has(.openclaw-sidebar-container) { - min-width: 560px !important; -} - -.openclaw-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--openclaw-space-md); - padding: var(--openclaw-space-md) var(--openclaw-space-lg); - border-bottom: 1px solid var(--openclaw-color-border); - background: rgba(0,0,0,0.15); -} - -.openclaw-status-dot { - width: 10px; - height: 10px; - border-radius: 50%; - background: #666; - flex: 0 0 auto; -} -.openclaw-status-dot.ok { background: #2a2; } -.openclaw-status-dot.warn { background: #ea0; } -.openclaw-status-dot.err { background: #c44; } - -.openclaw-title { - font-size: var(--openclaw-font-lg); - font-weight: 700; - flex: 1 1 auto; - min-width: 0; -} - -.openclaw-badges { - display: flex; - align-items: center; - justify-content: flex-end; - gap: var(--openclaw-space-sm); - flex: 0 0 auto; -} - -.openclaw-version { - font-size: var(--openclaw-font-sm); - color: var(--openclaw-color-fg-muted); -} - -.openclaw-repo-link { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 4px 8px; - border: 1px solid var(--openclaw-color-border); - border-radius: 999px; - background: rgba(255,255,255,0.04); - color: var(--openclaw-color-fg); - text-decoration: none; - font-size: var(--openclaw-font-sm); - white-space: nowrap; -} -.openclaw-repo-link:hover { background: rgba(255,255,255,0.08); } - -.openclaw-banner { - padding: var(--openclaw-space-sm) var(--openclaw-space-lg); - border-bottom: 1px solid var(--openclaw-color-border); - font-size: var(--openclaw-font-sm); - display: flex; - align-items: center; - gap: var(--openclaw-space-md); - justify-content: space-between; -} -.openclaw-banner > span { flex: 1; } - -.openclaw-banner-warning { background: rgba(255, 170, 0, 0.10); color: #ffd27a; } -.openclaw-banner-info { background: rgba(0, 120, 255, 0.10); color: #a8d1ff; } -.openclaw-banner-success { background: rgba(42, 170, 42, 0.15); color: #bfffc0; } -.openclaw-banner-error { background: rgba(200, 50, 50, 0.15); color: #ffb4b4; } - -.openclaw-banner-action { - background: rgba(255,255,255,0.1); - border: 1px solid rgba(255,255,255,0.2); - color: inherit; - padding: 2px 8px; - border-radius: 4px; - cursor: pointer; - font-size: var(--openclaw-font-xs); - text-transform: uppercase; - font-weight: bold; -} -.openclaw-banner-action:hover { background: rgba(255,255,255,0.2); } - -.openclaw-banner-close { - background: none; - border: none; - color: inherit; - opacity: 0.7; - cursor: pointer; - font-size: 16px; - line-height: 1; - padding: 0 4px; -} -.openclaw-banner-close:hover { opacity: 1; } - -.openclaw-tabs { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); /* 4 tabs per row */ - grid-auto-flow: row; /* left-to-right, then top-to-bottom */ - gap: 6px; - padding: 8px var(--openclaw-space-lg); - border-bottom: 1px solid var(--openclaw-color-border); - background: rgba(0,0,0,0.10); -} - -.openclaw-tab { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 10px; - border-radius: 6px; - border: 1px solid transparent; - cursor: pointer; - user-select: none; - color: var(--openclaw-color-fg-muted); - background: rgba(255,255,255,0.02); - font-size: var(--openclaw-font-sm); - line-height: 1; - width: 100%; - min-width: 0; - justify-content: center; -} - -.openclaw-tab:hover { - color: var(--openclaw-color-fg); - border-color: rgba(255,255,255,0.08); - background: rgba(255,255,255,0.04); -} - -.openclaw-tab.active { - color: var(--openclaw-color-fg); - border-color: rgba(42, 170, 42, 0.5); - background: rgba(42, 170, 42, 0.15); -} - -.openclaw-tab-icon { - font-size: 13px; - opacity: 0.9; -} - -.openclaw-tab-label { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.openclaw-content { - flex: 1 1 auto; - min-height: 0; - overflow: hidden; -} - -.openclaw-tab-pane { - display: none; - height: 100%; - min-height: 0; -} -.openclaw-tab-pane.active { - display: block; -} - -.openclaw-panel { - display: flex; - flex-direction: column; - height: 100%; - overflow: hidden; - color: var(--openclaw-color-fg); - font-size: var(--openclaw-font-md); - background: var(--openclaw-color-bg); -} - -.openclaw-scroll-area { - flex: 1; - overflow-y: auto; - padding: var(--openclaw-space-lg); /* More breathing room */ - display: flex; - flex-direction: column; - gap: var(--openclaw-space-lg); -} - -.openclaw-card { - background: rgba(0, 0, 0, 0.2); - border: 1px solid var(--openclaw-color-border); - border-radius: 4px; - padding: var(--openclaw-space-md); - display: flex; - flex-direction: column; - gap: var(--openclaw-space-sm); -} - -.openclaw-section-header { - font-size: var(--openclaw-font-sm); - text-transform: uppercase; - color: var(--openclaw-color-fg-muted); - letter-spacing: 0.05em; - margin-bottom: var(--openclaw-space-xs); - font-weight: bold; - border-bottom: 1px solid var(--openclaw-color-border); - padding-bottom: var(--openclaw-space-xs); -} - -/* Grids & Splits */ -.openclaw-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--openclaw-space-md); -} - -.openclaw-split-v { - display: flex; - flex-direction: column; - gap: var(--openclaw-space-md); -} - -.openclaw-split-h { - display: flex; - flex-direction: row; - gap: var(--openclaw-space-md); - align-items: center; -} - -/* Form Elements */ -.openclaw-input-group { - display: flex; - flex-direction: column; - gap: var(--openclaw-space-xs); -} - -.openclaw-section { - background: rgba(0,0,0,0.18); - border: 1px solid var(--openclaw-color-border); - border-radius: 6px; - padding: var(--openclaw-space-lg); - display: flex; - flex-direction: column; - gap: var(--openclaw-space-md); -} - -.openclaw-section > h4 { - margin: 0; - font-size: var(--openclaw-font-lg); -} - -.openclaw-form-row { - display: flex; - flex-direction: column; - gap: var(--openclaw-space-xs); -} - -.openclaw-btn-row { - display: flex; - flex-direction: row; - gap: var(--openclaw-space-sm); - flex-wrap: wrap; -} - -.openclaw-note { - padding: var(--openclaw-space-sm) var(--openclaw-space-md); - border: 1px solid var(--openclaw-color-border); - border-radius: 4px; - background: rgba(255,255,255,0.03); - color: var(--openclaw-color-fg-muted); - font-size: var(--openclaw-font-sm); - line-height: 1.35; -} - -.openclaw-status { - font-size: var(--openclaw-font-sm); - color: var(--openclaw-color-fg-muted); - min-height: 16px; -} -.openclaw-status.ok { color: #bfffc0; } -.openclaw-status.error { color: #ffb4b4; } - -.openclaw-kv-row { - display: flex; - justify-content: space-between; - gap: var(--openclaw-space-md); -} -.openclaw-kv-key { color: var(--openclaw-color-fg-muted); } -.openclaw-kv-val { color: var(--openclaw-color-fg); } -.openclaw-kv-val.ok { color: #bfffc0; } -.openclaw-kv-val.error { color: #ffb4b4; } - -.openclaw-log-viewer { - white-space: pre-wrap; - font-family: var(--openclaw-font-mono); - font-size: var(--openclaw-font-sm); - background: rgba(0,0,0,0.25); - border: 1px solid var(--openclaw-color-border); - border-radius: 4px; - padding: var(--openclaw-space-md); - max-height: 260px; - overflow: auto; -} - -.openclaw-checkbox { - width: 16px; - height: 16px; - flex: 0 0 auto; -} - -.openclaw-help-btn { - width: 22px; - height: 22px; - border-radius: 999px; - border: 1px solid var(--openclaw-color-border); - background: rgba(255,255,255,0.04); - color: var(--openclaw-color-fg); - cursor: pointer; - font-size: var(--openclaw-font-sm); - line-height: 1; - flex: 0 0 auto; -} -.openclaw-help-btn:hover { - background: rgba(255,255,255,0.08); -} - -.openclaw-label { - font-size: var(--openclaw-font-sm); - color: var(--openclaw-color-fg-muted); -} - -.openclaw-input, .openclaw-select, .openclaw-textarea { - background: var(--openclaw-color-bg-light); - border: 1px solid var(--openclaw-color-border); - color: var(--openclaw-color-fg); - padding: 6px 8px; - border-radius: 2px; - font-size: var(--openclaw-font-md); - width: 100%; - box-sizing: border-box; -} - -.openclaw-input:focus, .openclaw-select:focus, .openclaw-textarea:focus { - border-color: var(--openclaw-color-primary); - outline: none; -} - -.openclaw-textarea { - font-family: var(--openclaw-font-mono); - resize: vertical; - min-height: 60px; -} - -.openclaw-textarea-sm { min-height: 80px; } -.openclaw-textarea-md { min-height: 150px; } -.openclaw-textarea-lg { min-height: 250px; } -.openclaw-textarea-xl { min-height: 400px; } - -/* Buttons */ -.openclaw-btn { - background: var(--openclaw-color-bg-light); - border: 1px solid var(--openclaw-color-border); - color: var(--openclaw-color-fg); - padding: 6px 12px; - cursor: pointer; - font-size: var(--openclaw-font-md); - border-radius: 2px; - text-align: center; - transition: background 0.1s; -} - -.openclaw-btn:hover:not(:disabled) { - background: #444; -} - -.openclaw-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.openclaw-btn-primary { - background: #2a2; /* Green-ish */ - color: #fff; - border-color: #181; -} -.openclaw-btn-primary:hover:not(:disabled) { background: #3b3; } - -.openclaw-btn-danger { - background: #a33; - color: #fff; - border-color: #822; -} -.openclaw-btn-danger:hover:not(:disabled) { background: #c44; } - -.openclaw-btn-sm { - padding: 2px 6px; - font-size: var(--openclaw-font-sm); -} - -.openclaw-btn-success { - background: rgba(42, 170, 42, 0.2); - border-color: rgba(42, 170, 42, 0.6); - color: #dfffe0; -} - -/* Compatibility aliases used by existing tabs */ -.openclaw-btn.primary { - background: rgba(42, 170, 42, 0.2); - border-color: rgba(42, 170, 42, 0.6); - color: #dfffe0; -} -.openclaw-btn.primary:hover:not(:disabled) { - background: rgba(42, 170, 42, 0.3); -} -.openclaw-btn.secondary { - background: rgba(255, 255, 255, 0.04); - border-color: var(--openclaw-color-border); - color: var(--openclaw-color-fg); -} - -.openclaw-btn.has-icon { - display: inline-flex; - align-items: center; - gap: 6px; -} - -.openclaw-btn-icon { - width: 26px; - height: 26px; - border: 1px solid var(--openclaw-color-border); - background: rgba(255, 255, 255, 0.04); - color: var(--openclaw-color-fg); - border-radius: 4px; - cursor: pointer; - font-size: var(--openclaw-font-sm); - line-height: 1; -} -.openclaw-btn-icon:hover { - background: rgba(255, 255, 255, 0.1); -} - -.openclaw-separator { - width: 1px; - height: 24px; - background: var(--openclaw-color-border); - opacity: 0.7; -} - -.openclaw-form-group { - display: flex; - flex-direction: column; - gap: 6px; -} - -.openclaw-form-group > label { - font-size: var(--openclaw-font-sm); - color: var(--openclaw-color-fg-muted); -} - -.openclaw-form-group > input, -.openclaw-form-group > select, -.openclaw-form-group > textarea { - background: var(--openclaw-color-bg-light); - border: 1px solid var(--openclaw-color-border); - color: var(--openclaw-color-fg); - padding: 6px 8px; - border-radius: 4px; - font-size: var(--openclaw-font-md); -} -.openclaw-form-group > input:focus, -.openclaw-form-group > select:focus, -.openclaw-form-group > textarea:focus { - outline: none; - border-color: rgba(42, 170, 42, 0.7); -} - -.openclaw-hint, -.openclaw-loading, -.openclaw-error { - padding: 10px 12px; - border-radius: 6px; - font-size: var(--openclaw-font-sm); - border: 1px solid var(--openclaw-color-border); - background: rgba(255, 255, 255, 0.03); - color: var(--openclaw-color-fg-muted); -} - -.openclaw-loading { - color: #d2e4ff; - border-color: rgba(90, 150, 255, 0.45); - background: rgba(90, 150, 255, 0.12); -} - -.openclaw-error { - color: #ffb4b4; - border-color: rgba(200, 60, 60, 0.6); - background: rgba(200, 60, 60, 0.18); -} - -/* Status Indicators */ -.openclaw-badge { - padding: 2px 6px; - border-radius: 4px; - font-size: var(--openclaw-font-xs); - font-weight: bold; - text-transform: uppercase; -} -.openclaw-badge.pending { background: #aa0; color: #000; } -.openclaw-badge.approved { background: #2a2; color: #fff; } -.openclaw-badge.rejected { background: #c00; color: #fff; } -.openclaw-badge.expired { background: #666; color: #ccc; } - -/* Error / Empty States */ -.openclaw-empty-state { - padding: var(--openclaw-space-xl); - text-align: center; - color: var(--openclaw-color-fg-muted); - border: 1px dashed var(--openclaw-color-border); - border-radius: 4px; - background: rgba(255, 255, 255, 0.02); -} - -.openclaw-error-box { - padding: var(--openclaw-space-md); - background: rgba(200, 50, 50, 0.1); - border: 1px solid #a33; - border-radius: 4px; - color: #eaa; - display: flex; - flex-direction: column; - gap: var(--openclaw-space-sm); -} - -.openclaw-error-title { - font-weight: bold; - display: flex; - align-items: center; - gap: var(--openclaw-space-sm); -} - -.openclaw-error-hint { - font-size: var(--openclaw-font-sm); - color: #ccc; - background: rgba(0,0,0,0.3); - padding: 4px; - border-radius: 2px; -} - -/* Loading Spinner (Simple) */ -.openclaw-spinner { - width: 20px; - height: 20px; - border: 2px solid rgba(255,255,255,0.3); - border-radius: 50%; - border-top-color: #fff; - animation: spin 1s ease-in-out infinite; -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* Modals */ -.openclaw-modal-overlay { - position: fixed; - top: 0; left: 0; right: 0; bottom: 0; - background: rgba(0,0,0,0.7); - display: flex; - align-items: center; - justify-content: center; - z-index: 9999; -} - -.openclaw-modal { - background: var(--openclaw-color-bg); - border: 1px solid var(--openclaw-color-border); - box-shadow: 0 10px 25px rgba(0,0,0,0.5); - border-radius: 6px; - min-width: 400px; - max-width: 90vw; - max-height: 90vh; - display: flex; - flex-direction: column; -} - -.openclaw-modal-header { - padding: var(--openclaw-space-md); - border-bottom: 1px solid var(--openclaw-color-border); - display: flex; - justify-content: space-between; - align-items: center; - font-weight: bold; - font-size: var(--openclaw-font-lg); -} - -.openclaw-modal-body { - padding: var(--openclaw-space-lg); - overflow-y: auto; - flex: 1; -} - -.openclaw-modal-footer { - padding: var(--openclaw-space-md); - border-top: 1px solid var(--openclaw-color-border); - display: flex; - justify-content: flex-end; - gap: var(--openclaw-space-md); - background: rgba(0,0,0,0.1); -} - -/* Parameter Lab */ -.openclaw-lab-container { - display: flex; - flex-direction: column; - gap: var(--openclaw-space-md); - height: 100%; - min-height: 0; - padding: var(--openclaw-space-md); - box-sizing: border-box; - overflow: hidden; -} - -.openclaw-lab-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - flex-wrap: wrap; - gap: var(--openclaw-space-md); - border: 1px solid var(--openclaw-color-border); - background: rgba(255, 255, 255, 0.03); - border-radius: 8px; - padding: var(--openclaw-space-md); -} - -.openclaw-lab-title-wrap { - flex: 1 1 100%; - min-width: 0; -} - -.openclaw-lab-title-wrap > h3 { - margin: 0; - font-size: 20px; - line-height: 1.1; - word-break: normal; - overflow-wrap: normal; -} - -.openclaw-lab-title-wrap > p { - margin: 4px 0 0; - color: var(--openclaw-color-fg-muted); - font-size: var(--openclaw-font-sm); - line-height: 1.35; - max-width: 60ch; - word-break: normal; - overflow-wrap: normal; -} - -.openclaw-lab-actions { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: var(--openclaw-space-sm); - width: 100%; - margin: 0 auto; - align-items: stretch; -} - -.openclaw-lab-action-btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; - min-width: 0; - width: 100%; - text-align: center; - overflow: hidden; -} - -.openclaw-lab-actions .openclaw-btn.has-icon.openclaw-lab-action-btn { - justify-content: center; -} - -.openclaw-lab-action-icon { - flex: 0 0 auto; - line-height: 1; -} - -.openclaw-lab-action-label { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.openclaw-lab-action-btn.active { - border-color: rgba(42, 170, 42, 0.65); - background: rgba(42, 170, 42, 0.2); - color: #dfffe0; -} - -.openclaw-lab-action-btn:focus { - outline: none; -} - -.openclaw-lab-action-btn:focus-visible { - border-color: rgba(42, 170, 42, 0.75); - box-shadow: 0 0 0 1px rgba(42, 170, 42, 0.35) inset; -} - -.openclaw-lab-actions .openclaw-separator { - display: none; -} - -.openclaw-lab-main { - display: grid; - grid-template-columns: minmax(0, 1fr); - gap: var(--openclaw-space-md); - min-height: 0; - overflow-y: auto; - padding-right: 2px; -} - -.openclaw-lab-card { - border: 1px solid var(--openclaw-color-border); - background: rgba(0, 0, 0, 0.16); - border-radius: 8px; - padding: var(--openclaw-space-md); - display: flex; - flex-direction: column; - gap: var(--openclaw-space-md); -} - -.openclaw-lab-card-head { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: var(--openclaw-space-md); - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - padding-bottom: var(--openclaw-space-sm); -} - -.openclaw-lab-card-head > h4 { - margin: 0; - font-size: 15px; -} - -.openclaw-lab-meta { - color: var(--openclaw-color-fg-muted); - font-size: var(--openclaw-font-sm); -} - -.openclaw-lab-config, -.openclaw-lab-results { - display: flex; - flex-direction: column; - gap: var(--openclaw-space-sm); -} - -.openclaw-lab-dim-row { - display: grid; - grid-template-columns: 84px 110px 1fr 32px; - gap: var(--openclaw-space-sm); - align-items: end; - border: 1px solid rgba(255, 255, 255, 0.08); - background: rgba(255, 255, 255, 0.02); - border-radius: 6px; - padding: var(--openclaw-space-sm); -} - -.openclaw-lab-dim-row .openclaw-form-group.wide { - min-width: 0; -} - -.openclaw-lab-plan-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--openclaw-space-sm); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 6px; - background: rgba(255, 255, 255, 0.02); - padding: var(--openclaw-space-sm); -} - -.openclaw-lab-plan-header > h4 { - margin: 0; - font-size: var(--openclaw-font-md); -} - -.openclaw-lab-run-list { - display: flex; - flex-direction: column; - gap: 6px; -} - -.openclaw-lab-run-item { - display: grid; - grid-template-columns: 72px 1fr auto 32px; - align-items: center; - gap: var(--openclaw-space-sm); - padding: 8px; - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 6px; - background: rgba(255, 255, 255, 0.02); -} - -.run-idx { - font-family: var(--openclaw-font-mono); - color: var(--openclaw-color-fg-muted); - font-size: var(--openclaw-font-sm); -} - -.run-params { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-family: var(--openclaw-font-mono); - font-size: var(--openclaw-font-sm); -} - -.run-status { - font-size: var(--openclaw-font-sm); - border-radius: 999px; - padding: 2px 8px; - border: 1px solid rgba(255, 255, 255, 0.15); - color: var(--openclaw-color-fg-muted); - background: rgba(255, 255, 255, 0.05); - white-space: nowrap; -} - -.run-status.pending, -.run-status.queued { - color: #ffe38f; - border-color: rgba(230, 180, 50, 0.55); - background: rgba(230, 180, 50, 0.14); -} - -.run-status.running { - color: #a8d1ff; - border-color: rgba(90, 150, 255, 0.55); - background: rgba(90, 150, 255, 0.16); -} - -.run-status.success, -.run-status.completed { - color: #bfffc0; - border-color: rgba(42, 170, 42, 0.55); - background: rgba(42, 170, 42, 0.16); -} - -.run-status.error, -.run-status.failed { - color: #ffb4b4; - border-color: rgba(200, 60, 60, 0.6); - background: rgba(200, 60, 60, 0.16); -} - -@media (max-width: 820px) { - .openclaw-lab-header { - flex-direction: column; - align-items: stretch; - } - - .openclaw-lab-actions { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .openclaw-lab-dim-row { - grid-template-columns: 1fr; - } - - .openclaw-lab-run-item { - grid-template-columns: 1fr; - align-items: start; - } -} - -@media (max-width: 720px) { - .openclaw-lab-actions { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } -} - - -/*==================================== - * LEGACY COMPATIBILITY - *====================================*/ - -/* Moltbot Design System */ - -:root { - /* Spacing Scale */ - --moltbot-space-xs: 4px; - --moltbot-space-sm: 8px; - --moltbot-space-md: 12px; - --moltbot-space-lg: 16px; - --moltbot-space-xl: 24px; - - /* Typography */ - --moltbot-font-xs: 11px; - --moltbot-font-sm: 12px; - --moltbot-font-md: 13px; - --moltbot-font-lg: 14px; - --moltbot-font-mono: 'Consolas', 'Monaco', 'Courier New', monospace; - - /* Colors (inheriting from ComfyUI variable names where possible, fallbacks provided) */ - --moltbot-color-bg: var(--comfy-menu-bg, #222); - --moltbot-color-bg-light: var(--comfy-input-bg, #333); - --moltbot-color-fg: var(--fg-color, #eee); - --moltbot-color-fg-muted: #aaa; - --moltbot-color-border: var(--border-color, #444); - --moltbot-color-primary: var(--primary-color, #2a2); - --moltbot-color-danger: #d44; - --moltbot-color-warning: #ea0; - --moltbot-color-success: #2a2; -} - -/* Layout Primitives */ - -.moltbot-sidebar-container { - display: flex; - flex-direction: column; - height: 100%; - min-width: 560px; /* Keep sidebar readable: header tabs + Parameter Lab controls */ - min-height: 0; /* allow children to shrink for overflow handling */ - background: var(--moltbot-color-bg); - color: var(--moltbot-color-fg); - font-family: Arial, sans-serif; - font-size: var(--moltbot-font-md); -} - -/* CRITICAL: Keep this rule + !important; SplitterPanel inline sizing can override inner container min-width. */ -.side-bar-panel:has(.moltbot-sidebar-container) { - min-width: 560px !important; -} - -.moltbot-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--moltbot-space-md); - padding: var(--moltbot-space-md) var(--moltbot-space-lg); - border-bottom: 1px solid var(--moltbot-color-border); - background: rgba(0,0,0,0.15); -} - -.moltbot-status-dot { - width: 10px; - height: 10px; - border-radius: 50%; - background: #666; - flex: 0 0 auto; -} -.moltbot-status-dot.ok { background: #2a2; } -.moltbot-status-dot.warn { background: #ea0; } -.moltbot-status-dot.err { background: #c44; } - -.moltbot-title { - font-size: var(--moltbot-font-lg); - font-weight: 700; - flex: 1 1 auto; - min-width: 0; -} - -.moltbot-badges { - display: flex; - align-items: center; - justify-content: flex-end; - gap: var(--moltbot-space-sm); - flex: 0 0 auto; -} - -.moltbot-version { - font-size: var(--moltbot-font-sm); - color: var(--moltbot-color-fg-muted); -} - -.moltbot-repo-link { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 4px 8px; - border: 1px solid var(--moltbot-color-border); - border-radius: 999px; - background: rgba(255,255,255,0.04); - color: var(--moltbot-color-fg); - text-decoration: none; - font-size: var(--moltbot-font-sm); - white-space: nowrap; -} -.moltbot-repo-link:hover { background: rgba(255,255,255,0.08); } - -.moltbot-banner { - padding: var(--moltbot-space-sm) var(--moltbot-space-lg); - border-bottom: 1px solid var(--moltbot-color-border); - font-size: var(--moltbot-font-sm); - display: flex; - align-items: center; - gap: var(--moltbot-space-md); - justify-content: space-between; -} -.moltbot-banner > span { flex: 1; } - -.moltbot-banner-warning { background: rgba(255, 170, 0, 0.10); color: #ffd27a; } -.moltbot-banner-info { background: rgba(0, 120, 255, 0.10); color: #a8d1ff; } -.moltbot-banner-success { background: rgba(42, 170, 42, 0.15); color: #bfffc0; } -.moltbot-banner-error { background: rgba(200, 50, 50, 0.15); color: #ffb4b4; } - -.moltbot-banner-action { - background: rgba(255,255,255,0.1); - border: 1px solid rgba(255,255,255,0.2); - color: inherit; - padding: 2px 8px; - border-radius: 4px; - cursor: pointer; - font-size: var(--moltbot-font-xs); - text-transform: uppercase; - font-weight: bold; -} -.moltbot-banner-action:hover { background: rgba(255,255,255,0.2); } - -.moltbot-banner-close { - background: none; - border: none; - color: inherit; - opacity: 0.7; - cursor: pointer; - font-size: 16px; - line-height: 1; - padding: 0 4px; -} -.moltbot-banner-close:hover { opacity: 1; } - -.moltbot-tabs { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); /* 4 tabs per row */ - grid-auto-flow: row; /* left-to-right, then top-to-bottom */ - gap: 6px; - padding: 8px var(--moltbot-space-lg); - border-bottom: 1px solid var(--moltbot-color-border); - background: rgba(0,0,0,0.10); -} - -.moltbot-tab { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 10px; - border-radius: 6px; - border: 1px solid transparent; - cursor: pointer; - user-select: none; - color: var(--moltbot-color-fg-muted); - background: rgba(255,255,255,0.02); - font-size: var(--moltbot-font-sm); - line-height: 1; - width: 100%; - min-width: 0; - justify-content: center; -} - -.moltbot-tab:hover { - color: var(--moltbot-color-fg); - border-color: rgba(255,255,255,0.08); - background: rgba(255,255,255,0.04); -} - -.moltbot-tab.active { - color: var(--moltbot-color-fg); - border-color: rgba(42, 170, 42, 0.5); - background: rgba(42, 170, 42, 0.15); -} - -.moltbot-tab-icon { - font-size: 13px; - opacity: 0.9; -} - -.moltbot-tab-label { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.moltbot-content { - flex: 1 1 auto; - min-height: 0; - overflow: hidden; -} - -.moltbot-tab-pane { - display: none; - height: 100%; - min-height: 0; -} -.moltbot-tab-pane.active { - display: block; -} - -.moltbot-panel { - display: flex; - flex-direction: column; - height: 100%; - overflow: hidden; - color: var(--moltbot-color-fg); - font-size: var(--moltbot-font-md); - background: var(--moltbot-color-bg); -} - -.moltbot-scroll-area { - flex: 1; - overflow-y: auto; - padding: var(--moltbot-space-lg); /* More breathing room */ - display: flex; - flex-direction: column; - gap: var(--moltbot-space-lg); -} - -.moltbot-card { - background: rgba(0, 0, 0, 0.2); - border: 1px solid var(--moltbot-color-border); - border-radius: 4px; - padding: var(--moltbot-space-md); - display: flex; - flex-direction: column; - gap: var(--moltbot-space-sm); -} - -.moltbot-section-header { - font-size: var(--moltbot-font-sm); - text-transform: uppercase; - color: var(--moltbot-color-fg-muted); - letter-spacing: 0.05em; - margin-bottom: var(--moltbot-space-xs); - font-weight: bold; - border-bottom: 1px solid var(--moltbot-color-border); - padding-bottom: var(--moltbot-space-xs); -} - -/* Grids & Splits */ -.moltbot-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--moltbot-space-md); -} - -.moltbot-split-v { - display: flex; - flex-direction: column; - gap: var(--moltbot-space-md); -} - -.moltbot-split-h { - display: flex; - flex-direction: row; - gap: var(--moltbot-space-md); - align-items: center; -} - -/* Form Elements */ -.moltbot-input-group { - display: flex; - flex-direction: column; - gap: var(--moltbot-space-xs); -} - -.moltbot-section { - background: rgba(0,0,0,0.18); - border: 1px solid var(--moltbot-color-border); - border-radius: 6px; - padding: var(--moltbot-space-lg); - display: flex; - flex-direction: column; - gap: var(--moltbot-space-md); -} - -.moltbot-section > h4 { - margin: 0; - font-size: var(--moltbot-font-lg); -} - -.moltbot-form-row { - display: flex; - flex-direction: column; - gap: var(--moltbot-space-xs); -} - -.moltbot-btn-row { - display: flex; - flex-direction: row; - gap: var(--moltbot-space-sm); - flex-wrap: wrap; -} - -.moltbot-note { - padding: var(--moltbot-space-sm) var(--moltbot-space-md); - border: 1px solid var(--moltbot-color-border); - border-radius: 4px; - background: rgba(255,255,255,0.03); - color: var(--moltbot-color-fg-muted); - font-size: var(--moltbot-font-sm); - line-height: 1.35; -} - -.moltbot-status { - font-size: var(--moltbot-font-sm); - color: var(--moltbot-color-fg-muted); - min-height: 16px; -} -.moltbot-status.ok { color: #bfffc0; } -.moltbot-status.error { color: #ffb4b4; } - -.moltbot-kv-row { - display: flex; - justify-content: space-between; - gap: var(--moltbot-space-md); -} -.moltbot-kv-key { color: var(--moltbot-color-fg-muted); } -.moltbot-kv-val { color: var(--moltbot-color-fg); } -.moltbot-kv-val.ok { color: #bfffc0; } -.moltbot-kv-val.error { color: #ffb4b4; } - -.moltbot-log-viewer { - white-space: pre-wrap; - font-family: var(--moltbot-font-mono); - font-size: var(--moltbot-font-sm); - background: rgba(0,0,0,0.25); - border: 1px solid var(--moltbot-color-border); - border-radius: 4px; - padding: var(--moltbot-space-md); - max-height: 260px; - overflow: auto; -} - -.moltbot-checkbox { - width: 16px; - height: 16px; - flex: 0 0 auto; -} - -.moltbot-help-btn { - width: 22px; - height: 22px; - border-radius: 999px; - border: 1px solid var(--moltbot-color-border); - background: rgba(255,255,255,0.04); - color: var(--moltbot-color-fg); - cursor: pointer; - font-size: var(--moltbot-font-sm); - line-height: 1; - flex: 0 0 auto; -} -.moltbot-help-btn:hover { - background: rgba(255,255,255,0.08); -} - -.moltbot-label { - font-size: var(--moltbot-font-sm); - color: var(--moltbot-color-fg-muted); -} - -.moltbot-input, .moltbot-select, .moltbot-textarea { - background: var(--moltbot-color-bg-light); - border: 1px solid var(--moltbot-color-border); - color: var(--moltbot-color-fg); - padding: 6px 8px; - border-radius: 2px; - font-size: var(--moltbot-font-md); - width: 100%; - box-sizing: border-box; -} - -.moltbot-input:focus, .moltbot-select:focus, .moltbot-textarea:focus { - border-color: var(--moltbot-color-primary); - outline: none; -} - -.moltbot-textarea { - font-family: var(--moltbot-font-mono); - resize: vertical; - min-height: 60px; -} - -.moltbot-textarea-sm { min-height: 80px; } -.moltbot-textarea-md { min-height: 150px; } -.moltbot-textarea-lg { min-height: 250px; } -.moltbot-textarea-xl { min-height: 400px; } - -/* Buttons */ -.moltbot-btn { - background: var(--moltbot-color-bg-light); - border: 1px solid var(--moltbot-color-border); - color: var(--moltbot-color-fg); - padding: 6px 12px; - cursor: pointer; - font-size: var(--moltbot-font-md); - border-radius: 2px; - text-align: center; - transition: background 0.1s; -} - -.moltbot-btn:hover:not(:disabled) { - background: #444; -} - -.moltbot-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.moltbot-btn-primary { - background: #2a2; /* Green-ish */ - color: #fff; - border-color: #181; -} -.moltbot-btn-primary:hover:not(:disabled) { background: #3b3; } - -.moltbot-btn-danger { - background: #a33; - color: #fff; - border-color: #822; -} -.moltbot-btn-danger:hover:not(:disabled) { background: #c44; } - -.moltbot-btn-sm { - padding: 2px 6px; - font-size: var(--moltbot-font-sm); -} - -.moltbot-btn-success { - background: rgba(42, 170, 42, 0.2); - border-color: rgba(42, 170, 42, 0.6); - color: #dfffe0; -} - -/* Compatibility aliases used by existing tabs */ -.moltbot-btn.primary { - background: rgba(42, 170, 42, 0.2); - border-color: rgba(42, 170, 42, 0.6); - color: #dfffe0; -} -.moltbot-btn.primary:hover:not(:disabled) { - background: rgba(42, 170, 42, 0.3); -} -.moltbot-btn.secondary { - background: rgba(255, 255, 255, 0.04); - border-color: var(--moltbot-color-border); - color: var(--moltbot-color-fg); -} - -.moltbot-btn.has-icon { - display: inline-flex; - align-items: center; - gap: 6px; -} - -.moltbot-btn-icon { - width: 26px; - height: 26px; - border: 1px solid var(--moltbot-color-border); - background: rgba(255, 255, 255, 0.04); - color: var(--moltbot-color-fg); - border-radius: 4px; - cursor: pointer; - font-size: var(--moltbot-font-sm); - line-height: 1; -} -.moltbot-btn-icon:hover { - background: rgba(255, 255, 255, 0.1); -} - -.moltbot-separator { - width: 1px; - height: 24px; - background: var(--moltbot-color-border); - opacity: 0.7; -} - -.moltbot-form-group { - display: flex; - flex-direction: column; - gap: 6px; -} - -.moltbot-form-group > label { - font-size: var(--moltbot-font-sm); - color: var(--moltbot-color-fg-muted); -} - -.moltbot-form-group > input, -.moltbot-form-group > select, -.moltbot-form-group > textarea { - background: var(--moltbot-color-bg-light); - border: 1px solid var(--moltbot-color-border); - color: var(--moltbot-color-fg); - padding: 6px 8px; - border-radius: 4px; - font-size: var(--moltbot-font-md); -} -.moltbot-form-group > input:focus, -.moltbot-form-group > select:focus, -.moltbot-form-group > textarea:focus { - outline: none; - border-color: rgba(42, 170, 42, 0.7); -} - -.moltbot-hint, -.moltbot-loading, -.moltbot-error { - padding: 10px 12px; - border-radius: 6px; - font-size: var(--moltbot-font-sm); - border: 1px solid var(--moltbot-color-border); - background: rgba(255, 255, 255, 0.03); - color: var(--moltbot-color-fg-muted); -} - -.moltbot-loading { - color: #d2e4ff; - border-color: rgba(90, 150, 255, 0.45); - background: rgba(90, 150, 255, 0.12); -} - -.moltbot-error { - color: #ffb4b4; - border-color: rgba(200, 60, 60, 0.6); - background: rgba(200, 60, 60, 0.18); -} - -/* Status Indicators */ -.moltbot-badge { - padding: 2px 6px; - border-radius: 4px; - font-size: var(--moltbot-font-xs); - font-weight: bold; - text-transform: uppercase; -} -.moltbot-badge.pending { background: #aa0; color: #000; } -.moltbot-badge.approved { background: #2a2; color: #fff; } -.moltbot-badge.rejected { background: #c00; color: #fff; } -.moltbot-badge.expired { background: #666; color: #ccc; } - -/* Error / Empty States */ -.moltbot-empty-state { - padding: var(--moltbot-space-xl); - text-align: center; - color: var(--moltbot-color-fg-muted); - border: 1px dashed var(--moltbot-color-border); - border-radius: 4px; - background: rgba(255, 255, 255, 0.02); -} - -.moltbot-error-box { - padding: var(--moltbot-space-md); - background: rgba(200, 50, 50, 0.1); - border: 1px solid #a33; - border-radius: 4px; - color: #eaa; - display: flex; - flex-direction: column; - gap: var(--moltbot-space-sm); -} - -.moltbot-error-title { - font-weight: bold; - display: flex; - align-items: center; - gap: var(--moltbot-space-sm); -} - -.moltbot-error-hint { - font-size: var(--moltbot-font-sm); - color: #ccc; - background: rgba(0,0,0,0.3); - padding: 4px; - border-radius: 2px; -} - -/* Loading Spinner (Simple) */ -.moltbot-spinner { - width: 20px; - height: 20px; - border: 2px solid rgba(255,255,255,0.3); - border-radius: 50%; - border-top-color: #fff; - animation: spin 1s ease-in-out infinite; -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* Modals */ -.moltbot-modal-overlay { - position: fixed; - top: 0; left: 0; right: 0; bottom: 0; - background: rgba(0,0,0,0.7); - display: flex; - align-items: center; - justify-content: center; - z-index: 9999; -} - -.moltbot-modal { - background: var(--moltbot-color-bg); - border: 1px solid var(--moltbot-color-border); - box-shadow: 0 10px 25px rgba(0,0,0,0.5); - border-radius: 6px; - min-width: 400px; - max-width: 90vw; - max-height: 90vh; - display: flex; - flex-direction: column; -} - -.moltbot-modal-header { - padding: var(--moltbot-space-md); - border-bottom: 1px solid var(--moltbot-color-border); - display: flex; - justify-content: space-between; - align-items: center; - font-weight: bold; - font-size: var(--moltbot-font-lg); -} - -.moltbot-modal-body { - padding: var(--moltbot-space-lg); - overflow-y: auto; - flex: 1; -} - -.moltbot-modal-footer { - padding: var(--moltbot-space-md); - border-top: 1px solid var(--moltbot-color-border); - display: flex; - justify-content: flex-end; - gap: var(--moltbot-space-md); - background: rgba(0,0,0,0.1); -} - -/* Parameter Lab */ -.moltbot-lab-container { - display: flex; - flex-direction: column; - gap: var(--moltbot-space-md); - height: 100%; - min-height: 0; - padding: var(--moltbot-space-md); - box-sizing: border-box; - overflow: hidden; -} - -.moltbot-lab-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - flex-wrap: wrap; - gap: var(--moltbot-space-md); - border: 1px solid var(--moltbot-color-border); - background: rgba(255, 255, 255, 0.03); - border-radius: 8px; - padding: var(--moltbot-space-md); -} - -.moltbot-lab-title-wrap { - flex: 1 1 100%; - min-width: 0; -} - -.moltbot-lab-title-wrap > h3 { - margin: 0; - font-size: 20px; - line-height: 1.1; - word-break: normal; - overflow-wrap: normal; -} - -.moltbot-lab-title-wrap > p { - margin: 4px 0 0; - color: var(--moltbot-color-fg-muted); - font-size: var(--moltbot-font-sm); - line-height: 1.35; - max-width: 60ch; - word-break: normal; - overflow-wrap: normal; -} - -.moltbot-lab-actions { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: var(--moltbot-space-sm); - width: 100%; - margin: 0 auto; - align-items: stretch; -} - -.moltbot-lab-action-btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; - min-width: 0; - width: 100%; - text-align: center; - overflow: hidden; -} - -.moltbot-lab-actions .moltbot-btn.has-icon.moltbot-lab-action-btn { - justify-content: center; -} - -.moltbot-lab-action-icon { - flex: 0 0 auto; - line-height: 1; -} - -.moltbot-lab-action-label { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.moltbot-lab-action-btn.active { - border-color: rgba(42, 170, 42, 0.65); - background: rgba(42, 170, 42, 0.2); - color: #dfffe0; -} - -.moltbot-lab-action-btn:focus { - outline: none; -} - -.moltbot-lab-action-btn:focus-visible { - border-color: rgba(42, 170, 42, 0.75); - box-shadow: 0 0 0 1px rgba(42, 170, 42, 0.35) inset; -} - -.moltbot-lab-actions .moltbot-separator { - display: none; -} - -.moltbot-lab-main { - display: grid; - grid-template-columns: minmax(0, 1fr); - gap: var(--moltbot-space-md); - min-height: 0; - overflow-y: auto; - padding-right: 2px; -} - -.moltbot-lab-card { - border: 1px solid var(--moltbot-color-border); - background: rgba(0, 0, 0, 0.16); - border-radius: 8px; - padding: var(--moltbot-space-md); - display: flex; - flex-direction: column; - gap: var(--moltbot-space-md); -} - -.moltbot-lab-card-head { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: var(--moltbot-space-md); - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - padding-bottom: var(--moltbot-space-sm); -} - -.moltbot-lab-card-head > h4 { - margin: 0; - font-size: 15px; -} - -.moltbot-lab-meta { - color: var(--moltbot-color-fg-muted); - font-size: var(--moltbot-font-sm); -} - -.moltbot-lab-config, -.moltbot-lab-results { - display: flex; - flex-direction: column; - gap: var(--moltbot-space-sm); -} - -.moltbot-lab-dim-row { - display: grid; - grid-template-columns: 84px 110px 1fr 32px; - gap: var(--moltbot-space-sm); - align-items: end; - border: 1px solid rgba(255, 255, 255, 0.08); - background: rgba(255, 255, 255, 0.02); - border-radius: 6px; - padding: var(--moltbot-space-sm); -} - -.moltbot-lab-dim-row .moltbot-form-group.wide { - min-width: 0; -} - -.moltbot-lab-plan-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--moltbot-space-sm); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 6px; - background: rgba(255, 255, 255, 0.02); - padding: var(--moltbot-space-sm); -} - -.moltbot-lab-plan-header > h4 { - margin: 0; - font-size: var(--moltbot-font-md); -} - -.moltbot-lab-run-list { - display: flex; - flex-direction: column; - gap: 6px; -} - -.moltbot-lab-run-item { - display: grid; - grid-template-columns: 72px 1fr auto 32px; - align-items: center; - gap: var(--moltbot-space-sm); - padding: 8px; - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 6px; - background: rgba(255, 255, 255, 0.02); -} - -.run-idx { - font-family: var(--moltbot-font-mono); - color: var(--moltbot-color-fg-muted); - font-size: var(--moltbot-font-sm); -} - -.run-params { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-family: var(--moltbot-font-mono); - font-size: var(--moltbot-font-sm); -} - -.run-status { - font-size: var(--moltbot-font-sm); - border-radius: 999px; - padding: 2px 8px; - border: 1px solid rgba(255, 255, 255, 0.15); - color: var(--moltbot-color-fg-muted); - background: rgba(255, 255, 255, 0.05); - white-space: nowrap; -} - -.run-status.pending, -.run-status.queued { - color: #ffe38f; - border-color: rgba(230, 180, 50, 0.55); - background: rgba(230, 180, 50, 0.14); -} - -.run-status.running { - color: #a8d1ff; - border-color: rgba(90, 150, 255, 0.55); - background: rgba(90, 150, 255, 0.16); -} - -.run-status.success, -.run-status.completed { - color: #bfffc0; - border-color: rgba(42, 170, 42, 0.55); - background: rgba(42, 170, 42, 0.16); -} - -.run-status.error, -.run-status.failed { - color: #ffb4b4; - border-color: rgba(200, 60, 60, 0.6); - background: rgba(200, 60, 60, 0.16); -} - -@media (max-width: 820px) { - .moltbot-lab-header { - flex-direction: column; - align-items: stretch; - } - - .moltbot-lab-actions { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .moltbot-lab-dim-row { - grid-template-columns: 1fr; - } - - .moltbot-lab-run-item { - grid-template-columns: 1fr; - align-items: start; - } -} - -@media (max-width: 720px) { - .moltbot-lab-actions { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } -} +/* OpenClaw stylesheet entry point. Keep import order deterministic. */ +@import "./styles/openclaw_core.css"; +@import "./styles/openclaw_legacy_aliases.css"; diff --git a/web/openclaw_tabs.js b/web/openclaw_tabs.js index 0402339..d28c7f4 100644 --- a/web/openclaw_tabs.js +++ b/web/openclaw_tabs.js @@ -3,6 +3,7 @@ * Handles tab creation, switching, and lazy rendering. */ import { ErrorBoundary } from "./ErrorBoundary.js"; +import { normalizeLegacyClassNames } from "./openclaw_utils.js"; export class TabManager { constructor() { @@ -49,12 +50,12 @@ export class TabManager { this.tabs.forEach(tab => { const btn = document.createElement("div"); - btn.className = "openclaw-tab moltbot-tab"; + btn.className = "openclaw-tab"; if (tab.icon) { const icon = document.createElement("i"); - icon.className = `openclaw-tab-icon moltbot-tab-icon ${tab.icon}`; + icon.className = `openclaw-tab-icon ${tab.icon}`; const label = document.createElement("span"); - label.className = "openclaw-tab-label moltbot-tab-label"; + label.className = "openclaw-tab-label"; label.textContent = tab.title; btn.appendChild(icon); btn.appendChild(label); @@ -70,10 +71,13 @@ export class TabManager { if (!this.contentEl.querySelector(`#openclaw-tab-${tab.id}`)) { const pane = document.createElement("div"); pane.id = `openclaw-tab-${tab.id}`; - pane.className = "openclaw-tab-pane moltbot-tab-pane"; + pane.className = "openclaw-tab-pane"; this.contentEl.appendChild(pane); } }); + + normalizeLegacyClassNames(this.tabsEl); + normalizeLegacyClassNames(this.contentEl); } activateTab(id) { @@ -111,6 +115,10 @@ export class TabManager { }); tab.loaded = true; } + + if (pane) { + normalizeLegacyClassNames(pane); + } } _restoreActiveTab() { diff --git a/web/openclaw_ui.js b/web/openclaw_ui.js index b84c3ac..ffe8aeb 100644 --- a/web/openclaw_ui.js +++ b/web/openclaw_ui.js @@ -5,6 +5,7 @@ import { tabManager } from "./openclaw_tabs.js"; import { ErrorBoundary } from "./ErrorBoundary.js"; import { openclawApi } from "./openclaw_api.js"; +import { normalizeLegacyClassNames } from "./openclaw_utils.js"; export class OpenClawUI { constructor() { @@ -27,7 +28,7 @@ export class OpenClawUI { } _enforceSidebarMinWidth(container) { - // IMPORTANT: Keep this value aligned with CSS .openclaw-sidebar-container/.moltbot-sidebar-container min-width. + // IMPORTANT: Keep this value aligned with CSS .openclaw-sidebar-container min-width. const minWidthPx = 560; const applyMinWidth = () => { @@ -62,10 +63,10 @@ export class OpenClawUI { toggleFloatingPanel() { if (!this.floating.panel) { const panel = document.createElement("div"); - panel.className = "openclaw-floating-panel moltbot-floating-panel"; + panel.className = "openclaw-floating-panel"; const close = document.createElement("button"); - close.className = "openclaw-floating-close moltbot-floating-close"; + close.className = "openclaw-floating-close"; close.textContent = "\u00D7"; close.title = "Close"; close.addEventListener("click", () => { @@ -73,7 +74,7 @@ export class OpenClawUI { }); const content = document.createElement("div"); - content.className = "openclaw-floating-content moltbot-floating-content"; + content.className = "openclaw-floating-content"; panel.appendChild(close); panel.appendChild(content); @@ -98,31 +99,31 @@ export class OpenClawUI { _render(container) { container.innerHTML = ""; - container.className = "openclaw-sidebar-container moltbot-sidebar-container"; + container.className = "openclaw-sidebar-container"; // 1. Header const header = document.createElement("div"); - header.className = "openclaw-header moltbot-header"; + header.className = "openclaw-header"; const statusDot = document.createElement("div"); - statusDot.className = "openclaw-status-dot moltbot-status-dot ok"; + statusDot.className = "openclaw-status-dot ok"; statusDot.title = "System Status"; this.statusDot = statusDot; const title = document.createElement("div"); - title.className = "openclaw-title moltbot-title"; + title.className = "openclaw-title"; title.textContent = "OpenClaw"; // F9: About badges (version fetched from /openclaw/health; legacy /moltbot/health) const badges = document.createElement("div"); - badges.className = "openclaw-badges moltbot-badges"; + badges.className = "openclaw-badges"; const versionSpan = document.createElement("span"); - versionSpan.className = "openclaw-version moltbot-version"; + versionSpan.className = "openclaw-version"; versionSpan.textContent = "v..."; const repoLink = document.createElement("a"); repoLink.href = "https://github.com/rookiestar28/ComfyUI-OpenClaw"; repoLink.target = "_blank"; - repoLink.className = "openclaw-repo-link moltbot-repo-link"; + repoLink.className = "openclaw-repo-link"; repoLink.title = "View on GitHub"; repoLink.textContent = "View on GitHub"; badges.appendChild(versionSpan); @@ -139,7 +140,7 @@ export class OpenClawUI { // F55: Control plane mode indicator badge const cpMode = data?.control_plane?.mode || data?.deployment_profile || "local"; const modeBadge = document.createElement("span"); - modeBadge.className = `openclaw-mode-badge moltbot-mode-badge openclaw-mode-${cpMode} moltbot-mode-${cpMode}`; + modeBadge.className = `openclaw-mode-badge openclaw-mode-${cpMode}`; modeBadge.textContent = cpMode.toUpperCase(); modeBadge.title = `Control plane: ${cpMode}`; // Style inline for immediate visibility @@ -183,18 +184,19 @@ export class OpenClawUI { // 2. Tab Bar const tabBar = document.createElement("div"); - tabBar.className = "openclaw-tabs moltbot-tabs"; + tabBar.className = "openclaw-tabs"; this.tabBar = tabBar; container.appendChild(tabBar); // 3. Content Area const contentArea = document.createElement("div"); - contentArea.className = "openclaw-content moltbot-content"; + contentArea.className = "openclaw-content"; this.contentArea = contentArea; container.appendChild(contentArea); // Initialize Tabs tabManager.init(tabBar, contentArea); + normalizeLegacyClassNames(container); } /** @@ -268,7 +270,7 @@ export class OpenClawUI { header.after(bannerEl); } - bannerEl.className = `openclaw-banner moltbot-banner openclaw-banner-${severity} moltbot-banner-${severity}`; + bannerEl.className = `openclaw-banner openclaw-banner-${severity}`; bannerEl.dataset.id = id; bannerEl.dataset.severity = severity; bannerEl.innerHTML = ""; // Clear content @@ -281,7 +283,7 @@ export class OpenClawUI { // Action Button if (action) { const btn = document.createElement("button"); - btn.className = "openclaw-banner-action moltbot-banner-action"; + btn.className = "openclaw-banner-action"; btn.textContent = action.label; btn.addEventListener("click", () => this.handleAction(action)); bannerEl.appendChild(btn); @@ -290,7 +292,7 @@ export class OpenClawUI { // Dismiss Button if (dismissible) { const close = document.createElement("button"); - close.className = "openclaw-banner-close moltbot-banner-close"; + close.className = "openclaw-banner-close"; close.textContent = "\u00D7"; close.addEventListener("click", () => { bannerEl.remove(); @@ -345,10 +347,10 @@ export class OpenClawUI { showConfirm({ title, message, fatal = false, onConfirm }) { // Create modal overlay const overlay = document.createElement("div"); - overlay.className = "openclaw-modal-overlay moltbot-modal-overlay"; + overlay.className = "openclaw-modal-overlay"; const modal = document.createElement("div"); - modal.className = `openclaw-modal moltbot-modal ${fatal ? "fatal" : ""}`; + modal.className = `openclaw-modal ${fatal ? "fatal" : ""}`; const h3 = document.createElement("h3"); h3.textContent = title || "Confirm Action"; @@ -357,15 +359,15 @@ export class OpenClawUI { p.textContent = message || "Are you sure?"; const buttons = document.createElement("div"); - buttons.className = "openclaw-modal-buttons moltbot-modal-buttons"; + buttons.className = "openclaw-modal-buttons"; const cancelBtn = document.createElement("button"); - cancelBtn.className = "openclaw-btn moltbot-btn secondary"; + cancelBtn.className = "openclaw-btn secondary"; cancelBtn.textContent = "Cancel"; cancelBtn.onclick = () => overlay.remove(); const confirmBtn = document.createElement("button"); - confirmBtn.className = `openclaw-btn moltbot-btn ${fatal ? "danger" : "primary"}`; + confirmBtn.className = `openclaw-btn ${fatal ? "danger" : "primary"}`; confirmBtn.textContent = "Confirm"; confirmBtn.onclick = () => { overlay.remove(); @@ -381,6 +383,7 @@ export class OpenClawUI { overlay.appendChild(modal); this.container.appendChild(overlay); + normalizeLegacyClassNames(overlay); } } @@ -574,7 +577,7 @@ export class OpenClawActions { */ _showBlockedToast(actionName, reason) { const toast = document.createElement("div"); - toast.className = "openclaw-blocked-toast moltbot-blocked-toast"; + toast.className = "openclaw-blocked-toast"; toast.style.cssText = ` position: fixed; bottom: 20px; right: 20px; z-index: 99999; background: #1e1e2e; border: 1px solid #f59e0b; diff --git a/web/openclaw_utils.js b/web/openclaw_utils.js index d52dca9..e493d65 100644 --- a/web/openclaw_utils.js +++ b/web/openclaw_utils.js @@ -18,6 +18,59 @@ export function makeEl(tag, className = "", text = "") { return el; } +/** + * F63: prefer canonical `openclaw-*` classes when both legacy and canonical + * variants are present on the same node. + */ +export function normalizeLegacyClassTokens(className = "") { + const tokens = String(className) + .split(/\s+/) + .map((token) => token.trim()) + .filter(Boolean); + const canonical = new Set( + tokens.filter((token) => token.startsWith("openclaw-")) + ); + const seen = new Set(); + const normalized = []; + + tokens.forEach((token) => { + if (token.startsWith("moltbot-")) { + const suffix = token.slice("moltbot-".length); + if (canonical.has(`openclaw-${suffix}`)) { + return; + } + } + if (seen.has(token)) { + return; + } + seen.add(token); + normalized.push(token); + }); + + return normalized.join(" "); +} + +export function normalizeLegacyClassNames(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 normalized = normalizeLegacyClassTokens(node.className); + if (normalized !== node.className) { + node.className = normalized; + } + }); + + return root; +} + /** * Lightweight toast helper for UI feedback. * @param {string} message diff --git a/web/styles/openclaw_core.css b/web/styles/openclaw_core.css new file mode 100644 index 0000000..302ce90 --- /dev/null +++ b/web/styles/openclaw_core.css @@ -0,0 +1,926 @@ +/* Moltbot Design System */ + +:root { + /* Spacing Scale */ + --openclaw-space-xs: 4px; + --openclaw-space-sm: 8px; + --openclaw-space-md: 12px; + --openclaw-space-lg: 16px; + --openclaw-space-xl: 24px; + + /* Typography */ + --openclaw-font-xs: 11px; + --openclaw-font-sm: 12px; + --openclaw-font-md: 13px; + --openclaw-font-lg: 14px; + --openclaw-font-mono: 'Consolas', 'Monaco', 'Courier New', monospace; + + /* Colors (inheriting from ComfyUI variable names where possible, fallbacks provided) */ + --openclaw-color-bg: var(--comfy-menu-bg, #222); + --openclaw-color-bg-light: var(--comfy-input-bg, #333); + --openclaw-color-fg: var(--fg-color, #eee); + --openclaw-color-fg-muted: #aaa; + --openclaw-color-border: var(--border-color, #444); + --openclaw-color-primary: var(--primary-color, #2a2); + --openclaw-color-danger: #d44; + --openclaw-color-warning: #ea0; + --openclaw-color-success: #2a2; +} + +/* Layout Primitives */ + +.openclaw-sidebar-container { + display: flex; + flex-direction: column; + height: 100%; + min-width: 560px; /* Keep sidebar readable: header tabs + Parameter Lab controls */ + min-height: 0; /* allow children to shrink for overflow handling */ + background: var(--openclaw-color-bg); + color: var(--openclaw-color-fg); + font-family: Arial, sans-serif; + font-size: var(--openclaw-font-md); +} + +/* CRITICAL: Keep this rule + !important; SplitterPanel inline sizing can override inner container min-width. */ +.side-bar-panel:has(.openclaw-sidebar-container) { + min-width: 560px !important; +} + +.openclaw-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--openclaw-space-md); + padding: var(--openclaw-space-md) var(--openclaw-space-lg); + border-bottom: 1px solid var(--openclaw-color-border); + background: rgba(0,0,0,0.15); +} + +.openclaw-status-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: #666; + flex: 0 0 auto; +} +.openclaw-status-dot.ok { background: #2a2; } +.openclaw-status-dot.warn { background: #ea0; } +.openclaw-status-dot.err { background: #c44; } + +.openclaw-title { + font-size: var(--openclaw-font-lg); + font-weight: 700; + flex: 1 1 auto; + min-width: 0; +} + +.openclaw-badges { + display: flex; + align-items: center; + justify-content: flex-end; + gap: var(--openclaw-space-sm); + flex: 0 0 auto; +} + +.openclaw-version { + font-size: var(--openclaw-font-sm); + color: var(--openclaw-color-fg-muted); +} + +.openclaw-repo-link { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + border: 1px solid var(--openclaw-color-border); + border-radius: 999px; + background: rgba(255,255,255,0.04); + color: var(--openclaw-color-fg); + text-decoration: none; + font-size: var(--openclaw-font-sm); + white-space: nowrap; +} +.openclaw-repo-link:hover { background: rgba(255,255,255,0.08); } + +.openclaw-banner { + padding: var(--openclaw-space-sm) var(--openclaw-space-lg); + border-bottom: 1px solid var(--openclaw-color-border); + font-size: var(--openclaw-font-sm); + display: flex; + align-items: center; + gap: var(--openclaw-space-md); + justify-content: space-between; +} +.openclaw-banner > span { flex: 1; } + +.openclaw-banner-warning { background: rgba(255, 170, 0, 0.10); color: #ffd27a; } +.openclaw-banner-info { background: rgba(0, 120, 255, 0.10); color: #a8d1ff; } +.openclaw-banner-success { background: rgba(42, 170, 42, 0.15); color: #bfffc0; } +.openclaw-banner-error { background: rgba(200, 50, 50, 0.15); color: #ffb4b4; } + +.openclaw-banner-action { + background: rgba(255,255,255,0.1); + border: 1px solid rgba(255,255,255,0.2); + color: inherit; + padding: 2px 8px; + border-radius: 4px; + cursor: pointer; + font-size: var(--openclaw-font-xs); + text-transform: uppercase; + font-weight: bold; +} +.openclaw-banner-action:hover { background: rgba(255,255,255,0.2); } + +.openclaw-banner-close { + background: none; + border: none; + color: inherit; + opacity: 0.7; + cursor: pointer; + font-size: 16px; + line-height: 1; + padding: 0 4px; +} +.openclaw-banner-close:hover { opacity: 1; } + +.openclaw-tabs { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); /* 4 tabs per row */ + grid-auto-flow: row; /* left-to-right, then top-to-bottom */ + gap: 6px; + padding: 8px var(--openclaw-space-lg); + border-bottom: 1px solid var(--openclaw-color-border); + background: rgba(0,0,0,0.10); +} + +.openclaw-tab { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 10px; + border-radius: 6px; + border: 1px solid transparent; + cursor: pointer; + user-select: none; + color: var(--openclaw-color-fg-muted); + background: rgba(255,255,255,0.02); + font-size: var(--openclaw-font-sm); + line-height: 1; + width: 100%; + min-width: 0; + justify-content: center; +} + +.openclaw-tab:hover { + color: var(--openclaw-color-fg); + border-color: rgba(255,255,255,0.08); + background: rgba(255,255,255,0.04); +} + +.openclaw-tab.active { + color: var(--openclaw-color-fg); + border-color: rgba(42, 170, 42, 0.5); + background: rgba(42, 170, 42, 0.15); +} + +.openclaw-tab-icon { + font-size: 13px; + opacity: 0.9; +} + +.openclaw-tab-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.openclaw-content { + flex: 1 1 auto; + min-height: 0; + overflow: hidden; +} + +.openclaw-tab-pane { + display: none; + height: 100%; + min-height: 0; +} +.openclaw-tab-pane.active { + display: block; +} + +.openclaw-panel { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + color: var(--openclaw-color-fg); + font-size: var(--openclaw-font-md); + background: var(--openclaw-color-bg); +} + +.openclaw-scroll-area { + flex: 1; + overflow-y: auto; + padding: var(--openclaw-space-lg); /* More breathing room */ + display: flex; + flex-direction: column; + gap: var(--openclaw-space-lg); +} + +.openclaw-card { + background: rgba(0, 0, 0, 0.2); + border: 1px solid var(--openclaw-color-border); + border-radius: 4px; + padding: var(--openclaw-space-md); + display: flex; + flex-direction: column; + gap: var(--openclaw-space-sm); +} + +.openclaw-section-header { + font-size: var(--openclaw-font-sm); + text-transform: uppercase; + color: var(--openclaw-color-fg-muted); + letter-spacing: 0.05em; + margin-bottom: var(--openclaw-space-xs); + font-weight: bold; + border-bottom: 1px solid var(--openclaw-color-border); + padding-bottom: var(--openclaw-space-xs); +} + +/* Grids & Splits */ +.openclaw-grid-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--openclaw-space-md); +} + +.openclaw-split-v { + display: flex; + flex-direction: column; + gap: var(--openclaw-space-md); +} + +.openclaw-split-h { + display: flex; + flex-direction: row; + gap: var(--openclaw-space-md); + align-items: center; +} + +/* Form Elements */ +.openclaw-input-group { + display: flex; + flex-direction: column; + gap: var(--openclaw-space-xs); +} + +.openclaw-section { + background: rgba(0,0,0,0.18); + border: 1px solid var(--openclaw-color-border); + border-radius: 6px; + padding: var(--openclaw-space-lg); + display: flex; + flex-direction: column; + gap: var(--openclaw-space-md); +} + +.openclaw-section > h4 { + margin: 0; + font-size: var(--openclaw-font-lg); +} + +.openclaw-form-row { + display: flex; + flex-direction: column; + gap: var(--openclaw-space-xs); +} + +.openclaw-btn-row { + display: flex; + flex-direction: row; + gap: var(--openclaw-space-sm); + flex-wrap: wrap; +} + +.openclaw-note { + padding: var(--openclaw-space-sm) var(--openclaw-space-md); + border: 1px solid var(--openclaw-color-border); + border-radius: 4px; + background: rgba(255,255,255,0.03); + color: var(--openclaw-color-fg-muted); + font-size: var(--openclaw-font-sm); + line-height: 1.35; +} + +.openclaw-status { + font-size: var(--openclaw-font-sm); + color: var(--openclaw-color-fg-muted); + min-height: 16px; +} +.openclaw-status.ok { color: #bfffc0; } +.openclaw-status.error { color: #ffb4b4; } + +.openclaw-kv-row { + display: flex; + justify-content: space-between; + gap: var(--openclaw-space-md); +} +.openclaw-kv-key { color: var(--openclaw-color-fg-muted); } +.openclaw-kv-val { color: var(--openclaw-color-fg); } +.openclaw-kv-val.ok { color: #bfffc0; } +.openclaw-kv-val.error { color: #ffb4b4; } + +.openclaw-log-viewer { + white-space: pre-wrap; + font-family: var(--openclaw-font-mono); + font-size: var(--openclaw-font-sm); + background: rgba(0,0,0,0.25); + border: 1px solid var(--openclaw-color-border); + border-radius: 4px; + padding: var(--openclaw-space-md); + max-height: 260px; + overflow: auto; +} + +.openclaw-checkbox { + width: 16px; + height: 16px; + flex: 0 0 auto; +} + +.openclaw-help-btn { + width: 22px; + height: 22px; + border-radius: 999px; + border: 1px solid var(--openclaw-color-border); + background: rgba(255,255,255,0.04); + color: var(--openclaw-color-fg); + cursor: pointer; + font-size: var(--openclaw-font-sm); + line-height: 1; + flex: 0 0 auto; +} +.openclaw-help-btn:hover { + background: rgba(255,255,255,0.08); +} + +.openclaw-label { + font-size: var(--openclaw-font-sm); + color: var(--openclaw-color-fg-muted); +} + +.openclaw-input, .openclaw-select, .openclaw-textarea { + background: var(--openclaw-color-bg-light); + border: 1px solid var(--openclaw-color-border); + color: var(--openclaw-color-fg); + padding: 6px 8px; + border-radius: 2px; + font-size: var(--openclaw-font-md); + width: 100%; + box-sizing: border-box; +} + +.openclaw-input:focus, .openclaw-select:focus, .openclaw-textarea:focus { + border-color: var(--openclaw-color-primary); + outline: none; +} + +.openclaw-textarea { + font-family: var(--openclaw-font-mono); + resize: vertical; + min-height: 60px; +} + +.openclaw-textarea-sm { min-height: 80px; } +.openclaw-textarea-md { min-height: 150px; } +.openclaw-textarea-lg { min-height: 250px; } +.openclaw-textarea-xl { min-height: 400px; } + +/* Buttons */ +.openclaw-btn { + background: var(--openclaw-color-bg-light); + border: 1px solid var(--openclaw-color-border); + color: var(--openclaw-color-fg); + padding: 6px 12px; + cursor: pointer; + font-size: var(--openclaw-font-md); + border-radius: 2px; + text-align: center; + transition: background 0.1s; +} + +.openclaw-btn:hover:not(:disabled) { + background: #444; +} + +.openclaw-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.openclaw-btn-primary { + background: #2a2; /* Green-ish */ + color: #fff; + border-color: #181; +} +.openclaw-btn-primary:hover:not(:disabled) { background: #3b3; } + +.openclaw-btn-danger { + background: #a33; + color: #fff; + border-color: #822; +} +.openclaw-btn-danger:hover:not(:disabled) { background: #c44; } + +.openclaw-btn-sm { + padding: 2px 6px; + font-size: var(--openclaw-font-sm); +} + +.openclaw-btn-success { + background: rgba(42, 170, 42, 0.2); + border-color: rgba(42, 170, 42, 0.6); + color: #dfffe0; +} + +/* Compatibility aliases used by existing tabs */ +.openclaw-btn.primary { + background: rgba(42, 170, 42, 0.2); + border-color: rgba(42, 170, 42, 0.6); + color: #dfffe0; +} +.openclaw-btn.primary:hover:not(:disabled) { + background: rgba(42, 170, 42, 0.3); +} +.openclaw-btn.secondary { + background: rgba(255, 255, 255, 0.04); + border-color: var(--openclaw-color-border); + color: var(--openclaw-color-fg); +} + +.openclaw-btn.has-icon { + display: inline-flex; + align-items: center; + gap: 6px; +} + +.openclaw-btn-icon { + width: 26px; + height: 26px; + border: 1px solid var(--openclaw-color-border); + background: rgba(255, 255, 255, 0.04); + color: var(--openclaw-color-fg); + border-radius: 4px; + cursor: pointer; + font-size: var(--openclaw-font-sm); + line-height: 1; +} +.openclaw-btn-icon:hover { + background: rgba(255, 255, 255, 0.1); +} + +.openclaw-separator { + width: 1px; + height: 24px; + background: var(--openclaw-color-border); + opacity: 0.7; +} + +.openclaw-form-group { + display: flex; + flex-direction: column; + gap: 6px; +} + +.openclaw-form-group > label { + font-size: var(--openclaw-font-sm); + color: var(--openclaw-color-fg-muted); +} + +.openclaw-form-group > input, +.openclaw-form-group > select, +.openclaw-form-group > textarea { + background: var(--openclaw-color-bg-light); + border: 1px solid var(--openclaw-color-border); + color: var(--openclaw-color-fg); + padding: 6px 8px; + border-radius: 4px; + font-size: var(--openclaw-font-md); +} +.openclaw-form-group > input:focus, +.openclaw-form-group > select:focus, +.openclaw-form-group > textarea:focus { + outline: none; + border-color: rgba(42, 170, 42, 0.7); +} + +.openclaw-hint, +.openclaw-loading, +.openclaw-error { + padding: 10px 12px; + border-radius: 6px; + font-size: var(--openclaw-font-sm); + border: 1px solid var(--openclaw-color-border); + background: rgba(255, 255, 255, 0.03); + color: var(--openclaw-color-fg-muted); +} + +.openclaw-loading { + color: #d2e4ff; + border-color: rgba(90, 150, 255, 0.45); + background: rgba(90, 150, 255, 0.12); +} + +.openclaw-error { + color: #ffb4b4; + border-color: rgba(200, 60, 60, 0.6); + background: rgba(200, 60, 60, 0.18); +} + +/* Status Indicators */ +.openclaw-badge { + padding: 2px 6px; + border-radius: 4px; + font-size: var(--openclaw-font-xs); + font-weight: bold; + text-transform: uppercase; +} +.openclaw-badge.pending { background: #aa0; color: #000; } +.openclaw-badge.approved { background: #2a2; color: #fff; } +.openclaw-badge.rejected { background: #c00; color: #fff; } +.openclaw-badge.expired { background: #666; color: #ccc; } + +/* Error / Empty States */ +.openclaw-empty-state { + padding: var(--openclaw-space-xl); + text-align: center; + color: var(--openclaw-color-fg-muted); + border: 1px dashed var(--openclaw-color-border); + border-radius: 4px; + background: rgba(255, 255, 255, 0.02); +} + +.openclaw-error-box { + padding: var(--openclaw-space-md); + background: rgba(200, 50, 50, 0.1); + border: 1px solid #a33; + border-radius: 4px; + color: #eaa; + display: flex; + flex-direction: column; + gap: var(--openclaw-space-sm); +} + +.openclaw-error-title { + font-weight: bold; + display: flex; + align-items: center; + gap: var(--openclaw-space-sm); +} + +.openclaw-error-hint { + font-size: var(--openclaw-font-sm); + color: #ccc; + background: rgba(0,0,0,0.3); + padding: 4px; + border-radius: 2px; +} + +/* Loading Spinner (Simple) */ +.openclaw-spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(255,255,255,0.3); + border-radius: 50%; + border-top-color: #fff; + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Modals */ +.openclaw-modal-overlay { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0,0,0,0.7); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; +} + +.openclaw-modal { + background: var(--openclaw-color-bg); + border: 1px solid var(--openclaw-color-border); + box-shadow: 0 10px 25px rgba(0,0,0,0.5); + border-radius: 6px; + min-width: 400px; + max-width: 90vw; + max-height: 90vh; + display: flex; + flex-direction: column; +} + +.openclaw-modal-header { + padding: var(--openclaw-space-md); + border-bottom: 1px solid var(--openclaw-color-border); + display: flex; + justify-content: space-between; + align-items: center; + font-weight: bold; + font-size: var(--openclaw-font-lg); +} + +.openclaw-modal-body { + padding: var(--openclaw-space-lg); + overflow-y: auto; + flex: 1; +} + +.openclaw-modal-footer { + padding: var(--openclaw-space-md); + border-top: 1px solid var(--openclaw-color-border); + display: flex; + justify-content: flex-end; + gap: var(--openclaw-space-md); + background: rgba(0,0,0,0.1); +} + +/* Parameter Lab */ +.openclaw-lab-container { + display: flex; + flex-direction: column; + gap: var(--openclaw-space-md); + height: 100%; + min-height: 0; + padding: var(--openclaw-space-md); + box-sizing: border-box; + overflow: hidden; +} + +.openclaw-lab-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + flex-wrap: wrap; + gap: var(--openclaw-space-md); + border: 1px solid var(--openclaw-color-border); + background: rgba(255, 255, 255, 0.03); + border-radius: 8px; + padding: var(--openclaw-space-md); +} + +.openclaw-lab-title-wrap { + flex: 1 1 100%; + min-width: 0; +} + +.openclaw-lab-title-wrap > h3 { + margin: 0; + font-size: 20px; + line-height: 1.1; + word-break: normal; + overflow-wrap: normal; +} + +.openclaw-lab-title-wrap > p { + margin: 4px 0 0; + color: var(--openclaw-color-fg-muted); + font-size: var(--openclaw-font-sm); + line-height: 1.35; + max-width: 60ch; + word-break: normal; + overflow-wrap: normal; +} + +.openclaw-lab-actions { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--openclaw-space-sm); + width: 100%; + margin: 0 auto; + align-items: stretch; +} + +.openclaw-lab-action-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + min-width: 0; + width: 100%; + text-align: center; + overflow: hidden; +} + +.openclaw-lab-actions .openclaw-btn.has-icon.openclaw-lab-action-btn { + justify-content: center; +} + +.openclaw-lab-action-icon { + flex: 0 0 auto; + line-height: 1; +} + +.openclaw-lab-action-label { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.openclaw-lab-action-btn.active { + border-color: rgba(42, 170, 42, 0.65); + background: rgba(42, 170, 42, 0.2); + color: #dfffe0; +} + +.openclaw-lab-action-btn:focus { + outline: none; +} + +.openclaw-lab-action-btn:focus-visible { + border-color: rgba(42, 170, 42, 0.75); + box-shadow: 0 0 0 1px rgba(42, 170, 42, 0.35) inset; +} + +.openclaw-lab-actions .openclaw-separator { + display: none; +} + +.openclaw-lab-main { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: var(--openclaw-space-md); + min-height: 0; + overflow-y: auto; + padding-right: 2px; +} + +.openclaw-lab-card { + border: 1px solid var(--openclaw-color-border); + background: rgba(0, 0, 0, 0.16); + border-radius: 8px; + padding: var(--openclaw-space-md); + display: flex; + flex-direction: column; + gap: var(--openclaw-space-md); +} + +.openclaw-lab-card-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: var(--openclaw-space-md); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + padding-bottom: var(--openclaw-space-sm); +} + +.openclaw-lab-card-head > h4 { + margin: 0; + font-size: 15px; +} + +.openclaw-lab-meta { + color: var(--openclaw-color-fg-muted); + font-size: var(--openclaw-font-sm); +} + +.openclaw-lab-config, +.openclaw-lab-results { + display: flex; + flex-direction: column; + gap: var(--openclaw-space-sm); +} + +.openclaw-lab-dim-row { + display: grid; + grid-template-columns: 84px 110px 1fr 32px; + gap: var(--openclaw-space-sm); + align-items: end; + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(255, 255, 255, 0.02); + border-radius: 6px; + padding: var(--openclaw-space-sm); +} + +.openclaw-lab-dim-row .openclaw-form-group.wide { + min-width: 0; +} + +.openclaw-lab-plan-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--openclaw-space-sm); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; + background: rgba(255, 255, 255, 0.02); + padding: var(--openclaw-space-sm); +} + +.openclaw-lab-plan-header > h4 { + margin: 0; + font-size: var(--openclaw-font-md); +} + +.openclaw-lab-run-list { + display: flex; + flex-direction: column; + gap: 6px; +} + +.openclaw-lab-run-item { + display: grid; + grid-template-columns: 72px 1fr auto 32px; + align-items: center; + gap: var(--openclaw-space-sm); + padding: 8px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; + background: rgba(255, 255, 255, 0.02); +} + +.run-idx { + font-family: var(--openclaw-font-mono); + color: var(--openclaw-color-fg-muted); + font-size: var(--openclaw-font-sm); +} + +.run-params { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: var(--openclaw-font-mono); + font-size: var(--openclaw-font-sm); +} + +.run-status { + font-size: var(--openclaw-font-sm); + border-radius: 999px; + padding: 2px 8px; + border: 1px solid rgba(255, 255, 255, 0.15); + color: var(--openclaw-color-fg-muted); + background: rgba(255, 255, 255, 0.05); + white-space: nowrap; +} + +.run-status.pending, +.run-status.queued { + color: #ffe38f; + border-color: rgba(230, 180, 50, 0.55); + background: rgba(230, 180, 50, 0.14); +} + +.run-status.running { + color: #a8d1ff; + border-color: rgba(90, 150, 255, 0.55); + background: rgba(90, 150, 255, 0.16); +} + +.run-status.success, +.run-status.completed { + color: #bfffc0; + border-color: rgba(42, 170, 42, 0.55); + background: rgba(42, 170, 42, 0.16); +} + +.run-status.error, +.run-status.failed { + color: #ffb4b4; + border-color: rgba(200, 60, 60, 0.6); + background: rgba(200, 60, 60, 0.16); +} + +@media (max-width: 820px) { + .openclaw-lab-header { + flex-direction: column; + align-items: stretch; + } + + .openclaw-lab-actions { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .openclaw-lab-dim-row { + grid-template-columns: 1fr; + } + + .openclaw-lab-run-item { + grid-template-columns: 1fr; + align-items: start; + } +} + +@media (max-width: 720px) { + .openclaw-lab-actions { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + + diff --git a/web/styles/openclaw_legacy_aliases.css b/web/styles/openclaw_legacy_aliases.css new file mode 100644 index 0000000..dab6640 --- /dev/null +++ b/web/styles/openclaw_legacy_aliases.css @@ -0,0 +1,928 @@ +/*==================================== + * LEGACY COMPATIBILITY + *====================================*/ + +/* Moltbot Design System */ + +:root { + /* Spacing Scale */ + --moltbot-space-xs: 4px; + --moltbot-space-sm: 8px; + --moltbot-space-md: 12px; + --moltbot-space-lg: 16px; + --moltbot-space-xl: 24px; + + /* Typography */ + --moltbot-font-xs: 11px; + --moltbot-font-sm: 12px; + --moltbot-font-md: 13px; + --moltbot-font-lg: 14px; + --moltbot-font-mono: 'Consolas', 'Monaco', 'Courier New', monospace; + + /* Colors (inheriting from ComfyUI variable names where possible, fallbacks provided) */ + --moltbot-color-bg: var(--comfy-menu-bg, #222); + --moltbot-color-bg-light: var(--comfy-input-bg, #333); + --moltbot-color-fg: var(--fg-color, #eee); + --moltbot-color-fg-muted: #aaa; + --moltbot-color-border: var(--border-color, #444); + --moltbot-color-primary: var(--primary-color, #2a2); + --moltbot-color-danger: #d44; + --moltbot-color-warning: #ea0; + --moltbot-color-success: #2a2; +} + +/* Layout Primitives */ + +.moltbot-sidebar-container { + display: flex; + flex-direction: column; + height: 100%; + min-width: 560px; /* Keep sidebar readable: header tabs + Parameter Lab controls */ + min-height: 0; /* allow children to shrink for overflow handling */ + background: var(--moltbot-color-bg); + color: var(--moltbot-color-fg); + font-family: Arial, sans-serif; + font-size: var(--moltbot-font-md); +} + +/* CRITICAL: Keep this rule + !important; SplitterPanel inline sizing can override inner container min-width. */ +.side-bar-panel:has(.moltbot-sidebar-container) { + min-width: 560px !important; +} + +.moltbot-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--moltbot-space-md); + padding: var(--moltbot-space-md) var(--moltbot-space-lg); + border-bottom: 1px solid var(--moltbot-color-border); + background: rgba(0,0,0,0.15); +} + +.moltbot-status-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: #666; + flex: 0 0 auto; +} +.moltbot-status-dot.ok { background: #2a2; } +.moltbot-status-dot.warn { background: #ea0; } +.moltbot-status-dot.err { background: #c44; } + +.moltbot-title { + font-size: var(--moltbot-font-lg); + font-weight: 700; + flex: 1 1 auto; + min-width: 0; +} + +.moltbot-badges { + display: flex; + align-items: center; + justify-content: flex-end; + gap: var(--moltbot-space-sm); + flex: 0 0 auto; +} + +.moltbot-version { + font-size: var(--moltbot-font-sm); + color: var(--moltbot-color-fg-muted); +} + +.moltbot-repo-link { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + border: 1px solid var(--moltbot-color-border); + border-radius: 999px; + background: rgba(255,255,255,0.04); + color: var(--moltbot-color-fg); + text-decoration: none; + font-size: var(--moltbot-font-sm); + white-space: nowrap; +} +.moltbot-repo-link:hover { background: rgba(255,255,255,0.08); } + +.moltbot-banner { + padding: var(--moltbot-space-sm) var(--moltbot-space-lg); + border-bottom: 1px solid var(--moltbot-color-border); + font-size: var(--moltbot-font-sm); + display: flex; + align-items: center; + gap: var(--moltbot-space-md); + justify-content: space-between; +} +.moltbot-banner > span { flex: 1; } + +.moltbot-banner-warning { background: rgba(255, 170, 0, 0.10); color: #ffd27a; } +.moltbot-banner-info { background: rgba(0, 120, 255, 0.10); color: #a8d1ff; } +.moltbot-banner-success { background: rgba(42, 170, 42, 0.15); color: #bfffc0; } +.moltbot-banner-error { background: rgba(200, 50, 50, 0.15); color: #ffb4b4; } + +.moltbot-banner-action { + background: rgba(255,255,255,0.1); + border: 1px solid rgba(255,255,255,0.2); + color: inherit; + padding: 2px 8px; + border-radius: 4px; + cursor: pointer; + font-size: var(--moltbot-font-xs); + text-transform: uppercase; + font-weight: bold; +} +.moltbot-banner-action:hover { background: rgba(255,255,255,0.2); } + +.moltbot-banner-close { + background: none; + border: none; + color: inherit; + opacity: 0.7; + cursor: pointer; + font-size: 16px; + line-height: 1; + padding: 0 4px; +} +.moltbot-banner-close:hover { opacity: 1; } + +.moltbot-tabs { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); /* 4 tabs per row */ + grid-auto-flow: row; /* left-to-right, then top-to-bottom */ + gap: 6px; + padding: 8px var(--moltbot-space-lg); + border-bottom: 1px solid var(--moltbot-color-border); + background: rgba(0,0,0,0.10); +} + +.moltbot-tab { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 10px; + border-radius: 6px; + border: 1px solid transparent; + cursor: pointer; + user-select: none; + color: var(--moltbot-color-fg-muted); + background: rgba(255,255,255,0.02); + font-size: var(--moltbot-font-sm); + line-height: 1; + width: 100%; + min-width: 0; + justify-content: center; +} + +.moltbot-tab:hover { + color: var(--moltbot-color-fg); + border-color: rgba(255,255,255,0.08); + background: rgba(255,255,255,0.04); +} + +.moltbot-tab.active { + color: var(--moltbot-color-fg); + border-color: rgba(42, 170, 42, 0.5); + background: rgba(42, 170, 42, 0.15); +} + +.moltbot-tab-icon { + font-size: 13px; + opacity: 0.9; +} + +.moltbot-tab-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.moltbot-content { + flex: 1 1 auto; + min-height: 0; + overflow: hidden; +} + +.moltbot-tab-pane { + display: none; + height: 100%; + min-height: 0; +} +.moltbot-tab-pane.active { + display: block; +} + +.moltbot-panel { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + color: var(--moltbot-color-fg); + font-size: var(--moltbot-font-md); + background: var(--moltbot-color-bg); +} + +.moltbot-scroll-area { + flex: 1; + overflow-y: auto; + padding: var(--moltbot-space-lg); /* More breathing room */ + display: flex; + flex-direction: column; + gap: var(--moltbot-space-lg); +} + +.moltbot-card { + background: rgba(0, 0, 0, 0.2); + border: 1px solid var(--moltbot-color-border); + border-radius: 4px; + padding: var(--moltbot-space-md); + display: flex; + flex-direction: column; + gap: var(--moltbot-space-sm); +} + +.moltbot-section-header { + font-size: var(--moltbot-font-sm); + text-transform: uppercase; + color: var(--moltbot-color-fg-muted); + letter-spacing: 0.05em; + margin-bottom: var(--moltbot-space-xs); + font-weight: bold; + border-bottom: 1px solid var(--moltbot-color-border); + padding-bottom: var(--moltbot-space-xs); +} + +/* Grids & Splits */ +.moltbot-grid-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--moltbot-space-md); +} + +.moltbot-split-v { + display: flex; + flex-direction: column; + gap: var(--moltbot-space-md); +} + +.moltbot-split-h { + display: flex; + flex-direction: row; + gap: var(--moltbot-space-md); + align-items: center; +} + +/* Form Elements */ +.moltbot-input-group { + display: flex; + flex-direction: column; + gap: var(--moltbot-space-xs); +} + +.moltbot-section { + background: rgba(0,0,0,0.18); + border: 1px solid var(--moltbot-color-border); + border-radius: 6px; + padding: var(--moltbot-space-lg); + display: flex; + flex-direction: column; + gap: var(--moltbot-space-md); +} + +.moltbot-section > h4 { + margin: 0; + font-size: var(--moltbot-font-lg); +} + +.moltbot-form-row { + display: flex; + flex-direction: column; + gap: var(--moltbot-space-xs); +} + +.moltbot-btn-row { + display: flex; + flex-direction: row; + gap: var(--moltbot-space-sm); + flex-wrap: wrap; +} + +.moltbot-note { + padding: var(--moltbot-space-sm) var(--moltbot-space-md); + border: 1px solid var(--moltbot-color-border); + border-radius: 4px; + background: rgba(255,255,255,0.03); + color: var(--moltbot-color-fg-muted); + font-size: var(--moltbot-font-sm); + line-height: 1.35; +} + +.moltbot-status { + font-size: var(--moltbot-font-sm); + color: var(--moltbot-color-fg-muted); + min-height: 16px; +} +.moltbot-status.ok { color: #bfffc0; } +.moltbot-status.error { color: #ffb4b4; } + +.moltbot-kv-row { + display: flex; + justify-content: space-between; + gap: var(--moltbot-space-md); +} +.moltbot-kv-key { color: var(--moltbot-color-fg-muted); } +.moltbot-kv-val { color: var(--moltbot-color-fg); } +.moltbot-kv-val.ok { color: #bfffc0; } +.moltbot-kv-val.error { color: #ffb4b4; } + +.moltbot-log-viewer { + white-space: pre-wrap; + font-family: var(--moltbot-font-mono); + font-size: var(--moltbot-font-sm); + background: rgba(0,0,0,0.25); + border: 1px solid var(--moltbot-color-border); + border-radius: 4px; + padding: var(--moltbot-space-md); + max-height: 260px; + overflow: auto; +} + +.moltbot-checkbox { + width: 16px; + height: 16px; + flex: 0 0 auto; +} + +.moltbot-help-btn { + width: 22px; + height: 22px; + border-radius: 999px; + border: 1px solid var(--moltbot-color-border); + background: rgba(255,255,255,0.04); + color: var(--moltbot-color-fg); + cursor: pointer; + font-size: var(--moltbot-font-sm); + line-height: 1; + flex: 0 0 auto; +} +.moltbot-help-btn:hover { + background: rgba(255,255,255,0.08); +} + +.moltbot-label { + font-size: var(--moltbot-font-sm); + color: var(--moltbot-color-fg-muted); +} + +.moltbot-input, .moltbot-select, .moltbot-textarea { + background: var(--moltbot-color-bg-light); + border: 1px solid var(--moltbot-color-border); + color: var(--moltbot-color-fg); + padding: 6px 8px; + border-radius: 2px; + font-size: var(--moltbot-font-md); + width: 100%; + box-sizing: border-box; +} + +.moltbot-input:focus, .moltbot-select:focus, .moltbot-textarea:focus { + border-color: var(--moltbot-color-primary); + outline: none; +} + +.moltbot-textarea { + font-family: var(--moltbot-font-mono); + resize: vertical; + min-height: 60px; +} + +.moltbot-textarea-sm { min-height: 80px; } +.moltbot-textarea-md { min-height: 150px; } +.moltbot-textarea-lg { min-height: 250px; } +.moltbot-textarea-xl { min-height: 400px; } + +/* Buttons */ +.moltbot-btn { + background: var(--moltbot-color-bg-light); + border: 1px solid var(--moltbot-color-border); + color: var(--moltbot-color-fg); + padding: 6px 12px; + cursor: pointer; + font-size: var(--moltbot-font-md); + border-radius: 2px; + text-align: center; + transition: background 0.1s; +} + +.moltbot-btn:hover:not(:disabled) { + background: #444; +} + +.moltbot-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.moltbot-btn-primary { + background: #2a2; /* Green-ish */ + color: #fff; + border-color: #181; +} +.moltbot-btn-primary:hover:not(:disabled) { background: #3b3; } + +.moltbot-btn-danger { + background: #a33; + color: #fff; + border-color: #822; +} +.moltbot-btn-danger:hover:not(:disabled) { background: #c44; } + +.moltbot-btn-sm { + padding: 2px 6px; + font-size: var(--moltbot-font-sm); +} + +.moltbot-btn-success { + background: rgba(42, 170, 42, 0.2); + border-color: rgba(42, 170, 42, 0.6); + color: #dfffe0; +} + +/* Compatibility aliases used by existing tabs */ +.moltbot-btn.primary { + background: rgba(42, 170, 42, 0.2); + border-color: rgba(42, 170, 42, 0.6); + color: #dfffe0; +} +.moltbot-btn.primary:hover:not(:disabled) { + background: rgba(42, 170, 42, 0.3); +} +.moltbot-btn.secondary { + background: rgba(255, 255, 255, 0.04); + border-color: var(--moltbot-color-border); + color: var(--moltbot-color-fg); +} + +.moltbot-btn.has-icon { + display: inline-flex; + align-items: center; + gap: 6px; +} + +.moltbot-btn-icon { + width: 26px; + height: 26px; + border: 1px solid var(--moltbot-color-border); + background: rgba(255, 255, 255, 0.04); + color: var(--moltbot-color-fg); + border-radius: 4px; + cursor: pointer; + font-size: var(--moltbot-font-sm); + line-height: 1; +} +.moltbot-btn-icon:hover { + background: rgba(255, 255, 255, 0.1); +} + +.moltbot-separator { + width: 1px; + height: 24px; + background: var(--moltbot-color-border); + opacity: 0.7; +} + +.moltbot-form-group { + display: flex; + flex-direction: column; + gap: 6px; +} + +.moltbot-form-group > label { + font-size: var(--moltbot-font-sm); + color: var(--moltbot-color-fg-muted); +} + +.moltbot-form-group > input, +.moltbot-form-group > select, +.moltbot-form-group > textarea { + background: var(--moltbot-color-bg-light); + border: 1px solid var(--moltbot-color-border); + color: var(--moltbot-color-fg); + padding: 6px 8px; + border-radius: 4px; + font-size: var(--moltbot-font-md); +} +.moltbot-form-group > input:focus, +.moltbot-form-group > select:focus, +.moltbot-form-group > textarea:focus { + outline: none; + border-color: rgba(42, 170, 42, 0.7); +} + +.moltbot-hint, +.moltbot-loading, +.moltbot-error { + padding: 10px 12px; + border-radius: 6px; + font-size: var(--moltbot-font-sm); + border: 1px solid var(--moltbot-color-border); + background: rgba(255, 255, 255, 0.03); + color: var(--moltbot-color-fg-muted); +} + +.moltbot-loading { + color: #d2e4ff; + border-color: rgba(90, 150, 255, 0.45); + background: rgba(90, 150, 255, 0.12); +} + +.moltbot-error { + color: #ffb4b4; + border-color: rgba(200, 60, 60, 0.6); + background: rgba(200, 60, 60, 0.18); +} + +/* Status Indicators */ +.moltbot-badge { + padding: 2px 6px; + border-radius: 4px; + font-size: var(--moltbot-font-xs); + font-weight: bold; + text-transform: uppercase; +} +.moltbot-badge.pending { background: #aa0; color: #000; } +.moltbot-badge.approved { background: #2a2; color: #fff; } +.moltbot-badge.rejected { background: #c00; color: #fff; } +.moltbot-badge.expired { background: #666; color: #ccc; } + +/* Error / Empty States */ +.moltbot-empty-state { + padding: var(--moltbot-space-xl); + text-align: center; + color: var(--moltbot-color-fg-muted); + border: 1px dashed var(--moltbot-color-border); + border-radius: 4px; + background: rgba(255, 255, 255, 0.02); +} + +.moltbot-error-box { + padding: var(--moltbot-space-md); + background: rgba(200, 50, 50, 0.1); + border: 1px solid #a33; + border-radius: 4px; + color: #eaa; + display: flex; + flex-direction: column; + gap: var(--moltbot-space-sm); +} + +.moltbot-error-title { + font-weight: bold; + display: flex; + align-items: center; + gap: var(--moltbot-space-sm); +} + +.moltbot-error-hint { + font-size: var(--moltbot-font-sm); + color: #ccc; + background: rgba(0,0,0,0.3); + padding: 4px; + border-radius: 2px; +} + +/* Loading Spinner (Simple) */ +.moltbot-spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(255,255,255,0.3); + border-radius: 50%; + border-top-color: #fff; + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Modals */ +.moltbot-modal-overlay { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0,0,0,0.7); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; +} + +.moltbot-modal { + background: var(--moltbot-color-bg); + border: 1px solid var(--moltbot-color-border); + box-shadow: 0 10px 25px rgba(0,0,0,0.5); + border-radius: 6px; + min-width: 400px; + max-width: 90vw; + max-height: 90vh; + display: flex; + flex-direction: column; +} + +.moltbot-modal-header { + padding: var(--moltbot-space-md); + border-bottom: 1px solid var(--moltbot-color-border); + display: flex; + justify-content: space-between; + align-items: center; + font-weight: bold; + font-size: var(--moltbot-font-lg); +} + +.moltbot-modal-body { + padding: var(--moltbot-space-lg); + overflow-y: auto; + flex: 1; +} + +.moltbot-modal-footer { + padding: var(--moltbot-space-md); + border-top: 1px solid var(--moltbot-color-border); + display: flex; + justify-content: flex-end; + gap: var(--moltbot-space-md); + background: rgba(0,0,0,0.1); +} + +/* Parameter Lab */ +.moltbot-lab-container { + display: flex; + flex-direction: column; + gap: var(--moltbot-space-md); + height: 100%; + min-height: 0; + padding: var(--moltbot-space-md); + box-sizing: border-box; + overflow: hidden; +} + +.moltbot-lab-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + flex-wrap: wrap; + gap: var(--moltbot-space-md); + border: 1px solid var(--moltbot-color-border); + background: rgba(255, 255, 255, 0.03); + border-radius: 8px; + padding: var(--moltbot-space-md); +} + +.moltbot-lab-title-wrap { + flex: 1 1 100%; + min-width: 0; +} + +.moltbot-lab-title-wrap > h3 { + margin: 0; + font-size: 20px; + line-height: 1.1; + word-break: normal; + overflow-wrap: normal; +} + +.moltbot-lab-title-wrap > p { + margin: 4px 0 0; + color: var(--moltbot-color-fg-muted); + font-size: var(--moltbot-font-sm); + line-height: 1.35; + max-width: 60ch; + word-break: normal; + overflow-wrap: normal; +} + +.moltbot-lab-actions { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: var(--moltbot-space-sm); + width: 100%; + margin: 0 auto; + align-items: stretch; +} + +.moltbot-lab-action-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + min-width: 0; + width: 100%; + text-align: center; + overflow: hidden; +} + +.moltbot-lab-actions .moltbot-btn.has-icon.moltbot-lab-action-btn { + justify-content: center; +} + +.moltbot-lab-action-icon { + flex: 0 0 auto; + line-height: 1; +} + +.moltbot-lab-action-label { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.moltbot-lab-action-btn.active { + border-color: rgba(42, 170, 42, 0.65); + background: rgba(42, 170, 42, 0.2); + color: #dfffe0; +} + +.moltbot-lab-action-btn:focus { + outline: none; +} + +.moltbot-lab-action-btn:focus-visible { + border-color: rgba(42, 170, 42, 0.75); + box-shadow: 0 0 0 1px rgba(42, 170, 42, 0.35) inset; +} + +.moltbot-lab-actions .moltbot-separator { + display: none; +} + +.moltbot-lab-main { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: var(--moltbot-space-md); + min-height: 0; + overflow-y: auto; + padding-right: 2px; +} + +.moltbot-lab-card { + border: 1px solid var(--moltbot-color-border); + background: rgba(0, 0, 0, 0.16); + border-radius: 8px; + padding: var(--moltbot-space-md); + display: flex; + flex-direction: column; + gap: var(--moltbot-space-md); +} + +.moltbot-lab-card-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: var(--moltbot-space-md); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + padding-bottom: var(--moltbot-space-sm); +} + +.moltbot-lab-card-head > h4 { + margin: 0; + font-size: 15px; +} + +.moltbot-lab-meta { + color: var(--moltbot-color-fg-muted); + font-size: var(--moltbot-font-sm); +} + +.moltbot-lab-config, +.moltbot-lab-results { + display: flex; + flex-direction: column; + gap: var(--moltbot-space-sm); +} + +.moltbot-lab-dim-row { + display: grid; + grid-template-columns: 84px 110px 1fr 32px; + gap: var(--moltbot-space-sm); + align-items: end; + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(255, 255, 255, 0.02); + border-radius: 6px; + padding: var(--moltbot-space-sm); +} + +.moltbot-lab-dim-row .moltbot-form-group.wide { + min-width: 0; +} + +.moltbot-lab-plan-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--moltbot-space-sm); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; + background: rgba(255, 255, 255, 0.02); + padding: var(--moltbot-space-sm); +} + +.moltbot-lab-plan-header > h4 { + margin: 0; + font-size: var(--moltbot-font-md); +} + +.moltbot-lab-run-list { + display: flex; + flex-direction: column; + gap: 6px; +} + +.moltbot-lab-run-item { + display: grid; + grid-template-columns: 72px 1fr auto 32px; + align-items: center; + gap: var(--moltbot-space-sm); + padding: 8px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; + background: rgba(255, 255, 255, 0.02); +} + +.run-idx { + font-family: var(--moltbot-font-mono); + color: var(--moltbot-color-fg-muted); + font-size: var(--moltbot-font-sm); +} + +.run-params { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: var(--moltbot-font-mono); + font-size: var(--moltbot-font-sm); +} + +.run-status { + font-size: var(--moltbot-font-sm); + border-radius: 999px; + padding: 2px 8px; + border: 1px solid rgba(255, 255, 255, 0.15); + color: var(--moltbot-color-fg-muted); + background: rgba(255, 255, 255, 0.05); + white-space: nowrap; +} + +.run-status.pending, +.run-status.queued { + color: #ffe38f; + border-color: rgba(230, 180, 50, 0.55); + background: rgba(230, 180, 50, 0.14); +} + +.run-status.running { + color: #a8d1ff; + border-color: rgba(90, 150, 255, 0.55); + background: rgba(90, 150, 255, 0.16); +} + +.run-status.success, +.run-status.completed { + color: #bfffc0; + border-color: rgba(42, 170, 42, 0.55); + background: rgba(42, 170, 42, 0.16); +} + +.run-status.error, +.run-status.failed { + color: #ffb4b4; + border-color: rgba(200, 60, 60, 0.6); + background: rgba(200, 60, 60, 0.16); +} + +@media (max-width: 820px) { + .moltbot-lab-header { + flex-direction: column; + align-items: stretch; + } + + .moltbot-lab-actions { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .moltbot-lab-dim-row { + grid-template-columns: 1fr; + } + + .moltbot-lab-run-item { + grid-template-columns: 1fr; + align-items: start; + } +} + +@media (max-width: 720px) { + .moltbot-lab-actions { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} diff --git a/web/tabs/approvals_tab.js b/web/tabs/approvals_tab.js index 243ac5e..d8c6d6e 100644 --- a/web/tabs/approvals_tab.js +++ b/web/tabs/approvals_tab.js @@ -1,152 +1,139 @@ import { openclawApi } from "../openclaw_api.js"; -import { showError, clearError } from "../openclaw_utils.js"; +import { + showError, + clearError, + normalizeLegacyClassNames, +} from "../openclaw_utils.js"; -// Helper for safe HTML escaping function escapeHtml(text) { if (!text) return ""; return text .replace(/&/g, "&") .replace(//g, ">") - .replace(/"/g, """) + .replace(/\"/g, """) .replace(/'/g, "'"); } +function stringifyVal(value) { + if (typeof value === "object" && value !== null) return "{...}"; + return String(value); +} + +function renderInputsSummary(inputs) { + if (!inputs) return ""; + const keys = Object.keys(inputs); + if (keys.length === 0) return "No inputs"; + const preview = keys.slice(0, 2).map((key) => `${key}: ${stringifyVal(inputs[key])}`); + if (keys.length > 2) preview.push(`+${keys.length - 2} more`); + return escapeHtml(preview.join(", ")); +} + +function renderApprovalItem(request) { + const statusClass = request.status; + const isPending = request.status === "pending"; + + return ` +
+
+
+
+ ${escapeHtml(request.template_id)} + ${escapeHtml(request.approval_id)} +
+
+ Inputs: ${renderInputsSummary(request.inputs)} +
+
+ Requested: ${new Date(request.requested_at).toLocaleString()} + ${request.source ? `via ${escapeHtml(request.source)}` : ""} +
+
+
+ ${request.status.toUpperCase()} +
+ + ${isPending ? ` + + + ` : ""} +
+
+
+
+ `; +} + export const ApprovalsTab = { id: "approvals", title: "Approvals", icon: "pi pi-check-circle", render(container) { - // --- 1. Static Layout --- container.innerHTML = ` -
-
-
Approval Requests
- -
-
- - - - +
+
+
Approval Requests
+ +
+
+ + + +
- +
-
-
Loading...
+
+
Loading...
- -