Skip to content

Commit d96e2b3

Browse files
authored
feat: add built-in service (#471)
* feat: add built-in service * feat: add built-in service for explorer * feat: add built-in modules for editor * feat: activitybar support to sortIndex * feat: add built-in service for editorTree * ci: fix ci problems * test: improve unit test * feat: add built-in service for setting * feat: add built-in service for problems * feat: add built-in for notification * feat: add built-in service for statusBar * test: update the snapshot and improve testings about default value * feat: add built-in service for search * feat: add built-in service in panel * feat: add built-in for keybinding * feat: add built-in for menu * feat: add built-in for folderTree * test: update snapshot * test: add unit tests for built-in service * feat: add the initView method for base Controller * feat: support to autoInject the controllers in Provider * test: update snapshot * test: add unit tests for controllers * feat: add the annotations for built-in service * test: add unit tests for controllers * test: add unit tests for controllers * feat: add built-in for activityBar
1 parent 35e66fd commit d96e2b3

File tree

90 files changed

+3585
-1778
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+3585
-1778
lines changed

src/components/actionBar/index.tsx

+12-9
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,18 @@ export function ActionBar<T = any>(props: IActionBarProps<T>) {
130130

131131
const claNames = classNames(defaultActionBarClassName, className);
132132

133-
const items = data.map((item: IActionBarItemProps<T>, index) => (
134-
<ActionBarItem
135-
key={item.id}
136-
{...item}
137-
onContextMenuClick={onContextMenuClick}
138-
data-index={index}
139-
onClick={mergeFunctions(onClick, item.onClick)}
140-
/>
141-
));
133+
const items = data.map(
134+
(item: IActionBarItemProps<T>, index) =>
135+
item.id && (
136+
<ActionBarItem
137+
key={item.id}
138+
{...item}
139+
onContextMenuClick={onContextMenuClick}
140+
data-index={index}
141+
onClick={mergeFunctions(onClick, item.onClick)}
142+
/>
143+
)
144+
);
142145

143146
return (
144147
<div className={claNames} {...custom}>
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import {
2+
ExplorerService,
3+
BuiltinService,
4+
EditorTreeService,
5+
} from 'mo/services';
6+
import { constants, modules } from 'mo/services/builtinService/const';
7+
import 'reflect-metadata';
8+
import { container } from 'tsyringe';
9+
import { EditorTreeController } from '../explorer/editorTree';
10+
11+
const editorTreeController = container.resolve(EditorTreeController);
12+
const editorTreeService = container.resolve(EditorTreeService);
13+
const explorerService = container.resolve(ExplorerService);
14+
const builtinService = container.resolve(BuiltinService);
15+
16+
describe('The editor tree controller', () => {
17+
test('Should inject the default value into service', () => {
18+
editorTreeController.initView();
19+
20+
const { data } = explorerService.getState();
21+
expect(data).toHaveLength(1);
22+
const {
23+
groupToolbar,
24+
...restEditor
25+
} = modules.builtInExplorerEditorPanel;
26+
expect(data[0]).toEqual(expect.objectContaining(restEditor));
27+
28+
explorerService.reset();
29+
});
30+
31+
test('Should support to controll the default value', () => {
32+
builtinService.inactiveModule('builtInExplorerEditorPanel');
33+
editorTreeController.initView();
34+
const { data } = explorerService.getState();
35+
expect(data).toHaveLength(0);
36+
37+
builtinService.reset();
38+
});
39+
40+
test('Should execute the onContextMenu method', () => {
41+
const mockItem = { id: constants.EDITOR_MENU_CLOSE };
42+
const mockGroupId = 1;
43+
const mockFile = { id: 'file' };
44+
const mockFn = jest.fn();
45+
editorTreeService.onClose(mockFn);
46+
editorTreeController.onContextMenu(mockItem, mockGroupId, mockFile);
47+
48+
expect(mockFn).toBeCalled();
49+
expect(mockFn.mock.calls[0][0]).toBe(mockFile.id);
50+
expect(mockFn.mock.calls[0][1]).toBe(mockGroupId);
51+
mockFn.mockClear();
52+
53+
// close others
54+
editorTreeService.onCloseOthers(mockFn);
55+
mockItem.id = constants.EDITOR_MENU_CLOSE_OTHERS;
56+
editorTreeController.onContextMenu(mockItem, mockGroupId, mockFile);
57+
58+
expect(mockFn).toBeCalled();
59+
expect(mockFn.mock.calls[0][0]).toEqual(mockFile);
60+
expect(mockFn.mock.calls[0][1]).toBe(mockGroupId);
61+
mockFn.mockClear();
62+
63+
// close saved
64+
editorTreeService.onCloseSaved(mockFn);
65+
mockItem.id = constants.EDITOR_MENU_CLOSE_SAVED;
66+
editorTreeController.onContextMenu(mockItem, mockGroupId, mockFile);
67+
68+
expect(mockFn).toBeCalled();
69+
expect(mockFn.mock.calls[0][0]).toEqual(mockGroupId);
70+
mockFn.mockClear();
71+
72+
// close all
73+
editorTreeService.onCloseAll(mockFn);
74+
mockItem.id = constants.EDITOR_MENU_CLOSE_ALL;
75+
editorTreeController.onContextMenu(mockItem, mockGroupId, mockFile);
76+
77+
expect(mockFn).toBeCalled();
78+
expect(mockFn.mock.calls[0][0]).toEqual(mockGroupId);
79+
mockFn.mockClear();
80+
81+
// default
82+
editorTreeService.onContextMenu(mockFn);
83+
mockItem.id = 'custom-id';
84+
editorTreeController.onContextMenu(mockItem, mockGroupId, mockFile);
85+
86+
expect(mockFn).toBeCalled();
87+
expect(mockFn.mock.calls[0][0]).toEqual(mockItem);
88+
expect(mockFn.mock.calls[0][1]).toEqual(mockFile);
89+
expect(mockFn.mock.calls[0][2]).toEqual(mockGroupId);
90+
});
91+
92+
test('Should support to emit events', () => {
93+
const mockTabId = '1';
94+
const mockGroupId = 1;
95+
const mockFn = jest.fn();
96+
editorTreeService.onClose(mockFn);
97+
editorTreeController.onClose(mockTabId, mockGroupId);
98+
99+
expect(mockFn).toBeCalled();
100+
mockFn.mockClear();
101+
102+
// onSelect
103+
editorTreeService.onSelect(mockFn);
104+
editorTreeController.onSelect(mockTabId, mockGroupId);
105+
expect(mockFn).toBeCalled();
106+
expect(mockFn.mock.calls[0][0]).toBe(mockTabId);
107+
expect(mockFn.mock.calls[0][1]).toBe(mockGroupId);
108+
mockFn.mockClear();
109+
110+
// onCloseGroup
111+
editorTreeService.onCloseAll(mockFn);
112+
editorTreeController.onCloseGroup(mockGroupId);
113+
expect(mockFn).toBeCalled();
114+
mockFn.mockClear();
115+
116+
// onSaveGroup
117+
editorTreeService.onSaveAll(mockFn);
118+
editorTreeController.onSaveGroup(mockGroupId);
119+
expect(mockFn).toBeCalled();
120+
expect(mockFn.mock.calls[0][0]).toBe(mockGroupId);
121+
mockFn.mockClear();
122+
123+
// onToolbarClick
124+
const mockToolbar = { id: 'test' };
125+
editorTreeService.onToolbarClick(mockFn);
126+
editorTreeController.onToolbarClick(mockToolbar, mockGroupId);
127+
expect(mockFn).toBeCalled();
128+
expect(mockFn.mock.calls[0][0]).toBe(mockToolbar);
129+
expect(mockFn.mock.calls[0][1]).toBe(mockGroupId);
130+
mockFn.mockClear();
131+
});
132+
});
+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import { EditorTreeEvent, ExplorerEvent, FileTypes } from 'mo/model';
2+
import {
3+
ActivityBarService,
4+
SidebarService,
5+
ExplorerService,
6+
BuiltinService,
7+
} from 'mo/services';
8+
import { constants, modules } from 'mo/services/builtinService/const';
9+
import 'reflect-metadata';
10+
import { container } from 'tsyringe';
11+
import { ExplorerController, FolderTreeController } from '..';
12+
13+
const explorerController = container.resolve(ExplorerController);
14+
15+
const activityBarService = container.resolve(ActivityBarService);
16+
const sidebarService = container.resolve(SidebarService);
17+
const explorerService = container.resolve(ExplorerService);
18+
const folderTreeController = container.resolve(FolderTreeController);
19+
const builtinService = container.resolve(BuiltinService);
20+
21+
describe('The explorer controller', () => {
22+
test('Should support to inject the default value into service', () => {
23+
explorerController.initView();
24+
25+
const { headerToolBar, data } = explorerService.getState();
26+
expect(headerToolBar.id).toBe(modules.builtInExplorerHeaderToolbar.id);
27+
expect(headerToolBar.icon).toBe(
28+
modules.builtInExplorerHeaderToolbar.icon
29+
);
30+
expect(headerToolBar.title).toBe(
31+
modules.builtInExplorerHeaderToolbar.title
32+
);
33+
expect(headerToolBar.contextMenu).toHaveLength(1);
34+
35+
expect(data).toHaveLength(1);
36+
expect(data[0]).toEqual(
37+
expect.objectContaining(modules.builtInExplorerFolderPanel)
38+
);
39+
40+
const {
41+
data: activityBarData,
42+
selected,
43+
} = activityBarService.getState();
44+
expect(activityBarData).toHaveLength(1);
45+
expect(activityBarData![0]).toEqual(
46+
expect.objectContaining(modules.builtInExplorerActivityItem)
47+
);
48+
expect(selected).toBe(modules.builtInExplorerActivityItem.id);
49+
50+
const { current, panes } = sidebarService.getState();
51+
expect(panes).toHaveLength(1);
52+
expect(panes[0]).toEqual(
53+
expect.objectContaining({
54+
id: constants.EXPLORER_ACTIVITY_ITEM,
55+
title: 'EXPLORER',
56+
})
57+
);
58+
expect(current).toBe(constants.EXPLORER_ACTIVITY_ITEM);
59+
60+
explorerService.reset();
61+
activityBarService.reset();
62+
sidebarService.reset();
63+
});
64+
65+
test('Should support to controll the default value by built-in service', () => {
66+
builtinService.inactiveModule('builtInExplorerActivityItem');
67+
builtinService.inactiveModule('builtInExplorerFolderPanel');
68+
builtinService.inactiveModule('builtInExplorerHeaderToolbar');
69+
70+
explorerController.initView();
71+
const { data, headerToolBar } = explorerService.getState();
72+
expect(headerToolBar).toEqual({});
73+
expect(data).toHaveLength(0);
74+
75+
const {
76+
data: activityBarData,
77+
selected,
78+
} = activityBarService.getState();
79+
expect(activityBarData).toHaveLength(0);
80+
expect(selected).toBe('');
81+
82+
const { current, panes } = sidebarService.getState();
83+
expect(panes).toHaveLength(0);
84+
expect(current).toBe('');
85+
86+
builtinService.reset();
87+
});
88+
89+
test('Should support to emit the onClick method', () => {
90+
explorerController.initView();
91+
92+
const mockFn = jest.fn();
93+
explorerService.onClick(mockFn);
94+
95+
const mockEvent = {} as any;
96+
const mockItem = { id: 'test' };
97+
explorerController.onClick(mockEvent, mockItem);
98+
99+
expect(mockFn).toBeCalled();
100+
expect(mockFn.mock.calls[0][0]).toBe(mockEvent);
101+
expect(mockFn.mock.calls[0][1]).toBe(mockItem);
102+
});
103+
104+
test('Should execute onActionsContextMenuClick', () => {
105+
const original = explorerService.togglePanel;
106+
const mockFn = jest.fn();
107+
explorerService.togglePanel = mockFn;
108+
109+
const mockItem = { id: 'test' };
110+
explorerController.onActionsContextMenuClick({} as any, mockItem);
111+
expect(mockFn).toBeCalled();
112+
expect(mockFn.mock.calls[0][0]).toBe(mockItem.id);
113+
114+
explorerService.togglePanel = original;
115+
});
116+
117+
test('Should support to emit the onCollapseChange method', () => {
118+
const mockFn = jest.fn();
119+
explorerController.subscribe(ExplorerEvent.onCollapseChange, mockFn);
120+
121+
const mockKeys = [1, 2, 3];
122+
explorerController.onCollapseChange(mockKeys);
123+
124+
expect(mockFn).toBeCalled();
125+
expect(mockFn.mock.calls[0][0]).toBe(mockKeys);
126+
});
127+
128+
test('Should support to execute the onToolbarClick method', () => {
129+
const original = folderTreeController.createTreeNode;
130+
const mockFn = jest.fn();
131+
folderTreeController.createTreeNode = mockFn;
132+
133+
const mockItem = { id: constants.NEW_FILE_COMMAND_ID };
134+
const mockParentPanel = { id: 'test', name: 'test' };
135+
explorerController.onToolbarClick(mockItem, mockParentPanel);
136+
137+
expect(mockFn).toBeCalled();
138+
expect(mockFn.mock.calls[0][0]).toBe(FileTypes.File);
139+
140+
mockFn.mockClear();
141+
142+
mockItem.id = constants.NEW_FOLDER_COMMAND_ID;
143+
explorerController.onToolbarClick(mockItem, mockParentPanel);
144+
145+
expect(mockFn).toBeCalled();
146+
expect(mockFn.mock.calls[0][0]).toBe(FileTypes.Folder);
147+
148+
folderTreeController.createTreeNode = original;
149+
});
150+
151+
test('Should support to execute the onToolbarClick method', () => {
152+
// REMOVE_COMMAND_ID
153+
const mockItem = { id: constants.REMOVE_COMMAND_ID };
154+
const mockParentPanel = { id: 'test', name: 'test' };
155+
156+
const mockFn = jest.fn();
157+
explorerService.onRemovePanel(mockFn);
158+
159+
explorerController.onToolbarClick(mockItem, mockParentPanel);
160+
161+
expect(mockFn).toBeCalled();
162+
expect(mockFn.mock.calls[0][0]).toBe(mockParentPanel);
163+
164+
// EXPLORER_TOGGLE_CLOSE_ALL_EDITORS
165+
mockItem.id = constants.EXPLORER_TOGGLE_CLOSE_ALL_EDITORS;
166+
mockFn.mockClear();
167+
expect(mockFn).not.toBeCalled();
168+
explorerController.subscribe(EditorTreeEvent.onCloseAll, mockFn);
169+
170+
explorerController.onToolbarClick(mockItem, mockParentPanel);
171+
172+
expect(mockFn).toBeCalled();
173+
174+
// EXPLORER_TOGGLE_SAVE_ALL
175+
mockItem.id = constants.EXPLORER_TOGGLE_SAVE_ALL;
176+
mockFn.mockClear();
177+
expect(mockFn).not.toBeCalled();
178+
explorerController.subscribe(EditorTreeEvent.onSaveAll, mockFn);
179+
180+
explorerController.onToolbarClick(mockItem, mockParentPanel);
181+
182+
expect(mockFn).toBeCalled();
183+
184+
// EXPLORER_TOGGLE_VERTICAL
185+
mockItem.id = constants.EXPLORER_TOGGLE_VERTICAL;
186+
mockFn.mockClear();
187+
expect(mockFn).not.toBeCalled();
188+
explorerController.subscribe(
189+
EditorTreeEvent.onSplitEditorLayout,
190+
mockFn
191+
);
192+
193+
explorerController.onToolbarClick(mockItem, mockParentPanel);
194+
195+
expect(mockFn).toBeCalled();
196+
197+
// default
198+
mockItem.id = 'custom-id';
199+
mockFn.mockClear();
200+
expect(mockFn).not.toBeCalled();
201+
explorerService.onPanelToolbarClick(mockFn);
202+
203+
explorerController.onToolbarClick(mockItem, mockParentPanel);
204+
205+
expect(mockFn).toBeCalled();
206+
expect(mockFn.mock.calls[0][0]).toBe(mockParentPanel);
207+
expect(mockFn.mock.calls[0][1]).toBe(mockItem.id);
208+
});
209+
});

0 commit comments

Comments
 (0)