refactor(client)!: upgrade antd to v5 (#2078)

* refactor: change moment to dayjs

* refactor: remove antd css

* refactor: change @formily/antd to @formily/antd-v5

* chore: add dep

* chore: upgrade babel/core and typescript

* refactor: rename moment to dayjs

* fix(dayjs): add plugins

* refactor: fix type errors

* refactor: change default export to named export

* chore: upgrade ts-loader

* refactor: rename moment to dayjs

* refactor: fix type errors

* chore: upgrade deps for build

* fix: fix build errors

* fix: add antd reset css

* fix: fix build error

* chore: add __builtins__

* chore: optimize genStyleHook

* refactor(Calendar): less to css-in-js

* refactor(acl): less to css-in-js

* refactor(board): less to css-in-js

* chore: add antd-style

* refactor(acl): use antd-style

* refactor(board): use antd-style

* refactor: schema-initializer

* refactor: refactor genStyleHook

* refactor: kanban

* refactor: filter

* refactor: upload

* refactor: markdown

* refactor: rename className to componentCls

* refactor: rich-text

* style: fix style

* fix: fix merge error

* chore: update yarn.lock

* chore: upgrade formily

* style: fix pageHeader

* style: fix add button style

* style: fix header menu color

* chore: update yarn.lock

* chore: upgrade deps

* test: fix tests

* test: fix tests

* fix: fix build error

* fix: fix style of plugin doc

* fix: fix tests

* fix: fix drag bug

* refactor: remove useless code

* fix: fix Modal style (T-621)

* fix: fix box-shadow of subMenu (T-622)

* fix: fix style of linkage rules (T-623)

* fix: fix style of DataTemplate

* fix: fix style of variable (T-620)

* chore: update yarn.lock

* fix: avoid test failed

* test: fix error

* chore: update yarn.lock

* test: fix error

* test(dayjs): fix error

* fix: should delay show menu to avoid the menu not hidden

* test: skip failure test

* fix(mouseEnterDelay): change default value from 100 to 150

* test: avoid failed

* refactor: rename component names

* chore: optimize types

* chore: lock antd version

* fix: fix build

* fix: fix build

* fix: layout bg color use variable

* fix: fix style of buttons

* feat: remove theme config

* fix(calendar): fix style

* fix(mobile-client): fix dialog style

* fix: fix test

* refactor: make code gooder

* chore: change code

* fix: fix T-847

* fix: fix T-845

* fix: display block

* fix: danger button

* refactor: make tester better

* fix: change moment to dayjs

* fix: build error

* fix: import dayjs/plugin/isSameOrBefore

* refactor: downgrade @testing-library/react to fix warning

* fix: fix CI

* fix: upgrade deps to fix build

* fix: fix test

* fix: skip some filed tests to avoid error

* fix: fix build errors that maked by merge code

* refactor: remove moment

* fix: error

* feat: update doc

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
被雨水过滤的空气-Rairn 2023-07-08 08:26:27 +08:00 committed by GitHub
parent 6b220c342c
commit fd36c970bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
329 changed files with 12919 additions and 9670 deletions

View File

@ -1 +0,0 @@
@import 'antd/dist/antd.css';

View File

@ -14,7 +14,9 @@
"react", "react",
"react-hooks", "react-hooks",
"prettier", "prettier",
"promise" "promise",
"jest-dom",
"testing-library"
//"import" //"import"
], ],
"globals": { "globals": {

View File

@ -6,7 +6,10 @@ English | [中文](./README.zh-CN.md) | [Türkçe](./README.tr-TR.md)
NocoBase is in early stage of development and is subject to frequent changes, please use caution in production environments. NocoBase is in early stage of development and is subject to frequent changes, please use caution in production environments.
NocoBase v0.10 has been released, see [v0.10: update instructions](http://docs.nocobase.com/welcome/release/v10-changelog) for details. ## Recent major updates
- [v0.11: New client application, plugin and router - 2023/07/08](http://docs.nocobase.com/welcome/release/v11-changelog)
- [v0.10: Update instructions - 2023/06/23](http://docs.nocobase.com/welcome/release/v10-changelog)
## We are hiring ## We are hiring

View File

@ -8,6 +8,11 @@ NocoBase, geliştirmenin ilk aşamasındadır ve sık sık değişiklik yaparak
NocoBase v0.10 has been released, see [v0.10: update instructions](http://docs.nocobase.com/welcome/release/v10-changelog) for details. NocoBase v0.10 has been released, see [v0.10: update instructions](http://docs.nocobase.com/welcome/release/v10-changelog) for details.
## Recent major updates
- [v0.11: New client application, plugin and router - 2023/07/08](http://docs.nocobase.com/welcome/release/v11-changelog)
- [v0.10: Update instructions - 2023/06/23](http://docs.nocobase.com/welcome/release/v10-changelog)
## Çalışma arkadaşımız olabilirsiniz ## Çalışma arkadaşımız olabilirsiniz
Takıma katılacak tam zamanlı, uzaktan ürün tasarımı ve geliştirme arkadaşları arıyoruz. NocoBase'e güçlü bir ilginiz varsa, lütfen bize hello@nocobase.com adresinden e-posta göndermekten çekinmeyin. Takıma katılacak tam zamanlı, uzaktan ürün tasarımı ve geliştirme arkadaşları arıyoruz. NocoBase'e güçlü bir ilginiz varsa, lütfen bize hello@nocobase.com adresinden e-posta göndermekten çekinmeyin.

View File

@ -6,7 +6,10 @@
NocoBase 正处在早期开发阶段,可能变动频繁,请谨慎用于生产环境。 NocoBase 正处在早期开发阶段,可能变动频繁,请谨慎用于生产环境。
NocoBase v0.10 已发布,详情查看 [v0.10 更新说明](http://docs-cn.nocobase.com/welcome/release/v10-changelog)。 ## 最近重要更新
- [v0.11: New client application, plugin and router - 2023/07/08](http://docs-cn.nocobase.com/welcome/release/v11-changelog)
- [v0.10: Update instructions - 2023/06/23](http://docs-cn.nocobase.com/welcome/release/v10-changelog)
## 我们在招聘 ## 我们在招聘

View File

@ -11,8 +11,7 @@ import {
CollectionProvider, CollectionProvider,
CollectionField, CollectionField,
} from '@nocobase/client'; } from '@nocobase/client';
import 'antd/dist/antd.css'; import { FormItem, Input } from '@formily/antd-v5';
import { FormItem, Input } from '@formily/antd';
export default observer(() => { export default observer(() => {
const collection = { const collection = {

View File

@ -1,6 +1,19 @@
# v0.11: Update instructions # v0.11: Update instructions
## Plugin registration and use ## New features
- New client application, plugin and router
- Ant design upgrade to v5
- New plugin
- Data visualization
- API keys
- Google map
## Incompatible changes
### New client application, plugin and router
#### Plugin changes
before you had to pass a component and the component needed to pass `props.children`, for example: before you had to pass a component and the component needed to pass `props.children`, for example:
@ -45,6 +58,8 @@ plugins are very powerful and can do a lot of things in the `load` phase:
- add Scopes - add Scopes
- load other plugins - load other plugins
#### Routing changes
if you used `RouteSwitchContext` to modify the route before, you now need to replace it with a plugin: if you used `RouteSwitchContext` to modify the route before, you now need to replace it with a plugin:
```tsx | pure ```tsx | pure
@ -97,4 +112,9 @@ const HelloProvider = (props) => {
+ export default HelloPlugin; + export default HelloPlugin;
``` ```
more details can be found in [plugin development](/development/client). more details can be found in [packages/core/client/src/application/index.md](https://github.com/nocobase/nocobase/blob/main/packages/core/client/src/application/index.md)
### antd upgrade to v5
- antd related details view the official website [V4 to V5](https://ant.design/docs/react/migration-v5)
- `@formily/antd` replace with `@formily/antd-v5`

View File

@ -11,8 +11,7 @@ import {
CollectionProvider, CollectionProvider,
CollectionField, CollectionField,
} from '@nocobase/client'; } from '@nocobase/client';
import 'antd/dist/antd.css'; import { FormItem, Input } from '@formily/antd-v5';
import { FormItem, Input } from '@formily/antd';
export default observer(() => { export default observer(() => {
const collection = { const collection = {

View File

@ -11,8 +11,7 @@ import {
CollectionProvider, CollectionProvider,
CollectionField, CollectionField,
} from '@nocobase/client'; } from '@nocobase/client';
import 'antd/dist/antd.css'; import { FormItem, Input } from '@formily/antd-v5';
import { FormItem, Input } from '@formily/antd';
export default observer(() => { export default observer(() => {
const collection = { const collection = {

View File

@ -45,27 +45,30 @@
}, },
"devDependencies": { "devDependencies": {
"commander": "^9.2.0", "commander": "^9.2.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"@commitlint/cli": "^16.1.0", "@commitlint/cli": "^16.1.0",
"@commitlint/config-conventional": "^16.0.0", "@commitlint/config-conventional": "^16.0.0",
"@commitlint/prompt-cli": "^16.1.0", "@commitlint/prompt-cli": "^16.1.0",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5", "@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.4.3",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@vitejs/plugin-react": "^4.0.0", "@vitejs/plugin-react": "^4.0.0",
"auto-changelog": "^2.4.0", "auto-changelog": "^2.4.0",
"dumi": "^2.2.0", "dumi": "^2.2.0",
"dumi-theme-nocobase": "^0.2.14", "dumi-theme-nocobase": "^0.2.14",
"eslint-plugin-jest-dom": "^5.0.1",
"eslint-plugin-testing-library": "^5.11.0",
"ghooks": "^2.0.4", "ghooks": "^2.0.4",
"jsdom-worker": "^0.3.0", "jsdom-worker": "^0.3.0",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"pretty-format": "^24.0.0", "pretty-format": "^24.0.0",
"pretty-quick": "^3.1.0", "pretty-quick": "^3.1.0",
"vite": "^4.3.9", "react": "^18.0.0",
"vitest": "^0.32.0" "react-dom": "^18.0.0",
"typescript": "5.1.3",
"vite": "^4.4.1",
"vitest": "^0.33.0"
}, },
"volta": { "volta": {
"node": "18.14.2", "node": "18.14.2",

View File

@ -1,4 +1,3 @@
import '@/theme';
import { Application } from '@nocobase/client'; import { Application } from '@nocobase/client';
import { NocoBaseClientPresetPlugin } from '@nocobase/preset-nocobase/client'; import { NocoBaseClientPresetPlugin } from '@nocobase/preset-nocobase/client';

View File

@ -1,6 +0,0 @@
if (localStorage.getItem('NOCOBASE_THEME') === 'compact') {
import('antd/dist/antd.compact.css');
} else {
import('antd/dist/antd.css');
}
window.document.documentElement.classList.add('theme-' + (localStorage.getItem('NOCOBASE_THEME') || 'default'));

View File

@ -8,31 +8,31 @@
}, },
"typings": "./index.d.ts", "typings": "./index.d.ts",
"dependencies": { "dependencies": {
"@babel/core": "7.12.3", "@babel/core": "7.22.5",
"@babel/plugin-proposal-class-properties": "7.12.1", "@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-decorators": "7.12.1", "@babel/plugin-proposal-decorators": "7.22.5",
"@babel/plugin-proposal-do-expressions": "7.12.1", "@babel/plugin-proposal-do-expressions": "7.22.5",
"@babel/plugin-proposal-export-default-from": "7.12.1", "@babel/plugin-proposal-export-default-from": "7.22.5",
"@babel/plugin-proposal-export-namespace-from": "7.12.1", "@babel/plugin-proposal-export-namespace-from": "7.18.9",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
"@babel/plugin-proposal-optional-chaining": "7.12.1", "@babel/plugin-proposal-optional-chaining": "7.21.0",
"@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/plugin-transform-modules-commonjs": "7.12.1", "@babel/plugin-transform-modules-commonjs": "7.22.5",
"@babel/plugin-transform-runtime": "7.12.1", "@babel/plugin-transform-runtime": "7.22.5",
"@babel/preset-env": "7.12.1", "@babel/preset-env": "7.12.1",
"@babel/preset-react": "7.12.1", "@babel/preset-react": "7.22.5",
"@babel/preset-typescript": "7.12.1", "@babel/preset-typescript": "7.22.5",
"@babel/register": "7.12.1", "@babel/register": "7.22.5",
"@lerna/filter-packages": "4.0.0", "@lerna/filter-packages": "4.0.0",
"@lerna/project": "4.0.0", "@lerna/project": "4.0.0",
"@lerna/query-graph": "4.0.0", "@lerna/query-graph": "4.0.0",
"@rollup/plugin-babel": "5.3.1", "@rollup/plugin-babel": "6.0.3",
"@rollup/plugin-commonjs": "16.0.0", "@rollup/plugin-commonjs": "25.0.1",
"@rollup/plugin-inject": "4.0.2", "@rollup/plugin-inject": "5.0.3",
"@rollup/plugin-json": "4.1.0", "@rollup/plugin-json": "6.0.0",
"@rollup/plugin-node-resolve": "10.0.0", "@rollup/plugin-node-resolve": "15.1.0",
"@rollup/plugin-replace": "2.3.4", "@rollup/plugin-replace": "5.0.2",
"@rollup/plugin-url": "5.0.1", "@rollup/plugin-url": "8.0.1",
"@svgr/rollup": "5.5.0", "@svgr/rollup": "5.5.0",
"ajv": "6.12.6", "ajv": "6.12.6",
"autoprefixer": "9.6.0", "autoprefixer": "9.6.0",
@ -45,23 +45,23 @@
"gulp-if": "2.0.2", "gulp-if": "2.0.2",
"gulp-less": "^5.0.0", "gulp-less": "^5.0.0",
"gulp-plumber": "^1.2.1", "gulp-plumber": "^1.2.1",
"gulp-typescript": "5.0.1", "gulp-typescript": "6.0.0-alpha.1",
"less": "4.1.3", "less": "4.1.3",
"less-plugin-npm-import": "2.1.0", "less-plugin-npm-import": "2.1.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"pkg-up": "3.1.0", "pkg-up": "3.1.0",
"rimraf": "2.6.3", "rimraf": "2.6.3",
"rollup": "2.33.3", "rollup": "3.25.1",
"rollup-plugin-postcss": "3.1.8", "rollup-plugin-postcss": "4.0.2",
"rollup-plugin-terser": "7.0.2", "rollup-plugin-terser": "7.0.2",
"rollup-plugin-typescript2": "0.29.0", "rollup-plugin-typescript2": "0.34.1",
"semver": "6.1.1", "semver": "6.1.1",
"signale": "1.4.0", "signale": "1.4.0",
"slash2": "2.0.0", "slash2": "2.0.0",
"temp-dir": "2.0.0", "temp-dir": "2.0.0",
"through2": "3.0.1", "through2": "3.0.1",
"ts-loader": "^8.0.7", "ts-loader": "^9.4.3",
"typescript": "4.5.5", "typescript": "5.1.3",
"update-notifier": "3.0.0", "update-notifier": "3.0.0",
"vinyl-fs": "3.0.3", "vinyl-fs": "3.0.3",
"yargs-parser": "13.1.2" "yargs-parser": "13.1.2"

View File

@ -1 +0,0 @@
@import 'antd/dist/antd.css';

View File

@ -11,14 +11,15 @@
"@dnd-kit/core": "^5.0.1", "@dnd-kit/core": "^5.0.1",
"@dnd-kit/sortable": "^6.0.0", "@dnd-kit/sortable": "^6.0.0",
"@emotion/css": "^11.7.1", "@emotion/css": "^11.7.1",
"@formily/antd": "2.2.26", "@formily/antd-v5": "^1.1.0-beta.4",
"@formily/core": "2.2.26", "@formily/core": "2.2.26",
"@formily/react": "2.2.26", "@formily/react": "2.2.26",
"@nocobase/evaluators": "0.10.1-alpha.1", "@nocobase/evaluators": "0.10.1-alpha.1",
"@nocobase/sdk": "0.10.1-alpha.1", "@nocobase/sdk": "0.10.1-alpha.1",
"@nocobase/utils": "0.10.1-alpha.1", "@nocobase/utils": "0.10.1-alpha.1",
"ahooks": "^3.7.2", "ahooks": "^3.7.2",
"antd": "^4.24.8", "antd": "^5.6.4",
"antd-style": "^3.3.0",
"axios": "^0.26.1", "axios": "^0.26.1",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"cron-parser": "^4.6.0", "cron-parser": "^4.6.0",
@ -31,16 +32,16 @@
"mathjs": "^10.6.0", "mathjs": "^10.6.0",
"mermaid": "9.4.3", "mermaid": "9.4.3",
"react-beautiful-dnd": "^13.1.0", "react-beautiful-dnd": "^13.1.0",
"react-big-calendar": "^0.38.7", "react-big-calendar": "^1.8.1",
"react-drag-listview": "^0.1.9", "react-drag-listview": "^0.1.9",
"react-error-boundary": "^4.0.3", "react-error-boundary": "^4.0.10",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-hotkeys-hook": "^3.4.7", "react-hotkeys-hook": "^3.4.7",
"react-i18next": "^11.15.1", "react-i18next": "^11.15.1",
"react-iframe": "~1.8.5", "react-iframe": "~1.8.5",
"react-image-lightbox": "^5.1.4", "react-image-lightbox": "^5.1.4",
"react-js-cron": "^3.1.0", "react-js-cron": "^3.1.0",
"react-quill": "^1.3.5", "react-quill": "^2.0.0",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-to-print": "^2.14.7", "react-to-print": "^2.14.7",
"sanitize-html": "2.10.0", "sanitize-html": "2.10.0",
@ -55,9 +56,10 @@
"devDependencies": { "devDependencies": {
"dumi": "^2.2.0", "dumi": "^2.2.0",
"dumi-theme-nocobase": "^0.2.14", "dumi-theme-nocobase": "^0.2.14",
"@testing-library/react": "^12.1.2", "@testing-library/react": "^12.1.5",
"@types/markdown-it": "12.2.3", "@types/markdown-it": "12.2.3",
"@types/markdown-it-highlightjs": "3.3.1", "@types/markdown-it-highlightjs": "3.3.1",
"@types/react-big-calendar": "^1.6.4",
"axios-mock-adapter": "^1.20.0" "axios-mock-adapter": "^1.20.0"
}, },
"gitHead": "ce588eefb0bfc50f7d5bbee575e0b5e843bf6644" "gitHead": "ce588eefb0bfc50f7d5bbee575e0b5e843bf6644"

View File

@ -5,6 +5,7 @@ import { useAPIClient, useRequest } from '../../api-client';
import { SettingsCenterContext } from '../../pm'; import { SettingsCenterContext } from '../../pm';
import { useRecord } from '../../record-provider'; import { useRecord } from '../../record-provider';
import { useCompile } from '../../schema-component'; import { useCompile } from '../../schema-component';
import { useStyles } from '../style';
const getParentKeys = (tree, func, path = []) => { const getParentKeys = (tree, func, path = []) => {
if (!tree) return []; if (!tree) return [];
@ -69,6 +70,7 @@ const formatPluginTabs = (data) => {
}; };
export const SettingsCenterConfigure = () => { export const SettingsCenterConfigure = () => {
const { styles } = useStyles();
const record = useRecord(); const record = useRecord();
const api = useAPIClient(); const api = useAPIClient();
const pluginTags = useContext(SettingMenuContext); const pluginTags = useContext(SettingMenuContext);
@ -104,6 +106,7 @@ export const SettingsCenterConfigure = () => {
return ( return (
items?.length && ( items?.length && (
<Table <Table
className={styles}
loading={loading} loading={loading}
rowKey={'key'} rowKey={'key'}
pagination={false} pagination={false}

View File

@ -4,6 +4,7 @@ import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useAPIClient, useRequest } from '../../api-client'; import { useAPIClient, useRequest } from '../../api-client';
import { useRecord } from '../../record-provider'; import { useRecord } from '../../record-provider';
import { useStyles } from '../style';
import { useMenuItems } from './MenuItemsProvider'; import { useMenuItems } from './MenuItemsProvider';
const findUids = (items) => { const findUids = (items) => {
@ -39,6 +40,7 @@ const getChildrenUids = (data = [], arr = []) => {
}; };
export const MenuConfigure = () => { export const MenuConfigure = () => {
const { styles } = useStyles();
const record = useRecord(); const record = useRecord();
const api = useAPIClient(); const api = useAPIClient();
const { items } = useMenuItems(); const { items } = useMenuItems();
@ -86,6 +88,7 @@ export const MenuConfigure = () => {
}; };
return ( return (
<Table <Table
className={styles}
loading={loading} loading={loading}
rowKey={'uid'} rowKey={'uid'}
pagination={false} pagination={false}

View File

@ -14,6 +14,7 @@ const SnippetCheckboxGroup = connect((props) => {
<Checkbox.Group <Checkbox.Group
style={{ style={{
width: '100%', width: '100%',
display: 'block',
}} }}
value={props.value} value={props.value}
onChange={(values) => { onChange={(values) => {

View File

@ -1,4 +1,4 @@
import { FormItem, FormLayout } from '@formily/antd'; import { FormItem, FormLayout } from '@formily/antd-v5';
import { ArrayField } from '@formily/core'; import { ArrayField } from '@formily/core';
import { connect, useField, useForm } from '@formily/react'; import { connect, useField, useForm } from '@formily/react';
import { Checkbox, Table, Tag } from 'antd'; import { Checkbox, Table, Tag } from 'antd';
@ -6,6 +6,7 @@ import { isEmpty } from 'lodash';
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useCollectionManager, useCompile, useRecord } from '../..'; import { useCollectionManager, useCompile, useRecord } from '../..';
import { useStyles } from '../style';
import { useAvailableActions } from './RoleTable'; import { useAvailableActions } from './RoleTable';
import { ScopeSelect } from './ScopeSelect'; import { ScopeSelect } from './ScopeSelect';
@ -23,6 +24,7 @@ const toActionMap = (arr: any[]) => {
export const RoleResourceCollectionContext = createContext<any>({}); export const RoleResourceCollectionContext = createContext<any>({});
export const RolesResourcesActions = connect((props) => { export const RolesResourcesActions = connect((props) => {
const { styles } = useStyles();
// const { onChange } = props; // const { onChange } = props;
const onChange = (values) => { const onChange = (values) => {
const items = values.map((item) => { const items = values.map((item) => {
@ -91,6 +93,7 @@ export const RolesResourcesActions = connect((props) => {
<FormLayout layout={'vertical'}> <FormLayout layout={'vertical'}>
<FormItem label={t('Action permission')}> <FormItem label={t('Action permission')}>
<Table <Table
className={styles}
size={'small'} size={'small'}
pagination={false} pagination={false}
columns={[ columns={[
@ -154,6 +157,7 @@ export const RolesResourcesActions = connect((props) => {
</FormItem> </FormItem>
<FormItem label={t('Field permission')}> <FormItem label={t('Field permission')}>
<Table <Table
className={styles}
pagination={false} pagination={false}
dataSource={fieldPermissions} dataSource={fieldPermissions}
columns={[ columns={[

View File

@ -84,7 +84,7 @@ export const StrategyActions = connect((props) => {
render: (scope, action) => render: (scope, action) =>
!action.onNewRecord && ( !action.onNewRecord && (
<Select <Select
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
size={'small'} size={'small'}
value={scope} value={scope}
options={[ options={[

View File

@ -8,7 +8,6 @@ import {
ACLCollectionProvider, ACLCollectionProvider,
ACLMenuItemProvider, ACLMenuItemProvider,
} from './ACLProvider'; } from './ACLProvider';
import './style.less';
export class ACLPlugin extends Plugin { export class ACLPlugin extends Plugin {
async load() { async load() {

View File

@ -1,10 +0,0 @@
.ant-table-cell {
> .ant-space-horizontal {
.ant-space-item:empty:not(:last-child) + .ant-space-item-split {
display: none;
}
.ant-space-item-split:has(+ .ant-space-item:last-child:empty) {
display: none;
}
}
}

View File

@ -0,0 +1,16 @@
import { createStyles } from 'antd-style';
export const useStyles = createStyles(({ css }) => {
return css`
.ant-table-cell {
> .ant-space-horizontal {
.ant-space-item:empty:not(:last-child) + .ant-space-item-split {
display: none;
}
.ant-space-item-split:has(+ .ant-space-item:last-child:empty) {
display: none;
}
}
}
`;
});

View File

@ -1,5 +1,5 @@
import { dayjs } from '@nocobase/utils/client';
import { ConfigProvider, Spin } from 'antd'; import { ConfigProvider, Spin } from 'antd';
import moment from 'moment';
import React, { createContext, useContext } from 'react'; import React, { createContext, useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useAPIClient, useRequest } from '../api-client'; import { useAPIClient, useRequest } from '../api-client';
@ -34,7 +34,7 @@ export function AntdConfigProvider(props) {
i18n.addResources(data?.data?.lang, key, data?.data?.resources[key] || {}); i18n.addResources(data?.data?.lang, key, data?.data?.resources[key] || {});
}); });
loadConstrueLocale(data?.data); loadConstrueLocale(data?.data);
moment.locale(data?.data?.moment); dayjs.locale(data?.data?.moment);
window['cronLocale'] = data?.data?.cron; window['cronLocale'] = data?.data?.cron;
}, },
manual: !remoteLocale, manual: !remoteLocale,
@ -45,7 +45,7 @@ export function AntdConfigProvider(props) {
} }
return ( return (
<AppLangContext.Provider value={data?.data}> <AppLangContext.Provider value={data?.data}>
<ConfigProvider dropdownMatchSelectWidth={false} {...others} locale={data?.data?.antd || {}}> <ConfigProvider popupMatchSelectWidth={false} {...others} locale={data?.data?.antd || {}}>
{props.children} {props.children}
</ConfigProvider> </ConfigProvider>
</AppLangContext.Provider> </AppLangContext.Provider>

View File

@ -8,24 +8,9 @@ export const useCurrentAppInfo = () => {
return useContext(CurrentAppInfoContext); return useContext(CurrentAppInfoContext);
}; };
export const CurrentAppInfoProvider = (props) => { export const CurrentAppInfoProvider = (props) => {
const result = useRequest( const result = useRequest({
{ url: 'app:getInfo',
url: 'app:getInfo', });
},
{
onSuccess(data) {
const localTheme = localStorage.getItem('NOCOBASE_THEME');
if (localTheme !== data?.data?.theme) {
localStorage.setItem('NOCOBASE_THEME', data?.data?.theme);
window.location.reload();
}
},
},
);
const localTheme = localStorage.getItem('NOCOBASE_THEME');
if (localTheme && localTheme !== result?.data?.data?.theme) {
return <Spin />;
}
if (result.loading) { if (result.loading) {
return <Spin />; return <Spin />;
} }

View File

@ -6,12 +6,12 @@ import set from 'lodash/set';
import React, { ComponentType, FC, ReactElement } from 'react'; import React, { ComponentType, FC, ReactElement } from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import { I18nextProvider } from 'react-i18next'; import { I18nextProvider } from 'react-i18next';
import { Link, Navigate, NavLink } from 'react-router-dom'; import { Link, NavLink, Navigate } from 'react-router-dom';
import { APIClient, APIClientProvider } from '../api-client'; import { APIClient, APIClientProvider } from '../api-client';
import { i18n } from '../i18n'; import { i18n } from '../i18n';
import { AppComponent, BlankComponent, defaultAppComponents } from './components';
import { PluginManager, PluginType } from './PluginManager'; import { PluginManager, PluginType } from './PluginManager';
import { ComponentTypeAndString, RouterManager, RouterOptions } from './RouterManager'; import { ComponentTypeAndString, RouterManager, RouterOptions } from './RouterManager';
import { AppComponent, BlankComponent, defaultAppComponents } from './components';
import { compose, normalizeContainer } from './utils'; import { compose, normalizeContainer } from './utils';
export type ComponentAndProps<T = any> = [ComponentType, T]; export type ComponentAndProps<T = any> = [ComponentType, T];

View File

@ -13,6 +13,7 @@ import {
isMovingACardToAnotherPosition, isMovingACardToAnotherPosition,
isMovingAColumnToAnotherPosition, isMovingAColumnToAnotherPosition,
} from './services'; } from './services';
import { useStyles } from './style';
import { partialRight, when } from './utils'; import { partialRight, when } from './utils';
import withDroppable from './withDroppable'; import withDroppable from './withDroppable';
@ -23,7 +24,13 @@ const Columns = forwardRef((props, ref: any) => (
const DroppableBoard = withDroppable(Columns); const DroppableBoard = withDroppable(Columns);
const Board: any = (props) => { const Board: any = (props) => {
return props.initialBoard ? <UncontrolledBoard {...props} /> : <ControlledBoard {...props} />; const { styles } = useStyles();
return (
<div className={styles}>
{props.initialBoard ? <UncontrolledBoard {...props} /> : <ControlledBoard {...props} />}
</div>
);
}; };
Object.keys(helpers).forEach((key) => { Object.keys(helpers).forEach((key) => {

View File

@ -1,7 +1,6 @@
import { Board } from '@nocobase/client'; import { Board } from '@nocobase/client';
import { Button, Card } from 'antd'; import { Button, Card } from 'antd';
import React, { useState } from 'react'; import React, { useState } from 'react';
import '../style.less';
const board = { const board = {
columns: [ columns: [

View File

@ -1,154 +0,0 @@
.react-kanban-board {
height: 100%;
// padding: 5px;
// margin-bottom: 24px;
}
.react-kanban-card {
box-sizing: border-box;
max-width: 250px;
min-width: 250px;
border-radius: 3px;
background-color: #fff;
padding: 10px;
margin-bottom: 7px;
}
.react-kanban-card-skeleton {
box-sizing: border-box;
max-width: 300px;
min-width: 300px;
height: 70vh;
overflow-x: hidden;
overflow-y: auto;
padding: 0 12px;
margin-bottom: 12px;
> div {
margin-bottom: 12px;
}
+ div {
display: none !important;
}
}
.react-kanban-card--dragging {
box-shadow: 2px 2px grey;
}
.react-kanban-card__description {
padding-top: 10px;
}
.react-kanban-card__title {
border-bottom: 1px solid #eee;
padding-bottom: 5px;
font-weight: bold;
display: flex;
justify-content: space-between;
}
.react-kanban-column {
// padding: 15px 0;
// border-radius: 2px;
background-color: #f9f9f9;
margin-right: 15px;
padding-bottom: 15px;
width: 300px;
}
.react-kanban-column-header {
padding: 15px;
}
.react-kanban-card-adder-form {
box-sizing: border-box;
max-width: 250px;
min-width: 250px;
border-radius: 3px;
background-color: #fff;
padding: 10px;
margin-bottom: 7px;
input {
border: 0px;
font-family: inherit;
font-size: inherit;
}
}
.react-kanban-card-adder-button {
width: 100%;
margin-top: 5px;
background-color: transparent;
cursor: pointer;
border: 1px solid #ccc;
transition: 0.3s;
border-radius: 3px;
font-size: 20px;
margin-bottom: 10px;
font-weight: bold;
&:hover {
background-color: #ccc;
}
}
.react-kanban-card-adder-form__title {
font-weight: bold;
border-bottom: 1px solid #eee;
padding-bottom: 5px;
font-weight: bold;
display: flex;
justify-content: space-between;
width: 100%;
padding: 0px;
&:focus {
outline: none;
}
}
.react-kanban-card-adder-form__description {
width: 100%;
margin-top: 10px;
&:focus {
outline: none;
}
}
.react-kanban-card-adder-form__button {
background-color: #eee;
border: none;
padding: 5px;
width: 45%;
margin-top: 5px;
border-radius: 3px;
&:hover {
transition: 0.3s;
cursor: pointer;
background-color: #ccc;
}
}
.react-kanban-column-header {
}
.react-kanban-column-header__button {
color: #333333;
background-color: #ffffff;
border-color: #cccccc;
&:hover,
&:focus,
&:active {
background-color: #e6e6e6;
}
}
.react-kanban-column-adder-button {
border: 2px dashed #eee;
height: 132px;
margin: 5px;
&:hover {
cursor: pointer;
}
}

View File

@ -0,0 +1,159 @@
import { createStyles } from 'antd-style';
export const useStyles = createStyles(({ css }) => {
return css`
.react-kanban-board {
height: 100%;
// padding: 5px;
// margin-bottom: 24px;
}
.react-kanban-card {
box-sizing: border-box;
max-width: 250px;
min-width: 250px;
border-radius: 3px;
background-color: #fff;
padding: 10px;
margin-bottom: 7px;
}
.react-kanban-card-skeleton {
box-sizing: border-box;
max-width: 300px;
min-width: 300px;
height: 70vh;
overflow-x: hidden;
overflow-y: auto;
padding: 0 12px;
margin-bottom: 12px;
> div {
margin-bottom: 12px;
}
+ div {
display: none !important;
}
}
.react-kanban-card--dragging {
box-shadow: 2px 2px grey;
}
.react-kanban-card__description {
padding-top: 10px;
}
.react-kanban-card__title {
border-bottom: 1px solid #eee;
padding-bottom: 5px;
font-weight: bold;
display: flex;
justify-content: space-between;
}
.react-kanban-column {
// padding: 15px 0;
// border-radius: 2px;
background-color: #f9f9f9;
margin-right: 15px;
padding-bottom: 15px;
width: 300px;
}
.react-kanban-column-header {
padding: 15px;
}
.react-kanban-card-adder-form {
box-sizing: border-box;
max-width: 250px;
min-width: 250px;
border-radius: 3px;
background-color: #fff;
padding: 10px;
margin-bottom: 7px;
input {
border: 0px;
font-family: inherit;
font-size: inherit;
}
}
.react-kanban-card-adder-button {
width: 100%;
margin-top: 5px;
background-color: transparent;
cursor: pointer;
border: 1px solid #ccc;
transition: 0.3s;
border-radius: 3px;
font-size: 20px;
margin-bottom: 10px;
font-weight: bold;
&:hover {
background-color: #ccc;
}
}
.react-kanban-card-adder-form__title {
font-weight: bold;
border-bottom: 1px solid #eee;
padding-bottom: 5px;
font-weight: bold;
display: flex;
justify-content: space-between;
width: 100%;
padding: 0px;
&:focus {
outline: none;
}
}
.react-kanban-card-adder-form__description {
width: 100%;
margin-top: 10px;
&:focus {
outline: none;
}
}
.react-kanban-card-adder-form__button {
background-color: #eee;
border: none;
padding: 5px;
width: 45%;
margin-top: 5px;
border-radius: 3px;
&:hover {
transition: 0.3s;
cursor: pointer;
background-color: #ccc;
}
}
.react-kanban-column-header {
}
.react-kanban-column-header__button {
color: #333333;
background-color: #ffffff;
border-color: #cccccc;
&:hover,
&:focus,
&:active {
background-color: #e6e6e6;
}
}
.react-kanban-column-adder-button {
border: 2px dashed #eee;
height: 132px;
margin: 5px;
&:hover {
cursor: pointer;
}
}
`;
});

View File

@ -1,5 +1,5 @@
import { DownOutlined, PlusOutlined } from '@ant-design/icons'; import { DownOutlined, PlusOutlined } from '@ant-design/icons';
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema, useField, useForm } from '@formily/react'; import { ISchema, useField, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { Button, Dropdown, MenuProps } from 'antd'; import { Button, Dropdown, MenuProps } from 'antd';

View File

@ -1,5 +1,5 @@
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { useField, useForm } from '@formily/react'; import { useField, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { Button, Dropdown, MenuProps } from 'antd'; import { Button, Dropdown, MenuProps } from 'antd';

View File

@ -1,5 +1,5 @@
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { Button, Dropdown, MenuProps } from 'antd'; import { Button, Dropdown, MenuProps } from 'antd';

View File

@ -1,4 +1,4 @@
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema, useForm } from '@formily/react'; import { ISchema, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';

View File

@ -1,4 +1,4 @@
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema, useForm } from '@formily/react'; import { ISchema, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';

View File

@ -1,4 +1,4 @@
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema, useForm } from '@formily/react'; import { ISchema, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';

View File

@ -1,4 +1,4 @@
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema, useForm } from '@formily/react'; import { ISchema, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { omit, set } from 'lodash'; import { omit, set } from 'lodash';

View File

@ -1,22 +1,21 @@
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { useForm, useField } from '@formily/react'; import { useField, useForm } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { Button } from 'antd'; import { Button } from 'antd';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useRequest } from '../../api-client'; import { useAPIClient, useRequest } from '../../api-client';
import { RecordProvider, useRecord } from '../../record-provider'; import { RecordProvider, useRecord } from '../../record-provider';
import { ActionContextProvider, SchemaComponent, useActionContext, useCompile } from '../../schema-component'; import { ActionContextProvider, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
import { useCancelAction } from '../action-hooks'; import { useCancelAction } from '../action-hooks';
import { useCollectionManager } from '../hooks'; import { useCollectionManager } from '../hooks';
import { IField } from '../interfaces/types'; import { IField } from '../interfaces/types';
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
import * as components from './components';
import { useAPIClient } from '../../api-client';
import { PreviewFields } from '../templates/components/PreviewFields'; import { PreviewFields } from '../templates/components/PreviewFields';
import { PreviewTable } from '../templates/components/PreviewTable'; import { PreviewTable } from '../templates/components/PreviewTable';
import * as components from './components';
const getSchema = (schema: IField, record: any, compile) => { const getSchema = (schema: IField, record: any, compile) => {
if (!schema) { if (!schema) {

View File

@ -1,4 +1,4 @@
import { ArrayTable } from '@formily/antd'; import { ArrayTable } from '@formily/antd-v5';
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';

View File

@ -45,7 +45,7 @@ export const ThroughForeignKey = observer(
<div> <div>
<Select <Select
allowClear allowClear
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
placeholder={'留空时,自动生成 FK 字段'} placeholder={'留空时,自动生成 FK 字段'}
disabled={field.disabled} disabled={field.disabled}
value={field.value} value={field.value}
@ -73,7 +73,7 @@ export const TargetForeignKey = observer(
<div> <div>
<Select <Select
allowClear allowClear
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
placeholder={'留空时,自动生成 FK 字段'} placeholder={'留空时,自动生成 FK 字段'}
disabled={field.disabled} disabled={field.disabled}
value={field.value} value={field.value}
@ -102,7 +102,7 @@ export const SourceCollection = observer(
<div> <div>
<Select <Select
disabled disabled
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
value={collection.name} value={collection.name}
options={[{ value: collection.name, label: compile(collection.title) }]} options={[{ value: collection.name, label: compile(collection.title) }]}
/> />

View File

@ -1,15 +1,14 @@
import React from 'react'; import { FormItem, Input } from '@formily/antd-v5';
import { observer, ISchema, useForm } from '@formily/react'; import { ISchema, observer, useForm } from '@formily/react';
import { import {
Action,
CollectionField,
CollectionProvider,
Form,
SchemaComponent, SchemaComponent,
SchemaComponentProvider, SchemaComponentProvider,
Form,
Action,
CollectionProvider,
CollectionField,
} from '@nocobase/client'; } from '@nocobase/client';
import 'antd/dist/antd.css'; import React from 'react';
import { FormItem, Input } from '@formily/antd';
export default observer(() => { export default observer(() => {
const collection = { const collection = {

View File

@ -1,4 +1,4 @@
import { FormDrawer, FormLayout } from '@formily/antd'; import { FormDrawer, FormLayout } from '@formily/antd-v5';
import { createForm } from '@formily/core'; import { createForm } from '@formily/core';
import { FormContext, ISchema, SchemaOptionsContext } from '@formily/react'; import { FormContext, ISchema, SchemaOptionsContext } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';

View File

@ -1,4 +1,4 @@
import { Cascader } from '@formily/antd'; import { Cascader } from '@formily/antd-v5';
import { useField, useForm } from '@formily/react'; import { useField, useForm } from '@formily/react';
import { Input, Select, Spin, Table, Tag } from 'antd'; import { Input, Select, Spin, Table, Tag } from 'antd';
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
@ -123,7 +123,7 @@ const PreviewCom = (props) => {
) : ( ) : (
<Select <Select
defaultValue={text} defaultValue={text}
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
style={{ width: '100%' }} style={{ width: '100%' }}
options={ options={
item?.possibleTypes.map((v) => { item?.possibleTypes.map((v) => {
@ -149,7 +149,7 @@ const PreviewCom = (props) => {
<Select <Select
defaultValue={text} defaultValue={text}
style={{ width: '100%' }} style={{ width: '100%' }}
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
onChange={(value) => { onChange={(value) => {
const interfaceConfig = getInterface(value); const interfaceConfig = getInterface(value);
handleFieldChange({ ...item, interface: value, uiSchema: interfaceConfig?.default?.uiSchema }, index); handleFieldChange({ ...item, interface: value, uiSchema: interfaceConfig?.default?.uiSchema }, index);

View File

@ -1,4 +1,15 @@
import './global.less'; // 解决 build 报 dayjs 相关类型错误的问题
import 'dayjs/plugin/isBetween';
import 'dayjs/plugin/isSameOrAfter';
import 'dayjs/plugin/isSameOrBefore';
import 'dayjs/plugin/isoWeek';
import 'dayjs/plugin/localeData';
import 'dayjs/plugin/quarterOfYear';
import 'dayjs/plugin/utc';
import 'dayjs/plugin/weekday';
// 重置浏览器样式
import 'antd/dist/reset.css';
export * from '@emotion/css'; export * from '@emotion/css';
export * from './acl'; export * from './acl';

View File

@ -31,7 +31,7 @@ export const PinnedPluginList = () => {
width: 46px; width: 46px;
border-radius: 0; border-radius: 0;
background: none; background: none;
color: rgba(255, 255, 255, 0.65); color: rgba(255, 255, 255, 0.65) !important;
&:hover { &:hover {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
} }

View File

@ -14,7 +14,6 @@ import {
Typography, Typography,
message, message,
} from 'antd'; } from 'antd';
import cls from 'classnames';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -128,7 +127,7 @@ function PluginDetail(props: IPluginDetail) {
footer={false} footer={false}
className={css` className={css`
.ant-modal-header { .ant-modal-header {
background: #f0f2f5; background: var(--nb-box-bg);
padding-bottom: 8px; padding-bottom: 8px;
} }
@ -136,8 +135,8 @@ function PluginDetail(props: IPluginDetail) {
padding-top: 0; padding-top: 0;
} }
.ant-modal-body { .ant-modal-content {
background: #f0f2f5; background: var(--nb-box-bg);
.plugin-desc { .plugin-desc {
padding-bottom: 8px; padding-bottom: 8px;
} }
@ -175,14 +174,15 @@ function CommonCard(props: ICommonCard) {
bordered={false} bordered={false}
style={{ width: 'calc(20% - 24px)', marginRight: 24, marginBottom: 24, transition: 'all 0.35s ease-in-out' }} style={{ width: 'calc(20% - 24px)', marginRight: 24, marginBottom: 24, transition: 'all 0.35s ease-in-out' }}
onClick={onClick} onClick={onClick}
className={cls(css` hoverable
&:hover { // className={cls(css`
border: 1px solid var(--antd-wave-shadow-color); // &:hover {
cursor: pointer; // border: 1px solid var(--antd-wave-shadow-color);
} // cursor: pointer;
// }
border: 1px solid transparent; // border: 1px solid transparent;
`)} // `)}
actions={actions} actions={actions}
// actions={[<a>Settings</a>, <a>Remove</a>, <Switch size={'small'} defaultChecked={true}></Switch>]} // actions={[<a>Settings</a>, <a>Remove</a>, <Switch size={'small'} defaultChecked={true}></Switch>]}
> >

View File

@ -17,6 +17,7 @@ import { BlockTemplatesPane } from '../schema-templates';
import { SystemSettingsPane } from '../system-settings'; import { SystemSettingsPane } from '../system-settings';
import { BuiltInPluginCard, PluginCard } from './Card'; import { BuiltInPluginCard, PluginCard } from './Card';
import { PluginManagerLink, SettingsCenterDropdown } from './PluginManagerLink'; import { PluginManagerLink, SettingsCenterDropdown } from './PluginManagerLink';
import { useStyles } from './style';
export interface TData { export interface TData {
data: IPluginData[]; data: IPluginData[];
@ -110,12 +111,13 @@ const MarketplacePlugins = () => {
return <div style={{ fontSize: 18 }}>{t('Coming soon...')}</div>; return <div style={{ fontSize: 18 }}>{t('Coming soon...')}</div>;
}; };
const PluginList = (props) => { const PluginList = () => {
const params = useParams<any>(); const params = useParams<any>();
const navigate = useNavigate(); const navigate = useNavigate();
const { tabName = 'local' } = params; const { tabName = 'local' } = params;
const { t } = useTranslation(); const { t } = useTranslation();
const { snippets = [] } = useACLRoleContext(); const { snippets = [] } = useACLRoleContext();
const { styles } = useStyles();
useEffect(() => { useEffect(() => {
const { tabName } = params; const { tabName } = params;
@ -127,10 +129,7 @@ const PluginList = (props) => {
return snippets.includes('pm') ? ( return snippets.includes('pm') ? (
<div> <div>
<PageHeader <PageHeader
style={{ className={styles.pageHeader}
backgroundColor: 'white',
paddingBottom: 0,
}}
ghost={false} ghost={false}
title={t('Plugin manager')} title={t('Plugin manager')}
footer={ footer={
@ -240,7 +239,8 @@ export const getPluginsTabs = _.memoize((items, snippets) => {
return sortBy(pluginsTabs, (o) => !o.isAllow); return sortBy(pluginsTabs, (o) => !o.isAllow);
}); });
const SettingsCenter = (props) => { const SettingsCenter = () => {
const { styles } = useStyles();
const { snippets = [] } = useACLRoleContext(); const { snippets = [] } = useACLRoleContext();
const params = useParams<any>(); const params = useParams<any>();
const navigate = useNavigate(); const navigate = useNavigate();
@ -311,7 +311,7 @@ const SettingsCenter = (props) => {
<Layout.Content> <Layout.Content>
{aclPluginTabCheck && ( {aclPluginTabCheck && (
<PageHeader <PageHeader
style={{ backgroundColor: 'white', paddingBottom: 0 }} className={styles.pageHeader}
ghost={false} ghost={false}
title={compile(items[pluginName]?.title)} title={compile(items[pluginName]?.title)}
footer={ footer={

View File

@ -0,0 +1,14 @@
import { createStyles } from 'antd-style';
export const useStyles = createStyles(() => {
return {
pageHeader: {
backgroundColor: 'white',
paddingBottom: 0,
paddingTop: 12,
'& .ant-tabs-nav': {
marginBottom: 0,
},
},
};
});

View File

@ -157,7 +157,8 @@ export const InternalAdminLayout = (props: any) => {
<Layout.Header <Layout.Header
className={css` className={css`
.ant-menu.ant-menu-dark .ant-menu-item-selected, .ant-menu.ant-menu-dark .ant-menu-item-selected,
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected { .ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,
.ant-menu-submenu-horizontal.ant-menu-submenu-selected {
background-color: rgba(255, 255, 255, 0.1); background-color: rgba(255, 255, 255, 0.1);
} }
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover { .ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {

View File

@ -0,0 +1,4 @@
export * from './useConfig';
export * from './usePrefixCls';
export * from './useToken';

View File

@ -0,0 +1,5 @@
import { ConfigProvider } from 'antd';
import { useContext } from 'react';
const { ConfigContext } = ConfigProvider;
export const useConfig = () => useContext(ConfigContext);

View File

@ -0,0 +1,17 @@
import { ConfigProvider } from 'antd';
import { useContext } from 'react';
export const usePrefixCls = (
tag?: string,
props?: {
prefixCls?: string;
},
) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext) || {};
if ('ConfigContext' in ConfigProvider) {
return getPrefixCls?.(tag, props?.prefixCls) || '';
} else {
const prefix = props?.prefixCls ?? 'ant-';
return `${prefix}${tag ?? ''}`;
}
};

View File

@ -0,0 +1,3 @@
import { theme } from 'antd';
const { useToken } = theme;
export { useToken };

View File

@ -0,0 +1,3 @@
export * from './hooks';
export * from './style';

View File

@ -0,0 +1,103 @@
import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
import { useStyleRegister } from '@ant-design/cssinjs';
import { merge } from '@formily/shared';
import type { ComponentTokenMap, GlobalToken } from 'antd/es/theme/interface';
import { useConfig, usePrefixCls, useToken } from './hooks';
export type OverrideComponent = keyof ComponentTokenMap | string;
export interface StyleInfo {
hashId: string;
prefixCls: string;
rootPrefixCls: string;
iconPrefixCls: string;
}
export type TokenWithCommonCls<T> = T & {
/** Wrap component class with `.` prefix */
componentCls: string;
/** Origin prefix which do not have `.` prefix */
prefixCls: string;
/** Wrap icon class with `.` prefix */
iconCls: string;
/** Wrap ant prefixCls class with `.` prefix */
antCls: string;
};
export type GenerateStyle<
ComponentToken extends object = TokenWithCommonCls<GlobalToken>,
ReturnType = CSSInterpolation,
> = (token: ComponentToken, options?: any) => ReturnType;
export const genCommonStyle = (token: any, componentPrefixCls: string): CSSObject => {
const { fontFamily, fontSize } = token;
const rootPrefixSelector = `[class^="${componentPrefixCls}"], [class*=" ${componentPrefixCls}"]`;
return {
[rootPrefixSelector]: {
fontFamily,
fontSize,
boxSizing: 'border-box',
'&::before, &::after': {
boxSizing: 'border-box',
},
[rootPrefixSelector]: {
boxSizing: 'border-box',
'&::before, &::after': {
boxSizing: 'border-box',
},
},
},
};
};
export type UseComponentStyleResult = {
wrapSSR: ReturnType<typeof useStyleRegister>;
hashId: string;
componentCls: string;
};
export const genStyleHook = <ComponentName extends OverrideComponent>(
component: ComponentName,
styleFn: (token: TokenWithCommonCls<GlobalToken>, props: any, info: StyleInfo) => CSSInterpolation,
) => {
return (props?: any): UseComponentStyleResult => {
const { theme, token, hashId } = useToken();
const { getPrefixCls, iconPrefixCls } = useConfig();
const prefixCls = usePrefixCls(component);
const rootPrefixCls = getPrefixCls();
return {
wrapSSR: useStyleRegister(
{
theme,
token,
hashId,
path: ['formily-antd', component, prefixCls, iconPrefixCls],
},
() => {
const componentCls = `.${prefixCls}`;
const mergedToken: TokenWithCommonCls<GlobalToken> = merge(token, {
componentCls,
prefixCls,
iconCls: `.${iconPrefixCls}`,
antCls: `.${rootPrefixCls}`,
});
const styleInterpolation = styleFn(mergedToken, props, {
hashId,
prefixCls,
rootPrefixCls,
iconPrefixCls,
});
return [genCommonStyle(token, prefixCls), styleInterpolation];
},
),
hashId,
componentCls: prefixCls,
};
};
};

View File

@ -43,7 +43,7 @@ export const ActionDrawer: ComposedActionDrawer = observer(
destroyOnClose destroyOnClose
open={visible} open={visible}
onClose={() => setVisible(false, true)} onClose={() => setVisible(false, true)}
className={classNames( rootClassName={classNames(
drawerProps?.className, drawerProps?.className,
others.className, others.className,
css` css`
@ -57,7 +57,7 @@ export const ActionDrawer: ComposedActionDrawer = observer(
} }
.ant-drawer-content { .ant-drawer-content {
background: #f0f2f5; background: var(--nb-box-bg);
} }
} }

View File

@ -46,18 +46,8 @@ export const ActionModal: ComposedActionDrawer<ModalProps> = observer(
display: none; display: none;
} }
.ant-modal-body { .ant-modal-content {
padding-top: 16px; background: var(--nb-box-bg);
}
.ant-modal-body {
background: #f0f2f5;
}
.ant-modal-close-x {
width: 32px;
height: 32px;
line-height: 32px;
} }
} }
`, `,

View File

@ -114,7 +114,7 @@ export const Action: ComposedAction = observer(
<SortableItem <SortableItem
{...others} {...others}
loading={field?.data?.loading} loading={field?.data?.loading}
icon={<Icon type={icon} />} icon={icon ? <Icon type={icon} /> : null}
disabled={disabled} disabled={disabled}
style={{ style={{
...others.style, ...others.style,
@ -141,6 +141,7 @@ export const Action: ComposedAction = observer(
}} }}
component={tarComponent || Button} component={tarComponent || Button}
className={classnames(actionDesignerCss, className)} className={classnames(actionDesignerCss, className)}
type={props.type === 'danger' ? undefined : props.type}
> >
{title || compile(fieldSchema.title)} {title || compile(fieldSchema.title)}
<Designer {...designerProps} /> <Designer {...designerProps} />

View File

@ -9,7 +9,7 @@ import {
Input, Input,
NumberPicker, NumberPicker,
Submit, Submit,
} from '@formily/antd'; } from '@formily/antd-v5';
import { Field, createForm, onFieldValueChange } from '@formily/core'; import { Field, createForm, onFieldValueChange } from '@formily/core';
import { connect, createSchemaField, observer, useField, useForm, useFormEffects } from '@formily/react'; import { connect, createSchemaField, observer, useField, useForm, useFormEffects } from '@formily/react';
import { Select } from 'antd'; import { Select } from 'antd';

View File

@ -1,13 +1,12 @@
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
import { RecursionField, connect, mapProps, observer, useField, useFieldSchema, useForm } from '@formily/react'; import { RecursionField, connect, mapProps, observer, useField, useFieldSchema, useForm } from '@formily/react';
import { Input, Button, message } from 'antd'; import { Space, message } from 'antd';
import { isFunction } from 'mathjs';
import React from 'react'; import React from 'react';
import { RecordProvider } from '../../../';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { RecordProvider, useAPIClient, useCollectionManager } from '../../../';
import { RemoteSelect, RemoteSelectProps } from '../remote-select'; import { RemoteSelect, RemoteSelectProps } from '../remote-select';
import useServiceOptions, { useAssociationFieldContext } from './hooks'; import useServiceOptions, { useAssociationFieldContext } from './hooks';
import { useAPIClient, useCollectionManager } from '../../../';
import { isFunction } from 'mathjs';
export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & { export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & {
action?: string; action?: string;
@ -66,7 +65,7 @@ const InternalAssociationSelect = observer((props: AssociationSelectProps) => {
}; };
return ( return (
<div key={fieldSchema.name}> <div key={fieldSchema.name}>
<Input.Group compact style={{ display: 'flex', lineHeight: '32px' }}> <Space.Compact style={{ display: 'flex', lineHeight: '32px' }}>
<RemoteSelect <RemoteSelect
style={{ width: '100%' }} style={{ width: '100%' }}
{...props} {...props}
@ -89,7 +88,7 @@ const InternalAssociationSelect = observer((props: AssociationSelectProps) => {
/> />
</RecordProvider> </RecordProvider>
)} )}
</Input.Group> </Space.Compact>
</div> </div>
); );
}); });

View File

@ -1,10 +1,9 @@
import { FormLayout } from '@formily/antd'; import { css, cx } from '@emotion/css';
import { FormLayout } from '@formily/antd-v5';
import { RecursionField, useField, useFieldSchema } from '@formily/react'; import { RecursionField, useField, useFieldSchema } from '@formily/react';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { css, cx } from '@emotion/css';
import { CollectionProvider } from '../../../collection-manager'; import { CollectionProvider } from '../../../collection-manager';
import { useInsertSchema } from './hooks'; import { useAssociationFieldContext, useInsertSchema } from './hooks';
import { useAssociationFieldContext } from './hooks';
import schema from './schema'; import schema from './schema';
export const InternalNester = () => { export const InternalNester = () => {

View File

@ -133,7 +133,7 @@ export const InternalPicker = observer(
<div style={{ width: '100%' }}> <div style={{ width: '100%' }}>
<Select <Select
style={{ width: '100%' }} style={{ width: '100%' }}
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
{...others} {...others}
mode={multiple ? 'multiple' : props.mode} mode={multiple ? 'multiple' : props.mode}
fieldNames={fieldNames} fieldNames={fieldNames}

View File

@ -1,5 +1,5 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { FormItem, FormLayout } from '@formily/antd'; import { FormItem, FormLayout } from '@formily/antd-v5';
import { RecursionField, observer, useField, useFieldSchema } from '@formily/react'; import { RecursionField, observer, useField, useFieldSchema } from '@formily/react';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { CollectionProvider } from '../../../collection-manager'; import { CollectionProvider } from '../../../collection-manager';

View File

@ -1,8 +1,7 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { isArr } from '@formily/shared'; import { isArr } from '@formily/shared';
import { getDefaultFormat, str2moment } from '@nocobase/utils/client'; import { dayjs, getDefaultFormat, str2moment } from '@nocobase/utils/client';
import { Tag } from 'antd'; import { Tag } from 'antd';
import moment from 'moment';
import React from 'react'; import React from 'react';
import { CollectionFieldOptions, useCollectionManager } from '../../../collection-manager'; import { CollectionFieldOptions, useCollectionManager } from '../../../collection-manager';
@ -17,7 +16,7 @@ export const useLabelUiSchema = (collectionField: CollectionFieldOptions, label:
export const getDatePickerLabels = (props): string => { export const getDatePickerLabels = (props): string => {
const format = getDefaultFormat(props) as string; const format = getDefaultFormat(props) as string;
const m = str2moment(props.value, props) as moment.Moment; const m = str2moment(props.value, props) as dayjs.Dayjs;
const labels = m && m.isValid() ? m.format(format) : props.value; const labels = m && m.isValid() ? m.format(format) : props.value;
return isArr(labels) ? labels.join('~') : labels; return isArr(labels) ? labels.join('~') : labels;
}; };

View File

@ -1,5 +1,5 @@
import { LoadingOutlined } from '@ant-design/icons'; import { LoadingOutlined } from '@ant-design/icons';
import { ArrayCollapse, ArrayItems, FormLayout } from '@formily/antd'; import { ArrayCollapse, ArrayItems, FormLayout } from '@formily/antd-v5';
import { Field } from '@formily/core'; import { Field } from '@formily/core';
import { ISchema, connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react'; import { ISchema, connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';

View File

@ -1,12 +1,13 @@
import { LeftOutlined, RightOutlined } from '@ant-design/icons'; import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { createForm } from '@formily/core'; import { createForm } from '@formily/core';
import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react'; import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react';
import { dayjs } from '@nocobase/utils/client';
import { parseExpression } from 'cron-parser'; import { parseExpression } from 'cron-parser';
import { eq } from 'date-arithmetic'; import { eq } from 'date-arithmetic';
import type { Dayjs } from 'dayjs';
import get from 'lodash/get'; import get from 'lodash/get';
import moment from 'moment';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar'; import { Calendar as BigCalendar, View, dayjsLocalizer } from 'react-big-calendar';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { RecordProvider } from '../../../'; import { RecordProvider } from '../../../';
import { i18n } from '../../../i18n'; import { i18n } from '../../../i18n';
@ -14,13 +15,14 @@ import { useProps } from '../../hooks/useProps';
import { ActionContextProvider } from '../action'; import { ActionContextProvider } from '../action';
import Header from './components/Header'; import Header from './components/Header';
import { CalendarToolbarContext } from './context'; import { CalendarToolbarContext } from './context';
import './style.less'; import GlobalStyle from './global.style';
import useStyle from './style';
import type { ToolbarProps } from './types'; import type { ToolbarProps } from './types';
import { formatDate } from './utils'; import { formatDate } from './utils';
const Weeks = ['month', 'week', 'day'] as const; const Weeks = ['month', 'week', 'day'] as View[];
const localizer = momentLocalizer(moment); const localizer = dayjsLocalizer(dayjs);
export const DeleteEventContext = React.createContext({ export const DeleteEventContext = React.createContext({
close: () => {}, close: () => {},
}); });
@ -77,18 +79,18 @@ const useEvents = (dataSource: any, fieldNames: any, date: Date, view: (typeof W
dataSource.forEach((item) => { dataSource.forEach((item) => {
const { cron, exclude = [] } = item; const { cron, exclude = [] } = item;
const start = moment(get(item, fieldNames.start) || moment()); const start = dayjs(get(item, fieldNames.start) || dayjs());
const end = moment(get(item, fieldNames.end) || start); const end = dayjs(get(item, fieldNames.end) || start);
const intervalTime = end.diff(start, 'millisecond', true); const intervalTime = end.diff(start, 'millisecond', true);
const dateM = moment(date); const dateM = dayjs(date);
const startDate = dateM.clone().startOf('month'); const startDate = dateM.clone().startOf('month');
const endDate = startDate.clone().endOf('month'); const endDate = startDate.clone().endOf('month');
if (view === 'month') { if (view === 'month') {
startDate.startOf('week'); startDate.startOf('week');
endDate.endOf('week'); endDate.endOf('week');
} }
const push = (eventStart: moment.Moment = start.clone()) => { const push = (eventStart: Dayjs = start.clone()) => {
// 必须在这个月的开始时间和结束时间,且在日程的开始时间之后 // 必须在这个月的开始时间和结束时间,且在日程的开始时间之后
if (eventStart.isBefore(start) || !eventStart.isBetween(startDate, endDate)) { if (eventStart.isBefore(start) || !eventStart.isBetween(startDate, endDate)) {
return; return;
@ -147,7 +149,7 @@ const useEvents = (dataSource: any, fieldNames: any, date: Date, view: (typeof W
}); });
while (interval.hasNext()) { while (interval.hasNext()) {
const { value } = interval.next(); const { value } = interval.next();
if (push(moment(value.toDate()))) break; if (push(dayjs(value.toDate()))) break;
} }
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -194,10 +196,11 @@ export const Calendar: any = observer(
(props: any) => { (props: any) => {
const { dataSource, fieldNames, showLunar, fixedBlock } = useProps(props); const { dataSource, fieldNames, showLunar, fixedBlock } = useProps(props);
const [date, setDate] = useState<Date>(new Date()); const [date, setDate] = useState<Date>(new Date());
const [view, setView] = useState<(typeof Weeks)[number]>('month'); const [view, setView] = useState<View>('month');
const events = useEvents(dataSource, fieldNames, date, view); const events = useEvents(dataSource, fieldNames, date, view);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [record, setRecord] = useState<any>({}); const [record, setRecord] = useState<any>({});
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
const components = useMemo(() => { const components = useMemo(() => {
return { return {
@ -211,8 +214,9 @@ export const Calendar: any = observer(
}; };
}, [showLunar]); }, [showLunar]);
return ( return wrapSSR(
<div style={{ height: fixedBlock ? '100%' : 700 }}> <div className={`${hashId} ${containerClassName}`} style={{ height: fixedBlock ? '100%' : 700 }}>
<GlobalStyle />
<CalendarRecordViewer visible={visible} setVisible={setVisible} record={record} /> <CalendarRecordViewer visible={visible} setVisible={setVisible} record={record} />
<BigCalendar <BigCalendar
popup popup
@ -229,7 +233,7 @@ export const Calendar: any = observer(
onSelectSlot={(slotInfo) => { onSelectSlot={(slotInfo) => {
console.log('onSelectSlot', slotInfo); console.log('onSelectSlot', slotInfo);
}} }}
onDoubleClickEvent={(event) => { onDoubleClickEvent={() => {
console.log('onDoubleClickEvent'); console.log('onDoubleClickEvent');
}} }}
onSelectEvent={(event) => { onSelectEvent={(event) => {
@ -237,15 +241,15 @@ export const Calendar: any = observer(
if (!record) { if (!record) {
return; return;
} }
record.__event = { ...event, start: formatDate(moment(event.start)), end: formatDate(moment(event.end)) }; record.__event = { ...event, start: formatDate(dayjs(event.start)), end: formatDate(dayjs(event.end)) };
setRecord(record); setRecord(record);
setVisible(true); setVisible(true);
}} }}
formats={{ formats={{
monthHeaderFormat: 'Y-M', monthHeaderFormat: 'YYYY-M',
agendaDateFormat: 'M-DD', agendaDateFormat: 'M-DD',
dayHeaderFormat: 'Y-M-DD', dayHeaderFormat: 'YYYY-M-DD',
dayRangeHeaderFormat: ({ start, end }, culture, local) => { dayRangeHeaderFormat: ({ start, end }, culture, local) => {
if (eq(start, end, 'month')) { if (eq(start, end, 'month')) {
return local.format(start, 'Y-M', culture); return local.format(start, 'Y-M', culture);
@ -256,7 +260,7 @@ export const Calendar: any = observer(
components={components} components={components}
localizer={localizer} localizer={localizer}
/> />
</div> </div>,
); );
}, },
{ displayName: 'Calendar' }, { displayName: 'Calendar' },

View File

@ -1,6 +1,6 @@
import { observer } from '@formily/react'; import { observer } from '@formily/react';
import { dayjs } from '@nocobase/utils/client';
import { Modal, Radio, Space, Typography } from 'antd'; import { Modal, Radio, Space, Typography } from 'antd';
import moment from 'moment';
import React, { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -16,7 +16,7 @@ export const DeleteEvent = observer(
const { visible, setVisible } = useActionContext(); const { visible, setVisible } = useActionContext();
const { exclude = [], cron, ...record } = useRecord(); const { exclude = [], cron, ...record } = useRecord();
const { close } = useContext(DeleteEventContext); const { close } = useContext(DeleteEventContext);
const startDate = formatDate(moment(record.__parent.__event.start)); const startDate = formatDate(dayjs(record.__parent.__event.start));
const filterByTk = useFilterByTk(); const filterByTk = useFilterByTk();
const { resource, service, __parent } = useBlockRequestContext(); const { resource, service, __parent } = useBlockRequestContext();
const [value, onChange] = useState(startDate); const [value, onChange] = useState(startDate);

View File

@ -7,15 +7,15 @@ import { useDesignable } from '../../hooks';
import { CalendarToolbarContext } from './context'; import { CalendarToolbarContext } from './context';
export const Nav = observer( export const Nav = observer(
(props) => { () => {
const { DesignableBar } = useDesignable(); const { DesignableBar } = useDesignable();
const { onNavigate } = useContext(CalendarToolbarContext); const { onNavigate } = useContext(CalendarToolbarContext);
return ( return (
<div className="ant-btn-group"> <Button.Group>
<Button icon={<LeftOutlined />} onClick={() => onNavigate(Navigate.PREVIOUS)}></Button> <Button icon={<LeftOutlined />} onClick={() => onNavigate(Navigate.PREVIOUS)}></Button>
<Button icon={<RightOutlined />} onClick={() => onNavigate(Navigate.NEXT)}></Button> <Button icon={<RightOutlined />} onClick={() => onNavigate(Navigate.NEXT)}></Button>
<DesignableBar /> <DesignableBar />
</div> </Button.Group>
); );
}, },
{ displayName: 'Nav' }, { displayName: 'Nav' },

View File

@ -1,4 +1,5 @@
import { observer } from '@formily/react'; import { observer } from '@formily/react';
import { Button } from 'antd';
import React, { useContext, useMemo } from 'react'; import React, { useContext, useMemo } from 'react';
import { useDesignable } from '../../hooks'; import { useDesignable } from '../../hooks';
import { CalendarToolbarContext } from './context'; import { CalendarToolbarContext } from './context';
@ -17,11 +18,11 @@ export const Title = observer(
}, [view, date, showLunar]); }, [view, date, showLunar]);
return ( return (
<div className="ant-btn-group" style={{ fontSize: '1.75em', fontWeight: 300 }}> <Button.Group style={{ fontSize: '1.75em', fontWeight: 300 }}>
<span>{label}</span> <span>{label}</span>
<span style={{ marginLeft: '4px' }}>{lunarElement}</span> <span style={{ marginLeft: '4px' }}>{lunarElement}</span>
<DesignableBar /> <DesignableBar />
</div> </Button.Group>
); );
}, },
{ displayName: 'Title' }, { displayName: 'Title' },

View File

@ -15,7 +15,7 @@ export const ViewSelect = observer(
} = useContext(CalendarToolbarContext); } = useContext(CalendarToolbarContext);
return ( return (
<div className="ant-btn-group"> <div className="ant-btn-group">
<Select dropdownMatchSelectWidth={false} value={view} onChange={onView}> <Select popupMatchSelectWidth={false} value={view} onChange={onView}>
{views.map((name) => ( {views.map((name) => (
<Select.Option key={name} value={name}> <Select.Option key={name} value={name}>
{messages[name]} {messages[name]}

View File

@ -1,4 +1,4 @@
import moment from 'moment'; import { dayjs } from '@nocobase/utils/client';
import React from 'react'; import React from 'react';
import { render, screen } from 'testUtils'; import { render, screen } from 'testUtils';
import App1 from '../demos/demo1'; import App1 from '../demos/demo1';
@ -8,7 +8,7 @@ describe('Calendar', () => {
it('basic', () => { it('basic', () => {
render(<App1 />); render(<App1 />);
const currentDate = moment().format('YYYY-M'); const currentDate = dayjs().format('YYYY-M');
expect(screen.getByText('Today')).toBeInTheDocument(); expect(screen.getByText('Today')).toBeInTheDocument();
expect(screen.getByText(currentDate)).toBeInTheDocument(); expect(screen.getByText(currentDate)).toBeInTheDocument();
@ -18,7 +18,7 @@ describe('Calendar', () => {
it('use CalendarBlockProvider', () => { it('use CalendarBlockProvider', () => {
render(<App2 />); render(<App2 />);
const currentDate = moment().format('YYYY-M'); const currentDate = dayjs().format('YYYY-M');
expect(screen.getByText('Today')).toBeInTheDocument(); expect(screen.getByText('Today')).toBeInTheDocument();
expect(screen.getByText(currentDate)).toBeInTheDocument(); expect(screen.getByText(currentDate)).toBeInTheDocument();

View File

@ -1,7 +1,4 @@
import React from 'react'; import React, { useMemo } from 'react';
import moment from 'moment';
import { useMemo } from 'react';
import solarLunar from 'solarlunar-es';
import { getLunarDay } from '../utils'; import { getLunarDay } from '../utils';
const Header = ({ date, label, drilldownView, onDrillDown, showLunar = false, type, localizer }) => { const Header = ({ date, label, drilldownView, onDrillDown, showLunar = false, type, localizer }) => {

View File

@ -0,0 +1,87 @@
import { createGlobalStyle } from 'antd-style';
const GlobalStyle = createGlobalStyle`
.rbc-overlay {
position: absolute;
z-index: 50;
margin-top: 5px;
border-radius: 2px;
// border: 1px solid #e5e5e5;
background-color: #fff;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
padding: 12px 16px;
}
.rbc-overlay > * + * {
margin-top: 1px;
}
.rbc-overlay-header {
font-weight: 500;
min-height: 32px;
border-bottom: 1px solid #f0f0f0;
margin: -12px -16px 12px -16px;
padding: 5px 16px 4px;
}
.rbc-event {
border: none;
box-sizing: border-box;
box-shadow: none;
margin: 0;
padding: 2px 5px;
background-color: rgba(240, 240, 240, 0.65);
border-radius: 2px;
// color: #1890ff;
cursor: pointer;
font-size: 12px;
width: 100%;
text-align: left;
&:hover {
background-color: #e6f7ff;
color: #1890ff;
}
}
.rbc-slot-selecting .rbc-event {
cursor: inherit;
pointer-events: none;
}
.rbc-event.rbc-selected {
background-color: #e6f7ff;
color: #1890ff;
}
.rbc-event:focus {
// outline: 5px auto #3b99fc;
}
.rbc-event-label {
font-size: 80%;
}
.rbc-event-overlaps {
box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
}
.rbc-event-continues-prior {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-event-continues-after {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-event-continues-earlier {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.rbc-event-continues-later {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
`;
GlobalStyle.displayName = 'GlobalStyle';
export default GlobalStyle;

View File

@ -1,10 +1,9 @@
import DeleteEvent from './DeleteEvent';
import { ActionBar } from '../action'; import { ActionBar } from '../action';
import { Calendar } from './Calendar'; import { Calendar } from './Calendar';
import { CalendarDesigner } from './Calendar.Designer'; import { CalendarDesigner } from './Calendar.Designer';
import DeleteEvent from './DeleteEvent';
import { Event } from './Event'; import { Event } from './Event';
import { Nav } from './Nav'; import { Nav } from './Nav';
import './style.less';
import { Title } from './Title'; import { Title } from './Title';
import { Today } from './Today'; import { Today } from './Today';
import { ViewSelect } from './ViewSelect'; import { ViewSelect } from './ViewSelect';

View File

@ -1,811 +0,0 @@
@charset "UTF-8";
.rbc-btn {
color: inherit;
font: inherit;
margin: 0;
}
button.rbc-btn {
overflow: visible;
text-transform: none;
-webkit-appearance: button;
cursor: pointer;
}
button[disabled].rbc-btn {
cursor: not-allowed;
}
button.rbc-input::-moz-focus-inner {
border: 0;
padding: 0;
}
.rbc-calendar {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: stretch;
height: 100%;
}
.rbc-calendar *,
.rbc-calendar *:before,
.rbc-calendar *:after {
box-sizing: inherit;
}
.rbc-abs-full,
.rbc-row-bg {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.rbc-ellipsis,
.rbc-event-label,
.rbc-row-segment .rbc-event-content,
.rbc-show-more {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rbc-rtl {
direction: rtl;
}
.rbc-off-range {
color: rgba(0, 0, 0, 0.25);
}
.rbc-off-range-bg {
// background: #e6e6e6;
}
.rbc-header {
// font-size: 16px;
overflow: hidden;
flex: 1 0 0%;
text-overflow: ellipsis;
white-space: nowrap;
padding: 4px 12px;
vertical-align: middle;
// font-weight: 500;
min-height: 32px;
color: rgba(0, 0, 0, 0.85);
margin: 0 4px;
border-bottom: 2px solid #f0f0f0;
}
.rbc-header + .rbc-header {
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-header + .rbc-header {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-header > a,
.rbc-header > a:active,
.rbc-header > a:visited {
color: inherit;
text-decoration: none;
}
.rbc-row-content {
position: relative;
user-select: none;
-webkit-user-select: none;
z-index: 4;
}
.rbc-row-content-scrollable {
display: flex;
flex-direction: column;
height: 100%;
}
.rbc-row-content-scrollable .rbc-row-content-scroll-container {
height: 100%;
overflow-y: scroll;
/* Hide scrollbar for Chrome, Safari and Opera */
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
.rbc-row-content-scrollable .rbc-row-content-scroll-container::-webkit-scrollbar {
display: none;
}
.rbc-toolbar {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
margin-bottom: 10px;
font-size: 16px;
}
.rbc-toolbar .rbc-toolbar-label {
flex-grow: 1;
padding: 0 10px;
text-align: center;
}
.rbc-toolbar button {
outline: none;
font-size: 14px;
line-height: 1.5715;
height: 32px;
color: #373a3c;
display: inline-block;
margin: 0;
position: relative;
z-index: 1;
text-align: center;
vertical-align: middle;
background: none;
background-image: none;
border: 1px solid #d9d9d9;
padding: 4px 15px;
border-radius: 2px;
line-height: normal;
white-space: nowrap;
}
.rbc-toolbar button:active,
.rbc-toolbar button.rbc-active {
// background-image: none;
// box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
// background-color: #e6e6e6;
z-index: 2;
color: #1890ff;
border-color: #1890ff;
}
.rbc-toolbar button:active:hover,
.rbc-toolbar button:active:focus,
.rbc-toolbar button.rbc-active:hover,
.rbc-toolbar button.rbc-active:focus {
// color: #373a3c;
// background-color: #d4d4d4;
// border-color: #8c8c8c;
z-index: 2;
color: #40a9ff;
border-color: #40a9ff;
}
// .rbc-toolbar button:focus {
// color: #373a3c;
// background-color: #e6e6e6;
// border-color: #adadad; }
.rbc-toolbar button:hover {
// color: #373a3c;
// background-color: #e6e6e6;
z-index: 2;
color: #40a9ff;
border-color: #40a9ff;
}
.rbc-btn-group {
display: inline-block;
white-space: nowrap;
}
.rbc-btn-group > button:first-child:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-btn-group > button:last-child:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) {
border-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) {
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-btn-group > button:not(:first-child):not(:last-child) {
border-radius: 0;
}
.rbc-btn-group button + button {
margin-left: -1px;
}
.rbc-rtl .rbc-btn-group button + button {
margin-left: 0;
margin-right: -1px;
}
.rbc-btn-group + .rbc-btn-group,
.rbc-btn-group + button {
margin-left: 10px;
}
.rbc-event {
border: none;
box-sizing: border-box;
box-shadow: none;
margin: 0;
padding: 2px 5px;
background-color: rgba(240, 240, 240, 0.65);
border-radius: 2px;
// color: #1890ff;
cursor: pointer;
font-size: 12px;
width: 100%;
text-align: left;
&:hover {
background-color: #e6f7ff;
color: #1890ff;
}
}
.rbc-slot-selecting .rbc-event {
cursor: inherit;
pointer-events: none;
}
.rbc-event.rbc-selected {
background-color: #e6f7ff;
color: #1890ff;
}
.rbc-event:focus {
// outline: 5px auto #3b99fc;
}
.rbc-event-label {
font-size: 80%;
}
.rbc-event-overlaps {
box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
}
.rbc-event-continues-prior {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.rbc-event-continues-after {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-event-continues-earlier {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.rbc-event-continues-later {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.rbc-row {
display: flex;
flex-direction: row;
}
.rbc-row-segment {
padding: 0 4px 1px 4px;
}
.rbc-selected-cell {
background-color: rgba(0, 0, 0, 0.1);
}
.rbc-show-more {
z-index: 4;
font-weight: bold;
font-size: 85%;
height: auto;
line-height: normal;
color: inherit;
padding: 2px 5px;
}
.rbc-month-view {
position: relative;
// border: 1px solid #f0f0f0;
display: flex;
flex-direction: column;
flex: 1 0 0;
width: 100%;
user-select: none;
-webkit-user-select: none;
height: 68vh;
}
.rbc-month-header {
display: flex;
flex-direction: row;
}
.rbc-month-row {
display: flex;
position: relative;
flex-direction: column;
flex: 1 0 0;
flex-basis: 0px;
overflow: hidden;
height: 100%;
}
.rbc-month-row + .rbc-month-row {
// border-top: 1px solid #f0f0f0;
}
.rbc-date-cell {
// cursor: pointer;
flex: 1 1 0;
min-width: 0;
padding-left: 12px;
padding-top: 4px;
}
.rbc-date-cell.rbc-now span {
// font-weight: bold;
color: #1890ff;
}
.rbc-date-cell a,
.rbc-date-cell a:active,
.rbc-date-cell a:visited {
color: inherit;
text-decoration: none;
}
.rbc-date-cell a:hover {
color: #1890ff;
}
.rbc-date-cell .rbc-date-solar {
font-weight: 500;
}
.rbc-date-cell .rbc-date-lunar {
padding-left: 12px;
}
.rbc-date-cell:not(.rbc-off-range) .rbc-date-lunar {
color: #aaa
}
.rbc-date-cell .rbc-date-lunar:hover {
color: inherit
}
.rbc-row-bg {
display: flex;
flex-direction: row;
flex: 1 0 0;
overflow: hidden;
}
.rbc-day-bg {
flex: 1 0 0%;
// border-top: 2px solid #f0f0f0;
margin: 0 4px;
&:hover {
background: #f5f5f5;
}
// cursor: pointer;
}
.rbc-month-view {
.rbc-day-bg {
border-top: 2px solid #f0f0f0;
}
.rbc-today {
border-color: #1890ff !important;
background-color: #e6f7ff !important;
}
.rbc-header {
border-bottom: 0 !important;
}
}
.rbc-day-bg + .rbc-day-bg {
// margin-left: 8px;
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-day-bg + .rbc-day-bg {
// border-left-width: 0;
// border-right: 1px solid #f0f0f0;
}
.rbc-overlay {
position: absolute;
z-index: 50;
margin-top: 5px;
border-radius: 2px;
// border: 1px solid #e5e5e5;
background-color: #fff;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
padding: 12px 16px;
}
.rbc-overlay > * + * {
margin-top: 1px;
}
.rbc-overlay-header {
font-weight: 500;
min-height: 32px;
border-bottom: 1px solid #f0f0f0;
margin: -12px -16px 12px -16px;
padding: 5px 16px 4px;
}
.rbc-agenda-view {
display: flex;
flex-direction: column;
flex: 1 0 0;
overflow: auto;
}
.rbc-agenda-view table.rbc-agenda-table {
width: 100%;
border: 1px solid #f0f0f0;
border-spacing: 0;
border-collapse: collapse;
}
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
padding: 5px 10px;
vertical-align: top;
}
.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
padding-left: 15px;
padding-right: 15px;
text-transform: lowercase;
}
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
border-top: 1px solid #f0f0f0;
}
.rbc-agenda-view table.rbc-agenda-table thead > tr > th {
padding: 3px 5px;
text-align: left;
border-bottom: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
text-align: right;
}
.rbc-agenda-time-cell {
text-transform: lowercase;
}
.rbc-agenda-time-cell .rbc-continues-after:after {
content: ' »';
}
.rbc-agenda-time-cell .rbc-continues-prior:before {
content: '« ';
}
.rbc-agenda-date-cell,
.rbc-agenda-time-cell {
white-space: nowrap;
}
.rbc-agenda-event-cell {
width: 100%;
}
.rbc-time-column {
display: flex;
flex-direction: column;
min-height: 100%;
}
.rbc-time-column .rbc-timeslot-group {
flex: 1;
}
.rbc-timeslot-group {
border-bottom: 1px solid #f0f0f0;
min-height: 40px;
line-height: 39px;
display: flex;
flex-flow: column nowrap;
// cursor: pointer;
&:hover {
background: #f0f0f0;
}
}
.rbc-time-gutter,
.rbc-header-gutter {
flex: none;
}
.rbc-label {
padding: 0 5px;
}
.rbc-day-slot {
position: relative;
}
.rbc-day-slot .rbc-events-container {
bottom: 0;
left: 0;
position: absolute;
right: 0;
margin-right: 10px;
top: 0;
}
.rbc-day-slot .rbc-events-container.rbc-rtl {
left: 10px;
right: 0;
}
.rbc-day-slot .rbc-event {
border: 1px solid #265985;
display: flex;
max-height: 100%;
min-height: 20px;
flex-flow: column wrap;
align-items: flex-start;
overflow: hidden;
position: absolute;
}
.rbc-day-slot .rbc-event-label {
flex: none;
padding-right: 5px;
width: auto;
}
.rbc-day-slot .rbc-event-content {
width: 100%;
flex: 1 1 0;
word-wrap: break-word;
line-height: 1;
height: 100%;
min-height: 1em;
}
.rbc-day-slot .rbc-time-slot {
// border-top: 1px solid #f7f7f7;
}
.rbc-time-header-gutter {
line-height: 40px;
}
.rbc-time-header-cell {
min-height: 32px !important;
}
.rbc-time-header-cell .rbc-header {
display: flex;
}
.rbc-time-header-cell .rbc-header.rbc-today {
border-color: #1890ff;
background-color: #e6f7ff;
color: #1890ff
}
.rbc-time-header-cell .rbc-header a {
display: flex;
flex-direction: column;
}
.rbc-time-header-cell .rbc-date-wrap {
display: flex;
align-items: center;
}
.rbc-time-header-cell .rbc-date-solar {
font-size: 18px;
}
.rbc-time-header-cell .rbc-date-lunar {
margin-left: 4px;
}
.rbc-time-header-cell .rbc-header:not(.rbc-today) .rbc-date-lunar {
color: #aaa;
}
.rbc-calendar.view-week {
.rbc-time-header-cell {
margin-top: -32px;
margin-bottom: 4px;
}
.rbc-time-view {
padding-top: 32px;
border-top: 0;
}
.rbc-header {
padding: 4px 8px;
}
.rbc-time-header-content {
padding: 4px 0;
}
.rbc-time-header-gutter {
padding: 0;
padding-top: 2px;
> div {
border-top: 2px solid #f0f0f0;
padding: 0 5px;
}
}
}
.rbc-time-view-resources .rbc-time-gutter,
.rbc-time-view-resources .rbc-time-header-gutter {
position: sticky;
left: 0;
background-color: white;
border-right: 1px solid #f0f0f0;
z-index: 10;
margin-right: -1px;
}
.rbc-time-view-resources .rbc-time-header {
overflow: hidden;
}
.rbc-time-view-resources .rbc-time-header-content {
min-width: auto;
flex: 1 0 0;
flex-basis: 0px;
}
.rbc-time-view-resources .rbc-time-header-cell-single-day {
display: none;
}
.rbc-time-view-resources .rbc-day-slot {
min-width: 140px;
}
.rbc-time-view-resources .rbc-header,
.rbc-time-view-resources .rbc-day-bg {
width: 140px;
flex: 1 1 0;
flex-basis: 0 px;
}
.rbc-time-header-content + .rbc-time-header-content {
margin-left: -1px;
}
.rbc-time-slot {
flex: 1 0 0;
}
.rbc-time-slot.rbc-now {
font-weight: bold;
}
.rbc-day-header {
text-align: center;
}
.rbc-slot-selection {
z-index: 10;
position: absolute;
background-color: rgba(0, 0, 0, 0.5);
color: white;
font-size: 75%;
width: 100%;
padding: 3px;
}
.rbc-slot-selecting {
cursor: move;
}
.rbc-time-view {
display: flex;
flex-direction: column;
flex: 1;
width: 100%;
border-top: 1px solid #f0f0f0;
min-height: 0;
}
.rbc-time-view .rbc-time-gutter {
white-space: nowrap;
}
.rbc-time-view .rbc-allday-cell {
box-sizing: content-box;
width: 100%;
height: 100%;
position: relative;
}
.rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
border-left: 1px solid #f0f0f0;
}
.rbc-time-view .rbc-allday-events {
position: relative;
z-index: 4;
}
.rbc-time-view .rbc-row {
box-sizing: border-box;
min-height: 20px;
}
.rbc-time-header {
display: flex;
flex: 0 0 auto;
flex-direction: row;
}
.rbc-time-header.rbc-overflowing {
border-right: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-time-header.rbc-overflowing {
border-right-width: 0;
border-left: 1px solid #f0f0f0;
}
.rbc-time-header > .rbc-row:first-child {
border-bottom: 1px solid #f0f0f0;
}
.rbc-time-header > .rbc-row.rbc-row-resource {
border-bottom: 1px solid #f0f0f0;
}
.rbc-time-header-cell-single-day {
display: none;
}
.rbc-time-header-content {
flex: 1;
// display: flex;
min-width: 0;
flex-direction: column;
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-time-header-content {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-time-header-content > .rbc-row.rbc-row-resource {
border-bottom: 1px solid #f0f0f0;
flex-shrink: 0;
}
.rbc-time-content {
display: flex;
flex: 1 0 0%;
align-items: flex-start;
width: 100%;
border-top: 1px solid #f0f0f0;
overflow-y: auto;
position: relative;
}
.rbc-time-content > .rbc-time-gutter {
flex: none;
}
.rbc-time-content > * + * > * {
// border-left: 1px solid #f0f0f0;
}
.rbc-rtl .rbc-time-content > * + * > * {
border-left-width: 0;
border-right: 1px solid #f0f0f0;
}
.rbc-time-content > .rbc-day-slot {
width: 100%;
user-select: none;
-webkit-user-select: none;
}
.rbc-current-time-indicator {
position: absolute;
z-index: 3;
left: 0;
right: 0;
height: 1px;
background-color: #74ad31;
pointer-events: none;
}
@media only screen and (max-width: 800px) {
.view-type-calendar .action-buttons {
position: relative !important;
left: 0 !important;
.filter-action-button {
left: 0 !important;
}
}
.rbc-toolbar .rbc-toolbar-label {
position: absolute;
top: 28px;
left: 50%;
transform: translateX(-50%);
}
.rbc-toolbar {
justify-content: space-between !important;
}
.rbc-header {
padding: 4px !important;
}
}

View File

@ -0,0 +1,526 @@
import { genStyleHook } from './../__builtins__';
export default genStyleHook('nb-calendar', (token) => {
const { componentCls } = token;
return {
[componentCls]: {
'.rbc-btn': { color: 'inherit', font: 'inherit', margin: '0' },
'button.rbc-btn': {
overflow: 'visible',
textTransform: 'none',
WebkitAppearance: 'button',
cursor: 'pointer',
},
'button[disabled].rbc-btn': { cursor: 'not-allowed' },
'button.rbc-input::-moz-focus-inner': { border: '0', padding: '0' },
'.rbc-button-link': {
border: 'none',
backgroundColor: 'transparent',
},
'.rbc-calendar': {
boxSizing: 'border-box',
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch',
height: '100%',
},
'.rbc-calendar *,\n.rbc-calendar *:before,\n.rbc-calendar *:after': {
boxSizing: 'inherit',
},
'.rbc-abs-full,\n.rbc-row-bg': {
overflow: 'hidden',
position: 'absolute',
top: '0',
left: '0',
right: '0',
bottom: '0',
},
'.rbc-ellipsis,\n.rbc-event-label,\n.rbc-row-segment .rbc-event-content,\n.rbc-show-more': {
display: 'block',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
'.rbc-rtl': { direction: 'rtl' },
'.rbc-off-range': { color: 'rgba(0, 0, 0, 0.25)' },
'.rbc-header': {
overflow: 'hidden',
flex: '1 0 0%',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
padding: '4px 12px',
verticalAlign: 'middle',
minHeight: '32px',
color: 'rgba(0, 0, 0, 0.85)',
margin: '0 4px',
borderBottom: '2px solid #f0f0f0',
},
'.rbc-rtl .rbc-header + .rbc-header': {
borderLeftWidth: '0',
borderRight: '1px solid #f0f0f0',
},
'.rbc-header > a,\n.rbc-header > a:active,\n.rbc-header > a:visited': {
color: 'inherit',
textDecoration: 'none',
},
'.rbc-row-content': {
position: 'relative',
userSelect: 'none',
WebkitUserSelect: 'none',
zIndex: 4,
},
'.rbc-row-content-scrollable': {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
'.rbc-row-content-scrollable .rbc-row-content-scroll-container': {
height: '100%',
overflowY: 'scroll',
msOverflowStyle: 'none',
scrollbarWidth: 'none',
},
'.rbc-row-content-scrollable .rbc-row-content-scroll-container::-webkit-scrollbar': {
display: 'none',
},
'.rbc-toolbar': {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center',
marginBottom: '10px',
fontSize: '16px',
},
'.rbc-toolbar .rbc-toolbar-label': {
flexGrow: 1,
padding: '0 10px',
textAlign: 'center',
},
'.rbc-toolbar button': {
outline: 'none',
fontSize: '14px',
lineHeight: [1.5715, 'normal'],
height: '32px',
color: '#373a3c',
display: 'inline-block',
margin: '0',
position: 'relative',
zIndex: 1,
textAlign: 'center',
verticalAlign: 'middle',
background: 'none',
backgroundImage: 'none',
border: '1px solid #d9d9d9',
padding: '4px 15px',
borderRadius: '2px',
whiteSpace: 'nowrap',
},
'.rbc-toolbar button:active,\n.rbc-toolbar button.rbc-active': {
zIndex: 2,
color: '#1890ff',
borderColor: '#1890ff',
},
'.rbc-toolbar button:active:hover,\n.rbc-toolbar button:active:focus,\n.rbc-toolbar button.rbc-active:hover,\n.rbc-toolbar button.rbc-active:focus':
{
zIndex: 2,
color: '#40a9ff',
borderColor: '#40a9ff',
},
'.rbc-toolbar button:hover': {
zIndex: 2,
color: '#40a9ff',
borderColor: '#40a9ff',
},
'.rbc-btn-group': { display: 'inline-block', whiteSpace: 'nowrap' },
'.rbc-btn-group > button:first-child:not(:last-child)': {
borderTopRightRadius: '0',
borderBottomRightRadius: '0',
},
'.rbc-btn-group > button:last-child:not(:first-child)': {
borderTopLeftRadius: '0',
borderBottomLeftRadius: '0',
},
'.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child)': {
borderRadius: '4px',
borderTopLeftRadius: '0',
borderBottomLeftRadius: '0',
},
'.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child)': {
borderRadius: '4px',
borderTopRightRadius: '0',
borderBottomRightRadius: '0',
},
'.rbc-btn-group > button:not(:first-child):not(:last-child)': {
borderRadius: '0',
},
'.rbc-btn-group button + button': { marginLeft: '-1px' },
'.rbc-rtl .rbc-btn-group button + button': {
marginLeft: '0',
marginRight: '-1px',
},
'.rbc-btn-group + .rbc-btn-group,\n.rbc-btn-group + button': {
marginLeft: '10px',
},
'.rbc-event': {
border: 'none',
boxSizing: 'border-box',
boxShadow: 'none',
margin: '0',
padding: '2px 5px',
backgroundColor: 'rgba(240, 240, 240, 0.65)',
borderRadius: '2px',
cursor: 'pointer',
fontSize: '12px',
width: '100%',
textAlign: 'left',
'&:hover': { backgroundColor: '#e6f7ff', color: '#1890ff' },
},
'.rbc-slot-selecting .rbc-event': {
cursor: 'inherit',
pointerEvents: 'none',
},
'.rbc-event.rbc-selected': { backgroundColor: '#e6f7ff', color: '#1890ff' },
'.rbc-event-label': { fontSize: '80%' },
'.rbc-event-overlaps': {
boxShadow: '-1px 1px 5px 0px rgba(51, 51, 51, 0.5)',
},
'.rbc-event-continues-prior': {
borderTopLeftRadius: '0',
borderBottomLeftRadius: '0',
},
'.rbc-event-continues-after': {
borderTopRightRadius: '0',
borderBottomRightRadius: '0',
},
'.rbc-event-continues-earlier': {
borderTopLeftRadius: '0',
borderTopRightRadius: '0',
},
'.rbc-event-continues-later': {
borderBottomLeftRadius: '0',
borderBottomRightRadius: '0',
},
'.rbc-row': { display: 'flex', flexDirection: 'row' },
'.rbc-row-segment': { padding: '0 4px 1px 4px' },
'.rbc-selected-cell': { backgroundColor: 'rgba(0, 0, 0, 0.1)' },
'.rbc-show-more': {
zIndex: 4,
fontWeight: 'bold',
fontSize: '85%',
height: 'auto',
lineHeight: 'normal',
color: 'inherit',
padding: '2px 5px',
},
'.rbc-month-view': {
position: 'relative',
display: 'flex',
flexDirection: 'column',
flex: '1 0 0',
width: '100%',
userSelect: 'none',
WebkitUserSelect: 'none',
height: '68vh',
'.rbc-day-bg': { borderTop: '2px solid #f0f0f0' },
'.rbc-today': {
borderColor: '#1890ff !important',
backgroundColor: '#e6f7ff !important',
},
'.rbc-header': { borderBottom: '0 !important' },
},
'.rbc-month-header': { display: 'flex', flexDirection: 'row' },
'.rbc-month-row': {
display: 'flex',
position: 'relative',
flexDirection: 'column',
flex: '1 0 0',
flexBasis: '0px',
overflow: 'hidden',
height: '100%',
},
'.rbc-date-cell': {
flex: '1 1 0',
minWidth: '0',
paddingLeft: '12px',
paddingTop: '4px',
},
'.rbc-date-cell.rbc-now span': { color: '#1890ff' },
'.rbc-date-cell a,\n.rbc-date-cell a:active,\n.rbc-date-cell a:visited': {
color: 'inherit',
textDecoration: 'none',
},
'.rbc-date-cell a:hover': { color: '#1890ff' },
'.rbc-date-cell .rbc-date-solar': { fontWeight: 500 },
'.rbc-date-cell .rbc-date-lunar': { paddingLeft: '12px' },
'.rbc-date-cell:not(.rbc-off-range) .rbc-date-lunar': { color: '#aaa' },
'.rbc-date-cell .rbc-date-lunar:hover': { color: 'inherit' },
'.rbc-row-bg': {
display: 'flex',
flexDirection: 'row',
flex: '1 0 0',
overflow: 'hidden',
},
'.rbc-day-bg': {
flex: '1 0 0%',
margin: '0 4px',
'&:hover': { background: '#f5f5f5' },
},
'.rbc-agenda-view': {
display: 'flex',
flexDirection: 'column',
flex: '1 0 0',
overflow: 'auto',
},
'.rbc-agenda-view table.rbc-agenda-table': {
width: '100%',
border: '1px solid #f0f0f0',
borderSpacing: '0',
borderCollapse: 'collapse',
},
'.rbc-agenda-view table.rbc-agenda-table tbody > tr > td': {
padding: '5px 10px',
verticalAlign: 'top',
},
'.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell': {
paddingLeft: '15px',
paddingRight: '15px',
textTransform: 'lowercase',
},
'.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td': {
borderLeft: '1px solid #f0f0f0',
},
'.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td': {
borderLeftWidth: '0',
borderRight: '1px solid #f0f0f0',
},
'.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr': {
borderTop: '1px solid #f0f0f0',
},
'.rbc-agenda-view table.rbc-agenda-table thead > tr > th': {
padding: '3px 5px',
textAlign: 'left',
borderBottom: '1px solid #f0f0f0',
},
'.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th': {
textAlign: 'right',
},
'.rbc-agenda-time-cell': { textTransform: 'lowercase' },
'.rbc-agenda-time-cell .rbc-continues-after:after': { content: "' »'" },
'.rbc-agenda-time-cell .rbc-continues-prior:before': { content: "'« '" },
'.rbc-agenda-date-cell,\n.rbc-agenda-time-cell': { whiteSpace: 'nowrap' },
'.rbc-agenda-event-cell': { width: '100%' },
'.rbc-time-column': {
display: 'flex',
flexDirection: 'column',
minHeight: '100%',
},
'.rbc-time-column .rbc-timeslot-group': { flex: 1 },
'.rbc-timeslot-group': {
borderBottom: '1px solid #f0f0f0',
minHeight: '40px',
lineHeight: '39px',
display: 'flex',
flexFlow: 'column nowrap',
'&:hover': { background: '#f0f0f0' },
},
'.rbc-time-gutter,\n.rbc-header-gutter': { flex: 'none' },
'.rbc-label': { padding: '0 5px' },
'.rbc-day-slot': { position: 'relative' },
'.rbc-day-slot .rbc-events-container': {
bottom: '0',
left: '0',
position: 'absolute',
right: '0',
marginRight: '10px',
top: '0',
},
'.rbc-day-slot .rbc-events-container.rbc-rtl': { left: '10px', right: '0' },
'.rbc-day-slot .rbc-event': {
border: '1px solid #265985',
display: 'flex',
maxHeight: '100%',
minHeight: '20px',
flexFlow: 'column wrap',
alignItems: 'flex-start',
overflow: 'hidden',
position: 'absolute',
},
'.rbc-day-slot .rbc-event-label': {
flex: 'none',
paddingRight: '5px',
width: 'auto',
},
'.rbc-day-slot .rbc-event-content': {
width: '100%',
flex: '1 1 0',
wordWrap: 'break-word',
lineHeight: 1,
height: '100%',
minHeight: '1em',
},
'.rbc-time-header-gutter': { lineHeight: '40px' },
'.rbc-time-header-cell': { minHeight: '32px !important' },
'.rbc-time-header-cell .rbc-header': { display: 'flex' },
'.rbc-time-header-cell .rbc-header.rbc-today': {
borderColor: '#1890ff',
backgroundColor: '#e6f7ff',
color: '#1890ff',
},
'.rbc-time-header-cell .rbc-header a': {
display: 'flex',
flexDirection: 'column',
},
'.rbc-time-header-cell .rbc-date-wrap': {
display: 'flex',
alignItems: 'center',
},
'.rbc-time-header-cell .rbc-date-solar': { fontSize: '18px' },
'.rbc-time-header-cell .rbc-date-lunar': { marginLeft: '4px' },
'.rbc-time-header-cell .rbc-header:not(.rbc-today) .rbc-date-lunar': {
color: '#aaa',
},
'.rbc-calendar.view-week': {
'.rbc-time-header-cell': { marginTop: '-32px', marginBottom: '4px' },
'.rbc-time-view': { paddingTop: '32px', borderTop: '0' },
'.rbc-header': { padding: '4px 8px' },
'.rbc-time-header-content': { padding: '4px 0' },
'.rbc-time-header-gutter': {
padding: '0',
paddingTop: '2px',
'> div': { borderTop: '2px solid #f0f0f0', padding: '0 5px' },
},
},
'.rbc-time-view-resources .rbc-time-gutter,\n.rbc-time-view-resources .rbc-time-header-gutter': {
position: 'sticky',
left: '0',
backgroundColor: 'white',
borderRight: '1px solid #f0f0f0',
zIndex: 10,
marginRight: '-1px',
},
'.rbc-time-view-resources .rbc-time-header': { overflow: 'hidden' },
'.rbc-time-view-resources .rbc-time-header-content': {
minWidth: 'auto',
flex: '1 0 0',
flexBasis: '0px',
},
'.rbc-time-view-resources .rbc-time-header-cell-single-day': {
display: 'none',
},
'.rbc-time-view-resources .rbc-day-slot': { minWidth: '140px' },
'.rbc-time-view-resources .rbc-header,\n.rbc-time-view-resources .rbc-day-bg': {
width: '140px',
flex: '1 1 0',
flexBasis: '0 px',
},
'.rbc-time-header-content + .rbc-time-header-content': { marginLeft: '-1px' },
'.rbc-time-slot': { flex: '1 0 0' },
'.rbc-time-slot.rbc-now': { fontWeight: 'bold' },
'.rbc-day-header': { textAlign: 'center' },
'.rbc-slot-selection': {
zIndex: 10,
position: 'absolute',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
color: 'white',
fontSize: '75%',
width: '100%',
padding: '3px',
},
'.rbc-slot-selecting': { cursor: 'move' },
'.rbc-time-view': {
display: 'flex',
flexDirection: 'column',
flex: 1,
width: '100%',
borderTop: '1px solid #f0f0f0',
minHeight: '0',
},
'.rbc-time-view .rbc-time-gutter': { whiteSpace: 'nowrap' },
'.rbc-time-view .rbc-allday-cell': {
boxSizing: 'content-box',
width: '100%',
height: '100%',
position: 'relative',
},
'.rbc-time-view .rbc-allday-cell + .rbc-allday-cell': {
borderLeft: '1px solid #f0f0f0',
},
'.rbc-time-view .rbc-allday-events': { position: 'relative', zIndex: 4 },
'.rbc-time-view .rbc-row': { boxSizing: 'border-box', minHeight: '20px' },
'.rbc-time-header': {
display: 'flex',
flex: '0 0 auto',
flexDirection: 'row',
},
'.rbc-time-header.rbc-overflowing': { borderRight: '1px solid #f0f0f0' },
'.rbc-rtl .rbc-time-header.rbc-overflowing': {
borderRightWidth: '0',
borderLeft: '1px solid #f0f0f0',
},
'.rbc-time-header > .rbc-row:first-child': {
borderBottom: '1px solid #f0f0f0',
},
'.rbc-time-header > .rbc-row.rbc-row-resource': {
borderBottom: '1px solid #f0f0f0',
},
'.rbc-time-header-cell-single-day': { display: 'none' },
'.rbc-time-header-content': {
flex: 1,
minWidth: '0',
flexDirection: 'column',
},
'.rbc-rtl .rbc-time-header-content': {
borderLeftWidth: '0',
borderRight: '1px solid #f0f0f0',
},
'.rbc-time-header-content > .rbc-row.rbc-row-resource': {
borderBottom: '1px solid #f0f0f0',
flexShrink: 0,
},
'.rbc-time-content': {
display: 'flex',
flex: '1 0 0%',
alignItems: 'flex-start',
width: '100%',
borderTop: '1px solid #f0f0f0',
overflowY: 'auto',
position: 'relative',
},
'.rbc-time-content > .rbc-time-gutter': { flex: 'none' },
'.rbc-rtl .rbc-time-content > * + * > *': {
borderLeftWidth: '0',
borderRight: '1px solid #f0f0f0',
},
'.rbc-time-content > .rbc-day-slot': {
width: '100%',
userSelect: 'none',
WebkitUserSelect: 'none',
},
'.rbc-current-time-indicator': {
position: 'absolute',
zIndex: 3,
left: '0',
right: '0',
height: '1px',
backgroundColor: '#74ad31',
pointerEvents: 'none',
},
'@media only screen and (max-width: 800px)': {
'.view-type-calendar .action-buttons': {
position: 'relative !important',
left: '0 !important',
'.filter-action-button': { left: '0 !important' },
},
'.rbc-toolbar .rbc-toolbar-label': {
position: 'absolute',
top: '28px',
left: '50%',
transform: 'translateX(-50%)',
},
'.rbc-toolbar': { justifyContent: 'space-between !important' },
'.rbc-header': { padding: '4px !important' },
} as any,
},
};
});

View File

@ -1,5 +1,5 @@
import { dayjs } from '@nocobase/utils/client';
import { get } from 'lodash'; import { get } from 'lodash';
import moment from 'moment';
import solarLunar from 'solarlunar-es'; import solarLunar from 'solarlunar-es';
import { i18n } from '../../../i18n'; import { i18n } from '../../../i18n';
@ -14,12 +14,12 @@ export const toEvents = (data: any[], fieldNames: any) => {
}); });
}; };
export const getLunarDay = (date: moment.MomentInput) => { export const getLunarDay = (date: dayjs.Dayjs | string) => {
const md = moment(date); const md = dayjs(date);
const result = solarLunar.solar2lunar(md.year(), md.month() + 1, md.date()); const result = solarLunar.solar2lunar(md.year(), md.month() + 1, md.date());
return typeof result !== 'number' ? result.lunarFestival || result.term || result.dayCn : result; return typeof result !== 'number' ? result.lunarFestival || result.term || result.dayCn : result;
}; };
export const formatDate = (date: moment.Moment) => { export const formatDate = (date: dayjs.Dayjs) => {
return date.format('YYYY-MM-DDTHH:mm:ss.SSSZ'); return date.format('YYYY-MM-DDTHH:mm:ss.SSSZ');
}; };

View File

@ -1,4 +1,4 @@
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { Cascader, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { Cascader, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,4 +1,4 @@
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { ArrayField } from '@formily/core'; import { ArrayField } from '@formily/core';
import { useField } from '@formily/react'; import { useField } from '@formily/react';
import { action } from '@formily/reactive'; import { action } from '@formily/reactive';

View File

@ -7,7 +7,9 @@ import uniq from 'lodash/uniq';
import React from 'react'; import React from 'react';
import { EllipsisWithTooltip } from '../input/EllipsisWithTooltip'; import { EllipsisWithTooltip } from '../input/EllipsisWithTooltip';
type ComposedCheckbox = React.FC<CheckboxProps> & { type ComposedCheckbox = React.ForwardRefExoticComponent<
Pick<Partial<any>, string | number | symbol> & React.RefAttributes<unknown>
> & {
Group?: React.FC<CheckboxGroupProps>; Group?: React.FC<CheckboxGroupProps>;
__ANT_CHECKBOX?: boolean; __ANT_CHECKBOX?: boolean;
ReadPretty?: React.FC<CheckboxProps>; ReadPretty?: React.FC<CheckboxProps>;

View File

@ -56,7 +56,7 @@ describe('Checkbox.Group', () => {
expect(container.querySelectorAll('.ant-tag')).toMatchInlineSnapshot(` expect(container.querySelectorAll('.ant-tag')).toMatchInlineSnapshot(`
NodeList [ NodeList [
<span <span
class="ant-tag ant-tag-red" class="ant-tag ant-tag-red css-dev-only-do-not-override-14wwjjs"
> >
1 1
</span>, </span>,
@ -66,12 +66,12 @@ describe('Checkbox.Group', () => {
expect(container.querySelectorAll('.ant-tag')).toMatchInlineSnapshot(` expect(container.querySelectorAll('.ant-tag')).toMatchInlineSnapshot(`
NodeList [ NodeList [
<span <span
class="ant-tag ant-tag-red" class="ant-tag ant-tag-red css-dev-only-do-not-override-14wwjjs"
> >
1 1
</span>, </span>,
<span <span
class="ant-tag ant-tag-blue" class="ant-tag ant-tag-blue css-dev-only-do-not-override-14wwjjs"
> >
2 2
</span>, </span>,

View File

@ -1,7 +1,7 @@
/** /**
* title: * title:
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { Checkbox, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { Checkbox, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,7 +1,7 @@
/** /**
* title: 勾选 * title: 勾选
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { Checkbox, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { Checkbox, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -46,7 +46,7 @@ export const CollectionSelect = connect(
return ( return (
<Select <Select
placeholder={t('Select collection')} placeholder={t('Select collection')}
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
{...others} {...others}
showSearch showSearch
filterOption={(input, option) => (option?.label ?? '').includes(input)} filterOption={(input, option) => (option?.label ?? '').includes(input)}

View File

@ -1,4 +1,4 @@
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { CollectionManagerProvider, CollectionSelect, FormProvider, SchemaComponent } from '@nocobase/client'; import { CollectionManagerProvider, CollectionSelect, FormProvider, SchemaComponent } from '@nocobase/client';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';

View File

@ -1,7 +1,7 @@
/** /**
* title: 勾选 * title: 勾选
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { ColorSelect, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { ColorSelect, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -64,7 +64,7 @@ const CronSetInternal = (props: CronSetProps) => {
return ( return (
<fieldset> <fieldset>
<Select <Select
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
allowClear allowClear
{...props} {...props}
value={value} value={value}

View File

@ -1,4 +1,4 @@
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { Cron, FormProvider, SchemaComponent } from '@nocobase/client'; import { Cron, FormProvider, SchemaComponent } from '@nocobase/client';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';

View File

@ -1,4 +1,4 @@
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { CronSet, FormProvider, SchemaComponent } from '@nocobase/client'; import { CronSet, FormProvider, SchemaComponent } from '@nocobase/client';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';

View File

@ -23,13 +23,13 @@ const DatePickerContext = React.createContext<IDatePickerProps>({ utc: true });
export const useDatePickerContext = () => React.useContext(DatePickerContext); export const useDatePickerContext = () => React.useContext(DatePickerContext);
export const DatePickerProvider = DatePickerContext.Provider; export const DatePickerProvider = DatePickerContext.Provider;
const _DatePicker: ComposedDatePicker = connect( const InternalDatePicker: ComposedDatePicker = connect(
AntdDatePicker, AntdDatePicker,
mapProps(mapDatePicker()), mapProps(mapDatePicker()),
mapReadPretty(ReadPretty.DatePicker), mapReadPretty(ReadPretty.DatePicker),
); );
const _RangePicker = connect( const InternalRangePicker = connect(
AntdDatePicker.RangePicker, AntdDatePicker.RangePicker,
mapProps(mapRangePicker()), mapProps(mapRangePicker()),
mapReadPretty(ReadPretty.DateRangePicker), mapReadPretty(ReadPretty.DateRangePicker),
@ -38,7 +38,7 @@ const _RangePicker = connect(
export const DatePicker = (props) => { export const DatePicker = (props) => {
const { utc = true } = useDatePickerContext(); const { utc = true } = useDatePickerContext();
props = { utc, ...props }; props = { utc, ...props };
return <_DatePicker {...props} />; return <InternalDatePicker {...props} />;
}; };
DatePicker.ReadPretty = ReadPretty.DatePicker; DatePicker.ReadPretty = ReadPretty.DatePicker;
@ -47,29 +47,29 @@ DatePicker.RangePicker = function RangePicker(props) {
const { t } = useTranslation(); const { t } = useTranslation();
const { utc = true } = useDatePickerContext(); const { utc = true } = useDatePickerContext();
const rangesValue = getDateRanges(); const rangesValue = getDateRanges();
const ranges = { const presets = [
[t('Today')]: rangesValue.today, { label: t('Today'), value: rangesValue.today },
[t('Last week')]: rangesValue.lastWeek, { label: t('Last week'), value: rangesValue.lastWeek },
[t('This week')]: rangesValue.thisWeek, { label: t('This week'), value: rangesValue.thisWeek },
[t('Next week')]: rangesValue.nextWeek, { label: t('Next week'), value: rangesValue.nextWeek },
[t('Last month')]: rangesValue.lastMonth, { label: t('Last month'), value: rangesValue.lastMonth },
[t('This month')]: rangesValue.thisMonth, { label: t('This month'), value: rangesValue.thisMonth },
[t('Next month')]: rangesValue.nextMonth, { label: t('Next month'), value: rangesValue.nextMonth },
[t('Last quarter')]: rangesValue.lastQuarter, { label: t('Last quarter'), value: rangesValue.lastQuarter },
[t('This quarter')]: rangesValue.thisQuarter, { label: t('This quarter'), value: rangesValue.thisQuarter },
[t('Next quarter')]: rangesValue.nextQuarter, { label: t('Next quarter'), value: rangesValue.nextQuarter },
[t('Last year')]: rangesValue.lastYear, { label: t('Last year'), value: rangesValue.lastYear },
[t('This year')]: rangesValue.thisYear, { label: t('This year'), value: rangesValue.thisYear },
[t('Next year')]: rangesValue.nextYear, { label: t('Next year'), value: rangesValue.nextYear },
[t('Last 7 days')]: rangesValue.last7Days, { label: t('Last 7 days'), value: rangesValue.last7Days },
[t('Next 7 days')]: rangesValue.next7Days, { label: t('Next 7 days'), value: rangesValue.next7Days },
[t('Last 30 days')]: rangesValue.last30Days, { label: t('Last 30 days'), value: rangesValue.last30Days },
[t('Next 30 days')]: rangesValue.next30Days, { label: t('Next 30 days'), value: rangesValue.next30Days },
[t('Last 90 days')]: rangesValue.last90Days, { label: t('Last 90 days'), value: rangesValue.last90Days },
[t('Next 90 days')]: rangesValue.next90Days, { label: t('Next 90 days'), value: rangesValue.next90Days },
}; ];
props = { utc, ranges, ...props }; props = { utc, presets, ...props };
return <_RangePicker {...props} />; return <InternalRangePicker {...props} />;
}; };
export default DatePicker; export default DatePicker;

View File

@ -1,12 +1,11 @@
import { usePrefixCls } from '@formily/antd/esm/__builtins__'; import { usePrefixCls } from '@formily/antd-v5/esm/__builtins__';
import { isArr } from '@formily/shared'; import { isArr } from '@formily/shared';
import { getDefaultFormat, str2moment } from '@nocobase/utils/client'; import { dayjs, getDefaultFormat, str2moment } from '@nocobase/utils/client';
import type { import type {
DatePickerProps as AntdDatePickerProps, DatePickerProps as AntdDatePickerProps,
RangePickerProps as AntdRangePickerProps, RangePickerProps as AntdRangePickerProps,
} from 'antd/es/date-picker'; } from 'antd/es/date-picker';
import cls from 'classnames'; import cls from 'classnames';
import moment from 'moment';
import React from 'react'; import React from 'react';
type Composed = { type Composed = {
@ -16,21 +15,23 @@ type Composed = {
export const ReadPretty: Composed = () => null; export const ReadPretty: Composed = () => null;
ReadPretty.DatePicker = (props: any) => { ReadPretty.DatePicker = function DatePicker(props: any) {
const prefixCls = usePrefixCls('description-date-picker', props);
if (!props.value) { if (!props.value) {
return <div></div>; return <div></div>;
} }
const prefixCls = usePrefixCls('description-date-picker', props);
const getLabels = () => { const getLabels = () => {
const format = getDefaultFormat(props) as string; const format = getDefaultFormat(props) as string;
const m = str2moment(props.value, props); const m = str2moment(props.value, props);
const labels = moment.isMoment(m) ? m.format(format) : ''; const labels = dayjs.isDayjs(m) ? m.format(format) : '';
return isArr(labels) ? labels.join('~') : labels; return isArr(labels) ? labels.join('~') : labels;
}; };
return <div className={cls(prefixCls, props.className)}>{getLabels()}</div>; return <div className={cls(prefixCls, props.className)}>{getLabels()}</div>;
}; };
ReadPretty.DateRangePicker = (props: any) => { ReadPretty.DateRangePicker = function DateRangePicker(props: any) {
const prefixCls = usePrefixCls('description-text', props); const prefixCls = usePrefixCls('description-text', props);
const format = getDefaultFormat(props); const format = getDefaultFormat(props);
const getLabels = () => { const getLabels = () => {

View File

@ -82,8 +82,8 @@ describe('RangePicker', () => {
await userEvent.click(document.querySelector('[title="2023-05-01"]') as HTMLElement); await userEvent.click(document.querySelector('[title="2023-05-01"]') as HTMLElement);
await userEvent.click(document.querySelector('[title="2023-05-02"]') as HTMLElement); await userEvent.click(document.querySelector('[title="2023-05-02"]') as HTMLElement);
expect(startInput).toHaveValue('2023-05-01'); await waitFor(() => expect(startInput).toHaveValue('2023-05-01'));
expect(endInput).toHaveValue('2023-05-02'); await waitFor(() => expect(endInput).toHaveValue('2023-05-02'));
// Read pretty // Read pretty
expect(screen.getByText('2023-05-01~2023-05-02', { selector: '.ant-description-text' })).toBeInTheDocument(); expect(screen.getByText('2023-05-01~2023-05-02', { selector: '.ant-description-text' })).toBeInTheDocument();
// Value // Value

View File

@ -1,4 +1,4 @@
import moment from 'moment'; import { dayjs } from '@nocobase/utils/client';
import { getDateRanges } from '../util'; import { getDateRanges } from '../util';
describe('getDateRanges', () => { describe('getDateRanges', () => {
@ -6,115 +6,115 @@ describe('getDateRanges', () => {
it('today', () => { it('today', () => {
const [start, end] = dateRanges.today(); const [start, end] = dateRanges.today();
expect(start.toISOString()).toBe(moment().startOf('day').toISOString()); expect(start.toISOString()).toBe(dayjs().startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().endOf('day').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('day').toISOString());
}); });
it('lastWeek', () => { it('lastWeek', () => {
const [start, end] = dateRanges.lastWeek(); const [start, end] = dateRanges.lastWeek();
expect(start.toISOString()).toBe(moment().add(-1, 'week').startOf('isoWeek').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-1, 'week').startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'week').endOf('isoWeek').toISOString()); expect(end.toISOString()).toBe(dayjs().add(-1, 'week').endOf('isoWeek').toISOString());
}); });
it('thisWeek', () => { it('thisWeek', () => {
const [start, end] = dateRanges.thisWeek(); const [start, end] = dateRanges.thisWeek();
expect(start.toISOString()).toBe(moment().startOf('isoWeek').toISOString()); expect(start.toISOString()).toBe(dayjs().startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(moment().endOf('isoWeek').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('isoWeek').toISOString());
}); });
it('nextWeek', () => { it('nextWeek', () => {
const [start, end] = dateRanges.nextWeek(); const [start, end] = dateRanges.nextWeek();
expect(start.toISOString()).toBe(moment().add(1, 'week').startOf('isoWeek').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'week').startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'week').endOf('isoWeek').toISOString()); expect(end.toISOString()).toBe(dayjs().add(1, 'week').endOf('isoWeek').toISOString());
}); });
it('lastMonth', () => { it('lastMonth', () => {
const [start, end] = dateRanges.lastMonth(); const [start, end] = dateRanges.lastMonth();
expect(start.toISOString()).toBe(moment().add(-1, 'month').startOf('month').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-1, 'month').startOf('month').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'month').endOf('month').toISOString()); expect(end.toISOString()).toBe(dayjs().add(-1, 'month').endOf('month').toISOString());
}); });
it('thisMonth', () => { it('thisMonth', () => {
const [start, end] = dateRanges.thisMonth(); const [start, end] = dateRanges.thisMonth();
expect(start.toISOString()).toBe(moment().startOf('month').toISOString()); expect(start.toISOString()).toBe(dayjs().startOf('month').toISOString());
expect(end.toISOString()).toBe(moment().endOf('month').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('month').toISOString());
}); });
it('nextMonth', () => { it('nextMonth', () => {
const [start, end] = dateRanges.nextMonth(); const [start, end] = dateRanges.nextMonth();
expect(start.toISOString()).toBe(moment().add(1, 'month').startOf('month').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'month').startOf('month').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'month').endOf('month').toISOString()); expect(end.toISOString()).toBe(dayjs().add(1, 'month').endOf('month').toISOString());
}); });
it('lastQuarter', () => { it('lastQuarter', () => {
const [start, end] = dateRanges.lastQuarter(); const [start, end] = dateRanges.lastQuarter();
expect(start.toISOString()).toBe(moment().add(-1, 'quarter').startOf('quarter').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-1, 'quarter').startOf('quarter').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'quarter').endOf('quarter').toISOString()); expect(end.toISOString()).toBe(dayjs().add(-1, 'quarter').endOf('quarter').toISOString());
}); });
it('thisQuarter', () => { it('thisQuarter', () => {
const [start, end] = dateRanges.thisQuarter(); const [start, end] = dateRanges.thisQuarter();
expect(start.toISOString()).toBe(moment().startOf('quarter').toISOString()); expect(start.toISOString()).toBe(dayjs().startOf('quarter').toISOString());
expect(end.toISOString()).toBe(moment().endOf('quarter').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('quarter').toISOString());
}); });
it('nextQuarter', () => { it('nextQuarter', () => {
const [start, end] = dateRanges.nextQuarter(); const [start, end] = dateRanges.nextQuarter();
expect(start.toISOString()).toBe(moment().add(1, 'quarter').startOf('quarter').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'quarter').startOf('quarter').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'quarter').endOf('quarter').toISOString()); expect(end.toISOString()).toBe(dayjs().add(1, 'quarter').endOf('quarter').toISOString());
}); });
it('lastYear', () => { it('lastYear', () => {
const [start, end] = dateRanges.lastYear(); const [start, end] = dateRanges.lastYear();
expect(start.toISOString()).toBe(moment().add(-1, 'year').startOf('year').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-1, 'year').startOf('year').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'year').endOf('year').toISOString()); expect(end.toISOString()).toBe(dayjs().add(-1, 'year').endOf('year').toISOString());
}); });
it('thisYear', () => { it('thisYear', () => {
const [start, end] = dateRanges.thisYear(); const [start, end] = dateRanges.thisYear();
expect(start.toISOString()).toBe(moment().startOf('year').toISOString()); expect(start.toISOString()).toBe(dayjs().startOf('year').toISOString());
expect(end.toISOString()).toBe(moment().endOf('year').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('year').toISOString());
}); });
it('nextYear', () => { it('nextYear', () => {
const [start, end] = dateRanges.nextYear(); const [start, end] = dateRanges.nextYear();
expect(start.toISOString()).toBe(moment().add(1, 'year').startOf('year').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'year').startOf('year').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'year').endOf('year').toISOString()); expect(end.toISOString()).toBe(dayjs().add(1, 'year').endOf('year').toISOString());
}); });
it('last7Days', () => { it('last7Days', () => {
const [start, end] = dateRanges.last7Days(); const [start, end] = dateRanges.last7Days();
expect(start.toISOString()).toBe(moment().add(-6, 'days').startOf('days').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-6, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(moment().endOf('days').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('days').toISOString());
}); });
it('next7Days', () => { it('next7Days', () => {
const [start, end] = dateRanges.next7Days(); const [start, end] = dateRanges.next7Days();
expect(start.toISOString()).toBe(moment().add(1, 'day').startOf('day').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().add(7, 'days').endOf('days').toISOString()); expect(end.toISOString()).toBe(dayjs().add(7, 'days').endOf('days').toISOString());
}); });
it('last30Days', () => { it('last30Days', () => {
const [start, end] = dateRanges.last30Days(); const [start, end] = dateRanges.last30Days();
expect(start.toISOString()).toBe(moment().add(-29, 'days').startOf('days').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-29, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(moment().endOf('days').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('days').toISOString());
}); });
it('next30Days', () => { it('next30Days', () => {
const [start, end] = dateRanges.next30Days(); const [start, end] = dateRanges.next30Days();
expect(start.toISOString()).toBe(moment().add(1, 'day').startOf('day').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().add(30, 'days').endOf('days').toISOString()); expect(end.toISOString()).toBe(dayjs().add(30, 'days').endOf('days').toISOString());
}); });
it('last90Days', () => { it('last90Days', () => {
const [start, end] = dateRanges.last90Days(); const [start, end] = dateRanges.last90Days();
expect(start.toISOString()).toBe(moment().add(-89, 'days').startOf('days').toISOString()); expect(start.toISOString()).toBe(dayjs().add(-89, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(moment().endOf('days').toISOString()); expect(end.toISOString()).toBe(dayjs().endOf('days').toISOString());
}); });
it('next90Days', () => { it('next90Days', () => {
const [start, end] = dateRanges.next90Days(); const [start, end] = dateRanges.next90Days();
expect(start.toISOString()).toBe(moment().add(1, 'day').startOf('day').toISOString()); expect(start.toISOString()).toBe(dayjs().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().add(90, 'days').endOf('days').toISOString()); expect(end.toISOString()).toBe(dayjs().add(90, 'days').endOf('days').toISOString());
}); });
}); });

View File

@ -1,4 +1,4 @@
import moment from 'moment'; import { dayjs } from '@nocobase/utils/client';
import { mapDatePicker } from '../util'; import { mapDatePicker } from '../util';
describe('mapDatePicker', () => { describe('mapDatePicker', () => {
@ -20,7 +20,7 @@ describe('mapDatePicker', () => {
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
expect(result.value.format('YYYY-MM-DD HH:mm:ss')).toBe( expect(result.value.format('YYYY-MM-DD HH:mm:ss')).toBe(
moment('2022-02-22T22:22:22.000Z').format('YYYY-MM-DD HH:mm:ss'), dayjs('2022-02-22T22:22:22.000Z').format('YYYY-MM-DD HH:mm:ss'),
); );
}); });
@ -51,7 +51,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment.utc('2022-02-22 22:22:22')); result.onChange(dayjs.utc('2022-02-22 22:22:22'));
expect(props.onChange).toHaveBeenCalledWith('2022-02-22T22:22:22.000Z'); expect(props.onChange).toHaveBeenCalledWith('2022-02-22T22:22:22.000Z');
}); });
@ -62,7 +62,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment('2022-02-22 22:22:22'); const m = dayjs('2022-02-22 22:22:22');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.toISOString());
}); });
@ -74,7 +74,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment.utc('2022-02-22')); result.onChange(dayjs.utc('2022-02-22'));
expect(props.onChange).toHaveBeenCalledWith('2022-02-22T00:00:00.000Z'); expect(props.onChange).toHaveBeenCalledWith('2022-02-22T00:00:00.000Z');
}); });
@ -85,7 +85,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment('2022-02-22'); const m = dayjs('2022-02-22');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.toISOString());
}); });
@ -97,7 +97,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment.utc('2022-01-01T00:00:00.000Z')); result.onChange(dayjs.utc('2022-01-01T00:00:00.000Z'));
expect(props.onChange).toHaveBeenCalledWith('2022-01-01T00:00:00.000Z'); expect(props.onChange).toHaveBeenCalledWith('2022-01-01T00:00:00.000Z');
}); });
@ -108,7 +108,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment('2022-02-01 00:00:00'); const m = dayjs('2022-02-01 00:00:00');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('year').toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.startOf('year').toISOString());
}); });
@ -120,7 +120,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment.utc('2022-02-22T00:00:00.000Z')); result.onChange(dayjs.utc('2022-02-22T00:00:00.000Z'));
expect(props.onChange).toHaveBeenCalledWith('2022-02-01T00:00:00.000Z'); expect(props.onChange).toHaveBeenCalledWith('2022-02-01T00:00:00.000Z');
}); });
@ -131,7 +131,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment('2022-02-01 00:00:00'); const m = dayjs('2022-02-01 00:00:00');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('month').toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.startOf('month').toISOString());
}); });
@ -143,7 +143,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment.utc('2022-02-22T00:00:00.000Z')); result.onChange(dayjs.utc('2022-02-22T00:00:00.000Z'));
expect(props.onChange).toHaveBeenCalledWith('2022-01-01T00:00:00.000Z'); expect(props.onChange).toHaveBeenCalledWith('2022-01-01T00:00:00.000Z');
}); });
@ -154,7 +154,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment('2022-02-01 00:00:00'); const m = dayjs('2022-02-01 00:00:00');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('quarter').toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.startOf('quarter').toISOString());
}); });
@ -166,7 +166,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment.utc('2022-02-21T00:00:00.000Z'); const m = dayjs.utc('2022-02-21T00:00:00.000Z');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString());
}); });
@ -178,7 +178,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
const m = moment('2022-02-21 00:00:00'); const m = dayjs('2022-02-21 00:00:00');
result.onChange(m); result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString()); expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString());
}); });
@ -191,7 +191,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment('2022-02-22 22:22:22')); result.onChange(dayjs('2022-02-22 22:22:22'));
expect(props.onChange).toHaveBeenCalledWith('2022-02-22 22:22:22'); expect(props.onChange).toHaveBeenCalledWith('2022-02-22 22:22:22');
}); });
@ -203,7 +203,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const result = mapDatePicker()(props); const result = mapDatePicker()(props);
result.onChange(moment('2022-01-01 23:00:00')); result.onChange(dayjs('2022-01-01 23:00:00'));
expect(props.onChange).toHaveBeenCalledWith('2022-01-01'); expect(props.onChange).toHaveBeenCalledWith('2022-01-01');
}); });

View File

@ -1,4 +1,4 @@
import moment from 'moment'; import { dayjs } from '@nocobase/utils/client';
import { mapRangePicker } from '../util'; import { mapRangePicker } from '../util';
describe('mapRangePicker', () => { describe('mapRangePicker', () => {
@ -10,7 +10,7 @@ describe('mapRangePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const { onChange } = mapRangePicker()(props); const { onChange } = mapRangePicker()(props);
const value = [moment.utc('2023-01-01T00:00:00.000Z'), moment.utc('2023-01-02T00:00:00.000Z')]; const value = [dayjs.utc('2023-01-01T00:00:00.000Z'), dayjs.utc('2023-01-02T00:00:00.000Z')];
onChange(value); onChange(value);
expect(props.onChange).toHaveBeenCalledWith(['2023-01-01T00:00:00.000Z', '2023-01-02T23:59:59.999Z']); expect(props.onChange).toHaveBeenCalledWith(['2023-01-01T00:00:00.000Z', '2023-01-02T23:59:59.999Z']);
}); });
@ -23,7 +23,7 @@ describe('mapRangePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const { onChange } = mapRangePicker()(props); const { onChange } = mapRangePicker()(props);
const value = [moment.utc('2023-01-01T00:00:00.000Z'), moment.utc('2023-01-02T00:00:00.000Z')]; const value = [dayjs.utc('2023-01-01T00:00:00.000Z'), dayjs.utc('2023-01-02T00:00:00.000Z')];
onChange(value); onChange(value);
expect(props.onChange).toHaveBeenCalledWith(['2023-01-01T00:00:00.000Z', '2023-01-02T00:00:00.000Z']); expect(props.onChange).toHaveBeenCalledWith(['2023-01-01T00:00:00.000Z', '2023-01-02T00:00:00.000Z']);
}); });
@ -36,7 +36,7 @@ describe('mapRangePicker', () => {
onChange: vi.fn(), onChange: vi.fn(),
}; };
const { onChange } = mapRangePicker()(props); const { onChange } = mapRangePicker()(props);
const value = [moment.utc('2023-01-01T00:00:00.000Z'), moment.utc('2023-01-02T00:00:00.000Z')]; const value = [dayjs.utc('2023-01-01T00:00:00.000Z'), dayjs.utc('2023-01-02T00:00:00.000Z')];
onChange(value); onChange(value);
expect(props.onChange).toHaveBeenCalledWith(['2023-01-01', '2023-01-02']); expect(props.onChange).toHaveBeenCalledWith(['2023-01-01', '2023-01-02']);
}); });

View File

@ -1,5 +1,5 @@
import { str2moment } from '@nocobase/utils'; import { str2moment } from '@nocobase/utils';
import moment from 'moment'; import { dayjs } from '@nocobase/utils/client';
import { moment2str } from '../util'; import { moment2str } from '../util';
describe('str2moment', () => { describe('str2moment', () => {
@ -44,91 +44,91 @@ describe('str2moment', () => {
describe('moment2str', () => { describe('moment2str', () => {
test('gmt date', () => { test('gmt date', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { showTime: true, gmt: true }); const str = moment2str(m, { showTime: true, gmt: true });
expect(str).toBe('2023-06-21T10:10:00.000Z'); expect(str).toBe('2023-06-21T10:10:00.000Z');
}); });
test('showTime is true, gmt is false', () => { test('showTime is true, gmt is false', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { showTime: true, gmt: false }); const str = moment2str(m, { showTime: true, gmt: false });
expect(str).toBe(m.toISOString()); expect(str).toBe(m.toISOString());
}); });
test('gmt is true', () => { test('gmt is true', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { gmt: true }); const str = moment2str(m, { gmt: true });
expect(str).toBe('2023-06-21T10:10:00.000Z'); expect(str).toBe('2023-06-21T10:10:00.000Z');
}); });
test('gmt is false', () => { test('gmt is false', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { gmt: false }); const str = moment2str(m, { gmt: false });
expect(str).toBe(moment('2023-06-21 10:10:00').toISOString()); expect(str).toBe(dayjs('2023-06-21 10:10:00').toISOString());
}); });
test('with time', () => { test('with time', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { showTime: true }); const str = moment2str(m, { showTime: true });
expect(str).toBe(m.toISOString()); expect(str).toBe(m.toISOString());
}); });
test('picker is year, gmt is false', () => { test('picker is year, gmt is false', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'year', gmt: false }); const str = moment2str(m, { picker: 'year', gmt: false });
expect(str).toBe(moment('2023-01-01 00:00:00').toISOString()); expect(str).toBe(dayjs('2023-01-01 00:00:00').toISOString());
}); });
test('picker is year, gmt is true', () => { test('picker is year, gmt is true', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'year', gmt: true }); const str = moment2str(m, { picker: 'year', gmt: true });
expect(str).toBe('2023-01-01T00:00:00.000Z'); expect(str).toBe('2023-01-01T00:00:00.000Z');
}); });
test('picker is year', () => { test('picker is year', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'year' }); const str = moment2str(m, { picker: 'year' });
expect(str).toBe('2023-01-01T00:00:00.000Z'); expect(str).toBe('2023-01-01T00:00:00.000Z');
}); });
test('picker is quarter, gmt is false', () => { test('picker is quarter, gmt is false', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'quarter', gmt: false }); const str = moment2str(m, { picker: 'quarter', gmt: false });
expect(str).toBe(moment('2023-04-01 00:00:00').toISOString()); expect(str).toBe(dayjs('2023-04-01 00:00:00').toISOString());
}); });
test('picker is quarter, gmt is true', () => { test('picker is quarter, gmt is true', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'quarter', gmt: true }); const str = moment2str(m, { picker: 'quarter', gmt: true });
expect(str).toBe('2023-04-01T00:00:00.000Z'); expect(str).toBe('2023-04-01T00:00:00.000Z');
}); });
test('picker is month, gmt is false', () => { test('picker is month, gmt is false', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'month', gmt: false }); const str = moment2str(m, { picker: 'month', gmt: false });
expect(str).toBe(moment('2023-06-01 00:00:00').toISOString()); expect(str).toBe(dayjs('2023-06-01 00:00:00').toISOString());
}); });
test('picker is month, gmt is true', () => { test('picker is month, gmt is true', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'month', gmt: true }); const str = moment2str(m, { picker: 'month', gmt: true });
expect(str).toBe('2023-06-01T00:00:00.000Z'); expect(str).toBe('2023-06-01T00:00:00.000Z');
}); });
test('picker is month', () => { test('picker is month', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'month' }); const str = moment2str(m, { picker: 'month' });
expect(str).toBe('2023-06-01T00:00:00.000Z'); expect(str).toBe('2023-06-01T00:00:00.000Z');
}); });
test('picker is week, gmt is false', () => { test('picker is week, gmt is false', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'week', gmt: false }); const str = moment2str(m, { picker: 'week', gmt: false });
expect(str).toBe(moment('2023-06-19 00:00:00').toISOString()); expect(str).toBe(dayjs('2023-06-19 00:00:00').toISOString());
}); });
test('picker is week, gmt is true', () => { test('picker is week, gmt is true', () => {
const m = moment('2023-06-21 10:10:00'); const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { picker: 'week', gmt: true }); const str = moment2str(m, { picker: 'week', gmt: true });
expect(str).toBe('2023-06-19T00:00:00.000Z'); expect(str).toBe('2023-06-19T00:00:00.000Z');
}); });

View File

@ -1,7 +1,7 @@
/** /**
* title: DatePicker * title: DatePicker
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';
@ -17,7 +17,6 @@ const schema = {
dateFormat: 'YYYY/MM/DD', dateFormat: 'YYYY/MM/DD',
showTime: true, showTime: true,
}, },
// default: '2022-11-22',
'x-reactions': { 'x-reactions': {
target: '*(read1,read2)', target: '*(read1,read2)',
fulfill: { fulfill: {

View File

@ -1,7 +1,7 @@
/** /**
* title: DatePicker * title: DatePicker
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,7 +1,7 @@
/** /**
* title: DatePicker (GMT) * title: DatePicker (GMT)
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

View File

@ -1,7 +1,7 @@
/** /**
* title: DatePicker * title: DatePicker
*/ */
import { FormItem } from '@formily/antd'; import { FormItem } from '@formily/antd-v5';
import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react'; import React from 'react';

Some files were not shown because too many files have changed in this diff Show More