refactor: migrate assistant/page-style/hera-version (#817)
Reviewed-on: daoyoucloud/tachybase#817
This commit is contained in:
parent
5b8bd6e19c
commit
090db400a4
@ -0,0 +1,17 @@
|
||||
import { CalculatorOutlined, CommentOutlined, HighlightOutlined, ToolOutlined } from '@ant-design/icons';
|
||||
import { useDesignable } from '@nocobase/client';
|
||||
import { FloatButton } from 'antd';
|
||||
import React from 'react';
|
||||
export const AssistantProvider = ({ children }) => {
|
||||
const { designable, setDesignable } = useDesignable();
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<FloatButton.Group trigger="hover" type="primary" style={{ right: 24, zIndex: 1250 }} icon={<ToolOutlined />}>
|
||||
<FloatButton icon={<HighlightOutlined />} onClick={() => setDesignable(!designable)} />
|
||||
<FloatButton icon={<CalculatorOutlined />} />
|
||||
<FloatButton icon={<CommentOutlined />} />
|
||||
</FloatButton.Group>
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
import { Plugin } from '@nocobase/client';
|
||||
import { AssistantProvider } from './Assistant.provider';
|
||||
|
||||
export class PluginAssistant extends Plugin {
|
||||
async load() {
|
||||
this.app.use(AssistantProvider);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useCurrentUserSettingsMenu } from '@nocobase/client';
|
||||
import { usePluginVersion } from '../../hooks/usePluginVersion';
|
||||
import { useTabSettings } from '../page-style/useTabSettings';
|
||||
|
||||
const useHeraVersion = () => {
|
||||
const version = usePluginVersion();
|
||||
return {
|
||||
key: 'hera-version',
|
||||
eventKey: 'hera-version',
|
||||
label: <span>赫拉系统 - {version}</span>,
|
||||
};
|
||||
};
|
||||
|
||||
export const HeraVersionProvider = ({ children }) => {
|
||||
const { addMenuItem } = useCurrentUserSettingsMenu();
|
||||
const heraVersion = useHeraVersion();
|
||||
const tabItem = useTabSettings();
|
||||
useEffect(() => {
|
||||
addMenuItem(heraVersion, { before: 'divider_1' });
|
||||
}, [addMenuItem, tabItem, heraVersion]);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
@ -0,0 +1,8 @@
|
||||
import { Plugin } from '@nocobase/client';
|
||||
import { HeraVersionProvider } from './HeraVersion.provider';
|
||||
|
||||
export class PluginHeraVersion extends Plugin {
|
||||
async load() {
|
||||
this.app.use(HeraVersionProvider);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { useCurrentUserContext, useCurrentUserSettingsMenu } from '@nocobase/client';
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import { useTabSettings } from './useTabSettings';
|
||||
import { TabsProps } from 'antd';
|
||||
|
||||
export interface PageStyleContextValue {
|
||||
style: string;
|
||||
items: TabsProps['items'];
|
||||
setItems: React.Dispatch<React.SetStateAction<TabsProps['items']>>;
|
||||
}
|
||||
|
||||
export const PageStyleContext = createContext<Partial<PageStyleContextValue>>({
|
||||
style: 'classical',
|
||||
});
|
||||
|
||||
export const PageStyleProvider = ({ children }) => {
|
||||
const currentUser = useCurrentUserContext();
|
||||
const tabItem = useTabSettings();
|
||||
const [items, setItems] = useState<TabsProps['items']>([]);
|
||||
const { addMenuItem } = useCurrentUserSettingsMenu();
|
||||
useEffect(() => {
|
||||
addMenuItem(tabItem, { before: 'divider_3' });
|
||||
}, [addMenuItem, tabItem]);
|
||||
|
||||
return (
|
||||
<PageStyleContext.Provider
|
||||
value={{ style: currentUser.data.data.systemSettings?.pageStyle || 'classical', items, setItems }}
|
||||
>
|
||||
{children}
|
||||
</PageStyleContext.Provider>
|
||||
);
|
||||
};
|
@ -0,0 +1,62 @@
|
||||
import { RemoteSchemaComponent, css, useDocumentTitle } from '@nocobase/client';
|
||||
import { Tabs } from 'antd';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { PageStyleContext } from './PageStyle.provider';
|
||||
|
||||
export const PageTab = () => {
|
||||
const params = useParams<{ name?: string }>();
|
||||
const { title, setTitle } = useDocumentTitle();
|
||||
const navigate = useNavigate();
|
||||
const { items, setItems } = useContext(PageStyleContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (params.name && title) {
|
||||
const targetItem = items.find((value) => value.key === params.name);
|
||||
if (!targetItem) {
|
||||
// 现有tab页数组里,不存在之前浏览的tab页面,添加新的tab页进数组
|
||||
setItems([
|
||||
...items,
|
||||
{
|
||||
key: params.name,
|
||||
label: title,
|
||||
children: <MyRouteSchemaComponent name={params.name} />,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
// 如果存在之前浏览的tab页面,只用更新页面标题
|
||||
setTitle(targetItem.label);
|
||||
}
|
||||
}
|
||||
}, [params.name, title]);
|
||||
|
||||
const onEdit = (targetKey: React.MouseEvent | React.KeyboardEvent | string, action: 'add' | 'remove') => {
|
||||
if (action === 'remove') {
|
||||
setItems((items) => {
|
||||
return items.filter((item) => item.key !== targetKey);
|
||||
});
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Tabs
|
||||
className={css`
|
||||
margin: 0;
|
||||
.ant-tabs-nav {
|
||||
margin: 0;
|
||||
}
|
||||
`}
|
||||
type="editable-card"
|
||||
items={items}
|
||||
onEdit={onEdit}
|
||||
hideAdd
|
||||
onChange={(key) => {
|
||||
navigate(`/admin/${key}`);
|
||||
}}
|
||||
activeKey={params.name}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export function MyRouteSchemaComponent({ name }: { name: string }) {
|
||||
return <RemoteSchemaComponent onlyRenderProperties uid={name} />;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { Plugin } from '@nocobase/client';
|
||||
import { PageStyleProvider } from './PageStyle.provider';
|
||||
|
||||
export class PluginPageStyle extends Plugin {
|
||||
async load() {
|
||||
this.app.use(PageStyleProvider);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
import { PageStyleContext } from './PageStyle.provider';
|
||||
|
||||
export const usePageStyle = () => {
|
||||
return useContext(PageStyleContext).style;
|
||||
};
|
@ -0,0 +1,73 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { SelectWithTitle, useAPIClient, useCurrentUserContext } from '@nocobase/client';
|
||||
import { error } from '@nocobase/utils/client';
|
||||
import { useTranslation } from '../../locale';
|
||||
|
||||
export const useTabSettings = () => {
|
||||
return {
|
||||
key: 'tab',
|
||||
eventKey: 'tab',
|
||||
label: <Label />,
|
||||
};
|
||||
};
|
||||
|
||||
export function Label() {
|
||||
const { t } = useTranslation();
|
||||
const { updateUserPageStyle } = useUpdatePageStyleSettings();
|
||||
const currentUser = useCurrentUserContext();
|
||||
|
||||
return (
|
||||
<SelectWithTitle
|
||||
title={t('Page style')}
|
||||
defaultValue={currentUser.data.data.systemSettings?.pageStyle || 'classical'}
|
||||
options={[
|
||||
{
|
||||
label: t('classical'),
|
||||
value: 'classical',
|
||||
},
|
||||
{
|
||||
label: t('tabs'),
|
||||
value: 'tab',
|
||||
},
|
||||
]}
|
||||
onChange={updateUserPageStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function useUpdatePageStyleSettings() {
|
||||
const api = useAPIClient();
|
||||
const currentUser = useCurrentUserContext();
|
||||
|
||||
const updateUserPageStyle = useCallback(
|
||||
async (pageStyle: string | null) => {
|
||||
if (pageStyle === currentUser.data.data.systemSettings?.pageStyle) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await api.resource('users').updateProfile({
|
||||
values: {
|
||||
systemSettings: {
|
||||
...(currentUser.data.data.systemSettings || {}),
|
||||
pageStyle,
|
||||
},
|
||||
},
|
||||
});
|
||||
currentUser.mutate({
|
||||
data: {
|
||||
...currentUser.data.data,
|
||||
systemSettings: {
|
||||
...(currentUser.data.data.systemSettings || {}),
|
||||
pageStyle,
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
},
|
||||
[api, currentUser],
|
||||
);
|
||||
|
||||
return { updateUserPageStyle };
|
||||
}
|
@ -76,6 +76,9 @@ import {
|
||||
import { SchemaSettingsSubmitDataType } from './schema-settings/SchemaSettingsSubmitDataType';
|
||||
import { EmbedPlugin } from './features/embed';
|
||||
import { DepartmentsPlugin } from './features/departments';
|
||||
import { PluginPageStyle } from './features/page-style';
|
||||
import { PluginHeraVersion } from './features/hera-version';
|
||||
import { PluginAssistant } from './features/assistant';
|
||||
export { usePDFViewerRef } from './schema-initializer';
|
||||
export * from './components/custom-components/custom-components';
|
||||
|
||||
@ -86,6 +89,9 @@ export class PluginCoreClient extends Plugin {
|
||||
await this.app.pm.add(GroupBlockPlugin);
|
||||
await this.app.pm.add(EmbedPlugin);
|
||||
await this.app.pm.add(DepartmentsPlugin);
|
||||
await this.app.pm.add(PluginPageStyle);
|
||||
await this.app.pm.add(PluginHeraVersion);
|
||||
await this.app.pm.add(PluginAssistant);
|
||||
}
|
||||
|
||||
async registerSettings() {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { useSessionStorageState } from 'ahooks';
|
||||
import { App, Layout, Spin, FloatButton } from 'antd';
|
||||
import { ToolOutlined, CommentOutlined, CalculatorOutlined, HighlightOutlined } from '@ant-design/icons';
|
||||
import { App, Layout } from 'antd';
|
||||
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Link, Outlet, useMatch, useNavigate, useParams } from 'react-router-dom';
|
||||
import {
|
||||
@ -16,27 +15,13 @@ import {
|
||||
useRequest,
|
||||
useSystemSettings,
|
||||
useToken,
|
||||
useApp,
|
||||
AdminProvider,
|
||||
RemoteSchemaComponent,
|
||||
useCurrentUserSettingsMenu,
|
||||
SelectWithTitle,
|
||||
useDesignable,
|
||||
} from '@nocobase/client';
|
||||
import { Tabs } from 'antd';
|
||||
import type { TabsProps } from 'antd';
|
||||
import { usePluginVersion } from '../hooks/usePluginVersion';
|
||||
import { OnlineUserDropdown } from '../components/system/OnlineUserProvider';
|
||||
import { MobileLink } from '../components/system/MobileLink';
|
||||
import { Notifications } from '../components/system/Notifications';
|
||||
import { useTranslation } from '../locale';
|
||||
|
||||
export const useAppSpin = () => {
|
||||
const app = useApp();
|
||||
return {
|
||||
render: () => (app ? app?.renderComponent?.('AppSpin') : React.createElement(Spin)),
|
||||
};
|
||||
};
|
||||
import { usePageStyle } from '../features/page-style/usePageStyle';
|
||||
import { PageTab } from '../features/page-style/PageTab';
|
||||
|
||||
const filterByACL = (schema, options) => {
|
||||
const { allowAll, allowMenuItemIds = [] } = options;
|
||||
@ -90,7 +75,6 @@ const MenuEditor = (props) => {
|
||||
setCurrent(schema);
|
||||
navigate(`/admin/${schema['x-uid']}`);
|
||||
};
|
||||
const { render } = useAppSpin();
|
||||
const adminSchemaUid = useAdminSchemaUid();
|
||||
const { data, loading } = useRequest<{
|
||||
data: any;
|
||||
@ -204,50 +188,13 @@ const MenuEditor = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export function MyRouteSchemaComponent({ name }: { name: string }) {
|
||||
return <RemoteSchemaComponent onlyRenderProperties uid={name} />;
|
||||
}
|
||||
|
||||
export const InternalAdminLayout = (props: any) => {
|
||||
const app = useApp();
|
||||
export const InternalAdminLayout = () => {
|
||||
const sideMenuRef = useRef<HTMLDivElement>();
|
||||
const result = useSystemSettings();
|
||||
const params = useParams<{ name?: string }>();
|
||||
const { token } = useToken();
|
||||
const { render } = useAppSpin();
|
||||
const { title, setTitle } = useDocumentTitle();
|
||||
const navigate = useNavigate();
|
||||
const [items, setItems] = useState<TabsProps['items']>([]);
|
||||
const pageStyle = usePageStyle();
|
||||
|
||||
useEffect(() => {
|
||||
if (params.name && title && pageStyle === 'tab') {
|
||||
const targetItem = items.find((value) => value.key === params.name);
|
||||
if (!targetItem) {
|
||||
// 现有tab页数组里,不存在之前浏览的tab页面,添加新的tab页进数组
|
||||
setItems([
|
||||
...items,
|
||||
{
|
||||
key: params.name,
|
||||
label: title,
|
||||
children: <MyRouteSchemaComponent name={params.name} />,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
// 如果存在之前浏览的tab页面,只用更新页面标题
|
||||
setTitle(targetItem.label);
|
||||
}
|
||||
}
|
||||
}, [params.name, title]);
|
||||
|
||||
const onEdit = (targetKey: React.MouseEvent | React.KeyboardEvent | string, action: 'add' | 'remove') => {
|
||||
if (action === 'remove') {
|
||||
setItems((items) => {
|
||||
return items.filter((item) => item.key !== targetKey);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Layout.Header
|
||||
@ -404,108 +351,17 @@ export const InternalAdminLayout = (props: any) => {
|
||||
pointer-events: none;
|
||||
`}
|
||||
></header>
|
||||
<>
|
||||
{params.name && pageStyle === 'tab' ? (
|
||||
<Tabs
|
||||
className={css`
|
||||
margin: 0;
|
||||
.ant-tabs-nav {
|
||||
margin: 0;
|
||||
}
|
||||
`}
|
||||
type="editable-card"
|
||||
items={items}
|
||||
onEdit={onEdit}
|
||||
hideAdd
|
||||
onChange={(key) => {
|
||||
navigate(`/admin/${key}`);
|
||||
}}
|
||||
activeKey={params.name}
|
||||
/>
|
||||
) : (
|
||||
<Outlet />
|
||||
)}
|
||||
</>
|
||||
<>{params.name && pageStyle === 'tab' ? <PageTab /> : <Outlet />}</>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export const useTabSettings = (props) => {
|
||||
return {
|
||||
key: 'tab',
|
||||
eventKey: 'tab',
|
||||
label: <Label {...props} />,
|
||||
};
|
||||
};
|
||||
|
||||
const useHeraVersion = () => {
|
||||
const version = usePluginVersion();
|
||||
return {
|
||||
key: 'hera-version',
|
||||
eventKey: 'hera-version',
|
||||
label: <span>赫拉系统 - {version}</span>,
|
||||
};
|
||||
};
|
||||
|
||||
const usePageStyle = () => {
|
||||
return useContext(PageStyleContext).style;
|
||||
};
|
||||
|
||||
export const AdminLayout = (props) => {
|
||||
const { addMenuItem } = useCurrentUserSettingsMenu();
|
||||
const [style, setStyle] = useState('classical');
|
||||
const tabItem = useTabSettings({ style, setStyle });
|
||||
const heraVersion = useHeraVersion();
|
||||
const { designable, setDesignable } = useDesignable();
|
||||
|
||||
useEffect(() => {
|
||||
addMenuItem(tabItem, { before: 'divider_3' });
|
||||
}, [addMenuItem, tabItem]);
|
||||
useEffect(() => {
|
||||
addMenuItem(heraVersion, { before: 'divider_1' });
|
||||
}, [addMenuItem, tabItem]);
|
||||
|
||||
const AdminComponent = (
|
||||
<AdminProvider>
|
||||
<PageStyleContext.Provider value={{ style }}>
|
||||
<InternalAdminLayout {...props} />
|
||||
</PageStyleContext.Provider>
|
||||
<FloatButton.Group trigger="hover" type="primary" style={{ right: 24, zIndex: 1250 }} icon={<ToolOutlined />}>
|
||||
<FloatButton icon={<HighlightOutlined />} onClick={() => setDesignable(!designable)} />
|
||||
<FloatButton icon={<CalculatorOutlined />} />
|
||||
<FloatButton icon={<CommentOutlined />} />
|
||||
</FloatButton.Group>
|
||||
<InternalAdminLayout {...props} />
|
||||
</AdminProvider>
|
||||
);
|
||||
return AdminComponent;
|
||||
};
|
||||
|
||||
export interface PageStyleContextValue {
|
||||
style: string;
|
||||
}
|
||||
|
||||
const PageStyleContext = createContext<PageStyleContextValue>({
|
||||
style: 'classical',
|
||||
});
|
||||
|
||||
function Label({ style, setStyle }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<SelectWithTitle
|
||||
title={t('Page style')}
|
||||
defaultValue={style}
|
||||
options={[
|
||||
{
|
||||
label: t('classical'),
|
||||
value: 'classical',
|
||||
},
|
||||
{
|
||||
label: t('tabs'),
|
||||
value: 'tab',
|
||||
},
|
||||
]}
|
||||
onChange={setStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useStyles } from './style';
|
||||
import { Carousel, Image } from 'antd';
|
||||
import { useRequest } from '@nocobase/client';
|
||||
import { useAppSpin } from './AdminLayout';
|
||||
import { useAppSpin, useRequest } from '@nocobase/client';
|
||||
|
||||
export const HomePage: React.FC<{}> = () => {
|
||||
const { styles } = useStyles();
|
||||
|
Loading…
Reference in New Issue
Block a user