summaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2
diff options
context:
space:
mode:
authorandre.schmid <andre.schmid@est.tech>2022-10-04 20:29:28 +0100
committerMichael Morris <michael.morris@est.tech>2022-10-17 14:42:22 +0000
commitaa72781388f3e6408bb43f1b024d88ec1c9d2c10 (patch)
tree15002a934486557f1d62eec49e57af1e2e59b443 /catalog-ui/src/app/ng2
parentb75fe3c7ce231c86cd4c6d052da453d02809c8f9 (diff)
Add data type properties workspace
Implements the properties workspace for a data type, with the list and filter feature. Change-Id: I2ec337a0481bddd5fe32e45644abdc88e197fa49 Issue-ID: SDC-4214 Signed-off-by: André Schmid <andre.schmid@est.tech>
Diffstat (limited to 'catalog-ui/src/app/ng2')
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html62
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less141
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts111
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts115
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html6
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts6
-rw-r--r--catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts7
-rw-r--r--catalog-ui/src/app/ng2/services/data-type.service.ts7
8 files changed, 448 insertions, 7 deletions
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html
new file mode 100644
index 0000000000..61c319eb6f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.html
@@ -0,0 +1,62 @@
+<!--
+ ~ -
+ ~ ============LICENSE_START=======================================================
+ ~ Copyright (C) 2022 Nordix Foundation.
+ ~ ================================================================================
+ ~ 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.
+ ~
+ ~ SPDX-License-Identifier: Apache-2.0
+ ~ ============LICENSE_END=========================================================
+ -->
+
+<div class="workspace-properties">
+ <div id="left-top-bar">
+ <span id="properties-count">{{'PROPERTY_SHOWING_LABEL' | translate}}: {{filteredProperties.length}} of {{properties.length}}</span>
+ <input id="search-by-name" type="search" [placeholder]="'SEARCH_LABEL' | translate" [ngModel]="tableFilterTerm" (ngModelChange)="this.tableSearchTermUpdate.next($event)"/>
+ <span class="sprite magnification-glass search-button"></span>
+ </div>
+ <div class="table-container-flex">
+ <div class="table" [ngClass]="{'view-mode': isViewOnly}">
+ <div class="head flex-container">
+ <div class="table-header head-row hand flex-item" *ngFor="let header of tableHeadersList" (click)="onUpdateSort(header.property)">{{header.title}}
+ <span *ngIf="tableSortBy === header.property" class="table-header-sort-arrow" [ngClass]="{'down': tableColumnReverse, 'up': !tableColumnReverse}"></span>
+ </div>
+ <div class="table-no-text-header head-row flex-item" *ngIf="!isViewOnly"><span class="delete-col-header"></span></div>
+ </div>
+
+ <div class="body">
+ <div *ngIf="filteredProperties.length === 0" class="no-row-text">
+ {{'PROPERTY_LIST_EMPTY_MESSAGE' | translate}}
+ </div>
+ <div *ngFor="let property of filteredProperties" [attr.data-tests-id]="'property-row-' + property.name" class="flex-container data-row">
+ <div class="table-col-general flex-item text" [title]="property.name">
+ <a [attr.data-tests-id]="'property-name-' + property.name" [ngClass]="{'disabled': isViewOnly}">{{property.name}}</a>
+ </div>
+
+ <div class="table-col-general flex-item text" [title]="property.type">
+ <span [attr.data-tests-id]="'property-type-' + property.name">{{property.type}}</span>
+ </div>
+ <div class="table-col-general flex-item text" [title]="property.getSchemaType() || ''">
+ <span [attr.data-tests-id]="'property-schema-' + property.name">{{property.getSchemaType() || ''}}</span>
+ </div>
+ <div class="table-col-general flex-item text" [title]="property.description">
+ <span [attr.data-tests-id]="'property-description-' + property.name" [title]="property.description">{{property.description}}</span>
+ </div>
+ <div class="table-btn-col flex-item" *ngIf="!isViewOnly"></div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less
new file mode 100644
index 0000000000..9c101e8ce3
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.less
@@ -0,0 +1,141 @@
+/*
+ * -
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+@import "../../../../../assets/styles/sprite-old";
+@import "../../../../../assets/styles/mixins_old";
+
+.workspace-properties {
+
+ width: 93%;
+ display: inline-block;
+
+ #left-top-bar {
+ float: left;
+ width: 186px;
+
+ ::-webkit-input-placeholder {
+ font-style: italic;
+ }
+
+ :-moz-placeholder {
+ font-style: italic;
+ }
+
+ ::-moz-placeholder {
+ font-style: italic;
+ }
+
+ :-ms-input-placeholder {
+ font-style: italic;
+ }
+
+ #properties-count {
+ font-weight: bold;
+ float: left;
+ }
+
+ #search-by-name {
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ width: 270px;
+ height: 32px;
+ line-height: 32px;
+ border: 1px solid @main_color_o;
+ text-indent: 10px;
+ }
+
+ .search-button {
+ .hand;
+ cursor: pointer;
+ float: right;
+ position: relative;
+ top: -22px;
+ right: -80px;
+ }
+ }
+
+ .delete-col-header {
+ .sprite();
+ .sprite.e-sdc-small-icon-delete();
+ }
+
+ .table {
+ height: 100%;
+ min-height: 500px;
+ margin-bottom: 0;
+ }
+
+ .data-row {
+ .table-delete-btn {
+ display: none !important;
+ }
+
+ &:hover {
+ .table-delete-btn {
+ display: inline-block !important;
+ }
+ }
+ }
+
+ .table-container-flex {
+ margin-top: 0;
+ overflow: scroll;
+ &::-webkit-scrollbar-track {
+ border: 0;
+ }
+
+ .text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: inline-block;
+ white-space: nowrap;
+ }
+
+ .flex-item:nth-child(1) {
+ flex-grow: 15;
+
+ a {
+ .hand
+ }
+ }
+
+ .flex-item:nth-child(2) {
+ flex-grow: 6;
+ }
+
+ .flex-item:nth-child(3) {
+ flex-grow: 6;
+ }
+
+ .flex-item:nth-child(4) {
+ flex-grow: 20;
+ white-space: normal;
+ }
+
+ .flex-item:nth-child(5) {
+ flex-grow: 3;
+ padding-top: 10px;
+ }
+
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts
new file mode 100644
index 0000000000..6be572d16a
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.spec.ts
@@ -0,0 +1,111 @@
+/*
+ * -
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {TypeWorkspacePropertiesComponent} from './type-workspace-properties.component';
+import {FormsModule} from "@angular/forms";
+import {TranslateModule} from "../../../shared/translator/translate.module";
+import {TranslateService} from "../../../shared/translator/translate.service";
+import {DataTypeService} from "../../../services/data-type.service";
+import {Observable} from "rxjs/Observable";
+import {DataTypeModel} from "../../../../models/data-types";
+import {Component, ViewChild} from "@angular/core";
+import {PropertyBEModel} from "../../../../models/properties-inputs/property-be-model";
+
+describe('TypeWorkspacePropertiesComponent', () => {
+ const messages = require("../../../../../assets/languages/en_US.json");
+ let testHostComponent: TestHostComponent;
+ let testHostFixture: ComponentFixture<TestHostComponent>;
+ let dataTypeServiceMock: Partial<DataTypeService> = {
+ findAllProperties: jest.fn( (dataTypeId) => {
+ if (dataTypeId === 'dataTypeId') {
+ const property1 = new PropertyBEModel();
+ property1.name = 'property1'
+ property1.type = 'string'
+ return Observable.of([property1]);
+ }
+ return Observable.of([]);
+ })
+ };
+
+ let translateServiceMock: Partial<TranslateService> = {
+ 'translate': jest.fn( (translateKey: string) => {
+ return messages[translateKey];
+ })
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [TypeWorkspacePropertiesComponent, TestHostComponent],
+ imports: [
+ TranslateModule,
+ FormsModule
+ ],
+ providers: [
+ {provide: DataTypeService, useValue: dataTypeServiceMock},
+ {provide: TranslateService, useValue: translateServiceMock}
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ testHostFixture = TestBed.createComponent(TestHostComponent);
+ testHostComponent = testHostFixture.componentInstance;
+ testHostFixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(testHostComponent).toBeTruthy();
+ });
+
+ it('empty property list', () => {
+ const element = testHostFixture.nativeElement;
+ const div: HTMLDivElement = element.querySelector('.no-row-text');
+ expect(div.textContent).toContain(messages.PROPERTY_LIST_EMPTY_MESSAGE);
+ });
+
+ it('test property list', () => {
+ testHostFixture = TestBed.createComponent(TestHostComponent);
+ testHostComponent = testHostFixture.componentInstance;
+ const dataType = new DataTypeModel();
+ dataType.uniqueId = 'dataTypeId';
+ testHostComponent.typeWorkspacePropertiesComponent.dataType = dataType;
+ testHostFixture.detectChanges();
+
+ const element = testHostFixture.nativeElement;
+ expect(element.querySelector('.no-row-text')).toBeFalsy();
+ const expectedPropertyName = 'property1';
+ const propertyNameLink: HTMLAnchorElement = element.querySelector(`a[data-tests-id^="property-name-${expectedPropertyName}"]`);
+ expect(propertyNameLink.textContent).toContain(expectedPropertyName);
+ });
+
+ @Component({
+ selector: 'host-component',
+ template: `<app-type-workspace-properties></app-type-workspace-properties>`
+ })
+ class TestHostComponent {
+ @ViewChild(TypeWorkspacePropertiesComponent)
+ public typeWorkspacePropertiesComponent: TypeWorkspacePropertiesComponent;
+ }
+
+});
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts
new file mode 100644
index 0000000000..931fd3d97c
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace-properties/type-workspace-properties.component.ts
@@ -0,0 +1,115 @@
+/*
+ * -
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import {Component, Input, OnInit} from '@angular/core';
+import {DataTypeModel} from "../../../../models/data-types";
+import {DataTypeService} from "../../../services/data-type.service";
+import {PropertyBEModel} from "../../../../models/properties-inputs/property-be-model";
+import { Subject } from "rxjs";
+import {debounceTime, distinctUntilChanged} from "rxjs/operators";
+
+@Component({
+ selector: 'app-type-workspace-properties',
+ templateUrl: './type-workspace-properties.component.html',
+ styleUrls: ['./type-workspace-properties.component.less']
+})
+export class TypeWorkspacePropertiesComponent implements OnInit {
+ @Input() isViewOnly = true;
+ @Input() dataType: DataTypeModel = new DataTypeModel();
+
+ properties: Array<PropertyBEModel> = [];
+ filteredProperties: Array<PropertyBEModel> = [];
+ tableHeadersList: Array<TableHeader> = [];
+ tableSortBy: string = 'name';
+ tableColumnReverse: boolean = false;
+ tableFilterTerm: string = undefined;
+ tableSearchTermUpdate = new Subject<string>();
+
+ constructor(private dataTypeService: DataTypeService) { }
+
+ ngOnInit(): void {
+ this.initTable();
+ this.initProperties();
+ this.tableSearchTermUpdate.pipe(
+ debounceTime(400),
+ distinctUntilChanged())
+ .subscribe(searchTerm => {
+ this.filter(searchTerm);
+ });
+ }
+
+ private initTable(): void {
+ this.tableHeadersList = [
+ {title: 'Name', property: 'name'},
+ {title: 'Type', property: 'type'},
+ {title: 'Schema', property: 'schema.property.type'},
+ {title: 'Description', property: 'description'},
+ ];
+
+ this.tableSortBy = this.tableHeadersList[0].property;
+ }
+
+ private initProperties(): void {
+ this.dataTypeService.findAllProperties(this.dataType.uniqueId).subscribe(properties => {
+ this.properties = properties.map(value => new PropertyBEModel(value));
+ this.filteredProperties = Array.from(this.properties);
+ this.sort();
+ });
+ }
+
+ onUpdateSort(property: string): void {
+ if (this.tableSortBy === property) {
+ this.tableColumnReverse = !this.tableColumnReverse;
+ } else {
+ this.tableColumnReverse = false;
+ this.tableSortBy = property;
+ }
+ this.sort();
+ }
+
+ private sort(): void {
+ const field = this.tableSortBy;
+ this.filteredProperties = this.filteredProperties.sort((property1, property2) => {
+ const result = property1[field] > property2[field] ? 1 : property1[field] < property2[field] ? -1 : 0;
+ return this.tableColumnReverse ? result * -1 : result;
+ });
+ }
+
+ private filter(searchTerm: string): void {
+ if (searchTerm) {
+ searchTerm = searchTerm.toLowerCase();
+ this.filteredProperties = this.properties.filter(property =>
+ property.name.toLowerCase().includes(searchTerm)
+ || property.type.toLowerCase().includes(searchTerm)
+ || (property.getSchemaType() && property.getSchemaType().toLowerCase().includes(searchTerm))
+ || (property.description && property.description.toLowerCase().includes(searchTerm))
+ );
+ } else {
+ this.filteredProperties = Array.from(this.properties);
+ }
+ this.sort();
+ }
+}
+
+interface TableHeader {
+ title: string;
+ property: string;
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html
index 8d6ae02598..193c94e6ad 100644
--- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.html
@@ -42,9 +42,11 @@
{{currentMenu.text}}
</div>
</div>
- <div class="w-sdc-main-container-body-content">
- <app-type-workspace-general *ngIf="currentMenu.state === 'general' && dataType" [dataType]="dataType"></app-type-workspace-general>
+ <div class="w-sdc-main-container-body-content" *ngIf="dataType">
+ <app-type-workspace-general *ngIf="currentMenu.state === 'general'" [dataType]="dataType"></app-type-workspace-general>
+ <app-type-workspace-properties *ngIf="currentMenu.state === 'properties'" [dataType]="dataType"></app-type-workspace-properties>
</div>
+
</div>
</div>
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts
index 8450da829b..fcad472890 100644
--- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.component.spec.ts
@@ -22,7 +22,7 @@
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {TypeWorkspaceComponent} from './type-workspace.component';
-import {ReactiveFormsModule} from "@angular/forms";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {TranslateModule} from "../../shared/translator/translate.module";
import {UiElementsModule} from "../../components/ui/ui-elements.module";
import {DataTypeService} from "../../services/data-type.service";
@@ -37,6 +37,7 @@ import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
import {States} from "../../../utils/constants";
import {IUserProperties} from "../../../models/user";
import {Observable} from "rxjs/Observable";
+import {TypeWorkspacePropertiesComponent} from "./type-workspace-properties/type-workspace-properties.component";
describe('TypeWorkspaceComponent', () => {
let component: TypeWorkspaceComponent;
@@ -88,9 +89,10 @@ describe('TypeWorkspaceComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent ],
+ declarations: [ TypeWorkspaceComponent, WorkspaceMenuComponent, TypeWorkspaceGeneralComponent, TypeWorkspacePropertiesComponent ],
imports: [
ReactiveFormsModule,
+ FormsModule,
TranslateModule,
UiElementsModule,
LayoutModule
diff --git a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts
index d3f391db24..021f84af09 100644
--- a/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts
+++ b/catalog-ui/src/app/ng2/pages/type-workspace/type-workspace.module.ts
@@ -28,9 +28,10 @@ import {UiElementsModule} from "../../components/ui/ui-elements.module";
import {LayoutModule} from "../../components/layout/layout.module";
import {TypeWorkspaceGeneralComponent} from './type-workspace-general/type-workspace-general.component';
import {UpgradeModule} from "@angular/upgrade/static";
-import {ReactiveFormsModule} from "@angular/forms";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {TranslateModule} from "../../shared/translator/translate.module";
import {DataTypeService} from "../../services/data-type.service";
+import { TypeWorkspacePropertiesComponent } from './type-workspace-properties/type-workspace-properties.component';
@NgModule({
imports: [
@@ -40,11 +41,13 @@ import {DataTypeService} from "../../services/data-type.service";
UpgradeModule,
ReactiveFormsModule,
TranslateModule,
+ FormsModule,
],
declarations: [
TypeWorkspaceComponent,
WorkspaceMenuComponent,
- TypeWorkspaceGeneralComponent
+ TypeWorkspaceGeneralComponent,
+ TypeWorkspacePropertiesComponent
],
providers: [
CacheService,
diff --git a/catalog-ui/src/app/ng2/services/data-type.service.ts b/catalog-ui/src/app/ng2/services/data-type.service.ts
index bf500ec16e..74d48d35de 100644
--- a/catalog-ui/src/app/ng2/services/data-type.service.ts
+++ b/catalog-ui/src/app/ng2/services/data-type.service.ts
@@ -20,7 +20,7 @@
import * as _ from "lodash";
import {Inject, Injectable} from '@angular/core';
-import { DataTypeModel, DataTypesMap, PropertyFEModel, DerivedFEProperty} from "app/models";
+import {DataTypeModel, DataTypesMap, PropertyFEModel, DerivedFEProperty, PropertyBEModel} from "app/models";
import { DataTypesService } from "app/services/data-types-service";
import { PROPERTY_DATA } from "app/utils";
import {DerivedFEAttribute} from "../../models/attributes-outputs/derived-fe-attribute";
@@ -78,6 +78,11 @@ export class DataTypeService {
return this.httpClient.get<DataTypeModel>(url);
}
+ public findAllProperties(id: string): Observable<Array<PropertyBEModel>> {
+ const url = `${this.dataTypeUrl}/${id}/properties`
+ return this.httpClient.get<Array<PropertyBEModel>>(url);
+ }
+
public getConstraintsByParentTypeAndUniqueID(rootPropertyType, propertyName){
// const property = this.dataTypes[rootPropertyType].properties.filter(property =>
// property.name == propertyName);