feat: add demo for plugin manager toolbar

This commit is contained in:
chenos 2022-01-19 22:21:20 +08:00
parent d1f9d3e25d
commit b49440da00
9 changed files with 320 additions and 78 deletions

View File

@ -1,53 +1,71 @@
import React, { createContext } from 'react'; import React, { createContext, useContext } from 'react';
import { Menu, Space } from 'antd'; import { Menu, Space, Tooltip } from 'antd';
import { SettingOutlined, MoreOutlined, DesktopOutlined } from '@ant-design/icons'; import { SettingOutlined, MoreOutlined, DesktopOutlined } from '@ant-design/icons';
import { CurrentUser, DesignableSwitch, CollectionManagerAction, ACLAction, SystemSettings } from '../'; import { CurrentUser, DesignableSwitch, CollectionManagerAction, ACLAction, SystemSettings } from '../';
import { get } from 'lodash'; import { get } from 'lodash';
import { PluginManagerProvider } from '.'; import { PluginManagerContext, PluginManagerProvider } from '.';
export const PluginManager = () => null; // TODO
export const PluginManager: any = () => null;
PluginManager.Provider = PluginManagerProvider; PluginManager.Provider = PluginManagerProvider;
const ToolbarItemContext = createContext(null);
PluginManager.Toolbar = (props: any) => { PluginManager.Toolbar = (props: any) => {
const components = { CurrentUser, DesignableSwitch, CollectionManagerAction, ACLAction, SystemSettings }; const { components } = useContext(PluginManagerContext);
const items = [ const { items = [] } = props;
{
action: 'DesignableSwitch',
pin: true,
},
{
action: 'CollectionManagerAction',
pin: true,
},
{
action: 'ACLAction',
pin: true,
},
{
action: 'SystemSettings.Action',
},
];
const CurrentUserDropdown = get(components, 'CurrentUser.Dropdown');
return ( return (
<Menu selectable={false} mode={'horizontal'} theme={'dark'}> <div style={{ display: 'inline-block' }}>
{items <Menu style={{ width: '100%' }} selectable={false} mode={'horizontal'} theme={'dark'}>
.filter((item) => item.pin)
.map((item) => {
const Action = get(components, item.action);
return Action && <Action />;
})}
<Menu.SubMenu key={'more'} title={<MoreOutlined />}>
{items {items
.filter((item) => !item.pin) .filter((item) => item.pin)
.map((item) => { .map((item) => {
const Action = get(components, item.action); const Action = get(components, item.component);
return Action && <Action />; return (
Action && (
<ToolbarItemContext.Provider value={item}>
<Action />
</ToolbarItemContext.Provider>
)
);
})} })}
<Menu.Divider></Menu.Divider> <Menu.SubMenu key={'more'} title={<MoreOutlined />}>
<Menu.Item icon={<SettingOutlined />}></Menu.Item> {items
</Menu.SubMenu> .filter((item) => !item.pin)
<CurrentUserDropdown /> .map((item) => {
</Menu> const Action = get(components, item.component);
return (
Action && (
<ToolbarItemContext.Provider value={item}>
<Action />
</ToolbarItemContext.Provider>
)
);
})}
<Menu.Divider></Menu.Divider>
<Menu.Item icon={<SettingOutlined />}></Menu.Item>
</Menu.SubMenu>
</Menu>
</div>
);
};
PluginManager.Toolbar.Item = (props) => {
const item = useContext(ToolbarItemContext);
const { icon, title, ...others } = props;
if (item.pin) {
return (
<Tooltip title={title}>
<Menu.Item {...others} eventKey={item.component}>
{icon}
</Menu.Item>
</Tooltip>
);
}
return (
<Menu.Item {...others} eventKey={item.component} icon={icon}>
{title}
</Menu.Item>
); );
}; };

View File

@ -0,0 +1,34 @@
import React from 'react';
import { Action, PluginManager, PluginManagerProvider, SchemaComponentProvider } from '@nocobase/client';
import * as plugins from './plugins';
export default () => {
return (
<SchemaComponentProvider components={{ Action }}>
<PluginManagerProvider components={plugins}>
<PluginManager.Toolbar
items={[
{
component: 'Plugin1.ToolbarItem',
pin: true,
},
{
component: 'Plugin2.ToolbarItem',
pin: true,
},
{
component: 'Plugin3.ToolbarItem',
pin: true,
},
{
component: 'Plugin4.ToolbarItem',
},
{
component: 'Plugin5.ToolbarItem',
},
]}
/>
</PluginManagerProvider>
</SchemaComponentProvider>
);
};

View File

@ -0,0 +1,5 @@
export * from './plugin1';
export * from './plugin2';
export * from './plugin3';
export * from './plugin4';
export * from './plugin5';

View File

@ -0,0 +1,17 @@
import { Menu } from 'antd';
import React from 'react';
import { SaveOutlined, KeyOutlined, DatabaseOutlined, VerifiedOutlined, NotificationOutlined } from '@ant-design/icons';
import { PluginManager } from '@nocobase/client';
export const Plugin1 = () => null;
Plugin1.ToolbarItem = () => {
return (
<PluginManager.Toolbar.Item
icon={<DatabaseOutlined />}
title={'Plugin1'}
onClick={() => {
alert('Plugin1');
}}
/>
);
};

View File

