Browse Source

Merge branch 'master' into lwm2m_M15

pull/11784/head
nick 2 years ago
parent
commit
fddffce58f
  1. 26
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  2. 133
      ui-ngx/.eslintrc.json
  3. 44
      ui-ngx/angular.json
  4. 43
      ui-ngx/e2e/protractor.conf.js
  5. 39
      ui-ngx/e2e/src/app.e2e-spec.ts
  6. 27
      ui-ngx/e2e/src/app.po.ts
  7. 13
      ui-ngx/e2e/tsconfig.e2e.json
  8. 2
      ui-ngx/extra-webpack.config.js
  9. 221
      ui-ngx/package.json
  10. 10
      ui-ngx/patches/@angular+core+18.2.6.patch
  11. 21
      ui-ngx/patches/@angular+flex-layout+15.0.0-beta.42.patch
  12. 51
      ui-ngx/patches/@mat-datetimepicker+core+11.0.3.patch
  13. 34
      ui-ngx/patches/@mat-datetimepicker+core+14.0.0.patch
  14. 28
      ui-ngx/patches/angular-gridster2+18.0.1.patch
  15. 2
      ui-ngx/pom.xml
  16. 1
      ui-ngx/src/app/core/api/widget-api.models.ts
  17. 140
      ui-ngx/src/app/core/core.module.ts
  18. 4
      ui-ngx/src/app/core/guards/auth.guard.ts
  19. 4
      ui-ngx/src/app/core/guards/confirm-on-exit.guard.ts
  20. 23
      ui-ngx/src/app/core/http/rule-chain.service.ts
  21. 10
      ui-ngx/src/app/core/interceptors/entity-conflict.interceptor.ts
  22. 10
      ui-ngx/src/app/core/services/dynamic-component-factory.service.ts
  23. 211
      ui-ngx/src/app/core/services/resources.service.ts
  24. 2
      ui-ngx/src/app/core/settings/settings.utils.ts
  25. 2
      ui-ngx/src/app/core/translate/translate-default-compiler.ts
  26. 8
      ui-ngx/src/app/modules/common/modules-map.ts
  27. 4
      ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts
  28. 4
      ui-ngx/src/app/modules/home/components/alarm/alarm-comment.component.scss
  29. 4
      ui-ngx/src/app/modules/home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component.scss
  30. 3
      ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts
  31. 9
      ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.service.ts
  32. 6
      ui-ngx/src/app/modules/home/components/entity/add-entity-dialog.component.ts
  33. 5
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts
  34. 5
      ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts
  35. 10
      ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts
  36. 2
      ui-ngx/src/app/modules/home/components/notification/notification-bell.component.html
  37. 19
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
  38. 14
      ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.ts
  39. 14
      ui-ngx/src/app/modules/home/components/profile/device-profile-dialog.component.ts
  40. 14
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.ts
  41. 2
      ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts
  42. 16
      ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts
  43. 14
      ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts
  44. 10
      ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.ts
  45. 8
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts
  46. 1
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
  47. 2
      ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts
  48. 2
      ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.models.ts
  49. 2
      ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts
  50. 7
      ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts
  51. 50
      ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts
  52. 2
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts
  53. 6
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts
  54. 4
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts
  55. 4
      ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts
  56. 18
      ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts
  57. 12
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts
  58. 2
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts
  59. 22
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts
  60. 6
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts
  61. 6
      ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts
  62. 2
      ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
  63. 11
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/switch.component.ts
  64. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.html
  65. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.ts
  66. 58
      ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
  67. 5
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
  68. 45
      ui-ngx/src/app/modules/home/components/widget/widget.component.ts
  69. 10
      ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts
  70. 3
      ui-ngx/src/app/modules/home/pages/admin/mail-server.component.scss
  71. 4
      ui-ngx/src/app/modules/home/pages/admin/oauth2/clients/clients-table-config.resolver.ts
  72. 4
      ui-ngx/src/app/modules/home/pages/admin/oauth2/domains/domain-table-config.resolver.ts
  73. 4
      ui-ngx/src/app/modules/home/pages/admin/oauth2/mobile-apps/mobile-app-table-config.resolver.ts
  74. 4
      ui-ngx/src/app/modules/home/pages/admin/oauth2/oauth2-routing.module.ts
  75. 4
      ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts
  76. 4
      ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts
  77. 4
      ui-ngx/src/app/modules/home/pages/alarm/alarm-routing.module.ts
  78. 4
      ui-ngx/src/app/modules/home/pages/asset-profile/asset-profiles-table-config.resolver.ts
  79. 4
      ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts
  80. 4
      ui-ngx/src/app/modules/home/pages/customer/customers-table-config.resolver.ts
  81. 4
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts
  82. 4
      ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts
  83. 4
      ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts
  84. 4
      ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts
  85. 4
      ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts
  86. 4
      ui-ngx/src/app/modules/home/pages/entity-view/entity-views-table-config.resolver.ts
  87. 4
      ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts
  88. 3
      ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-header.component.scss
  89. 4
      ui-ngx/src/app/modules/home/pages/notification/recipient/recipient-table-config.resolver.ts
  90. 4
      ui-ngx/src/app/modules/home/pages/notification/rule/rule-table-config.resolver.ts
  91. 4
      ui-ngx/src/app/modules/home/pages/notification/sent/sent-table-config.resolver.ts
  92. 11
      ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts
  93. 4
      ui-ngx/src/app/modules/home/pages/notification/template/template-table-config.resolver.ts
  94. 4
      ui-ngx/src/app/modules/home/pages/ota-update/ota-update-table-config.resolve.ts
  95. 4
      ui-ngx/src/app/modules/home/pages/profile/profile-routing.module.ts
  96. 22
      ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts
  97. 2
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss
  98. 21
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts
  99. 4
      ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts
  100. 1
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts

26
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

133
ui-ngx/.eslintrc.json

@ -1,68 +1,69 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"arrow-parens": [
"off",
"always"
],
"@angular-eslint/component-selector": [
"error",
{
"prefix": [ "tb" ]
}
],
"id-blacklist": [
"error",
"any",
"Number",
"String",
"string",
"Boolean",
"boolean",
"Undefined",
"undefined"
],
"import/order": "off",
"@typescript-eslint/member-ordering": "off",
"no-underscore-dangle": "off",
"@typescript-eslint/naming-convention": "off",
"jsdoc/newline-after-description": 0
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx"
],
"parserOptions": {
"project": [
"tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"arrow-parens": [
"off",
"always"
],
"@angular-eslint/component-selector": [
"error",
{
"prefix": [
"tb"
]
}
],
"id-blacklist": [
"error",
"any",
"Number",
"String",
"string",
"Boolean",
"boolean",
"Undefined",
"undefined"
],
"import/order": "off",
"@typescript-eslint/member-ordering": "off",
"no-underscore-dangle": "off",
"@typescript-eslint/naming-convention": "off",
"jsdoc/newline-after-description": 0
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}

44
ui-ngx/angular.json

@ -217,15 +217,15 @@
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "thingsboard:build",
"buildTarget": "thingsboard:build",
"proxyConfig": "proxy.conf.js"
},
"configurations": {
"production": {
"browserTarget": "thingsboard:build:production"
"buildTarget": "thingsboard:build:production"
},
"development": {
"browserTarget": "thingsboard:build:development"
"buildTarget": "thingsboard:build:development"
}
},
"defaultConfiguration": "development"
@ -233,24 +233,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "thingsboard:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.scss"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
"buildTarget": "thingsboard:build"
}
},
"lint": {
@ -263,25 +246,6 @@
}
}
}
},
"thingsboard-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "thingsboard:serve"
},
"configurations": {
"production": {
"devServerTarget": "thingsboard:serve:production"
}
}
}
}
}
},
"cli": {

43
ui-ngx/e2e/protractor.conf.js

@ -1,43 +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.
*/
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require("jasmine-spec-reporter");
exports.config = {
allScriptsTimeout: 11000,
specs: [
"./src/**/*.e2e-spec.ts",
],
capabilities: {
"browserName": "chrome",
},
directConnect: true,
baseUrl: "http://localhost:4200/",
framework: "jasmine",
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {},
},
onPrepare() {
require("ts-node").register({
project: require("path").join(__dirname, "./tsconfig.e2e.json"),
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
},
};

39
ui-ngx/e2e/src/app.e2e-spec.ts

@ -1,39 +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 { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('Welcome to tb-license-server!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});

27
ui-ngx/e2e/src/app.po.ts

@ -1,27 +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 { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('tb-root h1')).getText() as Promise<string>;
}
}

13
ui-ngx/e2e/tsconfig.e2e.json

@ -1,13 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

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

@ -14,7 +14,7 @@
* limitations under the License.
*/
const CompressionPlugin = require("compression-webpack-plugin");
const JavaScriptOptimizerPlugin = require("@angular-devkit/build-angular/src/webpack/plugins/javascript-optimizer-plugin").JavaScriptOptimizerPlugin;
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');

221
ui-ngx/package.json

@ -8,172 +8,163 @@
"build:prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration production --vendor-chunk",
"build:types": "node generate-types.js",
"build:icon-metadata": "node generate-icon-metadata.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"prepare": "patch-package"
},
"private": true,
"dependencies": {
"@angular/animations": "^15.2.10",
"@angular/cdk": "^15.2.9",
"@angular/common": "^15.2.10",
"@angular/compiler": "^15.2.10",
"@angular/core": "^15.2.10",
"@angular/animations": "18.2.6",
"@angular/cdk": "18.2.6",
"@angular/common": "18.2.6",
"@angular/compiler": "18.2.6",
"@angular/core": "18.2.6",
"@angular/flex-layout": "^15.0.0-beta.42",
"@angular/forms": "^15.2.10",
"@angular/material": "^15.2.9",
"@angular/platform-browser": "^15.2.10",
"@angular/platform-browser-dynamic": "^15.2.10",
"@angular/router": "^15.2.10",
"@auth0/angular-jwt": "^5.1.2",
"@date-io/core": "1.3.7",
"@date-io/date-fns": "1.3.7",
"@angular/forms": "18.2.6",
"@angular/material": "18.2.6",
"@angular/platform-browser": "18.2.6",
"@angular/platform-browser-dynamic": "18.2.6",
"@angular/router": "18.2.6",
"@auth0/angular-jwt": "^5.2.0",
"@emotion/react": "11.13.3",
"@emotion/styled": "11.13.0",
"@flowjs/flow.js": "^2.14.1",
"@flowjs/ngx-flow": "~0.6.0",
"@geoman-io/leaflet-geoman-free": "2.14.2",
"@iplab/ngx-color-picker": "^15.0.2",
"@mat-datetimepicker/core": "~11.0.3",
"@material-ui/core": "4.12.3",
"@material-ui/icons": "4.11.2",
"@material-ui/pickers": "3.3.10",
"@mdi/svg": "^7.2.96",
"@messageformat/core": "^3.1.0",
"@ngrx/effects": "^15.4.0",
"@ngrx/store": "^15.4.0",
"@ngrx/store-devtools": "^15.4.0",
"@ngx-translate/core": "^14.0.0",
"@flowjs/ngx-flow": "~0.8.1",
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@geoman-io/leaflet-geoman-free": "2.17.0",
"@iplab/ngx-color-picker": "^18.0.1",
"@mat-datetimepicker/core": "~14.0.0",
"@mdi/svg": "^7.4.47",
"@messageformat/core": "^3.4.0",
"@mui/icons-material": "6.1.2",
"@mui/lab": "6.0.0-beta.10",
"@mui/material": "6.1.2",
"@mui/styles": "6.1.2",
"@mui/system": "6.1.2",
"@mui/x-date-pickers": "7.18.0",
"@ngrx/effects": "^18.0.2",
"@ngrx/store": "^18.0.2",
"@ngrx/store-devtools": "^18.0.2",
"@ngx-translate/core": "^15.0.0",
"@svgdotjs/svg.filter.js": "^3.0.8",
"@svgdotjs/svg.js": "^3.2.0",
"@svgdotjs/svg.js": "^3.2.4",
"@svgdotjs/svg.panzoom.js": "^2.1.2",
"@tinymce/tinymce-angular": "^7.0.0",
"ace-builds": "1.4.13",
"@tinymce/tinymce-angular": "^8.0.1",
"ace-builds": "1.36.2",
"ace-diff": "^3.0.3",
"angular-gridster2": "~15.0.4",
"angular2-hotkeys": "^13.1.0",
"angular-gridster2": "~18.0.1",
"angular2-hotkeys": "^16.0.1",
"canvas-gauges": "^2.1.7",
"core-js": "^3.29.1",
"date-fns": "2.0.0-alpha.27",
"dayjs": "1.11.4",
"core-js": "^3.38.1",
"dayjs": "1.11.13",
"echarts": "https://github.com/thingsboard/echarts/archive/5.5.0-TB.tar.gz",
"flot": "https://github.com/thingsboard/flot.git#0.9-work",
"flot.curvedlines": "https://github.com/MichaelZinsmaier/CurvedLines.git#master",
"font-awesome": "^4.7.0",
"html2canvas": "^1.4.1",
"jquery": "^3.7.1",
"jquery.terminal": "^2.35.3",
"js-beautify": "1.14.7",
"jquery.terminal": "^2.43.1",
"js-beautify": "1.15.1",
"json-schema-defaults": "^0.4.0",
"jstree": "^3.3.15",
"jstree": "^3.3.17",
"jstree-bootstrap-theme": "^1.0.1",
"jszip": "^3.10.1",
"leaflet": "1.8.0",
"leaflet": "1.9.4",
"leaflet-polylinedecorator": "1.6.0",
"leaflet-providers": "1.13.0",
"leaflet-providers": "2.0.0",
"leaflet.gridlayer.googlemutant": "0.14.1",
"leaflet.markercluster": "1.5.3",
"libphonenumber-js": "^1.10.4",
"marked": "^4.0.17",
"moment": "^2.29.4",
"moment-timezone": "^0.5.42",
"ngx-clipboard": "^15.1.0",
"libphonenumber-js": "^1.11.10",
"marked": "~12.0.2",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
"ngx-clipboard": "^16.0.0",
"ngx-daterangepicker-material": "^6.0.4",
"ngx-drag-drop": "^15.0.1",
"ngx-flowchart": "https://github.com/thingsboard/ngx-flowchart.git#release/2.0.0",
"ngx-hm-carousel": "^3.0.0",
"ngx-markdown": "^15.1.2",
"ngx-sharebuttons": "^12.0.0",
"ngx-translate-messageformat-compiler": "^6.2.0",
"ngx-drag-drop": "^18.0.2",
"ngx-flowchart": "https://github.com/thingsboard/ngx-flowchart.git#release/3.0.0",
"ngx-hm-carousel": "^18.0.0",
"ngx-markdown": "^18.1.0",
"ngx-sharebuttons": "^15.0.3",
"ngx-translate-messageformat-compiler": "^7.0.0",
"objectpath": "^2.0.0",
"prettier": "^2.8.3",
"prop-types": "^15.8.1",
"qrcode": "^1.5.1",
"qrcode": "^1.5.4",
"raphael": "^2.3.0",
"rc-select": "13.2.1",
"react": "17.0.2",
"react-ace": "9.5.0",
"react-dom": "17.0.2",
"react-dropzone": "^11.4.2",
"rc-select": "14.15.2",
"react": "18.3.1",
"react-ace": "12.0.0",
"react-dom": "18.3.1",
"react-dropzone": "14.2.9",
"reactcss": "^1.2.3",
"rxjs": "~7.8.0",
"schema-inspector": "^2.0.2",
"rxjs": "~7.8.1",
"schema-inspector": "^2.1.0",
"screenfull": "^6.0.2",
"sorted-btree": "^1.8.1",
"split.js": "^1.6.5",
"systemjs": "6.14.1",
"systemjs": "6.15.1",
"tinycolor2": "^1.6.0",
"tinymce": "~5.10.7",
"tinymce": "~6.8.4",
"tooltipster": "^4.2.8",
"ts-transformer-keys": "^0.4.4",
"tslib": "^2.5.0",
"tslib": "^2.7.0",
"tv4": "^1.3.0",
"typeface-roboto": "^1.1.13",
"zone.js": "~0.13.0"
"zone.js": "~0.14.10"
},
"devDependencies": {
"@angular-builders/custom-webpack": "~15.0.0",
"@angular-devkit/build-angular": "^15.2.10",
"@angular-eslint/builder": "15.2.1",
"@angular-eslint/eslint-plugin": "15.2.1",
"@angular-eslint/eslint-plugin-template": "15.2.1",
"@angular-eslint/schematics": "15.2.1",
"@angular-eslint/template-parser": "15.2.1",
"@angular/cli": "^15.2.10",
"@angular/compiler-cli": "^15.2.10",
"@angular/language-service": "^15.2.10",
"@ngtools/webpack": "15.2.10",
"@types/ace-diff": "^2.1.1",
"@types/canvas-gauges": "^2.1.4",
"@types/flot": "^0.0.32",
"@types/flowjs": "^2.13.9",
"@types/jasmine": "~3.10.2",
"@types/jasminewd2": "^2.0.10",
"@types/jquery": "^3.5.30",
"@types/js-beautify": "^1.13.3",
"@types/leaflet": "1.8.0",
"@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-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",
"@types/ace-diff": "^2.1.4",
"@types/canvas-gauges": "^2.1.8",
"@types/flot": "^0.0.36",
"@types/flowjs": "^2.13.14",
"@types/jquery": "^3.5.31",
"@types/js-beautify": "^1.14.3",
"@types/leaflet": "1.9.12",
"@types/leaflet-polylinedecorator": "1.6.4",
"@types/leaflet-providers": "1.2.4",
"@types/leaflet.gridlayer.googlemutant": "0.4.9",
"@types/leaflet.markercluster": "1.5.4",
"@types/lodash": "^4.14.192",
"@types/marked": "^4.0.8",
"@types/lodash": "^4.17.10",
"@types/node": "~18.15.11",
"@types/raphael": "^2.3.2",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/systemjs": "6.13.1",
"@types/tinycolor2": "^1.4.3",
"@types/tooltipster": "^0.0.31",
"@typescript-eslint/eslint-plugin": "5.57.0",
"@typescript-eslint/parser": "5.57.0",
"compression-webpack-plugin": "^10.0.0",
"directory-tree": "^3.5.1",
"eslint": "^8.37.0",
"@types/raphael": "^2.3.9",
"@types/react": "18.3.10",
"@types/react-dom": "18.3.0",
"@types/systemjs": "6.15.1",
"@types/tinycolor2": "^1.4.6",
"@types/tooltipster": "^0.0.35",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"@typescript-eslint/utils": "^8.7.0",
"compression-webpack-plugin": "^11.1.0",
"directory-tree": "^3.5.2",
"eslint": "~8.57.1",
"eslint-plugin-import": "latest",
"eslint-plugin-jsdoc": "latest",
"eslint-plugin-prefer-arrow": "latest",
"jasmine-core": "~3.10.1",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.3.9",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"ngrx-store-freeze": "^0.2.4",
"patch-package": "^6.5.1",
"patch-package": "^8.0.0",
"postinstall-prepare": "^2.0.0",
"protractor": "~7.0.0",
"raw-loader": "^4.0.2",
"ts-node": "^10.9.1",
"typescript": "~4.9.5",
"webpack": "5.77.0"
"ts-node": "^10.9.2",
"typescript": "~5.5.4",
"webpack": "5.95.0"
},
"resolutions": {
"@types/react": "17.0.37",
"ace-builds": "1.4.13",
"@date-io/core": "1.3.7",
"rc-virtual-list": "3.4.13",
"read-package-json": "6.0.0",
"cacache": "17.0.4"
"@types/react": "18.3.10",
"rc-virtual-list": "3.5.2",
"ace-builds": "1.36.2",
"tinymce": "6.8.4"
}
}

