diff options
-rw-r--r-- | .vscode/settings.json | 4 | ||||
-rw-r--r-- | lib/apiv1/apiv1.go | 8 | ||||
-rw-r--r-- | lib/apiv1/make.go | 12 | ||||
-rw-r--r-- | lib/apiv1/sdks.go | 31 | ||||
-rw-r--r-- | lib/crosssdk/sdk.go | 22 | ||||
-rw-r--r-- | lib/crosssdk/sdks.go | 57 | ||||
-rw-r--r-- | lib/model/folder.go | 9 | ||||
-rw-r--r-- | lib/syncthing/st.go | 2 | ||||
-rw-r--r-- | lib/syncthing/stfolder.go | 14 | ||||
-rw-r--r-- | lib/webserver/server.go | 2 | ||||
-rw-r--r-- | lib/xdsconfig/folderconfig.go | 4 | ||||
-rw-r--r-- | main.go | 7 | ||||
-rw-r--r-- | webapp/src/app/app.module.ts | 11 | ||||
-rw-r--r-- | webapp/src/app/build/build.component.html | 10 | ||||
-rw-r--r-- | webapp/src/app/build/build.component.ts | 16 | ||||
-rw-r--r-- | webapp/src/app/common/config.service.ts | 2 | ||||
-rw-r--r-- | webapp/src/app/common/sdk.service.ts | 43 | ||||
-rw-r--r-- | webapp/src/app/common/xdsserver.service.ts | 15 | ||||
-rw-r--r-- | webapp/src/app/config/config.component.html | 11 | ||||
-rw-r--r-- | webapp/src/app/config/config.component.ts | 9 | ||||
-rw-r--r-- | webapp/src/app/sdks/sdkCard.component.ts | 51 | ||||
-rw-r--r-- | webapp/src/app/sdks/sdkSelectDropdown.component.ts | 44 | ||||
-rw-r--r-- | webapp/src/app/sdks/sdksListAccordion.component.ts | 26 |
23 files changed, 360 insertions, 50 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 9023297..8274151 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ "cSpell.words": [ "apiv", "gonic", "devel", "csrffound", "Syncthing", "STID", "ISTCONFIG", "socketio", "ldflags", "SThg", "Intf", "dismissible", - "rpath", "WSID", "sess", "IXDS", "xdsconfig", "xdsserver", "mfolder", - "inotify", "Inot", "pname", "pkill" + "rpath", "WSID", "sess", "IXDS", "xdsconfig", "xdsserver", "mfolder", + "inotify", "Inot", "pname", "pkill", "sdkid", "CLOUDSYNC" ] }
\ No newline at end of file diff --git a/lib/apiv1/apiv1.go b/lib/apiv1/apiv1.go index c94849d..7359266 100644 --- a/lib/apiv1/apiv1.go +++ b/lib/apiv1/apiv1.go @@ -4,6 +4,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/gin-gonic/gin" + "github.com/iotbzh/xds-server/lib/crosssdk" "github.com/iotbzh/xds-server/lib/model" "github.com/iotbzh/xds-server/lib/session" "github.com/iotbzh/xds-server/lib/xdsconfig" @@ -16,17 +17,19 @@ type APIService struct { sessions *session.Sessions cfg *xdsconfig.Config mfolder *model.Folder + sdks *crosssdk.SDKs log *logrus.Logger } // New creates a new instance of API service -func New(sess *session.Sessions, cfg *xdsconfig.Config, mfolder *model.Folder, r *gin.Engine) *APIService { +func New(r *gin.Engine, sess *session.Sessions, cfg *xdsconfig.Config, mfolder *model.Folder, sdks *crosssdk.SDKs) *APIService { s := &APIService{ router: r, sessions: sess, apiRouter: r.Group("/api/v1"), cfg: cfg, mfolder: mfolder, + sdks: sdks, log: cfg.Log, } @@ -40,6 +43,9 @@ func New(sess *session.Sessions, cfg *xdsconfig.Config, mfolder *model.Folder, r s.apiRouter.POST("/folder", s.addFolder) s.apiRouter.DELETE("/folder/:id", s.delFolder) + s.apiRouter.GET("/sdks", s.getSdks) + s.apiRouter.GET("/sdk/:id", s.getSdk) + s.apiRouter.POST("/make", s.buildMake) s.apiRouter.POST("/make/:id", s.buildMake) diff --git a/lib/apiv1/make.go b/lib/apiv1/make.go index 1e6d937..fb6435e 100644 --- a/lib/apiv1/make.go +++ b/lib/apiv1/make.go @@ -14,8 +14,9 @@ import ( // MakeArgs is the parameters (json format) of /make command type MakeArgs struct { ID string `json:"id"` - RPath string `json:"rpath"` // relative path into project - Args string `json:"args"` + RPath string `json:"rpath"` // relative path into project + Args string `json:"args"` // args to pass to make command + SdkID string `json:"sdkid"` // sdk ID to use for setting env CmdTimeout int `json:"timeout"` // command completion timeout in Second } @@ -138,9 +139,10 @@ func (s *APIService) buildMake(c *gin.Context) { cmdID := makeCommandID makeCommandID++ - /* SEB TODO . /opt/poky-agl/3.90.0+snapshot/environment-setup-aarch64-agl-linux - env := os.Environ() - */ + // Retrieve env command regarding Sdk ID + if envCmd := s.sdks.GetEnvCmd(args.SdkID, prj.DefaultSdk); envCmd != "" { + cmd = envCmd + " && " + cmd + } s.log.Debugf("Execute [Cmd ID %d]: %v", cmdID, cmd) err := common.ExecPipeWs(cmd, sop, sess.ID, cmdID, execTmo, s.log, oCB, eCB) diff --git a/lib/apiv1/sdks.go b/lib/apiv1/sdks.go new file mode 100644 index 0000000..5ae2b03 --- /dev/null +++ b/lib/apiv1/sdks.go @@ -0,0 +1,31 @@ +package apiv1 + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/iotbzh/xds-server/lib/common" +) + +// getSdks returns all SDKs configuration +func (s *APIService) getSdks(c *gin.Context) { + c.JSON(http.StatusOK, s.sdks.GetAll()) +} + +// getSdk returns a specific Sdk configuration +func (s *APIService) getSdk(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + common.APIError(c, "Invalid id") + return + } + + sdk := s.sdks.Get(id) + if sdk.Profile == "" { + common.APIError(c, "Invalid id") + return + } + + c.JSON(http.StatusOK, sdk) +} diff --git a/lib/crosssdk/sdk.go b/lib/crosssdk/sdk.go index 2f22f22..9aeec90 100644 --- a/lib/crosssdk/sdk.go +++ b/lib/crosssdk/sdk.go @@ -2,17 +2,20 @@ package crosssdk import ( "fmt" - "path" "path/filepath" ) // SDK Define a cross tool chain used to build application type SDK struct { - Profile string - Version string - Arch string - Path string - EnvFile string + ID string `json:"id" binding:"required"` + Name string `json:"name"` + Profile string `json:"profile"` + Version string `json:"version"` + Arch string `json:"arch"` + Path string `json:"path"` + + // Not exported fields + EnvFile string `json:"-"` } // NewCrossSDK creates a new instance of Syncthing @@ -28,6 +31,9 @@ func NewCrossSDK(path string) (*SDK, error) { d = filepath.Dir(d) s.Profile = filepath.Base(d) + s.ID = s.Profile + "_" + s.Arch + "_" + s.Version + s.Name = s.Arch + " (" + s.Version + ")" + envFile := filepath.Join(path, "environment-setup*") ef, err := filepath.Glob(envFile) if err != nil { @@ -41,7 +47,7 @@ func NewCrossSDK(path string) (*SDK, error) { return &s, nil } -// GetEnvCmd returns the command to initialized the environment to use a cross SDK +// GetEnvCmd returns the command used to initialized the environment func (s *SDK) GetEnvCmd() string { - return ". " + path.Join(s.Path, s.EnvFile) + return ". " + s.EnvFile } diff --git a/lib/crosssdk/sdks.go b/lib/crosssdk/sdks.go index 435aae6..87bb85d 100644 --- a/lib/crosssdk/sdks.go +++ b/lib/crosssdk/sdks.go @@ -3,6 +3,7 @@ package crosssdk import ( "path" "path/filepath" + "sync" "github.com/Sirupsen/logrus" "github.com/iotbzh/xds-server/lib/common" @@ -10,7 +11,11 @@ import ( ) // SDKs List of installed SDK -type SDKs []*SDK +type SDKs struct { + Sdks []SDK + + mutex sync.Mutex +} // Init creates a new instance of Syncthing func Init(cfg *xdsconfig.Config, log *logrus.Logger) (*SDKs, error) { @@ -27,13 +32,61 @@ func Init(cfg *xdsconfig.Config, log *logrus.Logger) (*SDKs, error) { log.Debugf("Error while retrieving SDKs: dir=%s, error=%s", sdkRD, err.Error()) return &s, err } + s.mutex.Lock() + defer s.mutex.Unlock() + for _, d := range dirs { sdk, err := NewCrossSDK(d) if err != nil { log.Debugf("Error while processing SDK dir=%s, err=%s", d, err.Error()) } - s = append(s, sdk) + s.Sdks = append(s.Sdks, *sdk) } } + + log.Debugf("SDKs: %d cross sdks found", len(s.Sdks)) + return &s, nil } + +// GetAll returns all existing SDKs +func (s *SDKs) GetAll() []SDK { + s.mutex.Lock() + defer s.mutex.Unlock() + res := s.Sdks + return res +} + +// Get returns an SDK from id +func (s *SDKs) Get(id int) SDK { + s.mutex.Lock() + defer s.mutex.Unlock() + + if id < 0 || id > len(s.Sdks) { + return SDK{} + } + res := s.Sdks[id] + return res +} + +// GetEnvCmd returns the command used to initialized the environment for an SDK +func (s *SDKs) GetEnvCmd(id string, defaultID string) string { + if id == "" && defaultID == "" { + // no env cmd + return "" + } + + s.mutex.Lock() + defer s.mutex.Unlock() + defaultEnv := "" + for _, sdk := range s.Sdks { + if sdk.ID == id { + return sdk.GetEnvCmd() + } + if sdk.ID == defaultID { + defaultEnv = sdk.GetEnvCmd() + } + } + // Return default env that may be empty + return defaultEnv +} diff --git a/lib/model/folder.go b/lib/model/folder.go index 6687b68..be1bc33 100644 --- a/lib/model/folder.go +++ b/lib/model/folder.go @@ -71,13 +71,8 @@ func (c *Folder) UpdateFolder(newFolder xdsconfig.FolderConfig) (xdsconfig.Folde c.Conf.Folders = c.Conf.Folders.Update(xdsconfig.FoldersConfig{newFolder}) - err := c.SThg.FolderChange(st.FolderChangeArg{ - ID: newFolder.ID, - Label: newFolder.Label, - RelativePath: newFolder.RelativePath, - SyncThingID: newFolder.SyncThingID, - ShareRootDir: c.Conf.ShareRootDir, - }) + err := c.SThg.FolderChange(newFolder) + newFolder.BuilderSThgID = c.Conf.Builder.SyncThingID // FIXME - should be removed after local ST config rework newFolder.Status = xdsconfig.FolderStatusEnable diff --git a/lib/syncthing/st.go b/lib/syncthing/st.go index 841901d..957dd65 100644 --- a/lib/syncthing/st.go +++ b/lib/syncthing/st.go @@ -38,6 +38,7 @@ type SyncThing struct { logsDir string exitSTChan chan ExitChan exitSTIChan chan ExitChan + conf *xdsconfig.Config client *common.HTTPClient log *logrus.Logger } @@ -85,6 +86,7 @@ func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing { binDir: binDir, logsDir: conf.FileConf.LogsDir, log: log, + conf: conf, } return &s diff --git a/lib/syncthing/stfolder.go b/lib/syncthing/stfolder.go index d79e579..45ac60d 100644 --- a/lib/syncthing/stfolder.go +++ b/lib/syncthing/stfolder.go @@ -4,21 +4,13 @@ import ( "path/filepath" "strings" + "github.com/iotbzh/xds-server/lib/xdsconfig" "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/protocol" ) -// FIXME remove and use an interface on xdsconfig.FolderConfig -type FolderChangeArg struct { - ID string - Label string - RelativePath string - SyncThingID string - ShareRootDir string -} - // FolderChange is called when configuration has changed -func (s *SyncThing) FolderChange(f FolderChangeArg) error { +func (s *SyncThing) FolderChange(f xdsconfig.FolderConfig) error { // Get current config stCfg, err := s.ConfigGet() @@ -63,7 +55,7 @@ func (s *SyncThing) FolderChange(f FolderChangeArg) error { folder := config.FolderConfiguration{ ID: id, Label: label, - RawPath: filepath.Join(f.ShareRootDir, f.RelativePath), + RawPath: filepath.Join(s.conf.ShareRootDir, f.RelativePath), } folder.Devices = append(folder.Devices, config.FolderDeviceConfiguration{ diff --git a/lib/webserver/server.go b/lib/webserver/server.go index 40ce948..0905c77 100644 --- a/lib/webserver/server.go +++ b/lib/webserver/server.go @@ -83,7 +83,7 @@ func (s *Server) Serve() error { s.sessions = session.NewClientSessions(s.router, s.log, cookieMaxAge) // Create REST API - s.api = apiv1.New(s.sessions, s.cfg, s.mfolder, s.router) + s.api = apiv1.New(s.router, s.sessions, s.cfg, s.mfolder, s.sdks) // Websocket routes s.sIOServer, err = socketio.NewServer(nil) diff --git a/lib/xdsconfig/folderconfig.go b/lib/xdsconfig/folderconfig.go index e32f46a..bb2b56f 100644 --- a/lib/xdsconfig/folderconfig.go +++ b/lib/xdsconfig/folderconfig.go @@ -29,13 +29,14 @@ type FolderConfig struct { SyncThingID string `json:"syncThingID"` BuilderSThgID string `json:"builderSThgID"` Status string `json:"status"` + DefaultSdk string `json:"defaultSdk"` // Not exported fields RootPath string `json:"-"` } // NewFolderConfig creates a new folder object -func NewFolderConfig(id, label, rootDir, path string) FolderConfig { +func NewFolderConfig(id, label, rootDir, path string, defaultSdk string) FolderConfig { return FolderConfig{ ID: id, Label: label, @@ -44,6 +45,7 @@ func NewFolderConfig(id, label, rootDir, path string) FolderConfig { SyncThingID: "", Status: FolderStatusDisable, RootPath: rootDir, + DefaultSdk: defaultSdk, } } @@ -168,6 +168,10 @@ func xdsApp(cliCtx *cli.Context) error { } // Retrieve initial Syncthing config + + // FIXME: cannot retrieve default SDK, need to save on disk or somewhere + // else all config to be able to restore it. + defaultSdk := "" stCfg, err := ctx.SThg.ConfigGet() if err != nil { return cli.NewExitError(err, 2) @@ -177,7 +181,8 @@ func xdsApp(cliCtx *cli.Context) error { if relativePath == "" { relativePath = stFld.RawPath } - newFld := xdsconfig.NewFolderConfig(stFld.ID, stFld.Label, ctx.Config.ShareRootDir, strings.Trim(relativePath, "/")) + + newFld := xdsconfig.NewFolderConfig(stFld.ID, stFld.Label, ctx.Config.ShareRootDir, strings.Trim(relativePath, "/"), defaultSdk) ctx.Config.Folders = ctx.Config.Folders.Update(xdsconfig.FoldersConfig{newFld}) } diff --git a/webapp/src/app/app.module.ts b/webapp/src/app/app.module.ts index 5c33e43..d4a6918 100644 --- a/webapp/src/app/app.module.ts +++ b/webapp/src/app/app.module.ts @@ -19,12 +19,17 @@ import { ConfigComponent } from "./config/config.component"; import { ProjectCardComponent } from "./projects/projectCard.component"; import { ProjectReadableTypePipe } from "./projects/projectCard.component"; import { ProjectsListAccordionComponent } from "./projects/projectsListAccordion.component"; +import { SdkCardComponent } from "./sdks/sdkCard.component"; +import { SdksListAccordionComponent } from "./sdks/sdksListAccordion.component"; +import { SdkSelectDropdownComponent } from "./sdks/sdkSelectDropdown.component"; + import { HomeComponent } from "./home/home.component"; import { BuildComponent } from "./build/build.component"; import { XDSServerService } from "./common/xdsserver.service"; import { SyncthingService } from "./common/syncthing.service"; import { ConfigService } from "./common/config.service"; import { AlertService } from './common/alert.service'; +import { SdkService } from "./common/sdk.service"; @@ -51,6 +56,9 @@ import { AlertService } from './common/alert.service'; ProjectCardComponent, ProjectReadableTypePipe, ProjectsListAccordionComponent, + SdkCardComponent, + SdksListAccordionComponent, + SdkSelectDropdownComponent, ], providers: [ AppRoutingProviders, @@ -61,7 +69,8 @@ import { AlertService } from './common/alert.service'; XDSServerService, ConfigService, SyncthingService, - AlertService + AlertService, + SdkService, ], bootstrap: [AppComponent] }) diff --git a/webapp/src/app/build/build.component.html b/webapp/src/app/build/build.component.html index d2a8da6..2ab7821 100644 --- a/webapp/src/app/build/build.component.html +++ b/webapp/src/app/build/build.component.html @@ -21,6 +21,16 @@ </div> </div> + <div class="row"> + <div class="col-xs-8"> + <label>Cross SDK </label> + <!-- FIXME why not working ? + <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown> + --> + <sdk-select-dropdown></sdk-select-dropdown> + </div> + </div> + <div class="row "> <div class="col-xs-8 pull-left "> <label>Sub-directory</label> diff --git a/webapp/src/app/build/build.component.ts b/webapp/src/app/build/build.component.ts index a1a965b..a99a1fe 100644 --- a/webapp/src/app/build/build.component.ts +++ b/webapp/src/app/build/build.component.ts @@ -8,6 +8,7 @@ import 'rxjs/add/operator/startWith'; import { XDSServerService, ICmdOutput } from "../common/xdsserver.service"; import { ConfigService, IConfig, IProject } from "../common/config.service"; import { AlertService, IAlert } from "../common/alert.service"; +import { SdkService } from "../common/sdk.service"; @Component({ selector: 'build', @@ -32,8 +33,11 @@ export class BuildComponent implements OnInit, AfterViewChecked { private startTime: Map<string, number> = new Map<string, number>(); // I initialize the app component. - constructor(private configSvr: ConfigService, private sdkSvr: XDSServerService, - private fb: FormBuilder, private alertSvr: AlertService + constructor(private configSvr: ConfigService, + private xdsSvr: XDSServerService, + private fb: FormBuilder, + private alertSvr: AlertService, + private sdkSvr: SdkService ) { this.cmdOutput = ""; this.confValid = false; @@ -54,12 +58,12 @@ export class BuildComponent implements OnInit, AfterViewChecked { }); // Command output data tunneling - this.sdkSvr.CmdOutput$.subscribe(data => { + this.xdsSvr.CmdOutput$.subscribe(data => { this.cmdOutput += data.stdout + "\n"; }); // Command exit - this.sdkSvr.CmdExit$.subscribe(exit => { + this.xdsSvr.CmdExit$.subscribe(exit => { if (this.startTime.has(exit.cmdID)) { this.cmdInfo = 'Last command duration: ' + this._computeTime(this.startTime.get(exit.cmdID)); this.startTime.delete(exit.cmdID); @@ -93,7 +97,9 @@ export class BuildComponent implements OnInit, AfterViewChecked { let t0 = performance.now(); this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0; - this.sdkSvr.make(prjID, this.buildForm.value.subpath, args) + let sdkid = this.sdkSvr.getCurrentId(); + + this.xdsSvr.make(prjID, this.buildForm.value.subpath, args, sdkid) .subscribe(res => { this.startTime.set(String(res.cmdID), t0); }, diff --git a/webapp/src/app/common/config.service.ts b/webapp/src/app/common/config.service.ts index 67ee14c..201ee8b 100644 --- a/webapp/src/app/common/config.service.ts +++ b/webapp/src/app/common/config.service.ts @@ -35,6 +35,7 @@ export interface IProject { localPrjDef?: any; isExpanded?: boolean; visible?: boolean; + defaultSdkID?: string; } export interface ILocalSTConfig { @@ -213,6 +214,7 @@ export class ConfigService { label: prj.label, path: prj.path, hostSyncThingID: this.confStore.localSThg.ID, + defaultSdkID: prj.defaultSdkID, }; // Send config to XDS server diff --git a/webapp/src/app/common/sdk.service.ts b/webapp/src/app/common/sdk.service.ts new file mode 100644 index 0000000..3f2f32a --- /dev/null +++ b/webapp/src/app/common/sdk.service.ts @@ -0,0 +1,43 @@ +import { Injectable, SecurityContext } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; + +import { XDSServerService } from "../common/xdsserver.service"; + +export interface ISdk { + id: string; + profile: string; + version: string; + arch: number; + path: string; +} + +@Injectable() +export class SdkService { + public Sdks$: Observable<ISdk[]>; + + private _sdksList = []; + private current: ISdk; + private sdksSubject = <BehaviorSubject<ISdk[]>>new BehaviorSubject(this._sdksList); + + constructor(private xdsSvr: XDSServerService) { + this.current = null; + this.Sdks$ = this.sdksSubject.asObservable(); + + this.xdsSvr.getSdks().subscribe((s) => { + this._sdksList = s; + this.sdksSubject.next(s); + }); + } + + public setCurrent(s: ISdk) { + this.current = s; + } + + public getCurrentId(): string { + if (this.current && this.current.id) { + return this.current.id; + } + return ""; + } +}
\ No newline at end of file diff --git a/webapp/src/app/common/xdsserver.service.ts b/webapp/src/app/common/xdsserver.service.ts index fd2e32a..6cd9ba3 100644 --- a/webapp/src/app/common/xdsserver.service.ts +++ b/webapp/src/app/common/xdsserver.service.ts @@ -7,6 +7,8 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import * as io from 'socket.io-client'; import { AlertService } from './alert.service'; +import { ISdk } from './sdk.service'; + // Import RxJs required methods import 'rxjs/add/operator/map'; @@ -20,6 +22,7 @@ export interface IXDSConfigProject { path: string; hostSyncThingID: string; label?: string; + defaultSdkID?: string; } interface IXDSBuilderConfig { @@ -36,6 +39,7 @@ interface IXDSFolderConfig { syncThingID: string; builderSThgID?: string; status?: string; + defaultSdkID: string; } interface IXDSConfig { @@ -136,6 +140,10 @@ export class XDSServerService { } + getSdks(): Observable<ISdk[]> { + return this._get('/sdks'); + } + getProjects(): Observable<IXDSFolderConfig[]> { return this._get('/folders'); } @@ -146,7 +154,8 @@ export class XDSServerService { label: cfg.label || "", path: cfg.path, type: FOLDER_TYPE_CLOUDSYNC, - syncThingID: cfg.hostSyncThingID + syncThingID: cfg.hostSyncThingID, + defaultSdkID: cfg.defaultSdkID || "", }; return this._post('/folder', folder); } @@ -163,8 +172,8 @@ export class XDSServerService { }); } - make(prjID: string, dir: string, args: string): Observable<any> { - return this._post('/make', { id: prjID, rpath: dir, args: args }); + make(prjID: string, dir: string, args: string, sdkid?: string): Observable<any> { + return this._post('/make', { id: prjID, rpath: dir, args: args, sdkid: sdkid }); } diff --git a/webapp/src/app/config/config.component.html b/webapp/src/app/config/config.component.html index 45b0e14..2a3d322 100644 --- a/webapp/src/app/config/config.component.html +++ b/webapp/src/app/config/config.component.html @@ -40,6 +40,17 @@ <div class="panel panel-default"> <div class="panel-heading"> + <h2 class="panel-title">Cross SDKs Configuration</h2> + </div> + <div class="panel-body"> + <div class="row col-xs-12"> + <sdks-list-accordion [sdks]="(sdks$ | async)"></sdks-list-accordion> + </div> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> <h2 class="panel-title">Projects Configuration</h2> </div> <div class="panel-body"> diff --git a/webapp/src/app/config/config.component.ts b/webapp/src/app/config/config.component.ts index 681c296..745e9f6 100644 --- a/webapp/src/app/config/config.component.ts +++ b/webapp/src/app/config/config.component.ts @@ -11,6 +11,7 @@ import { ConfigService, IConfig, IProject, ProjectType } from "../common/config. import { XDSServerService, IServerStatus } from "../common/xdsserver.service"; import { SyncthingService, ISyncThingStatus } from "../common/syncthing.service"; import { AlertService } from "../common/alert.service"; +import { ISdk, SdkService } from "../common/sdk.service"; @Component({ templateUrl: './app/config/config.component.html', @@ -23,6 +24,7 @@ import { AlertService } from "../common/alert.service"; export class ConfigComponent implements OnInit { config$: Observable<IConfig>; + sdks$: Observable<ISdk[]>; severStatus$: Observable<IServerStatus>; localSTStatus$: Observable<ISyncThingStatus>; @@ -44,8 +46,9 @@ export class ConfigComponent implements OnInit { constructor( private configSvr: ConfigService, - private sdkSvr: XDSServerService, + private xdsSvr: XDSServerService, private stSvr: SyncthingService, + private sdkSvr: SdkService, private alert: AlertService, private fb: FormBuilder ) { @@ -59,7 +62,8 @@ export class ConfigComponent implements OnInit { ngOnInit() { this.config$ = this.configSvr.conf; - this.severStatus$ = this.sdkSvr.Status$; + this.sdks$ = this.sdkSvr.Sdks$; + this.severStatus$ = this.xdsSvr.Status$; this.localSTStatus$ = this.stSvr.Status$; // Bind syncToolUrl to baseURL @@ -117,6 +121,7 @@ export class ConfigComponent implements OnInit { label: formVal['label'], path: formVal['path'], type: ProjectType.SYNCTHING, + // FIXME: allow to set defaultSdkID from New Project config panel }); } diff --git a/webapp/src/app/sdks/sdkCard.component.ts b/webapp/src/app/sdks/sdkCard.component.ts new file mode 100644 index 0000000..f5d2a54 --- /dev/null +++ b/webapp/src/app/sdks/sdkCard.component.ts @@ -0,0 +1,51 @@ +import { Component, Input } from '@angular/core'; +import { ISdk } from "../common/sdk.service"; + +@Component({ + selector: 'sdk-card', + template: ` + <div class="row"> + <div class="col-xs-12"> + <div class="text-right" role="group"> + <button disabled class="btn btn-link" (click)="delete(sdk)"><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> <span>Profile</span></th> + <td>{{ sdk.profile }}</td> + </tr> + <tr> + <th><span class="fa fa-fw fa-tasks"></span> <span>Architecture</span></th> + <td>{{ sdk.arch }}</td> + </tr> + <tr> + <th><span class="fa fa-fw fa-code-fork"></span> <span>Version</span></th> + <td>{{ sdk.version }}</td> + </tr> + <tr> + <th><span class="fa fa-fw fa-folder-open-o"></span> <span>Sdk path</span></th> + <td>{{ sdk.path}}</td> + </tr> + + </tbody> + </table > + `, + styleUrls: ['./app/config/config.component.css'] +}) + +export class SdkCardComponent { + + @Input() sdk: ISdk; + + constructor() { } + + + delete(sdk: ISdk) { + // Not supported for now + } + +} diff --git a/webapp/src/app/sdks/sdkSelectDropdown.component.ts b/webapp/src/app/sdks/sdkSelectDropdown.component.ts new file mode 100644 index 0000000..5122cd2 --- /dev/null +++ b/webapp/src/app/sdks/sdkSelectDropdown.component.ts @@ -0,0 +1,44 @@ +import { Component, Input } from "@angular/core"; + +import { ISdk, SdkService } from "../common/sdk.service"; + +@Component({ + selector: 'sdk-select-dropdown', + template: ` + <div class="btn-group" dropdown *ngIf="curSdk" > + <button dropdownToggle type="button" class="btn btn-primary dropdown-toggle" style="width: 20em;"> + {{curSdk.name}} <span class="caret" style="float: right; margin-top: 8px;"></span> + </button> + <ul *dropdownMenu class="dropdown-menu" role="menu"> + <li role="menuitem"><a class="dropdown-item" *ngFor="let sdk of sdks" (click)="select(sdk)"> + {{sdk.name}}</a> + </li> + </ul> + </div> + ` +}) +export class SdkSelectDropdownComponent { + + // FIXME investigate to understand why not working with sdks as input + // <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown> + //@Input() sdks: ISdk[]; + sdks: ISdk[]; + + curSdk: ISdk; + + constructor(private sdkSvr: SdkService) { } + + ngOnInit() { + this.sdkSvr.Sdks$.subscribe((s) => { + this.sdks = s; + this.curSdk = this.sdks.length ? this.sdks[0] : null; + this.sdkSvr.setCurrent(this.curSdk); + }); + } + + select(s) { + this.sdkSvr.setCurrent(this.curSdk = s); + } +} + + diff --git a/webapp/src/app/sdks/sdksListAccordion.component.ts b/webapp/src/app/sdks/sdksListAccordion.component.ts new file mode 100644 index 0000000..9094f27 --- /dev/null +++ b/webapp/src/app/sdks/sdksListAccordion.component.ts @@ -0,0 +1,26 @@ +import { Component, Input } from "@angular/core"; + +import { ISdk } from "../common/sdk.service"; + +@Component({ + selector: 'sdks-list-accordion', + template: ` + <accordion> + <accordion-group #group *ngFor="let sdk of sdks"> + <div accordion-heading> + {{ sdk.name }} + <i class="pull-right float-xs-right fa" + [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i> + </div> + <sdk-card [sdk]="sdk"></sdk-card> + </accordion-group> + </accordion> + ` +}) +export class SdksListAccordionComponent { + + @Input() sdks: ISdk[]; + +} + + |