Browse Source

Merge pull request #11985 from thingsboard/develop/esbuild

Switch to angular esbuild
pull/11990/head
Igor Kulikov 2 years ago
committed by GitHub
parent
commit
7c201d0a79
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 67
      ui-ngx/angular.json
  2. 104
      ui-ngx/esbuild/tb-esbuild-plugins.ts
  3. 100
      ui-ngx/extra-webpack.config.js
  4. 19
      ui-ngx/package.json
  5. 43
      ui-ngx/patches/@angular+build+18.2.10.patch
  6. 14
      ui-ngx/patches/jquery.terminal+2.43.1.patch
  7. 8
      ui-ngx/src/app/core/utils.ts
  8. 2
      ui-ngx/src/app/modules/common/modules-map.ts
  9. 2
      ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts
  10. 20
      ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts
  11. 77
      ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts
  12. 4
      ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts
  13. 4
      ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts
  14. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts
  15. 15
      ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts
  16. 26
      ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts
  17. 28
      ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-widget-settings.component.ts
  18. 8
      ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
  19. 10
      ui-ngx/src/app/modules/home/components/widget/widget.component.ts
  20. 6
      ui-ngx/src/app/modules/home/models/widget-component.models.ts
  21. 2
      ui-ngx/src/app/modules/home/pages/security/authentication-dialog/backup-code-auth-dialog.component.ts
  22. 3
      ui-ngx/src/app/modules/home/pages/security/authentication-dialog/totp-auth-dialog.component.ts
  23. 8
      ui-ngx/src/app/shared/components/json-form/json-form.component.ts
  24. 7
      ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx
  25. 7
      ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx
  26. 6
      ui-ngx/src/app/shared/components/page.component.ts
  27. 1
      ui-ngx/src/app/shared/decorators/public-api.ts
  28. 23
      ui-ngx/src/app/shared/decorators/tb-inject.ts
  29. 9
      ui-ngx/src/app/shared/models/ace/ace.models.ts
  30. 4
      ui-ngx/src/app/shared/models/beautify.models.ts
  31. 5
      ui-ngx/src/main.ts
  32. 4
      ui-ngx/src/styles.scss
  33. 4
      ui-ngx/src/tsconfig.app.json
  34. 6
      ui-ngx/src/typings/rawloader.typings.d.ts
  35. 1
      ui-ngx/tsconfig.json
  36. 189
      ui-ngx/yarn.lock

67
ui-ngx/angular.json

@ -18,12 +18,20 @@
}, },
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-builders/custom-webpack:browser", "builder": "@angular-builders/custom-esbuild:application",
"options": { "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", "index": "src/index.html",
"main": "src/main.ts", "browser": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": ["src/polyfills.ts"],
"tsConfig": "src/tsconfig.app.json", "tsConfig": "src/tsconfig.app.json",
"aot": true, "aot": true,
"assets": [ "assets": [
@ -122,49 +130,8 @@
"node_modules/prismjs/components/prism-typescript.min.js", "node_modules/prismjs/components/prism-typescript.min.js",
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.min.js" "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.min.js"
], ],
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
},
"allowedCommonJsDependencies": [ "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": { "configurations": {
@ -187,8 +154,6 @@
"sourceMap": false, "sourceMap": false,
"namedChunks": false, "namedChunks": false,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
@ -198,7 +163,6 @@
] ]
}, },
"development": { "development": {
"buildOptimizer": false,
"optimization": { "optimization": {
"scripts": false, "scripts": false,
"styles": { "styles": {
@ -207,7 +171,6 @@
}, },
"fonts": false "fonts": false
}, },
"vendorChunk": true,
"extractLicenses": false, "extractLicenses": false,
"sourceMap": true, "sourceMap": true,
"namedChunks": true "namedChunks": true
@ -215,7 +178,7 @@
} }
}, },
"serve": { "serve": {
"builder": "@angular-builders/custom-webpack:dev-server", "builder": "@angular-builders/custom-esbuild:dev-server",
"options": { "options": {
"buildTarget": "thingsboard:build", "buildTarget": "thingsboard:build",
"proxyConfig": "proxy.conf.js" "proxyConfig": "proxy.conf.js"
@ -231,7 +194,7 @@
"defaultConfiguration": "development" "defaultConfiguration": "development"
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular/build:extract-i18n",
"options": { "options": {
"buildTarget": "thingsboard:build" "buildTarget": "thingsboard:build"
} }

104
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<Buffer> {
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];

100
ui-ngx/extra-webpack.config.js

@ -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]);
};
}

19
ui-ngx/package.json

@ -5,7 +5,7 @@
"ng": "ng", "ng": "ng",
"start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "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": "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:types": "node generate-types.js",
"build:icon-metadata": "node generate-icon-metadata.js", "build:icon-metadata": "node generate-icon-metadata.js",
"lint": "ng lint", "lint": "ng lint",
@ -105,26 +105,25 @@
"tinycolor2": "^1.6.0", "tinycolor2": "^1.6.0",
"tinymce": "~6.8.5", "tinymce": "~6.8.5",
"tooltipster": "^4.2.8", "tooltipster": "^4.2.8",
"ts-transformer-keys": "^0.4.4",
"tslib": "^2.7.0", "tslib": "^2.7.0",
"tv4": "^1.3.0", "tv4": "^1.3.0",
"typeface-roboto": "^1.1.13", "typeface-roboto": "^1.1.13",
"zone.js": "~0.14.10" "zone.js": "~0.14.10"
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/custom-webpack": "~18.0.0", "@angular-builders/custom-esbuild": "18.0.0",
"@angular-devkit/build-angular": "18.2.7", "@angular-devkit/build-angular": "18.2.10",
"@angular-devkit/core": "18.2.7", "@angular-devkit/core": "18.2.10",
"@angular-devkit/schematics": "18.2.7", "@angular-devkit/schematics": "18.2.10",
"@angular-eslint/builder": "18.3.1", "@angular-eslint/builder": "18.3.1",
"@angular-eslint/eslint-plugin": "18.3.1", "@angular-eslint/eslint-plugin": "18.3.1",
"@angular-eslint/eslint-plugin-template": "18.3.1", "@angular-eslint/eslint-plugin-template": "18.3.1",
"@angular-eslint/schematics": "18.3.1", "@angular-eslint/schematics": "18.3.1",
"@angular-eslint/template-parser": "18.3.1", "@angular-eslint/template-parser": "18.3.1",
"@angular/cli": "18.2.7", "@angular/build": "18.2.10",
"@angular/compiler-cli": "18.2.6", "@angular/cli": "18.2.10",
"@angular/language-service": "18.2.6", "@angular/compiler-cli": "18.2.9",
"@ngtools/webpack": "18.2.7", "@angular/language-service": "18.2.9",
"@types/ace-diff": "^2.1.4", "@types/ace-diff": "^2.1.4",
"@types/canvas-gauges": "^2.1.8", "@types/canvas-gauges": "^2.1.8",
"@types/flot": "^0.0.36", "@types/flot": "^0.0.36",

43
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;*/
}
},
};

14
ui-ngx/patches/jquery.terminal+2.43.1.patch

File diff suppressed because one or more lines are too long

8
ui-ngx/src/app/core/utils.ts

