Commit 6e8b3ac0 authored by FORESTIER Fabien's avatar FORESTIER Fabien
Browse files

Add data detail panel outside of the map

parent 498c18fd
<div *ngFor="let key of keys; let odd=odd; let even=even;" class="property" [ngClass]="{'even': even, 'odd': odd}">
<p class="property-key" *ngIf="!inputIsArray()" [ngClass]="{'is-parent': isParent && isPropertyObjectOrArray(key)}"
(click)="toggleProperty(key)">
<ng-container *ngIf="isParent && isPropertyObjectOrArray(key)">
<span class="icon-minus" *ngIf="isOpenProperties[key]"></span>
<span class="icon-plus" *ngIf="!isOpenProperties[key]"></span>
</ng-container>
<span>{{ key }}</span>
</p>
<div class="property-child" [ngClass]="{'is-hidden': (!isOpenProperties[key] && isParent)}">
<ng-container [ngSwitch]="getTypeOfProperty(key)">
<div *ngSwitchCase="'object'">
<app-dataset-data-detail-properties [properties]="properties[key]" [isParent]="false">
</app-dataset-data-detail-properties>
</div>
<div *ngSwitchCase="'array'">
<app-dataset-data-detail-properties [properties]="properties[key]" [isParent]="false">
</app-dataset-data-detail-properties>
</div>
<!-- Display the value. If it is url, display a link -->
<div *ngSwitchDefault class="property-value">
<span
*ngIf="!isUrl(properties[key])">{{ (properties[key] && properties[key] !== '') ? properties[key] : '-' }}</span>
<a [href]="properties[key]" *ngIf="isUrl(properties[key])">{{ properties[key] }}</a>
</div>
</ng-container>
</div>
</div>
\ No newline at end of file
@import "../../../../../../scss/variables";
.property-value {
font-weight: bold;
word-break: break-all;
}
.property-child {
display: block;
&.is-hidden {
display: none;
}
}
.property-key {
display: flex;
align-items: center;
.icon-minus {
height: 2px;
width: 10px;
margin-right: 0.5rem;
background: $grey-dark-color;
}
.icon-plus {
height: 2px;
width: 10px;
margin-right: 0.5rem;
background: $grey-dark-color;
position: relative;
&::after {
content: '';
height: 10px;
width: 2px;
background: $grey-dark-color;
position: absolute;
top: -4px;
left: 4px;
}
}
}
.is-parent {
cursor: pointer;
}
.property {
border: 1px solid #e8ecef;
padding: 0.625rem;
font-size: $size-7;
&.odd {
background-color: white;
}
&.even {
background-color: #f9f9f9;
}
}
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-dataset-data-detail-properties',
templateUrl: './dataset-data-detail-properties.component.html',
styleUrls: ['./dataset-data-detail-properties.component.scss'],
})
export class DatasetDataDetailPropertiesComponent implements OnInit {
@Input() properties: Object;
// This input is used to display complex objects.
// When the value is an array or object, we will hide in first place, then allow to toggle the element.
// But (because we use recurcivity, this compnent can call himself, cf template) if the value of the value
// is still an array or an object, we don't reproduce this behavior to hide. This toggle system is used
// only for the first data-detail component, not for the children.
@Input() isParent: boolean;
keys: string[];
isOpenProperties = {};
constructor() { }
ngOnInit() {
// Initilize the array with the keys of the json object received in the input
this.keys = this.getKeys(this.properties);
this.isOpenProperties = this.keys.reduce((acc, it) => {
acc[it] = (this.getTypeOfProperty(it) === 'object' || Array.isArray(this.properties[it])) ? false : true;
return acc;
// tslint:disable-next-line:align
}, {});
}
getKeys(obj) {
const keys = Object.keys(obj);
return keys;
}
// Return the type of the 'key' property of the input object
getTypeOfProperty(key: string) {
const type = typeof this.properties[key];
let res: string;
if (type === 'object' && Array.isArray(this.properties[key])) {
res = 'array';
} else {
res = type;
}
return res;
}
isPropertyObjectOrArray(key: string) {
return this.getTypeOfProperty(key) === 'object' || Array.isArray(this.properties[key]);
}
// Return true if the 'object' Input of the component is an array
inputIsArray() {
return Array.isArray(this.properties);
}
toggleProperty(key: string) {
if (this.getTypeOfProperty(key) === 'object' || Array.isArray(this.properties[key])) {
this.isOpenProperties[key] = !this.isOpenProperties[key];
}
}
isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
isUrl(value: any) {
const expression = 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)';
const regex = new RegExp(expression);
const isStringAndNotNull = value ? typeof value === 'string' : false;
return isStringAndNotNull ? value.match(regex) : false;
}
}
<div class="data-details">
<button class="close-button button is-danger" (click)="closeSelf()"><i class="fas fa-angle-right"></i></button>
<div class="properties">
<app-dataset-data-detail-properties [properties]="properties" [isParent]="true">
</app-dataset-data-detail-properties>
</div>
</div>
\ No newline at end of file
@import "../../../../../scss/variables";
.data-details {
background-color: white;
width: 100%;
height: 100%;
padding: 20px;
box-shadow: -2px 0px 5px -1px rgba(0, 0, 0, 0.3);
position: relative;
.close-button {
// background-color: $tomato-color;
// color: white;
border-radius: unset;
width: 2rem;
left: -2rem;
box-shadow: -2px 0px 5px -1px rgba(0, 0, 0, 0.3);
position: absolute;
}
.properties {
margin-top: 0.625rem;
overflow-y: auto;
width: 100%;
height: 100%;
}
}
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-dataset-data-details',
templateUrl: './dataset-data-details.component.html',
styleUrls: ['./dataset-data-details.component.scss'],
})
export class DatasetDataDetailsComponent implements OnInit {
@Input() properties;
@Output() close = new EventEmitter<boolean>();
constructor() { }
ngOnInit() {
}
get propertiesKeys() {
let keys;
if (this.properties) {
keys = Object.keys(this.properties);
}
return keys;
}
closeSelf() {
this.close.emit(true);
}
}
......@@ -73,14 +73,21 @@
</button>
</div>
</div>
<div class="table-map-container"
[ngClass]="{'noMap': !hasMap || (hasMap && !mapIsEnabled), 'noTable': !hasTable || (hasTable && !tableIsEnabled)}">
<div class="table-component-container" [attr.aria-hidden]="!hasTable || (hasTable && !tableIsEnabled)">
<app-dataset-table [selectedProperties]="selectedProperties">
<app-dataset-table [selectedProperties]="selectedProperties" (dataSelected)="onDataSelected($event)">
</app-dataset-table>
</div>
<div class="map-component-container" [attr.aria-hidden]="!hasMap || (hasMap && !mapIsEnabled)">
<app-dataset-map></app-dataset-map>
</div>
<div class="data-details-wrapper" *ngIf="selectedData !== null"
[ngClass]="{'data-details-opened': selectedData !== null && displayDataDetails === true, 'data-details-closed': displayDataDetails === false}">
<app-dataset-data-details (close)="closeDataDetails()" [properties]="selectedData" class="app-data-details">
</app-dataset-data-details>
</div>
</div>
</div>
\ No newline at end of file
......@@ -131,6 +131,7 @@
display: flex;
height: 80vh;
border-top: 1px solid $grey-super-light-color;
position: relative;
}
.table-component-container {
......@@ -181,3 +182,48 @@
flex-grow: 1;
}
}
.data-details-opened {
animation: open_details 200ms;
animation-fill-mode: forwards;
visibility: visible;
}
.data-details-closed {
animation: close_details 200ms;
animation-fill-mode: forwards;
}
@keyframes open_details {
from {
transform: translateX(400px);
}
to {
transform: translateX(0);
}
}
@keyframes close_details {
from {
transform: translateX(0);
}
to {
transform: translateX(400px);
}
}
.data-details-wrapper {
position: absolute;
width: 350px;
height: 100%;
right: 0;
top: 0;
z-index: 3;
max-width: 80%;
.app-dataset-data-details {
max-height: 100%;
}
}
......@@ -6,6 +6,7 @@ import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { Router, ActivatedRoute } from '@angular/router';
import { AppRoutes } from '../../../../routes';
import { Data } from '../../../models';
@Component({
selector: 'app-dataset-table-map',
......@@ -23,9 +24,11 @@ export class DatasetTableMapComponent implements OnInit, OnDestroy {
displayColumnsMenu = false;
mapIsEnabled = true;
tableIsEnabled = true;
displayDataDetails = true; // Wether the data details should be displayed or not
properties: string[];
selectedProperties: string[] = []; // Array of columns to be displayed
selectedData: Data = null; // Contains the properties of the selected feature
// search
searchInput = new FormControl('');
......@@ -133,6 +136,12 @@ export class DatasetTableMapComponent implements OnInit, OnDestroy {
this._datasetDetailService.searchChanged(this.searchInput.value);
}
onDataSelected(data: Data) {
console.log(data)
this.selectedData = data.properties;
this.displayDataDetails = true;
}
// Get the number of documents in this dataset
get datasetDataNumber() {
return this._datasetDetailService.datasetDataNumber;
......@@ -150,4 +159,8 @@ export class DatasetTableMapComponent implements OnInit, OnDestroy {
return this._datasetDetailService.isLoading;
}
closeDataDetails() {
this.displayDataDetails = false;
}
}
......@@ -15,7 +15,8 @@
</div>
<ng-container *ngFor="let element of data; let indexData = index;">
<div [class]="'item-grid' + ' item-grid-' + indexData" [ngClass]="{'is-first': indexRow === 0 }"
*ngFor="let key of selectedProperties; let indexRow=index;" (click)="setStyleForAllRow(indexData)">
*ngFor="let key of selectedProperties; let indexRow=index;"
(click)="setStyleForAllRow(indexData);emitSelectedData(element)">
<span *ngIf="!isPropertyComplex(element,key)" class="data-property-value">{{ element.properties[key] }}</span>
<span *ngIf="isPropertyComplex(element,key)">
<span class="tooltip-right" i18n-data-tooltip="@@dataset.data.tooltip"
......
import { Component, OnInit, ElementRef, QueryList, ViewChildren, OnDestroy, Input } from '@angular/core';
import { Component, OnInit, ElementRef, QueryList, ViewChildren, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
import { DatasetDetailService } from '../../../services';
import { Data } from '../../../models';
import { Subscription, Observable } from '../../../../../../node_modules/rxjs';
import { debounceTime } from '../../../../../../node_modules/rxjs/operators';
import { Subscription } from '../../../../../../node_modules/rxjs';
import { geosource } from '../../../../../i18n/traductions';
import { FormControl } from '@angular/forms';
import { AppRoutes } from '../../../../routes';
@Component({
......@@ -15,6 +13,10 @@ import { AppRoutes } from '../../../../routes';
export class DatasetTableComponent implements OnInit, OnDestroy {
@ViewChildren('itemsToCollapse', { read: ElementRef }) itemsToCollapseList: QueryList<ElementRef>;
// columns options
@Input() selectedProperties: string[] = []; // Array of columns to be displayed
@Output() dataSelected = new EventEmitter<Data>();
AppRoutes = AppRoutes;
data: Data[];
subscriptions: Subscription[] = [];
......@@ -33,9 +35,6 @@ export class DatasetTableComponent implements OnInit, OnDestroy {
previousSelectedRow: string;
// columns options
@Input() selectedProperties: string[] = []; // Array of columns to be displayed
constructor(
private _datasetDetailService: DatasetDetailService,
) { }
......@@ -144,6 +143,10 @@ export class DatasetTableComponent implements OnInit, OnDestroy {
});
}
emitSelectedData(data: Data) {
this.dataSelected.emit(data);
}
get sortValue() {
return this._datasetDetailService.sortValue;
}
......
......@@ -23,6 +23,8 @@ import { ResultDatasetComponent } from './results/result-dataset/result-dataset.
import { ResultsTabScopeComponent } from './results/results-tab-scope/results-tab-scope.component';
import { ResultPostComponent } from './results/result-post/result-post.component';
import { DatasetTableMapComponent } from './dataset-detail/dataset-table-map/dataset-table-map.component';
import { DatasetDataDetailsComponent } from './dataset-detail/dataset-data-details/dataset-data-details.component';
import { DatasetDataDetailPropertiesComponent } from './dataset-detail/dataset-data-details/dataset-data-detail-properties/dataset-data-detail-properties.component';
export {
DatasetDetailComponent,
......@@ -46,6 +48,8 @@ export {
ResultPostComponent,
ResourcesQueryableComponent,
IconFormatComponent,
DatasetDataDetailsComponent,
DatasetDataDetailPropertiesComponent,
};
// tslint:disable-next-line:variable-name
......@@ -71,4 +75,6 @@ export const GeosourceComponents = [
ResultPostComponent,
ResourcesQueryableComponent,
IconFormatComponent,
DatasetDataDetailsComponent,
DatasetDataDetailPropertiesComponent,
];
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment