Skip to content

Commit 5670a1d

Browse files
committed
in progress
1 parent 2225a9c commit 5670a1d

14 files changed

+551
-6
lines changed

src/main/ngapp/src/app/app-routing.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
} from "./components/admin/admin-web-of-registries/admin-web-of-registries.component";
3030
import {AdminSampleRequestsComponent} from "./components/admin/admin-sample-requests/admin-sample-requests.component";
3131
import {AdminPublicGroupsComponent} from "./components/admin/admin-public-groups/admin-public-groups.component";
32+
import {AdminCustomFieldsComponent} from "./components/admin/admin-custom-fields/admin-custom-fields.component";
3233

3334
const routes: Routes = [
3435
{path: '', redirectTo: '/collection/personal', pathMatch: 'full'},
@@ -80,7 +81,8 @@ const routes: Routes = [
8081
{path: 'users', component: AdminUsersComponent},
8182
{path: 'web', component: AdminWebOfRegistriesComponent},
8283
{path: 'samples', component: AdminSampleRequestsComponent},
83-
{path: 'groups', component: AdminPublicGroupsComponent}
84+
{path: 'groups', component: AdminPublicGroupsComponent},
85+
{path: 'fields', component: AdminCustomFieldsComponent}
8486
]
8587
}, // todo resolver
8688
{path: 'create/:type', component: CreateNewEntryComponent},

src/main/ngapp/src/app/app.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ import {
5353
} from './components/admin/admin-web-of-registries/admin-web-of-registries.component';
5454
import {AdminSampleRequestsComponent} from './components/admin/admin-sample-requests/admin-sample-requests.component';
5555
import {AdminPublicGroupsComponent} from './components/admin/admin-public-groups/admin-public-groups.component';
56+
import {AdminCustomFieldsComponent} from './components/admin/admin-custom-fields/admin-custom-fields.component';
57+
import {
58+
EditCustomFieldModalComponent
59+
} from './components/modal/edit-custom-field-modal/edit-custom-field-modal.component';
5660

