Skip to content

Commit

Permalink
feat(notification): add simple Notification module
Browse files Browse the repository at this point in the history
support the basic notification display panel, add, and remove methods

re #18
  • Loading branch information
wewoor authored and mumiao committed Mar 16, 2021
1 parent 53fc63e commit a99d855
Show file tree
Hide file tree
Showing 15 changed files with 384 additions and 67 deletions.
2 changes: 2 additions & 0 deletions src/controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EditorController } from './editor';
import { ExplorerController } from './explorer/explorer';
import { FolderTreeController } from './explorer/folderTree';
import { MenuBarController } from './menuBar';
import { NotificationController } from './notification';
import { PanelController } from './panel';
import { SettingsController } from './settings';
import { SidebarController } from './sidebar';
Expand All @@ -20,3 +21,4 @@ export const statusBarController = container.resolve(StatusBarController);
export const settingsController = container.resolve(SettingsController);
export const folderTreeController = container.resolve(FolderTreeController);
export const workbenchController = container.resolve(WorkbenchController);
export const notificationController = container.resolve(NotificationController);
30 changes: 0 additions & 30 deletions src/controller/notification.ts

This file was deleted.

95 changes: 95 additions & 0 deletions src/controller/notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { connect, IStatusBarItem } from 'mo';
import { Controller } from 'mo/react/controller';
import { notificationService, statusBarService } from 'mo/services';
import { singleton } from 'tsyringe';
import { Notification } from 'mo/workbench/statusBar/notification';
import { NotificationPanel } from 'mo/workbench/statusBar/notification/notificationPanel';

import { IActionBarItem } from 'mo/components/actionBar';
import {
INotificationItem,
NOTIFICATION_CLEAR_ALL,
NOTIFICATION_HIDE,
} from 'mo/model/notification';
import { select } from 'mo/common/dom';
import { ID_APP } from 'mo/common/id';

export interface INotificationController {
onCloseNotification(item: INotificationItem): void;
onClick?: (e: React.MouseEvent, item: IStatusBarItem) => void;
onActionBarClick?(
event: React.MouseEvent<Element, MouseEvent>,
item: IActionBarItem<any>
): void;
}

@singleton()
export class NotificationController
extends Controller
implements INotificationController {
constructor() {
super();
this.init();
}

public onCloseNotification(item: INotificationItem<any>): void {
if (typeof item.id === 'number') {
notificationService.removeNotification(item.id);
}
}

private _notificationPanel: HTMLDivElement | undefined = undefined;

private showHideNotifications() {
if (!this._notificationPanel) {
this.renderNotificationPanel();
}
notificationService.showHideNotifications();
}

public onClick = (e: React.MouseEvent, item: IStatusBarItem) => {
this.showHideNotifications();
};

public onActionBarClick = (
event: React.MouseEvent<Element, MouseEvent>,
item: IActionBarItem<any>
) => {
const action = item.id;
if (action === NOTIFICATION_CLEAR_ALL.id) {
notificationService.showHideNotifications();
} else if (action === NOTIFICATION_HIDE.id) {
this.showHideNotifications();
}
};

private init() {
const notificationItem = notificationService.getState();
const NotificationView = connect(notificationService, Notification);
notificationService.setState({
...notificationItem,
render: () => <NotificationView onClick={this.onClick} />,
});
statusBarService.appendRightItem(notificationItem);
}

public renderNotificationPanel() {
const NotificationPanelView = connect(
notificationService,
NotificationPanel
);
const root = select('#' + ID_APP);
const container = document.createElement('div');
root?.appendChild(container);
ReactDOM.render(
<NotificationPanelView
onActionBarClick={this.onActionBarClick}
onCloseNotification={this.onCloseNotification}
/>,
container
);
this._notificationPanel = container;
}
}
14 changes: 0 additions & 14 deletions src/controller/statusBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { IStatusBarItem, StatusBarEvent } from 'mo';
import { Controller } from 'mo/react/controller';
import { statusBarService } from 'mo/services';
import { singleton } from 'tsyringe';
import { Icon } from 'mo/components/icon';

export interface IStatusBarController {
onClick?: (e: React.MouseEvent, item: IStatusBarItem) => void;
}
Expand All @@ -15,13 +13,6 @@ const problems: IStatusBarItem = {
name: 'Problems',
};

const notifications: IStatusBarItem = {
id: 'MoNotification',
sortIndex: 1,
name: 'Notification',
render: () => <Icon type="bell" />,
};

export const editorLineColumnItem: IStatusBarItem = {
id: 'EditorCountInfo',
sortIndex: 2,
Expand All @@ -42,13 +33,8 @@ export class StatusBarController
this.emit(StatusBarEvent.onClick, e, item);
};

public notify() {
console.log('service:', statusBarService);
}

private initStatusBar() {
statusBarService.appendLeftItem(problems);
statusBarService.appendRightItem(notifications);
statusBarService.appendRightItem(editorLineColumnItem);
}
}
1 change: 0 additions & 1 deletion src/model/notification.ts

This file was deleted.

48 changes: 38 additions & 10 deletions src/model/notification.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,69 @@
import { IActionBarItem } from 'mo/components/actionBar';
import { Icon } from 'mo/components/icon';
import * as React from 'react';
import { injectable } from 'tsyringe';
import { IStatusBarItem } from './workbench/statusBar';

