Skip to content

Commit

Permalink
fix: fix can't clear the notifications (#518)
Browse files Browse the repository at this point in the history
* fix: fix can't clear the notifications

* test: update tests

* test: ignore render tests
  • Loading branch information
mortalYoung authored Nov 23, 2021
1 parent 76f2be1 commit 2503f4a
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 69 deletions.
29 changes: 6 additions & 23 deletions src/controller/__tests__/notification.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ const notificationService = container.resolve(NotificationService);
const statusBarService = container.resolve(StatusBarService);
const builtinService = container.resolve(BuiltinService);

jest.mock('react-dom', () => {
return {
render: jest.fn(),
};
});

describe('The notification controller', () => {
test('Should support initialize the service', () => {
notificationController.initView();
Expand Down Expand Up @@ -94,34 +88,23 @@ describe('The notification controller', () => {
expect(notificationService.getState().data).toHaveLength(0);
});

test('Should support to toggleNotifications', () => {
expect(
(notificationController as any)._notificationPane
).toBeUndefined();
expect(notificationService.getState().showNotifications).toBeFalsy();
notificationController.toggleNotifications();

expect(
(notificationController as any)._notificationPane
).not.toBeUndefined();
expect(notificationService.getState().showNotifications).toBeTruthy();
});

test('Should support to execute onClick', () => {
expect(notificationService.getState().showNotifications).toBeTruthy();
expect(notificationService.getState().showNotifications).toBeFalsy();

notificationController.onClick({} as any, { id: 'test' });

expect(notificationService.getState().showNotifications).toBeFalsy();
expect(notificationService.getState().showNotifications).toBeTruthy();
});

test('Should support to execute onActionBarClick', () => {
expect(notificationService.getState().showNotifications).toBeFalsy();
notificationService.add([{ id: 1, value: 'test' }]);
expect(notificationService.getState().data).toHaveLength(1);
notificationController.onActionBarClick({} as any, {
id: constants.NOTIFICATION_CLEAR_ALL_ID,
});
expect(notificationService.getState().showNotifications).toBeTruthy();
expect(notificationService.getState().data).toHaveLength(0);

expect(notificationService.getState().showNotifications).toBeTruthy();
notificationController.onActionBarClick({} as any, {
id: constants.NOTIFICATION_HIDE_ID,
});
Expand Down
48 changes: 11 additions & 37 deletions src/controller/notification.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import 'reflect-metadata';
import { container, singleton } from 'tsyringe';
import React from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'mo/react';
import { Float, IStatusBarItem } from 'mo/model';
import { Controller } from 'mo/react/controller';
import { IActionBarItemProps } from 'mo/components/actionBar';
import { INotificationItem } from 'mo/model/notification';
import {
NotificationPane,
NotificationStatusBarView,
} from 'mo/workbench/notification';
import { NotificationStatusBarView } from 'mo/workbench/notification';
import {
IStatusBarService,
StatusBarService,
INotificationService,
NotificationService,
ILayoutService,
LayoutService,
IBuiltinService,
BuiltinService,
} from 'mo/services';
Expand All @@ -41,29 +35,20 @@ export class NotificationController
implements INotificationController {
private readonly notificationService: INotificationService;
private readonly statusBarService: IStatusBarService;
private readonly layoutService: ILayoutService;
private readonly builtinService: IBuiltinService;

constructor() {
super();
this.notificationService = container.resolve(NotificationService);
this.statusBarService = container.resolve(StatusBarService);
this.layoutService = container.resolve(LayoutService);
this.builtinService = container.resolve(BuiltinService);
}

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

private _notificationPane: HTMLDivElement | undefined = undefined;

public toggleNotifications() {
if (!this._notificationPane) {
this.renderNotificationPane();
}
this.notificationService.toggleNotification();
}

Expand All @@ -82,7 +67,7 @@ export class NotificationController
} = this.builtinService.getConstants();

if (action === NOTIFICATION_CLEAR_ALL_ID) {
this.notificationService.toggleNotification();
this.notificationService.clear();
} else if (action === NOTIFICATION_HIDE_ID) {
this.toggleNotifications();
}
Expand All @@ -100,35 +85,24 @@ export class NotificationController
this.notificationService,
NotificationStatusBarView
);
/* istanbul ignore next */
const defaultNotification = {
...builtInNotification,
actionBar: [NOTIFICATION_CLEAR_ALL, NOTIFICATION_HIDE].filter(
Boolean
) as IActionBarItemProps[],
render: () => <NotificationView onClick={this.onClick} />,
render: () => (
<NotificationView
onClick={this.onClick}
onActionBarClick={this.onActionBarClick}
onCloseNotification={this.onCloseNotification}
/>
),
};
this.notificationService.setState({
...defaultNotification,
});
this.statusBarService.add(defaultNotification, Float.right);
}
}

public renderNotificationPane() {
const NotificationPaneView = connect(
this.notificationService,
NotificationPane
);
const root = this.layoutService.container;
const container = document.createElement('div');
root?.appendChild(container);
ReactDOM.render(
<NotificationPaneView
onActionBarClick={this.onActionBarClick}
onCloseNotification={this.onCloseNotification}
/>,
container
);
this._notificationPane = container;
}
}
8 changes: 8 additions & 0 deletions src/services/__tests__/notificationService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,12 @@ describe('The Notification Service', () => {
notificationService.toggleNotification();
expect(notificationService.getState().showNotifications).toBeTruthy();
});

test('Should support to clear all notifications', () => {
notificationService.add([{ id: 1, value: 'test' }]);
expect(notificationService.getState().data).toHaveLength(1);

notificationService.clear();
expect(notificationService.getState().data).toHaveLength(0);
});
});
10 changes: 10 additions & 0 deletions src/services/notificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export interface INotificationService extends Component<INotification> {
* Toggle the Notification view between display or hidden
*/
toggleNotification(): void;
/**
* Clear the notifications
*/
clear(): void;
/**
* Reset notifications, this will clear the pending notifications
*/
Expand Down Expand Up @@ -117,6 +121,12 @@ export class NotificationService
return null;
}

