diff --git a/.eslintrc.json b/.eslintrc.json index 3b4249064..e7f593ed7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -36,7 +36,13 @@ "style": "kebab-case" } ], - "@typescript-eslint/no-explicit-any": "error" + "@typescript-eslint/no-explicit-any": "error", + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ] } }, { diff --git a/package-lock.json b/package-lock.json index b7f177a0f..7942ba922 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@angular/platform-browser": "^14.2.0", "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", + "fast-json-patch": "^3.1.1", "primeflex": "^3.2.1", "primeicons": "^6.0.1", "primeng": "^14.1.2", @@ -6910,6 +6911,11 @@ "node": ">=8.6.0" } }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "dev": true, @@ -19045,6 +19051,11 @@ "micromatch": "^4.0.4" } }, + "fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, "fast-json-stable-stringify": { "version": "2.1.0", "dev": true diff --git a/package.json b/package.json index 765638f2d..83d91da0c 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@angular/platform-browser": "^14.2.0", "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", + "fast-json-patch": "^3.1.1", "primeflex": "^3.2.1", "primeicons": "^6.0.1", "primeng": "^14.1.2", diff --git a/src/app/project-administration/backend.service.ts b/src/app/project-administration/backend.service.ts index ba56a26f7..fe263eacc 100644 --- a/src/app/project-administration/backend.service.ts +++ b/src/app/project-administration/backend.service.ts @@ -1,6 +1,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; +import { PatchResponse } from '../shared/interfacing/patch-response.interface'; import { ActiveProjectsInterface } from './active-projects/active-projects.interface'; import { ProjectInterface } from './project/project.interface'; import { IBackendService } from './backend.service.interface'; @@ -37,8 +38,8 @@ export class BackendService implements IBackendService { return this.http.get('resource/SESSION/1/List_32_all_32_interfaces'); } - public patchProject(id: string, data: any): Observable { - return this.http.patch(`resource/Project/${id}/New_47_edit_32_project`, data); + public patchProject(id: string, data: any): Observable> { + return this.http.patch>(`resource/Project/${id}/New_47_edit_32_project`, data); } public patchPerson(id: string, data: any): Observable { diff --git a/src/app/project-administration/person/person.component.html b/src/app/project-administration/person/person.component.html index 8799ee9db..63af801b3 100644 --- a/src/app/project-administration/person/person.component.html +++ b/src/app/project-administration/person/person.component.html @@ -13,7 +13,6 @@
{{ data.First_32_name }} {{ data.Last_32_name }}
isUni isTot crud="cRUd" - (propertyEvent)="patchPerson($event, '/First_32_name')" > @@ -26,7 +25,6 @@
{{ data.First_32_name }} {{ data.Last_32_name }}
isUni isTot crud="cRUd" - (propertyEvent)="patchPerson($event, '/Last_32_name')" > @@ -39,7 +37,6 @@
{{ data.First_32_name }} {{ data.Last_32_name }}
isUni isTot crud="cRUd" - (propertyEvent)="patchPerson($event, '/Status')" > @@ -52,7 +49,6 @@
{{ data.First_32_name }} {{ data.Last_32_name }}
isUni isTot crud="cRUd" - (propertyEvent)="patchPerson($event, '/Email')" > diff --git a/src/app/project-administration/project-edit/project-edit.component.html b/src/app/project-administration/project-edit/project-edit.component.html index bb3505161..5acc17a7e 100644 --- a/src/app/project-administration/project-edit/project-edit.component.html +++ b/src/app/project-administration/project-edit/project-edit.component.html @@ -8,11 +8,12 @@
{{ data.Name }}
@@ -24,7 +25,6 @@
{{ data.Name }}
isUni isTot crud="CRUD" - (propertyEvent)="patchProject($event, '/Description')" > @@ -36,7 +36,6 @@
{{ data.Name }}
isUni isTot crud="CRUD" - (propertyEvent)="patchProject($event, '/Start_32_date')" > @@ -48,32 +47,19 @@
{{ data.Name }}
isUni isTot crud="CRUD" - (propertyEvent)="patchProject($event, '/Status')" >
- +
- +
@@ -84,7 +70,6 @@
{{ data.Name }}
isUni isTot crud="CRUD" - (propertyEvent)="patchProject($event, '/Project_32_members')" >
diff --git a/src/app/project-administration/project-edit/project-edit.component.ts b/src/app/project-administration/project-edit/project-edit.component.ts index 828f0e341..a55e6260f 100644 --- a/src/app/project-administration/project-edit/project-edit.component.ts +++ b/src/app/project-administration/project-edit/project-edit.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, ParamMap } from '@angular/router'; -import { Observable, switchMap } from 'rxjs'; +import { from, Observable, switchMap, tap } from 'rxjs'; +import { PatchReplace } from 'src/app/shared/interfacing/patch-replace.interface'; +import { PatchResponse } from 'src/app/shared/interfacing/patch-response.interface'; +import { Resource } from 'src/app/shared/interfacing/resource.interface'; import { BackendService } from '../backend.service'; import { ProjectInterface } from '../project/project.interface'; @@ -9,7 +12,7 @@ import { ProjectInterface } from '../project/project.interface'; templateUrl: './project-edit.component.html', styleUrls: ['./project-edit.component.scss'], }) -export class ProjectEditComponent implements OnInit { +export class ProjectEditComponent implements OnInit, Resource { public data$!: Observable; public projectId!: string; @@ -27,17 +30,13 @@ export class ProjectEditComponent implements OnInit { ); } - patchProject(property: any, path: string) { - let body = [ - { - op: 'replace', - path: path, - value: property, - }, - ]; - - this.service.patchProject(this.projectId, body).subscribe(() => { - this.data$ = this.service.getProject(this.projectId); - }); + patch(patches: PatchReplace[]): Observable> { + return this.service.patchProject(this.projectId, patches).pipe( + tap((x) => { + if (x.isCommitted) { + this.data$ = from([x.content]); + } + }), + ); } } diff --git a/src/app/shared/atomic-components/BaseAtomicComponent.class.ts b/src/app/shared/atomic-components/BaseAtomicComponent.class.ts index ab8b4aac3..b3c694cc7 100644 --- a/src/app/shared/atomic-components/BaseAtomicComponent.class.ts +++ b/src/app/shared/atomic-components/BaseAtomicComponent.class.ts @@ -1,16 +1,15 @@ -import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; @Component({ template: '', }) export abstract class BaseAtomicComponent implements OnInit, OnChanges { - @Input() property: T | Array | null = null; + @Input() + // TODO Refactor to combination of parent-propertyName. We need a link to the parent anyway + property: T | Array | null = null; + public data: Array = []; - private oldProperty: Array = []; - public canCreate!: boolean; - public canRead!: boolean; - public canUpdate!: boolean; - public canDelete!: boolean; + private _isUni: boolean = false; @Input() set isUni(attribute: boolean | '') { @@ -19,6 +18,7 @@ export abstract class BaseAtomicComponent implements OnInit, OnChanges { get isUni(): boolean { return this._isUni; } + private _isTot: boolean = false; @Input() set isTot(attribute: boolean | '') { @@ -27,13 +27,24 @@ export abstract class BaseAtomicComponent implements OnInit, OnChanges { get isTot(): boolean { return this._isTot; } - @Input() crud: string = 'crud'; - @Output() propertyEvent = new EventEmitter | null>(); + + @Input() + crud: string = 'cRud'; + + public canCreate(): boolean { + return this.crud.includes('C'); + } + public canRead(): boolean { + return this.crud.includes('R'); + } + public canUpdate(): boolean { + return this.crud.includes('U'); + } + public canDelete(): boolean { + return this.crud.includes('D'); + } ngOnInit(): void { - this.setCRUDPermissions(this.crud); - // TODO: unneeded when ng formcontrols work - this.oldProperty = this.requireArray(this.property); this.data = this.requireArray(this.property); } @@ -42,26 +53,6 @@ export abstract class BaseAtomicComponent implements OnInit, OnChanges { if (changes.hasOwnProperty('isUni')) { this.isUni = changes['isUni'].firstChange; } - this.setCRUDPermissions(changes['crud'].currentValue); - } - - public changeProperty(): void { - if (this.oldProperty == this.data) { - return; - } - this.propertyEvent.emit(this.data); - } - - private setCRUDPermissions(crud: string) { - let c = crud[0]; - let r = crud[1]; - let u = crud[2]; - let d = crud[3]; - - this.canCreate = c == c.toUpperCase(); - this.canRead = r == r.toUpperCase(); - this.canUpdate = u == u.toUpperCase(); - this.canDelete = d == d.toUpperCase(); } public requireArray(property: T | Array | null) { @@ -73,4 +64,8 @@ export abstract class BaseAtomicComponent implements OnInit, OnChanges { return [property]; } } + + public isNewItemInputRequired() { + return this.isTot && this.data.length === 0; + } } diff --git a/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.html b/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.html index 25f7d05e6..1b1b032cc 100644 --- a/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.html +++ b/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.html @@ -1,14 +1,7 @@ -
-
+
+
- +
@@ -25,7 +18,7 @@ type="text" class="min-w-10rem w-full" pInputText - [(ngModel)]="newItem" + [formControl]="newItemControl" placeholder="Add text" [required]="isNewItemInputRequired()" /> diff --git a/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.ts b/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.ts index 6543dc515..74f0fc5e4 100644 --- a/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.ts +++ b/src/app/shared/atomic-components/atomic-alphanumeric/atomic-alphanumeric.component.ts @@ -1,15 +1,47 @@ -import { Component } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { BaseAtomicComponent } from '../BaseAtomicComponent.class'; +import { FormControl } from '@angular/forms'; +import { debounceTime, distinctUntilChanged, map, tap } from 'rxjs'; +import { Resource } from '../../interfacing/resource.interface'; @Component({ selector: 'app-atomic-alphanumeric', templateUrl: './atomic-alphanumeric.component.html', styleUrls: ['./atomic-alphanumeric.component.css'], }) -export class AtomicAlphanumericComponent extends BaseAtomicComponent { - newItem!: string; +export class AtomicAlphanumericComponent extends BaseAtomicComponent implements OnInit { + formControl!: FormControl; + newItemControl: FormControl = new FormControl('', { nonNullable: true, updateOn: 'blur' }); - isNewItemInputRequired() { - return this.isTot && this.property?.length === 0; + @Input() + // The type of the T for Resource is not relevant nor to determine here; therefore unknow + // We require a Resource, that implements the required methods (like patch) + // Most likely this is a top-level component for a specific application interface (e.g. ProjectComponent) + resource!: Resource; // TODO move to the base class. It is needed for all atomic components + + @Input() + propertyName!: string; // TODO move to the base class. It is needed for all atomic components + + override ngOnInit(): void { + super.ngOnInit(); + this.formControl = new FormControl(this.data[0], { nonNullable: false, updateOn: 'blur' }); + + this.formControl.valueChanges + .pipe( + debounceTime(300), + distinctUntilChanged(), + map((x) => (x === '' ? null : x)), // transform empty string to null value + ) + .subscribe((x) => + this.resource + .patch([ + { + op: 'replace', + path: this.propertyName, // FIXME: this must be relative to path of this.resource + value: x, + }, + ]) + .subscribe(), + ); } } diff --git a/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.html b/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.html index 1e4938988..c5486e079 100644 --- a/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.html +++ b/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.html @@ -1,11 +1,10 @@ -
-
+
+
diff --git a/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.ts b/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.ts index 0b4363792..f9a00815b 100644 --- a/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.ts +++ b/src/app/shared/atomic-components/atomic-bigalphanumeric/atomic-bigalphanumeric.component.ts @@ -8,8 +8,4 @@ import { BaseAtomicComponent } from '../BaseAtomicComponent.class'; }) export class AtomicBigalphanumericComponent extends BaseAtomicComponent { newItem!: string; - - isNewItemInputRequired() { - return this.isTot && this.property?.length === 0; - } } diff --git a/src/app/shared/atomic-components/atomic-boolean/atomic-boolean.component.html b/src/app/shared/atomic-components/atomic-boolean/atomic-boolean.component.html index ecdb3f165..9184abaa1 100644 --- a/src/app/shared/atomic-components/atomic-boolean/atomic-boolean.component.html +++ b/src/app/shared/atomic-components/atomic-boolean/atomic-boolean.component.html @@ -1,11 +1,11 @@ -
+
diff --git a/src/app/shared/atomic-components/atomic-date/atomic-date.component.html b/src/app/shared/atomic-components/atomic-date/atomic-date.component.html index ba4e46bd8..14609568e 100644 --- a/src/app/shared/atomic-components/atomic-date/atomic-date.component.html +++ b/src/app/shared/atomic-components/atomic-date/atomic-date.component.html @@ -1,13 +1,11 @@ -
+
diff --git a/src/app/shared/atomic-components/atomic-datetime/atomic-datetime.component.html b/src/app/shared/atomic-components/atomic-datetime/atomic-datetime.component.html index 909103f4d..77ac512d7 100644 --- a/src/app/shared/atomic-components/atomic-datetime/atomic-datetime.component.html +++ b/src/app/shared/atomic-components/atomic-datetime/atomic-datetime.component.html @@ -1,6 +1,6 @@ -
+
diff --git a/src/app/shared/atomic-components/atomic-object/atomic-object.component.ts b/src/app/shared/atomic-components/atomic-object/atomic-object.component.ts index e98ceb9c3..fdd180618 100644 --- a/src/app/shared/atomic-components/atomic-object/atomic-object.component.ts +++ b/src/app/shared/atomic-components/atomic-object/atomic-object.component.ts @@ -3,8 +3,6 @@ import { MenuItem } from 'primeng/api'; import { BaseAtomicComponent } from '../BaseAtomicComponent.class'; import { Router } from '@angular/router'; import { InterfaceRefObject, ObjectBase } from '../../objectBase.interface'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type AtomicObjectMenuItem = any; @Component({ selector: 'app-atomic-object', @@ -12,7 +10,7 @@ type AtomicObjectMenuItem = any; styleUrls: ['./atomic-object.component.scss'], }) export class AtomicObjectComponent extends BaseAtomicComponent implements OnInit { - public menuItems: AtomicObjectMenuItem = []; + public menuItems: { [index: string]: Array } = {}; constructor(private router: Router) { super(); diff --git a/src/app/shared/atomic-components/atomic-password/atomic-password.component.html b/src/app/shared/atomic-components/atomic-password/atomic-password.component.html index 815ffe867..a04cefb86 100644 --- a/src/app/shared/atomic-components/atomic-password/atomic-password.component.html +++ b/src/app/shared/atomic-components/atomic-password/atomic-password.component.html @@ -1,13 +1,13 @@ - + For this template, the password expression must be univalent - + For this template, the password expression must have update rights diff --git a/src/app/shared/interfacing/patch-replace.interface.ts b/src/app/shared/interfacing/patch-replace.interface.ts new file mode 100644 index 000000000..c0ee3a9eb --- /dev/null +++ b/src/app/shared/interfacing/patch-replace.interface.ts @@ -0,0 +1,5 @@ +export interface PatchReplace { + op: 'replace'; + path: string; + value: string | null; +} diff --git a/src/app/shared/interfacing/patch-response.interface.ts b/src/app/shared/interfacing/patch-response.interface.ts new file mode 100644 index 000000000..184f4f3da --- /dev/null +++ b/src/app/shared/interfacing/patch-response.interface.ts @@ -0,0 +1,19 @@ +import { PatchReplace } from './patch-replace.interface'; + +export interface PatchResponse { + content: T; + patches: Array; + // TODO: change unknown types + notifications: { + errors: Array; + warnings: Array; + infos: Array; + successes: Array; + invariants: Array; + signals: Array; + }; + invariantRulesHold: boolean; + isCommitted: boolean; + sessionRefreshAdvice: boolean; + navTo: string | null; +} diff --git a/src/app/shared/interfacing/resource.interface.ts b/src/app/shared/interfacing/resource.interface.ts new file mode 100644 index 000000000..f6a710e63 --- /dev/null +++ b/src/app/shared/interfacing/resource.interface.ts @@ -0,0 +1,7 @@ +import { Observable } from 'rxjs'; +import { PatchReplace } from './patch-replace.interface'; +import { PatchResponse } from './patch-response.interface'; + +export interface Resource { + patch(patches: Array): Observable>; +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 7f39c7ee2..b363b2e15 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; // Components import { AtomicAlphanumericComponent } from './atomic-components/atomic-alphanumeric/atomic-alphanumeric.component'; @@ -58,6 +58,7 @@ import { ButtonModule } from 'primeng/button'; ], imports: [ CommonModule, + ReactiveFormsModule, FormsModule, InputTextModule, InputSwitchModule, diff --git a/src/app/tools/test-data.interface.ts b/src/app/tools/test-data.interface.ts new file mode 100644 index 000000000..2953a6769 --- /dev/null +++ b/src/app/tools/test-data.interface.ts @@ -0,0 +1,50 @@ +export interface TestDataInterface extends ObjectBase { + _view_: ProjectNameView; + _sortValues_: { + Projects: string; + Name: string; + Description: string; + Projectleider: string; + _64_: string; + Start: string | null; + Status: string; + Active: boolean; + }; + Projects: ObjectBase & { + _view_: ProjectNameView; + }; + Name: string; + Description: string; + Projectleider: ObjectBase & { + _view_: PersonNameView; + }; + _64_: ObjectBase & { + _view_: PersonNameView; + }; + Start: string | null; + Status: string; + Active: boolean; + _id_: string; +} + +interface PersonNameView { + firstName: string; + txt1: string; + lastName: string; +} + +interface ProjectNameView { + name: string; +} + +interface ObjectBase { + _id_: string; + _label_: string; + _path_: string; + _ifcs_: Array; +} + +interface InterfaceRefObject { + id: string; + label: string; +} diff --git a/src/app/tools/testdata.ts b/src/app/tools/testdata.ts new file mode 100644 index 000000000..7be8c1a3b --- /dev/null +++ b/src/app/tools/testdata.ts @@ -0,0 +1,336 @@ +import { TestDataInterface } from './test-data.interface'; + +export const testdata: TestDataInterface[] = [ + { + _id_: '1970_13', + _label_: 'Apollo 13', + _path_: 'resource/SESSION/1/Active_32_projects/1970_13', + _view_: { + name: 'Apollo 13', + }, + Projects: { + _id_: '1970_13', + _label_: 'Apollo 13', + _path_: 'resource/SESSION/1/Active_32_projects/1970_13/Projects', + _view_: { + name: 'Apollo 13', + }, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + _sortValues_: { + Projects: 'Apollo 13', + Name: 'Apollo 13', + Description: 'Joosten, get us back to earth please!', + Projectleider: 'J. Lovell', + _64_: 'J. Lovell', + Start: '1970-04-17', + Status: 'Succes', + Active: true, + }, + Name: 'Apollo 13', + Description: 'Joosten, get us back to earth please!', + Projectleider: { + _id_: 'p10008', + _label_: 'J. Lovell', + _path_: 'resource/SESSION/1/Active_32_projects/1970_13/Projectleider/p10008', + _view_: { + firstName: 'J.', + txt1: ' ', + lastName: 'Lovell', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + _64_: { + _id_: 'p10008', + _label_: 'J. Lovell', + _path_: 'resource/SESSION/1/Active_32_projects/1970_13/_64_/p10008', + _view_: { + firstName: 'J.', + txt1: ' ', + lastName: 'Lovell', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + Start: '1970-04-17', + Status: 'Succes', + Active: true, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + { + _id_: '2013_01', + _label_: 'Alfa board', + _path_: 'resource/SESSION/1/Active_32_projects/2013_01', + _view_: { + name: 'Alfa board', + }, + Projects: { + _id_: '2013_01', + _label_: 'Alfa board', + _path_: 'resource/SESSION/1/Active_32_projects/2013_01/Projects', + _view_: { + name: 'Alfa board', + }, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + _sortValues_: { + Projects: 'Alfa board', + Name: 'Alfa board', + Description: 'Create an Alpha board for the customer', + Projectleider: 'P. Leider', + _64_: 'P. Leider', + Start: '2013-12-31', + Status: 'Completed', + Active: true, + }, + Name: 'Alfa board', + Description: 'Create an Alpha board for the customer', + Projectleider: { + _id_: 'p10012', + _label_: 'P. Leider', + _path_: 'resource/SESSION/1/Active_32_projects/2013_01/Projectleider/p10012', + _view_: { + firstName: 'P.', + txt1: ' ', + lastName: 'Leider', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + _64_: { + _id_: 'p10012', + _label_: 'P. Leider', + _path_: 'resource/SESSION/1/Active_32_projects/2013_01/_64_/p10012', + _view_: { + firstName: 'P.', + txt1: ' ', + lastName: 'Leider', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + Start: '2013-12-31', + Status: 'Completed', + Active: true, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + { + _id_: '2014_01', + _label_: 'Beta board', + _path_: 'resource/SESSION/1/Active_32_projects/2014_01', + _view_: { + name: 'Beta board', + }, + Projects: { + _id_: '2014_01', + _label_: 'Beta board', + _path_: 'resource/SESSION/1/Active_32_projects/2014_01/Projects', + _view_: { + name: 'Beta board', + }, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + _sortValues_: { + Projects: 'Beta board', + Name: 'Beta board', + Description: 'further development of the board to Beta', + Projectleider: 'P. Leider', + _64_: 'P. Leider', + Start: '2014-02-15', + Status: 'Under way', + Active: true, + }, + Name: 'Beta board', + Description: 'further development of the board to Beta', + Projectleider: { + _id_: 'p10012', + _label_: 'P. Leider', + _path_: 'resource/SESSION/1/Active_32_projects/2014_01/Projectleider/p10012', + _view_: { + firstName: 'P.', + txt1: ' ', + lastName: 'Leider', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + _64_: { + _id_: 'p10012', + _label_: 'P. Leider', + _path_: 'resource/SESSION/1/Active_32_projects/2014_01/_64_/p10012', + _view_: { + firstName: 'P.', + txt1: ' ', + lastName: 'Leider', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + Start: '2014-02-15', + Status: 'Under way', + Active: true, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + { + _id_: '2014_05', + _label_: 'Argos', + _path_: 'resource/SESSION/1/Active_32_projects/2014_05', + _view_: { + name: 'Argos', + }, + Projects: { + _id_: '2014_05', + _label_: 'Argos', + _path_: 'resource/SESSION/1/Active_32_projects/2014_05/Projects', + _view_: { + name: 'Argos', + }, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, + _sortValues_: { + Projects: 'Argos', + Name: 'Argos', + Description: 'get the Golden Fleece', + Projectleider: 'J. Ason', + _64_: 'J. Ason', + Start: null, + Status: 'Completed', + Active: true, + }, + Name: 'Argos', + Description: 'get the Golden Fleece', + Projectleider: { + _id_: 'p10007', + _label_: 'J. Ason', + _path_: 'resource/SESSION/1/Active_32_projects/2014_05/Projectleider/p10007', + _view_: { + firstName: 'J.', + txt1: ' ', + lastName: 'Ason', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + _64_: { + _id_: 'p10007', + _label_: 'J. Ason', + _path_: 'resource/SESSION/1/Active_32_projects/2014_05/_64_/p10007', + _view_: { + firstName: 'J.', + txt1: ' ', + lastName: 'Ason', + }, + _ifcs_: [ + { + id: 'Person', + label: 'Person', + }, + ], + }, + Start: null, + Status: 'Completed', + Active: true, + _ifcs_: [ + { + id: 'Project', + label: 'Project', + }, + { + id: 'New_47_edit_32_project', + label: 'New/edit project', + }, + ], + }, +]; diff --git a/src/app/tools/tool-gallery/tool-gallery.component.html b/src/app/tools/tool-gallery/tool-gallery.component.html index 128a07afd..d307dd9d8 100644 --- a/src/app/tools/tool-gallery/tool-gallery.component.html +++ b/src/app/tools/tool-gallery/tool-gallery.component.html @@ -1,8 +1,32 @@
+ -