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-hooks",
"prettier",
"promise"
"promise",
"jest-dom",
"testing-library"
//"import"
],
"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 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

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.
## 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
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 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,
CollectionField,
} from '@nocobase/client';
import 'antd/dist/antd.css';
import { FormItem, Input } from '@formily/antd';
import { FormItem, Input } from '@formily/antd-v5';
export default observer(() => {
const collection = {

View File

@ -1,6 +1,19 @@
# 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:
@ -45,6 +58,8 @@ plugins are very powerful and can do a lot of things in the `load` phase:
- add Scopes
- load other plugins
#### Routing changes
if you used `RouteSwitchContext` to modify the route before, you now need to replace it with a plugin:
```tsx | pure
@ -97,4 +112,9 @@ const HelloProvider = (props) => {
+ 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,
CollectionField,
} from '@nocobase/client';
import 'antd/dist/antd.css';
import { FormItem, Input } from '@formily/antd';
import { FormItem, Input } from '@formily/antd-v5';
export default observer(() => {
const collection = {

View File

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

View File

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

View File

@ -1,4 +1,3 @@
import '@/theme';
import { Application } from '@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",
"dependencies": {
"@babel/core": "7.12.3",
"@babel/plugin-proposal-class-properties": "7.12.1",
"@babel/plugin-proposal-decorators": "7.12.1",
"@babel/plugin-proposal-do-expressions": "7.12.1",
"@babel/plugin-proposal-export-default-from": "7.12.1",
"@babel/plugin-proposal-export-namespace-from": "7.12.1",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.12.1",
"@babel/plugin-proposal-optional-chaining": "7.12.1",
"@babel/core": "7.22.5",
"@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-decorators": "7.22.5",
"@babel/plugin-proposal-do-expressions": "7.22.5",
"@babel/plugin-proposal-export-default-from": "7.22.5",
"@babel/plugin-proposal-export-namespace-from": "7.18.9",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
"@babel/plugin-proposal-optional-chaining": "7.21.0",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/plugin-transform-modules-commonjs": "7.12.1",
"@babel/plugin-transform-runtime": "7.12.1",
"@babel/plugin-transform-modules-commonjs": "7.22.5",
"@babel/plugin-transform-runtime": "7.22.5",
"@babel/preset-env": "7.12.1",
"@babel/preset-react": "7.12.1",
"@babel/preset-typescript": "7.12.1",
"@babel/register": "7.12.1",
"@babel/preset-react": "7.22.5",
"@babel/preset-typescript": "7.22.5",
"@babel/register": "7.22.5",
"@lerna/filter-packages": "4.0.0",
"@lerna/project": "4.0.0",
"@lerna/query-graph": "4.0.0",
"@rollup/plugin-babel": "5.3.1",
"@rollup/plugin-commonjs": "16.0.0",
"@rollup/plugin-inject": "4.0.2",
"@rollup/plugin-json": "4.1.0",
"@rollup/plugin-node-resolve": "10.0.0",
"@rollup/plugin-replace": "2.3.4",
"@rollup/plugin-url": "5.0.1",
"@rollup/plugin-babel": "6.0.3",
"@rollup/plugin-commonjs": "25.0.1",
"@rollup/plugin-inject": "5.0.3",
"@rollup/plugin-json": "6.0.0",
"@rollup/plugin-node-resolve": "15.1.0",
"@rollup/plugin-replace": "5.0.2",
"@rollup/plugin-url": "8.0.1",
"@svgr/rollup": "5.5.0",
"ajv": "6.12.6",
"autoprefixer": "9.6.0",
@ -45,23 +45,23 @@
"gulp-if": "2.0.2",
"gulp-less": "^5.0.0",
"gulp-plumber": "^1.2.1",
"gulp-typescript": "5.0.1",
"gulp-typescript": "6.0.0-alpha.1",
"less": "4.1.3",
"less-plugin-npm-import": "2.1.0",
"lodash": "4.17.21",
"pkg-up": "3.1.0",
"rimraf": "2.6.3",
"rollup": "2.33.3",
"rollup-plugin-postcss": "3.1.8",
"rollup": "3.25.1",
"rollup-plugin-postcss": "4.0.2",
"rollup-plugin-terser": "7.0.2",
"rollup-plugin-typescript2": "0.29.0",
"rollup-plugin-typescript2": "0.34.1",
"semver": "6.1.1",
"signale": "1.4.0",
"slash2": "2.0.0",
"temp-dir": "2.0.0",
"through2": "3.0.1",
"ts-loader": "^8.0.7",
"typescript": "4.5.5",
"ts-loader": "^9.4.3",
"typescript": "5.1.3",
"update-notifier": "3.0.0",
"vinyl-fs": "3.0.3",
"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/sortable": "^6.0.0",
"@emotion/css": "^11.7.1",
"@formily/antd": "2.2.26",
"@formily/antd-v5": "^1.1.0-beta.4",
"@formily/core": "2.2.26",
"@formily/react": "2.2.26",
"@nocobase/evaluators": "0.10.1-alpha.1",
"@nocobase/sdk": "0.10.1-alpha.1",
"@nocobase/utils": "0.10.1-alpha.1",
"ahooks": "^3.7.2",
"antd": "^4.24.8",
"antd": "^5.6.4",
"antd-style": "^3.3.0",
"axios": "^0.26.1",
"classnames": "^2.3.1",
"cron-parser": "^4.6.0",
@ -31,16 +32,16 @@
"mathjs": "^10.6.0",
"mermaid": "9.4.3",
"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-error-boundary": "^4.0.3",
"react-error-boundary": "^4.0.10",
"react-helmet": "^6.1.0",
"react-hotkeys-hook": "^3.4.7",
"react-i18next": "^11.15.1",
"react-iframe": "~1.8.5",
"react-image-lightbox": "^5.1.4",
"react-js-cron": "^3.1.0",
"react-quill": "^1.3.5",
"react-quill": "^2.0.0",
"react-router-dom": "^6.11.2",
"react-to-print": "^2.14.7",
"sanitize-html": "2.10.0",
@ -55,9 +56,10 @@
"devDependencies": {
"dumi": "^2.2.0",
"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-highlightjs": "3.3.1",
"@types/react-big-calendar": "^1.6.4",
"axios-mock-adapter": "^1.20.0"
},
"gitHead": "ce588eefb0bfc50f7d5bbee575e0b5e843bf6644"

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ import {
ACLCollectionProvider,
ACLMenuItemProvider,
} from './ACLProvider';
import './style.less';
export class ACLPlugin extends Plugin {
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 moment from 'moment';
import React, { createContext, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient, useRequest } from '../api-client';
@ -34,7 +34,7 @@ export function AntdConfigProvider(props) {
i18n.addResources(data?.data?.lang, key, data?.data?.resources[key] || {});
});
loadConstrueLocale(data?.data);
moment.locale(data?.data?.moment);
dayjs.locale(data?.data?.moment);
window['cronLocale'] = data?.data?.cron;
},
manual: !remoteLocale,
@ -45,7 +45,7 @@ export function AntdConfigProvider(props) {
}
return (
<AppLangContext.Provider value={data?.data}>
<ConfigProvider dropdownMatchSelectWidth={false} {...others} locale={data?.data?.antd || {}}>
<ConfigProvider popupMatchSelectWidth={false} {...others} locale={data?.data?.antd || {}}>
{props.children}
</ConfigProvider>
</AppLangContext.Provider>

View File

@ -8,24 +8,9 @@ export const useCurrentAppInfo = () => {
return useContext(CurrentAppInfoContext);
};
export const CurrentAppInfoProvider = (props) => {
const result = useRequest(
{
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 />;
}
const result = useRequest({
url: 'app:getInfo',
});
if (result.loading) {
return <Spin />;
}

View File

@ -6,12 +6,12 @@ import set from 'lodash/set';
import React, { ComponentType, FC, ReactElement } from 'react';
import { createRoot } from 'react-dom/client';
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 { i18n } from '../i18n';
import { AppComponent, BlankComponent, defaultAppComponents } from './components';
import { PluginManager, PluginType } from './PluginManager';
import { ComponentTypeAndString, RouterManager, RouterOptions } from './RouterManager';
import { AppComponent, BlankComponent, defaultAppComponents } from './components';
import { compose, normalizeContainer } from './utils';
export type ComponentAndProps<T = any> = [ComponentType, T];

View File

@ -13,6 +13,7 @@ import {
isMovingACardToAnotherPosition,
isMovingAColumnToAnotherPosition,
} from './services';
import { useStyles } from './style';
import { partialRight, when } from './utils';
import withDroppable from './withDroppable';
@ -23,7 +24,13 @@ const Columns = forwardRef((props, ref: any) => (
const DroppableBoard = withDroppable(Columns);
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) => {

View File

@ -1,7 +1,6 @@
import { Board } from '@nocobase/client';
import { Button, Card } from 'antd';
import React, { useState } from 'react';
import '../style.less';
const board = {
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 { ArrayTable } from '@formily/antd';
import { ArrayTable } from '@formily/antd-v5';
import { ISchema, useField, useForm } from '@formily/react';
import { uid } from '@formily/shared';
import { Button, Dropdown, MenuProps } from 'antd';

View File

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

View File

@ -1,5 +1,5 @@
import { PlusOutlined } from '@ant-design/icons';
import { ArrayTable } from '@formily/antd';
import { ArrayTable } from '@formily/antd-v5';
import { ISchema } from '@formily/react';
import { uid } from '@formily/shared';
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 { uid } from '@formily/shared';
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 { uid } from '@formily/shared';
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 { uid } from '@formily/shared';
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 { uid } from '@formily/shared';
import { omit, set } from 'lodash';

View File

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

View File

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

View File

@ -1,15 +1,14 @@
import React from 'react';
import { observer, ISchema, useForm } from '@formily/react';
import { FormItem, Input } from '@formily/antd-v5';
import { ISchema, observer, useForm } from '@formily/react';
import {
Action,
CollectionField,
CollectionProvider,
Form,
SchemaComponent,
SchemaComponentProvider,
Form,
Action,
CollectionProvider,
CollectionField,
} from '@nocobase/client';
import 'antd/dist/antd.css';
import { FormItem, Input } from '@formily/antd';
import React from 'react';
export default observer(() => {
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 { FormContext, ISchema, SchemaOptionsContext } from '@formily/react';
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 { Input, Select, Spin, Table, Tag } from 'antd';
import React, { useContext, useEffect, useState } from 'react';
@ -123,7 +123,7 @@ const PreviewCom = (props) => {
) : (
<Select
defaultValue={text}
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
style={{ width: '100%' }}
options={
item?.possibleTypes.map((v) => {
@ -149,7 +149,7 @@ const PreviewCom = (props) => {
<Select
defaultValue={text}
style={{ width: '100%' }}
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
onChange={(value) => {
const interfaceConfig = getInterface(value);
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 './acl';

View File

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

View File

@ -14,7 +14,6 @@ import {
Typography,
message,
} from 'antd';
import cls from 'classnames';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
@ -128,7 +127,7 @@ function PluginDetail(props: IPluginDetail) {
footer={false}
className={css`
.ant-modal-header {
background: #f0f2f5;
background: var(--nb-box-bg);
padding-bottom: 8px;
}
@ -136,8 +135,8 @@ function PluginDetail(props: IPluginDetail) {
padding-top: 0;
}
.ant-modal-body {
background: #f0f2f5;
.ant-modal-content {
background: var(--nb-box-bg);
.plugin-desc {
padding-bottom: 8px;
}
@ -175,14 +174,15 @@ function CommonCard(props: ICommonCard) {
bordered={false}
style={{ width: 'calc(20% - 24px)', marginRight: 24, marginBottom: 24, transition: 'all 0.35s ease-in-out' }}
onClick={onClick}
className={cls(css`
&:hover {
border: 1px solid var(--antd-wave-shadow-color);
cursor: pointer;
}
hoverable
// className={cls(css`
// &:hover {
// border: 1px solid var(--antd-wave-shadow-color);
// cursor: pointer;
// }
border: 1px solid transparent;
`)}
// border: 1px solid transparent;
// `)}
actions={actions}
// 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 { BuiltInPluginCard, PluginCard } from './Card';
import { PluginManagerLink, SettingsCenterDropdown } from './PluginManagerLink';
import { useStyles } from './style';
export interface TData {
data: IPluginData[];
@ -110,12 +111,13 @@ const MarketplacePlugins = () => {
return <div style={{ fontSize: 18 }}>{t('Coming soon...')}</div>;
};
const PluginList = (props) => {
const PluginList = () => {
const params = useParams<any>();
const navigate = useNavigate();
const { tabName = 'local' } = params;
const { t } = useTranslation();
const { snippets = [] } = useACLRoleContext();
const { styles } = useStyles();
useEffect(() => {
const { tabName } = params;
@ -127,10 +129,7 @@ const PluginList = (props) => {
return snippets.includes('pm') ? (
<div>
<PageHeader
style={{
backgroundColor: 'white',
paddingBottom: 0,
}}
className={styles.pageHeader}
ghost={false}
title={t('Plugin manager')}
footer={
@ -240,7 +239,8 @@ export const getPluginsTabs = _.memoize((items, snippets) => {
return sortBy(pluginsTabs, (o) => !o.isAllow);
});
const SettingsCenter = (props) => {
const SettingsCenter = () => {
const { styles } = useStyles();
const { snippets = [] } = useACLRoleContext();
const params = useParams<any>();
const navigate = useNavigate();
@ -311,7 +311,7 @@ const SettingsCenter = (props) => {
<Layout.Content>
{aclPluginTabCheck && (
<PageHeader
style={{ backgroundColor: 'white', paddingBottom: 0 }}
className={styles.pageHeader}
ghost={false}
title={compile(items[pluginName]?.title)}
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
className={css`
.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);
}
.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
open={visible}
onClose={() => setVisible(false, true)}
className={classNames(
rootClassName={classNames(
drawerProps?.className,
others.className,
css`
@ -57,7 +57,7 @@ export const ActionDrawer: ComposedActionDrawer = observer(
}
.ant-drawer-content {
background: #f0f2f5;
background: var(--nb-box-bg);
}
}

View File

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

View File

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

View File

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

View File

@ -1,13 +1,12 @@
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
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 { RecordProvider } from '../../../';
import { useTranslation } from 'react-i18next';
import { RecordProvider, useAPIClient, useCollectionManager } from '../../../';
import { RemoteSelect, RemoteSelectProps } from '../remote-select';
import useServiceOptions, { useAssociationFieldContext } from './hooks';
import { useAPIClient, useCollectionManager } from '../../../';
import { isFunction } from 'mathjs';
export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & {
action?: string;
@ -66,7 +65,7 @@ const InternalAssociationSelect = observer((props: AssociationSelectProps) => {
};
return (
<div key={fieldSchema.name}>
<Input.Group compact style={{ display: 'flex', lineHeight: '32px' }}>
<Space.Compact style={{ display: 'flex', lineHeight: '32px' }}>
<RemoteSelect
style={{ width: '100%' }}
{...props}
@ -89,7 +88,7 @@ const InternalAssociationSelect = observer((props: AssociationSelectProps) => {
/>
</RecordProvider>
)}
</Input.Group>
</Space.Compact>
</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 React, { useEffect } from 'react';
import { css, cx } from '@emotion/css';
import { CollectionProvider } from '../../../collection-manager';
import { useInsertSchema } from './hooks';
import { useAssociationFieldContext } from './hooks';
import { useAssociationFieldContext, useInsertSchema } from './hooks';
import schema from './schema';
export const InternalNester = () => {

View File

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

View File

@ -1,5 +1,5 @@
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 React, { useEffect } from 'react';
import { CollectionProvider } from '../../../collection-manager';

View File

@ -1,8 +1,7 @@
import { ISchema } from '@formily/react';
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 moment from 'moment';
import React from 'react';
import { CollectionFieldOptions, useCollectionManager } from '../../../collection-manager';
@ -17,7 +16,7 @@ export const useLabelUiSchema = (collectionField: CollectionFieldOptions, label:
export const getDatePickerLabels = (props): 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;
return isArr(labels) ? labels.join('~') : labels;
};

View File

@ -1,5 +1,5 @@
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 { ISchema, connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';

View File

@ -1,12 +1,13 @@
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { createForm } from '@formily/core';
import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react';
import { dayjs } from '@nocobase/utils/client';
import { parseExpression } from 'cron-parser';
import { eq } from 'date-arithmetic';
import type { Dayjs } from 'dayjs';
import get from 'lodash/get';
import moment from 'moment';
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 { RecordProvider } from '../../../';
import { i18n } from '../../../i18n';
@ -14,13 +15,14 @@ import { useProps } from '../../hooks/useProps';
import { ActionContextProvider } from '../action';
import Header from './components/Header';
import { CalendarToolbarContext } from './context';
import './style.less';
import GlobalStyle from './global.style';
import useStyle from './style';
import type { ToolbarProps } from './types';
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({
close: () => {},
});
@ -77,18 +79,18 @@ const useEvents = (dataSource: any, fieldNames: any, date: Date, view: (typeof W
dataSource.forEach((item) => {
const { cron, exclude = [] } = item;
const start = moment(get(item, fieldNames.start) || moment());
const end = moment(get(item, fieldNames.end) || start);
const start = dayjs(get(item, fieldNames.start) || dayjs());
const end = dayjs(get(item, fieldNames.end) || start);
const intervalTime = end.diff(start, 'millisecond', true);
const dateM = moment(date);
const dateM = dayjs(date);
const startDate = dateM.clone().startOf('month');
const endDate = startDate.clone().endOf('month');
if (view === 'month') {
startDate.startOf('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)) {
return;
@ -147,7 +149,7 @@ const useEvents = (dataSource: any, fieldNames: any, date: Date, view: (typeof W
});
while (interval.hasNext()) {
const { value } = interval.next();
if (push(moment(value.toDate()))) break;
if (push(dayjs(value.toDate()))) break;
}
} catch (err) {
console.error(err);
@ -194,10 +196,11 @@ export const Calendar: any = observer(
(props: any) => {
const { dataSource, fieldNames, showLunar, fixedBlock } = useProps(props);
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 [visible, setVisible] = useState(false);
const [record, setRecord] = useState<any>({});
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
const components = useMemo(() => {
return {
@ -211,8 +214,9 @@ export const Calendar: any = observer(
};
}, [showLunar]);
return (
<div style={{ height: fixedBlock ? '100%' : 700 }}>
return wrapSSR(
<div className={`${hashId} ${containerClassName}`} style={{ height: fixedBlock ? '100%' : 700 }}>
<GlobalStyle />
<CalendarRecordViewer visible={visible} setVisible={setVisible} record={record} />
<BigCalendar
popup
@ -229,7 +233,7 @@ export const Calendar: any = observer(
onSelectSlot={(slotInfo) => {
console.log('onSelectSlot', slotInfo);
}}
onDoubleClickEvent={(event) => {
onDoubleClickEvent={() => {
console.log('onDoubleClickEvent');
}}
onSelectEvent={(event) => {
@ -237,15 +241,15 @@ export const Calendar: any = observer(
if (!record) {
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);
setVisible(true);
}}
formats={{
monthHeaderFormat: 'Y-M',
monthHeaderFormat: 'YYYY-M',
agendaDateFormat: 'M-DD',
dayHeaderFormat: 'Y-M-DD',
dayHeaderFormat: 'YYYY-M-DD',
dayRangeHeaderFormat: ({ start, end }, culture, local) => {
if (eq(start, end, 'month')) {
return local.format(start, 'Y-M', culture);
@ -256,7 +260,7 @@ export const Calendar: any = observer(
components={components}
localizer={localizer}
/>
</div>
</div>,
);
},
{ displayName: 'Calendar' },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,4 @@
import React from 'react';
import moment from 'moment';
import { useMemo } from 'react';
import solarLunar from 'solarlunar-es';
import React, { useMemo } from 'react';
import { getLunarDay } from '../utils';
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 { Calendar } from './Calendar';
import { CalendarDesigner } from './Calendar.Designer';
import DeleteEvent from './DeleteEvent';
import { Event } from './Event';
import { Nav } from './Nav';
import './style.less';
import { Title } from './Title';
import { Today } from './Today';
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 moment from 'moment';
import solarLunar from 'solarlunar-es';
import { i18n } from '../../../i18n';
@ -14,12 +14,12 @@ export const toEvents = (data: any[], fieldNames: any) => {
});
};
export const getLunarDay = (date: moment.MomentInput) => {
const md = moment(date);
export const getLunarDay = (date: dayjs.Dayjs | string) => {
const md = dayjs(date);
const result = solarLunar.solar2lunar(md.year(), md.month() + 1, md.date());
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');
};

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 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 { useField } from '@formily/react';
import { action } from '@formily/reactive';

View File

@ -7,7 +7,9 @@ import uniq from 'lodash/uniq';
import React from 'react';
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>;
__ANT_CHECKBOX?: boolean;
ReadPretty?: React.FC<CheckboxProps>;

View File

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

View File

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

View File

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

View File

@ -46,7 +46,7 @@ export const CollectionSelect = connect(
return (
<Select
placeholder={t('Select collection')}
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
{...others}
showSearch
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 React from 'react';
import { useTranslation } from 'react-i18next';

View File

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

View File

@ -64,7 +64,7 @@ const CronSetInternal = (props: CronSetProps) => {
return (
<fieldset>
<Select
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
allowClear
{...props}
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 React from 'react';
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 React from 'react';
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 DatePickerProvider = DatePickerContext.Provider;
const _DatePicker: ComposedDatePicker = connect(
const InternalDatePicker: ComposedDatePicker = connect(
AntdDatePicker,
mapProps(mapDatePicker()),
mapReadPretty(ReadPretty.DatePicker),
);
const _RangePicker = connect(
const InternalRangePicker = connect(
AntdDatePicker.RangePicker,
mapProps(mapRangePicker()),
mapReadPretty(ReadPretty.DateRangePicker),
@ -38,7 +38,7 @@ const _RangePicker = connect(
export const DatePicker = (props) => {
const { utc = true } = useDatePickerContext();
props = { utc, ...props };
return <_DatePicker {...props} />;
return <InternalDatePicker {...props} />;
};
DatePicker.ReadPretty = ReadPretty.DatePicker;
@ -47,29 +47,29 @@ DatePicker.RangePicker = function RangePicker(props) {
const { t } = useTranslation();
const { utc = true } = useDatePickerContext();
const rangesValue = getDateRanges();
const ranges = {
[t('Today')]: rangesValue.today,
[t('Last week')]: rangesValue.lastWeek,
[t('This week')]: rangesValue.thisWeek,
[t('Next week')]: rangesValue.nextWeek,
[t('Last month')]: rangesValue.lastMonth,
[t('This month')]: rangesValue.thisMonth,
[t('Next month')]: rangesValue.nextMonth,
[t('Last quarter')]: rangesValue.lastQuarter,
[t('This quarter')]: rangesValue.thisQuarter,
[t('Next quarter')]: rangesValue.nextQuarter,
[t('Last year')]: rangesValue.lastYear,
[t('This year')]: rangesValue.thisYear,
[t('Next year')]: rangesValue.nextYear,
[t('Last 7 days')]: rangesValue.last7Days,
[t('Next 7 days')]: rangesValue.next7Days,
[t('Last 30 days')]: rangesValue.last30Days,
[t('Next 30 days')]: rangesValue.next30Days,
[t('Last 90 days')]: rangesValue.last90Days,
[t('Next 90 days')]: rangesValue.next90Days,
};
props = { utc, ranges, ...props };
return <_RangePicker {...props} />;
const presets = [
{ label: t('Today'), value: rangesValue.today },
{ label: t('Last week'), value: rangesValue.lastWeek },
{ label: t('This week'), value: rangesValue.thisWeek },
{ label: t('Next week'), value: rangesValue.nextWeek },
{ label: t('Last month'), value: rangesValue.lastMonth },
{ label: t('This month'), value: rangesValue.thisMonth },
{ label: t('Next month'), value: rangesValue.nextMonth },
{ label: t('Last quarter'), value: rangesValue.lastQuarter },
{ label: t('This quarter'), value: rangesValue.thisQuarter },
{ label: t('Next quarter'), value: rangesValue.nextQuarter },
{ label: t('Last year'), value: rangesValue.lastYear },
{ label: t('This year'), value: rangesValue.thisYear },
{ label: t('Next year'), value: rangesValue.nextYear },
{ label: t('Last 7 days'), value: rangesValue.last7Days },
{ label: t('Next 7 days'), value: rangesValue.next7Days },
{ label: t('Last 30 days'), value: rangesValue.last30Days },
{ label: t('Next 30 days'), value: rangesValue.next30Days },
{ label: t('Last 90 days'), value: rangesValue.last90Days },
{ label: t('Next 90 days'), value: rangesValue.next90Days },
];
props = { utc, presets, ...props };
return <InternalRangePicker {...props} />;
};
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 { getDefaultFormat, str2moment } from '@nocobase/utils/client';
import { dayjs, getDefaultFormat, str2moment } from '@nocobase/utils/client';
import type {
DatePickerProps as AntdDatePickerProps,
RangePickerProps as AntdRangePickerProps,
} from 'antd/es/date-picker';
import cls from 'classnames';
import moment from 'moment';
import React from 'react';
type Composed = {
@ -16,21 +15,23 @@ type Composed = {
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) {
return <div></div>;
}
const prefixCls = usePrefixCls('description-date-picker', props);
const getLabels = () => {
const format = getDefaultFormat(props) as string;
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 <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 format = getDefaultFormat(props);
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-02"]') as HTMLElement);
expect(startInput).toHaveValue('2023-05-01');
expect(endInput).toHaveValue('2023-05-02');
await waitFor(() => expect(startInput).toHaveValue('2023-05-01'));
await waitFor(() => expect(endInput).toHaveValue('2023-05-02'));
// Read pretty
expect(screen.getByText('2023-05-01~2023-05-02', { selector: '.ant-description-text' })).toBeInTheDocument();
// Value

View File

@ -1,4 +1,4 @@
import moment from 'moment';
import { dayjs } from '@nocobase/utils/client';
import { getDateRanges } from '../util';
describe('getDateRanges', () => {
@ -6,115 +6,115 @@ describe('getDateRanges', () => {
it('today', () => {
const [start, end] = dateRanges.today();
expect(start.toISOString()).toBe(moment().startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().endOf('day').toISOString());
expect(start.toISOString()).toBe(dayjs().startOf('day').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('day').toISOString());
});
it('lastWeek', () => {
const [start, end] = dateRanges.lastWeek();
expect(start.toISOString()).toBe(moment().add(-1, 'week').startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'week').endOf('isoWeek').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-1, 'week').startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(dayjs().add(-1, 'week').endOf('isoWeek').toISOString());
});
it('thisWeek', () => {
const [start, end] = dateRanges.thisWeek();
expect(start.toISOString()).toBe(moment().startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(moment().endOf('isoWeek').toISOString());
expect(start.toISOString()).toBe(dayjs().startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('isoWeek').toISOString());
});
it('nextWeek', () => {
const [start, end] = dateRanges.nextWeek();
expect(start.toISOString()).toBe(moment().add(1, 'week').startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'week').endOf('isoWeek').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'week').startOf('isoWeek').toISOString());
expect(end.toISOString()).toBe(dayjs().add(1, 'week').endOf('isoWeek').toISOString());
});
it('lastMonth', () => {
const [start, end] = dateRanges.lastMonth();
expect(start.toISOString()).toBe(moment().add(-1, 'month').startOf('month').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'month').endOf('month').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-1, 'month').startOf('month').toISOString());
expect(end.toISOString()).toBe(dayjs().add(-1, 'month').endOf('month').toISOString());
});
it('thisMonth', () => {
const [start, end] = dateRanges.thisMonth();
expect(start.toISOString()).toBe(moment().startOf('month').toISOString());
expect(end.toISOString()).toBe(moment().endOf('month').toISOString());
expect(start.toISOString()).toBe(dayjs().startOf('month').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('month').toISOString());
});
it('nextMonth', () => {
const [start, end] = dateRanges.nextMonth();
expect(start.toISOString()).toBe(moment().add(1, 'month').startOf('month').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'month').endOf('month').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'month').startOf('month').toISOString());
expect(end.toISOString()).toBe(dayjs().add(1, 'month').endOf('month').toISOString());
});
it('lastQuarter', () => {
const [start, end] = dateRanges.lastQuarter();
expect(start.toISOString()).toBe(moment().add(-1, 'quarter').startOf('quarter').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'quarter').endOf('quarter').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-1, 'quarter').startOf('quarter').toISOString());
expect(end.toISOString()).toBe(dayjs().add(-1, 'quarter').endOf('quarter').toISOString());
});
it('thisQuarter', () => {
const [start, end] = dateRanges.thisQuarter();
expect(start.toISOString()).toBe(moment().startOf('quarter').toISOString());
expect(end.toISOString()).toBe(moment().endOf('quarter').toISOString());
expect(start.toISOString()).toBe(dayjs().startOf('quarter').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('quarter').toISOString());
});
it('nextQuarter', () => {
const [start, end] = dateRanges.nextQuarter();
expect(start.toISOString()).toBe(moment().add(1, 'quarter').startOf('quarter').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'quarter').endOf('quarter').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'quarter').startOf('quarter').toISOString());
expect(end.toISOString()).toBe(dayjs().add(1, 'quarter').endOf('quarter').toISOString());
});
it('lastYear', () => {
const [start, end] = dateRanges.lastYear();
expect(start.toISOString()).toBe(moment().add(-1, 'year').startOf('year').toISOString());
expect(end.toISOString()).toBe(moment().add(-1, 'year').endOf('year').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-1, 'year').startOf('year').toISOString());
expect(end.toISOString()).toBe(dayjs().add(-1, 'year').endOf('year').toISOString());
});
it('thisYear', () => {
const [start, end] = dateRanges.thisYear();
expect(start.toISOString()).toBe(moment().startOf('year').toISOString());
expect(end.toISOString()).toBe(moment().endOf('year').toISOString());
expect(start.toISOString()).toBe(dayjs().startOf('year').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('year').toISOString());
});
it('nextYear', () => {
const [start, end] = dateRanges.nextYear();
expect(start.toISOString()).toBe(moment().add(1, 'year').startOf('year').toISOString());
expect(end.toISOString()).toBe(moment().add(1, 'year').endOf('year').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'year').startOf('year').toISOString());
expect(end.toISOString()).toBe(dayjs().add(1, 'year').endOf('year').toISOString());
});
it('last7Days', () => {
const [start, end] = dateRanges.last7Days();
expect(start.toISOString()).toBe(moment().add(-6, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(moment().endOf('days').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-6, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('days').toISOString());
});
it('next7Days', () => {
const [start, end] = dateRanges.next7Days();
expect(start.toISOString()).toBe(moment().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().add(7, 'days').endOf('days').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(dayjs().add(7, 'days').endOf('days').toISOString());
});
it('last30Days', () => {
const [start, end] = dateRanges.last30Days();
expect(start.toISOString()).toBe(moment().add(-29, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(moment().endOf('days').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-29, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('days').toISOString());
});
it('next30Days', () => {
const [start, end] = dateRanges.next30Days();
expect(start.toISOString()).toBe(moment().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().add(30, 'days').endOf('days').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(dayjs().add(30, 'days').endOf('days').toISOString());
});
it('last90Days', () => {
const [start, end] = dateRanges.last90Days();
expect(start.toISOString()).toBe(moment().add(-89, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(moment().endOf('days').toISOString());
expect(start.toISOString()).toBe(dayjs().add(-89, 'days').startOf('days').toISOString());
expect(end.toISOString()).toBe(dayjs().endOf('days').toISOString());
});
it('next90Days', () => {
const [start, end] = dateRanges.next90Days();
expect(start.toISOString()).toBe(moment().add(1, 'day').startOf('day').toISOString());
expect(end.toISOString()).toBe(moment().add(90, 'days').endOf('days').toISOString());
expect(start.toISOString()).toBe(dayjs().add(1, 'day').startOf('day').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';
describe('mapDatePicker', () => {
@ -20,7 +20,7 @@ describe('mapDatePicker', () => {
};
const result = mapDatePicker()(props);
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(),
};
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');
});
@ -62,7 +62,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(m.toISOString());
});
@ -74,7 +74,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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');
});
@ -85,7 +85,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
const result = mapDatePicker()(props);
const m = moment('2022-02-22');
const m = dayjs('2022-02-22');
result.onChange(m);
expect(props.onChange).toHaveBeenCalledWith(m.toISOString());
});
@ -97,7 +97,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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');
});
@ -108,7 +108,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('year').toISOString());
});
@ -120,7 +120,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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');
});
@ -131,7 +131,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('month').toISOString());
});
@ -143,7 +143,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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');
});
@ -154,7 +154,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('quarter').toISOString());
});
@ -166,7 +166,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString());
});
@ -178,7 +178,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString());
});
@ -191,7 +191,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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');
});
@ -203,7 +203,7 @@ describe('mapDatePicker', () => {
onChange: vi.fn(),
};
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');
});

View File

@ -1,4 +1,4 @@
import moment from 'moment';
import { dayjs } from '@nocobase/utils/client';
import { mapRangePicker } from '../util';
describe('mapRangePicker', () => {
@ -10,7 +10,7 @@ describe('mapRangePicker', () => {
onChange: vi.fn(),
};
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);
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(),
};
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);
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(),
};
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);
expect(props.onChange).toHaveBeenCalledWith(['2023-01-01', '2023-01-02']);
});

View File

@ -1,5 +1,5 @@
import { str2moment } from '@nocobase/utils';
import moment from 'moment';
import { dayjs } from '@nocobase/utils/client';
import { moment2str } from '../util';
describe('str2moment', () => {
@ -44,91 +44,91 @@ describe('str2moment', () => {
describe('moment2str', () => {
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 });
expect(str).toBe('2023-06-21T10:10:00.000Z');
});
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 });
expect(str).toBe(m.toISOString());
});
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 });
expect(str).toBe('2023-06-21T10:10:00.000Z');
});
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 });
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', () => {
const m = moment('2023-06-21 10:10:00');
const m = dayjs('2023-06-21 10:10:00');
const str = moment2str(m, { showTime: true });
expect(str).toBe(m.toISOString());
});
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 });
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', () => {
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 });
expect(str).toBe('2023-01-01T00:00:00.000Z');
});
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' });
expect(str).toBe('2023-01-01T00:00:00.000Z');
});
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 });
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', () => {
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 });
expect(str).toBe('2023-04-01T00:00:00.000Z');
});
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 });
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', () => {
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 });
expect(str).toBe('2023-06-01T00:00:00.000Z');
});
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' });
expect(str).toBe('2023-06-01T00:00:00.000Z');
});
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 });
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', () => {
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 });
expect(str).toBe('2023-06-19T00:00:00.000Z');
});

View File

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

View File

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

View File

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

View File

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

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