5761
// register Handsontable's modules
5862
registerAllModules();
@@ -102,6 +106,8 @@ registerAllModules();
102106
AdminWebOfRegistriesComponent,
103107
AdminSampleRequestsComponent,
104108
AdminPublicGroupsComponent,
109+
AdminCustomFieldsComponent,
110+
EditCustomFieldModalComponent,
105111
],
106112
imports: [
107113
BrowserModule,

src/main/ngapp/src/app/components/admin/admin-custom-fields/admin-custom-fields.component.css

Whitespace-only changes.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<div class="container-fluid">
2+
<div class="row">
3+
<div class="col p-3">
4+
<div ng-controller="AdminCustomFieldsController" style="height: 1050px">
5+
6+
<uib-tabset class="pad_top">
7+
<uib-tab select="selectedTab('plasmid')">
8+
<uib-tab-heading>Plasmid</uib-tab-heading>
9+
</uib-tab>
10+
11+
<uib-tab select="selectedTab('strain')">
12+
<uib-tab-heading>Strain</uib-tab-heading>
13+
</uib-tab>
14+
15+
<uib-tab select="selectedTab('part')">
16+
<uib-tab-heading>Part</uib-tab-heading>
17+
</uib-tab>
18+
19+
<uib-tab select="selectedTab('seed')">
20+
<uib-tab-heading>Seed</uib-tab-heading>
21+
</uib-tab>
22+
23+
<uib-tab select="selectedTab('protein')">
24+
<uib-tab-heading>Protein</uib-tab-heading>
25+
</uib-tab>
26+
27+
</uib-tabset>
28+
29+
<br>
30+
<button class="ice-button" ng-click="addNewCustomEntryField()">Create Custom Field</button>
31+
<br><br>
32+
33+
<div ng-if="partCustomFields.length">
34+
<table class="table table-border-bottom table-hover table-condensed font-95em"
35+
ng-class="{'opacity_4':loadingPage}">
36+
<thead>
37+
<th>Label</th>
38+
<th>Field Type</th>
39+
<th>Entry Type</th>
40+
<th>Required</th>
41+
<th>Value(s)</th>
42+
<th></th>
43+
</thead>
44+
<tbody ng-repeat="field in partCustomFields">
45+
<tr>
46+
<td>{{field.label}}</td>
47+
<td>{{optionsText(field.fieldType)}}</td>
48+
<td>{{field.entryType}}</td>
49+
<td style="text-align: center; width: 80px">
50+
<i class="fa fa-fw fa-check green" ng-if="field.required"></i></td>
51+
<td>
52+
<div ng-repeat="option in field.options">{{option.name}}</div>
53+
</td>
54+
<td style="width: 180px; border: 1px solid #ccc; vertical-align: middle">
55+
<i ng-if="!field.delete" class="fa fa-fw fa-trash-o opacity_hover font-14em"
56+
ng-click="field.delete = true"></i>
57+
<span ng-if="field.delete">Permanently remove field?<br>
58+
<button class="btn btn-xs btn-primary" ng-click="deleteCustomField(field)">Yes</button>
59+
<button class="btn btn-xs btn-default" ng-click="field.delete = false">No</button>
60+
</span>
61+
</td>
62+
</tr>
63+
</tbody>
64+
</table>
65+
</div>
66+
67+
<div class="pad_top" ng-if="!partCustomFields.length">
68+
<i>No custom fields available for parts of type <b class="text-muted">{{selection | capitalize}}</b></i>
69+
</div>
70+
71+
</div>
72+
</div>
73+
</div>
74+
</div>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {ComponentFixture, TestBed} from '@angular/core/testing';
2+
3+
import {AdminCustomFieldsComponent} from './admin-custom-fields.component';
4+
5+
describe('AdminCustomFieldsComponent', () => {
6+
let component: AdminCustomFieldsComponent;
7+
let fixture: ComponentFixture<AdminCustomFieldsComponent>;
8+
9+
beforeEach(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [AdminCustomFieldsComponent]
12+
});
13+
fixture = TestBed.createComponent(AdminCustomFieldsComponent);
14+
component = fixture.componentInstance;
15+
fixture.detectChanges();
16+
});
17+
18+
it('should create', () => {
19+
expect(component).toBeTruthy();
20+
});
21+
});
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {Component} from '@angular/core';
2+
import {HttpService} from "../../../services/http.service";
3+
import {NgbModal, NgbModalOptions} from "@ng-bootstrap/ng-bootstrap";
4+
import {EditCustomFieldModalComponent} from "../../modal/edit-custom-field-modal/edit-custom-field-modal.component";
5+
6+
@Component({
7+
selector: 'app-admin-custom-fields',
8+
templateUrl: './admin-custom-fields.component.html',
9+
styleUrls: ['./admin-custom-fields.component.css']
10+
})
11+
export class AdminCustomFieldsComponent {
12+
13+
selection = 'plasmid';
14+
loading: boolean;
15+
partCustomFields: any;
16+
17+
constructor(private http: HttpService, private modalService: NgbModal) {
18+
this.retrievePartFields();
19+
}
20+
21+
options = [
22+
{name: "Built in field", value: 'EXISTING'},
23+
{name: 'Text', value: 'TEXT_INPUT'},
24+
{name: 'Options', value: 'MULTI_CHOICE'},
25+
{name: 'Options with Text', value: 'MULTI_CHOICE_PLUS'}];
26+
27+
optionsText(value: string): string {
28+
for (let i = 0; i < this.options.length; i += 1) {
29+
if (value === this.options[i].value) {
30+
return this.options[i].name;
31+
}
32+
}
33+
return value;
34+
}
35+
36+
retrievePartFields(): void {
37+
this.partCustomFields = undefined;
38+
this.loading = true;
39+
this.http.get("rest/fields/" + this.selection).subscribe({
40+
next: (result: any) => {
41+
this.partCustomFields = result.data;
42+
}
43+
});
44+
};
45+
46+
selectedTab(selection: string): void {
47+
if (this.selection === selection)
48+
return;
49+
50+
this.selection = selection;
51+
this.retrievePartFields();
52+
};
53+
54+
deleteCustomField(customField: any): void {
55+
this.http.delete("rest/fields/" + customField.entryType + "/" + customField.id)
56+
.subscribe({
57+
next: (result: any) => {
58+
const index = this.partCustomFields.indexOf(customField);
59+
if (index !== -1)
60+
this.partCustomFields.splice(index, 1);
61+
}
62+
});
63+
};
64+
65+
addNewCustomEntryField() {
66+
const options: NgbModalOptions = {backdrop: 'static', size: 'md'};
67+
const modalInstance = this.modalService.open(EditCustomFieldModalComponent, options);
68+
modalInstance.componentInstance.entryType = this.selection;
69+
70+
modalInstance.result.then((result) => {
71+
if (!result)
72+
return;
73+
74+
if (!this.partCustomFields)
75+
this.partCustomFields = [];
76+
this.partCustomFields.push(result);
77+
});
78+
};
79+
}
80+
81+
Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,88 @@
1-
<p>admin-public-groups works!</p>
1+
<div>
2+
<div class="pad_top">
3+
<button type="button" (click)="openCreatePublicGroupModal(null)" class="ice-button">
4+
Create Public Group
5+
</button>
6+
</div>
7+
8+
<div class="pad_top" *ngIf="!groups.length">
9+
<i class="text-muted">No public groups available</i>
10+
</div>
11+
12+
<div class="pad_top" *ngIf="groups.length" style="width: 96%">
13+
<table class="table table-hover table-border-bottom" [ngClass]="{'opacity_4':loadingPage}">
14+
<thead>
15+
<tr>
16+
<th>&nbsp;</th>
17+
<th class="entry-table-header" style="width: 360px">Label</th>
18+
<th class="entry-table-header" style="width: 130px">Members</th>
19+
<th class="entry-table-header">Created</th>
20+
<th style="width:120px"></th>
21+
</tr>
22+
</thead>
23+
<tbody>
24+
<tr data-ng-repeat="group in groups">
25+
<td style="vertical-align: middle; line-height:1; opacity:0.2; text-shadow:0 1px 0 #fff"
26+
class="font-14em">
27+
<b></b>
28+
</td>
29+
<td>{{group.label}}
30+
<br>
31+
<i class="small text-muted">{{group.description || 'No description provided'}}</i>
32+
</td>
33+
<td style="width:180px; white-space:nowrap; vertical-align: middle">
34+
<span class="label"
35+
[ngClass]="{
36+
'label-primary': group.memberCount,
37+
'label-default': group.memberCount == 0}">{{group.memberCount | number}}
38+
</span>
39+
</td>
40+
<td style="width:190px">
41+
{{group.ownerEmail}} <br>
42+
<small class="text-muted">{{group.creationTime | date:'MMM d, yyyy'}}</small>
43+
</td>
44+
<td style="border-left: 1px solid #EEEEEE; width:150px; white-space:nowrap; vertical-align: middle">
45+
<div *ngIf="!group.confirmDeleteGroup">
46+
<i class="fa fa-fw fa-pencil font-14em edit_icon" [ngbTooltip]="'Edit'"
47+
(click)="openCreatePublicGroupModal(group)"></i>
48+
&nbsp;
49+
<i class="fa fa-fw fa-trash font-14em delete_icon" (click)="group.confirmDeleteGroup = true"
50+
[ngbTooltip]="'Delete'"></i>
51+
</div>
52+
53+
<div *ngIf="group.confirmDeleteGroup">
54+
Delete?
55+
<button class="btn btn-primary btn-xs" (click)="deletePublicGroup(group)">Yes</button>
56+
<button class="btn btn-default btn-xs" (click)="group.confirmDeleteGroup=false">No</button>
57+
</div>
58+
</td>
59+
</tr>
60+
</tbody>
61+
</table>
62+
63+
<div class="col-md-5" style="padding-left: 0">
64+
<ngb-pagination [collectionSize]="paging.available" [pageSize]="paging.limit" [(page)]="paging.currentPage"
65+
[boundaryLinks]="true" [maxSize]="5" (pageChange)="pageChange($event)" size="sm">
66+
<ng-template ngbPaginationFirst><i
67+
class="fa fa-fw fa-angle-double-left"></i> First
68+
</ng-template>
69+
<ng-template ngbPaginationPrevious><i
70+
class="fa fa-fw fa-angle-left"></i>Prev
71+
</ng-template>
72+
<!-- <ng-template ngbPaginationNumber let-p><button class="btn btn-sm btn-white">{{p}}</button></ng-template>-->
73+
<ng-template ngbPaginationNext>Next<i
74+
class="fa fa-fw fa-angle-right"></i></ng-template>
75+
<ng-template ngbPaginationLast>Last<i
76+
class="fa fa-fw fa-angle-double-right"></i>
77+
</ng-template>
78+
</ngb-pagination>
79+
</div>
80+
81+
<div class="col-md-7" style="margin-top: 25px;">
82+
<strong class="small">
83+
<i *ngIf="loadingPage" class="fa fa-spin fa-gear opacity_4"></i>
84+
{{pageNumber | number}} - {{pageCount | number}} of {{paging.available}}
85+
</strong>
86+
</div>
87+
</div>
88+
</div>

