-
-
-
-
-
- {render()}
-
-
+
+
+
+
+
+
+ {render()}
+
-
+
);
};
diff --git a/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx b/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx
index 01654a8784..05fecbda1a 100644
--- a/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx
+++ b/packages/core/client/src/schema-component/antd/page/__tests__/page.test.tsx
@@ -8,26 +8,10 @@
*/
import { DocumentTitleProvider, Form, FormItem, Grid, IconPicker, Input } from '@nocobase/client';
-import { render, renderAppOptions, screen, userEvent, waitFor } from '@nocobase/test/client';
-import React from 'react';
-import App1 from '../demos/demo1';
+import { renderAppOptions, screen, userEvent, waitFor } from '@nocobase/test/client';
import { isTabPage, navigateToTab, Page } from '../Page';
describe('Page', () => {
- it('should render correctly', async () => {
- render(
);
-
- await waitFor(() => {
- expect(screen.getByText(/page title/i)).toBeInTheDocument();
- });
- await waitFor(() => {
- expect(screen.getByText(/page content/i)).toBeInTheDocument();
- });
- await waitFor(() => {
- expect(document.title).toBe('Page Title - NocoBase');
- });
- });
-
describe('Page Component', () => {
const title = 'Test Title';
diff --git a/packages/core/client/src/schema-component/antd/page/demos/demo1.tsx b/packages/core/client/src/schema-component/antd/page/demos/demo1.tsx
deleted file mode 100644
index e947ddbc50..0000000000
--- a/packages/core/client/src/schema-component/antd/page/demos/demo1.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-import { ISchema } from '@formily/react';
-import { DocumentTitleProvider, Page, SchemaComponent, SchemaComponentProvider, Application } from '@nocobase/client';
-import React from 'react';
-
-const schema: ISchema = {
- type: 'object',
- properties: {
- page1: {
- type: 'void',
- 'x-component': 'Page',
- title: 'Page Title',
- properties: {
- content: {
- type: 'void',
- 'x-component': 'div',
- 'x-content': 'Page Content',
- },
- },
- },
- },
-};
-
-const Root = () => {
- return (
-
-
-
-
-
- );
-};
-
-const app = new Application({
- providers: [Root],
-});
-
-export default app.getRootComponent();
diff --git a/packages/core/client/src/schema-component/core/RemoteSchemaComponent.tsx b/packages/core/client/src/schema-component/core/RemoteSchemaComponent.tsx
index b42eac095c..356705c31b 100644
--- a/packages/core/client/src/schema-component/core/RemoteSchemaComponent.tsx
+++ b/packages/core/client/src/schema-component/core/RemoteSchemaComponent.tsx
@@ -84,4 +84,5 @@ const RequestSchemaComponent: React.FC
= (props) =>
export const RemoteSchemaComponent: React.FC = memo((props) => {
return props.uid ? : null;
});
+
RemoteSchemaComponent.displayName = 'RemoteSchemaComponent';
diff --git a/packages/core/client/src/schema-settings/GeneralSchemaDesigner.tsx b/packages/core/client/src/schema-settings/GeneralSchemaDesigner.tsx
index 3f41bf55ec..7ba10563d5 100644
--- a/packages/core/client/src/schema-settings/GeneralSchemaDesigner.tsx
+++ b/packages/core/client/src/schema-settings/GeneralSchemaDesigner.tsx
@@ -17,13 +17,14 @@ import React, {
FC,
startTransition,
useCallback,
+ useContext,
useEffect,
useMemo,
useRef,
useState,
- useContext,
} from 'react';
import { useTranslation } from 'react-i18next';
+import { SchemaComponentContext } from '../';
import { SchemaInitializer, SchemaSettings, SchemaToolbarProvider, useSchemaInitializerRender } from '../application';
import { useSchemaSettingsRender } from '../application/schema-settings/hooks/useSchemaSettingsRender';
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
@@ -33,7 +34,6 @@ import { DragHandler, useCompile, useDesignable, useGridContext, useGridRowConte
import { gridRowColWrap } from '../schema-initializer/utils';
import { SchemaSettingsDropdown } from './SchemaSettings';
import { useGetAriaLabelOfDesigner } from './hooks/useGetAriaLabelOfDesigner';
-import { SchemaComponentContext } from '../';
import { useStyles } from './styles';
const titleCss = css`
@@ -208,6 +208,11 @@ export interface SchemaToolbarProps {
spaceWrapperStyle?: React.CSSProperties;
spaceClassName?: string;
spaceStyle?: React.CSSProperties;
+ /**
+ * The HTML element that listens for mouse enter/leave events.
+ * Parent element is used by default.
+ */
+ container?: HTMLElement;
onVisibleChange?: (nextVisible: boolean) => void;
}
@@ -226,6 +231,7 @@ const InternalSchemaToolbar: FC = React.memo((props) => {
spaceStyle,
toolbarClassName,
toolbarStyle = {},
+ container,
} = {
...props,
...(fieldSchema?.['x-toolbar-props'] || {}),
@@ -312,7 +318,10 @@ const InternalSchemaToolbar: FC = React.memo((props) => {
while (parentElement && parentElement.clientHeight === 0) {
parentElement = parentElement.parentElement;
}
- if (!parentElement) {
+
+ const el = container || parentElement;
+
+ if (!el) {
return;
}
@@ -330,18 +339,18 @@ const InternalSchemaToolbar: FC = React.memo((props) => {
}
}
- const style = window.getComputedStyle(parentElement);
- if (style.position === 'static') {
- parentElement.style.position = 'relative';
- }
+ // const style = window.getComputedStyle(parentElement);
+ // if (style.position === 'static') {
+ // parentElement.style.position = 'relative';
+ // }
- parentElement.addEventListener('mouseenter', show);
- parentElement.addEventListener('mouseleave', hide);
+ el.addEventListener('mouseenter', show);
+ el.addEventListener('mouseleave', hide);
return () => {
- parentElement.removeEventListener('mouseenter', show);
- parentElement.removeEventListener('mouseleave', hide);
+ el.removeEventListener('mouseenter', show);
+ el.removeEventListener('mouseleave', hide);
};
- }, [props.onVisibleChange]);
+ }, [props.onVisibleChange, container]);
const containerStyle = useMemo(
() => ({
diff --git a/packages/core/client/src/schema-settings/hooks/useGetAriaLabelOfDesigner.ts b/packages/core/client/src/schema-settings/hooks/useGetAriaLabelOfDesigner.ts
index bcb54d9e51..a0cdc9d51d 100644
--- a/packages/core/client/src/schema-settings/hooks/useGetAriaLabelOfDesigner.ts
+++ b/packages/core/client/src/schema-settings/hooks/useGetAriaLabelOfDesigner.ts
@@ -20,7 +20,7 @@ export const useGetAriaLabelOfDesigner = () => {
const { name: _collectionName } = useCollection_deprecated();
const getAriaLabel = useCallback(
(name: string, postfix?: string) => {
- if (!fieldSchema) return '';
+ if (!fieldSchema) return `designer-${name}-${postfix}`;
const component = fieldSchema['x-component'];
const componentName = typeof component === 'string' ? component : component?.displayName || component?.name;
diff --git a/packages/core/test/src/e2e/e2eUtils.ts b/packages/core/test/src/e2e/e2eUtils.ts
index f3a46dd8ce..0f2a11c16d 100644
--- a/packages/core/test/src/e2e/e2eUtils.ts
+++ b/packages/core/test/src/e2e/e2eUtils.ts
@@ -13,6 +13,24 @@ import { Browser, Page, test as base, expect, request } from '@playwright/test';
import _ from 'lodash';
import { defineConfig } from './defineConfig';
+function getPageMenuSchema({ pageSchemaUid, tabSchemaUid, tabSchemaName }) {
+ return {
+ type: 'void',
+ 'x-component': 'Page',
+ properties: {
+ [tabSchemaName]: {
+ type: 'void',
+ 'x-component': 'Grid',
+ 'x-initializer': 'page:addBlock',
+ properties: {},
+ 'x-uid': tabSchemaUid,
+ 'x-async': true,
+ },
+ },
+ 'x-uid': pageSchemaUid,
+ };
+}
+
export * from '@playwright/test';
export { defineConfig };
@@ -360,7 +378,7 @@ export class NocoPage {
this.uid = schemaUid;
this.desktopRouteId = routeId;
- this.url = `${this.options?.basePath || '/admin/'}${this.uid}`;
+ this.url = `${this.options?.basePath || '/admin/'}${this.uid || this.desktopRouteId}`;
}
async goto() {
@@ -393,7 +411,7 @@ export class NocoPage {
async destroy() {
const waitList: any[] = [];
- if (this.uid) {
+ if (this.uid || this.desktopRouteId !== undefined) {
waitList.push(deletePage(this.uid, this.desktopRouteId));
this.uid = undefined;
this.desktopRouteId = undefined;
@@ -723,30 +741,15 @@ const createPage = async (options?: CreatePageOptions) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
- const typeToSchema = {
- group: {
- 'x-component': 'Menu.SubMenu',
- 'x-component-props': {},
- },
- page: {
- 'x-component': 'Menu.Item',
- 'x-component-props': {},
- },
- link: {
- 'x-component': 'Menu.URL',
- 'x-component-props': {
- href: url,
- },
- },
- };
const state = await api.storageState();
const headers = getHeaders(state);
- const menuSchemaUid = pageUidFromOptions || uid();
- const pageSchemaUid = uid();
- const tabSchemaUid = uid();
- const tabSchemaName = uid();
- const title = name || menuSchemaUid;
const newPageSchema = keepUid ? pageSchema : updateUidOfPageSchema(pageSchema);
+ const pageSchemaUid = newPageSchema?.['x-uid'] || uid();
+ const newTabSchemaUid = uid();
+ const newTabSchemaName = uid();
+
+ const title = name || pageSchemaUid;
+
let routeId;
let schemaUid;
@@ -756,7 +759,6 @@ const createPage = async (options?: CreatePageOptions) => {
data: {
type: 'group',
title,
- schemaUid: menuSchemaUid,
hideInMenu: false,
},
});
@@ -767,17 +769,15 @@ const createPage = async (options?: CreatePageOptions) => {
const data = await result.json();
routeId = data.data?.id;
- schemaUid = menuSchemaUid;
}
if (type === 'page') {
- const result = await api.post('/api/desktopRoutes:create', {
+ const routeResult = await api.post('/api/desktopRoutes:create', {
headers,
data: {
type: 'page',
title,
- schemaUid: newPageSchema?.['x-uid'] || pageSchemaUid,
- menuSchemaUid,
+ schemaUid: pageSchemaUid,
hideInMenu: false,
enableTabs: !!newPageSchema?.['x-component-props']?.enablePageTabs,
children: newPageSchema
@@ -786,21 +786,36 @@ const createPage = async (options?: CreatePageOptions) => {
{
type: 'tabs',
title: '{{t("Unnamed")}}',
- schemaUid: tabSchemaUid,
- tabSchemaName,
+ schemaUid: newTabSchemaUid,
+ tabSchemaName: newTabSchemaName,
hideInMenu: false,
},
],
},
});
- if (!result.ok()) {
- throw new Error(await result.text());
+ if (!routeResult.ok()) {
+ throw new Error(await routeResult.text());
}
- const data = await result.json();
+ const schemaResult = await api.post(`/api/uiSchemas:insert`, {
+ headers,
+ data:
+ newPageSchema ||
+ getPageMenuSchema({
+ pageSchemaUid,
+ tabSchemaUid: newTabSchemaUid,
+ tabSchemaName: newTabSchemaName,
+ }),
+ });
+
+ if (!schemaResult.ok()) {
+ throw new Error(await routeResult.text());
+ }
+
+ const data = await routeResult.json();
routeId = data.data?.id;
- schemaUid = menuSchemaUid;
+ schemaUid = pageSchemaUid;
}
if (type === 'link') {
@@ -809,7 +824,6 @@ const createPage = async (options?: CreatePageOptions) => {
data: {
type: 'link',
title,
- schemaUid: menuSchemaUid,
hideInMenu: false,
options: {
href: url,
@@ -823,50 +837,6 @@ const createPage = async (options?: CreatePageOptions) => {
const data = await result.json();
routeId = data.data?.id;
- schemaUid = menuSchemaUid;
- }
-
- const result = await api.post(`/api/uiSchemas:insertAdjacent/nocobase-admin-menu?position=beforeEnd`, {
- headers,
- data: {
- schema: {
- _isJSONSchemaObject: true,
- version: '2.0',
- type: 'void',
- title,
- ...typeToSchema[type],
- 'x-decorator': 'ACLMenuItemProvider',
- properties: {
- page: newPageSchema || {
- _isJSONSchemaObject: true,
- version: '2.0',
- type: 'void',
- 'x-component': 'Page',
- 'x-async': true,
- properties: {
- [tabSchemaName]: {
- _isJSONSchemaObject: true,
- version: '2.0',
- type: 'void',
- 'x-component': 'Grid',
- 'x-initializer': 'page:addBlock',
- 'x-uid': tabSchemaUid,
- name: tabSchemaName,
- },
- },
- 'x-uid': pageSchemaUid,
- name: 'page',
- },
- },
- name: uid(),
- 'x-uid': menuSchemaUid,
- },
- wrap: null,
- },
- });
-
- if (!result.ok()) {
- throw new Error(await result.text());
}
return { schemaUid, routeId };
@@ -1063,7 +1033,7 @@ const deleteMobileRoutes = async (mobileRouteId: number) => {
};
/**
- * 根据页面 uid 删除一个 NocoBase 的页面
+ * 根据页面 uid 删除一个页面的 schema,根据页面路由的 id 删除一个页面的路由
*/
const deletePage = async (pageUid: string, routeId: number) => {
const api = await request.newContext({
@@ -1083,12 +1053,14 @@ const deletePage = async (pageUid: string, routeId: number) => {
}
}
- const result = await api.post(`/api/uiSchemas:remove/${pageUid}`, {
- headers,
- });
+ if (pageUid) {
+ const result = await api.post(`/api/uiSchemas:remove/${pageUid}`, {
+ headers,
+ });
- if (!result.ok()) {
- throw new Error(await result.text());
+ if (!result.ok()) {
+ throw new Error(await result.text());
+ }
}
};
diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts
index b4fe1bf717..e204788c54 100644
--- a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts
+++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts
@@ -8,7 +8,6 @@
*/
import { expect, test } from '@nocobase/test/e2e';
-import { oneTableBlock } from './utils';
test('allows to configure interface', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
@@ -121,13 +120,13 @@ test('new menu items allow to be asscessed by default ', async ({ page, mockPage
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
- await mockPage({ ...oneTableBlock, name: 'new page' }).goto();
+ await mockPage({ name: 'new page' }).goto();
await expect(page.getByLabel('new page')).not.toBeVisible();
await updateRole({
name: roleData.name,
allowNewMenu: true,
});
- await mockPage({ ...oneTableBlock, name: 'new page' }).goto();
+ await mockPage({ name: 'new page' }).goto();
await expect(page.getByLabel('new page')).toBeVisible();
});
diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/permissions/MenuPermissions.tsx b/packages/plugins/@nocobase/plugin-acl/src/client/permissions/MenuPermissions.tsx
index 2a1fdecd0d..2aebfaf4b6 100644
--- a/packages/plugins/@nocobase/plugin-acl/src/client/permissions/MenuPermissions.tsx
+++ b/packages/plugins/@nocobase/plugin-acl/src/client/permissions/MenuPermissions.tsx
@@ -9,7 +9,7 @@
import { createForm, Form, onFormValuesChange } from '@formily/core';
import { uid } from '@formily/shared';
-import { css, SchemaComponent, 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 +68,7 @@ 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);
+ const title = (menu.title?.match(/^\s*\{\{\s*.+?\s*\}\}\s*$/) ? compile(menu.title) : t(menu.title)) || t('Unnamed');
if (menu.children) {
return {
...menu,
@@ -123,7 +123,7 @@ const DesktopRoutesProvider: FC<{
};
export const DesktopAllRoutesProvider: React.FC<{ active: boolean }> = ({ children, active }) => {
- const refreshRef = React.useRef(() => {});
+ const refreshRef = React.useRef(() => { });
useEffect(() => {
if (active) {
@@ -166,6 +166,7 @@ export const MenuPermissions: React.FC<{
);
const resource = api.resource('roles.desktopRoutes', role.name);
const allChecked = allIDList.length === IDList.length;
+ const { refresh: refreshDesktopRoutes } = useAllAccessDesktopRoutes();
const handleChange = async (checked, menuItem) => {
// 处理取消选中
@@ -214,6 +215,7 @@ export const MenuPermissions: React.FC<{
values: shouldAdd,
});
}
+ refreshDesktopRoutes();
message.success(t('Saved successfully'));
};
@@ -288,6 +290,7 @@ export const MenuPermissions: React.FC<{
});
}
refresh();
+ refreshDesktopRoutes();
message.success(t('Saved successfully'));
}}
/>{' '}
diff --git a/packages/plugins/@nocobase/plugin-action-print/src/client/__e2e__/utils.ts b/packages/plugins/@nocobase/plugin-action-print/src/client/__e2e__/utils.ts
index 27faa3662d..0eced99eeb 100644
--- a/packages/plugins/@nocobase/plugin-action-print/src/client/__e2e__/utils.ts
+++ b/packages/plugins/@nocobase/plugin-action-print/src/client/__e2e__/utils.ts
@@ -382,8 +382,11 @@ export const oneTableWithViewAction: PageConfig = {
'x-index': 1,
},
},
+ 'x-uid': 'j0k2m5r9z3b',
+ 'x-async': false,
},
},
+ 'x-uid': 'l6ioayfnq6c',
},
};
diff --git a/packages/plugins/@nocobase/plugin-calendar/src/client/calendar/Calendar.tsx b/packages/plugins/@nocobase/plugin-calendar/src/client/calendar/Calendar.tsx
index f012dbc4d5..653ffc6219 100644
--- a/packages/plugins/@nocobase/plugin-calendar/src/client/calendar/Calendar.tsx
+++ b/packages/plugins/@nocobase/plugin-calendar/src/client/calendar/Calendar.tsx
@@ -20,6 +20,7 @@ import {
handleDateChangeOnForm,
useACLRoleContext,
useActionContext,
+ useApp,
useCollection,
useCollectionParentRecordData,
useDesignable,
@@ -27,10 +28,8 @@ import {
useLazy,
usePopupUtils,
useProps,
- useToken,
withDynamicSchemaProps,
- withSkeletonComponent,
- useApp,
+ withSkeletonComponent
} from '@nocobase/client';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
@@ -76,7 +75,7 @@ const getColorString = (
};
export const DeleteEventContext = React.createContext({
- close: () => {},
+ close: () => { },
allowDeleteEvent: false,
});
diff --git a/packages/plugins/@nocobase/plugin-calendar/src/client/index.tsx b/packages/plugins/@nocobase/plugin-calendar/src/client/index.tsx
index f6ed96abb9..7ad775475f 100644
--- a/packages/plugins/@nocobase/plugin-calendar/src/client/index.tsx
+++ b/packages/plugins/@nocobase/plugin-calendar/src/client/index.tsx
@@ -6,8 +6,8 @@
* 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 { Plugin, useToken } from '@nocobase/client';
+import React from 'react';
import { generateNTemplate } from '../locale';
import { CalendarV2 } from './calendar';
import { calendarBlockSettings } from './calendar/Calender.Settings';
@@ -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'];
diff --git a/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx b/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx
index 6c2ed43808..c261329184 100644
--- a/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx
+++ b/packages/plugins/@nocobase/plugin-client/src/client/routesTableSchema.tsx
@@ -13,8 +13,6 @@ import { useField, useForm } from '@formily/react';
import {
CollectionField,
css,
- getGroupMenuSchema,
- getLinkMenuSchema,
getPageMenuSchema,
getTabSchema,
getVariableComponentWithScope,
@@ -26,6 +24,7 @@ import {
useCollectionRecordData,
useDataBlockRequestData,
useDataBlockRequestGetter,
+ useInsertPageSchema,
useNocoBaseRoutes,
useRequest,
useRouterBasename,
@@ -237,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
@@ -575,9 +574,8 @@ 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;
@@ -697,13 +695,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
@@ -986,13 +984,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
@@ -1244,22 +1242,15 @@ function useCreateRouteSchema(isMobile: boolean) {
const collectionName = 'uiSchemas';
const api = useAPIClient();
const resource = useMemo(() => api.resource(collectionName), [api, collectionName]);
+ const insertPageSchema = useInsertPageSchema();
const createRouteSchema = useCallback(
async ({
- title,
- icon,
type,
- href,
- params,
}: {
- title: string;
- icon: string;
type: NocoBaseDesktopRouteType;
- href?: string;
- params?: Record;
}) => {
- const menuSchemaUid = uid();
+ const menuSchemaUid = isMobile ? undefined : uid();
const pageSchemaUid = uid();
const tabSchemaName = uid();
const tabSchemaUid = type === NocoBaseDesktopRouteType.page ? uid() : undefined;
@@ -1268,17 +1259,16 @@ function useCreateRouteSchema(isMobile: boolean) {
[NocoBaseDesktopRouteType.page]: isMobile
? getMobilePageSchema(pageSchemaUid, tabSchemaUid).schema
: getPageMenuSchema({
- title,
- icon,
- pageSchemaUid,
- tabSchemaUid,
- menuSchemaUid,
- tabSchemaName,
- }),
- [NocoBaseDesktopRouteType.group]: getGroupMenuSchema({ title, icon, schemaUid: menuSchemaUid }),
- [NocoBaseDesktopRouteType.link]: getLinkMenuSchema({ title, icon, schemaUid: menuSchemaUid, href, params }),
+ pageSchemaUid,
+ tabSchemaUid,
+ tabSchemaName,
+ }),
};
+ if (!typeToSchema[type]) {
+ return {};
+ }
+
if (isMobile) {
await resource['insertAdjacent']({
resourceIndex: 'mobile',
@@ -1288,17 +1278,12 @@ function useCreateRouteSchema(isMobile: boolean) {
},
});
} else {
- await resource['insertAdjacent/nocobase-admin-menu']({
- position: 'beforeEnd',
- values: {
- schema: typeToSchema[type],
- },
- });
+ await insertPageSchema(typeToSchema[type]);
}
return { menuSchemaUid, pageSchemaUid, tabSchemaUid, tabSchemaName };
},
- [isMobile, resource],
+ [isMobile, resource, insertPageSchema],
);
/**
diff --git a/packages/plugins/@nocobase/plugin-client/src/server/server.ts b/packages/plugins/@nocobase/plugin-client/src/server/server.ts
index c114001b5a..eb6b8ac748 100644
--- a/packages/plugins/@nocobase/plugin-client/src/server/server.ts
+++ b/packages/plugins/@nocobase/plugin-client/src/server/server.ts
@@ -8,14 +8,14 @@
*/
import { Model } from '@nocobase/database';
+import PluginLocalizationServer from '@nocobase/plugin-localization';
import { Plugin } from '@nocobase/server';
+import { tval } from '@nocobase/utils';
import * as process from 'node:process';
import { resolve } from 'path';
import { getAntdLocale } from './antd';
import { getCronLocale } from './cron';
import { getCronstrueLocale } from './cronstrue';
-import PluginLocalizationServer from '@nocobase/plugin-localization';
-import { tval } from '@nocobase/utils';
async function getLang(ctx) {
const SystemSetting = ctx.db.getRepository('systemSettings');
@@ -33,7 +33,7 @@ async function getLang(ctx) {
}
export class PluginClientServer extends Plugin {
- async beforeLoad() {}
+ async beforeLoad() { }
async install() {
const uiSchemas = this.db.getRepository('uiSchemas');
@@ -218,8 +218,6 @@ export class PluginClientServer extends Plugin {
const desktopRoutesId = role
.get('desktopRoutes')
- // hidden 为 true 的节点不会显示在权限配置表格中,所以无法被配置,需要被过滤掉
- .filter((item) => !item.hidden)
.map((item) => item.id);
ctx.body = await desktopRoutesRepository.find({
diff --git a/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/navigation-bar/actions/mobile-navigation-bar-action/styles.ts b/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/navigation-bar/actions/mobile-navigation-bar-action/styles.ts
index a506df1fad..06751439b7 100644
--- a/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/navigation-bar/actions/mobile-navigation-bar-action/styles.ts
+++ b/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/navigation-bar/actions/mobile-navigation-bar-action/styles.ts
@@ -29,25 +29,15 @@ export const useStyles = genStyleHook('nb-mobile-navigation-bar-action', (token)
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
-
- '.schema-toolbar': {
- inset: '-15px -8px',
- },
},
'.nb-navigation-bar-action-title': {
fontSize: 17,
padding: 0,
- '.schema-toolbar': {
- inset: '-15px -8px',
- },
},
'.nb-navigation-bar-action-icon-and-title': {
height: '32px !important',
fontSize: '17px !important',
padding: '0 6px !important',
- '.schema-toolbar': {
- inset: '-15px',
- },
},
},
};
diff --git a/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/settings.tsx b/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/settings.tsx
index 9f6fa411f6..299fcf3aeb 100644
--- a/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/settings.tsx
+++ b/packages/plugins/@nocobase/plugin-mobile/src/client/pages/dynamic-page/header/tabs/settings.tsx
@@ -7,20 +7,20 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
-import React, { FC } from 'react';
-import { App } from 'antd';
-import { useNavigate } from 'react-router-dom';
import {
- SchemaSettings,
- SchemaToolbar,
- useSchemaToolbar,
- SchemaToolbarProvider,
createTextSettingsItem,
+ SchemaSettings,
SchemaSettingsItemType,
+ SchemaToolbar,
+ SchemaToolbarProvider,
+ useSchemaToolbar,
} from '@nocobase/client';
+import { App } from 'antd';
+import React, { FC } from 'react';
+import { useNavigate } from 'react-router-dom';
-import { MobileRouteItem, useMobileRoutes } from '../../../../mobile-providers';
import { generatePluginTranslationTemplate, usePluginTranslation } from '../../../../locale';
+import { MobileRouteItem, useMobileRoutes } from '../../../../mobile-providers';
const remove = createTextSettingsItem({
name: 'remove',
@@ -118,7 +118,7 @@ export const MobilePageTabsSettings: FC = ({ tab })
settings={mobilePageTabsSettings}
showBackground
showBorder={false}
- toolbarStyle={{ inset: '-15px -12px' }}
+ toolbarStyle={{ inset: '0 -12px' }}
spaceWrapperStyle={{ top: 3 }}
/>
diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/index.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/index.tsx
index b51e3afab7..2fb72f3640 100644
--- a/packages/plugins/@nocobase/plugin-workflow/src/client/index.tsx
+++ b/packages/plugins/@nocobase/plugin-workflow/src/client/index.tsx
@@ -18,22 +18,22 @@ const { ExecutionPage } = lazy(() => import('./ExecutionPage'), 'ExecutionPage')
const { WorkflowPage } = lazy(() => import('./WorkflowPage'), 'WorkflowPage');
const { WorkflowPane } = lazy(() => import('./WorkflowPane'), 'WorkflowPane');
-import { Trigger } from './triggers';
-import CollectionTrigger from './triggers/collection';
-import ScheduleTrigger from './triggers/schedule';
+import { NAMESPACE } from './locale';
import { Instruction } from './nodes';
import CalculationInstruction from './nodes/calculation';
import ConditionInstruction from './nodes/condition';
+import CreateInstruction from './nodes/create';
+import DestroyInstruction from './nodes/destroy';
import EndInstruction from './nodes/end';
import QueryInstruction from './nodes/query';
-import CreateInstruction from './nodes/create';
import UpdateInstruction from './nodes/update';
-import DestroyInstruction from './nodes/destroy';
-import { getWorkflowDetailPath, getWorkflowExecutionsPath } from './utils';
-import { lang, NAMESPACE } from './locale';
-import { VariableOption } from './variable';
-import { WorkflowTasks, TasksProvider, TaskTypeOptions } from './WorkflowTasks';
import { BindWorkflowConfig } from './settings/BindWorkflowConfig';
+import { Trigger } from './triggers';
+import CollectionTrigger from './triggers/collection';
+import ScheduleTrigger from './triggers/schedule';
+import { getWorkflowDetailPath, getWorkflowExecutionsPath } from './utils';
+import { VariableOption } from './variable';
+import { TasksProvider, TaskTypeOptions, WorkflowTasks } from './WorkflowTasks';
const workflowConfigSettings = {
Component: BindWorkflowConfig,
@@ -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) {
@@ -182,15 +182,15 @@ export default class PluginWorkflowClient extends Plugin {
}
export * from './Branch';
-export * from './FlowContext';
-export * from './constants';
-export * from './nodes';
-export { Trigger, useTrigger } from './triggers';
-export * from './variable';
export * from './components';
-export * from './utils';
-export * from './hooks';
-export { default as useStyles } from './style';
-export * from './variable';
+export * from './constants';
export * from './ExecutionContextProvider';
+export * from './FlowContext';
+export * from './hooks';
+export * from './nodes';
export * from './settings/BindWorkflowConfig';
+export { default as useStyles } from './style';
+export { Trigger, useTrigger } from './triggers';
+export * from './utils';
+export * from './variable';
+