Rework on Notification API + some sytem packages

- Rename Syslog to SystemReport
- All services previously on SystemReport now moved to the dedicated SystemServices Packages
- Rework on a more versatile notification GUI and API
- Applications now can display a local toast message instead of pushing a global notification message
This commit is contained in:
DanyLE 2023-01-06 18:44:11 +01:00 committed by Dany LE
parent c52e4b649e
commit 242df06a28
28 changed files with 917 additions and 171 deletions

View File

@ -43,7 +43,8 @@ tags = dist/core/tags/tag.js \
dist/core/tags/DesktopTag.js \ dist/core/tags/DesktopTag.js \
dist/core/tags/StackMenuTag.js \ dist/core/tags/StackMenuTag.js \
dist/core/tags/StackPanelTag.js \ dist/core/tags/StackPanelTag.js \
dist/core/tags/InputTag.js dist/core/tags/InputTag.js \
dist/core/tags/NotificationTag.js
javascripts= dist/core/core.js \ javascripts= dist/core/core.js \
dist/core/settings.js \ dist/core/settings.js \
@ -63,7 +64,7 @@ javascripts= dist/core/core.js \
antfx = $(tags) \ antfx = $(tags) \
dist/core/Announcerment.js dist/core/Announcerment.js
packages = Syslog Files MarketPlace Setting NotePad packages = SystemServices SystemReport Files MarketPlace Setting NotePad
main: initd build_javascripts build_themes libs build_packages languages main: initd build_javascripts build_themes libs build_packages languages
- cp src/index.html $(BUILDDIR)/ - cp src/index.html $(BUILDDIR)/

225
d.ts/antos.d.ts vendored
View File

