diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index f1efd8943a..f605bfee8a 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -99,8 +99,6 @@ "node_modules/jquery.terminal/css/jquery.terminal.min.css", "node_modules/tooltipster/dist/css/tooltipster.bundle.min.css", "node_modules/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css", - "src/app/shared/components/json-form/react/json-form.scss", - "node_modules/rc-select/assets/index.less", "node_modules/jstree-bootstrap-theme/dist/themes/proton/style.min.css", "node_modules/leaflet/dist/leaflet.css", "src/app/modules/home/components/widget/lib/maps/markers.scss", diff --git a/ui-ngx/package.json b/ui-ngx/package.json index d8870a3568..85c00e0a2e 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -25,8 +25,6 @@ "@angular/platform-browser-dynamic": "18.2.13", "@angular/router": "18.2.13", "@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": "18.0.1", "@geoman-io/leaflet-geoman-free": "2.17.0", @@ -34,12 +32,6 @@ "@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.1.1", "@ngrx/store": "^18.1.1", "@ngrx/store-devtools": "^18.1.1", @@ -85,16 +77,8 @@ "ngx-sharebuttons": "^15.0.6", "ngx-translate-messageformat-compiler": "^7.0.0", "objectpath": "^2.0.0", - "prettier": "^2.8.3", - "prop-types": "^15.8.1", "qrcode": "^1.5.4", "raphael": "^2.3.0", - "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.1", "schema-inspector": "^2.1.0", "screenfull": "^6.0.2", @@ -137,8 +121,6 @@ "@types/lodash": "^4.17.13", "@types/node": "~20.17.8", "@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", @@ -162,8 +144,6 @@ "typescript": "~5.5.4" }, "resolutions": { - "@types/react": "18.3.10", - "rc-virtual-list": "3.5.2", "ace-builds": "1.36.5", "tinymce": "6.8.5", "rollup": "4.22.4", diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts index 0d3718ee12..ebf390866c 100644 --- a/ui-ngx/src/app/core/http/widget.service.ts +++ b/ui-ngx/src/app/core/http/widget.service.ts @@ -24,7 +24,7 @@ import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; import { BaseWidgetType, DeprecatedFilter, - fullWidgetTypeFqn, + fullWidgetTypeFqn, migrateWidgetTypeToDynamicForms, WidgetType, widgetType, WidgetTypeDetails, @@ -271,6 +271,7 @@ export class WidgetService { return this.getWidgetType(templateWidgetType.template.fullFqn, config).pipe( map((result) => { + result = migrateWidgetTypeToDynamicForms(result); const widgetInfo = toWidgetInfo(result); widgetInfo.fullFqn = undefined; return widgetInfo; diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index 79fde27014..90c2547e09 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -23,7 +23,6 @@ import { baseUrl, createLabelFromDatasource, deepClone, - deleteNullProperties, guid, hashCode, isDefined, @@ -41,7 +40,6 @@ import { DataKeyType, SharedTelemetrySubscriber } from '@app/shared/models/telem import { alarmFields, alarmSeverityTranslations, alarmStatusTranslations } from '@shared/models/alarm.models'; import { materialColors } from '@app/shared/models/material.models'; import { WidgetInfo } from '@home/models/widget-component.models'; -import jsonSchemaDefaults from 'json-schema-defaults'; import { Observable } from 'rxjs'; import { publishReplay, refCount } from 'rxjs/operators'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; @@ -51,6 +49,7 @@ import { DatePipe, DOCUMENT } from '@angular/common'; import { entityTypeTranslations } from '@shared/models/entity-type.models'; import cssjs from '@core/css/css'; import { isNotEmptyTbFunction } from '@shared/models/js-function.models'; +import { defaultFormProperties, FormProperty } from '@shared/models/dynamic-form.models'; const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g'); @@ -138,10 +137,10 @@ export class UtilsService { return predefinedFunctions[func]; } - public getDefaultDatasource(dataKeySchema: any): Datasource { + public getDefaultDatasource(dataKeyForm: FormProperty[]): Datasource { const datasource = deepClone(this.defaultDatasource); - if (isDefined(dataKeySchema)) { - datasource.dataKeys[0].settings = this.generateObjectFromJsonSchema(dataKeySchema); + if (dataKeyForm?.length) { + datasource.dataKeys[0].settings = defaultFormProperties(dataKeyForm); } return datasource; } @@ -189,12 +188,6 @@ export class UtilsService { return ''; } - public generateObjectFromJsonSchema(schema: any): any { - const obj = jsonSchemaDefaults(schema); - deleteNullProperties(obj); - return obj; - } - public processWidgetException(exception: any): ExceptionData { const data = this.parseException(exception, -6); if (data.message?.startsWith('NG0')) { diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 0cc3f5bb2f..257e1bf348 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -160,7 +160,6 @@ import * as MaterialIconsDialogComponent from '@shared/components/dialog/materia import * as ColorInputComponent from '@shared/components/color-input.component'; import * as MaterialIconSelectComponent from '@shared/components/material-icon-select.component'; import * as NodeScriptTestDialogComponent from '@shared/components/dialog/node-script-test-dialog.component'; -import * as JsonFormComponent from '@shared/components/json-form/json-form.component'; import * as NotificationComponent from '@shared/components/notification/notification.component'; import * as TemplateAutocompleteComponent from '@shared/components/notification/template-autocomplete.component'; import * as ImageInputComponent from '@shared/components/image-input.component'; @@ -507,7 +506,6 @@ class ModulesMap implements IModulesMap { '@shared/components/color-input.component': ColorInputComponent, '@shared/components/material-icon-select.component': MaterialIconSelectComponent, '@shared/components/dialog/node-script-test-dialog.component': NodeScriptTestDialogComponent, - '@shared/components/json-form/json-form.component': JsonFormComponent, '@shared/components/notification/notification.component': NotificationComponent, '@shared/components/notification/template-autocomplete.component': TemplateAutocompleteComponent, '@shared/components/image-input.component': ImageInputComponent, diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts index 860825f5e8..fe96529a1d 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts @@ -26,11 +26,10 @@ import { Widget, WidgetConfigMode, widgetTypesData } from '@shared/models/widget import { Dashboard } from '@app/shared/models/dashboard.models'; import { IAliasController, IStateController } from '@core/api/widget-api.models'; import { WidgetConfigComponentData, WidgetInfo } from '@home/models/widget-component.models'; -import { isDefined, isDefinedAndNotNull, isString } from '@core/utils'; +import { isDefined, isDefinedAndNotNull } from '@core/utils'; import { TranslateService } from '@ngx-translate/core'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; -import { jsonFormSchemaToFormProperties } from '@shared/models/dynamic-form.models'; export interface AddWidgetDialogData { dashboard: Dashboard; @@ -102,34 +101,17 @@ export class AddWidgetDialogComponent extends DialogComponent !!key && !!key.type && !!key.name; @@ -197,16 +191,16 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.widgetConfigComponent.aliasController; } - get dataKeySettingsSchema(): JsonSettingsSchema { - return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema; + get dataKeySettingsForm(): FormProperty[] { + return this.widgetConfigComponent.modelValue?.dataKeySettingsForm; } get dataKeySettingsDirective(): string { return this.widgetConfigComponent.modelValue?.dataKeySettingsDirective; } - get latestDataKeySettingsSchema(): JsonSettingsSchema { - return this.widgetConfigComponent.modelValue?.latestDataKeySettingsSchema; + get latestDataKeySettingsForm(): FormProperty[] { + return this.widgetConfigComponent.modelValue?.latestDataKeySettingsForm; } get latestDataKeySettingsDirective(): string { @@ -325,7 +319,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan data: { dataKey: deepClone(this.modelValue), dataKeyConfigMode: advanced ? DataKeyConfigMode.advanced : DataKeyConfigMode.general, - dataKeySettingsSchema: this.isLatestDataKeys ? this.latestDataKeySettingsSchema : this.dataKeySettingsSchema, + dataKeySettingsForm: this.isLatestDataKeys ? this.latestDataKeySettingsForm : this.dataKeySettingsForm, dataKeySettingsDirective: this.isLatestDataKeys ? this.latestDataKeySettingsDirective : this.dataKeySettingsDirective, dashboard: this.dashboard, aliasController: this.aliasController, @@ -359,7 +353,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } private _generateDataKey(key: DataKey): DataKey { - key = this.callbacks.generateDataKey(key.name, key.type, this.dataKeySettingsSchema, this.isLatestDataKeys, + key = this.callbacks.generateDataKey(key.name, key.type, this.dataKeySettingsForm, this.isLatestDataKeys, this.dataKeySettingsFunction); if (!this.keyRowFormGroup.get('label').value) { this.keyRowFormGroup.get('label').patchValue(key.label, {emitEvent: false}); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts index 67ed19b2d2..c66ce1a289 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts @@ -37,7 +37,7 @@ import { } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; -import { DataKey, DatasourceType, JsonSettingsSchema, widgetType } from '@shared/models/widget.models'; +import { DataKey, DatasourceType, widgetType } from '@shared/models/widget.models'; import { dataKeyRowValidator, dataKeyValid } from '@home/components/widget/config/basic/common/data-key-row.component'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; @@ -45,6 +45,7 @@ import { UtilsService } from '@core/services/utils.service'; import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; import { coerceBoolean } from '@shared/decorators/coercion'; import { TimeSeriesChartYAxisId } from '@home/components/widget/lib/chart/time-series-chart.models'; +import { FormProperty } from '@shared/models/dynamic-form.models'; @Component({ selector: 'tb-data-keys-panel', @@ -154,8 +155,8 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC this.widgetConfigComponent.modelValue?.typeParameters?.hasAdditionalLatestDataKeys; } - get datakeySettingsSchema(): JsonSettingsSchema { - return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema; + get dataKeySettingsForm(): FormProperty[] { + return this.widgetConfigComponent.modelValue?.dataKeySettingsForm; } get dataKeySettingsFunction(): DataKeySettingsFunction { @@ -276,7 +277,7 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC } addKey() { - const dataKey = this.callbacks.generateDataKey('', null, this.datakeySettingsSchema, + const dataKey = this.callbacks.generateDataKey('', null, this.dataKeySettingsForm, false, this.dataKeySettingsFunction); dataKey.label = ''; dataKey.decimals = 0; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html index 4d5f38d30e..ca5ae93a84 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html @@ -35,7 +35,7 @@
; private functionTypeKeys: Array; @@ -226,15 +227,11 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con type: DataKeyType.function }); } - if (this.dataKeySettingsSchema && this.dataKeySettingsSchema.schema || + if (this.dataKeySettingsForm?.length || this.dataKeySettingsDirective && this.dataKeySettingsDirective.length) { this.hasAdvanced = true; this.dataKeySettingsData = { - schema: this.dataKeySettingsSchema?.schema || { - type: 'object', - properties: {} - }, - form: this.dataKeySettingsSchema?.form || ['*'], + settingsForm: this.dataKeySettingsForm, settingsDirective: this.dataKeySettingsDirective }; this.dataKeySettingsFormGroup = this.fb.group({ diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.models.ts index b0e80973f0..a0c211f32f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.models.ts @@ -15,13 +15,14 @@ /// import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; -import { DataKey, JsonSettingsSchema } from '@shared/models/widget.models'; +import { DataKey } from '@shared/models/widget.models'; import { Observable } from 'rxjs'; +import { FormProperty } from '@shared/models/dynamic-form.models'; export type DataKeySettingsFunction = (key: DataKey, isLatestDataKey: boolean) => any; export interface DataKeysCallbacks { - generateDataKey: (chip: any, type: DataKeyType, datakeySettingsSchema: JsonSettingsSchema, + generateDataKey: (chip: any, type: DataKeyType, dataKeySettingsForm: FormProperty[], isLatestDataKey: boolean, dataKeySettingsFunction: DataKeySettingsFunction) => DataKey; fetchEntityKeys: (entityAliasId: string, types: Array) => Observable>; fetchEntityKeysForDevice: (deviceId: string, types: Array) => Observable>; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts index e4f0b41500..bb1647faa4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts @@ -50,7 +50,7 @@ import { MatAutocomplete, MatAutocompleteTrigger } from '@angular/material/autoc import { MatChipGrid, MatChipInputEvent, MatChipRow } from '@angular/material/chips'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; -import { DataKey, DatasourceType, JsonSettingsSchema, Widget, widgetType } from '@shared/models/widget.models'; +import { DataKey, DatasourceType, Widget, widgetType } from '@shared/models/widget.models'; import { IAliasController } from '@core/api/widget-api.models'; import { DataKeySettingsFunction } from './data-keys.component.models'; import { alarmFields } from '@shared/models/alarm.models'; @@ -72,6 +72,7 @@ import { ColorPickerPanelComponent } from '@shared/components/color-picker/color import { TbPopoverService } from '@shared/components/popover.service'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { FormProperty } from '@shared/models/dynamic-form.models'; @Component({ selector: 'tb-data-keys', @@ -151,7 +152,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange aliasController: IAliasController; @Input() - datakeySettingsSchema: JsonSettingsSchema; + dataKeySettingsForm: FormProperty[]; @Input() datakeySettingsFunction: DataKeySettingsFunction; @@ -375,7 +376,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange if (this.widgetType === widgetType.alarm) { this.keys = this.utils.getDefaultAlarmDataKeys(); } else if (this.isCountDatasource) { - this.keys = [this.callbacks.generateDataKey('count', DataKeyType.count, this.datakeySettingsSchema, + this.keys = [this.callbacks.generateDataKey('count', DataKeyType.count, this.dataKeySettingsForm, this.latestDataKeys, this.datakeySettingsFunction)]; } else { this.keys = []; @@ -462,7 +463,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange } private addFromChipValue(chip: DataKey) { - const key = this.callbacks.generateDataKey(chip.name, chip.type, this.datakeySettingsSchema, this.latestDataKeys, + const key = this.callbacks.generateDataKey(chip.name, chip.type, this.dataKeySettingsForm, this.latestDataKeys, this.datakeySettingsFunction); this.addKey(key); } @@ -562,7 +563,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { dataKey: deepClone(key), - dataKeySettingsSchema: this.datakeySettingsSchema, + dataKeySettingsForm: this.dataKeySettingsForm, dataKeySettingsDirective: this.dataKeySettingsDirective, dashboard: this.dashboard, aliasController: this.aliasController, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html index 18eb6f7a23..8af7753525 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html @@ -70,7 +70,7 @@ [optDataKeys]="isDataKeysOptional(datasourceFormGroup.get('type').value)" [simpleDataKeysLabel]="!hasAdditionalLatestDataKeys" [aliasController]="aliasController" - [datakeySettingsSchema]="dataKeySettingsSchema" + [dataKeySettingsForm]="dataKeySettingsForm" [dataKeySettingsDirective]="dataKeySettingsDirective" [datakeySettingsFunction]="dataKeySettingsFunction" [dashboard]="dashboard" @@ -86,7 +86,7 @@ latestDataKeys [optDataKeys]="true" [aliasController]="aliasController" - [datakeySettingsSchema]="latestDataKeySettingsSchema" + [dataKeySettingsForm]="latestDataKeySettingsForm" [dataKeySettingsDirective]="latestDataKeySettingsDirective" [datakeySettingsFunction]="dataKeySettingsFunction" [dashboard]="dashboard" diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts index 6038982d48..df7c6162fb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts @@ -29,8 +29,8 @@ import { Datasource, DatasourceType, datasourceTypeTranslationMap, - JsonSettingsSchema, - Widget, WidgetConfigMode, + Widget, + WidgetConfigMode, widgetType } from '@shared/models/widget.models'; import { AlarmSearchStatus } from '@shared/models/alarm.models'; @@ -43,6 +43,7 @@ import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/wid import { EntityType } from '@shared/models/entity-type.models'; import { DatasourcesComponent } from '@home/components/widget/config/datasources.component'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; +import { FormProperty } from '@shared/models/dynamic-form.models'; @Component({ selector: 'tb-datasource', @@ -108,16 +109,16 @@ export class DatasourceComponent implements ControlValueAccessor, OnInit, Valida return this.widgetConfigComponent.modelValue?.typeParameters?.maxDataKeys; } - public get dataKeySettingsSchema(): JsonSettingsSchema { - return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema; + public get dataKeySettingsForm(): FormProperty[] { + return this.widgetConfigComponent.modelValue?.dataKeySettingsForm; } public get dataKeySettingsDirective(): string { return this.widgetConfigComponent.modelValue?.dataKeySettingsDirective; } - public get latestDataKeySettingsSchema(): JsonSettingsSchema { - return this.widgetConfigComponent.modelValue?.latestDataKeySettingsSchema; + public get latestDataKeySettingsForm(): FormProperty[] { + return this.widgetConfigComponent.modelValue?.latestDataKeySettingsForm; } public get latestDataKeySettingsDirective(): string { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts index 6ad1972886..7b048d0945 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts @@ -30,8 +30,8 @@ import { import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { Datasource, - DatasourceType, datasourceValid, - JsonSettingsSchema, + DatasourceType, + datasourceValid, WidgetConfigMode, widgetType } from '@shared/models/widget.models'; @@ -42,6 +42,7 @@ import { UtilsService } from '@core/services/utils.service'; import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { FormProperty } from '@shared/models/dynamic-form.models'; @Component({ selector: 'tb-datasources', @@ -336,8 +337,8 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid public addDatasource(emitEvent = true) { let newDatasource: Datasource; if (this.widgetConfigComponent.functionsOnly) { - newDatasource = deepClone(this.utils.getDefaultDatasource(this.dataKeySettingsSchema.schema)); - newDatasource.dataKeys = [this.dataKeysCallbacks.generateDataKey('Sin', DataKeyType.function, this.dataKeySettingsSchema, + newDatasource = deepClone(this.utils.getDefaultDatasource(this.dataKeySettingsForm)); + newDatasource.dataKeys = [this.dataKeysCallbacks.generateDataKey('Sin', DataKeyType.function, this.dataKeySettingsForm, false, this.dataKeySettingsFunction)]; } else { const type = this.basicMode ? this.datasourcesMode : DatasourceType.entity; @@ -351,8 +352,8 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid this.datasourcesFormArray.push(this.fb.control(newDatasource, []), {emitEvent}); } - private get dataKeySettingsSchema(): JsonSettingsSchema { - return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema; + private get dataKeySettingsForm(): FormProperty[] { + return this.widgetConfigComponent.modelValue?.dataKeySettingsForm; } private get dataKeySettingsFunction(): DataKeySettingsFunction { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts index f3807d319d..07f8b1b501 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts @@ -202,7 +202,7 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement protected constructDataKey(configData: WidgetConfigComponentData, key: DataKey, isLatestKey: boolean): DataKey { const dataKey = this.widgetConfigComponent.widgetConfigCallbacks.generateDataKey(key.name, key.type, - configData.dataKeySettingsSchema, isLatestKey, configData.dataKeySettingsFunction); + configData.dataKeySettingsForm, isLatestKey, configData.dataKeySettingsFunction); if (key.label) { dataKey.label = key.label; } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.html index a0840b84e1..c3490e9def 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.html @@ -18,9 +18,6 @@
{{definedDirectiveError}}
- - diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts index 6e1131cc3e..4743bff002 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts @@ -38,8 +38,6 @@ import { } from '@angular/forms'; import { Subscription } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; -import { JsonFormComponent } from '@shared/components/json-form/json-form.component'; -import { JsonFormComponentData } from '@shared/components/json-form/json-form-component.models'; import { DynamicFormData, IWidgetSettingsComponent, Widget, WidgetSettings } from '@shared/models/widget.models'; import { widgetSettingsComponentsMap } from '@home/components/widget/lib/settings/widget-settings.module'; import { Dashboard } from '@shared/models/dashboard.models'; @@ -99,7 +97,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, private definedSettingsComponentRef: ComponentRef; private definedSettingsComponent: IWidgetSettingsComponent; - private widgetSettingsFormData: JsonFormComponentData | DynamicFormData; + private widgetSettingsFormData: DynamicFormData; private propagateChange = (_v: any) => { }; constructor(private translate: TranslateService, @@ -166,13 +164,9 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, } } - writeValue(value: JsonFormComponentData | DynamicFormData): void { + writeValue(value: DynamicFormData): void { this.widgetSettingsFormData = value; - if ('settingsForm' in this.widgetSettingsFormData) { - this.settingsForm = this.widgetSettingsFormData.settingsForm; - } else { - this.settingsForm = null; - } + this.settingsForm = this.widgetSettingsFormData.settingsForm; if (this.changeSubscription) { this.changeSubscription.unsubscribe(); this.changeSubscription = null; @@ -187,12 +181,10 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, this.updateModel(settings); }); } else { - const settingsValue = this.useJsonForm() ? this.widgetSettingsFormData : this.widgetSettingsFormData.model; - this.widgetSettingsFormGroup.get('settings').patchValue(settingsValue, {emitEvent: false}); + this.widgetSettingsFormGroup.get('settings').patchValue(this.widgetSettingsFormData.model, {emitEvent: false}); this.changeSubscription = this.widgetSettingsFormGroup.get('settings').valueChanges.subscribe( - (data: JsonFormComponentData | WidgetSettings) => { - const settings = this.useJsonForm() ? data.model : data; - this.updateModel(settings); + (data: WidgetSettings) => { + this.updateModel(data); } ); } @@ -203,12 +195,8 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, this.settingsDirective.length && !this.definedDirectiveError; } - useJsonForm(): boolean { - return (!this.settingsDirective || !this.settingsDirective.length) && !this.settingsForm?.length; - } - useDynamicForm(): boolean { - return (!this.settingsDirective || !this.settingsDirective.length) && !!this.settingsForm?.length; + return !this.settingsDirective || !this.settingsDirective.length; } private updateModel(settings: WidgetSettings) { @@ -258,7 +246,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, } }; } - } else if (this.useJsonForm() || this.useDynamicForm()) { + } else if (this.useDynamicForm()) { if (!this.widgetSettingsFormGroup.get('settings').valid) { return { widgetSettings: { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 8dea835e24..4ca5d4302a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -19,23 +19,18 @@ import LeafletMap from './leaflet-map'; import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { getDefCenterPosition, parseWithTranslation } from './common-maps-utils'; -import { - Datasource, - DatasourceData, - FormattedData, - JsonSettingsSchema, - WidgetActionDescriptor -} from '@shared/models/widget.models'; +import { Datasource, DatasourceData, FormattedData, WidgetActionDescriptor } from '@shared/models/widget.models'; import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; import { EntityDataPageLink } from '@shared/models/query/query.models'; import { providerClass } from '@home/components/widget/lib/maps/providers/public-api'; -import { isDefined, isDefinedAndNotNull, parseFunction, parseTbFunction } from '@core/utils'; +import { isDefined, isDefinedAndNotNull, parseTbFunction } from '@core/utils'; import L from 'leaflet'; import { firstValueFrom, forkJoin, from, Observable, of } from 'rxjs'; import { AttributeService } from '@core/http/attribute.service'; import { EntityId } from '@shared/models/id/entity-id'; import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; +import { FormProperty } from '@shared/models/dynamic-form.models'; // @dynamic export class MapWidgetController implements MapWidgetInterface { @@ -113,7 +108,7 @@ export class MapWidgetController implements MapWidgetInterface { map: LeafletMap; provider: MapProviders; - schema: JsonSettingsSchema; + form: FormProperty[]; data: DatasourceData[]; settings: WidgetUnitedMapSettings; pageLink: EntityDataPageLink; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 648491faed..d9b18d896a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -36,7 +36,7 @@ import { ResourcesService } from '@core/services/resources.service'; import { - IWidgetSettingsComponent, + IWidgetSettingsComponent, migrateWidgetTypeToDynamicForms, Widget, widgetActionSources, WidgetControllerDescriptor, @@ -63,6 +63,7 @@ import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/b import { IBasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { compileTbFunction, TbFunction } from '@shared/models/js-function.models'; import { HttpClient } from '@angular/common/http'; +import { jsonFormSchemaToFormProperties } from '@shared/models/dynamic-form.models'; @Injectable() export class WidgetComponentService { @@ -113,9 +114,8 @@ export class WidgetComponentService { templateCss: this.utils.editWidgetInfo.templateCss, controllerScript: this.utils.editWidgetInfo.controllerScript, settingsForm: this.utils.editWidgetInfo.settingsForm, - settingsSchema: this.utils.editWidgetInfo.settingsSchema, - dataKeySettingsSchema: this.utils.editWidgetInfo.dataKeySettingsSchema, - latestDataKeySettingsSchema: this.utils.editWidgetInfo.latestDataKeySettingsSchema, + dataKeySettingsForm: this.utils.editWidgetInfo.dataKeySettingsForm, + latestDataKeySettingsForm: this.utils.editWidgetInfo.latestDataKeySettingsForm, settingsDirective: this.utils.editWidgetInfo.settingsDirective, dataKeySettingsDirective: this.utils.editWidgetInfo.dataKeySettingsDirective, latestDataKeySettingsDirective: this.utils.editWidgetInfo.latestDataKeySettingsDirective, @@ -276,6 +276,7 @@ export class WidgetComponentService { this.widgetsInfoFetchQueue.set(fullFqn, fetchQueue); this.widgetService.getWidgetType(fullFqn, {ignoreErrors: true}).subscribe( (widgetType) => { + widgetType = migrateWidgetTypeToDynamicForms(widgetType); this.loadWidget(widgetType, widgetInfoSubject); }, () => { @@ -302,14 +303,11 @@ export class WidgetComponentService { if (widgetControllerDescriptor.settingsForm) { widgetInfo.typeSettingsForm = widgetControllerDescriptor.settingsForm; } - if (widgetControllerDescriptor.settingsSchema) { - widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema; + if (widgetControllerDescriptor.dataKeySettingsForm) { + widgetInfo.typeDataKeySettingsForm = widgetControllerDescriptor.dataKeySettingsForm; } - if (widgetControllerDescriptor.dataKeySettingsSchema) { - widgetInfo.typeDataKeySettingsSchema = widgetControllerDescriptor.dataKeySettingsSchema; - } - if (widgetControllerDescriptor.latestDataKeySettingsSchema) { - widgetInfo.typeLatestDataKeySettingsSchema = widgetControllerDescriptor.latestDataKeySettingsSchema; + if (widgetControllerDescriptor.latestDataKeySettingsForm) { + widgetInfo.typeLatestDataKeySettingsForm = widgetControllerDescriptor.latestDataKeySettingsForm; } widgetInfo.typeParameters = widgetControllerDescriptor.typeParameters; widgetInfo.actionSources = widgetControllerDescriptor.actionSources; @@ -510,12 +508,23 @@ export class WidgetComponentService { ' }\n\n' + - ' self.getSettingsSchema = function() {\n\n' + - + ' self.getSettingsForm = function() {\n\n' + + return [ + { + 'id': 'testProp', + 'name': 'Test property', + 'type': 'text', + 'default': 'Default value' + } + ]; ' }\n\n' + - ' self.getDataKeySettingsSchema = function() {\n\n' + + ' self.getDataKeySettingsForm = function() {\n\n' + + return []; + ' }\n\n' + + ' self.getLatestDataKeySettingsForm = function() {\n\n' + + return []; ' }\n\n' + ' self.onDestroy = function() {\n\n' + @@ -546,15 +555,30 @@ export class WidgetComponentService { if (isFunction(widgetTypeInstance.getSettingsForm)) { result.settingsForm = widgetTypeInstance.getSettingsForm(); } - if (isFunction(widgetTypeInstance.getSettingsSchema)) { - result.settingsSchema = widgetTypeInstance.getSettingsSchema(); + if (isFunction(widgetTypeInstance.getDataKeySettingsForm)) { + result.dataKeySettingsForm = widgetTypeInstance.getDataKeySettingsForm(); } - if (isFunction(widgetTypeInstance.getDataKeySettingsSchema)) { - result.dataKeySettingsSchema = widgetTypeInstance.getDataKeySettingsSchema(); + if (isFunction(widgetTypeInstance.getLatestDataKeySettingsForm)) { + result.latestDataKeySettingsForm = widgetTypeInstance.getLatestDataKeySettingsForm(); } - if (isFunction(widgetTypeInstance.getLatestDataKeySettingsSchema)) { - result.latestDataKeySettingsSchema = widgetTypeInstance.getLatestDataKeySettingsSchema(); + + /** Start migrate from old JSON Schema Form **/ + + if (isFunction((widgetTypeInstance as any).getSettingsSchema) && !result.settingsForm?.length) { + const settingsSchema = (widgetTypeInstance as any).getSettingsSchema(); + result.settingsForm = jsonFormSchemaToFormProperties(settingsSchema); } + if (isFunction((widgetTypeInstance as any).getDataKeySettingsSchema) && !result.dataKeySettingsForm?.length) { + const dataKeySettingsSchema = (widgetTypeInstance as any).getDataKeySettingsSchema(); + result.dataKeySettingsForm = jsonFormSchemaToFormProperties(dataKeySettingsSchema); + } + if (isFunction((widgetTypeInstance as any).getLatestDataKeySettingsSchema) && !result.latestDataKeySettingsForm?.length) { + const latestDataKeySettingsSchema = (widgetTypeInstance as any).getLatestDataKeySettingsSchema(); + result.latestDataKeySettingsForm = jsonFormSchemaToFormProperties(latestDataKeySettingsSchema); + } + + /** End migrate from old JSON Schema Form **/ + if (isFunction(widgetTypeInstance.typeParameters)) { result.typeParameters = widgetTypeInstance.typeParameters(); } else { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 3af9faca69..b2d1d68ed0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -32,9 +32,6 @@
-
- -
widget-config.card-title
@@ -313,17 +310,5 @@
- -
- - -
-
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index c9bbcab5d7..52fce38975 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -32,10 +32,8 @@ import { CellClickColumnInfo, DataKey, datasourcesHasAggregation, - datasourcesHasOnlyComparisonAggregation, DynamicFormData, - GroupInfo, - JsonSchema, - JsonSettingsSchema, + datasourcesHasOnlyComparisonAggregation, + DynamicFormData, TargetDevice, targetDeviceValid, Widget, @@ -74,7 +72,6 @@ import { import { catchError, map, mergeMap, tap } from 'rxjs/operators'; import { MatDialog } from '@angular/material/dialog'; import { EntityService } from '@core/http/entity.service'; -import { JsonFormComponentData } from '@shared/components/json-form/json-form-component.models'; import { Dashboard } from '@shared/models/dashboard.models'; import { entityFields } from '@shared/models/entity.models'; import { Filter, singleEntityFilterFromDeviceId } from '@shared/models/query/query.models'; @@ -84,17 +81,9 @@ import { coerceBoolean } from '@shared/decorators/coercion'; import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module'; import { TimewindowConfigData } from '@home/components/widget/config/timewindow-config-panel.component'; import { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; +import { defaultFormProperties, FormProperty } from '@shared/models/dynamic-form.models'; import Timeout = NodeJS.Timeout; -const emptySettingsSchema: JsonSchema = { - type: 'object', - properties: {} -}; -const emptySettingsGroupInfoes: GroupInfo[] = []; -const defaultSettingsForm = [ - '*' -]; - @Component({ selector: 'tb-widget-config', templateUrl: './widget-config.component.html', @@ -190,7 +179,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe public widgetSettings: UntypedFormGroup; public layoutSettings: UntypedFormGroup; public advancedSettings: UntypedFormGroup; - public oldAdvancedSettings: UntypedFormGroup; public actionsSettings: UntypedFormGroup; private createBasicModeComponentTimeout: Timeout; @@ -204,7 +192,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe private widgetSettingsSubscription: Subscription; private layoutSettingsSubscription: Subscription; private advancedSettingsSubscription: Subscription; - private oldAdvancedSettingsSubscription: Subscription; private actionsSettingsSubscription: Subscription; private defaultConfigFormsType: widgetType; @@ -223,7 +210,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.dataSettings = this.fb.group({}); this.targetDeviceSettings = this.fb.group({}); this.advancedSettings = this.fb.group({}); - this.oldAdvancedSettings = this.fb.group({}); this.widgetSettings = this.fb.group({ title: [null, []], titleFont: [null, []], @@ -299,10 +285,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.advancedSettingsSubscription.unsubscribe(); this.advancedSettingsSubscription = null; } - if (this.oldAdvancedSettingsSubscription) { - this.oldAdvancedSettingsSubscription.unsubscribe(); - this.oldAdvancedSettingsSubscription = null; - } if (this.actionsSettingsSubscription) { this.actionsSettingsSubscription.unsubscribe(); this.actionsSettingsSubscription = null; @@ -325,9 +307,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.advancedSettingsSubscription = this.advancedSettings.valueChanges.subscribe( () => this.updateAdvancedSettings() ); - this.oldAdvancedSettingsSubscription = this.oldAdvancedSettings.valueChanges.subscribe( - () => this.updateOldAdvancedSettings() - ); this.actionsSettingsSubscription = this.actionsSettings.valueChanges.subscribe( () => this.updateActionSettings() ); @@ -350,12 +329,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe value: 'appearance' } ); - this.headerOptions.push( - { - name: 'Old appearance', - value: 'oldAppearance' - } - ); } this.headerOptions.push( { @@ -409,8 +382,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe } this.advancedSettings.addControl('settings', this.fb.control(null, [])); - this.oldAdvancedSettings.addControl('settings', - this.fb.control(null, [])); } registerOnChange(fn: any): void { @@ -582,7 +553,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe } this.updateAdvancedForm(config.settings); - this.updateSchemaFormOld(config.settings); if (layout) { this.layoutSettings.patchValue( @@ -664,23 +634,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.advancedSettings.patchValue({ settings: dynamicFormData }, {emitEvent: false}); } - private updateSchemaFormOld(settings?: any) { - const widgetSettingsFormData: JsonFormComponentData = {}; - if (this.modelValue.settingsSchema && this.modelValue.settingsSchema.schema) { - widgetSettingsFormData.schema = this.modelValue.settingsSchema.schema; - widgetSettingsFormData.form = this.modelValue.settingsSchema.form || deepClone(defaultSettingsForm); - widgetSettingsFormData.groupInfoes = this.modelValue.settingsSchema.groupInfoes; - widgetSettingsFormData.model = settings; - } else { - widgetSettingsFormData.schema = deepClone(emptySettingsSchema); - widgetSettingsFormData.form = deepClone(defaultSettingsForm); - widgetSettingsFormData.groupInfoes = deepClone(emptySettingsGroupInfoes); - widgetSettingsFormData.model = settings || {}; - } - widgetSettingsFormData.settingsDirective = this.modelValue.settingsDirective; - this.oldAdvancedSettings.patchValue({ settings: widgetSettingsFormData }, {emitEvent: false}); - } - private updateDataSettings() { if (this.modelValue) { if (this.modelValue.config) { @@ -732,15 +685,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe } } - private updateOldAdvancedSettings() { - if (this.modelValue) { - if (this.modelValue.config) { - this.modelValue.config.settings = this.advancedSettings.get('settings').value?.model; - } - this.propagateChange(this.modelValue); - } - } - private updateActionSettings() { if (this.modelValue) { if (this.modelValue.config) { @@ -763,7 +707,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe } public get displayAdvancedAppearance(): boolean { - return !!this.modelValue && (!!this.modelValue.settingsSchema && !!this.modelValue.settingsSchema.schema || + return !!this.modelValue && (!!this.modelValue.settingsForm && !!this.modelValue.settingsForm.length || !!this.modelValue.settingsDirective && !!this.modelValue.settingsDirective.length); } @@ -802,7 +746,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe } } - public generateDataKey(chip: any, type: DataKeyType, datakeySettingsSchema: JsonSettingsSchema, + public generateDataKey(chip: any, type: DataKeyType, dataKeySettingsForm: FormProperty[], isLatestDataKey: boolean, dataKeySettingsFunction: DataKeySettingsFunction): DataKey { if (isObject(chip)) { (chip as DataKey)._hash = Math.random(); @@ -834,8 +778,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe } else if (type === DataKeyType.count) { result.name = 'count'; } - if (datakeySettingsSchema && isDefined(datakeySettingsSchema.schema)) { - result.settings = this.utils.generateObjectFromJsonSchema(datakeySettingsSchema.schema); + if (dataKeySettingsForm?.length) { + result.settings = defaultFormProperties(dataKeySettingsForm); } else if (dataKeySettingsFunction) { const settings = dataKeySettingsFunction(result, isLatestDataKey); if (settings) { diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 8de7dbfb8b..b1958cb3db 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -21,7 +21,6 @@ import { DatasourceData, FormattedData, fullWidgetTypeFqn, - JsonSettingsSchema, Widget, WidgetActionDescriptor, WidgetActionSource, @@ -562,9 +561,8 @@ export interface WidgetInfo extends WidgetTypeDescriptor, WidgetControllerDescri deprecated: boolean; scada: boolean; typeSettingsForm?: FormProperty[]; - typeSettingsSchema?: string | any; - typeDataKeySettingsSchema?: string | any; - typeLatestDataKeySettingsSchema?: string | any; + typeDataKeySettingsForm?: FormProperty[]; + typeLatestDataKeySettingsForm?: FormProperty[]; image?: string; description?: string; tags?: string[]; @@ -580,9 +578,8 @@ export interface WidgetConfigComponentData { actionSources: {[actionSourceId: string]: WidgetActionSource}; isDataEnabled: boolean; settingsForm: FormProperty[]; - settingsSchema: JsonSettingsSchema; - dataKeySettingsSchema: JsonSettingsSchema; - latestDataKeySettingsSchema: JsonSettingsSchema; + dataKeySettingsForm: FormProperty[]; + latestDataKeySettingsForm: FormProperty[]; dataKeySettingsFunction: DataKeySettingsFunction; settingsDirective: string; dataKeySettingsDirective: string; @@ -605,8 +602,8 @@ export const MissingWidgetType: WidgetInfo = { '
', templateCss: '', controllerScript: 'self.onInit = function() {}', - settingsSchema: '{}\n', - dataKeySettingsSchema: '{}\n', + settingsForm: [], + dataKeySettingsForm: [], image: null, description: null, defaultConfig: '{\n' + @@ -632,8 +629,8 @@ export const ErrorWidgetType: WidgetInfo = { '
', templateCss: '', controllerScript: 'self.onInit = function() {}', - settingsSchema: '{}\n', - dataKeySettingsSchema: '{}\n', + settingsForm: [], + dataKeySettingsForm: [], image: null, description: null, defaultConfig: '{\n' + @@ -646,9 +643,8 @@ export const ErrorWidgetType: WidgetInfo = { export interface WidgetTypeInstance { getSettingsForm?: () => FormProperty[]; - getSettingsSchema?: () => string; - getDataKeySettingsSchema?: () => string; - getLatestDataKeySettingsSchema?: () => string; + getDataKeySettingsForm?: () => FormProperty[]; + getLatestDataKeySettingsForm?: () => FormProperty[]; typeParameters?: () => WidgetTypeParameters; useCustomDatasources?: () => boolean; actionSources?: () => {[actionSourceId: string]: WidgetActionSource}; @@ -675,9 +671,8 @@ export const toWidgetInfo = (widgetTypeEntity: WidgetType): WidgetInfo => ({ templateCss: widgetTypeEntity.descriptor.templateCss, controllerScript: widgetTypeEntity.descriptor.controllerScript, settingsForm: widgetTypeEntity.descriptor.settingsForm, - settingsSchema: widgetTypeEntity.descriptor.settingsSchema, - dataKeySettingsSchema: widgetTypeEntity.descriptor.dataKeySettingsSchema, - latestDataKeySettingsSchema: widgetTypeEntity.descriptor.latestDataKeySettingsSchema, + dataKeySettingsForm: widgetTypeEntity.descriptor.dataKeySettingsForm, + latestDataKeySettingsForm: widgetTypeEntity.descriptor.latestDataKeySettingsForm, settingsDirective: widgetTypeEntity.descriptor.settingsDirective, dataKeySettingsDirective: widgetTypeEntity.descriptor.dataKeySettingsDirective, latestDataKeySettingsDirective: widgetTypeEntity.descriptor.latestDataKeySettingsDirective, @@ -705,9 +700,8 @@ export const toWidgetType = (widgetInfo: WidgetInfo, id: WidgetTypeId, tenantId: templateCss: widgetInfo.templateCss, controllerScript: widgetInfo.controllerScript, settingsForm: widgetInfo.settingsForm, - settingsSchema: widgetInfo.settingsSchema, - dataKeySettingsSchema: widgetInfo.dataKeySettingsSchema, - latestDataKeySettingsSchema: widgetInfo.latestDataKeySettingsSchema, + dataKeySettingsForm: widgetInfo.dataKeySettingsForm, + latestDataKeySettingsForm: widgetInfo.latestDataKeySettingsForm, settingsDirective: widgetInfo.settingsDirective, dataKeySettingsDirective: widgetInfo.dataKeySettingsDirective, latestDataKeySettingsDirective: widgetInfo.latestDataKeySettingsDirective, diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html index 02f0ecead8..5e550cdc69 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html @@ -199,52 +199,26 @@ - -
-
- - -
-
-
-
- -
-
- - -
-
+ +
+ +
- -
-
- - -
-
+ +
+ +
diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts index 0a3d711dee..71b30c1464 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts @@ -32,6 +32,7 @@ import { AppState } from '@core/core.state'; import { WidgetService } from '@core/http/widget.service'; import { detailsToWidgetInfo, WidgetInfo } from '@home/models/widget-component.models'; import { + migrateWidgetTypeToDynamicForms, TargetDeviceType, Widget, WidgetConfig, @@ -71,7 +72,7 @@ import { loadModulesCompleter } from '@shared/models/js-function.models'; import { TbPopoverService } from '@shared/components/popover.service'; import { JsFuncModulesComponent } from '@shared/components/js-func-modules.component'; import { MatIconButton } from '@angular/material/button'; -import { formPropertyCompletions, jsonFormSchemaToFormProperties } from '@shared/models/dynamic-form.models'; +import { formPropertyCompletions } from '@shared/models/dynamic-form.models'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import Timeout = NodeJS.Timeout; @@ -108,15 +109,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe @ViewChild('cssInput', {static: true}) cssInputElmRef: ElementRef; - @ViewChild('settingsJsonInput', {static: true}) - settingsJsonInputElmRef: ElementRef; - - @ViewChild('dataKeySettingsJsonInput', {static: true}) - dataKeySettingsJsonInputElmRef: ElementRef; - - @ViewChild('latestDataKeySettingsJsonInput', {static: true}) - latestDataKeySettingsJsonInputElmRef: ElementRef; - @ViewChild('javascriptInput', {static: true}) javascriptInputElmRef: ElementRef; @@ -154,9 +146,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe fullscreen = false; htmlFullscreen = false; cssFullscreen = false; - jsonSettingsFullscreen = false; - jsonDataKeySettingsFullscreen = false; - jsonLatestDataKeySettingsFullscreen = false; javascriptFullscreen = false; iFrameFullscreen = false; @@ -164,9 +153,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe editorsResizeCafs: {[editorId: string]: CancelAnimationFrame} = {}; htmlEditor: Ace.Editor; cssEditor: Ace.Editor; - jsonSettingsEditor: Ace.Editor; - dataKeyJsonSettingsEditor: Ace.Editor; - latestDataKeyJsonSettingsEditor: Ace.Editor; jsEditor: Ace.Editor; private initialCompleters: Ace.Completer[]; aceResize$: ResizeObserver; @@ -227,9 +213,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe const config = JSON.parse(this.widget.defaultConfig); this.widget.defaultConfig = JSON.stringify(config); } - if (!this.widget.settingsForm?.length) { - this.widget.settingsForm = jsonFormSchemaToFormProperties(this.widget.settingsSchema); - } this.origWidget = deepClone(this.widget); if (!this.widgetTypeDetails) { this.isDirty = true; @@ -360,45 +343,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe }) )); - editorsObservables.push(this.createAceEditor(this.settingsJsonInputElmRef, 'json').pipe( - tap((editor) => { - this.jsonSettingsEditor = editor; - this.jsonSettingsEditor.on('input', () => { - const editorValue = this.jsonSettingsEditor.getValue(); - if (this.widget.settingsSchema !== editorValue) { - this.widget.settingsSchema = editorValue; - this.isDirty = true; - } - }); - }) - )); - - editorsObservables.push(this.createAceEditor(this.dataKeySettingsJsonInputElmRef, 'json').pipe( - tap((editor) => { - this.dataKeyJsonSettingsEditor = editor; - this.dataKeyJsonSettingsEditor.on('input', () => { - const editorValue = this.dataKeyJsonSettingsEditor.getValue(); - if (this.widget.dataKeySettingsSchema !== editorValue) { - this.widget.dataKeySettingsSchema = editorValue; - this.isDirty = true; - } - }); - }) - )); - - editorsObservables.push(this.createAceEditor(this.latestDataKeySettingsJsonInputElmRef, 'json').pipe( - tap((editor) => { - this.latestDataKeyJsonSettingsEditor = editor; - this.latestDataKeyJsonSettingsEditor.on('input', () => { - const editorValue = this.latestDataKeyJsonSettingsEditor.getValue(); - if (this.widget.latestDataKeySettingsSchema !== editorValue) { - this.widget.latestDataKeySettingsSchema = editorValue; - this.isDirty = true; - } - }); - }) - )); - editorsObservables.push(this.createAceEditor(this.javascriptInputElmRef, 'javascript').pipe( tap((editor) => { this.jsEditor = editor; @@ -432,10 +376,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe private setAceEditorValues() { this.htmlEditor.setValue(this.widget.templateHtml ? this.widget.templateHtml : '', -1); this.cssEditor.setValue(this.widget.templateCss ? this.widget.templateCss : '', -1); - this.jsonSettingsEditor.setValue(this.widget.settingsSchema ? this.widget.settingsSchema : '', -1); - this.dataKeyJsonSettingsEditor.setValue(this.widget.dataKeySettingsSchema ? this.widget.dataKeySettingsSchema : '', -1); - this.latestDataKeyJsonSettingsEditor.setValue(this.widget.latestDataKeySettingsSchema ? - this.widget.latestDataKeySettingsSchema : '', -1); this.jsEditor.setValue(this.controllerScriptBody ? this.controllerScriptBody : '', -1); this.updateControllerScriptCompleters(); } @@ -608,7 +548,11 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe }), catchError((err) => { if (id && err.status === HttpStatusCode.Conflict) { - return this.widgetService.getWidgetTypeById(id.id); + return this.widgetService.getWidgetTypeById(id.id).pipe( + map((details) => { + return migrateWidgetTypeToDynamicForms(details); + }) + ); } return throwError(() => err); }), @@ -766,43 +710,6 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe ); } - beautifyJson(): void { - beautifyJs(this.widget.settingsSchema, {indent_size: 4}).subscribe( - (res) => { - if (this.widget.settingsSchema !== res) { - this.isDirty = true; - this.widget.settingsSchema = res; - this.jsonSettingsEditor.setValue(this.widget.settingsSchema ? this.widget.settingsSchema : '', -1); - } - } - ); - } - - beautifyDataKeyJson(): void { - beautifyJs(this.widget.dataKeySettingsSchema, {indent_size: 4}).subscribe( - (res) => { - if (this.widget.dataKeySettingsSchema !== res) { - this.isDirty = true; - this.widget.dataKeySettingsSchema = res; - this.dataKeyJsonSettingsEditor.setValue(this.widget.dataKeySettingsSchema ? this.widget.dataKeySettingsSchema : '', -1); - } - } - ); - } - - beautifyLatestDataKeyJson(): void { - beautifyJs(this.widget.latestDataKeySettingsSchema, {indent_size: 4}).subscribe( - (res) => { - if (this.widget.latestDataKeySettingsSchema !== res) { - this.isDirty = true; - this.widget.latestDataKeySettingsSchema = res; - this.latestDataKeyJsonSettingsEditor.setValue(this.widget.latestDataKeySettingsSchema ? - this.widget.latestDataKeySettingsSchema : '', -1); - } - } - ); - } - beautifyJs(): void { beautifyJs(this.controllerScriptBody, {indent_size: 4, wrap_line_length: 60}).subscribe( (res) => { @@ -890,6 +797,14 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe this.updateControllerScriptCompleters(); } + dataKeySettingsFormUpdated() { + this.isDirty = true; + } + + latestDataKeySettingsFormUpdated() { + this.isDirty = true; + } + editControllerScriptModules($event: Event, button: MatIconButton) { if ($event) { $event.stopPropagation(); diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts index 046737ac10..acd48f79ab 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts @@ -26,7 +26,12 @@ import { WidgetService } from '@core/http/widget.service'; import { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component'; import { map } from 'rxjs/operators'; import { detailsToWidgetInfo, WidgetInfo } from '@home/models/widget-component.models'; -import { widgetType, WidgetTypeDetails, WidgetTypeInfo } from '@app/shared/models/widget.models'; +import { + migrateWidgetTypeToDynamicForms, + widgetType, + WidgetTypeDetails, + WidgetTypeInfo +} from '@app/shared/models/widget.models'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { RouterTabsComponent } from '@home/components/router-tabs.component'; import { WidgetTypesTableConfigResolver } from '@home/pages/widget/widget-types-table-config.resolver'; @@ -68,10 +73,13 @@ const widgetEditorDataResolver: ResolveFn = (route: ActivatedR ); } else { return inject(WidgetService).getWidgetTypeById(widgetTypeId).pipe( - map((result) => ({ - widgetTypeDetails: result, - widget: detailsToWidgetInfo(result) - })) + map((result) => { + result = migrateWidgetTypeToDynamicForms(result); + return { + widgetTypeDetails: result, + widget: detailsToWidgetInfo(result) + }; + }) ); } }; diff --git a/ui-ngx/src/app/shared/components/json-form/json-form-component.models.ts b/ui-ngx/src/app/shared/components/json-form/json-form-component.models.ts deleted file mode 100644 index 75bcf2d1fd..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/json-form-component.models.ts +++ /dev/null @@ -1,23 +0,0 @@ -/// -/// Copyright © 2016-2024 The Thingsboard Authors -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// - - -import { JsonSettingsSchema } from '@shared/models/widget.models'; - -export interface JsonFormComponentData extends JsonSettingsSchema { - model?: any; - settingsDirective?: string; -} diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.html b/ui-ngx/src/app/shared/components/json-form/json-form.component.html deleted file mode 100644 index 0ed848ded5..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.html +++ /dev/null @@ -1,23 +0,0 @@ - -
-
-
-
diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.scss b/ui-ngx/src/app/shared/components/json-form/json-form.component.scss deleted file mode 100644 index 3ab3d5f26b..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.scss +++ /dev/null @@ -1,20 +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. - */ -.tb-json-form { - padding: 12px; - padding-bottom: 14px !important; - overflow: auto; -} diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts deleted file mode 100644 index 76647b5bae..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts +++ /dev/null @@ -1,293 +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 { - ChangeDetectorRef, - Component, - ElementRef, - forwardRef, - Input, - OnChanges, - OnDestroy, - Renderer2, - SimpleChanges, - ViewChild, ViewContainerRef, - ViewEncapsulation -} from '@angular/core'; -import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { deepClone, isString, unwrapModule } from '@app/core/utils'; -import { JsonFormProps } from './react/json-form.models'; -import inspector from 'schema-inspector'; -import tinycolor from 'tinycolor2'; -import { DialogService } from '@app/core/services/dialog.service'; -import JsonFormUtils from './react/json-form-utils'; -import { JsonFormComponentData } from './json-form-component.models'; -import { GroupInfo } from '@shared/models/widget.models'; -import { Observable } from 'rxjs/internal/Observable'; -import { forkJoin, from } from 'rxjs'; -import { TbPopoverService } from '@shared/components/popover.service'; - -@Component({ - selector: 'tb-json-form', - templateUrl: './json-form.component.html', - styleUrls: ['./json-form.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => JsonFormComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => JsonFormComponent), - multi: true, - } - ], - encapsulation: ViewEncapsulation.None -}) -export class JsonFormComponent implements ControlValueAccessor, Validator, OnChanges, OnDestroy { - - @ViewChild('reactRoot', {static: true}) - reactRootElmRef: ElementRef; - - @ViewChild('reactFullscreen', {static: true}) - reactFullscreenElmRef: ElementRef; - - private readonlyValue: boolean; - get readonly(): boolean { - return this.readonlyValue; - } - @Input() - set required(value: boolean) { - this.readonlyValue = coerceBooleanProperty(value); - } - - formProps: JsonFormProps = { - isFullscreen: false, - option: { - formDefaults: { - startEmpty: true - } - }, - onModelChange: this.onModelChange.bind(this), - onColorClick: this.onColorClick.bind(this), - onIconClick: this.onIconClick.bind(this), - onToggleFullscreen: this.onToggleFullscreen.bind(this), - onHelpClick: this.onHelpClick.bind(this) - }; - - data: JsonFormComponentData; - - model: any; - schema: any; - form: any; - groupInfoes: GroupInfo[]; - - isModelValid = true; - - isFullscreen = false; - fullscreenFinishFn: (el: Element) => void; - - private reactRoot: any; - - private propagateChange = null; - private propagateChangePending = false; - private writingValue = false; - private updateViewPending = false; - - constructor(public elementRef: ElementRef, - private dialogs: DialogService, - private popoverService: TbPopoverService, - private renderer: Renderer2, - private viewContainerRef: ViewContainerRef, - protected store: Store, - private cd: ChangeDetectorRef) { - } - - ngOnDestroy(): void { - this.destroyReactSchemaForm(); - } - - registerOnChange(fn: any): void { - this.propagateChange = fn; - if (this.propagateChangePending) { - this.propagateChangePending = false; - setTimeout(() => { - this.propagateChange(this.data); - }, 0); - } - } - - registerOnTouched(fn: any): void { - } - - setDisabledState(isDisabled: boolean): void { - } - - public validate(c: UntypedFormControl) { - return this.isModelValid ? null : { - modelValid: false - }; - } - - writeValue(data: JsonFormComponentData): void { - this.writingValue = true; - this.data = data; - this.schema = this.data && this.data.schema ? deepClone(this.data.schema) : { - type: 'object' - }; - this.schema.strict = true; - this.form = this.data && this.data.form ? deepClone(this.data.form) : [ '*' ]; - this.groupInfoes = this.data && this.data.groupInfoes ? deepClone(this.data.groupInfoes) : []; - this.model = this.data && this.data.model || {}; - this.model = inspector.sanitize(this.schema, this.model).data; - this.updateAndRender(); - this.isModelValid = this.validateModel(); - this.writingValue = false; - if (!this.isModelValid || this.updateViewPending) { - this.updateView(); - } -} - - updateView() { - if (!this.writingValue) { - this.updateViewPending = false; - if (this.data) { - this.data.model = this.model; - if (this.propagateChange) { - try { - this.propagateChange(this.data); - } catch (e) { - this.propagateChangePending = true; - } - } else { - this.propagateChangePending = true; - } - } - } else { - this.updateViewPending = true; - } - } - - ngOnChanges(changes: SimpleChanges): void { - for (const propName of Object.keys(changes)) { - const change = changes[propName]; - if (!change.firstChange && change.currentValue !== change.previousValue) { - if (propName === 'readonly') { - this.updateAndRender(); - } - } - } - } - - private onModelChange(key: (string | number)[], val: any, forceUpdate = false) { - if (isString(val) && val === '') { - val = undefined; - } - if (JsonFormUtils.updateValue(key, this.model, val) || forceUpdate) { - this.isModelValid = this.validateModel(); - this.updateView(); - } - } - - private onColorClick(key: (string | number)[], - val: tinycolor.ColorFormats.RGBA, - colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) { - this.dialogs.colorPicker(tinycolor(val).toRgbString()).subscribe((result) => { - if (!result?.canceled && colorSelectedFn) { - colorSelectedFn(tinycolor(result?.color).toRgb()); - } - }); - } - - private onIconClick(key: (string | number)[], - val: string, - iconSelectedFn: (icon: string) => void) { - this.dialogs.materialIconPicker(val).subscribe((result) => { - if (!result?.canceled && iconSelectedFn) { - iconSelectedFn(result?.icon); - } - }); - } - - private onToggleFullscreen(fullscreenFinishFn?: (el: Element) => void) { - this.isFullscreen = !this.isFullscreen; - this.fullscreenFinishFn = fullscreenFinishFn; - this.cd.markForCheck(); - } - - onFullscreenChanged(fullscreen: boolean) { - this.formProps.isFullscreen = fullscreen; - this.renderReactSchemaForm(false); - if (this.fullscreenFinishFn) { - this.fullscreenFinishFn(this.reactFullscreenElmRef.nativeElement); - this.fullscreenFinishFn = null; - } - } - - private onHelpClick(event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, helpReadyFn: (ready: boolean) => void) { - const trigger = event.currentTarget as Element; - this.popoverService.toggleHelpPopover(trigger, this.renderer, this.viewContainerRef, helpId, '', '', null, helpVisibleFn, helpReadyFn); - } - - private updateAndRender() { - - this.formProps.option.formDefaults.readonly = this.readonly; - this.formProps.schema = this.schema; - this.formProps.form = this.form; - this.formProps.groupInfoes = this.groupInfoes; - this.formProps.model = this.model; - this.renderReactSchemaForm(); - } - - private renderReactSchemaForm(destroy: boolean = true) { - if (destroy) { - this.destroyReactSchemaForm(); - } - - // import ReactSchemaForm from './react/json-form-react'; - const reactSchemaFormObservables: Observable[] = [ - from(import('react')), - from(import('react-dom')), - from(import('react-dom/client')), - from(import('./react/json-form-react')) - ]; - forkJoin(reactSchemaFormObservables).subscribe( - (modules) => { - const react = unwrapModule(modules[0]); - const reactDomClient = unwrapModule(modules[2]); - const jsonFormReact = unwrapModule(modules[3]); - this.reactRoot = reactDomClient.createRoot(this.reactRootElmRef.nativeElement); - this.reactRoot.render(react.createElement(jsonFormReact, this.formProps)); - } - ); - } - - private destroyReactSchemaForm() { - this.reactRoot?.unmount(); - } - - private validateModel(): boolean { - if (this.schema && this.model) { - return JsonFormUtils.validateBySchema(this.schema, this.model).valid; - } - return true; - } -} - diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx deleted file mode 100644 index 649ee16c95..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx +++ /dev/null @@ -1,239 +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 * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import ThingsboardBaseComponent from './json-form-base-component'; -import reactCSS from 'reactcss'; -import Button from '@mui/material/Button'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { IEditorProps } from 'react-ace/src/types'; -import { map, mergeMap } from 'rxjs/operators'; -import { getAce } from '@shared/models/ace/ace.models'; -import { from, lastValueFrom } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { CircularProgress, IconButton } from '@mui/material'; -import { MouseEvent } from 'react'; -import { Help, HelpOutline } from '@mui/icons-material'; -import { unwrapModule } from '@core/utils'; - -const ReactAce = React.lazy(() => { - return lastValueFrom(getAce().pipe( - mergeMap(() => { - return from(import('react-ace')).pipe( - map((module) => unwrapModule(module) - )); - }) - )); -}); - -interface ThingsboardAceEditorProps extends JsonFormFieldProps { - mode: string; - onTidy: (value: string) => Observable; -} - -interface ThingsboardAceEditorState extends JsonFormFieldState { - isFull: boolean; - fullscreenContainerElement: Element; - helpVisible: boolean; - helpReady: boolean; - focused: boolean; -} - -class ThingsboardAceEditor extends React.Component { - - private aceEditor: IEditorProps; - - constructor(props: ThingsboardAceEditorProps) { - super(props); - this.onValueChanged = this.onValueChanged.bind(this); - this.onBlur = this.onBlur.bind(this); - this.onFocus = this.onFocus.bind(this); - this.onTidy = this.onTidy.bind(this); - this.onHelp = this.onHelp.bind(this); - this.onLoad = this.onLoad.bind(this); - this.onToggleFull = this.onToggleFull.bind(this); - const value = props.value ? props.value + '' : ''; - this.state = { - isFull: false, - fullscreenContainerElement: null, - helpVisible: false, - helpReady: true, - value, - focused: false - }; - } - - onValueChanged(value) { - this.setState({ - value - }); - this.props.onChangeValidate({ - target: { - value - } - }); - } - - onBlur() { - this.setState({ focused: false }); - } - - onFocus() { - this.setState({ focused: true }); - } - - onTidy() { - if (!this.props.form.readonly) { - const value = this.state.value; - this.props.onTidy(value).subscribe( - (processedValue) => { - this.setState({ - value: processedValue - }); - this.props.onChangeValidate({ - target: { - value: processedValue - } - }); - } - ); - } - } - - onHelp(event: MouseEvent) { - if (this.state.helpVisible && !this.state.helpReady) { - event.preventDefault(); - event.stopPropagation(); - } else { - this.props.onHelpClick(event, this.props.form.helpId, - (visible) => { - this.setState({ - helpVisible: visible - }); - }, (ready) => { - this.setState({ - helpReady: ready - }); - }); - } - } - - onLoad(editor: IEditorProps) { - this.aceEditor = editor; - } - - onToggleFull() { - this.props.onToggleFullscreen((el) => { - this.setState({ isFull: !this.state.isFull, fullscreenContainerElement: el }); - }); - } - - componentDidUpdate() { - } - - render() { - - const styles = reactCSS({ - default: { - tidyButtonStyle: { - color: '#7B7B7B', - minWidth: '32px', - minHeight: '15px', - lineHeight: '15px', - fontSize: '0.800rem', - margin: '0', - padding: '4px', - height: '23px', - borderRadius: '5px', - marginLeft: '5px' - } - } - }); - - let labelClass = 'tb-label'; - if (this.props.form.required) { - labelClass += ' tb-required'; - } - if (this.props.form.readonly) { - labelClass += ' tb-readonly'; - } - if (this.state.focused) { - labelClass += ' tb-focused'; - } - let containerClass = 'tb-container'; - const style = this.props.form.style || {width: '100%'}; - if (this.state.isFull) { - containerClass += ' fullscreen-form-field'; - } - const formDom = ( -
- -
-
- - { this.props.onTidy ? : null } - { this.props.form.helpId ?
- - {this.state.helpVisible ? : } - - { this.state.helpVisible && !this.state.helpReady ? -
- -
: null }
: null } - -
- Loading...
}> - - -
-
{this.props.error}
-
- ); - if (this.state.isFull) { - return ReactDOM.createPortal(formDom, this.state.fullscreenContainerElement); - } else { - return ( -
- {formDom} -
- ); - } - } -} - -export default ThingsboardBaseComponent(ThingsboardAceEditor); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-array.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-array.tsx deleted file mode 100644 index 681fe69aab..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-array.tsx +++ /dev/null @@ -1,177 +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 * as React from 'react'; -import JsonFormUtils from './json-form-utils'; -import ThingsboardBaseComponent from './json-form-base-component'; -import Button from '@mui/material/Button'; -import _ from 'lodash'; -import IconButton from '@mui/material/IconButton'; -import Clear from '@mui/icons-material/Clear'; -import Add from '@mui/icons-material/Add'; -import Tooltip from '@mui/material/Tooltip'; -import { - JsonFormData, - JsonFormFieldProps, - JsonFormFieldState -} from '@shared/components/json-form/react/json-form.models'; - -interface ThingsboardArrayState extends JsonFormFieldState { - model: any[]; - keys: number[]; -} - -class ThingsboardArray extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onAppend = this.onAppend.bind(this); - this.onDelete = this.onDelete.bind(this); - const model = JsonFormUtils.selectOrSet(this.props.form.key, this.props.model) || []; - const keys: number[] = []; - for (let i = 0; i < model.length; i++) { - keys.push(i); - } - this.state = { - model, - keys - }; - } - - componentDidMount() { - if (this.props.form.startEmpty !== true && this.state.model.length === 0) { - this.onAppend(); - } - } - - onAppend() { - let empty; - if (this.props.form && this.props.form.schema && this.props.form.schema.items) { - const items = this.props.form.schema.items; - if (items.type && items.type.indexOf('object') !== -1) { - empty = {}; - if (!this.props.options || this.props.options.setSchemaDefaults !== false) { - empty = typeof items.default !== 'undefined' ? items.default : empty; - if (empty) { - JsonFormUtils.traverseSchema(items, (prop, path) => { - if (typeof prop.default !== 'undefined') { - JsonFormUtils.selectOrSet(path, empty, prop.default); - } - }); - } - } - } else if (items.type && items.type.indexOf('array') !== -1) { - empty = []; - if (!this.props.options || this.props.options.setSchemaDefaults !== false) { - empty = items.default || empty; - } - } else { - if (!this.props.options || this.props.options.setSchemaDefaults !== false) { - empty = items.default || empty; - } - } - } - const newModel = this.state.model; - newModel.push(empty); - const newKeys = this.state.keys; - let key = 0; - if (newKeys.length > 0) { - key = newKeys[newKeys.length - 1] + 1; - } - newKeys.push(key); - this.setState({ - model: newModel, - keys: newKeys - } - ); - this.props.onChangeValidate(this.state.model, true); - } - - onDelete(index: number) { - const newModel = this.state.model; - newModel.splice(index, 1); - const newKeys = this.state.keys; - newKeys.splice(index, 1); - this.setState( - { - model: newModel, - keys: newKeys - } - ); - this.props.onChangeValidate(this.state.model, true); - } - - setIndex(index: number) { - return (form: JsonFormData) => { - if (form.key) { - form.key[form.key.indexOf('')] = index; - } - }; - } - - copyWithIndex(form: JsonFormData, index: number): JsonFormData { - const copy: JsonFormData = _.cloneDeep(form); - copy.arrayIndex = index; - JsonFormUtils.traverseForm(copy, this.setIndex(index)); - return copy; - } - - render() { - const arrays = []; - const model = this.state.model; - const keys = this.state.keys; - for (let i = 0; i < model.length; i++ ) { - let removeButton: React.JSX.Element = null; - if (!this.props.form.readonly) { - const boundOnDelete = this.onDelete.bind(this, i); - removeButton = ; - } - const forms = (this.props.form.items as JsonFormData[]).map((form, index) => { - const copy = this.copyWithIndex(form, i); - return this.props.builder(copy, this.props.model, index, this.props.onChange, - this.props.onColorClick, this.props.onIconClick, this.props.onToggleFullscreen, - this.props.onHelpClick, this.props.mapper); - }); - arrays.push( -
  • - {removeButton} - {forms} -
  • - ); - } - let addButton: JSX.Element = null; - if (!this.props.form.readonly) { - addButton = ; - } - - return ( -
    -
    -
    {this.props.form.title}
    -
      - {arrays} -
    -
    - {addButton} -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardArray); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx deleted file mode 100644 index 4e9687ce3a..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-base-component.tsx +++ /dev/null @@ -1,122 +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 * as React from 'react'; -import JsonFormUtils from './json-form-utils'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { isDefinedAndNotNull } from '@core/utils'; - -export default ThingsboardBaseComponent => class

    - extends React.Component { - - constructor(props: P) { - super(props); - this.onChangeValidate = this.onChangeValidate.bind(this); - const value = this.defaultValue(); - const validationResult = JsonFormUtils.validate(this.props.form, value); - this.state = { - value, - valid: !!(validationResult.valid || !value), - error: !validationResult.valid && value ? validationResult.error.message : null - }; - } - - componentDidMount() { - if (typeof this.state.value !== 'undefined') { - this.props.onChange(this.props.form.key, this.state.value); - } - } - - onChangeValidate(e, forceUpdate?: boolean) { - let value = null; - if (this.props.form.schema.type === 'integer' || this.props.form.schema.type === 'number') { - if (!e || e.target?.value === null || e.target?.value === '') { - value = undefined; - } else if (typeof e === 'number') { - value = Number(e); - } else if (e.target.value.indexOf('.') === -1) { - value = parseInt(e.target.value, 10); - } else { - value = parseFloat(e.target.value); - } - } else if (this.props.form.schema.type === 'boolean') { - value = e.target.checked; - } else if (this.props.form.schema.type === 'date' || this.props.form.schema.type === 'array') { - value = e; - } else { // string - value = e.target.value; - } - const validationResult = JsonFormUtils.validate(this.props.form, value); - this.setState({ - value, - valid: validationResult.valid, - error: validationResult.valid ? null : validationResult.error.message - }); - this.props.onChange(this.props.form.key, value, forceUpdate); - } - - defaultValue() { - let value = JsonFormUtils.selectOrSet(this.props.form.key, this.props.model); - if (this.props.form.schema.type === 'boolean') { - if (typeof value !== 'boolean' && typeof this.props.form.default === 'boolean') { - value = this.props.form.default; - } - if (typeof value !== 'boolean' && this.props.form.schema && typeof this.props.form.schema.default === 'boolean') { - value = this.props.form.schema.default; - } - if (typeof value !== 'boolean' && - this.props.form.schema && - this.props.form.required) { - value = false; - } - } else if (this.props.form.schema.type === 'integer' || this.props.form.schema.type === 'number') { - if (typeof value !== 'number' && typeof this.props.form.default === 'number') { - value = this.props.form.default; - } - if (typeof value !== 'number' && this.props.form.schema && typeof this.props.form.schema.default === 'number') { - value = this.props.form.schema.default; - } - if (typeof value !== 'number' && this.props.form.titleMap && typeof this.props.form.titleMap[0].value === 'number') { - value = this.props.form.titleMap[0].value; - } - if (value && typeof value === 'string') { - if (value.indexOf('.') === -1) { - value = parseInt(value, 10); - } else { - value = parseFloat(value); - } - } - } else { - if (!value && isDefinedAndNotNull(this.props.form.default)) { - value = this.props.form.default; - } - if (!value && this.props.form.schema && isDefinedAndNotNull(this.props.form.schema.default)) { - value = this.props.form.schema.default; - } - if (!value && this.props.form.titleMap && isDefinedAndNotNull(this.props.form.titleMap[0].value)) { - value = this.props.form.titleMap[0].value; - } - } - return value; - } - - render() { - if (this.props.form && this.props.form.schema) { - return ; - } else { - return

    ; - } - } -}; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-checkbox.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-checkbox.tsx deleted file mode 100644 index fd3bac8f2c..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-checkbox.tsx +++ /dev/null @@ -1,46 +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 * as React from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import Checkbox from '@mui/material/Checkbox'; -import { JsonFormFieldProps, JsonFormFieldState } from './json-form.models.js'; -import FormControlLabel from '@mui/material/FormControlLabel'; - -class ThingsboardCheckbox extends React.Component { - render() { - return ( -
    - { - this.props.onChangeValidate(e); - }} - /> - } - label={this.props.form.title} - /> -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardCheckbox); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx deleted file mode 100644 index bf3a245663..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx +++ /dev/null @@ -1,186 +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 * as React from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import reactCSS from 'reactcss'; -import tinycolor from 'tinycolor2'; -import TextField from '@mui/material/TextField'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import IconButton from '@mui/material/IconButton'; -import Clear from '@mui/icons-material/Clear'; -import Tooltip from '@mui/material/Tooltip'; - -interface ThingsboardColorState extends JsonFormFieldState { - color: tinycolor.ColorFormats.RGBA | null; - focused: boolean; -} - -class ThingsboardColor extends React.Component { - - containerRef = React.createRef(); - - constructor(props: JsonFormFieldProps) { - super(props); - this.onBlur = this.onBlur.bind(this); - this.onFocus = this.onFocus.bind(this); - this.onValueChanged = this.onValueChanged.bind(this); - this.onSwatchClick = this.onSwatchClick.bind(this); - this.onClear = this.onClear.bind(this); - const value = props.value ? props.value + '' : null; - const color = value != null ? tinycolor(value).toRgb() : null; - this.state = { - color, - focused: false - }; - } - - onBlur() { - this.setState({focused: false}); - } - - onFocus() { - this.setState({focused: true}); - } - - componentDidMount() { - const node = this.containerRef.current; - const colContainer = $(node).children('#color-container'); - colContainer.click(() => { - if (!this.props.form.readonly) { - this.onSwatchClick(); - } - }); - } - - componentWillUnmount() { - const node = this.containerRef.current; - const colContainer = $(node).children('#color-container'); - colContainer.off( 'click' ); - } - - onValueChanged(value: tinycolor.ColorFormats.RGBA | null) { - let color: tinycolor.Instance = null; - if (value != null) { - color = tinycolor(value); - } - this.setState({ - color: value - }); - let colorValue = ''; - if (color != null && color.getAlpha() !== 1) { - colorValue = color.toRgbString(); - } else if (color != null) { - colorValue = color.toHexString(); - } - this.props.onChangeValidate({ - target: { - value: colorValue - } - }); - } - - onSwatchClick() { - this.props.onColorClick(this.props.form.key, this.state.color, - (color) => { - this.onValueChanged(color); - } - ); - } - - onClear(event: React.MouseEvent) { - if (event) { - event.stopPropagation(); - } - this.onValueChanged(null); - } - - render() { - - let background = 'rgba(0,0,0,0)'; - if (this.state.color != null) { - background = `rgba(${ this.state.color.r }, ${ this.state.color.g }, ${ this.state.color.b }, ${ this.state.color.a })`; - } - - const styles = reactCSS({ - default: { - color: { - background: `${ background }` - }, - swatch: { - display: 'inline-block', - marginRight: '10px', - marginTop: 'auto', - marginBottom: 'auto', - cursor: 'pointer', - opacity: `${ this.props.form.readonly ? '0.6' : '1' }` - }, - swatchText: { - width: '100%' - }, - container: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center' - }, - colorContainer: { - display: 'flex', - width: '100%' - } - }, - }); - - let fieldClass = 'tb-field'; - if (this.props.form.required) { - fieldClass += ' tb-required'; - } - if (this.props.form.readonly) { - fieldClass += ' tb-readonly'; - } - if (this.state.focused) { - fieldClass += ' tb-focused'; - } - - let stringColor = ''; - if (this.state.color != null) { - const color = tinycolor(this.state.color); - stringColor = color.toRgbString(); - } - - return ( -
    -
    -
    -
    -
    - -
    - -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardColor); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-css.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-css.tsx deleted file mode 100644 index 600ae8c12b..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-css.tsx +++ /dev/null @@ -1,40 +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 * as React from 'react'; -import ThingsboardAceEditor from './json-form-ace-editor'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { Observable } from 'rxjs/internal/Observable'; -import { beautifyCss } from '@shared/models/beautify.models'; - -class ThingsboardCss extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onTidyCss = this.onTidyCss.bind(this); - } - - onTidyCss(css: string): Observable { - return beautifyCss(css, {indent_size: 4}); - } - - render() { - return ( - - ); - } -} - -export default ThingsboardCss; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-date.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-date.tsx deleted file mode 100644 index 3b253cfa8e..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-date.tsx +++ /dev/null @@ -1,83 +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 * as React from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment' -import { LocalizationProvider, DatePicker } from '@mui/x-date-pickers'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import moment from 'moment'; - -interface ThingsboardDateState extends JsonFormFieldState { - currentValue: Date | null; -} - -class ThingsboardDate extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onDatePicked = this.onDatePicked.bind(this); - let value: Date | null = null; - if (this.props.value && typeof this.props.value === 'number') { - value = new Date(this.props.value); - } - this.state = { - currentValue: value - }; - } - - - onDatePicked(date: moment.Moment | null) { - this.setState({ - currentValue: date?.toDate() - }); - this.props.onChangeValidate(date ? date.valueOf() : null); - } - - render() { - - let fieldClass = 'tb-date-field'; - if (this.props.form.required) { - fieldClass += ' tb-required'; - } - if (this.props.form.readonly) { - fieldClass += ' tb-readonly'; - } - - return ( - -
    - - -
    -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardDate); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-fieldset.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-fieldset.tsx deleted file mode 100644 index 31f09fc409..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-fieldset.tsx +++ /dev/null @@ -1,44 +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 * as React from 'react'; -import { - JsonFormData, - JsonFormFieldProps, - JsonFormFieldState -} from '@shared/components/json-form/react/json-form.models'; - -class ThingsboardFieldSet extends React.Component { - - render() { - const forms = (this.props.form.items as JsonFormData[]).map((form: JsonFormData, index) => { - return this.props.builder(form, this.props.model, index, this.props.onChange, - this.props.onColorClick, this.props.onIconClick, this.props.onToggleFullscreen, this.props.onHelpClick, this.props.mapper); - }); - - return ( -
    -
    - {this.props.form.title} -
    -
    - {forms} -
    -
    - ); - } -} - -export default ThingsboardFieldSet; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-help.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-help.tsx deleted file mode 100644 index 68536f457e..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-help.tsx +++ /dev/null @@ -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 * as React from 'react'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; - -class ThingsboardHelp extends React.Component { - render() { - return ( -
    - ); - } -} - -export default ThingsboardHelp; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-html.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-html.tsx deleted file mode 100644 index f267154182..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-html.tsx +++ /dev/null @@ -1,40 +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 * as React from 'react'; -import ThingsboardAceEditor from './json-form-ace-editor'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { Observable } from 'rxjs/internal/Observable'; -import { beautifyHtml } from '@shared/models/beautify.models'; - -class ThingsboardHtml extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onTidyHtml = this.onTidyHtml.bind(this); - } - - onTidyHtml(html: string): Observable { - return beautifyHtml(html, {indent_size: 4}); - } - - render() { - return ( - - ); - } -} - -export default ThingsboardHtml; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-icon.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-icon.tsx deleted file mode 100644 index 00366b86e8..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-icon.tsx +++ /dev/null @@ -1,162 +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 * as React from 'react'; -import { MouseEvent } from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import reactCSS from 'reactcss'; -import TextField from '@mui/material/TextField'; -import IconButton from '@mui/material/IconButton'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import Clear from '@mui/icons-material/Clear'; -import Icon from '@mui/material/Icon'; -import Tooltip from '@mui/material/Tooltip'; - -interface ThingsboardIconState extends JsonFormFieldState { - icon: string | null; - focused: boolean; -} - -class ThingsboardIcon extends React.Component { - - containerRef = React.createRef(); - - constructor(props: JsonFormFieldProps) { - super(props); - this.onBlur = this.onBlur.bind(this); - this.onFocus = this.onFocus.bind(this); - this.onValueChanged = this.onValueChanged.bind(this); - this.onIconClick = this.onIconClick.bind(this); - this.onClear = this.onClear.bind(this); - const icon = props.value ? props.value : ''; - this.state = { - icon, - focused: false - }; - } - - onBlur() { - this.setState({focused: false}); - } - - onFocus() { - this.setState({focused: true}); - } - - componentDidMount() { - const node = this.containerRef.current; - const iconContainer = $(node).children('#icon-container'); - iconContainer.on('click', (event) => { - if (!this.props.form.readonly) { - this.onIconClick(event); - } - }); - } - - componentWillUnmount() { - const node = this.containerRef.current; - const iconContainer = $(node).children('#icon-container'); - iconContainer.off( 'click' ); - } - - onValueChanged(value: string | null) { - this.setState({ - icon: value - }); - this.props.onChange(this.props.form.key, value); - } - - onIconClick(_event) { - this.props.onIconClick(this.props.form.key, this.state.icon, - (color) => { - this.onValueChanged(color); - } - ); - } - - onClear(event: MouseEvent) { - if (event) { - event.stopPropagation(); - } - this.onValueChanged(''); - } - - render() { - - const styles = reactCSS({ - default: { - container: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center' - }, - icon: { - padding: '12px', - marginRight: '10px', - marginBottom: 'auto', - cursor: 'pointer', - border: 'solid 1px rgba(0, 0, 0, .27)', - borderRadius: '0' - }, - iconContainer: { - display: 'flex', - width: '100%' - }, - iconText: { - width: '100%' - }, - }, - }); - - let fieldClass = 'tb-field'; - if (this.props.form.required) { - fieldClass += ' tb-required'; - } - if (this.state.focused) { - fieldClass += ' tb-focused'; - } - - let pickedIcon = 'more_horiz'; - let icon = ''; - if (this.state.icon !== '') { - pickedIcon = this.state.icon; - icon = this.state.icon; - } - - return ( -
    -
    - - {pickedIcon} - - -
    - -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardIcon); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-image.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-image.tsx deleted file mode 100644 index 2a03d95669..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-image.tsx +++ /dev/null @@ -1,108 +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 React, { MouseEvent } from 'react'; -import Dropzone from 'react-dropzone'; -import ThingsboardBaseComponent from './json-form-base-component'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import IconButton from '@mui/material/IconButton'; -import Clear from '@mui/icons-material/Clear'; -import Tooltip from '@mui/material/Tooltip'; - -interface ThingsboardImageState extends JsonFormFieldState { - imageUrl: string; -} - -class ThingsboardImage extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onDrop = this.onDrop.bind(this); - this.onClear = this.onClear.bind(this); - const value = props.value ? props.value + '' : null; - this.state = { - imageUrl: value - }; - } - - onDrop(acceptedFiles: File[]) { - const reader = new FileReader(); - reader.onload = () => { - this.onValueChanged(reader.result as string); - }; - reader.readAsDataURL(acceptedFiles[0]); - } - - onValueChanged(value: string) { - this.setState({ - imageUrl: value - }); - this.props.onChangeValidate({ - target: { - value - } - }); - } - - onClear(event: MouseEvent) { - if (event) { - event.stopPropagation(); - } - this.onValueChanged(''); - } - - render() { - - let labelClass = 'tb-label'; - if (this.props.form.required) { - labelClass += ' tb-required'; - } - if (this.props.form.readonly) { - labelClass += ' tb-readonly'; - } - - let previewComponent: React.JSX.Element; - if (this.state.imageUrl) { - previewComponent = ; - } else { - previewComponent =
    No image selected
    ; - } - - return ( -
    - -
    -
    {previewComponent}
    -
    - - - -
    - - {({getRootProps, getInputProps}) => ( -
    -
    Drop an image or click to select a file to upload.
    - -
    - )} -
    -
    -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardImage); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-javascript.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-javascript.tsx deleted file mode 100644 index 74d01137a8..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-javascript.tsx +++ /dev/null @@ -1,40 +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 * as React from 'react'; -import ThingsboardAceEditor from './json-form-ace-editor'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { Observable } from 'rxjs/internal/Observable'; -import { beautifyJs } from '@shared/models/beautify.models'; - -class ThingsboardJavaScript extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onTidyJavascript = this.onTidyJavascript.bind(this); - } - - onTidyJavascript(javascript: string): Observable { - return beautifyJs(javascript, {indent_size: 4, wrap_line_length: 60}); - } - - render() { - return ( - - ); - } -} - -export default ThingsboardJavaScript; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-json.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-json.tsx deleted file mode 100644 index 9ab839616b..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-json.tsx +++ /dev/null @@ -1,40 +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 * as React from 'react'; -import ThingsboardAceEditor from './json-form-ace-editor'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { Observable } from 'rxjs/internal/Observable'; -import { beautifyJs } from '@shared/models/beautify.models'; - -class ThingsboardJson extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onTidyJson = this.onTidyJson.bind(this); - } - - onTidyJson(json: string): Observable { - return beautifyJs(json, {indent_size: 4}); - } - - render() { - return ( - - ); - } -} - -export default ThingsboardJson; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-markdown.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-markdown.tsx deleted file mode 100644 index 57fb97ae23..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-markdown.tsx +++ /dev/null @@ -1,33 +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 * as React from 'react'; -import ThingsboardAceEditor from './json-form-ace-editor'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; - -class ThingsboardMarkdown extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - } - - render() { - return ( - - ); - } -} - -export default ThingsboardMarkdown; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-number.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-number.tsx deleted file mode 100644 index 4616324de2..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-number.tsx +++ /dev/null @@ -1,99 +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 * as React from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import { TextField } from '@mui/material'; -import { ChangeEvent } from 'react'; - -interface ThingsboardNumberState extends JsonFormFieldState { - focused: boolean; - lastSuccessfulValue: number; -} - -class ThingsboardNumber extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.preValidationCheck = this.preValidationCheck.bind(this); - this.onBlur = this.onBlur.bind(this); - this.onFocus = this.onFocus.bind(this); - this.state = { - lastSuccessfulValue: this.props.value, - focused: false - }; - } - - isNumeric(n: any) { - return n === null || n === '' || !isNaN(n) && isFinite(n); - } - - onBlur() { - this.setState({focused: false}); - } - - onFocus() { - this.setState({focused: true}); - } - - preValidationCheck(e: ChangeEvent) { - if (this.isNumeric(e.target.value)) { - this.setState({ - lastSuccessfulValue: Number(e.target.value) - }); - this.props.onChangeValidate(e); - } - } - - render() { - - let fieldClass = 'tb-field'; - if (this.props.form.required) { - fieldClass += ' tb-required'; - } - if (this.props.form.readonly) { - fieldClass += ' tb-readonly'; - } - if (this.state.focused) { - fieldClass += ' tb-focused'; - } - let value = this.state.lastSuccessfulValue; - if (typeof value !== 'undefined') { - value = Number(value); - } else { - value = null; - } - return ( -
    - -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardNumber); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx deleted file mode 100644 index 99031ff480..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-radios.tsx +++ /dev/null @@ -1,51 +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 * as React from 'react'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import { FormLabel, Radio, RadioGroup } from '@mui/material'; -import FormControl from '@mui/material/FormControl'; -import ThingsboardBaseComponent from '@shared/components/json-form/react/json-form-base-component'; - -class ThingsboardRadios extends React.Component { - render() { - const items = this.props.form.titleMap.map((item, index) => { - return ( - } label={item.name} key={index} /> - ); - }); - - let row = false; - if (this.props.form.direction === 'row') { - row = true; - } - - return ( - - {this.props.form.title} - { - this.props.onChangeValidate(e); - }}> - {items} - - - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardRadios); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx deleted file mode 100644 index ee21674b94..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-rc-select.tsx +++ /dev/null @@ -1,202 +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 * as React from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import Select, { Option } from 'rc-select'; -import { - JsonFormFieldProps, - JsonFormFieldState, - KeyLabelItem -} from '@shared/components/json-form/react/json-form.models'; -import { Mode } from 'rc-select/lib/interface'; -import { deepClone } from '@core/utils'; - -interface ThingsboardRcSelectState extends JsonFormFieldState { - currentValue: KeyLabelItem | KeyLabelItem[]; - items: Array; - focused: boolean; -} - -class ThingsboardRcSelect extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onSelect = this.onSelect.bind(this); - this.onDeselect = this.onDeselect.bind(this); - this.onBlur = this.onBlur.bind(this); - this.onFocus = this.onFocus.bind(this); - this.state = { - currentValue: this.keyToCurrentValue(this.props.value, this.props.form.schema.type === 'array'), - items: this.props.form.items as KeyLabelItem[], - focused: false - }; - } - - keyToCurrentValue(key: string | string[], isArray: boolean): KeyLabelItem | KeyLabelItem[] { - let currentValue: KeyLabelItem | KeyLabelItem[] = isArray ? [] : null; - if (isArray) { - const keys = key; - if (keys) { - (keys as string[]).forEach((keyVal) => { - (currentValue as KeyLabelItem[]).push({key: keyVal, label: this.labelFromKey(keyVal)}); - }); - } - } else { - currentValue = {key: key as string, label: this.labelFromKey(key as string)}; - } - return currentValue; - } - - labelFromKey(key: string): string { - let label = key || ''; - if (key) { - for (const item of this.props.form.items) { - if (item.value === key) { - label = item.label; - break; - } - } - } - return label; - } - - arrayValues(items: KeyLabelItem[]): string[] { - const v: string[] = []; - if (items) { - items.forEach(item => { - v.push(item.key); - }); - } - return v; - } - - keyIndex(values: KeyLabelItem[], key: string): number { - let index = -1; - if (values) { - for (let i = 0; i < values.length; i++) { - if (values[i].key === key) { - index = i; - break; - } - } - } - return index; - } - - onSelect(value: KeyLabelItem) { - if (this.props.form.schema.type === 'array') { - const v = this.state.currentValue as KeyLabelItem[]; - v.push(this.keyToCurrentValue(value.key, false) as KeyLabelItem); - this.setState({ - currentValue: v - }); - this.props.onChangeValidate(this.arrayValues(v)); - } else { - this.setState({currentValue: this.keyToCurrentValue(value.key, false)}); - this.props.onChangeValidate({target: {value: value.key}}); - } - } - - onDeselect(value: KeyLabelItem) { - if (this.props.form.schema.type === 'array') { - const v = this.state.currentValue as KeyLabelItem[]; - const index = this.keyIndex(v, value.key); - if (index > -1) { - v.splice(index, 1); - } - this.setState({ - currentValue: v - }); - this.props.onChangeValidate(this.arrayValues(v)); - } - } - - onBlur() { - this.setState({ focused: false }); - } - - onFocus() { - this.setState({ focused: true }); - } - - render() { - - let options: React.JSX.Element[] = []; - if (this.state.items && this.state.items.length > 0) { - options = this.state.items.map((item) => ( - - )); - } - - let labelClass = 'tb-label'; - if (this.props.form.required) { - labelClass += ' tb-required'; - } - if (this.props.form.readonly) { - labelClass += ' tb-readonly'; - } - if (this.state.focused) { - labelClass += ' tb-focused'; - } - let mode: Mode; - let value = this.state.currentValue; - if (this.props.form.tags || this.props.form.multiple) { - value = deepClone(value); - if (this.props.form.tags) { - mode = 'tags'; - } else if (this.props.form.multiple) { - mode = 'multiple'; - } - } - - const dropdownStyle = {...this.props.form.dropdownStyle, ...{zIndex: 100001}}; - let dropdownClassName = 'tb-rc-select-dropdown'; - if (this.props.form.dropdownClassName) { - dropdownClassName += ' ' + this.props.form.dropdownClassName; - } - - return ( -
    - - -
    {this.props.error}
    -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardRcSelect); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx deleted file mode 100644 index a56054a614..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-react.tsx +++ /dev/null @@ -1,53 +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 * as React from 'react'; -import { createTheme, ThemeProvider } from '@mui/material/styles'; -import thingsboardTheme from './styles/thingsboardTheme'; -import ThingsboardSchemaForm from './json-form-schema-form'; -import { JsonFormProps } from './json-form.models'; - -const tbTheme = createTheme(thingsboardTheme); - -class ReactSchemaForm extends React.Component { - - static defaultProps: JsonFormProps; - - constructor(props) { - super(props); - } - - render() { - if (this.props.form.length > 0) { - return ; - } else { - return
    ; - } - } -} - -ReactSchemaForm.defaultProps = { - isFullscreen: false, - schema: {}, - form: ['*'], - groupInfoes: [], - option: { - formDefaults: { - startEmpty: true - } - } -}; - -export default ReactSchemaForm; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx deleted file mode 100644 index bbdd90cbe7..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx +++ /dev/null @@ -1,217 +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 * as React from 'react'; -import JsonFormUtils from './json-form-utils'; - -import ThingsboardArray from './json-form-array'; -import ThingsboardJavaScript from './json-form-javascript'; -import ThingsboardJson from './json-form-json'; -import ThingsboardHtml from './json-form-html'; -import ThingsboardCss from './json-form-css'; -import ThingsboardColor from './json-form-color'; -import ThingsboardRcSelect from './json-form-rc-select'; -import ThingsboardNumber from './json-form-number'; -import ThingsboardText from './json-form-text'; -import ThingsboardSelect from './json-form-select'; -import ThingsboardRadios from './json-form-radios'; -import ThingsboardDate from './json-form-date'; -import ThingsboardImage from './json-form-image'; -import ThingsboardCheckbox from './json-form-checkbox'; -import ThingsboardHelp from './json-form-help'; -import ThingsboardFieldSet from './json-form-fieldset'; -import ThingsboardIcon from './json-form-icon'; -import { - JsonFormData, - JsonFormProps, - onChangeFn, - OnColorClickFn, onHelpClickFn, - OnIconClickFn, - onToggleFullscreenFn -} from './json-form.models'; - -import _ from 'lodash'; -import tinycolor from 'tinycolor2'; -import { GroupInfo } from '@shared/models/widget.models'; -import ThingsboardMarkdown from '@shared/components/json-form/react/json-form-markdown'; -import { MouseEvent, ReactNode } from 'react'; - -class ThingsboardSchemaForm extends React.Component { - - private hasConditions: boolean; - private conditionFunction: Function; - private readonly mapper: {[type: string]: any}; - - constructor(props: JsonFormProps) { - super(props); - - this.mapper = { - number: ThingsboardNumber, - text: ThingsboardText, - password: ThingsboardText, - textarea: ThingsboardText, - select: ThingsboardSelect, - radios: ThingsboardRadios, - date: ThingsboardDate, - image: ThingsboardImage, - checkbox: ThingsboardCheckbox, - help: ThingsboardHelp, - array: ThingsboardArray, - javascript: ThingsboardJavaScript, - json: ThingsboardJson, - html: ThingsboardHtml, - css: ThingsboardCss, - markdown: ThingsboardMarkdown, - color: ThingsboardColor, - 'rc-select': ThingsboardRcSelect, - fieldset: ThingsboardFieldSet, - icon: ThingsboardIcon - }; - - this.onChange = this.onChange.bind(this); - this.onColorClick = this.onColorClick.bind(this); - this.onIconClick = this.onIconClick.bind(this); - this.onToggleFullscreen = this.onToggleFullscreen.bind(this); - this.onHelpClick = this.onHelpClick.bind(this); - this.hasConditions = false; - } - - onChange(key: (string | number)[], val: any, forceUpdate?: boolean) { - this.props.onModelChange(key, val, forceUpdate); - if (this.hasConditions) { - this.forceUpdate(); - } - } - - onColorClick(key: (string | number)[], val: tinycolor.ColorFormats.RGBA, - colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) { - this.props.onColorClick(key, val, colorSelectedFn); - } - - onIconClick(key: (string | number)[], val: string, - iconSelectedFn: (icon: string) => void) { - this.props.onIconClick(key, val, iconSelectedFn); - } - - onToggleFullscreen(fullscreenFinishFn?: (el: Element) => void) { - this.props.onToggleFullscreen(fullscreenFinishFn); - } - - onHelpClick(event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, helpReadyFn: (ready: boolean) => void) { - this.props.onHelpClick(event, helpId, helpVisibleFn, helpReadyFn); - } - - - builder(form: JsonFormData, - model: any, - index: number, - onChange: onChangeFn, - onColorClick: OnColorClickFn, - onIconClick: OnIconClickFn, - onToggleFullscreen: onToggleFullscreenFn, - onHelpClick: onHelpClickFn, - mapper: {[type: string]: any}): React.JSX.Element { - const type = form.type; - const Field = this.mapper[type]; - if (!Field) { - console.log('Invalid field: \"' + form.key[0] + '\"!'); - return null; - } - if (form.condition) { - this.hasConditions = true; - if (!form.conditionFunction) { - form.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`); - } - if (form.conditionFunction(form, model, index) === false) { - return null; - } - } - return ; - } - - createSchema(theForm: any[]): React.JSX.Element { - const merged = JsonFormUtils.merge(this.props.schema, theForm, this.props.ignore, this.props.option); - let mapper = this.mapper; - if (this.props.mapper) { - mapper = _.merge(this.mapper, this.props.mapper); - } - const forms: ReactNode[] = merged.map(function(form: JsonFormData, index: number) { - return this.builder(form, this.props.model, index, this.onChange, this.onColorClick, - this.onIconClick, this.onToggleFullscreen, this.onHelpClick, mapper); - }.bind(this)); - - let formClass = 'SchemaForm'; - if (this.props.isFullscreen) { - formClass += ' SchemaFormFullscreen'; - } - - return ( -
    {forms}
    - ); - } - - render() { - if (this.props.groupInfoes && this.props.groupInfoes.length > 0) { - const content: React.JSX.Element[] = []; - for (const info of this.props.groupInfoes) { - const forms = this.createSchema(this.props.form[info.formIndex]); - const item = ; - content.push(item); - } - return (
    {content}
    ); - } else { - return this.createSchema(this.props.form); - } - } -} -export default ThingsboardSchemaForm; - -interface ThingsboardSchemaGroupProps { - info: GroupInfo; - forms: React.JSX.Element; -} - -interface ThingsboardSchemaGroupState { - showGroup: boolean; -} - -class ThingsboardSchemaGroup extends React.Component { - constructor(props: ThingsboardSchemaGroupProps) { - super(props); - this.state = { - showGroup: true - }; - } - - toogleGroup() { - this.setState({ - showGroup: !this.state.showGroup - }); - } - - render() { - const theCla = 'pull-right fa fa-chevron-down tb-toggle-icon' + (this.state.showGroup ? '' : ' tb-toggled'); - return (
    -
    {this.props.info.GroupTitle}
    -
    {this.props.forms}
    -
    ); - } -} diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-select.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-select.tsx deleted file mode 100644 index 46da881e38..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-select.tsx +++ /dev/null @@ -1,93 +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 * as React from 'react'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import MenuItem from '@mui/material/MenuItem'; -import FormControl from '@mui/material/FormControl'; -import InputLabel from '@mui/material/InputLabel'; -import Select, { SelectChangeEvent } from '@mui/material/Select'; -import ThingsboardBaseComponent from '@shared/components/json-form/react/json-form-base-component'; -import { isObject } from '@core/utils'; - -interface ThingsboardSelectState extends JsonFormFieldState { - currentValue: any; -} - -class ThingsboardSelect extends React.Component { - - static getDerivedStateFromProps(props: JsonFormFieldProps) { - if (props.model && props.form.key) { - return { - currentValue: ThingsboardSelect.getModelKey(props.model, props.form.key) - || (props.form.titleMap != null ? props.form.titleMap[0].value : '') - } - } - } - - static getModelKey(model: any, key: (string | number)[]) { - if (Array.isArray(key)) { - const res = key.reduce((cur, nxt) => (cur[nxt] || {}), model); - if (res && isObject(res)) { - return undefined; - } else { - return res; - } - } else { - return model[key]; - } - } - - constructor(props: JsonFormFieldProps) { - super(props); - this.onSelected = this.onSelected.bind(this); - const possibleValue = ThingsboardSelect.getModelKey(this.props.model, this.props.form.key); - this.state = { - currentValue: this.props.model !== undefined && possibleValue ? possibleValue : this.props.form.titleMap != null ? - this.props.form.titleMap[0].value : '' - }; - } - - onSelected(event: SelectChangeEvent) { - - this.setState({ - currentValue: event.target.value - }); - this.props.onChangeValidate(event); - } - - render() { - const menuItems = this.props.form.titleMap.map((item, idx) => ( - {item.name} - )); - - return ( - - {this.props.form.title} - - - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardSelect); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-text.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-text.tsx deleted file mode 100644 index 6fad3f3480..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-text.tsx +++ /dev/null @@ -1,92 +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 * as React from 'react'; -import ThingsboardBaseComponent from './json-form-base-component'; -import TextField from '@mui/material/TextField'; -import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; - -interface ThingsboardTextState extends JsonFormFieldState { - focused: boolean; -} - -class ThingsboardText extends React.Component { - - constructor(props: JsonFormFieldProps) { - super(props); - this.onBlur = this.onBlur.bind(this); - this.onFocus = this.onFocus.bind(this); - this.state = { - focused: false - }; - } - - onBlur() { - this.setState({focused: false}); - } - - onFocus() { - this.setState({focused: true}); - } - - render() { - - let fieldClass = 'tb-field'; - if (this.props.form.required) { - fieldClass += ' tb-required'; - } - if (this.props.form.readonly) { - fieldClass += ' tb-readonly'; - } - if (this.state.focused) { - fieldClass += ' tb-focused'; - } - - const multiline = this.props.form.type === 'textarea'; - let rows = 1; - let rowsMax = 1; - let minHeight = 48; - if (multiline) { - rows = this.props.form.rows || 2; - rowsMax = this.props.form.rowsMax; - minHeight = 19 * rows + 48; - } - - return ( -
    - { - this.props.onChangeValidate(e); - }} - defaultValue={this.props.value} - disabled={this.props.form.readonly} - rows={rows} - maxRows={rowsMax} - onFocus={this.onFocus} - onBlur={this.onBlur} - style={this.props.form.style || {width: '100%', minHeight: minHeight + 'px'}}/> -
    - ); - } -} - -export default ThingsboardBaseComponent(ThingsboardText); diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts deleted file mode 100644 index ffcf201136..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts +++ /dev/null @@ -1,141 +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 tinycolor from 'tinycolor2'; -import { GroupInfo } from '@shared/models/widget.models'; -import { MouseEvent } from 'react'; - -export interface SchemaValidationResult { - valid: boolean; - error?: { - message?: string; - }; -} - -export interface FormOption { - formDefaults?: { - startEmpty?: boolean; - readonly?: boolean; - }; - supressPropertyTitles?: boolean; -} - -export interface DefaultsFormOptions { - global?: FormOption; - required?: boolean; - path?: string[]; - lookup?: {[key: string]: any}; - ignore?: {[key: string]: boolean}; -} - -export type onChangeFn = (key: (string | number)[], val: any, forceUpdate?: boolean) => void; -export type OnColorClickFn = (key: (string | number)[], val: tinycolor.ColorFormats.RGBA, - colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) => void; -export type OnIconClickFn = (key: (string | number)[], val: string, - iconSelectedFn: (icon: string) => void) => void; -export type onToggleFullscreenFn = (fullscreenFinishFn?: (el: Element) => void) => void; -export type onHelpClickFn = (event: MouseEvent, helpId: string, helpVisibleFn: (visible: boolean) => void, - helpReadyFn: (ready: boolean) => void) => void; - -export interface JsonFormProps { - model?: any; - schema?: any; - form?: any; - groupInfoes?: GroupInfo[]; - isFullscreen: boolean; - ignore?: {[key: string]: boolean}; - option: FormOption; - onModelChange?: onChangeFn; - onColorClick?: OnColorClickFn; - onIconClick?: OnIconClickFn; - onToggleFullscreen?: onToggleFullscreenFn; - onHelpClick?: onHelpClickFn; - mapper?: {[type: string]: any}; -} - -export interface KeyLabelItem { - key: string; - label: string; - value?: string; -} - -export interface JsonSchemaData { - type: string; - default: any; - items?: JsonSchemaData; - properties?: any; -} - -export interface JsonFormData { - type: string; - key: (string | number)[]; - title: string; - readonly: boolean; - required: boolean; - default?: any; - condition?: string; - conditionFunction?: Function; - style?: any; - rows?: number; - rowsMax?: number; - placeholder?: string; - schema: JsonSchemaData; - titleMap: { - value: any; - name: string; - }[]; - items?: Array | Array; - tabs?: Array; - tags?: any; - helpId?: string; - startEmpty?: boolean; - [key: string]: any; -} - -export type ComponentBuilderFn = (form: JsonFormData, - model: any, - index: number, - onChange: onChangeFn, - onColorClick: OnColorClickFn, - onIconClick: OnIconClickFn, - onToggleFullscreen: onToggleFullscreenFn, - onHelpClick: onHelpClickFn, - mapper: {[type: string]: any}) => JSX.Element; - -export interface JsonFormFieldProps { - value: any; - model: any; - form: JsonFormData; - builder: ComponentBuilderFn; - mapper?: {[type: string]: any}; - onChange?: onChangeFn; - onColorClick?: OnColorClickFn; - onIconClick?: OnIconClickFn; - onChangeValidate?: (e: any, forceUpdate?: boolean) => void; - onToggleFullscreen?: onToggleFullscreenFn; - onHelpClick?: onHelpClickFn; - valid?: boolean; - error?: string; - options?: { - setSchemaDefaults?: boolean; - }; -} - -export interface JsonFormFieldState { - value?: any; - valid?: boolean; - error?: string; -} diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.scss b/ui-ngx/src/app/shared/components/json-form/react/json-form.scss deleted file mode 100644 index 42e1dc9677..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.scss +++ /dev/null @@ -1,361 +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. - */ -$swift-ease-out-duration: .4s !default; -$swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default; - -$input-label-float-offset: 6px !default; -$input-label-float-scale: .75 !default; - -$previewSize: 100px !default; - -.tb-json-form { - - &.tb-fullscreen { - background: #fff; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - > div.fullscreen-form-field { - position: relative; - width: 100%; - height: 100%; - } - } - - .json-form-error { - position: relative; - bottom: -5px; - font-size: 12px; - line-height: 12px; - color: rgb(244, 67, 54); - - transition: all 450ms cubic-bezier(.23, 1, .32, 1) 0ms; - } - - .tb-container { - position: relative; - box-sizing: border-box; - padding: 10px 0; - margin-top: 32px; - } - - .tb-field { - padding-bottom: 18px; - - .MuiInputBase-multiline { - flex: 1; - flex-direction: column; - .MuiInputBase-inputMultiline { - flex: 1; - } - } - - &.tb-required { - label::after { - font-size: 13px; - color: rgba(0, 0, 0, .54); - vertical-align: top; - content: " *"; - } - } - - &.tb-focused:not(.tb-readonly) { - label::after { - color: rgb(221, 44, 0); - } - } - } - - .tb-date-field { - &.tb-required { - div > div:first-child::after { - font-size: 13px; - color: rgba(0, 0, 0, .54); - vertical-align: top; - content: " *"; - } - } - - &.tb-focused:not(.tb-readonly) { - div > div:first-child::after { - color: rgb(221, 44, 0); - } - } - } - - label.tb-label { - position: absolute; - right: auto; - bottom: 100%; - left: 0; - color: rgba(0, 0, 0, .54); - - transition: transform $swift-ease-out-timing-function $swift-ease-out-duration, width $swift-ease-out-timing-function $swift-ease-out-duration; - - transform: translate3d(0, $input-label-float-offset, 0) scale($input-label-float-scale); - transform-origin: left top; - -webkit-font-smoothing: antialiased; - - &.tb-focused { - color: rgb(96, 125, 139); - } - - &.tb-required::after { - font-size: 13px; - color: rgba(0, 0, 0, .54); - vertical-align: top; - content: " *"; - } - - &.tb-focused:not(.tb-readonly)::after { - color: rgb(221, 44, 0); - } - } - - .tb-head-label { - color: rgba(0, 0, 0, .54); - padding-bottom: 15px; - } - - .SchemaGroupname { - padding: 10px 20px; - background-color: #f1f1f1; - } - - .invisible { - display: none; - } - - .tb-button-toggle .tb-toggle-icon { - display: inline-block; - width: 15px; - margin: auto 0 auto auto; - background-size: 100% auto; - - transition: transform .3s, ease-in-out; - } - - .tb-button-toggle .tb-toggle-icon.tb-toggled { - transform: rotateZ(180deg); - } - - .fullscreen-form-field { - .json-form-ace-editor { - height: calc(100% - 60px); - } - } - - .json-form-ace-editor { - position: relative; - height: 100%; - border: 1px solid #c0c0c0; - - .title-panel { - position: absolute; - top: 10px; - right: 20px; - z-index: 5; - font-size: .8rem; - font-weight: 500; - - label { - padding: 4px; - color: #00acc1; - background: rgba(220, 220, 220, .35); - border-radius: 5px; - } - - button.tidy-button { - background: rgba(220, 220, 220, .35) !important; - - span { - padding: 0 !important; - font-size: 12px !important; - } - } - button.help-button { - background: rgba(220, 220, 220, .35); - padding: 4px; - } - div.help-button-loading { - pointer-events: none; - background: #f3f3f3; - border-radius: 50%; - display: flex; - place-content: center; - align-items: center; - } - } - } - - .tb-image-select-container { - position: relative; - width: 100%; - height: $previewSize; - } - - .tb-image-preview { - width: auto; - max-width: $previewSize; - height: auto; - max-height: $previewSize; - } - - .tb-image-preview-container { - position: relative; - float: left; - width: $previewSize; - height: $previewSize; - margin-right: 12px; - vertical-align: top; - border: solid 1px; - - div { - width: 100%; - font-size: 18px; - text-align: center; - } - - div, .tb-image-preview { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - } - - .tb-dropzone { - outline: none; - position: relative; - height: $previewSize; - padding: 0 8px; - overflow: hidden; - vertical-align: top; - border: dashed 2px; - - div { - position: absolute; - top: 50%; - left: 50%; - width: 100%; - font-size: 24px; - text-align: center; - transform: translate(-50%, -50%); - } - } - - .tb-image-clear-container { - position: relative; - float: right; - width: 48px; - height: $previewSize; - } - - .tb-image-clear-btn { - position: absolute !important; - top: 50%; - transform: translate(0%, -50%) !important; - } - - .MuiButton-root { - text-transform: none; - } - -} - -.rc-select { - box-sizing: border-box; - display: inline-block; - position: relative; - vertical-align: middle; - color: #666; - line-height: 28px; - font-size: inherit !important; - .rc-select-selector { - outline: none; - user-select: none; - box-sizing: border-box; - display: block; - background-color: #fff; - border-radius: 6px; - } - &.rc-select-single { - &:not(.rc-select-customize-input) { - .rc-select-selector { - height: 28px; - line-height: 28px; - position: relative; - border: 1px solid #d9d9d9; - &:hover { - border-color: #23c0fa; - box-shadow: 0 0 2px rgba(45, 183, 245, 0.8); - } - .rc-select-selection-search { - .rc-select-selection-search-input { - cursor: pointer; - background: transparent; - margin-left: 10px; - } - } - .rc-select-selection-item, .rc-select-selection-placeholder { - top: 0; - left: 10px; - } - } - &.rc-select-focused { - .rc-select-selector { - border-color: #23c0fa !important; - box-shadow: 0 0 2px rgba(45, 183, 245, 0.8) !important; - } - } - } - } -} - -.rc-select-dropdown { - &.tb-rc-select-dropdown { - z-index: 100001; - background-color: white; - border: 1px solid #d9d9d9; - box-shadow: 0 0 4px #d9d9d9; - border-radius: 4px; - box-sizing: border-box; - outline: none; - - .rc-select-item { - &.rc-select-item-option { - margin: 0; - position: relative; - display: block; - padding: 7px 10px; - font-weight: normal; - color: #666; - white-space: nowrap; - &.rc-select-item-option-selected { - color: #666; - background-color: #ddd; - } - &.rc-select-item-option-active { - background-color: #5897fb; - color: white; - cursor: pointer; - } - } - } - } -} diff --git a/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts b/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts deleted file mode 100644 index ab3497fd53..0000000000 --- a/ui-ngx/src/app/shared/components/json-form/react/styles/thingsboardTheme.ts +++ /dev/null @@ -1,46 +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 { indigo, deepOrange } from '@mui/material/colors'; -import { ThemeOptions } from '@mui/material/styles'; -import { PaletteOptions } from '@mui/material/styles/createPalette'; -import { mergeDeep } from '@core/utils'; - -const PRIMARY_COLOR = '#305680'; -const SECONDARY_COLOR = '#527dad'; -const HUE3_COLOR = '#a7c1de'; - -const tbIndigo = mergeDeep({}, indigo, { - 500: PRIMARY_COLOR, - 600: SECONDARY_COLOR, - 700: PRIMARY_COLOR, - A100: HUE3_COLOR -}); - -const thingsboardPalette: PaletteOptions = { - primary: tbIndigo, - secondary: deepOrange, - background: { - default: '#eee' - } -}; - -export default { - typography: { - fontFamily: 'Roboto, \'Helvetica Neue\', sans-serif' - }, - palette: thingsboardPalette, -} as ThemeOptions; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-utils.ts b/ui-ngx/src/app/shared/legacy/json-form-utils.ts similarity index 70% rename from ui-ngx/src/app/shared/components/json-form/react/json-form-utils.ts rename to ui-ngx/src/app/shared/legacy/json-form-utils.ts index d75819b73d..87e0afb31c 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-utils.ts +++ b/ui-ngx/src/app/shared/legacy/json-form-utils.ts @@ -14,63 +14,12 @@ /// limitations under the License. /// -import * as tv from 'tv4'; import ObjectPath from 'objectpath'; import _ from 'lodash'; import { DefaultsFormOptions, - FormOption, - JsonFormData, - JsonSchemaData, - SchemaValidationResult + FormOption } from './json-form.models'; -import { isDefined, isEqual, isString, isUndefined } from '@core/utils'; - -function validateBySchema(schema: any, value: any): SchemaValidationResult { - return tv.validateResult(value, schema); -} - -function validate(form: any, value: any): SchemaValidationResult { - - if (!form) { - return {valid: true}; - } - const schema = form.schema; - - if (!schema) { - return {valid: true}; - } - - if (value === '') { - value = undefined; - } - - // Numbers fields will give a null value, which also means empty field - if (form.type === 'number' && value === null) { - value = undefined; - } - - if (form.type === 'number' && isNaN(parseFloat(value))) { - value = undefined; - } - const wrap: any = {type: 'object', properties: {}}; - const propName = form.key[form.key.length - 1]; - wrap.properties[propName] = schema; - - if (form.required) { - wrap.required = [propName]; - } - const valueWrap = {}; - if (typeof value !== 'undefined') { - valueWrap[propName] = value; - } - - const tv4Result: SchemaValidationResult = tv.validateResult(valueWrap, wrap); - if (tv4Result != null && !tv4Result.valid && form.validationMessage != null && typeof value !== 'undefined') { - tv4Result.error.message = form.validationMessage; - } - return tv4Result; -} function stripNullType(type: any): string { if (Array.isArray(type) && type.length === 2) { @@ -438,155 +387,7 @@ function merge(schema: any, form: any[], ignore: { [key: string]: boolean }, opt })); } -function selectOrSet(projection: string | (string | number)[], obj: any, valueToSet?: any): any { - const numRe = /^\d+$/; - - if (!obj) { - obj = this; - } - const parts = typeof projection === 'string' ? ObjectPath.parse(projection) : projection; - - if (typeof valueToSet !== 'undefined' && parts.length === 1) { - obj[parts[0]] = valueToSet; - return obj; - } - - if (typeof valueToSet !== 'undefined' && typeof obj[parts[0]] === 'undefined') { - obj[parts[0]] = parts.length > 2 && numRe.test(parts[1]) ? [] : {}; - } - - let value = obj[parts[0]]; - for (let i = 1; i < parts.length; i++) { - if (parts[i] === '') { - return undefined; - } - if (typeof valueToSet !== 'undefined') { - if (i === parts.length - 1) { - value[parts[i]] = valueToSet; - return valueToSet; - } else { - let tmp = value[parts[i]]; - if (typeof tmp === 'undefined' || tmp === null) { - tmp = numRe.test(parts[i + 1]) ? [] : {}; - value[parts[i]] = tmp; - } - value = tmp; - } - } else if (value) { - value = value[parts[i]]; - } - } - return value; -} - -function updateValue(projection: string | (string | number)[], obj: any, valueToSet: any): boolean { - const numRe = /^\d+$/; - - if (!obj) { - obj = this; - } - - if (!obj) { - return false; - } - - const parts: string[] = isString(projection) ? ObjectPath.parse(projection) : projection; - - if (parts.length === 1) { - return setValue(obj, parts[0], valueToSet); - } - - if (isUndefined(obj[parts[0]])) { - obj[parts[0]] = parts.length > 2 && numRe.test(parts[1]) ? [] : {}; - } - - let value = obj[parts[0]]; - for (let i = 1; i < parts.length; i++) { - if (parts[i] === '') { - return false; - } - if (i === parts.length - 1) { - return setValue(value, parts[i], valueToSet); - } else { - let tmp = value[parts[i]]; - if (isUndefined(tmp) || tmp === null) { - tmp = numRe.test(parts[i + 1]) ? [] : {}; - value[parts[i]] = tmp; - } - value = tmp; - } - } - return value; -} - - -function setValue(obj: any, key: string, val: any): boolean { - let changed = false; - if (obj) { - if (isUndefined(val)) { - if (isDefined(obj[key])) { - delete obj[key]; - changed = true; - } - } else { - changed = !isEqual(obj[key], val); - obj[key] = val; - } - } - return changed; -} - -function traverseSchema(schema: JsonSchemaData, fn: (prop: any, path: string[]) => any, path?: string[], ignoreArrays?: boolean) { - ignoreArrays = typeof ignoreArrays !== 'undefined' ? ignoreArrays : true; - - path = path || []; - - const traverse = ($schema: JsonSchemaData, $fn: (prop: any, path: string[]) => any, $path: string[]) => { - $fn($schema, $path); - if ($schema.properties) { - for (const k of Object.keys($schema.properties)) { - if ($schema.properties.hasOwnProperty(k)) { - const currentPath = $path.slice(); - currentPath.push(k); - traverse($schema.properties[k], $fn, currentPath); - } - } - } - if (!ignoreArrays && $schema.items) { - const arrPath = $path.slice(); - arrPath.push(''); - traverse($schema.items, $fn, arrPath); - } - }; - - traverse(schema, fn, path || []); -} - -function traverseForm(form: JsonFormData, fn: (form: JsonFormData) => any) { - fn(form); - if (form.items) { - form.items.forEach((f) => { - traverseForm(f, fn); - }); - } - - if (form.tabs) { - form.tabs.forEach((tab) => { - tab.items.forEach((f) => { - traverseForm(f, fn); - }); - }); - } -} - - const utils = { - validateBySchema, - validate, - merge, - updateValue, - selectOrSet, - traverseSchema, - traverseForm + merge }; export default utils; diff --git a/ui-ngx/src/app/shared/legacy/json-form.models.ts b/ui-ngx/src/app/shared/legacy/json-form.models.ts new file mode 100644 index 0000000000..ffd2830133 --- /dev/null +++ b/ui-ngx/src/app/shared/legacy/json-form.models.ts @@ -0,0 +1,88 @@ +/// +/// 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. +/// + +export interface FormOption { + formDefaults?: { + startEmpty?: boolean; + readonly?: boolean; + }; + supressPropertyTitles?: boolean; +} + +export interface DefaultsFormOptions { + global?: FormOption; + required?: boolean; + path?: string[]; + lookup?: {[key: string]: any}; + ignore?: {[key: string]: boolean}; +} + +export interface KeyLabelItem { + key: string; + label: string; + value?: string; +} + +export interface JsonSchemaData { + type: string; + default: any; + items?: JsonSchemaData; + properties?: any; +} + +export interface JsonFormData { + type: string; + key: (string | number)[]; + title: string; + readonly: boolean; + required: boolean; + default?: any; + condition?: string; + conditionFunction?: Function; + style?: any; + rows?: number; + rowsMax?: number; + placeholder?: string; + schema: JsonSchemaData; + titleMap: { + value: any; + name: string; + }[]; + items?: Array | Array; + tabs?: Array; + tags?: any; + helpId?: string; + startEmpty?: boolean; + [key: string]: any; +} + +export interface GroupInfo { + formIndex: number; + GroupTitle: string; +} + +export interface JsonSchema { + type: string; + title?: string; + properties: {[key: string]: any}; + required?: string[]; +} + +export interface JsonSettingsSchema { + schema?: JsonSchema; + form?: any[]; + groupInfoes?: GroupInfo[]; +} diff --git a/ui-ngx/src/app/shared/models/dynamic-form.models.ts b/ui-ngx/src/app/shared/models/dynamic-form.models.ts index 14df1ff3b2..bb7f134c28 100644 --- a/ui-ngx/src/app/shared/models/dynamic-form.models.ts +++ b/ui-ngx/src/app/shared/models/dynamic-form.models.ts @@ -17,9 +17,8 @@ import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models'; import { deepClone, isDefinedAndNotNull, isString } from '@core/utils'; -import { JsonSchema, JsonSettingsSchema } from '@shared/models/widget.models'; -import JsonFormUtils from '@shared/components/json-form/react/json-form-utils'; -import { JsonFormData, KeyLabelItem } from '@shared/components/json-form/react/json-form.models'; +import { JsonSchema, JsonSettingsSchema, JsonFormData, KeyLabelItem } from '@shared/legacy/json-form.models'; +import JsonFormUtils from '@shared/legacy/json-form-utils'; import { constantColor, Font } from '@shared/models/widget-settings.models'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; @@ -573,29 +572,34 @@ const formPropertyCompletionType = (property: FormProperty): string => { export const jsonFormSchemaToFormProperties = (rawSchema: string | any) : FormProperty[] => { - const properties: FormProperty[] = []; - let settingsSchema: JsonSettingsSchema; - if (!rawSchema || rawSchema === '') { - settingsSchema = {}; - } else { - settingsSchema = isString(rawSchema) ? JSON.parse(rawSchema) : rawSchema; - } - if (settingsSchema.schema) { - const schema = settingsSchema.schema; - const form = settingsSchema.form || ['*']; - const groupInfoes = settingsSchema.groupInfoes || []; - if (form.length > 0) { - if (groupInfoes.length) { - for (const info of groupInfoes) { - const theForm: any[] = form[info.formIndex]; - properties.push(...schemaFormToProperties(schema, theForm, info.GroupTitle)); + try { + const properties: FormProperty[] = []; + let settingsSchema: JsonSettingsSchema; + if (!rawSchema || rawSchema === '') { + settingsSchema = {}; + } else { + settingsSchema = isString(rawSchema) ? JSON.parse(rawSchema) : rawSchema; + } + if (settingsSchema.schema) { + const schema = settingsSchema.schema; + const form = settingsSchema.form || ['*']; + const groupInfoes = settingsSchema.groupInfoes || []; + if (form.length > 0) { + if (groupInfoes.length) { + for (const info of groupInfoes) { + const theForm: any[] = form[info.formIndex]; + properties.push(...schemaFormToProperties(schema, theForm, info.GroupTitle)); + } + } else { + properties.push(...schemaFormToProperties(schema, form)); } - } else { - properties.push(...schemaFormToProperties(schema, form)); } } + return properties; + } catch (e) { + console.warn('Failed to convert old JSON form schema to form properties:', e); + return []; } - return properties; } const schemaFormToProperties = (schema: JsonSchema, theForm: any[], groupTitle?: string): FormProperty[] => { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index f3c82571e1..5015f6cb80 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -45,7 +45,7 @@ import { HasTenantId, HasVersion } from '@shared/models/entity.models'; import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; import { TbFunction } from '@shared/models/js-function.models'; -import { FormProperty } from '@shared/models/dynamic-form.models'; +import { FormProperty, jsonFormSchemaToFormProperties } from '@shared/models/dynamic-form.models'; export enum widgetType { timeseries = 'timeseries', @@ -155,9 +155,8 @@ export interface WidgetTypeDescriptor { templateCss: string; controllerScript: TbFunction; settingsForm?: FormProperty[]; - settingsSchema?: string | any; - dataKeySettingsSchema?: string | any; - latestDataKeySettingsSchema?: string | any; + dataKeySettingsForm?: FormProperty[]; + latestDataKeySettingsForm?: FormProperty[]; settingsDirective?: string; dataKeySettingsDirective?: string; latestDataKeySettingsDirective?: string; @@ -196,9 +195,8 @@ export interface WidgetTypeParameters { export interface WidgetControllerDescriptor { widgetTypeFunction?: any; settingsForm?: FormProperty[]; - settingsSchema?: string | any; - dataKeySettingsSchema?: string | any; - latestDataKeySettingsSchema?: string | any; + dataKeySettingsForm?: FormProperty[]; + latestDataKeySettingsForm?: FormProperty[]; typeParameters?: WidgetTypeParameters; actionSources?: {[actionSourceId: string]: WidgetActionSource}; } @@ -238,6 +236,30 @@ export const isValidWidgetFullFqn = (fullFqn: string): boolean => { return false; }; + +export const migrateWidgetTypeToDynamicForms = (widgetType: T): T => { + const descriptor = widgetType.descriptor; + if ((descriptor as any).settingsSchema) { + if (!descriptor.settingsForm?.length) { + descriptor.settingsForm = jsonFormSchemaToFormProperties((descriptor as any).settingsSchema); + } + delete (descriptor as any).settingsSchema; + } + if ((descriptor as any).dataKeySettingsSchema) { + if (!descriptor.dataKeySettingsForm?.length) { + descriptor.dataKeySettingsForm = jsonFormSchemaToFormProperties((descriptor as any).dataKeySettingsSchema); + } + delete (descriptor as any).dataKeySettingsSchema; + } + if ((descriptor as any).latestDataKeySettingsSchema) { + if (!descriptor.latestDataKeySettingsForm?.length) { + descriptor.latestDataKeySettingsForm = jsonFormSchemaToFormProperties((descriptor as any).latestDataKeySettingsSchema); + } + delete (descriptor as any).latestDataKeySettingsSchema; + } + return widgetType; +} + export interface WidgetType extends BaseWidgetType { descriptor: WidgetTypeDescriptor; } @@ -815,24 +837,6 @@ export interface WidgetInfo extends BaseWidgetInfo { deprecated?: boolean; } -export interface GroupInfo { - formIndex: number; - GroupTitle: string; -} - -export interface JsonSchema { - type: string; - title?: string; - properties: {[key: string]: any}; - required?: string[]; -} - -export interface JsonSettingsSchema { - schema?: JsonSchema; - form?: any[]; - groupInfoes?: GroupInfo[]; -} - export interface DynamicFormData { settingsForm?: FormProperty[]; model?: any; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index c1f243ae14..5b40dadf5f 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -121,7 +121,6 @@ import { TbJsonPipe } from '@shared/pipe/tbJson.pipe'; import { ColorPickerDialogComponent } from '@shared/components/dialog/color-picker-dialog.component'; import { ColorInputComponent } from '@shared/components/color-input.component'; import { JsFuncComponent } from '@shared/components/js-func.component'; -import { JsonFormComponent } from '@shared/components/json-form/json-form.component'; import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component'; import { AlertDialogComponent } from '@shared/components/dialog/alert-dialog.component'; import { ErrorAlertDialogComponent } from '@shared/components/dialog/error-alert-dialog.component'; @@ -362,7 +361,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ColorInputComponent, MaterialIconSelectComponent, NodeScriptTestDialogComponent, - JsonFormComponent, ImageInputComponent, MultipleImageInputComponent, FileInputComponent, @@ -625,7 +623,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ColorInputComponent, MaterialIconSelectComponent, NodeScriptTestDialogComponent, - JsonFormComponent, ImageInputComponent, MultipleImageInputComponent, FileInputComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index a8ed773047..875613fb6a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5481,9 +5481,8 @@ "tidy": "Tidy", "css": "CSS", "settings-form": "Settings form", - "settings-schema": "Settings schema", - "datakey-settings-schema": "Data key settings schema", - "latest-datakey-settings-schema": "Latest data key settings schema", + "data-key-settings-form": "Data key settings form", + "latest-data-key-settings-form": "Latest data key settings form", "widget-settings": "Widget settings", "description": "Description", "tags": "Tags", diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index c394a29826..dbc69fb9dd 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -58,6 +58,10 @@ tb-root { * TYPE DEFAULTS ***************/ +* { + box-sizing: border-box; +} + body, button, html, diff --git a/ui-ngx/src/tsconfig.app.json b/ui-ngx/src/tsconfig.app.json index 7a029aa8c7..7c7b2e93d4 100644 --- a/ui-ngx/src/tsconfig.app.json +++ b/ui-ngx/src/tsconfig.app.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "../out-tsc/app", "types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", - "react", "react-dom", "raphael", "canvas-gauges", "systemjs"] + "raphael", "canvas-gauges", "systemjs"] }, "angularCompilerOptions": { "fullTemplateTypeCheck": true, diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index 61712840f4..c667775ba9 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -14,7 +14,6 @@ "target": "ES2022", "module": "es2020", "emitDecoratorMetadata": true, - "jsx": "react", "resolveJsonModule": true, "typeRoots": [ "node_modules/@types", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index b7e5e21e55..04c3abda1d 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -499,7 +499,7 @@ "@babel/traverse" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.24.7", "@babel/helper-module-imports@^7.25.9": +"@babel/helper-module-imports@^7.24.7", "@babel/helper-module-imports@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== @@ -1296,7 +1296,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.25.0", "@babel/runtime@^7.25.6", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.8.4": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== @@ -1382,113 +1382,6 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz#593da7a17a31a72a874e313677183334a49b01c9" integrity sha512-boghen8F0Q8D+0/Q1/1r6DUEieUJ8w2a1gIknExMSHBsJFOr2+0KUfHiVYBvucPwl3+RU5PFBK833FjFCh3BhA== -"@emotion/babel-plugin@^11.12.0": - version "11.12.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" - integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.2" - "@emotion/memoize" "^0.9.0" - "@emotion/serialize" "^1.2.0" - babel-plugin-macros "^3.1.0" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.2.0" - -"@emotion/cache@^11.13.0", "@emotion/cache@^11.13.1": - version "11.13.1" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7" - integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== - dependencies: - "@emotion/memoize" "^0.9.0" - "@emotion/sheet" "^1.4.0" - "@emotion/utils" "^1.4.0" - "@emotion/weak-memoize" "^0.4.0" - stylis "4.2.0" - -"@emotion/hash@^0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" - integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== - -"@emotion/is-prop-valid@^1.3.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz#8d5cf1132f836d7adbe42cf0b49df7816fc88240" - integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw== - dependencies: - "@emotion/memoize" "^0.9.0" - -"@emotion/memoize@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" - integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== - -"@emotion/react@11.13.3": - version "11.13.3" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.3.tgz#a69d0de2a23f5b48e0acf210416638010e4bd2e4" - integrity sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg== - dependencies: - "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" - "@emotion/cache" "^11.13.0" - "@emotion/serialize" "^1.3.1" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" - "@emotion/weak-memoize" "^0.4.0" - hoist-non-react-statics "^3.3.1" - -"@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0", "@emotion/serialize@^1.3.1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.2.tgz#e1c1a2e90708d5d85d81ccaee2dfeb3cc0cccf7a" - integrity sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA== - dependencies: - "@emotion/hash" "^0.9.2" - "@emotion/memoize" "^0.9.0" - "@emotion/unitless" "^0.10.0" - "@emotion/utils" "^1.4.1" - csstype "^3.0.2" - -"@emotion/sheet@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" - integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== - -"@emotion/styled@11.13.0": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.13.0.tgz#633fd700db701472c7a5dbef54d6f9834e9fb190" - integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== - dependencies: - "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" - "@emotion/is-prop-valid" "^1.3.0" - "@emotion/serialize" "^1.3.0" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" - -"@emotion/unitless@^0.10.0": - version "0.10.0" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" - integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== - -"@emotion/use-insertion-effect-with-fallbacks@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" - integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== - -"@emotion/utils@^1.4.0", "@emotion/utils@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.1.tgz#b3adbb43de12ee2149541c4f1337d2eb7774f0ad" - integrity sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA== - -"@emotion/weak-memoize@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" - integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== - "@es-joy/jsdoccomment@~0.49.0": version "0.49.0" resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz#e5ec1eda837c802eca67d3b29e577197f14ba1db" @@ -1676,33 +1569,6 @@ dependencies: levn "^0.4.1" -"@floating-ui/core@^1.6.0": - version "1.6.8" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12" - integrity sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA== - dependencies: - "@floating-ui/utils" "^0.2.8" - -"@floating-ui/dom@^1.0.0": - version "1.6.11" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.11.tgz#8631857838d34ee5712339eb7cbdfb8ad34da723" - integrity sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ== - dependencies: - "@floating-ui/core" "^1.6.0" - "@floating-ui/utils" "^0.2.8" - -"@floating-ui/react-dom@^2.1.1": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" - integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== - dependencies: - "@floating-ui/dom" "^1.0.0" - -"@floating-ui/utils@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" - integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== - "@flowjs/flow.js@^2.14.1": version "2.14.1" resolved "https://registry.yarnpkg.com/@flowjs/flow.js/-/flow.js-2.14.1.tgz#267d9f9d0958f32267ea5815c2a7cc09b9219304" @@ -2150,181 +2016,6 @@ resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz#0aa5502d547b57abfc4ac492de68e2006e417242" integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== -"@mui/base@5.0.0-beta.58": - version "5.0.0-beta.58" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.58.tgz#66ae4e1aaef8cfd9ae81bd55a70ce76b02eb5d3e" - integrity sha512-P0E7ZrxOuyYqBvVv9w8k7wm+Xzx/KRu+BGgFcR2htTsGCpJNQJCSUXNUZ50MUmSU9hzqhwbQWNXhV1MBTl6F7A== - dependencies: - "@babel/runtime" "^7.25.0" - "@floating-ui/react-dom" "^2.1.1" - "@mui/types" "^7.2.15" - "@mui/utils" "6.0.0-rc.0" - "@popperjs/core" "^2.11.8" - clsx "^2.1.1" - prop-types "^15.8.1" - -"@mui/core-downloads-tracker@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.2.tgz#a15eb14d433100f734e56929f842c2ccc7cab691" - integrity sha512-1oE4U38/TtzLWRYWEm/m70dUbpcvBx0QvDVg6NtpOmSNQC1Mbx0X/rNvYDdZnn8DIsAiVQ+SZ3am6doSswUQ4g== - -"@mui/icons-material@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-6.1.2.tgz#3e4537c312687afbdd2fd289d5412731d5da3d11" - integrity sha512-7NNcjW5JoT9jHagrVbARA1o41vQY2xezDamtke+mEKKZmsJyejfRBOacSrPDfjZQ//lyhIjNKyzAwisxYJR47w== - dependencies: - "@babel/runtime" "^7.25.6" - -"@mui/lab@6.0.0-beta.10": - version "6.0.0-beta.10" - resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-6.0.0-beta.10.tgz#cf6dce21e8491aa00facc0d6b1cd357bfb2ed58e" - integrity sha512-eqCBz5SZS8Un9To3UcjH01AxkOOgvme/g0ZstFC8Nz1Kg5/EJMA0ByhKS5AvUMzUKrv0FXMdbuPqbBvF3bVrXg== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/base" "5.0.0-beta.58" - "@mui/system" "^6.1.1" - "@mui/types" "^7.2.17" - "@mui/utils" "^6.1.1" - clsx "^2.1.1" - prop-types "^15.8.1" - -"@mui/material@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-6.1.2.tgz#9f47bfa6adcf3b8245799cbf4c027e3cb949bcc6" - integrity sha512-5TtHeAVX9D5d2LYfB1GAUn29BcVETVsrQ76Dwb2SpAfQGW3JVy4deJCAd0RrIkI3eEUrsl0E4xuBdreszxdTTg== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/core-downloads-tracker" "^6.1.2" - "@mui/system" "^6.1.2" - "@mui/types" "^7.2.17" - "@mui/utils" "^6.1.2" - "@popperjs/core" "^2.11.8" - "@types/react-transition-group" "^4.4.11" - clsx "^2.1.1" - csstype "^3.1.3" - prop-types "^15.8.1" - react-is "^18.3.1" - react-transition-group "^4.4.5" - -"@mui/private-theming@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-6.1.2.tgz#1e093c7194dd9f8a511179e0e5c5b10798a4bfae" - integrity sha512-S8WcjZdNdi++8UhrrY8Lton5h/suRiQexvdTfdcPAlbajlvgM+kx+uJstuVIEyTb3gMkxzIZep87knZ0tqcR0g== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/utils" "^6.1.2" - prop-types "^15.8.1" - -"@mui/styled-engine@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-6.1.2.tgz#bef156ac2e47a67d49982ddb5fa4211974740a26" - integrity sha512-uKOfWkR23X39xj7th2nyTcCHqInTAXtUnqD3T5qRVdJcOPvu1rlgTleTwJC/FJvWZJBU6ieuTWDhbcx5SNViHQ== - dependencies: - "@babel/runtime" "^7.25.6" - "@emotion/cache" "^11.13.1" - "@emotion/sheet" "^1.4.0" - csstype "^3.1.3" - prop-types "^15.8.1" - -"@mui/styles@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-6.1.2.tgz#24bc654cdb0aae369348453ee8d25e3a9c1ace56" - integrity sha512-fsQkTCyyBnjsmy7CM0LG95PJZAhTsmoC/iNk4ihVYmdubMQEeGXzeAWL8E6QBChCnANmjZwm2h5ENyLnCUUuzg== - dependencies: - "@babel/runtime" "^7.25.6" - "@emotion/hash" "^0.9.2" - "@mui/private-theming" "^6.1.2" - "@mui/types" "^7.2.17" - "@mui/utils" "^6.1.2" - clsx "^2.1.1" - csstype "^3.1.3" - hoist-non-react-statics "^3.3.2" - jss "^10.10.0" - jss-plugin-camel-case "^10.10.0" - jss-plugin-default-unit "^10.10.0" - jss-plugin-global "^10.10.0" - jss-plugin-nested "^10.10.0" - jss-plugin-props-sort "^10.10.0" - jss-plugin-rule-value-function "^10.10.0" - jss-plugin-vendor-prefixer "^10.10.0" - prop-types "^15.8.1" - -"@mui/system@6.1.2", "@mui/system@^6.1.1", "@mui/system@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-6.1.2.tgz#28840b04c6fc70780620759d67de2c20bdc7d1c7" - integrity sha512-mzW7F1ZMIYS1aLON48Nrk9c65OrVEVQ+R4lUcTWs1lCSul0VGK23eo4dmY0NX5PS7Oe4xz3P5B9tQZZ7SYgxcg== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/private-theming" "^6.1.2" - "@mui/styled-engine" "^6.1.2" - "@mui/types" "^7.2.17" - "@mui/utils" "^6.1.2" - clsx "^2.1.1" - csstype "^3.1.3" - prop-types "^15.8.1" - -"@mui/types@^7.2.15", "@mui/types@^7.2.17": - version "7.2.17" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.17.tgz#329826062d4079de5ea2b97007575cebbba1fdbc" - integrity sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ== - -"@mui/utils@6.0.0-rc.0": - version "6.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-6.0.0-rc.0.tgz#208c12c919b5cd1731f9d14784c05c35294a893e" - integrity sha512-tBp0ILEXDL0bbDDT8PnZOjCqSm5Dfk2N0Z45uzRw+wVl6fVvloC9zw8avl+OdX1Bg3ubs/ttKn8nRNv17bpM5A== - dependencies: - "@babel/runtime" "^7.25.0" - "@mui/types" "^7.2.15" - "@types/prop-types" "^15.7.12" - clsx "^2.1.1" - prop-types "^15.8.1" - react-is "^18.3.1" - -"@mui/utils@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" - integrity sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA== - dependencies: - "@babel/runtime" "^7.23.9" - "@mui/types" "^7.2.15" - "@types/prop-types" "^15.7.12" - clsx "^2.1.1" - prop-types "^15.8.1" - react-is "^18.3.1" - -"@mui/utils@^6.1.1", "@mui/utils@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-6.1.2.tgz#3717cd9373324a92e48c34f74385350104be652c" - integrity sha512-6+B1YZ8cCBWD1fc3RjqpclF9UA0MLUiuXhyCO+XowD/Z2ku5IlxeEhHHlgglyBWFGMu4kib4YU3CDsG5/zVjJQ== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/types" "^7.2.17" - "@types/prop-types" "^15.7.13" - clsx "^2.1.1" - prop-types "^15.8.1" - react-is "^18.3.1" - -"@mui/x-date-pickers@7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-7.18.0.tgz#264158195aeeaf32a00519718f6c67c165b06711" - integrity sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/utils" "^5.16.6" - "@mui/x-internals" "7.18.0" - "@types/react-transition-group" "^4.4.11" - clsx "^2.1.1" - prop-types "^15.8.1" - react-transition-group "^4.4.5" - -"@mui/x-internals@7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@mui/x-internals/-/x-internals-7.18.0.tgz#f079968d4f7ea93e63be9faf6ba8558d6f12923b" - integrity sha512-lzCHOWIR0cAIY1bGrWSprYerahbnH5C31ql/2OWCEjcngL2NAV1M6oKI2Vp4HheqzJ822c60UyWyapvyjSzY/A== - dependencies: - "@babel/runtime" "^7.25.6" - "@mui/utils" "^5.16.6" - "@nghedgehog/core@^0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@nghedgehog/core/-/core-0.0.4.tgz#4e3231847d0dac557a2e2dbdf1e3a52b106dd57c" @@ -2482,32 +2173,6 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== -"@popperjs/core@^2.11.8": - version "2.11.8" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" - integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== - -"@rc-component/portal@^1.1.0": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rc-component/portal/-/portal-1.1.2.tgz#55db1e51d784e034442e9700536faaa6ab63fc71" - integrity sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg== - dependencies: - "@babel/runtime" "^7.18.0" - classnames "^2.3.2" - rc-util "^5.24.4" - -"@rc-component/trigger@^2.1.1": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.2.3.tgz#b47e945115e2d0a7f7e067dbb9ed76c91c1b4385" - integrity sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A== - dependencies: - "@babel/runtime" "^7.23.2" - "@rc-component/portal" "^1.1.0" - classnames "^2.3.2" - rc-motion "^2.0.0" - rc-resize-observer "^1.3.1" - rc-util "^5.38.0" - "@rollup/rollup-android-arm-eabi@4.22.4": version "4.22.4" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" @@ -3118,16 +2783,6 @@ dependencies: undici-types "~6.19.2" -"@types/parse-json@^4.0.0": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" - integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== - -"@types/prop-types@*", "@types/prop-types@^15.7.12", "@types/prop-types@^15.7.13": - version "15.7.13" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" - integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== - "@types/qs@*": version "6.9.16" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" @@ -3143,28 +2798,6 @@ resolved "https://registry.yarnpkg.com/@types/raphael/-/raphael-2.3.9.tgz#d53bb8930431524f42987a8a19815c0d42a61eb5" integrity sha512-K1dZwoLNvEN+mvleFU/t2swG9Z4SE5Vub7dA5wDYojH0bVTQ8ZAP+lNsl91t1njdu/B+roSEL4QXC67I7Hpiag== -"@types/react-dom@18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== - dependencies: - "@types/react" "*" - -"@types/react-transition-group@^4.4.11": - version "4.4.11" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz#d963253a611d757de01ebb241143b1017d5d63d5" - integrity sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@18.3.10": - version "18.3.10" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.10.tgz#6edc26dc22ff8c9c226d3c7bf8357b013c842219" - integrity sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - "@types/retry@0.12.2": version "0.12.2" resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" @@ -3470,7 +3103,7 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -ace-builds@1.36.5, ace-builds@^1.32.8: +ace-builds@1.36.5: version "1.36.5" resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.36.5.tgz#ae9cc7a32eccc2f484926131c00545cd6b78a6a6" integrity sha512-mZ5KVanRT6nLRDLqtG/1YQQLX/gZVC/v526cm1Ru/MTSlrbweSmqv2ZT0d2GaHpJq035MwCMIrj+LgDAUnDXrg== @@ -3790,11 +3423,6 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -attr-accept@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" - integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== - autoprefixer@10.4.20, autoprefixer@^10.4.20: version "10.4.20" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b" @@ -3827,15 +3455,6 @@ babel-loader@9.1.3: find-cache-dir "^4.0.0" schema-utils "^4.0.0" -babel-plugin-macros@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - babel-plugin-polyfill-corejs2@^0.4.10: version "0.4.11" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" @@ -4129,11 +3748,6 @@ ci-info@^3.7.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -classnames@2.x, classnames@^2.2.1, classnames@^2.2.6, classnames@^2.3.2: - version "2.5.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" - integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -4212,11 +3826,6 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" - integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -4363,7 +3972,7 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.5.0, convert-source-map@^1.5.1, convert-source-map@^1.7.0: +convert-source-map@^1.5.1, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -4433,17 +4042,6 @@ cose-base@^2.2.0: dependencies: layout-base "^2.0.0" -cosmiconfig@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - cosmiconfig@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" @@ -4524,14 +4122,6 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" -css-vendor@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" - integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ== - dependencies: - "@babel/runtime" "^7.8.3" - is-in-browser "^1.0.2" - css-what@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" @@ -4542,11 +4132,6 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -csstype@^3.0.2, csstype@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - cytoscape-cose-bilkent@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b" @@ -5062,14 +4647,6 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" -dom-helpers@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - dom-serializer@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" @@ -5703,13 +5280,6 @@ file-entry-cache@^8.0.0: dependencies: flat-cache "^4.0.0" -file-selector@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc" - integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw== - dependencies: - tslib "^2.4.0" - fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -5745,11 +5315,6 @@ find-replace@^3.0.0: dependencies: array-back "^3.0.1" -find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -6126,13 +5691,6 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" -hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - hosted-git-info@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" @@ -6267,11 +5825,6 @@ hyperdyperid@^1.2.0: resolved "https://registry.yarnpkg.com/hyperdyperid/-/hyperdyperid-1.2.0.tgz#59668d323ada92228d2a869d3e474d5a33b69e6b" integrity sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A== -hyphenate-style-name@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436" - integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw== - iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -6511,11 +6064,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-in-browser@^1.0.2, is-in-browser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" - integrity sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g== - is-inside-container@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" @@ -6746,7 +6294,7 @@ js-cookie@^3.0.5: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc" integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw== -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -6861,76 +6409,6 @@ jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jss-plugin-camel-case@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz#27ea159bab67eb4837fa0260204eb7925d4daa1c" - integrity sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw== - dependencies: - "@babel/runtime" "^7.3.1" - hyphenate-style-name "^1.0.3" - jss "10.10.0" - -jss-plugin-default-unit@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz#db3925cf6a07f8e1dd459549d9c8aadff9804293" - integrity sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-global@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz#1c55d3c35821fab67a538a38918292fc9c567efd" - integrity sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-nested@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz#db872ed8925688806e77f1fc87f6e62264513219" - integrity sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - tiny-warning "^1.0.2" - -jss-plugin-props-sort@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz#67f4dd4c70830c126f4ec49b4b37ccddb680a5d7" - integrity sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-rule-value-function@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz#7d99e3229e78a3712f78ba50ab342e881d26a24b" - integrity sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - tiny-warning "^1.0.2" - -jss-plugin-vendor-prefixer@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz#c01428ef5a89f2b128ec0af87a314d0c767931c7" - integrity sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg== - dependencies: - "@babel/runtime" "^7.3.1" - css-vendor "^2.0.8" - jss "10.10.0" - -jss@10.10.0, jss@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.10.0.tgz#a75cc85b0108c7ac8c7b7d296c520a3e4fbc6ccc" - integrity sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw== - dependencies: - "@babel/runtime" "^7.3.1" - csstype "^3.0.2" - is-in-browser "^1.1.3" - tiny-warning "^1.0.2" - jstree-bootstrap-theme@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/jstree-bootstrap-theme/-/jstree-bootstrap-theme-1.0.1.tgz#7d5edc73a846e8da7f94f57a1cc5ddee9d9eab4b" @@ -7221,22 +6699,12 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== - -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@4.17.21, lodash@^4.0.1, lodash@^4.17.14: +lodash@4.17.21, lodash@^4.17.14: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7265,13 +6733,6 @@ log-update@^6.1.0: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" -loose-envify@^1.1.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - lru-cache@^10.0.1, lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -7913,7 +7374,7 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -object-assign@^4.0.1, object-assign@^4.1.1: +object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -8185,7 +7646,7 @@ parse-imports@^2.1.1: es-module-lexer "^1.5.3" slashes "^3.0.12" -parse-json@^5.0.0, parse-json@^5.2.0: +parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -8292,11 +7753,6 @@ path-to-regexp@0.1.10: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - path-type@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-5.0.0.tgz#14b01ed7aea7ddf9c7c3f46181d4d04f9c785bb8" @@ -8505,11 +7961,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.8.3: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - prismjs@^1.27.0, prismjs@^1.28.0: version "1.29.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" @@ -8538,15 +7989,6 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" -prop-types@^15.6.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -8632,128 +8074,6 @@ rbush@^3.0.1: dependencies: quickselect "^2.0.0" -rc-motion@^2.0.0, rc-motion@^2.0.1: - version "2.9.3" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.9.3.tgz#b1bdaf816f1ccb3e4b3b0c531c3037a59286379e" - integrity sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-util "^5.43.0" - -rc-overflow@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.3.2.tgz#72ee49e85a1308d8d4e3bd53285dc1f3e0bcce2c" - integrity sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw== - dependencies: - "@babel/runtime" "^7.11.1" - classnames "^2.2.1" - rc-resize-observer "^1.0.0" - rc-util "^5.37.0" - -rc-resize-observer@^1.0.0, rc-resize-observer@^1.3.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz#7bba61e6b3c604834980647cce6451914750d0cc" - integrity sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q== - dependencies: - "@babel/runtime" "^7.20.7" - classnames "^2.2.1" - rc-util "^5.38.0" - resize-observer-polyfill "^1.5.1" - -rc-select@14.15.2: - version "14.15.2" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.15.2.tgz#d85fcf3a708bdf837b003feeed653347b8980ad0" - integrity sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw== - dependencies: - "@babel/runtime" "^7.10.1" - "@rc-component/trigger" "^2.1.1" - classnames "2.x" - rc-motion "^2.0.1" - rc-overflow "^1.3.1" - rc-util "^5.16.1" - rc-virtual-list "^3.5.2" - -rc-util@^5.15.0, rc-util@^5.16.1, rc-util@^5.24.4, rc-util@^5.37.0, rc-util@^5.38.0, rc-util@^5.43.0: - version "5.43.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.43.0.tgz#bba91fbef2c3e30ea2c236893746f3e9b05ecc4c" - integrity sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw== - dependencies: - "@babel/runtime" "^7.18.3" - react-is "^18.2.0" - -rc-virtual-list@3.5.2, rc-virtual-list@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.5.2.tgz#5e1028869bae900eacbae6788d4eca7210736006" - integrity sha512-sE2G9hTPjVmatQni8OP2Kx33+Oth6DMKm67OblBBmgMBJDJQOOFpSGH7KZ6Pm85rrI2IGxDRXZCr0QhYOH2pfQ== - dependencies: - "@babel/runtime" "^7.20.0" - classnames "^2.2.6" - rc-resize-observer "^1.0.0" - rc-util "^5.15.0" - -react-ace@12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-12.0.0.tgz#d40afc7382092109eead7227d9426f55dcc2209d" - integrity sha512-PstU6CSMfYIJknb4su2Fa0WgLXzq2ufQgR6fjcSWuGT1hGTHkBzuKw+SncV8PuLCdSJBJc1VehPhyeXlWByG/g== - dependencies: - ace-builds "^1.32.8" - diff-match-patch "^1.0.5" - lodash.get "^4.4.2" - lodash.isequal "^4.5.0" - prop-types "^15.8.1" - -react-dom@18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" - -react-dropzone@14.2.9: - version "14.2.9" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.2.9.tgz#193a33f9035e29fc91abf24e50de5d66cfa7c8c0" - integrity sha512-jRZsMC7h48WONsOLHcmhyn3cRWJoIPQjPApvt/sJVfnYaB3Qltn025AoRTTJaj4WdmmgmLl6tUQg1s0wOhpodQ== - dependencies: - attr-accept "^2.2.2" - file-selector "^0.6.0" - prop-types "^15.8.1" - -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-is@^18.2.0, react-is@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== - -react-transition-group@^4.4.5: - version "4.4.5" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" - integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - -react@18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -reactcss@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" - integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== - dependencies: - lodash "^4.0.1" - read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" @@ -8888,11 +8208,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -resize-observer-polyfill@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -8909,7 +8224,7 @@ resolve-url-loader@5.0.0: postcss "^8.2.14" source-map "0.6.1" -resolve@1.22.8, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.4, resolve@^1.22.8: +resolve@1.22.8, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.4, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -9092,13 +8407,6 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - schema-inspector@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/schema-inspector/-/schema-inspector-2.1.0.tgz#85096fbc78162a420262ed41b82e60ac927767b2" @@ -9408,11 +8716,6 @@ source-map@0.7.4: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - spdx-correct@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" @@ -9621,11 +8924,6 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -stylis@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" - integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== - stylis@^4.3.1: version "4.3.4" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.4.tgz#ca5c6c4a35c4784e4e93a2a24dc4e9fa075250a4" @@ -9810,11 +9108,6 @@ tiny-emitter@^2.0.0: resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== -tiny-warning@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - tinycolor2@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" @@ -10504,11 +9797,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - yaml@^2.2.2, yaml@^2.3.4: version "2.6.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773"