Skip to content

Commit 2503f4a

Browse files
authored
fix: fix can't clear the notifications (#518)
* fix: fix can't clear the notifications * test: update tests * test: ignore render tests
1 parent 76f2be1 commit 2503f4a

File tree

8 files changed

+120
-69
lines changed

8 files changed

+120
-69
lines changed

src/controller/__tests__/notification.test.ts

+6-23
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ const notificationService = container.resolve(NotificationService);
1313
const statusBarService = container.resolve(StatusBarService);
1414
const builtinService = container.resolve(BuiltinService);
1515

16-
jest.mock('react-dom', () => {
17-
return {
18-
render: jest.fn(),
19-
};
20-
});
21-
2216
describe('The notification controller', () => {
2317
test('Should support initialize the service', () => {
2418
notificationController.initView();
@@ -94,34 +88,23 @@ describe('The notification controller', () => {
9488
expect(notificationService.getState().data).toHaveLength(0);
9589
});
9690

97-
test('Should support to toggleNotifications', () => {
98-
expect(
99-
(notificationController as any)._notificationPane
100-
).toBeUndefined();
101-
expect(notificationService.getState().showNotifications).toBeFalsy();
102-
notificationController.toggleNotifications();
103-
104-
expect(
105-
(notificationController as any)._notificationPane
106-
).not.toBeUndefined();
107-
expect(notificationService.getState().showNotifications).toBeTruthy();
108-
});
109-
11091
test('Should support to execute onClick', () => {
111-
expect(notificationService.getState().showNotifications).toBeTruthy();
92+
expect(notificationService.getState().showNotifications).toBeFalsy();
11293

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

115-
expect(notificationService.getState().showNotifications).toBeFalsy();
96+
expect(notificationService.getState().showNotifications).toBeTruthy();
11697
});
11798

11899
test('Should support to execute onActionBarClick', () => {
119-
expect(notificationService.getState().showNotifications).toBeFalsy();
100+
notificationService.add([{ id: 1, value: 'test' }]);
101+
expect(notificationService.getState().data).toHaveLength(1);
120102
notificationController.onActionBarClick({} as any, {
121103
id: constants.NOTIFICATION_CLEAR_ALL_ID,
122104
});
123-
expect(notificationService.getState().showNotifications).toBeTruthy();
105+
expect(notificationService.getState().data).toHaveLength(0);
124106

107+
expect(notificationService.getState().showNotifications).toBeTruthy();
125108
notificationController.onActionBarClick({} as any, {
126109
id: constants.NOTIFICATION_HIDE_ID,
127110
});

src/controller/notification.tsx

+11-37
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
import 'reflect-metadata';
22
import { container, singleton } from 'tsyringe';
33
import React from 'react';
4-
import ReactDOM from 'react-dom';
54
import { connect } from 'mo/react';
65
import { Float, IStatusBarItem } from 'mo/model';
76
import { Controller } from 'mo/react/controller';
87
import { IActionBarItemProps } from 'mo/components/actionBar';
98
import { INotificationItem } from 'mo/model/notification';
10-
import {
11-
NotificationPane,
12-
NotificationStatusBarView,
13-
} from 'mo/workbench/notification';
9+
import { NotificationStatusBarView } from 'mo/workbench/notification';
1410
import {
1511
IStatusBarService,
1612
StatusBarService,
1713
INotificationService,
1814
NotificationService,
19-
ILayoutService,
20-
LayoutService,
2115
IBuiltinService,
2216
BuiltinService,
2317
} from 'mo/services';
@@ -41,29 +35,20 @@ export class NotificationController
4135
implements INotificationController {
4236
private readonly notificationService: INotificationService;
4337
private readonly statusBarService: IStatusBarService;
44-
private readonly layoutService: ILayoutService;
4538
private readonly builtinService: IBuiltinService;
4639

4740
constructor() {
4841
super();
4942
this.notificationService = container.resolve(NotificationService);
5043
this.statusBarService = container.resolve(StatusBarService);
51-
this.layoutService = container.resolve(LayoutService);
5244
this.builtinService = container.resolve(BuiltinService);
5345
}
5446

5547
public onCloseNotification = (item: INotificationItem<any>): void => {
56-
if (typeof item.id === 'number' || typeof item.id === 'string') {
57-
this.notificationService.remove(item.id);
58-
}
48+
this.notificationService.remove(item.id);
5949
};
6050

61-
private _notificationPane: HTMLDivElement | undefined = undefined;
62-
6351
public toggleNotifications() {
64-
if (!this._notificationPane) {
65-
this.renderNotificationPane();
66-
}
6752
this.notificationService.toggleNotification();
6853
}
6954

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

8469
if (action === NOTIFICATION_CLEAR_ALL_ID) {
85-
this.notificationService.toggleNotification();
70+
this.notificationService.clear();
8671
} else if (action === NOTIFICATION_HIDE_ID) {
8772
this.toggleNotifications();
8873
}
@@ -100,35 +85,24 @@ export class NotificationController
10085
this.notificationService,
10186
NotificationStatusBarView
10287
);
88+
/* istanbul ignore next */
10389
const defaultNotification = {
10490
...builtInNotification,
10591
actionBar: [NOTIFICATION_CLEAR_ALL, NOTIFICATION_HIDE].filter(
10692
Boolean
10793
) as IActionBarItemProps[],
108-
render: () => <NotificationView onClick={this.onClick} />,
94+
render: () => (
95+
<NotificationView
96+
onClick={this.onClick}
97+
onActionBarClick={this.onActionBarClick}
98+
onCloseNotification={this.onCloseNotification}
99+
/>
100+
),
109101
};
110102
this.notificationService.setState({
111103
...defaultNotification,
112104
});
113105
this.statusBarService.add(defaultNotification, Float.right);
114106
}
115107
}
116-
117-
public renderNotificationPane() {
118-
const NotificationPaneView = connect(
119-
this.notificationService,
120-
NotificationPane
121-
);
122-
const root = this.layoutService.container;
123-
const container = document.createElement('div');
124-
root?.appendChild(container);
125-
ReactDOM.render(
126-
<NotificationPaneView
127-
onActionBarClick={this.onActionBarClick}
128-
onCloseNotification={this.onCloseNotification}
129-
/>,
130-
container
131-
);
132-
this._notificationPane = container;
133-
}
134108
}

src/services/__tests__/notificationService.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,12 @@ describe('The Notification Service', () => {
9494
notificationService.toggleNotification();
9595
expect(notificationService.getState().showNotifications).toBeTruthy();
9696
});
97+
98+
test('Should support to clear all notifications', () => {
99+
notificationService.add([{ id: 1, value: 'test' }]);
100+
expect(notificationService.getState().data).toHaveLength(1);
101+
102+
notificationService.clear();
103+
expect(notificationService.getState().data).toHaveLength(0);
104+
});
97105
});

src/services/notificationService.ts

+10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ export interface INotificationService extends Component<INotification> {
3232
* Toggle the Notification view between display or hidden
3333
*/
3434
toggleNotification(): void;
35+
/**
36+
* Clear the notifications
37+
*/
38+
clear(): void;
3539
/**
3640
* Reset notifications, this will clear the pending notifications
3741
*/
@@ -117,6 +121,12 @@ export class NotificationService
117121
return null;
118122
}
119123

124+
public clear() {
125+
this.setState({
126+
data: [],
127+
});
128+
}
129+
120130
public reset() {
121131
this.setState({
122132
id: '',
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,44 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`Test Notification StatusBar View Component Match The NotificationStatusBarView snapshot 1`] = `
4-
<span
5-
className="codicon codicon-bell-dot"
6-
/>
4+
Array [
5+
<span
6+
className="codicon codicon-bell-dot"
7+
/>,
8+
<div
9+
className="mo-notification mo-context-view--shadow"
10+
style={
11+
Object {
12+
"display": "none",
13+
}
14+
}
15+
>
16+
<header
17+
className="mo-notification__header"
18+
>
19+
<span>
20+
Notifications
21+
</span>
22+
<div
23+
className="mo-action-bar"
24+
>
25+
<ul
26+
className="mo-action-bar__container"
27+
/>
28+
</div>
29+
</header>
30+
<div
31+
className="mo-notification__body"
32+
>
33+
<div>
34+
35+
<span
36+
className="mo-notification--close codicon codicon-close"
37+
onClick={[Function]}
38+
title="Clear Notification"
39+
/>
40+
</div>
41+
</div>
42+
</div>,
43+
]
744
`;

src/workbench/notification/__tests__/statusBarView.test.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,23 @@ import { expectFnCalled } from '@test/utils';
1010
describe('Test Notification StatusBar View Component', () => {
1111
test('Match The NotificationStatusBarView snapshot', () => {
1212
const component = renderer.create(
13-
<NotificationStatusBarView data={[{ id: '' }]} id="test" />
13+
<NotificationStatusBarView
14+
data={[{ id: '', value: '' }]}
15+
id="test"
16+
/>
1417
);
1518
expect(component.toJSON()).toMatchSnapshot();
1619
});
1720

1821
test('Should display the bell dot icon', () => {
1922
const { rerender } = render(<NotificationStatusBarView id="test" />);
2023
expect(select('.codicon-bell-dot')).not.toBeInTheDocument();
21-
rerender(<NotificationStatusBarView id="test" data={[{ id: '' }]} />);
24+
rerender(
25+
<NotificationStatusBarView
26+
id="test"
27+
data={[{ id: '', value: '' }]}
28+
/>
29+
);
2230
expect(select('.codicon-bell-dot')).toBeInTheDocument();
2331
});
2432

Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
import React, { memo } from 'react';
22
import { Icon } from 'mo/components/icon';
3-
import { IStatusBarItem } from 'mo/model/workbench/statusBar';
3+
import type { INotification } from 'mo/model';
4+
import { NotificationPane } from '../notificationPane';
5+
import type { INotificationController } from 'mo/controller';
46

5-
export function NotificationStatusBarView(props: IStatusBarItem) {
6-
const { data = [], onClick } = props;
7+
export function NotificationStatusBarView(
8+
props: INotification & Partial<INotificationController>
9+
) {
10+
const {
11+
data = [],
12+
onClick,
13+
showNotifications,
14+
id,
15+
actionBar,
16+
onActionBarClick,
17+
onCloseNotification,
18+
} = props;
719
const hasNotifications = data.length > 0;
820
const renderIcon = hasNotifications ? 'bell-dot' : 'bell';
9-
return <Icon onClick={onClick} type={renderIcon} />;
21+
return (
22+
<>
23+
<Icon onClick={onClick} type={renderIcon} />
24+
<NotificationPane
25+
id={id}
26+
data={data}
27+
actionBar={actionBar}
28+
showNotifications={showNotifications}
29+
onActionBarClick={onActionBarClick}
30+
onCloseNotification={onCloseNotification}
31+
/>
32+
</>
33+
);
1034
}
1135
export default memo(NotificationStatusBarView);

stories/extensions/test/testPane.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ export type GenericClassDecorator<T> = (target: T) => void;`,
229229
}
230230
};
231231

232+
const toggleNotification = function () {
233+
molecule.notification.toggleNotification();
234+
};
235+
232236
const openCommand = function () {};
233237

234238
const appendMenu = function () {
@@ -345,6 +349,9 @@ PARTITIONED BY (ds string) lifecycle 1000;
345349
<Button onClick={removeNotification}>
346350
Remove A Notification
347351
</Button>
352+
<Button onClick={toggleNotification}>
353+
Toggle Notifications
354+
</Button>
348355
</div>
349356
<div style={{ margin: '50px 20px' }}>
350357
<h2>MenuBar:</h2>

0 commit comments

Comments
 (0)