fix(popup): z-index (#5373)
Some checks are pending
auto-merge / push-commit (push) Waiting to run
Build Docker Image / build-and-push (push) Waiting to run
Build Pro Image / build-and-push (push) Waiting to run
deploy client docs / Build (push) Waiting to run
E2E / Build (push) Waiting to run
E2E / Core and plugins (push) Blocked by required conditions
E2E / plugin-workflow (push) Blocked by required conditions
E2E / plugin-workflow-approval (push) Blocked by required conditions
E2E / plugin-data-source-main (push) Blocked by required conditions
E2E / Comment on PR (push) Blocked by required conditions
NocoBase Backend Test / sqlite-test (20, false) (push) Waiting to run
NocoBase Backend Test / sqlite-test (20, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, nocobase, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, nocobase, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, public, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (public, 20, public, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, nocobase, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, nocobase, true) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, public, false) (push) Waiting to run
NocoBase Backend Test / postgres-test (user_schema, 20, public, true) (push) Waiting to run
NocoBase Backend Test / mysql-test (20, false) (push) Waiting to run
NocoBase Backend Test / mysql-test (20, true) (push) Waiting to run
NocoBase Backend Test / mariadb-test (20, false) (push) Waiting to run
NocoBase Backend Test / mariadb-test (20, true) (push) Waiting to run
NocoBase FrontEnd Test / frontend-test (18) (push) Waiting to run
Test on Windows / build (push) Waiting to run

* fix(popup): z-index

* test: add e2e test

* chore: fix build error

* Revert "chore: fix build error"

This reverts commit d0fe9ba217.

* refactor: avoid build error

* chore: make e2e more stable
This commit is contained in:
Zeke Zhang 2024-10-09 10:33:29 +08:00 committed by GitHub
parent 259b0b707a
commit 1fc2f388e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 165 additions and 116 deletions

View File

@ -51,4 +51,26 @@ test.describe('z-index of dialog', () => {
await page.getByRole('button', { name: 'Cancel' }).click({ timeout: 1000 }); await page.getByRole('button', { name: 'Cancel' }).click({ timeout: 1000 });
await expect(page.getByRole('dialog').getByText('Assign field values')).not.toBeVisible(); await expect(page.getByRole('dialog').getByText('Assign field values')).not.toBeVisible();
}); });
test('Users & Permissions', async ({ page }) => {
await page.goto('/admin/settings/users-permissions/roles');
// Data source
await page.getByRole('tab', { name: 'Data sources' }).click();
await page.getByLabel('action-Action.Link-Configure-').click();
await page.getByRole('tab', { name: 'Action permissions', exact: true }).click();
await page.getByLabel('action-Action.Link-Configure-dataSourcesCollections-users', { exact: true }).click();
await page.getByLabel('Individual').check();
await page
.getByTestId('drawer-Action.Drawer-dataSourcesCollections-Configure permission')
.getByRole('cell')
.locator('.ant-select-selector')
.first()
.click();
await page
.getByTestId('drawer-RecordPicker.Selector-dataSourcesCollections-Select record')
.getByLabel('action-Action-Add new-create-')
.click();
await expect(page.getByText('Add condition', { exact: true })).toBeVisible();
});
}); });

View File

