diff options
-rw-r--r-- | .vscode/settings.json | 1 | ||||
-rw-r--r-- | lib/folder/folder-pathmap.go | 20 | ||||
-rw-r--r-- | lib/model/folders.go | 2 | ||||
-rw-r--r-- | webapp/src/app/app.module.ts | 8 | ||||
-rw-r--r-- | webapp/src/app/config/config.component.css | 2 | ||||
-rw-r--r-- | webapp/src/app/config/config.component.html | 78 | ||||
-rw-r--r-- | webapp/src/app/config/config.component.ts | 69 | ||||
-rw-r--r-- | webapp/src/app/projects/projectAddModal.component.css | 24 | ||||
-rw-r--r-- | webapp/src/app/projects/projectAddModal.component.html | 54 | ||||
-rw-r--r-- | webapp/src/app/projects/projectAddModal.component.ts | 142 | ||||
-rw-r--r-- | webapp/src/app/projects/projectCard.component.ts | 12 | ||||
-rw-r--r-- | webapp/src/app/sdks/sdkAddModal.component.html | 23 | ||||
-rw-r--r-- | webapp/src/app/sdks/sdkAddModal.component.ts | 24 | ||||
-rw-r--r-- | webapp/src/app/services/alert.service.ts | 6 | ||||
-rw-r--r-- | webapp/src/app/services/config.service.ts | 85 | ||||
-rw-r--r-- | webapp/src/systemjs.config.js | 3 |
16 files changed, 403 insertions, 150 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 60fab57..7ccd637 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,7 +12,6 @@ "webapp/dist": true, "webapp/node_modules": true }, - // Specify paths/files to ignore. (Supports Globs) "cSpell.ignorePaths": [ "**/node_modules/**", diff --git a/lib/folder/folder-pathmap.go b/lib/folder/folder-pathmap.go index 8711df2..2ad8a93 100644 --- a/lib/folder/folder-pathmap.go +++ b/lib/folder/folder-pathmap.go @@ -7,18 +7,22 @@ import ( "path/filepath" common "github.com/iotbzh/xds-common/golib" + "github.com/iotbzh/xds-server/lib/xdsconfig" ) // IFOLDER interface implementation for native/path mapping folders // PathMap . type PathMap struct { - config FolderConfig + globalConfig *xdsconfig.Config + config FolderConfig } // NewFolderPathMap Create a new instance of PathMap -func NewFolderPathMap() *PathMap { - f := PathMap{} +func NewFolderPathMap(gc *xdsconfig.Config) *PathMap { + f := PathMap{ + globalConfig: gc, + } return &f } @@ -28,8 +32,13 @@ func (f *PathMap) Add(cfg FolderConfig) (*FolderConfig, error) { return nil, fmt.Errorf("ServerPath must be set") } - // Sanity check + // Use shareRootDir if ServerPath is a relative path dir := cfg.DataPathMap.ServerPath + if !filepath.IsAbs(dir) { + dir = filepath.Join(f.globalConfig.FileConf.ShareRootDir, dir) + } + + // Sanity check if !common.Exists(dir) { // try to create if not existing if err := os.MkdirAll(dir, 0755); err != nil { @@ -52,7 +61,8 @@ func (f *PathMap) Add(cfg FolderConfig) (*FolderConfig, error) { } f.config = cfg - f.config.RootPath = cfg.DataPathMap.ServerPath + f.config.RootPath = dir + f.config.DataPathMap.ServerPath = dir f.config.Status = StatusEnable return &f.config, nil diff --git a/lib/model/folders.go b/lib/model/folders.go index 3c2457c..02c3254 100644 --- a/lib/model/folders.go +++ b/lib/model/folders.go @@ -208,7 +208,7 @@ func (f *Folders) createUpdate(newF folder.FolderConfig, create bool) (*folder.F fld = f.SThg.NewFolderST(f.Conf) // PATH MAP case folder.TypePathMap: - fld = folder.NewFolderPathMap() + fld = folder.NewFolderPathMap(f.Conf) default: return nil, fmt.Errorf("Unsupported folder type") } diff --git a/webapp/src/app/app.module.ts b/webapp/src/app/app.module.ts index 4877f6e..10ff7a4 100644 --- a/webapp/src/app/app.module.ts +++ b/webapp/src/app/app.module.ts @@ -10,6 +10,7 @@ import { ModalModule } from 'ngx-bootstrap/modal'; import { AccordionModule } from 'ngx-bootstrap/accordion'; import { CarouselModule } from 'ngx-bootstrap/carousel'; import { PopoverModule } from 'ngx-bootstrap/popover'; +import { CollapseModule } from 'ngx-bootstrap/collapse'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; // Import the application components and services. @@ -21,9 +22,11 @@ import { DlXdsAgentComponent, CapitalizePipe } from "./config/downloadXdsAgent.c import { ProjectCardComponent } from "./projects/projectCard.component"; import { ProjectReadableTypePipe } from "./projects/projectCard.component"; import { ProjectsListAccordionComponent } from "./projects/projectsListAccordion.component"; +import { ProjectAddModalComponent} from "./projects/projectAddModal.component"; import { SdkCardComponent } from "./sdks/sdkCard.component"; import { SdksListAccordionComponent } from "./sdks/sdksListAccordion.component"; import { SdkSelectDropdownComponent } from "./sdks/sdkSelectDropdown.component"; +import { SdkAddModalComponent} from "./sdks/sdkAddModal.component"; import { HomeComponent } from "./home/home.component"; import { DevelComponent } from "./devel/devel.component"; @@ -52,6 +55,7 @@ import { SdkService } from "./services/sdk.service"; AccordionModule.forRoot(), CarouselModule.forRoot(), PopoverModule.forRoot(), + CollapseModule.forRoot(), BsDropdownModule.forRoot(), ], declarations: [ @@ -67,9 +71,11 @@ import { SdkService } from "./services/sdk.service"; ProjectCardComponent, ProjectReadableTypePipe, ProjectsListAccordionComponent, + ProjectAddModalComponent, SdkCardComponent, SdksListAccordionComponent, SdkSelectDropdownComponent, + SdkAddModalComponent, ], providers: [ AppRoutingProviders, @@ -88,4 +94,4 @@ import { SdkService } from "./services/sdk.service"; bootstrap: [AppComponent] }) export class AppModule { -}
\ No newline at end of file +} diff --git a/webapp/src/app/config/config.component.css b/webapp/src/app/config/config.component.css index f480857..208ce6f 100644 --- a/webapp/src/app/config/config.component.css +++ b/webapp/src/app/config/config.component.css @@ -23,4 +23,4 @@ tr.info>th { tr.info>td { vertical-align: middle; -}
\ No newline at end of file +} diff --git a/webapp/src/app/config/config.component.html b/webapp/src/app/config/config.component.html index 5211c2d..6af7f0d 100644 --- a/webapp/src/app/config/config.component.html +++ b/webapp/src/app/config/config.component.html @@ -1,11 +1,18 @@ <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h2 class="panel-title pull-left">Global Configuration</h2> - <div class="pull-right"> - <span class="fa fa-fw fa-exchange fa-size-x2" [style.color]="((serverStatus$ | async)?.WS_connected)?'green':'red'"></span> - </div> + <div class="panel-heading"> + <h2 class="panel-title" (click)="gConfigIsCollapsed = !gConfigIsCollapsed"> + Global Configuration + <div class="pull-right"> + <span class="fa fa-fw fa-exchange fa-size-x2" [style.color]="((serverStatus$ | async)?.WS_connected)?'green':'red'"></span> + + <button class="btn btn-link" (click)="gConfigIsCollapsed = !gConfigIsCollapsed; $event.stopPropagation()"> + <span *ngIf="gConfigIsCollapsed" class="fa fa-angle-double-right fa-size-x2"></span> + <span *ngIf="!gConfigIsCollapsed" class="fa fa-angle-double-down fa-size-x2"></span> + </button> + </div> + </h2> </div> - <div class="panel-body"> + <div class="panel-body" [collapse]="gConfigIsCollapsed"> <div class="row"> <div class="col-xs-12"> <table class="table table-condensed"> @@ -50,9 +57,19 @@ <div class="panel panel-default"> <div class="panel-heading"> - <h2 class="panel-title">Cross SDKs Configuration</h2> + <h2 class="panel-title" (click)="sdksIsCollapsed = !sdksIsCollapsed"> + Cross SDKs + <div class="pull-right"> + <button class="btn btn-link" (click)="childSdkModal.show(); $event.stopPropagation()"><span class="fa fa-plus fa-size-x2"></span></button> + + <button class="btn btn-link" (click)="sdksIsCollapsed = !sdksIsCollapsed; $event.stopPropagation()"> + <span *ngIf="sdksIsCollapsed" class="fa fa-angle-double-right fa-size-x2"></span> + <span *ngIf="!sdksIsCollapsed" class="fa fa-angle-double-down fa-size-x2"></span> + </button> + </div> + </h2> </div> - <div class="panel-body"> + <div class="panel-body" [collapse]="sdksIsCollapsed"> <div class="row col-xs-12"> <sdks-list-accordion [sdks]="(sdks$ | async)"></sdks-list-accordion> </div> @@ -61,43 +78,30 @@ <div class="panel panel-default"> <div class="panel-heading"> - <h2 class="panel-title">Projects Configuration</h2> - </div> - <div class="panel-body"> - <form [formGroup]="addProjectForm" (ngSubmit)="onSubmit()"> - <div class="row "> - <div class="col-xs-2"> - <button class="btn btn-primary" type="submit" [disabled]="!addProjectForm.valid"><i class="fa fa-plus"></i> Add Folder</button> - </div> + <h2 class="panel-title" (click)="projectsIsCollapsed = !projectsIsCollapsed; $event.stopPropagation()"> + Projects + <div class="pull-right"> + <button class="btn btn-link" (click)="childProjectModal.show(); $event.stopPropagation()"><span class="fa fa-plus fa-size-x2"></span></button> - <div class="col-xs-6"> - <label>Client/Local Path </label> - <input type="text" style="width:70%;" formControlName="pathCli" placeholder="myProject"> - </div> - <div class="col-xs-6"> - <label>Server Path </label> - <input type="text" style="width:70%;" formControlName="pathSvr" placeholder="myProject"> - </div> - <div class="col-xs-4"> - <label>Label </label> - <input type="text" formControlName="label" (keyup)="onKeyLabel($event)"> - </div> - <div class="col-xs-4"> - <label>Type </label> - <select class="form-control" formControlName="type"> - <option *ngFor="let t of projectTypes" [value]="t.value">{{t.display}} - </option> - </select> - </div> + <button class="btn btn-link" (click)="projectsIsCollapsed = !projectsIsCollapsed; $event.stopPropagation()"> + <span *ngIf="projectsIsCollapsed" class="fa fa-angle-double-right fa-size-x2"></span> + <span *ngIf="!projectsIsCollapsed" class="fa fa-angle-double-down fa-size-x2"></span> + </button> </div> - </form> - + </h2> + </div> + <div class="panel-body" [collapse]="projectsIsCollapsed"> <div class="row col-xs-12"> <projects-list-accordion [projects]="(config$ | async).projects"></projects-list-accordion> </div> </div> </div> +<!-- Modals --> +<project-add-modal #childProjectModal [title]="'Add a new project'"> +</project-add-modal> +<sdk-add-modal #childSdkModal [title]="'Add a new SDK'"> +</sdk-add-modal> <!-- only for debug --> <div *ngIf="false" class="row"> diff --git a/webapp/src/app/config/config.component.ts b/webapp/src/app/config/config.component.ts index 0df707b..b107e81 100644 --- a/webapp/src/app/config/config.component.ts +++ b/webapp/src/app/config/config.component.ts @@ -1,19 +1,16 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, ViewChild, OnInit } from "@angular/core"; import { Observable } from 'rxjs/Observable'; import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms'; +import { CollapseModule } from 'ngx-bootstrap/collapse'; -// Import RxJs required methods -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/filter'; -import 'rxjs/add/operator/debounceTime'; - -import { ConfigService, IConfig, IProject, ProjectType, ProjectTypes, - IxdsAgentPackage } from "../services/config.service"; +import { ConfigService, IConfig, IxdsAgentPackage } from "../services/config.service"; import { XDSServerService, IServerStatus, IXDSAgentInfo } from "../services/xdsserver.service"; import { XDSAgentService, IAgentStatus } from "../services/xdsagent.service"; import { SyncthingService, ISyncThingStatus } from "../services/syncthing.service"; import { AlertService } from "../services/alert.service"; import { ISdk, SdkService } from "../services/sdk.service"; +import { ProjectAddModalComponent } from "../projects/projectAddModal.component"; +import { SdkAddModalComponent } from "../sdks/sdkAddModal.component"; @Component({ templateUrl: './app/config/config.component.html', @@ -24,6 +21,8 @@ import { ISdk, SdkService } from "../services/sdk.service"; // and from http://plnkr.co/edit/vCdjZM?p=preview export class ConfigComponent implements OnInit { + @ViewChild('childProjectModal') childProjectModal: ProjectAddModalComponent; + @ViewChild('childSdkModal') childSdkModal: SdkAddModalComponent; config$: Observable<IConfig>; sdks$: Observable<ISdk[]>; @@ -34,22 +33,21 @@ export class ConfigComponent implements OnInit { curProj: number; userEditedLabel: boolean = false; xdsAgentPackages: IxdsAgentPackage[] = []; - projectTypes = ProjectTypes; + + gConfigIsCollapsed: boolean = true; + sdksIsCollapsed: boolean = true; + projectsIsCollapsed: boolean = false; // TODO replace by reactive FormControl + add validation syncToolUrl: string; xdsAgentUrl: string; xdsAgentRetry: string; - projectsRootDir: string; + projectsRootDir: string; // FIXME: should be remove when projectAddModal will always return full path showApplyBtn = { // Used to show/hide Apply buttons "retry": false, "rootDir": false, }; - addProjectForm: FormGroup; - pathCliCtrl = new FormControl("", Validators.required); - pathSvrCtrl = new FormControl("", Validators.required); - constructor( private configSvr: ConfigService, private xdsServerSvr: XDSServerService, @@ -57,19 +55,7 @@ export class ConfigComponent implements OnInit { private stSvr: SyncthingService, private sdkSvr: SdkService, private alert: AlertService, - private fb: FormBuilder ) { - // Define types (first one is special/placeholder) - this.projectTypes.unshift({value: -1, display: "--Select a type--"}); - let selectedType = this.projectTypes[0].value; - - this.curProj = 0; - this.addProjectForm = fb.group({ - pathCli: this.pathCliCtrl, - pathSvr: this.pathSvrCtrl, - label: ["", Validators.nullValidator], - type: [selectedType, Validators.pattern("[0-9]+")], - }); } ngOnInit() { @@ -88,23 +74,6 @@ export class ConfigComponent implements OnInit { this.xdsAgentPackages = cfg.xdsAgentPackages; }); - // Auto create label name - this.pathCliCtrl.valueChanges - .debounceTime(100) - .filter(n => n) - .map(n => "Project_" + n.split('/')[0]) - .subscribe(value => { - if (value && !this.userEditedLabel) { - this.addProjectForm.patchValue({ label: value }); - } - }); - - // Select 1 first type by default - // SEB this.typeCtrl.setValue({type: ProjectTypes[0].value}); - } - - onKeyLabel(event: any) { - this.userEditedLabel = (this.addProjectForm.value.label !== ""); } submitGlobConf(field: string) { @@ -134,18 +103,4 @@ export class ConfigComponent implements OnInit { this.configSvr.loadProjects(); } - onSubmit() { - let formVal = this.addProjectForm.value; - - let type = formVal['type'].value; - let numType = Number(formVal['type']); - this.configSvr.addProject({ - label: formVal['label'], - pathClient: formVal['pathCli'], - pathServer: formVal['pathSvr'], - type: numType, - // FIXME: allow to set defaultSdkID from New Project config panel - }); - } - } 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">×</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..47e9c89 --- /dev/null +++ b/webapp/src/app/projects/projectAddModal.component.ts @@ -0,0 +1,142 @@ +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 { + ConfigService, IConfig, IProject, ProjectType, ProjectTypes, + IxdsAgentPackage +} from "../services/config.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; + + config$: Observable<IConfig>; + + cancelAction: boolean = false; + userEditedLabel: boolean = false; + projectTypes = ProjectTypes; + + addProjectForm: FormGroup; + typeCtrl: FormControl; + pathCliCtrl: FormControl; + pathSvrCtrl: FormControl; + + constructor( + private alert: AlertService, + private configSvr: ConfigService, + private fb: FormBuilder + ) { + // Define types (first one is special/placeholder) + this.projectTypes.unshift({ value: -1, display: "--Select a type--" }); + + this.typeCtrl = new FormControl(this.projectTypes[0].value, Validators.pattern("[0-9]+")); + 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() { + this.config$ = this.configSvr.conf; + + // Auto create label name + this.pathCliCtrl.valueChanges + .debounceTime(100) + .filter(n => n) + .map(n => "Project_" + n.split('/')[0]) + .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.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('SEB NO files'); + } + let dir = e.target.files[0].webkitRelativePath; + console.log("SEB 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; + let numType = Number(formVal['type']); + this.configSvr.addProject({ + label: formVal['label'], + pathClient: formVal['pathCli'], + pathServer: formVal['pathSvr'], + type: numType, + // 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("Configuration ERROR: " + err, 60); + this.hide(); + }); + } + +} diff --git a/webapp/src/app/projects/projectCard.component.ts b/webapp/src/app/projects/projectCard.component.ts index 23e10a6..1b89fe7 100644 --- a/webapp/src/app/projects/projectCard.component.ts +++ b/webapp/src/app/projects/projectCard.component.ts @@ -1,5 +1,6 @@ import { Component, Input, Pipe, PipeTransform } from '@angular/core'; import { ConfigService, IProject, ProjectType } from "../services/config.service"; +import { AlertService } from "../services/alert.service"; @Component({ selector: 'project-card', @@ -46,12 +47,19 @@ export class ProjectCardComponent { @Input() project: IProject; - constructor(private configSvr: ConfigService) { + constructor( + private alert: AlertService, + private configSvr: ConfigService + ) { } delete(prj: IProject) { - this.configSvr.deleteProject(prj); + this.configSvr.deleteProject(prj) + .subscribe(res => { + }, err => { + this.alert.error("Delete local ERROR: " + err); + }); } } diff --git a/webapp/src/app/sdks/sdkAddModal.component.html b/webapp/src/app/sdks/sdkAddModal.component.html new file mode 100644 index 0000000..2c07fca --- /dev/null +++ b/webapp/src/app/sdks/sdkAddModal.component.html @@ -0,0 +1,23 @@ +<div bsModal #sdkChildModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" + 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)="hideChildModal()"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <ng-content select=".modal-body"> </ng-content> + <i>Not available for now.</i> + </div> + + <div class="modal-footer"> + <div class="pull-left"> + <button class="btn btn-default" (click)="hide()"> Cancel </button> + </div> + </div> + </div> + </div> +</div> diff --git a/webapp/src/app/sdks/sdkAddModal.component.ts b/webapp/src/app/sdks/sdkAddModal.component.ts new file mode 100644 index 0000000..b6c8eb2 --- /dev/null +++ b/webapp/src/app/sdks/sdkAddModal.component.ts @@ -0,0 +1,24 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { ModalDirective } from 'ngx-bootstrap/modal'; + +@Component({ + selector: 'sdk-add-modal', + templateUrl: './app/sdks/sdkAddModal.component.html', +}) +export class SdkAddModalComponent { + @ViewChild('sdkChildModal') public sdkChildModal: ModalDirective; + + @Input() title?: string; + + // TODO + constructor() { + } + + show() { + this.sdkChildModal.show(); + } + + hide() { + this.sdkChildModal.hide(); + } +} diff --git a/webapp/src/app/services/alert.service.ts b/webapp/src/app/services/alert.service.ts index 9dab36a..c3cae7a 100644 --- a/webapp/src/app/services/alert.service.ts +++ b/webapp/src/app/services/alert.service.ts @@ -30,8 +30,10 @@ export class AlertService { this.uid = 0; } - public error(msg: string) { - this.add({ type: "danger", msg: msg, dismissible: true }); + public error(msg: string, dismissTime?: number) { + this.add({ + type: "danger", msg: msg, dismissible: true, dismissTimeout: dismissTime + }); } public warning(msg: string, dismissible?: boolean) { diff --git a/webapp/src/app/services/config.service.ts b/webapp/src/app/services/config.service.ts index c65332f..3b51768 100644 --- a/webapp/src/app/services/config.service.ts +++ b/webapp/src/app/services/config.service.ts @@ -277,7 +277,7 @@ export class ConfigService { return id.slice(0, 15); } - addProject(prj: IProject) { + addProject(prj: IProject): Observable<IProject> { // Substitute tilde with to user home path let pathCli = prj.pathClient.trim(); if (pathCli.charAt(0) === '~') { @@ -304,57 +304,58 @@ export class ConfigService { }; // Send config to XDS server let newPrj = prj; - this.xdsServerSvr.addProject(xdsPrj) - .subscribe(resStRemotePrj => { + return this.xdsServerSvr.addProject(xdsPrj) + .flatMap(resStRemotePrj => { newPrj.remotePrjDef = resStRemotePrj; newPrj.id = resStRemotePrj.id; + newPrj.pathClient = resStRemotePrj.path; - // FIXME REWORK local ST config - // move logic to server side tunneling-back by WS - let stData = resStRemotePrj.dataCloudSync; - - // Now setup local config - let stLocPrj: ISyncThingProject = { - id: resStRemotePrj.id, - label: xdsPrj.label, - path: xdsPrj.path, - serverSyncThingID: stData.builderSThgID - }; - - // Set local Syncthing config - this.stSvr.addProject(stLocPrj) - .subscribe(resStLocalPrj => { - newPrj.localPrjDef = resStLocalPrj; - - // FIXME: maybe reduce subject to only .project - //this.confSubject.next(Object.assign({}, this.confStore).project); - this.confStore.projects.push(Object.assign({}, newPrj)); - this.confSubject.next(Object.assign({}, this.confStore)); - }, - err => { - this.alert.error("Configuration local ERROR: " + err); - }); - }, - err => { - this.alert.error("Configuration remote ERROR: " + err); + if (newPrj.type === ProjectType.SYNCTHING) { + // FIXME REWORK local ST config + // move logic to server side tunneling-back by WS + let stData = resStRemotePrj.dataCloudSync; + + // Now setup local config + let stLocPrj: ISyncThingProject = { + id: resStRemotePrj.id, + label: xdsPrj.label, + path: xdsPrj.path, + serverSyncThingID: stData.builderSThgID + }; + + // Set local Syncthing config + return this.stSvr.addProject(stLocPrj); + + } else { + newPrj.pathServer = resStRemotePrj.dataPathMap.serverPath; + return Observable.of(null); + } + }) + .map(resStLocalPrj => { + newPrj.localPrjDef = resStLocalPrj; + + // FIXME: maybe reduce subject to only .project + //this.confSubject.next(Object.assign({}, this.confStore).project); + this.confStore.projects.push(Object.assign({}, newPrj)); + this.confSubject.next(Object.assign({}, this.confStore)); + + return newPrj; }); } - deleteProject(prj: IProject) { + deleteProject(prj: IProject): Observable<IProject> { let idx = this._getProjectIdx(prj.id); + let delPrj = prj; if (idx === -1) { throw new Error("Invalid project id (id=" + prj.id + ")"); } - this.xdsServerSvr.deleteProject(prj.id) - .subscribe(res => { - this.stSvr.deleteProject(prj.id) - .subscribe(res => { - this.confStore.projects.splice(idx, 1); - }, err => { - this.alert.error("Delete local ERROR: " + err); - }); - }, err => { - this.alert.error("Delete remote ERROR: " + err); + return this.xdsServerSvr.deleteProject(prj.id) + .flatMap(res => { + return this.stSvr.deleteProject(prj.id); + }) + .map(res => { + this.confStore.projects.splice(idx, 1); + return delPrj; }); } diff --git a/webapp/src/systemjs.config.js b/webapp/src/systemjs.config.js index 19fe225..15c52ba 100644 --- a/webapp/src/systemjs.config.js +++ b/webapp/src/systemjs.config.js @@ -39,6 +39,7 @@ 'ngx-bootstrap/carousel': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', 'ngx-bootstrap/popover': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', 'ngx-bootstrap/dropdown': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', + 'ngx-bootstrap/collapse': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', // other libraries 'socket.io-client': 'npm:socket.io-client/dist/socket.io.min.js' }, @@ -65,4 +66,4 @@ } } }); -})(this);
\ No newline at end of file +})(this); |