Skip to content

Commit

Permalink
Merge branch 'main' into chore/external-services-ux-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ngruelaneo authored Sep 9, 2024
2 parents a67007b + b7b7ea8 commit 2b70828
Show file tree
Hide file tree
Showing 35 changed files with 1,387 additions and 989 deletions.
32 changes: 16 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@
},
"private": true,
"dependencies": {
"@aneoconsultingfr/armonik.api.angular": "^3.19.0",
"@aneoconsultingfr/armonik.api.angular": "^3.20.0",
"@angular-material-components/datetime-picker": "^16.0.1",
"@angular/animations": "^18.2.2",
"@angular/cdk": "18.2.2",
"@angular/common": "^18.2.2",
"@angular/compiler": "^18.2.2",
"@angular/core": "^18.2.2",
"@angular/forms": "^18.2.2",
"@angular/material": "18.2.2",
"@angular/material-luxon-adapter": "^18.2.2",
"@angular/platform-browser": "^18.2.2",
"@angular/platform-browser-dynamic": "^18.2.2",
"@angular/router": "^18.2.2",
"@angular/animations": "^18.2.3",
"@angular/cdk": "18.2.3",
"@angular/common": "^18.2.3",
"@angular/compiler": "^18.2.3",
"@angular/core": "^18.2.3",
"@angular/forms": "^18.2.3",
"@angular/material": "18.2.3",
"@angular/material-luxon-adapter": "^18.2.3",
"@angular/platform-browser": "^18.2.3",
"@angular/platform-browser-dynamic": "^18.2.3",
"@angular/router": "^18.2.3",
"@ngx-grpc/common": "^3.1.2",
"@ngx-grpc/core": "^3.1.2",
"@ngx-grpc/grpc-web-client": "^3.1.2",
Expand All @@ -46,10 +46,10 @@
"@angular-eslint/eslint-plugin-template": "18.3.0",
"@angular-eslint/schematics": "18.3.0",
"@angular-eslint/template-parser": "18.3.0",
"@angular/build": "^18.2.2",
"@angular/cli": "~18.2.2",
"@angular/compiler-cli": "^18.2.2",
"@angular/localize": "18.2.2",
"@angular/build": "^18.2.3",
"@angular/cli": "~18.2.3",
"@angular/compiler-cli": "^18.2.3",
"@angular/localize": "18.2.3",
"@types/google-protobuf": "^3.15.12",
"@types/jest": "^29.5.12",
"@types/luxon": "^3.4.2",
Expand Down
1,075 changes: 360 additions & 715 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions src/app/components/inspection/inspection-json.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<mat-toolbar>
<section>
<span i18n>Raw JSON</span>
<button mat-icon-button (click)="copy()" i18n-matTooltip matTooltip="Copy JSON">
<mat-icon [fontIcon]="copyIcon" />
</button>
</section>
<button mat-icon-button (click)="toggleDisplay()" [matTooltip]="display ? hideToolTip : displayToolTip">
@if (!display) {
<mat-icon [fontIcon]="arrowDownIcon" />
} @else {
<mat-icon [fontIcon]="arrowUpIcon" />
}
</button>
</mat-toolbar>
@if (display) {
<mat-card>
<span>&#x7b;</span>
<app-json [data]="data" />
<span>&#x7d;</span>
</mat-card>
}
87 changes: 87 additions & 0 deletions src/app/components/inspection/inspection-json.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Clipboard } from '@angular/cdk/clipboard';
import { TestBed } from '@angular/core/testing';
import { IconsService } from '@services/icons.service';
import { NotificationService } from '@services/notification.service';
import { InspectionJsonComponent } from './inspection-json.component';