@ -953,6 +953,46 @@ declare namespace OS {
* - System dialogs definition * - System dialogs definition
*/ */
namespace GUI { namespace GUI {
/**
* Enum definition of different UI locattion
*
* @export
* @enum {string }
*/
enum ANCHOR {
/**
* Center top
*/
NORTH = "NORTH",
/**
* Center bottom
*/
SOUTH = "SOUTH",
/**
* Center left
*/
WEST = "WEST",
/**
* Center right
*/
EST = "EST",
/**
* Top left
*/
NORTH_WEST = "NORTH_WEST",
/**
* Bottom left
*/
SOUTH_WEST = "SOUTH_WEST",
/**
* Top right
*/
NORTH_EST = "NORTH_EST",
/**
* Bottom right
*/
SOUTH_EST = "SOUTH_EST"
}
/** /**
* AntOS keyboard shortcut type definition * AntOS keyboard shortcut type definition
* *
@ -1084,6 +1124,46 @@ declare namespace OS {
* to each dialog definition for the format of the callback data * to each dialog definition for the format of the callback data
*/ */
function openDialog(d: string | BaseDialog, data: GenericObject<any>): Promise<any>; function openDialog(d: string | BaseDialog, data: GenericObject<any>): Promise<any>;
/**
* Toast notification configuration options
*
*
* @export
* @interface ToastOptions
*/
interface ToastOptions {
/**
* Where the Toast is displayed?
*
* @type {ANCHOR}
* @memberof ToastOptions
*/
location?: ANCHOR;
/**
* Timeout (in seconds) before the Toast disappear
* Set this value to 0 to prevent the Toast to disappear,
* in this case, use need to explicitly close the notification
*
* @type {number}
* @memberof ToastOptions
*/
timeout?: number;
/**
* AFXTag that is used to render the data
*
* @type {number}
* @memberof ToastOptions
*/
tag?: string;
}
/**
* Toast notification API
*
* @export
* @param
* @returns
*/
function toast(data: any, opts?: ToastOptions, app?: application.BaseApplication): void;
/** /**
* Find a list of applications that support a specific mime * Find a list of applications that support a specific mime
* type in the system packages meta-data * type in the system packages meta-data
@ -2443,6 +2523,12 @@ declare namespace OS {
* @memberof BaseApplication * @memberof BaseApplication
*/ */
title(): string | FormattedString; title(): string | FormattedString;
/**
* Getter to access the application window instance
*
* @memberof BaseApplication
*/
get window(): GUI.tag.WindowTag;
/** /**
* Function called when the application exit. * Function called when the application exit.
* If the input exit event is prevented, the application * If the input exit event is prevented, the application
@ -2489,6 +2575,15 @@ declare namespace OS {
* @memberof BaseApplication * @memberof BaseApplication
*/ */
protected menu(): GUI.BasicItemType[]; protected menu(): GUI.BasicItemType[];
/**
* Show local toast notification
*
* @param {any} data to send
* @param {GUI.ToastOptions} notification options see [[GUI.ToastOptions]]
* @returns {void}
* @memberof BaseApplication
*/
toast(data: any, opts?: GUI.ToastOptions): void;
/** /**
* The cleanup function that is called by [[onexit]] function. * The cleanup function that is called by [[onexit]] function.
* Application need to override this function to perform some * Application need to override this function to perform some
@ -3926,6 +4021,12 @@ declare namespace OS {
* stored in the `customElements` registry of the browser * stored in the `customElements` registry of the browser
*/ */
namespace tag { namespace tag {
/**
* Alias to all classes that extends [[AFXTag]]
*/
type AFXTagTypeClass = {
new <T extends AFXTag>(): T;
};
/** /**
* Define an AFX tag as a custom element and add it to the * Define an AFX tag as a custom element and add it to the
* global `customElements` registry. If the tag is redefined, i.e. * global `customElements` registry. If the tag is redefined, i.e.
@ -7974,7 +8075,7 @@ declare namespace OS {
*/ */
reset(): void; reset(): void;
/** /**
* Mount the tab bar and bind some basic events * Mount the menu and bind some basic events
* *
* @protected * @protected
* @memberof StackMenuTag * @memberof StackMenuTag
@ -8059,7 +8160,7 @@ declare namespace OS {
*/ */
show(e?: JQuery.MouseEventBase): void; show(e?: JQuery.MouseEventBase): void;
/** /**
* TabBar layout definition * Tag layout definition
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}
@ -8362,7 +8463,7 @@ declare namespace OS {
*/ */
navigateBack(): void; navigateBack(): void;
/** /**
* Navigate to a custom tab * Navigate to a custom panel
* *
* @memberof StackPanelTag * @memberof StackPanelTag
*/ */
@ -8454,6 +8555,118 @@ declare namespace OS {
} }
} }
} }
declare namespace OS {
namespace GUI {
namespace tag {
/**
* Toast notification tag
*
* @export
* @class ToastNotificationTag
* @extends {AFXTag}
*/
class ToastNotificationTag extends AFXTag {
/**
*Creates an instance of ToastNotificationTag.
* @memberof ToastNotificationTag
*/
constructor();
/**
* Mount the tag
*
* @protected
* @memberof ToastNotificationTag
*/
protected mount(): void;
/**
* Init the tag before mounting
*
* @protected
* @memberof ToastNotificationTag
*/
protected init(): void;
/**
* Re-calibrate tag
*
* @protected
* @memberof ToastNotificationTag
*/
protected calibrate(): void;
/**
* Update the current tag, do nothing in this tag
*
* @param {*} [d]
* @memberof ToastNotificationTag
*/
reload(d?: any): void;
/**
* Tag layout definition
*
* @protected
* @returns {TagLayoutType[]}
* @memberof ToastNotificationTag
*/
protected layout(): TagLayoutType[];
}
/**
* This tag manage all notification UI on the desktop
*
* @export
* @class NotificationTag
* @extends {AFXTag}
*/
class NotificationTag extends AFXTag {
/**
*Creates an instance of NotificationTag.
* @memberof NotificationTag
*/
constructor();
/**
* Mount the tag
*
* @protected
* @memberof NotificationTag
*/
protected mount(): void;
/**
* Init the tag before mounting
*
* @protected
* @memberof NotificationTag
*/
protected init(): void;
/**
* Push anotification to a specific location
*
* @memberof NotificationTag
*/
push(tag: AFXTag, loc?: ANCHOR): void;
/**
* Re-calibrate tag
*
* @protected
* @memberof NotificationTag
*/
protected calibrate(): void;
/**
* Update the current tag, do nothing in this tag
*
* @param {*} [d]
* @memberof NotificationTag
*/
reload(d?: any): void;
/**
* Tag layout definition
*
* @protected
* @returns {TagLayoutType[]}
* @memberof NotificationTag
*/
protected layout(): TagLayoutType[];
}
}
}
}
declare namespace OS { declare namespace OS {
namespace GUI { namespace GUI {
namespace tag { namespace tag {
@ -9066,6 +9279,12 @@ declare namespace OS {
*/ */
set apptitle(v: string | FormattedString); set apptitle(v: string | FormattedString);
get apptitle(): string | FormattedString; get apptitle(): string | FormattedString;
/**
* Get the notification tag
*
* @memberof WindowTag
*/
get notification(): NotificationTag;
/** /**
* Resize all the children of the window based on its width and height * Resize all the children of the window based on its width and height
* *

View File

@ -380,7 +380,17 @@ namespace OS {
title(): string | FormattedString { title(): string | FormattedString {
return (this.scheme as GUI.tag.WindowTag).apptitle; return (this.scheme as GUI.tag.WindowTag).apptitle;
} }
/**
* Getter to access the application window instance
*
* @memberof BaseApplication
*/
get window(): GUI.tag.WindowTag
{
return this.scheme as GUI.tag.WindowTag;
}
/** /**
* Function called when the application exit. * Function called when the application exit.
* If the input exit event is prevented, the application * If the input exit event is prevented, the application
@ -455,6 +465,35 @@ namespace OS {
return []; return [];
} }
/**
* Show local toast notification
*
* @param {any} data to send
* @param {GUI.ToastOptions} notification options see [[GUI.ToastOptions]]
* @returns {void}
* @memberof BaseApplication
*/
toast(data: any, opts?: GUI.ToastOptions): void {
let options: GUI.ToastOptions = {
location: GUI.ANCHOR.SOUTH_EST,
timeout: 3,
tag: "afx-label"
};
if(opts)
{
for(const k in opts)
{
options[k] = opts[k];
}
}
let d = data;
if(typeof data == "string" || data instanceof FormattedString)
{
d = {text: data};
}
this._gui.toast(d,options, this);
}
/** /**
* The cleanup function that is called by [[onexit]] function. * The cleanup function that is called by [[onexit]] function.
* Application need to override this function to perform some * Application need to override this function to perform some

View File

@ -26,6 +26,48 @@ namespace OS {
* - System dialogs definition * - System dialogs definition
*/ */
export namespace GUI { export namespace GUI {
/**
* Enum definition of different UI locattion
*
* @export
* @enum {string }
*/
export enum ANCHOR {
/**
* Center top
*/
NORTH = "NORTH",
/**
* Center bottom
*/
SOUTH = "SOUTH",
/**
* Center left
*/
WEST = "WEST",
/**
* Center right
*/
EST = "EST",
/**
* Top left
*/
NORTH_WEST = "NORTH_WEST",
/**
* Bottom left
*/
SOUTH_WEST = "SOUTH_WEST",
/**
* Top right
*/
NORTH_EST = "NORTH_EST",
/**
* Bottom right
*/
SOUTH_EST = "SOUTH_EST",
}
/** /**
* AntOS keyboard shortcut type definition * AntOS keyboard shortcut type definition
* *
@ -242,6 +284,87 @@ namespace OS {
return dialog.init(); return dialog.init();
}); });
} }
/**
* Toast notification configuration options
*
*
* @export
* @interface ToastOptions
*/
export interface ToastOptions {
/**
* Where the Toast is displayed? see [[ANCHOR]]
*
* @type {ANCHOR}
* @memberof ToastOptions
*/
location?: ANCHOR;
/**
* Timeout (in seconds) before the Toast disappear
* Set this value to 0 to prevent the Toast to disappear,
* in this case, use need to explicitly close the notification
*
* @type {number}
* @memberof ToastOptions
*/
timeout?: number;
/**
* AFXTag that is used to render the data
*
* @type {number}
* @memberof ToastOptions
*/
tag?: string;
}
/**
* Toast notification API
* Show a toad message on different posisition on screen, see [[ToastOptions]]
*
* @export
* @param
* @returns
*/
export function toast(data: any, opts?: ToastOptions, app: application.BaseApplication = undefined): void
{
let notification_el = undefined;
if(app)
{
notification_el = app.window.notification;
}
else
{
notification_el = $("#sys_notification")[0] as tag.NotificationTag;
}
let options: ToastOptions = {
location: ANCHOR.NORTH,
timeout: 3,
tag: "afx-label"
};
if(opts)
{
for(const k in opts)
{
options[k] = opts[k];
}
}
const toast_el = $(`<afx-toast-notification>`)[0] as tag.ToastNotificationTag;
const content_el = $(`<${options.tag}>`)[0] as AFXTag;
$(toast_el).append(content_el);
toast_el.uify(undefined);
notification_el.push(toast_el, options.location);
content_el.set(data);
if(options.timeout && options.timeout != 0)
{
setTimeout(function(){
$(toast_el).remove();
clearTimeout(this);
}, options.timeout*1000);
}
}
/** /**
* Find a list of applications that support a specific mime * Find a list of applications that support a specific mime
@ -951,6 +1074,8 @@ namespace OS {
); );
}); });
// mount it // mount it
const nottification = $("#sys_notification")[0] as tag.NotificationTag;
nottification.uify(undefined);
desktop().uify(undefined); desktop().uify(undefined);
} }
@ -1104,6 +1229,7 @@ namespace OS {
<afx-sys-panel id = "syspanel"></afx-sys-panel> <afx-sys-panel id = "syspanel"></afx-sys-panel>
<div id = "workspace"> <div id = "workspace">
<afx-desktop id = "desktop" dir="vertical" ></afx-desktop> <afx-desktop id = "desktop" dir="vertical" ></afx-desktop>
<afx-notification id="sys_notification" ></afx-notification>
</div> </div>
<afx-stack-menu id="contextmenu" data-id="contextmenu" context="true" style="display:none;"></afx-stack-menu> <afx-stack-menu id="contextmenu" data-id="contextmenu" context="true" style="display:none;"></afx-stack-menu>
<afx-label id="systooltip" data-id="systooltip" style="display:none;position:absolute;"></afx-label> <afx-label id="systooltip" data-id="systooltip" style="display:none;position:absolute;"></afx-label>

View File

@ -0,0 +1,189 @@
namespace OS {
export namespace GUI {
export namespace tag {
/**
* Toast notification tag
*
* @export
* @class ToastNotificationTag
* @extends {AFXTag}
*/
export class ToastNotificationTag extends AFXTag {
/**
*Creates an instance of ToastNotificationTag.
* @memberof ToastNotificationTag
*/
constructor() {
super();
}
/**
* Mount the tag
*
* @protected
* @memberof ToastNotificationTag
*/
protected mount() {
$(this.refs.header).on('click',(e) => {
$(this).remove();
})
}
/**
* Init the tag before mounting
*
* @protected
* @memberof ToastNotificationTag
*/
protected init(): void {
};
/**
* Re-calibrate tag
*
* @protected
* @memberof ToastNotificationTag
*/
protected calibrate(): void {}
/**
* Update the current tag, do nothing in this tag
*
* @param {*} [d]
* @memberof ToastNotificationTag
*/
reload(d?: any): void {}
/**
* Tag layout definition
*
* @protected
* @returns {TagLayoutType[]}
* @memberof ToastNotificationTag
*/
protected layout(): TagLayoutType[] {
return [
{
el: "div", id: "toast_container", ref: "container",
children:[
{
el: "div",
ref: "header",
id: "toast_header",
},
{
el: "div",
ref: "yield",
id:"toast_content",
}
]
}
];
}
}
/**
* This tag manage all notification UI on the desktop
*
* @export
* @class NotificationTag
* @extends {AFXTag}
*/
export class NotificationTag extends AFXTag {
/**
*Creates an instance of NotificationTag.
* @memberof NotificationTag
*/
constructor() {
super();
}
/**
* Mount the tag
*
* @protected
* @memberof NotificationTag
*/
protected mount() {
}
/**
* Init the tag before mounting
*
* @protected
* @memberof NotificationTag
*/
protected init(): void {
};
/**
* Push anotification to a specific location
*
* @memberof NotificationTag
*/
push(tag: AFXTag, loc: ANCHOR = ANCHOR.NORTH): void
{
if(!this.refs[loc])
{
return;
}
switch(loc)
{
case ANCHOR.NORTH:
case ANCHOR.NORTH_EST:
case ANCHOR.NORTH_WEST:
$(this.refs[loc]).prepend(tag);
break;
case ANCHOR.SOUTH:
case ANCHOR.SOUTH_EST:
case ANCHOR.SOUTH_WEST:
$(this.refs[loc]).append(tag);
break;
default: break;
}
this.calibrate();
}
/**
* Re-calibrate tag
*
* @protected
* @memberof NotificationTag
*/
protected calibrate(): void {}
/**
* Update the current tag, do nothing in this tag
*
* @param {*} [d]
* @memberof NotificationTag
*/
reload(d?: any): void {}
/**
* Tag layout definition
*
* @protected
* @returns {TagLayoutType[]}
* @memberof NotificationTag
*/
protected layout(): TagLayoutType[] {
return [
{ el: "div", id: "north", ref: "NORTH" },
{ el: "div", id: "south", ref: "SOUTH" },
{ el: "div", id: "north_west", ref: "NORTH_WEST" },
{ el: "div", id: "south_west", ref: "SOUTH_WEST" },
{ el: "div", id: "north_est", ref: "NORTH_EST" },
{ el: "div", id: "south_est", ref: "SOUTH_EST" }
];
}
}
define("afx-notification", NotificationTag);
define("afx-toast-notification", ToastNotificationTag);
}
}
}

View File

@ -325,7 +325,7 @@ namespace OS {
} }
/** /**
* Mount the tab bar and bind some basic events * Mount the menu and bind some basic events
* *
* @protected * @protected
* @memberof StackMenuTag * @memberof StackMenuTag
@ -546,7 +546,7 @@ namespace OS {
} }
/** /**
* TabBar layout definition * Tag layout definition
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}

View File

@ -61,7 +61,7 @@ namespace OS {
this.navigate() this.navigate()
} }
/** /**
* Navigate to a custom tab * Navigate to a custom panel
* *
* @memberof StackPanelTag * @memberof StackPanelTag
*/ */

View File

@ -272,6 +272,15 @@ namespace OS {
return $(this).attr("apptitle"); return $(this).attr("apptitle");
} }
/**
* Get the notification tag
*
* @memberof WindowTag
*/
get notification(): NotificationTag
{
return this.refs.notification as NotificationTag;
}
/** /**
* Resize all the children of the window based on its width and height * Resize all the children of the window based on its width and height
* *
@ -703,6 +712,10 @@ namespace OS {
{ {
el: "afx-stack-menu", el: "afx-stack-menu",
ref: "stackmenu" ref: "stackmenu"
},
{
el: "afx-notification",
ref: "notification"
} }
], ],
}, },

View File

@ -595,6 +595,7 @@ namespace OS {
return element.hasAttribute(v); return element.hasAttribute(v);
} }
} }
HTMLElement.prototype.update = function (d): void { HTMLElement.prototype.update = function (d): void {
$(this) $(this)
@ -632,6 +633,12 @@ namespace OS {
* stored in the `customElements` registry of the browser * stored in the `customElements` registry of the browser
*/ */
export namespace tag { export namespace tag {
/**
* Alias to all classes that extends [[AFXTag]]
*/
export type AFXTagTypeClass = {
new <T extends AFXTag>(): T;
};
/** /**
* Define an AFX tag as a custom element and add it to the * Define an AFX tag as a custom element and add it to the
* global `customElements` registry. If the tag is redefined, i.e. * global `customElements` registry. If the tag is redefined, i.e.

View File

@ -154,7 +154,7 @@ namespace OS {
} }
const path = `${d.file.path}/${d.name}`; const path = `${d.file.path}/${d.name}`;
await API.VFS.mkar(file.path, path); await API.VFS.mkar(file.path, path);
this.notify(__("Archive file created: {0}",path )); this.toast(__("Archive file created: {0}",path ));
} catch (error) { } catch (error) {
this.error(__("Unable to compress file, folder"), error); this.error(__("Unable to compress file, folder"), error);
} }
@ -638,7 +638,7 @@ namespace OS {
cut: true, cut: true,
files: this.view.selectedFiles.map(x => x.path.asFileHandle()), files: this.view.selectedFiles.map(x => x.path.asFileHandle()),
}; };
return this.notify(__("{0} files cut", this.clipboard.files.length)); return this.toast(__("{0} files cut", this.clipboard.files.length));
case `${this.name}-copy`: case `${this.name}-copy`:
if (!file) { if (!file) {
@ -648,7 +648,7 @@ namespace OS {
cut: false, cut: false,
files: this.view.selectedFiles.map(x => x.path.asFileHandle()), files: this.view.selectedFiles.map(x => x.path.asFileHandle()),
}; };
return this.notify( return this.toast(
__("{0} files copied", this.clipboard.files.length) __("{0} files copied", this.clipboard.files.length)
); );
@ -747,8 +747,7 @@ namespace OS {
.publish() .publish()
.then((r) => { .then((r) => {
return this.notify( return this.notify(
__("Shared url: {0}", r.result) __("Shared url: {0}", r.result));
);
}) })
.catch((e) => { .catch((e) => {
return this.error( return this.error(

View File

@ -126,10 +126,10 @@ namespace OS {
try { try {
if (this.btinstall.data.dirty) { if (this.btinstall.data.dirty) {
await this.updatePackage(); await this.updatePackage();
return this.notify(__("Package updated")); return this.toast(__("Package updated"));
} }
const n = await this.remoteInstall(); const n = await this.remoteInstall();
return this.notify(__("Package installed: {0}", n)); return this.toast(__("Package installed: {0}", n));
} catch (error) { } catch (error) {
return this.error(error.toString(), error); return this.error(error.toString(), error);
} }
@ -138,7 +138,7 @@ namespace OS {
this.btremove.onbtclick = async () => { this.btremove.onbtclick = async () => {
try { try {
await this.uninstall(); await this.uninstall();
return this.notify(__("Packaged uninstalled")); return this.toast(__("Packaged uninstalled"));
} catch (e) { } catch (e) {
return this.error(e.toString(), e); return this.error(e.toString(), e);
} }
@ -401,8 +401,8 @@ namespace OS {
); );
}) })
.catch((_e) => { .catch((_e) => {
this.notify( this.error(
__("Unable to read package description") __("Unable to read package description"), _e
); );
return $(this.appdesc).empty(); return $(this.appdesc).empty();
}); });
@ -487,7 +487,7 @@ namespace OS {
case "install": case "install":
this.localInstall() this.localInstall()
.then((n) => { .then((n) => {
return this.notify( return this.toast(
__("Package installed: {0}", n) __("Package installed: {0}", n)
); );
}) })
@ -734,7 +734,7 @@ namespace OS {
if (r.error) { if (r.error) {
throw __("Cannot uninstall package: {0}", r.error).__(); throw __("Cannot uninstall package: {0}", r.error).__();
} }
this.notify(__("Package uninstalled")); this.toast(__("Package uninstalled"));
// stop all the services if any // stop all the services if any
if (app.services) { if (app.services) {
for (let srv of Array.from(app.services)) { for (let srv of Array.from(app.services)) {
@ -787,7 +787,7 @@ namespace OS {
} }
this.bulkUninstall([...dep.uninstall]) this.bulkUninstall([...dep.uninstall])
.then((_b) => { .then((_b) => {
this.notify(__("Uninstall successfully")); this.toast(__("Uninstall successfully"));
}) })
.catch((err) => { .catch((err) => {
this.error(__("Unable to uninstall package(s): {0}", err.toString()), err); this.error(__("Unable to uninstall package(s): {0}", err.toString()), err);

View File

@ -1,6 +0,0 @@
# Syslog: System notification management and service
Provide system wise notification service (Push Notification)
## Change logs
-v0.1.2-b: add README

View File

@ -1,20 +0,0 @@
{
"app": "Syslog",
"pkgname": "Syslog",
"services": [
"Calendar",
"PushNotification"
],
"name": "System log",
"description": "Core services and system log",
"info": {
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com",
"credit": "dedicated to some one here",
"licences": "GPLv3"
},
"version": "0.1.2-b",
"category": "System",
"iconclass": "fa fa-bug",
"mimes": []
}

View File

@ -1,4 +1,4 @@
module_files = Calendar.js PushNotification.js Syslog.js module_files = SystemReport.js
libfiles = libfiles =
@ -7,5 +7,5 @@ cssfiles = main.css
copyfiles = package.json scheme.html README.md copyfiles = package.json scheme.html README.md
PKG_NAME=Syslog PKG_NAME=SystemReport
include ../pkg.mk include ../pkg.mk

View File

@ -0,0 +1,7 @@
# SystemReport: System notification management and service
Provide system wise notification service (Push Notification)
## Change logs
-v0.1.3-b: Rename from Syslog to SystemReport, move all services to SystemServices package
-v0.1.2-b: add README

View File

@ -110,33 +110,33 @@ detail:
* *
* *
* @export * @export
* @class Syslog * @class SystemReport
* @extends {BaseApplication} * @extends {BaseApplication}
*/ */
export class Syslog extends BaseApplication { export class SystemReport extends BaseApplication {
private loglist: TAG.ListViewTag; private loglist: TAG.ListViewTag;
private logdetail: HTMLElement; private logdetail: HTMLElement;
private srv: PushNotification; private srv: PushNotification;
constructor(args: AppArgumentsType[]) { constructor(args: AppArgumentsType[]) {
super("Syslog", args); super("SystemReport", args);
} }
/** /**
* *
* *
* @memberof Syslog * @memberof SystemReport
*/ */
/** /**
* *
* *
* @memberof Syslog * @memberof SystemReport
*/ */
main(): void { main(): void {
this.loglist = this.find("loglist") as TAG.ListViewTag; this.loglist = this.find("loglist") as TAG.ListViewTag;
this.logdetail = this.find("logdetail"); this.logdetail = this.find("logdetail");
this._gui this._gui
.pushService("Syslog/PushNotification") .pushService("SystemServices/PushNotification")
.then((srv) => { .then((srv) => {
this.srv = srv as PushNotification; this.srv = srv as PushNotification;
@ -231,7 +231,7 @@ detail:
* *
* *
* @param {GenericObject<any>} log * @param {GenericObject<any>} log
* @memberof Syslog * @memberof SystemReport
*/ */
addLog(log: GenericObject<any>): void { addLog(log: GenericObject<any>): void {
this.loglist.push(log); this.loglist.push(log);
@ -241,7 +241,7 @@ detail:
* *
* *
* @returns {void} * @returns {void}
* @memberof Syslog * @memberof SystemReport
*/ */
cleanup(): void { cleanup(): void {
if (this.srv) { if (this.srv) {
@ -250,6 +250,6 @@ detail:
} }
} }
Syslog.singleton = true; SystemReport.singleton = true;
} }
} }

View File

@ -0,0 +1,35 @@
afx-app-window[data-id ='Syslog'] div[data-id ='container']{
overflow: auto;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-error {
display: block;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-error i::before {
color: chocolate;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-time{
display: block;
padding-left: 10px;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-time i.label-text{
font-size: 10px;
font-style: italic;
}
afx-app-window[data-id ='Syslog'] afx-bug-list-item li.selected {
background-color: #116cd6;
color: white;
}
afx-app-window[data-id ='Syslog'] pre {
padding: 10px;
margin:0;
user-select: text;
cursor: text;
}
afx-app-window[data-id ='Syslog'] input{
height: 100%;
}

View File

@ -0,0 +1,15 @@
{
"app": "SystemReport",
"pkgname": "SystemReport",
"name": "System report",
"description": "System reports",
"info": {
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com",
"licences": "GPLv3"
},
"version": "0.1.3-b",
"category": "System",
"iconclass": "fa fa-bug",
"mimes": []
}

View File

@ -1,4 +1,4 @@
<afx-app-window data-id="Syslog" width='600' height='450' apptitle = "__(System error log)" > <afx-app-window data-id="SystemReport" width='600' height='450' apptitle = "__(System error log)" >
<afx-hbox> <afx-hbox>
<afx-list-view data-id = "loglist" data-width="200"> </afx-list-view> <afx-list-view data-id = "loglist" data-width="200"> </afx-list-view>
<afx-resizer data-width = "2" ></afx-resizer> <afx-resizer data-width = "2" ></afx-resizer>

View File

@ -0,0 +1,11 @@
module_files = Calendar.js PushNotification.js
libfiles =
cssfiles = main.css
copyfiles = package.json README.md
PKG_NAME=SystemServices
include ../pkg.mk

View File

@ -31,12 +31,10 @@ namespace OS {
private cb: (e: JQuery.ClickEvent) => void; private cb: (e: JQuery.ClickEvent) => void;
private view: boolean; private view: boolean;
private mlist: TAG.ListViewTag; private mlist: TAG.ListViewTag;
private mfeed: TAG.ListViewTag;
private nzone: TAG.OverlayTag; private nzone: TAG.OverlayTag;
private fzone: TAG.OverlayTag;
logs: GenericObject<any>[]; logs: GenericObject<any>[];
logmon: Syslog; logmon: SystemReport;
/** /**
*Creates an instance of PushNotification. *Creates an instance of PushNotification.
@ -70,9 +68,7 @@ namespace OS {
*/ */
main(): void { main(): void {
this.mlist = this.find("notifylist") as TAG.ListViewTag; this.mlist = this.find("notifylist") as TAG.ListViewTag;
this.mfeed = this.find("notifeed") as TAG.ListViewTag;
this.nzone = this.find("notifyzone") as TAG.OverlayTag; this.nzone = this.find("notifyzone") as TAG.OverlayTag;
this.fzone = this.find("feedzone") as TAG.OverlayTag;
(this.find("btclear") as TAG.ButtonTag).onbtclick = (e) => (this.find("btclear") as TAG.ButtonTag).onbtclick = (e) =>
(this.mlist.data = []); (this.mlist.data = []);
(this.find("bterrlog") as TAG.ButtonTag).onbtclick = (e) => (this.find("bterrlog") as TAG.ButtonTag).onbtclick = (e) =>
@ -83,18 +79,12 @@ namespace OS {
this.subscribe("info", (o) => this.pushout("INFO", o)); this.subscribe("info", (o) => this.pushout("INFO", o));
this.nzone.height = "100%"; this.nzone.height = "100%";
this.fzone.height = "100%";
$(this.nzone) $(this.nzone)
.css("right", 0) .css("right", 0)
.css("top", "0") .css("top", "0")
.css("bottom", "0") .css("bottom", "0")
.hide(); .hide();
$(this.fzone)
//.css("z-index", 99999)
.css("bottom", "0")
.css("bottom", "0")
.hide();
} }
/** /**
@ -105,7 +95,7 @@ namespace OS {
* @memberof PushNotification * @memberof PushNotification
*/ */
private showLogReport(): void { private showLogReport(): void {
this._gui.launch("Syslog", []); this._gui.launch("SystemReport", []);
} }
/** /**
@ -167,16 +157,7 @@ namespace OS {
* @memberof PushNotification * @memberof PushNotification
*/ */
private notifeed(d: GenericObject<any>): void { private notifeed(d: GenericObject<any>): void {
let timer: number; GUI.toast(d,{timeout: 3, location: GUI.ANCHOR.NORTH});
this.mfeed.unshift(d);
$(this.fzone).show();
timer = window.setTimeout(() => {
this.mfeed.delete(d.domel);
if (this.mfeed.data.length === 0) {
$(this.fzone).hide();
}
return clearTimeout(timer);
}, 3000);
} }
/** /**
@ -230,10 +211,6 @@ namespace OS {
</afx-hbox> </afx-hbox>
<afx-list-view data-id="notifylist"></afx-list-view> <afx-list-view data-id="notifylist"></afx-list-view>
</afx-overlay> </afx-overlay>
<afx-overlay data-id = "feedzone" width = "250">
<afx-list-view data-id = "notifeed">
</afx-list-view>
</afx-overlay>
</div>\ </div>\
`; `;
} }

View File

View File

@ -1,86 +1,50 @@
afx-overlay[data-id = "notifyzone"]{ afx-overlay[data-id = "notifyzone"]{
/*opacity: 0.85;*/ /*opacity: 0.85;*/
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
padding:3px; padding:3px;
margin: 0; margin: 0;
} }
afx-overlay[data-id = "notifyzone"] afx-button button{ afx-overlay[data-id = "notifyzone"] afx-button button{
width: 100%; width: 100%;
border-radius: 0; border-radius: 0;
} }
afx-list-view[data-id = "notifylist"] afx-list-view[data-id = "notifylist"]
{ {
padding:0; padding:0;
} }
afx-list-view[data-id = "notifylist"] > div.list-container > ul li{ afx-list-view[data-id = "notifylist"] > div.list-container > ul li{
border:1px solid #464646; border:1px solid #464646;
border-radius: 3px; border-radius: 3px;
margin-bottom: 5px; margin-bottom: 5px;
-ms-word-break: break-all; -ms-word-break: break-all;
word-break: break-all; word-break: break-all;
word-break: break-word; word-break: break-word;
padding-top: 5px; padding-top: 5px;
padding-bottom: 5px; padding-bottom: 5px;
} }
afx-overlay[data-id = "feedzone"]{ afx-overlay[data-id = "feedzone"]{
overflow: hidden; overflow: hidden;
background-color:transparent; background-color:transparent;
right:5px; right:5px;
margin: 0; margin: 0;
padding:0; padding:0;
top:0; top:0;
} }
afx-list-view[data-id = "notifeed"] afx-list-view[data-id = "notifeed"]
{ {
padding:0; padding:0;
margin:0; margin:0;
} }
afx-list-view[data-id = "notifeed"] li{ afx-list-view[data-id = "notifeed"] li{
box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.65); box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.65);
border:1px solid #262626; border:1px solid #262626;
border-radius: 6px; border-radius: 6px;
margin-bottom: 2px; margin-bottom: 2px;
z-index: 99999; z-index: 99999;
-ms-word-break: break-all; -ms-word-break: break-all;
word-break: break-all; word-break: break-all;
word-break: break-word; word-break: break-word;
}
afx-app-window[data-id ='Syslog'] div[data-id ='container']{
overflow: auto;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-error {
display: block;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-error i::before {
color: chocolate;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-time{
display: block;
padding-left: 10px;
}
afx-app-window[data-id ='Syslog'] .afx-bug-list-item-time i.label-text{
font-size: 10px;
font-style: italic;
}
afx-app-window[data-id ='Syslog'] afx-bug-list-item li.selected {
background-color: #116cd6;
color: white;
}
afx-app-window[data-id ='Syslog'] pre {
padding: 10px;
margin:0;
user-select: text;
cursor: text;
}
afx-app-window[data-id ='Syslog'] input{
height: 100%;
} }

View File

@ -0,0 +1,15 @@
{
"pkgname": "SystemServices",
"services": ["PushNotification", "Calendar"],
"name": "System services",
"description": "System services",
"info": {
"author": "Xuan Sang LE",
"email": "xsang.le@gmail.com",
"licences": "GPLv3"
},
"version": "0.1.0-a",
"category": "System",
"iconclass": "fa fa-cog",
"mimes": []
}

View File

@ -0,0 +1,19 @@
afx-toast-notification div[data-id="toast_container"] div[data-id="toast_header"]::before
{
font-family: "bootstrap-icons";
content: "\F62A";
font-size: 20px;
}
afx-toast-notification div[data-id="toast_container"] div[data-id="toast_header"]:hover
{
color: orangered;
}
afx-toast-notification div[data-id="toast_container"]
{
box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.65);
border:1px solid #262626;
background-color:#3b3b3b;
border-radius: 6px;
}

View File

@ -0,0 +1,19 @@
afx-toast-notification div[data-id="toast_container"] div[data-id="toast_header"]::before
{
font-family: "bootstrap-icons";
content: "\F62A";
font-size: 20px;
}
afx-toast-notification div[data-id="toast_container"] div[data-id="toast_header"]:hover
{
color: orangered;
}
afx-toast-notification div[data-id="toast_container"]
{
box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.65);
border: 1px solid #a6a6a6;
background-color: #f6F6F6;
border-radius: 6px;
}

View File

@ -0,0 +1,117 @@
afx-notification {
display: contents;
}
afx-notification div[data-id="north"] {
position: absolute;
top: 5px;
left: 50%;
transform: translate(-50%, 0);
/*max-width: 30%;*/
max-height: 100%;
width: fit-content;
height: fit-content;
z-index: 1000000;
display: flex;
flex-direction: column;
align-items: center;
}
afx-notification div[data-id="south"] {
position: absolute;
bottom: 5px;
left: 50%;
transform: translate(-50%, 0);
/*max-width: 30%;*/
max-height: 100%;
width: fit-content;
height: fit-content;
z-index: 1000000;
display: flex;
flex-direction: column;
align-items: center;
}
afx-notification div[data-id="north_west"] {
position: absolute;
left: 5px;
top: 5px;
/*max-width: 30%;*/
max-height: 100%;
width: fit-content;
height: fit-content;
z-index: 1000000;
display: flex;
flex-direction: column;
align-items: flex-start;
}
afx-notification div[data-id="south_west"] {
position: absolute;
left: 5px;
bottom: 5px;
/*max-width: 30%;*/
max-height: 100%;
width: fit-content;
height: fit-content;
z-index: 1000000;
display: flex;
flex-direction: column;
align-items: flex-start;
}
afx-notification div[data-id="north_est"] {
position: absolute;
right: 5px;
top: 5px;
/*max-width: 30%;*/
max-height: 100%;
width: fit-content;
height: fit-content;
z-index: 1000000;
display: flex;
flex-direction: column;
align-items: flex-end;
}
afx-notification div[data-id="south_est"] {
position: absolute;
right: 5px;
bottom: 5px;
/*max-width: 30%;*/
max-height: 100%;
width: fit-content;
height: fit-content;
z-index: 1000000;
display: flex;
flex-direction: column;
align-items: flex-end;
}
afx-toast-notification {
display: contents;
}
afx-toast-notification div[data-id="toast_container"]
{
display: block;
width: fit-content;
height: fit-content;
position: relative;
max-width: 300px;
}
afx-toast-notification div[data-id="toast_container"] div[data-id="toast_header"]
{
position: absolute;
width: 20px;
height: 20px;
right: 5px;
}
afx-toast-notification div[data-id="toast_container"] div[data-id="toast_content"]
{
padding: 20px 15px;
}