@ -0,0 +1,65 @@
import React, { useState } from 'react';
import { VerifiedOutlined } from '@ant-design/icons';
import { ISchema, useForm } from '@formily/react';
import { PluginManager, SchemaComponent, useActionVisible, VisibleContext } from '@nocobase/client';
const useCloseAction = () => {
const { setVisible } = useActionVisible();
const form = useForm();
return {
async run() {
setVisible(false);
form.submit((values) => {
console.log(values);
});
},
};
};
const schema: ISchema = {
type: 'object',
properties: {
drawer1: {
'x-component': 'Action.Drawer',
type: 'void',
title: 'Drawer Title',
properties: {
hello1: {
'x-content': 'Hello',
title: 'T1',
},
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
close1: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useCloseAction }}',
},
},
},
},
},
},
},
};
export const Plugin2 = () => null;
Plugin2.ToolbarItem = () => {
const [visible, setVisible] = useState(false);
return (
<VisibleContext.Provider value={[visible, setVisible]}>
<PluginManager.Toolbar.Item
icon={<VerifiedOutlined />}
title={'Plugin2'}
onClick={() => {
setVisible(true);
}}
/>
<SchemaComponent scope={{ useCloseAction }} schema={schema} />
</VisibleContext.Provider>
);
};

View File

@ -0,0 +1,17 @@
import { Menu } from 'antd';
import React from 'react';
import { SaveOutlined, KeyOutlined, DatabaseOutlined, VerifiedOutlined, NotificationOutlined } from '@ant-design/icons';
import { PluginManager } from '@nocobase/client';
export const Plugin3 = () => null;
Plugin3.ToolbarItem = () => {
return (
<PluginManager.Toolbar.Item
icon={<DatabaseOutlined />}
title={'Plugin3'}
onClick={() => {
alert('Plugin3');
}}
/>
);
};

View File

@ -0,0 +1,65 @@
import React, { useState } from 'react';
import { VerifiedOutlined } from '@ant-design/icons';
import { ISchema, useForm } from '@formily/react';
import { PluginManager, SchemaComponent, useActionVisible, VisibleContext } from '@nocobase/client';
const useCloseAction = () => {
const { setVisible } = useActionVisible();
const form = useForm();
return {
async run() {
setVisible(false);
form.submit((values) => {
console.log(values);
});
},
};
};
const schema: ISchema = {
type: 'object',
properties: {
drawer1: {
'x-component': 'Action.Drawer',
type: 'void',
title: 'Drawer Title',
properties: {
hello1: {
'x-content': 'Hello',
title: 'T1',
},
footer1: {
'x-component': 'Action.Drawer.Footer',
type: 'void',
properties: {
close1: {
title: 'Close',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useCloseAction }}',
},
},
},
},
},
},
},
};
export const Plugin4 = () => null;
Plugin4.ToolbarItem = () => {
const [visible, setVisible] = useState(false);
return (
<VisibleContext.Provider value={[visible, setVisible]}>
<PluginManager.Toolbar.Item
icon={<VerifiedOutlined />}
title={'Plugin4'}
onClick={() => {
setVisible(true);
}}
/>
<SchemaComponent scope={{ useCloseAction }} schema={schema} />
</VisibleContext.Provider>
);
};

View File

@ -0,0 +1,17 @@
import { Menu } from 'antd';
import React from 'react';
import { SaveOutlined, KeyOutlined, DatabaseOutlined, VerifiedOutlined, NotificationOutlined } from '@ant-design/icons';
import { PluginManager } from '@nocobase/client';
export const Plugin5 = () => null;
Plugin5.ToolbarItem = () => {
return (
<PluginManager.Toolbar.Item
icon={<DatabaseOutlined />}
title={'Plugin5'}
onClick={() => {
alert('Plugin5');
}}
/>
);
};

View File

@ -7,49 +7,53 @@ group:
# PluginManager # PluginManager
```tsx | pure ## PluginManagerProvider
<PluginManager.Provider components={{
CurrentUser,
DesignableSwitch,
CollectionManagerAction,
ACLAction,
SystemSettings,
}}>
<PluginManager.Toolbar items={[
{
action: 'DesignableSwitch',
pin: true,
},
{
action: 'CollectionManagerAction',
pin: true,
},
{
action: 'ACLAction',
pin: true,
},
{
action: 'SystemSettings.Action',
},
]}/>
</PluginManager.Provider>
```
## 扩展 ## PluginManager.Toolbar
如何扩展插件的 `PluginManager.Toolbar.Item` 插件管理器的工具栏,用于便捷的展示所有插件,不常用的可折叠显示。
<code src="./demos/demo1.tsx"/>
## PluginManager.Toolbar.Item
工具栏项,各个插件都可以配置自己的 `PluginManager.Toolbar.Item`
- `icon` pin 时,只显示 icon
- `title` pin 时title 以 tooltip 的方式显示
最简单的示例
```tsx | pure ```tsx | pure
import React from 'react'; Plugin1.ToolbarItem = () => {
import { Button, Menu } from 'antd';
import { HighlightOutlined } from '@ant-design/icons';
export const DesignableSwitch = () => {
const { designable, setDesignable } = useDesignable();
return ( return (
<Menu.Item key={'DesignableSwitch'} eventKey={'DesignableSwitch'}> <PluginManager.Toolbar.Item
<HighlightOutlined /> icon={<DatabaseOutlined />}
</Menu.Item> title={'Plugin1'}
onClick={() => {
alert('Plugin1');
}}
/>
); );
}; };
``` ```
弹出抽屉
```tsx | pure
Plugin2.ToolbarItem = () => {
const [visible, setVisible] = useState(false);
return (
<VisibleContext.Provider value={[visible, setVisible]}>
<PluginManager.Toolbar.Item
icon={<VerifiedOutlined />}
title={'Plugin2'}
onClick={() => {
setVisible(true);
}}
/>
<SchemaComponent scope={{ useCloseAction }} schema={schema} />
</VisibleContext.Provider>
);
};
```