@ -19,7 +19,7 @@ import { useStyles } from './Action.Drawer.style';
import { useActionContext } from './hooks'; import { useActionContext } from './hooks';
import { useSetAriaLabelForDrawer } from './hooks/useSetAriaLabelForDrawer'; import { useSetAriaLabelForDrawer } from './hooks/useSetAriaLabelForDrawer';
import { ActionDrawerProps, ComposedActionDrawer, OpenSize } from './types'; import { ActionDrawerProps, ComposedActionDrawer, OpenSize } from './types';
import { antdDrawerZIndex } from './utils'; import { useZIndexContext, zIndexContext } from './zIndexContext';
const DrawerErrorFallback: React.FC<FallbackProps> = (props) => { const DrawerErrorFallback: React.FC<FallbackProps> = (props) => {
const { visible, setVisible } = useActionContext(); const { visible, setVisible } = useActionContext();
@ -43,6 +43,7 @@ export const InternalActionDrawer: React.FC<ActionDrawerProps> = observer(
const field = useField(); const field = useField();
const { componentCls, hashId } = useStyles(); const { componentCls, hashId } = useStyles();
const tabContext = useTabsContext(); const tabContext = useTabsContext();
const parentZIndex = useZIndexContext();
const footerSchema = schema.reduceProperties((buf, s) => { const footerSchema = schema.reduceProperties((buf, s) => {
if (s['x-component'] === footerNodeName) { if (s['x-component'] === footerNodeName) {
return s; return s;
@ -62,44 +63,48 @@ export const InternalActionDrawer: React.FC<ActionDrawerProps> = observer(
useSetAriaLabelForDrawer(visible); useSetAriaLabelForDrawer(visible);
} }
const zIndex = parentZIndex + (props.level || 0);
return ( return (
<TabsContextProvider {...tabContext} tabBarExtraContent={null}> <zIndexContext.Provider value={zIndex}>
<Drawer <TabsContextProvider {...tabContext} tabBarExtraContent={null}>
zIndex={antdDrawerZIndex + props.level} <Drawer
width={openSizeWidthMap.get(openSize)} zIndex={zIndex}
title={field.title} width={openSizeWidthMap.get(openSize)}
{...others} title={field.title}
{...drawerProps} {...others}
rootStyle={rootStyle} {...drawerProps}
destroyOnClose rootStyle={rootStyle}
open={visible} destroyOnClose
onClose={() => setVisible(false, true)} open={visible}
rootClassName={classNames(componentCls, hashId, drawerProps?.className, others.className, 'reset')} onClose={() => setVisible(false, true)}
footer={ rootClassName={classNames(componentCls, hashId, drawerProps?.className, others.className, 'reset')}
footerSchema && ( footer={
<div className={'footer'}> footerSchema && (
<RecursionField <div className={'footer'}>
basePath={field.address} <RecursionField
schema={schema} basePath={field.address}
onlyRenderProperties schema={schema}
filterProperties={(s) => { onlyRenderProperties
return s['x-component'] === footerNodeName; filterProperties={(s) => {
}} return s['x-component'] === footerNodeName;
/> }}
</div> />
) </div>
} )
> }
<RecursionField >
basePath={field.address} <RecursionField
schema={schema} basePath={field.address}
onlyRenderProperties schema={schema}
filterProperties={(s) => { onlyRenderProperties
return s['x-component'] !== footerNodeName; filterProperties={(s) => {
}} return s['x-component'] !== footerNodeName;
/> }}
</Drawer> />
</TabsContextProvider> </Drawer>
</TabsContextProvider>
</zIndexContext.Provider>
); );
}, },
{ displayName: 'ActionDrawer' }, { displayName: 'ActionDrawer' },

View File

@ -20,7 +20,7 @@ import { TabsContextProvider, useTabsContext } from '../tabs/context';
import { useActionContext } from './hooks'; import { useActionContext } from './hooks';
import { useSetAriaLabelForModal } from './hooks/useSetAriaLabelForModal'; import { useSetAriaLabelForModal } from './hooks/useSetAriaLabelForModal';
import { ActionDrawerProps, ComposedActionDrawer, OpenSize } from './types'; import { ActionDrawerProps, ComposedActionDrawer, OpenSize } from './types';
import { antdDrawerZIndex } from './utils'; import { useZIndexContext, zIndexContext } from './zIndexContext';
const ModalErrorFallback: React.FC<FallbackProps> = (props) => { const ModalErrorFallback: React.FC<FallbackProps> = (props) => {
const { visible, setVisible } = useActionContext(); const { visible, setVisible } = useActionContext();
@ -47,6 +47,7 @@ export const InternalActionModal: React.FC<ActionDrawerProps<ModalProps>> = obse
const field = useField(); const field = useField();
const { token } = useToken(); const { token } = useToken();
const tabContext = useTabsContext(); const tabContext = useTabsContext();
const parentZIndex = useZIndexContext();
const footerSchema = schema.reduceProperties((buf, s) => { const footerSchema = schema.reduceProperties((buf, s) => {
if (s['x-component'] === footerNodeName) { if (s['x-component'] === footerNodeName) {
return s; return s;
@ -70,79 +71,83 @@ export const InternalActionModal: React.FC<ActionDrawerProps<ModalProps>> = obse
useSetAriaLabelForModal(visible); useSetAriaLabelForModal(visible);
} }
const zIndex = parentZIndex + (props.level || 0);
return ( return (
<TabsContextProvider {...tabContext} tabBarExtraContent={null}> <zIndexContext.Provider value={zIndex}>
<Modal <TabsContextProvider {...tabContext} tabBarExtraContent={null}>
zIndex={antdDrawerZIndex + props.level} <Modal
width={actualWidth} zIndex={zIndex}
title={field.title} width={actualWidth}
{...(others as ModalProps)} title={field.title}
{...modalProps} {...(others as ModalProps)}
styles={styles} {...modalProps}
style={{ styles={styles}
...modalProps?.style, style={{
...others?.style, ...modalProps?.style,
}} ...others?.style,
destroyOnClose
open={visible}
onCancel={() => {
setVisible(false, true);
form.reset();
}}
className={classNames(
others.className,
modalProps?.className,
css`
&.nb-action-popup {
.ant-modal-header {
display: none;
}
.ant-modal-content {
background: var(--nb-box-bg);
border: 1px solid rgba(255, 255, 255, 0.1);
padding-bottom: 0;
}
// 这里的样式是为了保证页面 tabs 标签下面的分割线和页面内容对齐(页面内边距可以通过主题编辑器调节)
.ant-tabs-nav {
padding-left: ${token.paddingLG - token.paddingPageHorizontal}px;
padding-right: ${token.paddingLG - token.paddingPageHorizontal}px;
margin-left: ${token.paddingPageHorizontal - token.paddingLG}px;
margin-right: ${token.paddingPageHorizontal - token.paddingLG}px;
}
.ant-modal-footer {
display: ${showFooter ? 'block' : 'none'};
}
}
`,
)}
footer={
showFooter ? (
<RecursionField
basePath={field.address}
schema={schema}
onlyRenderProperties
filterProperties={(s) => {
return s['x-component'] === footerNodeName;
}}
/>
) : (
false
)
}
>
<RecursionField
basePath={field.address}
schema={schema}
onlyRenderProperties
filterProperties={(s) => {
return s['x-component'] !== footerNodeName;
}} }}
/> destroyOnClose
</Modal> open={visible}
</TabsContextProvider> onCancel={() => {
setVisible(false, true);
form.reset();
}}
className={classNames(
others.className,
modalProps?.className,
css`
&.nb-action-popup {
.ant-modal-header {
display: none;
}
.ant-modal-content {
background: var(--nb-box-bg);
border: 1px solid rgba(255, 255, 255, 0.1);
padding-bottom: 0;
}
// 这里的样式是为了保证页面 tabs 标签下面的分割线和页面内容对齐(页面内边距可以通过主题编辑器调节)
.ant-tabs-nav {
padding-left: ${token.paddingLG - token.paddingPageHorizontal}px;
padding-right: ${token.paddingLG - token.paddingPageHorizontal}px;
margin-left: ${token.paddingPageHorizontal - token.paddingLG}px;
margin-right: ${token.paddingPageHorizontal - token.paddingLG}px;
}
.ant-modal-footer {
display: ${showFooter ? 'block' : 'none'};
}
}
`,
)}
footer={
showFooter ? (
<RecursionField
basePath={field.address}
schema={schema}
onlyRenderProperties
filterProperties={(s) => {
return s['x-component'] === footerNodeName;
}}
/>
) : (
false
)
}
>
<RecursionField
basePath={field.address}
schema={schema}
onlyRenderProperties
filterProperties={(s) => {
return s['x-component'] !== footerNodeName;
}}
/>
</Modal>
</TabsContextProvider>
</zIndexContext.Provider>
); );
}, },
{ displayName: 'ActionModal' }, { displayName: 'ActionModal' },

View File

@ -15,7 +15,7 @@ import { BackButtonUsedInSubPage } from '../page/BackButtonUsedInSubPage';
import { TabsContextProvider, useTabsContext } from '../tabs/context'; import { TabsContextProvider, useTabsContext } from '../tabs/context';
import { useActionPageStyle } from './Action.Page.style'; import { useActionPageStyle } from './Action.Page.style';
import { usePopupOrSubpagesContainerDOM } from './hooks/usePopupSlotDOM'; import { usePopupOrSubpagesContainerDOM } from './hooks/usePopupSlotDOM';
import { antdDrawerZIndex } from './utils'; import { useZIndexContext, zIndexContext } from './zIndexContext';
export function ActionPage({ level }) { export function ActionPage({ level }) {
const filedSchema = useFieldSchema(); const filedSchema = useFieldSchema();
@ -23,12 +23,13 @@ export function ActionPage({ level }) {
const { getContainerDOM } = usePopupOrSubpagesContainerDOM(); const { getContainerDOM } = usePopupOrSubpagesContainerDOM();
const { styles } = useActionPageStyle(); const { styles } = useActionPageStyle();
const tabContext = useTabsContext(); const tabContext = useTabsContext();
const parentZIndex = useZIndexContext();
const style = useMemo(() => { const style = useMemo(() => {
return { return {
zIndex: antdDrawerZIndex + level, zIndex: parentZIndex + (level || 0),
}; };
}, [level]); }, [parentZIndex, level]);
if (!ctx.visible) { if (!ctx.visible) {
return null; return null;
@ -37,7 +38,9 @@ export function ActionPage({ level }) {
const actionPageNode = ( const actionPageNode = (
<div className={styles.container} style={style}> <div className={styles.container} style={style}>
<TabsContextProvider {...tabContext} tabBarExtraContent={<BackButtonUsedInSubPage />}> <TabsContextProvider {...tabContext} tabBarExtraContent={<BackButtonUsedInSubPage />}>
<RecursionField schema={filedSchema} onlyRenderProperties /> <zIndexContext.Provider value={style.zIndex}>
<RecursionField schema={filedSchema} onlyRenderProperties />
</zIndexContext.Provider>
</TabsContextProvider> </TabsContextProvider>
</div> </div>
); );

View File

@ -154,5 +154,3 @@ export const setInitialActionState = (field) => {
field.data.hidden = false; field.data.hidden = false;
field.componentProps['disabled'] = false; field.componentProps['disabled'] = false;
}; };
export const antdDrawerZIndex = 100;

View File

@ -0,0 +1,16 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React from 'react';
export const zIndexContext = React.createContext(100);
export const useZIndexContext = () => {
return React.useContext(zIndexContext);
};