aboutsummaryrefslogtreecommitdiffstats
path: root/webapp/src/app/projects
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/src/app/projects')
-rw-r--r--webapp/src/app/projects/projectAddModal.component.css24
-rw-r--r--webapp/src/app/projects/projectAddModal.component.html54
-rw-r--r--webapp/src/app/projects/projectAddModal.component.ts147
-rw-r--r--webapp/src/app/projects/projectCard.component.ts91
-rw-r--r--webapp/src/app/projects/projectsListAccordion.component.ts39
5 files changed, 355 insertions, 0 deletions
diff --git a/webapp/src/app/projects/projectAddModal.component.css b/webapp/src/app/projects/projectAddModal.component.css
new file mode 100644
index 0000000..77f73a5
--- /dev/null
+++ b/webapp/src/app/projects/projectAddModal.component.css
@@ -0,0 +1,24 @@
+.table-borderless>tbody>tr>td,
+.table-borderless>tbody>tr>th,
+.table-borderless>tfoot>tr>td,
+.table-borderless>tfoot>tr>th,
+.table-borderless>thead>tr>td,
+.table-borderless>thead>tr>th {
+ border: none;
+}
+
+tr>th {
+ vertical-align: middle;
+}
+
+tr>td {
+ vertical-align: middle;
+}
+
+th label {
+ margin-bottom: 0;
+}
+
+td input {
+ width: 100%;
+}
diff --git a/webapp/src/app/projects/projectAddModal.component.html b/webapp/src/app/projects/projectAddModal.component.html
new file mode 100644
index 0000000..dc84985
--- /dev/null
+++ b/webapp/src/app/projects/projectAddModal.component.html
@@ -0,0 +1,54 @@
+<div bsModal #childProjectModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel"
+ [config]="{backdrop: 'static'}" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title pull-left">{{title}}</h4>
+ <button type="button" class="close pull-right" aria-label="Close" (click)="hide()">
+ <span aria-hidden="true">&times;</span>
+ </button>
+ </div>
+
+ <form [formGroup]="addProjectForm" (ngSubmit)="onSubmit()">
+ <div class="modal-body">
+ <div class="row ">
+ <div class="col-xs-12">
+ <table class="table table-borderless">
+ <tbody>
+ <tr>
+ <th><label>Sharing Type </label></th>
+ <td><select class="form-control" formControlName="type">
+ <option *ngFor="let t of projectTypes" [value]="t.value">{{t.display}}
+ </option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th><label for="select-local-path">Local Path </label></th>
+ <td><input type="text" id="select-local-path" formControlName="pathCli" placeholder="/tmp/myProject" (change)="onChangeLocalProject($event)"></td>
+ </tr>
+ <tr>
+ <th><label for="select-server-path">Server Path </label></th>
+ <td><input type="text" id="select-server-path" formControlName="pathSvr"></td>
+ </tr>
+ <tr>
+ <th><label for="select-label">Label </label></th>
+ <td><input type="text" formControlName="label" id="select-label" (keyup)="onKeyLabel($event)"></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <div class="pull-left">
+ <button class="btn btn-default" (click)="cancelAction=true; hide()"> Cancel </button>
+ </div>
+ <div class="">
+ <button class="btn btn-primary" type="submit" [disabled]="!addProjectForm.valid">Add Folder</button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+</div>
diff --git a/webapp/src/app/projects/projectAddModal.component.ts b/webapp/src/app/projects/projectAddModal.component.ts
new file mode 100644
index 0000000..1352060
--- /dev/null
+++ b/webapp/src/app/projects/projectAddModal.component.ts
@@ -0,0 +1,147 @@
+import { Component, Input, ViewChild, OnInit } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import { ModalDirective } from 'ngx-bootstrap/modal';
+import { FormControl, FormGroup, Validators, 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 "../services/alert.service";
+import { ProjectService, IProject, ProjectType, ProjectTypes } from "../services/project.service";
+
+
+@Component({
+ selector: 'project-add-modal',
+ templateUrl: './app/projects/projectAddModal.component.html',
+ styleUrls: ['./app/projects/projectAddModal.component.css']
+})
+export class ProjectAddModalComponent {
+ @ViewChild('childProjectModal') public childProjectModal: ModalDirective;
+ @Input() title?: string;
+ @Input('server-id') serverID: string;
+
+ cancelAction: boolean = false;
+ userEditedLabel: boolean = false;
+ projectTypes = ProjectTypes;
+
+ addProjectForm: FormGroup;
+ typeCtrl: FormControl;
+ pathCliCtrl: FormControl;
+ pathSvrCtrl: FormControl;
+
+ constructor(
+ private alert: AlertService,
+ private projectSvr: ProjectService,
+ private fb: FormBuilder
+ ) {
+ // 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, Validators.pattern("[A-Za-z]+"));
+ this.pathCliCtrl = new FormControl("", Validators.required);
+ this.pathSvrCtrl = new FormControl({ value: "", disabled: true }, [Validators.required, Validators.minLength(1)]);
+
+ this.addProjectForm = fb.group({
+ type: this.typeCtrl,
+ pathCli: this.pathCliCtrl,
+ pathSvr: this.pathSvrCtrl,
+ label: ["", Validators.nullValidator],
+ });
+ }
+
+ ngOnInit() {
+ // Auto create label name
+ this.pathCliCtrl.valueChanges
+ .debounceTime(100)
+ .filter(n => n)
+ .map(n => {
+ let 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 => {
+ let dis = (valType === String(ProjectType.SYNCTHING));
+ this.pathSvrCtrl.reset({ value: "", disabled: dis });
+ });
+ }
+
+ show() {
+ this.cancelAction = false;
+ this.userEditedLabel = false;
+ this.childProjectModal.show();
+ }
+
+ hide() {
+ this.childProjectModal.hide();
+ }
+
+ onKeyLabel(event: any) {
+ this.userEditedLabel = (this.addProjectForm.value.label !== "");
+ }
+
+ /* FIXME: change input to file type
+ <td><input type="file" id="select-local-path" webkitdirectory
+ formControlName="pathCli" placeholder="myProject" (change)="onChangeLocalProject($event)"></td>
+
+ onChangeLocalProject(e) {
+ if e.target.files.length < 1 {
+ console.log('NO files');
+ }
+ let dir = e.target.files[0].webkitRelativePath;
+ console.log("files: " + dir);
+ let u = URL.createObjectURL(e.target.files[0]);
+ }
+ */
+ onChangeLocalProject(e) {
+ }
+
+ onSubmit() {
+ if (this.cancelAction) {
+ return;
+ }
+
+ let formVal = this.addProjectForm.value;
+
+ let 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.hide();
+
+ // Reset Value for the next creation
+ this.addProjectForm.reset();
+ let selectedType = this.projectTypes[0].value;
+ this.addProjectForm.patchValue({ type: selectedType });
+
+ },
+ err => {
+ this.alert.error(err, 60);
+ this.hide();
+ });
+ }
+
+}
diff --git a/webapp/src/app/projects/projectCard.component.ts b/webapp/src/app/projects/projectCard.component.ts
new file mode 100644
index 0000000..fdacba4
--- /dev/null
+++ b/webapp/src/app/projects/projectCard.component.ts
@@ -0,0 +1,91 @@
+import { Component, Input, Pipe, PipeTransform } from '@angular/core';
+import { ProjectService, IProject, ProjectType } from "../services/project.service";
+import { AlertService } from "../services/alert.service";
+
+@Component({
+ selector: 'project-card',
+ template: `
+ <div class="row">
+ <div class="col-xs-12">
+ <div class="text-right" role="group">
+ <button class="btn btn-link" (click)="delete(project)">
+ <span class="fa fa-trash fa-size-x2"></span>
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <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-link" (click)="sync(project)">
+ <span class="fa fa-refresh fa-size-x2"></span>
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table >
+ `,
+ styleUrls: ['./app/config/config.component.css']
+})
+
+export class ProjectCardComponent {
+
+ @Input() project: IProject;
+
+ constructor(
+ private alert: AlertService,
+ private projectSvr: ProjectService
+ ) {
+ }
+
+ delete(prj: IProject) {
+ this.projectSvr.Delete(prj)
+ .subscribe(res => {
+ }, err => {
+ this.alert.error("Delete ERROR: " + err);
+ });
+ }
+
+ sync(prj: IProject) {
+ this.projectSvr.Sync(prj)
+ .subscribe(res => {
+ }, err => {
+ this.alert.error("ERROR: " + err);
+ });
+ }
+
+}
+
+// Remove APPS. prefix if translate has failed
+@Pipe({
+ name: 'readableType'
+})
+
+export class ProjectReadableTypePipe implements PipeTransform {
+ transform(type: ProjectType): 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/projects/projectsListAccordion.component.ts b/webapp/src/app/projects/projectsListAccordion.component.ts
new file mode 100644
index 0000000..210be5c
--- /dev/null
+++ b/webapp/src/app/projects/projectsListAccordion.component.ts
@@ -0,0 +1,39 @@
+import { Component, Input } from "@angular/core";
+
+import { IProject } from "../services/project.service";
+
+@Component({
+ selector: 'projects-list-accordion',
+ template: `
+ <style>
+ .fa.fa-exclamation-triangle {
+ margin-right: 2em;
+ color: red;
+ }
+ .fa.fa-refresh {
+ margin-right: 10px;
+ color: darkviolet;
+ }
+ </style>
+ <accordion>
+ <accordion-group #group *ngFor="let prj of projects">
+ <div accordion-heading>
+ {{ prj.label }}
+ <div class="pull-right">
+ <i *ngIf="prj.status == 'Syncing'" class="fa fa-refresh faa-spin animated"></i>
+ <i *ngIf="!prj.isInSync && prj.status != 'Syncing'" class="fa fa-exclamation-triangle"></i>
+ <i class="fa" [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i>
+ </div>
+ </div>
+ <project-card [project]="prj"></project-card>
+ </accordion-group>
+ </accordion>
+ `
+})
+export class ProjectsListAccordionComponent {
+
+ @Input() projects: IProject[];
+
+}
+
+