fix: should show/hide schema when enabled/disabled TabBar, Tabs, Header (#2428)

This commit is contained in:
Dunqing 2023-08-14 20:32:40 +08:00 committed by GitHub
parent b542802667
commit 26cd9e810c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 111 deletions

View File

@ -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",

View File

@ -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('../');
} }
}} }}
/> />

View File

@ -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>
); );
}; };

View File

@ -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>

View File

@ -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>

View File

@ -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 };
}; };