@ -894,3 +894,11 @@ export const camelCase = (str: string): string => {
export const convertKeysToCamelCase = (obj: Record<string, any>): Record<string, any> => { export const convertKeysToCamelCase = (obj: Record<string, any>): Record<string, any> => {
return _.mapKeys(obj, (value, key) => _.camelCase(key)); 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;
}
};

2
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 coercion from '@shared/decorators/coercion';
import * as enumerable from '@shared/decorators/enumerable'; 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 FooterComponent from '@shared/components/footer.component';
import * as LogoComponent from '@shared/components/logo.component'; import * as LogoComponent from '@shared/components/logo.component';
@ -432,7 +431,6 @@ class ModulesMap implements IModulesMap {
'@shared/decorators/coercion': coercion, '@shared/decorators/coercion': coercion,
'@shared/decorators/enumerable': enumerable, '@shared/decorators/enumerable': enumerable,
'@shared/decorators/tb-inject': TbInject,
'@shared/import-export/import-export.service': ImportExportService, '@shared/import-export/import-export.service': ImportExportService,
'@shared/import-export/import-dialog.component': ImportDialogComponent, '@shared/import-export/import-dialog.component': ImportDialogComponent,

2
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(); this.popoverComponent.updatePosition();
} }
setTimeout(() => { setTimeout(() => {
this.differ = new aceDiff.default( this.differ = new aceDiff(
{ {
element: this.diffViewerElmRef.nativeElement, element: this.diffViewerElmRef.nativeElement,
mode: 'ace/mode/json', mode: 'ace/mode/json',

20
ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.component.ts

@ -15,16 +15,13 @@
/// ///
import { MatDialogRef } from '@angular/material/dialog'; import { MatDialogRef } from '@angular/material/dialog';
import { Directive, InjectionToken } from '@angular/core'; import { Directive, inject, InjectionToken } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { PageComponent } from '@shared/components/page.component'; import { PageComponent } from '@shared/components/page.component';
import { CustomDialogContainerComponent } from './custom-dialog-container.component'; import { CustomDialogContainerComponent } from './custom-dialog-container.component';
import { UntypedFormBuilder, Validators } from '@angular/forms'; import { UntypedFormBuilder, Validators } from '@angular/forms';
import { TbInject } from '@shared/decorators/tb-inject';
export const CUSTOM_DIALOG_DATA = new InjectionToken<any>('ConfigDialogData'); export const CUSTOM_DIALOG_DATA = new InjectionToken<CustomDialogData>('ConfigDialogData');
export interface CustomDialogData { export interface CustomDialogData {
controller: (instance: CustomDialogComponent) => void; controller: (instance: CustomDialogComponent) => void;
@ -37,12 +34,13 @@ export class CustomDialogComponent extends PageComponent {
[key: string]: any; [key: string]: any;
constructor(@TbInject(Store) protected store: Store<AppState>, protected router = inject(Router);
@TbInject(Router) protected router: Router, public dialogRef = inject(MatDialogRef<CustomDialogContainerComponent>);
@TbInject(MatDialogRef) public dialogRef: MatDialogRef<CustomDialogContainerComponent>, public data = inject(CUSTOM_DIALOG_DATA);
@TbInject(UntypedFormBuilder) public fb: UntypedFormBuilder, public fb = inject(UntypedFormBuilder);
@TbInject(CUSTOM_DIALOG_DATA) public data: CustomDialogData) {
super(store); constructor() {
super();
// @ts-ignore // @ts-ignore
this.validators = Validators; this.validators = Validators;
this.data.controller(this); this.data.controller(this);

77
ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts

@ -15,10 +15,13 @@
/// ///
import { PageComponent } from '@shared/components/page.component'; import { PageComponent } from '@shared/components/page.component';
import { Directive, Injector, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { Directive, inject, Injector, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store'; import {
import { AppState } from '@core/core.state'; IDynamicWidgetComponent,
import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models'; widgetContextToken,
widgetErrorMessagesToken,
widgetTitlePanelToken
} from '@home/models/widget-component.models';
import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { RafService } from '@core/services/raf.service'; import { RafService } from '@core/services/raf.service';
import { import {
@ -45,7 +48,6 @@ import { DatePipe } from '@angular/common';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TbInject } from '@shared/decorators/tb-inject';
import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe'; import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe';
import { UserSettingsService } from '@core/http/user-settings.service'; import { UserSettingsService } from '@core/http/user-settings.service';
import { ImagePipe } from '@shared/pipe/image.pipe'; import { ImagePipe } from '@shared/pipe/image.pipe';
@ -64,38 +66,39 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid
validators = Validators; validators = Validators;
constructor(@TbInject(RafService) public raf: RafService, public raf = inject(RafService);
@TbInject(Store) protected store: Store<AppState>, public fb = inject(UntypedFormBuilder);
@TbInject(UntypedFormBuilder) public fb: UntypedFormBuilder, public readonly $injector = inject(Injector);
@TbInject(Injector) public readonly $injector: Injector, public readonly ctx = inject(widgetContextToken);
@TbInject('widgetContext') public readonly ctx: WidgetContext, public readonly errorMessages = inject(widgetErrorMessagesToken);
@TbInject('errorMessages') public readonly errorMessages: string[], public readonly widgetTitlePanel = inject(widgetTitlePanelToken);
@TbInject('widgetTitlePanel') public readonly widgetTitlePanel: TemplateRef<any>) {
super(store); constructor() {
this.ctx.$injector = $injector; super();
this.ctx.deviceService = $injector.get(DeviceService); this.ctx.$injector = this.$injector;
this.ctx.assetService = $injector.get(AssetService); this.ctx.deviceService = this.$injector.get(DeviceService);
this.ctx.entityViewService = $injector.get(EntityViewService); this.ctx.assetService = this.$injector.get(AssetService);
this.ctx.customerService = $injector.get(CustomerService); this.ctx.entityViewService = this.$injector.get(EntityViewService);
this.ctx.dashboardService = $injector.get(DashboardService); this.ctx.customerService = this.$injector.get(CustomerService);
this.ctx.userService = $injector.get(UserService); this.ctx.dashboardService = this.$injector.get(DashboardService);
this.ctx.attributeService = $injector.get(AttributeService); this.ctx.userService = this.$injector.get(UserService);
this.ctx.entityRelationService = $injector.get(EntityRelationService); this.ctx.attributeService = this.$injector.get(AttributeService);
this.ctx.entityService = $injector.get(EntityService); this.ctx.entityRelationService = this.$injector.get(EntityRelationService);
this.ctx.authService = $injector.get(AuthService); this.ctx.entityService = this.$injector.get(EntityService);
this.ctx.dialogs = $injector.get(DialogService); this.ctx.authService = this.$injector.get(AuthService);
this.ctx.customDialog = $injector.get(CustomDialogService); this.ctx.dialogs = this.$injector.get(DialogService);
this.ctx.resourceService = $injector.get(ResourceService); this.ctx.customDialog = this.$injector.get(CustomDialogService);
this.ctx.userSettingsService = $injector.get(UserSettingsService); this.ctx.resourceService = this.$injector.get(ResourceService);
this.ctx.utilsService = $injector.get(UtilsService); this.ctx.userSettingsService = this.$injector.get(UserSettingsService);
this.ctx.telemetryWsService = $injector.get(TelemetryWebsocketService); this.ctx.utilsService = this.$injector.get(UtilsService);
this.ctx.date = $injector.get(DatePipe); this.ctx.telemetryWsService = this.$injector.get(TelemetryWebsocketService);
this.ctx.imagePipe = $injector.get(ImagePipe); this.ctx.date = this.$injector.get(DatePipe);
this.ctx.milliSecondsToTimeString = $injector.get(MillisecondsToTimeStringPipe); this.ctx.imagePipe = this.$injector.get(ImagePipe);
this.ctx.translate = $injector.get(TranslateService); this.ctx.milliSecondsToTimeString = this.$injector.get(MillisecondsToTimeStringPipe);
this.ctx.http = $injector.get(HttpClient); this.ctx.translate = this.$injector.get(TranslateService);
this.ctx.sanitizer = $injector.get(DomSanitizer); this.ctx.http = this.$injector.get(HttpClient);
this.ctx.router = $injector.get(Router); this.ctx.sanitizer = this.$injector.get(DomSanitizer);
this.ctx.router = this.$injector.get(Router);
this.ctx.$scope = this; this.ctx.$scope = this;
if (this.ctx.defaultSubscription) { if (this.ctx.defaultSubscription) {

4
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 { UtilsService } from '@core/services/utils.service';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { MINUTE } from '@shared/models/time/time.models'; 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 { backgroundStyle, ComponentStyle, overlayStyle } from '@shared/models/widget-settings.models';
import { ImagePipe } from '@shared/pipe/image.pipe'; import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
@ -157,7 +157,7 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI
private updateQRCode(link: string) { private updateQRCode(link: string) {
import('qrcode').then((QRCode) => { import('qrcode').then((QRCode) => {
QRCode.toString(link, (err, string) => { unwrapModule(QRCode).toString(link, (err, string) => {
this.qrCodeSVG = string; this.qrCodeSVG = string;
this.cd.markForCheck(); this.cd.markForCheck();
}) })

4
ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts

@ -28,7 +28,7 @@ import {
isNumber, isNumber,
isObject, isObject,
parseFunction, parseFunction,
safeExecute safeExecute, unwrapModule
} from '@core/utils'; } from '@core/utils';
interface QrCodeWidgetSettings { interface QrCodeWidgetSettings {
@ -124,7 +124,7 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte
private updateCanvas() { private updateCanvas() {
if (this.viewInited) { if (this.viewInited) {
import('qrcode').then((QRCode) => { 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.width = 'auto';
this.canvasRef.nativeElement.style.height = 'auto'; this.canvasRef.nativeElement.style.height = 'auto';
}); });

6
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 { entityIdHref, entityTypeHref, serviceCompletions } from '@shared/models/ace/service-completion.models';
import { CustomActionDescriptor, WidgetAction } from '@shared/models/widget.models'; import { CustomActionDescriptor, WidgetAction } from '@shared/models/widget.models';
import { deepClone, isDefined, isUndefined } from '@core/utils'; import { deepClone, isDefined, isUndefined } from '@core/utils';
import customSampleJs from '!raw-loader!./custom-sample-js.raw'; import customSampleJs from './custom-sample-js.raw';
import customSampleCss from '!raw-loader!./custom-sample-css.raw'; import customSampleCss from './custom-sample-css.raw';
import customSampleHtml from '!raw-loader!./custom-sample-html.raw'; import customSampleHtml from './custom-sample-html.raw';
const customActionCompletions: TbEditorCompletions = { const customActionCompletions: TbEditorCompletions = {
...{ ...{

15
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 { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
defaultGoogleMapProviderSettings,
defaultHereMapProviderSettings,
defaultImageMapProviderSettings,
defaultOpenStreetMapProviderSettings, defaultTencentMapProviderSettings,
GoogleMapProviderSettings, GoogleMapProviderSettings,
HereMapProviderSettings, HereMapProviderSettings,
ImageMapProviderSettings, ImageMapProviderSettings,
@ -39,7 +43,6 @@ import {
TencentMapProviderSettings TencentMapProviderSettings
} from '@home/components/widget/lib/maps/map-models'; } from '@home/components/widget/lib/maps/map-models';
import { extractType } from '@core/utils'; import { extractType } from '@core/utils';
import { keys } from 'ts-transformer-keys';
import { IAliasController } from '@core/api/widget-api.models'; import { IAliasController } from '@core/api/widget-api.models';
@Component({ @Component({
@ -128,11 +131,11 @@ export class MapProviderSettingsComponent extends PageComponent implements OnIni
writeValue(value: MapProviderSettings): void { writeValue(value: MapProviderSettings): void {
this.modelValue = value; this.modelValue = value;
const provider = value?.provider; const provider = value?.provider;
const googleProviderSettings = extractType<GoogleMapProviderSettings>(value, keys<GoogleMapProviderSettings>()); const googleProviderSettings = extractType<GoogleMapProviderSettings>(value, Object.keys(defaultGoogleMapProviderSettings) as (keyof GoogleMapProviderSettings)[]);
const openstreetProviderSettings = extractType<OpenStreetMapProviderSettings>(value, keys<OpenStreetMapProviderSettings>()); const openstreetProviderSettings = extractType<OpenStreetMapProviderSettings>(value, Object.keys(defaultOpenStreetMapProviderSettings) as (keyof OpenStreetMapProviderSettings)[]);
const hereProviderSettings = extractType<HereMapProviderSettings>(value, keys<HereMapProviderSettings>()); const hereProviderSettings = extractType<HereMapProviderSettings>(value, Object.keys(defaultHereMapProviderSettings) as (keyof HereMapProviderSettings)[]);
const imageMapProviderSettings = extractType<ImageMapProviderSettings>(value, keys<ImageMapProviderSettings>()); const imageMapProviderSettings = extractType<ImageMapProviderSettings>(value, Object.keys(defaultImageMapProviderSettings) as (keyof ImageMapProviderSettings)[]);
const tencentMapProviderSettings = extractType<TencentMapProviderSettings>(value, keys<TencentMapProviderSettings>()); const tencentMapProviderSettings = extractType<TencentMapProviderSettings>(value, Object.keys(defaultTencentMapProviderSettings) as (keyof TencentMapProviderSettings)[]);
this.providerSettingsFormGroup.patchValue( this.providerSettingsFormGroup.patchValue(
{ {
provider, provider,

26
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 { Component, forwardRef, Input, OnInit } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormBuilder, UntypedFormBuilder,
UntypedFormControl, UntypedFormControl,
UntypedFormGroup, UntypedFormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator Validator
} from '@angular/forms'; } from '@angular/forms';
import { PageComponent } from '@shared/components/page.component'; import { PageComponent } from '@shared/components/page.component';
@ -31,6 +31,13 @@ import { TranslateService } from '@ngx-translate/core';
import { import {
CircleSettings, CircleSettings,
CommonMapSettings, CommonMapSettings,
defaultCircleSettings,
defaultCommonMapSettings,
defaultMapEditorSettings,
defaultMapProviderSettings,
defaultMarkerClusteringSettings,
defaultMarkersSettings,
defaultPolygonSettings,
MapEditorSettings, MapEditorSettings,
MapProviders, MapProviders,
MapProviderSettings, MapProviderSettings,
@ -41,7 +48,6 @@ import {
UnitedMapSettings UnitedMapSettings
} from '@home/components/widget/lib/maps/map-models'; } from '@home/components/widget/lib/maps/map-models';
import { extractType } from '@core/utils'; import { extractType } from '@core/utils';
import { keys } from 'ts-transformer-keys';
import { IAliasController } from '@core/api/widget-api.models'; import { IAliasController } from '@core/api/widget-api.models';
import { Widget } from '@shared/models/widget.models'; import { Widget } from '@shared/models/widget.models';
@ -140,12 +146,12 @@ export class MapSettingsComponent extends PageComponent implements OnInit, Contr
writeValue(value: UnitedMapSettings): void { writeValue(value: UnitedMapSettings): void {
this.modelValue = value; this.modelValue = value;
const mapProviderSettings = extractType<MapProviderSettings>(value, keys<MapProviderSettings>()); const mapProviderSettings = extractType<MapProviderSettings>(value, Object.keys(defaultMapProviderSettings) as (keyof MapProviderSettings)[]);
const commonMapSettings = extractType<CommonMapSettings>(value, keys<CommonMapSettings>()); const commonMapSettings = extractType<CommonMapSettings>(value, Object.keys(defaultCommonMapSettings) as (keyof CommonMapSettings)[]);
const markersSettings = extractType<MarkersSettings>(value, keys<MarkersSettings>()); const markersSettings = extractType<MarkersSettings>(value, Object.keys(defaultMarkersSettings) as (keyof MarkersSettings)[]);
const polygonSettings = extractType<PolygonSettings>(value, keys<PolygonSettings>()); const polygonSettings = extractType<PolygonSettings>(value, Object.keys(defaultPolygonSettings) as (keyof PolygonSettings)[]);
const circleSettings = extractType<CircleSettings>(value, keys<CircleSettings>()); const circleSettings = extractType<CircleSettings>(value, Object.keys(defaultCircleSettings) as (keyof CircleSettings)[]);
const mapEditorSettings = extractType<MapEditorSettings>(value, keys<MapEditorSettings>()); const mapEditorSettings = extractType<MapEditorSettings>(value, Object.keys(defaultMapEditorSettings) as (keyof MapEditorSettings)[]);
const formValue = { const formValue = {
mapProviderSettings, mapProviderSettings,
commonMapSettings, commonMapSettings,
@ -157,7 +163,7 @@ export class MapSettingsComponent extends PageComponent implements OnInit, Contr
if (this.routeMap) { if (this.routeMap) {
formValue.routeMapSettings = extractType<PolylineSettings>(value, ['strokeWeight', 'strokeOpacity']); formValue.routeMapSettings = extractType<PolylineSettings>(value, ['strokeWeight', 'strokeOpacity']);
} else { } else {
formValue.markerClusteringSettings = extractType<MarkerClusteringSettings>(value, keys<MarkerClusteringSettings>()); formValue.markerClusteringSettings = extractType<MarkerClusteringSettings>(value, Object.keys(defaultMarkerClusteringSettings) as (keyof MarkerClusteringSettings)[]);
} }
this.mapSettingsFormGroup.patchValue( formValue, {emitEvent: false} ); this.mapSettingsFormGroup.patchValue( formValue, {emitEvent: false} );
this.updateValidators(false); this.updateValidators(false);

28
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 { AppState } from '@core/core.state';
import { import {
CircleSettings, CircleSettings,
CommonMapSettings,
defaultCircleSettings,
defaultCommonMapSettings,
defaultMapProviderSettings,
defaultMarkersSettings,
defaultPolygonSettings,
defaultTripAnimationPathSettings,
defaultTripAnimationPointSettings,
defaultTripAnimationSettings, defaultTripAnimationSettings,
MapProviderSettings, MapProviderSettings,
MarkersSettings,
PointsSettings, PointsSettings,
PolygonSettings, PolygonSettings,
PolylineSettings, PolylineSettings
TripAnimationCommonSettings,
TripAnimationMarkerSettings
} from 'src/app/modules/home/components/widget/lib/maps/map-models'; } from 'src/app/modules/home/components/widget/lib/maps/map-models';
import { extractType } from '@core/utils'; import { extractType } from '@core/utils';
import { keys } from 'ts-transformer-keys';
@Component({ @Component({
selector: 'tb-trip-animation-widget-settings', selector: 'tb-trip-animation-widget-settings',
@ -69,13 +75,13 @@ export class TripAnimationWidgetSettingsComponent extends WidgetSettingsComponen
} }
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
const mapProviderSettings = extractType<MapProviderSettings>(settings, keys<MapProviderSettings>()); const mapProviderSettings = extractType<MapProviderSettings>(settings, Object.keys(defaultMapProviderSettings) as (keyof MapProviderSettings)[]);
const commonMapSettings = extractType<TripAnimationCommonSettings>(settings, keys<TripAnimationCommonSettings>()); const commonMapSettings = extractType<CommonMapSettings>(settings, Object.keys(defaultCommonMapSettings) as (keyof CommonMapSettings)[]);
const markersSettings = extractType<TripAnimationMarkerSettings>(settings, keys<TripAnimationMarkerSettings>()); const markersSettings = extractType<MarkersSettings>(settings, Object.keys(defaultMarkersSettings) as (keyof MarkersSettings)[]);
const pathSettings = extractType<PolylineSettings>(settings, keys<PolylineSettings>()); const pathSettings = extractType<PolylineSettings>(settings, Object.keys(defaultTripAnimationPathSettings) as (keyof PolylineSettings)[]);
const pointSettings = extractType<PointsSettings>(settings, keys<PointsSettings>()); const pointSettings = extractType<PointsSettings>(settings, Object.keys(defaultTripAnimationPointSettings) as (keyof PointsSettings)[]);
const polygonSettings = extractType<PolygonSettings>(settings, keys<PolygonSettings>()); const polygonSettings = extractType<PolygonSettings>(settings, Object.keys(defaultPolygonSettings) as (keyof PolygonSettings)[]);
const circleSettings = extractType<CircleSettings>(settings, keys<CircleSettings>()); const circleSettings = extractType<CircleSettings>(settings, Object.keys(defaultCircleSettings) as (keyof CircleSettings)[]);
return { return {
mapProviderSettings, mapProviderSettings,
commonMapSettings, commonMapSettings,

8
ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts

@ -129,11 +129,13 @@ export class WidgetComponentService {
w.tinycolor = tinycolor; w.tinycolor = tinycolor;
w.cssjs = cssjs; w.cssjs = cssjs;
w.moment = moment; w.moment = moment;
w.$ = $;
w.jQuery = $;
const widgetModulesTasks: Observable<any>[] = []; const widgetModulesTasks: Observable<any>[] = [];
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( widgetModulesTasks.push(from(import('flot/src/jquery.flot.js')).pipe(
mergeMap(() => { mergeMap(() => {

10
ui-ngx/src/app/modules/home/components/widget/widget.component.ts

@ -70,9 +70,9 @@ import {
IDynamicWidgetComponent, IDynamicWidgetComponent,
ShowWidgetHeaderActionFunction, ShowWidgetHeaderActionFunction,
updateEntityParams, updateEntityParams,
WidgetContext, WidgetContext, widgetContextToken, widgetErrorMessagesToken,
WidgetHeaderAction, WidgetHeaderAction,
WidgetInfo, WidgetInfo, widgetTitlePanelToken,
WidgetTypeInstance WidgetTypeInstance
} from '@home/models/widget-component.models'; } from '@home/models/widget-component.models';
import { import {
@ -743,15 +743,15 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges,
{ {
providers: [ providers: [
{ {
provide: 'widgetContext', provide: widgetContextToken,
useValue: this.widgetContext useValue: this.widgetContext
}, },
{ {
provide: 'errorMessages', provide: widgetErrorMessagesToken,
useValue: this.errorMessages useValue: this.errorMessages
}, },
{ {
provide: 'widgetTitlePanel', provide: widgetTitlePanelToken,
useValue: this.widgetTitlePanel useValue: this.widgetTitlePanel
} }
], ],

6
ui-ngx/src/app/modules/home/models/widget-component.models.ts

@ -47,7 +47,7 @@ import {
WidgetActionsApi, WidgetActionsApi,
WidgetSubscriptionApi WidgetSubscriptionApi
} from '@core/api/widget-api.models'; } 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 { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { RafService } from '@core/services/raf.service'; import { RafService } from '@core/services/raf.service';
import { WidgetTypeId } from '@shared/models/id/widget-type-id'; import { WidgetTypeId } from '@shared/models/id/widget-type-id';
@ -538,6 +538,10 @@ export class LabelVariablePattern {
} }
} }
export const widgetContextToken = new InjectionToken<WidgetContext>('widgetContext');
export const widgetErrorMessagesToken = new InjectionToken<string[]>('errorMessages');
export const widgetTitlePanelToken = new InjectionToken<TemplateRef<any>>('widgetTitlePanel');
export interface IDynamicWidgetComponent { export interface IDynamicWidgetComponent {
readonly ctx: WidgetContext; readonly ctx: WidgetContext;
readonly errorMessages: string[]; readonly errorMessages: string[];

2
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 { ImportExportService } from '@shared/import-export/import-export.service';
import { deepClone } from '@core/utils'; import { deepClone } from '@core/utils';
import printTemplate from '!raw-loader!./backup-code-print-template.raw'; import printTemplate from './backup-code-print-template.raw';
@Component({ @Component({
selector: 'tb-backup-code-auth-dialog', selector: 'tb-backup-code-auth-dialog',

3
ui-ngx/src/app/modules/home/pages/security/authentication-dialog/totp-auth-dialog.component.ts

@ -28,6 +28,7 @@ import {
TwoFactorAuthProviderType TwoFactorAuthProviderType
} from '@shared/models/two-factor-auth.models'; } from '@shared/models/two-factor-auth.models';
import { MatStepper } from '@angular/material/stepper'; import { MatStepper } from '@angular/material/stepper';
import { unwrapModule } from '@core/utils';
@Component({ @Component({
selector: 'tb-totp-auth-dialog', selector: 'tb-totp-auth-dialog',
@ -56,7 +57,7 @@ export class TotpAuthDialogComponent extends DialogComponent<TotpAuthDialogCompo
this.totpAuthURL = this.authAccountConfig.authUrl; this.totpAuthURL = this.authAccountConfig.authUrl;
this.authAccountConfig.useByDefault = true; this.authAccountConfig.useByDefault = true;
import('qrcode').then((QRCode) => { import('qrcode').then((QRCode) => {
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.width = 'auto';
this.canvasRef.nativeElement.style.height = 'auto'; this.canvasRef.nativeElement.style.height = 'auto';
}); });

8
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 { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; 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 { JsonFormProps } from './react/json-form.models';
import inspector from 'schema-inspector'; import inspector from 'schema-inspector';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
@ -270,9 +270,9 @@ export class JsonFormComponent implements ControlValueAccessor, Validator, OnCha
]; ];
forkJoin(reactSchemaFormObservables).subscribe( forkJoin(reactSchemaFormObservables).subscribe(
(modules) => { (modules) => {
const react = modules[0]; const react = unwrapModule(modules[0]);
const reactDomClient = modules[2]; const reactDomClient = unwrapModule(modules[2]);
const jsonFormReact = modules[3].default; const jsonFormReact = unwrapModule(modules[3]);
this.reactRoot = reactDomClient.createRoot(this.reactRootElmRef.nativeElement); this.reactRoot = reactDomClient.createRoot(this.reactRootElmRef.nativeElement);
this.reactRoot.render(react.createElement(jsonFormReact, this.formProps)); this.reactRoot.render(react.createElement(jsonFormReact, this.formProps));
} }

7
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 Button from '@mui/material/Button';
import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models';
import { IEditorProps } from 'react-ace/src/types'; 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 { getAce } from '@shared/models/ace/ace.models';
import { from, lastValueFrom } from 'rxjs'; import { from, lastValueFrom } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { CircularProgress, IconButton } from '@mui/material'; import { CircularProgress, IconButton } from '@mui/material';
import { MouseEvent } from 'react'; import { MouseEvent } from 'react';
import { Help, HelpOutline } from '@mui/icons-material'; import { Help, HelpOutline } from '@mui/icons-material';
import { unwrapModule } from '@core/utils';
const ReactAce = React.lazy(() => { const ReactAce = React.lazy(() => {
return lastValueFrom(getAce().pipe( return lastValueFrom(getAce().pipe(
mergeMap(() => { mergeMap(() => {
return from(import('react-ace')); return from(import('react-ace')).pipe(
map((module) => unwrapModule(module)
));
}) })
)); ));
}); });

7
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<JsonFormProps, any> { class ThingsboardSchemaForm extends React.Component<JsonFormProps, any> {
private hasConditions: boolean; private hasConditions: boolean;
private conditionFunction: Function;
private readonly mapper: {[type: string]: any}; private readonly mapper: {[type: string]: any};
constructor(props: JsonFormProps) { constructor(props: JsonFormProps) {
@ -130,8 +131,10 @@ class ThingsboardSchemaForm extends React.Component<JsonFormProps, any> {
} }
if (form.condition) { if (form.condition) {
this.hasConditions = true; this.hasConditions = true;
// tslint:disable-next-line:no-eval if (!this.conditionFunction) {
if (eval(form.condition) === false) { this.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`);
}
if (this.conditionFunction(form, model, index) === false) {
return null; return null;
} }
} }

6
ui-ngx/src/app/shared/components/page.component.ts

@ -14,7 +14,7 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Directive, OnDestroy } from '@angular/core'; import { Directive, inject, OnDestroy } from '@angular/core';
import { select, Store } from '@ngrx/store'; import { select, Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
@ -25,13 +25,15 @@ import { AbstractControl } from '@angular/forms';
@Directive() @Directive()
export abstract class PageComponent implements OnDestroy { export abstract class PageComponent implements OnDestroy {
protected store: Store<AppState> = inject(Store<AppState>);
isLoading$: Observable<boolean>; isLoading$: Observable<boolean>;
loadingSubscription: Subscription; loadingSubscription: Subscription;
disabledOnLoadFormControls: Array<AbstractControl> = []; disabledOnLoadFormControls: Array<AbstractControl> = [];
showMainLoadingBar = true; showMainLoadingBar = true;
protected constructor(protected store: Store<AppState>) { protected constructor(...args: unknown[]) {
this.isLoading$ = this.store.pipe(delay(0), select(selectIsLoading), share()); this.isLoading$ = this.store.pipe(delay(0), select(selectIsLoading), share());
} }

1
ui-ngx/src/app/shared/decorators/public-api.ts

@ -16,4 +16,3 @@
export * from './coercion'; export * from './coercion';
export * from './enumerable'; export * from './enumerable';
export * from './tb-inject';

23
ui-ngx/src/app/shared/decorators/tb-inject.ts

@ -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<T>(token: any): (target: Type<T>, key: any, paramIndex: number) => void {
return (target: Type<T>, key: any, paramIndex: number) => {
Inject(token)(target, key, paramIndex);
};
}

9
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 { Observable } from 'rxjs/internal/Observable';
import { forkJoin, from, of } from 'rxjs'; import { forkJoin, from, of } from 'rxjs';
import { map, mergeMap, tap } from 'rxjs/operators'; import { map, mergeMap, tap } from 'rxjs/operators';
import { unwrapModule } from '@core/utils';
let aceDependenciesLoaded = false; let aceDependenciesLoaded = false;
let aceModule: any; let aceModule: any;
@ -67,10 +68,10 @@ export function getAce(): Observable<any> {
if (aceModule) { if (aceModule) {
return of(aceModule); return of(aceModule);
} else { } else {
return from(import('ace')).pipe( return from(import('ace-builds/src-noconflict/ace')).pipe(
mergeMap((module) => { mergeMap((module) => {
return loadAceDependencies().pipe( return loadAceDependencies().pipe(
map(() => module) map(() => unwrapModule(module))
); );
}), }),
tap((module) => { tap((module) => {
@ -86,7 +87,9 @@ export function getAceDiff(): Observable<any> {
} else { } else {
return getAce().pipe( return getAce().pipe(
mergeMap((ace) => { mergeMap((ace) => {
return from(import('ace-diff')); return from(import('ace-diff')).pipe(
map((module) => unwrapModule(module))
);
}), }),
tap((module) => { tap((module) => {
aceDiffModule = module; aceDiffModule = module;

4
ui-ngx/src/app/shared/models/beautify.models.ts

@ -17,6 +17,7 @@
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { from, of } from 'rxjs'; import { from, of } from 'rxjs';
import { map, tap } from 'rxjs/operators'; import { map, tap } from 'rxjs/operators';
import { unwrapModule } from '@core/utils';
let jsBeautifyModule: any; let jsBeautifyModule: any;
let htmlBeautifyModule: any; let htmlBeautifyModule: any;
@ -27,6 +28,7 @@ function loadJsBeautify(): Observable<any> {
return of(jsBeautifyModule); return of(jsBeautifyModule);
} else { } else {
return from(import('js-beautify/js/lib/beautify.js')).pipe( return from(import('js-beautify/js/lib/beautify.js')).pipe(
map((module) => unwrapModule(module)),
tap((module) => { tap((module) => {
jsBeautifyModule = module; jsBeautifyModule = module;
}) })
@ -39,6 +41,7 @@ function loadHtmlBeautify(): Observable<any> {
return of(htmlBeautifyModule); return of(htmlBeautifyModule);
} else { } else {
return from(import('js-beautify/js/lib/beautify-html.js')).pipe( return from(import('js-beautify/js/lib/beautify-html.js')).pipe(
map((module) => unwrapModule(module)),
tap((module) => { tap((module) => {
htmlBeautifyModule = module; htmlBeautifyModule = module;
}) })
@ -51,6 +54,7 @@ function loadCssBeautify(): Observable<any> {
return of(cssBeautifyModule); return of(cssBeautifyModule);
} else { } else {
return from(import('js-beautify/js/lib/beautify-css.js')).pipe( return from(import('js-beautify/js/lib/beautify-css.js')).pipe(
map((module) => unwrapModule(module)),
tap((module) => { tap((module) => {
cssBeautifyModule = module; cssBeautifyModule = module;
}) })

5
ui-ngx/src/main.ts

@ -22,6 +22,11 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from '@app/app.module'; import { AppModule } from '@app/app.module';
import { environment } from '@env/environment'; import { environment } from '@env/environment';
import $ from 'jquery';
(window as any).jQuery = $;
(window as any).$ = $;
if (environment.production) { if (environment.production) {
enableProdMode(); enableProdMode();
} }

4
ui-ngx/src/styles.scss

@ -15,8 +15,8 @@
*/ */
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@import '~typeface-roboto/index.css'; @import 'typeface-roboto/index.css';
@import '~font-awesome/css/font-awesome.min.css'; @import 'font-awesome/css/font-awesome.min.css';
@import 'theme.scss'; @import 'theme.scss';
@import './scss/constants'; @import './scss/constants';
@import './scss/animations'; @import './scss/animations';

4
ui-ngx/src/tsconfig.app.json

@ -6,7 +6,9 @@
"react", "react-dom", "raphael", "canvas-gauges", "systemjs"] "react", "react-dom", "raphael", "canvas-gauges", "systemjs"]
}, },
"angularCompilerOptions": { "angularCompilerOptions": {
"fullTemplateTypeCheck": true "fullTemplateTypeCheck": true,
"supportTestBed": true,
"supportJitMode": true
}, },
"files": [ "files": [
"main.ts", "main.ts",

6
ui-ngx/src/typings/rawloader.typings.d.ts

@ -14,7 +14,7 @@
/// limitations under the License. /// limitations under the License.
/// ///
declare module '!raw-loader!*' { declare module '*.raw' {
const contents: string; const content: string;
export = contents; export default content;
} }

1
ui-ngx/tsconfig.json

@ -15,6 +15,7 @@
"module": "es2020", "module": "es2020",
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"jsx": "react", "jsx": "react",
"resolveJsonModule": true,
"typeRoots": [ "typeRoots": [
"node_modules/@types", "node_modules/@types",
"src/typings" "src/typings"

189
ui-ngx/yarn.lock

@ -24,36 +24,34 @@
ts-node "^10.0.0" ts-node "^10.0.0"
tsconfig-paths "^4.1.0" tsconfig-paths "^4.1.0"
"@angular-builders/custom-webpack@~18.0.0": "@angular-builders/custom-esbuild@18.0.0":
version "18.0.0" version "18.0.0"
resolved "https://registry.yarnpkg.com/@angular-builders/custom-webpack/-/custom-webpack-18.0.0.tgz#b51f8b03d6fff4955f63cbe9e090e0366acc90d2" resolved "https://registry.yarnpkg.com/@angular-builders/custom-esbuild/-/custom-esbuild-18.0.0.tgz#7da11ce47cfa0bbab1e5e07a9bdefb8a6afe8ed8"
integrity sha512-XSynPSXHq5+nrh7J2snfrcbvm6YGwUGQRzr7OuO3wURJ6CHOD9C+xEAmvEUWW8c1YjEslVNG7aLtCGz7LA4ymw== integrity sha512-SdAGatJMJJjPYrdkUupdRazid3xe1sIj/CAHDdDVP094vZ9CrZs6fgcsOF17waAo6uMxrQCWmPDrTjNgR3CvMQ==
dependencies: dependencies:
"@angular-builders/common" "2.0.0" "@angular-builders/common" "2.0.0"
"@angular-devkit/architect" ">=0.1800.0 < 0.1900.0" "@angular-devkit/architect" ">=0.1800.0 < 0.1900.0"
"@angular-devkit/build-angular" "^18.0.0" "@angular-devkit/build-angular" "^18.0.0"
"@angular-devkit/core" "^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": "@angular-devkit/architect@0.1802.10", "@angular-devkit/architect@>=0.1800.0 < 0.1900.0":
version "0.1802.7" version "0.1802.10"
resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1802.7.tgz#eb69e6b94473c3ca3428b71c5f31ee418724a8e5" resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1802.10.tgz#1ae877263261e33a86fb3a047c3741ab09a9c599"
integrity sha512-kpcgXnepEXcoxDTbqbGj7Hg1WJLWj1HLR3/FKmC5TbpBf1xiLxiqfkQNwz3BbE/W9JWMLdrXr3GI9O3O2gWPLg== integrity sha512-/xudcHK2s4J/GcL6qyobmGaWMHQcYLSMqCaWMT+nK6I6tu9VEAj/p3R83Tzx8B/eKi31Pz499uHw9pmqdtbafg==
dependencies: dependencies:
"@angular-devkit/core" "18.2.7" "@angular-devkit/core" "18.2.10"
rxjs "7.8.1" rxjs "7.8.1"
"@angular-devkit/build-angular@18.2.7", "@angular-devkit/build-angular@^18.0.0": "@angular-devkit/build-angular@18.2.10", "@angular-devkit/build-angular@^18.0.0":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-18.2.7.tgz#21b72596f270e4a5a16d38224b38e46a609aad80" resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-18.2.10.tgz#7eab5b31856f8d3ce02e89771e3966328d13268f"
integrity sha512-u8PriYdgddK7k+OS/pOFPD1v4Iu5bztUJZXZVcGeXBZFFdnGFFzKmQw9mfcyGvTMJp2ABgBuuJT0YqYgNfAhzw== integrity sha512-47XgJ5fdIqlZUFWAo/XtNsh3y597DtLZWvfsnwShw6/TgyiV0rbL1Z24Rn2TCV1D/b3VhLutAIIZ/i5O5BirxQ==
dependencies: dependencies:
"@ampproject/remapping" "2.3.0" "@ampproject/remapping" "2.3.0"
"@angular-devkit/architect" "0.1802.7" "@angular-devkit/architect" "0.1802.10"
"@angular-devkit/build-webpack" "0.1802.7" "@angular-devkit/build-webpack" "0.1802.10"
"@angular-devkit/core" "18.2.7" "@angular-devkit/core" "18.2.10"
"@angular/build" "18.2.7" "@angular/build" "18.2.10"
"@babel/core" "7.25.2" "@babel/core" "7.25.2"
"@babel/generator" "7.25.0" "@babel/generator" "7.25.0"
"@babel/helper-annotate-as-pure" "7.24.7" "@babel/helper-annotate-as-pure" "7.24.7"
@ -64,7 +62,7 @@
"@babel/preset-env" "7.25.3" "@babel/preset-env" "7.25.3"
"@babel/runtime" "7.25.0" "@babel/runtime" "7.25.0"
"@discoveryjs/json-ext" "0.6.1" "@discoveryjs/json-ext" "0.6.1"
"@ngtools/webpack" "18.2.7" "@ngtools/webpack" "18.2.10"
"@vitejs/plugin-basic-ssl" "1.1.0" "@vitejs/plugin-basic-ssl" "1.1.0"
ansi-colors "4.1.3" ansi-colors "4.1.3"
autoprefixer "10.4.20" autoprefixer "10.4.20"
@ -75,7 +73,7 @@
css-loader "7.1.2" css-loader "7.1.2"
esbuild-wasm "0.23.0" esbuild-wasm "0.23.0"
fast-glob "3.3.2" fast-glob "3.3.2"
http-proxy-middleware "3.0.0" http-proxy-middleware "3.0.3"
https-proxy-agent "7.0.5" https-proxy-agent "7.0.5"
istanbul-lib-instrument "6.0.3" istanbul-lib-instrument "6.0.3"
jsonc-parser "3.3.1" jsonc-parser "3.3.1"
@ -114,18 +112,18 @@
optionalDependencies: optionalDependencies:
esbuild "0.23.0" esbuild "0.23.0"
"@angular-devkit/build-webpack@0.1802.7": "@angular-devkit/build-webpack@0.1802.10":
version "0.1802.7" version "0.1802.10"
resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1802.7.tgz#07c64d2763b10bedacff29795b778c81e888ca2c" resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1802.10.tgz#cf55fd2bee8a7d86b91bfeb0c8af9c22957c6727"
integrity sha512-VrtbrhZ+dht3f0GjtfRLRGRN4XHN/W+/bA9DqckdxVS6SydsrCWNHonvEPmOs4jJmGIGXIu6tUBMcWleTao2sg== integrity sha512-WRftK/RJ9rBDDmkx5IAtIpyNo0DJiMfgGUTuZNpNUaJfSfGeaSZYgC7o1++axMchID8pncmI3Hr8L8gaP94WQg==
dependencies: dependencies:
"@angular-devkit/architect" "0.1802.7" "@angular-devkit/architect" "0.1802.10"
rxjs "7.8.1" rxjs "7.8.1"
"@angular-devkit/core@18.2.7", "@angular-devkit/core@^18.0.0": "@angular-devkit/core@18.2.10", "@angular-devkit/core@^18.0.0":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-18.2.7.tgz#f7133c9c50eb1916f8862370be975e4e2b84cca3" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-18.2.10.tgz#7565f0c7bf0fa3318d08c4a696e890ab0b670032"
integrity sha512-1ZTi4A6tEC2bkJ/puCIdIPYhesnlCVOMSDJL/lZAd0hC6X22T4pwu0AEvue7mcP5NbXpQDiBaXOZ3MmCA8PwOA== integrity sha512-LFqiNdraBujg8e1lhuB0bkFVAoIbVbeXXwfoeROKH60OPbP8tHdgV6sFTqU7UGBKA+b+bYye70KFTG2Ys8QzKQ==
dependencies: dependencies:
ajv "8.17.1" ajv "8.17.1"
ajv-formats "3.0.1" ajv-formats "3.0.1"
@ -134,12 +132,12 @@
rxjs "7.8.1" rxjs "7.8.1"
source-map "0.7.4" source-map "0.7.4"
"@angular-devkit/schematics@18.2.7": "@angular-devkit/schematics@18.2.10":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-18.2.7.tgz#348cb0d790720a66e8183d6876effc262571086c" resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-18.2.10.tgz#2ca7dde6f8c9062c3ef8254a12edeffdd180272e"
integrity sha512-j7198lpkOXMG+Gyfln/5aDgBZV7m4pWMzHFhkO3+w3cbCNUN1TVZW0SyJcF+CYaxANzTbuumfvpsYc/fTeAGLw== integrity sha512-EIm/yCYg3ZYPsPYJxXRX5F6PofJCbNQ5rZEuQEY09vy+ZRTqGezH0qoUP5WxlYeJrjiRLYqADI9WtVNzDyaD4w==
dependencies: dependencies:
"@angular-devkit/core" "18.2.7" "@angular-devkit/core" "18.2.10"
jsonc-parser "3.3.1" jsonc-parser "3.3.1"
magic-string "0.30.11" magic-string "0.30.11"
ora "5.4.1" ora "5.4.1"
@ -206,13 +204,13 @@
dependencies: dependencies:
tslib "^2.3.0" tslib "^2.3.0"
"@angular/build@18.2.7": "@angular/build@18.2.10":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@angular/build/-/build-18.2.7.tgz#3bdb7c18e8f3bee00c0ce12a48216ce2df15f87c" resolved "https://registry.yarnpkg.com/@angular/build/-/build-18.2.10.tgz#98eb7f1ced225483693280964482e617eba3eb1b"
integrity sha512-oq6JsVxLP9/w9F2IjKroJwPB9CdlMblu2Xhfq/qQZRSUuM8Ppt1svr2FBTo1HrLIbosqukkVcSSdmKYDneo+cg== integrity sha512-YFBKvAyC5sH17yRYcx7VHCtJ4KUg7xCjCQ4Pe16kiTvW6vuYsgU6Btyti0Qgewd7XaWpTM8hk8N6hE4Z0hpflw==
dependencies: dependencies:
"@ampproject/remapping" "2.3.0" "@ampproject/remapping" "2.3.0"
"@angular-devkit/architect" "0.1802.7" "@angular-devkit/architect" "0.1802.10"
"@babel/core" "7.25.2" "@babel/core" "7.25.2"
"@babel/helper-annotate-as-pure" "7.24.7" "@babel/helper-annotate-as-pure" "7.24.7"
"@babel/helper-split-export-declaration" "7.24.7" "@babel/helper-split-export-declaration" "7.24.7"
@ -246,17 +244,17 @@
optionalDependencies: optionalDependencies:
parse5 "^7.1.2" parse5 "^7.1.2"
"@angular/cli@18.2.7": "@angular/cli@18.2.10":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-18.2.7.tgz#b5fe23d6d9d65d37ba580f1860c8a09c7578bc69" resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-18.2.10.tgz#29ab1344bb496122b2689ebbb862f2b44fb31848"
integrity sha512-KoWgSvhRsU05A2m6B7jw1kdpyoS+Ce5GGLW6xcnX7VF2AckW54vYd/8ZkgpzQrKfvIpVblYd4KJGizKoaLZ5jA== integrity sha512-qW/F3XVZMzzenFzbn+7FGpw8GOt9qW8UxBtYya7gUNdWlcsgGUk+ZaGC2OLbfI5gX6pchW4TOPMsDSMeaCEI2Q==
dependencies: dependencies:
"@angular-devkit/architect" "0.1802.7" "@angular-devkit/architect" "0.1802.10"
"@angular-devkit/core" "18.2.7" "@angular-devkit/core" "18.2.10"
"@angular-devkit/schematics" "18.2.7" "@angular-devkit/schematics" "18.2.10"
"@inquirer/prompts" "5.3.8" "@inquirer/prompts" "5.3.8"
"@listr2/prompt-adapter-inquirer" "2.0.15" "@listr2/prompt-adapter-inquirer" "2.0.15"
"@schematics/angular" "18.2.7" "@schematics/angular" "18.2.10"
"@yarnpkg/lockfile" "1.1.0" "@yarnpkg/lockfile" "1.1.0"
ini "4.1.3" ini "4.1.3"
jsonc-parser "3.3.1" jsonc-parser "3.3.1"
@ -276,14 +274,14 @@
dependencies: dependencies:
tslib "^2.3.0" tslib "^2.3.0"
"@angular/compiler-cli@18.2.6": "@angular/compiler-cli@18.2.9":
version "18.2.6" version "18.2.9"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-18.2.6.tgz#84d94852ec5088107a9ffa81908b38c51c576bd5" resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-18.2.9.tgz#637f40e0fbb210ccd8d4ff464ddb6628ffa0fc46"
integrity sha512-b5x9STfjNiNM/S0D+CnqRP9UOxPtSz1+RlCH5WdOMiW/p8j5p6dBix8YYgTe6Wg3OD7eItD2pnFQKgF/dWiopA== integrity sha512-4iMoRvyMmq/fdI/4Gob9HKjL/jvTlCjbS4kouAYHuGO9w9dmUhi1pY1z+mALtCEl9/Q8CzU2W8e5cU2xtV4nVg==
dependencies: dependencies:
"@babel/core" "7.25.2" "@babel/core" "7.25.2"
"@jridgewell/sourcemap-codec" "^1.4.14" "@jridgewell/sourcemap-codec" "^1.4.14"
chokidar "^3.0.0" chokidar "^4.0.0"
convert-source-map "^1.5.1" convert-source-map "^1.5.1"
reflect-metadata "^0.2.0" reflect-metadata "^0.2.0"
semver "^7.0.0" semver "^7.0.0"
@ -318,10 +316,10 @@
dependencies: dependencies:
tslib "^2.3.0" tslib "^2.3.0"
"@angular/language-service@18.2.6": "@angular/language-service@18.2.9":
version "18.2.6" version "18.2.9"
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.6.tgz#c1cd36e40579b5bacaf0d666477c138577d2a6dd" resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.9.tgz#f24f5e7e53036f6c9c4968113a3ea9ea827048f7"
integrity sha512-GBvBvS2llh+/l2YhO7UO5o3GftlvQQoXnw3v0hcNoHKwcnvqXV4CCi+T2WOaZyK0iB8Is4QRbMrpJUC66HokZg== integrity sha512-vC9la5VpvfX27ept36rlc42nGxDak7YfbWtSoZUageyZJUWyIEAvW8rNNPEvoO86RLi011/HmyyIr2GSQLKvxA==
"@angular/material@18.2.6": "@angular/material@18.2.6":
version "18.2.6" version "18.2.6"
@ -2535,10 +2533,10 @@
dependencies: dependencies:
tslib "^2.0.0" tslib "^2.0.0"
"@ngtools/webpack@18.2.7": "@ngtools/webpack@18.2.10":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-18.2.7.tgz#2e8e7a3753ccdf49a3f350e082bdf79c7550db44" resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-18.2.10.tgz#6fd94d33a9de0b5f48f8b900a9d32e4f8c89872e"
integrity sha512-BmnFxss6zGobGyq9Mi7736golbK8RLgF+zYCQZ+4/OfMMA1jKVoELnyJqNyAx+DQn3m1qKVBjtGEL7pTNpPzOw== integrity sha512-CGYr8rdM5ntdb4kLUAhrLBPrhJQ4KBPo3KMT6qJE/S+jJJn5zHzedpuGFOCVhC1Siw+n1pOBSI8leTRJIW/eCQ==
"@ngx-translate/core@^15.0.0": "@ngx-translate/core@^15.0.0":
version "15.0.0" version "15.0.0"
@ -2855,13 +2853,13 @@
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
"@schematics/angular@18.2.7": "@schematics/angular@18.2.10":
version "18.2.7" version "18.2.10"
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-18.2.7.tgz#0b6caf0491618c2e9b24506cc68fb629845b6c6c" resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-18.2.10.tgz#8ef1e67d266c334e71bac38cdef4cefab141f244"
integrity sha512-WOBzO11qstznHbC9tZXQf6/8+PqmaRI6QYcdTspqXNh9q9nNglvi43Xn4tSIpEhW8aSHea9hgWZV8sG+i/4W9Q== integrity sha512-2pDHT4aSzfs8Up4RQmHHuFd5FeuUebS1ZJwyt46MfXzRMFtzUZV/JKsIvDqyMwnkvFfLvgJyTCkl8JGw5jQObg==
dependencies: dependencies:
"@angular-devkit/core" "18.2.7" "@angular-devkit/core" "18.2.10"
"@angular-devkit/schematics" "18.2.7" "@angular-devkit/schematics" "18.2.10"
jsonc-parser "3.3.1" jsonc-parser "3.3.1"
"@sigstore/bundle@^2.3.2": "@sigstore/bundle@^2.3.2":
@ -3273,7 +3271,7 @@
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== 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" version "1.17.15"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36"
integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==
@ -4354,7 +4352,7 @@ chevrotain@~11.0.3:
"@chevrotain/utils" "11.0.3" "@chevrotain/utils" "11.0.3"
lodash-es "4.17.21" 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" version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
@ -4369,6 +4367,13 @@ chevrotain@~11.0.3:
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" 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: chownr@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" 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" agent-base "^7.1.0"
debug "^4.3.4" debug "^4.3.4"
http-proxy-middleware@3.0.0: http-proxy-middleware@3.0.3:
version "3.0.0" version "3.0.3"
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz#550790357d6f92a9b82ab2d63e07343a791cf26b" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz#dc1313c75bd00d81e103823802551ee30130ebd1"
integrity sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw== integrity sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==
dependencies: dependencies:
"@types/http-proxy" "^1.17.10" "@types/http-proxy" "^1.17.15"
debug "^4.3.4" debug "^4.3.6"
http-proxy "^1.18.1" http-proxy "^1.18.1"
is-glob "^4.0.1" is-glob "^4.0.3"
is-plain-obj "^3.0.0" is-plain-object "^5.0.0"
micromatch "^4.0.5" micromatch "^4.0.8"
http-proxy-middleware@^2.0.3: http-proxy-middleware@^2.0.3:
version "2.0.6" version "2.0.6"
@ -6860,6 +6865,11 @@ is-plain-object@^2.0.4:
dependencies: dependencies:
isobject "^3.0.1" 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: is-regex@^1.1.4:
version "1.1.4" version "1.1.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" 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" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 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" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -7685,7 +7695,7 @@ methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== 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" version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
@ -9079,6 +9089,11 @@ readable-stream@^3.0.6, readable-stream@^3.4.0:
string_decoder "^1.1.1" string_decoder "^1.1.1"
util-deprecate "^1.0.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: readdirp@~3.6.0:
version "3.6.0" version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 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" v8-compile-cache-lib "^3.0.1"
yn "3.1.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: tsconfig-paths@^3.15.0:
version "3.15.0" version "3.15.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" 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" flat "^5.0.2"
wildcard "^2.0.1" 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: webpack-sources@^3.0.0, webpack-sources@^3.2.3:
version "3.2.3" version "3.2.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
@ -10780,7 +10781,7 @@ which@^4.0.0:
dependencies: dependencies:
isexe "^3.1.1" isexe "^3.1.1"
wildcard@^2.0.0, wildcard@^2.0.1: wildcard@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==

Loading…
Cancel
Save