aboutsummaryrefslogtreecommitdiffstats
path: root/webapp/src/app/pages/projects
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/src/app/pages/projects')
-rw-r--r--webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.html51
-rw-r--r--webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.scss1
-rw-r--r--webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.ts143
-rw-r--r--webapp/src/app/pages/projects/project-card/project-card.component.html65
-rw-r--r--webapp/src/app/pages/projects/project-card/project-card.component.scss54
-rw-r--r--webapp/src/app/pages/projects/project-card/project-card.component.ts52
-rw-r--r--webapp/src/app/pages/projects/projects.component.html26
-rw-r--r--webapp/src/app/pages/projects/projects.component.scss83
-rw-r--r--webapp/src/app/pages/projects/projects.component.ts33
-rw-r--r--webapp/src/app/pages/projects/projects.module.ts23
10 files changed, 531 insertions, 0 deletions
diff --git a/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.html b/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.html
new file mode 100644
index 0000000..e2c6748
--- /dev/null
+++ b/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.html
@@ -0,0 +1,51 @@
+<div class="modal-header">
+ <span>Add a new project</span>
+ <button class="close" aria-label="Close" (click)="closeModal()">
+ <span aria-hidden="true">&times;</span>
+ </button>
+</div>
+
+<div class="modal-body row">
+ <div class="col-12">
+ <form [formGroup]="addProjectForm" (ngSubmit)="onSubmit()">
+
+ <div class="form-group row">
+ <label for="sharing-type" class="col-sm-3 col-form-label">Sharing Type</label>
+ <div class="col-sm-9">
+ <select id="select-sharing-type" class="form-control" formControlName="type">
+ <option *ngFor="let t of projectTypes" [value]="t.value">{{t.display}}
+ </option>
+ </select>
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="select-local-path" class="col-sm-3 col-form-label">Local Path</label>
+ <div class="col-sm-9">
+ <input type="text" id="inputLocalPath" class="form-control" formControlName="pathCli" placeholder="/tmp/myProject" (change)="onChangeLocalProject($event)">
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="select-server-path" class="col-sm-3 col-form-label">Server Path</label>
+ <div class="col-sm-9">
+ <input type="text" id="inputServerPath" class="form-control" formControlName="pathSvr">
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="select-label" class="col-sm-3 col-form-label">Label</label>
+ <div class="col-sm-9">
+ <input type="text" id="inputLabel" class="form-control" formControlName="label" (keyup)="onKeyLabel($event)">
+ </div>
+ </div>
+
+ <div class="offset-sm-3 col-sm-9">
+ <button class="btn btn-md btn-secondary" (click)="cancelAction=true; closeModal()"> Cancel </button>
+ <button class="btn btn-md btn-primary" type="submit" [disabled]="!addProjectForm.valid">Add Folder</button>
+ </div>
+ </form>
+ </div>
+</div>
+<div class="modal-footer form-group">
+</div>
diff --git a/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.scss b/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.scss
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.scss
@@ -0,0 +1 @@
+
diff --git a/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.ts b/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.ts
new file mode 100644
index 0000000..640ac5c
--- /dev/null
+++ b/webapp/src/app/pages/projects/project-add-modal/project-add-modal.component.ts
@@ -0,0 +1,143 @@
+import { Component, Input, ViewChild, OnInit } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { FormControl, FormGroup, Validators, ValidationErrors, FormBuilder, ValidatorFn, AbstractControl } from '@angular/forms';
+
+// Import RxJs required methods
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/filter';
+import 'rxjs/add/operator/debounceTime';
+
+import { AlertService, IAlert } from '../../../@core-xds/services/alert.service';
+import { ProjectService, IProject, ProjectType, ProjectTypes } from '../../../@core-xds/services/project.service';
+import { XDSConfigService } from '../../../@core-xds/services/xds-config.service';
+
+
+@Component({
+ selector: 'xds-project-add-modal',
+ templateUrl: 'project-add-modal.component.html',
+ styleUrls: ['project-add-modal.component.scss']
+})
+export class ProjectAddModalComponent implements OnInit {
+ // @Input('server-id') serverID: string;
+ private serverID: string;
+
+ cancelAction = false;
+ userEditedLabel = false;
+ projectTypes = ProjectTypes;
+
+ addProjectForm: FormGroup;
+ typeCtrl: FormControl;
+ pathCliCtrl: FormControl;
+ pathSvrCtrl: FormControl;
+
+ constructor(
+ private alert: AlertService,
+ private projectSvr: ProjectService,
+ private XdsConfigSvr: XDSConfigService,
+ private fb: FormBuilder,
+ private activeModal: NgbActiveModal
+ ) {
+ // Define types (first one is special/placeholder)
+ this.projectTypes.unshift({ value: ProjectType.UNSET, display: '--Select a type--' });
+
+ this.typeCtrl = new FormControl(this.projectTypes[0].value, this.validatorProjType);
+ this.pathCliCtrl = new FormControl('', this.validatorProjPath);
+ this.pathSvrCtrl = new FormControl({ value: '', disabled: true }, this.validatorProjPath);
+
+ this.addProjectForm = fb.group({
+ type: this.typeCtrl,
+ pathCli: this.pathCliCtrl,
+ pathSvr: this.pathSvrCtrl,
+ label: ['', Validators.nullValidator],
+ });
+ }
+
+
+ ngOnInit() {
+ // Update server ID
+ this.serverID = this.XdsConfigSvr.getCurServer().id;
+ this.XdsConfigSvr.onCurServer().subscribe(svr => this.serverID = svr.id);
+
+ // Auto create label name
+ this.pathCliCtrl.valueChanges
+ .debounceTime(100)
+ .filter(n => n)
+ .map(n => {
+ const last = n.split('/');
+ let nm = n;
+ if (last.length > 0) {
+ nm = last.pop();
+ if (nm === '' && last.length > 0) {
+ nm = last.pop();
+ }
+ }
+ return 'Project_' + nm;
+ })
+ .subscribe(value => {
+ if (value && !this.userEditedLabel) {
+ this.addProjectForm.patchValue({ label: value });
+ }
+ });
+
+ // Handle disabling of Server path
+ this.typeCtrl.valueChanges
+ .debounceTime(500)
+ .subscribe(valType => {
+ const dis = (valType === String(ProjectType.SYNCTHING));
+ this.pathSvrCtrl.reset({ value: '', disabled: dis });
+ });
+ }
+
+ closeModal() {
+ this.activeModal.close();
+ }
+
+ onKeyLabel(event: any) {
+ this.userEditedLabel = (this.addProjectForm.value.label !== '');
+ }
+
+ onChangeLocalProject(e) {
+ }
+
+ onSubmit() {
+ if (this.cancelAction) {
+ return;
+ }
+
+ const formVal = this.addProjectForm.value;
+
+ const type = formVal['type'].value;
+ this.projectSvr.Add({
+ serverId: this.serverID,
+ label: formVal['label'],
+ pathClient: formVal['pathCli'],
+ pathServer: formVal['pathSvr'],
+ type: formVal['type'],
+ // FIXME: allow to set defaultSdkID from New Project config panel
+ })
+ .subscribe(prj => {
+ this.alert.info('Project ' + prj.label + ' successfully created.');
+ this.closeModal();
+
+ // Reset Value for the next creation
+ this.addProjectForm.reset();
+ const selectedType = this.projectTypes[0].value;
+ this.addProjectForm.patchValue({ type: selectedType });
+
+ },
+ err => {
+ this.alert.error(err, 60);
+ this.closeModal();
+ });
+ }
+
+ private validatorProjType(g: FormGroup): ValidationErrors | null {
+ return (g.value !== ProjectType.UNSET) ? null : { validatorProjType: { valid: false } };
+ }
+
+ private validatorProjPath(g: FormGroup): ValidationErrors | null {
+ return (g.disabled || g.value !== '') ? null : { validatorProjPath: { valid: false } };
+ }
+
+}
diff --git a/webapp/src/app/pages/projects/project-card/project-card.component.html b/webapp/src/app/pages/projects/project-card/project-card.component.html
new file mode 100644
index 0000000..c54d581
--- /dev/null
+++ b/webapp/src/app/pages/projects/project-card/project-card.component.html
@@ -0,0 +1,65 @@
+<nb-card class="xds-projects">
+ <nb-card-header>
+
+ <div class="row">
+ <div class="col-12 col-md-8">
+ {{ project.label }}
+ </div>
+ <div class="col-6 col-md-4 text-right" role="group">
+ <button class="btn btn-outline-danger btn-tn btn-xds" (click)="delete(project)">
+ <span class="fa fa-trash fa-size-x2"></span>
+ </button>
+ </div>
+ </div>
+ </nb-card-header>
+
+ <nb-card-body>
+ <table class="table table-striped">
+ <tbody>
+ <tr>
+ <th>
+ <span class="fa fa-fw fa-id-badge"></span>&nbsp;
+ <span>Project ID</span>
+ </th>
+ <td>{{ project.id }}</td>
+ </tr>
+ <tr>
+ <th>
+ <span class="fa fa-fw fa-exchange"></span>&nbsp;
+ <span>Sharing type</span>
+ </th>
+ <td>{{ project.type | readableType }}</td>
+ </tr>
+ <tr>
+ <th>
+ <span class="fa fa-fw fa-folder-open-o"></span>&nbsp;
+ <span>Local path</span>
+ </th>
+ <td>{{ project.pathClient }}</td>
+ </tr>
+ <tr *ngIf="project.pathServer && project.pathServer != ''">
+ <th>
+ <span class="fa fa-fw fa-folder-open-o"></span>&nbsp;
+ <span>Server path</span>
+ </th>
+ <td>{{ project.pathServer }}</td>
+ </tr>
+ <tr>
+ <th>
+ <span class="fa fa-fw fa-flag"></span>&nbsp;
+ <span>Status</span>
+ </th>
+ <td>{{ project.status }} - {{ project.isInSync ? "Up to Date" : "Out of Sync"}}
+ <button *ngIf="!project.isInSync" class="btn btn-outline-info btn-tn btn-xds" (click)="sync(project)" style="margin-left:2em;">
+ <span class="fa fa-refresh fa-size-x2"></span>
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </nb-card-body>
+
+ <nb-card-footer>
+ <!-- <pre>{{project | json}}</pre> -->
+ </nb-card-footer>
+</nb-card>
diff --git a/webapp/src/app/pages/projects/project-card/project-card.component.scss b/webapp/src/app/pages/projects/project-card/project-card.component.scss
new file mode 100644
index 0000000..a433f58
--- /dev/null
+++ b/webapp/src/app/pages/projects/project-card/project-card.component.scss
@@ -0,0 +1,54 @@
+@import '~@nebular/theme/styles/global/bootstrap/buttons';
+
+.xds-project-card .icon {
+ padding: 0.75rem 0;
+ font-size: 1.75rem;
+}
+
+nb-card-body {
+ padding: 0;
+}
+
+nb-card-footer {
+ text-align: right;
+}
+
+.fa-big {
+ font-size: 20px;
+ font-weight: bold;
+}
+
+.fa-size-x2 {
+ font-size: 20px;
+}
+
+th span {
+ font-weight: 100;
+}
+
+th label {
+ font-weight: 100;
+ margin-bottom: 0;
+}
+
+tr.info>th {
+ vertical-align: middle;
+}
+
+tr.info>td {
+ vertical-align: middle;
+}
+
+.btn-outline-danger.btn-xds {
+ color: #ff4c6a;
+ &:focus {
+ color: white;
+ }
+}
+
+.btn-outline-info.btn-xds {
+ color: #4ca6ff;
+ &:focus {
+ color: white;
+ }
+}
diff --git a/webapp/src/app/pages/projects/project-card/project-card.component.ts b/webapp/src/app/pages/projects/project-card/project-card.component.ts
new file mode 100644
index 0000000..160c4c8
--- /dev/null
+++ b/webapp/src/app/pages/projects/project-card/project-card.component.ts
@@ -0,0 +1,52 @@
+import { Component, Input, Pipe, PipeTransform } from '@angular/core';
+import { ProjectService, IProject, ProjectType, ProjectTypeEnum } from '../../../@core-xds/services/project.service';
+import { AlertService } from '../../../@core-xds/services/alert.service';
+
+
+@Component({
+ selector: 'xds-project-card',
+ styleUrls: ['./project-card.component.scss'],
+ templateUrl: './project-card.component.html',
+})
+export class ProjectCardComponent {
+
+ // FIXME workaround of https://github.com/angular/angular-cli/issues/2034
+ // should be removed with angular 5
+ // @Input() project: IProject;
+ @Input() project = <IProject>null;
+
+ constructor(
+ private alert: AlertService,
+ private projectSvr: ProjectService
+ ) {
+ }
+
+ delete(prj: IProject) {
+ this.projectSvr.Delete(prj).subscribe(
+ res => { },
+ err => this.alert.error('ERROR delete: ' + err)
+ );
+ }
+
+ sync(prj: IProject) {
+ this.projectSvr.Sync(prj).subscribe(
+ res => { },
+ err => this.alert.error('ERROR: ' + err)
+ );
+ }
+}
+
+// Make Project type human readable
+@Pipe({
+ name: 'readableType'
+})
+
+export class ProjectReadableTypePipe implements PipeTransform {
+ transform(type: ProjectTypeEnum): string {
+ switch (type) {
+ case ProjectType.NATIVE_PATHMAP: return 'Native (path mapping)';
+ case ProjectType.SYNCTHING: return 'Cloud (Syncthing)';
+ default: return String(type);
+ }
+ }
+}
diff --git a/webapp/src/app/pages/projects/projects.component.html b/webapp/src/app/pages/projects/projects.component.html
new file mode 100644
index 0000000..662dfcc
--- /dev/null
+++ b/webapp/src/app/pages/projects/projects.component.html
@@ -0,0 +1,26 @@
+<div class="row">
+ <div class="col-12">
+ <nb-card-body>
+ <div class="col-9">
+ <nb-actions size="medium">
+ <nb-action>
+ <button (click)="add()">
+ <i class="nb-plus"></i>
+ <span>Add Project</span>
+ </button>
+ </nb-action>
+ </nb-actions>
+ </div>
+ <div class="col-3 right">
+ <nb-actions size="medium">
+ <nb-action>
+ <nb-search type="rotate-layout"></nb-search>
+ </nb-action>
+ </nb-actions>
+ </div>
+ </nb-card-body>
+ </div>
+ <div class="col-md-12 col-lg-12 col-xxxl-6" *ngFor="let prj of (projects$ | async)">
+ <xds-project-card [project]="prj"></xds-project-card>
+ </div>
+</div>
diff --git a/webapp/src/app/pages/projects/projects.component.scss b/webapp/src/app/pages/projects/projects.component.scss
new file mode 100644
index 0000000..3631fbb
--- /dev/null
+++ b/webapp/src/app/pages/projects/projects.component.scss
@@ -0,0 +1,83 @@
+@import '../../@theme/styles/themes';
+@import '~@nebular/theme/components/card/card.component.theme';
+@import '~bootstrap/scss/mixins/breakpoints';
+@import '~@nebular/theme/styles/global/bootstrap/breakpoints';
+@include nb-install-component() {
+ nb-card-body {
+ display: flex;
+ align-items: center;
+ }
+ .action-groups-header {
+ flex-basis: 20%;
+ color: nb-theme(card-header-fg-heading);
+ font-family: nb-theme(card-header-font-family);
+ font-size: nb-theme(card-header-font-size);
+ font-weight: nb-theme(card-header-font-weight);
+ }
+ .nb-actions {
+ flex-basis: 80%;
+ }
+ .right {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ order: 1;
+ flex-direction: row-reverse;
+ }
+ nb-actions>nb-action {
+ padding: 0;
+ }
+ nb-action {
+ i {
+ color: nb-theme(color-fg);
+ font-size: 2.5rem;
+ margin-right: 1rem;
+ }
+ span {
+ font-family: nb-theme(font-secondary);
+ font-weight: nb-theme(font-weight-bold);
+ color: nb-theme(color-fg-heading);
+ text-transform: uppercase;
+ }
+ button {
+ margin: 0 auto;
+ padding: 0;
+ cursor: pointer;
+ border: none;
+ background: none;
+ display: flex;
+ align-items: center;
+ &:focus {
+ box-shadow: none;
+ outline: none;
+ }
+ }
+ }
+ @include media-breakpoint-down(md) {
+ nb-actions nb-action {
+ padding: 0 0.75rem;
+ }
+ }
+ @include media-breakpoint-down(sm) {
+ nb-card-body {
+ padding: 1rem;
+ }
+ nb-action {
+ font-size: 0.75rem;
+ i {
+ font-size: 2rem;
+ margin-right: 0.5rem;
+ }
+ }
+ }
+ @include media-breakpoint-down(is) {
+ nb-action i {
+ font-size: 1.75rem;
+ margin: 0;
+ }
+ span {
+ display: none;
+ }
+ }
+}
diff --git a/webapp/src/app/pages/projects/projects.component.ts b/webapp/src/app/pages/projects/projects.component.ts
new file mode 100644
index 0000000..179bbd0
--- /dev/null
+++ b/webapp/src/app/pages/projects/projects.component.ts
@@ -0,0 +1,33 @@
+import { Component, OnInit } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { ProjectAddModalComponent } from './project-add-modal/project-add-modal.component';
+
+import { ProjectService, IProject } from '../../@core-xds/services/project.service';
+
+@Component({
+ selector: 'xds-projects',
+ styleUrls: ['./projects.component.scss'],
+ templateUrl: './projects.component.html',
+})
+export class ProjectsComponent implements OnInit {
+
+ projects$: Observable<IProject[]>;
+ projects: IProject[];
+
+ constructor(
+ private projectSvr: ProjectService,
+ private modalService: NgbModal,
+ ) {
+ }
+
+ ngOnInit() {
+ this.projects$ = this.projectSvr.Projects$;
+ }
+
+ add() {
+ const activeModal = this.modalService.open(ProjectAddModalComponent, { size: 'lg', container: 'nb-layout' });
+ activeModal.componentInstance.modalHeader = 'Large Modal';
+ }
+}
diff --git a/webapp/src/app/pages/projects/projects.module.ts b/webapp/src/app/pages/projects/projects.module.ts
new file mode 100644
index 0000000..48f37ce
--- /dev/null
+++ b/webapp/src/app/pages/projects/projects.module.ts
@@ -0,0 +1,23 @@
+import { NgModule } from '@angular/core';
+import { ThemeModule } from '../../@theme/theme.module';
+
+import { ProjectsComponent } from './projects.component';
+import { ProjectCardComponent, ProjectReadableTypePipe } from './project-card/project-card.component';
+import { ProjectAddModalComponent } from './project-add-modal/project-add-modal.component';
+
+
+@NgModule({
+ imports: [
+ ThemeModule,
+ ],
+ declarations: [
+ ProjectsComponent,
+ ProjectCardComponent,
+ ProjectAddModalComponent,
+ ProjectReadableTypePipe,
+ ],
+ entryComponents: [
+ ProjectAddModalComponent
+ ],
+})
+export class ProjectsModule { }