Commit 8bd44424 authored by FORESTIER Fabien's avatar FORESTIER Fabien
Browse files

Merge branch 'fusion-table-map-universe' into feature-389-conditional_tabs

parents f8aeacfd aa1fb918
......@@ -28,9 +28,6 @@ export class DatasetDataComponent implements OnInit, OnDestroy {
message: string = null;
maximumNumberOfData = 10000;
// Opened data
openedData: number[] = [];
// search
searchInput = new FormControl('');
......@@ -110,18 +107,6 @@ export class DatasetDataComponent implements OnInit, OnDestroy {
return this._datasetDetailService.datasetDataNumber;
}
// Add or Remove the id (given in the code) of the data
// from the array of openned data (details displayed)
toogleData(num: number) {
// If id found remove it from array alse add it to array
const index = this.openedData.findIndex(e => e === num);
if (index !== -1) {
this.openedData.splice(index, 1);
} else {
this.openedData.push(num);
}
}
toogleColumsMenu() {
this.displayColumnsMenu = !this.displayColumnsMenu;
}
......@@ -132,14 +117,7 @@ export class DatasetDataComponent implements OnInit, OnDestroy {
}
}
// If id of the data is in array return true (details should be displayed)
isDataOpened(index: number): boolean {
return this.openedData.findIndex(e => e === index) !== -1;
}
sortBy(key: string) {
// Set the new sort value in the service
this.openedData = [];
this._datasetDetailService.sortBy(key);
this.newAsyncRequest();
// Retrieve date sorted with the new value
......@@ -157,7 +135,6 @@ export class DatasetDataComponent implements OnInit, OnDestroy {
// Get the new data
this._datasetDetailService.retrieveDatasetData().subscribe((data) => {
this.asyncRequestDone();
this.openedData = [];
this.data = data;
});
}
......
<div class="columns is-multiline page-header">
<div class="restricted-access-container" *ngIf="isSample">
<app-restricted-access-banner></app-restricted-access-banner>
</div>
<div class="column is-paddingless">
<div class="documents-number">
<span class="documents-number">
<span class="research-documents-number">
{{ researchMaxResult }}
</span>
<span>/ {{ datasetDataNumber }}</span>
<span i18n="@@dataset.data.recordsFound"> records found</span>
</span>
</div>
<div class="search-container">
<div class="control has-icons-left search-control" [ngClass]="{'is-loading': isLoading}">
<span class="icon is-medium is-left">
<svg xmlns="http://www.w3.org/2000/svg" id="loupe" viewBox="0 0 17 16">
<path
d="M9 3zM3.5 4.5zM15.8 14.4h-.1l-3.1-3.1v-.1h-.8v.9l3.1 3.1.8-.8zM3.7 12.1zM9.9 1.5C9 1 8.1.8 7 .8c-1.1 0-2 .2-2.9.7C3.2 2 2.5 2.7 2 3.6c-.5.9-.8 1.8-.8 2.9 0 1.1.3 2 .8 2.9.5.9 1.2 1.6 2.1 2.1.9.5 1.8.7 2.9.7 1.3 0 2.5-.4 3.5-1.2l.6-.4.4-.6c.8-1 1.2-2.2 1.2-3.5 0-1.1-.3-2-.8-2.9-.4-.9-1.1-1.6-2-2.1m-7 2.6c.4-.7 1-1.3 1.7-1.7.7-.4 1.5-.6 2.4-.6.9 0 1.6.2 2.4.6.7.4 1.3 1 1.7 1.7.4.7.6 1.5.6 2.4 0 .9-.2 1.7-.6 2.4-.4.7-1 1.3-1.7 1.7-.8.4-1.5.6-2.4.6-.9 0-1.7-.2-2.4-.6-.7-.4-1.3-1-1.7-1.7-.4-.7-.7-1.5-.7-2.4 0-.9.3-1.6.7-2.4z"
class="st0" />
</svg>
</span>
<input type="text" [formControl]="searchInput" class="input" placeholder="Filter records"
i18n-placeholder="@@dataset.data.filterReccordPlaceholder">
</div>
</div>
</div>
<div class="column is-paddingless">
<div class="properties-number">
<span><span
class="selected-properties-number">{{ selectedProperties.length }}</span><span>/{{ properties.length }}</span>
<span i18n="@@dataset.data.displayedProperties"> displayed properties</span></span>
</div>
<div class="dropdown properties-dropdown" [ngClass]="{'is-active': displayColumnsMenu}"
(clickOutside)="closeColumsMenu()">
<div class="dropdown-trigger">
<button class="button button-gl is-outlined" aria-haspopup="true" aria-controls="dropdown-menu"
(click)="toogleColumsMenu()" i18n="@@dataset.data.customizeButton">
Customize
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content has-text-left">
<div class="field dropdown-item" *ngFor="let prop of properties">
<input class="is-checkradio has-error is-small" [id]="prop" type="checkbox" name="selectedColumns"
[checked]="columnIsSelected(prop) !== -1" (click)="toogleColumn(prop)">
<label [for]="prop">{{ prop }}</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="data-table" infinite-scroll [infiniteScrollDistance]="scrollDistance"
[infiniteScrollUpDistance]="scrollUpDistance" [infiniteScrollThrottle]="throttle" [scrollWindow]="false"
(scrolled)="onScrollDown()" [ngStyle]="getStyle()">
<div class=" item-grid column-header" *ngFor="let key of selectedProperties" (click)="sortBy(key)">
<span class="sort-icons">
<span class="icon">
<i class="fas fa-sort-up" [ngClass]="{'icon-red': sortValue === key && sortOrder === 'desc'}"></i>
</span>
<span class="icon">
<i class="fas fa-sort-down" [ngClass]="{'icon-red': sortValue === key && sortOrder === 'asc'}"></i>
</span>
</span>
<span class="column-title" [ngClass]="{'active': sortValue === key}">{{ key }}</span>
</div>
<ng-container *ngFor="let element of data; let i=index; let even=even;">
<div class="item-grid" [ngClass]="'item-grid-' + i" *ngFor="let key of selectedProperties"
(click)="setStyleForAllRow(i)">
<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"
data-tooltip="Complex property, please unfold the line">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="14" fill="none" viewBox="0 0 16 14">
<path fill="#fff"
d="M15.581 12.031c.146.292.191.584.137.875-.055.31-.2.565-.438.766-.237.219-.52.328-.848.328H1.308c-.329 0-.611-.11-.848-.328a1.26 1.26 0 0 1-.438-.766 1.356 1.356 0 0 1 .137-.875L6.722.656c.164-.291.392-.483.683-.574.31-.11.61-.11.903 0 .31.091.546.283.71.574l6.563 11.375zM7.87 9.68c-.346 0-.647.127-.902.383a1.19 1.19 0 0 0-.356.874c0 .347.119.648.356.903.255.237.556.355.902.355s.638-.118.875-.355c.255-.255.383-.556.383-.902 0-.347-.128-.639-.383-.876a1.147 1.147 0 0 0-.875-.382zM6.667 5.168l.219 3.719c0 .073.027.146.082.218a.4.4 0 0 0 .246.082h1.312a.296.296 0 0 0 .219-.082c.073-.072.11-.145.11-.218l.218-3.719c0-.11-.036-.191-.11-.246a.26.26 0 0 0-.218-.11h-1.75a.34.34 0 0 0-.246.11c-.055.055-.082.137-.082.246z" />
</svg>
<span class="warning-complexity" i18n="@@dataset.data.complexProperty">Complex property</span>
</span>
</span>
</div>
</ng-container>
</div>
\ No newline at end of file
@import "../../../../../scss/variables";
@import "../../../../../../node_modules/bulma/sass/utilities/_all";
:root {
--colNum: 1;
}
.data-table {
display: grid;
max-height: 80vh;
overflow: auto;
grid-template-rows: 44px repeat(auto-fill, 35px);
grid-auto-rows: 35px;
// grid-template-columns: repeat(var(--colNum), 1fr);
}
.item-grid {
display: flex;
align-items: center;
padding-right: 1rem;
cursor: pointer;
}
.selected {
background-color: #f1f3f8;
span {
color: $tomato-color;
}
}
.column-header {
position: sticky;
top: 0;
background-color: $grey-background-color;
display: flex;
justify-content: flex-start;
border-bottom: 1px solid $grey-super-light-color;
span {
cursor: pointer;
}
.sort-icons {
display: flex;
flex-direction: column;
align-self: center;
.icon {
height: 0.2rem;
width: unset;
justify-content: center;
}
.icon-red {
color: $tomato-color;
}
}
.column-title {
margin-left: 0.3rem;
}
}
.arrows {
svg {
/* stylelint-disable-line */
margin-right: 1rem;
width: 16px;
fill: $grey-dark-color;
transform: rotate(-90deg);
}
}
import { Component, OnInit, ElementRef, QueryList, ViewChildren, OnDestroy } from '@angular/core';
import { DatasetDetailService } from '../../../services';
import { Data } from '../../../models';
import { Subscription } from '../../../../../../node_modules/rxjs';
import { debounceTime } from '../../../../../../node_modules/rxjs/operators';
import { geosource } from '../../../../../i18n/traductions';
import { FormControl } from '@angular/forms';
import { AppRoutes } from '../../../../routes';
@Component({
selector: 'app-dataset-table',
templateUrl: './dataset-table.component.html',
styleUrls: ['./dataset-table.component.scss'],
})
export class DatasetTableComponent implements OnInit, OnDestroy {
@ViewChildren('itemsToCollapse', { read: ElementRef }) itemsToCollapseList: QueryList<ElementRef>;
AppRoutes = AppRoutes;
data: Data[];
subscriptions: Subscription[] = [];
// Count the number of currently running queries in order do display or not a loading icon
private _pendingRequests: number = 0;
isSample = false;
// Infinite scroll
throttle = 300;
scrollDistance = 1;
scrollUpDistance = 2;
message: string = null;
maximumNumberOfData = 10000;
// Opened data
openedData: number[] = [];
// search
searchInput = new FormControl('');
previousSelectedRow: string;
// columns options
displayColumnsMenu = false;
selectedProperties: string[] = []; // Array of columns to be displayed
properties: string[];
// maxDisplayedColumns = 5; // Set the max number of columns to be displayed in the table
constructor(
private _datasetDetailService: DatasetDetailService,
) { }
ngOnInit() {
this.initializeComponent();
// Intialize the search value with the value from the service in order to keep it when navigating in tabs
this.searchInput.setValue(this._datasetDetailService.searchString);
this.subscriptions.push(
// Subscribe to input changes
this.searchInput.valueChanges.pipe(debounceTime(500)).subscribe(() => {
this.searchChanged();
}),
// Subscribe to dataset changes
this._datasetDetailService.dataset$.subscribe(() => {
this.initializeComponent();
}),
);
}
ngOnDestroy() {
this.subscriptions.forEach((sub) => {
sub.unsubscribe();
});
}
initializeComponent() {
this.isSample = this._datasetDetailService.dataset.editorialMetadata.isSample;
this.data = this._datasetDetailService.datasetData;
this.properties = [];
if (this.data && this.data.length > 0) {
// If dataset has data, initialize an array with the
// the key of each property
this.properties = this._datasetDetailService.dataset.fields.list;
// Initialize an array with max 'maxDisplayedColumns' properties
this.selectedProperties = Array.from(this.properties);
}
}
getStyle() {
return {
// 'grid-template-columns': `repeat(${this.selectedProperties.length}, minmax(50px, 1fr)`,
'grid-template-columns': `repeat(${this.selectedProperties.length}, max-content`,
};
}
setStyleForAllRow(index) {
// Remove the style form previous selected row
Array.from(document.getElementsByClassName(this.previousSelectedRow)).forEach((el) => {
el.className = el.className.replace(/\bselected\b/g, '');
});
const className = `item-grid-${index}`;
Array.from(document.getElementsByClassName(className)).forEach((el) => {
el.className += ' selected';
});
this.previousSelectedRow = className;
}
// Method called when the scrolled down
onScrollDown() {
// Only call the service if the actual number of data is smaller than the
// total number of data found for this reseach
if (this.data.length < this.researchMaxResult) {
// Increase the from value to get more data
this._datasetDetailService.nextPage();
// Make sure from + size (in the service) dont exceed maximumNumberOfData, limit set by elasticsearch
// if a request is made with a size and from and the sum of those is over maximumNumberOfData it will
// cause an internal error in elaticsearch and the request will fail
if (this._datasetDetailService.scrollOptionsSum <= this.maximumNumberOfData) {
// Update the array of data with the newly retrieved data (size shoul have increased by 'size' value)
this._datasetDetailService.retrieveMoreDatasetData().subscribe((data) => {
this.data = data;
});
} else {
this.message = `${geosource.datasetData.maxDataDisplayedMessage}${this.maximumNumberOfData}.`;
}
} else {
// console.log('Already retrieved all occurences');
}
}
// Get the number of documents in this dataset
get datasetDataNumber() {
return this._datasetDetailService.datasetDataNumber;
}
// Add or Remove the id (given in the code) of the data
// from the array of openned data (details displayed)
toogleData(num: number) {
// If id found remove it from array alse add it to array
const index = this.openedData.findIndex(e => e === num);
if (index !== -1) {
this.openedData.splice(index, 1);
} else {
this.openedData.push(num);
}
}
toogleColumsMenu() {
this.displayColumnsMenu = !this.displayColumnsMenu;
}
closeColumsMenu() {
if (this.displayColumnsMenu) {
this.displayColumnsMenu = false;
}
}
sortBy(key: string) {
// Set the new sort value in the service
this.openedData = [];
this._datasetDetailService.sortBy(key);
this.newAsyncRequest();
// Retrieve date sorted with the new value
this._datasetDetailService.retrieveDatasetData().subscribe((data) => {
this.asyncRequestDone();
this.data = data;
});
}
searchChanged() {
this._datasetDetailService.searchChanged(this.searchInput.value);
this.newAsyncRequest();
// Get the new data
this._datasetDetailService.retrieveDatasetData().subscribe((data) => {
this.asyncRequestDone();
this.openedData = [];
this.data = data;
});
}
get sortValue() {
return this._datasetDetailService.sortValue;
}
get sortOrder() {
return this._datasetDetailService.sortOrder;
}
get researchMaxResult() {
return this._datasetDetailService.researchMaxResult;
}
// Returns the index if found in the array, -1 if not found
columnIsSelected(name: string) {
return this.selectedProperties.findIndex(e => e === name);
}
// Return the type of the 'key' property of the input object
isPropertyComplex(element, key: string) {
const type = typeof element.properties[key];
return type === 'object' || Array.isArray(element.properties[key]);
}
toogleColumn(name: string) {
const index = this.selectedProperties.findIndex(e => e === name);
// If value found remove it from the array
if (index !== -1) {
this.selectedProperties.splice(index, 1);
} else {
// If not found add the value to the array
this.selectedProperties.push(name);
}
}
// Increments the number of curretly running async request by one
newAsyncRequest() {
this._pendingRequests += 1;
}
// Decrement the number of async requests by one
asyncRequestDone() {
this._pendingRequests -= 1;
}
// Return true if http queries are being made
get isLoading() {
return this._pendingRequests > 0 ? true : false;
}
}
......@@ -11,6 +11,7 @@ import { ResourceDownloadableComponent } from './dataset-detail/dataset-resource
import { DatasetMapComponent } from './dataset-detail/dataset-map/dataset-map.component';
import { DatasetInfoComponent } from './dataset-detail/dataset-info/dataset-info.component';
import { DatasetDataComponent } from './dataset-detail/dataset-data/dataset-data.component';
import { DatasetTableComponent } from './dataset-detail/dataset-table/dataset-table.component';
import { DataPropertiesComponent } from './dataset-detail/dataset-data/data-properties/data-properties.component';
import { IconFormatComponent } from './dataset-detail/dataset-resources/icon-format/icon-format.component';
import { SearchBarComponent } from './search-bar/search-bar.component';
......@@ -31,7 +32,11 @@ export {
DatasetMapComponent,
DatasetInfoComponent,
DatasetDataComponent,
<<<<<<< HEAD
DatasetTableMapComponent,
=======
DatasetTableComponent,
>>>>>>> fusion-table-map-universe
ResultsComponent,
SearchBarComponent,
ResearchComponent,
......@@ -55,7 +60,11 @@ export const GeosourceComponents = [
DatasetMapComponent,
DatasetInfoComponent,
DatasetDataComponent,
<<<<<<< HEAD
DatasetTableMapComponent,
=======
DatasetTableComponent,
>>>>>>> fusion-table-map-universe
ResultsComponent,
SearchBarComponent,
ResearchComponent,
......
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
<<<<<<< HEAD
import {
ResultsComponent, DatasetDetailComponent, ResearchComponent, DatasetInfoComponent,
DatasetMapComponent, DatasetResourcesComponent, DatasetDataComponent, DatasetTableMapComponent
} from './components';
=======
import { ResultsComponent, DatasetDetailComponent, ResearchComponent, DatasetInfoComponent,
DatasetMapComponent, DatasetResourcesComponent, DatasetTableComponent } from './components';
>>>>>>> fusion-table-map-universe
import { AppRoutes } from '../routes';
export const routes: Routes = [
......@@ -42,7 +47,11 @@ export const routes: Routes = [
},
{
path: AppRoutes.data.uri,
<<<<<<< HEAD
component: DatasetTableMapComponent,
=======
component: DatasetTableComponent,
>>>>>>> fusion-table-map-universe
data: {
title: AppRoutes.data.title,
},
......
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