Improvement + fix bug:

- improve Tag API
- Improve CodePad UI + Extension API
- Add package dependencies to Market Place
This commit is contained in:
lxsang 2020-12-18 19:51:19 +01:00
parent 6c935e88ee
commit 566592dc8e
15 changed files with 480 additions and 158 deletions

View File

@ -5,7 +5,7 @@ DOCDIR?=/opt/www/htdocs/doc/antos
BLUE=\033[1;34m BLUE=\033[1;34m
NC=\033[0m NC=\033[0m
VERSION=1.0.0 VERSION=1.1.2
GSED=sed GSED=sed
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)

BIN
release/antos-1.1.2.tar.gz Normal file

Binary file not shown.

View File

@ -301,7 +301,7 @@ namespace OS {
* @memberof BaseApplication * @memberof BaseApplication
*/ */
show(): void { show(): void {
return this.trigger("focus", undefined); this.trigger("focus", undefined);
} }
/** /**

View File

@ -63,7 +63,6 @@ namespace OS {
*/ */
quit(): void { quit(): void {
const evt = new BaseEvent("exit", false); const evt = new BaseEvent("exit", false);
this.onexit(evt);
if (!evt.prevent) { if (!evt.prevent) {
delete this._observable; delete this._observable;
if (this.scheme) { if (this.scheme) {
@ -72,6 +71,7 @@ namespace OS {
if (this.dialog) { if (this.dialog) {
return this.dialog.quit(); return this.dialog.quit();
} }
this.onexit(evt);
} }
} }
@ -117,6 +117,9 @@ namespace OS {
show(): void { show(): void {
this.trigger("focus"); this.trigger("focus");
$(this.scheme).css("z-index", GUI.zindex + 2); $(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) { if (this.data && this.data.value) {
$input.val(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) => { (this.find("btnOk") as tag.ButtonTag).onbtclick = (e) => {
const value = $input.val(); const value = $input.val();
if (!value || value === "") { if (!value || value === "") {

View File

@ -565,7 +565,6 @@ namespace OS {
this.dialog.handle = resolve; this.dialog.handle = resolve;
this.dialog.pid = this.pid; this.dialog.pid = this.pid;
this.dialog.data = data; this.dialog.data = data;
return this.dialog.init(); return this.dialog.init();
}); });
} }

View File

@ -1059,6 +1059,25 @@ namespace OS {
* @memberof PackageMetaType * @memberof PackageMetaType
*/ */
version: string; 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; [propName: string]: any;
} }
/** /**
@ -1359,11 +1378,12 @@ namespace OS {
* *
* @export * @export
* @param {string} l VFS path to the library * @param {string} l VFS path to the library
* @param {string} force force reload library
* @returns {Promise<any>} a promise on the result data * @returns {Promise<any>} a promise on the result data
*/ */
export function requires(l: string): Promise<any> { export function requires(l: string, force: boolean = false): Promise<any> {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (!API.shared[l]) { if (!API.shared[l] || force) {
const libfp = l.asFileHandle(); const libfp = l.asFileHandle();
switch (libfp.ext) { switch (libfp.ext) {
case "css": case "css":
@ -1427,7 +1447,7 @@ namespace OS {
} }
return resolve(r); return resolve(r);
}); });
return API.requires(libs[0]).catch((e: Error) => return API.requires(libs[0], false).catch((e: Error) =>
reject(__e(e)) reject(__e(e))
); );
}); });

View File

@ -108,7 +108,7 @@ namespace OS {
); );
} catch (e) { } catch (e) {
return this.logger().error( return this.logger().error(
__("Unable to create package archive: {}", __("Unable to create package archive: {0}",
e.stack) e.stack)
); );
} }

View File

@ -5,7 +5,29 @@ afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view > div.list-contai
{ {
/*border-top: 1px solid #272822;*/ /*border-top: 1px solid #272822;*/
overflow: hidden; overflow: hidden;
overflow-x: auto;
font-size: 12px; 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, afx-app-window[data-id = "codepad"] afx-tab-bar> afx-list-view ul afx-list-item:nth-child(even) li.selected,

View File

@ -311,7 +311,7 @@ namespace OS {
highlightSelectedWord: true, highlightSelectedWord: true,
behavioursEnabled: true, behavioursEnabled: true,
wrap: true, wrap: true,
fontSize: "11pt", fontSize: "10pt",
showInvisibles: true, showInvisibles: true,
}); });
//themes = ace.require "ace/ext/themelist" //themes = ace.require "ace/ext/themelist"
@ -466,8 +466,7 @@ namespace OS {
return this.fileview.update(path); 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() this.logger.clear()
} }
@ -837,23 +836,32 @@ namespace OS {
* Run an extension action from the command palette * Run an extension action from the command palette
* *
* @private * @private
* @param {string} name extension name * @param { GenericObject<any>} extmeta extension name
* @param {string} action action name * @param {string} action action name
* @returns {void} * @returns {void}
* @memberof CodePad * @memberof CodePad
*/ */
private runExtensionAction(name: string, action: string): void { private runExtensionAction(extmeta: GenericObject<any>, action: string): void {
if (!CodePad.extensions[name]) { let ext = undefined;
if (extmeta.ext) {
if (!extmeta.ext[action]) {
return this.error(__("Unknown extension action: {0}", action));
}
}
else {
if (!CodePad.extensions[extmeta.name]) {
return this.error( return this.error(
__("Unable to find extension: {0}", name) __("Unable to find extension: {0}", extmeta.name)
); );
} }
const ext = new CodePad.extensions[name](this); extmeta.ext = new CodePad.extensions[extmeta.name](this);
if (!ext[action]) { if (!extmeta.ext[action]) {
return this.error(__("Unable to find action: {0}", 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) => { .catch((e: Error) => {
return this.error(__("Unable to preload extension"), e); return this.error(__("Unable to preload extension"), e);
}); });
@ -872,9 +880,9 @@ namespace OS {
/** /**
* Parent context of the current action * Parent context of the current action
* *
* @type {{ name: any }} * @type {{ name: any, ext: any }}
*/ */
parent: { name: any }; parent: { name: any, ext: any };
/** /**
* Action name * Action name
@ -883,15 +891,15 @@ namespace OS {
*/ */
name: any; name: any;
}): void { }): void {
const { name } = data.parent; const name = data.parent.name;
const action = data.name; const action = data.name;
//verify if the extension is load //verify if the extension is load
if (!CodePad.extensions[name]) { if (!CodePad.extensions[name]) {
//load the extension //load the extension
const path = `${this.meta().path}/${name}.js`; const path = `${this.meta().path}/${name}.js`;
this._api this._api
.requires(path) .requires(path, true)
.then(() => this.runExtensionAction(name, action)) .then(() => this.runExtensionAction(data.parent, action))
.catch((e) => { .catch((e) => {
return this.error( return this.error(
__("unable to load extension: {0}", name), __("unable to load extension: {0}", name),
@ -899,7 +907,7 @@ namespace OS {
); );
}); });
} else { } else {
this.runExtensionAction(name, action); this.runExtensionAction(data.parent, action);
} }
} }
@ -1461,7 +1469,7 @@ namespace OS {
"os://scripts/ace/ace.js", "os://scripts/ace/ace.js",
"os://scripts/ace/ext-language_tools.js", "os://scripts/ace/ext-language_tools.js",
"os://scripts/ace/ext-modelist.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.data = this.data.nodes;
} }
$(this.cmdlist).click((e) => { $(this.cmdlist).click((e) => {
$(document).unbind("mousedown", cb);
return this.selectCommand(); return this.selectCommand();
}); });
@ -1585,11 +1594,11 @@ namespace OS {
if (!el) { if (!el) {
return; return;
} }
this.quit();
el.selected = false; el.selected = false;
if (this.handle) { if (this.handle) {
this.handle({ data: { item: el } }); this.handle({ data: { item: el } });
} }
return this.quit();
} }
} }

View File

@ -7,7 +7,7 @@
"email": "xsang.le@gmail.com", "email": "xsang.le@gmail.com",
"licences": "GPLv3" "licences": "GPLv3"
}, },
"version":"0.0.2-a", "version":"0.0.3-b",
"category":"Developments", "category":"Developments",
"iconclass":"fa fa-pencil-square-o", "iconclass":"fa fa-pencil-square-o",
"mimes":[ "mimes":[

View File

@ -99,7 +99,7 @@ namespace OS {
} }
protected onexit(e: BaseEvent): void{ protected onexit(e: BaseEvent): void{
(this.parent as OS.application.MarketPlace).refreshRepoList(); (this.parent as OS.application.MarketPlace).fetchApps();
return super.onexit(e); return super.onexit(e);
} }
} }

