mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
feat: add tooltip configuration to menu item and table headers (#6346)
* feat: add tooltip configuration to menu item and table headers * feat: add tooltip to link and group menus * feat: menu tooltip icon style adjustment * feat: menu tooltip icon style adjustment * fix: e2e * refactor: optimize tooltip component usage in table columns * feat: add tooltip editing functionality and enhance tooltip display in menu items --------- Co-authored-by: Zeke Zhang <958414905@qq.com>
This commit is contained in:
parent
a9000d16c1
commit
c2928d38cf
37
packages/core/client/src/hoc/withTooltipComponent.tsx
Normal file
37
packages/core/client/src/hoc/withTooltipComponent.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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';
|
||||
import { Tooltip } from 'antd';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
const titleWrapperStyle = {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
};
|
||||
|
||||
export const withTooltipComponent = (Component: React.FC) => {
|
||||
return (props) => {
|
||||
const { tooltip } = props;
|
||||
|
||||
if (!tooltip) {
|
||||
return <Component {...props} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={titleWrapperStyle}>
|
||||
<Component {...props} />
|
||||
<Tooltip title={tooltip}>
|
||||
<QuestionCircleOutlined style={{ zIndex: 1 }} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
@ -88,6 +88,5 @@ export {
|
||||
IsInNocoBaseRecursionFieldContext,
|
||||
NocoBaseRecursionField,
|
||||
RefreshComponentProvider,
|
||||
useRefreshFieldSchema
|
||||
useRefreshFieldSchema,
|
||||
} from './formily/NocoBaseRecursionField';
|
||||
|
||||
|
@ -306,6 +306,9 @@ test.describe('configure actions column', () => {
|
||||
await page.getByText('Actions', { exact: true }).hover();
|
||||
await page.getByLabel('designer-schema-initializer-TableV2.Column-TableV2.ActionColumnDesigner-').hover();
|
||||
await page.getByRole('menuitem', { name: 'Delete' }).click();
|
||||
|
||||
await page.getByText('Actions', { exact: true }).hover();
|
||||
await page.getByLabel('designer-schema-initializer-TableV2.Column-TableV2.ActionColumnDesigner-').hover();
|
||||
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
|
||||
|
||||
await page.mouse.move(300, 0);
|
||||
|
@ -82,6 +82,43 @@ export const tableColumnSettings = new SchemaSettings({
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'editTooltip',
|
||||
type: 'modal',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const field = useField();
|
||||
const columnSchema = useFieldSchema();
|
||||
|
||||
return {
|
||||
title: t('Edit tooltip'),
|
||||
schema: {
|
||||
type: 'object',
|
||||
title: t('Edit tooltip'),
|
||||
properties: {
|
||||
tooltip: {
|
||||
default: columnSchema?.['x-component-props']?.tooltip || '',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
} as ISchema,
|
||||
onSubmit({ tooltip }) {
|
||||
field.componentProps.tooltip = tooltip;
|
||||
columnSchema['x-component-props'] = columnSchema['x-component-props'] || {};
|
||||
columnSchema['x-component-props']['tooltip'] = tooltip;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': columnSchema['x-uid'],
|
||||
'x-component-props': columnSchema['x-component-props'],
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'style',
|
||||
Component: (props) => {
|
||||
|
@ -17,7 +17,7 @@ test.describe('group page side menus schema settings', () => {
|
||||
await expectSettingsMenu({
|
||||
page,
|
||||
showMenu: () => showSettingsInSide(page, 'group page in side'),
|
||||
supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Insert inner', 'Delete'],
|
||||
supportedOptions: ['Edit', 'Edit tooltip', 'Move to', 'Insert before', 'Insert after', 'Insert inner', 'Delete'],
|
||||
});
|
||||
});
|
||||
|
||||
@ -28,7 +28,7 @@ test.describe('group page side menus schema settings', () => {
|
||||
await expectSettingsMenu({
|
||||
page,
|
||||
showMenu: () => showSettingsInSide(page, 'link page in side'),
|
||||
supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Delete'],
|
||||
supportedOptions: ['Edit', 'Edit tooltip', 'Move to', 'Insert before', 'Insert after', 'Delete'],
|
||||
});
|
||||
});
|
||||
|
||||
@ -39,7 +39,7 @@ test.describe('group page side menus schema settings', () => {
|
||||
await expectSettingsMenu({
|
||||
page,
|
||||
showMenu: () => showSettingsInSide(page, 'single page in side'),
|
||||
supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Delete'],
|
||||
supportedOptions: ['Edit', 'Edit tooltip', 'Move to', 'Insert before', 'Insert after', 'Delete'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ test.describe('group page menus schema settings', () => {
|
||||
test('edit', async ({ page, mockPage }) => {
|
||||
await mockPage({ type: 'group', name: 'group page' }).goto();
|
||||
await showSettings(page, 'group page');
|
||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||
await page.getByRole('menuitem', { name: 'Edit', exact: true }).click();
|
||||
await page.mouse.move(300, 0);
|
||||
|
||||
// 设置一个新名称
|
||||
|
@ -23,6 +23,7 @@ export interface NocoBaseDesktopRoute {
|
||||
children?: NocoBaseDesktopRoute[];
|
||||
|
||||
title?: string;
|
||||
tooltip?: string;
|
||||
icon?: string;
|
||||
schemaUid?: string;
|
||||
menuSchemaUid?: string;
|
||||
|
@ -50,6 +50,7 @@ import { KeepAlive } from './KeepAlive';
|
||||
import { NocoBaseDesktopRoute, NocoBaseDesktopRouteType } from './convertRoutesToSchema';
|
||||
import { MenuSchemaToolbar, ResetThemeTokenAndKeepAlgorithm } from './menuItemSettings';
|
||||
import { userCenterSettings } from './userCenterSettings';
|
||||
import { withTooltipComponent } from '../../../hoc/withTooltipComponent';
|
||||
|
||||
export { KeepAlive, NocoBaseDesktopRouteType };
|
||||
|
||||
@ -434,16 +435,26 @@ const actionsRender: any = (props) => {
|
||||
return <PinnedPluginList />;
|
||||
};
|
||||
|
||||
const MenuItemTitle: React.FC = (props) => {
|
||||
return <>{props.children}</>;
|
||||
};
|
||||
|
||||
const MenuItemTitleWithTooltip = withTooltipComponent(MenuItemTitle);
|
||||
|
||||
const menuItemRender = (item, dom, options) => {
|
||||
return (
|
||||
<MenuItem item={item} options={options}>
|
||||
{dom}
|
||||
<MenuItemTitleWithTooltip tooltip={item._route?.tooltip}>{dom}</MenuItemTitleWithTooltip>
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
const subMenuItemRender = (item, dom) => {
|
||||
return <GroupItem item={item}>{dom}</GroupItem>;
|
||||
return (
|
||||
<GroupItem item={item}>
|
||||
<MenuItemTitleWithTooltip tooltip={item._route?.tooltip}>{dom}</MenuItemTitleWithTooltip>
|
||||
</GroupItem>
|
||||
);
|
||||
};
|
||||
|
||||
const CollapsedButton: FC<{ collapsed: boolean }> = (props) => {
|
||||
@ -753,6 +764,8 @@ function convertRoutesToLayout(routes: NocoBaseDesktopRoute[], { designable, par
|
||||
name: <MenuDesignerButton testId={testId} />,
|
||||
path: '/',
|
||||
disabled: true,
|
||||
_route: {},
|
||||
_parentRoute: {},
|
||||
icon: <Icon type="setting" />,
|
||||
};
|
||||
};
|
||||
|
@ -525,6 +525,53 @@ const MoveToMenuItem = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const EditTooltip = () => {
|
||||
const { t } = useTranslation();
|
||||
const currentRoute = useCurrentRoute();
|
||||
const { updateRoute } = useNocoBaseRoutes();
|
||||
|
||||
const editTooltipSchema = useMemo(() => {
|
||||
return {
|
||||
type: 'object',
|
||||
title: t('Edit tooltip'),
|
||||
properties: {
|
||||
tooltip: {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
};
|
||||
}, [t]);
|
||||
const initialTooltipValues = useMemo(() => {
|
||||
return {
|
||||
tooltip: currentRoute.tooltip,
|
||||
};
|
||||
}, [currentRoute.tooltip]);
|
||||
|
||||
const onEditTooltipSubmit: (values: any) => void = useCallback(
|
||||
({ tooltip }) => {
|
||||
// 更新菜单对应的路由
|
||||
if (currentRoute.id !== undefined) {
|
||||
updateRoute(currentRoute.id, {
|
||||
tooltip,
|
||||
});
|
||||
}
|
||||
},
|
||||
[currentRoute.id, updateRoute],
|
||||
);
|
||||
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
title={t('Edit tooltip')}
|
||||
eventKey="edit-tooltip"
|
||||
schema={editTooltipSchema as ISchema}
|
||||
initialValues={initialTooltipValues}
|
||||
onSubmit={onEditTooltipSubmit}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const menuItemSettings = new SchemaSettings({
|
||||
name: 'menuSettings:menuItem',
|
||||
items: [
|
||||
@ -532,6 +579,10 @@ export const menuItemSettings = new SchemaSettings({
|
||||
name: 'edit',
|
||||
Component: EditMenuItem,
|
||||
},
|
||||
{
|
||||
name: 'editTooltip',
|
||||
Component: EditTooltip,
|
||||
},
|
||||
{
|
||||
name: 'hidden',
|
||||
Component: HiddenMenuItem,
|
||||
|
@ -45,6 +45,7 @@ import { useToken } from '../__builtins__';
|
||||
import { SubFormProvider, useAssociationFieldContext } from '../association-field/hooks';
|
||||
import { ColumnFieldProvider } from '../table-v2/components/ColumnFieldProvider';
|
||||
import { extractIndex, isCollectionFieldComponent, isColumnComponent } from '../table-v2/utils';
|
||||
import { withTooltipComponent } from '../../../hoc/withTooltipComponent';
|
||||
|
||||
const InViewContext = React.createContext(false);
|
||||
|
||||
@ -85,6 +86,8 @@ export const useColumnsDeepMemoized = (columns: any[]) => {
|
||||
return oldObj.value;
|
||||
};
|
||||
|
||||
const TableColumnTitle = withTooltipComponent(RecursionField);
|
||||
|
||||
const useTableColumns = (props: { showDel?: any; isSubTable?: boolean }, paginationProps) => {
|
||||
const { token } = useToken();
|
||||
const field = useArrayField(props);
|
||||
@ -112,7 +115,6 @@ const useTableColumns = (props: { showDel?: any; isSubTable?: boolean }, paginat
|
||||
}, [token.paddingContentVerticalLG, token.marginSM]);
|
||||
|
||||
const collection = useCollection();
|
||||
|
||||
const columns = useMemo(
|
||||
() =>
|
||||
columnsSchema?.map((s: Schema) => {
|
||||
@ -124,7 +126,7 @@ const useTableColumns = (props: { showDel?: any; isSubTable?: boolean }, paginat
|
||||
const dataIndex = collectionFields?.length > 0 ? collectionFields[0].name : s.name;
|
||||
const columnHidden = !!s['x-component-props']?.['columnHidden'];
|
||||
return {
|
||||
title: <RecursionField name={s.name} schema={s} onlyRenderSelf />,
|
||||
title: <TableColumnTitle name={s.name} schema={s} onlyRenderSelf tooltip={s['x-component-props']?.tooltip} />,
|
||||
dataIndex,
|
||||
key: s.name,
|
||||
sorter: s['x-component-props']?.['sorter'],
|
||||
|
@ -286,14 +286,14 @@ export const MenuDesigner = () => {
|
||||
f.dataSource =
|
||||
component === 'Menu.SubMenu'
|
||||
? [
|
||||
{ label: t('Before'), value: 'beforeBegin' },
|
||||
{ label: t('After'), value: 'afterEnd' },
|
||||
{ label: t('Inner'), value: 'beforeEnd' },
|
||||
]
|
||||
{ label: t('Before'), value: 'beforeBegin' },
|
||||
{ label: t('After'), value: 'afterEnd' },
|
||||
{ label: t('Inner'), value: 'beforeEnd' },
|
||||
]
|
||||
: [
|
||||
{ label: t('Before'), value: 'beforeBegin' },
|
||||
{ label: t('After'), value: 'afterEnd' },
|
||||
];
|
||||
{ label: t('Before'), value: 'beforeBegin' },
|
||||
{ label: t('After'), value: 'afterEnd' },
|
||||
];
|
||||
});
|
||||
});
|
||||
},
|
||||
@ -325,6 +325,24 @@ export const MenuDesigner = () => {
|
||||
icon: field.componentProps.icon,
|
||||
};
|
||||
}, [field.title, field.componentProps.icon]);
|
||||
const editTooltipSchema = useMemo(() => {
|
||||
return {
|
||||
type: 'object',
|
||||
title: t('Edit tooltip'),
|
||||
properties: {
|
||||
tooltip: {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
};
|
||||
}, [t]);
|
||||
const initialTooltipValues = useMemo(() => {
|
||||
return {
|
||||
tooltip: field.componentProps.tooltip,
|
||||
};
|
||||
}, [field.componentProps.tooltip]);
|
||||
if (fieldSchema['x-component'] === 'Menu.URL') {
|
||||
schema.properties['href'] = urlSchema;
|
||||
schema.properties['params'] = paramsSchema;
|
||||
@ -369,15 +387,26 @@ export const MenuDesigner = () => {
|
||||
options:
|
||||
href || params
|
||||
? {
|
||||
href,
|
||||
params,
|
||||
}
|
||||
href,
|
||||
params,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
},
|
||||
[fieldSchema, field, dn, refresh, onSelect],
|
||||
);
|
||||
const onEditTooltipSubmit: (values: any) => void = useCallback(
|
||||
({ tooltip }) => {
|
||||
// 更新菜单对应的路由
|
||||
if (fieldSchema['__route__']?.id) {
|
||||
updateRoute(fieldSchema['__route__'].id, {
|
||||
tooltip,
|
||||
});
|
||||
}
|
||||
},
|
||||
[fieldSchema, field, dn, refresh, onSelect],
|
||||
);
|
||||
|
||||
const modalSchema = useMemo(() => {
|
||||
return {
|
||||
@ -471,6 +500,13 @@ export const MenuDesigner = () => {
|
||||
initialValues={initialValues}
|
||||
onSubmit={onEditSubmit}
|
||||
/>
|
||||
<SchemaSettingsModalItem
|
||||
title={t('Edit tooltip')}
|
||||
eventKey="edit-tooltip"
|
||||
schema={editTooltipSchema as ISchema}
|
||||
initialValues={initialTooltipValues}
|
||||
onSubmit={onEditTooltipSubmit}
|
||||
/>
|
||||
<SchemaSettingsSwitchItem
|
||||
title={t('Hidden')}
|
||||
checked={fieldSchema['x-component-props']?.hidden}
|
||||
|
@ -40,6 +40,7 @@ import { useUpdate } from 'ahooks';
|
||||
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useRefreshComponent, useRefreshFieldSchema } from '../../../formily/NocoBaseRecursionField';
|
||||
import { NocoBaseDesktopRoute } from '../../../route-switch/antd/admin-layout/convertRoutesToSchema';
|
||||
import { withTooltipComponent } from '../../../hoc/withTooltipComponent';
|
||||
|
||||
const subMenuDesignerCss = css`
|
||||
position: relative;
|
||||
@ -96,7 +97,7 @@ const subMenuDesignerCss = css`
|
||||
const designerCss = css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
// justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
@ -203,6 +204,16 @@ type ComposedMenu = React.FC<any> & {
|
||||
Designer?: React.FC<any>;
|
||||
};
|
||||
|
||||
const MenuItemTitle: React.FC<{
|
||||
schema: any;
|
||||
style?: React.CSSProperties;
|
||||
}> = ({ schema, style }) => {
|
||||
const { t } = useMenuTranslation();
|
||||
return <span style={style}>{t(schema.title)}</span>;
|
||||
};
|
||||
|
||||
const MenuItemTitleWithTooltip = withTooltipComponent(MenuItemTitle);
|
||||
|
||||
export const ParentRouteContext = createContext<NocoBaseDesktopRoute>(null);
|
||||
ParentRouteContext.displayName = 'ParentRouteContext';
|
||||
|
||||
@ -668,8 +679,9 @@ const menuItemTitleStyle = {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
display: 'inline-block',
|
||||
width: '100%',
|
||||
// width: '100%',
|
||||
verticalAlign: 'middle',
|
||||
// marginInlineEnd: '4px',
|
||||
};
|
||||
|
||||
Menu.Item = observer(
|
||||
@ -698,7 +710,11 @@ Menu.Item = observer(
|
||||
removeParentsIfNoChildren={false}
|
||||
>
|
||||
<Icon type={icon} />
|
||||
<span style={menuItemTitleStyle}>{t(schema.title)}</span>
|
||||
<MenuItemTitleWithTooltip
|
||||
schema={schema}
|
||||
style={menuItemTitleStyle}
|
||||
tooltip={schema?.['x-component-props']?.tooltip}
|
||||
/>
|
||||
<Designer />
|
||||
</SortableItem>
|
||||
</FieldContext.Provider>
|
||||
@ -720,6 +736,7 @@ Menu.Item = observer(
|
||||
|
||||
const MenuURLButton = ({ href, params, icon }) => {
|
||||
const field = useField();
|
||||
const schema = useFieldSchema();
|
||||
const { t } = useMenuTranslation();
|
||||
const Designer = useContext(MenuItemDesignerContext);
|
||||
const { parseURLAndParams } = useParseURLAndParams();
|
||||
@ -749,17 +766,11 @@ const MenuURLButton = ({ href, params, icon }) => {
|
||||
aria-label={t(field.title)}
|
||||
>
|
||||
<Icon type={icon} />
|
||||
<span
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
display: 'inline-block',
|
||||
width: '100%',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
{t(field.title)}
|
||||
</span>
|
||||
<MenuItemTitleWithTooltip
|
||||
schema={schema}
|
||||
style={menuItemTitleStyle}
|
||||
tooltip={schema?.['x-component-props']?.tooltip}
|
||||
/>
|
||||
<Designer />
|
||||
</SortableItem>
|
||||
);
|
||||
@ -814,6 +825,7 @@ Menu.SubMenu = observer(
|
||||
const field = useField();
|
||||
const mode = useContext(MenuModeContext);
|
||||
const Designer = useContext(MenuItemDesignerContext);
|
||||
|
||||
const submenu = useMemo(() => {
|
||||
return {
|
||||
...others,
|
||||
@ -830,7 +842,11 @@ Menu.SubMenu = observer(
|
||||
aria-label={t(field.title)}
|
||||
>
|
||||
<Icon type={icon} />
|
||||
{t(field.title)}
|
||||
<MenuItemTitleWithTooltip
|
||||
schema={schema}
|
||||
style={{ marginInlineStart: 0 }}
|
||||
tooltip={schema?.['x-component-props']?.tooltip}
|
||||
/>
|
||||
<Designer />
|
||||
</SortableItem>
|
||||
</FieldContext.Provider>
|
||||
|
@ -66,6 +66,7 @@ import { useToken } from '../__builtins__';
|
||||
import { useAssociationFieldContext } from '../association-field/hooks';
|
||||
import { TableSkeleton } from './TableSkeleton';
|
||||
import { extractIndex, isCollectionFieldComponent, isColumnComponent } from './utils';
|
||||
import { withTooltipComponent } from '../../../hoc/withTooltipComponent';
|
||||
|
||||
type BodyRowComponentProps = {
|
||||
rowIndex?: number;
|
||||
@ -198,6 +199,9 @@ const useTableColumns = (
|
||||
|
||||
const collection = useCollection();
|
||||
|
||||
// 不能提取到外部,否则 NocoBaseRecursionField 的值在一开始会是 undefined。原因未知
|
||||
const TableColumnTitle = useMemo(() => withTooltipComponent(NocoBaseRecursionField), []);
|
||||
|
||||
const columns = useMemo(
|
||||
() =>
|
||||
columnsSchemas?.map((columnSchema: Schema) => {
|
||||
@ -217,11 +221,12 @@ const useTableColumns = (
|
||||
return {
|
||||
title: (
|
||||
<RefreshComponentProvider refresh={refresh}>
|
||||
<NocoBaseRecursionField
|
||||
<TableColumnTitle
|
||||
name={columnSchema.name}
|
||||
schema={columnSchema}
|
||||
onlyRenderSelf
|
||||
isUseFormilyField={false}
|
||||
tooltip={columnSchema?.['x-component-props']?.tooltip}
|
||||
/>
|
||||
</RefreshComponentProvider>
|
||||
),
|
||||
|
@ -1396,11 +1396,11 @@ export async function expectSettingsMenu({
|
||||
await page.waitForTimeout(100);
|
||||
await showMenu();
|
||||
for (const option of supportedOptions) {
|
||||
await expect(page.getByRole('menuitem', { name: option })).toBeVisible();
|
||||
await expect(page.getByRole('menuitem', { name: option, exact: option === 'Edit' })).toBeVisible();
|
||||
}
|
||||
if (unsupportedOptions) {
|
||||
for (const option of unsupportedOptions) {
|
||||
await expect(page.getByRole('menuitem', { name: option })).not.toBeVisible();
|
||||
await expect(page.getByRole('menuitem', { name: option, exact: option === 'Edit' })).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,14 @@
|
||||
|
||||
import { createForm, Form, onFormValuesChange } from '@formily/core';
|
||||
import { uid } from '@formily/shared';
|
||||
import { css, SchemaComponent, useAllAccessDesktopRoutes, useAPIClient, useCompile, useRequest } from '@nocobase/client';
|
||||
import {
|
||||
css,
|
||||
SchemaComponent,
|
||||
useAllAccessDesktopRoutes,
|
||||
useAPIClient,
|
||||
useCompile,
|
||||
useRequest,
|
||||
} from '@nocobase/client';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { Checkbox, message, Table } from 'antd';
|
||||
import { uniq } from 'lodash';
|
||||
@ -68,7 +75,8 @@ const style = css`
|
||||
|
||||
const translateTitle = (menus: any[], t, compile) => {
|
||||
return menus.map((menu) => {
|
||||
const title = (menu.title?.match(/^\s*\{\{\s*.+?\s*\}\}\s*$/) ? compile(menu.title) : t(menu.title)) || t('Unnamed');
|
||||
const title =
|
||||
(menu.title?.match(/^\s*\{\{\s*.+?\s*\}\}\s*$/) ? compile(menu.title) : t(menu.title)) || t('Unnamed');
|
||||
if (menu.children) {
|
||||
return {
|
||||
...menu,
|
||||
@ -123,7 +131,7 @@ const DesktopRoutesProvider: FC<{
|
||||
};
|
||||
|
||||
export const DesktopAllRoutesProvider: React.FC<{ active: boolean }> = ({ children, active }) => {
|
||||
const refreshRef = React.useRef(() => { });
|
||||
const refreshRef = React.useRef(() => {});
|
||||
|
||||
useEffect(() => {
|
||||
if (active) {
|
||||
|
@ -29,7 +29,7 @@ import {
|
||||
usePopupUtils,
|
||||
useProps,
|
||||
withDynamicSchemaProps,
|
||||
withSkeletonComponent
|
||||
withSkeletonComponent,
|
||||
} from '@nocobase/client';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import dayjs from 'dayjs';
|
||||
@ -75,7 +75,7 @@ const getColorString = (
|
||||
};
|
||||
|
||||
export const DeleteEventContext = React.createContext({
|
||||
close: () => { },
|
||||
close: () => {},
|
||||
allowDeleteEvent: false,
|
||||
});
|
||||
|
||||
|
@ -70,9 +70,9 @@ export class PluginCalendarClient extends Plugin {
|
||||
colorFieldInterfaces: {
|
||||
[T: string]: { useGetColor: (field: any) => ColorFunctions };
|
||||
} = {
|
||||
select: { useGetColor },
|
||||
radioGroup: { useGetColor },
|
||||
};
|
||||
select: { useGetColor },
|
||||
radioGroup: { useGetColor },
|
||||
};
|
||||
|
||||
dateTimeFieldInterfaces = ['date', 'datetime', 'dateOnly', 'datetimeNoTz', 'unixTimestamp', 'createdAt', 'updatedAt'];
|
||||
|
||||
|
@ -236,13 +236,13 @@ export const createRoutesTableSchema = (collectionName: string, basename: string
|
||||
'x-component': 'IconPicker',
|
||||
'x-reactions': isMobile
|
||||
? {
|
||||
dependencies: ['type'],
|
||||
fulfill: {
|
||||
state: {
|
||||
required: '{{$deps[0] !== "tabs"}}',
|
||||
dependencies: ['type'],
|
||||
fulfill: {
|
||||
state: {
|
||||
required: '{{$deps[0] !== "tabs"}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
// 由于历史原因,桌面端使用的是 'href' 作为 key,移动端使用的是 'url' 作为 key
|
||||
@ -574,8 +574,9 @@ export const createRoutesTableSchema = (collectionName: string, basename: string
|
||||
}
|
||||
|
||||
if (recordData.type === NocoBaseDesktopRouteType.page) {
|
||||
const path = `${basenameOfCurrentRouter.slice(0, -1)}${basename}/${isMobile ? recordData.schemaUid : recordData.menuSchemaUid
|
||||
}`;
|
||||
const path = `${basenameOfCurrentRouter.slice(0, -1)}${basename}/${
|
||||
isMobile ? recordData.schemaUid : recordData.menuSchemaUid
|
||||
}`;
|
||||
// 在点击 Access 按钮时,会用到
|
||||
recordData._path = path;
|
||||
|
||||
@ -695,13 +696,13 @@ export const createRoutesTableSchema = (collectionName: string, basename: string
|
||||
'x-component': 'IconPicker',
|
||||
'x-reactions': isMobile
|
||||
? {
|
||||
dependencies: ['type'],
|
||||
fulfill: {
|
||||
state: {
|
||||
required: '{{$deps[0] !== "tabs"}}',
|
||||
dependencies: ['type'],
|
||||
fulfill: {
|
||||
state: {
|
||||
required: '{{$deps[0] !== "tabs"}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
// 由于历史原因,桌面端使用的是 'href' 作为 key,移动端使用的是 'url' 作为 key
|
||||
@ -984,13 +985,13 @@ export const createRoutesTableSchema = (collectionName: string, basename: string
|
||||
'x-component': 'IconPicker',
|
||||
'x-reactions': isMobile
|
||||
? {
|
||||
dependencies: ['type'],
|
||||
fulfill: {
|
||||
state: {
|
||||
required: '{{$deps[0] !== "tabs"}}',
|
||||
dependencies: ['type'],
|
||||
fulfill: {
|
||||
state: {
|
||||
required: '{{$deps[0] !== "tabs"}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
// 由于历史原因,桌面端使用的是 'href' 作为 key,移动端使用的是 'url' 作为 key
|
||||
@ -1245,11 +1246,7 @@ function useCreateRouteSchema(isMobile: boolean) {
|
||||
const insertPageSchema = useInsertPageSchema();
|
||||
|
||||
const createRouteSchema = useCallback(
|
||||
async ({
|
||||
type,
|
||||
}: {
|
||||
type: NocoBaseDesktopRouteType;
|
||||
}) => {
|
||||
async ({ type }: { type: NocoBaseDesktopRouteType }) => {
|
||||
const menuSchemaUid = isMobile ? undefined : uid();
|
||||
const pageSchemaUid = uid();
|
||||
const tabSchemaName = uid();
|
||||
@ -1259,10 +1256,10 @@ function useCreateRouteSchema(isMobile: boolean) {
|
||||
[NocoBaseDesktopRouteType.page]: isMobile
|
||||
? getMobilePageSchema(pageSchemaUid, tabSchemaUid).schema
|
||||
: getPageMenuSchema({
|
||||
pageSchemaUid,
|
||||
tabSchemaUid,
|
||||
tabSchemaName,
|
||||
}),
|
||||
pageSchemaUid,
|
||||
tabSchemaUid,
|
||||
tabSchemaName,
|
||||
}),
|
||||
};
|
||||
|
||||
if (!typeToSchema[type]) {
|
||||
|
@ -205,6 +205,21 @@ export default {
|
||||
title: '{{t("Title")}}',
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'brt6tz4hgin',
|
||||
name: 'tooltip',
|
||||
type: 'string',
|
||||
interface: 'textarea',
|
||||
description: null,
|
||||
collectionName: 'desktopRoutes',
|
||||
parentKey: null,
|
||||
reverseKey: null,
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
'x-component': 'Input.TextArea',
|
||||
title: '{{t("Tooltip")}}',
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'ozl5d8t2d5e',
|
||||
name: 'icon',
|
||||
|
@ -76,7 +76,7 @@ export default class PluginWorkflowClient extends Plugin {
|
||||
return this.triggers.get(workflow.type)?.sync ?? workflow.sync;
|
||||
}
|
||||
|
||||
registerTrigger(type: string, trigger: Trigger | { new(): Trigger }) {
|
||||
registerTrigger(type: string, trigger: Trigger | { new (): Trigger }) {
|
||||
if (typeof trigger === 'function') {
|
||||
this.triggers.register(type, new trigger());
|
||||
} else if (trigger) {
|
||||
@ -86,7 +86,7 @@ export default class PluginWorkflowClient extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
registerInstruction(type: string, instruction: Instruction | { new(): Instruction }) {
|
||||
registerInstruction(type: string, instruction: Instruction | { new (): Instruction }) {
|
||||
if (typeof instruction === 'function') {
|
||||
this.instructions.register(type, new instruction());
|
||||
} else if (instruction instanceof Instruction) {
|
||||
@ -193,4 +193,3 @@ export { default as useStyles } from './style';
|
||||
export { Trigger, useTrigger } from './triggers';
|
||||
export * from './utils';
|
||||
export * from './variable';
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user