diff --git a/Makefile b/Makefile index 852f006..6e369df 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ DOCDIR?=/opt/www/htdocs/doc/antos BLUE=\033[1;34m NC=\033[0m -VERSION=1.0.0 +VERSION=1.1.2 GSED=sed UNAME_S := $(shell uname -s) diff --git a/release/antos-1.1.2.tar.gz b/release/antos-1.1.2.tar.gz new file mode 100644 index 0000000..1192960 Binary files /dev/null and b/release/antos-1.1.2.tar.gz differ diff --git a/src/core/BaseApplication.ts b/src/core/BaseApplication.ts index 3eb0943..643c050 100644 --- a/src/core/BaseApplication.ts +++ b/src/core/BaseApplication.ts @@ -301,7 +301,7 @@ namespace OS { * @memberof BaseApplication */ show(): void { - return this.trigger("focus", undefined); + this.trigger("focus", undefined); } /** diff --git a/src/core/BaseDialog.ts b/src/core/BaseDialog.ts index 5ff186f..26a9cb1 100644 --- a/src/core/BaseDialog.ts +++ b/src/core/BaseDialog.ts @@ -63,7 +63,6 @@ namespace OS { */ quit(): void { const evt = new BaseEvent("exit", false); - this.onexit(evt); if (!evt.prevent) { delete this._observable; if (this.scheme) { @@ -72,6 +71,7 @@ namespace OS { if (this.dialog) { return this.dialog.quit(); } + this.onexit(evt); } } @@ -117,6 +117,9 @@ namespace OS { show(): void { this.trigger("focus"); $(this.scheme).css("z-index", GUI.zindex + 2); + if (this.dialog) { + this.dialog.show(); + } } /** @@ -406,7 +409,10 @@ namespace OS { if (this.data && this.data.value) { $input.val(this.data.value); } - + if(this.data && this.data.disable) + { + $input.prop('disabled', true); + } (this.find("btnOk") as tag.ButtonTag).onbtclick = (e) => { const value = $input.val(); if (!value || value === "") { diff --git a/src/core/BaseModel.ts b/src/core/BaseModel.ts index 3216ec3..4f948d1 100644 --- a/src/core/BaseModel.ts +++ b/src/core/BaseModel.ts @@ -565,7 +565,6 @@ namespace OS { this.dialog.handle = resolve; this.dialog.pid = this.pid; this.dialog.data = data; - return this.dialog.init(); }); } diff --git a/src/core/core.ts b/src/core/core.ts index d463749..408b364 100644 --- a/src/core/core.ts +++ b/src/core/core.ts @@ -1059,6 +1059,25 @@ namespace OS { * @memberof PackageMetaType */ version: string; + + /** + * Package dependencies, each entry is in the following format + * + * `package_name@version` + * + * Example: + * + * ```json + * [ + * "File@0.1.5-b" + * ] + * ``` + * + * @type {string[]} + * @memberof PackageMetaType + */ + dependencies: string[]; + [propName: string]: any; } /** @@ -1359,11 +1378,12 @@ namespace OS { * * @export * @param {string} l VFS path to the library + * @param {string} force force reload library * @returns {Promise} a promise on the result data */ - export function requires(l: string): Promise { + export function requires(l: string, force: boolean = false): Promise { return new Promise(function(resolve, reject) { - if (!API.shared[l]) { + if (!API.shared[l] || force) { const libfp = l.asFileHandle(); switch (libfp.ext) { case "css": @@ -1427,7 +1447,7 @@ namespace OS { } return resolve(r); }); - return API.requires(libs[0]).catch((e: Error) => + return API.requires(libs[0], false).catch((e: Error) => reject(__e(e)) ); }); diff --git a/src/packages/CodePad/AntOSDK.ts b/src/packages/CodePad/AntOSDK.ts index c06ffd8..c384592 100644 --- a/src/packages/CodePad/AntOSDK.ts +++ b/src/packages/CodePad/AntOSDK.ts @@ -108,7 +108,7 @@ namespace OS { ); } catch (e) { return this.logger().error( - __("Unable to create package archive: {}", + __("Unable to create package archive: {0}", e.stack) ); } diff --git a/src/packages/CodePad/css/main.css b/src/packages/CodePad/css/main.css index a774baf..48b34dd 100644 --- a/src/packages/CodePad/css/main.css +++ b/src/packages/CodePad/css/main.css @@ -5,7 +5,29 @@ afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view > div.list-contai { /*border-top: 1px solid #272822;*/ overflow: hidden; + overflow-x: auto; font-size: 12px; + scrollbar-width: none; + /*scrollbar-color: #656565 transparent;*/ +} + +afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar { + height: 0; +} +afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar-track { + background: transparent; +} +afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view > div.list-container::-webkit-scrollbar-thumb { + background-color: #656565; + border: 0; + } + +afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view > div.list-container > ul +{ + width: intrinsic; + width: -moz-max-content; + width: -webkit-max-content; + width: max-content; } afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view ul afx-list-item:nth-child(even) li.selected, diff --git a/src/packages/CodePad/main.ts b/src/packages/CodePad/main.ts index 9e433dd..99b375f 100644 --- a/src/packages/CodePad/main.ts +++ b/src/packages/CodePad/main.ts @@ -183,7 +183,7 @@ namespace OS { */ spotlight: CMDMenu; - + /** * Reference to the editor logger * @@ -311,7 +311,7 @@ namespace OS { highlightSelectedWord: true, behavioursEnabled: true, wrap: true, - fontSize: "11pt", + fontSize: "10pt", showInvisibles: true, }); //themes = ace.require "ace/ext/themelist" @@ -466,8 +466,7 @@ namespace OS { return this.fileview.update(path); }); - (this.find("logger-clear") as GUI.tag.ButtonTag).onbtclick = () => - { + (this.find("logger-clear") as GUI.tag.ButtonTag).onbtclick = () => { this.logger.clear() } @@ -837,23 +836,32 @@ namespace OS { * Run an extension action from the command palette * * @private - * @param {string} name extension name + * @param { GenericObject} extmeta extension name * @param {string} action action name * @returns {void} * @memberof CodePad */ - private runExtensionAction(name: string, action: string): void { - if (!CodePad.extensions[name]) { - return this.error( - __("Unable to find extension: {0}", name) - ); + private runExtensionAction(extmeta: GenericObject, action: string): void { + let ext = undefined; + if (extmeta.ext) { + if (!extmeta.ext[action]) { + return this.error(__("Unknown extension action: {0}", action)); + } } - const ext = new CodePad.extensions[name](this); - if (!ext[action]) { - return this.error(__("Unable to find action: {0}", action)); + else { + if (!CodePad.extensions[extmeta.name]) { + return this.error( + __("Unable to find extension: {0}", extmeta.name) + ); + } + extmeta.ext = new CodePad.extensions[extmeta.name](this); + if (!extmeta.ext[action]) { + return this.error(__("Unable to find action: {0}", action)); + } } - ext.preload() - .then(() => ext[action]()) + + extmeta.ext.preload() + .then(() => extmeta.ext[action]()) .catch((e: Error) => { return this.error(__("Unable to preload extension"), e); }); @@ -872,9 +880,9 @@ namespace OS { /** * Parent context of the current action * - * @type {{ name: any }} + * @type {{ name: any, ext: any }} */ - parent: { name: any }; + parent: { name: any, ext: any }; /** * Action name @@ -883,15 +891,15 @@ namespace OS { */ name: any; }): void { - const { name } = data.parent; + const name = data.parent.name; const action = data.name; //verify if the extension is load if (!CodePad.extensions[name]) { //load the extension const path = `${this.meta().path}/${name}.js`; this._api - .requires(path) - .then(() => this.runExtensionAction(name, action)) + .requires(path, true) + .then(() => this.runExtensionAction(data.parent, action)) .catch((e) => { return this.error( __("unable to load extension: {0}", name), @@ -899,7 +907,7 @@ namespace OS { ); }); } else { - this.runExtensionAction(name, action); + this.runExtensionAction(data.parent, action); } } @@ -1400,7 +1408,7 @@ namespace OS { * @param {string|FormattedString} s * @memberof Logger */ - error(s: string|FormattedString): void { + error(s: string | FormattedString): void { this.log("error", s, true); } @@ -1415,7 +1423,7 @@ namespace OS { * in the log string * @memberof Logger */ - private log(c: string, s: string|FormattedString, showtime: boolean): void { + private log(c: string, s: string | FormattedString, showtime: boolean): void { let el = $("
")
                     .attr("class", `code-pad-log-${c}`);
                 if (showtime) {
@@ -1433,14 +1441,14 @@ namespace OS {
                 }
                 $(this.target).append(el);
             }
-            
+
             /**
              * Print a log message without prefix
              *
              * @param {string|FormattedString} s text to print
              * @memberof Logger
              */
-            print(s: string|FormattedString): void {
+            print(s: string | FormattedString): void {
                 this.log("info", s, false);
             }
 
@@ -1461,7 +1469,7 @@ namespace OS {
             "os://scripts/ace/ace.js",
             "os://scripts/ace/ext-language_tools.js",
             "os://scripts/ace/ext-modelist.js",
-            "os://scripts/ace/ext-themelist.js",
+            "os://scripts/ace/ext-themelist.js"
         ];
 
         /**
@@ -1513,6 +1521,7 @@ namespace OS {
                     this.cmdlist.data = this.data.nodes;
                 }
                 $(this.cmdlist).click((e) => {
+                    $(document).unbind("mousedown", cb);
                     return this.selectCommand();
                 });
 
@@ -1585,11 +1594,11 @@ namespace OS {
                 if (!el) {
                     return;
                 }
+                this.quit();
                 el.selected = false;
                 if (this.handle) {
                     this.handle({ data: { item: el } });
                 }
-                return this.quit();
             }
         }
 
diff --git a/src/packages/CodePad/package.json b/src/packages/CodePad/package.json
index 605377b..ccf8c0a 100644
--- a/src/packages/CodePad/package.json
+++ b/src/packages/CodePad/package.json
@@ -7,7 +7,7 @@
         "email": "xsang.le@gmail.com",
         "licences": "GPLv3"
     },
-    "version":"0.0.2-a",
+    "version":"0.0.3-b",
     "category":"Developments",
     "iconclass":"fa fa-pencil-square-o",
     "mimes":[
diff --git a/src/packages/MarketPlace/dialog.ts b/src/packages/MarketPlace/dialog.ts
index d70eb70..bfada60 100644
--- a/src/packages/MarketPlace/dialog.ts
+++ b/src/packages/MarketPlace/dialog.ts
@@ -99,7 +99,7 @@ namespace OS {
         }
     
         protected onexit(e: BaseEvent): void{
-            (this.parent as OS.application.MarketPlace).refreshRepoList();
+            (this.parent as OS.application.MarketPlace).fetchApps();
             return super.onexit(e);
         }
     }
diff --git a/src/packages/MarketPlace/main.ts b/src/packages/MarketPlace/main.ts
index e1baa74..afc2f6c 100644
--- a/src/packages/MarketPlace/main.ts
+++ b/src/packages/MarketPlace/main.ts
@@ -21,8 +21,7 @@ namespace OS {
         declare var JSZip: any;
         export class MarketPlace extends BaseApplication {
             private installdir: string;
-            private apps_meta: GenericObject[];
-            private repo: GUI.tag.ListViewTag;
+            private apps_meta: GenericObject;
             private applist: GUI.tag.ListViewTag;
             private container: GUI.tag.VBoxTag;
             private appname: GUI.tag.LabelTag;
@@ -41,16 +40,6 @@ namespace OS {
                 this.installdir = this.systemsetting.system.pkgpaths.user;
                 // test repository
                 this.apps_meta = [];
-                this.repo = this.find("repo") as GUI.tag.ListViewTag;
-                this.repo.onlistselect = (e) => {
-                    const data = e.data.item.data;
-                    if (!data) {
-                        return;
-                    }
-                    return this.fetchApps(data);
-                };
-
-                this.refreshRepoList();
 
                 this.applist = this.find("applist") as GUI.tag.ListViewTag;
                 this.applist.onlistselect = (e) => {
@@ -109,19 +98,14 @@ namespace OS {
                 });
 
                 $(this.searchbox).keyup((e) => this.search(e));
-            }
 
-            refreshRepoList(): void {
-                const list = Array.from(this.systemsetting.system.repositories);
-                list.unshift({
-                    text: "Installed",
-                    url: undefined,
+                this.fetchApps().then((d) => {
+                    //console.log(d);
                 });
-                this.repo.data = list;
             }
 
             private search(e: JQuery.KeyboardEventBase) {
-                let v: GenericObject;
+                let k: string;
                 switch (e.which) {
                     case 37:
                         return e.preventDefault();
@@ -140,8 +124,8 @@ namespace OS {
                         if (text.length === 2) {
                             this.applist.data = (() => {
                                 const result1 = [];
-                                for (v of this.apps_meta) {
-                                    result1.push(v);
+                                for (k in this.apps_meta) {
+                                    result1.push(this.apps_meta[k]);
                                 }
                                 return result1;
                             })();
@@ -151,58 +135,135 @@ namespace OS {
                         }
                         var result = [];
                         var term = new RegExp(text, "i");
-                        for (v of this.apps_meta) {
-                            if (v.text.match(term)) {
-                                result.push(v);
+                        for (k in this.apps_meta) {
+                            if (this.apps_meta[k].text.match(term)) {
+                                result.push(this.apps_meta[k]);
                             }
                         }
                         this.applist.data = result;
                 }
             }
 
-            private fetchApps(data: GenericObject): void {
-                let v: API.PackageMetaType;
-                if (!data.url) {
+            /**
+             * Load package meta-data from remote sources
+             *
+             * @private
+             * @param {string} url repository url
+             * @return {*}  {Promise>}
+             * @memberof MarketPlace
+             */
+            private loadRemoteRepository(url: string): Promise> {
+                return new Promise((resolve, reject) => {
+                    url.asFileHandle().read('json')
+                        //this._api
+                        //.get(url + "?_=" + new Date().getTime(), "json")
+                        .then((d) => {
+                            for (let v of d) {
+                                v.text = `${v.name} v${v.version}`;
+                                v.iconclass = "fa fa-adn";
+                                v.dependBy = [];
+                                if (!v.dependencies) {
+                                    v.dependencies = [];
+                                }
+                            }
+                            resolve(d);
+                        })
+                        .catch((e) => {
+                            return this.error(
+                                __(
+                                    "Fail to fetch packages list from: {0}",
+                                    url
+                                ),
+                                e
+                            );
+                            reject(e);
+                        });
+                });
+            }
+
+
+            /**
+             * Load packages meta-data from a list of repositories
+             *
+             * @private
+             * @param {string[]} list repositories list
+             * @return {*}  {Promise[]>} a Promise on a list of package meta-data
+             * @memberof MarketPlace
+             */
+            private loadRemoteRepositories(list: string[]): Promise[]> {
+                return new Promise((resolve, reject) => {
+                    if (list.length == 0) {
+                        let app_list = [];
+                        for (let k in this.apps_meta) {
+                            for (let dep of this.apps_meta[k].dependencies) {
+                                if (this.apps_meta[dep]) {
+                                    this.apps_meta[dep].dependBy.push(k)
+                                }
+                            }
+                            app_list.push(this.apps_meta[k]);
+                        }
+                        return resolve(app_list);
+                    }
+                    let url = list.splice(0, 1)[0];
+                    this.loadRemoteRepository(url)
+                        .then((d: GenericObject[]) => {
+                            for (let pkg of d) {
+                                // check if the package exists
+                                let name = pkg.pkgname ? pkg.pkgname : pkg.app;
+                                name = `${name}@${pkg.version}`;
+                                if (this.apps_meta[name]) {
+                                    pkg.icon = this.apps_meta[name].icon;
+                                    pkg.iconclass = this.apps_meta[name].iconclass;
+                                }
+                                this.apps_meta[name] = pkg;
+                            }
+                            this.loadRemoteRepositories(list)
+                                .then((l) => {
+                                    resolve(l);
+                                });
+                        })
+                        .catch((e) => {
+                            this.error(__("Unable to load repository: {0}: {1}", url, e.toString()), e);
+                            this.loadRemoteRepositories(list)
+                                .then((l) => {
+                                    resolve(l);
+                                });
+                        });
+                });
+            }
+
+            fetchApps(): Promise> {
+                return new Promise((resolve, reject) => {
+                    let v: API.PackageMetaType;
+                    this.apps_meta = {};
                     const pkgcache = this.systemsetting.system.packages;
-                    const list = [];
                     for (let k in pkgcache) {
                         v = pkgcache[k];
-                        list.push({
+                        this.apps_meta[`${k}@${v.version}`] = {
                             pkgname: v.pkgname ? v.pkgname : v.app,
                             name: v.name,
-                            text: v.name,
+                            text: `${v.name} v${v.version}`,
                             icon: v.icon,
                             iconclass: v.iconclass,
                             category: v.category,
                             author: v.info.author,
                             version: v.version,
-                            description: `${v.path}/REAME.md`,
-                        });
+                            description: `${v.path}/README.md`,
+                            dependencies: v.dependencies ? Array.from(v.dependencies) : [],
+                            dependBy: []
+                        };
                     }
-                    this.apps_meta = list;
-                    this.applist.data = list;
-                    return;
-                }
 
-                this._api
-                    .get(data.url + "?_=" + new Date().getTime(), "json")
-                    .then((d) => {
-                        for (v of d) {
-                            v.text = v.name;
-                            v.iconclass = "fa fa-adn";
-                        }
-                        this.apps_meta = d;
-                        return (this.applist.data = d);
-                    })
-                    .catch((e) => {
-                        return this.error(
-                            __(
-                                "Fail to fetch packages list from: {0}",
-                                data.url
-                            ),
-                            e
-                        );
-                    });
+                    const list: string[] = []
+                    for (let d of Array.from(this.systemsetting.system.repositories)) {
+                        list.push(d.url);
+                    }
+                    this.loadRemoteRepositories(list)
+                        .then((apps_list) => {
+                            this.applist.data = apps_list;
+                            resolve(this.apps_meta);
+                        });
+                });
             }
 
             private appDetail(d: GenericObject): void {
@@ -321,7 +382,119 @@ namespace OS {
                     default:
                 }
             }
+            private checkDependencies(pkgname: string, is_uninstall: boolean = false): GenericObject> {
+                let dep_list = {
+                    install: new Set(),
+                    uninstall: new Set(),
+                    notfound: new Set()
+                };
+                let meta = this.apps_meta[pkgname];
+                if (!meta) {
+                    this.error(__("Invalid package name: {0}", pkgname));
+                    return dep_list;
+                }
+                let installed_pkgs = this.systemsetting.system.packages;
+                const list = is_uninstall ? meta.dependBy : meta.dependencies;
+                list.push(pkgname);
 
+                for (let k in list) {
+                    const arr: string[] = list[k].split("@");
+                    if (is_uninstall) {
+                        // dependencies for uninstall
+                        if (installed_pkgs[arr[0]]) {
+                            let name = `${arr[0]}@${installed_pkgs[arr[0]].version}`;
+                            dep_list.uninstall.add(name);
+                            if(list[k] != pkgname)
+                            {
+                                let subdep = this.checkDependencies(name, true);
+                                dep_list.uninstall = new Set([...dep_list.uninstall, ...subdep.uninstall]);
+                            }
+                        }
+                    }
+                    else {
+                        // dependencies for install
+                        let need_install: boolean = true;
+                        if (installed_pkgs[arr[0]]) {
+                            let name = `${arr[0]}@${installed_pkgs[arr[0]].version}`;
+                            // check version
+                            if (installed_pkgs[arr[0]].version.__v().compare(arr[1].__v()) != 0) {
+                                // this package is to be uninstalled
+                                dep_list.uninstall.add(name);
+                                let subdep = this.checkDependencies(name, true);
+                                dep_list.uninstall = new Set([...dep_list.uninstall, ...subdep.uninstall]);
+                                need_install = true;
+                            }
+                            else {
+                                need_install = false;
+                            }
+                        }
+                        if (need_install) {
+                            if (this.apps_meta[list[k]]) {
+                                // new package should be installed
+                                dep_list.install.add(list[k]);
+                                if(list[k] != pkgname)
+                                {
+                                    let subdep = this.checkDependencies(list[k], false);
+                                    dep_list.uninstall = new Set([...dep_list.uninstall, ...subdep.uninstall]);
+                                    dep_list.notfound = new Set([...dep_list.notfound, ...subdep.notfound]);
+                                    dep_list.install = new Set([...dep_list.install, ...subdep.install]);
+                                }
+                            }
+                            else {
+                                // not found
+                                dep_list.notfound.add(meta.dependencies[k]);
+                            }
+                        }
+                    }
+                }
+                return dep_list;
+            }
+            private installPkg(pkgname:string): Promise
+            {
+                return new Promise(async (resolve, reject) =>{
+                    const meta = this.apps_meta[pkgname];
+                    if(!meta || !meta.download)
+                    {
+                        return reject(this._api.throwe(__("Unable to find package: {0}", pkgname)));
+                    }
+                    try {
+                        const data = await this._api.blob(
+                            meta.download + "?_=" + new Date().getTime()
+                        );
+                        try {
+                            const n = await this.install(data, meta);
+                            return resolve(meta);
+                        } catch (e) {
+                            return reject(__e(e));
+                        }
+                    } catch (e_1) {
+                        return reject(__e(e_1));
+                    }
+                });
+            }
+            private bulkInstall(list:string[]): Promise
+            {
+                return new Promise((resolve, reject)=>{
+                    if(list.length == 0)
+                    {
+                        return resolve(true);
+                    }
+                    const pkgname = list.splice(0,1)[0];
+                    this.installPkg(pkgname)
+                        .then((meta) =>{
+                            this.bulkInstall(list)
+                                .then((b) =>{
+                                    resolve(b);
+                                })
+                                .catch((e) =>{
+                                    reject(e);
+                                })
+                        })
+                        .catch((err) =>{
+                            reject(err);
+                        })
+                });
+            }
             private remoteInstall(): Promise {
                 const el = this.applist.selectedItem;
                 if (!el) {
@@ -333,19 +506,47 @@ namespace OS {
                 }
                 // get blob file
                 return new Promise(async (resolve, reject) => {
-                    try {
-                        const data = await this._api.blob(
-                            app.download + "?_=" + new Date().getTime()
-                        );
-                        try {
-                            const n = await this.install(data, app);
-                            return resolve(n);
-                        } catch (e) {
-                            return reject(__e(e));
-                        }
-                    } catch (e_1) {
-                        return reject(__e(e_1));
+                    let pkgname = `${el.data.pkgname}@${el.data.version}`;
+                    const dep = this.checkDependencies(pkgname);
+                    if (dep.notfound.size != 0) {
+                        return this.openDialog("TextDialog", {
+                            disable: true,
+                            title: __("Unresolved dependencies"),
+                            value: __(
+                                "Unable to install: The package `{0}` depends on these packages, but they are not found:\n{1}",
+                                pkgname,
+                                [...dep.notfound].join("\n")
+                            )
+                        })
+                            .then((v) => {
+                                reject(__("Unresolved dependencies on: {0}", pkgname))
+                            });
                     }
+                    this.openDialog("TextDialog", {
+                        title: __("Confirm install"),
+                        disable: true,
+                        value: __(
+                            "Please confirm the following operation:\n\n{0} packages will be removed:\n\n{1}\n\n{2} packages will be installed:\n\n{3}",
+                            dep.uninstall.size.toString(),
+                            [...dep.uninstall].join("\n"),
+                            dep.install.size.toString(),
+                            [...dep.install].join("\n")
+                        )
+                    }).then((v) => {
+                        this.bulkUninstall([...dep.uninstall])
+                            .then((b)=>{
+                                this.bulkInstall([...dep.install])
+                                    .then((b1)=>{
+                                        resolve(pkgname);
+                                    })
+                                    .catch((e1) =>{
+                                        reject(e1);
+                                    })
+                            })
+                            .catch((e2) =>{
+                                reject(e2);
+                            })
+                    })
                 });
             }
 
@@ -361,8 +562,6 @@ namespace OS {
                             .then((data: Uint8Array) => {
                                 return this.install(data)
                                     .then((n) => {
-                                        this.repo.unselect();
-                                        this.repo.selected = 0;
                                         const apps = this.applist.data.map(
                                             (v) => v.pkgname
                                         );
@@ -393,7 +592,7 @@ namespace OS {
                                 .then((d: string) => {
                                     let name: string;
                                     const v = JSON.parse(d);
-                                    const pth = `${this.installdir}/${v.pkgname?v.pkgname:v.app}`;
+                                    const pth = `${this.installdir}/${v.pkgname ? v.pkgname : v.app}`;
                                     const dir = [pth];
                                     const files = [];
                                     for (name in zip.files) {
@@ -408,13 +607,13 @@ namespace OS {
                                     return this.mkdirs(dir)
                                         .then(() => {
                                             return this.installFile(
-                                                v.pkgname?v.pkgname:v.app,
+                                                v.pkgname ? v.pkgname : v.app,
                                                 zip,
                                                 files
                                             )
                                                 .then(() => {
                                                     const app_meta = {
-                                                        pkgname: v.pkgname?v.pkgname:v.app,
+                                                        pkgname: v.pkgname ? v.pkgname : v.app,
                                                         name: v.name,
                                                         text: v.name,
                                                         icon: v.icon,
@@ -430,7 +629,7 @@ namespace OS {
                                                             : undefined,
                                                     };
                                                     v.text = v.name;
-                                                    v.filename = v.pkgname?v.pkgname:v.app;
+                                                    v.filename = v.pkgname ? v.pkgname : v.app;
                                                     v.type = "app";
                                                     v.mime = "antos/app";
                                                     if (
@@ -442,7 +641,7 @@ namespace OS {
                                                     }
                                                     v.path = pth;
                                                     this.systemsetting.system.packages[
-                                                        v.pkgname?v.pkgname:v.app
+                                                        v.pkgname ? v.pkgname : v.app
                                                     ] = v;
                                                     this.appDetail(app_meta);
                                                     return resolve(v.name);
@@ -456,7 +655,74 @@ namespace OS {
                         .catch((e: Error) => reject(__e(e)));
                 });
             }
-
+            private bulkUninstall(list: string[]): Promise
+            {
+                return new Promise(async (resolve, reject) => {
+                    if(list.length == 0)
+                    {
+                        return resolve(true);
+                    }
+                    const pkgname = list.splice(0,1)[0];
+                    this.uninstallPkg(pkgname)
+                        .then((meta) =>{
+                            this.bulkUninstall(list)
+                                .then((b)=>{
+                                    resolve(b);
+                                })
+                                .catch((e)=>{
+                                    reject(e);
+                                })
+                        })
+                        .catch((err) =>{
+                            reject(err);
+                        })
+                });
+            }
+            private uninstallPkg(pkgname: string): Promise
+            {
+                return new Promise(async (resolve, reject) => {
+                    const meta = this.apps_meta[pkgname];
+                    if(!meta)
+                    {
+                        return reject(this._api.throwe(__("Unable to find application meta-data: {0}", pkgname)));
+                    }
+                    const app = this.systemsetting.system.packages[meta.pkgname];
+                    if(!app)
+                    {
+                        return reject(this._api.throwe(__("Application {0} is not installed", pkgname)));
+                    }
+                    // got the app meta
+                    try {
+                        const r = await app.path
+                            .asFileHandle()
+                            .remove();
+                        if (r.error) {
+                            return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error)));
+                        }
+                        this.notify(__("Package uninstalled"));
+                        // stop all the services if any
+                        if (app.services) {
+                            for (let srv of Array.from(app.services)) {
+                                this._gui.unloadApp(srv);
+                            }
+                        }
+                        delete this.systemsetting.system.packages[meta.pkgname];
+                        this._gui.unloadApp(meta.pkgname);
+                        if (meta.download) {
+                            this.appDetail(meta);
+                        }
+                        else {
+                            if(meta.domel)
+                                this.applist.delete(meta.domel);
+                            $(this.container).css("visibility", "hidden");
+                        }
+                        return resolve(meta);
+                    }
+                    catch (e) {
+                        return reject(__e(e));
+                    }
+                });
+            }
             private uninstall(): Promise {
                 return new Promise(async (resolve, reject) => {
                     const el = this.applist.selectedItem;
@@ -472,42 +738,24 @@ namespace OS {
                     if (!app) {
                         return;
                     }
+                    const pkgname = `${sel.pkgname}@${app.version}`;
+                    const dep = this.checkDependencies(pkgname, true);
                     try {
-                        const d = await this.openDialog("YesNoDialog", {
+                        const d = await this.openDialog("TextDialog", {
                             title: __("Uninstall"),
-                            text: __("Uninstall: {0}?", app.name),
+                            disable: true,
+                            value: __("{0} Packages to be Uninstalled:\n\n{1}", dep.uninstall.size, [...dep.uninstall].join("\n")),
                         });
                         if (!d) {
                             return;
                         }
-                        try {
-                            const r = await app.path
-                                .asFileHandle()
-                                .remove();
-                            if (r.error) {
-                                return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error)));
-                            }
-                            this.notify(__("Package uninstalled"));
-                            // stop all the services if any
-                            if (app.services) {
-                                for (let srv of Array.from(app.services)) {
-                                    this._gui.unloadApp(srv);
-                                }
-                            }
-                            delete this.systemsetting.system.packages[name];
-                            this._gui.unloadApp(name);
-                            if (sel.download) {
-                                this.appDetail(sel);
-                            }
-                            else {
-                                this.applist.delete(el);
-                                $(this.container).css("visibility", "hidden");
-                            }
-                            return resolve();
-                        }
-                        catch (e) {
-                            return reject(__e(e));
-                        }
+                        this.bulkUninstall([...dep.uninstall])
+                            .then((b)=>{
+                                this.notify(__("Uninstall successfully"));
+                            })
+                            .catch((err)=>{
+                                this.error(__("Unable to uninstall package(s): {0}", err.toString()), err);
+                            });
                     }
                     catch (e_1) {
                         return reject(__e(e_1));
@@ -515,17 +763,36 @@ namespace OS {
                 });
             }
 
-            private updatePackage(): Promise{
+            private updatePackage(): Promise {
                 return new Promise(async (resolve, reject) => {
                     try {
-                        await this.uninstall();
+                        const el = this.applist.selectedItem;
+                        if (!el) {
+                            return;
+                        }
+                        const sel = el.data;
+                        if (!sel) {
+                            return;
+                        }
+                        const name = sel.pkgname;
+                        const app = this.systemsetting.system.packages[sel.pkgname];
+                        if (!app) {
+                            return;
+                        }
+                        const meta = this.apps_meta[`${sel.pkgname}@${app.version}`];
+                        await this.remoteInstall();
                         try {
-                            await this.remoteInstall();
-                            return resolve();
+                            if(meta)
+                            {
+                                if(meta.domel)
+                                    this.applist.delete(meta.domel);
+                            }
+                            return resolve(true);
                         }
                         catch (e) {
                             return reject(__e(e));
                         }
+                        
                     }
                     catch (e_1) {
                         return reject(__e(e_1));
@@ -536,7 +803,7 @@ namespace OS {
             private mkdirs(list: string[]): Promise {
                 return new Promise((resolve, reject) => {
                     if (list.length === 0) {
-                        return resolve();
+                        return resolve(true);
                     }
                     const dir = list.splice(0, 1)[0].asFileHandle();
                     const path = dir.parent();
@@ -556,17 +823,17 @@ namespace OS {
                                 );
                             }
                             return this.mkdirs(list)
-                                .then(() => resolve())
+                                .then(() => resolve(true))
                                 .catch((e) => reject(__e(e)));
                         })
                         .catch((e) => reject(__e(e)));
                 });
             }
 
-            private installFile(n: string, zip: any, files: string[]): Promise{
+            private installFile(n: string, zip: any, files: string[]): Promise {
                 return new Promise((resolve, reject) => {
                     if (files.length === 0) {
-                        return resolve();
+                        return resolve(true);
                     }
                     const file = files.splice(0, 1)[0];
                     const path = `${this.installdir}/${n}/${file}`;
@@ -587,7 +854,7 @@ namespace OS {
                                         );
                                     }
                                     return this.installFile(n, zip, files)
-                                        .then(() => resolve())
+                                        .then(() => resolve(true))
                                         .catch((e) => reject(__e(e)));
                                 })
                                 .catch((e) => reject(__e(e)));
diff --git a/src/packages/MarketPlace/package.json b/src/packages/MarketPlace/package.json
index c8d2db5..de8f4dd 100644
--- a/src/packages/MarketPlace/package.json
+++ b/src/packages/MarketPlace/package.json
@@ -6,7 +6,7 @@
         "author": "Xuan Sang LE",
         "email": "xsang.le@gmail.com"
     },
-    "version":"0.1.5-a",
+    "version":"0.2.1-a",
     "category":"System",
     "iconclass":"fa fa-adn",
     "mimes":["none"],
diff --git a/src/packages/MarketPlace/scheme.html b/src/packages/MarketPlace/scheme.html
index 866c648..1653615 100644
--- a/src/packages/MarketPlace/scheme.html
+++ b/src/packages/MarketPlace/scheme.html
@@ -1,7 +1,6 @@
-
+
         
-            
-                
+            
                 
                     
diff --git a/src/themes/system/afx-tab-bar.css b/src/themes/system/afx-tab-bar.css index 27e71a6..0969db9 100644 --- a/src/themes/system/afx-tab-bar.css +++ b/src/themes/system/afx-tab-bar.css @@ -15,4 +15,4 @@ afx-tab-bar afx-list-view > div.list-container > ul afx-list-item:nth-child(even afx-tab-bar afx-list-view > div.list-container > ul li{ float:left; -} \ No newline at end of file +}