View File

@ -21,8 +21,7 @@ namespace OS {
declare var JSZip: any; declare var JSZip: any;
export class MarketPlace extends BaseApplication { export class MarketPlace extends BaseApplication {
private installdir: string; private installdir: string;
private apps_meta: GenericObject<any>[]; private apps_meta: GenericObject<any>;
private repo: GUI.tag.ListViewTag;
private applist: GUI.tag.ListViewTag; private applist: GUI.tag.ListViewTag;
private container: GUI.tag.VBoxTag; private container: GUI.tag.VBoxTag;
private appname: GUI.tag.LabelTag; private appname: GUI.tag.LabelTag;
@ -41,16 +40,6 @@ namespace OS {
this.installdir = this.systemsetting.system.pkgpaths.user; this.installdir = this.systemsetting.system.pkgpaths.user;
// test repository // test repository
this.apps_meta = []; 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 = this.find("applist") as GUI.tag.ListViewTag;
this.applist.onlistselect = (e) => { this.applist.onlistselect = (e) => {
@ -109,19 +98,14 @@ namespace OS {
}); });
$(this.searchbox).keyup((e) => this.search(e)); $(this.searchbox).keyup((e) => this.search(e));
}
refreshRepoList(): void { this.fetchApps().then((d) => {
const list = Array.from(this.systemsetting.system.repositories); //console.log(d);
list.unshift({
text: "Installed",
url: undefined,
}); });
this.repo.data = list;
} }
private search(e: JQuery.KeyboardEventBase) { private search(e: JQuery.KeyboardEventBase) {
let v: GenericObject<any>; let k: string;
switch (e.which) { switch (e.which) {
case 37: case 37:
return e.preventDefault(); return e.preventDefault();
@ -140,8 +124,8 @@ namespace OS {
if (text.length === 2) { if (text.length === 2) {
this.applist.data = (() => { this.applist.data = (() => {
const result1 = []; const result1 = [];
for (v of this.apps_meta) { for (k in this.apps_meta) {
result1.push(v); result1.push(this.apps_meta[k]);
} }
return result1; return result1;
})(); })();
@ -151,57 +135,134 @@ namespace OS {
} }
var result = []; var result = [];
var term = new RegExp(text, "i"); var term = new RegExp(text, "i");
for (v of this.apps_meta) { for (k in this.apps_meta) {
if (v.text.match(term)) { if (this.apps_meta[k].text.match(term)) {
result.push(v); result.push(this.apps_meta[k]);
} }
} }
this.applist.data = result; this.applist.data = result;
} }
} }
private fetchApps(data: GenericObject<any>): void { /**
let v: API.PackageMetaType; * Load package meta-data from remote sources
if (!data.url) { *
const pkgcache = this.systemsetting.system.packages; * @private
const list = []; * @param {string} url repository url
for (let k in pkgcache) { * @return {*} {Promise<GenericObject<any>>}
v = pkgcache[k]; * @memberof MarketPlace
list.push({ */
pkgname: v.pkgname ? v.pkgname : v.app, private loadRemoteRepository(url: string): Promise<GenericObject<any>> {
name: v.name, return new Promise((resolve, reject) => {
text: v.name, url.asFileHandle().read('json')
icon: v.icon, //this._api
iconclass: v.iconclass, //.get(url + "?_=" + new Date().getTime(), "json")
category: v.category,
author: v.info.author,
version: v.version,
description: `${v.path}/REAME.md`,
});
}
this.apps_meta = list;
this.applist.data = list;
return;
}
this._api
.get(data.url + "?_=" + new Date().getTime(), "json")
.then((d) => { .then((d) => {
for (v of d) { for (let v of d) {
v.text = v.name; v.text = `${v.name} v${v.version}`;
v.iconclass = "fa fa-adn"; v.iconclass = "fa fa-adn";
v.dependBy = [];
if (!v.dependencies) {
v.dependencies = [];
} }
this.apps_meta = d; }
return (this.applist.data = d); resolve(d);
}) })
.catch((e) => { .catch((e) => {
return this.error( return this.error(
__( __(
"Fail to fetch packages list from: {0}", "Fail to fetch packages list from: {0}",
data.url url
), ),
e e
); );
reject(e);
});
});
}
/**
* Load packages meta-data from a list of repositories
*
* @private
* @param {string[]} list repositories list
* @return {*} {Promise<GenericObject<any>[]>} a Promise on a list of package meta-data
* @memberof MarketPlace
*/
private loadRemoteRepositories(list: string[]): Promise<GenericObject<any>[]> {
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<any>[]) => {
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<GenericObject<any>> {
return new Promise((resolve, reject) => {
let v: API.PackageMetaType;
this.apps_meta = {};
const pkgcache = this.systemsetting.system.packages;
for (let k in pkgcache) {
v = pkgcache[k];
this.apps_meta[`${k}@${v.version}`] = {
pkgname: v.pkgname ? v.pkgname : v.app,
name: 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}/README.md`,
dependencies: v.dependencies ? Array.from(v.dependencies) : [],
dependBy: []
};
}
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);
});
}); });
} }
@ -321,7 +382,119 @@ namespace OS {
default: default:
} }
} }
private checkDependencies(pkgname: string, is_uninstall: boolean = false): GenericObject<Set<string>> {
let dep_list = {
install: new Set<string>(),
uninstall: new Set<string>(),
notfound: new Set<string>()
};
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<string>
{
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<any>
{
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<string> { private remoteInstall(): Promise<string> {
const el = this.applist.selectedItem; const el = this.applist.selectedItem;
if (!el) { if (!el) {
@ -333,19 +506,47 @@ namespace OS {
} }
// get blob file // get blob file
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { let pkgname = `${el.data.pkgname}@${el.data.version}`;
const data = await this._api.blob( const dep = this.checkDependencies(pkgname);
app.download + "?_=" + new Date().getTime() if (dep.notfound.size != 0) {
); return this.openDialog("TextDialog", {
try { disable: true,
const n = await this.install(data, app); title: __("Unresolved dependencies"),
return resolve(n); value: __(
} catch (e) { "Unable to install: The package `{0}` depends on these packages, but they are not found:\n{1}",
return reject(__e(e)); pkgname,
} [...dep.notfound].join("\n")
} catch (e_1) { )
return reject(__e(e_1)); })
.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) => { .then((data: Uint8Array) => {
return this.install(data) return this.install(data)
.then((n) => { .then((n) => {
this.repo.unselect();
this.repo.selected = 0;
const apps = this.applist.data.map( const apps = this.applist.data.map(
(v) => v.pkgname (v) => v.pkgname
); );
@ -456,7 +655,74 @@ namespace OS {
.catch((e: Error) => reject(__e(e))); .catch((e: Error) => reject(__e(e)));
}); });
} }
private bulkUninstall(list: string[]): Promise<any>
{
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<any>
{
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<any> { private uninstall(): Promise<any> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const el = this.applist.selectedItem; const el = this.applist.selectedItem;
@ -472,42 +738,24 @@ namespace OS {
if (!app) { if (!app) {
return; return;
} }
const pkgname = `${sel.pkgname}@${app.version}`;
const dep = this.checkDependencies(pkgname, true);
try { try {
const d = await this.openDialog("YesNoDialog", { const d = await this.openDialog("TextDialog", {
title: __("Uninstall"), 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) { if (!d) {
return; return;
} }
try { this.bulkUninstall([...dep.uninstall])
const r = await app.path .then((b)=>{
.asFileHandle() this.notify(__("Uninstall successfully"));
.remove(); })
if (r.error) { .catch((err)=>{
return reject(this._api.throwe(__("Cannot uninstall package: {0}", r.error))); this.error(__("Unable to uninstall package(s): {0}", err.toString()), err);
} });
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));
}
} }
catch (e_1) { catch (e_1) {
return reject(__e(e_1)); return reject(__e(e_1));
@ -518,14 +766,33 @@ namespace OS {
private updatePackage(): Promise<any> { private updatePackage(): Promise<any> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
await this.uninstall(); const el = this.applist.selectedItem;
try { 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(); await this.remoteInstall();
return resolve(); try {
if(meta)
{
if(meta.domel)
this.applist.delete(meta.domel);
}
return resolve(true);
} }
catch (e) { catch (e) {
return reject(__e(e)); return reject(__e(e));
} }
} }
catch (e_1) { catch (e_1) {
return reject(__e(e_1)); return reject(__e(e_1));
@ -536,7 +803,7 @@ namespace OS {
private mkdirs(list: string[]): Promise<any> { private mkdirs(list: string[]): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (list.length === 0) { if (list.length === 0) {
return resolve(); return resolve(true);
} }
const dir = list.splice(0, 1)[0].asFileHandle(); const dir = list.splice(0, 1)[0].asFileHandle();
const path = dir.parent(); const path = dir.parent();
@ -556,7 +823,7 @@ namespace OS {
); );
} }
return this.mkdirs(list) return this.mkdirs(list)
.then(() => resolve()) .then(() => resolve(true))
.catch((e) => reject(__e(e))); .catch((e) => reject(__e(e)));
}) })
.catch((e) => reject(__e(e))); .catch((e) => reject(__e(e)));
@ -566,7 +833,7 @@ namespace OS {
private installFile(n: string, zip: any, files: string[]): Promise<any> { private installFile(n: string, zip: any, files: string[]): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (files.length === 0) { if (files.length === 0) {
return resolve(); return resolve(true);
} }
const file = files.splice(0, 1)[0]; const file = files.splice(0, 1)[0];
const path = `${this.installdir}/${n}/${file}`; const path = `${this.installdir}/${n}/${file}`;
@ -587,7 +854,7 @@ namespace OS {
); );
} }
return this.installFile(n, zip, files) return this.installFile(n, zip, files)
.then(() => resolve()) .then(() => resolve(true))
.catch((e) => reject(__e(e))); .catch((e) => reject(__e(e)));
}) })
.catch((e) => reject(__e(e))); .catch((e) => reject(__e(e)));

View File

@ -6,7 +6,7 @@
"author": "Xuan Sang LE", "author": "Xuan Sang LE",
"email": "xsang.le@gmail.com" "email": "xsang.le@gmail.com"
}, },
"version":"0.1.5-a", "version":"0.2.1-a",
"category":"System", "category":"System",
"iconclass":"fa fa-adn", "iconclass":"fa fa-adn",
"mimes":["none"], "mimes":["none"],

View File

@ -1,7 +1,6 @@
<afx-app-window data-id = "marketplace-win" apptitle="MarketPlace" width="500" height="400"> <afx-app-window data-id = "marketplace-win" apptitle="MarketPlace" width="600" height="400">
<afx-hbox > <afx-hbox >
<afx-vbox data-width = "172" data-id = "sidebar" min-width="172"> <afx-vbox data-width = "200" data-id = "sidebar" min-width="150">
<afx-list-view data-id = "repo" dropdown = "true" data-height= "25" width = "150"></afx-list-view>
<afx-hbox data-height= "23" data-id="search-container"> <afx-hbox data-height= "23" data-id="search-container">
<div data-width="17" data-id="searchicon"></div> <div data-width="17" data-id="searchicon"></div>
<input data-id = "searchbox" /> <input data-id = "searchbox" />