export type NotificationStatusType = 'message' | 'normal';
export enum NotificationStatus {
Read = 1,
WaitRead = 2,
}

export interface INotificationItem<T = any> {
id?: number;
value: T;
status?: NotificationStatus;
}

export interface INotification<T = any> extends IStatusBarItem {
data: T[];
status: NotificationStatusType;
data?: INotificationItem<T>[];
showNotifications?: boolean;
actionBar?: IActionBarItem[];
}

export const NOTIFICATION_CLEAR_ALL: IActionBarItem = {
id: 'ClearAll',
title: 'Clear All Notifications',
iconName: 'codicon-clear-all',
};

export const NOTIFICATION_HIDE: IActionBarItem = {
id: 'HideNotifications',
title: 'Hide Notifications',
iconName: 'codicon-chevron-down',
};

@injectable()
export class NotificationModel<T> implements INotification<T> {

static readonly ID = 'MO_NOTIFICATION';
static readonly NAME = 'Notification';

public id: string;
public name: string;
public data: T[];
public data: INotificationItem<T>[];
public sortIndex: number;
public render: () => ReactNode;
public status: NotificationStatusType;
public showNotifications: boolean;
public actionBar: IActionBarItem[];

constructor(
id: string = NotificationModel.ID,
name: string = NotificationModel.NAME,
data: T[] = [],
data: INotificationItem<T>[] = [],
sortIndex: number = 1,
render: () => ReactNode = () => <Icon type="bell" />,
status: NotificationStatusType = 'normal'
showNotifications: boolean = false,
actionBar: IActionBarItem[] = [
NOTIFICATION_CLEAR_ALL,
NOTIFICATION_HIDE,
],
render: () => ReactNode = () => <Icon type="bell" />
) {
this.id = id;
this.name = name;
this.sortIndex = sortIndex;
this.render = render;
this.status = status;
this.showNotifications = showNotifications;
this.data = data;
this.actionBar = actionBar;
}
}
8 changes: 8 additions & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import {
PanelService,
} from './workbench';
import { ISettingsService, SettingsService } from './settingsService';
import {
INotificationService,
NotificationService,
} from './notificationService';

/**
* The Services of Workbench
Expand All @@ -42,6 +46,9 @@ const menuBarService = container.resolve<IMenuBarService>(MenuBarService);
const editorService = container.resolve<IEditorService>(EditorService);
const statusBarService = container.resolve<IStatusBarService>(StatusBarService);
const panelService = container.resolve<IPanelService>(PanelService);
const notificationService = container.resolve<INotificationService>(
NotificationService
);

/**
* The ColorTheme service,
Expand Down Expand Up @@ -72,4 +79,5 @@ export {
extensionService,
colorThemeService,
settingsService,
notificationService,
};
88 changes: 87 additions & 1 deletion src/services/notificationService.ts
Original file line number Diff line number Diff line change
@@ -1 +1,87 @@
// TODO notificationService
import {
INotification,
INotificationItem,
NotificationModel,
NotificationStatus,
} from 'mo/model/notification';
import { Component } from 'mo/react';
import { singleton, container } from 'tsyringe';
import { searchById } from './helper';

export interface INotificationService extends Component<INotification> {
addNotification<T>(item: INotificationItem<T>): null | INotificationItem<T>;
removeNotification(id: number): void;
updateNotification<T>(
item: INotificationItem<T>
): null | INotificationItem<T>;
showHideNotifications(): void;
}

@singleton()
export class NotificationService
extends Component<INotification>
implements INotificationService {
protected state: INotification;

constructor() {
super();
this.state = container.resolve(NotificationModel);
}

public showHideNotifications(): void {
this.setState({
...this.state,
showNotifications: !this.state.showNotifications,
});
}

public updateNotification<T>(
item: INotificationItem<T>
): INotificationItem<T> | null {
const { data = [] } = this.state;
if (data.length > -1) {
const index = data.findIndex(searchById(item.id));
if (index > -1) {
const original = data[index];
data[index] = Object.assign(original, item);
this.setState({
...this.state,
data: [...data],
});
return data[index];
}
}
return null;
}

public removeNotification(id: number): void {
const { data = [] } = this.state;
if (data.length > -1) {
const index = data.findIndex(searchById(id));
if (index > -1) {
data.splice(index, 1);
this.setState({
...this.state,
data: [...data],
});
}
}
}

public addNotification<T>(
item: INotificationItem<T>
): null | INotificationItem<T> {
const { data = [] } = this.state;
if (item) {
if (item.id === undefined) item.id = data.length;
item.status = NotificationStatus.WaitRead;
const arr = [...data, item];
this.setState({
...this.state,
data: arr,
});
return item;
}
return null;
}
}
1 change: 1 addition & 0 deletions src/style/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ $sidebar: prefix('sidebar');
$statusBar: prefix('statusBar');
$workbench: prefix('workbench');
$mainBench: prefix('mainBench');
$notification: prefix('notification');

// The Naming of BEM Element
@function bem-ele($block, $element) {
Expand Down
1 change: 1 addition & 0 deletions src/style/mo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
@import 'mo/workbench/settings/style';
@import 'mo/workbench/sidebar/style';
@import 'mo/workbench/statusBar/style';
@import 'mo/workbench/statusBar/notification/style';
@import 'mo/workbench/sidebar/explore/style';

.#{$prefix} {
Expand Down
Loading

0 comments on commit a99d855

Please sign in to comment.