Commit df7318d0 authored by Rajkumar-D's avatar Rajkumar-D
Browse files

Adding checklist table changes

parent 589cf5b5
Pipeline #175923 passed with stages
in 5 minutes and 36 seconds
......@@ -49,3 +49,61 @@ mat-card {
.mat-row:hover {
background-color: #f0f5f5;
}
.w-5{
width: 5%;
}
.w-10{
width: 10%;
}
.w-20{
width: 20%;
}
.w-30{
width: 30%;
}
.w-70{
width: 70%;
}
mat-select{
width: 70% !important;
}
.table {
background: white;
}
.mat-row:nth-child(even) {
background-color: #f8f8f8;
}
.mat-header-cell{
font-weight: bold;
font-size: 14px;
color: #000000c7;
}
.mat-option-text {
overflow: auto !important;
text-overflow: unset !important;
}
.infoText{
float: right;
margin-right: 32px;
cursor: pointer;
}
.addIcon{
font-size: 34px;
padding-top: 0px;
vertical-align: middle;
cursor: pointer;
}
.searchSpan{
float: right;
margin-right: 10px;
}
\ No newline at end of file
......@@ -138,70 +138,100 @@
You have selected <b>{{ selectedChecklist.name }}</b>. Please select the checklist fields below.
</p>
<div class="mat-elevation-z8">
<mat-accordion>
<mat-expansion-panel *ngFor="let fieldGroup of selectedChecklist.fieldGroups">
<!-- Show checklist fields in table-->
<mat-card class="mat-body">
<div class="tableOperations">
<!-- form for custom field validation. -->
<form #cf="ngForm">
<mat-form-field class="app-field-padding">
<input matInput placeholder="Add custom field" [(ngModel)]="customField"
pattern="^[A-Za-z0-9_-]*$" name="customField" #customText />
<mat-error *ngIf="cf.controls['customField']?.errors">
Alphanumeric charecters with _ and - are allowed.
</mat-error>
</mat-form-field>
<mat-icon class=" app-primary-color addIcon" [disabled]="cf.invalid"
(click)="addCustomField(customField,customText,accordion,cf)">add_box
</mat-icon>
<span style=" margin-left: 30px;">
Show Description <mat-checkbox matInput [(ngModel)]="isChecked"
(change)="addDescription(isChecked)" style="padding-left: 20px" name="showDesc">
</mat-checkbox>
</span>
<span class="searchSpan">
<mat-form-field class="app-field-padding">
<input matInput type="filter" [(ngModel)]="filter" placeholder="Search fields"
(keyup)="applyFilter($event.target.value,accordion)" name="filter" />
</mat-form-field>
<mat-icon class=" app-primary-color addIcon" (click)="applyFilter(filter)">pageview</mat-icon>
</span>
</form>
</div>
<!-- Field accordions -->
<mat-accordion [multi]="false" #accordion="matAccordion">
<!-- Mandatory fields-->
<mat-expansion-panel #firstPanel *ngIf="mandatoryFieldsDataSource.data.length > 0"
(opened)=" panelOpenState=true" (closed)="panelOpenState = false" class="mat-body"
[expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
{{ fieldGroup.name
}}<span fxHide fxShow.gt-sm>
{{ getSelectedFieldsDisplayText(fieldGroup) }}</span>
<b>Mandatory Fields</b>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template *ngIf="mandatoryFieldsDataSource" [ngTemplateOutlet]="checklistFieldsTable"
[ngTemplateOutletContext]="{datasource:mandatoryFieldsDataSource}">
</ng-template>
</mat-expansion-panel>
<!-- Recommended Fields -->
<mat-expansion-panel *ngIf="recommendedFieldsDataSource.data.length > 0"
(opened)="panelOpenState = true" (closed)="panelOpenState = false" class="mat-body">
<div *ngFor="let field of fieldGroup.fields">
<mat-checkbox [(ngModel)]="selectedFields[field.label]" [disabled]="mandatoryFields[field.label]">
{{
field.label
}}
</mat-checkbox>
<p fxHide fxShow.gt-sm>
<i>{{ field.mandatory }}
{{ getFieldTypeDisplayText(field) }}</i>
</p>
<!--
<p *ngIf="checklistType === ChecklistType.sequence">
{{field.name}}
</p>
-->
<p>
{{ field.description }}
</p>
<div fxLayout="row">
<div fxFlex="200px">
<p *ngIf="field.units.length > 0">
<mat-select class="checklist-restriction" placeholder="Permitted units">
<mat-option *ngFor="let unit of field.units" [value]="unit" disabled>
{{ unit }}
</mat-option>
</mat-select>
</p>
<p *ngIf="field.regexValue" class="checklist-restriction">
<mat-select class="checklist-restriction" placeholder="Regular expression">
<mat-option disabled>
{{ field.regexValue }}
</mat-option>
</mat-select>
</p>
<p *ngIf="
field.textChoice && field.textChoice.length > 0
">
<mat-select class="checklist-restriction" placeholder="Permitted values">
<mat-option *ngFor="let textChoice of field.textChoice" [value]="textChoice" disabled>
{{ textChoice }}
</mat-option>
</mat-select>
</p>
<p *ngIf="field.ontologyId" class="checklist-restriction">
Permitted ontology: {{ field.ontologyId }}
</p>
</div>
<div fxFlex></div>
</div>
</div>
<mat-expansion-panel-header>
<mat-panel-title>
<b>Recommended Fields</b>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template [ngTemplateOutlet]="checklistFieldsTable"
[ngTemplateOutletContext]="{datasource:recommendedFieldsDataSource}">
</ng-template>
</mat-expansion-panel>
<!-- Optional Fields -->
<mat-expansion-panel *ngIf="optionalFieldsDataSource.data.length > 0" (opened)="panelOpenState = true"
(closed)="panelOpenState = false" class="mat-body">
<mat-expansion-panel-header>
<mat-panel-title>
<b>Optional Fields</b>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template [ngTemplateOutlet]="checklistFieldsTable"
[ngTemplateOutletContext]="{datasource:optionalFieldsDataSource}">
</ng-template>
</mat-expansion-panel>
<!-- Custom Fields -->
<mat-expansion-panel *ngIf="customFieldsDataSource && customFieldsDataSource.data.length > 0"
(opened)="panelOpenState = true" (closed)="panelOpenState = false" class="mat-body"
#customFieldsPanel [hideToggle]="true">
<mat-expansion-panel-header>
<mat-panel-title>
<b>Custom Fields</b>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template [ngTemplateOutlet]="checklistFieldsTable"
[ngTemplateOutletContext]="{datasource:customFieldsDataSource}">
</ng-template>
</mat-expansion-panel>
</mat-accordion>
</div>
<!-- Field accordions -->
</mat-card>
</div>
<div>
<button mat-button matStepperPrevious>Back</button>
......@@ -285,4 +315,87 @@
</mat-accordion>
</div>
</div>
\ No newline at end of file
</div>
<!-- Template for displaying checklist-->
<ng-template #checklistFieldsTable let-datasource="datasource">
<table mat-table class="mat-body" *ngIf="datasource" #table [dataSource]="datasource" class="mat-elevation-z8"
multiTemplateDataRows>
<ng-container matColumnDef="selection">
<th mat-header-cell *matHeaderCellDef class="w-5">Selection</th>
<td mat-cell *matCellDef="let element">
<mat-checkbox *ngIf="element.mandatory=='mandatory'" matInput [checked]="true" disabled
[(ngModel)]="selectedFields[element.label]" style="padding-left: 20px"></mat-checkbox>
<mat-checkbox *ngIf="element.mandatory=='recommended'" matInput [checked]="true"
[(ngModel)]="selectedFields[element.label]" style="padding-left: 20px">
</mat-checkbox>
<mat-checkbox *ngIf="element.mandatory=='optional'" matInput [checked]="false"
[(ngModel)]="selectedFields[element.label]" style="padding-left: 20px">
</mat-checkbox>
</td>
</ng-container>
<ng-container *ngIf="checklistType === ChecklistType.sequence" matColumnDef="fieldLabel">
<th mat-header-cell *matHeaderCellDef class="w-10">Field Label</th>
<td mat-cell *matCellDef="let element">{{ element.label }}
</td>
</ng-container>
<ng-container matColumnDef="fieldName">
<th mat-header-cell *matHeaderCellDef class="w-10">Field Name</th>
<td mat-cell *matCellDef="let element">{{ element.name }}
</td>
</ng-container>
<ng-container matColumnDef="validation">
<th mat-header-cell *matHeaderCellDef class="w-20">Validation</th>
<td mat-cell *matCellDef="let element">
<mat-select class="w-70" *ngIf="element.type=='TEXT_CHOICE_FIELD'" class="checklist-restriction"
placeholder="Permitted values">
<mat-option *ngFor="let textChoice of element.textChoice" [value]="textChoice" disabled>
{{ textChoice }}
</mat-option>
</mat-select>
<mat-select *ngIf="element.regexValue" class="checklist-restriction" placeholder="Regular expression">
<mat-option disabled>
{{ element.regexValue }}
</mat-option>
</mat-select>
<p *ngIf="element.type=='TEXT_FIELD' && !element.regexValue">
Text field
</p>
</td>
</ng-container>
<ng-container matColumnDef="units">
<th mat-header-cell *matHeaderCellDef class="w-5">Units</th>
<td mat-cell *matCellDef="let element">
<p *ngIf="element.units && element.units.length > 0">
{{ element.units }}
</p>
<p *ngIf="!element.units || element.units.length <= 0">
None
</p>
</td>
</ng-container>
<ng-container *ngIf="showDescription" matColumnDef="description">
<th mat-header-cell *matHeaderCellDef class="w-30">Description</th>
<td mat-cell *matCellDef="let element">{{ element.description }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="fieldsDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: fieldsDisplayedColumns; when: isVisible"></tr>
</table>
</ng-template>
\ No newline at end of file
......@@ -9,9 +9,10 @@
* specific language governing permissions and limitations under the License.
*/
import { Component, Input, ViewEncapsulation, OnInit } from '@angular/core';
import { Component, Input, ViewEncapsulation, OnInit, Optional, Inject, ViewChild, QueryList, ElementRef, ViewChildren } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { MatTableDataSource, MatDialog } from '@angular/material';
import { MatTableDataSource, MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatExpansionPanel } from '@angular/material';
import { saveAs } from 'file-saver';
import { retry, mergeMap, map } from 'rxjs/operators';
import { ChecklistType } from '../checklist-type.enum';
......@@ -28,22 +29,38 @@ import { PopupMessageComponent } from '../popup-message/popup-message.component'
import { UtilService } from '../util/Util-services'
import { SubmissionResultDialogComponent } from '../submission-result-dialog/submission-result-dialog.component';
import { NonSubmissionResultDialogComponent } from '../non-submission-result-dialog/non-submission-result-dialog.component';
import { ReleaseDatePopupComponent } from '../release-date-popup/release-date-popup/release-date-popup.component';
interface BooleanFieldInterface {
[key: string]: boolean;
}
export interface GroupBy {
fieldType: string;
isGroupBy: boolean;
}
@Component({
selector: 'app-checklist',
templateUrl: './checklist.component.html',
styleUrls: ['./checklist.component.css'],
encapsulation: ViewEncapsulation.None
})
export class ChecklistComponent implements OnInit {
@ViewChild('customFieldsPanel', { static: false }) customFieldsPanel: MatExpansionPanel;
//@ViewChild(MatExpansionPanel, { static: false }) customFieldsPanel: MatExpansionPanel;
@Input() checklistType: ChecklistType;
@Input() init = true;
panelOpenState: boolean = false;
//@ViewChildren(MatExpansionPanel) matExpansionPanelQueryList: QueryList<MatExpansionPanel>;
//@ViewChild('itemDescInput', { static: true }) itemDescInput: ElementRef;
ChecklistType = ChecklistType; // Allows use in template
private _checklistGroups: Array<ChecklistGroupInterface>;
......@@ -61,7 +78,20 @@ export class ChecklistComponent implements OnInit {
active: boolean;
dataError: string;
spreadSheet: File;
checklistFields = [];
mandatoryFieldsDataSource: MatTableDataSource<any>;
recommendedFieldsDataSource: MatTableDataSource<any>;
optionalFieldsDataSource: MatTableDataSource<any>;
customFields: ChecklistFieldInterface;
customFieldsDataSource: MatTableDataSource<any>;
fieldsDisplayedColumns: string[] = [
"selection",
"fieldName",
"validation",
"units",
];
showDescription = false;
constructor(
private _webinAuthenticationService: WebinAuthenticationService,
private _webinReportService: WebinReportService,
......@@ -69,7 +99,9 @@ export class ChecklistComponent implements OnInit {
private _route: ActivatedRoute,
public dialog: MatDialog,
private util: UtilService,
private router: Router) {
private router: Router,
) {
if (_route) {
switch (_route.snapshot.data.checklistType) {
case 'sample': {
......@@ -95,8 +127,10 @@ export class ChecklistComponent implements OnInit {
this.initChecklists();
}
// Adding fieldLabel only for sequence.
if (this.checklistType === ChecklistType.sequence) {
this.insertAt(this.fieldsDisplayedColumns, 1, "fieldLabel");
}
}
// field group restriction type (not supported for spreadsheets)
......@@ -178,6 +212,30 @@ export class ChecklistComponent implements OnInit {
this.mandatoryFields[field.label] = (field.mandatory === 'mandatory');
});
});
/** Code for checklist table view */
let mandatoryChecklistFields = [];
let recommendedChecklistFields = [];
let optionalChecklistFields = [];
this.selectedChecklist.fieldGroups.forEach((fieldGroup) => {
this.getValidFields(fieldGroup, 'mandatory') ? mandatoryChecklistFields = mandatoryChecklistFields.concat(this.getValidFields(fieldGroup, 'mandatory')) : "do nothing";
this.getValidFields(fieldGroup, 'recommended') ? recommendedChecklistFields = recommendedChecklistFields.concat(this.getValidFields(fieldGroup, 'recommended')) : "do nothing";
this.getValidFields(fieldGroup, 'optional') ? optionalChecklistFields = optionalChecklistFields.concat(this.getValidFields(fieldGroup, 'optional')) : "do nothing";
});
/** Spilit the fields based on their type */
this.mandatoryFieldsDataSource = new MatTableDataSource<any>(mandatoryChecklistFields);
this.recommendedFieldsDataSource = new MatTableDataSource<any>(recommendedChecklistFields);
this.optionalFieldsDataSource = new MatTableDataSource<any>(optionalChecklistFields);
// Setting filterPredicate that is used for filtering.
this.mandatoryFieldsDataSource.filterPredicate = this.getPredicate();
this.recommendedFieldsDataSource.filterPredicate = this.getPredicate();
this.optionalFieldsDataSource.filterPredicate = this.getPredicate();
stepper.next();
}
......@@ -467,6 +525,91 @@ export class ChecklistComponent implements OnInit {
}
getPredicate() {
return (data: ChecklistFieldInterface, filter: string) => data.label.trim().toLowerCase().indexOf(filter.trim().toLowerCase()) != -1;
}
applyFilter(filterValue: string, accordion: any) {
// If the filter text is empty close all expansion panel.
if (filterValue != "") {
accordion.multi = true;
accordion.openAll();
filterValue = filterValue.trim();
filterValue = filterValue.toLowerCase();
} else {
// Open all expansions while filter text is not empty.
accordion.closeAll();
accordion.multi = false;
}
this.mandatoryFieldsDataSource.filter = filterValue;
this.recommendedFieldsDataSource.filter = filterValue;
this.optionalFieldsDataSource.filter = filterValue;
this.customFieldsDataSource.filter = filterValue;
}
addCustomField(customField: string, customText, accordion, form) {
if (!form.invalid) {
this.customFields = this.getCustomField(customField);
this.selectedFields[customField] = true;
// Get custom field group if already added to selectedChecklist.fieldGroups
let customFieldGroup: ChecklistFieldGroupInterface = this.selectedChecklist.fieldGroups.filter(fieldGroup => fieldGroup.name === "custom_fields")[0];
if (customFieldGroup) {
customFieldGroup.fields.push(this.customFields);
} else {
// create new custom field group
customFieldGroup = { "name": "custom_fields", fields: [this.customFields] };
this.selectedChecklist.fieldGroups.push(customFieldGroup);
}
this.customFieldsDataSource = new MatTableDataSource<any>(customFieldGroup.fields);
this.customFieldsDataSource.filterPredicate = this.getPredicate();
this.showSuccessPopup("Successfully added custom field '" + customField + "'. The field can be viewed in custom fields grouping below.", "Custom field");
customText.value = "";
//opening custom panal is not woeking as expected so closing all the panels after adding custom field.
accordion.multi = true;
accordion.closeAll();
accordion.multi = false;
//this.customFieldsPanel.open();
}
}
showSuccessPopup(message, title) {
const dialogRef = this.dialog.open(PopupMessageComponent, {
width: '500px',
backdropClass: 'custom-dialog-backdrop-class',
panelClass: 'custom-dialog-panel-class',
data: { 'action': 'SuccessAndClose', 'message': message, 'title': title }
});
}
getValidFields(fieldGroup, fieldType) {
let fieldArr = fieldGroup.fields.filter(field => field.mandatory === fieldType);
if (fieldArr && fieldArr.length > 0) {
return fieldArr;
}
}
addDescription(isChecked) {
if (isChecked) {
this.fieldsDisplayedColumns.push("description");
this.showDescription = true;
} else {
this.fieldsDisplayedColumns.pop()
this.showDescription = false;
}
}
// The below method is used to insert value to exact position of an array.
insertAt(array, index, elementsArray) {
array.splice(index, 0, elementsArray);
}
uploadFile(form) {
if (!this._webinRestService.isValidTabSubmissionFile(form.spreadSheet)) {
this.util.showError(this, NonSubmissionResultDialogComponent, "The uploaded file is not valid for sample submission. Please upload file in any of the following format: .csv, .tsv, .tab", "Submission Result")
......@@ -490,6 +633,18 @@ export class ChecklistComponent implements OnInit {
}
}
getCustomField(customFieldValue) {
return {
"name": customFieldValue,
"label": customFieldValue,
"type": "TEXT_FIELD",
"mandatory": "recommended",
"description": "custom field",
"units": [],
"textChoice": []
};
}
getSampleSpecificFields() {
let sampleSpecificFields = {
name: "Sample Details",
......@@ -500,7 +655,8 @@ export class ChecklistComponent implements OnInit {
mandatory: "mandatory",
textChoice: [],
type: "TEXT_FIELD",
units: []
units: [],
isVisible: true
},
{
name: "sample_title",
......@@ -509,7 +665,8 @@ export class ChecklistComponent implements OnInit {
mandatory: "mandatory",
textChoice: [],
type: "TEXT_FIELD",
units: []
units: [],
isVisible: true
},
{
name: "sample_description",
......@@ -518,7 +675,8 @@ export class ChecklistComponent implements OnInit {
mandatory: "mandatory",
textChoice: [],
type: "TEXT_FIELD",
units: []
units: [],
isVisible: true
}]
}
return sampleSpecificFields;
......
......@@ -42,8 +42,6 @@
</mat-card>
<ng-container>
<mat-card class="mat-elevation-z8 mat-card-css">
<mat-card-title class="cardTitle"> Studies (Projects) </mat-card-title>
......@@ -190,20 +188,21 @@
</ng-container>
<ng-container>
<mat-card *ngIf="!isEga()" class="mat-elevation-z8 mat-card-css">
<mat-card class="mat-elevation-z8 mat-card-css">
<mat-card-title class="cardTitle"> Data Analyses</mat-card-title>
<mat-card-subtitle class="cardSubTitle">Assemblies and annotated sequences must be submitted with <a
href="https://ena-docs.readthedocs.io/en/latest/reads/webin-cli.html">Webin-CLI</a>. Other analyses can be
<mat-card-subtitle class="cardSubTitle" *ngIf="!isEga()">Assemblies and annotated sequences must be submitted
with <a href="https://ena-docs.readthedocs.io/en/latest/reads/webin-cli.html">Webin-CLI</a>. Other analyses
can be
submitted as XMLs.
</mat-card-subtitle>
<div class="cat-element">
<div class="cat-element">
<div class="cat-column1">
<span [routerLink]="['/app-checklist','sequence',true]">
<span *ngIf="!isEga()" [routerLink]="['/app-checklist','sequence',true]">
</