src/main/ngapp/src/app/components/admin/admin-public-groups/admin-public-groups.component.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import {Component} from '@angular/core';
2+
import {HttpService} from "../../../services/http.service";
3+
import {Group} from "../../../models/group";
4+
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
5+
import {Paging} from "../../../models/paging";
26

37
@Component({
48
selector: 'app-admin-public-groups',
@@ -7,4 +11,65 @@ import {Component} from '@angular/core';
711
})
812
export class AdminPublicGroupsComponent {
913

14+
groups = undefined;
15+
group: Group;
16+
loadingPage: boolean;
17+
paging: Paging;
18+
pageNumber: number;
19+
pageCount: number;
20+
21+
adminGroupsPagingParams = {
22+
offset: 0,
23+
limit: 10,
24+
available: 0,
25+
currentPage: 1,
26+
maxSize: 5,
27+
type: 'PUBLIC'
28+
};
29+
30+
constructor(private http: HttpService, private modalService: NgbModal) {
31+
this.groupListPageChanged();
32+
this.paging = new Paging();
33+
}
34+
35+
groupListPageChanged(): void {
36+
this.http.get("rest/groups", this.adminGroupsPagingParams).subscribe({
37+
next: (result: any) => {
38+
this.groups = result.data;
39+
this.adminGroupsPagingParams.available = result.resultCount;
40+
}
41+
})
42+
};
43+
44+
pageChange(page: number): void {
45+
this.paging.offset = ((page - 1) * this.paging.limit);
46+
}
47+
48+
49+
openCreatePublicGroupModal(group: Group): void {
50+
//
51+
// const modalInstance = this.modalService.open();
52+
// modalInstance.result.then(function (result) {
53+
// if (!result)
54+
// return;
55+
//
56+
// var msg = "Group successfully ";
57+
// if (group && group.id)
58+
// msg += "updated";
59+
// else
60+
// msg += "created";
61+
// // Util.setFeedback(msg, "success");
62+
// this.groupListPageChanged();
63+
// })
64+
};
65+
66+
deletePublicGroup(group: Group): void {
67+
this.http.delete("rest/groups/" + group.id).subscribe({
68+
next: () => {
69+
const i = this.groups.indexOf(group);
70+
if (i !== -1)
71+
this.groups.splice(i, 1);
72+
}
73+
});
74+
}
1075
}

src/main/ngapp/src/app/components/admin/admin/admin.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@
4747
</div>
4848
</li>
4949
<li class="nav-item">
50-
<div class="nav-link cursor-pointer" [ngClass]="{'active': active === 'keys'}"
51-
aria-current="page" (click)="goToActiveTab('keys')">Public Groups
50+
<div class="nav-link cursor-pointer" [ngClass]="{'active': active === 'groups'}"
51+
aria-current="page" (click)="goToActiveTab('groups')">Public Groups
5252
</div>
5353
</li>
5454
<li class="nav-item">
55-
<div class="nav-link cursor-pointer" [ngClass]="{'active': active === 'keys'}"
56-
aria-current="page" (click)="goToActiveTab('keys')">Custom Fields
55+
<div class="nav-link cursor-pointer" [ngClass]="{'active': active === 'fields'}"
56+
aria-current="page" (click)="goToActiveTab('fields')">Custom Fields
5757
</div>
5858
</li>
5959
<li class="nav-item">

src/main/ngapp/src/app/components/modal/edit-custom-field-modal/edit-custom-field-modal.component.css

Whitespace-only changes.

0 commit comments

Comments
 (0)