diff --git a/.eslintrc.json b/.eslintrc.json index 6065ea813..474ecebe5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -43,9 +43,9 @@ "@angular-eslint/component-selector": [ "error", { - "type": "attribute", + "type": "string", "prefix": "senergy", - "style": "camelCase" + "style": "kebab-case" } ], "brace-style": [ diff --git a/angular.json b/angular.json index 404fdced4..3c35572fb 100644 --- a/angular.json +++ b/angular.json @@ -30,6 +30,11 @@ ], "styles": [ "src/styles.css", + { + "input": "src/themes/indigo.scss", + "bundleName": "indigo", + "inject": false + }, { "input": "src/themes/lll.scss", "bundleName": "lll", diff --git a/src/app/core/directives/matError.directive.ts b/src/app/core/directives/matError.directive.ts index 57e38adc3..aad79615c 100644 --- a/src/app/core/directives/matError.directive.ts +++ b/src/app/core/directives/matError.directive.ts @@ -51,7 +51,13 @@ export class MatErrorMessagesDirective implements AfterViewInit, OnDestroy { const container = this._inj.get(MatFormField); this.inputRef = container._control; if (this.formControl == null) { - this.formControl = this.inputRef.ngControl.control; + try { + this.formControl = this.inputRef.ngControl.control; + } catch (e) { + throw new Error('FormControl must be provided to mat-error with label: ' + this.label + '\n This ' + + 'can be done by using formControlName, formControl, or ngModel in the relevant mat-form-field. ' + + 'If there is no FormControl needed for the mat-form-field, then the mat-error is redundant, too.'); + } } //console.log(this.label, ' inputRef: ', this.inputRef); diff --git a/src/app/core/model/permissions/permissions.ts b/src/app/core/model/permissions/permissions.ts deleted file mode 100644 index 6aef6b346..000000000 --- a/src/app/core/model/permissions/permissions.ts +++ /dev/null @@ -1,57 +0,0 @@ -interface ListAfter { - sort_field_value: any; - id: string; -} - -interface UrlValues { - [key: string]: string[]; -} - -interface QueryListCommons { - limit?: Number; - offset?: Number; - after?: ListAfter; - rights?: string; - sort_by?: string; - sort_desc?: boolean; - add_id_modifier?: UrlValues; -} - -interface Condition { - feature: string; - operation: '==' | '!=' | 'any_value_in_feature'; - value: any; - ref?: string; -} - -export interface Selection { - and?: Selection[]; - or?: Selection[]; - not?: Selection; - condition?: Condition; -} - -interface QueryFind extends QueryListCommons { - search?: string; - filter?: Selection; - with_total?: boolean; -} - -interface QueryListIds extends QueryListCommons { - ids: string[]; - with_total?: boolean; -} - -interface QueryCheckIds { - ids: string[]; - rights: string; -} - -export interface PermissionQueryRequest { - resource: string; - find?: QueryFind; - list_ids?: QueryListIds; - check_ids?: QueryCheckIds; - term_aggregate?: string; - term_aggregate_limit?: Number; -} diff --git a/src/app/modules/admin/permissions/shared/services/ladom.service.ts b/src/app/modules/admin/permissions/shared/services/ladom.service.ts index 5e76a8ff1..7132cedfd 100644 --- a/src/app/modules/admin/permissions/shared/services/ladom.service.ts +++ b/src/app/modules/admin/permissions/shared/services/ladom.service.ts @@ -94,18 +94,11 @@ export class LadonService { const requests: AuthorizationRequest[] = []; const methods: AllowedMethods[] = ['GET', 'DELETE', 'POST', 'PUT', 'PATCH']; - const ServiceEndpoints = [ + const serviceEndpoints = [ environment.flowRepoUrl, environment.flowEngineUrl, environment.flowParserUrl, - environment.permissionSearchUrl, - environment.permissionSearchUrl + '/v3/resources/characteristics', - environment.permissionSearchUrl + '/v3/resources/device-classes', - environment.permissionSearchUrl + '/v3/resources/functions', - environment.permissionSearchUrl + '/v3/resources/concepts', - environment.permissionSearchUrl + '/v3/resources/device-types', - environment.apiAggregatorUrl, environment.deviceRepoUrl, environment.iotRepoUrl, @@ -127,6 +120,11 @@ export class LadonService { environment.deviceRepoUrl, environment.deviceRepoUrl + '/aspects', + environment.deviceRepoUrl + '/v2/device-classes', + environment.deviceRepoUrl + '/characteristics', + environment.deviceRepoUrl + '/v2/concepts', + environment.deviceRepoUrl + '/device-types', + environment.deviceRepoUrl + '/functions', environment.deviceManagerUrl, environment.deviceManagerUrl + '/device-types', @@ -149,7 +147,7 @@ export class LadonService { environment.reportEngineUrl, ]; - ServiceEndpoints.forEach(endpointURL => { + serviceEndpoints.forEach(endpointURL => { const endpoint = new URL(endpointURL).pathname; methods.forEach(method => { @@ -160,7 +158,7 @@ export class LadonService { return new Promise((resolve, _) => { this.userIsAuthorized(requests).subscribe(authResponse => { const allRules: Record = {}; - ServiceEndpoints.forEach((endpointURL, endpointIndex) => { + serviceEndpoints.forEach((endpointURL, endpointIndex) => { allRules[endpointURL] = { GET: true, POST: false, diff --git a/src/app/modules/admin/timescale-rules/timescale-rules.component.ts b/src/app/modules/admin/timescale-rules/timescale-rules.component.ts index 9d1949635..a29cc6915 100644 --- a/src/app/modules/admin/timescale-rules/timescale-rules.component.ts +++ b/src/app/modules/admin/timescale-rules/timescale-rules.component.ts @@ -18,7 +18,7 @@ import {Component, OnInit, ViewChild} from '@angular/core'; import {TimescaleRulesService} from './shared/timescale-rules.service'; import {TimescaleRuleModel, TimescaleRuleTemplateModel} from './shared/timescale-rule.model'; import {MatTable} from '@angular/material/table'; -import {ImportTypePermissionSearchModel} from '../../imports/import-types/shared/import-types.model'; +import {ImportTypeModel} from '../../imports/import-types/shared/import-types.model'; import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; import {TimescaleRulesCreateEditComponent} from './timescale-rules-create-edit/timescale-rules-create-edit.component'; import {DialogsService} from '../../../core/services/dialogs.service'; @@ -35,7 +35,7 @@ import { styleUrls: ['./timescale-rules.component.css'] }) export class TimescaleRulesComponent implements OnInit { - @ViewChild(MatTable, {static: false}) table!: MatTable; + @ViewChild(MatTable, {static: false}) table!: MatTable; constructor( private timescaleRuleService: TimescaleRulesService, diff --git a/src/app/modules/devices/device-groups/edit/device-groups-edit.component.spec.ts b/src/app/modules/devices/device-groups/edit/device-groups-edit.component.spec.ts index 484ed1048..8e87afb18 100644 --- a/src/app/modules/devices/device-groups/edit/device-groups-edit.component.spec.ts +++ b/src/app/modules/devices/device-groups/edit/device-groups-edit.component.spec.ts @@ -36,8 +36,7 @@ import { MatCardModule } from '@angular/material/card'; import { MatTooltipModule } from '@angular/material/tooltip'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; -import { DeviceTypeFunctionModel } from '../../../metadata/device-types-overview/shared/device-type.model'; -import { DeviceClassesPermSearchModel } from '../../../metadata/device-classes/shared/device-classes-perm-search.model'; +import { DeviceTypeDeviceClassModel, DeviceTypeFunctionModel } from '../../../metadata/device-types-overview/shared/device-type.model'; import { AspectsPermSearchModel } from '../../../metadata/aspects/shared/aspects-perm-search.model'; import { DeviceInstancesService } from '../../device-instances/shared/device-instances.service'; @@ -137,11 +136,8 @@ describe('DeviceGroupsEditComponent', () => { id: 'device-class:id-1', name: 'controller-type', image: '', - creator: '', - permissions: { r: true, w: true, x: true, a: true }, - shared: false, }, - ] as DeviceClassesPermSearchModel[]; + ] as DeviceTypeDeviceClassModel[]; const knownAspects = [ { @@ -481,7 +477,7 @@ describe('DeviceGroupsEditComponent', () => { return of(JSON.parse(JSON.stringify(result))); }); deviceGroupServiceSpy.getDeviceClassListByIds.and.callFake(function(ids: string[]) { - const result: DeviceClassesPermSearchModel[] = []; + const result: DeviceTypeDeviceClassModel[] = []; for (const id of ids) { for (const dc of knownDeviceClasses) { if (id === dc.id) { diff --git a/src/app/modules/devices/device-groups/edit/device-groups-edit.component.ts b/src/app/modules/devices/device-groups/edit/device-groups-edit.component.ts index a1cf5507e..2af0ef279 100644 --- a/src/app/modules/devices/device-groups/edit/device-groups-edit.component.ts +++ b/src/app/modules/devices/device-groups/edit/device-groups-edit.component.ts @@ -27,9 +27,7 @@ import { } from '../shared/device-groups.model'; import {Attribute, DeviceInstancesBaseModel} from '../../device-instances/shared/device-instances.model'; import { debounceTime, delay } from 'rxjs/operators'; -import { DeviceTypeFunctionModel } from '../../../metadata/device-types-overview/shared/device-type.model'; -import { AspectsPermSearchModel } from '../../../metadata/aspects/shared/aspects-perm-search.model'; -import { DeviceClassesPermSearchModel } from '../../../metadata/device-classes/shared/device-classes-perm-search.model'; +import { DeviceTypeAspectModel, DeviceTypeDeviceClassModel, DeviceTypeFunctionModel } from '../../../metadata/device-types-overview/shared/device-type.model'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { DeviceGroupsPipelineHelperDialogComponent } from './device-groups-pipeline-helper-dialog/device-groups-pipeline-helper-dialog.component'; import { PipelineRegistryService } from '../../../data/pipeline-registry/shared/pipeline-registry.service'; @@ -52,8 +50,8 @@ export class DeviceGroupsEditComponent implements OnInit { deviceCache: Map = new Map(); functionsCache: Map = new Map(); - aspectCache: Map = new Map(); - deviceClassCache: Map = new Map(); + aspectCache: Map = new Map(); + deviceClassCache: Map = new Map(); debounceTimeInMs = 500; rerouteAfterSaveDelayInMs = 2000; @@ -307,8 +305,8 @@ export class DeviceGroupsEditComponent implements OnInit { Promise.all([this.loadIotFunctions(functionIds), this.loadAspects(aspectIds), this.loadDeviceClasses(deviceClassIds)]).then( (infos) => { const functions: Map = infos[0]; - const aspects: Map = infos[1]; - const deviceClasses: Map = infos[2]; + const aspects: Map = infos[1]; + const deviceClasses: Map = infos[2]; let result: DeviceGroupCapability[] = []; for (const c of criteria) { const element: DeviceGroupCapability = { @@ -418,8 +416,8 @@ export class DeviceGroupsEditComponent implements OnInit { } } - private loadAspects(aspectIds: string[]): Promise> { - const result: Map = new Map(); + private loadAspects(aspectIds: string[]): Promise> { + const result: Map = new Map(); const idsForRepoSearch: string[] = []; for (const id of aspectIds) { const cachedElement = this.aspectCache.get(id); @@ -430,7 +428,7 @@ export class DeviceGroupsEditComponent implements OnInit { } } if (idsForRepoSearch.length) { - return new Promise>((resolve) => { + return new Promise>((resolve) => { this.deviceGroupService.getAspectListByIds(idsForRepoSearch).subscribe((value) => { for (const element of value) { result.set(element.id, element); @@ -443,8 +441,8 @@ export class DeviceGroupsEditComponent implements OnInit { } } - private loadDeviceClasses(deviceClassIds: string[]): Promise> { - const result: Map = new Map(); + private loadDeviceClasses(deviceClassIds: string[]): Promise> { + const result: Map = new Map(); const idsForRepoSearch: string[] = []; for (const id of deviceClassIds) { const cachedElement = this.deviceClassCache.get(id); @@ -455,7 +453,7 @@ export class DeviceGroupsEditComponent implements OnInit { } } if (idsForRepoSearch.length) { - return new Promise>((resolve) => { + return new Promise>((resolve) => { this.deviceGroupService.getDeviceClassListByIds(idsForRepoSearch).subscribe((value) => { for (const element of value) { result.set(element.id, element); diff --git a/src/app/modules/devices/device-groups/shared/device-groups.service.ts b/src/app/modules/devices/device-groups/shared/device-groups.service.ts index 288b5d58f..af000060a 100644 --- a/src/app/modules/devices/device-groups/shared/device-groups.service.ts +++ b/src/app/modules/devices/device-groups/shared/device-groups.service.ts @@ -21,9 +21,7 @@ import {Observable} from 'rxjs'; import {environment} from '../../../../../environments/environment'; import {catchError, map} from 'rxjs/operators'; import {DeviceGroupCriteriaModel, DeviceGroupHelperResultModel, DeviceGroupModel} from './device-groups.model'; -import {DeviceTypeFunctionModel} from '../../../metadata/device-types-overview/shared/device-type.model'; -import {DeviceClassesPermSearchModel} from '../../../metadata/device-classes/shared/device-classes-perm-search.model'; -import {AspectsPermSearchModel} from '../../../metadata/aspects/shared/aspects-perm-search.model'; +import {DeviceTypeAspectModel, DeviceTypeDeviceClassModel, DeviceTypeFunctionModel} from '../../../metadata/device-types-overview/shared/device-type.model'; import { PermissionTestResponse } from 'src/app/modules/admin/permissions/shared/permission.model'; import { LadonService } from 'src/app/modules/admin/permissions/shared/services/ladom.service'; @@ -159,55 +157,25 @@ export class DeviceGroupsService { getFunctionListByIds(ids: string[]): Observable { return this.http - .post(environment.permissionSearchUrl + '/v3/query/functions', { // TODO SNRGY-3575 - resource: 'functions', - list_ids: { - ids, - limit: ids.length, - offset: 0, - rights: 'r', - sort_by: 'name', - sort_desc: false, - }, - }) + .get(environment.deviceRepoUrl + '/functions?ids='+ids.join(',')) .pipe( map((resp) => resp || []), catchError(this.errorHandlerService.handleError(DeviceGroupsService.name, 'getFunctionListByIds(ids)', [])), ); } - getAspectListByIds(ids: string[]): Observable { + getAspectListByIds(ids: string[]): Observable { return this.http - .post(environment.permissionSearchUrl + '/v3/query/aspects', { // TODO SNRGY-3576 - resource: 'aspects', - list_ids: { - ids, - limit: ids.length, - offset: 0, - rights: 'r', - sort_by: 'name', - sort_desc: false, - }, - }) + .get(environment.deviceRepoUrl + '/v2/aspects?ids='+ids.join(',')) .pipe( map((resp) => resp || []), catchError(this.errorHandlerService.handleError(DeviceGroupsService.name, 'getAspectListByIds(ids)', [])), ); } - getDeviceClassListByIds(ids: string[]): Observable { + getDeviceClassListByIds(ids: string[]): Observable { return this.http - .post(environment.permissionSearchUrl + '/v3/query/device-classes', { // TODO SNRGY-3577 - resource: 'device-classes', - list_ids: { - ids, - limit: ids.length, - offset: 0, - rights: 'r', - sort_by: 'name', - sort_desc: false, - }, - }) + .get(environment.deviceRepoUrl + '/v2/device-classes?ids='+ids.join(',')) .pipe( map((resp) => resp || []), catchError(this.errorHandlerService.handleError(DeviceGroupsService.name, 'getDeviceClassListByIds(ids)', [])), diff --git a/src/app/modules/devices/device-instances/device-instances.component.spec.ts b/src/app/modules/devices/device-instances/device-instances.component.spec.ts index 61cbe1325..2878d3f85 100644 --- a/src/app/modules/devices/device-instances/device-instances.component.spec.ts +++ b/src/app/modules/devices/device-instances/device-instances.component.spec.ts @@ -43,7 +43,7 @@ describe('DeviceInstancesComponent', () => { deviceInstanceServiceSpy.userHasCreateAuthorization.and.returnValue(true); deviceInstanceServiceSpy.listUsedDeviceTypeIds.and.returnValue(of()); const deviceTypeServiceSpy: Spy = createSpyFromClass(DeviceTypeService); - deviceTypeServiceSpy.userHasPermSearchAuthorization.and.returnValue(true); + deviceTypeServiceSpy.userHasListAuthorization.and.returnValue(true); const exportDataServiceSpy: Spy = createSpyFromClass(ExportDataService); exportDataServiceSpy.userHasUsageAuthroization.and.returnValue(false); diff --git a/src/app/modules/devices/networks/networks.component.html b/src/app/modules/devices/networks/networks.component.html index f81d89277..f8762904c 100644 --- a/src/app/modules/devices/networks/networks.component.html +++ b/src/app/modules/devices/networks/networks.component.html @@ -60,7 +60,7 @@ Shared - + share diff --git a/src/app/modules/devices/networks/networks.component.ts b/src/app/modules/devices/networks/networks.component.ts index 81447606a..664793dbb 100644 --- a/src/app/modules/devices/networks/networks.component.ts +++ b/src/app/modules/devices/networks/networks.component.ts @@ -28,7 +28,7 @@ import {MatDialog} from '@angular/material/dialog'; import {NetworksDeleteDialogComponent} from './dialogs/networks-delete-dialog.component'; import {DeviceInstancesService} from '../device-instances/shared/device-instances.service'; import {MatTableDataSource} from '@angular/material/table'; -import {MatSort, Sort, SortDirection} from '@angular/material/sort'; +import {Sort, SortDirection} from '@angular/material/sort'; import {SelectionModel} from '@angular/cdk/collections'; import {MatPaginator} from '@angular/material/paginator'; import {DialogsService} from 'src/app/core/services/dialogs.service'; @@ -111,9 +111,9 @@ export class NetworksComponent implements OnInit, OnDestroy, AfterViewInit { this.sortBy = $event.active; // TODO Ingo suche connection - if (this.sortBy == 'connection') { + if (this.sortBy === 'connection') { this.sortBy = 'annotations.connected'; - } else if (this.sortBy == 'number_devices') { + } else if (this.sortBy === 'number_devices') { this.sortBy = 'device_local_ids'; } this.sortDirection = $event.direction; @@ -298,6 +298,6 @@ export class NetworksComponent implements OnInit, OnDestroy, AfterViewInit { } shareNetwork(network: HubModel): void { - this.permissionsDialogService.openPermissionDialog('hubs', network.id, network.name ); + this.permissionsDialogService.openPermissionV2Dialog('hubs', network.id, network.name ); } } diff --git a/src/app/modules/exports/export.component.ts b/src/app/modules/exports/export.component.ts index 5f789b0a4..2ce4352bd 100644 --- a/src/app/modules/exports/export.component.ts +++ b/src/app/modules/exports/export.component.ts @@ -262,7 +262,7 @@ export class ExportComponent implements OnInit, OnDestroy, AfterViewInit { concatMap(_ => this.loadExportPermissions()), concatMap(_ => { if (this.exports !=null && this.exports !== undefined && this.exports.length > 0) { - const exportIds = this.exports.filter(e => e.ExportDatabaseID === environment.exportDatabaseIdInternalTimescaleDb && e.ID !== undefined && this.permissionsPerExports.find(x => x.id === e.ID)?.execute === true).map(e => e.ID) as string[]; // TODO also filter for permissions (must contain x) + const exportIds = this.exports.filter(e => e.ExportDatabaseID === environment.exportDatabaseIdInternalTimescaleDb && e.ID !== undefined && this.permissionsPerExports.find(x => x.id === e.ID)?.execute === true).map(e => e.ID) as string[]; return this.exportDataService.getTimescaleExportUsage(exportIds).pipe(map(usage => { this.usage = usage; })); diff --git a/src/app/modules/imports/import-deploy-edit-dialog/import-deploy-edit-dialog.component.ts b/src/app/modules/imports/import-deploy-edit-dialog/import-deploy-edit-dialog.component.ts index 8c12b8359..fe81cff91 100644 --- a/src/app/modules/imports/import-deploy-edit-dialog/import-deploy-edit-dialog.component.ts +++ b/src/app/modules/imports/import-deploy-edit-dialog/import-deploy-edit-dialog.component.ts @@ -19,10 +19,9 @@ import { ImportInstanceConfigModel, ImportInstancesModel } from '../import-insta import { ImportInstancesService } from '../import-instances/shared/import-instances.service'; import { ImportTypesService } from '../import-types/shared/import-types.service'; import { ImportTypeConfigModel, ImportTypeModel } from '../import-types/shared/import-types.model'; -import {FormArray, FormBuilder, FormGroup, UntypedFormBuilder, Validators} from '@angular/forms'; +import {FormArray, FormGroup, UntypedFormBuilder, Validators} from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; import { typeValueValidator } from '../validators/type-value-validator'; -import {HttpErrorResponse} from '@angular/common/http'; @Component({ selector: 'senergy-import-deploy-dialog', diff --git a/src/app/modules/imports/import-types/import-types.component.html b/src/app/modules/imports/import-types/import-types.component.html index 9b80e4398..247792521 100644 --- a/src/app/modules/imports/import-types/import-types.component.html +++ b/src/app/modules/imports/import-types/import-types.component.html @@ -55,11 +55,11 @@ Cost -
- {{m.cost.min | currency:'EUR'}} - {{m.cost.max | +
+ {{m.costEstimation.min | currency:'EUR'}} - {{m.costEstimation.max | currency:'EUR'}}
-
+
Unknown cost
@@ -75,7 +75,7 @@ Start - @@ -83,7 +83,7 @@ Share - @@ -91,7 +91,7 @@ Edit - @@ -101,7 +101,7 @@ Delete - diff --git a/src/app/modules/imports/import-types/import-types.component.spec.ts b/src/app/modules/imports/import-types/import-types.component.spec.ts index 14c7433a2..7ac8acb97 100644 --- a/src/app/modules/imports/import-types/import-types.component.spec.ts +++ b/src/app/modules/imports/import-types/import-types.component.spec.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {ImportTypesComponent} from './import-types.component'; import {CoreModule} from '../../../core/core.module'; @@ -21,7 +21,7 @@ import {Router, RouterModule} from '@angular/router'; import {ReactiveFormsModule} from '@angular/forms'; import {HttpClientModule} from '@angular/common/http'; import {MatDialog, MatDialogModule} from '@angular/material/dialog'; -import {MatSnackBar, MatSnackBarModule} from '@angular/material/snack-bar'; +import {MatSnackBarModule} from '@angular/material/snack-bar'; import {FlexModule} from '@angular/flex-layout'; import {MatTooltipModule} from '@angular/material/tooltip'; import {MatButtonModule} from '@angular/material/button'; @@ -34,15 +34,16 @@ import {MatTreeModule} from '@angular/material/tree'; import {WidgetModule} from '../../../widgets/widget.module'; import {createSpyFromClass, Spy} from 'jasmine-auto-spies'; import {ImportTypesService} from './shared/import-types.service'; -import {BehaviorSubject, Observable, of} from 'rxjs'; +import {of} from 'rxjs'; import {InfiniteScrollModule} from 'ngx-infinite-scroll'; import {MatTableModule} from '@angular/material/table'; -import {ImportTypePermissionSearchModel} from './shared/import-types.model'; import {DialogsService} from '../../../core/services/dialogs.service'; import {PermissionsDialogService} from '../../permissions/shared/permissions-dialog.service'; import { SearchbarService } from 'src/app/core/components/searchbar/shared/searchbar.service'; import { MatPaginatorModule } from '@angular/material/paginator'; import { CostService } from '../../cost/shared/cost.service'; +import { ImportTypeModel } from './shared/import-types.model'; +import { PermissionsService } from '../../permissions/shared/permissions.service'; describe('ImportTypesComponent', () => { let component: ImportTypesComponent; @@ -52,20 +53,14 @@ describe('ImportTypesComponent', () => { const permSearchModelExample = { id: '0', - permissions: { - a: true, - r: true, - w: true, - x: true, - }, - } as ImportTypePermissionSearchModel; - importTypesServiceSpy.listImportTypes.and.returnValue(of([permSearchModelExample] as ImportTypePermissionSearchModel[])); + name: 'example', + } as ImportTypeModel; + importTypesServiceSpy.listImportTypes.and.returnValue(of({result: [permSearchModelExample], total: 1})); importTypesServiceSpy.deleteImportInstance.and.returnValue(of()); importTypesServiceSpy.userHasUpdateAuthorization.and.returnValue(of(true)); importTypesServiceSpy.userHasDeleteAuthorization.and.returnValue(of(true)); importTypesServiceSpy.userHasCreateAuthorization.and.returnValue(of(true)); - importTypesServiceSpy.getTotalCountOfTypes.and.returnValue(of(0)); const deleteDialogServiceSpy: Spy = createSpyFromClass(DialogsService); deleteDialogServiceSpy.openDeleteDialog.and.returnValue({afterClosed: () => of(true)}); @@ -85,6 +80,9 @@ describe('ImportTypesComponent', () => { const costServiceSpy: Spy = createSpyFromClass(CostService); costServiceSpy.userMayGetImportCostEstimations.and.returnValue(false); + const permissionsServiceSpy: Spy = createSpyFromClass(PermissionsService); + permissionsServiceSpy.getComputedResourcePermissionsV2.and.callFake((_: string, ressourceIds: string[]) => of(ressourceIds.map(id => ({id, execute: true, read: true, write: true, administrate: true})))); + beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ImportTypesComponent], @@ -121,7 +119,8 @@ describe('ImportTypesComponent', () => { {provide: SearchbarService, useValue: searchbarSpy}, {provide: Router, useValue: routerSpy}, {provide: MatDialog, useValue: dialogSpy}, - {provide: CostService, useValue: costServiceSpy} + {provide: CostService, useValue: costServiceSpy}, + {provide: PermissionsService, useValue: permissionsServiceSpy}, ], }).compileComponents(); }); @@ -136,6 +135,7 @@ describe('ImportTypesComponent', () => { searchbarSpy.currentSearchText.nextWith('search'); expect(component).toBeTruthy(); expect(importTypesServiceSpy.listImportTypes).toHaveBeenCalled(); + expect(permissionsServiceSpy.getComputedResourcePermissionsV2).toHaveBeenCalled(); }); it('should delete a type', () => { @@ -173,8 +173,8 @@ describe('ImportTypesComponent', () => { }); it('should open the permission dialog', () => { - permissionsDialogServiceSpy.openPermissionDialog.calls.reset(); + permissionsDialogServiceSpy.openPermissionV2Dialog.calls.reset(); component.share(permSearchModelExample); - expect(permissionsDialogServiceSpy.openPermissionDialog).toHaveBeenCalled(); + expect(permissionsDialogServiceSpy.openPermissionV2Dialog).toHaveBeenCalled(); }); }); diff --git a/src/app/modules/imports/import-types/import-types.component.ts b/src/app/modules/imports/import-types/import-types.component.ts index 45401a8f5..3635481c5 100644 --- a/src/app/modules/imports/import-types/import-types.component.ts +++ b/src/app/modules/imports/import-types/import-types.component.ts @@ -13,35 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; -import {ImportTypePermissionSearchModel, ImportTypePermissionSearchModelWithCosts} from './shared/import-types.model'; -import {ImportTypesService} from './shared/import-types.service'; -import {Sort} from '@angular/material/sort'; -import {Router} from '@angular/router'; -import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; -import {ImportInstancesModel} from '../import-instances/shared/import-instances.model'; -import {ImportDeployEditDialogComponent} from '../import-deploy-edit-dialog/import-deploy-edit-dialog.component'; -import {PermissionsDialogService} from '../../permissions/shared/permissions-dialog.service'; -import {MatSnackBar} from '@angular/material/snack-bar'; -import {DialogsService} from '../../../core/services/dialogs.service'; -import { forkJoin, Observable, map, Subscription, of, mergeMap } from 'rxjs'; +import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { ImportTypeModel, ImportTypeModelWithCostEstimation } from './shared/import-types.model'; +import { ImportTypesService } from './shared/import-types.service'; +import { Sort } from '@angular/material/sort'; +import { Router } from '@angular/router'; +import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; +import { ImportInstancesModel } from '../import-instances/shared/import-instances.model'; +import { ImportDeployEditDialogComponent } from '../import-deploy-edit-dialog/import-deploy-edit-dialog.component'; +import { PermissionsDialogService } from '../../permissions/shared/permissions-dialog.service'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { DialogsService } from '../../../core/services/dialogs.service'; +import { forkJoin, Observable, map, Subscription, of, mergeMap, concatMap } from 'rxjs'; import { SearchbarService } from 'src/app/core/components/searchbar/shared/searchbar.service'; import { MatTableDataSource } from '@angular/material/table'; import { SelectionModel } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { CostService } from '../../cost/shared/cost.service'; +import { PermissionsService } from '../../permissions/shared/permissions.service'; +import { PermissionsV2RightsAndIdModel } from '../../permissions/shared/permissions-resource.model'; @Component({ selector: 'senergy-import-types', templateUrl: './import-types.component.html', styleUrls: ['./import-types.component.css'], }) -export class ImportTypesComponent implements OnInit { +export class ImportTypesComponent implements OnInit, AfterViewInit { displayedColumns = ['select', 'name', 'description', 'image', 'details', 'start', 'share']; pageSize = 20; - dataSource = new MatTableDataSource(); + dataSource = new MatTableDataSource(); @ViewChild('paginator', { static: false }) paginator!: MatPaginator; - selection = new SelectionModel(true, []); + selection = new SelectionModel(true, []); dataReady = false; sort = 'name.asc'; searchText = ''; @@ -51,6 +53,7 @@ export class ImportTypesComponent implements OnInit { userHasUpdateAuthorization = false; userHasDeleteAuthorization = false; userHasCreateAuthorization = false; + permissionsPerType: PermissionsV2RightsAndIdModel[] = []; constructor( private importTypesService: ImportTypesService, @@ -61,21 +64,16 @@ export class ImportTypesComponent implements OnInit { private deleteDialog: DialogsService, private searchbarService: SearchbarService, private costService: CostService, - ) {} + private permissionsService: PermissionsService, + ) { } ngOnInit(): void { this.initSearch(); this.checkAuthorization(); } - getTotalNumberOfTypes(): Observable { - return this.importTypesService.getTotalCountOfTypes(this.searchText).pipe( - map((totalCount: number) => this.totalCount = totalCount) - ); - } - ngAfterViewInit(): void { - this.paginator.page.subscribe(()=>{ + this.paginator.page.subscribe(() => { this.pageSize = this.paginator.pageSize; this.offset = this.paginator.pageSize * this.paginator.pageIndex; this.load().subscribe(); @@ -84,12 +82,12 @@ export class ImportTypesComponent implements OnInit { checkAuthorization() { this.userHasUpdateAuthorization = this.importTypesService.userHasUpdateAuthorization(); - if(this.userHasUpdateAuthorization) { + if (this.userHasUpdateAuthorization) { this.displayedColumns.push('edit'); } this.userHasDeleteAuthorization = this.importTypesService.userHasDeleteAuthorization(); - if(this.userHasDeleteAuthorization) { + if (this.userHasDeleteAuthorization) { this.displayedColumns.push('delete'); } @@ -107,11 +105,11 @@ export class ImportTypesComponent implements OnInit { }); } - details(m: ImportTypePermissionSearchModel) { + details(m: ImportTypeModel) { this.router.navigateByUrl('/imports/types/details/' + m.id); } - start(m: ImportTypePermissionSearchModel) { + start(m: ImportTypeModel) { const config: MatDialogConfig = { data: { name: m.name, @@ -130,15 +128,15 @@ export class ImportTypesComponent implements OnInit { }); } - share(m: ImportTypePermissionSearchModel) { - this.permissionsDialogService.openPermissionDialog('import-types', m.id, m.name); + share(m: ImportTypeModel) { + this.permissionsDialogService.openPermissionV2Dialog('import-types', m.id, m.name); } - edit(m: ImportTypePermissionSearchModel) { + edit(m: ImportTypeModel) { this.router.navigateByUrl('/imports/types/edit/' + m.id); } - delete(m: ImportTypePermissionSearchModel) { + delete(m: ImportTypeModel) { this.deleteDialog .openDeleteDialog('import type') .afterClosed() @@ -164,23 +162,28 @@ export class ImportTypesComponent implements OnInit { this.reload(); } - load(): Observable { + load(): Observable { this.dataReady = false; return this.importTypesService.listImportTypes(this.searchText, this.pageSize, this.offset, this.sort).pipe( - mergeMap((types: ImportTypePermissionSearchModelWithCosts[]) => { + mergeMap((types) => { + this.totalCount = types.total; if (this.costService.userMayGetImportCostEstimations()) { - return this.costService.getImportCostEstimations(types.map(t => t.id)).pipe(map(costs => { + return this.costService.getImportCostEstimations(types.result.map(t => t.id)).pipe(map(costs => { costs.forEach((cost, i) => { - types[i].cost = cost; + (types.result[i] as ImportTypeModelWithCostEstimation).costEstimation = cost; }); - this.dataSource.data = types; - return types; + this.dataSource.data = types.result; + return types.result; })); } else { - this.dataSource.data = types; - return of(types); + this.dataSource.data = types.result; + return of(types.result); } - }) + }), + concatMap(a => this.permissionsService.getComputedResourcePermissionsV2('import-types', this.dataSource.data.map(t => t.id)).pipe(map(perm => { + this.permissionsPerType = perm; + return a; + }))), ); } @@ -189,7 +192,7 @@ export class ImportTypesComponent implements OnInit { this.dataReady = false; this.selectionClear(); - forkJoin([this.load(), this.getTotalNumberOfTypes()]).subscribe(_ => { + this.load().subscribe(_ => { this.dataReady = true; }); } @@ -226,7 +229,7 @@ export class ImportTypesComponent implements OnInit { .subscribe((deletePipelines: boolean) => { if (deletePipelines) { this.dataReady = false; - this.selection.selected.forEach((importType: ImportTypePermissionSearchModel) => { + this.selection.selected.forEach((importType: ImportTypeModel) => { deletionJobs.push(this.importTypesService.deleteImportInstance(importType.id)); }); } @@ -234,12 +237,24 @@ export class ImportTypesComponent implements OnInit { forkJoin(deletionJobs).subscribe((deletionJobResults) => { const ok = deletionJobResults.findIndex((r: any) => r === null || r.status === 500) === -1; if (ok) { - this.snackBar.open(text + ' deleted successfully.', undefined, {duration: 2000}); + this.snackBar.open(text + ' deleted successfully.', undefined, { duration: 2000 }); } else { - this.snackBar.open('Error while deleting ' + text + '!', 'close', {panelClass: 'snack-bar-error'}); + this.snackBar.open('Error while deleting ' + text + '!', 'close', { panelClass: 'snack-bar-error' }); } this.reload(); }); }); } + + hasWPermission(m: ImportTypeModel): boolean { + return this.permissionsPerType.find(t => t.id === m.id)?.write || false; + } + + hasAPermission(m: ImportTypeModel): boolean { + return this.permissionsPerType.find(t => t.id === m.id)?.administrate || false; + } + + hasXPermission(m: ImportTypeModel): boolean { + return this.permissionsPerType.find(t => t.id === m.id)?.execute || false; + } } diff --git a/src/app/modules/imports/import-types/shared/import-types.model.ts b/src/app/modules/imports/import-types/shared/import-types.model.ts index ff07d3825..1d5b67065 100644 --- a/src/app/modules/imports/import-types/shared/import-types.model.ts +++ b/src/app/modules/imports/import-types/shared/import-types.model.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { CostEstimationModel } from "src/app/modules/cost/shared/cost.model"; +import { CostEstimationModel } from 'src/app/modules/cost/shared/cost.model'; export interface ImportTypeModel { id: string; @@ -45,25 +45,6 @@ export interface ImportTypeContentVariableModel { function_id?: string; } -export interface ImportTypePermissionSearchModel { - aspect_functions: string[]; - content_aspect_ids: string[]; - creator: string; - default_restart: boolean; - description: string; - content_function_ids: string[]; - id: string; - image: string; - name: string; - permissions: { - a: boolean; - r: boolean; - w: boolean; - x: boolean; - }; - shared: boolean; -} - -export interface ImportTypePermissionSearchModelWithCosts extends ImportTypePermissionSearchModel { - cost?: CostEstimationModel; +export interface ImportTypeModelWithCostEstimation extends ImportTypeModel { + costEstimation?: CostEstimationModel; } diff --git a/src/app/modules/imports/import-types/shared/import-types.service.spec.ts b/src/app/modules/imports/import-types/shared/import-types.service.spec.ts index ab81fd745..284a0f9aa 100644 --- a/src/app/modules/imports/import-types/shared/import-types.service.spec.ts +++ b/src/app/modules/imports/import-types/shared/import-types.service.spec.ts @@ -130,9 +130,9 @@ describe('ImportTypesService', () => { }); it('should correctly request lists', () => { - service.listImportTypes('search', 10, 1, 'name.asc').subscribe((val) => expect(val).toEqual([])); + service.listImportTypes('search', 10, 1, 'name.asc').subscribe((val) => expect(val).toEqual({result: [], total: 0})); expect(httpClientSpy.get.calls.mostRecent().args[0]).toEqual( - environment.permissionSearchUrl + '/v3/resources/import-types?&search=search&limit=10&offset=1&sort=name.asc', //TODO + environment.importRepoUrl + '/import-types?&search=search&limit=10&offset=1&sort=name.asc', ); }); diff --git a/src/app/modules/imports/import-types/shared/import-types.service.ts b/src/app/modules/imports/import-types/shared/import-types.service.ts index 9ed8b6884..5ac1bccb1 100644 --- a/src/app/modules/imports/import-types/shared/import-types.service.ts +++ b/src/app/modules/imports/import-types/shared/import-types.service.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { Injectable, OnInit } from '@angular/core'; -import { ImportTypeContentVariableModel, ImportTypeModel, ImportTypePermissionSearchModel } from './import-types.model'; +import { ImportTypeContentVariableModel, ImportTypeModel } from './import-types.model'; import { HttpClient, HttpParams } from '@angular/common/http'; import { environment } from '../../../../../environments/environment'; import { Observable, catchError } from 'rxjs'; @@ -51,8 +51,8 @@ export class ImportTypesService { limit: number | undefined, offset: number | undefined, sort: string, - ): Observable { - let url = environment.permissionSearchUrl + '/v3/resources/import-types?'; //TODO + ): Observable<{ result: ImportTypeModel[]; total: number }> { + let url = environment.importRepoUrl + '/import-types?'; if (search.length > 0) { url += '&search=' + search; } @@ -66,18 +66,14 @@ export class ImportTypesService { url += '&sort=' + sort; } return this.http - .get(url) - .pipe(map((types) => types || [])) - .pipe( - map((types) => { - types.forEach((type) => { - type.aspect_functions = type.aspect_functions || []; - type.content_aspect_ids = type.content_aspect_ids || []; - type.content_function_ids = type.content_function_ids || []; - }); - return types; - }), - ); + .get(url, { observe: 'response' }).pipe( + map(resp => { + const totalStr = resp?.headers.get('X-Total-Count') || '0'; + return { + total: parseInt(totalStr, 10), + result: resp?.body || [], + }; + })); } getImportType(id: string): Observable { @@ -165,12 +161,4 @@ export class ImportTypesService { userHasReadAuthorization(): boolean { return this.authorizations['GET']; } - - getTotalCountOfTypes(searchText: string): Observable { - const options = searchText ? - { params: new HttpParams().set('search', searchText) } : {}; - - return this.http - .get(environment.permissionSearchUrl + '/v3/total/import-types', options); //TODO - } } diff --git a/src/app/modules/metadata/characteristics/characteristics.component.html b/src/app/modules/metadata/characteristics/characteristics.component.html index a383089b5..4b54a7097 100644 --- a/src/app/modules/metadata/characteristics/characteristics.component.html +++ b/src/app/modules/metadata/characteristics/characteristics.component.html @@ -69,7 +69,7 @@ Edit @@ -80,7 +80,7 @@ Delete diff --git a/src/app/modules/metadata/characteristics/characteristics.component.ts b/src/app/modules/metadata/characteristics/characteristics.component.ts index 213f54a9a..2f7db4d6b 100644 --- a/src/app/modules/metadata/characteristics/characteristics.component.ts +++ b/src/app/modules/metadata/characteristics/characteristics.component.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; import {DeviceTypeCharacteristicsModel} from '../device-types-overview/shared/device-type.model'; import {Navigation, Router} from '@angular/router'; @@ -25,29 +25,25 @@ import {CharacteristicsPermSearchModel} from './shared/characteristics-perm-sear import {CharacteristicsEditDialogComponent} from './dialogs/characteristics-edit-dialog.component'; import {MatSnackBar} from '@angular/material/snack-bar'; import {ConceptsPermSearchModel} from '../concepts/shared/concepts-perm-search.model'; -import {MatSort, Sort, SortDirection} from '@angular/material/sort'; +import {Sort, SortDirection} from '@angular/material/sort'; import {MatTableDataSource} from '@angular/material/table'; import { SelectionModel } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { SearchbarService } from 'src/app/core/components/searchbar/shared/searchbar.service'; -import {DeviceClassesPermSearchModel} from "../device-classes/shared/device-classes-perm-search.model"; -import { - UsedInDeviceTypeQuery, - UsedInDeviceTypeResponseElement -} from "../device-types-overview/shared/used-in-device-type.model"; -import {DeviceTypeService} from "../device-types-overview/shared/device-type.service"; +import { UsedInDeviceTypeQuery, UsedInDeviceTypeResponseElement } from '../device-types-overview/shared/used-in-device-type.model'; +import {DeviceTypeService} from '../device-types-overview/shared/device-type.service'; @Component({ selector: 'senergy-characteristic', templateUrl: './characteristics.component.html', styleUrls: ['./characteristics.component.css'], }) -export class CharacteristicsComponent implements OnInit, OnDestroy { +export class CharacteristicsComponent implements OnInit, OnDestroy, AfterViewInit { displayedColumns = ['select', 'name']; pageSize = 20; ready = false; - dataSource = new MatTableDataSource(); - selection = new SelectionModel(true, []); + dataSource = new MatTableDataSource(); + selection = new SelectionModel(true, []); totalCount = 200; offset = 0; @ViewChild('paginator', { static: false }) paginator!: MatPaginator; @@ -80,15 +76,6 @@ export class CharacteristicsComponent implements OnInit, OnDestroy { this.checkAuthorization(); } - getTotalCounts(): Observable { - return this.characteristicsService.getTotalCountOfCharacteristics(this.searchText).pipe( - map((totalCount: number) => { - this.totalCount = totalCount; - return totalCount; - }) - ); - } - ngOnDestroy() { this.searchSub.unsubscribe(); } @@ -101,7 +88,7 @@ export class CharacteristicsComponent implements OnInit, OnDestroy { checkAuthorization() { - this.userHasUsedInAuthorization = this.deviceTypeService.userHasUsedInAuthorization() + this.userHasUsedInAuthorization = this.deviceTypeService.userHasUsedInAuthorization(); if(this.userHasUsedInAuthorization) { this.displayedColumns.push('useCount'); } @@ -241,22 +228,23 @@ export class CharacteristicsComponent implements OnInit, OnDestroy { }); } - private getCharacteristics(): Observable { + private getCharacteristics(): Observable { if (this.routerConcept !== null) { this.selectedTag = this.routerConcept.name; } return this.characteristicsService .getCharacteristics(this.searchText, this.pageSize, this.offset, this.sortBy, this.sortDirection, this.routerConcept?.characteristic_ids || []) .pipe( - map((characteristics: CharacteristicsPermSearchModel[]) => { - this.setCharacteristics(characteristics); - this.updateCharacteristicInDeviceTypes(characteristics); - return characteristics; + map((characteristics) => { + this.totalCount = characteristics.total; + this.setCharacteristics(characteristics.result); + this.updateCharacteristicInDeviceTypes(characteristics.result); + return characteristics.result; }) ); } - private setCharacteristics(characteristics: CharacteristicsPermSearchModel[]) { + private setCharacteristics(characteristics: DeviceTypeCharacteristicsModel[]) { this.dataSource.data = characteristics; } @@ -275,7 +263,7 @@ export class CharacteristicsComponent implements OnInit, OnDestroy { this.offset = 0; this.selectionClear(); - forkJoin([this.getCharacteristics(), this.getTotalCounts()]).subscribe(_ => { + this.getCharacteristics().subscribe(_ => { this.ready = true; }); } @@ -307,8 +295,8 @@ export class CharacteristicsComponent implements OnInit, OnDestroy { .subscribe((deleteConcepts: boolean) => { if (deleteConcepts) { this.ready = false; - this.selection.selected.forEach((characteristic: CharacteristicsPermSearchModel) => { - const job = this.characteristicsService.deleteCharacteristic(characteristic.id); + this.selection.selected.forEach((characteristic: DeviceTypeCharacteristicsModel) => { + const job = this.characteristicsService.deleteCharacteristic(characteristic.id || ''); deletionJobs.push(job); }); } @@ -325,19 +313,19 @@ export class CharacteristicsComponent implements OnInit, OnDestroy { }); } - private updateCharacteristicInDeviceTypes(list: CharacteristicsPermSearchModel[]) { + private updateCharacteristicInDeviceTypes(list: DeviceTypeCharacteristicsModel[]) { if (!this.userHasUsedInAuthorization) { return; } - let query: UsedInDeviceTypeQuery = { - resource: "characteristics", - ids: list.map(f => f.id) - } + const query: UsedInDeviceTypeQuery = { + resource: 'characteristics', + ids: list.map(f => f.id || '') + }; this.deviceTypeService.getUsedInDeviceType(query).subscribe(result => { result?.forEach((value, key) => { this.usedIn.set(key, value); - }) - }) + }); + }); } public showUsedInDialog(usedIn: UsedInDeviceTypeResponseElement | undefined) { diff --git a/src/app/modules/metadata/characteristics/shared/characteristics.service.ts b/src/app/modules/metadata/characteristics/shared/characteristics.service.ts index a835e2813..9a42d73da 100644 --- a/src/app/modules/metadata/characteristics/shared/characteristics.service.ts +++ b/src/app/modules/metadata/characteristics/shared/characteristics.service.ts @@ -36,8 +36,8 @@ export class CharacteristicsService { private errorHandlerService: ErrorHandlerService, private ladonService: LadonService ) { - const characteristicPermSearchURL = environment.permissionSearchUrl + '/v3/resources/characteristics'; //TODO - this.authorizations = this.ladonService.getUserAuthorizationsForURI(characteristicPermSearchURL); + const characteristicsURL = environment.deviceRepoUrl + '/characteristics'; + this.authorizations = this.ladonService.getUserAuthorizationsForURI(characteristicsURL); } createCharacteristic( @@ -87,14 +87,14 @@ export class CharacteristicsService { sortBy: string, sortDirection: string, ids: string[] = [], - ): Observable { + ): Observable<{result: DeviceTypeCharacteristicsModel[]; total: number}> { if (sortDirection === '' || sortDirection === null || sortDirection === undefined) { sortDirection = 'asc'; } if (sortBy === '' || sortBy === null || sortBy === undefined) { sortBy = 'name'; } - const params = ['limit=' + limit, 'offset=' + offset, 'rights=r', 'sort=' + sortBy + '.' + sortDirection]; + const params = ['limit=' + limit, 'offset=' + offset, 'sort=' + sortBy + '.' + sortDirection]; if (query) { params.push('search=' + encodeURIComponent(query)); } @@ -103,26 +103,12 @@ export class CharacteristicsService { } return this.http - .get(environment.permissionSearchUrl + '/v3/resources/characteristics?' + params.join('&')) //TODO - .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(CharacteristicsService.name, 'getCharacteristics(search)', [])), - ); - } - - getTotalCountOfCharacteristics(searchText: string): Observable { - const options = searchText ? - { params: new HttpParams().set('search', searchText) } : {}; - - return this.http - .get(environment.permissionSearchUrl + '/v3/total/characteristics', options) //TODO - .pipe( - catchError( - this.errorHandlerService.handleError( - CharacteristicsService.name, - 'getTotalCountOfCharacteristics', - ), - ), + .get(environment.deviceRepoUrl + '/v2/characteristics?' + params.join('&'), { observe: 'response'}).pipe( + map(resp => { + const totalStr = resp.headers.get('X-Total-Count') || '0'; + return {result: resp.body || [], total: parseInt(totalStr, 10)}; + }), + catchError(this.errorHandlerService.handleError(CharacteristicsService.name, 'getCharacteristics(search)', {result: [], total: 0})), ); } diff --git a/src/app/modules/metadata/concepts/concepts.component.html b/src/app/modules/metadata/concepts/concepts.component.html index 2796ec75e..d411070dc 100644 --- a/src/app/modules/metadata/concepts/concepts.component.html +++ b/src/app/modules/metadata/concepts/concepts.component.html @@ -59,7 +59,7 @@ Edit - @@ -80,7 +80,7 @@ Delete - diff --git a/src/app/modules/metadata/concepts/concepts.component.ts b/src/app/modules/metadata/concepts/concepts.component.ts index 2beb46a43..f44cbc98f 100644 --- a/src/app/modules/metadata/concepts/concepts.component.ts +++ b/src/app/modules/metadata/concepts/concepts.component.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; import {ConceptsNewDialogComponent} from './dialogs/concepts-new-dialog.component'; import {Router} from '@angular/router'; @@ -22,11 +22,10 @@ import {ConceptsService} from './shared/concepts.service'; import {forkJoin, Observable, Subscription, map} from 'rxjs'; import {DialogsService} from '../../../core/services/dialogs.service'; import {ConceptsEditDialogComponent} from './dialogs/concepts-edit-dialog.component'; -import {ConceptsPermSearchModel} from './shared/concepts-perm-search.model'; import {DeviceTypeConceptModel} from '../device-types-overview/shared/device-type.model'; import {MatSnackBar} from '@angular/material/snack-bar'; import {MatTableDataSource} from '@angular/material/table'; -import {MatSort, Sort, SortDirection} from '@angular/material/sort'; +import {Sort, SortDirection} from '@angular/material/sort'; import { SelectionModel } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { SearchbarService } from 'src/app/core/components/searchbar/shared/searchbar.service'; @@ -36,13 +35,13 @@ import { SearchbarService } from 'src/app/core/components/searchbar/shared/searc templateUrl: './concepts.component.html', styleUrls: ['./concepts.component.css'], }) -export class ConceptsComponent implements OnInit, OnDestroy { +export class ConceptsComponent implements OnInit, OnDestroy, AfterViewInit { displayedColumns = ['select', 'name', 'info', 'characteristic']; pageSize = 20; - concepts: ConceptsPermSearchModel[] = []; + concepts: DeviceTypeConceptModel[] = []; ready = false; dataSource = new MatTableDataSource(this.concepts); - selection = new SelectionModel(true, []); + selection = new SelectionModel(true, []); totalCount = 200; offset = 0; @ViewChild('paginator', { static: false }) paginator!: MatPaginator; @@ -72,15 +71,6 @@ export class ConceptsComponent implements OnInit, OnDestroy { this.searchSub.unsubscribe(); } - getTotalCounts() { - return this.conceptsService.getTotalCountOfConcepts(this.searchText).pipe( - map((totalCount: number) => { - this.totalCount = totalCount; - return totalCount; - }) - ); - } - checkAuthorization() { this.userHasUpdateAuthorization = this.conceptsService.userHasUpdateAuthorization(); if(this.userHasUpdateAuthorization) { @@ -128,7 +118,7 @@ export class ConceptsComponent implements OnInit, OnDestroy { }); } - editConcept(conceptInput: ConceptsPermSearchModel) { + editConcept(conceptInput: DeviceTypeConceptModel) { const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.data = { @@ -150,7 +140,7 @@ export class ConceptsComponent implements OnInit, OnDestroy { }); } - showConcept(conceptInput: ConceptsPermSearchModel) { + showConcept(conceptInput: DeviceTypeConceptModel) { const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.data = { @@ -173,7 +163,7 @@ export class ConceptsComponent implements OnInit, OnDestroy { }); } - deleteConcept(concept: ConceptsPermSearchModel): void { + deleteConcept(concept: DeviceTypeConceptModel): void { this.dialogsService .openDeleteDialog('concept ' + concept.name) .afterClosed() @@ -193,17 +183,18 @@ export class ConceptsComponent implements OnInit, OnDestroy { }); } - showCharacteristics(concept: ConceptsPermSearchModel) { + showCharacteristics(concept: DeviceTypeConceptModel) { this.router.navigateByUrl('/metadata/characteristics', { state: concept }); } - private getConcepts(): Observable { + private getConcepts(): Observable { return this.conceptsService .getConcepts(this.searchText, this.pageSize, this.offset, this.sortBy, this.sortDirection) .pipe( - map((concepts: ConceptsPermSearchModel[]) => { - this.dataSource.data = concepts; - return concepts; + map(concepts => { + this.totalCount = concepts.total; + this.dataSource.data = concepts.result; + return concepts.result; }) ); } @@ -213,7 +204,7 @@ export class ConceptsComponent implements OnInit, OnDestroy { this.offset = 0; this.selectionClear(); - forkJoin([this.getConcepts(), this.getTotalCounts()]).subscribe(_ => { + this.getConcepts().subscribe(_ => { this.ready = true; }); } @@ -251,7 +242,7 @@ export class ConceptsComponent implements OnInit, OnDestroy { .subscribe((deleteConcepts: boolean) => { if (deleteConcepts) { this.ready = false; - this.selection.selected.forEach((concept: ConceptsPermSearchModel) => { + this.selection.selected.forEach((concept: DeviceTypeConceptModel) => { deletionJobs.push(this.conceptsService.deleteConcept(concept.id)); }); } diff --git a/src/app/modules/metadata/concepts/dialogs/concepts-edit-dialog.component.ts b/src/app/modules/metadata/concepts/dialogs/concepts-edit-dialog.component.ts index 352c116c7..4bcf9dd3e 100644 --- a/src/app/modules/metadata/concepts/dialogs/concepts-edit-dialog.component.ts +++ b/src/app/modules/metadata/concepts/dialogs/concepts-edit-dialog.component.ts @@ -16,14 +16,12 @@ import {ChangeDetectorRef, Component, Inject, OnInit} from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import {FormArray, FormControl, UntypedFormControl, Validators} from '@angular/forms'; +import {UntypedFormControl, Validators} from '@angular/forms'; import { - ConverterExtensionTryRequest, DeviceTypeCharacteristicsModel, DeviceTypeConceptModel } from '../../device-types-overview/shared/device-type.model'; import { ConceptsService } from '../shared/concepts.service'; -import { ConceptsCharacteristicsModel } from '../shared/concepts-characteristics.model'; import {CharacteristicsService} from '../../characteristics/shared/characteristics.service'; import {CharacteristicsPermSearchModel} from '../../characteristics/shared/characteristics-perm-search.model'; import {forkJoin, Observable} from 'rxjs'; @@ -39,7 +37,7 @@ export class ConceptsEditDialogComponent implements OnInit { idFormControl = new UntypedFormControl({ value: '', disabled: true }); characteristicsControl = new UntypedFormControl('', [Validators.required]); baseCharacteristicControl = new UntypedFormControl('', [Validators.required]); - characteristics: CharacteristicsPermSearchModel[] = []; + characteristics: DeviceTypeCharacteristicsModel[] = []; concept: DeviceTypeConceptModel|undefined; ready = false; @@ -69,7 +67,7 @@ export class ConceptsEditDialogComponent implements OnInit { } }))); obs.push(this.characteristicsService.getCharacteristics('', 9999, 0, 'name', 'asc').pipe(map(characteristics => { - this.characteristics = characteristics; + this.characteristics = characteristics.result; }))); forkJoin(obs).subscribe(() => { this.baseCharacteristicControl.setValue(this.concept?.base_characteristic_id); diff --git a/src/app/modules/metadata/concepts/shared/concepts.service.ts b/src/app/modules/metadata/concepts/shared/concepts.service.ts index aa02ff99f..d7fe4b92a 100644 --- a/src/app/modules/metadata/concepts/shared/concepts.service.ts +++ b/src/app/modules/metadata/concepts/shared/concepts.service.ts @@ -42,8 +42,8 @@ export class ConceptsService { private errorHandlerService: ErrorHandlerService, private ladonService: LadonService ) { - const permSearchURL = environment.permissionSearchUrl + '/v3/resources/concepts'; //TODO - this.authorizations = this.ladonService.getUserAuthorizationsForURI(permSearchURL); + const url = environment.deviceRepoUrl + '/v2/concepts'; + this.authorizations = this.ladonService.getUserAuthorizationsForURI(url); } tryConverterExtension(extensionTryRequest: ConverterExtensionTryRequest): Observable { @@ -81,7 +81,7 @@ export class ConceptsService { return new Observable((obs) => { this.getConcepts('', 9999, 0, 'name', 'asc').subscribe((concepts) => { const observables: Observable[] = []; - concepts.forEach((permConcept) => + concepts.result.forEach((permConcept) => observables.push( this.getConceptWithCharacteristics(permConcept.id).pipe( map((concept) => { @@ -113,39 +113,25 @@ export class ConceptsService { offset: number, sortBy: string, sortDirection: string, - ): Observable { + ): Observable<{result: DeviceTypeConceptModel[]; total: number}> { if (sortDirection === '' || sortDirection === null || sortDirection === undefined) { sortDirection = 'asc'; } if (sortBy === '' || sortBy === null || sortBy === undefined) { sortBy = 'name'; } - const params = ['limit=' + limit, 'offset=' + offset, 'rights=r', 'sort=' + sortBy + '.' + sortDirection]; + const params = ['limit=' + limit, 'offset=' + offset, 'sort=' + sortBy + '.' + sortDirection]; if (query) { params.push('search=' + encodeURIComponent(query)); } return this.http - .get(environment.permissionSearchUrl + '/v3/resources/concepts?' + params.join('&')) //TODO - .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(ConceptsService.name, 'getConcepts(search)', [])), - ); - } - - getTotalCountOfConcepts(searchText: string): Observable { - const options = searchText ? - { params: new HttpParams().set('search', searchText) } : {}; - - return this.http - .get(environment.permissionSearchUrl + '/v3/total/concepts', options) //TODO - .pipe( - catchError( - this.errorHandlerService.handleError( - ConceptsService.name, - 'getTotalCountOfConcepts', - ), - ), + .get(environment.deviceRepoUrl + '/v2/concepts?' + params.join('&'), { observe: 'response'}).pipe( + map(resp => { + const totalStr = resp.headers.get('X-Total-Count') || '0'; + return {result: resp.body || [], total: parseInt(totalStr, 10)}; + }), + catchError(this.errorHandlerService.handleError(ConceptsService.name, 'getConcepts(search)', {result: [], total: 0})), ); } diff --git a/src/app/modules/metadata/device-classes/device-classes.component.html b/src/app/modules/metadata/device-classes/device-classes.component.html index 4806777cf..63001f890 100644 --- a/src/app/modules/metadata/device-classes/device-classes.component.html +++ b/src/app/modules/metadata/device-classes/device-classes.component.html @@ -58,7 +58,7 @@ Edit - @@ -69,7 +69,7 @@ Delete - diff --git a/src/app/modules/metadata/device-classes/device-classes.component.ts b/src/app/modules/metadata/device-classes/device-classes.component.ts index 79031f5da..72c907947 100644 --- a/src/app/modules/metadata/device-classes/device-classes.component.ts +++ b/src/app/modules/metadata/device-classes/device-classes.component.ts @@ -14,45 +14,37 @@ * limitations under the License. */ -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { SortModel } from '../../../core/components/sort/shared/sort.model'; -import { debounceTime, forkJoin, Observable, Subscription, map } from 'rxjs'; +import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { forkJoin, Observable, Subscription, map } from 'rxjs'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; -import { ResponsiveService } from '../../../core/services/responsive.service'; import { SearchbarService } from '../../../core/components/searchbar/shared/searchbar.service'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { Router } from '@angular/router'; import { DialogsService } from '../../../core/services/dialogs.service'; -import { DeviceClassesPermSearchModel } from './shared/device-classes-perm-search.model'; import { DeviceClassesService } from './shared/device-classes.service'; import { DeviceClassesEditDialogComponent } from './dialog/device-classes-edit-dialog.component'; import { DeviceTypeDeviceClassModel } from '../device-types-overview/shared/device-type.model'; -import uuid = util.uuid; -import { util } from 'jointjs'; import {AuthorizationService} from '../../../core/services/authorization.service'; -import { MatSort, Sort, SortDirection } from '@angular/material/sort'; +import { Sort, SortDirection } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; -import { UntypedFormControl } from '@angular/forms'; import { SelectionModel } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { UsedInDeviceTypeQuery, UsedInDeviceTypeResponseElement -} from "../device-types-overview/shared/used-in-device-type.model"; -import {DeviceTypeService} from "../device-types-overview/shared/device-type.service"; -import {FunctionsPermSearchModel} from "../functions/shared/functions-perm-search.model"; +} from '../device-types-overview/shared/used-in-device-type.model'; +import {DeviceTypeService} from '../device-types-overview/shared/device-type.service'; @Component({ selector: 'senergy-device-classes', templateUrl: './device-classes.component.html', styleUrls: ['./device-classes.component.css'], }) -export class DeviceClassesComponent implements OnInit, OnDestroy { +export class DeviceClassesComponent implements OnInit, OnDestroy, AfterViewInit { displayedColumns = ['select', 'name']; pageSize = 20; ready = false; - dataSource = new MatTableDataSource(); - selection = new SelectionModel(true, []); + dataSource = new MatTableDataSource(); + selection = new SelectionModel(true, []); totalCount = 200; @ViewChild('paginator', { static: false }) paginator!: MatPaginator; userIsAdmin = false; @@ -65,18 +57,16 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { userHasDeleteAuthorization = false; userHasCreateAuthorization = false; userHasUsedInAuthorization = false; - usedIn: Map = new Map() + usedIn: Map = new Map(); constructor( private dialog: MatDialog, - private responsiveService: ResponsiveService, private deviceClassesService: DeviceClassesService, private searchbarService: SearchbarService, private snackBar: MatSnackBar, - private router: Router, private dialogsService: DialogsService, private authService: AuthorizationService, - private deviceTypeService: DeviceTypeService + private deviceTypeService: DeviceTypeService, ) {} ngOnInit() { @@ -85,15 +75,6 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { this.checkAuthorization(); } - getTotalCounts() { - return this.deviceClassesService.getTotalCountOfDevicesClasses(this.searchText).pipe( - map((totalCount: number) => { - this.totalCount = totalCount; - return totalCount; - }) - ); - } - ngAfterViewInit(): void { this.paginator.page.subscribe(()=>{ this.pageSize = this.paginator.pageSize; @@ -107,7 +88,7 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { } checkAuthorization() { - this.userHasUsedInAuthorization = this.deviceTypeService.userHasUsedInAuthorization() + this.userHasUsedInAuthorization = this.deviceTypeService.userHasUsedInAuthorization(); if(this.userHasUsedInAuthorization) { this.displayedColumns.push('useCount'); } @@ -132,7 +113,7 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { }); } - editDeviceClass(inputDeviceClass: DeviceClassesPermSearchModel): void { + editDeviceClass(inputDeviceClass: DeviceTypeDeviceClassModel): void { const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.data = { @@ -152,7 +133,7 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { }); } - deleteDeviceClass(deviceClass: DeviceClassesPermSearchModel): void { + deleteDeviceClass(deviceClass: DeviceTypeDeviceClassModel): void { this.dialogsService .openDeleteDialog('device class ' + deviceClass.name) .afterClosed() @@ -193,14 +174,15 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { }); } - private getDeviceClasses(): Observable { + private getDeviceClasses(): Observable { return this.deviceClassesService .getDeviceClasses(this.searchText, this.pageSize, this.offset, this.sortBy, this.sortDirection) .pipe( - map((deviceClasses: DeviceClassesPermSearchModel[]) => { - this.dataSource = new MatTableDataSource(deviceClasses); - this.updateDeviceClassInDeviceTypes(deviceClasses) - return deviceClasses; + map((deviceClasses) => { + this.totalCount = deviceClasses.total; + this.dataSource = new MatTableDataSource(deviceClasses.result); + this.updateDeviceClassInDeviceTypes(deviceClasses.result); + return deviceClasses.result; }) ); } @@ -210,7 +192,7 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { this.ready = false; this.selectionClear(); - forkJoin([this.getDeviceClasses(), this.getTotalCounts()]).subscribe(_ => { + this.getDeviceClasses().subscribe(_ => { this.ready = true; }); } @@ -257,7 +239,7 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { .subscribe((deleteDeviceClass: boolean) => { if (deleteDeviceClass) { this.ready = false; - this.selection.selected.forEach((deviceClass: DeviceClassesPermSearchModel) => { + this.selection.selected.forEach((deviceClass: DeviceTypeDeviceClassModel) => { deletionJobs.push(this.deviceClassesService.deleteDeviceClasses(deviceClass.id)); }); } @@ -274,19 +256,19 @@ export class DeviceClassesComponent implements OnInit, OnDestroy { }); } - private updateDeviceClassInDeviceTypes(list: DeviceClassesPermSearchModel[]) { + private updateDeviceClassInDeviceTypes(list: DeviceTypeDeviceClassModel[]) { if (!this.userHasUsedInAuthorization) { return; } - let query: UsedInDeviceTypeQuery = { - resource: "device-classes", + const query: UsedInDeviceTypeQuery = { + resource: 'device-classes', ids: list.map(f => f.id) - } + }; this.deviceTypeService.getUsedInDeviceType(query).subscribe(result => { result?.forEach((value, key) => { this.usedIn.set(key, value); - }) - }) + }); + }); } public showUsedInDialog(usedIn: UsedInDeviceTypeResponseElement | undefined) { diff --git a/src/app/modules/metadata/device-classes/dialog/device-classes-edit-dialog.component.ts b/src/app/modules/metadata/device-classes/dialog/device-classes-edit-dialog.component.ts index fa82eb5f4..7cf2410ae 100644 --- a/src/app/modules/metadata/device-classes/dialog/device-classes-edit-dialog.component.ts +++ b/src/app/modules/metadata/device-classes/dialog/device-classes-edit-dialog.component.ts @@ -18,7 +18,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ConceptsService } from '../../concepts/shared/concepts.service'; -import { DeviceClassesPermSearchModel } from '../shared/device-classes-perm-search.model'; +import { DeviceTypeDeviceClassModel } from '../../device-types-overview/shared/device-type.model'; @Component({ templateUrl: './device-classes-edit-dialog.component.html', @@ -31,7 +31,7 @@ export class DeviceClassesEditDialogComponent implements OnInit { private conceptsService: ConceptsService, private dialogRef: MatDialogRef, private _formBuilder: FormBuilder, - @Inject(MAT_DIALOG_DATA) data: { deviceClass: DeviceClassesPermSearchModel }, + @Inject(MAT_DIALOG_DATA) data: { deviceClass: DeviceTypeDeviceClassModel }, ) { this.initDeviceClassFormGroup(data.deviceClass); } @@ -50,7 +50,7 @@ export class DeviceClassesEditDialogComponent implements OnInit { return a.id === b.id; } - private initDeviceClassFormGroup(deviceClass: DeviceClassesPermSearchModel): void { + private initDeviceClassFormGroup(deviceClass: DeviceTypeDeviceClassModel): void { this.deviceClassFormGroup = this._formBuilder.group({ id: [{ value: deviceClass.id, disabled: true }], name: [deviceClass.name, Validators.required], diff --git a/src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model.ts b/src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model.ts deleted file mode 100644 index 9264b5dc6..000000000 --- a/src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2020 InfAI (CC SES) - * - * 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 DeviceClassesPermSearchModel { - creator: string; - id: string; - image: string; - name: string; - permissions: { - a: boolean; - x: boolean; - r: boolean; - w: boolean; - }; - shared: false; -} diff --git a/src/app/modules/metadata/device-classes/shared/device-classes.service.ts b/src/app/modules/metadata/device-classes/shared/device-classes.service.ts index 32becf7ce..6a5ace9a5 100644 --- a/src/app/modules/metadata/device-classes/shared/device-classes.service.ts +++ b/src/app/modules/metadata/device-classes/shared/device-classes.service.ts @@ -20,10 +20,9 @@ import { ErrorHandlerService } from '../../../../core/services/error-handler.ser import { Observable } from 'rxjs'; import { environment } from '../../../../../environments/environment'; import { catchError, map } from 'rxjs/operators'; -import { DeviceTypeAspectModel, DeviceTypeDeviceClassModel } from '../../device-types-overview/shared/device-type.model'; -import { DeviceClassesPermSearchModel } from './device-classes-perm-search.model'; +import { DeviceTypeDeviceClassModel } from '../../device-types-overview/shared/device-type.model'; import { LadonService } from 'src/app/modules/admin/permissions/shared/services/ladom.service'; -import { AllowedMethods, PermissionTestResponse } from 'src/app/modules/admin/permissions/shared/permission.model'; +import { PermissionTestResponse } from 'src/app/modules/admin/permissions/shared/permission.model'; @Injectable({ providedIn: 'root', @@ -36,9 +35,8 @@ export class DeviceClassesService { private errorHandlerService: ErrorHandlerService, private ladonService: LadonService ) { - const permSearchURL = environment.permissionSearchUrl + '/v3/resources/device-classes'; //TODO - this.authorizations = this.ladonService.getUserAuthorizationsForURI(permSearchURL); - + const uri = environment.deviceRepoUrl + '/v2/device-classes'; + this.authorizations = this.ladonService.getUserAuthorizationsForURI(uri); } getDeviceClasses( @@ -47,35 +45,41 @@ export class DeviceClassesService { offset: number, sortBy: string, sortDirection: string, - ): Observable { + ): Observable<{ result: DeviceTypeDeviceClassModel[]; total: number; }> { if (sortDirection === '' || sortDirection === null || sortDirection === undefined) { sortDirection = 'asc'; } if (sortBy === '' || sortBy === null || sortBy === undefined) { sortBy = 'name'; } - const params = ['limit=' + limit, 'offset=' + offset, 'rights=r', 'sort=' + sortBy + '.' + sortDirection]; + const params = ['limit=' + limit, 'offset=' + offset, 'sort=' + sortBy + '.' + sortDirection]; if (query) { params.push('search=' + encodeURIComponent(query)); } return this.http - .get(environment.permissionSearchUrl + '/v3/resources/device-classes?' + params.join('&')) //TODO + .get(environment.deviceRepoUrl + '/v2/device-classes?' + params.join('&'), { observe: 'response' }) .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(DeviceClassesService.name, 'getAspects(search)', [])), + map(resp => { + const totalStr = resp.headers.get('X-Total-Count') || '0'; + return { + result: resp.body || [], + total: parseInt(totalStr, 10) + }; + }), + catchError(this.errorHandlerService.handleError(DeviceClassesService.name, 'getAspects(search)', { result: [], total: 0 })), ); } updateDeviceClasses(deviceClass: DeviceTypeDeviceClassModel): Observable { return this.http - .put(environment.deviceManagerUrl + '/device-classes/' + deviceClass.id , deviceClass) + .put(environment.deviceManagerUrl + '/device-classes/' + deviceClass.id, deviceClass) .pipe(catchError(this.errorHandlerService.handleError(DeviceClassesService.name, 'updateDeviceClasses', null))); } deleteDeviceClasses(deviceClassId: string): Observable { return this.http - .delete(environment.deviceManagerUrl + '/device-classes/' + deviceClassId ) + .delete(environment.deviceManagerUrl + '/device-classes/' + deviceClassId) .pipe(catchError(this.errorHandlerService.handleError(DeviceClassesService.name, 'deleteDeviceClasses', false))); } @@ -85,22 +89,6 @@ export class DeviceClassesService { .pipe(catchError(this.errorHandlerService.handleError(DeviceClassesService.name, 'createDeviceClass', null))); } - getTotalCountOfDevicesClasses(searchText: string): Observable { - const options = searchText ? - { params: new HttpParams().set('search', searchText) } : {}; - - return this.http - .get(environment.permissionSearchUrl + '/v3/total/device-classes', options) //TODO - .pipe( - catchError( - this.errorHandlerService.handleError( - DeviceClassesService.name, - 'getTotalCountOfDevicesClasses', - ), - ), - ); - } - userHasDeleteAuthorization(): boolean { return this.authorizations['DELETE']; } diff --git a/src/app/modules/metadata/device-types-overview/device-types-overview.component.ts b/src/app/modules/metadata/device-types-overview/device-types-overview.component.ts index 31058df08..5b6d66acc 100644 --- a/src/app/modules/metadata/device-types-overview/device-types-overview.component.ts +++ b/src/app/modules/metadata/device-types-overview/device-types-overview.component.ts @@ -70,15 +70,6 @@ export class DeviceTypesOverviewComponent implements OnInit, OnDestroy, AfterVie this.checkAuthorization(); } - getTotalCounts() { - return this.deviceTypeService.getTotalCountOfDevicesTypes(this.searchText).pipe( - map((totalCount: number) => { - this.totalCount = totalCount; - return totalCount; - }) - ); - } - ngOnDestroy() { this.searchSub.unsubscribe(); } @@ -185,9 +176,10 @@ export class DeviceTypesOverviewComponent implements OnInit, OnDestroy, AfterVie return this.deviceTypeService .getDeviceTypes(this.searchText, this.pageSize, this.offset, this.sortBy, this.sortDirection) .pipe( - map((deviceTypes: DeviceTypeModel[]) => { - this.dataSource.data = deviceTypes; - return deviceTypes; + map(deviceTypes => { + this.totalCount = deviceTypes.total; + this.dataSource.data = deviceTypes.result; + return deviceTypes.result; }) ); } @@ -198,7 +190,7 @@ export class DeviceTypesOverviewComponent implements OnInit, OnDestroy, AfterVie this.ready = false; this.selectionClear(); - forkJoin([this.getDeviceTypes(), this.getTotalCounts()]).subscribe(_ => { + this.getDeviceTypes().subscribe(_ => { this.ready = true; }); } diff --git a/src/app/modules/metadata/device-types-overview/device-types/dialogs/device-types-new-function-dialog.component.ts b/src/app/modules/metadata/device-types-overview/device-types/dialogs/device-types-new-function-dialog.component.ts index fd806e022..f42c7ca3f 100644 --- a/src/app/modules/metadata/device-types-overview/device-types/dialogs/device-types-new-function-dialog.component.ts +++ b/src/app/modules/metadata/device-types-overview/device-types/dialogs/device-types-new-function-dialog.component.ts @@ -16,12 +16,11 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import {FormControl, UntypedFormControl, Validators} from '@angular/forms'; -import { DeviceTypeFunctionModel, DeviceTypeFunctionType } from '../../shared/device-type.model'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import { DeviceTypeConceptModel, DeviceTypeFunctionModel, DeviceTypeFunctionType } from '../../shared/device-type.model'; import { util } from 'jointjs'; import uuid = util.uuid; import { ConceptsService } from '../../../concepts/shared/concepts.service'; -import { ConceptsPermSearchModel } from '../../../concepts/shared/concepts-perm-search.model'; import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ @@ -33,7 +32,7 @@ export class DeviceTypesNewFunctionDialogComponent implements OnInit { displayNameControl = new UntypedFormControl(''); descriptionControl = new UntypedFormControl(''); conceptControl = new UntypedFormControl(''); - concepts: ConceptsPermSearchModel[] = []; + concepts: DeviceTypeConceptModel[] = []; functionType = {} as DeviceTypeFunctionType; constructor( @@ -66,8 +65,8 @@ export class DeviceTypesNewFunctionDialogComponent implements OnInit { } ngOnInit(): void { - this.conceptsService.getConcepts('', 9999, 0, 'name', 'asc').subscribe((concepts: ConceptsPermSearchModel[]) => { - this.concepts = concepts; + this.conceptsService.getConcepts('', 9999, 0, 'name', 'asc').subscribe(concepts => { + this.concepts = concepts.result; }); } diff --git a/src/app/modules/metadata/device-types-overview/device-types/shared/device-type-helper.service.ts b/src/app/modules/metadata/device-types-overview/device-types/shared/device-type-helper.service.ts index 9ea312698..a9163a43d 100644 --- a/src/app/modules/metadata/device-types-overview/device-types/shared/device-type-helper.service.ts +++ b/src/app/modules/metadata/device-types-overview/device-types/shared/device-type-helper.service.ts @@ -15,9 +15,8 @@ */ import { Injectable } from '@angular/core'; -import { DeviceTypeCharacteristicsModel, DeviceTypeConceptModel, DeviceTypeContentVariableModel } from '../../shared/device-type.model'; +import { DeviceTypeCharacteristicsModel, DeviceTypeContentVariableModel } from '../../shared/device-type.model'; import * as _ from 'lodash'; -import { ConceptsCharacteristicsModel } from '../../../concepts/shared/concepts-characteristics.model'; @Injectable({ providedIn: 'root', diff --git a/src/app/modules/metadata/device-types-overview/shared/device-type.service.ts b/src/app/modules/metadata/device-types-overview/shared/device-type.service.ts index f9b0a933f..d5a3c7d8a 100644 --- a/src/app/modules/metadata/device-types-overview/shared/device-type.service.ts +++ b/src/app/modules/metadata/device-types-overview/shared/device-type.service.ts @@ -120,7 +120,7 @@ export class DeviceTypeService { offset: number, sortBy: string, sortDirection: string, - ): Observable { + ): Observable<{result: DeviceTypeModel[]; total: number}> { if (sortDirection === '' || sortDirection === null || sortDirection === undefined) { sortDirection = 'asc'; } @@ -133,10 +133,15 @@ export class DeviceTypeService { } return this.http - .get(environment.deviceRepoUrl + '/v3/device-types?' + params. join('&')) - .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(DeviceTypeService.name, 'getDeviceTypes(search)', [])), + .get(environment.deviceRepoUrl + '/v3/device-types?' + params. join('&'), { observe: 'response' }).pipe( + map(resp => { + const totalStr = resp.headers.get('X-Total-Count') || '0'; + return { + result: resp.body || [], + total: parseInt(totalStr, 10) + }; + }), + catchError(this.errorHandlerService.handleError(DeviceTypeService.name, 'getDeviceTypes(search)', {result: [], total: 0})), ); } @@ -299,22 +304,6 @@ export class DeviceTypeService { } } - getTotalCountOfDevicesTypes(searchText: string): Observable { - const options = searchText ? - { params: new HttpParams().set('search', searchText) } : {}; - - return this.http - .get(environment.permissionSearchUrl + '/v3/total/device-types', options) //TODO - .pipe( - catchError( - this.errorHandlerService.handleError( - DeviceTypeService.name, - 'getTotalCountOfDevicesTypes', - ), - ), - ); - } - userHasDeleteAuthorization(): boolean { return this.userHasDeviceManagerAuthorization('DELETE'); } @@ -328,11 +317,11 @@ export class DeviceTypeService { } userHasReadAuthorization(): boolean { - return this.userHasPermSearchAuthorization('GET'); + return this.userHasListAuthorization('GET'); } - userHasPermSearchAuthorization(method: AllowedMethods): boolean { - const permSearchURL = environment.permissionSearchUrl + '/v3/resources/device-types'; //TODO + userHasListAuthorization(method: AllowedMethods): boolean { + const permSearchURL = environment.deviceRepoUrl + '/device-types'; return this.ladonService.getUserAuthorizationsForURI(permSearchURL)[method]; } diff --git a/src/app/modules/metadata/functions/dialog/functions-create-dialog.component.ts b/src/app/modules/metadata/functions/dialog/functions-create-dialog.component.ts index 098ca4605..1c9a5b5e6 100644 --- a/src/app/modules/metadata/functions/dialog/functions-create-dialog.component.ts +++ b/src/app/modules/metadata/functions/dialog/functions-create-dialog.component.ts @@ -21,6 +21,7 @@ import {ConceptsService} from '../../concepts/shared/concepts.service'; import {ConceptsPermSearchModel} from '../../concepts/shared/concepts-perm-search.model'; import {util} from 'jointjs'; import uuid = util.uuid; +import { DeviceTypeConceptModel } from '../../device-types-overview/shared/device-type.model'; @Component({ templateUrl: './functions-create-dialog.component.html', @@ -30,7 +31,7 @@ export class FunctionsCreateDialogComponent implements OnInit { optionsFormControl = new UntypedFormControl('Controlling'); functionFormGroup!: FormGroup; - concepts: ConceptsPermSearchModel[] = []; + concepts: DeviceTypeConceptModel[] = []; constructor( private conceptsService: ConceptsService, @@ -42,8 +43,8 @@ export class FunctionsCreateDialogComponent implements OnInit { } ngOnInit(): void { - this.conceptsService.getConcepts('', 9999, 0, 'name', 'asc').subscribe((concepts: ConceptsPermSearchModel[]) => { - this.concepts = concepts; + this.conceptsService.getConcepts('', 9999, 0, 'name', 'asc').subscribe(concepts => { + this.concepts = concepts.result; }); } diff --git a/src/app/modules/metadata/functions/dialog/functions-edit-dialog.component.ts b/src/app/modules/metadata/functions/dialog/functions-edit-dialog.component.ts index d405ea166..9f5680fde 100644 --- a/src/app/modules/metadata/functions/dialog/functions-edit-dialog.component.ts +++ b/src/app/modules/metadata/functions/dialog/functions-edit-dialog.component.ts @@ -16,10 +16,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ConceptsService } from '../../concepts/shared/concepts.service'; -import { ConceptsPermSearchModel } from '../../concepts/shared/concepts-perm-search.model'; import { FunctionsPermSearchModel } from '../shared/functions-perm-search.model'; +import { DeviceTypeConceptModel } from '../../device-types-overview/shared/device-type.model'; @Component({ templateUrl: './functions-edit-dialog.component.html', @@ -28,7 +28,7 @@ import { FunctionsPermSearchModel } from '../shared/functions-perm-search.model' export class FunctionsEditDialogComponent implements OnInit { functionFormGroup!: FormGroup; - concepts: ConceptsPermSearchModel[] = []; + concepts: DeviceTypeConceptModel[] = []; disabled: boolean; @@ -43,8 +43,8 @@ export class FunctionsEditDialogComponent implements OnInit { } ngOnInit(): void { - this.conceptsService.getConcepts('', 9999, 0, 'name', 'asc').subscribe((concepts: ConceptsPermSearchModel[]) => { - this.concepts = concepts; + this.conceptsService.getConcepts('', 9999, 0, 'name', 'asc').subscribe(concepts => { + this.concepts = concepts.result; }); } diff --git a/src/app/modules/metadata/functions/functions.component.html b/src/app/modules/metadata/functions/functions.component.html index 8d00d24c5..f3ee696b8 100644 --- a/src/app/modules/metadata/functions/functions.component.html +++ b/src/app/modules/metadata/functions/functions.component.html @@ -67,7 +67,7 @@ Edit - @@ -78,7 +78,7 @@ Delete - diff --git a/src/app/modules/metadata/functions/functions.component.ts b/src/app/modules/metadata/functions/functions.component.ts index 91e1d0844..a61e9613a 100644 --- a/src/app/modules/metadata/functions/functions.component.ts +++ b/src/app/modules/metadata/functions/functions.component.ts @@ -14,40 +14,39 @@ * limitations under the License. */ -import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {forkJoin, Observable, Subscription, map} from 'rxjs'; import {MatDialog} from '@angular/material/dialog'; import {MatDialogConfig} from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; import {DialogsService} from '../../../core/services/dialogs.service'; -import {FunctionsPermSearchModel} from './shared/functions-perm-search.model'; import {FunctionsService} from './shared/functions.service'; import {DeviceTypeFunctionModel} from '../device-types-overview/shared/device-type.model'; import {FunctionsEditDialogComponent} from './dialog/functions-edit-dialog.component'; import {FunctionsCreateDialogComponent} from './dialog/functions-create-dialog.component'; import {AuthorizationService} from '../../../core/services/authorization.service'; import {MatTableDataSource} from '@angular/material/table'; -import {MatSort, Sort, SortDirection} from '@angular/material/sort'; +import {Sort, SortDirection} from '@angular/material/sort'; import { SelectionModel } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { SearchbarService } from 'src/app/core/components/searchbar/shared/searchbar.service'; -import {DeviceTypeService} from "../device-types-overview/shared/device-type.service"; +import {DeviceTypeService} from '../device-types-overview/shared/device-type.service'; import { UsedInDeviceTypeQuery, UsedInDeviceTypeResponseElement -} from "../device-types-overview/shared/used-in-device-type.model"; +} from '../device-types-overview/shared/used-in-device-type.model'; @Component({ selector: 'senergy-functions', templateUrl: './functions.component.html', styleUrls: ['./functions.component.css'], }) -export class FunctionsComponent implements OnInit, OnDestroy { +export class FunctionsComponent implements OnInit, OnDestroy, AfterViewInit { displayedColumns = ['select', 'name']; pageSize = 20; - dataSource = new MatTableDataSource(); + dataSource = new MatTableDataSource(); @ViewChild('paginator', { static: false }) paginator!: MatPaginator; - selection = new SelectionModel(true, []); + selection = new SelectionModel(true, []); totalCount = 200; offset = 0; ready = false; @@ -78,15 +77,6 @@ export class FunctionsComponent implements OnInit, OnDestroy { this.checkAuthorization(); } - getTotalCounts() { - return this.functionsService.getTotalCountOfFunctions(this.searchText).pipe( - map((totalCount: number) => { - this.totalCount = totalCount; - return totalCount; - }) - ); - } - ngAfterViewInit(): void { this.paginator.page.subscribe(()=> { this.pageSize = this.paginator.pageSize; @@ -100,7 +90,7 @@ export class FunctionsComponent implements OnInit, OnDestroy { } checkAuthorization() { - this.userHasUsedInAuthorization = this.deviceTypeService.userHasUsedInAuthorization() + this.userHasUsedInAuthorization = this.deviceTypeService.userHasUsedInAuthorization(); if(this.userHasUsedInAuthorization) { this.displayedColumns.push('useCount'); } @@ -125,7 +115,7 @@ export class FunctionsComponent implements OnInit, OnDestroy { }); } - editFunction(inputFunction: FunctionsPermSearchModel): void { + editFunction(inputFunction: DeviceTypeFunctionModel): void { const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.data = { @@ -143,7 +133,7 @@ export class FunctionsComponent implements OnInit, OnDestroy { }); } - showFunction(inputFunction: FunctionsPermSearchModel): void { + showFunction(inputFunction: DeviceTypeFunctionModel): void { const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.data = { @@ -178,7 +168,7 @@ export class FunctionsComponent implements OnInit, OnDestroy { }); } - deleteFunction(func: FunctionsPermSearchModel): void { + deleteFunction(func: DeviceTypeFunctionModel): void { this.dialogsService .openDeleteDialog('function ' + func.name) .afterClosed() @@ -197,14 +187,15 @@ export class FunctionsComponent implements OnInit, OnDestroy { }); } - private getFunctions(): Observable { + private getFunctions(): Observable { return this.functionsService .getFunctions(this.searchText, this.pageSize, this.offset, this.sortBy, this.sortDirection) .pipe( - map((functions: FunctionsPermSearchModel[]) => { - this.dataSource = new MatTableDataSource(functions); - this.updateFunctionUsedInDeviceTypes(functions); - return functions; + map(functions => { + this.totalCount = functions.total; + this.dataSource = new MatTableDataSource(functions.result); + this.updateFunctionUsedInDeviceTypes(functions.result); + return functions.result; }) ); } @@ -213,7 +204,7 @@ export class FunctionsComponent implements OnInit, OnDestroy { this.ready = false; this.offset = 0; this.selectionClear(); - forkJoin([this.getFunctions(), this.getTotalCounts()]).subscribe(_ => { + this.getFunctions().subscribe(_ => { this.ready = true; }); } @@ -261,7 +252,7 @@ export class FunctionsComponent implements OnInit, OnDestroy { .subscribe((deleteExports: boolean) => { if (deleteExports) { this.ready = false; - this.selection.selected.forEach((func: FunctionsPermSearchModel) => { + this.selection.selected.forEach((func: DeviceTypeFunctionModel) => { deletionJobs.push(this.functionsService.deleteFunction(func.id)); }); } @@ -278,19 +269,19 @@ export class FunctionsComponent implements OnInit, OnDestroy { }); } - private updateFunctionUsedInDeviceTypes(functions: FunctionsPermSearchModel[]) { + private updateFunctionUsedInDeviceTypes(functions: DeviceTypeFunctionModel[]) { if (!this.userHasUsedInAuthorization) { return; } - let query: UsedInDeviceTypeQuery = { - resource: "functions", + const query: UsedInDeviceTypeQuery = { + resource: 'functions', ids: functions.map(f => f.id) - } + }; this.deviceTypeService.getUsedInDeviceType(query).subscribe(result => { result?.forEach((value, key) => { this.usedIn.set(key, value); - }) - }) + }); + }); } public showUsedInDialog(usedIn: UsedInDeviceTypeResponseElement | undefined) { diff --git a/src/app/modules/metadata/functions/shared/functions.service.ts b/src/app/modules/metadata/functions/shared/functions.service.ts index e1c1dd1a3..d27634abf 100644 --- a/src/app/modules/metadata/functions/shared/functions.service.ts +++ b/src/app/modules/metadata/functions/shared/functions.service.ts @@ -15,14 +15,13 @@ */ import { Injectable } from '@angular/core'; -import { HttpClient, HttpParams } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { ErrorHandlerService } from '../../../../core/services/error-handler.service'; import { Observable } from 'rxjs'; import { environment } from '../../../../../environments/environment'; import { catchError, map } from 'rxjs/operators'; -import { FunctionsPermSearchModel } from './functions-perm-search.model'; import { DeviceTypeFunctionModel } from '../../device-types-overview/shared/device-type.model'; -import { AllowedMethods, PermissionTestResponse } from 'src/app/modules/admin/permissions/shared/permission.model'; +import { PermissionTestResponse } from 'src/app/modules/admin/permissions/shared/permission.model'; import { LadonService } from 'src/app/modules/admin/permissions/shared/services/ladom.service'; @Injectable({ @@ -36,8 +35,8 @@ export class FunctionsService { private errorHandlerService: ErrorHandlerService, private ladonService: LadonService ) { - const permSearchURL = environment.permissionSearchUrl + '/v3/resources/functions'; // TODO - this.authorizations = this.ladonService.getUserAuthorizationsForURI(permSearchURL); // TODO + const url = environment.deviceRepoUrl + '/functions'; + this.authorizations = this.ladonService.getUserAuthorizationsForURI(url); } getFunctions( @@ -46,63 +45,28 @@ export class FunctionsService { offset: number, sortBy: string, sortDirection: string, - ): Observable { + ): Observable<{result: DeviceTypeFunctionModel[]; total: number}> { if (sortDirection === '' || sortDirection === null || sortDirection === undefined) { sortDirection = 'asc'; } if (sortBy === '' || sortBy === null || sortBy === undefined) { sortBy = 'name'; } - const params = ['limit=' + limit, 'offset=' + offset, 'rights=r', 'sort=' + sortBy + '.' + sortDirection]; + const params = ['limit=' + limit, 'offset=' + offset, 'sort=' + sortBy + '.' + sortDirection]; if (query) { params.push('search=' + encodeURIComponent(query)); } return this.http - .get(environment.permissionSearchUrl + '/v3/resources/functions?' + params.join('&')) // TODO - .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(FunctionsService.name, 'getFunctions(search)', [])), - ); - } - - getFunctionsAfter( - query: string, - limit: number, - sortBy: string, - sortDirection: string, - after: FunctionsPermSearchModel, - ): Observable { - if (sortDirection === '' || sortDirection === null || sortDirection === undefined) { - sortDirection = 'asc'; - } - if (sortBy === '' || sortBy === null || sortBy === undefined) { - sortBy = 'name'; - } - - let sortFieldValue = ''; - switch (sortBy) { - case 'name': { - sortFieldValue = encodeURIComponent(JSON.stringify(after.name)); - } - } - - const params = [ - 'limit=' + limit, - 'rights=r', - 'sort=' + sortBy + '.' + sortDirection, - 'after.id=' + after.id, - 'after.sort_field_value=' + sortFieldValue, - ]; - if (query) { - params.push('search=' + encodeURIComponent(query)); - } - - return this.http - .get(environment.permissionSearchUrl + '/v3/resources/functions?' + params.join('&')) // TODO - .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(FunctionsService.name, 'getFunctions(search)', [])), + .get(environment.deviceRepoUrl + '/functions?' + params.join('&'), { observe: 'response' }).pipe( + map(resp => { + const totalStr = resp.headers.get('X-Total-Count') || '0'; + return { + result: resp.body || [], + total: parseInt(totalStr, 10) + }; + }), + catchError(this.errorHandlerService.handleError(FunctionsService.name, 'getFunctions(search)', {result: [], total: 0})), ); } @@ -130,23 +94,6 @@ export class FunctionsService { .pipe(catchError(this.errorHandlerService.handleError(FunctionsService.name, 'createFunction', null))); } - - getTotalCountOfFunctions(searchText: string): Observable { - const options = searchText ? - { params: new HttpParams().set('search', searchText) } : {}; - - return this.http - .get(environment.permissionSearchUrl + '/v3/total/functions', options) // TODO - .pipe( - catchError( - this.errorHandlerService.handleError( - FunctionsService.name, - 'getTotalCountOfFunctions', - ), - ), - ); - } - userHasDeleteAuthorization(): boolean { return this.authorizations['DELETE']; } @@ -162,6 +109,4 @@ export class FunctionsService { userHasReadAuthorization(): boolean { return this.authorizations['GET']; } - - } diff --git a/src/app/modules/permissions/shared/permissions-dialog.service.ts b/src/app/modules/permissions/shared/permissions-dialog.service.ts index f15a1aeb1..0c7189a56 100644 --- a/src/app/modules/permissions/shared/permissions-dialog.service.ts +++ b/src/app/modules/permissions/shared/permissions-dialog.service.ts @@ -15,41 +15,28 @@ */ import { Injectable } from '@angular/core'; -import {PermissionsResourceBaseModel, PermissionsResourceModel, PermissionsV2ResourceBaseModel, PermissionsV2ResourceModel} from './permissions-resource.model'; +import {PermissionsV2ResourceBaseModel, PermissionsV2ResourceModel} from './permissions-resource.model'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { PermissionDialogComponent, PermissionDialogComponentData } from '../dialogs/permission/permission-dialog.component'; import { PermissionsService } from './permissions.service'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { ErrorHandlerService } from 'src/app/core/services/error-handler.service'; @Injectable({ providedIn: 'root', }) export class PermissionsDialogService { constructor( - private errorHandlerService: ErrorHandlerService, private dialog: MatDialog, private permissionsService: PermissionsService, public snackBar: MatSnackBar, ) {} - //key is the kafka key this permission command will be published to. is optional - openPermissionDialog(kind: string, id: string, name: string, key?: string): void { - this.permissionsService.getResourcePermissions(kind, id).subscribe((permissionsModel: PermissionsResourceModel) => { - this.openPermDialog(name, permissionsModel, kind, id, key); - }); - } - openPermissionV2Dialog(topicID: string, ressourceID: string, name: string) { this.permissionsService.getResourcePermissionsV2(topicID, ressourceID).subscribe((permissionsModel: PermissionsV2ResourceModel) => { this.openPermV2Dialog(name, permissionsModel, topicID, ressourceID); }); } - private openPermDialog(_: string, __: PermissionsResourceBaseModel, ___: string, ____: string, _____?: string) { - this.errorHandlerService.showErrorInSnackBar("Currently not supported"); - } - private openPermV2Dialog(name: string, permissionsIn: PermissionsV2ResourceBaseModel, topicID: string, ressourceID: string) { const dialogConfig = new MatDialogConfig(); dialogConfig.disableClose = false; diff --git a/src/app/modules/permissions/shared/permissions-response.model.ts b/src/app/modules/permissions/shared/permissions-response.model.ts deleted file mode 100644 index f72bfcc35..000000000 --- a/src/app/modules/permissions/shared/permissions-response.model.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020 InfAI (CC SES) - * - * 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 PermissionsResponseModel { - status: string; -} diff --git a/src/app/modules/permissions/shared/permissions.service.ts b/src/app/modules/permissions/shared/permissions.service.ts index accb82b55..2218e543c 100644 --- a/src/app/modules/permissions/shared/permissions.service.ts +++ b/src/app/modules/permissions/shared/permissions.service.ts @@ -20,7 +20,7 @@ import { environment } from '../../../../environments/environment'; import { Observable } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; import { ErrorHandlerService } from '../../../core/services/error-handler.service'; -import { PermissionsResourceBaseModel, PermissionsResourceModel, PermissionsV2ResourceBaseModel, PermissionsV2ResourceModel, PermissionsV2RightsAndIdModel} from './permissions-resource.model'; +import { PermissionsResourceBaseModel, PermissionsV2ResourceBaseModel, PermissionsV2ResourceModel, PermissionsV2RightsAndIdModel} from './permissions-resource.model'; import { PermissionsUserModel } from './permissions-user.model'; import { PermissionsRightsModel } from './permissions-rights.model'; @@ -47,19 +47,6 @@ export class PermissionsService { return result; } - getResourcePermissions(kind: string, id: string): Observable { - return this.http - .get( - environment.permissionSearchUrl + '/v3/administrate/rights/' + encodeURIComponent(kind) + '/' + encodeURIComponent(id), //TODO - ) - .pipe( - map((resp) => resp || {} as PermissionsResourceModel), - catchError( - this.errorHandlerService.handleError(PermissionsService.name, 'getResourcePermissions', {} as PermissionsResourceModel), - ), - ); - } - getResourcePermissionsV2(topicID: string, ressourceId: string): Observable { return this.http .get( @@ -140,7 +127,7 @@ export class PermissionsService { getSharableUsers(): Observable { return this.http - .get(environment.usersServiceUrl + '/user-list?excludeCaller=true') - .pipe(catchError(this.errorHandlerService.handleError(PermissionsService.name, 'getSharableUsers', [] as PermissionsUserModel[]))); + .get(environment.usersServiceUrl + '/user-list?excludeCaller=true') + .pipe(catchError(this.errorHandlerService.handleError(PermissionsService.name, 'getSharableUsers', [] as PermissionsUserModel[]))); } } diff --git a/src/app/modules/processes/process-repo/process-repo.component.html b/src/app/modules/processes/process-repo/process-repo.component.html index cc74e9d97..5ccdad93f 100644 --- a/src/app/modules/processes/process-repo/process-repo.component.html +++ b/src/app/modules/processes/process-repo/process-repo.component.html @@ -38,7 +38,7 @@
- + share @@ -57,12 +57,12 @@
diff --git a/src/app/modules/processes/process-repo/process-repo.component.ts b/src/app/modules/processes/process-repo/process-repo.component.ts index 6433908a0..a41a77420 100644 --- a/src/app/modules/processes/process-repo/process-repo.component.ts +++ b/src/app/modules/processes/process-repo/process-repo.component.ts @@ -17,10 +17,10 @@ import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AuthorizationService } from '../../../core/services/authorization.service'; import { SortModel } from '../../../core/components/sort/shared/sort.model'; -import { forkJoin, Observable, Subscription } from 'rxjs'; +import { concatMap, forkJoin, map, Observable, Subscription } from 'rxjs'; import { SearchbarService } from '../../../core/components/searchbar/shared/searchbar.service'; import { ResponsiveService } from '../../../core/services/responsive.service'; -import {ProcessModel, ProcessPermModel} from './shared/process.model'; +import { ProcessModel } from './shared/process.model'; import { ProcessRepoService } from './shared/process-repo.service'; import { UtilService } from '../../../core/services/util.service'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; @@ -32,7 +32,8 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { ProcessRepoConditionModel, ProcessRepoConditionsModel } from './shared/process-repo-conditions.model'; import { Router } from '@angular/router'; import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; -import {PermissionsService} from "../../permissions/shared/permissions.service"; +import { PermissionsService } from '../../permissions/shared/permissions.service'; +import { PermissionsV2RightsAndIdModel } from '../../permissions/shared/permissions-resource.model'; const grids = new Map([ ['xs', 1], @@ -61,6 +62,7 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { searchText = ''; selectedItems: ProcessModel[] = []; rowHeight = 282; + permissionsPerModel: PermissionsV2RightsAndIdModel[] = []; userHasCreateAuthorization = false; userHasUpdateAuthorization = false; @@ -75,7 +77,7 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { private gridColChangeTimeout: number | undefined; private knownMainPanelOffsetHeight = 0; - userIdToName: {[key: string]: string} = {}; + userIdToName: { [key: string]: string } = {}; @ViewChild('mainPanel', { static: false }) mainPanel!: ElementRef; @@ -134,11 +136,11 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { } permission(process: ProcessModel): void { - this.permissionsDialogService.openPermissionDialog('processmodel', process.id, process.name); + this.permissionsDialogService.openPermissionV2Dialog('processmodel', process._id, process.name); } downloadDiagram(process: ProcessModel): void { - this.processRepoService.getProcessModel(process.id).subscribe((processModel: DesignerProcessModel | null) => { + this.processRepoService.getProcessModel(process._id).subscribe((processModel: DesignerProcessModel | null) => { if (processModel) { const xml = processModel.bpmn_xml; const file = new Blob([xml], { type: 'application/bpmn-xml' }); @@ -158,18 +160,12 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { .afterClosed() .subscribe((deleteProcess: boolean) => { if (deleteProcess) { - this.processRepoService.deleteProcess(process.id).subscribe((resp: { status: number }) => { + this.processRepoService.deleteProcess(process._id).subscribe((resp: { status: number }) => { if (resp.status === 200) { - this.repoItems.removeAt(this.repoItems.value.findIndex((item: ProcessModel) => process.id === item.id)); - this.processRepoService.checkForDeletedProcess(process.id, 10, 100).subscribe((exists) => { - if (exists) { - this.showSnackBarError('deleting the process!'); - } else { - this.showSnackBarSuccess('Process deleted'); - } - this.setRepoItemsParams(1); - this.getRepoItems(false); - }); + this.repoItems.removeAt(this.repoItems.value.findIndex((item: ProcessModel) => process._id === item._id)); + this.showSnackBarSuccess('Process deleted'); + this.setRepoItemsParams(1); + this.getRepoItems(false); } else { this.showSnackBarError('deleting the process!'); } @@ -180,7 +176,7 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { copyProcess(process: ProcessModel): void { this.reset(); - this.processRepoService.getProcessModel(process.id).subscribe((processModel: DesignerProcessModel | null) => { + this.processRepoService.getProcessModel(process._id).subscribe((processModel: DesignerProcessModel | null) => { if (processModel) { const newProcess = processModel.bpmn_xml; this.processRepoService @@ -190,14 +186,8 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { this.showSnackBarError('copying the process!'); this.getRepoItems(true); } else { - this.processRepoService.checkForCopiedProcess(processResp._id, 10, 100).subscribe((exists) => { - if (exists) { - this.showSnackBarSuccess('Process copied'); - } else { - this.showSnackBarError('copying the process!'); - } - this.getRepoItems(true); - }); + this.showSnackBarSuccess('Process copied'); + this.getRepoItems(true); } }); } @@ -233,8 +223,7 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { this.ready = false; const array: Observable[] = []; this.selectedItems.forEach((item: ProcessModel) => { - array.push(this.processRepoService.checkForDeletedProcess(item.id, 15, 200)); - this.processRepoService.deleteProcess(item.id).subscribe((resp: { status: number }) => { + this.processRepoService.deleteProcess(item._id).subscribe((resp: { status: number }) => { if (resp.status !== 200) { this.showSnackBarError( this.selectedItems.length === 1 ? 'deleting the process!' : 'deleting the processes!', @@ -259,6 +248,14 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { this.selectedItems = this.repoItems.value.filter((item: ProcessModel) => item.selected === true); } + hasAPermission(m: {_id: string}): boolean { + return this.permissionsPerModel.find(t => t.id === m._id)?.administrate || false; + } + + hasXPermission(m: {_id: string}): boolean { + return this.permissionsPerModel.find(t => t.id === m._id)?.execute || false; + } + private initGridCols(): void { this.gridCols = grids.get(this.responsiveService.getActiveMqAlias()) || 0; this.responsiveService.observeMqAlias().subscribe((mqAlias) => { @@ -291,51 +288,60 @@ export class ProcessRepoComponent implements OnInit, AfterViewInit, OnDestroy { this.limit, this.offset, this.sortAttribute.value, - this.sortAttribute.order, - this.getConditions(), - ) - .subscribe((repoItems: ProcessPermModel[]) => { - this.loadUserNames(repoItems); + this.sortAttribute.order + ).pipe(concatMap(x => this.permissionsService.getComputedResourcePermissionsV2('processmodel', x.result.map(e => e._id)).pipe(map(perm => this.permissionsPerModel = perm), map(_ => x)))) + .subscribe(repoItems => { + this.loadUserNames(repoItems.result); this.animationDone = true; - this.addToFormArray(repoItems); - if (repoItems.length !== this.limit) { + switch (this.activeIndex) { + case 0: + //all + break; + case 1: + //own + repoItems.result = repoItems.result.filter(r => r.owner === this.userID); + break; + case 2: + // shared + repoItems.result = repoItems.result.filter(r => r.owner !== this.userID); + break; + } + this.addToFormArray(repoItems.result); + if (repoItems.result.length !== this.limit) { this.allDataLoaded = true; } this.ready = true; }); } - private loadUserNames(elements: {creator: string, shared: boolean}[]) { - let missingCreators: string[] = []; + private loadUserNames(elements: { owner: string }[]) { + const missingCreators: string[] = []; elements?.forEach(element => { - if(element.shared && element.creator && !this.userIdToName[element.creator] && !missingCreators.includes(element.creator)) { - missingCreators.push(element.creator); + if (element.owner !== this.userID && !this.userIdToName[element.owner] && !missingCreators.includes(element.owner)) { + missingCreators.push(element.owner); } - }) + }); missingCreators.forEach(creator => { this.permissionsService.getUserById(creator).subscribe(value => { - if(value) { + if (value) { this.userIdToName[value.id] = value.username; } - }) - }) + }); + }); } - private addToFormArray(repoItems: ProcessPermModel[]): void { - repoItems.forEach((repoItem: ProcessPermModel) => { + private addToFormArray(repoItems: ProcessModel[]): void { + repoItems.forEach((repoItem: ProcessModel) => { this.repoItems.push( this._formBuilder.group({ - id: repoItem.id, + _id: repoItem._id, name: repoItem.name, date: repoItem.date, svgXML: repoItem.svgXML, bpmn_xml: repoItem.bpmn_xml, publish: repoItem.publish, - shared: repoItem.shared, - creator: repoItem.creator, - parent_id: repoItem.parent_id, + owner: repoItem.owner, image: this.provideImg(repoItem.svgXML), - permissions: repoItem.permissions, selected: false, }), ); diff --git a/src/app/modules/processes/process-repo/shared/process-repo.service.ts b/src/app/modules/processes/process-repo/shared/process-repo.service.ts index 2e9eff557..8c1bdbd79 100644 --- a/src/app/modules/processes/process-repo/shared/process-repo.service.ts +++ b/src/app/modules/processes/process-repo/shared/process-repo.service.ts @@ -15,14 +15,13 @@ */ import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponseBase } from '@angular/common/http'; +import { HttpClient, HttpParams, HttpResponseBase } from '@angular/common/http'; import { ErrorHandlerService } from '../../../../core/services/error-handler.service'; import { environment } from '../../../../../environments/environment'; -import { catchError, map, mergeMap, retryWhen } from 'rxjs/operators'; -import { Observable, timer } from 'rxjs'; -import {ProcessPermModel} from './process.model'; +import { catchError, map } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { ProcessModel } from './process.model'; import { DesignerProcessModel } from '../../designer/shared/designer.model'; -import { ProcessRepoConditionsModel } from './process-repo-conditions.model'; import { PermissionTestResponse } from 'src/app/modules/admin/permissions/shared/permission.model'; import { LadonService } from 'src/app/modules/admin/permissions/shared/services/ladom.service'; @@ -41,37 +40,29 @@ export class ProcessRepoService { } - list(kind: string, right: string) { - return this.http.get(environment.permissionSearchUrl + '/v3/resources/' + kind + '?limit=9999&rights=' + right).pipe( //TODO - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(ProcessRepoService.name, 'list', [])), - ); - } - getProcessModels( query: string, limit: number, offset: number, - feature: string, + sortBy: string, order: string, - conditions: ProcessRepoConditionsModel | null, - ): Observable { + ): Observable<{result: ProcessModel[]; total: number}> { + let params = new HttpParams(); + params = params.set('search', query); + params = params.set('limit', limit); + params = params.set('offset', offset); + params = params.set('sort', sortBy + '.' + order); + return this.http - .post(environment.permissionSearchUrl + '/v3/query/processmodel', { //TODO - resource: 'processmodel', - find: { - search: query, - limit, - offset, - rights: 'r', - sort_by: feature, - sort_desc: order !== 'asc', - filter: conditions, - }, - }) - .pipe( - map((resp) => resp || []), - catchError(this.errorHandlerService.handleError(ProcessRepoService.name, 'getProcessModels(search)', [])), + .get(environment.processRepoUrl.slice(0, -10) + '/v2/processes', { observe: 'response', params }).pipe( + map(resp => { + const totalStr = resp.headers.get('X-Total-Count') || '0'; + return { + result: resp.body || [], + total: parseInt(totalStr, 10) + }; + }), + catchError(this.errorHandlerService.handleError(ProcessRepoService.name, 'getProcessModels(search)', {result: [], total: 0})), ); } @@ -81,14 +72,6 @@ export class ProcessRepoService { .pipe(catchError(this.errorHandlerService.handleError(ProcessRepoService.name, 'getProcessModel()', null))); } - checkForCopiedProcess(id: string, maxRetries: number, intervalInMs: number): Observable { - return this.checkForProcessModelWithRetries(id, true, maxRetries, intervalInMs); - } - - checkForDeletedProcess(id: string, maxRetries: number, intervalInMs: number): Observable { - return this.checkForProcessModelWithRetries(id, false, maxRetries, intervalInMs); - } - deleteProcess(id: string): Observable<{ status: number }> { return this.http.delete(environment.processRepoUrl + '/' + id, { observe: 'response' }).pipe( map((resp) => ({ status: resp.status })), @@ -109,32 +92,6 @@ export class ProcessRepoService { } } - private checkForProcessModelWithRetries( - id: string, - shouldIdExists: boolean, - maxRetries: number, - intervalInMs: number, - ): Observable { - return this.http.get(environment.permissionSearchUrl + '/v3/resources/processmodel/' + id + '/access?rights=r').pipe( //TODO - map((data) => { - if (data === !shouldIdExists) { - throw Error(''); - } - return data; - }), - retryWhen( - mergeMap((error, i) => { - const retryAttempt = i + 1; - if (retryAttempt > maxRetries) { - throw error; - } - return timer(retryAttempt * intervalInMs); - }), - ), - catchError(this.errorHandlerService.handleError(ProcessRepoService.name, 'checkForProcessModelWithRetries', !shouldIdExists)), - ); - } - userHasDeleteAuthorization(): boolean { return this.authorizations['DELETE']; } diff --git a/src/app/modules/processes/process-repo/shared/process.model.ts b/src/app/modules/processes/process-repo/shared/process.model.ts index 8742c1083..c7d4de9e5 100644 --- a/src/app/modules/processes/process-repo/shared/process.model.ts +++ b/src/app/modules/processes/process-repo/shared/process.model.ts @@ -14,27 +14,14 @@ * limitations under the License. */ -import { SafeUrl } from '@angular/platform-browser'; export interface ProcessModel { - id: string; + _id: string; name: string; date: number; svgXML: string; bpmn_xml: string; publish: boolean; - shared: boolean; - parent_id: string; - image: SafeUrl; - permissions: { - a: boolean; - x: boolean; - r: boolean; - w: boolean; - }; - selected: boolean; + selected?: boolean; // only for internal use, not set by API + owner: string; } - -export interface ProcessPermModel extends ProcessModel { - creator: string; -} \ No newline at end of file diff --git a/src/app/modules/smart-services/designer/dialog/edit-smart-service-input-dialog/edit-smart-service-input-dialog.component.ts b/src/app/modules/smart-services/designer/dialog/edit-smart-service-input-dialog/edit-smart-service-input-dialog.component.ts index cdd5e6b2b..9eb5cc5dd 100644 --- a/src/app/modules/smart-services/designer/dialog/edit-smart-service-input-dialog/edit-smart-service-input-dialog.component.ts +++ b/src/app/modules/smart-services/designer/dialog/edit-smart-service-input-dialog/edit-smart-service-input-dialog.component.ts @@ -17,30 +17,15 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { - SmartServiceTaskInputDescription, - SmartServiceTaskDescription, SmartServiceInputsDescription, SmartServiceInput, SmartServiceInputProperty } from '../../shared/designer.model'; -import {ProcessRepoService} from '../../../../processes/process-repo/shared/process-repo.service'; -import {DeploymentsService} from '../../../../processes/deployments/shared/deployments.service'; -import {ProcessModel} from '../../../../processes/process-repo/shared/process.model'; -import {V2DeploymentsPreparedModel} from '../../../../processes/deployments/shared/deployments-prepared-v2.model'; -import {FlowRepoService} from '../../../../data/flow-repo/shared/flow-repo.service'; -import {FlowModel} from '../../../../data/flow-repo/shared/flow.model'; -import {FlowEngineService} from '../../../../data/flow-repo/shared/flow-engine.service'; -import {ParserService} from '../../../../data/flow-repo/shared/parser.service'; -import {ParseModel} from '../../../../data/flow-repo/shared/parse.model'; -import {BpmnElement, BpmnParameter, BpmnParameterWithLabel} from '../../../../processes/designer/shared/designer.model'; -import {AspectsPermSearchModel} from '../../../../metadata/aspects/shared/aspects-perm-search.model'; +import {BpmnElement} from '../../../../processes/designer/shared/designer.model'; import {FunctionsPermSearchModel} from '../../../../metadata/functions/shared/functions-perm-search.model'; -import {DeviceClassesPermSearchModel} from '../../../../metadata/device-classes/shared/device-classes-perm-search.model'; import {FunctionsService} from '../../../../metadata/functions/shared/functions.service'; -import {AspectsService} from '../../../../metadata/aspects/shared/aspects.service'; import {DeviceClassesService} from '../../../../metadata/device-classes/shared/device-classes.service'; import {DeviceTypeService} from '../../../../metadata/device-types-overview/shared/device-type.service'; -import {DeviceTypeAspectModel, DeviceTypeAspectNodeModel} from '../../../../metadata/device-types-overview/shared/device-type.model'; -import {CharacteristicsPermSearchModel} from '../../../../metadata/characteristics/shared/characteristics-perm-search.model'; +import {DeviceTypeAspectNodeModel, DeviceTypeCharacteristicsModel, DeviceTypeDeviceClassModel} from '../../../../metadata/device-types-overview/shared/device-type.model'; import {CharacteristicsService} from '../../../../metadata/characteristics/shared/characteristics.service'; import {AbstractControl, ValidationErrors} from '@angular/forms'; @@ -52,10 +37,10 @@ export class EditSmartServiceInputDialogComponent implements OnInit { abstract: AbstractSmartServiceInput[] = []; functions: (FunctionsPermSearchModel | {id?: string; name: string})[] = []; - deviceClasses: (DeviceClassesPermSearchModel | {id?: string; name: string})[] = []; + deviceClasses: (DeviceTypeDeviceClassModel | {id?: string; name: string})[] = []; nestedAspects: Map = new Map(); - characteristics: CharacteristicsPermSearchModel[] = []; + characteristics: DeviceTypeCharacteristicsModel[] = []; constructor( private dialogRef: MatDialogRef, @@ -66,13 +51,13 @@ export class EditSmartServiceInputDialogComponent implements OnInit { @Inject(MAT_DIALOG_DATA) private dialogParams: { info: SmartServiceInputsDescription; element: BpmnElement}, ) { this.characteristicsService.getCharacteristics('', 9999, 0, 'name', 'asc').subscribe(value => { - this.characteristics = value; + this.characteristics = value.result; }); this.functionsService.getFunctions('', 9999, 0, 'name', 'asc').subscribe(value => { - this.functions = value; + this.functions = value.result; }); this.deviceClassService.getDeviceClasses('', 9999, 0, 'name', 'asc').subscribe(value => { - this.deviceClasses = value; + this.deviceClasses = value.result; }); this.deviceTypesService.getAspectNodesWithMeasuringFunctionOfDevicesOnly().subscribe((aspects: DeviceTypeAspectNodeModel[]) => { const tmp: Map = new Map(); diff --git a/src/app/modules/smart-services/designer/dialog/edit-smart-service-json-extraction-dialog/edit-smart-service-json-extraction-dialog.component.ts b/src/app/modules/smart-services/designer/dialog/edit-smart-service-json-extraction-dialog/edit-smart-service-json-extraction-dialog.component.ts index 9c1a315ea..eb48179f0 100644 --- a/src/app/modules/smart-services/designer/dialog/edit-smart-service-json-extraction-dialog/edit-smart-service-json-extraction-dialog.component.ts +++ b/src/app/modules/smart-services/designer/dialog/edit-smart-service-json-extraction-dialog/edit-smart-service-json-extraction-dialog.component.ts @@ -18,29 +18,9 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { SmartServiceTaskInputDescription, - SmartServiceTaskDescription, - ServingRequest, SmartServiceTaskInputOutputDescription } from '../../shared/designer.model'; -import {ProcessRepoService} from '../../../../processes/process-repo/shared/process-repo.service'; -import {DeploymentsService} from '../../../../processes/deployments/shared/deployments.service'; -import {ProcessModel} from '../../../../processes/process-repo/shared/process.model'; -import {V2DeploymentsPreparedModel} from '../../../../processes/deployments/shared/deployments-prepared-v2.model'; -import {FlowRepoService} from '../../../../data/flow-repo/shared/flow-repo.service'; -import {FlowModel} from '../../../../data/flow-repo/shared/flow.model'; -import {ParserService} from '../../../../data/flow-repo/shared/parser.service'; -import {ParseModel} from '../../../../data/flow-repo/shared/parse.model'; import {BpmnElement, BpmnParameter, BpmnParameterWithLabel} from '../../../../processes/designer/shared/designer.model'; -import {ImportInstanceConfigModel, ImportInstancesModel} from '../../../../imports/import-instances/shared/import-instances.model'; -import { - ImportTypeContentVariableModel, - ImportTypeModel, - ImportTypePermissionSearchModel -} from '../../../../imports/import-types/shared/import-types.model'; -import {ImportTypesService} from '../../../../imports/import-types/shared/import-types.service'; -import {AbstractControl, FormGroup, ValidationErrors, ValidatorFn} from '@angular/forms'; -import {subtract} from 'lodash'; -import {DomSanitizer, SafeHtml} from '@angular/platform-browser'; @Component({ templateUrl: './edit-smart-service-json-extraction-dialog.component.html', diff --git a/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/criteria-list.component.ts b/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/criteria-list.component.ts index af8d83500..5564ec43a 100644 --- a/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/criteria-list.component.ts +++ b/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/criteria-list.component.ts @@ -16,14 +16,12 @@ -import {Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation} from '@angular/core'; -import {FormBuilder} from '@angular/forms'; -import {DeviceTypeAspectNodeModel} from '../../../../metadata/device-types-overview/shared/device-type.model'; +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {DeviceTypeAspectNodeModel, DeviceTypeDeviceClassModel} from '../../../../metadata/device-types-overview/shared/device-type.model'; import {FunctionsService} from '../../../../metadata/functions/shared/functions.service'; import {DeviceTypeService} from '../../../../metadata/device-types-overview/shared/device-type.service'; import {DeviceClassesService} from '../../../../metadata/device-classes/shared/device-classes.service'; import {FunctionsPermSearchModel} from '../../../../metadata/functions/shared/functions-perm-search.model'; -import {DeviceClassesPermSearchModel} from '../../../../metadata/device-classes/shared/device-classes-perm-search.model'; interface Criteria { interaction?: string; @@ -43,7 +41,7 @@ export class CriteriaListComponent implements OnInit { @Output() changed: EventEmitter = new EventEmitter(); functions: (FunctionsPermSearchModel | {id?: string; name: string})[] = []; - deviceClasses: (DeviceClassesPermSearchModel | {id?: string; name: string})[] = []; + deviceClasses: (DeviceTypeDeviceClassModel | {id?: string; name: string})[] = []; nestedAspects: Map = new Map(); criteriaList: Criteria[] = []; @@ -52,10 +50,10 @@ export class CriteriaListComponent implements OnInit { private deviceTypesService: DeviceTypeService, private deviceClassService: DeviceClassesService) { this.functionsService.getFunctions('', 9999, 0, 'name', 'asc').subscribe(value => { - this.functions = value; + this.functions = value.result; }); this.deviceClassService.getDeviceClasses('', 9999, 0, 'name', 'asc').subscribe(value => { - this.deviceClasses = value; + this.deviceClasses = value.result; }); this.deviceTypesService.getAspectNodesWithMeasuringFunctionOfDevicesOnly().subscribe((aspects: DeviceTypeAspectNodeModel[]) => { const tmp: Map = new Map(); diff --git a/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.html b/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.html index 8c537cc44..e9f28ddb8 100644 --- a/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.html +++ b/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.html @@ -34,7 +34,7 @@

Smart-Service Task

[options]="processModels || []" (selectionChange)="ensureProcessTaskParameter($event.value)" useOptionViewProperty="name" - useOptionValueProperty="id"> + useOptionValueProperty="_id"> diff --git a/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.ts b/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.ts index 7d0da76a3..89fa9d2a5 100644 --- a/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.ts +++ b/src/app/modules/smart-services/designer/dialog/edit-smart-service-task-dialog/edit-smart-service-task-dialog.component.ts @@ -44,7 +44,6 @@ import {ImportInstanceConfigModel, ImportInstancesModel} from '../../../../impor import { ImportTypeContentVariableModel, ImportTypeModel, - ImportTypePermissionSearchModel } from '../../../../imports/import-types/shared/import-types.model'; import {ImportTypesService} from '../../../../imports/import-types/shared/import-types.service'; import {DomSanitizer, SafeHtml} from '@angular/platform-browser'; @@ -55,8 +54,7 @@ import { smartServiceInputsDescriptionToAbstractSmartServiceInput } from '../edit-smart-service-input-dialog/edit-smart-service-input-dialog.component'; import {FunctionsPermSearchModel} from '../../../../metadata/functions/shared/functions-perm-search.model'; -import {DeviceClassesPermSearchModel} from '../../../../metadata/device-classes/shared/device-classes-perm-search.model'; -import {DeviceTypeAspectNodeModel} from '../../../../metadata/device-types-overview/shared/device-type.model'; +import {DeviceTypeAspectNodeModel, DeviceTypeDeviceClassModel} from '../../../../metadata/device-types-overview/shared/device-type.model'; import {FunctionsService} from '../../../../metadata/functions/shared/functions.service'; import {DeviceTypeService} from '../../../../metadata/device-types-overview/shared/device-type.service'; import {DeviceClassesService} from '../../../../metadata/device-classes/shared/device-classes.service'; @@ -106,7 +104,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni exportRequest: ServingRequest; importRequest: ImportInstancesModel; importRequestConfigValueType: Map = new Map(); - importTypes: ImportTypePermissionSearchModel[] = []; + importTypes: ImportTypeModel[] = []; knownImportTypes: Map = new Map(); importOverwrites: {config_name: string; json_value: string}[] = []; availableAnalyticsIotSelections: {name: string; value: string}[]; @@ -201,7 +199,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni this.addImportIotEntityWithPathToAvailableVariables(); this.exportRequest = this.parseExport(this.result.inputs.find(value => value.name === 'export.request')?.value || '{"generated": true}'); this.importRequest = this.parseImport(this.result.inputs.find(value => value.name === 'import.request')?.value || '{}'); - this.importTypeService.listImportTypes('', 9999, 0, 'name.asc').subscribe(value => this.importTypes = value); + this.importTypeService.listImportTypes('', 9999, 0, 'name.asc').subscribe(value => this.importTypes = value.result); if(this.importRequest.import_type_id) { this.loadImportType(false); } @@ -214,10 +212,10 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni this.initWatcherInfo(dialogParams.info.inputs); this.functionsService.getFunctions('', 9999, 0, 'name', 'asc').subscribe(value => { - this.functions = value; + this.functions = value.result; }); this.deviceClassService.getDeviceClasses('', 9999, 0, 'name', 'asc').subscribe(value => { - this.deviceClasses = value; + this.deviceClasses = value.result; }); this.deviceTypesService.getAspectNodesWithMeasuringFunctionOfDevicesOnly().subscribe((aspects: DeviceTypeAspectNodeModel[]) => { const tmp: Map = new Map(); @@ -327,7 +325,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni }); }); - that.nestedAspects.forEach((list, _) => { + that.nestedAspects.forEach(list => { list.forEach(value => { completers.push({ caption: 'aspect: '+value.name, @@ -337,7 +335,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni }); }); - const interactions: String[] = ['event', 'request', 'event+request']; + const interactions: string[] = ['event', 'request', 'event+request']; interactions.forEach(value => { completers.push({ caption: 'interaction: '+value, @@ -390,7 +388,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni ensureResultFields() { const processDeploymentTopic = this.tabs[0]; if(!this.processModels && this.result.topic === processDeploymentTopic) { - this.processRepo.getProcessModels('', 9999, 0, 'date', 'asc', null).subscribe(value => this.processModels = value); + this.processRepo.getProcessModels('', 9999, 0, 'date', 'asc').subscribe(value => this.processModels = value.result); } this.ensureFlowList(); this.ensureExportDatabaseList(); @@ -1361,7 +1359,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni case 'create_device_group': { result.push({name: this.deviceRepositoryCreateDeviceGroupFieldKey, type: 'text', value: this.deviceRepositoryWorkerInfo.create_device_group.ids}); result.push({name: this.deviceRepositoryNameFieldKey, type: 'text', value: this.deviceRepositoryWorkerInfo.name}); - result.push({name: this.deviceRepositoryWaitFieldKey, type: 'text', value: "true"}); + result.push({name: this.deviceRepositoryWaitFieldKey, type: 'text', value: 'true'}); if (this.deviceRepositoryWorkerInfo.key) { result.push({name: this.deviceRepositoryKeyFieldKey, type: 'text', value: this.deviceRepositoryWorkerInfo.key}); } @@ -1373,7 +1371,7 @@ export class EditSmartServiceTaskDialogComponent implements OnInit, AfterViewIni functions: (FunctionsPermSearchModel | {id?: string; name: string})[] = []; - deviceClasses: (DeviceClassesPermSearchModel | {id?: string; name: string})[] = []; + deviceClasses: (DeviceTypeDeviceClassModel | {id?: string; name: string})[] = []; nestedAspects: Map = new Map(); removeCriteria(list: Criteria[], index: number): Criteria[] { diff --git a/src/app/modules/smart-services/designs/designs.component.ts b/src/app/modules/smart-services/designs/designs.component.ts index 6aec5bb8a..9846dc5f9 100644 --- a/src/app/modules/smart-services/designs/designs.component.ts +++ b/src/app/modules/smart-services/designs/designs.component.ts @@ -225,7 +225,7 @@ export class SmartServiceDesignsComponent implements OnInit, AfterViewInit, OnDe if (deleteProcess) { this.designsService.deleteDesign(design.id).subscribe((resp: { status: number }) => { if (resp.status === 200) { - this.repoItems.removeAt(this.repoItems.value.findIndex((item: ProcessModel) => design.id === item.id)); + this.repoItems.removeAt(this.repoItems.value.findIndex((item: ProcessModel) => design.id === item._id)); } else { this.showSnackBarError('deleting the design'); } diff --git a/src/app/modules/smart-services/releases/releases.component.ts b/src/app/modules/smart-services/releases/releases.component.ts index 68124b8f6..2f005a079 100644 --- a/src/app/modules/smart-services/releases/releases.component.ts +++ b/src/app/modules/smart-services/releases/releases.component.ts @@ -232,7 +232,7 @@ export class SmartServiceReleasesComponent implements OnInit, AfterViewInit, OnD if (deleteProcess) { this.releasesService.deleteRelease(release.id).subscribe((resp: { status: number }) => { if (resp.status === 200) { - this.repoItems.removeAt(this.repoItems.value.findIndex((item: ProcessModel) => release.id === item.id)); + this.repoItems.removeAt(this.repoItems.value.findIndex((item: ProcessModel) => release.id === item._id)); } else { this.showSnackBarError('deleting the release!'); } diff --git a/src/app/widgets/air-quality/dialog/air-quality-edit-dialog.component.ts b/src/app/widgets/air-quality/dialog/air-quality-edit-dialog.component.ts index 73a2f1b56..5783e49f7 100644 --- a/src/app/widgets/air-quality/dialog/air-quality-edit-dialog.component.ts +++ b/src/app/widgets/air-quality/dialog/air-quality-edit-dialog.component.ts @@ -618,7 +618,7 @@ export class AirQualityEditDialogComponent implements OnInit { } insideExportChanged(option: MeasurementModel) { - console.log(option) + // console.log(option) if (option.export === null || option.export === undefined) { return; } diff --git a/src/app/widgets/anomaly/anomaly.component.ts b/src/app/widgets/anomaly/anomaly.component.ts index 7e45660d2..6d61f8285 100644 --- a/src/app/widgets/anomaly/anomaly.component.ts +++ b/src/app/widgets/anomaly/anomaly.component.ts @@ -1,4 +1,14 @@ -import { AfterContentInit, AfterViewChecked, AfterViewInit, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { + AfterContentChecked, + AfterContentInit, + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit +} from '@angular/core'; import moment from 'moment'; import { Subscription, concatMap, Observable, map, of, throwError } from 'rxjs'; import { ElementSizeService } from 'src/app/core/services/element-size.service'; @@ -13,7 +23,7 @@ import { AnomalyService } from './shared/anomaly.service'; templateUrl: './anomaly.component.html', styleUrls: ['./anomaly.component.css'] }) -export class AnomalyComponent implements OnInit,OnDestroy, AfterViewChecked { +export class AnomalyComponent implements OnInit,OnDestroy, AfterContentChecked { ready = false; refreshing = false; destroy = new Subscription(); @@ -42,12 +52,12 @@ export class AnomalyComponent implements OnInit,OnDestroy, AfterViewChecked { private elementSizeService: ElementSizeService, ) {} - ngAfterViewChecked(): void { - const element = this.elementSizeService.getHeightAndWidthByElementId(this.widget?.id||""); + ngAfterContentChecked(): void { + const element = this.elementSizeService.getHeightAndWidthByElementId(this.widget?.id||''); this.widgetWidth = element.width; this.widgetHeight = element.height; } - + ngOnInit(): void { this.configured = this.widget.properties.anomalyDetection !== undefined; if(!this.configured) { @@ -75,114 +85,114 @@ export class AnomalyComponent implements OnInit,OnDestroy, AfterViewChecked { return { 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e6': [{ - 'value': '350', - 'type': 'curve', - 'subType': '', - 'timestamp': '2024-06-27T09:47:14.058Z', - 'start_time': curve3Start, - 'end_time': curve3End, - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [ - [new Date(curve3Start).getTime(), 260, 270], - [new Date(curve3End).getTime(), 250, 260], + value: '350', + type: 'curve', + subType: '', + timestamp: '2024-06-27T09:47:14.058Z', + start_time: curve3Start, + end_time: curve3End, + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [ + [new Date(curve3Start).getTime(), 260, 270], + [new Date(curve3End).getTime(), 250, 260], ] }, { - 'value': '0.7', - 'type': 'curve', - 'subType': '', - 'timestamp': '2024-06-27T09:47:14.058Z', - 'start_time': curve1Start, - 'end_time': curve1End, - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [ - [new Date(curve1Start).getTime(), 260, 270], - [new Date(curve1End).getTime(), 240, 250], + value: '0.7', + type: 'curve', + subType: '', + timestamp: '2024-06-27T09:47:14.058Z', + start_time: curve1Start, + end_time: curve1End, + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [ + [new Date(curve1Start).getTime(), 260, 270], + [new Date(curve1End).getTime(), 240, 250], ], }, ], 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5': [{ - 'value': '350', - 'type': 'extreme_value', - 'subType': '', - 'timestamp': extreme1, - 'start_time': '2024-06-27T12:30:14.058Z', - 'end_time': '2024-06-26T12:50:14.058Z', - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [], - 'upper_bound': 500, - 'lower_bound': 800 + value: '350', + type: 'extreme_value', + subType: '', + timestamp: extreme1, + start_time: '2024-06-27T12:30:14.058Z', + end_time: '2024-06-26T12:50:14.058Z', + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [], + upper_bound: 500, + lower_bound: 800 }, { - 'value': '0.8', - 'type': 'curve', - 'subType': '', - 'timestamp': '2024-06-27T09:47:14.058Z', - 'start_time': curve3Start, - 'end_time': curve3End, - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [ - [new Date(curve3Start).getTime(), 270, 280], - [new Date(curve3End).getTime(), 240, 250], + value: '0.8', + type: 'curve', + subType: '', + timestamp: '2024-06-27T09:47:14.058Z', + start_time: curve3Start, + end_time: curve3End, + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [ + [new Date(curve3Start).getTime(), 270, 280], + [new Date(curve3End).getTime(), 240, 250], ] }, { - 'value': '0.9', - 'type': 'curve', - 'subType': '', - 'timestamp': '2024-06-27T09:47:14.058Z', - 'start_time': curve1Start, - 'end_time': curve1End, - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [ - [new Date(curve1Start).getTime(), 240, 250], - [new Date(curve1End).getTime(), 240, 250], + value: '0.9', + type: 'curve', + subType: '', + timestamp: '2024-06-27T09:47:14.058Z', + start_time: curve1Start, + end_time: curve1End, + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [ + [new Date(curve1Start).getTime(), 240, 250], + [new Date(curve1End).getTime(), 240, 250], ], - + }, { - 'value': '0.8', - 'type': 'curve', - 'subType': '', - 'timestamp': '2024-06-27T09:47:14.058Z', - 'start_time': curve2Start, - 'end_time': curve2End, - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [ - [new Date(curve2Start).getTime(),240, 250], - [new Date(curve2End).getTime(), 240, 250], + value: '0.8', + type: 'curve', + subType: '', + timestamp: '2024-06-27T09:47:14.058Z', + start_time: curve2Start, + end_time: curve2End, + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [ + [new Date(curve2Start).getTime(),240, 250], + [new Date(curve2End).getTime(), 240, 250], ] }, { - 'value': '10', - 'type': 'freq', - 'subType': '', - 'timestamp': freq1, - 'start_time': '2024-06-27T13:30:14.058Z', - 'end_time': '2024-06-27T13:59:14.058Z', - 'threshold': 0, - 'mean': 0, - 'initial_phase': '', - 'device_id': 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', - 'original_reconstructed_curves': [] + value: '10', + type: 'freq', + subType: '', + timestamp: freq1, + start_time: '2024-06-27T13:30:14.058Z', + end_time: '2024-06-27T13:59:14.058Z', + threshold: 0, + mean: 0, + initial_phase: '', + device_id: 'urn:infai:ses:device:b06a0104-95ae-4d8d-8811-af4bcff455e5', + original_reconstructed_curves: [] }] }; } @@ -262,7 +272,7 @@ export class AnomalyComponent implements OnInit,OnDestroy, AfterViewChecked { this.refreshing = false; }, error: (err) => { - console.log(err) + console.log(err); this.error = true; this.ready = true; this.refreshing = false; diff --git a/src/app/widgets/anomaly/reconstruction/reconstruction.component.ts b/src/app/widgets/anomaly/reconstruction/reconstruction.component.ts index 561730a98..911e12018 100644 --- a/src/app/widgets/anomaly/reconstruction/reconstruction.component.ts +++ b/src/app/widgets/anomaly/reconstruction/reconstruction.component.ts @@ -65,7 +65,7 @@ export class AnomalyReconstructionComponent implements OnInit { valueList.sort((a: any,b: any) => new Date(b[0] as string).getTime() - new Date(a[0] as string).getTime()); - console.log(valueList) + // console.log(valueList) dataTable = dataTable.concat(valueList); diff --git a/src/app/widgets/anomaly/sub-widgets/line/line.component.ts b/src/app/widgets/anomaly/sub-widgets/line/line.component.ts index 8d5480827..22aaebed9 100644 --- a/src/app/widgets/anomaly/sub-widgets/line/line.component.ts +++ b/src/app/widgets/anomaly/sub-widgets/line/line.component.ts @@ -128,7 +128,7 @@ export class LineComponent implements OnInit, OnChanges { } this.valueChartData.chart.width = this.chartWidth; this.valueChartData.chart.height = this.chartHeight; - + this.cdr.detectChanges(); this.render = true; } @@ -181,7 +181,7 @@ export class LineComponent implements OnInit, OnChanges { } private combineCurveAnomalies(curveAnomalies: AnomalyResultModel[]) { - /* Curve Anomalies can overlap. The interval bounds and reconstructions need to be merged + /* Curve Anomalies can overlap. The interval bounds and reconstructions need to be merged Assumption: curveAnomalies is sorted by ascending occurence */ let anomalyIntervals: any[] = []; @@ -202,7 +202,7 @@ export class LineComponent implements OnInit, OnChanges { if(overlapFound) { break; } - console.log('last anomaly without overlap'); + // console.log('last anomaly without overlap'); point.x = new Date(currentAnomaly.start_time).getTime(); point.x2 = new Date(currentAnomaly.end_time).getTime(); @@ -213,14 +213,14 @@ export class LineComponent implements OnInit, OnChanges { const nextAnomaly = curveAnomalies[index+1]; if(new Date(nextAnomaly.start_time).getTime() < new Date(currentAnomaly.end_time).getTime()) { // Case: Overlap with the next anomaly - console.log('overlap'); + // console.log('overlap'); overlapFound = true; currentAnomaly.end_time = nextAnomaly.end_time; anomaliesWithOverlap.push(currentAnomaly); - startTimesOfFirstOverlaps.push(nextAnomaly.start_time) + startTimesOfFirstOverlaps.push(nextAnomaly.start_time); } else { // Case: No Overlap, Interval can be directly created from anomaly - console.log('no overlap'); + // console.log('no overlap'); point.x = new Date(currentAnomaly.start_time).getTime(); point.x2 = new Date(currentAnomaly.end_time).getTime(); anomalyIntervals.push(point); @@ -365,34 +365,32 @@ export class LineComponent implements OnInit, OnChanges { } const self = this; - chartData.tooltip.custom = function({series, seriesIndex, dataPointIndex, w}) { - console.log(w) + chartData.tooltip.custom = function({series, seriesIndex, dataPointIndex}) { + // console.log(w) const value = series[seriesIndex][dataPointIndex].toFixed(2); let tooltipMsg; switch(seriesIndex) { - case 0: - tooltipMsg = "Device Output: " + value; - break; - case 1: - const anomaly = self.extremeOutliers[dataPointIndex]; - tooltipMsg = "Extreme Outlier: " + anomaly.value + " [" + anomaly.lower_bound + "-" + anomaly.upper_bound + "]"; - break; - case 2: - tooltipMsg = 'Predicted Value: ' + value; - break; - case 3: - tooltipMsg = 'Preprocessed Value: ' + value; - break; - default: - tooltipMsg = value; + case 0: + tooltipMsg = 'Device Output: ' + value; + break; + case 1: + const anomaly = self.extremeOutliers[dataPointIndex]; + tooltipMsg = 'Extreme Outlier: ' + anomaly.value + ' [' + anomaly.lower_bound + '-' + anomaly.upper_bound + ']'; + break; + case 2: + tooltipMsg = 'Predicted Value: ' + value; + break; + case 3: + tooltipMsg = 'Preprocessed Value: ' + value; + break; + default: + tooltipMsg = value; } - + return '
' + '' + tooltipMsg + '' + '
'; }; - - console.log(chartData) return chartData; }) ); @@ -491,11 +489,11 @@ export class LineComponent implements OnInit, OnChanges { } private getChartPointsWithBounds(data: DeviceValue[]) { - Each device value point needs to get the bounds from the next anomaly. + Each device value point needs to get the bounds from the next anomaly. This is needed so that the interval band can be drawn. Note, this is can take some time if lots of data points are present e.g. when multiple days of data are displayed. E.g Anomaly at 10 with bounds [0,20] -> Device Value at 9 gets bounds [0,20] - + const dataTable: any[] = []; const anomalyStack: any[] = JSON.parse(JSON.stringify(this.anomalies?.[Object.keys(this.anomalies)[0]])); data.forEach(row => { diff --git a/src/app/widgets/anomaly/sub-widgets/timeline/anomaly-phases.component.ts b/src/app/widgets/anomaly/sub-widgets/timeline/anomaly-phases.component.ts index 3d88d9bcb..a44ebe403 100644 --- a/src/app/widgets/anomaly/sub-widgets/timeline/anomaly-phases.component.ts +++ b/src/app/widgets/anomaly/sub-widgets/timeline/anomaly-phases.component.ts @@ -59,7 +59,7 @@ export class AnomalyPhasesComponent implements OnInit, OnChanges { } ngOnInit(): void { - console.log(this.curveAnomaliesPerDevice) + // console.log(this.curveAnomaliesPerDevice) this.filterCurveAnomalies(); // data must be sorted by descending time for timeline chart @@ -109,8 +109,8 @@ export class AnomalyPhasesComponent implements OnInit, OnChanges { } // I have to use arrow function, so that `this` is accesible from within the timeline apex chart code - onClick = (_: any, chartContext: any, config: any) => { - console.log(chartContext, config); + onClick = (_: any, config: any) => { + // console.log(chartContext, config); const selection = config.w.config.series[config.seriesIndex].data[config.dataPointIndex]; const deviceID = selection['x']; const timestamp = selection['y']; diff --git a/src/app/widgets/charts/export/charts-export.component.html b/src/app/widgets/charts/export/charts-export.component.html index c8bf3f5f0..d4501cc5c 100644 --- a/src/app/widgets/charts/export/charts-export.component.html +++ b/src/app/widgets/charts/export/charts-export.component.html @@ -46,11 +46,11 @@
Please configure widget!
- + [showIf]="configureWidget === false && (chartExportData.dataTable === undefined || chartExportData.dataTable[0].length === 0)">
diff --git a/src/app/widgets/charts/export/charts-export.component.ts b/src/app/widgets/charts/export/charts-export.component.ts index c237cd285..26151af29 100644 --- a/src/app/widgets/charts/export/charts-export.component.ts +++ b/src/app/widgets/charts/export/charts-export.component.ts @@ -114,7 +114,9 @@ export class ChartsExportComponent implements OnInit, OnDestroy, AfterViewInit { this.resizeChart(); } this.setupZoomChartSettings(); - this.ready = true; + setTimeout(() => { + this.ready = true; + }); } } @@ -172,7 +174,7 @@ export class ChartsExportComponent implements OnInit, OnDestroy, AfterViewInit { this.chartsExportService.getData(this.widget.properties, this.from?.toISOString(), this.to?.toISOString(), this.groupTime || undefined, this.hAxisFormat || undefined).subscribe({ next: (data) => { - this.timelineChartData = data; + this.timelineChartData = data.data; this.ready = true; this.refreshing = false; }, @@ -276,16 +278,18 @@ export class ChartsExportComponent implements OnInit, OnDestroy, AfterViewInit { if (this.widget.properties.group?.type === undefined || this.widget.properties.group?.type === '') { return; //no aggregation --> no detail gained or lost after zoom } - const getCoords = (): { min: Date; max: Date } => { + const getCoords = (): { min: Date; max: Date } | undefined => { const chart = wrapper.getChart(); - const chartLayout = chart.getChartLayoutInterface(); - const chartBounds = chartLayout.getChartAreaBoundingBox(); - - const res = { - min: chartLayout.getHAxisValue(chartBounds.left), - max: chartLayout.getHAxisValue(chartBounds.width + chartBounds.left) - }; + let res; + if (chart && chart.hasOwnProperty('getChartLayoutInterface')) { + const chartLayout = chart.getChartLayoutInterface(); + const chartBounds = chartLayout.getChartAreaBoundingBox(); + res = { + min: chartLayout.getHAxisValue(chartBounds.left), + max: chartLayout.getHAxisValue(chartBounds.width + chartBounds.left) + }; + } return res; }; @@ -296,47 +300,50 @@ export class ChartsExportComponent implements OnInit, OnDestroy, AfterViewInit { const msInY = msInD * 365; const observer = new MutationObserver(() => { const zoomCurrent = getCoords(); - if (this.chartExportData.dataTable.length === 0) { - return; - } - if (!this.refreshing && this.zoomedAfterRefesh > 2) { - const diff = zoomCurrent.max.valueOf() - zoomCurrent.min.valueOf(); // diff in ms - let timeUnit = ''; - let hAxisFormat = ''; - if (diff < msInS) { - timeUnit = 'ms'; - hAxisFormat = 'ss.SSS'; - } else if (diff < 2 * msInM) { - timeUnit = 's'; - hAxisFormat = 'ss'; - } else if (diff < 2 * msInH) { - timeUnit = 'm'; - hAxisFormat = 'mm'; - } else if (diff < 2 * msInD) { - timeUnit = 'h'; - hAxisFormat = 'HH'; - } else if (diff < 45 * msInD) { - timeUnit = 'd'; - hAxisFormat = 'dd'; - } else if (diff < msInY) { - timeUnit = 'months'; - hAxisFormat = 'MMM'; - } else { // use years - timeUnit = 'y'; - hAxisFormat = 'yyyy'; + if (zoomCurrent !== undefined) { + if (this.chartExportData.dataTable.length === 0) { + return; } - const groupTime = '1' + timeUnit; - if (this.detailLevel(groupTime) > this.detailLevel(this.groupTime)) { - this.ready = false; - this.groupTime = groupTime; - this.hAxisFormat = hAxisFormat; - this.to = zoomCurrent.max; - this.from = zoomCurrent.min; - this.refresh(); + if (!this.refreshing && this.zoomedAfterRefesh > 2) { + const diff = zoomCurrent.max.valueOf() - zoomCurrent.min.valueOf(); // diff in ms + console.log(diff); + let timeUnit = ''; + let hAxisFormat = ''; + if (diff < msInS) { + timeUnit = 'ms'; + hAxisFormat = 'ss.SSS'; + } else if (diff < 2 * msInM) { + timeUnit = 's'; + hAxisFormat = 'ss'; + } else if (diff < 2 * msInH) { + timeUnit = 'm'; + hAxisFormat = 'mm'; + } else if (diff < 2 * msInD) { + timeUnit = 'h'; + hAxisFormat = 'HH'; + } else if (diff < 45 * msInD) { + timeUnit = 'd'; + hAxisFormat = 'dd'; + } else if (diff < msInY) { + timeUnit = 'months'; + hAxisFormat = 'MMM'; + } else { // use years + timeUnit = 'y'; + hAxisFormat = 'yyyy'; + } + const groupTime = '1' + timeUnit; + if (this.detailLevel(groupTime) > this.detailLevel(this.groupTime)) { + this.ready = false; + this.groupTime = groupTime; + this.hAxisFormat = hAxisFormat; + this.to = zoomCurrent.max; + this.from = zoomCurrent.min; + this.refresh(); + } + } + if (!this.refreshing) { + this.zoomedAfterRefesh++; } - } - if (!this.refreshing) { - this.zoomedAfterRefesh++; } }); observer.observe(htmlElem, { diff --git a/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.html b/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.html index a19678141..022ed8f20 100644 --- a/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.html +++ b/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.html @@ -75,7 +75,6 @@

Configure Chart

X-Axis - diff --git a/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.ts b/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.ts index b99c57fc7..dd30f434c 100644 --- a/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.ts +++ b/src/app/widgets/charts/export/dialog/charts-export-edit-dialog.component.ts @@ -33,11 +33,10 @@ import {MatTableDataSource} from '@angular/material/table'; import {MAT_DIALOG_DATA, MatDialogRef, MatDialog} from '@angular/material/dialog'; import {forkJoin, Observable, of} from 'rxjs'; import {map} from 'rxjs/operators'; -import {DeviceTypeFunctionModel} from '../../../../modules/metadata/device-types-overview/shared/device-type.model'; +import {DeviceTypeDeviceClassModel, DeviceTypeFunctionModel} from '../../../../modules/metadata/device-types-overview/shared/device-type.model'; import {environment} from '../../../../../environments/environment'; import { DeviceGroupCriteriaModel, DeviceGroupModel } from 'src/app/modules/devices/device-groups/shared/device-groups.model'; import { AspectsPermSearchModel } from 'src/app/modules/metadata/aspects/shared/aspects-perm-search.model'; -import { DeviceClassesPermSearchModel } from 'src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model'; import { ConceptsCharacteristicsModel } from 'src/app/modules/metadata/concepts/shared/concepts-characteristics.model'; import { ListRulesComponent } from './list-rules/list-rules.component'; import { DataSourceConfig } from '../../shared/data-source-selector/data-source-selector.component'; @@ -91,7 +90,7 @@ export class ChartsExportEditDialogComponent implements OnInit { deviceGroups: DeviceGroupModel[] = []; aspects: AspectsPermSearchModel[] = []; functions: DeviceTypeFunctionModel[] = []; - deviceClasses: DeviceClassesPermSearchModel[] = []; + deviceClasses: DeviceTypeDeviceClassModel[] = []; concepts: Map = new Map(); constructor( @@ -170,7 +169,7 @@ export class ChartsExportEditDialogComponent implements OnInit { this.formGroupController.get('properties.exports')?.patchValue(updatedDataSourceConfig.exports); this.formGroupController.get('properties.timeRangeType')?.patchValue(updatedDataSourceConfig.timeRange?.type); const timeRangeType = updatedDataSourceConfig.timeRange?.type; - const timeRangeLevel = updatedDataSourceConfig.timeRange?.level || ""; + const timeRangeLevel = updatedDataSourceConfig.timeRange?.level || ''; if(timeRangeType === ChartsExportRangeTimeTypeEnum.Absolute) { const start = updatedDataSourceConfig.timeRange?.start; diff --git a/src/app/widgets/charts/export/shared/charts-export.model.ts b/src/app/widgets/charts/export/shared/charts-export.model.ts deleted file mode 100644 index 778d2477c..000000000 --- a/src/app/widgets/charts/export/shared/charts-export.model.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 InfAI (CC SES) - * - * 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 ChartsExportModel { - results: ChartsExportSeriesModel[]; -} - -export interface ChartsExportSeriesModel { - series: ChartsExportColumnsModel[]; - statement_id: number; -} - -export interface ChartsExportColumnsModel { - columns: string[]; - name: string; - values: (string | number | boolean)[][]; -} diff --git a/src/app/widgets/charts/open-window/dialog/edit/edit.component.ts b/src/app/widgets/charts/open-window/dialog/edit/edit.component.ts index 77a7ca359..aafde6372 100644 --- a/src/app/widgets/charts/open-window/dialog/edit/edit.component.ts +++ b/src/app/widgets/charts/open-window/dialog/edit/edit.component.ts @@ -203,7 +203,7 @@ export class OpenWindowEditComponent implements OnInit { } }); this.vAxesDataSource.data = this.vAxesDataSource.data; - console.log(this.vAxesDataSource) + // console.log(this.vAxesDataSource) } listRules(element: ChartsExportVAxesModel) { diff --git a/src/app/widgets/charts/open-window/open-window.component.ts b/src/app/widgets/charts/open-window/open-window.component.ts index 3baee315d..968f1de14 100644 --- a/src/app/widgets/charts/open-window/open-window.component.ts +++ b/src/app/widgets/charts/open-window/open-window.component.ts @@ -204,7 +204,6 @@ export class OpenWindowComponent implements OnInit { return this.exportDataService.queryTimescaleV2(timescaleElements).pipe( concatMap((resp: any) => { - console.log(resp) if (this.errorHandlerService.checkIfErrorExists(resp)) { this.errorHandlerService.logError('OpenWindow', 'getTimelineData', resp); return throwError(() => resp.error); diff --git a/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.html b/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.html index 3752b0300..2ea347223 100644 --- a/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.html +++ b/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.html @@ -2,14 +2,23 @@
-

Choose a {{dataSourcePlaceholder}}

- - {{dataSourcePlaceholder}} +

Choose a Data Source

+ + Data Source Class + + + {{entity}} + + + + + + {{getLabelFromCurrentDataSource()}} + (selectionChange)="dataSourceChanged($event.value)" [options]="currentDataSourceOptions" + [getOptionViewValue]="getDataSourceName"> - +
diff --git a/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.ts b/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.ts index 60f794bc4..6f2e5385a 100644 --- a/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.ts +++ b/src/app/widgets/charts/shared/data-source-selector/data-source-selector.component.ts @@ -1,14 +1,12 @@ -import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; +import {ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import { AbstractControl, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; -import { catchError, concatMap, defaultIfEmpty, EMPTY, forkJoin, map, mergeMap, Observable, of, Subject, throwError } from 'rxjs'; +import { catchError, concatMap, defaultIfEmpty, forkJoin, map, mergeMap, Observable, of, throwError } from 'rxjs'; import { DeviceGroupCriteriaModel, DeviceGroupModel } from 'src/app/modules/devices/device-groups/shared/device-groups.model'; import { DeviceInstanceModel } from 'src/app/modules/devices/device-instances/shared/device-instances.model'; import { ExportModel, ExportResponseModel, ExportValueModel } from 'src/app/modules/exports/shared/export.model'; -import { AspectsPermSearchModel } from 'src/app/modules/metadata/aspects/shared/aspects-perm-search.model'; import { ConceptsCharacteristicsModel } from 'src/app/modules/metadata/concepts/shared/concepts-characteristics.model'; import { ConceptsService } from 'src/app/modules/metadata/concepts/shared/concepts.service'; -import { DeviceClassesPermSearchModel } from 'src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model'; -import { DeviceTypeContentVariableModel, DeviceTypeModel } from 'src/app/modules/metadata/device-types-overview/shared/device-type.model'; +import { DeviceTypeAspectModel, DeviceTypeContentVariableModel, DeviceTypeDeviceClassModel, DeviceTypeFunctionModel, DeviceTypeModel } from 'src/app/modules/metadata/device-types-overview/shared/device-type.model'; import { DeviceTypeService } from 'src/app/modules/metadata/device-types-overview/shared/device-type.service'; import { ChartsExportMeasurementModel, ChartsExportVAxesModel } from '../../export/shared/charts-export-properties.model'; import { environment } from 'src/environments/environment'; @@ -19,7 +17,6 @@ import { DeviceGroupsService } from 'src/app/modules/devices/device-groups/share import { LocationModel } from 'src/app/modules/devices/locations/shared/locations.model'; import { LocationsService } from 'src/app/modules/devices/locations/shared/locations.service'; import { FunctionsService } from 'src/app/modules/metadata/functions/shared/functions.service'; -import { FunctionsPermSearchModel } from 'src/app/modules/metadata/functions/shared/functions-perm-search.model'; export interface DataSourceConfig { exports?: (ChartsExportMeasurementModel | DeviceInstanceModel | DeviceGroupModel | LocationModel)[]; @@ -40,24 +37,26 @@ export interface DataSourceConfig { }; @Component({ - selector: 'data-source-selector', - templateUrl: './data-source-selector.component.html', - styleUrls: ['./data-source-selector.component.css'] + selector: 'data-source-selector', + templateUrl: './data-source-selector.component.html', + styleUrls: ['./data-source-selector.component.css'] }) export class DataSourceSelectorComponent implements OnInit { form: any; deviceTypes: Map = new Map(); deviceGroups: DeviceGroupModel[] = []; - aspects: AspectsPermSearchModel[] = []; - functions: FunctionsPermSearchModel[] = []; - deviceClasses: DeviceClassesPermSearchModel[] = []; + aspects: DeviceTypeAspectModel[] = []; + functions: DeviceTypeFunctionModel[] = []; + deviceClasses: DeviceTypeDeviceClassModel[] = []; concepts: Map = new Map(); fieldOptionsTMP: Map = new Map(); timeRangeEnum = ChartsExportRangeTimeTypeEnum; timeRangeTypes = [this.timeRangeEnum.Relative, this.timeRangeEnum.RelativeAhead, this.timeRangeEnum.Absolute]; dataSourceOptions: Map = new Map(); + currentDataSourceOptions: ChartsExportMeasurementModel[] | DeviceInstanceModel[] | DeviceGroupModel[] = []; + currentDataSourceClass = ''; ready = false; waitingForDataSourceChange = false; exportList: ChartsExportMeasurementModel[] = []; @@ -108,9 +107,9 @@ export class DataSourceSelectorComponent implements OnInit { @Input() showTimeRange = true; @Input() showSource = true; @Output() updatedDataSourceConfig = new EventEmitter(); - dataSourcePlaceholder = ''; constructor( + private cdref: ChangeDetectorRef, private deviceTypeService: DeviceTypeService, private conceptsService: ConceptsService, private exportService: ExportService, @@ -121,8 +120,6 @@ export class DataSourceSelectorComponent implements OnInit { ) {} ngOnInit(): void { - console.log(this.dataSourceConfig) - this.setDataSourcePlaceholder(); this.setupDataSources().pipe( concatMap((_) => this.loadFieldOptions(this.dataSourceConfig?.exports || [])), map((fieldOptions) => { @@ -131,7 +128,9 @@ export class DataSourceSelectorComponent implements OnInit { this.form.get('fieldOptions').patchValue(fieldOptions); this.setupOutput(); this.setupGroupTypes(); - console.log(this.form) + this.form.controls['dataSourceClass'].valueChanges.subscribe((val: string) => { + this.updateCurrentDataSourceOptions(val); + }); }) ).subscribe({ next: (_) => { @@ -139,44 +138,18 @@ export class DataSourceSelectorComponent implements OnInit { this.waitingForDataSourceChange = false; }, error: (err) => { - console.log("Could not init: " + err); + console.log('Could not init: ' + err); this.ready = true; this.waitingForDataSourceChange = false; } }); } - setDataSourcePlaceholder() { - let seperatorNeeded = false; - if(this.showDevicesAsSource) { - this.dataSourcePlaceholder += 'Device'; - seperatorNeeded = true; - } - if(this.showDeviceGroupsAsSource) { - if(seperatorNeeded) { - this.dataSourcePlaceholder += '/'; - } - this.dataSourcePlaceholder += 'Device Group'; - } - - if(this.showExportsAsSource) { - if(seperatorNeeded) { - this.dataSourcePlaceholder += '/'; - } - this.dataSourcePlaceholder += 'Export'; - } - - if(this.showLocationsAsSource) { - if(seperatorNeeded) { - this.dataSourcePlaceholder += '/'; - } - this.dataSourcePlaceholder += 'Location'; - } - } initForm() { this.form = new FormGroup({ - exports: new FormControl(this.dataSourceConfig?.exports || []), + dataSourceClass: new FormControl(this.getDataSourceClassFromExports(this.dataSourceConfig?.exports) || '', Validators.required), + exports: new FormControl(this.dataSourceConfig?.exports || [], Validators.required), timeRange: new FormGroup({ type: new FormControl(this.dataSourceConfig?.timeRange?.type || '', Validators.required), start: new FormControl(this.dataSourceConfig?.timeRange?.start || ''), @@ -192,6 +165,9 @@ export class DataSourceSelectorComponent implements OnInit { fields: new FormControl(this.dataSourceConfig?.fields || []), fieldOptions: new FormControl([]) }); + setTimeout(() => { + this.currentDataSourceOptions = this.getDataSourceOptions(this.getDataSourceClassFromExports(this.dataSourceConfig?.exports)||''); + }, 0); } setupOutput() { @@ -463,7 +439,7 @@ export class DataSourceSelectorComponent implements OnInit { } }), catchError(err => { - console.log("could not get exports"); + console.log('could not get exports'); console.log(err); return throwError(() => err); }) @@ -476,7 +452,7 @@ export class DataSourceSelectorComponent implements OnInit { this.dataSourceOptions.set('Devices', devices.result); }), catchError(err => { - console.log("could not get devices"); + console.log('could not get devices'); console.log(err); return throwError(() => err); }) @@ -515,7 +491,7 @@ export class DataSourceSelectorComponent implements OnInit { return forkJoin(innerObs); }), catchError(err => { - console.log("could not get device group"); + console.log('could not get device group'); console.log(err); return throwError(() => err); }) @@ -541,7 +517,7 @@ export class DataSourceSelectorComponent implements OnInit { if(this.showLocationsAsSource) { obs.push(this.getLocations()); } - obs.push(this.functionsService.getFunctions('', 9999, 0, 'name', 'asc').pipe(map(functions => this.functions = functions))) + obs.push(this.functionsService.getFunctions('', 9999, 0, 'name', 'asc').pipe(map(functions => this.functions = functions.result))); if(obs.length === 0) { obs.push(of(true)); } @@ -572,7 +548,7 @@ export class DataSourceSelectorComponent implements OnInit { } filterSelectedFields(selectedDataSources: (ChartsExportMeasurementModel | DeviceInstanceModel | DeviceGroupModel)[]) { - /* Filter the selected fields depending on the current selection of the data source + /* Filter the selected fields depending on the current selection of the data source */ const selectedFields = JSON.parse(JSON.stringify(this.form.value['fields'])); const filteredFields: ChartsExportVAxesModel[] = []; @@ -611,7 +587,7 @@ export class DataSourceSelectorComponent implements OnInit { observables = observables.concat(this.updateDeviceFields(selectedElement as DeviceInstanceModel)); } }); - + return forkJoin(observables).pipe( defaultIfEmpty([]), // in case observables is empty @@ -625,7 +601,7 @@ export class DataSourceSelectorComponent implements OnInit { return options; }), catchError(err => { - console.log("could not load field options"); + console.log('could not load field options'); console.log(err); return throwError(() => err); }) @@ -743,7 +719,7 @@ export class DataSourceSelectorComponent implements OnInit { a.valueName === b.valueName); const deviceMatch = (a.deviceId != null && b.deviceId != null && a.deviceId === b.deviceId && - a.serviceId === b.serviceId && + a.serviceId === b.serviceId && a.valuePath === b.valuePath); const deviceGroupMatch = (a.deviceGroupId != null && b.deviceGroupId != null && a.deviceGroupId === b.deviceGroupId && @@ -757,4 +733,68 @@ export class DataSourceSelectorComponent implements OnInit { getDataSourceName(x: any): string { return x.display_name || x.name; } + + getSortedDataSourceClasses(): string[] { + let classes: string[] = []; + Array.from(this.dataSourceOptions.keys()).forEach(cl => { + const exports: any = this.dataSourceOptions.get(cl as string); + if (exports.length>0) { + classes.push(cl as string); + } + }); + classes = classes.sort(); + return classes; + } + + getDataSourceOptions(entity: string): ChartsExportMeasurementModel[] | DeviceInstanceModel[] | DeviceGroupModel[] | [] { + const val = this.dataSourceOptions.get(entity); + if (val !== undefined) { + return val; + } else { + return []; + } + } + + updateCurrentDataSourceOptions(dataSourceClass: string) { + if (dataSourceClass!== this.currentDataSourceClass) { + this.form.controls['exports'].reset([]); + } + this.currentDataSourceClass = dataSourceClass; + this.currentDataSourceOptions = this.getDataSourceOptions(dataSourceClass); + this.cdref.detectChanges(); + } + + getLabelFromCurrentDataSource(){ + const val = this.form.controls['dataSourceClass'].value; + const dataSourceSingular: Map = new Map([ + ['Device Groups', 'Device Group'], + ['Devices', 'Device'], + ['Exports', 'Export'], + ['Locations', 'Location'], + ]); + return dataSourceSingular.get(val) as string; + } + + getDataSourceClassFromExports(exports: (ChartsExportMeasurementModel | DeviceInstanceModel | DeviceGroupModel)[] | undefined){ + if (!exports){ + return null; + } + const searchItem = exports[0]; + for (const [key, values] of this.dataSourceOptions.entries()) { + if (this.getExportIDs(values).includes(searchItem.id)) { + return key; + } + } + return null; + } + + getExportIDs(exportValues: (ChartsExportMeasurementModel | DeviceInstanceModel | DeviceGroupModel) []){ + const ids: string[] = []; + exportValues.forEach(item => { + if ('id' in item) { + ids.push((item as any).id); + } + }); + return ids; + } } diff --git a/src/app/widgets/data-table/dialog/data-table-edit-dialog.component.ts b/src/app/widgets/data-table/dialog/data-table-edit-dialog.component.ts index dd73aa497..dc514096f 100644 --- a/src/app/widgets/data-table/dialog/data-table-edit-dialog.component.ts +++ b/src/app/widgets/data-table/dialog/data-table-edit-dialog.component.ts @@ -36,7 +36,9 @@ import { ExportValueTypes } from '../shared/data-table.model'; import { + DeviceTypeAspectModel, DeviceTypeCharacteristicsModel, + DeviceTypeDeviceClassModel, DeviceTypeFunctionModel, DeviceTypeInteractionEnum, DeviceTypeServiceModel, @@ -55,15 +57,11 @@ import { util } from 'jointjs'; import { environment } from '../../../../environments/environment'; import uuid = util.uuid; import { DashboardResponseMessageModel } from 'src/app/modules/dashboard/shared/dashboard-response-message.model'; -import { AspectsPermSearchModel } from 'src/app/modules/metadata/aspects/shared/aspects-perm-search.model'; -import { DeviceClassesPermSearchModel } from 'src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model'; import { ConceptsCharacteristicsModel } from 'src/app/modules/metadata/concepts/shared/concepts-characteristics.model'; import { DeviceGroupCriteriaModel, DeviceGroupModel } from 'src/app/modules/devices/device-groups/shared/device-groups.model'; import { DeviceGroupsService } from 'src/app/modules/devices/device-groups/shared/device-groups.service'; import { ConceptsService } from 'src/app/modules/metadata/concepts/shared/concepts.service'; import { SingleValueAggregations } from '../../single-value/shared/single-value.model'; -import { ConceptsNewDialogComponent } from 'src/app/modules/metadata/concepts/dialogs/concepts-new-dialog.component'; -import {required} from "yargs"; @Component({ templateUrl: './data-table-edit-dialog.component.html', @@ -128,10 +126,10 @@ export class DataTableEditDialogComponent implements OnInit { }); userHasUpdateNameAuthorization = false; userHasUpdatePropertiesAuthorization = false; - aspects: AspectsPermSearchModel[] = []; + aspects: DeviceTypeAspectModel[] = []; functions: DeviceTypeFunctionModel[] = []; - deviceClasses: DeviceClassesPermSearchModel[] = []; - concepts: Map = new Map(); + deviceClasses: DeviceTypeDeviceClassModel[] = []; + concepts: Map = new Map(); deviceGroups: DeviceGroupModel[] = []; aggregations = Object.values(SingleValueAggregations); diff --git a/src/app/widgets/data-table/shared/data-table-helper.service.ts b/src/app/widgets/data-table/shared/data-table-helper.service.ts index bb138e1b7..1299c3cc7 100644 --- a/src/app/widgets/data-table/shared/data-table-helper.service.ts +++ b/src/app/widgets/data-table/shared/data-table-helper.service.ts @@ -40,10 +40,7 @@ import {ExportValueTypes} from './data-table.model'; import {ImportInstancesService} from '../../../modules/imports/import-instances/shared/import-instances.service'; import {ImportTypesService} from '../../../modules/imports/import-types/shared/import-types.service'; import {ImportInstancesModel} from '../../../modules/imports/import-instances/shared/import-instances.model'; -import { - ImportTypeModel, - ImportTypePermissionSearchModel -} from '../../../modules/imports/import-types/shared/import-types.model'; +import {ImportTypeModel} from '../../../modules/imports/import-types/shared/import-types.model'; @Injectable({ providedIn: 'root', @@ -59,7 +56,7 @@ export class DataTableHelperService { operatorCache = new Map(); serviceExportValueCache = new Map(); importInstances: ImportInstancesModel[] = []; - importTypes: ImportTypePermissionSearchModel[] = []; + importTypes: ImportTypeModel[] = []; fullImportTypes = new Map(); importTypeValues = new Map(); @@ -304,16 +301,16 @@ export class DataTableHelperService { ); } - preloadImportTypes(): Observable { + preloadImportTypes(): Observable { return this.importTypesService.listImportTypes('', undefined, undefined, 'name.asc').pipe( map((types) => { - this.importTypes = types; - return types; + this.importTypes = types.result; + return types.result; }), ); } - getImportTypes(): ImportTypePermissionSearchModel[] { + getImportTypes(): ImportTypeModel[] { return this.importTypes; } diff --git a/src/app/widgets/leakage-detection/dialog/edit/edit.component.ts b/src/app/widgets/leakage-detection/dialog/edit/edit.component.ts index 08fcd023e..a4fcfcf27 100644 --- a/src/app/widgets/leakage-detection/dialog/edit/edit.component.ts +++ b/src/app/widgets/leakage-detection/dialog/edit/edit.component.ts @@ -54,7 +54,7 @@ export class LeakageDetectionEditComponent implements OnInit { this.exportService.getAvailableExports().pipe( concatMap((exports) => { this.exports = exports; - console.log(exports) + // console.log(exports) return this.getWidgetData(); }) ).subscribe({ @@ -95,7 +95,7 @@ export class LeakageDetectionEditComponent implements OnInit { } }; - console.log(leakageDetection) + // console.log(leakageDetection) return this.dashboardService.updateWidgetProperty(this.dashboardId, this.widget.id, [], leakageDetection); } diff --git a/src/app/widgets/process-model-list/shared/process-model-list.service.ts b/src/app/widgets/process-model-list/shared/process-model-list.service.ts index 17601c1ad..839cd33d9 100644 --- a/src/app/widgets/process-model-list/shared/process-model-list.service.ts +++ b/src/app/widgets/process-model-list/shared/process-model-list.service.ts @@ -50,8 +50,8 @@ export class ProcessModelListService { getProcesses(): Observable { return new Observable((observer) => { - this.processRepoService.getProcessModels('', 10, 0, 'date', 'desc', null).subscribe((processes: ProcessModel[]) => { - observer.next(this.prettifyProcessData(processes)); + this.processRepoService.getProcessModels('', 10, 0, 'date', 'desc').subscribe(processes => { + observer.next(this.prettifyProcessData(processes.result)); observer.complete(); }); }); @@ -61,7 +61,7 @@ export class ProcessModelListService { const processesArray: ProcessModelListModel[] = []; if (processes !== null) { processes.forEach((process) => { - processesArray.push(new ProcessModelListModel(process.name, process.id, new Date(process.date))); + processesArray.push(new ProcessModelListModel(process.name, process._id, new Date(process.date))); }); } return processesArray; diff --git a/src/app/widgets/process-state/shared/process-state.service.ts b/src/app/widgets/process-state/shared/process-state.service.ts index 659f939ea..9cb9e8e09 100644 --- a/src/app/widgets/process-state/shared/process-state.service.ts +++ b/src/app/widgets/process-state/shared/process-state.service.ts @@ -22,7 +22,7 @@ import { ProcessStateEditDialogComponent } from '../dialog/process-state-edit-di import { WidgetModel } from '../../../modules/dashboard/shared/dashboard-widget.model'; import { DashboardManipulationEnum } from '../../../modules/dashboard/shared/dashboard-manipulation.enum'; import { DeploymentsService } from '../../../modules/processes/deployments/shared/deployments.service'; -import { catchError } from 'rxjs/operators'; +import { catchError, map } from 'rxjs/operators'; import { ErrorHandlerService } from '../../../core/services/error-handler.service'; import { ProcessRepoService } from '../../../modules/processes/process-repo/shared/process-repo.service'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; @@ -76,7 +76,7 @@ export class ProcessStateService { private getRawData(): Observable { const array: Observable[] = []; - array.push(this.processRepoService.list('processmodel', 'r')); + array.push(this.processRepoService.getProcessModels('', 9999, 0, 'name', 'asc').pipe(map(x => x.result))); array.push(this.deploymentService.getAll('', 99999, 0, 'deploymentTime', 'desc', '')); return forkJoin(array).pipe(catchError(this.errorHandlerService.handleError(ProcessStateService.name, 'getRawData', []))); diff --git a/src/app/widgets/single-value/dialog/single-value-edit-dialog.component.ts b/src/app/widgets/single-value/dialog/single-value-edit-dialog.component.ts index f2d34ac81..0514bf38e 100644 --- a/src/app/widgets/single-value/dialog/single-value-edit-dialog.component.ts +++ b/src/app/widgets/single-value/dialog/single-value-edit-dialog.component.ts @@ -15,7 +15,7 @@ */ import { Component, Inject, OnInit } from '@angular/core'; -import {Form, FormControl, FormGroup, UntypedFormBuilder, Validators} from '@angular/forms'; +import {FormControl, FormGroup, UntypedFormBuilder, Validators} from '@angular/forms'; import { WidgetModel } from '../../../modules/dashboard/shared/dashboard-widget.model'; import { ChartsExportMeasurementModel } from '../../charts/export/shared/charts-export-properties.model'; import { DeploymentsService } from '../../../modules/processes/deployments/shared/deployments.service'; @@ -25,15 +25,13 @@ import { ExportService } from '../../../modules/exports/shared/export.service'; import { DashboardResponseMessageModel } from '../../../modules/dashboard/shared/dashboard-response-message.model'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DeviceInstanceModel } from '../../../modules/devices/device-instances/shared/device-instances.model'; -import { DeviceTypeCharacteristicsModel, DeviceTypeFunctionModel, DeviceTypeServiceModel } from '../../../modules/metadata/device-types-overview/shared/device-type.model'; +import { DeviceTypeAspectModel, DeviceTypeCharacteristicsModel, DeviceTypeDeviceClassModel, DeviceTypeFunctionModel, DeviceTypeServiceModel } from '../../../modules/metadata/device-types-overview/shared/device-type.model'; import { DeviceTypeService } from '../../../modules/metadata/device-types-overview/shared/device-type.service'; import { DeviceInstancesService } from '../../../modules/devices/device-instances/shared/device-instances.service'; import { ChartsExportRequestPayloadGroupModel } from '../../charts/export/shared/charts-export-request-payload.model'; import { concatMap, forkJoin, map, mergeMap, Observable, of } from 'rxjs'; import { DeviceGroupsService } from 'src/app/modules/devices/device-groups/shared/device-groups.service'; -import { DeviceGroupCriteriaModel, DeviceGroupHelperResultModel, DeviceGroupModel } from 'src/app/modules/devices/device-groups/shared/device-groups.model'; -import { AspectsPermSearchModel } from 'src/app/modules/metadata/aspects/shared/aspects-perm-search.model'; -import { DeviceClassesPermSearchModel } from 'src/app/modules/metadata/device-classes/shared/device-classes-perm-search.model'; +import { DeviceGroupCriteriaModel, DeviceGroupModel } from 'src/app/modules/devices/device-groups/shared/device-groups.model'; import { ConceptsCharacteristicsModel } from 'src/app/modules/metadata/concepts/shared/concepts-characteristics.model'; import { ConceptsService } from 'src/app/modules/metadata/concepts/shared/concepts.service'; import { SingleValueAggregations, ValueHighlightConfig } from '../shared/single-value.model'; @@ -76,9 +74,9 @@ export class SingleValueEditDialogComponent implements OnInit { deviceGroups: DeviceGroupModel[] = []; services: DeviceTypeServiceModel[] = []; paths: { Name: string }[] = []; - aspects: AspectsPermSearchModel[] = []; + aspects: DeviceTypeAspectModel[] = []; functions: DeviceTypeFunctionModel[] = []; - deviceClasses: DeviceClassesPermSearchModel[] = []; + deviceClasses: DeviceTypeDeviceClassModel[] = []; concept?: ConceptsCharacteristicsModel | null; form: FormGroup = new FormGroup({}); diff --git a/src/app/widgets/single-value/shared/single-value.service.ts b/src/app/widgets/single-value/shared/single-value.service.ts index b38602b61..b04a6dd0d 100644 --- a/src/app/widgets/single-value/shared/single-value.service.ts +++ b/src/app/widgets/single-value/shared/single-value.service.ts @@ -98,6 +98,7 @@ export class SingleValueService { criteria: widget.properties.deviceGroupCriteria, targetCharacteristicId: widget.properties.targetCharacteristic, },], + orderColumnIndex: 0, }]; if (date !== undefined) { requestPayload[0].time = { @@ -139,6 +140,7 @@ export class SingleValueService { // eslint-disable-next-line requestPayload[1].time!.end = '2099-01-01T00:00:00Z'; requestPayload[1].orderDirection = 'asc'; + requestPayload[1].orderColumnIndex = 0; }; diff --git a/src/assets/icons/icon-128x128.png b/src/assets/icons/icon-128x128.png index cd27101a8..e26da0d58 100644 Binary files a/src/assets/icons/icon-128x128.png and b/src/assets/icons/icon-128x128.png differ diff --git a/src/assets/icons/icon-144x144.png b/src/assets/icons/icon-144x144.png index c1f733c86..e26da0d58 100644 Binary files a/src/assets/icons/icon-144x144.png and b/src/assets/icons/icon-144x144.png differ diff --git a/src/assets/icons/icon-152x152.png b/src/assets/icons/icon-152x152.png index 65139a82b..e26da0d58 100644 Binary files a/src/assets/icons/icon-152x152.png and b/src/assets/icons/icon-152x152.png differ diff --git a/src/assets/icons/icon-192x192.png b/src/assets/icons/icon-192x192.png index d79608b07..e26da0d58 100644 Binary files a/src/assets/icons/icon-192x192.png and b/src/assets/icons/icon-192x192.png differ diff --git a/src/assets/icons/icon-384x384.png b/src/assets/icons/icon-384x384.png index 6937a70a4..e26da0d58 100644 Binary files a/src/assets/icons/icon-384x384.png and b/src/assets/icons/icon-384x384.png differ diff --git a/src/assets/icons/icon-512x512.png b/src/assets/icons/icon-512x512.png index 7a6d0c9a0..e26da0d58 100644 Binary files a/src/assets/icons/icon-512x512.png and b/src/assets/icons/icon-512x512.png differ diff --git a/src/assets/icons/icon-72x72.png b/src/assets/icons/icon-72x72.png index 871037a77..e26da0d58 100644 Binary files a/src/assets/icons/icon-72x72.png and b/src/assets/icons/icon-72x72.png differ diff --git a/src/assets/icons/icon-96x96.png b/src/assets/icons/icon-96x96.png index 5d44ec785..e26da0d58 100644 Binary files a/src/assets/icons/icon-96x96.png and b/src/assets/icons/icon-96x96.png differ diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 5c5ff499c..2815e5d73 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -50,7 +50,6 @@ export const environment = { flowRepoUrl: 'http://localhost', flowEngineUrl: 'http://localhost', flowParserUrl: 'http://localhost', - permissionSearchUrl: 'http://localhost', //TODO permissionCommandUrl: 'http://localhost', apiAggregatorUrl: 'http://localhost', iotRepoUrl: 'http://localhost', diff --git a/src/img/indigo/android-icon-128x128.png b/src/img/indigo/android-icon-128x128.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-128x128.png differ diff --git a/src/img/indigo/android-icon-144x144.png b/src/img/indigo/android-icon-144x144.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-144x144.png differ diff --git a/src/img/indigo/android-icon-152x152.png b/src/img/indigo/android-icon-152x152.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-152x152.png differ diff --git a/src/img/indigo/android-icon-192x192.png b/src/img/indigo/android-icon-192x192.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-192x192.png differ diff --git a/src/img/indigo/android-icon-384x384.png b/src/img/indigo/android-icon-384x384.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-384x384.png differ diff --git a/src/img/indigo/android-icon-512x512.png b/src/img/indigo/android-icon-512x512.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-512x512.png differ diff --git a/src/img/indigo/android-icon-72x72.png b/src/img/indigo/android-icon-72x72.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-72x72.png differ diff --git a/src/img/indigo/android-icon-96x96.png b/src/img/indigo/android-icon-96x96.png new file mode 100644 index 000000000..e26da0d58 Binary files /dev/null and b/src/img/indigo/android-icon-96x96.png differ diff --git a/src/img/indigo/favicon.ico b/src/img/indigo/favicon.ico new file mode 100644 index 000000000..f9b199f44 Binary files /dev/null and b/src/img/indigo/favicon.ico differ diff --git a/src/img/indigo/toolbar-logo.svg b/src/img/indigo/toolbar-logo.svg new file mode 100644 index 000000000..f2c68743d --- /dev/null +++ b/src/img/indigo/toolbar-logo.svg @@ -0,0 +1,47 @@ + + + + diff --git a/src/manifest.webmanifest b/src/manifest.webmanifest index 015dca158..49ba919c6 100644 --- a/src/manifest.webmanifest +++ b/src/manifest.webmanifest @@ -9,49 +9,49 @@ "icons": [ { "src": "assets/icons/icon-72x72.png", - "sizes": "72x72", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-96x96.png", - "sizes": "96x96", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-128x128.png", - "sizes": "128x128", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-144x144.png", - "sizes": "144x144", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-152x152.png", - "sizes": "152x152", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-192x192.png", - "sizes": "192x192", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-384x384.png", - "sizes": "384x384", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" }, { "src": "assets/icons/icon-512x512.png", - "sizes": "512x512", + "sizes": "124x90", "type": "image/png", "purpose": "maskable any" } diff --git a/src/themes/indigo.scss b/src/themes/indigo.scss new file mode 100644 index 000000000..5fe1a071e --- /dev/null +++ b/src/themes/indigo.scss @@ -0,0 +1,200 @@ +/*! + * Copyright 2020 InfAI (CC SES) + * + * 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. + */ +@use '@angular/material' as mat; + +@include mat.all-component-typographies(); +@include mat.core(); + +/* generated: http://mcg.mbitson.com/#!?customcolor=%232e7d32&themename=mcgtheme */ + +$md-custom-color: ( + 50 : #ffffff, + 100 : #ffffff, + 200 : #ffffff, + 300 : #ffffff, + 400 : #ffffff, + 500 : #ffffff, + 600 : #ffffff, + 700 : #ffffff, + 800 : #ffffff, + 900 : #ffffff, + A100 : #ffffff, + A200 : #ffffff, + A400 : #ffffff, + A700 : #ffffff, + contrast: ( + 50 : #000000, + 100 : #000000, + 200 : #000000, + 300 : #000000, + 400 : #000000, + 500 : #000000, + 600 : #000000, + 700 : #000000, + 800 : #000000, + 900 : #000000, + A100 : #000000, + A200 : #000000, + A400 : #000000, + A700 : #000000, + ) +); + +$md-custom-color-accent: ( + 50 : #e9f0f9, + 100 : #c7daf0, + 200 : #a2c2e7, + 300 : #7ca9dd, + 400 : #6096d5, + 500 : #4484ce, + 600 : #3e7cc9, + 700 : #3571c2, + 800 : #2d67bc, + 900 : #1f54b0, + A100 : #e9f0ff, + A200 : #b6cfff, + A400 : #83adff, + A700 : #699cff, + contrast: ( + 50 : #000000, + 100 : #000000, + 200 : #000000, + 300 : #000000, + 400 : #000000, + 500 : #ffffff, + 600 : #ffffff, + 700 : #ffffff, + 800 : #ffffff, + 900 : #ffffff, + A100 : #000000, + A200 : #000000, + A400 : #000000, + A700 : #000000, + ) +); + +$md-custom-color-warn: ( + 50 : #f9ece6, + 100 : #f0d0c0, + 200 : #e7b097, + 300 : #dd906d, + 400 : #d5794d, + 500 : #ce612e, + 600 : #c95929, + 700 : #c24f23, + 800 : #bc451d, + 900 : #b03312, + A100 : #ffe6e0, + A200 : #ffbcad, + A400 : #ff927a, + A700 : #ff7d61, + contrast: ( + 50 : #000000, + 100 : #000000, + 200 : #000000, + 300 : #000000, + 400 : #000000, + 500 : #ffffff, + 600 : #ffffff, + 700 : #ffffff, + 800 : #ffffff, + 900 : #ffffff, + A100 : #000000, + A200 : #000000, + A400 : #000000, + A700 : #000000, + ) +); + +$md-custom-color-sidenav: ( + 50 : #fdf3ea, + 100 : #fbe2ca, + 200 : #f8cfa6, + 300 : #f5bc82, + 400 : #f3ad68, + 500 : #f19f4d, + 600 : #ef9746, + 700 : #ed8d3d, + 800 : #eb8334, + 900 : #e77225, + A100 : #ffffff, + A200 : #fff4ee, + A400 : #ffd4bb, + A700 : #ffc4a1, + contrast: ( + 50 : #000000, + 100 : #000000, + 200 : #000000, + 300 : #000000, + 400 : #000000, + 500 : #000000, + 600 : #000000, + 700 : #000000, + 800 : #000000, + 900 : #000000, + A100 : #000000, + A200 : #000000, + A400 : #000000, + A700 : #000000, + ) +); + +$my-app-primary: mat.define-palette($md-custom-color); +$my-app-accent: mat.define-palette($md-custom-color-accent, 500, 900, A100); +$my-app-warn: mat.define-palette($md-custom-color-warn); +$my-app-sidenav: mat.define-palette($md-custom-color-sidenav); + +$my-app-theme: mat.define-light-theme($my-app-primary, $my-app-accent, $my-app-warn); + +@include mat.all-component-themes($my-app-theme); + +.background-color-accent { + color: white !important; + background-color: mat.get-color-from-palette($my-app-accent) !important; +} + +.background-color-sidenav { + color: white !important; + background-color: mat.get-color-from-palette($my-app-sidenav) !important; +} + +.color-accent { + color: mat.get-color-from-palette($my-app-accent) !important; +} + +.color-warn { + color: mat.get-color-from-palette($my-app-warn) !important; +} + +.color-sidenav { + color: mat.get-color-from-palette($my-app-sidenav) !important; +} + +.snack-bar-error { + .mdc-snackbar__surface { + background-color: darkred !important; + font-weight: bold!important; + } + .mat-mdc-snack-bar-actions .mdc-button__label { + color: white!important; + font-family: "Material Icons"!important; + font-weight: bold!important; + } +} + +.mdc-list-item--selected .mdc-list-item__primary-text, .mdc-list-item--activated .mdc-list-item__primary-text { + color: mat.get-color-from-palette($my-app-accent) !important; +}