diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 5b661e154f..f1efd8943a 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -18,12 +18,20 @@ }, "architect": { "build": { - "builder": "@angular-builders/custom-webpack:browser", + "builder": "@angular-builders/custom-esbuild:application", "options": { - "outputPath": "target/generated-resources/public", + "plugins": ["./esbuild/tb-esbuild-plugins.ts"], + "loader": { + ".raw": "text" + }, + "outputPath": { + "base": "target/generated-resources/public", + "media": ".", + "browser": "" + }, "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", + "browser": "src/main.ts", + "polyfills": ["src/polyfills.ts"], "tsConfig": "src/tsconfig.app.json", "aot": true, "assets": [ @@ -122,49 +130,8 @@ "node_modules/prismjs/components/prism-typescript.min.js", "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.min.js" ], - "customWebpackConfig": { - "path": "./extra-webpack.config.js" - }, "allowedCommonJsDependencies": [ - "hammerjs", - "react", - "react-dom", - "reactcss", - "react-ace", - "schema-inspector", - "@flowjs/flow.js", - "@material-ui/icons/Add", - "@material-ui/icons/Clear", - "js-beautify", - "mousetrap", - "prop-types", - "react-is", - "hoist-non-react-statics", - "classnames", - "raf", - "moment-timezone", - "tinycolor2", - "json-schema-defaults", - "leaflet-providers", - "lodash", - "jquery", - "jquery.terminal", - "tooltipster", - "jstree", - "qrcode", - "wcwidth", - "leaflet-polylinedecorator", - "ace-diff", - "messageformat-parser", - "html2canvas", - "jszip", - "moment", - "ace", - "ace-builds", - "diff-match-patch", - "tv4", - "@messageformat/parser", - "sorted-btree" + "*" ] }, "configurations": { @@ -187,8 +154,6 @@ "sourceMap": false, "namedChunks": false, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": false, "budgets": [ { "type": "initial", @@ -198,7 +163,6 @@ ] }, "development": { - "buildOptimizer": false, "optimization": { "scripts": false, "styles": { @@ -207,7 +171,6 @@ }, "fonts": false }, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -215,7 +178,7 @@ } }, "serve": { - "builder": "@angular-builders/custom-webpack:dev-server", + "builder": "@angular-builders/custom-esbuild:dev-server", "options": { "buildTarget": "thingsboard:build", "proxyConfig": "proxy.conf.js" @@ -231,7 +194,7 @@ "defaultConfiguration": "development" }, "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", + "builder": "@angular/build:extract-i18n", "options": { "buildTarget": "thingsboard:build" } diff --git a/ui-ngx/esbuild/tb-esbuild-plugins.ts b/ui-ngx/esbuild/tb-esbuild-plugins.ts new file mode 100644 index 0000000000..db2ec59930 --- /dev/null +++ b/ui-ngx/esbuild/tb-esbuild-plugins.ts @@ -0,0 +1,104 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import type { Plugin, PluginBuild, OutputFile } from 'esbuild'; +import dirTree from 'directory-tree'; +import * as packageJson from '../package.json'; +import { gzip } from 'node:zlib'; +import * as path from 'node:path'; + +const defineTbVariablesPlugin: Plugin = { + name: 'tb-define-variables', + setup(build: PluginBuild) { + const options = build.initialOptions; + + const langs: string[] = []; + + dirTree("./src/assets/locale/", {extensions: /\.json$/}, (item) => { + /* It is expected what the name of a locale file has the following format: */ + /* 'locale.constant-LANG_CODE[_REGION_CODE].json', e.g. locale.constant-es.json or locale.constant-zh_CN.json*/ + langs.push(item.name.slice(item.name.lastIndexOf("-") + 1, -5)); + }); + options.define.TB_VERSION = JSON.stringify(packageJson.version); + options.define.SUPPORTED_LANGS = JSON.stringify(langs); + options.define.ngJitMode = 'true'; + }, +}; + +const resolveJQueryPlugin: Plugin = { + name: 'tb-resolve-jquery-plugin', + setup(build: PluginBuild) { + if (isProduction()) { + const jQueryPath = require.resolve('jquery'); + build.onResolve({filter: /^(jquery|\$)$/}, () => { + return {path: jQueryPath}; + }) + } + } +}; + +const compressFileTypes = ['.js', '.css', '.html', '.svg', '.png', '.jpg', '.ttf', '.gif', '.woff', '.woff2', '.eot', '.json']; +const compressThreshold = 10240; + +const compressorPlugin: Plugin = { + name: 'tb-compressor-plugin', + setup(build) { + build.onEnd(async result => { + if (!result.outputFiles || !isProduction()) return; + const outputExt = '.gz'; + const gzippedFiles: OutputFile[] = []; + for (const file of result.outputFiles) { + if (!compressFileTypes.some((ext) => ext === path.extname(file.path))) continue; + if (file.contents.byteLength <= compressThreshold) continue; + const compressedContent = await gzipContent(file.contents); + const compressedFilePath = `${file.path}${outputExt}`; + gzippedFiles.push( + { + path: compressedFilePath, + hash: file.hash, + contents: new Uint8Array(compressedContent), + text: '', + } + ); + } + result.outputFiles.push(...gzippedFiles); + }); + }, +}; + +async function gzipContent(content): Promise { + return new Promise((resolve, reject) => { + gzip(content, (error, result) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + }); +} + +function isProduction(): boolean { + const configurationIndex = process.argv.indexOf('--configuration'); + let production = false; + if (configurationIndex > -1) { + const configurationValue = process.argv[configurationIndex + 1]; + production = configurationValue === 'production'; + } + return production; +} + +export default [defineTbVariablesPlugin, resolveJQueryPlugin, compressorPlugin]; diff --git a/ui-ngx/extra-webpack.config.js b/ui-ngx/extra-webpack.config.js deleted file mode 100644 index 2191d0a24c..0000000000 --- a/ui-ngx/extra-webpack.config.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright © 2016-2024 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -const CompressionPlugin = require("compression-webpack-plugin"); -const JavaScriptOptimizerPlugin = require("@angular-devkit/build-angular/src/tools/webpack/plugins/javascript-optimizer-plugin").JavaScriptOptimizerPlugin; -const webpack = require("webpack"); -const dirTree = require("directory-tree"); -const ngWebpack = require('@ngtools/webpack'); -const keysTransformer = require('ts-transformer-keys/transformer').default; - -var langs = []; - -dirTree("./src/assets/locale/", {extensions: /\.json$/}, (item) => { - /* It is expected what the name of a locale file has the following format: */ - /* 'locale.constant-LANG_CODE[_REGION_CODE].json', e.g. locale.constant-es.json or locale.constant-zh_CN.json*/ - langs.push(item.name.slice(item.name.lastIndexOf("-") + 1, -5)); -}); - -module.exports = (config, options) => { - - config.ignoreWarnings.push(/Usage of '~' in imports is deprecated/); - config.ignoreWarnings.push(/Did you mean "left" instead?/); - config.ignoreWarnings.push(/autoprefixer/); - - config.plugins.push( - new webpack.DefinePlugin({ - TB_VERSION: JSON.stringify(require("./package.json").version), - SUPPORTED_LANGS: JSON.stringify(langs), - }) - ); - config.plugins.push( - new webpack.ProvidePlugin( - { - $: "jquery" - } - ) - ); - config.plugins.push( - new CompressionPlugin({ - filename: "[path][base].gz[query]", - algorithm: "gzip", - test: /\.js$|\.css$|\.html$|\.svg?.+$|\.jpg$|\.ttf?.+$|\.woff?.+$|\.eot?.+$|\.json$/, - threshold: 10240, - minRatio: 0.8, - deleteOriginalAssets: false, - }) - ); - config.plugins.push( - new webpack.IgnorePlugin({ - resourceRegExp: /^\.\/locale$/, - contextRegExp: /moment$/, - }) - ); - - config.module.rules[2].use[0].options.aot = false; - const index = config.plugins.findIndex(p => p instanceof ngWebpack.AngularWebpackPlugin); - let angularWebpackPlugin = config.plugins[index]; - if (config.mode === 'production') { - const angularCompilerOptions = angularWebpackPlugin.pluginOptions; - angularCompilerOptions.emitClassMetadata = true; - angularCompilerOptions.emitNgModuleScope = true; - config.plugins.splice(index, 1); - angularWebpackPlugin = new ngWebpack.AngularWebpackPlugin(angularCompilerOptions); - config.plugins.push(angularWebpackPlugin); - const javascriptOptimizerOptions = config.optimization.minimizer[0].options; - delete javascriptOptimizerOptions.define.ngJitMode; - config.optimization.minimizer.splice(0, 1); - config.optimization.minimizer.unshift(new JavaScriptOptimizerPlugin(javascriptOptimizerOptions)); - } - - addTransformerToAngularWebpackPlugin(angularWebpackPlugin, keysTransformer); - - return config; -}; - -function addTransformerToAngularWebpackPlugin(plugin, transformer) { - const originalCreateFileEmitter = plugin.createFileEmitter; // private method - plugin.createFileEmitter = function (program, transformers, getExtraDependencies, onAfterEmit) { - if (!transformers) { - transformers = {}; - } - if (!transformers.before) { - transformers = { before: [] }; - } - transformers.before.push(transformer(program.getProgram())); - return originalCreateFileEmitter.apply(plugin, [program, transformers, getExtraDependencies, onAfterEmit]); - }; -} diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 7a0049d160..ee2eb448f1 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -5,7 +5,7 @@ "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", - "build:prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration production --vendor-chunk", + "build:prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration production", "build:types": "node generate-types.js", "build:icon-metadata": "node generate-icon-metadata.js", "lint": "ng lint", @@ -105,26 +105,25 @@ "tinycolor2": "^1.6.0", "tinymce": "~6.8.5", "tooltipster": "^4.2.8", - "ts-transformer-keys": "^0.4.4", "tslib": "^2.7.0", "tv4": "^1.3.0", "typeface-roboto": "^1.1.13", "zone.js": "~0.14.10" }, "devDependencies": { - "@angular-builders/custom-webpack": "~18.0.0", - "@angular-devkit/build-angular": "18.2.7", - "@angular-devkit/core": "18.2.7", - "@angular-devkit/schematics": "18.2.7", + "@angular-builders/custom-esbuild": "18.0.0", + "@angular-devkit/build-angular": "18.2.10", + "@angular-devkit/core": "18.2.10", + "@angular-devkit/schematics": "18.2.10", "@angular-eslint/builder": "18.3.1", "@angular-eslint/eslint-plugin": "18.3.1", "@angular-eslint/eslint-plugin-template": "18.3.1", "@angular-eslint/schematics": "18.3.1", "@angular-eslint/template-parser": "18.3.1", - "@angular/cli": "18.2.7", - "@angular/compiler-cli": "18.2.6", - "@angular/language-service": "18.2.6", - "@ngtools/webpack": "18.2.7", + "@angular/build": "18.2.10", + "@angular/cli": "18.2.10", + "@angular/compiler-cli": "18.2.9", + "@angular/language-service": "18.2.9", "@types/ace-diff": "^2.1.4", "@types/canvas-gauges": "^2.1.8", "@types/flot": "^0.0.36", diff --git a/ui-ngx/patches/@angular+build+18.2.10.patch b/ui-ngx/patches/@angular+build+18.2.10.patch new file mode 100644 index 0000000000..17b84e45c6 --- /dev/null +++ b/ui-ngx/patches/@angular+build+18.2.10.patch @@ -0,0 +1,43 @@ +diff --git a/node_modules/@angular/build/src/tools/angular/compilation/angular-compilation.js b/node_modules/@angular/build/src/tools/angular/compilation/angular-compilation.js +index 625c621..4fc8bd8 100755 +--- a/node_modules/@angular/build/src/tools/angular/compilation/angular-compilation.js ++++ b/node_modules/@angular/build/src/tools/angular/compilation/angular-compilation.js +@@ -68,8 +68,6 @@ class AngularCompilation { + allowEmptyCodegenFiles: false, + annotationsAs: 'decorators', + enableResourceInlining: false, +- supportTestBed: false, +- supportJitMode: false, + })); + } + async diagnoseFiles(modes = DiagnosticModes.All) { +diff --git a/node_modules/@angular/build/src/tools/esbuild/angular/compiler-plugin.js b/node_modules/@angular/build/src/tools/esbuild/angular/compiler-plugin.js +index b1bb6ea..c76b4c6 100755 +--- a/node_modules/@angular/build/src/tools/esbuild/angular/compiler-plugin.js ++++ b/node_modules/@angular/build/src/tools/esbuild/angular/compiler-plugin.js +@@ -79,7 +79,7 @@ function createCompilerPlugin(pluginOptions, styleOptions) { + sourcemap: !!pluginOptions.sourcemap, + thirdPartySourcemaps: pluginOptions.thirdPartySourcemaps, + advancedOptimizations: pluginOptions.advancedOptimizations, +- jit: pluginOptions.jit, ++ jit: true, // pluginOptions.jit, + }, environment_options_1.maxWorkers, cacheStore?.createCache('jstransformer')); + // Setup defines based on the values used by the Angular compiler-cli + build.initialOptions.define ??= {}; +@@ -377,12 +377,14 @@ function createCompilerPlugin(pluginOptions, styleOptions) { + async function hasSideEffects(path) { + if (!pluginOptions.advancedOptimizations) { + return undefined; ++ } else { ++ return true; + } +- const { sideEffects } = await build.resolve(path, { ++ /*const { sideEffects } = await build.resolve(path, { + kind: 'import-statement', + resolveDir: build.initialOptions.absWorkingDir ?? '', + }); +- return sideEffects; ++ return sideEffects;*/ + } + }, + }; diff --git a/ui-ngx/patches/jquery.terminal+2.43.1.patch b/ui-ngx/patches/jquery.terminal+2.43.1.patch new file mode 100644 index 0000000000..f5c34ac212 --- /dev/null +++ b/ui-ngx/patches/jquery.terminal+2.43.1.patch @@ -0,0 +1,14 @@ +diff --git a/node_modules/jquery.terminal/css/jquery.terminal.min.css b/node_modules/jquery.terminal/css/jquery.terminal.min.css +index 830ba6e..978e57b 100644 +--- a/node_modules/jquery.terminal/css/jquery.terminal.min.css ++++ b/node_modules/jquery.terminal/css/jquery.terminal.min.css +@@ -13,7 +13,7 @@ + * Released under the MIT license + * + * Date: Sun, 08 Sep 2024 09:58:43 +0000 +- */.cmd .format,.cmd-prompt,.cmd-prompt div,.terminal .terminal-output .format{display:inline-block}.cmd,.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h6,.terminal pre{margin:0}.cmd .cmd-clipboard{let:-16px;background:transparent!important;border:none!important;box-shadow:none!important;color:transparent!important;height:16px;height:calc(16px/var(--pixel-density, 1))!important;left:calc(-16px/var(--pixel-density, 1))!important;outline:none!important;overflow:hidden!important;padding:0!important;position:absolute!important;resize:none!important;text-indent:-9999em!important;top:0!important;top:calc(var(--cursor-line, 0)*var(--size, 1)*(14px/var(--pixel-density, 1)))!important;white-space:pre!important;width:16px;width:calc(16px/var(--pixel-density, 1))!important;z-index:1000!important}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;left:0;overflow:hidden;position:absolute;top:0;user-select:none;white-space:nowrap;width:1px}.cmd .cursor+span:empty,.cmd div.cmd-end-line span[data-text]:last-child,.cmd div.cmd-end-line span[data-text]:last-child span,.cmd span.cmd-end-line,.cmd span.cmd-end-line span,.cmd textarea{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.terminal audio,.terminal canvas,.terminal img,.terminal object{cursor:default}.terminal{--base-background:var(--background,#000);--base-color:var(--color);contain:content;line-height:normal;position:relative}.terminal-scroller{scrollbar-gutter:stable;box-sizing:border-box;height:100%;overflow-x:hidden;overflow-y:auto;position:relative}terminal.terminal-temp{visibility:hidden}body.terminal{height:100%;min-height:100vh}html{height:100%}body.full-screen-terminal,body.terminal{height:100%;margin:0}body.full-screen-terminal .terminal{height:100%!important}body.full-screen-terminal{height:100%;height:var(--terminal-force-height,100dvh)}.terminal>div.terminal-fill{height:100%;min-height:100%}.terminal>.terminal-pixel{display:inline;height:1px;left:-2px;position:absolute;top:-2px;width:1px}.terminal>.terminal-font .terminal-resizer,.terminal>.terminal-resizer{border:none!important;bottom:0!important;height:100%!important;left:0!important;overflow:hidden!important;padding:0!important;pointer-events:none!important;position:absolute!important;right:0!important;top:0!important;width:100%!important;z-index:-1!important}.cmd{padding:0;position:relative;width:100%;z-index:300}.terminal .cmd,.terminal .cmd div{background:transparent!important}.terminal a[tabindex="1000"],.terminal a[tabindex="1000"]:active,.terminal a[tabindex="1000"]:focus{outline:none}.cmd.cmd.cmd .cmd-inverted,.cmd.cmd.cmd .inverted,.terminal .inverted,.terminal .terminal-inverted{background-color:#aaa!important;color:#000!important}.cmd a[href],.terminal .terminal-output>:not(.raw) a[href],.terminal.external a[href]{color:#37f;color:var(--link-color,#37f);cursor:pointer}.cmd a[href]:not(.terminal-inverted),.terminal .terminal-output>:not(.raw) a[href]:not(.terminal-inverted),.terminal.external a[href]:not(.terminal-inverted){--color:var(--link-color,#37f);text-shadow:0 0 calc(var(--glow)*5px) var(--color,#ccc)}.terminal .terminal-output>:not(.raw) a[href].terminal-inverted,.terminal.external a[href].terminal-inverted{background:var(--color,#ccc);text-shadow:0 0 calc(var(--glow)*5px) var(--background,#000)}.cmd a[href]:hover,.terminal .terminal-output>:not(.raw) a[href]:hover,.terminal.external a[href]:hover{background-color:#37f;background-color:var(--link-color,#37f)!important;color:#000;color:var(--base-background,#000)!important;text-decoration:none}.cmd a[href] span,.terminal .terminal-output>:not(.raw) a[href] span,.terminal.external a[href] span{--color:var(--link-color,#37f);color:#37f!important;color:var(--link-color,#37f)!important;text-decoration:underline}.cmd a[href]:hover span,.terminal .terminal-output>:not(.raw) a[href]:hover span,.terminal.external a[href]:hover span{background-color:#37f!important;background-color:var(--link-color,#37f)!important;color:#000!important;color:var(--background,#000)!important;text-decoration:none}.terminal a[href]{transition-duration:.2s;transition-property:color,background-color;transition-timing-function:ease-out}.cmd .cmd-cursor,.cmd .cmd-cursor-line img,.cmd .cmd-cursor-line>span{display:inline-block}.cmd .cmd-cursor .emoji,.cmd .cmd-cursor.cmd-blink .fa,.cmd .cmd-cursor.cmd-blink .far,.cmd .cmd-cursor.cmd-blink .fas,.cmd .cmd-cursor.cmd-blink a,.cmd .cmd-cursor.cmd-blink>span[data-text]:not(.emoji):not(.fa):not(.far):not(.fas) span{-webkit-animation:terminal-blink 1s linear infinite;-moz-animation:terminal-blink 1s linear infinite;-ms-animation:terminal-blink 1s linear infinite;animation:terminal-blink 1s linear infinite}.bar.cmd .cmd-inverted,.bar.terminal .inverted{box-shadow:-2px 0 0 -1px #aaa;box-shadow:-2px 0 0 -1px var(--original-color,#aaa)}.cmd .cmd-prompt,.terminal,.terminal .terminal-output>div>div{display:block;height:auto}.terminal .terminal-output>div:not(.raw) div{clear:both;white-space:nowrap}.cmd .cmd-prompt:empty,.cmd .cmd-prompt>a,.cmd .cmd-prompt>span{float:left}.cmd-prompt [data-text]>span,.cmd-wrapper>div{white-space:pre}.cmd [data-text] span,.terminal [data-text] span{display:inline-block}.terminal-ouput span[style*=width]{min-height:14px;min-height:calc(var(--size, 1)*(14px/var(--pixel-density, 1)))}.cmd div,.terminal .terminal-output>:not(.raw)>div,.terminal.external div{line-height:1em}.cmd .cmd-prompt span.fa:before,.cmd .cmd-prompt span.fab:before,.cmd .cmd-prompt span.fad:before,.cmd .cmd-prompt span.fal:before,.cmd .cmd-prompt span.far:before,.cmd .cmd-prompt span.fas{position:relative;top:2px}.cmd,.cmd span:not(.fas):not(.far):not(.fa),.terminal,.terminal-font-forcer,.terminal-output>:not(.raw),.terminal-output>:not(.raw) a,.terminal-output>:not(.raw) span:not(.fas):not(.far):not(.fa){font-family:monospace;font-family:var(--font,monospace)}.cmd,.terminal{font-size:12px}.cmd .cmd-line:before,.terminal-output>div:not(.raw) div:before{content:"\0200B";display:inline-block;width:0}.cmd .cmd-line{white-space:nowrap}.cmd span[data-text],.terminal span[data-text]{display:inline-block}.cmd span[data-text]:not(.cmd-inverted):not(.token):not(.emoji),.terminal,terminal-output>div:not(.raw) div>span:not(.token):not(.inverted):not(.terminal-inverted):not(.cmd-inverted):not(.terminal-error):not(.emoji){background-color:#000;color:#aaa}.cmd span[data-text] span,.terminal span[data-text] span{text-decoration:inherit}.terminal .ansi>div{line-height:13px!important;line-height:calc(var(--size, 1)*(13px/var(--pixel-density, 1)))!important}.cmd .cmd-prompt span,.cmd span.cmd-prompt{--background:transparent}.cmd .emoji,.terminal-output .emoji{background-repeat:no-repeat;background-size:contain;color:transparent;height:12px;height:calc(12px/var(--pixel-density, 1));position:relative}.cmd .fa span,.cmd .far span,.cmd .fas span,.terminal .terminal-output .fa span,.terminal .terminal-output .far span,.terminal .terminal-output .fas span{clip:rect(1px,1px,1px,1px);background:transparent!important;color:transparent!important;position:absolute}.cmd .emoji,.cmd .emoji span,.terminal-output .emoji,.terminal-output .emoji span{display:inline-block;width:2ch}.cmd,.terminal{box-sizing:border-box}.cmd .cmd-cursor span:not(.token):not(.inverted){background-color:inherit;color:inherit}.cmd .emoji.emoji.emoji.emoji,.cmd .emoji.emoji.emoji.emoji span{background-color:transparent;color:transparent}.cmd .cmd-cursor *{background-color:transparent}.cmd span[style*=width] span,.terminal span[style*=width] span{width:inherit}.cmd div{clear:both}.cmd .cmd-prompt+div{clear:right}terminal .terminal-output>div{margin-top:-1px}.terminal-output>div.raw>div *{word-wrap:break-word;overflow-wrap:break-word}.terminal .terminal-font{float:left;font-size:inherit;left:0;line-height:inherit;margin-bottom:1px;position:absolute;top:-100%}.cmd>span:not(.cmd-prompt){float:left}.cmd .cmd-prompt span.cmd-line{display:block;float:none}.terminal table{border-collapse:collapse}.terminal td{border:1px solid #aaa}.cmd span[data-text]:not(.emoji):not(.fa):not(.fas):not(.far) span{background-color:inherit;color:inherit}.cmd [role=presentation].cmd-cursor-line{cursor:text;position:relative;z-index:100}.cmd .cmd-prompt{position:relative;z-index:200}.cmd [role=presentation]:not(.cmd-cursor-line){overflow:hidden}.cmd{--original-color:var( ++ */.cmd .format,.cmd-prompt,.cmd-prompt div,.terminal .terminal-output .format{display:inline-block}.cmd,.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h6,.terminal pre{margin:0}.cmd .cmd-clipboard{left:-16px;background:transparent!important;border:none!important;box-shadow:none!important;color:transparent!important;height:16px;height:calc(16px/var(--pixel-density, 1))!important;left:calc(-16px/var(--pixel-density, 1))!important;outline:none!important;overflow:hidden!important;padding:0!important;position:absolute!important;resize:none!important;text-indent:-9999em!important;top:0!important;top:calc(var(--cursor-line, 0)*var(--size, 1)*(14px/var(--pixel-density, 1)))!important;white-space:pre!important;width:16px;width:calc(16px/var(--pixel-density, 1))!important;z-index:1000!important}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;left:0;overflow:hidden;position:absolute;top:0;user-select:none;white-space:nowrap;width:1px}.cmd .cursor+span:empty,.cmd div.cmd-end-line span[data-text]:last-child,.cmd div.cmd-end-line span[data-text]:last-child span,.cmd span.cmd-end-line,.cmd span.cmd-end-line span,.cmd textarea{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.terminal audio,.terminal canvas,.terminal img,.terminal object{cursor:default}.terminal{--base-background:var(--background,#000);--base-color:var(--color);contain:content;line-height:normal;position:relative}.terminal-scroller{scrollbar-gutter:stable;box-sizing:border-box;height:100%;overflow-x:hidden;overflow-y:auto;position:relative}terminal.terminal-temp{visibility:hidden}body.terminal{height:100%;min-height:100vh}html{height:100%}body.full-screen-terminal,body.terminal{height:100%;margin:0}body.full-screen-terminal .terminal{height:100%!important}body.full-screen-terminal{height:100%;height:var(--terminal-force-height,100dvh)}.terminal>div.terminal-fill{height:100%;min-height:100%}.terminal>.terminal-pixel{display:inline;height:1px;left:-2px;position:absolute;top:-2px;width:1px}.terminal>.terminal-font .terminal-resizer,.terminal>.terminal-resizer{border:none!important;bottom:0!important;height:100%!important;left:0!important;overflow:hidden!important;padding:0!important;pointer-events:none!important;position:absolute!important;right:0!important;top:0!important;width:100%!important;z-index:-1!important}.cmd{padding:0;position:relative;width:100%;z-index:300}.terminal .cmd,.terminal .cmd div{background:transparent!important}.terminal a[tabindex="1000"],.terminal a[tabindex="1000"]:active,.terminal a[tabindex="1000"]:focus{outline:none}.cmd.cmd.cmd .cmd-inverted,.cmd.cmd.cmd .inverted,.terminal .inverted,.terminal .terminal-inverted{background-color:#aaa!important;color:#000!important}.cmd a[href],.terminal .terminal-output>:not(.raw) a[href],.terminal.external a[href]{color:#37f;color:var(--link-color,#37f);cursor:pointer}.cmd a[href]:not(.terminal-inverted),.terminal .terminal-output>:not(.raw) a[href]:not(.terminal-inverted),.terminal.external a[href]:not(.terminal-inverted){--color:var(--link-color,#37f);text-shadow:0 0 calc(var(--glow)*5px) var(--color,#ccc)}.terminal .terminal-output>:not(.raw) a[href].terminal-inverted,.terminal.external a[href].terminal-inverted{background:var(--color,#ccc);text-shadow:0 0 calc(var(--glow)*5px) var(--background,#000)}.cmd a[href]:hover,.terminal .terminal-output>:not(.raw) a[href]:hover,.terminal.external a[href]:hover{background-color:#37f;background-color:var(--link-color,#37f)!important;color:#000;color:var(--base-background,#000)!important;text-decoration:none}.cmd a[href] span,.terminal .terminal-output>:not(.raw) a[href] span,.terminal.external a[href] span{--color:var(--link-color,#37f);color:#37f!important;color:var(--link-color,#37f)!important;text-decoration:underline}.cmd a[href]:hover span,.terminal .terminal-output>:not(.raw) a[href]:hover span,.terminal.external a[href]:hover span{background-color:#37f!important;background-color:var(--link-color,#37f)!important;color:#000!important;color:var(--background,#000)!important;text-decoration:none}.terminal a[href]{transition-duration:.2s;transition-property:color,background-color;transition-timing-function:ease-out}.cmd .cmd-cursor,.cmd .cmd-cursor-line img,.cmd .cmd-cursor-line>span{display:inline-block}.cmd .cmd-cursor .emoji,.cmd .cmd-cursor.cmd-blink .fa,.cmd .cmd-cursor.cmd-blink .far,.cmd .cmd-cursor.cmd-blink .fas,.cmd .cmd-cursor.cmd-blink a,.cmd .cmd-cursor.cmd-blink>span[data-text]:not(.emoji):not(.fa):not(.far):not(.fas) span{-webkit-animation:terminal-blink 1s linear infinite;-moz-animation:terminal-blink 1s linear infinite;-ms-animation:terminal-blink 1s linear infinite;animation:terminal-blink 1s linear infinite}.bar.cmd .cmd-inverted,.bar.terminal .inverted{box-shadow:-2px 0 0 -1px #aaa;box-shadow:-2px 0 0 -1px var(--original-color,#aaa)}.cmd .cmd-prompt,.terminal,.terminal .terminal-output>div>div{display:block;height:auto}.terminal .terminal-output>div:not(.raw) div{clear:both;white-space:nowrap}.cmd .cmd-prompt:empty,.cmd .cmd-prompt>a,.cmd .cmd-prompt>span{float:left}.cmd-prompt [data-text]>span,.cmd-wrapper>div{white-space:pre}.cmd [data-text] span,.terminal [data-text] span{display:inline-block}.terminal-ouput span[style*=width]{min-height:14px;min-height:calc(var(--size, 1)*(14px/var(--pixel-density, 1)))}.cmd div,.terminal .terminal-output>:not(.raw)>div,.terminal.external div{line-height:1em}.cmd .cmd-prompt span.fa:before,.cmd .cmd-prompt span.fab:before,.cmd .cmd-prompt span.fad:before,.cmd .cmd-prompt span.fal:before,.cmd .cmd-prompt span.far:before,.cmd .cmd-prompt span.fas{position:relative;top:2px}.cmd,.cmd span:not(.fas):not(.far):not(.fa),.terminal,.terminal-font-forcer,.terminal-output>:not(.raw),.terminal-output>:not(.raw) a,.terminal-output>:not(.raw) span:not(.fas):not(.far):not(.fa){font-family:monospace;font-family:var(--font,monospace)}.cmd,.terminal{font-size:12px}.cmd .cmd-line:before,.terminal-output>div:not(.raw) div:before{content:"\0200B";display:inline-block;width:0}.cmd .cmd-line{white-space:nowrap}.cmd span[data-text],.terminal span[data-text]{display:inline-block}.cmd span[data-text]:not(.cmd-inverted):not(.token):not(.emoji),.terminal,terminal-output>div:not(.raw) div>span:not(.token):not(.inverted):not(.terminal-inverted):not(.cmd-inverted):not(.terminal-error):not(.emoji){background-color:#000;color:#aaa}.cmd span[data-text] span,.terminal span[data-text] span{text-decoration:inherit}.terminal .ansi>div{line-height:13px!important;line-height:calc(var(--size, 1)*(13px/var(--pixel-density, 1)))!important}.cmd .cmd-prompt span,.cmd span.cmd-prompt{--background:transparent}.cmd .emoji,.terminal-output .emoji{background-repeat:no-repeat;background-size:contain;color:transparent;height:12px;height:calc(12px/var(--pixel-density, 1));position:relative}.cmd .fa span,.cmd .far span,.cmd .fas span,.terminal .terminal-output .fa span,.terminal .terminal-output .far span,.terminal .terminal-output .fas span{clip:rect(1px,1px,1px,1px);background:transparent!important;color:transparent!important;position:absolute}.cmd .emoji,.cmd .emoji span,.terminal-output .emoji,.terminal-output .emoji span{display:inline-block;width:2ch}.cmd,.terminal{box-sizing:border-box}.cmd .cmd-cursor span:not(.token):not(.inverted){background-color:inherit;color:inherit}.cmd .emoji.emoji.emoji.emoji,.cmd .emoji.emoji.emoji.emoji span{background-color:transparent;color:transparent}.cmd .cmd-cursor *{background-color:transparent}.cmd span[style*=width] span,.terminal span[style*=width] span{width:inherit}.cmd div{clear:both}.cmd .cmd-prompt+div{clear:right}terminal .terminal-output>div{margin-top:-1px}.terminal-output>div.raw>div *{word-wrap:break-word;overflow-wrap:break-word}.terminal .terminal-font{float:left;font-size:inherit;left:0;line-height:inherit;margin-bottom:1px;position:absolute;top:-100%}.cmd>span:not(.cmd-prompt){float:left}.cmd .cmd-prompt span.cmd-line{display:block;float:none}.terminal table{border-collapse:collapse}.terminal td{border:1px solid #aaa}.cmd span[data-text]:not(.emoji):not(.fa):not(.fas):not(.far) span{background-color:inherit;color:inherit}.cmd [role=presentation].cmd-cursor-line{cursor:text;position:relative;z-index:100}.cmd .cmd-prompt{position:relative;z-index:200}.cmd [role=presentation]:not(.cmd-cursor-line){overflow:hidden}.cmd{--original-color:var( + --color,#aaa);--original-background:var( + --background)}.cmd a[href]{--original-color:var(--link-color,#37f)}@-webkit-keyframes terminal-blink{0%,50%{background-color:#aaa;background-color:var(--original-color,#aaa);-webkit-box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);color:#000;color:var(--original-background,#000)}50.1%,to{background-color:inherit;color:inherit;color:var(--original-color,#aaa)}}@-moz-keyframes terminal-blink{0%,50%{background-color:#aaa;background-color:var(--original-color,#aaa);-webkit-box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);color:#000;color:var(--original-background,#000)}50.1%,to{background-color:inherit;color:inherit;color:var(--original-color,#aaa)}}@keyframes terminal-blink{0%,50%{background-color:#aaa;background-color:var(--original-color,#aaa);-webkit-box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);color:#000;color:var(--original-background,#000)}50.1%,to{background-color:inherit;-webkit-box-shadow:none;box-shadow:none;color:inherit;color:var(--original-color,#aaa)}}@-webkit-keyframes terminal-glow{0%,50%{background-color:#aaa;background-color:var(--original-color,#aaa);box-shadow:0 0 3px #aaa;-webkit-box-shadow:0 0 3px var(--color,#aaa);box-shadow:0 0 3px var(--color,#aaa);color:#000;color:var(--original-background,#000)}50.1%,to{background-color:inherit;-webkit-box-shadow:none;box-shadow:none;color:inherit}}@-moz-keyframes terminal-glow{0%,50%{background-color:#aaa;background-color:var(--original-color,#aaa);box-shadow:0 0 3px #aaa;-moz-box-shadow:0 0 3px var(--color,#aaa);box-shadow:0 0 3px var(--color,#aaa);color:#000;color:var(--original-background,#000)}50.1%,to{background-color:inherit;-moz-box-shadow:none;box-shadow:none;color:inherit}}@keyframes terminal-glow{0%,50%{background-color:#aaa;background-color:var(--original-color,#aaa);box-shadow:0 0 3px #aaa;box-shadow:0 0 3px var(--color,#aaa);color:#000;color:var(--original-background,#000)}50.1%,to{background-color:inherit;box-shadow:none;color:inherit}}@-webkit-keyframes terminal-bar{0%,50%{box-shadow:-2px 0 0 -1px #aaa;box-shadow:calc(var(--line-thickness, 2)*-1px) 0 0 -1px var(--original-color,#aaa)}50.1%,to{box-shadow:none}}@-moz-keyframes terminal-bar{0%,50%{box-shadow:-2px 0 0 -1px #aaa;box-shadow:calc(var(--line-thickness, 2)*-1px) 0 0 -1px var(--original-color,#aaa)}50.1%,to{box-shadow:none}}@keyframes terminal-bar{0%,50%{box-shadow:-2px 0 0 -1px #aaa;box-shadow:calc(var(--line-thickness, 2)*-1px) 0 0 -1px var(--original-color,#aaa)}50.1%,to{box-shadow:none}}@-webkit-keyframes terminal-underline{0%,50%{box-shadow:0 2px 0 #aaa;box-shadow:0 calc(var(--line-thickness, 2)*1px) 0 var(--original-color,#aaa)}50.1%,to{box-shadow:none}}@-moz-keyframes terminal-underline{0%,50%{box-shadow:0 2px 0 #aaa;box-shadow:0 calc(var(--line-thickness, 2)*1px) 0 var(--original-color,#aaa)}50.1%,to{box-shadow:none}}@keyframes terminal-underline{0%,50%{box-shadow:0 2px 0 #aaa;box-shadow:0 calc(var(--line-thickness, 2)*1px) 0 var(--original-color,#aaa)}50.1%,to{box-shadow:none}}@-webkit-keyframes terminal-none{0%,to{background-color:#aaa;background-color:var(--original-color,#aaa);-webkit-box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);color:#000;color:var(--original-background,#000)}}@-moz-keyframes terminal-none{0%,to{background-color:#aaa;background-color:var(--original-color,#aaa);-webkit-box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);color:#000;color:var(--background,#000)}}@keyframes terminal-none{0%,to{background-color:#aaa;background-color:var(--original-color,#aaa);-webkit-box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);box-shadow:0 0 calc(var(--glow)*3px) var(--color,#aaa);color:#000;color:var(--original-background,#000)}}.underline-animation .cmd .cmd-cursor .emoji,.underline-animation .cmd .cmd-cursor.cmd-blink .fa,.underline-animation .cmd .cmd-cursor.cmd-blink .far,.underline-animation .cmd .cmd-cursor.cmd-blink .fas,.underline-animation .cmd .cmd-cursor.cmd-blink a,.underline-animation .cmd .cmd-cursor.cmd-blink>span[data-text]:not(.emoji):not(.fa):not(.far):not(.fas) span{-webkit-animation-name:terminal-underline;-moz-animation-name:terminal-underline;-ms-animation-name:terminal-underline;animation-name:terminal-underline}.glow-animation .cmd .cmd-cursor .emoji,.glow-animation .cmd .cmd-cursor.cmd-blink .fa,.glow-animation .cmd .cmd-cursor.cmd-blink .far,.glow-animation .cmd .cmd-cursor.cmd-blink .fas,.glow-animation .cmd .cmd-cursor.cmd-blink a,.glow-animation .cmd .cmd-cursor.cmd-blink>span[data-text]:not(.emoji):not(.fa):not(.far):not(.fas) span{-webkit-animation-name:terminal-glow;-moz-animation-name:terminal-glow;-ms-animation-name:terminal-glow;animation-name:terminal-glow}.bar-animation .cmd .cmd-cursor .emoji,.bar-animation .cmd .cmd-cursor.cmd-blink .fa,.bar-animation .cmd .cmd-cursor.cmd-blink .far,.bar-animation .cmd .cmd-cursor.cmd-blink .fas,.bar-animation .cmd .cmd-cursor.cmd-blink a,.bar-animation .cmd .cmd-cursor.cmd-blink>span[data-text]:not(.emoji):not(.fa):not(.far):not(.fas) span{-webkit-animation-name:terminal-bar;-moz-animation-name:terminal-bar;-ms-animation-name:terminal-bar;animation-name:terminal-bar}@supports (-ms-ime-align:auto){.cmd .cmd-clipboard{margin-left:-9999px}@keyframes terminal-blink{0%,50%{background-color:var(--original-color,#aaa);color:var(--background,#000)}50.1%,to{background-color:var(--background,#000);color:var(--original-color,#aaa)}}@keyframes terminal-bar{0%,50%{border-left-color:var(--color,#aaa)}50.1%,to{border-left-color:var(--background,#000)}}@keyframes terminal-underline{0%,50%{border-bottom-color:var(--color,#aaa);line-height:12px;line-height:calc(var(--size, 1)*(12px/var(--pixel-density, 1)))}50.1%,to{border-bottom-color:var(--background,#000);line-height:12px;line-height:calc(var(--size, 1)*(12px/var(--pixel-density, 1)))}}}@media (-ms-high-contrast:active),(-ms-high-contrast:none){.cmd .cmd-clipboard{margin-left:-9999px}.underline-animation .cursor.blink span span{margin-top:1px}@-ms-keyframes terminal-blink{0%,50%{background-color:#aaa;color:#000}50.1%,to{background-color:#000;color:#aaa}}}.cmd span[data-text]::-moz-selection,.cmd span[data-text]:not(.far):not(.fa):not(.fas) span::-moz-selection,.terminal .terminal-output .raw ::-moz-selection,.terminal .terminal-output .raw div::-moz-selection,.terminal .terminal-output div div a::-moz-selection,.terminal .terminal-output div div::-moz-selection,.terminal .terminal-output span[data-text]::-moz-selection,.terminal .terminal-output span[data-text]:not(.far):not(.fa):not(.fas) span::-moz-selection{background-color:#aaa;color:#000}.terminal .cmd{pointer-events:none}.terminal .cmd-prompt *{pointer-events:visible}.cmd-prompt>span:first-child{margin-left:var(--prompt-offset)}.terminal .cmd textarea,.terminal .cmd-cursor-line>span,.terminal .cmd-wrapper>div:not(.cmd-cursor-line){pointer-events:visible}.cmd span[data-text]:not(.far):not(.fa):not(.fas) span::selection,.terminal .terminal-output .raw ::selection,.terminal .terminal-output .raw div::selection,.terminal .terminal-output div div a::selection,.terminal .terminal-output div div::selection,.terminal .terminal-output span[data-text]::selection,.terminal .terminal-output span[data-text]:not(.far):not(.fa):not(.fas) span::selection,.terminal-revese{background-color:hsla(0,0%,67%,.99);color:#000}.cmd .emoji span::-moz-selection,.cmd .emoji::-moz-selection,.cmd textarea::-moz-selection,.terminal-output .emoji span::-moz-selection,.terminal-output .emoji::-moz-selection{background-color:transparent!important;color:transparent!important}.cmd .emoji span::selection,.cmd .emoji::selection,.cmd textarea::selection,.terminal-output .emoji span::selection,.terminal-output .emoji::selection{background-color:transparent!important;color:transparent!important}.terminal .terminal-output>:not(.raw) .terminal-error,.terminal .terminal-output>:not(.raw) .terminal-error *{color:red;color:var(--error-color,red)}.tilda{left:0;position:fixed;top:0;width:100%;z-index:1100}.ui-dialog-content .terminal{box-sizing:border-box;height:100%;width:100%}.ui-dialog .ui-dialog-content.dterm{padding:0}.clear{clear:both}.terminal .terminal-fill{border:none;box-sizing:border-box;height:100%;left:0;margin:1px 0 0;opacity:.01;pointer-events:none;position:absolute;top:-100%;width:100%}.cmd-editable,.terminal .terminal-fill,.terminal-scroller{padding:calc(1px*var(--padding, 10)/var(--pixel-density, 1))}.cmd-editable{padding-top:0}.terminal-scroller{padding-bottom:0}.terminal .terminal-output>:not(.raw) .terminal-error,.terminal .terminal-output>:not(.raw) .terminal-error *{--color:var(--error-color,red);text-shadow:0 0 calc(var(--glow)*5px) var(--color)}.terminal .terminal-output>:not(.raw) a[href]{text-shadow:0 0 calc(var(--glow)*5px) var(--color)}.terminal .cmd{margin-bottom:calc(1px*var(--padding, 10)/var(--pixel-density, 1));position:relative}.terminal .partial,.terminal .partial>div{display:inline-block}@supports (--css:variables){.cmd,.cmd div,.cmd span[data-text]:not(.cmd-inverted):not(.token):not(.emoji),.terminal,.terminal-output>:not(.raw) a,.terminal-output>:not(.raw) div,.terminal-output>:not(.raw) span[data-text]:not(.token):not(.inverted):not(.terminal-inverted):not(.cmd-inverted):not(.terminal-error):not(.emoji),.terminal.external [data-text]{background-color:var(--background,#000);color:var(--color,#aaa)}.terminal{--terminal-line:calc(var(--size, 1)*(16px/var(--pixel-density, 1)) + 1px/var(--pixel-density, 1));height:auto;height:calc(var(--terminal-line)*var(--rows) + var(--padding, 10)*2px)}.cmd div,.terminal .terminal-output>:not(.raw)>div,.terminal.external div{line-height:var(--terminal-line,1em)}.cmd [data-text],.terminal [data-text]{text-shadow:var(--text-shadow,0 0 calc(var(--glow)*5px) var(--color,#ccc))}.terminal span[style*="--length"]{display:inline-block;width:calc(var(--length, 1)*var(--char-width, 7.23438)*1px)}.cmd,.cmd div,.cmd span,.terminal,.terminal-output>:not(.raw) a,.terminal-output>:not(.raw) div,.terminal-output>:not(.raw) span{font-size:calc(var(--size, 1)*(12px/var(--pixel-density, 1)))}.cmd .emoji,.terminal-output .emoji{height:calc(var(--size, 1)*(12px/var(--pixel-density, 1)))}.cmd .clipboard{top:calc(var(--size, 1)*(14/var(--pixel-density, 1))*var(--cursor-line, 0)*1px)}.cmd span[style*="--background"],.terminal span[style*="--background"]{--base-background:var(--background)}.cmd.cmd.cmd .cmd-inverted,.cmd.cmd.cmd .inverted,.terminal .inverted>span,.terminal .terminal-inverted>span{background-color:var(--color,#aaa)!important;color:var(--base-background,#000)!important}.cmd .cmd-cursor.cmd-blink{background-color:var(--background,#000);color:var(--color,#aaa)}.cmd .cmd-cursor.cmd-blink .emoji,.cmd .cmd-cursor.cmd-blink .fa,.cmd .cmd-cursor.cmd-blink .far,.cmd .cmd-cursor.cmd-blink .fas,.cmd .cmd-cursor.cmd-blink a,.cmd .cmd-cursor.cmd-blink>span[data-text]:not(.emoji):not(.fa):not(.far):not(.fas) span{--original-background:inherit;-webkit-animation:var(--animation,terminal-blink) 1s infinite linear;-moz-animation:var(--animation,terminal-blink) 1s infinite linear;-ms-animation:var(--animation,terminal-blink) 1s infinite linear;animation:var(--animation,terminal-blink) 1s infinite linear}.cmd .cmd-cursor.cmd-blink .emoji span{background:transparent;color:transparent}.cmd span[data-text]:not(.far):not(.fa):not(.fas):not(.emoji) span::-moz-selection,.terminal .terminal-output .raw ::-moz-selection,.terminal .terminal-output .raw div::-moz-selection,.terminal .terminal-output div div a::-moz-selection,.terminal .terminal-output div div::-moz-selection,.terminal .terminal-output span[data-text]::-moz-selection,.terminal .terminal-output span[data-text]:not(.far):not(.fa):not(.fas):not(.emoji) span::-moz-selection{background-color:var(--color,#aaa);color:var(--background,#000)}.terminal .terminal-output div div a::-moz-selection{background-color:var(--link-color,rgba(15,96,255,.99))!important;color:var(--background,#000)!important}.terminal .terminal-output div div a:hover::-moz-selection{background-color:var(--link-color,rgba(2,50,144,.99))!important}.cmd span[data-text]:not(.far):not(.fa):not(.fas):not(.emoji) span::selection,.terminal .terminal-output .raw ::selection,.terminal .terminal-output .raw div::selection,.terminal .terminal-output div div a::selection,.terminal .terminal-output div div::selection,.terminal .terminal-output span[data-text]:not(.emoji)::selection,.terminal .terminal-output span[data-text]:not(.far):not(.fa):not(.fas):not(.emoji) span::selection{background-color:var(--color,hsla(0,0%,67%,.99))!important;color:var(--background,#000)!important}.terminal .terminal-output div div a::selection{background-color:var(--link-color,rgba(15,96,255,.99))!important;color:var(--background,#000)!important}.terminal .terminal-output div div a:hover::selection{background-color:var(--link-color,rgba(2,50,144,.99))!important}}@property --color{syntax:"";inherits:true;initial-value:hsla(0,0%,67%,.99)}@property --background{syntax:"";inherits:true;initial-value:#000}@property --link-color{syntax:"";inherits:true;initial-value:#37f}@property --size{syntax:"";inherits:true;initial-value:1}@property --padding{syntax:"";inherits:true;initial-value:10}@property --rows{syntax:"";inherits:true}@supports (-ms-ime-align:auto){.cmd span[data-text]::selection,.terminal .terminal-output div div a::selection,.terminal .terminal-output div div::selection,.terminal h1::selection,.terminal h2::selection,.terminal h3::selection,.terminal h4::selection,.terminal h5::selection,.terminal h6::selection,.terminal pre::selection,.terminal td::selection{background-color:hsla(0,0%,67%,.99);color:#000}}.cmd .style .token.string,.cmd .token.entity,.cmd .token.operator,.cmd .token.string,.cmd .token.token,.cmd .token.url,.cmd .token.variable,.terminal .style .token.string,.terminal .token.entity,.terminal .token.operator,.terminal .token.string,.terminal .token.token,.terminal .token.url,.terminal .token.variable{background-color:inherit}.cmd .cursor-wrapper ul{float:left;left:0;list-style:none;margin:0;padding:0;position:absolute;top:14px}.cmd .cursor-wrapper li{cursor:pointer;white-space:nowrap}.cmd .cursor-wrapper li:hover{background:#aaa;color:#000}.cursor-wrapper{position:relative}.terminal-output img{vertical-align:top}.cmd img{border:1px solid transparent;height:14px;height:calc(var(--size, 1)*(14px/var(--pixel-density, 1)))}.cmd-cursor img{border-color:#ccc;border-color:var(--color,#ccc)}.terminal-output svg.terminal-broken-image{height:calc(var(--size, 1)*(14px/var(--pixel-density, 1)))}.terminal-output svg.terminal-broken-image use{fill:var(--color,#ccc)}.terminal-error{--color:var(--error-color)}.terminal-glow{--animation:terminal-glow}.terminal-glow .cmd-prompt>span,.terminal-glow .terminal-output>div a[href],.terminal-glow .terminal-output>div span,.terminal-glow [data-text] span,.terminal-glow a[data-text],.terminal-glow span[data-text]{text-shadow:1px 1px 5px #ccc;text-shadow:1px 1px 5px var(--color,#ccc)}.terminal-scroll-marker{height:1px;height:calc(1px/var(--pixel-density, 1));margin-top:-1px;margin-top:calc(-1px/var(--pixel-density, 1));position:relative;z-index:100}.terminal-scroll-marker div{bottom:0;left:0;position:absolute;right:0;z-index:200}.terminal-less{overscroll-behavior-y:contain;touch-action:none}.terminal-mobile.terminal-less .terminal-wrapper{pointer-events:none}.cmd-editable,.terminal-mobile.terminal-less .terminal-output a{pointer-events:visible}.cmd-editable:before{content:attr(data-cmd-prompt);display:inline-block}.cmd-editable{background:transparent;bottom:0;color:transparent;left:0;opacity:.01;outline:0 solid transparent;position:absolute;right:0;top:calc(var(--cmd-top)*1px);z-index:500}.terminal-scroller::-webkit-scrollbar{background:var(--background,#000);height:calc(6px/var(--pixel-density, 1));width:calc(6px/var(--pixel-density, 1))}.terminal-scroller::-webkit-scrollbar-thumb,.terminal-scroller::-webkit-scrollbar-thumb:hover{background:var(--color,#aaa)}.terminal-scroller{scrollbar-color:#aaa #000;scrollbar-color:var(--color,#aaa) var(--background,#000);scrollbar-width:thin}.terminal-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}.terminal-wrapper{--color:var(--base-color);--background:var(--base-background)}.cmd .token{--original-color:var(--color)}.cmd .terminal-blink,.terminal .terminal-blink{animation:terminal-ansi-blink 1s steps(2,start) infinite;-webkit-animation:terminal-ansi-blink 1s steps(2,start) infinite}.terminal .cmd *,.terminal .terminal-output,.terminal .terminal-output *{--background:transparent}.terminal .cmd ::selection,.terminal .cmd::selection,.terminal .terminal-output ::selection,.terminal .terminal-output::selection{--background:var(--base-background)}@keyframes terminal-ansi-blink{to{color:var(--background)}}@-webkit-keyframes terminal-ansi-blink{to{color:var(--background)}}@media (prefers-reduced-motion){:root{--animation:terminal-none}} + /*# sourceMappingURL=jquery.terminal.min.css.map */ +\ No newline at end of file diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 2ab104f8f4..43030a19f6 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -894,3 +894,11 @@ export const camelCase = (str: string): string => { export const convertKeysToCamelCase = (obj: Record): Record => { return _.mapKeys(obj, (value, key) => _.camelCase(key)); }; + +export const unwrapModule = (module: any) : any => { + if ('default' in module && Object.keys(module).length === 1) { + return module.default; + } else { + return module; + } +}; diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 12041a71da..52995f3f9a 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -100,7 +100,6 @@ import * as TruncateWithTooltipDirective from '@shared/directives/truncate-with- import * as coercion from '@shared/decorators/coercion'; import * as enumerable from '@shared/decorators/enumerable'; -import * as TbInject from '@shared/decorators/tb-inject'; import * as FooterComponent from '@shared/components/footer.component'; import * as LogoComponent from '@shared/components/logo.component'; @@ -432,7 +431,6 @@ class ModulesMap implements IModulesMap { '@shared/decorators/coercion': coercion, '@shared/decorators/enumerable': enumerable, - '@shared/decorators/tb-inject': TbInject, '@shared/import-export/import-export.service': ImportExportService, '@shared/import-export/import-dialog.component': ImportDialogComponent, diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts index 9bb0a37066..2e09e54251 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts @@ -121,7 +121,7 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit, this.popoverComponent.updatePosition(); } setTimeout(() => { - this.differ = new aceDiff.default( + this.differ = new aceDiff( { element: this.diffViewerElmRef.nativeElement, mode: 'ace/mode/json', diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts index 6ac4ff8bd8..87c0696352 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts @@ -15,16 +15,13 @@ /// import { MatDialogRef } from '@angular/material/dialog'; -import { Directive, InjectionToken } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; +import { Directive, inject, InjectionToken } from '@angular/core'; import { Router } from '@angular/router'; import { PageComponent } from '@shared/components/page.component'; import { CustomDialogContainerComponent } from './custom-dialog-container.component'; import { UntypedFormBuilder, Validators } from '@angular/forms'; -import { TbInject } from '@shared/decorators/tb-inject'; -export const CUSTOM_DIALOG_DATA = new InjectionToken('ConfigDialogData'); +export const CUSTOM_DIALOG_DATA = new InjectionToken('ConfigDialogData'); export interface CustomDialogData { controller: (instance: CustomDialogComponent) => void; @@ -37,12 +34,13 @@ export class CustomDialogComponent extends PageComponent { [key: string]: any; - constructor(@TbInject(Store) protected store: Store, - @TbInject(Router) protected router: Router, - @TbInject(MatDialogRef) public dialogRef: MatDialogRef, - @TbInject(UntypedFormBuilder) public fb: UntypedFormBuilder, - @TbInject(CUSTOM_DIALOG_DATA) public data: CustomDialogData) { - super(store); + protected router = inject(Router); + public dialogRef = inject(MatDialogRef); + public data = inject(CUSTOM_DIALOG_DATA); + public fb = inject(UntypedFormBuilder); + + constructor() { + super(); // @ts-ignore this.validators = Validators; this.data.controller(this); diff --git a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts index d047abdec5..44008d3e0f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts @@ -15,10 +15,13 @@ /// import { PageComponent } from '@shared/components/page.component'; -import { Directive, Injector, OnDestroy, OnInit, TemplateRef } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models'; +import { Directive, inject, Injector, OnDestroy, OnInit } from '@angular/core'; +import { + IDynamicWidgetComponent, + widgetContextToken, + widgetErrorMessagesToken, + widgetTitlePanelToken +} from '@home/models/widget-component.models'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { RafService } from '@core/services/raf.service'; import { @@ -45,7 +48,6 @@ import { DatePipe } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; import { DomSanitizer } from '@angular/platform-browser'; import { Router } from '@angular/router'; -import { TbInject } from '@shared/decorators/tb-inject'; import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe'; import { UserSettingsService } from '@core/http/user-settings.service'; import { ImagePipe } from '@shared/pipe/image.pipe'; @@ -64,38 +66,39 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid validators = Validators; - constructor(@TbInject(RafService) public raf: RafService, - @TbInject(Store) protected store: Store, - @TbInject(UntypedFormBuilder) public fb: UntypedFormBuilder, - @TbInject(Injector) public readonly $injector: Injector, - @TbInject('widgetContext') public readonly ctx: WidgetContext, - @TbInject('errorMessages') public readonly errorMessages: string[], - @TbInject('widgetTitlePanel') public readonly widgetTitlePanel: TemplateRef) { - super(store); - this.ctx.$injector = $injector; - this.ctx.deviceService = $injector.get(DeviceService); - this.ctx.assetService = $injector.get(AssetService); - this.ctx.entityViewService = $injector.get(EntityViewService); - this.ctx.customerService = $injector.get(CustomerService); - this.ctx.dashboardService = $injector.get(DashboardService); - this.ctx.userService = $injector.get(UserService); - this.ctx.attributeService = $injector.get(AttributeService); - this.ctx.entityRelationService = $injector.get(EntityRelationService); - this.ctx.entityService = $injector.get(EntityService); - this.ctx.authService = $injector.get(AuthService); - this.ctx.dialogs = $injector.get(DialogService); - this.ctx.customDialog = $injector.get(CustomDialogService); - this.ctx.resourceService = $injector.get(ResourceService); - this.ctx.userSettingsService = $injector.get(UserSettingsService); - this.ctx.utilsService = $injector.get(UtilsService); - this.ctx.telemetryWsService = $injector.get(TelemetryWebsocketService); - this.ctx.date = $injector.get(DatePipe); - this.ctx.imagePipe = $injector.get(ImagePipe); - this.ctx.milliSecondsToTimeString = $injector.get(MillisecondsToTimeStringPipe); - this.ctx.translate = $injector.get(TranslateService); - this.ctx.http = $injector.get(HttpClient); - this.ctx.sanitizer = $injector.get(DomSanitizer); - this.ctx.router = $injector.get(Router); + public raf = inject(RafService); + public fb = inject(UntypedFormBuilder); + public readonly $injector = inject(Injector); + public readonly ctx = inject(widgetContextToken); + public readonly errorMessages = inject(widgetErrorMessagesToken); + public readonly widgetTitlePanel = inject(widgetTitlePanelToken); + + constructor() { + super(); + this.ctx.$injector = this.$injector; + this.ctx.deviceService = this.$injector.get(DeviceService); + this.ctx.assetService = this.$injector.get(AssetService); + this.ctx.entityViewService = this.$injector.get(EntityViewService); + this.ctx.customerService = this.$injector.get(CustomerService); + this.ctx.dashboardService = this.$injector.get(DashboardService); + this.ctx.userService = this.$injector.get(UserService); + this.ctx.attributeService = this.$injector.get(AttributeService); + this.ctx.entityRelationService = this.$injector.get(EntityRelationService); + this.ctx.entityService = this.$injector.get(EntityService); + this.ctx.authService = this.$injector.get(AuthService); + this.ctx.dialogs = this.$injector.get(DialogService); + this.ctx.customDialog = this.$injector.get(CustomDialogService); + this.ctx.resourceService = this.$injector.get(ResourceService); + this.ctx.userSettingsService = this.$injector.get(UserSettingsService); + this.ctx.utilsService = this.$injector.get(UtilsService); + this.ctx.telemetryWsService = this.$injector.get(TelemetryWebsocketService); + this.ctx.date = this.$injector.get(DatePipe); + this.ctx.imagePipe = this.$injector.get(ImagePipe); + this.ctx.milliSecondsToTimeString = this.$injector.get(MillisecondsToTimeStringPipe); + this.ctx.translate = this.$injector.get(TranslateService); + this.ctx.http = this.$injector.get(HttpClient); + this.ctx.sanitizer = this.$injector.get(DomSanitizer); + this.ctx.router = this.$injector.get(Router); this.ctx.$scope = this; if (this.ctx.defaultSubscription) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts index 39270125b6..848b727e61 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts @@ -24,7 +24,7 @@ import { WidgetContext } from '@home/models/widget-component.models'; import { UtilsService } from '@core/services/utils.service'; import { Observable, Subject } from 'rxjs'; import { MINUTE } from '@shared/models/time/time.models'; -import { isDefinedAndNotNull, mergeDeep } from '@core/utils'; +import { isDefinedAndNotNull, mergeDeep, unwrapModule } from '@core/utils'; import { backgroundStyle, ComponentStyle, overlayStyle } from '@shared/models/widget-settings.models'; import { ImagePipe } from '@shared/pipe/image.pipe'; import { DomSanitizer } from '@angular/platform-browser'; @@ -157,7 +157,7 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI private updateQRCode(link: string) { import('qrcode').then((QRCode) => { - QRCode.toString(link, (err, string) => { + unwrapModule(QRCode).toString(link, (err, string) => { this.qrCodeSVG = string; this.cd.markForCheck(); }) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts index d8d245eee8..bec9ea32aa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts @@ -28,7 +28,7 @@ import { isNumber, isObject, parseFunction, - safeExecute + safeExecute, unwrapModule } from '@core/utils'; interface QrCodeWidgetSettings { @@ -124,7 +124,7 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte private updateCanvas() { if (this.viewInited) { import('qrcode').then((QRCode) => { - QRCode.toCanvas(this.canvasRef.nativeElement, this.qrCodeText); + unwrapModule(QRCode).toCanvas(this.canvasRef.nativeElement, this.qrCodeText); this.canvasRef.nativeElement.style.width = 'auto'; this.canvasRef.nativeElement.style.height = 'auto'; }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts index f1c3b98c74..593b11080c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts @@ -19,9 +19,9 @@ import { widgetContextCompletions } from '@shared/models/ace/widget-completion.m import { entityIdHref, entityTypeHref, serviceCompletions } from '@shared/models/ace/service-completion.models'; import { CustomActionDescriptor, WidgetAction } from '@shared/models/widget.models'; import { deepClone, isDefined, isUndefined } from '@core/utils'; -import customSampleJs from '!raw-loader!./custom-sample-js.raw'; -import customSampleCss from '!raw-loader!./custom-sample-css.raw'; -import customSampleHtml from '!raw-loader!./custom-sample-html.raw'; +import customSampleJs from './custom-sample-js.raw'; +import customSampleCss from './custom-sample-css.raw'; +import customSampleHtml from './custom-sample-html.raw'; const customActionCompletions: TbEditorCompletions = { ...{ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts index 59513c978c..0f0fe7cc76 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts @@ -29,6 +29,10 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { + defaultGoogleMapProviderSettings, + defaultHereMapProviderSettings, + defaultImageMapProviderSettings, + defaultOpenStreetMapProviderSettings, defaultTencentMapProviderSettings, GoogleMapProviderSettings, HereMapProviderSettings, ImageMapProviderSettings, @@ -39,7 +43,6 @@ import { TencentMapProviderSettings } from '@home/components/widget/lib/maps/map-models'; import { extractType } from '@core/utils'; -import { keys } from 'ts-transformer-keys'; import { IAliasController } from '@core/api/widget-api.models'; @Component({ @@ -128,11 +131,11 @@ export class MapProviderSettingsComponent extends PageComponent implements OnIni writeValue(value: MapProviderSettings): void { this.modelValue = value; const provider = value?.provider; - const googleProviderSettings = extractType(value, keys()); - const openstreetProviderSettings = extractType(value, keys()); - const hereProviderSettings = extractType(value, keys()); - const imageMapProviderSettings = extractType(value, keys()); - const tencentMapProviderSettings = extractType(value, keys()); + const googleProviderSettings = extractType(value, Object.keys(defaultGoogleMapProviderSettings) as (keyof GoogleMapProviderSettings)[]); + const openstreetProviderSettings = extractType(value, Object.keys(defaultOpenStreetMapProviderSettings) as (keyof OpenStreetMapProviderSettings)[]); + const hereProviderSettings = extractType(value, Object.keys(defaultHereMapProviderSettings) as (keyof HereMapProviderSettings)[]); + const imageMapProviderSettings = extractType(value, Object.keys(defaultImageMapProviderSettings) as (keyof ImageMapProviderSettings)[]); + const tencentMapProviderSettings = extractType(value, Object.keys(defaultTencentMapProviderSettings) as (keyof TencentMapProviderSettings)[]); this.providerSettingsFormGroup.patchValue( { provider, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts index 3c6c4040af..2bd3a78560 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts @@ -17,11 +17,11 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; @@ -31,6 +31,13 @@ import { TranslateService } from '@ngx-translate/core'; import { CircleSettings, CommonMapSettings, + defaultCircleSettings, + defaultCommonMapSettings, + defaultMapEditorSettings, + defaultMapProviderSettings, + defaultMarkerClusteringSettings, + defaultMarkersSettings, + defaultPolygonSettings, MapEditorSettings, MapProviders, MapProviderSettings, @@ -41,7 +48,6 @@ import { UnitedMapSettings } from '@home/components/widget/lib/maps/map-models'; import { extractType } from '@core/utils'; -import { keys } from 'ts-transformer-keys'; import { IAliasController } from '@core/api/widget-api.models'; import { Widget } from '@shared/models/widget.models'; @@ -140,12 +146,12 @@ export class MapSettingsComponent extends PageComponent implements OnInit, Contr writeValue(value: UnitedMapSettings): void { this.modelValue = value; - const mapProviderSettings = extractType(value, keys()); - const commonMapSettings = extractType(value, keys()); - const markersSettings = extractType(value, keys()); - const polygonSettings = extractType(value, keys()); - const circleSettings = extractType(value, keys()); - const mapEditorSettings = extractType(value, keys()); + const mapProviderSettings = extractType(value, Object.keys(defaultMapProviderSettings) as (keyof MapProviderSettings)[]); + const commonMapSettings = extractType(value, Object.keys(defaultCommonMapSettings) as (keyof CommonMapSettings)[]); + const markersSettings = extractType(value, Object.keys(defaultMarkersSettings) as (keyof MarkersSettings)[]); + const polygonSettings = extractType(value, Object.keys(defaultPolygonSettings) as (keyof PolygonSettings)[]); + const circleSettings = extractType(value, Object.keys(defaultCircleSettings) as (keyof CircleSettings)[]); + const mapEditorSettings = extractType(value, Object.keys(defaultMapEditorSettings) as (keyof MapEditorSettings)[]); const formValue = { mapProviderSettings, commonMapSettings, @@ -157,7 +163,7 @@ export class MapSettingsComponent extends PageComponent implements OnInit, Contr if (this.routeMap) { formValue.routeMapSettings = extractType(value, ['strokeWeight', 'strokeOpacity']); } else { - formValue.markerClusteringSettings = extractType(value, keys()); + formValue.markerClusteringSettings = extractType(value, Object.keys(defaultMarkerClusteringSettings) as (keyof MarkerClusteringSettings)[]); } this.mapSettingsFormGroup.patchValue( formValue, {emitEvent: false} ); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-widget-settings.component.ts index 216530ffdc..ab4ab92e17 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-widget-settings.component.ts @@ -21,16 +21,22 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { CircleSettings, + CommonMapSettings, + defaultCircleSettings, + defaultCommonMapSettings, + defaultMapProviderSettings, + defaultMarkersSettings, + defaultPolygonSettings, + defaultTripAnimationPathSettings, + defaultTripAnimationPointSettings, defaultTripAnimationSettings, MapProviderSettings, + MarkersSettings, PointsSettings, PolygonSettings, - PolylineSettings, - TripAnimationCommonSettings, - TripAnimationMarkerSettings + PolylineSettings } from 'src/app/modules/home/components/widget/lib/maps/map-models'; import { extractType } from '@core/utils'; -import { keys } from 'ts-transformer-keys'; @Component({ selector: 'tb-trip-animation-widget-settings', @@ -69,13 +75,13 @@ export class TripAnimationWidgetSettingsComponent extends WidgetSettingsComponen } protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { - const mapProviderSettings = extractType(settings, keys()); - const commonMapSettings = extractType(settings, keys()); - const markersSettings = extractType(settings, keys()); - const pathSettings = extractType(settings, keys()); - const pointSettings = extractType(settings, keys()); - const polygonSettings = extractType(settings, keys()); - const circleSettings = extractType(settings, keys()); + const mapProviderSettings = extractType(settings, Object.keys(defaultMapProviderSettings) as (keyof MapProviderSettings)[]); + const commonMapSettings = extractType(settings, Object.keys(defaultCommonMapSettings) as (keyof CommonMapSettings)[]); + const markersSettings = extractType(settings, Object.keys(defaultMarkersSettings) as (keyof MarkersSettings)[]); + const pathSettings = extractType(settings, Object.keys(defaultTripAnimationPathSettings) as (keyof PolylineSettings)[]); + const pointSettings = extractType(settings, Object.keys(defaultTripAnimationPointSettings) as (keyof PointsSettings)[]); + const polygonSettings = extractType(settings, Object.keys(defaultPolygonSettings) as (keyof PolygonSettings)[]); + const circleSettings = extractType(settings, Object.keys(defaultCircleSettings) as (keyof CircleSettings)[]); return { mapProviderSettings, commonMapSettings, diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 80ab61df67..ae3cc237ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -129,11 +129,13 @@ export class WidgetComponentService { w.tinycolor = tinycolor; w.cssjs = cssjs; w.moment = moment; - w.$ = $; - w.jQuery = $; const widgetModulesTasks: Observable[] = []; - widgetModulesTasks.push(from(import('jquery.terminal'))); + widgetModulesTasks.push(from(import('jquery.terminal')).pipe( + tap((mod) => { + mod.default(window, $); + }) + )); widgetModulesTasks.push(from(import('flot/src/jquery.flot.js')).pipe( mergeMap(() => { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 8459a361e4..7329eb1eaf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -70,9 +70,9 @@ import { IDynamicWidgetComponent, ShowWidgetHeaderActionFunction, updateEntityParams, - WidgetContext, + WidgetContext, widgetContextToken, widgetErrorMessagesToken, WidgetHeaderAction, - WidgetInfo, + WidgetInfo, widgetTitlePanelToken, WidgetTypeInstance } from '@home/models/widget-component.models'; import { @@ -743,15 +743,15 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, { providers: [ { - provide: 'widgetContext', + provide: widgetContextToken, useValue: this.widgetContext }, { - provide: 'errorMessages', + provide: widgetErrorMessagesToken, useValue: this.errorMessages }, { - provide: 'widgetTitlePanel', + provide: widgetTitlePanelToken, useValue: this.widgetTitlePanel } ], diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index cfc706bccc..971c7db6f7 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -47,7 +47,7 @@ import { WidgetActionsApi, WidgetSubscriptionApi } from '@core/api/widget-api.models'; -import { ChangeDetectorRef, Injector, NgZone, Type } from '@angular/core'; +import { ChangeDetectorRef, InjectionToken, Injector, NgZone, TemplateRef, Type } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { RafService } from '@core/services/raf.service'; import { WidgetTypeId } from '@shared/models/id/widget-type-id'; @@ -538,6 +538,10 @@ export class LabelVariablePattern { } } +export const widgetContextToken = new InjectionToken('widgetContext'); +export const widgetErrorMessagesToken = new InjectionToken('errorMessages'); +export const widgetTitlePanelToken = new InjectionToken>('widgetTitlePanel'); + export interface IDynamicWidgetComponent { readonly ctx: WidgetContext; readonly errorMessages: string[]; diff --git a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/backup-code-auth-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/backup-code-auth-dialog.component.ts index 761ba9ce22..ba85e75e0c 100644 --- a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/backup-code-auth-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/backup-code-auth-dialog.component.ts @@ -31,7 +31,7 @@ import { mergeMap, tap } from 'rxjs/operators'; import { ImportExportService } from '@shared/import-export/import-export.service'; import { deepClone } from '@core/utils'; -import printTemplate from '!raw-loader!./backup-code-print-template.raw'; +import printTemplate from './backup-code-print-template.raw'; @Component({ selector: 'tb-backup-code-auth-dialog', diff --git a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/totp-auth-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/totp-auth-dialog.component.ts index f88d799f31..255c960dc8 100644 --- a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/totp-auth-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/totp-auth-dialog.component.ts @@ -28,6 +28,7 @@ import { TwoFactorAuthProviderType } from '@shared/models/two-factor-auth.models'; import { MatStepper } from '@angular/material/stepper'; +import { unwrapModule } from '@core/utils'; @Component({ selector: 'tb-totp-auth-dialog', @@ -56,7 +57,7 @@ export class TotpAuthDialogComponent extends DialogComponent { - QRCode.toCanvas(this.canvasRef.nativeElement, this.totpAuthURL); + unwrapModule(QRCode).toCanvas(this.canvasRef.nativeElement, this.totpAuthURL); this.canvasRef.nativeElement.style.width = 'auto'; this.canvasRef.nativeElement.style.height = 'auto'; }); diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts index 691b1eca1b..682a88ba98 100644 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts +++ b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts @@ -31,7 +31,7 @@ import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCES import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { deepClone, isString } from '@app/core/utils'; +import { deepClone, isString, unwrapModule } from '@app/core/utils'; import { JsonFormProps } from './react/json-form.models'; import inspector from 'schema-inspector'; import tinycolor from 'tinycolor2'; @@ -270,9 +270,9 @@ export class JsonFormComponent implements ControlValueAccessor, Validator, OnCha ]; forkJoin(reactSchemaFormObservables).subscribe( (modules) => { - const react = modules[0]; - const reactDomClient = modules[2]; - const jsonFormReact = modules[3].default; + const react = unwrapModule(modules[0]); + const reactDomClient = unwrapModule(modules[2]); + const jsonFormReact = unwrapModule(modules[3]); this.reactRoot = reactDomClient.createRoot(this.reactRootElmRef.nativeElement); this.reactRoot.render(react.createElement(jsonFormReact, this.formProps)); } diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx index d9fd64f951..649ee16c95 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx @@ -20,18 +20,21 @@ import reactCSS from 'reactcss'; import Button from '@mui/material/Button'; import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; import { IEditorProps } from 'react-ace/src/types'; -import { mergeMap } from 'rxjs/operators'; +import { map, mergeMap } from 'rxjs/operators'; import { getAce } from '@shared/models/ace/ace.models'; import { from, lastValueFrom } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; import { CircularProgress, IconButton } from '@mui/material'; import { MouseEvent } from 'react'; import { Help, HelpOutline } from '@mui/icons-material'; +import { unwrapModule } from '@core/utils'; const ReactAce = React.lazy(() => { return lastValueFrom(getAce().pipe( mergeMap(() => { - return from(import('react-ace')); + return from(import('react-ace')).pipe( + map((module) => unwrapModule(module) + )); }) )); }); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx index 7c37d720dd..5ce35ae96f 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx @@ -51,6 +51,7 @@ import { MouseEvent, ReactNode } from 'react'; class ThingsboardSchemaForm extends React.Component { private hasConditions: boolean; + private conditionFunction: Function; private readonly mapper: {[type: string]: any}; constructor(props: JsonFormProps) { @@ -130,8 +131,10 @@ class ThingsboardSchemaForm extends React.Component { } if (form.condition) { this.hasConditions = true; - // tslint:disable-next-line:no-eval - if (eval(form.condition) === false) { + if (!this.conditionFunction) { + this.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`); + } + if (this.conditionFunction(form, model, index) === false) { return null; } } diff --git a/ui-ngx/src/app/shared/components/page.component.ts b/ui-ngx/src/app/shared/components/page.component.ts index 4a5ee06cbc..ec6864e227 100644 --- a/ui-ngx/src/app/shared/components/page.component.ts +++ b/ui-ngx/src/app/shared/components/page.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Directive, OnDestroy } from '@angular/core'; +import { Directive, inject, OnDestroy } from '@angular/core'; import { select, Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Observable, Subscription } from 'rxjs'; @@ -25,13 +25,15 @@ import { AbstractControl } from '@angular/forms'; @Directive() export abstract class PageComponent implements OnDestroy { + protected store: Store = inject(Store); + isLoading$: Observable; loadingSubscription: Subscription; disabledOnLoadFormControls: Array = []; showMainLoadingBar = true; - protected constructor(protected store: Store) { + protected constructor(...args: unknown[]) { this.isLoading$ = this.store.pipe(delay(0), select(selectIsLoading), share()); } diff --git a/ui-ngx/src/app/shared/decorators/public-api.ts b/ui-ngx/src/app/shared/decorators/public-api.ts index e8dbfc608f..d8a8a397f4 100644 --- a/ui-ngx/src/app/shared/decorators/public-api.ts +++ b/ui-ngx/src/app/shared/decorators/public-api.ts @@ -16,4 +16,3 @@ export * from './coercion'; export * from './enumerable'; -export * from './tb-inject'; diff --git a/ui-ngx/src/app/shared/decorators/tb-inject.ts b/ui-ngx/src/app/shared/decorators/tb-inject.ts deleted file mode 100644 index 7c421c6514..0000000000 --- a/ui-ngx/src/app/shared/decorators/tb-inject.ts +++ /dev/null @@ -1,23 +0,0 @@ -/// -/// Copyright © 2016-2024 The Thingsboard Authors -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// - -import { Inject, Type } from '@angular/core'; - -export function TbInject(token: any): (target: Type, key: any, paramIndex: number) => void { - return (target: Type, key: any, paramIndex: number) => { - Inject(token)(target, key, paramIndex); - }; -} diff --git a/ui-ngx/src/app/shared/models/ace/ace.models.ts b/ui-ngx/src/app/shared/models/ace/ace.models.ts index 381d897066..29c018048e 100644 --- a/ui-ngx/src/app/shared/models/ace/ace.models.ts +++ b/ui-ngx/src/app/shared/models/ace/ace.models.ts @@ -18,6 +18,7 @@ import { Ace } from 'ace-builds'; import { Observable } from 'rxjs/internal/Observable'; import { forkJoin, from, of } from 'rxjs'; import { map, mergeMap, tap } from 'rxjs/operators'; +import { unwrapModule } from '@core/utils'; let aceDependenciesLoaded = false; let aceModule: any; @@ -67,10 +68,10 @@ export function getAce(): Observable { if (aceModule) { return of(aceModule); } else { - return from(import('ace')).pipe( + return from(import('ace-builds/src-noconflict/ace')).pipe( mergeMap((module) => { return loadAceDependencies().pipe( - map(() => module) + map(() => unwrapModule(module)) ); }), tap((module) => { @@ -86,7 +87,9 @@ export function getAceDiff(): Observable { } else { return getAce().pipe( mergeMap((ace) => { - return from(import('ace-diff')); + return from(import('ace-diff')).pipe( + map((module) => unwrapModule(module)) + ); }), tap((module) => { aceDiffModule = module; diff --git a/ui-ngx/src/app/shared/models/beautify.models.ts b/ui-ngx/src/app/shared/models/beautify.models.ts index 8cf54a1536..2975feeee5 100644 --- a/ui-ngx/src/app/shared/models/beautify.models.ts +++ b/ui-ngx/src/app/shared/models/beautify.models.ts @@ -17,6 +17,7 @@ import { Observable } from 'rxjs/internal/Observable'; import { from, of } from 'rxjs'; import { map, tap } from 'rxjs/operators'; +import { unwrapModule } from '@core/utils'; let jsBeautifyModule: any; let htmlBeautifyModule: any; @@ -27,6 +28,7 @@ function loadJsBeautify(): Observable { return of(jsBeautifyModule); } else { return from(import('js-beautify/js/lib/beautify.js')).pipe( + map((module) => unwrapModule(module)), tap((module) => { jsBeautifyModule = module; }) @@ -39,6 +41,7 @@ function loadHtmlBeautify(): Observable { return of(htmlBeautifyModule); } else { return from(import('js-beautify/js/lib/beautify-html.js')).pipe( + map((module) => unwrapModule(module)), tap((module) => { htmlBeautifyModule = module; }) @@ -51,6 +54,7 @@ function loadCssBeautify(): Observable { return of(cssBeautifyModule); } else { return from(import('js-beautify/js/lib/beautify-css.js')).pipe( + map((module) => unwrapModule(module)), tap((module) => { cssBeautifyModule = module; }) diff --git a/ui-ngx/src/main.ts b/ui-ngx/src/main.ts index ed9283d1ca..2fdf60da0c 100644 --- a/ui-ngx/src/main.ts +++ b/ui-ngx/src/main.ts @@ -22,6 +22,11 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from '@app/app.module'; import { environment } from '@env/environment'; +import $ from 'jquery'; + +(window as any).jQuery = $; +(window as any).$ = $; + if (environment.production) { enableProdMode(); } diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index d379d4fd9f..715165dd1a 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -15,8 +15,8 @@ */ /* You can add global styles to this file, and also import other style files */ -@import '~typeface-roboto/index.css'; -@import '~font-awesome/css/font-awesome.min.css'; +@import 'typeface-roboto/index.css'; +@import 'font-awesome/css/font-awesome.min.css'; @import 'theme.scss'; @import './scss/constants'; @import './scss/animations'; diff --git a/ui-ngx/src/tsconfig.app.json b/ui-ngx/src/tsconfig.app.json index 84be0c97d7..7a029aa8c7 100644 --- a/ui-ngx/src/tsconfig.app.json +++ b/ui-ngx/src/tsconfig.app.json @@ -6,7 +6,9 @@ "react", "react-dom", "raphael", "canvas-gauges", "systemjs"] }, "angularCompilerOptions": { - "fullTemplateTypeCheck": true + "fullTemplateTypeCheck": true, + "supportTestBed": true, + "supportJitMode": true }, "files": [ "main.ts", diff --git a/ui-ngx/src/typings/rawloader.typings.d.ts b/ui-ngx/src/typings/rawloader.typings.d.ts index 66b312befd..9bd5c14fb3 100644 --- a/ui-ngx/src/typings/rawloader.typings.d.ts +++ b/ui-ngx/src/typings/rawloader.typings.d.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -declare module '!raw-loader!*' { - const contents: string; - export = contents; +declare module '*.raw' { + const content: string; + export default content; } diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index 6ccaf0e518..61712840f4 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -15,6 +15,7 @@ "module": "es2020", "emitDecoratorMetadata": true, "jsx": "react", + "resolveJsonModule": true, "typeRoots": [ "node_modules/@types", "src/typings" diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 057f1c05e8..28b7cb2bd0 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -24,36 +24,34 @@ ts-node "^10.0.0" tsconfig-paths "^4.1.0" -"@angular-builders/custom-webpack@~18.0.0": +"@angular-builders/custom-esbuild@18.0.0": version "18.0.0" - resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-18.0.0.tgz#b51f8b03d6fff4955f63cbe9e090e0366acc90d2" - integrity sha512-XSynPSXHq5+nrh7J2snfrcbvm6YGwUGQRzr7OuO3wURJ6CHOD9C+xEAmvEUWW8c1YjEslVNG7aLtCGz7LA4ymw== + resolved "https://registry.yarnpkg.com/@angular-builders/custom-esbuild/-/custom-esbuild-18.0.0.tgz#7da11ce47cfa0bbab1e5e07a9bdefb8a6afe8ed8" + integrity sha512-SdAGatJMJJjPYrdkUupdRazid3xe1sIj/CAHDdDVP094vZ9CrZs6fgcsOF17waAo6uMxrQCWmPDrTjNgR3CvMQ== dependencies: "@angular-builders/common" "2.0.0" "@angular-devkit/architect" ">=0.1800.0 < 0.1900.0" "@angular-devkit/build-angular" "^18.0.0" "@angular-devkit/core" "^18.0.0" - lodash "^4.17.15" - webpack-merge "^5.7.3" -"@angular-devkit/architect@0.1802.7", "@angular-devkit/architect@>=0.1800.0 < 0.1900.0": - version "0.1802.7" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1802.7.tgz#eb69e6b94473c3ca3428b71c5f31ee418724a8e5" - integrity sha512-kpcgXnepEXcoxDTbqbGj7Hg1WJLWj1HLR3/FKmC5TbpBf1xiLxiqfkQNwz3BbE/W9JWMLdrXr3GI9O3O2gWPLg== +"@angular-devkit/architect@0.1802.10", "@angular-devkit/architect@>=0.1800.0 < 0.1900.0": + version "0.1802.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1802.10.tgz#1ae877263261e33a86fb3a047c3741ab09a9c599" + integrity sha512-/xudcHK2s4J/GcL6qyobmGaWMHQcYLSMqCaWMT+nK6I6tu9VEAj/p3R83Tzx8B/eKi31Pz499uHw9pmqdtbafg== dependencies: - "@angular-devkit/core" "18.2.7" + "@angular-devkit/core" "18.2.10" rxjs "7.8.1" -"@angular-devkit/build-angular@18.2.7", "@angular-devkit/build-angular@^18.0.0": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-18.2.7.tgz#21b72596f270e4a5a16d38224b38e46a609aad80" - integrity sha512-u8PriYdgddK7k+OS/pOFPD1v4Iu5bztUJZXZVcGeXBZFFdnGFFzKmQw9mfcyGvTMJp2ABgBuuJT0YqYgNfAhzw== +"@angular-devkit/build-angular@18.2.10", "@angular-devkit/build-angular@^18.0.0": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-18.2.10.tgz#7eab5b31856f8d3ce02e89771e3966328d13268f" + integrity sha512-47XgJ5fdIqlZUFWAo/XtNsh3y597DtLZWvfsnwShw6/TgyiV0rbL1Z24Rn2TCV1D/b3VhLutAIIZ/i5O5BirxQ== dependencies: "@ampproject/remapping" "2.3.0" - "@angular-devkit/architect" "0.1802.7" - "@angular-devkit/build-webpack" "0.1802.7" - "@angular-devkit/core" "18.2.7" - "@angular/build" "18.2.7" + "@angular-devkit/architect" "0.1802.10" + "@angular-devkit/build-webpack" "0.1802.10" + "@angular-devkit/core" "18.2.10" + "@angular/build" "18.2.10" "@babel/core" "7.25.2" "@babel/generator" "7.25.0" "@babel/helper-annotate-as-pure" "7.24.7" @@ -64,7 +62,7 @@ "@babel/preset-env" "7.25.3" "@babel/runtime" "7.25.0" "@discoveryjs/json-ext" "0.6.1" - "@ngtools/webpack" "18.2.7" + "@ngtools/webpack" "18.2.10" "@vitejs/plugin-basic-ssl" "1.1.0" ansi-colors "4.1.3" autoprefixer "10.4.20" @@ -75,7 +73,7 @@ css-loader "7.1.2" esbuild-wasm "0.23.0" fast-glob "3.3.2" - http-proxy-middleware "3.0.0" + http-proxy-middleware "3.0.3" https-proxy-agent "7.0.5" istanbul-lib-instrument "6.0.3" jsonc-parser "3.3.1" @@ -114,18 +112,18 @@ optionalDependencies: esbuild "0.23.0" -"@angular-devkit/build-webpack@0.1802.7": - version "0.1802.7" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1802.7.tgz#07c64d2763b10bedacff29795b778c81e888ca2c" - integrity sha512-VrtbrhZ+dht3f0GjtfRLRGRN4XHN/W+/bA9DqckdxVS6SydsrCWNHonvEPmOs4jJmGIGXIu6tUBMcWleTao2sg== +"@angular-devkit/build-webpack@0.1802.10": + version "0.1802.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1802.10.tgz#cf55fd2bee8a7d86b91bfeb0c8af9c22957c6727" + integrity sha512-WRftK/RJ9rBDDmkx5IAtIpyNo0DJiMfgGUTuZNpNUaJfSfGeaSZYgC7o1++axMchID8pncmI3Hr8L8gaP94WQg== dependencies: - "@angular-devkit/architect" "0.1802.7" + "@angular-devkit/architect" "0.1802.10" rxjs "7.8.1" -"@angular-devkit/core@18.2.7", "@angular-devkit/core@^18.0.0": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-18.2.7.tgz#f7133c9c50eb1916f8862370be975e4e2b84cca3" - integrity sha512-1ZTi4A6tEC2bkJ/puCIdIPYhesnlCVOMSDJL/lZAd0hC6X22T4pwu0AEvue7mcP5NbXpQDiBaXOZ3MmCA8PwOA== +"@angular-devkit/core@18.2.10", "@angular-devkit/core@^18.0.0": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-18.2.10.tgz#7565f0c7bf0fa3318d08c4a696e890ab0b670032" + integrity sha512-LFqiNdraBujg8e1lhuB0bkFVAoIbVbeXXwfoeROKH60OPbP8tHdgV6sFTqU7UGBKA+b+bYye70KFTG2Ys8QzKQ== dependencies: ajv "8.17.1" ajv-formats "3.0.1" @@ -134,12 +132,12 @@ rxjs "7.8.1" source-map "0.7.4" -"@angular-devkit/schematics@18.2.7": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-18.2.7.tgz#348cb0d790720a66e8183d6876effc262571086c" - integrity sha512-j7198lpkOXMG+Gyfln/5aDgBZV7m4pWMzHFhkO3+w3cbCNUN1TVZW0SyJcF+CYaxANzTbuumfvpsYc/fTeAGLw== +"@angular-devkit/schematics@18.2.10": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-18.2.10.tgz#2ca7dde6f8c9062c3ef8254a12edeffdd180272e" + integrity sha512-EIm/yCYg3ZYPsPYJxXRX5F6PofJCbNQ5rZEuQEY09vy+ZRTqGezH0qoUP5WxlYeJrjiRLYqADI9WtVNzDyaD4w== dependencies: - "@angular-devkit/core" "18.2.7" + "@angular-devkit/core" "18.2.10" jsonc-parser "3.3.1" magic-string "0.30.11" ora "5.4.1" @@ -206,13 +204,13 @@ dependencies: tslib "^2.3.0" -"@angular/build@18.2.7": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@angular/build/-/build-18.2.7.tgz#3bdb7c18e8f3bee00c0ce12a48216ce2df15f87c" - integrity sha512-oq6JsVxLP9/w9F2IjKroJwPB9CdlMblu2Xhfq/qQZRSUuM8Ppt1svr2FBTo1HrLIbosqukkVcSSdmKYDneo+cg== +"@angular/build@18.2.10": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@angular/build/-/build-18.2.10.tgz#98eb7f1ced225483693280964482e617eba3eb1b" + integrity sha512-YFBKvAyC5sH17yRYcx7VHCtJ4KUg7xCjCQ4Pe16kiTvW6vuYsgU6Btyti0Qgewd7XaWpTM8hk8N6hE4Z0hpflw== dependencies: "@ampproject/remapping" "2.3.0" - "@angular-devkit/architect" "0.1802.7" + "@angular-devkit/architect" "0.1802.10" "@babel/core" "7.25.2" "@babel/helper-annotate-as-pure" "7.24.7" "@babel/helper-split-export-declaration" "7.24.7" @@ -246,17 +244,17 @@ optionalDependencies: parse5 "^7.1.2" -"@angular/cli@18.2.7": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-18.2.7.tgz#b5fe23d6d9d65d37ba580f1860c8a09c7578bc69" - integrity sha512-KoWgSvhRsU05A2m6B7jw1kdpyoS+Ce5GGLW6xcnX7VF2AckW54vYd/8ZkgpzQrKfvIpVblYd4KJGizKoaLZ5jA== +"@angular/cli@18.2.10": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-18.2.10.tgz#29ab1344bb496122b2689ebbb862f2b44fb31848" + integrity sha512-qW/F3XVZMzzenFzbn+7FGpw8GOt9qW8UxBtYya7gUNdWlcsgGUk+ZaGC2OLbfI5gX6pchW4TOPMsDSMeaCEI2Q== dependencies: - "@angular-devkit/architect" "0.1802.7" - "@angular-devkit/core" "18.2.7" - "@angular-devkit/schematics" "18.2.7" + "@angular-devkit/architect" "0.1802.10" + "@angular-devkit/core" "18.2.10" + "@angular-devkit/schematics" "18.2.10" "@inquirer/prompts" "5.3.8" "@listr2/prompt-adapter-inquirer" "2.0.15" - "@schematics/angular" "18.2.7" + "@schematics/angular" "18.2.10" "@yarnpkg/lockfile" "1.1.0" ini "4.1.3" jsonc-parser "3.3.1" @@ -276,14 +274,14 @@ dependencies: tslib "^2.3.0" -"@angular/compiler-cli@18.2.6": - version "18.2.6" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-18.2.6.tgz#84d94852ec5088107a9ffa81908b38c51c576bd5" - integrity sha512-b5x9STfjNiNM/S0D+CnqRP9UOxPtSz1+RlCH5WdOMiW/p8j5p6dBix8YYgTe6Wg3OD7eItD2pnFQKgF/dWiopA== +"@angular/compiler-cli@18.2.9": + version "18.2.9" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-18.2.9.tgz#637f40e0fbb210ccd8d4ff464ddb6628ffa0fc46" + integrity sha512-4iMoRvyMmq/fdI/4Gob9HKjL/jvTlCjbS4kouAYHuGO9w9dmUhi1pY1z+mALtCEl9/Q8CzU2W8e5cU2xtV4nVg== dependencies: "@babel/core" "7.25.2" "@jridgewell/sourcemap-codec" "^1.4.14" - chokidar "^3.0.0" + chokidar "^4.0.0" convert-source-map "^1.5.1" reflect-metadata "^0.2.0" semver "^7.0.0" @@ -318,10 +316,10 @@ dependencies: tslib "^2.3.0" -"@angular/language-service@18.2.6": - version "18.2.6" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.6.tgz#c1cd36e40579b5bacaf0d666477c138577d2a6dd" - integrity sha512-GBvBvS2llh+/l2YhO7UO5o3GftlvQQoXnw3v0hcNoHKwcnvqXV4CCi+T2WOaZyK0iB8Is4QRbMrpJUC66HokZg== +"@angular/language-service@18.2.9": + version "18.2.9" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.9.tgz#f24f5e7e53036f6c9c4968113a3ea9ea827048f7" + integrity sha512-vC9la5VpvfX27ept36rlc42nGxDak7YfbWtSoZUageyZJUWyIEAvW8rNNPEvoO86RLi011/HmyyIr2GSQLKvxA== "@angular/material@18.2.6": version "18.2.6" @@ -2535,10 +2533,10 @@ dependencies: tslib "^2.0.0" -"@ngtools/webpack@18.2.7": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-18.2.7.tgz#2e8e7a3753ccdf49a3f350e082bdf79c7550db44" - integrity sha512-BmnFxss6zGobGyq9Mi7736golbK8RLgF+zYCQZ+4/OfMMA1jKVoELnyJqNyAx+DQn3m1qKVBjtGEL7pTNpPzOw== +"@ngtools/webpack@18.2.10": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-18.2.10.tgz#6fd94d33a9de0b5f48f8b900a9d32e4f8c89872e" + integrity sha512-CGYr8rdM5ntdb4kLUAhrLBPrhJQ4KBPo3KMT6qJE/S+jJJn5zHzedpuGFOCVhC1Siw+n1pOBSI8leTRJIW/eCQ== "@ngx-translate/core@^15.0.0": version "15.0.0" @@ -2855,13 +2853,13 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@schematics/angular@18.2.7": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-18.2.7.tgz#0b6caf0491618c2e9b24506cc68fb629845b6c6c" - integrity sha512-WOBzO11qstznHbC9tZXQf6/8+PqmaRI6QYcdTspqXNh9q9nNglvi43Xn4tSIpEhW8aSHea9hgWZV8sG+i/4W9Q== +"@schematics/angular@18.2.10": + version "18.2.10" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-18.2.10.tgz#8ef1e67d266c334e71bac38cdef4cefab141f244" + integrity sha512-2pDHT4aSzfs8Up4RQmHHuFd5FeuUebS1ZJwyt46MfXzRMFtzUZV/JKsIvDqyMwnkvFfLvgJyTCkl8JGw5jQObg== dependencies: - "@angular-devkit/core" "18.2.7" - "@angular-devkit/schematics" "18.2.7" + "@angular-devkit/core" "18.2.10" + "@angular-devkit/schematics" "18.2.10" jsonc-parser "3.3.1" "@sigstore/bundle@^2.3.2": @@ -3273,7 +3271,7 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== -"@types/http-proxy@^1.17.10", "@types/http-proxy@^1.17.8": +"@types/http-proxy@^1.17.15", "@types/http-proxy@^1.17.8": version "1.17.15" resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== @@ -4354,7 +4352,7 @@ chevrotain@~11.0.3: "@chevrotain/utils" "11.0.3" lodash-es "4.17.21" -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.3, chokidar@^3.6.0: +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -4369,6 +4367,13 @@ chevrotain@~11.0.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.1.tgz#4a6dff66798fb0f72a94f616abbd7e1a19f31d41" + integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA== + dependencies: + readdirp "^4.0.1" + chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" @@ -6515,17 +6520,17 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" -http-proxy-middleware@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz#550790357d6f92a9b82ab2d63e07343a791cf26b" - integrity sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw== +http-proxy-middleware@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz#dc1313c75bd00d81e103823802551ee30130ebd1" + integrity sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg== dependencies: - "@types/http-proxy" "^1.17.10" - debug "^4.3.4" + "@types/http-proxy" "^1.17.15" + debug "^4.3.6" http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.5" + is-glob "^4.0.3" + is-plain-object "^5.0.0" + micromatch "^4.0.8" http-proxy-middleware@^2.0.3: version "2.0.6" @@ -6860,6 +6865,11 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -7524,7 +7534,7 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.14, lodash@^4.17.15: +lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.14: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7685,7 +7695,7 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -9079,6 +9089,11 @@ readable-stream@^3.0.6, readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" + integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -10224,11 +10239,6 @@ ts-node@^10.0.0, ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -ts-transformer-keys@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/ts-transformer-keys/-/ts-transformer-keys-0.4.4.tgz#c185508b3ae9b79236aac58f788c85ca3ac807d7" - integrity sha512-LrqgvaFvar01/5mbunRyeLTSIkqoC2xfcpL/90aDY6vR07DGyH+UaYGdIEsUudnlAw2Sr0pxFgdZvE0QIyI4qA== - tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -10646,15 +10656,6 @@ webpack-merge@6.0.1: flat "^5.0.2" wildcard "^2.0.1" -webpack-merge@^5.7.3: - version "5.10.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" - integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== - dependencies: - clone-deep "^4.0.1" - flat "^5.0.2" - wildcard "^2.0.0" - webpack-sources@^3.0.0, webpack-sources@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" @@ -10780,7 +10781,7 @@ which@^4.0.0: dependencies: isexe "^3.1.1" -wildcard@^2.0.0, wildcard@^2.0.1: +wildcard@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==