describe('InspectionJsonComponent', () => {
let component: InspectionJsonComponent;

const data = {
one: 1,
two: 2,
object: {
three: 3
},
array: [1, 2, 3]
};

const mockNotificationService = {
success: jest.fn(),
error: jest.fn(),
};

const mockClipboard = {
copy: jest.fn(),
};

const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

beforeEach(() => {
component = TestBed.configureTestingModule({
providers: [
InspectionJsonComponent,
{ provide: NotificationService, useValue: mockNotificationService },
{ provide: Clipboard, useValue: mockClipboard },
IconsService,
]
}).inject(InspectionJsonComponent);
component.data = data;
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should set data', () => {
expect(component.data).toEqual(data);
});

describe('copy', () => {
it('should copy to clipboard', () => {
component.copy();
expect(mockClipboard.copy).toHaveBeenCalledWith(JSON.stringify(data, null, 2));
});

it('should notify on copy', () => {
component.copy();
expect(mockNotificationService.success).toHaveBeenCalled();
});

it('should log in case of an error', () => {
jest.spyOn(JSON, 'stringify').mockImplementationOnce(() => {throw new Error;});
component.copy();
expect(errorSpy).toHaveBeenCalled();
});

it('should notify in case of an error', () => {
jest.spyOn(JSON, 'stringify').mockImplementationOnce(() => {throw new Error;});
component.copy();
expect(mockNotificationService.error).toHaveBeenCalled();
});
});

describe('toggleDisplay', () => {
it('should set display to true if it is false', () => {
component.display = false;
component.toggleDisplay();
expect(component.display).toBeTruthy();
});

it('should set display to false if it is true', () => {
component.display = true;
component.toggleDisplay();
expect(component.display).toBeFalsy();
});
});
});
75 changes: 75 additions & 0 deletions src/app/components/inspection/inspection-json.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Clipboard } from '@angular/cdk/clipboard';
import { Component, Input, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { IconsService } from '@services/icons.service';
import { NotificationService } from '@services/notification.service';
import { JsonComponent } from './json.component';

@Component({
selector: 'app-json-inspection',
templateUrl: 'inspection-json.component.html',
standalone: true,
providers: [
IconsService,
],
imports: [
JsonComponent,
MatIconModule,
MatButtonModule,
MatToolbarModule,
MatCardModule,
MatTooltipModule,
],
styles: [`
mat-card {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
}
mat-toolbar {
display: flex;
justify-content: space-between;
}
section {
display: flex;
align-items: center;
}
`]
})
export class InspectionJsonComponent {
@Input({ required: true }) data: object | null;

display = false;

readonly iconsService = inject(IconsService);
readonly clipboard = inject(Clipboard);
readonly notificationService = inject(NotificationService);

readonly copyIcon = this.iconsService.getIcon('copy');
readonly arrowDownIcon = this.iconsService.getIcon('arrow-down');
readonly arrowUpIcon = this.iconsService.getIcon('arrow-up');

readonly displayToolTip = $localize`Display JSON`;
readonly hideToolTip = $localize`Hide JSON`;

copy() {
try {
const object = JSON.stringify(this.data, null, 2);
this.clipboard.copy(object);
this.notificationService.success('JSON copied to clipboard');
} catch (e) {
console.error(e);
this.notificationService.error('Could not copy JSON');
}
}

toggleDisplay() {
this.display = !this.display;
}
}
13 changes: 13 additions & 0 deletions src/app/components/inspection/json.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@for(key of keys; track key) {
<section>
@if(isObject(key) && !isArray(key)) {
<p>{{ key }}: &#x7b;</p>
<app-json [data]="data[key]" />
<p>&#x7d;</p>
} @else if (data[key]) {
<p>{{key}}: {{ data[key] | json }}</p>
} @else {
<p>{{key}}: undefined</p>
}
</section>
}
58 changes: 58 additions & 0 deletions src/app/components/inspection/json.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { JsonComponent } from './json.component';

describe('JsonComponent', () => {
const component = new JsonComponent();

const data = {
one: 1,
two: 2,
object: {
three: 3
},
array: [1, 2, 3]
};

beforeEach(() => {
component.data = data;
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should set data', () => {
expect(component.data).toEqual(data);
});

it('should set keys', () => {
expect(component.keys).toEqual(['one', 'two', 'object', 'array']);
});

describe('isArray', () => {
it('should return true if an array is passed', () => {
expect(component.isArray('array' as keyof object)).toBeTruthy();
});

it('should return false if an object is passed', () => {
expect(component.isArray('object' as keyof object)).toBeFalsy();
});

it('should return false if a simple value is passed', () => {
expect(component.isArray('one' as keyof object)).toBeFalsy();
});
});

describe('isObject', () => {
it('should return true if an object is passed', () => {
expect(component.isObject('object' as keyof object)).toBeTruthy();
});

it('should return true if an array is passed', () => {
expect(component.isObject('array' as keyof object)).toBeTruthy();
});

it('should return false if a simple value is passed', () => {
expect(component.isObject('one' as keyof object)).toBeFalsy();
});
});
});
43 changes: 43 additions & 0 deletions src/app/components/inspection/json.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { JsonPipe } from '@angular/common';
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-json',
templateUrl: 'json.component.html',
standalone: true,
imports: [
JsonPipe
],
styles: [`
section {
margin-left: 1rem;
}
p {
margin: 0;
}
`]
})
export class JsonComponent {
private _data: object;

keys: (keyof object)[];

@Input({ required: true }) set data(entry: object | null) {
if(entry) {
this.keys = Object.keys(entry).map(key => key.replace('_', '')) as keyof object;
this._data = entry;
}
}

get data(): object {
return this._data;
}

isArray(key: keyof object): boolean {
return this.data[key] && (this.data[key] as Array<string>).length;
}

isObject(key: keyof object): boolean {
return (this._data[key] as unknown) instanceof Object;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<button mat-button class="theme" [matMenuTriggerFor]="themeMenu" i18n-aria-label aria-label="Choose a theme" [matTooltip]="themeSelectionToolTip">
<button mat-icon-button class="theme" [matMenuTriggerFor]="themeMenu" i18n-aria-label aria-label="Choose a theme" [matTooltip]="themeSelectionToolTip">
<mat-icon matListItemIcon aria-hidden="true" [fontIcon]="getIcon('fill')"></mat-icon>
</button>
<mat-menu #themeMenu="matMenu">
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/show-page.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

@if (data) {
<app-inspection-card [data]="data" [statuses]="statuses" [fields]="fields" [optionsFields]="optionsFields"/>

<app-inspection-list-grid [arrays]="arrays" [data]="data" />
}
<app-json-inspection [data]="data" />
}
2 changes: 2 additions & 0 deletions src/app/components/show-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Field } from '@app/types/column.type';
import { ShowActionButton } from '@app/types/components/show';
import { DataRaw } from '@app/types/data';
import { InspectionCardComponent } from './inspection/inspection-card.component';
import { InspectionJsonComponent } from './inspection/inspection-json.component';
import { InspectionListGridComponent } from './inspection/inspection-list-grid.component';
import { InspectionHeaderComponent } from './inspection-header.component';
import { InspectionToolbarComponent } from './inspection-toolbar.component';
Expand All @@ -26,6 +27,7 @@ span {
InspectionHeaderComponent,
InspectionListGridComponent,
InspectionToolbarComponent,
InspectionJsonComponent,
],
changeDetection: ChangeDetectionStrategy.OnPush
})
Expand Down
Loading

0 comments on commit 2b70828

Please sign in to comment.