diff --git a/ui-ngx/package.json b/ui-ngx/package.json index ed096b871a..4112e24fce 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -96,7 +96,7 @@ "schema-inspector": "^2.0.2", "screenfull": "^6.0.2", "split.js": "^1.6.5", - "systemjs": "6.11.0", + "systemjs": "6.14.1", "tinycolor2": "^1.6.0", "tinymce": "~5.10.7", "tooltipster": "^4.2.8", @@ -137,7 +137,7 @@ "@types/raphael": "^2.3.2", "@types/react": "17.0.37", "@types/react-dom": "17.0.11", - "@types/systemjs": "6.1.1", + "@types/systemjs": "6.13.1", "@types/tinycolor2": "^1.4.3", "@types/tooltipster": "^0.0.31", "@typescript-eslint/eslint-plugin": "5.57.0", diff --git a/ui-ngx/src/app/core/http/resource.service.ts b/ui-ngx/src/app/core/http/resource.service.ts index 9296f701b0..f7cb8441d1 100644 --- a/ui-ngx/src/app/core/http/resource.service.ts +++ b/ui-ngx/src/app/core/http/resource.service.ts @@ -20,8 +20,9 @@ import { PageLink } from '@shared/models/page/page-link'; import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; import { forkJoin, Observable, of } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; -import { Resource, ResourceInfo } from '@shared/models/resource.models'; +import { Resource, ResourceInfo, ResourceType } from '@shared/models/resource.models'; import { catchError, map, mergeMap } from 'rxjs/operators'; +import { isNotEmptyStr } from '@core/utils'; @Injectable({ providedIn: 'root' @@ -33,15 +34,22 @@ export class ResourceService { } - public getResources(pageLink: PageLink, config?: RequestConfig): Observable> { - return this.http.get>(`/api/resource${pageLink.toQuery()}`, - defaultHttpOptionsFromConfig(config)); + public getResources(pageLink: PageLink, resourceType?: ResourceType, config?: RequestConfig): Observable> { + let url = `/api/resource${pageLink.toQuery()}`; + if (isNotEmptyStr(resourceType)) { + url += `&resourceType=${resourceType}`; + } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } public getResource(resourceId: string, config?: RequestConfig): Observable { return this.http.get(`/api/resource/${resourceId}`, defaultHttpOptionsFromConfig(config)); } + public getResourceInfo(resourceId: string, config?: RequestConfig): Observable { + return this.http.get(`/api/resource/info/${resourceId}`, defaultHttpOptionsFromConfig(config)); + } + public downloadResource(resourceId: string): Observable { return this.http.get(`/api/resource/${resourceId}/download`, { responseType: 'arraybuffer', diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts index b34cec5eb0..5dc20ddd46 100644 --- a/ui-ngx/src/app/core/services/resources.service.ts +++ b/ui-ngx/src/app/core/services/resources.service.ts @@ -27,6 +27,9 @@ import { DOCUMENT } from '@angular/common'; import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { IModulesMap } from '@modules/common/modules-map.models'; +import { TbResourceId } from '@shared/models/id/tb-resource-id'; +import { isObject } from '@core/utils'; +import { AuthService } from '@core/auth/auth.service'; declare const System; @@ -69,16 +72,18 @@ export class ResourcesService { return this.loadResourceByType(fileType, url); } - public loadFactories(url: string, modulesMap: IModulesMap): Observable { + public loadFactories(resourceId: string | TbResourceId, modulesMap: IModulesMap): Observable { + const url = this.getDownloadUrl(resourceId); if (this.loadedModulesAndFactories[url]) { return this.loadedModulesAndFactories[url].asObservable(); } modulesMap.init(); + const meta = this.getMetaInfo(resourceId); const subject = new ReplaySubject(); this.loadedModulesAndFactories[url] = subject; import('@angular/compiler').then( () => { - System.import(url).then( + System.import(url, undefined, meta).then( (module) => { const modules = this.extractNgModules(module); if (modules.length) { @@ -123,16 +128,18 @@ export class ResourcesService { return subject.asObservable(); } - public loadModules(url: string, modulesMap: IModulesMap): Observable[]> { + public loadModules(resourceId: string | TbResourceId, modulesMap: IModulesMap): Observable[]> { + const url = this.getDownloadUrl(resourceId); if (this.loadedModules[url]) { return this.loadedModules[url].asObservable(); } modulesMap.init(); + const meta = this.getMetaInfo(resourceId); const subject = new ReplaySubject[]>(); this.loadedModules[url] = subject; import('@angular/compiler').then( () => { - System.import(url).then( + System.import(url, undefined, meta).then( (module) => { try { let modules; @@ -246,4 +253,21 @@ export class ResourcesService { this.anchor.appendChild(el); return subject.asObservable(); } + + private getDownloadUrl(resourceId: string | TbResourceId): string { + if (isObject(resourceId)) { + return `/api/resource/js/${(resourceId as TbResourceId).id}/download`; + } + return resourceId as string; + } + + private getMetaInfo(resourceId: string | TbResourceId): object { + if (isObject(resourceId)) { + return { + additionalHeaders: { + 'X-Authorization': `Bearer ${AuthService.getJwtToken()}` + } + }; + } + } } diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index b3a14b0f61..961d34a1d4 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -614,6 +614,13 @@ class ModulesMap implements IModulesMap { for (const moduleId of Object.keys(this.modulesMap)) { System.set('app:' + moduleId, this.modulesMap[moduleId]); } + System.constructor.prototype.shouldFetch = (url: string) => url.endsWith('/download'); + System.constructor.prototype.fetch = (url, options: RequestInit & {meta?: any}) => { + if (options?.meta?.additionalHeaders) { + options.headers = { ...options.headers, ...options.meta.additionalHeaders }; + } + return fetch(url, options); + }; this.initialized = true; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.html b/ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.html index 7014570235..f44ff6138c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/custom-action-pretty-resources-tabs.component.html @@ -22,11 +22,14 @@
- - - + + {{ 'widget.resource-is-module' | translate }} @@ -40,16 +43,15 @@ close
-
- -
+ diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts index 02a4bf5867..533fd0fea1 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts @@ -28,6 +28,7 @@ import { SmsProviderComponent } from '@home/pages/admin/sms-provider.component'; import { SendTestSmsDialogComponent } from '@home/pages/admin/send-test-sms-dialog.component'; import { HomeSettingsComponent } from '@home/pages/admin/home-settings.component'; import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources-library.component'; +import { ResourcesTableHeaderComponent } from '@home/pages/admin/resource/resources-table-header.component'; import { QueueComponent } from '@home/pages/admin/queue/queue.component'; import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component'; import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component'; @@ -44,6 +45,7 @@ import { TwoFactorAuthSettingsComponent } from '@home/pages/admin/two-factor-aut OAuth2SettingsComponent, HomeSettingsComponent, ResourcesLibraryComponent, + ResourcesTableHeaderComponent, QueueComponent, RepositoryAdminSettingsComponent, AutoCommitAdminSettingsComponent, diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts index b3126c781b..733e5ef2b3 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts @@ -36,6 +36,7 @@ import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources- import { PageLink } from '@shared/models/page/page-link'; import { EntityAction } from '@home/models/entity/entity-component.models'; import { map } from 'rxjs/operators'; +import { ResourcesTableHeaderComponent } from '@home/pages/admin/resource/resources-table-header.component'; @Injectable() export class ResourcesLibraryTableConfigResolver implements Resolve> { @@ -53,6 +54,7 @@ export class ResourcesLibraryTableConfigResolver implements Resolve resource ? resource.title : ''; @@ -81,7 +83,7 @@ export class ResourcesLibraryTableConfigResolver implements Resolve this.translate.instant('resource.delete-resources-title', {count}); this.config.deleteEntitiesContent = () => this.translate.instant('resource.delete-resources-text'); - this.config.entitiesFetchFunction = pageLink => this.resourceService.getResources(pageLink); + this.config.entitiesFetchFunction = pageLink => this.resourceService.getResources(pageLink, this.config.componentsData.resourceType); this.config.loadEntity = id => this.resourceService.getResource(id.id); this.config.saveEntity = resource => this.saveResource(resource); this.config.deleteEntity = id => this.resourceService.deleteResource(id.id); @@ -110,6 +112,9 @@ export class ResourcesLibraryTableConfigResolver implements Resolve { this.config.tableTitle = this.translate.instant('resource.resources-library'); + this.config.componentsData = { + resourceType: '' + }; const authUser = getCurrentAuthUser(this.store); this.config.deleteEnabled = (resource) => this.isResourceEditable(resource, authUser.authority); this.config.entitySelectionEnabled = (resource) => this.isResourceEditable(resource, authUser.authority); diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts index 90f7847e10..99d8697dc5 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts @@ -57,7 +57,7 @@ export class ResourcesLibraryComponent extends EntityComponent impleme ngOnInit() { super.ngOnInit(); this.entityForm.get('resourceType').valueChanges.pipe( - startWith(ResourceType.LWM2M_MODEL), + startWith(ResourceType.JS_MODULE), filter(() => this.isAdd), takeUntil(this.destroy$) ).subscribe((type) => { @@ -91,7 +91,7 @@ export class ResourcesLibraryComponent extends EntityComponent impleme buildForm(entity: Resource): FormGroup { return this.fb.group({ title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], - resourceType: [entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL, Validators.required], + resourceType: [entity?.resourceType ? entity.resourceType : ResourceType.JS_MODULE, Validators.required], fileName: [entity ? entity.fileName : null, Validators.required], data: [entity ? entity.data : null, Validators.required] }); diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-table-header.component.html b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-table-header.component.html new file mode 100644 index 0000000000..ad8cf063e0 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-table-header.component.html @@ -0,0 +1,30 @@ + + + resource.resource-type + + + {{ "resource.all-types" | translate }} + + + {{ resourceTypesTranslationMap.get(resourceType) | translate }} + + + diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-table-header.component.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-table-header.component.ts new file mode 100644 index 0000000000..dfe4bacff8 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-table-header.component.ts @@ -0,0 +1,42 @@ +/// +/// Copyright © 2016-2023 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 { Component } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component'; +import { Resource, ResourceInfo, ResourceType, ResourceTypeTranslationMap } from '@shared/models/resource.models'; +import { PageLink } from '@shared/models/page/page-link'; + +@Component({ + selector: 'tb-resources-table-header', + templateUrl: './resources-table-header.component.html', + styleUrls: [] +}) +export class ResourcesTableHeaderComponent extends EntityTableHeaderComponent { + + readonly resourceTypes: ResourceType[] = Object.values(ResourceType); + readonly resourceTypesTranslationMap = ResourceTypeTranslationMap; + + constructor(protected store: Store) { + super(store); + } + + resourceTypeChanged(resourceType: ResourceType) { + this.entitiesTableConfig.componentsData.resourceType = resourceType; + this.entitiesTableConfig.getTable().resetSortAndFilter(true); + } +} 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 046ad5acb2..2b650cb1ce 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 @@ -122,12 +122,14 @@
- - - + + {{ 'widget.resource-is-module' | translate }} @@ -140,15 +142,14 @@ close
-
- -
+ diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss index 7d0d854d46..b8359b38db 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss @@ -31,18 +31,21 @@ tb-widget-editor { overflow-y: auto; } - mat-form-field.resource-field { - max-height: 40px; - margin: 10px 0 0; - .mat-mdc-text-field-wrapper { - padding-bottom: 0; - .mat-mdc-form-field-flex { - max-height: 40px; - .mat-mdc-form-field-infix { - border: 0; - padding-top: 7px; - padding-bottom: 7px; - min-height: 32px; + .resource-field { + mat-form-field { + .mat-mdc-text-field-wrapper { + padding-bottom: 0; + height: 40px; + + .mat-mdc-form-field-flex { + max-height: 40px; + + .mat-mdc-form-field-infix { + border: 0; + padding-top: 7px; + padding-bottom: 7px; + min-height: 32px; + } } } } diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts index 1dd31182f1..9ec226769a 100644 --- a/ui-ngx/src/app/shared/components/public-api.ts +++ b/ui-ngx/src/app/shared/components/public-api.ts @@ -22,4 +22,5 @@ export * from './js-func.component'; export * from './script-lang.component'; export * from './slack-conversation-autocomplete.component'; export * from './notification/template-autocomplete.component'; +export * from './resource/resource-autocomplete.component'; export * from './toggle-header.component'; diff --git a/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html new file mode 100644 index 0000000000..bd7a2016d0 --- /dev/null +++ b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.html @@ -0,0 +1,46 @@ + + + + + + + + + + {{ searchText }} + + + diff --git a/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts new file mode 100644 index 0000000000..6debdb49d9 --- /dev/null +++ b/ui-ngx/src/app/shared/components/resource/resource-autocomplete.component.ts @@ -0,0 +1,179 @@ +/// +/// Copyright © 2016-2023 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 { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { Observable, of } from 'rxjs'; +import { catchError, debounceTime, map, share, switchMap, tap } from 'rxjs/operators'; +import { isDefinedAndNotNull, isEmptyStr, isEqual, isObject } from '@core/utils'; +import { ResourceInfo, ResourceType } from '@shared/models/resource.models'; +import { TbResourceId } from '@shared/models/id/tb-resource-id'; +import { ResourceService } from '@core/http/resource.service'; +import { PageLink } from '@shared/models/page/page-link'; +import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field'; + +@Component({ + selector: 'tb-resource-autocomplete', + templateUrl: './resource-autocomplete.component.html', + styleUrls: [], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ResourceAutocompleteComponent), + multi: true + }] +}) +export class ResourceAutocompleteComponent implements ControlValueAccessor, OnInit { + + @Input() + @coerceBoolean() + disabled: boolean; + + @Input() + @coerceBoolean() + required: boolean; + + @Input() + appearance: MatFormFieldAppearance = 'fill'; + + @Input() + subscriptSizing: SubscriptSizing = 'fixed'; + + @Input() + placeholder: string; + + @Input() + @coerceBoolean() + hideRequiredMarker = false; + + @Input() + @coerceBoolean() + allowAutocomplete = false; + + resourceFormGroup = this.fb.group({ + resource: [null] + }); + + filteredResources$: Observable>; + + searchText = ''; + + @ViewChild('resourceInput', {static: true}) resourceInput: ElementRef; + + private modelValue: string | TbResourceId; + private dirty = false; + + private propagateChange = (v: any) => { }; + + constructor(private fb: FormBuilder, + private resourceService: ResourceService) { + } + + ngOnInit(): void { + if(this.required) { + this.resourceFormGroup.get('resource').setValidators(Validators.required); + this.resourceFormGroup.get('resource').updateValueAndValidity({emitEvent: false}); + } + this.filteredResources$ = this.resourceFormGroup.get('resource').valueChanges + .pipe( + debounceTime(150), + tap(value => { + let modelValue; + if (isObject(value)) { + modelValue = value.id; + } else if (isEmptyStr(value)) { + modelValue = null; + } else { + modelValue = value; + } + this.updateView(modelValue); + if (value === null) { + this.clear(); + } + }), + map(value => value ? (typeof value === 'string' ? value : value.title) : ''), + switchMap(name => this.fetchResources(name) ), + share() + ); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean) { + this.disabled = isDisabled; + if (this.disabled) { + this.resourceFormGroup.disable({emitEvent: false}); + } else { + this.resourceFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: string | TbResourceId) { + if (isDefinedAndNotNull(value)) { + this.searchText = ''; + if (isObject(value) && typeof value !== 'string' && (value as TbResourceId).id) { + this.resourceService.getResourceInfo(value.id, {ignoreLoading: true, ignoreErrors: true}).subscribe(resource => { + this.modelValue = resource.id; + this.resourceFormGroup.get('resource').patchValue(resource, {emitEvent: false}); + }); + } else { + this.modelValue = value; + this.resourceFormGroup.get('resource').patchValue(value, {emitEvent: false}); + } + this.dirty = true; + } + } + + displayResourceFn(resource?: ResourceInfo | string): string { + return isObject(resource) ? (resource as ResourceInfo).title : resource as string; + } + + clear() { + this.resourceFormGroup.get('resource').patchValue('', {emitEvent: true}); + setTimeout(() => { + this.resourceInput.nativeElement.blur(); + this.resourceInput.nativeElement.focus(); + }, 0); + } + + onFocus() { + if (this.dirty) { + this.resourceFormGroup.get('resource').updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + private updateView(value: string | TbResourceId ) { + if (!isEqual(this.modelValue, value)) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } + } + + private fetchResources(searchText?: string): Observable> { + this.searchText = searchText; + return this.resourceService.getResources(new PageLink(50, 0, searchText), ResourceType.JS_MODULE, {ignoreLoading: true}).pipe( + catchError(() => of(null)), + map(data => data.data) + ); + } + +} diff --git a/ui-ngx/src/app/shared/models/resource.models.ts b/ui-ngx/src/app/shared/models/resource.models.ts index 8d7121c5e5..6621f10c42 100644 --- a/ui-ngx/src/app/shared/models/resource.models.ts +++ b/ui-ngx/src/app/shared/models/resource.models.ts @@ -52,7 +52,7 @@ export const ResourceTypeTranslationMap = new Map( ] ); -export interface ResourceInfo extends BaseData { +export interface ResourceInfo extends Omit, 'name' | 'label'> { tenantId?: TenantId; resourceKey?: string; title?: string; @@ -62,6 +62,7 @@ export interface ResourceInfo extends BaseData { export interface Resource extends ResourceInfo { data: string; fileName: string; + name?: string; } export interface Resources extends ResourceInfo { diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 1d755c3bb1..7806c9c15b 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -189,6 +189,7 @@ import { GtMdLgShowHideDirective } from '@shared/layout/layout.directives'; import { ColorPickerComponent } from '@shared/components/color-picker/color-picker.component'; +import { ResourceAutocompleteComponent } from '@shared/components/resource/resource-autocomplete.component'; import { ShortNumberPipe } from '@shared/pipe/short-number.pipe'; import { ToggleHeaderComponent } from '@shared/components/toggle-header.component'; @@ -360,6 +361,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) GtMdLgLayoutGapDirective, GtMdLgShowHideDirective, ColorPickerComponent, + ResourceAutocompleteComponent, ToggleHeaderComponent ], imports: [ @@ -586,6 +588,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) GtMdLgLayoutGapDirective, GtMdLgShowHideDirective, ColorPickerComponent, + ResourceAutocompleteComponent, ToggleHeaderComponent ] }) 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 ea9230cf34..345d31067a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3252,6 +3252,7 @@ }, "resource": { "add": "Add Resource", + "all-types": "All", "copyId": "Copy resource Id", "delete": "Delete resource", "delete-resource-text": "Be careful, after the confirmation the resource will become unrecoverable.", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 8da9cb382a..2ff2c81163 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -3286,10 +3286,10 @@ dependencies: "@types/react" "*" -"@types/systemjs@6.1.1": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@types/systemjs/-/systemjs-6.1.1.tgz#eae17f2a080e867d01a2dd614f524ab227cf5a41" - integrity sha512-d1M6eDKBGWx7RbYy295VEFoOF9YDJkPI959QYnmzcmeaV+SP4D0xV7dEh3sN5XF3GvO3PhGzm+17Z598nvHQuQ== +"@types/systemjs@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@types/systemjs/-/systemjs-6.13.1.tgz#fccf8049fdf328bca4cfbad3a9cc7bf088b45048" + integrity sha512-Jxo2/uif1WpkabfyvWpFmPWFPDdwKUmyL7xWzjtxNALEu2pgce+eISjbf0Vr+SsK/D9savO5kTRcf+COLK5eiQ== "@types/tinycolor2@^1.4.3": version "1.4.3" @@ -10101,10 +10101,10 @@ symbol-observable@4.0.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== -systemjs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.11.0.tgz#8df8e74fc05822e6c40170aa409b9ca64833315f" - integrity sha512-7YPIY44j+BoY+E6cGBSw0oCU8SNTTIHKZgftcBdwWkDzs/M86Fdlr21FrzAyph7Zo8r3CFGscyFe4rrBtixrBg== +systemjs@6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.14.1.tgz#95a580b91b50d0d69ff178ed4816f0ddbcea23c1" + integrity sha512-8ftwWd+XnQtZ/aGbatrN4QFNGrKJzmbtixW+ODpci7pyoTajg4sonPP8aFLESAcuVxaC1FyDESt+SpfFCH9rZQ== table-layout@^1.0.2: version "1.0.2"