10
ui-ngx/patches/@angular+core+15.2.10.patch → ui-ngx/patches/@angular+core+18.2.6.patch

@ -1,8 +1,8 @@
diff --git a/node_modules/@angular/core/fesm2020/core.mjs b/node_modules/@angular/core/fesm2020/core.mjs
index e9a9b75..17044d9 100755
--- a/node_modules/@angular/core/fesm2020/core.mjs
+++ b/node_modules/@angular/core/fesm2020/core.mjs
@@ -11053,13 +11053,13 @@ function findDirectiveDefMatches(tView, tNode) {
diff --git a/node_modules/@angular/core/fesm2022/core.mjs b/node_modules/@angular/core/fesm2022/core.mjs
index 0fa881f..b844dfa 100755
--- a/node_modules/@angular/core/fesm2022/core.mjs
+++ b/node_modules/@angular/core/fesm2022/core.mjs
@@ -12868,13 +12868,13 @@ function findDirectiveDefMatches(tView, tNode) {
if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) {
matches || (matches = []);
if (isComponentDef(def)) {

21
ui-ngx/patches/@angular+flex-layout+15.0.0-beta.42.patch

File diff suppressed because one or more lines are too long

51
ui-ngx/patches/@mat-datetimepicker+core+11.0.3.patch

@ -1,51 +0,0 @@
diff --git a/node_modules/@mat-datetimepicker/core/esm2020/datetimepicker/clock.mjs b/node_modules/@mat-datetimepicker/core/esm2020/datetimepicker/clock.mjs
index e3457ea..a069460 100644
--- a/node_modules/@mat-datetimepicker/core/esm2020/datetimepicker/clock.mjs
+++ b/node_modules/@mat-datetimepicker/core/esm2020/datetimepicker/clock.mjs
@@ -259,9 +259,9 @@ export class MatDatetimepickerClockComponent {
value = 0;
}
// Don't close the minutes view if an invalid minute is clicked.
- if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
- return;
- }
+ // if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
+ // return;
+ // }
date = this._adapter.createDatetime(this._adapter.getYear(this.activeDate), this._adapter.getMonth(this.activeDate), this._adapter.getDate(this.activeDate), this._adapter.getHour(this.activeDate), value);
}
this._timeChanged = true;
diff --git a/node_modules/@mat-datetimepicker/core/fesm2015/mat-datetimepicker-core.mjs b/node_modules/@mat-datetimepicker/core/fesm2015/mat-datetimepicker-core.mjs
index 7699ff6..01aad13 100644
--- a/node_modules/@mat-datetimepicker/core/fesm2015/mat-datetimepicker-core.mjs
+++ b/node_modules/@mat-datetimepicker/core/fesm2015/mat-datetimepicker-core.mjs
@@ -951,9 +951,9 @@ class MatDatetimepickerClockComponent {
value = 0;
}
// Don't close the minutes view if an invalid minute is clicked.
- if (!((_b = this._minutes.find((m) => (m === null || m === void 0 ? void 0 : m['value']) === value)) === null || _b === void 0 ? void 0 : _b['enabled'])) {
- return;
- }
+ // if (!((_b = this._minutes.find((m) => (m === null || m === void 0 ? void 0 : m['value']) === value)) === null || _b === void 0 ? void 0 : _b['enabled'])) {
+ // return;
+ // }
date = this._adapter.createDatetime(this._adapter.getYear(this.activeDate), this._adapter.getMonth(this.activeDate), this._adapter.getDate(this.activeDate), this._adapter.getHour(this.activeDate), value);
}
this._timeChanged = true;
diff --git a/node_modules/@mat-datetimepicker/core/fesm2020/mat-datetimepicker-core.mjs b/node_modules/@mat-datetimepicker/core/fesm2020/mat-datetimepicker-core.mjs
index 809a57d..f712b84 100644
--- a/node_modules/@mat-datetimepicker/core/fesm2020/mat-datetimepicker-core.mjs
+++ b/node_modules/@mat-datetimepicker/core/fesm2020/mat-datetimepicker-core.mjs
@@ -946,9 +946,9 @@ class MatDatetimepickerClockComponent {
value = 0;
}
// Don't close the minutes view if an invalid minute is clicked.
- if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
- return;
- }
+ // if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
+ // return;
+ // }
date = this._adapter.createDatetime(this._adapter.getYear(this.activeDate), this._adapter.getMonth(this.activeDate), this._adapter.getDate(this.activeDate), this._adapter.getHour(this.activeDate), value);
}
this._timeChanged = true;

34
ui-ngx/patches/@mat-datetimepicker+core+14.0.0.patch

@ -0,0 +1,34 @@
diff --git a/node_modules/@mat-datetimepicker/core/esm2022/datetimepicker/clock.mjs b/node_modules/@mat-datetimepicker/core/esm2022/datetimepicker/clock.mjs
index 7ecfae7..08363d3 100644
--- a/node_modules/@mat-datetimepicker/core/esm2022/datetimepicker/clock.mjs
+++ b/node_modules/@mat-datetimepicker/core/esm2022/datetimepicker/clock.mjs
@@ -259,9 +259,9 @@ export class MatDatetimepickerClockComponent {
value = 0;
}
// Don't close the minutes view if an invalid minute is clicked.
- if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
- return;
- }
+ // if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
+ // return;
+ // }
date = this._adapter.createDatetime(this._adapter.getYear(this.activeDate), this._adapter.getMonth(this.activeDate), this._adapter.getDate(this.activeDate), this._adapter.getHour(this.activeDate), value);
}
this._timeChanged = true;
diff --git a/node_modules/@mat-datetimepicker/core/fesm2022/mat-datetimepicker-core.mjs b/node_modules/@mat-datetimepicker/core/fesm2022/mat-datetimepicker-core.mjs
index 00f4a52..df688e3 100644
--- a/node_modules/@mat-datetimepicker/core/fesm2022/mat-datetimepicker-core.mjs
+++ b/node_modules/@mat-datetimepicker/core/fesm2022/mat-datetimepicker-core.mjs
@@ -946,9 +946,9 @@ class MatDatetimepickerClockComponent {
value = 0;
}
// Don't close the minutes view if an invalid minute is clicked.
- if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
- return;
- }
+ // if (!this._minutes.find((m) => m?.['value'] === value)?.['enabled']) {
+ // return;
+ // }
date = this._adapter.createDatetime(this._adapter.getYear(this.activeDate), this._adapter.getMonth(this.activeDate), this._adapter.getDate(this.activeDate), this._adapter.getHour(this.activeDate), value);
}
this._timeChanged = true;

28
ui-ngx/patches/angular-gridster2+15.0.4.patch → ui-ngx/patches/angular-gridster2+18.0.1.patch

@ -1,15 +1,15 @@
diff --git a/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs b/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs
index cf4e220..df51c91 100644
--- a/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs
+++ b/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs
diff --git a/node_modules/angular-gridster2/fesm2022/angular-gridster2.mjs b/node_modules/angular-gridster2/fesm2022/angular-gridster2.mjs
index 0dcd873..e99b602 100644
--- a/node_modules/angular-gridster2/fesm2022/angular-gridster2.mjs
+++ b/node_modules/angular-gridster2/fesm2022/angular-gridster2.mjs
@@ -666,8 +666,8 @@ class GridsterRenderer {
renderer.setStyle(el, DirTypes.LTR ? 'margin-right' : 'margin-left', '');
}
else {
- const x = Math.round(this.gridster.curColWidth * item.x);
- const y = Math.round(this.gridster.curRowHeight * item.y);
+ const x = this.gridster.curColWidth * item.x;
+ const y = this.gridster.curRowHeight * item.y;
const width = this.gridster.curColWidth * item.cols - this.gridster.$options.margin;
const height = this.gridster.curRowHeight * item.rows - this.gridster.$options.margin;
// set the cell style
renderer.setStyle(el, DirTypes.LTR ? 'margin-right' : 'margin-left', '');
}
else {
- const x = Math.round(this.gridster.curColWidth * item.x);
- const y = Math.round(this.gridster.curRowHeight * item.y);
+ const x = this.gridster.curColWidth * item.x;
+ const y = this.gridster.curRowHeight * item.y;
const width = this.gridster.curColWidth * item.cols - this.gridster.$options.margin;
const height = this.gridster.curRowHeight * item.rows - this.gridster.$options.margin;
// set the cell style

2
ui-ngx/pom.xml

@ -57,7 +57,7 @@
</goals>
<configuration>
<nodeVersion>v20.11.1</nodeVersion>
<yarnVersion>v1.22.17</yarnVersion>
<yarnVersion>v1.22.22</yarnVersion>
</configuration>
</execution>
<execution>

1
ui-ngx/src/app/core/api/widget-api.models.ts

@ -42,7 +42,6 @@ import { RafService } from '@core/services/raf.service';
import { EntityAliases } from '@shared/models/alias.models';
import { EntityInfo } from '@app/shared/models/entity.models';
import { IDashboardComponent } from '@home/models/dashboard-component.models';
import moment_ from 'moment';
import {
AlarmData,
AlarmDataPageLink,

140
ui-ngx/src/app/core/core.module.ts

@ -15,8 +15,8 @@
///
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { CommonModule, IMAGE_CONFIG } from '@angular/common';
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
@ -43,74 +43,72 @@ import { TranslateDefaultParser } from '@core/translate/translate-default-parser
import { TranslateDefaultLoader } from '@core/translate/translate-default-loader';
import { EntityConflictInterceptor } from '@core/interceptors/entity-conflict.interceptor';
@NgModule({
imports: [
CommonModule,
HttpClientModule,
FlexLayoutModule.withConfig({addFlexToParent: false}),
MatDialogModule,
MatButtonModule,
MatSnackBarModule,
// ngx-translate
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateDefaultLoader
},
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: TbMissingTranslationHandler
},
compiler: {
provide: TranslateCompiler,
useClass: TranslateDefaultCompiler
},
parser: {
provide: TranslateParser,
useClass: TranslateDefaultParser
}
}),
HotkeyModule.forRoot(),
// ngrx
StoreModule.forRoot(reducers,
{ metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true,
strictStateSerializability: true,
strictActionSerializability: true
}}
),
EffectsModule.forRoot(effects),
env.production
? []
: StoreDevtoolsModule.instrument({
name: env.appTitle
})
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: GlobalHttpInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: EntityConflictInterceptor,
multi: true
},
{
provide: MAT_DIALOG_DEFAULT_OPTIONS,
useValue: {
...new MatDialogConfig(),
restoreFocus: false
}
},
WINDOW_PROVIDERS
],
exports: []
})
@NgModule({ exports: [], imports: [CommonModule,
FlexLayoutModule.withConfig({ addFlexToParent: false }),
MatDialogModule,
MatButtonModule,
MatSnackBarModule,
// ngx-translate
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateDefaultLoader
},
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: TbMissingTranslationHandler
},
compiler: {
provide: TranslateCompiler,
useClass: TranslateDefaultCompiler
},
parser: {
provide: TranslateParser,
useClass: TranslateDefaultParser
}
}),
HotkeyModule.forRoot(),
// ngrx
StoreModule.forRoot(reducers, { metaReducers,
runtimeChecks: {
strictStateImmutability: true,
strictActionImmutability: true,
strictStateSerializability: true,
strictActionSerializability: true
} }),
EffectsModule.forRoot(effects),
env.production
? []
: StoreDevtoolsModule.instrument({
name: env.appTitle,
connectInZone: true
})], providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: GlobalHttpInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: EntityConflictInterceptor,
multi: true
},
{
provide: MAT_DIALOG_DEFAULT_OPTIONS,
useValue: {
...new MatDialogConfig(),
restoreFocus: false
}
},
WINDOW_PROVIDERS,
provideHttpClient(withInterceptorsFromDi()),
{
provide: IMAGE_CONFIG,
useValue: {
disableImageSizeWarning: true,
disableImageLazyLoadWarning: true
}
}
] })
export class CoreModule {
}

