fix: should show/hide schema when enabled/disabled TabBar, Tabs, Header (#2428)
This commit is contained in:
parent
b542802667
commit
26cd9e810c
@ -20,7 +20,8 @@
|
|||||||
"react": "^18.0.0",
|
"react": "^18.0.0",
|
||||||
"react-dom": "^18.0.0",
|
"react-dom": "^18.0.0",
|
||||||
"react-i18next": "^11.15.1",
|
"react-i18next": "^11.15.1",
|
||||||
"react-router-dom": "^6.11.2"
|
"react-router-dom": "^6.11.2",
|
||||||
|
"ahooks": "^3.7.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@nocobase/client": "0.x",
|
"@nocobase/client": "0.x",
|
||||||
|
@ -6,20 +6,21 @@ import { Button } from 'antd';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { generateNTemplate, useTranslation } from '../../../../locale';
|
import { generateNTemplate, useTranslation } from '../../../../locale';
|
||||||
import { PageSchema } from '../../common';
|
|
||||||
import { findSchema } from '../../helpers';
|
import { findSchema } from '../../helpers';
|
||||||
|
import { useSchemaPatch } from '../../hooks';
|
||||||
|
|
||||||
export const ContainerDesigner = () => {
|
export const ContainerDesigner = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { dn } = useDesignable();
|
const { onUpdateComponentProps } = useSchemaPatch();
|
||||||
const tabBarSchema = fieldSchema.reduceProperties(
|
|
||||||
(schema, next) => schema || (next['x-component'] === 'MTabBar' && next),
|
|
||||||
) as Schema;
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const field = useField();
|
const field = useField();
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const tabBarSchema = findSchema(fieldSchema, 'MTabBar');
|
||||||
|
const tabBarEnabled = tabBarSchema && field.componentProps.tabBarEnabled !== false;
|
||||||
|
|
||||||
const schemaSettingsProps = {
|
const schemaSettingsProps = {
|
||||||
dn,
|
dn,
|
||||||
field,
|
field,
|
||||||
@ -43,13 +44,12 @@ export const ContainerDesigner = () => {
|
|||||||
{...schemaSettingsProps}
|
{...schemaSettingsProps}
|
||||||
>
|
>
|
||||||
<SchemaSettings.SwitchItem
|
<SchemaSettings.SwitchItem
|
||||||
checked={!!tabBarSchema}
|
checked={tabBarEnabled}
|
||||||
title={t('Enable TabBar')}
|
title={t('Enable TabBar')}
|
||||||
onChange={async (v) => {
|
onChange={async (v) => {
|
||||||
if (v) {
|
if (v) {
|
||||||
|
if (!tabBarSchema) {
|
||||||
const pageSchema = findSchema(fieldSchema, 'MPage');
|
const pageSchema = findSchema(fieldSchema, 'MPage');
|
||||||
if (!pageSchema) return;
|
|
||||||
await dn.remove(pageSchema);
|
|
||||||
await dn.insertBeforeEnd({
|
await dn.insertBeforeEnd({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'MTabBar',
|
'x-component': 'MTabBar',
|
||||||
@ -70,17 +70,15 @@ export const ContainerDesigner = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
const tabBarSchemaFirstKey = Object.keys(tabBarSchema.properties || {})?.[0];
|
}
|
||||||
const pageSchema = tabBarSchemaFirstKey
|
|
||||||
? findSchema(tabBarSchema.properties[tabBarSchemaFirstKey], 'MPage')
|
await onUpdateComponentProps({
|
||||||
: null;
|
tabBarEnabled: v,
|
||||||
await dn.remove(tabBarSchema);
|
|
||||||
await dn.insertBeforeEnd(pageSchema || PageSchema, {
|
|
||||||
onSuccess() {
|
|
||||||
navigate('../');
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (v === false) {
|
||||||
|
navigate('../');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useFieldSchema } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { cx, SchemaComponent, SortableItem, useDesigner, useToken } from '@nocobase/client';
|
import { cx, SchemaComponent, SortableItem, useDesigner, useToken } from '@nocobase/client';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Navigate, useLocation, useNavigate, useParams } from 'react-router-dom';
|
import { Navigate, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||||
@ -36,6 +36,8 @@ const InternalContainer: React.FC = (props) => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const params = useParams<{ name: string }>();
|
const params = useParams<{ name: string }>();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const field = useField();
|
||||||
|
const isTabBarEnabled = field.componentProps.tabBarEnabled !== false;
|
||||||
const tabBarSchema = fieldSchema?.properties?.['tabBar'];
|
const tabBarSchema = fieldSchema?.properties?.['tabBar'];
|
||||||
const tabBarCurrentFirstKey = tabBarSchema?.properties ? Object.keys(tabBarSchema.properties)[0] : null;
|
const tabBarCurrentFirstKey = tabBarSchema?.properties ? Object.keys(tabBarSchema.properties)[0] : null;
|
||||||
let redirectToUid = null;
|
let redirectToUid = null;
|
||||||
@ -69,6 +71,7 @@ const InternalContainer: React.FC = (props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{isTabBarEnabled && (
|
||||||
<div className={cx('nb-mobile-container-tab-bar', styles.tabBar)}>
|
<div className={cx('nb-mobile-container-tab-bar', styles.tabBar)}>
|
||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
onlyRenderProperties
|
onlyRenderProperties
|
||||||
@ -78,6 +81,7 @@ const InternalContainer: React.FC = (props) => {
|
|||||||
schema={fieldSchema}
|
schema={fieldSchema}
|
||||||
></SchemaComponent>
|
></SchemaComponent>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</SortableItem>
|
</SortableItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,15 +6,19 @@ import { Button } from 'antd';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { generateNTemplate, useTranslation } from '../../../../locale';
|
import { generateNTemplate, useTranslation } from '../../../../locale';
|
||||||
import { findGridSchema } from '../../helpers';
|
import { findGridSchema } from '../../helpers';
|
||||||
|
import { useSchemaPatch } from '../../hooks';
|
||||||
|
|
||||||
export const PageDesigner = (props) => {
|
export const PageDesigner = (props) => {
|
||||||
const { showBack } = props;
|
const { showBack } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const field = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
|
const { onUpdateComponentProps } = useSchemaPatch();
|
||||||
const headerSchema = fieldSchema?.properties?.['header'];
|
const headerSchema = fieldSchema?.properties?.['header'];
|
||||||
|
const isHeaderEnabled = !!headerSchema && field.componentProps?.headerEnabled !== false;
|
||||||
const tabsSchema = fieldSchema?.properties?.['tabs'];
|
const tabsSchema = fieldSchema?.properties?.['tabs'];
|
||||||
const field = useField();
|
const isTabsEnabled = !!tabsSchema && field.componentProps?.tabsEnabled !== false;
|
||||||
const schemaSettingsProps = {
|
const schemaSettingsProps = {
|
||||||
dn,
|
dn,
|
||||||
field,
|
field,
|
||||||
@ -39,10 +43,10 @@ export const PageDesigner = (props) => {
|
|||||||
{...schemaSettingsProps}
|
{...schemaSettingsProps}
|
||||||
>
|
>
|
||||||
<SchemaSettings.SwitchItem
|
<SchemaSettings.SwitchItem
|
||||||
checked={!!headerSchema}
|
checked={isHeaderEnabled}
|
||||||
title={t('Enable Header')}
|
title={t('Enable Header')}
|
||||||
onChange={async (v) => {
|
onChange={async (v) => {
|
||||||
if (v) {
|
if (!headerSchema) {
|
||||||
await dn.insertAfterBegin({
|
await dn.insertAfterBegin({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'header',
|
name: 'header',
|
||||||
@ -53,20 +57,19 @@ export const PageDesigner = (props) => {
|
|||||||
showBack,
|
showBack,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await dn.remove(headerSchema);
|
|
||||||
}
|
}
|
||||||
dn.refresh();
|
await onUpdateComponentProps({
|
||||||
|
headerEnabled: v,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SchemaSettings.SwitchItem
|
<SchemaSettings.SwitchItem
|
||||||
checked={!!tabsSchema}
|
checked={isTabsEnabled}
|
||||||
title={t('Enable Tabs')}
|
title={t('Enable Tabs')}
|
||||||
onChange={async (v) => {
|
onChange={async (v) => {
|
||||||
if (v) {
|
if (!tabsSchema) {
|
||||||
const gridSchema = findGridSchema(fieldSchema);
|
const gridSchema = findGridSchema(fieldSchema);
|
||||||
if (gridSchema) {
|
await dn.remove(gridSchema);
|
||||||
return dn.remove(gridSchema).then(() => {
|
|
||||||
return dn.insertBeforeEnd({
|
return dn.insertBeforeEnd({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'tabs',
|
name: 'tabs',
|
||||||
@ -92,14 +95,11 @@ export const PageDesigner = (props) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await onUpdateComponentProps({
|
||||||
|
tabsEnabled: v,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const gridSchema = findGridSchema(tabsSchema.properties[Object.keys(tabsSchema.properties)[0]]);
|
|
||||||
if (gridSchema) {
|
|
||||||
return dn.remove(tabsSchema).then(() => dn.insertBeforeEnd(gridSchema, {}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SchemaSettings>
|
</SchemaSettings>
|
||||||
|
@ -1,18 +1,32 @@
|
|||||||
import { RecursionField, useFieldSchema } from '@formily/react';
|
import { RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||||
import { ActionBarProvider, SortableItem, TabsContextProvider, cx, useDesigner } from '@nocobase/client';
|
import { ActionBarProvider, SortableItem, TabsContextProvider, cx, useDesigner } from '@nocobase/client';
|
||||||
import { TabsProps } from 'antd';
|
import { TabsProps } from 'antd';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { countGridCol } from '../../helpers';
|
import { countGridCol, findSchema } from '../../helpers';
|
||||||
import { PageDesigner } from './Page.Designer';
|
import { PageDesigner } from './Page.Designer';
|
||||||
import useStyles from './style';
|
import useStyles from './style';
|
||||||
|
|
||||||
const InternalPage: React.FC = (props) => {
|
const InternalPage: React.FC = (props) => {
|
||||||
const { styles } = useStyles();
|
const { styles } = useStyles();
|
||||||
const Designer = useDesigner();
|
const Designer = useDesigner();
|
||||||
|
const field = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const tabsSchema = fieldSchema.properties?.['tabs'];
|
const tabsSchema = fieldSchema.properties?.['tabs'];
|
||||||
|
const isHeaderEnabled = field.componentProps.headerEnabled !== false;
|
||||||
|
const isTabsEnabled = field.componentProps.tabsEnabled !== false;
|
||||||
|
|
||||||
|
let pageSchema = findSchema(fieldSchema, 'MPage');
|
||||||
|
if (!isTabsEnabled && !pageSchema && tabsSchema) {
|
||||||
|
const schemaArr = Object.values(tabsSchema.properties || {}).sort((k1, k2) => {
|
||||||
|
return k1['x-index'] - k2['x-index'];
|
||||||
|
});
|
||||||
|
if (schemaArr.length !== 0) {
|
||||||
|
pageSchema = Object.values(schemaArr[0].properties)?.[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only support globalActions in page
|
// Only support globalActions in page
|
||||||
const onlyInPage = fieldSchema.root === fieldSchema.parent;
|
const onlyInPage = fieldSchema.root === fieldSchema.parent;
|
||||||
let hasGlobalActions = false;
|
let hasGlobalActions = false;
|
||||||
@ -42,9 +56,9 @@ const InternalPage: React.FC = (props) => {
|
|||||||
|
|
||||||
const GlobalActionProvider = useCallback(
|
const GlobalActionProvider = useCallback(
|
||||||
(props) => {
|
(props) => {
|
||||||
if (hasGlobalActions) {
|
|
||||||
return (
|
return (
|
||||||
<TabsContextProvider>
|
<TabsContextProvider>
|
||||||
|
{hasGlobalActions ? (
|
||||||
<ActionBarProvider
|
<ActionBarProvider
|
||||||
container={
|
container={
|
||||||
(typeof props.active !== 'undefined' ? props.active : true) && onlyInPage
|
(typeof props.active !== 'undefined' ? props.active : true) && onlyInPage
|
||||||
@ -58,12 +72,13 @@ const InternalPage: React.FC = (props) => {
|
|||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</ActionBarProvider>
|
</ActionBarProvider>
|
||||||
|
) : (
|
||||||
|
props.children
|
||||||
|
)}
|
||||||
</TabsContextProvider>
|
</TabsContextProvider>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return <>{props.children}</>;
|
|
||||||
},
|
},
|
||||||
[hasGlobalActions, onlyInPage],
|
[hasGlobalActions, onlyInPage, styles.globalActionCSS],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -75,21 +90,23 @@ const InternalPage: React.FC = (props) => {
|
|||||||
}}
|
}}
|
||||||
className={cx('nb-mobile-page-header', styles.mobilePageHeader)}
|
className={cx('nb-mobile-page-header', styles.mobilePageHeader)}
|
||||||
>
|
>
|
||||||
|
{isHeaderEnabled && (
|
||||||
<RecursionField
|
<RecursionField
|
||||||
schema={fieldSchema}
|
schema={fieldSchema}
|
||||||
filterProperties={(s) => {
|
filterProperties={(s) => {
|
||||||
return 'MHeader' === s['x-component'];
|
return 'MHeader' === s['x-component'];
|
||||||
}}
|
}}
|
||||||
></RecursionField>
|
></RecursionField>
|
||||||
|
)}
|
||||||
<TabsContextProvider
|
<TabsContextProvider
|
||||||
PaneRoot={GlobalActionProvider}
|
PaneRoot={GlobalActionProvider}
|
||||||
activeKey={searchParams.get('tab')}
|
activeKey={searchParams.get('tab')}
|
||||||
onChange={onTabsChange}
|
onChange={onTabsChange}
|
||||||
>
|
>
|
||||||
<RecursionField
|
<RecursionField
|
||||||
schema={fieldSchema}
|
schema={isTabsEnabled ? fieldSchema : pageSchema}
|
||||||
filterProperties={(s) => {
|
filterProperties={(s) => {
|
||||||
return 'Tabs' === s['x-component'];
|
return 'Tabs' === s['x-component'] || 'Grid.Row' === s['x-component'];
|
||||||
}}
|
}}
|
||||||
></RecursionField>
|
></RecursionField>
|
||||||
</TabsContextProvider>
|
</TabsContextProvider>
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { useField, useFieldSchema } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { useDesignable } from '@nocobase/client';
|
import { useDesignable } from '@nocobase/client';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import { useCallback } from 'react';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
|
||||||
export const useSchemaPatch = () => {
|
export const useSchemaPatch = () => {
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
|
|
||||||
const onUpdateComponentProps = useCallback((data) => {
|
const onUpdateComponentProps = useMemoizedFn(async (data) => {
|
||||||
lodash.set(fieldSchema, 'x-component-props', data);
|
lodash.set(fieldSchema, 'x-component-props', data);
|
||||||
field.componentProps = { ...field.componentProps, ...data };
|
field.componentProps = { ...field.componentProps, ...data };
|
||||||
dn.emit('patch', {
|
await dn.emit('patch', {
|
||||||
schema: {
|
schema: {
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
'x-component-props': fieldSchema['x-component-props'],
|
'x-component-props': fieldSchema['x-component-props'],
|
||||||
@ -23,8 +23,8 @@ export const useSchemaPatch = () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dn.refresh();
|
await dn.refresh();
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
return { onUpdateComponentProps };
|
return { onUpdateComponentProps };
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user