fix: the left menu does not collapse when switching routes

This commit is contained in:
chenos 2022-04-24 16:05:08 +08:00
parent 85882f7c7a
commit 4f8cf13d1d
2 changed files with 92 additions and 50 deletions

View File

@ -1,6 +1,6 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { Layout, Spin } from 'antd'; import { Layout, Spin } from 'antd';
import React, { useRef, useState } from 'react'; import React, { createContext, useContext, useMemo, useRef } from 'react';
import { useHistory, useRouteMatch } from 'react-router-dom'; import { useHistory, useRouteMatch } from 'react-router-dom';
import { import {
ACLAllowConfigure, ACLAllowConfigure,
@ -11,10 +11,11 @@ import {
findMenuItem, findMenuItem,
PluginManager, PluginManager,
RemoteCollectionManagerProvider, RemoteCollectionManagerProvider,
RemoteSchemaComponent,
RemoteSchemaTemplateManagerProvider, RemoteSchemaTemplateManagerProvider,
SchemaComponent,
useACLRoleContext, useACLRoleContext,
useDocumentTitle, useDocumentTitle,
useRequest,
useRoute, useRoute,
useSystemSettings useSystemSettings
} from '../../../'; } from '../../../';
@ -27,6 +28,9 @@ const filterByACL = (schema, options) => {
return schema; return schema;
} }
const filterSchema = (s) => { const filterSchema = (s) => {
if (!s) {
return;
}
for (const key in s.properties) { for (const key in s.properties) {
if (Object.prototype.hasOwnProperty.call(s.properties, key)) { if (Object.prototype.hasOwnProperty.call(s.properties, key)) {
const element = s.properties[key]; const element = s.properties[key];
@ -40,23 +44,74 @@ const filterByACL = (schema, options) => {
return schema; return schema;
}; };
const SchemaIdContext = createContext(null);
const useMenuProps = () => {
const defaultSelectedUid = useContext(SchemaIdContext);
return {
selectedUid: defaultSelectedUid,
defaultSelectedUid,
};
};
const MenuEditor = (props) => {
const { setTitle } = useDocumentTitle();
const history = useHistory();
const match = useRouteMatch<any>();
const defaultSelectedUid = match.params.name;
const { sideMenuRef } = props;
const ctx = useACLRoleContext();
const route = useRoute();
const onSelect = ({ item }) => {
const schema = item.props.schema;
setTitle(schema.title);
history.push(`/admin/${schema['x-uid']}`);
};
const { data, loading } = useRequest(
{
url: `/uiSchemas:getJsonSchema/${route.uiSchemaUid}`,
},
{
refreshDeps: [route.uiSchemaUid],
onSuccess(data) {
const schema = filterByACL(data?.data, ctx);
if (defaultSelectedUid) {
const s = findByUid(schema, defaultSelectedUid);
if (s) {
setTitle(s.title);
}
} else {
const s = findMenuItem(schema);
if (s) {
history.push(`/admin/${s['x-uid']}`);
setTitle(s.title);
}
}
},
},
);
const schema = useMemo(() => {
const s = filterByACL(data?.data, ctx);
if (s?.['x-component-props']) {
s['x-component-props']['useProps'] = useMenuProps;
}
return s;
}, [data?.data]);
if (loading) {
return <Spin />;
}
return (
<SchemaIdContext.Provider value={defaultSelectedUid}>
<SchemaComponent memoized scope={{ useMenuProps, onSelect, sideMenuRef, defaultSelectedUid }} schema={schema} />
</SchemaIdContext.Provider>
);
};
const InternalAdminLayout = (props: any) => { const InternalAdminLayout = (props: any) => {
const route = useRoute(); const route = useRoute();
const history = useHistory(); const history = useHistory();
const match = useRouteMatch<any>(); const match = useRouteMatch<any>();
const { setTitle } = useDocumentTitle(); const { setTitle } = useDocumentTitle();
const sideMenuRef = useRef(); const sideMenuRef = useRef();
const defaultSelectedUid = match.params.name;
const [schema, setSchema] = useState({});
const ctx = useACLRoleContext();
const onSelect = ({ item }) => {
const schema = item.props.schema;
console.log('onSelect', schema);
setSchema(schema);
setTitle(schema.title);
history.push(`/admin/${schema['x-uid']}`);
};
const [hidden, setHidden] = useState(false);
const result = useSystemSettings(); const result = useSystemSettings();
const { service } = useCollectionManager(); const { service } = useCollectionManager();
return ( return (
@ -91,40 +146,7 @@ const InternalAdminLayout = (props: any) => {
width: 'calc(100% - 590px)', width: 'calc(100% - 590px)',
}} }}
> >
<RemoteSchemaComponent <MenuEditor sideMenuRef={sideMenuRef} />
hidden={hidden}
uid={route.uiSchemaUid}
scope={{ onSelect, sideMenuRef, defaultSelectedUid }}
schemaTransform={(data) => {
if (!data) {
return data;
}
data['x-component-props'] = data['x-component-props'] || {};
data['x-component-props']['defaultSelectedUid'] = defaultSelectedUid;
return filterByACL(data, ctx);
}}
onSuccess={(data) => {
if (defaultSelectedUid && defaultSelectedUid.includes('/')) {
return;
}
const schema = filterByACL(data?.data, ctx);
if (defaultSelectedUid) {
const s = findByUid(schema, defaultSelectedUid);
if (s) {
setTitle(s.title);
return;
}
}
setHidden(true);
setTimeout(() => setHidden(false), 11);
const s = findMenuItem(schema);
if (s) {
setSchema(s);
setTitle(s.title);
history.push(`/admin/${s['x-uid']}`);
}
}}
/>
</div> </div>
</div> </div>
<div style={{ position: 'absolute', top: 0, right: 0 }}> <div style={{ position: 'absolute', top: 0, right: 0 }}>

View File

@ -13,6 +13,7 @@ import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { createDesignable, DndContext, SortableItem, useDesignable, useDesigner } from '../..'; import { createDesignable, DndContext, SortableItem, useDesignable, useDesigner } from '../..';
import { Icon, useAPIClient, useSchemaInitializer } from '../../../'; import { Icon, useAPIClient, useSchemaInitializer } from '../../../';
import { useProps } from '../../hooks/useProps';
import { MenuDesigner } from './Menu.Designer'; import { MenuDesigner } from './Menu.Designer';
import { findKeysByUid, findMenuItem } from './util'; import { findKeysByUid, findMenuItem } from './util';
@ -139,12 +140,13 @@ export const Menu: ComposedMenu = observer((props) => {
let { let {
onSelect, onSelect,
mode, mode,
selectedUid,
defaultSelectedUid, defaultSelectedUid,
sideMenuRefScopeKey, sideMenuRefScopeKey,
defaultSelectedKeys: dSelectedKeys, defaultSelectedKeys: dSelectedKeys,
defaultOpenKeys: dOpenKeys, defaultOpenKeys: dOpenKeys,
...others ...others
} = props; } = useProps(props);
const { t } = useTranslation(); const { t } = useTranslation();
const Designer = useDesigner(); const Designer = useDesigner();
const schema = useFieldSchema(); const schema = useFieldSchema();
@ -178,6 +180,24 @@ export const Menu: ComposedMenu = observer((props) => {
} }
return null; return null;
}); });
useEffect(() => {
const keys = findKeysByUid(schema, selectedUid);
setDefaultSelectedKeys(keys);
if (['inline', 'mix'].includes(mode)) {
setDefaultOpenKeys(dOpenKeys || keys);
}
const key = keys?.[0] || null;
if (mode === 'mix') {
if (key) {
const s = schema.properties?.[key];
if (s['x-component'] === 'Menu.SubMenu') {
setSideMenuSchema(s);
}
} else {
setSideMenuSchema(null);
}
}
}, [selectedUid]);
useEffect(() => { useEffect(() => {
if (['inline', 'mix'].includes(mode)) { if (['inline', 'mix'].includes(mode)) {
setDefaultOpenKeys(defaultSelectedKeys); setDefaultOpenKeys(defaultSelectedKeys);
@ -244,8 +264,8 @@ export const Menu: ComposedMenu = observer((props) => {
} }
}} }}
mode={mode === 'mix' ? 'horizontal' : mode} mode={mode === 'mix' ? 'horizontal' : mode}
defaultOpenKeys={defaultOpenKeys} openKeys={defaultOpenKeys}
defaultSelectedKeys={defaultSelectedKeys} selectedKeys={defaultSelectedKeys}
> >
{designable && ( {designable && (
<AntdMenu.Item disabled style={{ padding: '0 8px', order: 9999 }}> <AntdMenu.Item disabled style={{ padding: '0 8px', order: 9999 }}>