Commit 77ee2ca3 authored by François Agneray's avatar François Agneray
Browse files

Merge branch '55-design-selectbox-output' into 'develop'

Resolve "Changer design selectbox page output"

Closes #55

See merge request !49
parents d3d872f5 21db22ec
Pipeline #1473 passed with stages
in 9 minutes and 18 seconds
......@@ -17,10 +17,10 @@ import { DetailService } from './detail.service';
import { AttributeService } from 'src/app/metamodel/services/attribute.service';
interface State {
router: fromRouter.RouterReducerState<utils.RouterStateUrl>,
metamodel: fromMetamodel.State,
search: fromSearch.State,
detail: fromDetail.State
router: fromRouter.RouterReducerState<utils.RouterStateUrl>;
metamodel: fromMetamodel.State;
search: fromSearch.State;
detail: fromDetail.State;
}
@Injectable()
......
......@@ -3,9 +3,9 @@ export interface Dataset {
table_ref: string;
label: string;
description: string;
illustration: string;
display: number;
count: number;
vo: boolean;
project_name: string;
id_dataset_family: number;
}
<div *ngFor="let attribute of getAttributeByFamily(criteriaFamily.id)">
<div *ngFor="let attribute of getAttributeListSortedByDisplay()">
<div [ngSwitch]="attribute.search_type">
<div *ngSwitchCase="'field'">
<app-field class="criteria" [id]="attribute.id" [operator]="attribute.operator"
......
......@@ -10,20 +10,18 @@ import { Family, Attribute, Option } from '../../../metamodel/model';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CriteriaByFamilyComponent {
@Input() criteriaFamily: Family;
@Input() datasetAttributeList: Attribute[];
@Input() attributeList: Attribute[];
@Input() criteriaList: Criterion[];
@Output() addCriterion: EventEmitter<Criterion> = new EventEmitter();
@Output() deleteCriterion: EventEmitter<number> = new EventEmitter();
getAttributeByFamily(idFamily: number): Attribute[] {
return this.datasetAttributeList
.filter(attribute => attribute.id_criteria_family === idFamily)
getAttributeListSortedByDisplay(): Attribute[] {
return this.attributeList
.sort((a, b) => a.criteria_display - b.criteria_display);
}
getOptions(idAttribute: number): Option[] {
return this.datasetAttributeList.find(attribute => attribute.id === idAttribute).options;
return this.attributeList.find(attribute => attribute.id === idAttribute).options;
}
getCriterion(id: number): Criterion {
......
......@@ -3,8 +3,7 @@
<p class="border-bottom bg-light text-primary py-4 pl-4">{{ criteriaFamilyList[0].label }}</p>
<div class="px-3">
<app-criteria-by-family
[criteriaFamily]="criteriaFamilyList[0]"
[datasetAttributeList]="datasetAttributeList"
[attributeList]="getAttributeByFamily(criteriaFamilyList[0].id)"
[criteriaList]="criteriaList"
(addCriterion)="add($event)"
(deleteCriterion)="delCriterion($event)">
......@@ -14,7 +13,7 @@
</div>
<accordion *ngIf="criteriaFamilyList.length > 1">
<ng-container *ngFor="let family of criteriaFamilyList">
<ng-container *ngFor="let family of getCriteriaFamilyListSortedByDisplay()">
<accordion-group #ag *ngIf="getAttributeByFamily(family.id).length > 0" [panelClass]="'custom-accordion'" [isOpen]="true"
class="my-2">
<button class="btn btn-link btn-block clearfix" accordion-heading>
......@@ -26,8 +25,7 @@
</div>
</button>
<app-criteria-by-family
[criteriaFamily]="family"
[datasetAttributeList]="datasetAttributeList"
[attributeList]="getAttributeByFamily(family.id)"
[criteriaList]="criteriaList"
(addCriterion)="add($event)"
(deleteCriterion)="delCriterion($event)">
......
......@@ -21,6 +21,11 @@ export class CriteriaTabsComponent {
.filter(attribute => attribute.id_criteria_family === idFamily);
}
getCriteriaFamilyListSortedByDisplay() {
return this.criteriaFamilyList
.sort((a, b) => a.display - b.display);
}
add(criterion: Criterion): void {
this.addCriterion.emit(criterion);
}
......
......@@ -2,10 +2,10 @@
<div class="border rounded my-2">
<p class="border-bottom bg-light text-primary py-4 pl-4">List of datasets</p>
<ul class="p-0">
<li *ngFor="let datasetName of datasetFamilyList[0].datasets; last as isLast"
<li *ngFor="let dataset of getDatasetListByFamily(datasetFamilyList[0].id); last as isLast"
class="list-unstyled px-3 pt-3 pb-0">
{{ i }}
<app-dataset-card [dataset]="getDataset(datasetName)" [project]="getProject(datasetName)"
<app-dataset-card [dataset]="dataset" [project]="getProject(dataset)"
[datasetSelected]="datasetSelected" (select)="select.emit($event)">
</app-dataset-card>
<hr *ngIf="!isLast">
......@@ -15,16 +15,16 @@
</div>
<tabset *ngIf="datasetFamilyList.length > 1" [justified]="true">
<tab *ngFor="let family of datasetFamilyList" heading="{{family.label}} ({{family.datasets.length}})">
<div *ngIf="family.datasets.length < 1" class="row align-items-center family-empty">
<tab *ngFor="let family of getDatasetFamilyListSortedByDisplay()" heading="{{family.label}} ({{getDatasetListByFamily(family.id).length}})">
<div *ngIf="getDatasetListByFamily(family.id).length < 1" class="row align-items-center family-empty">
<div class="col">
<p class="text-center">This family dataset is empty for now</p>
</div>
</div>
<ul *ngIf="family.datasets.length > 0" class="p-0">
<li *ngFor="let datasetName of family.datasets" class="list-unstyled p-1 mx-auto dataset-card">
<app-dataset-card [dataset]="getDataset(datasetName)" [project]="getProject(datasetName)"
<ul *ngIf="getDatasetListByFamily(family.id).length > 0" class="p-0">
<li *ngFor="let dataset of getDatasetListByFamily(family.id)" class="list-unstyled p-1 mx-auto dataset-card">
<app-dataset-card [dataset]="dataset" [project]="getProject(dataset)"
[datasetSelected]="datasetSelected" (select)="select.emit($event)">
</app-dataset-card>
</li>
......
......@@ -15,11 +15,18 @@ export class DatasetTabsComponent {
@Input() datasetSelected: string;
@Output() select: EventEmitter<string> = new EventEmitter();
getDataset(datasetName: string) {
return this.datasetList.find(dataset => dataset.name === datasetName);
getDatasetListByFamily(idFamily: number): Dataset[] {
return this.datasetList
.filter(d => d.id_dataset_family === idFamily)
.sort((a, b) => a.display - b.display);
}
getProject(datasetName: string) {
return this.projectList.find(project => project.name === this.getDataset(datasetName).project_name);
getDatasetFamilyListSortedByDisplay() {
return this.datasetFamilyList
.sort((a, b) => a.display - b.display);
}
getProject(dataset: Dataset): Project {
return this.projectList.find(project => project.name === dataset.project_name);
}
}
......@@ -5,6 +5,7 @@ import { CriteriaTabsComponent } from './criteria/criteria-tabs.component';
import { CriteriaByFamilyComponent } from './criteria/criteria-by-family.component';
import { OutputTabsComponent } from './output/output-tabs.component';
import { OutputByFamilyComponent } from './output/output-by-family.component';
import { OutputByCategoryComponent } from './output/output-by-category.component';
import { SummaryComponent } from './summary.component';
import { criteriaComponents } from './criteria/search-type';
import { UrlDisplayComponent } from './result/url-display.component';
......@@ -19,6 +20,7 @@ export const dummiesComponents = [
CriteriaByFamilyComponent,
OutputTabsComponent,
OutputByFamilyComponent,
OutputByCategoryComponent,
criteriaComponents,
SummaryComponent,
UrlDisplayComponent,
......
.selectbox {
height: 200px;
overflow-y: auto;
border: 1px solid #ced4da;
border-radius: .25rem;
}
.anis-color {
color: #7AC29A;
}
button:hover {
background-color: #F8F9FA;
}
button:focus {
box-shadow: none;
}
\ No newline at end of file
<p class="mb-3"><em>{{ categoryLabel }}</em></p>
<div class="selectbox py-1">
<button (click)="toggleSelectAll()" class="btn btn-block text-left py-0 m-0">
<div *ngIf="isAllSelected; then selected else unselected"></div>
<span *ngIf="!isAllSelected">Select All</span>
<span *ngIf="isAllSelected">Unselect All</span>
</button>
<hr class="my-1">
<button *ngFor="let attribute of getAttributeListSortedByDisplay()" class="btn btn-block text-left py-0 m-0"
(click)="toggleSelection(attribute.id)">
<div *ngIf="isSelected(attribute.id); then selected else unselected"></div>
{{ attribute.form_label }}
</button>
</div>
<ng-template #selected>
<span class="fa-stack fa-1x">
<i class="far fa-square fa-stack-1x text-secondary"></i>
<i class="fas fa-check fa-stack-1x anis-color"></i>
</span>
</ng-template>
<ng-template #unselected>
<span class="fa-stack fa-1x">
<i class="far fa-square fa-stack-1x text-secondary"></i>
</span>
</ng-template>
\ No newline at end of file
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
import { Attribute } from '../../../metamodel/model';
@Component({
selector: 'app-output-by-category',
templateUrl: 'output-by-category.component.html',
styleUrls: ['output-by-category.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OutputByCategoryComponent {
@Input() categoryLabel: string;
@Input() attributeList: Attribute[];
@Input() outputList: number[];
@Input() isAllSelected: boolean;
@Output() change: EventEmitter<number[]> = new EventEmitter();
getAttributeListSortedByDisplay() {
return this.attributeList
.sort((a, b) => a.output_display - b.output_display);
}
isSelected(id: number) {
return this.outputList.filter(i => i === id).length > 0;
}
toggleSelection(attributeId: number): void {
const clonedOutputList = [...this.outputList];
const index = clonedOutputList.indexOf(attributeId);
if (index > -1) {
clonedOutputList.splice(index, 1);
} else {
clonedOutputList.push(attributeId);
}
this.change.emit(clonedOutputList);
}
toggleSelectAll(): void {
const clonedOutputList = [...this.outputList];
const attributeListId = this.attributeList.map(a => a.id);
if (this.isAllSelected) {
attributeListId.forEach(id => {
const index = clonedOutputList.indexOf(id);
clonedOutputList.splice(index, 1);
});
} else {
attributeListId.filter(id => clonedOutputList.indexOf(id) === -1).forEach(id => {
clonedOutputList.push(id);
});
}
this.change.emit(clonedOutputList);
}
}
<div class="row">
<div *ngFor="let category of getCategoryByFamily(outputFamily.id)" class="col-12 col-md-6 text-center">
{{ category.label }}
<br />
<select class="form-control" multiple="multiple" size="10" (change)="change($event.target.options)">
<option *ngFor="let attribute of getAttributeByCategory(category.id)" [selected]="isSelected(attribute.id)"
[value]="attribute.id">
{{ attribute.form_label }}</option>
</select>
<div *ngFor="let category of getCategoryByFamilySortedByDisplay(outputFamily.id)" class="col-12 col-md-6 my-3 text-center">
<app-output-by-category
[categoryLabel]="category.label"
[attributeList]="getAttributeByCategory(category.id)"
[outputList]="outputList"
[isAllSelected]="getIsAllSelected(category.id)"
(change)="change($event)">
</app-output-by-category>
</div>
</div>
\ No newline at end of file
......@@ -14,33 +14,31 @@ export class OutputByFamilyComponent {
@Input() datasetAttributeList: Attribute[];
@Input() outputList: number[];
@Output() changed: EventEmitter<number[]> = new EventEmitter();
isAllSelected = false;
getCategoryByFamily(idFamily: number) {
getCategoryByFamilySortedByDisplay(idFamily: number): Category[] {
return this.categoryList
.filter(category => category.id_output_family === idFamily)
.sort((a, b) => a.display - b.display);
}
getAttributeByCategory(idCategory: number) {
getAttributeByCategory(idCategory: number): Attribute[] {
return this.datasetAttributeList
.filter(attribute => attribute.id_output_category === idCategory)
.sort((a, b) => a.output_display - b.output_display);
.filter(attribute => attribute.id_output_category === idCategory);
}
isSelected(id: number) {
return this.outputList.filter(i => i === id).length > 0;
getIsAllSelected(idCategory: number): boolean {
const attributeListId = this.getAttributeByCategory(idCategory).map(a => a.id)
const filteredOutputList = this.outputList.filter(id => attributeListId.indexOf(id) > -1);
return attributeListId.length === filteredOutputList.length;
}
change(options): void {
const clonedOutputList = [...this.outputList];
Array.apply(null, options).forEach(option => { // TODO: change Array.apply
if (option.selected && clonedOutputList.filter(i => i === +option.value).length < 1) {
clonedOutputList.push(+option.value);
} else if (!option.selected && clonedOutputList.filter(i => i === +option.value).length > 0) {
const index = clonedOutputList.indexOf(+option.value);
clonedOutputList.splice(index, 1);
}
});
this.changed.emit(clonedOutputList);
change(clonedOutputList: number[]): void {
this.changed.emit(
this.datasetAttributeList
.filter(a => clonedOutputList.indexOf(a.id) > -1)
.sort((a, b) => a.output_display - b.output_display)
.map(a => a.id)
);
}
}
.panel.card.custom-accordion .panel-heading.card-header .panel-title {
color: red;
}
\ No newline at end of file
......@@ -10,7 +10,7 @@
</div>
<accordion *ngIf="outputFamilyList.length > 1">
<accordion-group #ag *ngFor="let family of outputFamilyList" [panelClass]="'custom-accordion'" class="my-2"
<accordion-group #ag *ngFor="let family of getOutputFamilyListSortedByDisplay()" [panelClass]="'custom-accordion-output'" class="my-2"
[isOpen]="true">
<button class="btn btn-link btn-block clearfix" accordion-heading>
<div class="pull-left float-left">
......
......@@ -15,6 +15,11 @@ export class OutputTabsComponent {
@Input() outputList: number[];
@Output() changed: EventEmitter<number[]> = new EventEmitter();
getOutputFamilyListSortedByDisplay(): Family[] {
return this.outputFamilyList
.sort((a, b) => a.display - b.display);
}
change(clonedOutpuList: number[]): void {
this.changed.emit(clonedOutpuList);
}
......
......@@ -11,6 +11,7 @@ import { Criterion } from '../../store/model';
})
export class UrlDisplayComponent {
@Input() apiPath: string;
@Input() instanceName: string;
@Input() datasetName: string;
@Input() criteriaList: Criterion[];
@Input() outputList: number[];
......@@ -18,7 +19,7 @@ export class UrlDisplayComponent {
constructor(private toastr: ToastrService) { }
getUrl() {
let query = this.apiPath + '/data/' + this.datasetName + '?a=' + this.outputList.join(';');
let query = this.apiPath + '/' + this.instanceName + '/data/' + this.datasetName + '?a=' + this.outputList.join(';');
if (this.criteriaList.length > 0) {
query += '&c=' + this.criteriaList.map(criterion => criterion.getCriterionStr()).join(';');
}
......
......@@ -6,6 +6,7 @@
<div class="col-12 col-md-8">
<app-url-display
[apiPath]="apiPath"
[instanceName]="instanceName"
[datasetName]="datasetName | async"
[criteriaList]="criteriaList | async"
[outputList]="outputList | async">
......
......@@ -29,6 +29,7 @@ export class ResultComponent implements OnInit {
public attributeSearchMetaIsLoading: Observable<boolean>;
public attributeSearchMetaIsLoaded: Observable<boolean>;
public apiPath: string = environment.apiUrl + '/search';
public instanceName: string = environment.instanceName;
public datasetName: Observable<string>;
public currentStep: Observable<string>;
public datasetList: Observable<Dataset[]>;
......
Markdown is supported
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