diff --git a/.dumirc.ts b/.dumirc.ts index 71453f5951..eeb0d14d71 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -46,8 +46,8 @@ export default defineConfig({ github: 'https://github.com/nocobase/nocobase', footer: 'nocobase | Copyright © 2022', localesEnhance: [ - { id: 'zh-CN', switchPrefix: '中' }, - { id: 'en-US', switchPrefix: 'en' } + { id: 'zh-CN', switchPrefix: '中', hostname: 'docs-cn.nocobase.com' }, + { id: 'en-US', switchPrefix: 'en', hostname: 'docs.nocobase.com' } ], }), // mfsu: true, // 报错 diff --git a/deploy-docs-cn.sh b/deploy-docs-cn.sh new file mode 100755 index 0000000000..66a9021728 --- /dev/null +++ b/deploy-docs-cn.sh @@ -0,0 +1,9 @@ +cd docs/dist/zh-CN +echo "docs-cn.nocobase.com" >> CNAME +echo "" >> .nojekyll +git init +git remote add origin git@github.com:nocobase/docs-cn.nocobase.com.git +git branch -M main +git add . +git commit -m "first commit" +git push -f origin main diff --git a/deploy-docs.sh b/deploy-docs.sh new file mode 100755 index 0000000000..913028eabe --- /dev/null +++ b/deploy-docs.sh @@ -0,0 +1,9 @@ +cd docs/dist/en-US +echo "docs.nocobase.com" >> CNAME +echo "" >> .nojekyll +git init +git remote add origin git@github.com:nocobase/docs.nocobase.com.git +git branch -M main +git add . +git commit -m "first commit" +git push -f origin main diff --git a/docs/config.ts b/docs/config.ts index 47527f5b57..c0867ad3b4 100644 --- a/docs/config.ts +++ b/docs/config.ts @@ -285,23 +285,17 @@ const sidebar = { }, ], }, - '/api/cli', - '/api/actions', - '/api/sdk', { title: '@nocobase/cli', - path: '/api/cli', - type: 'item', + link: '/api/cli', }, { title: '@nocobase/actions', - path: '/api/actions', - type: 'item', + link: '/api/actions', }, { title: '@nocobase/sdk', - path: '/api/sdk', - type: 'item', + link: '/api/sdk', }, ], }; diff --git a/docs/en-US/api/cli.md b/docs/en-US/api/cli.md index 39be52aef4..a96084f02d 100644 --- a/docs/en-US/api/cli.md +++ b/docs/en-US/api/cli.md @@ -1,4 +1,4 @@ -# NocoBase CLI +# @nocobase/cli The NocoBase CLI is designed to help you develop, build, and deploy NocoBase applications. diff --git a/docs/en-US/welcome/getting-started/upgrading/git-clone.md b/docs/en-US/welcome/getting-started/upgrading/git-clone.md index 3eb0aa0279..732f8a1116 100644 --- a/docs/en-US/welcome/getting-started/upgrading/git-clone.md +++ b/docs/en-US/welcome/getting-started/upgrading/git-clone.md @@ -17,11 +17,11 @@ git pull v0.10 进行了依赖的重大升级,如果 v0.9 升级 v0.10,需要删掉以下目录之后再升级 ```bash -# 删除 .umi 相关缓存 -yarn rimraf -rf ./**/{.umi,.umi-production} -# 删除编译文件 -yarn rimraf -rf packages/*/*/{lib,esm,es,dist,node_modules} -# 删除全部依赖 +# Remove .umi cache +yarn rimraf -rf "./**/{.umi,.umi-production}" +# Delete compiled files +yarn rimraf -rf "./packages/*/*/{lib,esm,es,dist,node_modules}" +# Remove dependencies yarn rimraf -rf node_modules ``` diff --git a/docs/en-US/welcome/release/v10-changelog.md b/docs/en-US/welcome/release/v10-changelog.md index 2dbbcebb15..c05f3f1da7 100644 --- a/docs/en-US/welcome/release/v10-changelog.md +++ b/docs/en-US/welcome/release/v10-changelog.md @@ -44,7 +44,7 @@ No change, upgrade reference [Upgrading for Docker compose](/welcome/getting-sta v0.10 has a major upgrade of dependencies, so to prevent errors when upgrading the source code, you need to delete the following directories before upgrading ```bash -### Remove .umi-related cache +# Remove .umi cache yarn rimraf -rf "./**/{.umi,.umi-production}" # Delete compiled files yarn rimraf -rf "./packages/*/*/{lib,esm,es,dist,node_modules}" diff --git a/docs/zh-CN/welcome/getting-started/upgrading/git-clone.md b/docs/zh-CN/welcome/getting-started/upgrading/git-clone.md index 093a15ea66..e1dd0258cf 100644 --- a/docs/zh-CN/welcome/getting-started/upgrading/git-clone.md +++ b/docs/zh-CN/welcome/getting-started/upgrading/git-clone.md @@ -18,9 +18,9 @@ v0.10 进行了依赖的重大升级,如果 v0.9 升级 v0.10,需要删掉 ```bash # 删除 .umi 相关缓存 -yarn rimraf -rf ./**/{.umi,.umi-production} +yarn rimraf -rf "./**/{.umi,.umi-production}" # 删除编译文件 -yarn rimraf -rf packages/*/*/{lib,esm,es,dist,node_modules} +yarn rimraf -rf "./packages/*/*/{lib,esm,es,dist,node_modules}" # 删除全部依赖 yarn rimraf -rf node_modules ``` diff --git a/package.json b/package.json index e4a812d9ea..0e405358ce 100644 --- a/package.json +++ b/package.json @@ -57,13 +57,13 @@ "@vitejs/plugin-react": "^4.0.0", "auto-changelog": "^2.4.0", "dumi": "^2.2.0", - "dumi-theme-nocobase": "^0.2.11", + "dumi-theme-nocobase": "^0.2.12", "ghooks": "^2.0.4", "jsdom-worker": "^0.3.0", "prettier": "^2.2.1", "pretty-format": "^24.0.0", "pretty-quick": "^3.1.0", - "vite": "^4.3.8", + "vite": "^4.3.9", "vitest": "^0.32.0" }, "volta": { diff --git a/packages/core/cli/package.json b/packages/core/cli/package.json index 1f4852b740..b7d9970cee 100644 --- a/packages/core/cli/package.json +++ b/packages/core/cli/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@types/fs-extra": "^11.0.1", + "@umijs/utils": "3.5.20", "chalk": "^4.1.1", "commander": "^9.2.0", "dotenv": "^10.0.0", diff --git a/packages/core/cli/templates/plugin/src/client/index.tsx b/packages/core/cli/templates/plugin/src/client/index.tsx index c04046c360..e99af76e10 100644 --- a/packages/core/cli/templates/plugin/src/client/index.tsx +++ b/packages/core/cli/templates/plugin/src/client/index.tsx @@ -1,8 +1,8 @@ import React from 'react'; -const CommonMemo = React.memo((props) => { +const MyProvider = React.memo((props) => { return <>{props.children}; }); -CommonMemo.displayName = 'CommonMemo'; +MyProvider.displayName = 'MyProvider'; -export default CommonMemo; +export default MyProvider; diff --git a/packages/core/client/package.json b/packages/core/client/package.json index b5e529091e..32403c4fee 100644 --- a/packages/core/client/package.json +++ b/packages/core/client/package.json @@ -7,12 +7,13 @@ "typings": "es/index.d.ts", "dependencies": { "@antv/g2plot": "^2.4.18", + "@ant-design/pro-layout": "^7.14.3", "@dnd-kit/core": "^5.0.1", "@dnd-kit/sortable": "^6.0.0", "@emotion/css": "^11.7.1", - "@formily/antd": "2.2.24", - "@formily/core": "2.2.24", - "@formily/react": "2.2.24", + "@formily/antd": "2.2.26", + "@formily/core": "2.2.26", + "@formily/react": "2.2.26", "@nocobase/evaluators": "0.10.0-alpha.2", "@nocobase/sdk": "0.10.0-alpha.2", "@nocobase/utils": "0.10.0-alpha.2", diff --git a/packages/core/client/src/acl/Configuration/MenuItemsProvider.tsx b/packages/core/client/src/acl/Configuration/MenuItemsProvider.tsx index 7e79aed15d..fedadb2a1c 100644 --- a/packages/core/client/src/acl/Configuration/MenuItemsProvider.tsx +++ b/packages/core/client/src/acl/Configuration/MenuItemsProvider.tsx @@ -1,7 +1,7 @@ import { Spin } from 'antd'; import React, { createContext, useContext } from 'react'; -import { useRequest, useAPIClient } from '../../api-client'; -import { useRoute } from '../../route-switch'; +import { useRequest } from '../../api-client'; +import { useAdminSchemaUid } from '../../hooks'; const MenuItemsContext = createContext(null); @@ -28,9 +28,9 @@ export const useMenuItems = () => { }; export const MenuItemsProvider = (props) => { - const route = useRoute(); + const adminSchemaUid = useAdminSchemaUid(); const options = { - url: `uiSchemas:getProperties/${route.uiSchemaUid}`, + url: `uiSchemas:getProperties/${adminSchemaUid}`, }; const service = useRequest(options); if (service.loading) { diff --git a/packages/core/client/src/application/Application.tsx b/packages/core/client/src/application/Application.tsx index d2b2c606e5..948fde00c8 100644 --- a/packages/core/client/src/application/Application.tsx +++ b/packages/core/client/src/application/Application.tsx @@ -7,6 +7,8 @@ import { Link, NavLink } from 'react-router-dom'; import { ACLProvider } from '../acl'; import { AntdConfigProvider } from '../antd-config-provider'; import { APIClient, APIClientProvider } from '../api-client'; +import { SigninPage, SignupPage } from '../auth'; +import { SigninPageExtensionProvider } from '../auth/SigninPageExtension'; import { BlockSchemaComponentProvider } from '../block-provider'; import { RemoteDocumentTitleProvider } from '../document-title'; import { i18n } from '../i18n'; @@ -30,8 +32,6 @@ import { ErrorFallback } from '../schema-component/antd/error-fallback'; import { SchemaInitializerProvider } from '../schema-initializer'; import { BlockTemplateDetails, BlockTemplatePage } from '../schema-templates'; import { SystemSettingsProvider } from '../system-settings'; -import { SigninPage, SignupPage } from '../auth'; -import { SigninPageExtensionProvider } from '../auth/SigninPageExtension'; import { compose } from './compose'; export interface ApplicationOptions { @@ -52,9 +52,7 @@ export type PluginCallback = () => Promise; const App = React.memo((props: any) => { const C = compose(...props.providers)(() => { const routes = useRoutes(); - return ( - - ); + return ; }); return ; }); diff --git a/packages/core/client/src/auth/SigninPage.tsx b/packages/core/client/src/auth/SigninPage.tsx index 28c7f5cbeb..5ba7bd39a1 100644 --- a/packages/core/client/src/auth/SigninPage.tsx +++ b/packages/core/client/src/auth/SigninPage.tsx @@ -1,19 +1,19 @@ +import { css } from '@emotion/css'; +import { useForm } from '@formily/react'; import { Space, Tabs } from 'antd'; import React, { + FunctionComponent, + FunctionComponentElement, + createContext, + createElement, useCallback, useContext, - createContext, - FunctionComponent, - createElement, useState, - FunctionComponentElement, } from 'react'; -import { css } from '@emotion/css'; import { useTranslation } from 'react-i18next'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { useAPIClient, useCurrentDocumentTitle, useRequest, useViewport } from '..'; import { useSigninPageExtension } from './SigninPageExtension'; -import { useForm } from '@formily/react'; const SigninPageContext = createContext<{ [authType: string]: { @@ -132,13 +132,7 @@ export const SigninPage = () => { `} > {tabs.length > 1 ? ( - - {tabs.map((tab) => ( - - {tab.component} - - ))} - + ({ label: tab.tabTitle, key: tab.name, children: tab.component }))} /> ) : tabs.length ? (
{tabs[0].component}
) : ( diff --git a/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx b/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx index 00924a411f..9264ee0f3e 100644 --- a/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx @@ -2,9 +2,9 @@ import { DownOutlined, PlusOutlined } from '@ant-design/icons'; import { ArrayTable } from '@formily/antd'; import { ISchema, useField, useForm } from '@formily/react'; import { uid } from '@formily/shared'; -import { Button, Dropdown, Menu } from 'antd'; +import { Button, Dropdown, MenuProps } from 'antd'; import { cloneDeep } from 'lodash'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useRequest } from '../../api-client'; import { RecordProvider, useRecord } from '../../record-provider'; @@ -246,41 +246,41 @@ export const AddCollectionAction = (props) => { const [schema, setSchema] = useState({}); const compile = useCompile(); const { t } = useTranslation(); - const collectionTemplates = templateOptions(); - const items = []; - collectionTemplates.forEach((item) => { - if (item.divider) { - items.push({ - type: 'divider', - }); - } - items.push({ label: compile(item.title), key: item.name }); - }); + const collectionTemplates = useMemo(templateOptions, []); + const items = useMemo(() => { + const result = []; + collectionTemplates.forEach((item) => { + if (item.divider) { + result.push({ + type: 'divider', + }); + } + result.push({ label: compile(item.title), key: item.name }); + }); + return result; + }, [collectionTemplates]); const { state: { category }, } = useResourceActionContext(); + const menu = useMemo(() => { + return { + style: { + maxHeight: '60vh', + overflow: 'auto', + }, + onClick: (info) => { + const schema = getSchema(getTemplate(info.key), category, compile); + setSchema(schema); + setVisible(true); + }, + items, + }; + }, [category, items]); + return ( - { - const schema = getSchema(getTemplate(info.key), category, compile); - setSchema(schema); - setVisible(true); - }} - items={items} - /> - } - > + {children || ( diff --git a/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx b/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx index 8d8324569f..39eed38685 100644 --- a/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx +++ b/packages/core/client/src/collection-manager/Configuration/ConfigurationTabs.tsx @@ -11,7 +11,8 @@ import { } from '@dnd-kit/core'; import { RecursionField, observer } from '@formily/react'; import { uid } from '@formily/shared'; -import { Badge, Card, Dropdown, Menu, Modal, Tabs } from 'antd'; +import { Badge, Card, Dropdown, Modal, Tabs } from 'antd'; +import _ from 'lodash'; import React, { useContext, useState } from 'react'; import { useAPIClient } from '../../api-client'; import { SchemaComponent, SchemaComponentOptions, useCompile } from '../../schema-component'; @@ -181,28 +182,37 @@ export const ConfigurationTabs = () => { value: item.id, })); }; - const menu = (item) => ( - - - { + return { + items: [ + { + key: 'edit', + label: ( + - - remove(item.id)}> - {compile("{{t('Delete category')}}")} - - - ); + }} + /> + ), + }, + { + key: 'delete', + label: compile("{{t('Delete category')}}"), + onClick: () => remove(item.id), + }, + ], + }; + }); + return ( { type="editable-card" destroyInactiveTabPane={true} tabBarStyle={{ marginBottom: '0px' }} - > - {tabsItems.map((item) => { - return ( - - - - ) : ( - compile(item.name) - ) - } - key={item.id} - closable={item.closable} - closeIcon={ - - - - } - > + items={tabsItems.map((item) => { + return { + label: + item.id !== 'all' ? ( +
+ +
+ ) : ( + compile(item.name) + ), + key: item.id, + closable: item.closable, + closeIcon: ( + + + + ), + children: ( { -
- ); + ), + }; })} -
+ />
); }; diff --git a/packages/core/client/src/collection-manager/demos/demo5.tsx b/packages/core/client/src/collection-manager/demos/demo5.tsx index c9ef536339..5eb8d8df92 100644 --- a/packages/core/client/src/collection-manager/demos/demo5.tsx +++ b/packages/core/client/src/collection-manager/demos/demo5.tsx @@ -82,7 +82,7 @@ const FormItemInitializer = (props) => { collection.fields.push(options); form.setValuesIn(name, uid()); - const { values } = await FormDrawer('Add field', () => { + await FormDrawer('Add field', () => { return ( diff --git a/packages/core/client/src/collection-manager/hooks/useOptions.ts b/packages/core/client/src/collection-manager/hooks/useOptions.ts index d737a96021..eedaad0baf 100644 --- a/packages/core/client/src/collection-manager/hooks/useOptions.ts +++ b/packages/core/client/src/collection-manager/hooks/useOptions.ts @@ -1,45 +1,48 @@ import set from 'lodash/set'; +import { useMemo } from 'react'; import { useCollectionManager } from './useCollectionManager'; export const useOptions = () => { const { interfaces } = useCollectionManager(); - const fields = {}; + return useMemo(() => { + const fields = {}; - Object.keys(interfaces).forEach((type) => { - const schema = interfaces[type]; - registerField(schema.group || 'others', type, { order: 0, ...schema }); - }); + Object.keys(interfaces).forEach((type) => { + const schema = interfaces[type]; + registerField(schema.group || 'others', type, { order: 0, ...schema }); + }); - function registerField(group: string, type: string, schema) { - fields[group] = fields[group] || {}; - set(fields, [group, type], schema); - } + function registerField(group: string, type: string, schema) { + fields[group] = fields[group] || {}; + set(fields, [group, type], schema); + } - const groupLabels = { - basic: '{{t("Basic")}}', - choices: '{{t("Choices")}}', - media: '{{t("Media")}}', - datetime: '{{t("Date & Time")}}', - relation: '{{t("Relation")}}', - advanced: '{{t("Advanced type")}}', - systemInfo: '{{t("System info")}}', - others: '{{t("Others")}}', - }; + const groupLabels = { + basic: '{{t("Basic")}}', + choices: '{{t("Choices")}}', + media: '{{t("Media")}}', + datetime: '{{t("Date & Time")}}', + relation: '{{t("Relation")}}', + advanced: '{{t("Advanced type")}}', + systemInfo: '{{t("System info")}}', + others: '{{t("Others")}}', + }; - return Object.keys(groupLabels).map((groupName) => ({ - label: groupLabels[groupName], - key: groupName, - children: Object.keys(fields[groupName] || {}) - .map((type) => { - const field = fields[groupName][type]; - return { - value: type, - label: field.title, - name: type, - ...fields[groupName][type], - }; - }) - .sort((a, b) => a.order - b.order), - })); + return Object.keys(groupLabels).map((groupName) => ({ + label: groupLabels[groupName], + key: groupName, + children: Object.keys(fields[groupName] || {}) + .map((type) => { + const field = fields[groupName][type]; + return { + value: type, + label: field.title, + name: type, + ...fields[groupName][type], + }; + }) + .sort((a, b) => a.order - b.order), + })); + }, [interfaces]); }; diff --git a/packages/core/client/src/collection-manager/interfaces/integer.ts b/packages/core/client/src/collection-manager/interfaces/integer.ts index 5267d6ec6a..baf8c32c90 100644 --- a/packages/core/client/src/collection-manager/interfaces/integer.ts +++ b/packages/core/client/src/collection-manager/interfaces/integer.ts @@ -24,7 +24,7 @@ export const integer: IField = { 'x-component': 'InputNumber', 'x-component-props': { stringMode: true, - step: '0', + step: '1', }, 'x-validator': 'integer', }, diff --git a/packages/core/client/src/collection-manager/interfaces/number.ts b/packages/core/client/src/collection-manager/interfaces/number.ts index 73d61a98f8..525dc17d8f 100644 --- a/packages/core/client/src/collection-manager/interfaces/number.ts +++ b/packages/core/client/src/collection-manager/interfaces/number.ts @@ -18,7 +18,7 @@ export const number: IField = { 'x-component': 'InputNumber', 'x-component-props': { stringMode: true, - step: '0', + step: '1', }, }, }, @@ -32,9 +32,9 @@ export const number: IField = { title: '{{t("Precision")}}', 'x-component': 'Select', 'x-decorator': 'FormItem', - default: '0', + default: '1', enum: [ - { value: '0', label: '1' }, + { value: '1', label: '1' }, { value: '0.1', label: '1.0' }, { value: '0.01', label: '1.00' }, { value: '0.001', label: '1.000' }, diff --git a/packages/core/client/src/collection-manager/interfaces/percent.ts b/packages/core/client/src/collection-manager/interfaces/percent.ts index 35d42452fb..38e316ecd6 100644 --- a/packages/core/client/src/collection-manager/interfaces/percent.ts +++ b/packages/core/client/src/collection-manager/interfaces/percent.ts @@ -63,7 +63,7 @@ export const percent: IField = { 'x-component': 'Percent', 'x-component-props': { stringMode: true, - step: '0', + step: '1', addonAfter: '%', }, }, @@ -85,9 +85,9 @@ export const percent: IField = { title: '{{t("Precision")}}', 'x-component': 'Select', 'x-decorator': 'FormItem', - default: '0', + default: '1', enum: [ - { value: '0', label: '1%' }, + { value: '1', label: '1%' }, { value: '0.1', label: '1.0%' }, { value: '0.01', label: '1.00%' }, { value: '0.001', label: '1.000%' }, diff --git a/packages/core/client/src/formula/Expression.tsx b/packages/core/client/src/formula/Expression.tsx index 3eb424466a..a6e3eb0e66 100644 --- a/packages/core/client/src/formula/Expression.tsx +++ b/packages/core/client/src/formula/Expression.tsx @@ -1,8 +1,8 @@ import { css } from '@emotion/css'; import { Field, onFormSubmitValidateStart } from '@formily/core'; import { useField, useFormEffects } from '@formily/react'; -import { Dropdown, Menu } from 'antd'; -import React, { useEffect, useRef, useState } from 'react'; +import { Dropdown, MenuProps } from 'antd'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; function pasteHtml(html, selectPastedContent = false) { @@ -71,19 +71,27 @@ export const Expression = (props) => { const inputRef = useRef(); const [changed, setChanged] = useState(false); - const onChange = (value) => { - setChanged(true); - props.onChange(value); - }; + const onChange = useCallback( + (value) => { + setChanged(true); + props.onChange(value); + }, + [props.onChange], + ); + + const { numColumns, scope } = useMemo(() => { + const numColumns = new Map(); + const scope = {}; + fields + .filter((field) => supports.includes(field.interface)) + .forEach((field) => { + numColumns.set(field.name, field.uiSchema.title); + scope[field.name] = 1; + }); + + return { numColumns, scope }; + }, [fields, supports]); - const numColumns = new Map(); - const scope = {}; - fields - .filter((field) => supports.includes(field.interface)) - .forEach((field) => { - numColumns.set(field.name, field.uiSchema.title); - scope[field.name] = 1; - }); const keys = Array.from(numColumns.keys()); const [html, setHtml] = useState(() => { const scope = {}; @@ -95,6 +103,7 @@ export const Expression = (props) => { } return renderExp(value || '', scope); }); + useEffect(() => { if (changed) { return; @@ -109,34 +118,44 @@ export const Expression = (props) => { const val = renderExp(value || '', scope); setHtml(val); }, [value]); - const menu = ( - - {keys.length > 0 ? ( - keys.map((key) => ( - - - - )) - ) : ( - - {t('No available fields')} - - )} - - ); + + const menuItems = useMemo(() => { + if (keys.length > 0) { + return keys.map((key) => ({ + key, + disabled: true, + label: ( + + ), + })); + } else { + return [ + { + key: 0, + disabled: true, + label: t('No available fields'), + }, + ]; + } + }, [keys, numColumns, onChange]); + + const menu = useMemo(() => { + return { + items: menuItems, + }; + }, [menuItems]); useFormEffects(() => { onFormSubmitValidateStart(() => { @@ -157,7 +176,7 @@ export const Expression = (props) => { return ( { + const ctx = useSystemSettings(); + return ctx?.data?.data?.options?.adminSchemaUid; +}; diff --git a/packages/core/client/src/hooks/useMenuItem.tsx b/packages/core/client/src/hooks/useMenuItem.tsx new file mode 100644 index 0000000000..ba0520caba --- /dev/null +++ b/packages/core/client/src/hooks/useMenuItem.tsx @@ -0,0 +1,102 @@ +import { MenuProps } from 'antd'; +import React, { ReactNode, createContext, useCallback, useContext, useRef } from 'react'; + +type Item = MenuProps['items'][0] & { + /** 在清空数组时,如果该字段为 true 则保留该选项 */ + notdelete?: boolean; + /** 用于给列表排序 */ + order?: number; +}; + +export const GetMenuItemContext = createContext<{ collectMenuItem?(item: Item): void; onChange?: () => void }>(null); +export const GetMenuItemsContext = createContext<{ pushMenuItem?(item: Item): void }>(null); + +/** + * 用于为 SchemaInitializer.Item 组件提供一些方法,比如收集菜单项数据 + * @returns + */ +export const useCollectMenuItem = () => { + return useContext(GetMenuItemContext) || {}; +}; + +export const useCollectMenuItems = () => { + return useContext(GetMenuItemsContext) || {}; +}; + +/** + * 用于在 antd 从 4.x 升级到 5.x 中,用于把 SchemaInitializer.Item 组件这种写法转换成 Menu 组件的 items 写法 + * @returns + */ +export const useMenuItem = () => { + const list = useRef([]); + const renderItems = useRef<() => JSX.Element>(null); + const shouldRerender = useRef(false); + + const Component = useCallback(() => { + if (!shouldRerender.current) { + return null; + } + shouldRerender.current = false; + + if (renderItems.current) { + return renderItems.current(); + } + + return ( + <> + {list.current.map((Com, index) => ( + + ))} + + ); + }, []); + + const getMenuItems = useCallback((Com: () => ReactNode): Item[] => { + const items: Item[] = []; + + const pushMenuItem = (item: Item) => { + items.push(item); + items.sort((a, b) => (a.order || 0) - (b.order || 0)); + }; + + shouldRerender.current = true; + renderItems.current = () => { + const notDeleteItems = items.filter((item) => item.notdelete); + items.length = 0; + items.push(...notDeleteItems); + return ( + + {Com()} + + ); + }; + + return items; + }, []); + + const getMenuItem = useCallback((Com: () => JSX.Element): Item => { + const item = {} as Item; + + const collectMenuItem = (menuItem: Item) => { + Object.assign(item, menuItem); + }; + + shouldRerender.current = true; + list.current.push(() => { + return {Com()}; + }); + + return item; + }, []); + + // 防止 list 有重复元素 + const clean = useCallback(() => { + list.current = []; + }, []); + + return { Component, getMenuItems, getMenuItem, clean }; +}; diff --git a/packages/core/client/src/index.ts b/packages/core/client/src/index.ts index 0cde6613cf..3af144005a 100644 --- a/packages/core/client/src/index.ts +++ b/packages/core/client/src/index.ts @@ -14,6 +14,7 @@ export * from './collection-manager'; export * from './document-title'; export * from './filter-provider'; export * from './formula'; +export * from './hooks'; export * from './i18n'; export * from './icon'; export * from './plugin-manager'; @@ -23,10 +24,9 @@ export * from './record-provider'; export * from './route-switch'; export * from './schema-component'; export * from './schema-initializer'; +export * from './schema-items'; export * from './schema-settings'; export * from './schema-templates'; -export * from './schema-items'; -export * from './settings-form'; export * from './system-settings'; export * from './user'; -export * from './hooks'; + diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts index c483658311..2b233b0168 100644 --- a/packages/core/client/src/locale/en_US.ts +++ b/packages/core/client/src/locale/en_US.ts @@ -703,5 +703,7 @@ export default { "First or create":"First or create", "Update or create":"Update or create", "Find by the following fields":"Find by the following fields", - "Create":"Create" + "Create":"Create", + "Current form": "Current form", + "Current object":"Current object" }; diff --git a/packages/core/client/src/locale/ja_JP.ts b/packages/core/client/src/locale/ja_JP.ts index 71127e4a71..ff2d7a95ca 100644 --- a/packages/core/client/src/locale/ja_JP.ts +++ b/packages/core/client/src/locale/ja_JP.ts @@ -614,5 +614,7 @@ export default { "First or create":"存在しない場合に追加", "Update or create":"存在しなければ新規、存在すれば更新", "Find by the following fields":"次のフィールドで検索", - "Create":"新規のみ" + "Create":"新規のみ" , + "Current form":"現在のフォーム", + "Current object":"現在のオブジェクト" } diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts index 1febbdfe67..cad3a81435 100644 --- a/packages/core/client/src/locale/zh_CN.ts +++ b/packages/core/client/src/locale/zh_CN.ts @@ -782,6 +782,8 @@ export default { "Update or create":"不存在时新增,存在时更新", "Find by the following fields":"通过以下字段查找", "Create":"仅新增", + "Current form":"当前表单", + "Current object":"当前对象", "Quick create": "快速创建", "Dropdown": "下拉菜单", "Pop-up": "弹窗", diff --git a/packages/core/client/src/pm/Card.tsx b/packages/core/client/src/pm/Card.tsx index a2118db01c..bba0ff3b67 100644 --- a/packages/core/client/src/pm/Card.tsx +++ b/packages/core/client/src/pm/Card.tsx @@ -1,9 +1,8 @@ -import React, { useEffect, useMemo, useState, useCallback, MouseEventHandler } from 'react'; -import { useAPIClient, useRequest } from '../api-client'; +import { DeleteOutlined, SettingOutlined } from '@ant-design/icons'; +import { css } from '@emotion/css'; import { Avatar, Card, - message, Modal, Popconfirm, Spin, @@ -13,14 +12,15 @@ import { Tag, Tooltip, Typography, + message, } from 'antd'; -import { css } from '@emotion/css'; import cls from 'classnames'; -import { useNavigate } from 'react-router-dom'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { DeleteOutlined, SettingOutlined } from '@ant-design/icons'; -import { useParseMarkdown } from '../schema-component/antd/markdown/util'; +import { useNavigate } from 'react-router-dom'; import type { IPluginData } from '.'; +import { useAPIClient, useRequest } from '../api-client'; +import { useParseMarkdown } from '../schema-component/antd/markdown/util'; interface PluginDocumentProps { path: string; @@ -163,7 +163,7 @@ function PluginDetail(props: IPluginDetail) { destroyOnClose > {plugin?.description &&
{plugin?.description}
} - + ); } diff --git a/packages/core/client/src/pm/PluginManagerLink.tsx b/packages/core/client/src/pm/PluginManagerLink.tsx index 169d8d693a..5cffc26847 100644 --- a/packages/core/client/src/pm/PluginManagerLink.tsx +++ b/packages/core/client/src/pm/PluginManagerLink.tsx @@ -1,11 +1,12 @@ import { ApiOutlined, SettingOutlined } from '@ant-design/icons'; -import { Button, Dropdown, Menu, Tooltip } from 'antd'; -import React, { useContext, useState } from 'react'; +import { Button, Dropdown, MenuProps, Tooltip } from 'antd'; +import _ from 'lodash'; +import React, { useContext, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { useACLRoleContext } from '../acl/ACLProvider'; import { ActionContextProvider, useCompile } from '../schema-component'; -import { getPluginsTabs, SettingsCenterContext } from './index'; +import { SettingsCenterContext, getPluginsTabs } from './index'; export const PluginManagerLink = () => { const { t } = useTranslation(); @@ -23,7 +24,7 @@ export const PluginManagerLink = () => { ); }; -const getBookmarkTabs = (data) => { +const getBookmarkTabs = _.memoize((data) => { const bookmarkTabs = []; data.forEach((plugin) => { const tabs = plugin.tabs; @@ -32,7 +33,7 @@ const getBookmarkTabs = (data) => { }); }); return bookmarkTabs; -}; +}); export const SettingsCenterDropdown = () => { const { snippets = [] } = useACLRoleContext(); const [visible, setVisible] = useState(false); @@ -42,27 +43,28 @@ export const SettingsCenterDropdown = () => { const itemData = useContext(SettingsCenterContext); const pluginsTabs = getPluginsTabs(itemData, snippets); const bookmarkTabs = getBookmarkTabs(pluginsTabs); + const menu = useMemo(() => { + return { + items: [ + ...bookmarkTabs.map((tab) => ({ + key: `/admin/settings/${tab.path}`, + label: compile(tab.title), + })), + { type: 'divider' }, + { + key: '/admin/settings', + label: t('All plugin settings'), + }, + ], + onClick({ key }) { + navigate(key); + }, + }; + }, [bookmarkTabs]); + return ( - ({ - key: `/admin/settings/${tab.path}`, - label: compile(tab.title), - })), - { type: 'divider' }, - { - key: '/admin/settings', - label: t('All plugin settings'), - }, - ], - onClick({ key }) { - navigate(key); - }, - }} - > + ) } - > - {fieldSchema.mapProperties((schema) => { - return ( - - {schema['x-icon'] && } - {schema.title || t('Unnamed')} - - - } - key={schema.name} - /> - ); + items={fieldSchema.mapProperties((schema) => { + return { + label: ( + + {schema['x-icon'] && } + {schema.title || t('Unnamed')} + + + ), + key: schema.name as string, + }; })} - + /> ) } diff --git a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx index 33d0d02bd8..986f5d16a5 100644 --- a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx +++ b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx @@ -1,15 +1,18 @@ import { LoadingOutlined } from '@ant-design/icons'; -import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react'; -import { SelectProps, Tag, Empty, Divider } from 'antd'; +import { connect, mapProps, mapReadPretty, useField, useFieldSchema, useForm } from '@formily/react'; +import { Divider, SelectProps, Tag } from 'antd'; +import flat from 'flat'; import { uniqBy } from 'lodash'; import moment from 'moment'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { ResourceActionOptions, useRequest } from '../../../api-client'; +import { useBlockRequestContext } from '../../../block-provider/BlockProvider'; import { mergeFilter } from '../../../block-provider/SharedFilterProvider'; import { useCollection, useCollectionManager } from '../../../collection-manager'; -import { Select, defaultFieldNames } from '../select'; +import { getInnermostKeyAndValue } from '../../common/utils/uitls'; +import { defaultFieldNames, Select } from '../select'; import { ReadPretty } from './ReadPretty'; - +import { extractFilterfield, extractValuesByPattern, generatePattern, parseVariables } from './utils'; const EMPTY = 'N/A'; export type RemoteSelectProps

= SelectProps & { @@ -39,10 +42,12 @@ const InternalRemoteSelect = connect( ...others } = props; const [open, setOpen] = useState(false); + const form = useForm(); const firstRun = useRef(false); const fieldSchema = useFieldSchema(); const isQuickAdd = fieldSchema['x-component-props']?.addMode === 'quickAdd'; const field = useField(); + const ctx = useBlockRequestContext(); const { getField } = useCollection(); const searchData = useRef(null); const { getCollectionJoinField, getInterface } = useCollectionManager(); @@ -115,6 +120,49 @@ const InternalRemoteSelect = connect( }, [targetField?.uiSchema, fieldNames], ); + const parseFilter = (rules) => { + if (!rules) { + return undefined; + } + const type = Object.keys(rules)[0] || '$and'; + const conditions = rules[type]; + const results = []; + conditions?.forEach((c) => { + const jsonlogic = getInnermostKeyAndValue(c); + const regex = /{{(.*?)}}/; + const matches = jsonlogic.value?.match?.(regex); + if (!matches || (!matches[1].includes('$form') && !matches[1].includes('$iteration'))) { + results.push(c); + return; + } + const associationfield = extractFilterfield(matches[1]); + const filterCollectionField = getCollectionJoinField(`${ctx.props.collection}.${associationfield}`); + if (['o2m', 'm2m'].includes(filterCollectionField?.interface)) { + // 对多子表单 + const pattern = generatePattern(matches?.[1], associationfield); + const parseValue: any = extractValuesByPattern(flat(form.values), pattern); + const filters = parseValue.map((v) => { + return JSON.parse(JSON.stringify(c).replace(jsonlogic.value, v)); + }); + results.push({ $or: filters }); + } else { + const variablesCtx = { $form: form.values, $iteration: form.values }; + let str = matches?.[1]; + if (str.includes('$iteration')) { + const path = field.path.segments.concat([]); + path.pop(); + str = str.replace('$iteration.', `$iteration.${path.join('.')}.`); + } + const parseValue = parseVariables(str, variablesCtx); + const filterObj = JSON.parse( + JSON.stringify(c).replace(jsonlogic.value, str.endsWith('id') ? parseValue ?? 0 : parseValue), + ); + results.push(filterObj); + } + }); + return { [type]: results }; + }; + const { data, run, loading } = useRequest( { action: 'list', @@ -122,9 +170,8 @@ const InternalRemoteSelect = connect( params: { pageSize: 200, ...service?.params, - // fields: [fieldNames.label, fieldNames.value, ...(service?.params?.fields || [])], // search needs - filter: mergeFilter([field.componentProps?.service?.params?.filter || service?.params?.filter]), + filter: mergeFilter([parseFilter(field.componentProps?.service?.params?.filter) || service?.params?.filter]), }, }, { @@ -185,12 +232,10 @@ const InternalRemoteSelect = connect( const valueOptions = (value != null && (Array.isArray(value) ? value : [value])) || []; return uniqBy(data?.data?.concat(valueOptions) || [], fieldNames.value); }, [data?.data, value]); + const onDropdownVisibleChange = (visible) => { setOpen(visible); searchData.current = null; - if (firstRun.current && data?.data.length > 0) { - return; - } run(); firstRun.current = true; }; diff --git a/packages/core/client/src/schema-component/antd/remote-select/utils.ts b/packages/core/client/src/schema-component/antd/remote-select/utils.ts new file mode 100644 index 0000000000..bb6ba77599 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/remote-select/utils.ts @@ -0,0 +1,35 @@ +import { get, isFunction } from 'lodash'; + +export const parseVariables = (str: string, ctx) => { + if (str) { + const result = get(ctx, str); + return isFunction(result) ? result() : result; + } else { + return str; + } +}; +export function extractFilterfield(str) { + const match = str.match(/^\$form\.([^.[\]]+)/); + if (match) { + return match[1]; + } + return null; +} + +export function extractValuesByPattern(obj, pattern) { + const regexPattern = new RegExp(pattern.replace(/\*/g, '\\d+')); + const result = []; + + for (const key in obj) { + if (regexPattern.test(key)) { + const value = obj[key]; + result.push(value); + } + } + + return result; +} +export function generatePattern(str, fieldName) { + const result = str.replace(`$form.${fieldName}.`, `${fieldName}.*.`); + return result; +} diff --git a/packages/core/client/src/schema-component/antd/table-v2/FilterDynamicComponent.tsx b/packages/core/client/src/schema-component/antd/table-v2/FilterDynamicComponent.tsx index 258f652379..7ba7ce165a 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/FilterDynamicComponent.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/FilterDynamicComponent.tsx @@ -3,8 +3,8 @@ import { useVariableOptions } from '../../../schema-settings/VariableInput/hooks import { Variable } from '../variable'; export function FilterDynamicComponent(props) { - const { value, onChange, renderSchemaComponent } = props; - const options = useVariableOptions(); + const { value, onChange, renderSchemaComponent, form, collectionField, ...other } = props; + const options = useVariableOptions({ form, collectionField, ...other }); return ( diff --git a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx index e88b5491a7..9bd5a8a803 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx @@ -193,344 +193,347 @@ const useValidator = (validator: (value: any) => string) => { }, []); }; -export const Table: any = observer((props: any) => { - const { pagination: pagination1, useProps, onChange, ...others1 } = props; - const { pagination: pagination2, onClickRow, ...others2 } = useProps?.() || {}; - const { - dragSort = false, - showIndex = true, - onRowSelectionChange, - onChange: onTableChange, - rowSelection, - rowKey, - required, - onExpand, - ...others - } = { ...others1, ...others2 } as any; - const field = useArrayField(others); - const columns = useTableColumns(others); - const schema = useFieldSchema(); - const isTableSelector = schema?.parent?.['x-decorator'] === 'TableSelectorProvider'; - const ctx = isTableSelector ? useTableSelectorContext() : useTableBlockContext(); - const { expandFlag } = ctx; - const onRowDragEnd = useMemoizedFn(others.onRowDragEnd || (() => {})); - const paginationProps = usePaginationProps(pagination1, pagination2); - // const requiredValidator = field.required || required; - const { treeTable } = schema?.parent?.['x-decorator-props'] || {}; - const [expandedKeys, setExpandesKeys] = useState([]); - const [allIncludesChildren, setAllIncludesChildren] = useState([]); - const [selectedRowKeys, setSelectedRowKeys] = useState(field?.data?.selectedRowKeys || []); - const [selectedRow, setSelectedRow] = useState([]); - const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || []; - const isRowSelect = rowSelection?.type !== 'none'; +export const Table: any = observer( + (props: any) => { + const { pagination: pagination1, useProps, onChange, ...others1 } = props; + const { pagination: pagination2, onClickRow, ...others2 } = useProps?.() || {}; + const { + dragSort = false, + showIndex = true, + onRowSelectionChange, + onChange: onTableChange, + rowSelection, + rowKey, + required, + onExpand, + ...others + } = { ...others1, ...others2 } as any; + const field = useArrayField(others); + const columns = useTableColumns(others); + const schema = useFieldSchema(); + const isTableSelector = schema?.parent?.['x-decorator'] === 'TableSelectorProvider'; + const ctx = isTableSelector ? useTableSelectorContext() : useTableBlockContext(); + const { expandFlag } = ctx; + const onRowDragEnd = useMemoizedFn(others.onRowDragEnd || (() => {})); + const paginationProps = usePaginationProps(pagination1, pagination2); + // const requiredValidator = field.required || required; + const { treeTable } = schema?.parent?.['x-decorator-props'] || {}; + const [expandedKeys, setExpandesKeys] = useState([]); + const [allIncludesChildren, setAllIncludesChildren] = useState([]); + const [selectedRowKeys, setSelectedRowKeys] = useState(field?.data?.selectedRowKeys || []); + const [selectedRow, setSelectedRow] = useState([]); + const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || []; + const isRowSelect = rowSelection?.type !== 'none'; - let onRow = null, - highlightRow = ''; + let onRow = null, + highlightRow = ''; - if (onClickRow) { - onRow = (record) => { - return { - onClick: () => onClickRow(record, setSelectedRow, selectedRow), + if (onClickRow) { + onRow = (record) => { + return { + onClick: () => onClickRow(record, setSelectedRow, selectedRow), + }; }; - }; - highlightRow = css` - & > td { - background-color: #caedff !important; - } - &:hover > td { - background-color: #caedff !important; - } - `; - } - - // useEffect(() => { - // field.setValidator((value) => { - // if (requiredValidator) { - // return Array.isArray(value) && value.length > 0 ? null : 'The field value is required'; - // } - // return; - // }); - // }, [requiredValidator]); - - useEffect(() => { - if (treeTable !== false) { - const keys = getIdsWithChildren(field.value?.slice?.()); - setAllIncludesChildren(keys); + highlightRow = css` + & > td { + background-color: #caedff !important; + } + &:hover > td { + background-color: #caedff !important; + } + `; } - }, [field.value]); - useEffect(() => { - if (expandFlag) { - setExpandesKeys(allIncludesChildren); - } else { - setExpandesKeys([]); - } - }, [expandFlag, allIncludesChildren]); - const components = useMemo(() => { - return { - header: { - wrapper: (props) => { - return ( - - - - ); + // useEffect(() => { + // field.setValidator((value) => { + // if (requiredValidator) { + // return Array.isArray(value) && value.length > 0 ? null : 'The field value is required'; + // } + // return; + // }); + // }, [requiredValidator]); + + useEffect(() => { + if (treeTable !== false) { + const keys = getIdsWithChildren(field.value?.slice?.()); + setAllIncludesChildren(keys); + } + }, [field.value]); + useEffect(() => { + if (expandFlag) { + setExpandesKeys(allIncludesChildren); + } else { + setExpandesKeys([]); + } + }, [expandFlag, allIncludesChildren]); + + const components = useMemo(() => { + return { + header: { + wrapper: (props) => { + return ( + + + + ); + }, + cell: (props) => { + return ( + + ); + }, }, - cell: (props) => { - return ( - { + return ( + { + if (!e.active || !e.over) { + console.warn('move cancel'); + return; + } + + const fromIndex = e.active?.data.current?.sortable?.index; + const toIndex = e.over?.data.current?.sortable?.index; + const from = field.value[fromIndex]; + const to = field.value[toIndex]; + field.move(fromIndex, toIndex); + onRowDragEnd({ fromIndex, toIndex, from, to }); + }} + > + + + ); + }, + row: (props) => { + return ; + }, + cell: (props) => ( + - ); + ), }, - }, - body: { - wrapper: (props) => { - return ( - { - if (!e.active || !e.over) { - console.warn('move cancel'); - return; - } + }; + }, [field, onRowDragEnd, dragSort]); - const fromIndex = e.active?.data.current?.sortable?.index; - const toIndex = e.over?.data.current?.sortable?.index; - const from = field.value[fromIndex]; - const to = field.value[toIndex]; - field.move(fromIndex, toIndex); - onRowDragEnd({ fromIndex, toIndex, from, to }); - }} - > - - - ); - }, - row: (props) => { - return ; - }, - cell: (props) => ( - - ), - }, + const defaultRowKey = (record: any) => { + return field.value?.indexOf?.(record); }; - }, [field, onRowDragEnd, dragSort]); - const defaultRowKey = (record: any) => { - return field.value?.indexOf?.(record); - }; + const getRowKey = (record: any) => { + if (typeof rowKey === 'string') { + return record[rowKey]?.toString(); + } else { + return (rowKey ?? defaultRowKey)(record)?.toString(); + } + }; - const getRowKey = (record: any) => { - if (typeof rowKey === 'string') { - return record[rowKey]?.toString(); - } else { - return (rowKey ?? defaultRowKey)(record)?.toString(); - } - }; - - const restProps = { - rowSelection: rowSelection - ? { - type: 'checkbox', - selectedRowKeys: selectedRowKeys, - onChange(selectedRowKeys: any[], selectedRows: any[]) { - field.data = field.data || {}; - field.data.selectedRowKeys = selectedRowKeys; - setSelectedRowKeys(selectedRowKeys); - onRowSelectionChange?.(selectedRowKeys, selectedRows); - }, - renderCell: (checked, record, index, originNode) => { - if (!dragSort && !showIndex) { - return originNode; - } - const current = props?.pagination?.current; - const pageSize = props?.pagination?.pageSize || 20; - if (current) { - index = index + (current - 1) * pageSize + 1; - } else { - index = index + 1; - } - if (record.__index) { - index = extractIndex(record.__index); - } - return ( -

+ const restProps = { + rowSelection: rowSelection + ? { + type: 'checkbox', + selectedRowKeys: selectedRowKeys, + onChange(selectedRowKeys: any[], selectedRows: any[]) { + field.data = field.data || {}; + field.data.selectedRowKeys = selectedRowKeys; + setSelectedRowKeys(selectedRowKeys); + onRowSelectionChange?.(selectedRowKeys, selectedRows); + }, + renderCell: (checked, record, index, originNode) => { + if (!dragSort && !showIndex) { + return originNode; + } + const current = props?.pagination?.current; + const pageSize = props?.pagination?.pageSize || 20; + if (current) { + index = index + (current - 1) * pageSize + 1; + } else { + index = index + 1; + } + if (record.__index) { + index = extractIndex(record.__index); + } + return (
- {dragSort && } - {showIndex && } -
- {isRowSelect && (
- {originNode} + {dragSort && } + {showIndex && }
- )} -
- ); - }, - ...rowSelection, - } - : undefined, - }; - const SortableWrapper = useCallback( - ({ children }) => { - return dragSort - ? React.createElement(SortableContext, { - items: field.value?.map?.(getRowKey) || [], - children: children, - }) - : React.createElement(React.Fragment, { - children, - }); - }, - [field, dragSort], - ); - const fieldSchema = useFieldSchema(); - const fixedBlock = fieldSchema?.parent?.['x-decorator-props']?.fixedBlock; + {isRowSelect && ( +
+ {originNode} +
+ )} + + ); + }, + ...rowSelection, + } + : undefined, + }; + const SortableWrapper = useCallback( + ({ children }) => { + return dragSort + ? React.createElement(SortableContext, { + items: field.value?.map?.(getRowKey) || [], + children, + }) + : React.createElement(React.Fragment, { + children, + }); + }, + [field, dragSort], + ); + const fieldSchema = useFieldSchema(); + const fixedBlock = fieldSchema?.parent?.['x-decorator-props']?.fixedBlock; - const { height: tableHeight, tableSizeRefCallback } = useTableSize(); - const scroll = useMemo(() => { - return fixedBlock - ? { - x: 'max-content', - y: tableHeight, - } - : { - x: 'max-content', - }; - }, [fixedBlock, tableHeight]); - return ( -
{ + return fixedBlock + ? { + x: 'max-content', + y: tableHeight, + } + : { + x: 'max-content', + }; + }, [fixedBlock, tableHeight]); + return ( +
- - { - onTableChange?.(pagination, filters, sorter, extra); - }} - onRow={onRow} - rowClassName={(record) => (selectedRow.includes(record[rowKey]) ? highlightRow : '')} - tableLayout={'auto'} - scroll={scroll} - columns={columns} - expandable={{ - onExpand: (flag, record) => { - const newKeys = flag ? [...expandedKeys, record.id] : expandedKeys.filter((i) => record.id !== i); - setExpandesKeys(newKeys); - onExpand?.(flag, record); - }, - expandedRowKeys: expandedKeys, - }} - /> - - {field.errors.length > 0 && ( -
- {field.errors.map((error) => { - return error.messages.map((message) =>
{message}
); - })} -
- )} -
- ); -}); + .ant-table { + overflow-x: auto; + overflow-y: hidden; + } + `} + > + + { + onTableChange?.(pagination, filters, sorter, extra); + }} + onRow={onRow} + rowClassName={(record) => (selectedRow.includes(record[rowKey]) ? highlightRow : '')} + tableLayout={'auto'} + scroll={scroll} + columns={columns} + expandable={{ + onExpand: (flag, record) => { + const newKeys = flag ? [...expandedKeys, record.id] : expandedKeys.filter((i) => record.id !== i); + setExpandesKeys(newKeys); + onExpand?.(flag, record); + }, + expandedRowKeys: expandedKeys, + }} + /> + + {field.errors.length > 0 && ( +
+ {field.errors.map((error) => { + return error.messages.map((message) =>
{message}
); + })} +
+ )} +
+ ); + }, + { displayName: 'Table' }, +); diff --git a/packages/core/client/src/schema-component/antd/tabs/Tabs.tsx b/packages/core/client/src/schema-component/antd/tabs/Tabs.tsx index 7d08eabe97..f2e9adec7f 100644 --- a/packages/core/client/src/schema-component/antd/tabs/Tabs.tsx +++ b/packages/core/client/src/schema-component/antd/tabs/Tabs.tsx @@ -1,47 +1,51 @@ import { css } from '@emotion/css'; import { observer, RecursionField, useField, useFieldSchema } from '@formily/react'; -import { TabPaneProps, Tabs as AntdTabs, TabsProps } from 'antd'; +import { Tabs as AntdTabs, TabPaneProps, TabsProps } from 'antd'; import classNames from 'classnames'; import React, { useMemo } from 'react'; import { Icon } from '../../../icon'; import { useSchemaInitializer } from '../../../schema-initializer'; import { DndContext, SortableItem } from '../../common'; +import { useDesignable } from '../../hooks'; import { useDesigner } from '../../hooks/useDesigner'; -import { TabsContextProvider, useTabsContext } from './context'; +import { useTabsContext } from './context'; import { TabsDesigner } from './Tabs.Designer'; export const Tabs: any = observer( (props: TabsProps) => { const fieldSchema = useFieldSchema(); const { render } = useSchemaInitializer(fieldSchema['x-initializer']); + const { designable } = useDesignable(); const contextProps = useTabsContext(); + const { PaneRoot = React.Fragment as React.FC } = contextProps; - const PaneProvider = useMemo(() => { - if (contextProps.deep === false) { - return TabsContextProvider; + const items = useMemo(() => { + const result = fieldSchema.mapProperties((schema, key: string) => { + return { + key, + label: , + children: ( + + + + ), + }; + }); + + if (designable) { + result.push({ + key: 'designer', + label: render(), + children: null, + }); } - return React.Fragment; - }, [contextProps.deep]); + + return result; + }, [fieldSchema.mapProperties((s, key) => key).join()]); return ( - - {fieldSchema.mapProperties((schema, key) => { - return ( - } key={key}> - - - - - ); - })} - + ); }, diff --git a/packages/core/client/src/schema-component/antd/tabs/context.tsx b/packages/core/client/src/schema-component/antd/tabs/context.tsx index 24d05eddc8..e11dddba76 100644 --- a/packages/core/client/src/schema-component/antd/tabs/context.tsx +++ b/packages/core/client/src/schema-component/antd/tabs/context.tsx @@ -2,7 +2,7 @@ import { TabsProps } from 'antd'; import React from 'react'; interface TabsContextProps extends TabsProps { - deep?: boolean; + PaneRoot?: React.FC; } const TabsContext = React.createContext({}); diff --git a/packages/core/client/src/schema-component/antd/upload/ReadPretty.tsx b/packages/core/client/src/schema-component/antd/upload/ReadPretty.tsx index f5841591dd..a44f508514 100644 --- a/packages/core/client/src/schema-component/antd/upload/ReadPretty.tsx +++ b/packages/core/client/src/schema-component/antd/upload/ReadPretty.tsx @@ -18,7 +18,7 @@ type Composed = React.FC & { export const ReadPretty: Composed = () => null; -ReadPretty.File = (props: UploadProps) => { +ReadPretty.File = function File(props: UploadProps) { const record = useRecord(); const field = useField(); const value = isString(field.value) ? record : field.value; @@ -44,7 +44,7 @@ ReadPretty.File = (props: UploadProps) => { // } }; return ( -
+
@@ -114,6 +114,7 @@ ReadPretty.File = (props: UploadProps) => { imageTitle={images[photoIndex]?.title} toolbarButtons={[ + )} +
+ ); + if (!shouldRender || !items.length) { + return buttonDom; + } + const insertSchema = (schema) => { - if (props.insert) { - props.insert(wrap(schema)); + if (insert) { + insert(wrap(schema)); } else { insertAdjacent(insertPosition, wrap(schema), { onSuccess }); } }; + const renderItems = (items: any) => { return items - .filter((v) => { + .filter((v: any) => { return v && (v?.visible ? v.visible() : true); }) - ?.map((item, indexA) => { + ?.map((item: any, indexA: number) => { if (item.type === 'divider') { - return ; + return { type: 'divider', key: item.key || `item-${indexA}` }; } if (item.type === 'item' && item.component) { const Component = findComponent(item.component); - item.key = `${item.key || item.title}-${indexA}`; - return ( - Component && ( + if (!Component) { + error(`SchemaInitializer: component "${item.component}" not found`); + return null; + } + if (!item.key) { + item.key = `${item.title}-${indexA}`; + } + return getMenuItem(() => { + return ( - ) - ); + ); + }); } if (item.type === 'itemGroup') { + const label = compile(item.title); return ( - !!item.children?.length && ( - - {renderItems(item.children)} - - ) + !!item.children?.length && { + type: 'group', + key: item.key || `item-group-${indexA}`, + label, + title: label, + children: renderItems(item.children), + } ); } if (item.type === 'subMenu') { + const label = compile(item.title); return ( - !!item.children?.length && ( - - {renderItems(item.children)} - - ) + !!item.children?.length && { + key: item.key || `item-group-${indexA}`, + label, + title: label, + popupClassName: menuItemGroupCss, + children: renderItems(item.children), + } ); } }); }; - const buttonDom = ( - - ); - if (!items.length) { - return buttonDom; - } - const menu = {renderItems(items)}; - if (!designable && props.designable !== true) { - return null; - } + clean(); + const menuItems = renderItems(items); + return ( - + + { - setVisible(visible); + onOpenChange={() => { + // 如果不清空输入框的值,那么下次打开的时候会出现上次输入的值 + setSearchValue(''); + setShouldRender(false); + setVisible(false); + }} + menu={{ + style: { + maxHeight: '60vh', + overflowY: 'auto', + }, + items: menuItems, }} {...dropdown} - overlay={menu} > {component ? component : buttonDom} @@ -158,10 +203,17 @@ SchemaInitializer.Button = observer( { displayName: 'SchemaInitializer.Button' }, ); -SchemaInitializer.Item = (props: SchemaInitializerItemProps) => { - const { index, info } = useContext(SchemaInitializerItemContext); +SchemaInitializer.Item = function Item(props: SchemaInitializerItemProps) { + const { info } = useContext(SchemaInitializerItemContext); const compile = useCompile(); - const { eventKey, items = [], children = info?.title, icon, onClick, ...others } = props; + const { items = [], children = info?.title, icon, onClick } = props; + const { collectMenuItem } = useCollectMenuItem(); + + if (!collectMenuItem) { + error('SchemaInitializer.Item: collectMenuItem is undefined, please check the context'); + return null; + } + if (items?.length > 0) { const renderMenuItem = (items: SchemaInitializerItemOptions[]) => { if (!items?.length) { @@ -169,77 +221,70 @@ SchemaInitializer.Item = (props: SchemaInitializerItemProps) => { } return items.map((item, indexA) => { if (item.type === 'divider') { - return ; + return { type: 'divider', key: `divider-${indexA}` }; } if (item.type === 'itemGroup') { - return ( - - {renderMenuItem(item.children)} - - ); + const label = compile(item.title); + return { + type: 'group', + key: item.key || `item-group-${indexA}`, + label, + title: label, + className: menuItemGroupCss, + children: renderMenuItem(item.children), + } as MenuProps['items'][0]; } if (item.type === 'subMenu') { - return ( - - {renderMenuItem(item.children)} - - ); + const label = compile(item.title); + return { + key: item.key || `sub-menu-${indexA}`, + label, + title: label, + children: renderMenuItem(item.children), + }; } - return ( - { - item?.clearKeywords?.(); - if (item.onClick) { - item.onClick({ ...info, item }); - } else { - onClick({ ...info, item }); - } - }} - > - {compile(item.title)} - - ); + const label = compile(item.title); + return { + key: item.key || `${info.key}-${item.title}-${indexA}`, + label, + title: label, + onClick: (info) => { + item?.clearKeywords?.(); + if (item.onClick) { + item.onClick({ ...info, item }); + } else { + onClick({ ...info, item }); + } + }, + }; }); }; - return ( - : icon} - > - {renderMenuItem(items)} - - ); + + const item = { + key: info.key, + label: isString(children) ? compile(children) : children, + icon: typeof icon === 'string' ? : icon, + children: renderMenuItem(items), + }; + + collectMenuItem(item); + return null; } - return ( - : icon} - onClick={(opts) => { - info?.clearKeywords?.(); - onClick({ ...opts, item: info }); - }} - > - {compile(children)} - - ); + + const label = isString(children) ? compile(children) : children; + const item = { + key: info.key, + label, + title: label, + icon: typeof icon === 'string' ? : icon, + onClick: (opts) => { + info?.clearKeywords?.(); + onClick({ ...opts, item: info }); + }, + }; + + collectMenuItem(item); + return null; }; SchemaInitializer.itemWrap = (component?: SchemaInitializerItemComponent) => { @@ -253,11 +298,13 @@ interface SchemaInitializerActionModalProps { onSubmit?: (values: any) => void; buttonText?: any; } -SchemaInitializer.ActionModal = (props: SchemaInitializerActionModalProps) => { +SchemaInitializer.ActionModal = function ActionModal(props: SchemaInitializerActionModalProps) { const { title, schema, buttonText, onCancel, onSubmit } = props; const useCancelAction = useCallback(() => { + // eslint-disable-next-line react-hooks/rules-of-hooks const form = useForm(); + // eslint-disable-next-line react-hooks/rules-of-hooks const ctx = useActionContext(); return { async run() { @@ -269,7 +316,9 @@ SchemaInitializer.ActionModal = (props: SchemaInitializerActionModalProps) => { }, [onCancel]); const useSubmitAction = useCallback(() => { + // eslint-disable-next-line react-hooks/rules-of-hooks const form = useForm(); + // eslint-disable-next-line react-hooks/rules-of-hooks const ctx = useActionContext(); return { async run() { diff --git a/packages/core/client/src/schema-initializer/SelectCollection.tsx b/packages/core/client/src/schema-initializer/SelectCollection.tsx index 3764231a4d..f669b1a991 100644 --- a/packages/core/client/src/schema-initializer/SelectCollection.tsx +++ b/packages/core/client/src/schema-initializer/SelectCollection.tsx @@ -1,31 +1,28 @@ import { Divider, Input } from 'antd'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useCollectionManager } from '../collection-manager'; -export const SelectCollection = ({ value, onChange, setSelected }) => { +export const SelectCollection = ({ value: outValue, onChange }) => { const { t } = useTranslation(); - const { collections } = useCollectionManager(); + const [value, setValue] = useState(outValue); + + // 之所以要增加个内部的 value 是为了防止用户输入过快时造成卡顿的问题 + useEffect(() => { + setValue(outValue); + }, [outValue]); return (
{ - const names = collections - .filter((collection) => { - if (!collection.title) { - return; - } - return collection.title.toUpperCase().includes(e.target.value.toUpperCase()); - }) - .map((item) => item.name); - setSelected(names); onChange(e.target.value); + setValue(e.target.value); }} /> diff --git a/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx index dea3b2e274..4d52054780 100644 --- a/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx +++ b/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx @@ -1,12 +1,12 @@ import { MenuOutlined } from '@ant-design/icons'; import { ISchema, useFieldSchema } from '@formily/react'; +import _ from 'lodash'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { SchemaInitializer, SchemaSettings } from '../..'; import { useAPIClient } from '../../api-client'; import { useCollection } from '../../collection-manager'; import { createDesignable, useDesignable } from '../../schema-component'; -import _ from 'lodash'; export const Resizable = (props) => { const { t } = useTranslation(); diff --git a/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx index 1aea86da3f..6b79ab929c 100644 --- a/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx +++ b/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx @@ -32,7 +32,7 @@ export const TableActionInitializers = { skipScopeCheck: true, }, }, - visible: () => { + visible: function useVisible() { const collection = useCollection(); return collection.template !== 'view' && collection.template !== 'file'; }, @@ -45,7 +45,7 @@ export const TableActionInitializers = { 'x-align': 'right', 'x-decorator': 'ACLActionProvider', }, - visible: () => { + visible: function useVisible() { const collection = useCollection(); return (collection as any).template !== 'view'; }, @@ -65,7 +65,7 @@ export const TableActionInitializers = { schema: { 'x-align': 'right', }, - visible: () => { + visible: function useVisible() { const schema = useFieldSchema(); const collection = useCollection(); const { treeTable } = schema?.parent?.['x-decorator-props'] || {}; @@ -76,7 +76,7 @@ export const TableActionInitializers = { }, { type: 'divider', - visible: () => { + visible: function useVisible() { const collection = useCollection(); return (collection as any).template !== 'view'; }, @@ -157,7 +157,7 @@ export const TableActionInitializers = { }, }, ], - visible: () => { + visible: function useVisible() { const collection = useCollection(); return (collection as any).template !== 'view'; }, diff --git a/packages/core/client/src/schema-initializer/buttons/TableColumnInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/TableColumnInitializers.tsx index 10f468802c..06d96d0f82 100644 --- a/packages/core/client/src/schema-initializer/buttons/TableColumnInitializers.tsx +++ b/packages/core/client/src/schema-initializer/buttons/TableColumnInitializers.tsx @@ -8,12 +8,13 @@ import { useInheritsTableColumnInitializerFields, } from '../utils'; import { useCompile } from '../../schema-component'; -import { useFieldSchema } from '@formily/react'; +import { useField, useFieldSchema } from '@formily/react'; // 表格列配置 export const TableColumnInitializers = (props: any) => { const { items = [], action = true } = props; const { t } = useTranslation(); + const field = useField(); const fieldSchema = useFieldSchema(); const associatedFields = useAssociatedTableColumnInitializerFields(); const inheritFields = useInheritsTableColumnInitializerFields(); @@ -41,7 +42,7 @@ export const TableColumnInitializers = (props: any) => { ); }); } - if (associatedFields?.length > 0 && !isSubTable) { + if (associatedFields?.length > 0 && field.readPretty) { fieldItems.push( { type: 'divider', diff --git a/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx b/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx index 490fe0fada..540df7b890 100644 --- a/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx +++ b/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx @@ -1,8 +1,8 @@ import { DownOutlined, PlusOutlined } from '@ant-design/icons'; import { css } from '@emotion/css'; import { RecursionField, observer, useField, useFieldSchema } from '@formily/react'; -import { Button, Dropdown, Menu } from 'antd'; -import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, MenuProps } from 'antd'; +import React, { useEffect, useMemo, useState } from 'react'; import { useDesignable } from '../../'; import { useACLRolesCheck, useRecordPkValue } from '../../acl/ACLProvider'; import { CollectionProvider, useCollection, useCollectionManager } from '../../collection-manager'; @@ -131,44 +131,44 @@ export const CreateAction = observer( const componentType = field.componentProps.type || 'primary'; const { getChildrenCollections } = useCollectionManager(); const totalChildCollections = getChildrenCollections(collection.name); - const inheritsCollections = enableChildren - .map((k) => { - if (!k) { - return; - } - const childCollection = totalChildCollections.find((j) => j.name === k.collection); - if (!childCollection) { - return; - } - return { - ...childCollection, - title: k.title || childCollection.title, - }; - }) - .filter((v) => { - return v && actionAclCheck(`${v.name}:create`); - }); + const inheritsCollections = useMemo(() => { + return enableChildren + .map((k) => { + if (!k) { + return; + } + const childCollection = totalChildCollections.find((j) => j.name === k.collection); + if (!childCollection) { + return; + } + return { + ...childCollection, + title: k.title || childCollection.title, + }; + }) + .filter((v) => { + return v && actionAclCheck(`${v.name}:create`); + }); + }, [enableChildren, totalChildCollections]); const linkageRules = fieldSchema?.['x-linkage-rules'] || []; const values = useRecord(); const compile = useCompile(); const { designable } = useDesignable(); const icon = props.icon || ; - const menu = ( - - {inheritsCollections.map((option) => { - return ( - { - onClick?.(option.name); - }} - > - {compile(option.title)} - - ); - })} - - ); + const menuItems = useMemo(() => { + return inheritsCollections.map((option) => ({ + key: option.name, + label: compile(option.title), + onClick: () => onClick?.(option.name), + })); + }, [inheritsCollections, onClick]); + + const menu = useMemo(() => { + return { + items: menuItems, + }; + }, [menuItems]); + useEffect(() => { field.linkageProperty = {}; linkageRules @@ -190,7 +190,7 @@ export const CreateAction = observer( leftButton, React.cloneElement(rightButton as React.ReactElement, { loading: false }), ]} - overlay={menu} + menu={menu} onClick={(info) => { onClick?.(collection.name); }} @@ -199,7 +199,7 @@ export const CreateAction = observer( {props.children} ) : ( - + { ) : null} diff --git a/packages/plugins/workflow/src/client/locale/zh-CN.ts b/packages/plugins/workflow/src/client/locale/zh-CN.ts index 7fdee99685..37f4c443f2 100644 --- a/packages/plugins/workflow/src/client/locale/zh-CN.ts +++ b/packages/plugins/workflow/src/client/locale/zh-CN.ts @@ -171,6 +171,13 @@ export default { 'Update record': '更新数据', 'Update records of a collection. You can use variables from upstream nodes as query conditions and field values.': '更新一个数据表中的数据。可以使用上游节点里的变量作为查询条件和数据值。', + 'Update mode': '更新模式', + 'Update in a batch': '批量更新', + 'Update one by one': '逐条更新', + 'Update all eligible data at one time, which has better performance when the amount of data is large. But the updated data will not trigger other workflows, and will not record audit logs.': + '一次性更新所有符合条件的数据,在数据量较大时有比较好的性能;但被更新的数据不会触发其他工作流,也不会记录更新日志。', + 'The updated data can trigger other workflows, and the audit log will also be recorded. But it is usually only applicable to several or dozens of pieces of data, otherwise there will be performance problems.': + '被更新的数据可以再次触发其他工作流,也会记录更新日志;但通常只适用于数条或数十条数据,否则会有性能问题。', 'Query record': '查询数据', 'Query records from a collection. You can use variables from upstream nodes as query conditions.': '查询一个数据表中的数据。可以使用上游节点里的变量作为查询条件。', diff --git a/packages/plugins/workflow/src/client/nodes/index.tsx b/packages/plugins/workflow/src/client/nodes/index.tsx index 2e0e0b7471..b374d5cd97 100644 --- a/packages/plugins/workflow/src/client/nodes/index.tsx +++ b/packages/plugins/workflow/src/client/nodes/index.tsx @@ -240,7 +240,7 @@ function InnerJobButton({ job, ...props }) { const { icon, color } = JobStatusOptionsMap[job.status]; return ( - ); @@ -292,7 +292,7 @@ export function JobButton() { } `} > - + {icon} diff --git a/packages/plugins/workflow/src/client/nodes/update.tsx b/packages/plugins/workflow/src/client/nodes/update.tsx index 760f19323f..06588c6afa 100644 --- a/packages/plugins/workflow/src/client/nodes/update.tsx +++ b/packages/plugins/workflow/src/client/nodes/update.tsx @@ -1,11 +1,43 @@ +import React from 'react'; +import { onFieldInputValueChange } from '@formily/core'; +import { useForm, useField } from '@formily/react'; + import { useCollectionDataSource } from '@nocobase/client'; import { FilterDynamicComponent } from '../components/FilterDynamicComponent'; -import CollectionFieldset from '../components/CollectionFieldset'; +import CollectionFieldset, { useCollectionUIFields } from '../components/CollectionFieldset'; import { isValidFilter } from '../utils'; import { NAMESPACE } from '../locale'; import { collection, filter, values } from '../schemas/collection'; +import { RadioWithTooltip } from '../components/RadioWithTooltip'; + +function IndividualHooksRadioWithTooltip({ onChange, ...props }) { + const form = useForm(); + const { collection } = form.values; + const fields = useCollectionUIFields(collection); + const field = useField(); + + function onValueChange({ target }) { + const valuesField = field.query('.values').take(); + if (!valuesField) { + return; + } + const filteredValues = fields.reduce((result, item) => { + if ( + item.name in valuesField.value && + (target.value || !['hasOne', 'hasMany', 'belongsToMany'].includes(item.type)) + ) { + result[item.name] = valuesField.value[item.name]; + } + return result; + }, {}); + form.setValuesIn('params.values', filteredValues); + + onChange(target.value); + } + return ; +} export default { title: `{{t("Update record", { ns: "${NAMESPACE}" })}}`, @@ -17,6 +49,27 @@ export default { params: { type: 'object', properties: { + individualHooks: { + type: 'boolean', + title: `{{t("Update mode", { ns: "${NAMESPACE}" })}}`, + 'x-decorator': 'FormItem', + 'x-component': 'IndividualHooksRadioWithTooltip', + 'x-component-props': { + options: [ + { + label: `{{t("Update in a batch", { ns: "${NAMESPACE}" })}}`, + value: false, + tooltip: `{{t("Update all eligible data at one time, which has better performance when the amount of data is large. But the updated data will not trigger other workflows, and will not record audit logs.", { ns: "${NAMESPACE}" })}}`, + }, + { + label: `{{t("Update one by one", { ns: "${NAMESPACE}" })}}`, + value: true, + tooltip: `{{t("The updated data can trigger other workflows, and the audit log will also be recorded. But it is usually only applicable to several or dozens of pieces of data, otherwise there will be performance problems.", { ns: "${NAMESPACE}" })}}`, + }, + ], + }, + default: false, + }, filter: { ...filter, title: `{{t("Only update records matching conditions", { ns: "${NAMESPACE}" })}}`, @@ -24,7 +77,14 @@ export default { return isValidFilter(value) ? '' : `{{t("Please add at least one condition", { ns: "${NAMESPACE}" })}}`; }, }, - values, + values: { + ...values, + 'x-component-props': { + filter(this, field) { + return this.params?.individualHooks || !['hasOne', 'hasMany', 'belongsToMany'].includes(field.type); + }, + }, + }, }, }, }, @@ -35,5 +95,6 @@ export default { components: { FilterDynamicComponent, CollectionFieldset, + IndividualHooksRadioWithTooltip, }, }; diff --git a/packages/plugins/workflow/src/client/style.tsx b/packages/plugins/workflow/src/client/style.tsx index 22a051bc11..5e7623c762 100644 --- a/packages/plugins/workflow/src/client/style.tsx +++ b/packages/plugins/workflow/src/client/style.tsx @@ -255,6 +255,10 @@ export const nodeJobButtonClass = css` border: none; } + &.inner{ + position: static; + } + .ant-tag { padding: 0; width: 100%; diff --git a/packages/plugins/workflow/src/client/triggers/index.tsx b/packages/plugins/workflow/src/client/triggers/index.tsx index 1a2caf618b..1bee28ebbd 100644 --- a/packages/plugins/workflow/src/client/triggers/index.tsx +++ b/packages/plugins/workflow/src/client/triggers/index.tsx @@ -141,6 +141,7 @@ export const TriggerConfig = () => { const { workflow, refresh } = useFlowContext(); const [editingTitle, setEditingTitle] = useState(''); const [editingConfig, setEditingConfig] = useState(false); + let typeTitle = ''; useEffect(() => { if (workflow) { setEditingTitle(workflow.title ?? typeTitle); @@ -151,7 +152,9 @@ export const TriggerConfig = () => { return null; } const { title, type, config, executed } = workflow; - const { title: typeTitle, fieldset, scope, components } = triggers.get(type); + const trigger = triggers.get(type); + const { fieldset, scope, components } = trigger; + typeTitle = trigger.title; const detailText = executed ? '{{t("View")}}' : '{{t("Configure")}}'; const titleText = `${lang('Trigger')}: ${compile(typeTitle)}`; diff --git a/packages/plugins/workflow/src/server/Plugin.ts b/packages/plugins/workflow/src/server/Plugin.ts index fb1104030f..e20429b369 100644 --- a/packages/plugins/workflow/src/server/Plugin.ts +++ b/packages/plugins/workflow/src/server/Plugin.ts @@ -161,7 +161,9 @@ export default class WorkflowPlugin extends Plugin { workflows.forEach((workflow: WorkflowModel) => { this.toggle(workflow); }); + }); + this.app.on('afterStart', () => { // check for not started executions this.dispatch(); }); @@ -201,8 +203,9 @@ export default class WorkflowPlugin extends Plugin { this.events.push([workflow, context, options]); - this.getLogger(workflow.id).debug(`new event triggered, now events: ${this.events.length}`, { - data: workflow.config, + this.getLogger(workflow.id).info(`new event triggered, now events: ${this.events.length}`); + this.getLogger(workflow.id).debug(`event data:`, { + data: context, }); if (this.events.length > 1) { diff --git a/packages/plugins/workflow/src/server/Processor.ts b/packages/plugins/workflow/src/server/Processor.ts index 95ba65d4a8..2a6618b6a9 100644 --- a/packages/plugins/workflow/src/server/Processor.ts +++ b/packages/plugins/workflow/src/server/Processor.ts @@ -109,7 +109,7 @@ export default class Processor { const head = this.nodes.find((item) => !item.upstream); await this.run(head, { result: execution.context }); } else { - await this.exit(null); + await this.exit(JOB_STATUS.RESOLVED); } } @@ -192,7 +192,7 @@ export default class Processor { } // parent node should take over the control - public async end(node, job) { + public async end(node, job: JobModel) { this.logger.debug(`branch ended at node (${node.id})`); const parentNode = this.findBranchParentNode(node); // no parent, means on main flow @@ -204,7 +204,7 @@ export default class Processor { // really done for all nodes // * should mark execution as done with last job status - return this.exit(job); + return this.exit(job.status); } async recall(node, job) { @@ -217,12 +217,12 @@ export default class Processor { return this.exec(instruction.resume.bind(instruction), node, job); } - async exit(job: JobModel | null) { - const status = job - ? (this.constructor).StatusMap[job.status] ?? Math.sign(job.status) - : EXECUTION_STATUS.RESOLVED; - this.logger.info(`execution (${this.execution.id}) all nodes finished, finishing execution...`); - await this.execution.update({ status }, { transaction: this.transaction }); + async exit(s?: number) { + if (typeof s === 'number') { + const status = (this.constructor).StatusMap[s] ?? Math.sign(s); + await this.execution.update({ status }, { transaction: this.transaction }); + } + this.logger.info(`execution (${this.execution.id}) exiting with status ${this.execution.status}`); await this.commit(); return null; } @@ -235,9 +235,8 @@ export default class Processor { if (payload instanceof model) { job = await payload.save({ transaction: this.transaction }); } else if (payload.id) { - [job] = await model.update(payload, { - where: { id: payload.id }, - returning: true, + job = await model.findByPk(payload.id); + await job.update(payload, { transaction: this.transaction, }); } else { diff --git a/packages/plugins/workflow/src/server/__tests__/instructions/update.test.ts b/packages/plugins/workflow/src/server/__tests__/instructions/update.test.ts index 2a80d62123..69a104fedf 100644 --- a/packages/plugins/workflow/src/server/__tests__/instructions/update.test.ts +++ b/packages/plugins/workflow/src/server/__tests__/instructions/update.test.ts @@ -18,7 +18,6 @@ describe('workflow > instructions > update', () => { PostRepo = db.getCollection('posts').repository; workflow = await WorkflowModel.create({ - title: 'test workflow', enabled: true, type: 'collection', config: { @@ -54,51 +53,137 @@ describe('workflow > instructions > update', () => { const [execution] = await workflow.getExecutions(); const [job] = await execution.getJobs(); - expect(job.result.published).toBe(true); + expect(job.result).toBe(1); const updatedPost = await PostRepo.findById(post.id); expect(updatedPost.published).toBe(true); }); + + it('params: from job of node', async () => { + const n1 = await workflow.createNode({ + type: 'query', + config: { + collection: 'posts', + params: { + filter: { + title: 'test', + }, + }, + }, + }); + + const n2 = await workflow.createNode({ + type: 'update', + config: { + collection: 'posts', + params: { + filter: { + id: `{{$jobsMapByNodeId.${n1.id}.id}}`, + }, + values: { + title: 'changed', + }, + }, + }, + upstreamId: n1.id, + }); + + await n1.setDownstream(n2); + + // NOTE: the result of post immediately created will not be changed by workflow + const { id } = await PostRepo.create({ values: { title: 'test' } }); + + await sleep(500); + + // should get from db + const post = await PostRepo.findById(id); + expect(post.title).toBe('changed'); + }); }); - it('params: from job of node', async () => { - const n1 = await workflow.createNode({ - type: 'query', - config: { - collection: 'posts', - params: { - filter: { - title: 'test', + describe('update batch', () => { + it('individualHooks off should not trigger other workflow', async () => { + const w2 = await WorkflowModel.create({ + enabled: true, + type: 'collection', + config: { + mode: 2, + collection: 'posts', + }, + }); + + const n1 = await workflow.createNode({ + type: 'update', + config: { + collection: 'posts', + params: { + filter: { + id: '{{$context.data.id}}', + }, + values: { + published: true, + }, + individualHooks: false, }, }, - }, + }); + + const post = await PostRepo.create({ values: { title: 't1' } }); + expect(post.published).toBe(false); + + await sleep(500); + + const [execution] = await workflow.getExecutions(); + const [job] = await execution.getJobs(); + expect(job.result).toBe(1); + + const updatedPost = await PostRepo.findById(post.id); + expect(updatedPost.published).toBe(true); + + const w2Exes = await w2.getExecutions(); + expect(w2Exes.length).toBe(0); }); - const n2 = await workflow.createNode({ - type: 'update', - config: { - collection: 'posts', - params: { - filter: { - id: `{{$jobsMapByNodeId.${n1.id}.id}}`, - }, - values: { - title: 'changed', + it('individualHooks on should trigger other workflow', async () => { + const w2 = await WorkflowModel.create({ + enabled: true, + type: 'collection', + config: { + mode: 2, + collection: 'posts', + }, + }); + + const n1 = await workflow.createNode({ + type: 'update', + config: { + collection: 'posts', + params: { + filter: { + id: '{{$context.data.id}}', + }, + values: { + published: true, + }, + individualHooks: true, }, }, - }, - upstreamId: n1.id, + }); + + const post = await PostRepo.create({ values: { title: 't1' } }); + expect(post.published).toBe(false); + + await sleep(500); + + const [execution] = await workflow.getExecutions(); + const [job] = await execution.getJobs(); + expect(job.result).toBe(1); + + const updatedPost = await PostRepo.findById(post.id); + expect(updatedPost.published).toBe(true); + + const w2Exes = await w2.getExecutions(); + expect(w2Exes.length).toBe(1); }); - - await n1.setDownstream(n2); - - // NOTE: the result of post immediately created will not be changed by workflow - const { id } = await PostRepo.create({ values: { title: 'test' } }); - - await sleep(500); - - // should get from db - const post = await PostRepo.findById(id); - expect(post.title).toBe('changed'); }); }); diff --git a/packages/plugins/workflow/src/server/instructions/delay.ts b/packages/plugins/workflow/src/server/instructions/delay.ts index 6dafe578f6..93bae78a62 100644 --- a/packages/plugins/workflow/src/server/instructions/delay.ts +++ b/packages/plugins/workflow/src/server/instructions/delay.ts @@ -90,7 +90,7 @@ export default class implements Instruction { // add to schedule this.schedule(job, duration); - return processor.end(node, job); + return processor.exit(); }; resume = async (node, prevJob, processor: Processor) => { diff --git a/packages/plugins/workflow/src/server/instructions/loop.ts b/packages/plugins/workflow/src/server/instructions/loop.ts index 9c703b0792..596ed631d2 100644 --- a/packages/plugins/workflow/src/server/instructions/loop.ts +++ b/packages/plugins/workflow/src/server/instructions/loop.ts @@ -57,7 +57,7 @@ export default { const { result, status } = job; // if loop has been done (resolved / rejected), do not care newly executed branch jobs. if (status !== JOB_STATUS.PENDING) { - return null; + return processor.exit(); } const nextIndex = result + 1; diff --git a/packages/plugins/workflow/src/server/instructions/manual/actions.ts b/packages/plugins/workflow/src/server/instructions/manual/actions.ts index 16804fe5e8..f2a7a32990 100644 --- a/packages/plugins/workflow/src/server/instructions/manual/actions.ts +++ b/packages/plugins/workflow/src/server/instructions/manual/actions.ts @@ -65,7 +65,7 @@ export async function submit(context: Context, next) { await userJob.save({ transaction: processor.transaction }); - await processor.exit(userJob.job); + await processor.exit(); context.body = userJob; context.status = 202; diff --git a/packages/plugins/workflow/src/server/instructions/parallel.ts b/packages/plugins/workflow/src/server/instructions/parallel.ts index 4018c44442..d0cda6a8bf 100644 --- a/packages/plugins/workflow/src/server/instructions/parallel.ts +++ b/packages/plugins/workflow/src/server/instructions/parallel.ts @@ -96,7 +96,7 @@ export default { const { result, status } = job; // if parallel has been done (resolved / rejected), do not care newly executed branch jobs. if (status !== JOB_STATUS.PENDING) { - return null; + return processor.exit(); } // find the index of the node which start the branch @@ -114,7 +114,7 @@ export default { if (job.status === JOB_STATUS.PENDING) { await job.save({ transaction: processor.transaction }); - return processor.end(node, job); + return processor.exit(); } return job; diff --git a/packages/plugins/workflow/src/server/instructions/request.ts b/packages/plugins/workflow/src/server/instructions/request.ts index 5b1db106a4..41b950f084 100644 --- a/packages/plugins/workflow/src/server/instructions/request.ts +++ b/packages/plugins/workflow/src/server/instructions/request.ts @@ -67,13 +67,13 @@ export default class implements Instruction { }); }) .finally(() => { - this.plugin.app.logger.info(`[Workflow] request (#${node.id}) response received, status: ${job.get('status')}`); + processor.logger.info(`request (#${node.id}) response received, status: ${job.get('status')}`); this.plugin.resume(job); }); - this.plugin.app.logger.info(`[Workflow] request (#${node.id}) sent to "${config.url}", waiting for response...`); + processor.logger.info(`request (#${node.id}) sent to "${config.url}", waiting for response...`); - return null; + return processor.exit(); } async resume(node: FlowNodeModel, job, processor: Processor) { diff --git a/packages/plugins/workflow/src/server/instructions/update.ts b/packages/plugins/workflow/src/server/instructions/update.ts index 6ac3ee371c..94848172e0 100644 --- a/packages/plugins/workflow/src/server/instructions/update.ts +++ b/packages/plugins/workflow/src/server/instructions/update.ts @@ -4,7 +4,7 @@ import { JOB_STATUS } from '../constants'; export default { async run(node: FlowNodeModel, input, processor: Processor) { - const { collection, multiple = false, params = {} } = node.config; + const { collection, params = {} } = node.config; const repo = (node.constructor).database.getRepository(collection); const options = processor.getParsedValue(params, node); @@ -17,7 +17,7 @@ export default { }); return { - result: multiple ? result : result[0] || null, + result: result.length ?? result, status: JOB_STATUS.RESOLVED, }; }, diff --git a/yarn.lock b/yarn.lock index 875f1c0e43..1529091186 100644 --- a/yarn.lock +++ b/yarn.lock @@ -163,10 +163,10 @@ classnames "^2.2.6" rc-util "^5.9.4" -"@ant-design/icons@^5.1.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.1.2.tgz#6dc30c5caff0670f11b6391f0839ed41847c72e6" - integrity sha512-sSorFv+4e5nkSq9vD7UHG2IQYUmR8jCO49+z4vn3MUeiM1G1qxCqh7JiR5pexVY0hZywHes/uxiNflAQZCWZ8Q== +"@ant-design/icons@^5.0.0", "@ant-design/icons@^5.1.0": + version "5.1.4" + resolved "https://registry.npmmirror.com/@ant-design/icons/-/icons-5.1.4.tgz#614e29e26d092c2c1c1a2acbc0d84434d8d1474e" + integrity sha512-YHKL7Jx3bM12OxvtiYDon04BsBT/6LGitYEqar3GljzWaAyMOAD8i/uF1Rsi5Us/YNdWWXBGSvZV2OZWMpJlcA== dependencies: "@ant-design/colors" "^7.0.0" "@ant-design/icons-svg" "^4.2.1" @@ -185,6 +185,52 @@ classnames "^2.2.6" rc-util "^5.31.1" +"@ant-design/pro-layout@^7.14.3": + version "7.14.3" + resolved "https://registry.npmmirror.com/@ant-design/pro-layout/-/pro-layout-7.14.3.tgz#01063883a334060c41b72ec084c3e83200673952" + integrity sha512-FcKj23f/laod2hfSSYfBbkjb9r74lZLgan8dylI+tngQnZKQc1o1a1f9If7CggkrhEdgDyIkIyFl9Ii/tfDa+A== + dependencies: + "@ant-design/icons" "^5.0.0" + "@ant-design/pro-provider" "^2.10.2" + "@ant-design/pro-utils" "^2.11.3" + "@babel/runtime" "^7.18.0" + "@umijs/route-utils" "^4.0.0" + "@umijs/use-params" "^1.0.9" + classnames "^2.3.2" + lodash.merge "^4.6.2" + omit.js "^2.0.2" + path-to-regexp "2.4.0" + rc-resize-observer "^1.1.0" + rc-util "^5.0.6" + swr "^2.0.0" + use-json-comparison "^1.0.3" + use-media-antd-query "^1.1.0" + warning "^4.0.3" + +"@ant-design/pro-provider@^2.10.2": + version "2.10.2" + resolved "https://registry.npmmirror.com/@ant-design/pro-provider/-/pro-provider-2.10.2.tgz#3338afa88f35fe06da8f3573e7cf31c323cad456" + integrity sha512-I0wfnP/fJUgGrl/9P5haMtITg8oHe2NOm83QKFVjqQWGYnA2V4O5rVqD+vdWveuaJ6rtCW8mEoeelfHF6nOnxw== + dependencies: + "@ant-design/cssinjs" "^1.9.1" + "@babel/runtime" "^7.18.0" + "@ctrl/tinycolor" "^3.4.0" + rc-util "^5.0.1" + swr "^2.0.0" + +"@ant-design/pro-utils@^2.11.3": + version "2.11.3" + resolved "https://registry.npmmirror.com/@ant-design/pro-utils/-/pro-utils-2.11.3.tgz#847da90763f4157bc5e273bf0aa018af13ec28ae" + integrity sha512-Sd2oHzhQlSJ0svaD3Ih3v2VeXPnYWwJ05ul+ek8i9GWAGnFWD0yDTawGj7pDZwCQwJYaLpAzPHhfNvq3Led0/w== + dependencies: + "@ant-design/icons" "^5.0.0" + "@ant-design/pro-provider" "^2.10.2" + "@babel/runtime" "^7.18.0" + classnames "^2.3.2" + dayjs "^1.11.4" + rc-util "^5.0.6" + swr "^2.0.0" + "@ant-design/react-slick@~0.29.1": version "0.29.2" resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-0.29.2.tgz#53e6a7920ea3562eebb304c15a7fc2d7e619d29c" @@ -2935,12 +2981,6 @@ version "0.8.0" resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" -"@babel/runtime@7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" - dependencies: - regenerator-runtime "^0.13.4" - "@babel/runtime@7.21.0", "@babel/runtime@^7.1.5", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" @@ -3394,7 +3434,7 @@ "@emotion/hash@^0.8.0": version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== "@emotion/hash@^0.9.1": @@ -3442,16 +3482,15 @@ "@emotion/sheet@^1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" - integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== "@emotion/stylis@^0.8.4": version "0.8.5" - resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + resolved "https://registry.npmmirror.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== "@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5": version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + resolved "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== "@emotion/unitless@^0.8.1": @@ -3857,76 +3896,85 @@ intl-messageformat "10.3.5" tslib "^2.4.0" -"@formily/antd@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/antd/-/antd-2.2.24.tgz#d536cba6d4691b9c2089efd818cb85681a6d4c9b" +"@formily/antd@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/antd/-/antd-2.2.26.tgz#abfe15523932fec8527f9b6fe6e81a0f3f2d1678" + integrity sha512-uoUBR4IgCAL05eYvRJxZG54s1gI50fzTjpbVSFRLc+fzzEVn32Xuxt5/ANQmEvhLZWqxTgZHbyjkJKa/uXXokg== dependencies: - "@formily/core" "2.2.24" - "@formily/grid" "2.2.24" - "@formily/json-schema" "2.2.24" - "@formily/react" "2.2.24" - "@formily/reactive" "2.2.24" - "@formily/reactive-react" "2.2.24" - "@formily/shared" "2.2.24" + "@formily/core" "2.2.26" + "@formily/grid" "2.2.26" + "@formily/json-schema" "2.2.26" + "@formily/react" "2.2.26" + "@formily/reactive" "2.2.26" + "@formily/reactive-react" "2.2.26" + "@formily/shared" "2.2.26" classnames "^2.2.6" react-sortable-hoc "^1.11.0" react-sticky-box "^0.9.3" -"@formily/core@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/core/-/core-2.2.24.tgz#b96b72def806ee4c71c0a0279b678ffcc23828bf" +"@formily/core@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/core/-/core-2.2.26.tgz#4a80171ef5b38ff64b9308b5bd0174b0212fc949" + integrity sha512-K0hQtb1xyLVnIZIHq0X8wMxv4V7f+8ON3Rlz9wQlx2raVVyFzS+9Y92O5VncnFMAK3W77Zvz1bXz95oo1u0Q0A== dependencies: - "@formily/reactive" "2.2.24" - "@formily/shared" "2.2.24" - "@formily/validator" "2.2.24" + "@formily/reactive" "2.2.26" + "@formily/shared" "2.2.26" + "@formily/validator" "2.2.26" -"@formily/grid@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/grid/-/grid-2.2.24.tgz#e5e1163ef9597a4417fc2f2f4e438d48c0d3dd59" +"@formily/grid@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/grid/-/grid-2.2.26.tgz#1bf523693f9d38fb2a9e0fd9e0e135b9c27fc136" + integrity sha512-32SOe8yTxxN+ouVVVaYCnBDBPiNJ0z9AEyiO78ZgYqIU1IcV6eYLU+T2505+KLEDrWGd5pZdsSrn4dt+hfnfow== dependencies: - "@formily/reactive" "2.2.24" + "@formily/reactive" "2.2.26" "@juggle/resize-observer" "^3.3.1" -"@formily/json-schema@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/json-schema/-/json-schema-2.2.24.tgz#b23b9ae18a24fbcb716cd0e23677c8597abc5689" +"@formily/json-schema@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/json-schema/-/json-schema-2.2.26.tgz#04c92f0bf6cfa7822f085efe0e28eec6bf888332" + integrity sha512-SGcrL1bCgQmOCRG8zDSau/SSuaylRifnUMOoeQ2Ctb9OLYkkrJb2KVz8Sb+pRyE1SD/rLmCCmEN5AMWsMDtjlw== dependencies: - "@formily/core" "2.2.24" - "@formily/reactive" "2.2.24" - "@formily/shared" "2.2.24" + "@formily/core" "2.2.26" + "@formily/reactive" "2.2.26" + "@formily/shared" "2.2.26" -"@formily/path@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/path/-/path-2.2.24.tgz#1c15352dc72f78ef3e8924633a9d8a8182364d6b" +"@formily/path@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/path/-/path-2.2.26.tgz#b72453c293963c358a729a69a7c9b88e31ec449e" + integrity sha512-Bwc492hlbzmAyOllgMP/ZHPw+y3LqQumriOqup27TJwPBGMO4Ri9A5djftVmeDnX69NmB4BO/X0lVUnRuK/8jw== -"@formily/react@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/react/-/react-2.2.24.tgz#415ca8df2c445ba43fe596d0a6e8bd4236abe8d6" +"@formily/react@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/react/-/react-2.2.26.tgz#275bafae41a8440d62903c6a4b429848acfed0f6" + integrity sha512-fBlzoFt0fL9p58isJeg/Ir9TqtwaqhSlmrKdwvFkOQJXGTp6sMPlrQHBZiVpfsmzUuApe4CKYfPfT6PpdtHQXw== dependencies: - "@formily/core" "2.2.24" - "@formily/json-schema" "2.2.24" - "@formily/reactive" "2.2.24" - "@formily/reactive-react" "2.2.24" - "@formily/shared" "2.2.24" - "@formily/validator" "2.2.24" + "@formily/core" "2.2.26" + "@formily/json-schema" "2.2.26" + "@formily/reactive" "2.2.26" + "@formily/reactive-react" "2.2.26" + "@formily/shared" "2.2.26" + "@formily/validator" "2.2.26" hoist-non-react-statics "^3.3.2" -"@formily/reactive-react@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/reactive-react/-/reactive-react-2.2.24.tgz#187e6f07b1aab09f41134c4335200b38afdcc67c" +"@formily/reactive-react@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/reactive-react/-/reactive-react-2.2.26.tgz#6c145502d75e68eb3d02399f7c635aacc17d91d8" + integrity sha512-VnoRtwvVZU0kZyu54n17F3VuqpULNG4rto61seJTiR1+nZVW71i66+meXj37XjbgD9qbVmIvdt1QoVcODVbYHw== dependencies: - "@formily/reactive" "2.2.24" + "@formily/reactive" "2.2.26" hoist-non-react-statics "^3.3.2" -"@formily/reactive@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/reactive/-/reactive-2.2.24.tgz#758b0fb26568970cbd326e1abb86f0264713f0c1" +"@formily/reactive@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/reactive/-/reactive-2.2.26.tgz#f1cc26bffe542508773c8867ccc458741a7ce19d" + integrity sha512-eKCrFIFTm02CGGu99GCK4lBTte+hQecwjMKKmReeQ53QWZJZhSidnDgn4uoDme3m7CEsRJEMhhAhQnU5rENhtA== -"@formily/shared@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/shared/-/shared-2.2.24.tgz#f7939d8a36796db7fce580c2e6c52d04fed1b13b" +"@formily/shared@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/shared/-/shared-2.2.26.tgz#7efab8c79f30348552b4f322be62019b0a159407" + integrity sha512-PvAX3FvNu4PvZ4vXJKoDsVgGzhXEMD4+yPvekTHT8+wkJCFuU2P8/PDEhP+kJrmJ/rE2q51eNGOshjdcDdOOmQ== dependencies: - "@formily/path" "2.2.24" + "@formily/path" "2.2.26" camel-case "^4.1.1" lower-case "^2.0.1" no-case "^3.0.4" @@ -3934,11 +3982,12 @@ pascal-case "^3.1.1" upper-case "^2.0.1" -"@formily/validator@2.2.24": - version "2.2.24" - resolved "https://registry.yarnpkg.com/@formily/validator/-/validator-2.2.24.tgz#03fc909fe93694e895d73e6d9e445a9f89bc1d51" +"@formily/validator@2.2.26": + version "2.2.26" + resolved "https://registry.npmmirror.com/@formily/validator/-/validator-2.2.26.tgz#c4356ea849d67a11a2b85164eb028b31ca88ff15" + integrity sha512-b6Z7/VHQtPV6HrVGL+6yZv32Or99+UIxKpXEP48zSE+Nfie/thxsflieo/cFPpZphxKHfqLx1VY0HnRH+/M+WA== dependencies: - "@formily/shared" "2.2.24" + "@formily/shared" "2.2.26" "@formulajs/formulajs@4.2.0": version "4.2.0" @@ -7075,48 +7124,6 @@ dependencies: "@umijs/bundler-utils" "4.0.69" -"@umijs/babel-plugin-auto-css-modules@3.5.39": - version "3.5.39" - resolved "https://registry.npmmirror.com/@umijs/babel-plugin-auto-css-modules/-/babel-plugin-auto-css-modules-3.5.39.tgz#7b35c5d9cb36fe7b2d582c5fc1f7f0000bcbc0bd" - integrity sha512-T/gaGdti7xFqXRB07aEpmQN/hnhOBYf2AZ56A4SYBIALGeLxKP89L4Y21Gi1CbQUC2ma+JGAFZnfMsNpokzCUg== - dependencies: - "@umijs/utils" "3.5.39" - -"@umijs/babel-plugin-import-to-await-require@3.5.39": - version "3.5.39" - resolved "https://registry.npmmirror.com/@umijs/babel-plugin-import-to-await-require/-/babel-plugin-import-to-await-require-3.5.39.tgz#cbdbd685faac379c5f548aef9b57c278aceac58b" - integrity sha512-RaXWe7c2dWPMcSokAEN5tlP0pBCC6tL11/B3yEbmhL721bgs9JxVKn5sVBW1Sn+PTG+Liqe6/PGiDUDjzs/V5g== - dependencies: - "@umijs/utils" "3.5.39" - -"@umijs/babel-plugin-lock-core-js-3@3.5.39": - version "3.5.39" - resolved "https://registry.npmmirror.com/@umijs/babel-plugin-lock-core-js-3/-/babel-plugin-lock-core-js-3-3.5.39.tgz#934b7cbf16b4168392576e8a7c906c81335a2848" - integrity sha512-7vzlDAMzV7H+jfka0l7Q+MqDkUZGDuMeHRu/voZcxawZoZ6xI23xvmJcd4S9WWEoUdNcxb1bI1kwIU/h4tUFcQ== - dependencies: - "@umijs/utils" "3.5.39" - core-js "3.6.5" - -"@umijs/babel-plugin-no-anonymous-default-export@3.5.39": - version "3.5.39" - resolved "https://registry.npmmirror.com/@umijs/babel-plugin-no-anonymous-default-export/-/babel-plugin-no-anonymous-default-export-3.5.39.tgz#22fa818acd3cd74074f459fedf01a9284e06a06c" - integrity sha512-3BGK6zhO2rDtYPrya1P/Kw+xcCgKEXOZA17YapVm5ykOOE2/BE2sKfkkPl6JsLtdJ93CoaldYgnVHpLEPwjekg== - dependencies: - "@umijs/utils" "3.5.39" - -"@umijs/babel-preset-umi@3.5.39": - version "3.5.39" - resolved "https://registry.npmmirror.com/@umijs/babel-preset-umi/-/babel-preset-umi-3.5.39.tgz#d339071bb20a99ad78137e3670b0762427273467" - integrity sha512-35Wl3kB6am3SGMuQ7R2JAsyiD8tm1KIuFDzwO7ywiYAR9zUIwWN7egpT4qq6U0bfhs2U7nXFucU+4GWMVD1kHQ== - dependencies: - "@babel/runtime" "7.18.6" - "@umijs/babel-plugin-auto-css-modules" "3.5.39" - "@umijs/babel-plugin-import-to-await-require" "3.5.39" - "@umijs/babel-plugin-lock-core-js-3" "3.5.39" - "@umijs/babel-plugin-no-anonymous-default-export" "3.5.39" - "@umijs/deps" "3.5.39" - "@umijs/utils" "3.5.39" - "@umijs/babel-preset-umi@4.0.69": version "4.0.69" resolved "https://registry.yarnpkg.com/@umijs/babel-preset-umi/-/babel-preset-umi-4.0.69.tgz#094b46e84e4eda73a92916fb4b2801aa29470c5e" @@ -7205,10 +7212,10 @@ "@umijs/bundler-utils" "4.0.69" "@umijs/utils" "4.0.69" -"@umijs/deps@3.5.39": - version "3.5.39" - resolved "https://registry.npmmirror.com/@umijs/deps/-/deps-3.5.39.tgz#5ab1063cd7051244c2780380529953ae5b35bd85" - integrity sha512-V7vTEeq8iyp6LVM1tOfqBQKeYldASmJ64KQyeslafEJHpagnR8lCUWZSrsX6yx8kOibiDwWOaiCJacipx7iYGg== +"@umijs/deps@3.5.20": + version "3.5.20" + resolved "https://registry.yarnpkg.com/@umijs/deps/-/deps-3.5.20.tgz#002ad616fbe5c8b238f80fc9289d0aceb9b89c3c" + integrity sha512-75iqB0+ITFtxlLb945W2b6lVEgLWRFXaSQZD+wH6c4/WDiagOdYMWX9aiPs2JSzoM/yCtKpMaLeGbmVXsb7y4g== dependencies: "@bloomberg/record-tuple-polyfill" "0.0.3" chokidar "3.5.1" @@ -7216,7 +7223,6 @@ esbuild "0.12.15" jest-worker "24.9.0" prettier "2.2.1" - regenerate-unicode-properties "10.0.1" "@umijs/did-you-know@1.0.3": version "1.0.3" @@ -7376,6 +7382,11 @@ react-helmet-async "1.3.0" react-router-dom "6.3.0" +"@umijs/route-utils@^4.0.0": + version "4.0.1" + resolved "https://registry.npmmirror.com/@umijs/route-utils/-/route-utils-4.0.1.tgz#156df5b3f2328059722d3ee7dd8f65e18c3cde8b" + integrity sha512-+1ixf1BTOLuH+ORb4x8vYMPeIt38n9q0fJDwhv9nSxrV46mxbLF0nmELIo9CKQB2gHfuC4+hww6xejJ6VYnBHQ== + "@umijs/server@4.0.69": version "4.0.69" resolved "https://registry.yarnpkg.com/@umijs/server/-/server-4.0.69.tgz#6819612ee294ae432a37b7c673ea39e39a6aa7ef" @@ -7406,12 +7417,17 @@ resolved "https://registry.yarnpkg.com/@umijs/ui/-/ui-3.0.1.tgz#64ae7ef36bf9374823f7361a7a844876d96c9e06" integrity sha512-zcz37AJH0xt/6XVVbyO/hmsK9Hq4vH23HZ4KYVi5A8rbM9KeJkJigTS7ELOdArawZhVNGe+h3a5Oixs4a2QsWw== -"@umijs/utils@3.5.39", "@umijs/utils@^3.5.20": - version "3.5.39" - resolved "https://registry.yarnpkg.com/@umijs/utils/-/utils-3.5.39.tgz#86a57e262bfbdbc356cdcacaf415b11b1a450e12" +"@umijs/use-params@^1.0.9": + version "1.0.9" + resolved "https://registry.npmmirror.com/@umijs/use-params/-/use-params-1.0.9.tgz#0ae4a87f4922d8e8e3fb4495b0f8f4de9ca38c52" + integrity sha512-QlN0RJSBVQBwLRNxbxjQ5qzqYIGn+K7USppMoIOVlf7fxXHsnQZ2bEsa6Pm74bt6DVQxpUE8HqvdStn6Y9FV1w== + +"@umijs/utils@3.5.20": + version "3.5.20" + resolved "https://registry.yarnpkg.com/@umijs/utils/-/utils-3.5.20.tgz#45e89eeac734a3963205d55b0f533bd96492f3b9" + integrity sha512-Y0i27zZTCKoqdHHyTuebO/GOIY4gGLUwDFs1eoH+m4etPn+uRq0iax9KJOkelmax2K3YLsT4KbRwM1enlSsv3A== dependencies: - "@umijs/babel-preset-umi" "3.5.39" - "@umijs/deps" "3.5.39" + "@umijs/deps" "3.5.20" "@umijs/utils@4.0.69": version "4.0.69" @@ -10287,10 +10303,6 @@ core-js@3.28.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.28.0.tgz#ed8b9e99c273879fdfff0edfc77ee709a5800e4a" integrity sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw== -core-js@3.6.5: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - core-js@^2.4.0: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" @@ -11113,13 +11125,15 @@ dateformat@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" -dayjs@1.x, dayjs@^1.11.1, dayjs@^1.11.7, dayjs@^1.9.1, dayjs@~1.11.5: - version "1.11.7" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" +dayjs@1.x, dayjs@^1.11.1, dayjs@^1.11.4, dayjs@^1.11.7, dayjs@^1.9.1, dayjs@~1.11.5: + version "1.11.8" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.8.tgz#4282f139c8c19dd6d0c7bd571e30c2d0ba7698ea" + integrity sha512-LcgxzFoWMEPO7ggRv1Y2N31hUf2R0Vj7fuy/m+Bg1K8rr+KAs1AEy4y9jd5DXe8pbHgX+srkHNS7TH6Q6ZhYeQ== dayjs@~1.8.24: version "1.8.36" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50" + integrity sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw== debounce-fn@^4.0.0: version "4.0.0" @@ -11727,10 +11741,10 @@ dumi-assets-types@2.0.0-alpha.0: resolved "https://registry.yarnpkg.com/dumi-assets-types/-/dumi-assets-types-2.0.0-alpha.0.tgz#46bf619ed1cb6d27bbe6a9cfe4be51e5e9589981" integrity sha512-a/Y5lf0G6gwsEQ9hop/n03CcjmHsGBk384Cz/AEX6mRYrfSpUx/lQvP9HLoXkCzScl9PL1sSmLPnMkgaXDCZLA== -dumi-theme-nocobase@^0.2.11: - version "0.2.11" - resolved "https://registry.npmjs.org/dumi-theme-nocobase/-/dumi-theme-nocobase-0.2.11.tgz#690c64cd284c913d7f6428bc291c3a6cdf0f2d50" - integrity sha512-hpMJPgIYeUIXKlfxYI1LD3KL4vr6ZlFzeSXNVqAurnlLmP5zkyiGekA/Azgg5zSkeWdaYa+fbB6CPAVE9RCZ+Q== +dumi-theme-nocobase@^0.2.12: + version "0.2.12" + resolved "https://registry.yarnpkg.com/dumi-theme-nocobase/-/dumi-theme-nocobase-0.2.12.tgz#663c9bab60ae6dcfd5255b99780b4ddb7942ace7" + integrity sha512-ObjJZkKWYqeZ+JlQGOX71vI+FPD9RxASYRrFZV9vpkIALwkLfolwX+8JZTHq9VS8dG3+3tAukVY25FOagVs4ZA== dependencies: "@ant-design/icons" "^5.1.3" "@babel/runtime" "^7.22.3" @@ -19239,6 +19253,11 @@ omit-deep@0.3.0: is-plain-object "^2.0.1" unset-value "^0.1.1" +omit.js@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/omit.js/-/omit.js-2.0.2.tgz#dd9b8436fab947a5f3ff214cb2538631e313ec2f" + integrity sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg== + on-exit-leak-free@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" @@ -19874,6 +19893,11 @@ path-to-regexp@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" +path-to-regexp@2.4.0: + version "2.4.0" + resolved "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" + integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== + path-to-regexp@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" @@ -21883,17 +21907,17 @@ rc-upload@~4.3.0: classnames "^2.2.5" rc-util "^5.2.0" -rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.2, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.21.2, rc-util@^5.22.5, rc-util@^5.23.0, rc-util@^5.24.4, rc-util@^5.26.0, rc-util@^5.27.0, rc-util@^5.4.0, rc-util@^5.6.1, rc-util@^5.8.0, rc-util@^5.9.4: - version "5.29.3" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.29.3.tgz#dc02b7b2103468e9fdf14e0daa58584f47898e37" +rc-util@^5.0.1, rc-util@^5.0.6, rc-util@^5.15.0, rc-util@^5.16.0, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.19.2, rc-util@^5.2.0, rc-util@^5.2.1, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.21.2, rc-util@^5.22.5, rc-util@^5.23.0, rc-util@^5.24.4, rc-util@^5.25.2, rc-util@^5.26.0, rc-util@^5.27.0, rc-util@^5.31.1, rc-util@^5.4.0, rc-util@^5.6.1, rc-util@^5.8.0, rc-util@^5.9.4: + version "5.33.0" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.33.0.tgz#8e673700e467b24c722014f2fe2f2f77aa6c2c07" dependencies: "@babel/runtime" "^7.18.3" react-is "^16.12.0" -rc-util@^5.21.5, rc-util@^5.25.2, rc-util@^5.27.1, rc-util@^5.28.0, rc-util@^5.31.1, rc-util@^5.33.0: - version "5.33.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.33.0.tgz#8e673700e467b24c722014f2fe2f2f77aa6c2c07" - integrity sha512-mq2NkEAnHklq4fgU/JqjiE0PS8+8u33gEWw2bDUNDPck3OroPpSgw/8oEyuFrvPgaZEmt9BgQdh59JfQt2cU+w== +rc-util@^5.21.5, rc-util@^5.27.1, rc-util@^5.28.0, rc-util@^5.33.0: + version "5.33.1" + resolved "https://registry.npmmirror.com/rc-util/-/rc-util-5.33.1.tgz#96e5814400e04b819bace502b6ca40a67f3be37f" + integrity sha512-oMs2OIV/2lUCF8nllevzLccneyxAzdSOaHSs5y91qOLdqaLbIMsuL49C6/DhF/WKMqiAKEKGdVk2F1sB5HQe9A== dependencies: "@babel/runtime" "^7.18.3" react-is "^16.12.0" @@ -21906,16 +21930,7 @@ rc-util@^5.30.0: "@babel/runtime" "^7.18.3" react-is "^16.12.0" -rc-virtual-list@^3.2.0: - version "3.4.13" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.13.tgz#20acc934b263abcf7b7c161f50ef82281b2f7e8d" - dependencies: - "@babel/runtime" "^7.20.0" - classnames "^2.2.6" - rc-resize-observer "^1.0.0" - rc-util "^5.15.0" - -rc-virtual-list@^3.4.8, rc-virtual-list@^3.5.2: +rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.8, rc-virtual-list@^3.5.2: version "3.5.2" resolved "https://registry.npmmirror.com/rc-virtual-list/-/rc-virtual-list-3.5.2.tgz#5e1028869bae900eacbae6788d4eca7210736006" integrity sha512-sE2G9hTPjVmatQni8OP2Kx33+Oth6DMKm67OblBBmgMBJDJQOOFpSGH7KZ6Pm85rrI2IGxDRXZCr0QhYOH2pfQ== @@ -22452,12 +22467,6 @@ reflect.ownkeys@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" -regenerate-unicode-properties@10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties@10.1.0, regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -22468,7 +22477,7 @@ regenerate@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" -regenerator-runtime@0.13.11, regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4: +regenerator-runtime@0.13.11, regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.2: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" @@ -24256,25 +24265,21 @@ stylehacks@^4.0.0: stylelint-config-recommended@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz#7497372ae83ab7a6fffc18d7d7b424c6480ae15e" + resolved "https://registry.npmmirror.com/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz#7497372ae83ab7a6fffc18d7d7b424c6480ae15e" integrity sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q== stylelint-config-standard@25.0.0: version "25.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-25.0.0.tgz#2c916984e6655d40d6e8748b19baa8603b680bff" + resolved "https://registry.npmmirror.com/stylelint-config-standard/-/stylelint-config-standard-25.0.0.tgz#2c916984e6655d40d6e8748b19baa8603b680bff" integrity sha512-21HnP3VSpaT1wFjFvv9VjvOGDtAviv47uTp3uFmzcN+3Lt+RYRv6oAplLaV51Kf792JSxJ6svCJh/G18E9VnCA== dependencies: stylelint-config-recommended "^7.0.0" -stylis@4.2.0, stylis@^4.0.13: +stylis@4.2.0, stylis@^4.0.13, stylis@^4.1.2: version "4.2.0" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + resolved "https://registry.npmmirror.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== -stylis@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" - superagent@^8.0.5: version "8.0.9" resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.0.9.tgz#2c6fda6fadb40516515f93e9098c0eb1602e0535" @@ -24409,6 +24414,13 @@ svgson@^4.1.0: omit-deep "0.3.0" xml-reader "2.4.3" +swr@^2.0.0: + version "2.1.5" + resolved "https://registry.npmmirror.com/swr/-/swr-2.1.5.tgz#688effa719c03f6d35c66decbb0f8e79c7190399" + integrity sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw== + dependencies: + use-sync-external-store "^1.2.0" + symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -25641,6 +25653,16 @@ use-isomorphic-layout-effect@^1.1.1: resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== +use-json-comparison@^1.0.3: + version "1.0.6" + resolved "https://registry.npmmirror.com/use-json-comparison/-/use-json-comparison-1.0.6.tgz#a012bbc258ce745db1f56745dc653f575226cb21" + integrity sha512-xPadt5yMRbEmVfOSGFSMqjjICrq7nLbfSH3rYIXsrtcuFX7PmbYDN/ku8ObBn3v8o/yZelO1OxUS5+5TI3+fUw== + +use-media-antd-query@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/use-media-antd-query/-/use-media-antd-query-1.1.0.tgz#f083ad7e292c1c0261b6bbfaac0edc3e0920d85d" + integrity sha512-B6kKZwNV4R+l4Rl11sWO7HqOay9alzs1Vp1b4YJqjz33YxbltBCZtt/yxXxkXN9rc1S7OeEL/GbwC30Wmqhw6Q== + use-memo-one@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" @@ -25889,7 +25911,7 @@ vite-node@0.32.0: vite@4.3.1: version "4.3.1" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.1.tgz#9badb1377f995632cdcf05f32103414db6fbb95a" + resolved "https://registry.npmmirror.com/vite/-/vite-4.3.1.tgz#9badb1377f995632cdcf05f32103414db6fbb95a" integrity sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg== dependencies: esbuild "^0.17.5" @@ -25898,9 +25920,9 @@ vite@4.3.1: optionalDependencies: fsevents "~2.3.2" -"vite@^3.0.0 || ^4.0.0", vite@^4.3.8: +"vite@^3.0.0 || ^4.0.0", vite@^4.3.9: version "4.3.9" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d" + resolved "https://registry.npmmirror.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d" integrity sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg== dependencies: esbuild "^0.17.5"