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

#58 => done

parent 98f17f6b
......@@ -2,12 +2,14 @@
<table class="table table-bordered">
<thead>
<tr>
<th style="min-width:50px">ID</th>
<th style="min-width:150px">Name</th>
<th style="min-width:150px">Search flag</th>
<th style="min-width:150px">Label</th>
<th style="min-width:150px">FormLabel</th>
<th style="min-width:150px">Description</th>
<th style="width:50px">Save</th>
<th style="width:50px">Delete</th>
</tr>
</thead>
<tbody>
......
<td>
<input type="text" class="form-control" name="name" [formControl]="designForm.controls.name">
<input type="number" class="form-control" name="id" [formControl]="designForm.controls.id" required>
</td>
<td>
<input type="text" class="form-control" name="name" [formControl]="designForm.controls.name" required>
</td>
<td>
<select class="form-control" name="search_flag" [formControl]="designForm.controls.search_flag">
......@@ -21,3 +24,22 @@
<i class="fas fa-save"></i>
</button>
</td>
<td class="text-center align-middle">
<button title="Delete this attribute" (click)="openModal(template)" class="btn btn-outline-danger">
<i class="fas fa-trash-alt"></i>
</button>
</td>
<ng-template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">Confirm</h4>
</div>
<div class="modal-body">
<p>Are you sure you want to delete attribute with id <strong>{{ _attribute.id }}</strong> : <strong>{{ _attribute.name }}</strong> ?</p>
<p>
<button (click)="modalRef.hide()" class="btn btn-outline-primary">No</button>
&nbsp;
<button (click)="confirmDel()" class="btn btn-outline-danger">Yes</button>
</p>
</div>
</ng-template>
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, TemplateRef } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
import { SettingsSelectOption } from '../../../../settings/store/model';
import { Attribute } from '../../../store/model';
......@@ -13,6 +16,7 @@ import { Attribute } from '../../../store/model';
export class TrDesignComponent {
@Input() set attribute(attribute: Attribute) {
this._attribute = attribute;
this.designForm.controls.id.setValue(attribute.id);
this.designForm.controls.name.setValue(attribute.name);
this.designForm.controls.search_flag.setValue(attribute.search_flag);
this.designForm.controls.label.setValue(attribute.label);
......@@ -21,20 +25,35 @@ export class TrDesignComponent {
}
@Input() public searchFlags: SettingsSelectOption[];
@Output() public save: EventEmitter<Attribute> = new EventEmitter();
@Output() public delete: EventEmitter<Attribute> = new EventEmitter();
_attribute: Attribute;
designForm = new FormGroup({
name: new FormControl({value: '', disabled: true}),
id: new FormControl({value: '', disabled: true}),
name: new FormControl(),
search_flag: new FormControl(),
label: new FormControl(),
form_label: new FormControl(),
description: new FormControl()
});
modalRef: BsModalRef;
constructor(private modalService: BsModalService) { }
emitSave(): void {
this.save.emit({
...this._attribute,
...this.designForm.value
})
}
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
confirmDel() {
this.delete.emit(this._attribute);
this.modalRef.hide();
}
}
<div class="card">
<div class="btn-toolbar mb-3" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group mr-2" role="group" aria-label="First group">
<button (click)="openModal(templateForNew)" title="Add new attribute" class="btn btn-outline-success">
<span class="fas fa-plus"></span> New attribute
</button>
</div>
</div>
<div *ngIf="attributeList.length < 1" class="alert alert-warning" role="alert">
<i class="fas fa-exclamation-triangle"></i> You must add at least one attribute to use this dataset
</div>
<div *ngIf="attributeList.length > 0" class="card">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
......@@ -29,8 +41,12 @@
</div>
<div class="card-body" [ngSwitch]="tabSelected">
<app-table-design *ngSwitchCase="'design'">
<tr *ngFor="let attribute of attributeList" design [attribute]="attribute"
[searchFlags]="getSettingsSelectOptions('search_flag')" (save)="editAttribute.emit($event)">
<tr *ngFor="let attribute of attributeList"
design
[attribute]="attribute"
[searchFlags]="getSettingsSelectOptions('search_flag')"
(save)="editAttribute.emit($event)"
(delete)="deleteAttribute.emit($event)">
</tr>
</app-table-design>
<app-table-criteria *ngSwitchCase="'criteria'">
......@@ -42,6 +58,7 @@
[searchTypeList]="getSettingsSelectOptions('search_type')"
[operatorList]="getSettingsSelectOptions('operator')"
(save)="editAttribute.emit($event)"
(delete)="deleteAttribute($event)"
(generateOptionList)="generateAttributeOptionList.emit($event)">
</tr>
</app-table-criteria>
......@@ -84,3 +101,35 @@
</app-output-family-list>
</div>
</div>
<ng-template #templateForNew>
<div class="modal-header">
<h4 class="modal-title pull-left"><strong>Available columns</strong></h4>
</div>
<div class="modal-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let column of columnList">
<td>{{ column.name }}</td>
<td>{{ column.type }}</td>
<td>
<span *ngIf="alreadyExists(column.name)" class="badge badge-secondary">Already exists</span>
<button *ngIf="!alreadyExists(column.name)" (click)="addNewAttribute(column)" class="btn btn-outline-primary">Add</button>
</td>
</tr>
</tbody>
</table>
<p>
<button (click)="modalRef.hide()" class="btn btn-outline-primary">
Close
</button>
</p>
</div>
</ng-template>
\ No newline at end of file
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, TemplateRef } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
import { SettingsSelect, SettingsSelectOption } from '../../../settings/store/model';
import { Attribute, CriteriaFamily, OutputCategory, OutputFamily } from '../../store/model';
import { Attribute, Column, CriteriaFamily, OutputCategory, OutputFamily } from '../../store/model';
@Component({
selector: 'app-form-attribute-list',
......@@ -11,6 +14,7 @@ import { Attribute, CriteriaFamily, OutputCategory, OutputFamily } from '../../s
})
export class FormAttributeListComponent {
@Input() attributeList: Attribute[];
@Input() columnList: Column[];
@Input() optionListGenerated: string[];
@Input() criteriaFamilyList: CriteriaFamily[];
@Input() outputFamilyList: OutputFamily[];
......@@ -27,9 +31,43 @@ export class FormAttributeListComponent {
@Output() addOutputCategory: EventEmitter<OutputCategory> = new EventEmitter();
@Output() editOutputCategory: EventEmitter<OutputCategory> = new EventEmitter();
@Output() deleteOutputCategory: EventEmitter<OutputCategory> = new EventEmitter();
@Output() addAttribute: EventEmitter<Attribute> = new EventEmitter();
@Output() editAttribute: EventEmitter<Attribute> = new EventEmitter();
@Output() deleteAttribute: EventEmitter<Attribute> = new EventEmitter();
@Output() generateAttributeOptionList: EventEmitter<Attribute> = new EventEmitter();
modalRef: BsModalRef;
constructor(private modalService: BsModalService) { }
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
alreadyExists(columnName: string): boolean {
return this.attributeList.map(a => a.name).includes(columnName);
}
addNewAttribute(column: Column) {
let id = 1;
if (this.attributeList.length > 0) {
id = Math.max(...this.attributeList.map(a => a.id)) + 1;
}
this.addAttribute.emit({
id,
name: column.name,
label: column.name,
form_label: column.name,
type: column.type,
criteria_display: id * 10,
output_display: id * 10,
display_detail: id * 10,
order_display: id * 10,
selected: true
})
}
getSettingsSelectOptions(settingsSelectName: string): SettingsSelectOption[] {
const settingsSelect = this.settingsSelectList.find(o => o.name === settingsSelectName);
if (!settingsSelect) {
......
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Label</th>
<th>Save</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let attribute of attributeList">
<td>{{ attribute.id }}</td>
<td>{{ attribute.name }}</td>
<td>{{ attribute.label }}</td>
<td>
<button (click)="deleteAttribute.emit(attribute)" class="btn btn-outline-danger">
<i class="fas fa-trash-alt"></i> Delete attribute
</button>
</td>
</tr>
<tr *ngFor="let column of getColumnAvailable(); let index = index">
<td>{{ getMaxId() + index + 1 }}</td>
<td>{{ column.name }}</td>
<td>{{ column.name }}</td>
<td>
<button (click)="add(getMaxId() + index + 1, column)" class="btn btn-outline-primary">
<i class="fas fa-save"></i> Add attribute
</button>
</td>
</tr>
</tbody>
</table>
</div>
\ No newline at end of file
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter } from '@angular/core';
import { Attribute, Column } from '../../store/model';
@Component({
selector: 'app-form-manage-attribute',
templateUrl: 'form-manage-attribute.component.html',
styleUrls: [ 'form-manage-attribute.component.css' ],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FormManageAttributeComponent {
@Input() attributeList: Attribute[];
@Input() columnList: Column[];
@Output() addAttribute: EventEmitter<Attribute> = new EventEmitter();
@Output() deleteAttribute: EventEmitter<Attribute> = new EventEmitter();
getColumnAvailable(): Column[] {
return this.columnList.filter(c => !this.attributeList.map(a => a.name).includes(c.name));
}
getMaxId(): number {
return Math.max(...this.attributeList.map(a => a.id));
}
add(id: number, column: Column): void {
this.addAttribute.emit({
id,
name: column.name,
label: column.name,
form_label: column.name,
type: column.type,
criteria_display: id * 10,
output_display: id * 10,
display_detail: id * 10,
order_display: id * 10
})
}
}
import { FormManageAttributeComponent } from './form-manage-attribute.component';
import { FormAttributeListComponent } from './form-attribute-list.component';
import { TableDesignComponent } from './design/table-design.component';
import { TrDesignComponent } from './design/tr-design.component';
......@@ -25,7 +24,6 @@ import { OutputCategoryListComponent } from './families/output-category-list.co
import { FormOutputCategoryComponent } from './families/form-output-category.component';
export const attributeDummiesComponents = [
FormManageAttributeComponent,
FormAttributeListComponent,
TableDesignComponent,
TrDesignComponent,
......
......@@ -17,7 +17,9 @@
<div *ngIf="(attributeListIsLoaded | async)">
<div class="row mt-1">
<div class="col-12">
<app-form-attribute-list [attributeList]="attributeList | async"
<app-form-attribute-list
[attributeList]="attributeList | async"
[columnList]="columnList | async"
[optionListGenerated]="optionListGenerated | async"
[criteriaFamilyList]="criteriaFamilyList | async"
[outputFamilyList]="outputFamilyList | async"
......@@ -31,7 +33,9 @@
(addOutputFamily)="addOutputFamily($event)"
(editOutputFamily)="editOutputFamily($event)"
(deleteOutputFamily)="deleteOutputFamily($event)"
(addAttribute)="addAttribute($event)"
(editAttribute)="editAttribute($event)"
(deleteAttribute)="deleteAttribute($event)"
(addOutputCategory)="addOutputCategory($event)"
(editOutputCategory)="editOutputCategory($event)"
(deleteOutputCategory)="deleteOutputCategory($event)"
......
......@@ -3,7 +3,7 @@ import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Store } from '@ngrx/store';
import { Dataset, Attribute, CriteriaFamily, OutputCategory, OutputFamily } from '../../store/model';
import { Dataset, Attribute, Column, CriteriaFamily, OutputCategory, OutputFamily } from '../../store/model';
import { SettingsSelect, SettingsSelectOption } from '../../../settings/store/model';
import * as fromMetamodel from '../../store/reducer';
import * as fromSettings from '../../../settings/store/reducer';
......@@ -22,6 +22,8 @@ import * as selectActions from '../../../settings/store/action/select.action';
import * as selectSelector from '../../../settings/store/selector/select.selector';
import * as optionActions from '../../../settings/store/action/option.action';
import * as optionSelector from '../../../settings/store/selector/option.selector';
import * as databaseActions from '../../store/action/database.action';
import * as databaseSelector from '../../store/selector/database.selector';
@Component({
selector: 'app-attribute',
......@@ -38,6 +40,9 @@ export class AttributeComponent implements OnInit {
public attributeList: Observable<Attribute[]>;
public attributeListIsLoading: Observable<boolean>;
public attributeListIsLoaded: Observable<boolean>;
public columnList: Observable<Column[]>;
public columnListIsLoading: Observable<boolean>;
public columnListIsLoaded: Observable<boolean>;
public optionListGenerated: Observable<string[]>;
public criteriaFamilyList: Observable<CriteriaFamily[]>;
public outputFamilyList: Observable<OutputFamily[]>;
......@@ -55,6 +60,9 @@ export class AttributeComponent implements OnInit {
this.attributeList = store.select(attributeSelector.getAttributeList);
this.attributeListIsLoading = store.select(attributeSelector.getAttributeListIsLoading);
this.attributeListIsLoaded = store.select(attributeSelector.getAttributeListIsLoaded);
this.columnList = store.select(databaseSelector.getColumnList);
this.columnListIsLoading = store.select(databaseSelector.getColumnListIsLoading);
this.columnListIsLoaded = store.select(databaseSelector.getColumnListIsLoaded);
this.optionListGenerated = store.select(attributeSelector.getOptionListGenerated);
this.criteriaFamilyList = store.select(criteriaFamilySelector.getCriteriaFamilyList);
this.outputFamilyList = store.select(outputFamilySelector.getOutputFamilyList);
......@@ -71,6 +79,7 @@ export class AttributeComponent implements OnInit {
this.store.dispatch(new criteriaFamilyActions.LoadCriteriaFamilyListAction());
this.store.dispatch(new outputFamilyActions.LoadOutputFamilyListAction());
this.store.dispatch(new outputCategoryActions.LoadOutputCategoryListAction());
this.store.dispatch(new databaseActions.LoadColumnListAction());
}
addCriteriaFamily(criteriaFamily: CriteriaFamily) {
......@@ -109,10 +118,18 @@ export class AttributeComponent implements OnInit {
this.store.dispatch(new outputCategoryActions.DeleteOutputCategoryAction(outputCategory));
}
addAttribute(attribute: Attribute) {
this.store.dispatch(new attributeActions.AddNewAttributeAction(attribute));
}
editAttribute(attribute: Attribute) {
this.store.dispatch(new attributeActions.EditAttributeAction(attribute));
}
deleteAttribute(attribute: Attribute) {
this.store.dispatch(new attributeActions.DeleteAttributeAction(attribute));
}
generateAttributeOptionList(attribute: Attribute) {
this.store.dispatch(new attributeActions.GenerateOptionListAction(attribute));
}
......
<div class="container-fluid">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a routerLink="/instance-list">Instances</a></li>
<li class="breadcrumb-item"><a routerLink="/configure-instance/{{ instanceSelected | async }}">Configure
instance {{ instanceSelected | async }}</a></li>
<li class="breadcrumb-item active" aria-current="page">Manage attributes
{{ datasetSelected | async }}</li>
</ol>
</nav>
<div *ngIf="(attributeListIsLoading | async) || (columnListIsLoading | async)" class="row justify-content-center mt-5">
<span class="fas fa-circle-notch fa-spin fa-3x"></span>
<span class="sr-only">Loading...</span>
</div>
<div *ngIf="(attributeListIsLoaded | async) && (columnListIsLoaded | async)">
<app-form-manage-attribute
[attributeList]="attributeList | async"
[columnList]="columnList | async"
(addAttribute)="addAttribute($event)"
(deleteAttribute)="deleteAttribute($event)">
</app-form-manage-attribute>
</div>
</div>
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Store } from '@ngrx/store';
import { Attribute, Column} from '../../store/model';
import * as projectActions from '../../store/action/project.action';
import * as datasetActions from '../../store/action/dataset.action';
import * as attributeActions from '../../store/action/attribute.action';
import * as databaseActions from '../../store/action/database.action';
import * as attributeSelector from '../../store/selector/attribute.selector';
import * as datasetSelector from '../../store/selector/dataset.selector';
import * as instanceSelector from '../../store/selector/instance.selector';
import * as databaseSelector from '../../store/selector/database.selector';
import * as metamodelReducer from '../../store/reducer';
@Component({
selector: 'app-manage-attribute',
templateUrl: 'manage-attribute.component.html',
styleUrls: [ 'manage-attribute.component.css' ]
})
export class ManageAttributeComponent implements OnInit {
public instanceSelected: Observable<string>;
public datasetSelected: Observable<string>;
public attributeList: Observable<Attribute[]>;
public attributeListIsLoading: Observable<boolean>;
public attributeListIsLoaded: Observable<boolean>;
public columnList: Observable<Column[]>;
public columnListIsLoading: Observable<boolean>;
public columnListIsLoaded: Observable<boolean>;
constructor(private store: Store<metamodelReducer.State>) {
this.instanceSelected = store.select(instanceSelector.getInstanceSelected);
this.datasetSelected = store.select(datasetSelector.getDatasetSelected);
this.attributeList = store.select(attributeSelector.getAttributeList);
this.attributeListIsLoading = store.select(attributeSelector.getAttributeListIsLoading);
this.attributeListIsLoaded = store.select(attributeSelector.getAttributeListIsLoaded);
this.columnList = store.select(databaseSelector.getColumnList);
this.columnListIsLoading = store.select(databaseSelector.getColumnListIsLoading);
this.columnListIsLoaded = store.select(databaseSelector.getColumnListIsLoaded);
}
ngOnInit() {
this.store.dispatch(new projectActions.LoadProjectListAction());
this.store.dispatch(new datasetActions.LoadDatasetListAction());
this.store.dispatch(new attributeActions.LoadAttributeListAction());
this.store.dispatch(new databaseActions.LoadColumnListAction());
}
addAttribute(attribute: Attribute): void {
this.store.dispatch(new attributeActions.AddNewAttributeAction(attribute));
}
deleteAttribute(attribute: Attribute): void {
this.store.dispatch(new attributeActions.DeleteAttributeAction(attribute));
}
}
......@@ -13,7 +13,6 @@ import { NewInstanceComponent } from './containers/instance/new-instance.compone
import { EditInstanceComponent } from './containers/instance/edit-instance.component';
import { ConfigureInstanceComponent } from './containers/instance/configure-instance.component';
import { NewDatasetComponent } from './containers/dataset/new-dataset.component';
import { ManageAttributeComponent } from './containers/attribute/manage-attribute.component';
import { EditDatasetComponent } from './containers/dataset/edit-dataset.component';
import { AttributeComponent } from './containers/attribute/attribute.component';
import { GroupComponent } from './containers/group/group.component';
......@@ -31,7 +30,6 @@ const routes: Routes = [
{ path: 'configure-instance/:iname/new-group', component: NewGroupComponent },
{ path: 'configure-instance/:iname/edit-group/:id', component: EditGroupComponent },
{ path: 'configure-instance/:iname/new-dataset', component: NewDatasetComponent },
{ path: 'configure-instance/:iname/manage-attribute/:dname', component: ManageAttributeComponent },
{ path: 'configure-instance/:iname/edit-dataset/:dname', component: EditDatasetComponent },
{ path: 'configure-instance/:iname/configure-dataset/:dname', component: AttributeComponent },
{
......@@ -77,7 +75,6 @@ export const routedComponents = [
EditDatabaseComponent,
ConfigureInstanceComponent,
NewDatasetComponent,
ManageAttributeComponent,
EditDatasetComponent,
AttributeComponent,
GroupComponent,
......
......@@ -62,9 +62,8 @@ export class DatasetEffects {
ofType(datasetActions.ADD_NEW_DATASET_SUCCESS),
withLatestFrom(this.store$),
map(([action, state]) => {
const addNewDatasetSuccessAction = action as datasetActions.AddNewDatasetSuccessAction;
const instanceName = state.router.state.params.iname;
this.router.navigate(['/configure-instance/' + instanceName + '/manage-attribute/' + addNewDatasetSuccessAction.payload.name]);
this.router.navigate(['/configure-instance/' + instanceName]);
this.toastr.success('Add dataset success!', 'The new dataset has been created!');
})
);
......
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