New dashboard look & feel
[src/xds/xds-agent.git] / webapp / src / app / @core-xds / services / project.service.ts
1 import { Injectable, SecurityContext } from '@angular/core';
2 import { Observable } from 'rxjs/Observable';
3 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
4
5 import { XDSAgentService, IXDSProjectConfig } from '../services/xdsagent.service';
6
7 /* FIXME: syntax only compatible with TS>2.4.0
8 export enum ProjectType {
9     UNSET = '',
10     NATIVE_PATHMAP = 'PathMap',
11     SYNCTHING = 'CloudSync'
12 }
13 */
14 export type ProjectTypeEnum = '' | 'PathMap' | 'CloudSync';
15 export const ProjectType = {
16   UNSET: '',
17   NATIVE_PATHMAP: 'PathMap',
18   SYNCTHING: 'CloudSync'
19 };
20
21 export const ProjectTypes = [
22   { value: ProjectType.NATIVE_PATHMAP, display: 'Path mapping' },
23   { value: ProjectType.SYNCTHING, display: 'Cloud Sync' }
24 ];
25
26 export const ProjectStatus = {
27   ErrorConfig: 'ErrorConfig',
28   Disable: 'Disable',
29   Enable: 'Enable',
30   Pause: 'Pause',
31   Syncing: 'Syncing'
32 };
33
34 export interface IProject {
35   id?: string;
36   serverId: string;
37   label: string;
38   pathClient: string;
39   pathServer?: string;
40   type: ProjectTypeEnum;
41   status?: string;
42   isInSync?: boolean;
43   isUsable?: boolean;
44   serverPrjDef?: IXDSProjectConfig;
45   isExpanded?: boolean;
46   visible?: boolean;
47   defaultSdkID?: string;
48 }
49
50 @Injectable()
51 export class ProjectService {
52   public Projects$: Observable<IProject[]>;
53
54   private _prjsList: IProject[] = [];
55   private current: IProject;
56   private prjsSubject = <BehaviorSubject<IProject[]>>new BehaviorSubject(this._prjsList);
57
58   constructor(private xdsSvr: XDSAgentService) {
59     this.current = null;
60     this.Projects$ = this.prjsSubject.asObservable();
61
62     this.xdsSvr.getProjects().subscribe((projects) => {
63       this._prjsList = [];
64       projects.forEach(p => {
65         this._addProject(p, true);
66       });
67       this.prjsSubject.next(Object.assign([], this._prjsList));
68     });
69
70     // Update Project data
71     this.xdsSvr.ProjectState$.subscribe(prj => {
72       const i = this._getProjectIdx(prj.id);
73       if (i >= 0) {
74         // XXX for now, only isInSync and status may change
75         this._prjsList[i].isInSync = prj.isInSync;
76         this._prjsList[i].status = prj.status;
77         this._prjsList[i].isUsable = this._isUsableProject(prj);
78         this.prjsSubject.next(Object.assign([], this._prjsList));
79       }
80     });
81
82     // Add listener on create and delete project events
83     this.xdsSvr.addEventListener('event:project-add', (ev) => {
84       if (ev && ev.data && ev.data.id) {
85         this._addProject(ev.data);
86       } else {
87         console.log('Warning: received events with unknown data: ev=', ev);
88       }
89     });
90     this.xdsSvr.addEventListener('event:project-delete', (ev) => {
91       if (ev && ev.data && ev.data.id) {
92         const idx = this._prjsList.findIndex(item => item.id === ev.data.id);
93         if (idx === -1) {
94           console.log('Warning: received events on unknown project id: ev=', ev);
95           return;
96         }
97         this._prjsList.splice(idx, 1);
98         this.prjsSubject.next(Object.assign([], this._prjsList));
99       } else {
100         console.log('Warning: received events with unknown data: ev=', ev);
101       }
102     });
103
104   }
105
106   public setCurrent(s: IProject) {
107     this.current = s;
108   }
109
110   public getCurrent(): IProject {
111     return this.current;
112   }
113
114   public getCurrentId(): string {
115     if (this.current && this.current.id) {
116       return this.current.id;
117     }
118     return '';
119   }
120
121   Add(prj: IProject): Observable<IProject> {
122     const xdsPrj: IXDSProjectConfig = {
123       id: '',
124       serverId: prj.serverId,
125       label: prj.label || '',
126       clientPath: prj.pathClient.trim(),
127       serverPath: prj.pathServer,
128       type: prj.type,
129       defaultSdkID: prj.defaultSdkID,
130     };
131     // Send config to XDS server
132     return this.xdsSvr.addProject(xdsPrj)
133       .map(xp => this._convToIProject(xp));
134   }
135
136   Delete(prj: IProject): Observable<IProject> {
137     const idx = this._getProjectIdx(prj.id);
138     const delPrj = prj;
139     if (idx === -1) {
140       throw new Error('Invalid project id (id=' + prj.id + ')');
141     }
142     return this.xdsSvr.deleteProject(prj.id)
143       .map(res => delPrj);
144   }
145
146   Sync(prj: IProject): Observable<string> {
147     const idx = this._getProjectIdx(prj.id);
148     if (idx === -1) {
149       throw new Error('Invalid project id (id=' + prj.id + ')');
150     }
151     return this.xdsSvr.syncProject(prj.id);
152   }
153
154   private _isUsableProject(p) {
155     return p && p.isInSync &&
156       (p.status === ProjectStatus.Enable) &&
157       (p.status !== ProjectStatus.Syncing);
158   }
159
160   private _getProjectIdx(id: string): number {
161     return this._prjsList.findIndex((item) => item.id === id);
162   }
163
164   private _convToIProject(rPrj: IXDSProjectConfig): IProject {
165     // Convert XDSFolderConfig to IProject
166     const pp: IProject = {
167       id: rPrj.id,
168       serverId: rPrj.serverId,
169       label: rPrj.label,
170       pathClient: rPrj.clientPath,
171       pathServer: rPrj.serverPath,
172       type: rPrj.type,
173       status: rPrj.status,
174       isInSync: rPrj.isInSync,
175       isUsable: this._isUsableProject(rPrj),
176       defaultSdkID: rPrj.defaultSdkID,
177       serverPrjDef: Object.assign({}, rPrj),  // do a copy
178     };
179     return pp;
180   }
181
182   private _addProject(rPrj: IXDSProjectConfig, noNext?: boolean): IProject {
183
184     // Convert XDSFolderConfig to IProject
185     const pp = this._convToIProject(rPrj);
186
187     // add new project
188     this._prjsList.push(pp);
189
190     // sort project array
191     this._prjsList.sort((a, b) => {
192       if (a.label < b.label) {
193         return -1;
194       }
195       if (a.label > b.label) {
196         return 1;
197       }
198       return 0;
199     });
200
201     if (!noNext) {
202       this.prjsSubject.next(Object.assign([], this._prjsList));
203     }
204
205     return pp;
206   }
207 }