4
ui-ngx/src/app/core/guards/auth.guard.ts

@ -15,7 +15,7 @@
///
import { Injectable, NgZone } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../auth/auth.service';
import { select, Store } from '@ngrx/store';
import { AppState } from '../core.state';
@ -34,7 +34,7 @@ import { MobileService } from '@core/services/mobile.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanActivateChild {
export class AuthGuard {
constructor(private store: Store<AppState>,
private router: Router,

4
ui-ngx/src/app/core/guards/confirm-on-exit.guard.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { UntypedFormGroup } from '@angular/forms';
import { select, Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -39,7 +39,7 @@ export interface HasDirtyFlag {
@Injectable({
providedIn: 'root'
})
export class ConfirmOnExitGuard implements CanDeactivate<HasConfirmForm & HasDirtyFlag> {
export class ConfirmOnExitGuard {
constructor(private store: Store<AppState>,
private dialogService: DialogService,

23
ui-ngx/src/app/core/http/rule-chain.service.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { ComponentFactory, Injectable } from '@angular/core';
import { Injectable, Type } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { forkJoin, Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
@ -31,11 +31,13 @@ import { ComponentDescriptorService } from './component-descriptor.service';
import {
IRuleNodeConfigurationComponent,
LinkLabel,
RuleNodeComponentDescriptor, RuleNodeConfiguration, ScriptLanguage,
RuleNodeComponentDescriptor,
RuleNodeConfiguration,
ScriptLanguage,
TestScriptInputParams,
TestScriptResult
} from '@app/shared/models/rule-node.models';
import { ResourcesService } from '../services/resources.service';
import { componentTypeBySelector, ResourcesService } from '../services/resources.service';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { deepClone, snakeCase } from '@core/utils';
@ -50,7 +52,7 @@ export class RuleChainService {
private ruleNodeComponentsMap: Map<RuleChainType, Array<RuleNodeComponentDescriptor>> =
new Map<RuleChainType, Array<RuleNodeComponentDescriptor>>();
private ruleNodeConfigFactories: {[directive: string]: ComponentFactory<IRuleNodeConfigurationComponent>} = {};
private ruleNodeConfigComponents: {[directive: string]: Type<IRuleNodeConfigurationComponent>} = {};
constructor(
private http: HttpClient,
@ -126,8 +128,8 @@ export class RuleChainService {
}
}
public getRuleNodeConfigFactory(directive: string): ComponentFactory<IRuleNodeConfigurationComponent> {
return this.ruleNodeConfigFactories[directive];
public getRuleNodeConfigComponent(directive: string): Type<IRuleNodeConfigurationComponent> {
return this.ruleNodeConfigComponents[directive];
}
public getRuleNodeComponentByClazz(ruleChainType: RuleChainType = RuleChainType.CORE, clazz: string): RuleNodeComponentDescriptor {
@ -219,14 +221,13 @@ export class RuleChainService {
});
}
if (moduleResource) {
tasks.push(this.resourcesService.loadFactories(moduleResource, modulesMap).pipe(
tasks.push(this.resourcesService.loadModulesWithComponents(moduleResource, modulesMap).pipe(
map((res) => {
if (nodeDefinition.configDirective && nodeDefinition.configDirective.length) {
const selector = snakeCase(nodeDefinition.configDirective, '-');
const componentFactory = res.factories.find((factory) =>
factory.selector === selector);
if (componentFactory) {
this.ruleNodeConfigFactories[nodeDefinition.configDirective] = componentFactory;
const componentType = componentTypeBySelector(res, selector);
if (componentType) {
this.ruleNodeConfigComponents[nodeDefinition.configDirective] = componentType;
} else {
component.configurationDescriptor.nodeDefinition.uiResourceLoadError =
this.translate.instant('rulenode.directive-is-not-loaded',

10
ui-ngx/src/app/core/interceptors/entity-conflict.interceptor.ts

@ -15,15 +15,7 @@
///
import { Injectable } from '@angular/core';
import {
HttpErrorResponse,
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpParams,
HttpRequest,
HttpStatusCode
} from '@angular/common/http';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpParams, HttpRequest, HttpStatusCode } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog';

10
ui-ngx/src/app/core/services/dynamic-component-factory.service.ts

@ -18,6 +18,7 @@ import { Component, Injectable, Type, ɵComponentDef, ɵNG_COMP_DEF } from '@ang
import { from, Observable, of } from 'rxjs';
import { CommonModule } from '@angular/common';
import { mergeMap } from 'rxjs/operators';
import { guid } from '@core/utils';
@Injectable({
providedIn: 'root'
@ -30,14 +31,14 @@ export class DynamicComponentFactoryService {
public createDynamicComponent<T>(
componentType: Type<T>,
template: string,
modules?: Type<any>[],
imports?: Type<any>[],
preserveWhitespaces?: boolean,
styles?: string[]): Observable<Type<T>> {
return from(import('@angular/compiler')).pipe(
mergeMap(() => {
let componentImports: Type<any>[] = [CommonModule];
if (modules) {
componentImports = [...componentImports, ...modules];
if (imports) {
componentImports = [...componentImports, ...imports];
}
const comp = this.createAndCompileDynamicComponent(componentType, template, componentImports, preserveWhitespaces, styles);
return of(comp.type);
@ -60,7 +61,8 @@ export class DynamicComponentFactoryService {
imports,
preserveWhitespaces,
styles,
standalone: true
standalone: true,
selector: 'tb-dynamic-component#' + guid()
})(componentType);
// Trigger component compilation
return comp[ɵNG_COMP_DEF];

211
ui-ngx/src/app/core/services/resources.service.ts

@ -15,16 +15,19 @@
///
import {
Compiler,
ComponentFactory,
createNgModule,
Inject,
Injectable,
Injector,
ModuleWithComponentFactories,
Type, ɵNG_MOD_DEF
Type,
ɵComponentDef,
ɵCssSelectorList,
ɵNG_COMP_DEF,
ɵNG_MOD_DEF,
ɵNgModuleDef
} from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs';
import { Observable, ReplaySubject, throwError } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { IModulesMap } from '@modules/common/modules-map.models';
import { TbResourceId } from '@shared/models/id/tb-resource-id';
@ -36,13 +39,56 @@ import { AppState } from '@core/core.state';
import { map, tap } from 'rxjs/operators';
import { RequestConfig } from '@core/http/http-utils';
declare const System;
export interface ModuleInfo {
module: ɵNgModuleDef<any>;
components: ɵComponentDef<any>[];
}
export interface ModulesWithComponents {
modules: ModuleInfo[];
standaloneComponents: ɵComponentDef<any>[];
}
export const flatModulesWithComponents = (modulesWithComponentsList: ModulesWithComponents[]): ModulesWithComponents => {
const modulesWithComponents: ModulesWithComponents = {
modules: [],
standaloneComponents: []
};
for (const m of modulesWithComponentsList) {
for (const module of m.modules) {
if (!modulesWithComponents.modules.some(m1 => m1.module === module.module)) {
modulesWithComponents.modules.push(module);
}
}
for (const comp of m.standaloneComponents) {
if (!modulesWithComponents.standaloneComponents.includes(comp)) {
modulesWithComponents.standaloneComponents.push(comp);
}
}
}
return modulesWithComponents;
}
export interface ModulesWithFactories {
modules: Type<any>[];
factories: ComponentFactory<any>[];
export const modulesWithComponentsToTypes = (modulesWithComponents: ModulesWithComponents): Type<any>[] =>
[...modulesWithComponents.modules.map(m => m.module.type),
...modulesWithComponents.standaloneComponents.map(c => c.type)];
export const componentTypeBySelector = (modulesWithComponents: ModulesWithComponents, selector: string): Type<any> | undefined => {
let found = modulesWithComponents.standaloneComponents.find(c => matchesSelector(c.selectors, selector));
if (!found) {
for (const m of modulesWithComponents.modules) {
found = m.components.find(c => matchesSelector(c.selectors, selector));
if (found) {
break;
}
}
}
return found?.type;
}
const matchesSelector = (selectors: ɵCssSelectorList, selector: string) =>
selectors.some(s => s.some(s1 => typeof s1 === 'string' && s1 === selector));
@Injectable({
providedIn: 'root'
})
@ -50,16 +96,15 @@ export class ResourcesService {
private loadedJsonResources: { [url: string]: ReplaySubject<any> } = {};
private loadedResources: { [url: string]: ReplaySubject<void> } = {};
private loadedModulesAndFactories: { [url: string]: ReplaySubject<ModulesWithFactories> } = {};
private loadedModulesWithComponents: { [url: string]: ReplaySubject<ModulesWithComponents> } = {};
private anchor = this.document.getElementsByTagName('head')[0] || this.document.getElementsByTagName('body')[0];
constructor(@Inject(DOCUMENT) private readonly document: any,
constructor(@Inject(DOCUMENT) private readonly document: Document,
protected store: Store<AppState>,
private compiler: Compiler,
private http: HttpClient,
private injector: Injector) {
this.store.pipe(select(selectIsAuthenticated)).subscribe(() => this.clearModulesCache());
this.store.pipe(select(selectIsAuthenticated)).subscribe(() => this.clearModulesWithComponentsCache());
}
public loadJsonResource<T>(url: string, postProcess?: (data: T) => T): Observable<T> {
@ -93,7 +138,7 @@ export class ResourcesService {
return this.loadedResources[url].asObservable();
}
let fileType;
let fileType: string;
const match = /[./](css|less|html|htm|js)?(([?#]).*)?$/.exec(url);
if (match !== null) {
fileType = match[1];
@ -137,53 +182,38 @@ export class ResourcesService {
);
}
public loadFactories(resourceId: string | TbResourceId, modulesMap: IModulesMap): Observable<ModulesWithFactories> {
public loadModulesWithComponents(resourceId: string | TbResourceId, modulesMap: IModulesMap): Observable<ModulesWithComponents> {
const url = this.getDownloadUrl(resourceId);
if (this.loadedModulesAndFactories[url]) {
return this.loadedModulesAndFactories[url].asObservable();
if (this.loadedModulesWithComponents[url]) {
return this.loadedModulesWithComponents[url].asObservable();
}
modulesMap.init();
const meta = this.getMetaInfo(resourceId);
const subject = new ReplaySubject<ModulesWithFactories>();
this.loadedModulesAndFactories[url] = subject;
const subject = new ReplaySubject<ModulesWithComponents>();
this.loadedModulesWithComponents[url] = subject;
import('@angular/compiler').then(
() => {
// @ts-ignore
System.import(url, undefined, meta).then(
(module) => {
const modules = this.extractNgModules(module);
if (modules.length) {
const tasks: Promise<ModuleWithComponentFactories<any>>[] = [];
for (const m of modules) {
tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m));
}
forkJoin(tasks).subscribe({
next: (compiled) => {
try {
const componentFactories: ComponentFactory<any>[] = [];
for (const c of compiled) {
c.ngModuleFactory.create(this.injector);
componentFactories.push(...c.componentFactories);
}
const modulesWithFactories: ModulesWithFactories = {
modules,
factories: componentFactories
};
this.loadedModulesAndFactories[url].next(modulesWithFactories);
this.loadedModulesAndFactories[url].complete();
} catch (e) {
this.loadedModulesAndFactories[url].error(new Error(`Unable to init module from url: ${url}`));
}
},
error: (e) => {
this.loadedModulesAndFactories[url].error(new Error(`Unable to compile module from url: ${url}`));
(module: any) => {
try {
const modulesWithComponents = this.extractModulesWithComponents(module);
if (modulesWithComponents.modules.length || modulesWithComponents.standaloneComponents.length) {
for (const module of modulesWithComponents.modules) {
createNgModule(module.module.type, this.injector);
}
});
} else {
this.loadedModulesAndFactories[url].error(new Error(`Module '${url}' doesn't have default export!`));
this.loadedModulesWithComponents[url].next(modulesWithComponents);
this.loadedModulesWithComponents[url].complete();
} else {
this.loadedModulesWithComponents[url].error(new Error(`Module '${url}' doesn't have exported modules or components!`));
}
} catch (e) {
console.log(`Unable to parse module from url: ${url}`, e);
this.loadedModulesWithComponents[url].error(new Error(`Unable to parse module from url: ${url}`));
}
},
(e) => {
this.loadedModulesAndFactories[url].error(new Error(`Unable to load module from url: ${url}`));
() => {
this.loadedModulesWithComponents[url].error(new Error(`Unable to load module from url: ${url}`));
}
);
}
@ -192,7 +222,7 @@ export class ResourcesService {
tap({
next: () => System.delete(url),
error: () => {
delete this.loadedModulesAndFactories[url];
delete this.loadedModulesWithComponents[url];
System.delete(url);
},
complete: () => System.delete(url)
@ -200,41 +230,64 @@ export class ResourcesService {
);
}
private extractNgModules(module: any, modules: Type<any>[] = []): Type<any>[] {
try {
let potentialModules = [module];
let currentScanDepth = 0;
while (potentialModules.length && currentScanDepth < 10) {
const newPotentialModules = [];
for (const potentialModule of potentialModules) {
if (potentialModule && (ɵNG_MOD_DEF in potentialModule)) {
modules.push(potentialModule);
} else {
for (const k of Object.keys(potentialModule)) {
if (!this.isPrimitive(potentialModule[k])) {
newPotentialModules.push(potentialModule[k]);
}
private extractModulesWithComponents(module: any,
modulesWithComponents: ModulesWithComponents = {
modules: [],
standaloneComponents: []
},
visitedModules: Set<any> = new Set<any>()): ModulesWithComponents {
if (module && ['object', 'function'].includes(typeof module) && !visitedModules.has(module)) {
visitedModules.add(module);
if (ɵNG_MOD_DEF in module) {
const moduleDef: ɵNgModuleDef<any> = module[ɵNG_MOD_DEF];
const moduleInfo: ModuleInfo = {
module: moduleDef,
components: []
}
modulesWithComponents.modules.push(moduleInfo);
const exportsDecl = moduleDef.exports;
let exports: Type<any>[];
if (Array.isArray(exportsDecl)) {
exports = exportsDecl;
} else {
exports = exportsDecl();
}
for (const element of exports) {
if (ɵNG_COMP_DEF in element) {
const component: ɵComponentDef<any> = element[ɵNG_COMP_DEF];
if (!component.standalone) {
moduleInfo.components.push(component);
} else {
modulesWithComponents.standaloneComponents.push(component);
}
} else {
this.extractModulesWithComponents(module, modulesWithComponents, visitedModules);
}
}
} else if (ɵNG_COMP_DEF in module) {
const component: ɵComponentDef<any> = module[ɵNG_COMP_DEF];
if (component.standalone) {
if (!modulesWithComponents.standaloneComponents.includes(component)) {
modulesWithComponents.standaloneComponents.push(component);
}
}
} else {
for (const k of Object.keys(module)) {
const val = module[k];
if (val && ['object', 'function'].includes(typeof val)) {
this.extractModulesWithComponents(val, modulesWithComponents, visitedModules);
}
}
potentialModules = newPotentialModules;
currentScanDepth++;
}
} catch (e) {
console.log('Could not load NgModule', e);
}
return modules;
}
private isPrimitive(test) {
return test !== Object(test);
return modulesWithComponents;
}
private loadResourceByType(type: 'css' | 'js', url: string): Observable<any> {
const subject = new ReplaySubject<void>();
this.loadedResources[url] = subject;
let el;
let el: any;
let loaded = false;
switch (type) {
case 'js':
@ -250,7 +303,7 @@ export class ResourcesService {
el.href = url;
break;
}
el.onload = el.onreadystatechange = (e) => {
el.onload = el.onreadystatechange = () => {
if (el.readyState && !/^c|loade/.test(el.readyState) || loaded) { return; }
el.onload = el.onreadystatechange = null;
loaded = true;
@ -282,7 +335,7 @@ export class ResourcesService {
}
}
private clearModulesCache() {
this.loadedModulesAndFactories = {};
private clearModulesWithComponentsCache() {
this.loadedModulesWithComponents = {};
}
}

2
ui-ngx/src/app/core/settings/settings.utils.ts

@ -16,7 +16,7 @@
import { environment as env } from '@env/environment';
import { TranslateService } from '@ngx-translate/core';
import * as _moment from 'moment';
import _moment from 'moment';
import { Observable } from 'rxjs';
export function updateUserLang(translate: TranslateService, userLang: string, translations = env.supportedLangs): Observable<any> {

2
ui-ngx/src/app/core/translate/translate-default-compiler.ts

@ -33,7 +33,7 @@ export class TranslateDefaultCompiler extends TranslateMessageFormatCompiler {
super(config);
}
public compile(value: string, lang: string): (params: any) => string {
public compile(value: string, lang: string): any {
return this.defaultCompile(value, lang);
}

8
ui-ngx/src/app/modules/common/modules-map.ts

@ -78,7 +78,7 @@ import * as RxJs from 'rxjs';
import * as RxJsOperators from 'rxjs/operators';
import * as TranslateCore from '@ngx-translate/core';
import * as MatDateTimePicker from '@mat-datetimepicker/core';
import * as _moment from 'moment';
import _moment from 'moment';
import * as tslib from 'tslib';
import * as TbCore from '@core/public-api';
@ -339,8 +339,6 @@ import { TimezoneComponent } from '@shared/components/time/timezone.component';
import { TimezonePanelComponent } from '@shared/components/time/timezone-panel.component';
import { DatapointsLimitComponent } from '@shared/components/time/datapoints-limit.component';
declare const System;
class ModulesMap implements IModulesMap {
private initialized = false;
@ -673,7 +671,7 @@ class ModulesMap implements IModulesMap {
init() {
if (!this.initialized) {
System.constructor.prototype.resolve = (id) => {
System.constructor.prototype.resolve = (id: string) => {
try {
if (this.modulesMap[id]) {
return 'app:' + id;
@ -688,7 +686,7 @@ class ModulesMap implements IModulesMap {
System.set('app:' + moduleId, this.modulesMap[moduleId]);
}
System.constructor.prototype.shouldFetch = (url: string) => url.endsWith('/download');
System.constructor.prototype.fetch = (url, options: RequestInit & {meta?: any}) => {
System.constructor.prototype.fetch = (url: string, options: RequestInit & {meta?: any}) => {
if (options?.meta?.additionalHeaders) {
options.headers = { ...options.headers, ...options.meta.additionalHeaders };
}

4
ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts

@ -15,7 +15,7 @@
///
import { Injectable, NgModule } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterModule, Routes } from '@angular/router';
import { ActivatedRouteSnapshot, RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum';
import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component';
@ -28,7 +28,7 @@ import { Widget } from '@app/shared/models/widget.models';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
@Injectable()
export class WidgetEditorDashboardResolver implements Resolve<Dashboard> {
export class WidgetEditorDashboardResolver {
constructor(private dashboardService: DashboardService,
private dashboardUtils: DashboardUtilsService,

4
ui-ngx/src/app/modules/home/components/alarm/alarm-comment.component.scss

@ -16,8 +16,8 @@
@use '@angular/material' as mat;
@import '../theme.scss';
$primary-color: rgba(mat.get-color-from-palette($tb-primary, 50), 0.4);
$border: 1px solid mat.get-color-from-palette($tb-primary);
$primary-color: rgba(mat.m2-get-color-from-palette($tb-primary, 50), 0.4);
$border: 1px solid mat.m2-get-color-from-palette($tb-primary);
:host {
.tb-alarm-comments {

4
ui-ngx/src/app/modules/home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component.scss

@ -17,7 +17,7 @@
@import '../theme.scss';
@import '../scss/constants.scss';
$tb-warn: mat.get-color-from-palette(map-get($tb-theme, warn), text);
$tb-warn: mat.m2-get-color-from-palette(map-get($tb-theme, warn), text);
:host {
.tb-layout-fixed-container {
@ -35,7 +35,7 @@ $tb-warn: mat.get-color-from-palette(map-get($tb-theme, warn), text);
.tb-layout-preview {
width: 100%;
background-color: rgba(mat.get-color-from-palette($tb-primary, 50), 0.6);
background-color: rgba(mat.m2-get-color-from-palette($tb-primary, 50), 0.6);
padding: 35px;
&-container {

3
ui-ngx/src/app/modules/home/components/dashboard-page/states/states-component.directive.ts

@ -126,8 +126,7 @@ export class StatesComponentDirective implements OnInit, OnDestroy, OnChanges {
}
const stateControllerInstanceId = this.dashboardCtrl.dashboardCtx.instanceId + '_' + this.statesControllerId;
const preservedState = this.statesControllerService.withdrawStateControllerState(stateControllerInstanceId);
const stateControllerFactory = stateControllerData.factory;
this.stateControllerComponentRef = this.viewContainerRef.createComponent(stateControllerFactory);
this.stateControllerComponentRef = this.viewContainerRef.createComponent(stateControllerData.component);
this.stateControllerComponent = this.stateControllerComponentRef.instance;
this.dashboardCtrl.dashboardCtx.stateController = this.stateControllerComponent;
this.dashboardCtrl.dashboardCtx.stateChanged = this.stateChangedSubject.asObservable();

9
ui-ngx/src/app/modules/home/components/dashboard-page/states/states-controller.service.ts

@ -14,12 +14,12 @@
/// limitations under the License.
///
import { ComponentFactory, ComponentFactoryResolver, Injectable, Type } from '@angular/core';
import { Injectable, Type } from '@angular/core';
import { deepClone } from '@core/utils';
import { IStateControllerComponent } from '@home/components/dashboard-page/states/state-controller.models';
export interface StateControllerData {
factory: ComponentFactory<IStateControllerComponent>;
component: Type<IStateControllerComponent>;
}
@Injectable()
@ -29,13 +29,12 @@ export class StatesControllerService {
statesControllerStates: {[stateControllerInstanceId: string]: any} = {};
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
constructor() {
}
public registerStatesController(stateControllerId: string, stateControllerComponent: Type<IStateControllerComponent>): void {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(stateControllerComponent);
this.statesControllers[stateControllerId] = {
factory: componentFactory
component: stateControllerComponent
};
}

6
ui-ngx/src/app/modules/home/components/entity/add-entity-dialog.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, ComponentFactoryResolver, Inject, Injector, OnInit, SkipSelf, ViewChild } from '@angular/core';
import { Component, Inject, Injector, OnInit, SkipSelf, ViewChild } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
@ -55,7 +55,6 @@ export class AddEntityDialogComponent extends
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: AddEntityDialogData<BaseData<HasId>>,
public dialogRef: MatDialogRef<AddEntityDialogComponent, BaseData<HasId>>,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher) {
super(store, router, dialogRef);
@ -66,7 +65,6 @@ export class AddEntityDialogComponent extends
this.translations = this.entitiesTableConfig.entityTranslations;
this.resources = this.entitiesTableConfig.entityResources;
this.entity = {};
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.entitiesTableConfig.entityComponent);
const viewContainerRef = this.entityDetailsFormAnchor.viewContainerRef;
viewContainerRef.clear();
const injector: Injector = Injector.create(
@ -84,7 +82,7 @@ export class AddEntityDialogComponent extends
parent: this.injector
}
);
const componentRef = viewContainerRef.createComponent(componentFactory, 0, injector);
const componentRef = viewContainerRef.createComponent(this.entitiesTableConfig.entityComponent, {index: 0, injector});
this.entityComponent = componentRef.instance;
this.entityComponent.isEdit = true;
this.detailsForm = this.entityComponent.entityForm;

5
ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts

@ -19,7 +19,6 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ElementRef,
EventEmitter,
Input, NgZone,
@ -140,7 +139,6 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
private domSanitizer: DomSanitizer,
private cd: ChangeDetectorRef,
private router: Router,
private componentFactoryResolver: ComponentFactoryResolver,
private elementRef: ElementRef,
private fb: FormBuilder,
private zone: NgZone) {
@ -193,10 +191,9 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
this.entitiesTableConfig = entitiesTableConfig;
this.pageMode = this.entitiesTableConfig.pageMode;
if (this.entitiesTableConfig.headerComponent) {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.entitiesTableConfig.headerComponent);
const viewContainerRef = this.entityTableHeaderAnchor.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(componentFactory);
const componentRef = viewContainerRef.createComponent(this.entitiesTableConfig.headerComponent);
const headerComponent = componentRef.instance;
headerComponent.entitiesTableConfig = this.entitiesTableConfig;
}

5
ui-ngx/src/app/modules/home/components/entity/entity-details-page.component.ts

@ -18,7 +18,6 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
HostBinding,
Injector,
OnDestroy,
@ -30,7 +29,6 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod
import { BaseData, HasId } from '@shared/models/base-data';
import { ActivatedRoute, Router } from '@angular/router';
import { UntypedFormGroup } from '@angular/forms';
import { AssetId } from '@shared/models/id/asset-id';
import { TranslateService } from '@ngx-translate/core';
import { deepClone } from '@core/utils';
import { BroadcastService } from '@core/services/broadcast.service';
@ -74,12 +72,11 @@ export class EntityDetailsPageComponent extends EntityDetailsPanelComponent impl
private router: Router,
protected injector: Injector,
protected cd: ChangeDetectorRef,
protected componentFactoryResolver: ComponentFactoryResolver,
private broadcast: BroadcastService,
private translate: TranslateService,
private dialogService: DialogService,
protected store: Store<AppState>) {
super(store, injector, cd, componentFactoryResolver);
super(store, injector, cd);
this.entitiesTableConfig = this.route.snapshot.data.entitiesTableConfig;
this.backNavigationCommands = this.route.snapshot.data.backNavigationCommands;
}

10
ui-ngx/src/app/modules/home/components/entity/entity-details-panel.component.ts

@ -19,7 +19,6 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ComponentRef,
EventEmitter,
Injector,
@ -97,8 +96,7 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV
constructor(protected store: Store<AppState>,
protected injector: Injector,
protected cd: ChangeDetectorRef,
protected componentFactoryResolver: ComponentFactoryResolver) {
protected cd: ChangeDetectorRef) {
super(store);
}
@ -167,7 +165,6 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV
this.entityComponentRef.destroy();
this.entityComponentRef = null;
}
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.entitiesTableConfig.entityComponent);
const viewContainerRef = this.entityDetailsFormAnchor.viewContainerRef;
viewContainerRef.clear();
const injector: Injector = Injector.create(
@ -185,7 +182,7 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV
parent: this.injector
}
);
this.entityComponentRef = viewContainerRef.createComponent(componentFactory, 0, injector);
this.entityComponentRef = viewContainerRef.createComponent(this.entitiesTableConfig.entityComponent, {index: 0, injector});
this.entityComponent = this.entityComponentRef.instance;
this.entityComponent.isEdit = this.isEdit;
this.detailsForm = this.entityComponent.entityForm;
@ -207,8 +204,7 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV
viewContainerRef.clear();
this.entityTabsComponent = null;
if (this.entitiesTableConfig.entityTabsComponent) {
const componentTabsFactory = this.componentFactoryResolver.resolveComponentFactory(this.entitiesTableConfig.entityTabsComponent);
this.entityTabsComponentRef = viewContainerRef.createComponent(componentTabsFactory);
this.entityTabsComponentRef = viewContainerRef.createComponent(this.entitiesTableConfig.entityTabsComponent);
this.entityTabsComponent = this.entityTabsComponentRef.instance;
this.entityTabsComponent.isEdit = this.isEdit;
this.entityTabsComponent.entitiesTableConfig = this.entitiesTableConfig;

2
ui-ngx/src/app/modules/home/components/notification/notification-bell.component.html

@ -16,5 +16,5 @@
-->
<button mat-icon-button #showNotificationButton (click)="showNotification($event, showNotificationButton)">
<mat-icon class="material-icons" [matBadge]="(count$ | async)" [matBadgeHidden]="!(count$ | async)" matBadgeColor="warn" matBadgeSize="small">notifications</mat-icon>
<mat-icon class="material-icons" aria-hidden="false" [matBadge]="(count$ | async)" [matBadgeHidden]="!(count$ | async)" matBadgeColor="warn" matBadgeSize="small">notifications</mat-icon>
</button>

19
ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts

@ -14,16 +14,7 @@
/// limitations under the License.
///
import {
AfterViewInit,
Component,
ComponentFactoryResolver,
Inject,
Injector,
SkipSelf,
ViewChild
} from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { Component, Inject, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -68,7 +59,7 @@ export interface AddDeviceProfileDialogData {
styleUrls: ['./add-device-profile-dialog.component.scss']
})
export class AddDeviceProfileDialogComponent extends
DialogComponent<AddDeviceProfileDialogComponent, DeviceProfile> implements AfterViewInit {
DialogComponent<AddDeviceProfileDialogComponent, DeviceProfile> {
@ViewChild('addDeviceProfileStepper', {static: true}) addDeviceProfileStepper: MatStepper;
stepperOrientation: Observable<StepperOrientation>;
@ -105,10 +96,7 @@ export class AddDeviceProfileDialogComponent extends
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: AddDeviceProfileDialogData,
public dialogRef: MatDialogRef<AddDeviceProfileDialogComponent, DeviceProfile>,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
private breakpointObserver: BreakpointObserver,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
private deviceProfileService: DeviceProfileService,
private fb: UntypedFormBuilder) {
super(store, router, dialogRef);
@ -162,9 +150,6 @@ export class AddDeviceProfileDialogComponent extends
{transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)});
}
ngAfterViewInit(): void {
}
cancel(): void {
this.dialogRef.close(null);
}

14
ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.ts

@ -14,20 +14,12 @@
/// limitations under the License.
///
import {
AfterViewInit,
Component,
ComponentFactoryResolver,
Inject,
Injector,
SkipSelf,
ViewChild
} from '@angular/core';
import { AfterViewInit, Component, Inject, SkipSelf, ViewChild } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
import { FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms';
import { DialogComponent } from '@shared/components/dialog.component';
import { Router } from '@angular/router';
import { AssetProfile } from '@shared/models/asset.models';
@ -59,8 +51,6 @@ export class AssetProfileDialogComponent extends
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: AssetProfileDialogData,
public dialogRef: MatDialogRef<AssetProfileDialogComponent, AssetProfile>,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
private assetProfileService: AssetProfileService) {
super(store, router, dialogRef);

14
ui-ngx/src/app/modules/home/components/profile/device-profile-dialog.component.ts

@ -14,20 +14,12 @@
/// limitations under the License.
///
import {
AfterViewInit,
Component,
ComponentFactoryResolver,
Inject,
Injector,
SkipSelf,
ViewChild
} from '@angular/core';
import { AfterViewInit, Component, Inject, SkipSelf, ViewChild } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
import { FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms';
import { DialogComponent } from '@shared/components/dialog.component';
import { Router } from '@angular/router';
import { DeviceProfile } from '@shared/models/device.models';
@ -59,8 +51,6 @@ export class DeviceProfileDialogComponent extends
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: DeviceProfileDialogData,
public dialogRef: MatDialogRef<DeviceProfileDialogComponent, DeviceProfile>,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
private deviceProfileService: DeviceProfileService) {
super(store, router, dialogRef);

14
ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.ts

@ -14,20 +14,12 @@
/// limitations under the License.
///
import {
AfterViewInit,
Component,
ComponentFactoryResolver,
Inject,
Injector,
SkipSelf,
ViewChild
} from '@angular/core';
import { AfterViewInit, Component, Inject, SkipSelf, ViewChild } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UntypedFormControl, FormGroupDirective, NgForm } from '@angular/forms';
import { FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms';
import { DialogComponent } from '@shared/components/dialog.component';
import { Router } from '@angular/router';
import { TenantProfile } from '@shared/models/tenant.model';
@ -59,8 +51,6 @@ export class TenantProfileDialogComponent extends
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: TenantProfileDialogData,
public dialogRef: MatDialogRef<TenantProfileDialogComponent, TenantProfile>,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
private tenantProfileService: TenantProfileService) {
super(store, router, dialogRef);

2
ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts

@ -310,7 +310,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange
}
}),
filter((value) => typeof value === 'string'),
map((value) => value ? (typeof value === 'string' ? value : value.name) : ''),
map((value) => value ? value : ''),
mergeMap(name => this.fetchKeys(name) ),
share()
);

16
ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts

@ -15,15 +15,12 @@
///
import {
AfterViewInit,
Component,
ComponentFactoryResolver,
ComponentRef,
forwardRef,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
ViewChild,
ViewContainerRef
@ -49,7 +46,6 @@ import { Dashboard } from '@shared/models/dashboard.models';
import { WidgetService } from '@core/http/widget.service';
import { IAliasController } from '@core/api/widget-api.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models';
import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models';
@Component({
@ -67,7 +63,7 @@ import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-con
multi: true
}]
})
export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, OnDestroy, AfterViewInit, OnChanges, Validator {
export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, OnChanges, Validator {
@ViewChild('definedSettingsContent', {read: ViewContainerRef, static: true}) definedSettingsContainer: ViewContainerRef;
@ -106,7 +102,6 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
private propagateChange = (_v: any) => { };
constructor(private translate: TranslateService,
private cfr: ComponentFactoryResolver,
private widgetService: WidgetService,
private fb: UntypedFormBuilder) {
this.widgetSettingsFormGroup = this.fb.group({
@ -121,9 +116,6 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
registerOnTouched(fn: any): void {
}
ngOnInit(): void {
}
ngOnChanges(changes: SimpleChanges): void {
for (const propName of Object.keys(changes)) {
const change = changes[propName];
@ -164,9 +156,6 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
}
}
ngAfterViewInit(): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
@ -232,8 +221,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
this.changeSubscription = null;
}
this.definedSettingsContainer.clear();
const factory = this.cfr.resolveComponentFactory(componentType);
this.definedSettingsComponentRef = this.definedSettingsContainer.createComponent(factory);
this.definedSettingsComponentRef = this.definedSettingsContainer.createComponent(componentType);
this.definedSettingsComponent = this.definedSettingsComponentRef.instance;
this.definedSettingsComponent.aliasController = this.aliasController;
this.definedSettingsComponent.callbacks = this.callbacks;

14
ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts

@ -35,7 +35,7 @@ import {
@Injectable()
export class CustomDialogService {
private customModules: Array<Type<any>>;
private customImports: Array<Type<any>>;
constructor(
private dynamicComponentFactoryService: DynamicComponentFactoryService,
@ -47,19 +47,19 @@ export class CustomDialogService {
) {
}
setAdditionalModules(modules: Array<Type<any>>) {
this.customModules = modules;
setAdditionalImports(imports: Array<Type<any>>) {
this.customImports = imports;
}
customDialog(template: string, controller: (instance: CustomDialogComponent) => void, data?: any,
config?: MatDialogConfig): Observable<any> {
const modules = [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule,
const imports = [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule,
this.widgetComponentsModule];
if (Array.isArray(this.customModules)) {
modules.push(...this.customModules);
if (Array.isArray(this.customImports)) {
imports.push(...this.customImports);
}
return this.dynamicComponentFactoryService.createDynamicComponent(
class CustomDialogComponentInstance extends CustomDialogComponent {}, template, modules).pipe(
class CustomDialogComponentInstance extends CustomDialogComponent {}, template, imports).pipe(
mergeMap((componentType) => {
const dialogData: CustomDialogContainerData = {
controller,

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

@ -14,15 +14,7 @@
/// limitations under the License.
///
import {
Component,
ComponentFactoryResolver,
Inject,
Injector,
OnInit,
ViewChild,
ViewContainerRef
} from '@angular/core';
import { Component, Inject, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';

8
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts

@ -107,9 +107,9 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
}
let lowerLeft: number[];
if (offset !== 0 && isNumeric(value)) {
lowerLeft = api.coord([startTime, value >= 0 ? Number(value) + offset : offset]);
lowerLeft = api.coord([startTime, Number(value) >= 0 ? Number(value) + offset : offset]);
} else {
lowerLeft = api.coord([startTime, value >= 0 ? value : 0]);
lowerLeft = api.coord([startTime, value]);
}
const size = api.size([delta, value]);
const width = size[0];
@ -140,7 +140,7 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
if (renderCtx.labelOption.show) {
let position = renderCtx.labelOption.position;
if (value < 0) {
if (Number(value) < 0) {
if (position === 'top') {
position = 'bottom';
} else if (position === 'bottom') {
@ -164,7 +164,7 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
}
let borderRadius: number[];
if (value < 0) {
if (Number(value) < 0) {
borderRadius = [0, 0, renderCtx.visualSettings.borderRadius, renderCtx.visualSettings.borderRadius];
} else {
borderRadius = [renderCtx.visualSettings.borderRadius, renderCtx.visualSettings.borderRadius, 0, 0];

1
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts

@ -1012,7 +1012,6 @@ export const createTimeSeriesXAxis = (id: string,
mainType: 'xAxis',
show: settings.show,
type: 'time',
scale: true,
position: settings.position,
id,
name: utils.customTranslation(settings.label, settings.label),

2
ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.component.ts

@ -41,7 +41,7 @@ import {
getFormattedDate
} from '@home/components/widget/lib/date-range-navigator/date-range-navigator.models';
import { KeyValue } from '@angular/common';
import * as _moment from 'moment';
import _moment from 'moment';
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { MatSelect } from '@angular/material/select';

2
ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator.models.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import * as _moment from 'moment';
import _moment from 'moment';
export type DateRangeInterval = 'hour' | 'day' | 'week' | 'twoWeeks' | 'month' | 'threeMonths' | 'sixMonths';

2
ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts

@ -54,7 +54,7 @@ import {
TbFlotTicksFormatterFunction,
TooltipValueFormatFunction
} from './flot-widget.models';
import * as moment_ from 'moment';
import moment_ from 'moment';
import tinycolor from 'tinycolor2';
import { AggregationType, IntervalMath } from '@shared/models/time/time.models';
import { CancelAnimationFrame } from '@core/services/raf.service';

7
ui-ngx/src/app/modules/home/components/widget/lib/maps/common-maps-utils.ts

@ -14,7 +14,6 @@
/// limitations under the License.
///
import { MapProviders } from '@home/components/widget/lib/maps/map-models';
import {
createLabelFromDatasource,
hashCode,
@ -58,7 +57,7 @@ export function findAngle(startPoint: FormattedData, endPoint: FormattedData, la
}
export function getDefCenterPosition(position): [number, number] {
export function getDefCenterPosition(position: string | [number, number]): [number, number] {
if (typeof (position) === 'string') {
const parts = position.split(',');
if (parts.length === 2) {
@ -258,8 +257,8 @@ export const parseWithTranslation = {
}
};
export function functionValueCalculator(useFunction: boolean, func: (...args: any[]) => any, params = [], defaultValue: any) {
let res;
export function functionValueCalculator<T>(useFunction: boolean, func: (...args: any[]) => any, params = [], defaultValue: T): T {
let res: T;
if (useFunction && isDefined(func) && isFunction(func)) {
try {
res = func(...params);

50
ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts

@ -14,10 +14,10 @@
/// limitations under the License.
///
import L, { FeatureGroup, LatLngBounds, LatLngTuple, Projection } from 'leaflet';
import L, { FeatureGroup, LatLngBounds, LatLngTuple, PointExpression, Projection } from 'leaflet';
import tinycolor from 'tinycolor2';
import 'leaflet-providers';
import { MarkerClusterGroup, MarkerClusterGroupOptions } from 'leaflet.markercluster/dist/leaflet.markercluster';
import 'leaflet.markercluster';
import '@geoman-io/leaflet-geoman-free';
import {
@ -41,7 +41,8 @@ import {
entitiesParseName,
isCutPolygon,
isJSON,
isValidLatLng
isValidLatLng,
LabelSettings
} from '@home/components/widget/lib/maps/maps-utils';
import { checkLngLat, createLoadingDiv } from '@home/components/widget/lib/maps/common-maps-utils';
import { WidgetContext } from '@home/models/widget-component.models';
@ -76,7 +77,7 @@ export default abstract class LeafletMap {
options: WidgetUnitedMapSettings;
bounds: L.LatLngBounds;
datasources: FormattedData[];
markersCluster: MarkerClusterGroup;
markersCluster: L.MarkerClusterGroup;
points: FeatureGroup;
markersData: FormattedData[] = [];
polygonsData: FormattedData[] = [];
@ -99,9 +100,7 @@ export default abstract class LeafletMap {
selectedEntity: FormattedData;
ignoreUpdateBounds = false;
initDragModeIgnoreUpdateBoundsSet = false;
// eslint-disable-next-line @typescript-eslint/dot-notation
southWest = new L.LatLng(-Projection.SphericalMercator['MAX_LATITUDE'], -180);
// eslint-disable-next-line @typescript-eslint/dot-notation
northEast = new L.LatLng(Projection.SphericalMercator['MAX_LATITUDE'], 180);
saveLocation: (e: FormattedData, values: {[key: string]: any}) => Observable<any>;
saveMarkerLocation: (e: FormattedData, lat?: number, lng?: number) => Observable<any>;
@ -109,7 +108,7 @@ export default abstract class LeafletMap {
translateService: TranslateService;
tooltipInstances: ITooltipsterInstance[] = [];
clusteringSettings: MarkerClusterGroupOptions;
clusteringSettings: L.MarkerClusterGroupOptions;
protected constructor(public ctx: WidgetContext,
public $container: HTMLElement,
@ -185,13 +184,13 @@ export default abstract class LeafletMap {
if (markerClusteringSettings.maxZoom && markerClusteringSettings.maxZoom >= 0 && markerClusteringSettings.maxZoom < 19) {
this.clusteringSettings.disableClusteringAtZoom = Math.floor(markerClusteringSettings.maxZoom);
}
this.markersCluster = new MarkerClusterGroup(this.clusteringSettings);
this.markersCluster = new L.MarkerClusterGroup(this.clusteringSettings);
}
}
private selectEntityWithoutLocationDialog(shapes: L.PM.SUPPORTED_SHAPES): Observable<FormattedData> {
let entities;
let labelSettings;
let entities: FormattedData[];
let labelSettings: LabelSettings;
switch (shapes) {
case 'Polygon':
case 'Rectangle':
@ -244,8 +243,8 @@ export default abstract class LeafletMap {
if (data !== null) {
this.selectedEntity = data;
this.toggleDrawMode(type);
let tooltipText;
let customTranslation;
let tooltipText: string;
let customTranslation: L.PM.Translations;
switch (type) {
case 'tbMarker':
tooltipText = this.translateService.instant('widgets.maps.tooltips.placeMarker', {entityName: data.entityParseName});
@ -310,7 +309,7 @@ export default abstract class LeafletMap {
this.map.pm.Toolbar.copyDrawControl('Marker', {
name: 'tbMarker',
afterClick: () => this.selectEntityWithoutLocation('tbMarker'),
disabled: true,
disabled: false,
actions
});
}
@ -336,14 +335,14 @@ export default abstract class LeafletMap {
this.map.pm.Toolbar.copyDrawControl('Rectangle', {
name: 'tbRectangle',
afterClick: () => this.selectEntityWithoutLocation('tbRectangle'),
disabled: true,
disabled: false,
actions: rectangleActions
});
this.map.pm.Toolbar.copyDrawControl('Polygon', {
name: 'tbPolygon',
afterClick: () => this.selectEntityWithoutLocation('tbPolygon'),
disabled: true,
disabled: false,
actions: polygonActions
});
}
@ -426,7 +425,7 @@ export default abstract class LeafletMap {
switch (e.shape) {
case 'tbMarker':
// @ts-ignore
this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => {});
this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.marker.getLatLng())).subscribe(() => {});
break;
case 'tbRectangle':
case 'tbPolygon':
@ -567,8 +566,8 @@ export default abstract class LeafletMap {
}
$(this.ctx.$container)
.find('a[role="button"]:not(.leaflet-pm-action)')
.each((index, element) => {
let title;
.each((_index, element) => {
let title: string;
if (element.title) {
title = element.title;
$(element).removeAttr('title');
@ -589,7 +588,12 @@ export default abstract class LeafletMap {
},
side: 'right',
distance: 2,
trackOrigin: true
trackOrigin: true,
functionBefore: (instance, helper) => {
if (helper.origin.ariaDisabled === 'true' || helper.origin.parentElement.classList.contains('active')) {
return false;
}
},
}
);
this.tooltipInstances.push(tooltip.tooltipster('instance'));
@ -623,7 +627,7 @@ export default abstract class LeafletMap {
return this.map.getCenter();
}
fitBounds(bounds: LatLngBounds, padding?: LatLngTuple) {
fitBounds(bounds: LatLngBounds, padding?: PointExpression) {
if (bounds.isValid()) {
this.bounds = !!this.bounds ? this.bounds.extend(bounds) : bounds;
if (!this.options.fitMapBounds && this.options.defaultZoomLevel) {
@ -669,7 +673,7 @@ export default abstract class LeafletMap {
return L.latLng(position.x, position.y) as L.LatLng;
}
convertPosition(data: FormattedData, dsData: FormattedData[]): L.LatLng {
convertPosition(data: FormattedData, _dsData: FormattedData[]): L.LatLng {
const position = this.extractPosition(data);
if (position) {
return this.positionToLatLng(position);
@ -1075,7 +1079,7 @@ export default abstract class LeafletMap {
}
});
const toDelete: string[] = [];
this.polylines.forEach((v, mKey) => {
this.polylines.forEach((_v, mKey) => {
if (!keys.includes(mKey)) {
toDelete.push(mKey);
}
@ -1145,7 +1149,7 @@ export default abstract class LeafletMap {
}
});
const toDelete: string[] = [];
this.polygons.forEach((v, mKey) => {
this.polygons.forEach((_v, mKey) => {
if (!keys.includes(mKey)) {
toDelete.push(mKey);
}

2
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts

@ -51,7 +51,7 @@ export interface CircleData {
export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
export type MarkerImageFunction = (data: FormattedData, markerImages: string[],
dsData: FormattedData[], dsIndex: number) => MarkerImageInfo;
export type PosFunction = (origXPos, origYPos, data: FormattedData,
export type PosFunction = (origXPos: number, origYPos: number, data: FormattedData,
dsData: FormattedData[], dsIndex: number, aspect: number) => { x: number, y: number };
export type MarkerIconReadyFunction = (icon: MarkerIconInfo) => void;

6
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts

@ -18,9 +18,9 @@ import LeafletMap from '@home/components/widget/lib/maps/leaflet-map';
export interface MapWidgetInterface {
map?: LeafletMap;
resize();
update();
destroy();
resize(): void;
update(): void;
destroy(): void;
}
export interface MapWidgetStaticInterface {

4
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts

@ -150,7 +150,7 @@ export class MapWidgetController implements MapWidgetInterface {
}
setMarkerLocation(e: FormattedData, lat?: number, lng?: number) {
let markerValue;
let markerValue: {[p: string]: any};
if (isDefined(lat) && isDefined(lng)) {
const point = lat != null && lng !== null ? L.latLng(lat, lng) : null;
markerValue = this.map.convertToCustomFormat(point);
@ -169,7 +169,7 @@ export class MapWidgetController implements MapWidgetInterface {
}
savePolygonLocation(e: FormattedData, coordinates?: Array<any>) {
let polygonValue;
let polygonValue: {[p: string]: any};
if (isDefined(coordinates)) {
polygonValue = this.map.convertToPolygonFormat(coordinates);
} else {

4
ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts

@ -87,14 +87,14 @@ export function isJSON(data: string): boolean {
}
}
interface labelSettings {
export interface LabelSettings {
showLabel: boolean;
useLabelFunction: boolean;
parsedLabelFunction: GenericFunction;
label: string;
}
export function entitiesParseName(entities: FormattedData[], labelSettings: labelSettings): FormattedData[] {
export function entitiesParseName(entities: FormattedData[], labelSettings: LabelSettings): FormattedData[] {
const div = document.createElement('div');
for (const entity of entities) {
if (labelSettings?.showLabel) {

18
ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts

@ -30,7 +30,7 @@ export class Marker {
private editing = false;
leafletMarker: L.Marker;
labelOffset: L.LatLngTuple;
labelOffset: L.PointTuple;
tooltipOffset: L.LatLngTuple;
markerOffset: L.LatLngTuple;
tooltip: L.Popup;
@ -40,10 +40,10 @@ export class Marker {
private location: L.LatLng,
private settings: Partial<WidgetMarkersSettings>,
private data?: FormattedData,
private dataSources?,
private dataSources?: FormattedData[],
private onDragendListener?,
snappable = false) {
this.leafletMarker = L.marker(location, {
this.leafletMarker = L.marker(this.location, {
pmIgnore: !settings.draggableMarker,
snapIgnore: !snappable,
tbMarkerData: this.data
@ -78,7 +78,7 @@ export class Marker {
}
if (settings.draggableMarker && onDragendListener) {
this.leafletMarker.on('pm:dragstart', (e) => {
this.leafletMarker.on('pm:dragstart', () => {
(this.leafletMarker.dragging as any)._draggable = { _moved: true };
(this.leafletMarker.dragging as any)._enabled = true;
this.editing = true;
@ -134,7 +134,7 @@ export class Marker {
}
}
updateMarkerColor(color) {
updateMarkerColor(color: tinycolor.Instance) {
this.createDefaultMarkerIcon(color, (iconInfo) => {
this.leafletMarker.setIcon(iconInfo.icon);
});
@ -179,8 +179,8 @@ export class Marker {
loadImageWithAspect(this.map.ctx.$injector.get(ImagePipe), currentImage.url).subscribe(
(aspectImage) => {
if (aspectImage?.aspect) {
let width;
let height;
let width: number;
let height: number;
if (aspectImage.aspect > 1) {
width = currentImage.size;
height = currentImage.size / aspectImage.aspect;
@ -263,7 +263,7 @@ export class Marker {
this.leafletMarker.addTo(map))*/
}
extendBoundsWithMarker(bounds) {
extendBoundsWithMarker(bounds: L.LatLngBounds) {
bounds.extend(this.leafletMarker.getLatLng());
}
@ -271,7 +271,7 @@ export class Marker {
return this.leafletMarker.getLatLng();
}
setMarkerPosition(latLng) {
setMarkerPosition(latLng: L.LatLngExpression) {
this.leafletMarker.setLatLng(latLng);
}
}

12
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts

@ -31,7 +31,7 @@ interface GmGlobal {
export class GoogleMap extends LeafletMap {
private resource: ResourcesService;
constructor(ctx: WidgetContext, $container, options: WidgetUnitedMapSettings) {
constructor(ctx: WidgetContext, $container: HTMLElement, options: WidgetUnitedMapSettings) {
super(ctx, $container, options);
this.resource = ctx.$injector.get(ResourcesService);
this.loadGoogle(() => {
@ -47,20 +47,20 @@ export class GoogleMap extends LeafletMap {
}, options.gmApiKey);
}
private loadGoogle(callback, apiKey = 'AIzaSyDoEx2kaGz3PxwbI9T7ccTSg5xjdw8Nw8Q') {
private loadGoogle(callback: () => void, apiKey = 'AIzaSyDoEx2kaGz3PxwbI9T7ccTSg5xjdw8Nw8Q') {
if (gmGlobals[apiKey]) {
callback();
} else {
this.resource.loadResource(`https://maps.googleapis.com/maps/api/js?key=${apiKey}`).subscribe(
() => {
this.resource.loadResource(`https://maps.googleapis.com/maps/api/js?key=${apiKey}`).subscribe({
next: () => {
gmGlobals[apiKey] = true;
callback();
},
(error) => {
error: (error) => {
gmGlobals[apiKey] = false;
console.error(`Google map api load failed!`, error);
}
);
});
}
}
}

2
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts

@ -21,7 +21,7 @@ import { WidgetContext } from '@home/models/widget-component.models';
import { isDefinedAndNotNull } from '@core/utils';
export class HEREMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: WidgetUnitedMapSettings) {
constructor(ctx: WidgetContext, $container: HTMLElement, options: WidgetUnitedMapSettings) {
super(ctx, $container, options);
const map = L.map($container, {
doubleClickZoom: !this.options.disableDoubleClickZooming,

22
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import L, { LatLngBounds, LatLngLiteral, LatLngTuple } from 'leaflet';
import L, { LatLngBounds, LatLngLiteral, LatLngTuple, PointExpression } from 'leaflet';
import LeafletMap from '../leaflet-map';
import {
CircleData,
@ -24,10 +24,8 @@ import {
WidgetUnitedMapSettings
} from '../map-models';
import { Observable, of, ReplaySubject, switchMap } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import {
calculateNewPointCoordinate, loadImageWithAspect
} from '@home/components/widget/lib/maps/common-maps-utils';
import { catchError } from 'rxjs/operators';
import { calculateNewPointCoordinate, loadImageWithAspect } from '@home/components/widget/lib/maps/common-maps-utils';
import { WidgetContext } from '@home/models/widget-component.models';
import { DataSet, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
@ -135,7 +133,7 @@ export class ImageMap extends LeafletMap {
}
}
),
catchError((e) => this.imageFromUrl(defaultImageMapProviderSettings.mapImageUrl))
catchError(() => this.imageFromUrl(defaultImageMapProviderSettings.mapImageUrl))
);
}
@ -158,13 +156,13 @@ export class ImageMap extends LeafletMap {
return this.imageFromUrl(defaultImageMapProviderSettings.mapImageUrl);
}
}),
catchError((e) => this.imageFromUrl(defaultImageMapProviderSettings.mapImageUrl))
catchError(() => this.imageFromUrl(defaultImageMapProviderSettings.mapImageUrl))
);
})
);
}
updateBounds(updateImage?: boolean, lastCenterPos?) {
updateBounds(updateImage?: boolean, lastCenterPos?: L.Point) {
const w = this.width;
const h = this.height;
this.southWest = this.pointToLatLng(0, h);
@ -233,7 +231,7 @@ export class ImageMap extends LeafletMap {
}
}
fitBounds(bounds: LatLngBounds, padding?: LatLngTuple) { }
fitBounds(_bounds: LatLngBounds, _padding?: PointExpression) { }
initMap(updateImage?: boolean) {
if (!this.map && this.aspect > 0) {
@ -271,7 +269,7 @@ export class ImageMap extends LeafletMap {
position.y * this.height);
}
convertPosition(data, dsData: FormattedData[]): L.LatLng {
convertPosition(data: FormattedData, dsData: FormattedData[]): L.LatLng {
const position = this.extractPosition(data);
if (position) {
const converted = this.posFunction(position.x, position.y, data, dsData, data.dsIndex, this.aspect) || {x: 0, y: 0};
@ -296,7 +294,7 @@ export class ImageMap extends LeafletMap {
}).filter(el => !!el);
}
pointToLatLng(x, y): L.LatLng {
pointToLatLng(x: number, y: number): L.LatLng {
return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1);
}
@ -304,7 +302,7 @@ export class ImageMap extends LeafletMap {
return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
}
convertToCustomFormat(position: L.LatLng, offset = 0, width = this.width, height = this.height): {[key: string]: any} {
convertToCustomFormat(position: L.LatLng, _offset = 0, width = this.width, height = this.height): {[key: string]: any} {
if (!position) {
return {
[this.options.xPosKeyName]: null,

6
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts

@ -20,17 +20,17 @@ import { DEFAULT_ZOOM_LEVEL, WidgetUnitedMapSettings } from '../map-models';
import { WidgetContext } from '@home/models/widget-component.models';
export class OpenStreetMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: WidgetUnitedMapSettings) {
constructor(ctx: WidgetContext, $container: HTMLElement, options: WidgetUnitedMapSettings) {
super(ctx, $container, options);
const map = L.map($container, {
doubleClickZoom: !this.options.disableDoubleClickZooming,
zoomControl: !this.options.disableZoomControl
}).setView(options?.parsedDefaultCenterPosition, options?.defaultZoomLevel || DEFAULT_ZOOM_LEVEL);
let tileLayer;
let tileLayer: L.TileLayer;
if (options.useCustomProvider) {
tileLayer = L.tileLayer(options.customProviderTileUrl);
} else {
tileLayer = (L.tileLayer as any).provider(options.mapProvider || 'OpenStreetMap.Mapnik');
tileLayer = L.tileLayer.provider(options.mapProvider || 'OpenStreetMap.Mapnik');
}
tileLayer.addTo(map);
super.setMap(map);

6
ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts

@ -21,9 +21,9 @@ import { DEFAULT_ZOOM_LEVEL, WidgetUnitedMapSettings } from '../map-models';
import { WidgetContext } from '@home/models/widget-component.models';
export class TencentMap extends LeafletMap {
constructor(ctx: WidgetContext, $container, options: WidgetUnitedMapSettings) {
constructor(ctx: WidgetContext, $container: HTMLElement, options: WidgetUnitedMapSettings) {
super(ctx, $container, options);
const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
const txUrl = 'https://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
const map = L.map($container, {
doubleClickZoom: !this.options.disableDoubleClickZooming,
zoomControl: !this.options.disableZoomControl
@ -31,7 +31,7 @@ export class TencentMap extends LeafletMap {
const txLayer = L.tileLayer(txUrl, {
subdomains: '0123',
tms: true,
attribution: '&copy;2021 Tencent - GS(2020)2236号- Data&copy; NavInfo'
attribution: '&copy;2024 Tencent - GS(2023)1171号'
}).addTo(map);
txLayer.addTo(map);
super.setMap(map);

2
ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts

@ -33,7 +33,7 @@ import {
isUndefined
} from '@core/utils';
import { EntityType } from '@shared/models/entity-type.models';
import * as _moment from 'moment';
import _moment from 'moment';
import { UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
import { RequestConfig } from '@core/http/http-utils';
import { AttributeService } from '@core/http/attribute.service';

11
ui-ngx/src/app/modules/home/components/widget/lib/rpc/switch.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { WidgetContext } from '@home/models/widget-component.models';
import { UtilsService } from '@core/services/utils.service';
@ -55,11 +55,11 @@ interface SwitchSettings {
templateUrl: './switch.component.html',
styleUrls: ['./switch.component.scss']
})
export class SwitchComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy {
export class SwitchComponent extends PageComponent implements AfterViewInit, OnDestroy {
@ViewChild('switch', {static: false}) switchElementRef: ElementRef<HTMLElement>;
@ViewChild('switchContainer', {static: false}) switchContainerRef: ElementRef<HTMLElement>;
@ViewChild('matSlideToggle', {static: false}) matSlideToggleRef: MatSlideToggle;
@ViewChild('matSlideToggle', {static: false, read: ElementRef}) matSlideToggleRef: ElementRef<HTMLElement>;
@ViewChild('onoffContainer', {static: false}) onoffContainerRef: ElementRef<HTMLElement>;
@ViewChild('onLabel', {static: false}) onLabelRef: ElementRef<HTMLElement>;
@ViewChild('offLabel', {static: false}) offLabelRef: ElementRef<HTMLElement>;
@ -119,14 +119,11 @@ export class SwitchComponent extends PageComponent implements OnInit, AfterViewI
super(store);
}
ngOnInit(): void {
}
ngAfterViewInit() {
if (this.switchType === 'switch') {
this.switchElement = $(this.switchElementRef.nativeElement);
this.switchContainer = $(this.switchContainerRef.nativeElement);
this.matSlideToggle = $(this.matSlideToggleRef._elementRef.nativeElement);
this.matSlideToggle = $(this.matSlideToggleRef.nativeElement);
this.onoffContainer = $(this.onoffContainerRef.nativeElement);
this.onLabel = $(this.onLabelRef.nativeElement);
this.offLabel = $(this.offLabelRef.nativeElement);

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.html

@ -17,7 +17,7 @@
-->
<ng-container [formGroup]="axisSettingsFormGroup">
<div class="tb-form-panel stroked tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [(expanded)]="alwaysExpanded || settingsExpanded"
<mat-expansion-panel class="tb-settings" [expanded]="alwaysExpanded || settingsExpanded"
[disabled]="alwaysExpanded || !axisSettingsFormGroup.get('show').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.ts

@ -194,7 +194,7 @@ export class DataKeyInputComponent implements ControlValueAccessor, OnInit, OnCh
}
}),
filter((value) => typeof value === 'string'),
map((value) => value ? (typeof value === 'string' ? value : value.name) : ''),
map((value) => value ? value : ''),
mergeMap(name => this.fetchKeys(name) ),
share()
);

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

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { ComponentFactory, Inject, Injectable, Optional, Type } from '@angular/core';
import { Inject, Injectable, Optional, Type } from '@angular/core';
import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service';
import { WidgetService } from '@core/http/widget.service';
import { forkJoin, from, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs';
@ -28,7 +28,13 @@ import {
} from '@home/models/widget-component.models';
import cssjs from '@core/css/css';
import { UtilsService } from '@core/services/utils.service';
import { ModulesWithFactories, ResourcesService } from '@core/services/resources.service';
import {
componentTypeBySelector,
flatModulesWithComponents,
ModulesWithComponents,
modulesWithComponentsToTypes,
ResourcesService
} from '@core/services/resources.service';
import {
IWidgetSettingsComponent,
Widget,
@ -55,7 +61,6 @@ import { HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens';
import { widgetSettingsComponentsMap } from '@home/components/widget/lib/settings/widget-settings.module';
import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module';
import { IBasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { TbTimeSeriesChart } from '@home/components/widget/lib/chart/time-series-chart';
@Injectable()
export class WidgetComponentService {
@ -323,12 +328,12 @@ export class WidgetComponentService {
this.cssParser.cssPreviewNamespace = widgetNamespace;
this.cssParser.createStyleElement(widgetNamespace, widgetInfo.templateCss);
const resourceTasks: Observable<string>[] = [];
const modulesTasks: Observable<ModulesWithFactories | string>[] = [];
const modulesTasks: Observable<ModulesWithComponents | string>[] = [];
if (widgetInfo.resources.length > 0) {
widgetInfo.resources.filter(r => r.isModule).forEach(
(resource) => {
modulesTasks.push(
this.resources.loadFactories(resource.url, this.modulesMap).pipe(
this.resources.loadModulesWithComponents(resource.url, this.modulesMap).pipe(
catchError((e: Error) => of(e?.message ? e.message : `Failed to load widget resource module: '${resource.url}'`))
)
);
@ -345,7 +350,7 @@ export class WidgetComponentService {
}
);
let modulesObservable: Observable<string | ModulesWithFactories>;
let modulesObservable: Observable<string | ModulesWithComponents>;
if (modulesTasks.length) {
modulesObservable = forkJoin(modulesTasks).pipe(
map(res => {
@ -353,20 +358,13 @@ export class WidgetComponentService {
if (msg) {
return msg as string;
} else {
const modulesWithFactoriesList = res as ModulesWithFactories[];
const resModulesWithFactories: ModulesWithFactories = {
modules: modulesWithFactoriesList.map(mf => mf.modules).flat(),
factories: modulesWithFactoriesList.map(mf => mf.factories).flat()
};
if (modules && modules.length) {
resModulesWithFactories.modules = resModulesWithFactories.modules.concat(modules);
}
return resModulesWithFactories;
const modulesWithComponentsList = res as ModulesWithComponents[];
return flatModulesWithComponents(modulesWithComponentsList);
}
})
);
} else {
modulesObservable = modules && modules.length ? of({modules, factories: []}) : of({modules: [], factories: []});
modulesObservable = of({modules: [], standaloneComponents: []});
}
resourceTasks.push(
@ -375,11 +373,15 @@ export class WidgetComponentService {
if (typeof resolvedModules === 'string') {
return of(resolvedModules);
} else {
this.registerWidgetSettingsForms(widgetInfo, resolvedModules.factories);
this.registerWidgetSettingsForms(widgetInfo, resolvedModules);
let imports = modulesWithComponentsToTypes(resolvedModules);
if (modules && modules.length) {
imports = imports.concat(modules);
}
return this.dynamicComponentFactoryService.createDynamicComponent(
class DynamicWidgetComponentInstance extends DynamicWidgetComponent {},
widgetInfo.templateHtml,
resolvedModules.modules
imports
).pipe(
map((componentType) => {
widgetInfo.componentType = componentType;
@ -401,7 +403,7 @@ export class WidgetComponentService {
errors = msgs.filter(msg => msg && msg.length > 0);
}
if (errors && errors.length) {
return throwError(errors);
return throwError(() => errors);
} else {
return of(null);
}
@ -409,7 +411,7 @@ export class WidgetComponentService {
));
}
private registerWidgetSettingsForms(widgetInfo: WidgetInfo, factories: ComponentFactory<any>[]) {
private registerWidgetSettingsForms(widgetInfo: WidgetInfo, modulesWithComponents: ModulesWithComponents) {
const directives: string[] = [];
const basicDirectives: string[] = [];
if (widgetInfo.settingsDirective && widgetInfo.settingsDirective.length) {
@ -425,17 +427,19 @@ export class WidgetComponentService {
basicDirectives.push(widgetInfo.basicModeDirective);
}
this.expandSettingComponentMap(widgetSettingsComponentsMap, directives, factories);
this.expandSettingComponentMap(basicWidgetConfigComponentsMap, basicDirectives, factories);
this.expandSettingComponentMap(widgetSettingsComponentsMap, directives, modulesWithComponents);
this.expandSettingComponentMap(basicWidgetConfigComponentsMap, basicDirectives, modulesWithComponents);
}
private expandSettingComponentMap(settingsComponentsMap: {[key: string]: Type<IWidgetSettingsComponent | IBasicWidgetConfigComponent>},
directives: string[], factories: ComponentFactory<any>[]): void {
directives: string[], modulesWithComponents: ModulesWithComponents): void {
if (directives.length) {
factories.filter((factory) => directives.includes(factory.selector))
.forEach((foundFactory) => {
settingsComponentsMap[foundFactory.selector] = foundFactory.componentType;
});
directives.forEach(selector => {
const compType = componentTypeBySelector(modulesWithComponents, selector);
if (compType) {
settingsComponentsMap[selector] = compType;
}
});
}
}

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

@ -17,7 +17,6 @@
import {
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ComponentRef,
forwardRef,
Input,
@ -212,7 +211,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
private entityService: EntityService,
private dialog: MatDialog,
public translate: TranslateService,
private cfr: ComponentFactoryResolver,
private fb: UntypedFormBuilder,
private cd: ChangeDetectorRef) {
super(store);
@ -444,10 +442,9 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
this.basicModeDirectiveError = this.translate.instant('widget-config.settings-component-not-found',
{selector: this.modelValue.basicModeDirective});
} else {
const factory = this.cfr.resolveComponentFactory(componentType);
this.createBasicModeComponentTimeout = setTimeout(() => {
this.createBasicModeComponentTimeout = null;
this.basicModeComponentRef = this.basicModeContainer.createComponent(factory);
this.basicModeComponentRef = this.basicModeContainer.createComponent(componentType);
this.basicModeComponent = this.basicModeComponentRef.instance;
this.basicModeComponent.isAdd = isAdd;
this.basicModeComponent.widgetConfig = this.modelValue;

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

@ -15,7 +15,6 @@
///
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
@ -39,7 +38,8 @@ import {
} from '@angular/core';
import { DashboardWidget } from '@home/models/dashboard-component.models';
import {
Widget, WidgetAction,
Widget,
WidgetAction,
WidgetActionDescriptor,
widgetActionSources,
WidgetActionType,
@ -57,7 +57,8 @@ import { WidgetService } from '@core/http/widget.service';
import { UtilsService } from '@core/services/utils.service';
import { forkJoin, Observable, of, ReplaySubject, Subscription, throwError } from 'rxjs';
import {
deepClone, guid,
deepClone,
guid,
insertVariable,
isDefined,
isNotEmptyStr,
@ -87,7 +88,12 @@ import {
import { EntityId } from '@shared/models/id/entity-id';
import { ActivatedRoute, Router } from '@angular/router';
import cssjs from '@core/css/css';
import { ModulesWithFactories, ResourcesService } from '@core/services/resources.service';
import {
flatModulesWithComponents,
ModulesWithComponents,
modulesWithComponentsToTypes,
ResourcesService
} from '@core/services/resources.service';
import { catchError, map, switchMap } from 'rxjs/operators';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { TimeService } from '@core/services/time.service';
@ -122,7 +128,7 @@ import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class WidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy {
export class WidgetComponent extends PageComponent implements OnInit, OnChanges, OnDestroy {
@Input()
widgetTitlePanel: TemplateRef<any>;
@ -326,9 +332,6 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
}
}
ngAfterViewInit(): void {
}
ngOnChanges(changes: SimpleChanges): void {
for (const propName of Object.keys(changes)) {
const change = changes[propName];
@ -1129,7 +1132,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
}
const customActionPrettyFunction = new Function('$event', 'widgetContext', 'entityId',
'entityName', 'htmlTemplate', 'additionalParams', 'entityLabel', customPrettyFunction);
this.widgetContext.customDialog.setAdditionalModules(descriptor.customModules);
this.widgetContext.customDialog.setAdditionalImports(descriptor.customImports);
customActionPrettyFunction($event, this.widgetContext, entityId, entityName, htmlTemplate, additionalParams, entityLabel);
} catch (e) {
console.error(e);
@ -1459,7 +1462,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
private loadCustomActionResources(actionNamespace: string, customCss: string, customResources: Array<WidgetResource>,
actionDescriptor: WidgetAction): Observable<any> {
const resourceTasks: Observable<string>[] = [];
const modulesTasks: Observable<ModulesWithFactories | string>[] = [];
const modulesTasks: Observable<ModulesWithComponents | string>[] = [];
if (isDefined(customCss) && customCss.length > 0) {
this.cssParser.cssPreviewNamespace = actionNamespace;
@ -1470,7 +1473,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
customResources.forEach(resource => {
if (resource.isModule) {
modulesTasks.push(
this.resources.loadFactories(resource.url, this.modulesMap).pipe(
this.resources.loadModulesWithComponents(resource.url, this.modulesMap).pipe(
catchError((e: Error) => of(e?.message ? e.message : `Failed to load custom action resource module: '${resource.url}'`))
)
);
@ -1484,28 +1487,24 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
});
if (modulesTasks.length) {
const modulesObservable: Observable<string | Type<any>[]> = forkJoin(modulesTasks).pipe(
const importsObservable: Observable<string | Type<any>[]> = forkJoin(modulesTasks).pipe(
map(res => {
const msg = res.find(r => typeof r === 'string');
if (msg) {
return msg as string;
} else {
const modulesWithFactoriesList = res as ModulesWithFactories[];
const resModulesWithFactories: ModulesWithFactories = {
modules: modulesWithFactoriesList.map(mf => mf.modules).flat(),
factories: modulesWithFactoriesList.map(mf => mf.factories).flat()
};
return resModulesWithFactories.modules;
const modulesWithComponents = flatModulesWithComponents(res as ModulesWithComponents[]);
return modulesWithComponentsToTypes(modulesWithComponents);
}
})
);
resourceTasks.push(modulesObservable.pipe(
map((resolvedModules) => {
if (typeof resolvedModules === 'string') {
return resolvedModules;
resourceTasks.push(importsObservable.pipe(
map((resolvedImports) => {
if (typeof resolvedImports === 'string') {
return resolvedImports;
} else {
actionDescriptor.customModules = resolvedModules;
actionDescriptor.customImports = resolvedImports;
return null;
}
})));

10
ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts

@ -15,15 +15,7 @@
///
import { inject, NgModule } from '@angular/core';
import {
ActivatedRouteSnapshot,
Resolve,
ResolveFn,
Router,
RouterModule,
RouterStateSnapshot,
Routes
} from '@angular/router';
import { ActivatedRouteSnapshot, ResolveFn, Router, RouterModule, RouterStateSnapshot, Routes } from '@angular/router';
import { MailServerComponent } from '@modules/home/pages/admin/mail-server.component';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';

3
ui-ngx/src/app/modules/home/pages/admin/mail-server.component.scss

@ -97,6 +97,9 @@
line-height: 24px;
font-size: 16px;
font-weight: 500;
.mat-pseudo-checkbox {
display: none;
}
}
.mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay {

4
ui-ngx/src/app/modules/home/pages/admin/oauth2/clients/clients-table-config.resolver.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import {
DateEntityTableColumn,
EntityTableColumn,
@ -37,7 +37,7 @@ import { Direction } from '@shared/models/page/sort-order';
import { PageLink } from '@shared/models/page/page-link';
@Injectable()
export class ClientsTableConfigResolver implements Resolve<EntityTableConfig<OAuth2Client, PageLink, OAuth2ClientInfo>> {
export class ClientsTableConfigResolver {
private readonly config: EntityTableConfig<OAuth2Client, PageLink, OAuth2ClientInfo> =
new EntityTableConfig<OAuth2Client, PageLink, OAuth2ClientInfo>();

4
ui-ngx/src/app/modules/home/pages/admin/oauth2/domains/domain-table-config.resolver.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import {
DateEntityTableColumn,
EntityActionTableColumn,
@ -36,7 +36,7 @@ import { Direction } from '@app/shared/models/page/sort-order';
import { map, Observable, of, mergeMap } from 'rxjs';
@Injectable()
export class DomainTableConfigResolver implements Resolve<EntityTableConfig<DomainInfo>> {
export class DomainTableConfigResolver {
private readonly config: EntityTableConfig<DomainInfo> = new EntityTableConfig<DomainInfo>();

4
ui-ngx/src/app/modules/home/pages/admin/oauth2/mobile-apps/mobile-app-table-config.resolver.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import {
CellActionDescriptorType,
DateEntityTableColumn,
@ -36,7 +36,7 @@ import { MobileAppTableHeaderComponent } from '@home/pages/admin/oauth2/mobile-a
import { map, Observable, of, mergeMap } from 'rxjs';
@Injectable()
export class MobileAppTableConfigResolver implements Resolve<EntityTableConfig<MobileAppInfo>> {
export class MobileAppTableConfigResolver {
private readonly config: EntityTableConfig<MobileAppInfo> = new EntityTableConfig<MobileAppInfo>();

4
ui-ngx/src/app/modules/home/pages/admin/oauth2/oauth2-routing.module.ts

@ -15,7 +15,7 @@
///
import { Injectable, NgModule } from '@angular/core';
import { Resolve, RouterModule, Routes } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';
import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { Authority } from '@shared/models/authority.enum';
import { EntitiesTableComponent } from '@home/components/entity/entities-table.component';
@ -30,7 +30,7 @@ import { MobileAppTableConfigResolver } from '@home/pages/admin/oauth2/mobile-ap
import { MenuId } from '@core/services/menu.models';
@Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {
export class OAuth2LoginProcessingUrlResolver {
constructor(private oauth2Service: OAuth2Service) {
}

4
ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import {
QueueInfo,
@ -39,7 +39,7 @@ import { selectAuthUser } from '@core/auth/auth.selectors';
import { EntityAction } from '@home/models/entity/entity-component.models';
@Injectable()
export class QueuesTableConfigResolver implements Resolve<EntityTableConfig<QueueInfo>> {
export class QueuesTableConfigResolver {
readonly queueType = ServiceType.TB_RULE_ENGINE;

4
ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts

@ -21,7 +21,7 @@ import {
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
import { Resolve, Router } from '@angular/router';
import { Router } from '@angular/router';
import { Resource, ResourceInfo, ResourceType, ResourceTypeTranslationMap } from '@shared/models/resource.models';
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
@ -39,7 +39,7 @@ import { map } from 'rxjs/operators';
import { ResourcesTableHeaderComponent } from '@home/pages/admin/resource/resources-table-header.component';
@Injectable()
export class ResourcesLibraryTableConfigResolver implements Resolve<EntityTableConfig<Resource, PageLink, ResourceInfo>> {
export class ResourcesLibraryTableConfigResolver {
private readonly config: EntityTableConfig<Resource, PageLink, ResourceInfo> = new EntityTableConfig<Resource, PageLink, ResourceInfo>();
private readonly resourceTypesTranslationMap = ResourceTypeTranslationMap;

4
ui-ngx/src/app/modules/home/pages/alarm/alarm-routing.module.ts

@ -15,7 +15,7 @@
///
import { Injectable, NgModule } from '@angular/core';
import { Resolve, RouterModule, Routes } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';
import { Authority } from '@shared/models/authority.enum';
import { Observable } from 'rxjs';
import { OAuth2Service } from '@core/http/oauth2.service';
@ -24,7 +24,7 @@ import { AlarmsMode } from '@shared/models/alarm.models';
import { MenuId } from '@core/services/menu.models';
@Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {
export class OAuth2LoginProcessingUrlResolver {
constructor(private oauth2Service: OAuth2Service) {
}

4
ui-ngx/src/app/modules/home/pages/asset-profile/asset-profiles-table-config.resolver.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { Resolve, Router } from '@angular/router';
import { Router } from '@angular/router';
import {
checkBoxCell,
DateEntityTableColumn,
@ -37,7 +37,7 @@ import { AssetProfileComponent } from '@home/components/profile/asset-profile.co
import { AssetProfileTabsComponent } from './asset-profile-tabs.component';
@Injectable()
export class AssetProfilesTableConfigResolver implements Resolve<EntityTableConfig<AssetProfile>> {
export class AssetProfilesTableConfigResolver {
private readonly config: EntityTableConfig<AssetProfile> = new EntityTableConfig<AssetProfile>();

4
ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import {
CellActionDescriptor,
checkBoxCell,
@ -65,7 +65,7 @@ import {
} from '@home/dialogs/add-entities-to-edge-dialog.component';
@Injectable()
export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> {
export class AssetsTableConfigResolver {
private readonly config: EntityTableConfig<AssetInfo> = new EntityTableConfig<AssetInfo>();

4
ui-ngx/src/app/modules/home/pages/customer/customers-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { Resolve, Router } from '@angular/router';
import { Router } from '@angular/router';
import {
DateEntityTableColumn,
@ -37,7 +37,7 @@ import { AppState } from '@core/core.state';
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
@Injectable()
export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<Customer>> {
export class CustomersTableConfigResolver {
private readonly config: EntityTableConfig<Customer> = new EntityTableConfig<Customer>();

4
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts

@ -15,7 +15,7 @@
///
import { Injectable, NgModule } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterModule, Routes } from '@angular/router';
import { ActivatedRouteSnapshot, RouterModule, Routes } from '@angular/router';
import { EntitiesTableComponent } from '../../components/entity/entities-table.component';
import { Authority } from '@shared/models/authority.enum';
@ -36,7 +36,7 @@ import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
import { MenuId } from '@core/services/menu.models';
@Injectable()
export class DashboardResolver implements Resolve<Dashboard> {
export class DashboardResolver {
constructor(private store: Store<AppState>,
private dashboardService: DashboardService,

4
ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import {
CellActionDescriptor,
checkBoxCell,
@ -79,7 +79,7 @@ import {
} from '@home/components/alias/entity-aliases-dialog.component';
@Injectable()
export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<DashboardInfo | Dashboard>> {
export class DashboardsTableConfigResolver {
private readonly config: EntityTableConfig<DashboardInfo | Dashboard> = new EntityTableConfig<DashboardInfo | Dashboard>();

4
ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { Resolve, Router } from '@angular/router';
import { Router } from '@angular/router';
import {
checkBoxCell,
DateEntityTableColumn,
@ -45,7 +45,7 @@ import { ImportExportService } from '@shared/import-export/import-export.service
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
@Injectable()
export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableConfig<DeviceProfile>> {
export class DeviceProfilesTableConfigResolver {
private readonly config: EntityTableConfig<DeviceProfile> = new EntityTableConfig<DeviceProfile>();

4
ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRoute, ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRoute, ActivatedRouteSnapshot, Router } from '@angular/router';
import {
CellActionDescriptor,
checkBoxCell,
@ -91,7 +91,7 @@ interface DevicePageQueryParams extends PageQueryParam {
}
@Injectable()
export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> {
export class DevicesTableConfigResolver {
private readonly config: EntityTableConfig<DeviceInfo> = new EntityTableConfig<DeviceInfo>();

4
ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import {
CellActionDescriptor,
checkBoxCell,
@ -65,7 +65,7 @@ import {
import { AddEntityDialogComponent } from '@home/components/entity/add-entity-dialog.component';
@Injectable()
export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeInfo>> {
export class EdgesTableConfigResolver {
private readonly config: EntityTableConfig<EdgeInfo> = new EntityTableConfig<EdgeInfo>();
private customerId: string;

4
ui-ngx/src/app/modules/home/pages/entity-view/entity-views-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import {
CellActionDescriptor,
checkBoxCell,
@ -63,7 +63,7 @@ import {
} from '@home/dialogs/add-entities-to-edge-dialog.component';
@Injectable()
export class EntityViewsTableConfigResolver implements Resolve<EntityTableConfig<EntityViewInfo>> {
export class EntityViewsTableConfigResolver {
private readonly config: EntityTableConfig<EntityViewInfo> = new EntityTableConfig<EntityViewInfo>();

4
ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts

@ -38,11 +38,11 @@ import {
InboxNotificationDialogData
} from '@home/pages/notification/inbox/inbox-notification-dialog.component';
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import { UtilsService } from '@core/services/utils.service';
@Injectable()
export class InboxTableConfigResolver implements Resolve<EntityTableConfig<Notification>> {
export class InboxTableConfigResolver {
private readonly config: EntityTableConfig<Notification> = new EntityTableConfig<Notification>();

3
ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-header.component.scss

@ -63,6 +63,9 @@
font-size: 14px;
font-weight: 500;
letter-spacing: .25px;
.mat-pseudo-checkbox {
display: none;
}
}
.mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay {

4
ui-ngx/src/app/modules/home/pages/notification/recipient/recipient-table-config.resolver.ts

@ -32,12 +32,12 @@ import {
import { MatDialog } from '@angular/material/dialog';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { RecipientTableHeaderComponent } from '@home/pages/notification/recipient/recipient-table-header.component';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { DatePipe } from '@angular/common';
@Injectable()
export class RecipientTableConfigResolver implements Resolve<EntityTableConfig<NotificationTarget>> {
export class RecipientTableConfigResolver {
private readonly config: EntityTableConfig<NotificationTarget> = new EntityTableConfig<NotificationTarget>();

4
ui-ngx/src/app/modules/home/pages/notification/rule/rule-table-config.resolver.ts

@ -32,12 +32,12 @@ import {
RuleNotificationDialogComponent,
RuleNotificationDialogData
} from '@home/pages/notification/rule/rule-notification-dialog.component';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { DatePipe } from '@angular/common';
@Injectable()
export class RuleTableConfigResolver implements Resolve<EntityTableConfig<NotificationRule>> {
export class RuleTableConfigResolver {
private readonly config: EntityTableConfig<NotificationRule> = new EntityTableConfig<NotificationRule>();

4
ui-ngx/src/app/modules/home/pages/notification/sent/sent-table-config.resolver.ts

@ -45,11 +45,11 @@ import {
NotificationRequestErrorDialogData,
SentErrorDialogComponent
} from '@home/pages/notification/sent/sent-error-dialog.component';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
@Injectable()
export class SentTableConfigResolver implements Resolve<EntityTableConfig<NotificationRequest, PageLink, NotificationRequestInfo>> {
export class SentTableConfigResolver {
private readonly config: EntityTableConfig<NotificationRequest, PageLink, NotificationRequestInfo> =
new EntityTableConfig<NotificationRequest, PageLink, NotificationRequestInfo>();

11
ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts

@ -84,15 +84,16 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co
tinyMceOptions: Record<string, any> = {
base_url: '/assets/tinymce',
suffix: '.min',
plugins: ['link table image imagetools code fullscreen'],
plugins: ['link', 'table', 'image', 'lists', 'code', 'fullscreen'],
menubar: 'edit insert tools view format table',
toolbar: 'fontselect fontsizeselect | formatselect | bold italic strikethrough forecolor backcolor ' +
'| link | table | image | alignleft aligncenter alignright alignjustify ' +
'| numlist bullist outdent indent | removeformat | code | fullscreen',
toolbar: 'undo redo | fontfamily fontsize blocks | bold italic strikethrough | forecolor backcolor ' +
'| link table image | alignleft aligncenter alignright alignjustify ' +
'| numlist bullist | outdent indent | removeformat | code | fullscreen',
toolbar_mode: 'sliding',
height: 400,
autofocus: false,
branding: false
branding: false,
promotion: false
};
private propagateChange = null;

4
ui-ngx/src/app/modules/home/pages/notification/template/template-table-config.resolver.ts

@ -33,11 +33,11 @@ import {
import { TranslateService } from '@ngx-translate/core';
import { TemplateTableHeaderComponent } from '@home/pages/notification/template/template-table-header.component';
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot } from '@angular/router';
import { DatePipe } from '@angular/common';
@Injectable()
export class TemplateTableConfigResolver implements Resolve<EntityTableConfig<NotificationTemplate>> {
export class TemplateTableConfigResolver {
private readonly config: EntityTableConfig<NotificationTemplate> = new EntityTableConfig<NotificationTemplate>();

4
ui-ngx/src/app/modules/home/pages/ota-update/ota-update-table-config.resolve.ts

@ -15,7 +15,7 @@
///
import { Injectable } from '@angular/core';
import { Resolve, Router } from '@angular/router';
import { Router } from '@angular/router';
import {
CellActionDescriptorType,
DateEntityTableColumn,
@ -40,7 +40,7 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@Injectable()
export class OtaUpdateTableConfigResolve implements Resolve<EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo>> {
export class OtaUpdateTableConfigResolve {
private readonly config: EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo> =
new EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo>();

4
ui-ngx/src/app/modules/home/pages/profile/profile-routing.module.ts

@ -15,7 +15,7 @@
///
import { Injectable, NgModule } from '@angular/core';
import { Resolve, RouterModule, Routes } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';
import { ProfileComponent } from './profile.component';
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard';
@ -28,7 +28,7 @@ import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Observable } from 'rxjs';
@Injectable()
export class UserProfileResolver implements Resolve<User> {
export class UserProfileResolver {
constructor(private store: Store<AppState>,
private userService: UserService) {

22
ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts

@ -15,14 +15,12 @@
///
import {
AfterViewInit,
Component,
ComponentRef,
EventEmitter,
forwardRef,
Input,
OnDestroy,
OnInit,
Output,
ViewChild,
ViewContainerRef
@ -42,7 +40,6 @@ import {
import { Subscription } from 'rxjs';
import { RuleChainService } from '@core/http/rule-chain.service';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { TranslateService } from '@ngx-translate/core';
import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component';
import { deepClone } from '@core/utils';
import { RuleChainType } from '@shared/models/rule-chain.models';
@ -57,7 +54,7 @@ import { RuleChainType } from '@shared/models/rule-chain.models';
multi: true
}]
})
export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, OnDestroy, AfterViewInit {
export class RuleNodeConfigComponent implements ControlValueAccessor, OnDestroy {
@ViewChild('definedConfigContent', {read: ViewContainerRef, static: true}) definedConfigContainer: ViewContainerRef;
@ -121,10 +118,9 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
private configuration: RuleNodeConfiguration;
private propagateChange = (v: any) => { };
private propagateChange = (_v: any) => { };
constructor(private translate: TranslateService,
private ruleChainService: RuleChainService,
constructor(private ruleChainService: RuleChainService,
private fb: UntypedFormBuilder) {
this.ruleNodeConfigFormGroup = this.fb.group({
configuration: [null, Validators.required]
@ -135,10 +131,7 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit(): void {
registerOnTouched(_fn: any): void {
}
ngOnDestroy(): void {
@ -155,9 +148,6 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
}
}
ngAfterViewInit(): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
@ -218,8 +208,8 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
this.changeSubscription = null;
}
this.definedConfigContainer.clear();
const factory = this.ruleChainService.getRuleNodeConfigFactory(this.nodeDefinition.configDirective);
this.definedConfigComponentRef = this.definedConfigContainer.createComponent(factory);
const component = this.ruleChainService.getRuleNodeConfigComponent(this.nodeDefinition.configDirective);
this.definedConfigComponentRef = this.definedConfigContainer.createComponent(component);
this.definedConfigComponent = this.definedConfigComponentRef.instance;
this.definedConfigComponent.ruleNodeId = this.ruleNodeId;
this.definedConfigComponent.ruleChainId = this.ruleChainId;

2
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss

@ -345,7 +345,7 @@
}
}
.tb-rule-chain-context-menu.mat-mdc-menu-panel.mdc-menu-surface {
.tb-rule-chain-context-menu.mat-mdc-menu-panel {
min-width: 320px;
max-height: 404px;
border-radius: 8px;

21
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts

@ -15,16 +15,7 @@
///
import { Inject, Injectable, NgModule, Optional } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Resolve,
Router,
RouterModule,
RouterStateSnapshot,
Routes,
UrlTree
} from '@angular/router';
import { ActivatedRouteSnapshot, Router, RouterModule, RouterStateSnapshot, Routes, UrlTree } from '@angular/router';
import { EntitiesTableComponent } from '../../components/entity/entities-table.component';
import { Authority } from '@shared/models/authority.enum';
@ -44,7 +35,7 @@ import { MODULES_MAP } from '@shared/public-api';
import { IModulesMap } from '@modules/common/modules-map.models';
@Injectable()
export class RuleChainResolver implements Resolve<RuleChain> {
export class RuleChainResolver {
constructor(private ruleChainService: RuleChainService) {
}
@ -56,7 +47,7 @@ export class RuleChainResolver implements Resolve<RuleChain> {
}
@Injectable()
export class RuleChainMetaDataResolver implements Resolve<RuleChainMetaData> {
export class RuleChainMetaDataResolver {
constructor(private ruleChainService: RuleChainService) {
}
@ -68,7 +59,7 @@ export class RuleChainMetaDataResolver implements Resolve<RuleChainMetaData> {
}
@Injectable()
export class RuleNodeComponentsResolver implements Resolve<Array<RuleNodeComponentDescriptor>> {
export class RuleNodeComponentsResolver {
constructor(private ruleChainService: RuleChainService,
@Optional() @Inject(MODULES_MAP) private modulesMap: IModulesMap) {
@ -80,7 +71,7 @@ export class RuleNodeComponentsResolver implements Resolve<Array<RuleNodeCompone
}
@Injectable()
export class TooltipsterResolver implements Resolve<any> {
export class TooltipsterResolver {
constructor() {
}
@ -91,7 +82,7 @@ export class TooltipsterResolver implements Resolve<any> {
}
@Injectable()
export class RuleChainImportGuard implements CanActivate {
export class RuleChainImportGuard {
constructor(private itembuffer: ItemBufferService,
private router: Router) {

4
ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import {
CellActionDescriptor,
checkBoxCell,
@ -53,7 +53,7 @@ import { PageData } from '@shared/models/page/page-data';
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
@Injectable()
export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<RuleChain>> {
export class RuleChainsTableConfigResolver {
private readonly config: EntityTableConfig<RuleChain> = new EntityTableConfig<RuleChain>();
private edge: Edge;

1
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts

@ -78,7 +78,6 @@ import {
SaveWidgetTypeAsDialogResult
} from '@home/pages/widget/save-widget-type-as-dialog.component';
import { WidgetService } from '@core/http/widget.service';
import { de } from 'date-fns/locale';
@Component({
selector: 'tb-scada-symbol',

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save