public clear() {
this.setState({
data: [],
});
}

public reset() {
this.setState({
id: '',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Test Notification StatusBar View Component Match The NotificationStatusBarView snapshot 1`] = `
<span
className="codicon codicon-bell-dot"
/>
Array [
<span
className="codicon codicon-bell-dot"
/>,
<div
className="mo-notification mo-context-view--shadow"
style={
Object {
"display": "none",
}
}
>
<header
className="mo-notification__header"
>
<span>
Notifications
</span>
<div
className="mo-action-bar"
>
<ul
className="mo-action-bar__container"
/>
</div>
</header>
<div
className="mo-notification__body"
>
<div>
<span
className="mo-notification--close codicon codicon-close"
onClick={[Function]}
title="Clear Notification"
/>
</div>
</div>
</div>,
]
`;
12 changes: 10 additions & 2 deletions src/workbench/notification/__tests__/statusBarView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ import { expectFnCalled } from '@test/utils';
describe('Test Notification StatusBar View Component', () => {
test('Match The NotificationStatusBarView snapshot', () => {
const component = renderer.create(
<NotificationStatusBarView data={[{ id: '' }]} id="test" />
<NotificationStatusBarView
data={[{ id: '', value: '' }]}
id="test"
/>
);
expect(component.toJSON()).toMatchSnapshot();
});

test('Should display the bell dot icon', () => {
const { rerender } = render(<NotificationStatusBarView id="test" />);
expect(select('.codicon-bell-dot')).not.toBeInTheDocument();
rerender(<NotificationStatusBarView id="test" data={[{ id: '' }]} />);
rerender(
<NotificationStatusBarView
id="test"
data={[{ id: '', value: '' }]}
/>
);
expect(select('.codicon-bell-dot')).toBeInTheDocument();
});

Expand Down
32 changes: 28 additions & 4 deletions src/workbench/notification/statusBarView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
import React, { memo } from 'react';
import { Icon } from 'mo/components/icon';
import { IStatusBarItem } from 'mo/model/workbench/statusBar';
import type { INotification } from 'mo/model';
import { NotificationPane } from '../notificationPane';
import type { INotificationController } from 'mo/controller';

export function NotificationStatusBarView(props: IStatusBarItem) {
const { data = [], onClick } = props;
export function NotificationStatusBarView(
props: INotification & Partial<INotificationController>
) {
const {
data = [],
onClick,
showNotifications,
id,
actionBar,
onActionBarClick,
onCloseNotification,
} = props;
const hasNotifications = data.length > 0;
const renderIcon = hasNotifications ? 'bell-dot' : 'bell';
return <Icon onClick={onClick} type={renderIcon} />;
return (
<>
<Icon onClick={onClick} type={renderIcon} />
<NotificationPane
id={id}
data={data}
actionBar={actionBar}
showNotifications={showNotifications}
onActionBarClick={onActionBarClick}
onCloseNotification={onCloseNotification}
/>
</>
);
}
export default memo(NotificationStatusBarView);
7 changes: 7 additions & 0 deletions stories/extensions/test/testPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ export type GenericClassDecorator<T> = (target: T) => void;`,
}
};

const toggleNotification = function () {
molecule.notification.toggleNotification();
};

const openCommand = function () {};

const appendMenu = function () {
Expand Down Expand Up @@ -345,6 +349,9 @@ PARTITIONED BY (ds string) lifecycle 1000;
<Button onClick={removeNotification}>
Remove A Notification
</Button>
<Button onClick={toggleNotification}>
Toggle Notifications
</Button>
</div>
<div style={{ margin: '50px 20px' }}>
<h2>MenuBar:</h2>
Expand Down

0 comments on commit 2503f4a

Please sign in to comment.