mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +08:00
Merge branch 'next' into develop
This commit is contained in:
commit
f2f4cb1cac
@ -71,5 +71,7 @@ export * from './modules/blocks/data-blocks/table-selector';
|
|||||||
export * from './modules/blocks/index';
|
export * from './modules/blocks/index';
|
||||||
export * from './modules/blocks/useParentRecordCommon';
|
export * from './modules/blocks/useParentRecordCommon';
|
||||||
export { OpenModeProvider, useOpenModeContext } from './modules/popup/OpenModeProvider';
|
export { OpenModeProvider, useOpenModeContext } from './modules/popup/OpenModeProvider';
|
||||||
|
export { PopupContextProvider } from './modules/popup/PopupContextProvider';
|
||||||
|
export { usePopupUtils } from './modules/popup/usePopupUtils';
|
||||||
|
|
||||||
export { VariablePopupRecordProvider } from './modules/variable/variablesProvider/VariablePopupRecordProvider';
|
export { VariablePopupRecordProvider } from './modules/variable/variablesProvider/VariablePopupRecordProvider';
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { usePagePopup } from '../../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
||||||
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
||||||
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
||||||
export const CreateChildInitializer = (props) => {
|
export const CreateChildInitializer = (props) => {
|
||||||
const { defaultOpenMode } = useOpenModeContext();
|
const { defaultOpenMode } = useOpenModeContext();
|
||||||
const { getPopupContext } = usePagePopup();
|
const { getPopupContext } = usePopupUtils();
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{ t("Add child") }}',
|
title: '{{ t("Add child") }}',
|
||||||
|
@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSchemaInitializerItem } from '../../../application';
|
import { useSchemaInitializerItem } from '../../../application';
|
||||||
import { usePagePopup } from '../../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
||||||
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
||||||
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
||||||
|
|
||||||
export const CreateActionInitializer = () => {
|
export const CreateActionInitializer = () => {
|
||||||
const { defaultOpenMode } = useOpenModeContext();
|
const { defaultOpenMode } = useOpenModeContext();
|
||||||
const { getPopupContext } = usePagePopup();
|
const { getPopupContext } = usePopupUtils();
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-action': 'create',
|
'x-action': 'create',
|
||||||
|
@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSchemaInitializerItem } from '../../../application';
|
import { useSchemaInitializerItem } from '../../../application';
|
||||||
import { usePagePopup } from '../../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
||||||
import { BlockInitializer } from '../../../schema-initializer/items';
|
import { BlockInitializer } from '../../../schema-initializer/items';
|
||||||
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
||||||
|
|
||||||
export const PopupActionInitializer = (props) => {
|
export const PopupActionInitializer = (props) => {
|
||||||
const { defaultOpenMode } = useOpenModeContext();
|
const { defaultOpenMode } = useOpenModeContext();
|
||||||
const { getPopupContext } = usePagePopup();
|
const { getPopupContext } = usePopupUtils();
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{ t("Popup") }}',
|
title: '{{ t("Popup") }}',
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { usePagePopup } from '../../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
||||||
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
||||||
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
||||||
|
|
||||||
export const UpdateActionInitializer = (props) => {
|
export const UpdateActionInitializer = (props) => {
|
||||||
const { defaultOpenMode } = useOpenModeContext();
|
const { defaultOpenMode } = useOpenModeContext();
|
||||||
const { getPopupContext } = usePagePopup();
|
const { getPopupContext } = usePopupUtils();
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{ t("Edit") }}',
|
title: '{{ t("Edit") }}',
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { usePagePopup } from '../../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
import { CONTEXT_SCHEMA_KEY } from '../../../schema-component/antd/page/usePopupContextInActionOrAssociationField';
|
||||||
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
|
||||||
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
import { useOpenModeContext } from '../../popup/OpenModeProvider';
|
||||||
|
|
||||||
export const ViewActionInitializer = (props) => {
|
export const ViewActionInitializer = (props) => {
|
||||||
const { defaultOpenMode } = useOpenModeContext();
|
const { defaultOpenMode } = useOpenModeContext();
|
||||||
const { getPopupContext } = usePagePopup();
|
const { getPopupContext } = usePopupUtils();
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '{{ t("View") }}',
|
title: '{{ t("View") }}',
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useFieldSchema } from '@formily/react';
|
||||||
|
import React, { useCallback, useContext, useState } from 'react';
|
||||||
|
import { ActionContextProvider } from '../../schema-component';
|
||||||
|
import { PopupVisibleProvider, PopupVisibleProviderContext } from '../../schema-component/antd/page/PagePopups';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provider the context for popup to work
|
||||||
|
* @param props
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const PopupContextProvider: React.FC = (props) => {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { visible: visibleWithURL, setVisible: setVisibleWithURL } = useContext(PopupVisibleProviderContext) || {
|
||||||
|
visible: false,
|
||||||
|
setVisible: () => {},
|
||||||
|
};
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const _setVisible = useCallback(
|
||||||
|
(value: boolean): void => {
|
||||||
|
setVisible?.(value);
|
||||||
|
setVisibleWithURL?.(value);
|
||||||
|
},
|
||||||
|
[setVisibleWithURL],
|
||||||
|
);
|
||||||
|
const openMode = fieldSchema['x-component-props']?.['openMode'] || 'drawer';
|
||||||
|
const openSize = fieldSchema['x-component-props']?.['openSize'];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopupVisibleProvider visible={false}>
|
||||||
|
<ActionContextProvider
|
||||||
|
visible={visible || visibleWithURL}
|
||||||
|
setVisible={_setVisible}
|
||||||
|
openMode={openMode}
|
||||||
|
openSize={openSize}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</ActionContextProvider>
|
||||||
|
</PopupVisibleProvider>
|
||||||
|
);
|
||||||
|
};
|
10
packages/core/client/src/modules/popup/usePopupUtils.ts
Normal file
10
packages/core/client/src/modules/popup/usePopupUtils.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { usePopupUtils } from '../../schema-component/antd/page/pagePopupUtils';
|
@ -29,7 +29,7 @@ import { SortableItem } from '../../common';
|
|||||||
import { useCompile, useComponent, useDesigner } from '../../hooks';
|
import { useCompile, useComponent, useDesigner } from '../../hooks';
|
||||||
import { useProps } from '../../hooks/useProps';
|
import { useProps } from '../../hooks/useProps';
|
||||||
import { PopupVisibleProvider } from '../page/PagePopups';
|
import { PopupVisibleProvider } from '../page/PagePopups';
|
||||||
import { usePagePopup } from '../page/pagePopupUtils';
|
import { usePopupUtils } from '../page/pagePopupUtils';
|
||||||
import { usePopupSettings } from '../page/PopupSettingsProvider';
|
import { usePopupSettings } from '../page/PopupSettingsProvider';
|
||||||
import ActionContainer from './Action.Container';
|
import ActionContainer from './Action.Container';
|
||||||
import { ActionDesigner } from './Action.Designer';
|
import { ActionDesigner } from './Action.Designer';
|
||||||
@ -77,7 +77,7 @@ export const Action: ComposedAction = withDynamicSchemaProps(
|
|||||||
const aclCtx = useACLActionParamsContext();
|
const aclCtx = useACLActionParamsContext();
|
||||||
const { wrapSSR, componentCls, hashId } = useStyles();
|
const { wrapSSR, componentCls, hashId } = useStyles();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { visibleWithURL, setVisibleWithURL } = usePagePopup();
|
const { visibleWithURL, setVisibleWithURL } = usePopupUtils();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [formValueChanged, setFormValueChanged] = useState(false);
|
const [formValueChanged, setFormValueChanged] = useState(false);
|
||||||
const { setSubmitted: setParentSubmitted } = useActionContext();
|
const { setSubmitted: setParentSubmitted } = useActionContext();
|
||||||
@ -307,7 +307,7 @@ function RenderButton({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
||||||
const { openPopup } = usePagePopup();
|
const { openPopup } = usePopupUtils();
|
||||||
|
|
||||||
const handleButtonClick = useCallback(
|
const handleButtonClick = useCallback(
|
||||||
(e: React.MouseEvent, checkPortal = true) => {
|
(e: React.MouseEvent, checkPortal = true) => {
|
||||||
|
@ -15,7 +15,7 @@ import { useCollectionManager_deprecated } from '../../../collection-manager';
|
|||||||
import { useCollectionRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
import { useCollectionRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
|
||||||
import { useCompile } from '../../hooks';
|
import { useCompile } from '../../hooks';
|
||||||
import { useActionContext } from '../action';
|
import { useActionContext } from '../action';
|
||||||
import { usePagePopup } from '../page/pagePopupUtils';
|
import { usePopupUtils } from '../page/pagePopupUtils';
|
||||||
import { transformNestedData } from './InternalCascadeSelect';
|
import { transformNestedData } from './InternalCascadeSelect';
|
||||||
import { ButtonListProps, ReadPrettyInternalViewer, isObject } from './InternalViewer';
|
import { ButtonListProps, ReadPrettyInternalViewer, isObject } from './InternalViewer';
|
||||||
import { useAssociationFieldContext, useFieldNames, useInsertSchema } from './hooks';
|
import { useAssociationFieldContext, useFieldNames, useInsertSchema } from './hooks';
|
||||||
@ -47,7 +47,7 @@ const ButtonTabList: React.FC<ButtonListProps> = (props) => {
|
|||||||
const { getCollection } = useCollectionManager_deprecated();
|
const { getCollection } = useCollectionManager_deprecated();
|
||||||
const targetCollection = getCollection(collectionField?.target);
|
const targetCollection = getCollection(collectionField?.target);
|
||||||
const isTreeCollection = targetCollection?.template === 'tree';
|
const isTreeCollection = targetCollection?.template === 'tree';
|
||||||
const { openPopup } = usePagePopup();
|
const { openPopup } = usePopupUtils();
|
||||||
const recordData = useCollectionRecordData();
|
const recordData = useCollectionRecordData();
|
||||||
|
|
||||||
const renderRecords = () =>
|
const renderRecords = () =>
|
||||||
|
@ -19,7 +19,7 @@ import { useCompile } from '../../hooks';
|
|||||||
import { ActionContextProvider, useActionContext } from '../action';
|
import { ActionContextProvider, useActionContext } from '../action';
|
||||||
import { EllipsisWithTooltip } from '../input/EllipsisWithTooltip';
|
import { EllipsisWithTooltip } from '../input/EllipsisWithTooltip';
|
||||||
import { PopupVisibleProvider } from '../page/PagePopups';
|
import { PopupVisibleProvider } from '../page/PagePopups';
|
||||||
import { usePagePopup } from '../page/pagePopupUtils';
|
import { usePopupUtils } from '../page/pagePopupUtils';
|
||||||
import { useAssociationFieldContext, useFieldNames, useInsertSchema } from './hooks';
|
import { useAssociationFieldContext, useFieldNames, useInsertSchema } from './hooks';
|
||||||
import { transformNestedData } from './InternalCascadeSelect';
|
import { transformNestedData } from './InternalCascadeSelect';
|
||||||
import schema from './schema';
|
import schema from './schema';
|
||||||
@ -62,7 +62,7 @@ const ButtonLinkList: FC<ButtonListProps> = (props) => {
|
|||||||
const isTreeCollection = targetCollection?.template === 'tree';
|
const isTreeCollection = targetCollection?.template === 'tree';
|
||||||
const ellipsisWithTooltipRef = useRef<IEllipsisWithTooltipRef>();
|
const ellipsisWithTooltipRef = useRef<IEllipsisWithTooltipRef>();
|
||||||
const getLabelUiSchema = useLabelUiSchemaV2();
|
const getLabelUiSchema = useLabelUiSchemaV2();
|
||||||
const { openPopup } = usePagePopup();
|
const { openPopup } = usePopupUtils();
|
||||||
const recordData = useCollectionRecordData();
|
const recordData = useCollectionRecordData();
|
||||||
|
|
||||||
const renderRecords = () =>
|
const renderRecords = () =>
|
||||||
@ -143,7 +143,7 @@ export const ReadPrettyInternalViewer: React.FC = observer(
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { options: collectionField } = useAssociationFieldContext();
|
const { options: collectionField } = useAssociationFieldContext();
|
||||||
const ellipsisWithTooltipRef = useRef<IEllipsisWithTooltipRef>();
|
const ellipsisWithTooltipRef = useRef<IEllipsisWithTooltipRef>();
|
||||||
const { visibleWithURL, setVisibleWithURL } = usePagePopup();
|
const { visibleWithURL, setVisibleWithURL } = usePopupUtils();
|
||||||
const [btnHover, setBtnHover] = useState(!!visibleWithURL);
|
const [btnHover, setBtnHover] = useState(!!visibleWithURL);
|
||||||
const { defaultOpenMode } = useOpenModeContext();
|
const { defaultOpenMode } = useOpenModeContext();
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ISchema } from '@formily/json-schema';
|
import { ISchema, Schema } from '@formily/json-schema';
|
||||||
|
import { useFieldSchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { Result } from 'antd';
|
import { Result } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@ -21,7 +22,7 @@ import { SchemaComponent } from '../../core';
|
|||||||
import { TabsContextProvider } from '../tabs/context';
|
import { TabsContextProvider } from '../tabs/context';
|
||||||
import { usePopupSettings } from './PopupSettingsProvider';
|
import { usePopupSettings } from './PopupSettingsProvider';
|
||||||
import { deleteRandomNestedSchemaKey, getRandomNestedSchemaKey } from './nestedSchemaKeyStorage';
|
import { deleteRandomNestedSchemaKey, getRandomNestedSchemaKey } from './nestedSchemaKeyStorage';
|
||||||
import { PopupParams, getPopupParamsFromPath, getStoredPopupContext, usePagePopup } from './pagePopupUtils';
|
import { PopupParams, getPopupParamsFromPath, getStoredPopupContext, usePopupUtils } from './pagePopupUtils';
|
||||||
import {
|
import {
|
||||||
PopupContext,
|
PopupContext,
|
||||||
getPopupContextFromActionOrAssociationFieldSchema,
|
getPopupContextFromActionOrAssociationFieldSchema,
|
||||||
@ -86,7 +87,7 @@ const PopupParamsProvider: FC<Omit<PopupProps, 'hidden'>> = (props) => {
|
|||||||
|
|
||||||
const PopupTabsPropsProvider: FC = ({ children }) => {
|
const PopupTabsPropsProvider: FC = ({ children }) => {
|
||||||
const { params } = useCurrentPopupContext();
|
const { params } = useCurrentPopupContext();
|
||||||
const { changeTab } = usePagePopup();
|
const { changeTab } = usePopupUtils();
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(key: string) => {
|
(key: string) => {
|
||||||
changeTab(key);
|
changeTab(key);
|
||||||
@ -114,7 +115,7 @@ const PagePopupsItemProvider: FC<{
|
|||||||
*/
|
*/
|
||||||
currentLevel: number;
|
currentLevel: number;
|
||||||
}> = ({ params, context, currentLevel, children }) => {
|
}> = ({ params, context, currentLevel, children }) => {
|
||||||
const { closePopup } = usePagePopup();
|
const { closePopup } = usePopupUtils();
|
||||||
const [visible, _setVisible] = useState(true);
|
const [visible, _setVisible] = useState(true);
|
||||||
const setVisible = (visible: boolean) => {
|
const setVisible = (visible: boolean) => {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
@ -183,7 +184,17 @@ const PagePopupsItemProvider: FC<{
|
|||||||
* @param props
|
* @param props
|
||||||
* @param parentSchema
|
* @param parentSchema
|
||||||
*/
|
*/
|
||||||
export const insertChildToParentSchema = (childSchema: ISchema, props: PopupProps, parentSchema: ISchema) => {
|
export const insertChildToParentSchema = ({
|
||||||
|
childSchema,
|
||||||
|
props,
|
||||||
|
parentSchema,
|
||||||
|
getPopupSchema = (currentSchema) => _.get(currentSchema.properties, Object.keys(currentSchema.properties)[0]),
|
||||||
|
}: {
|
||||||
|
childSchema: ISchema;
|
||||||
|
props: PopupProps;
|
||||||
|
parentSchema: ISchema;
|
||||||
|
getPopupSchema?: (currentSchema: ISchema) => ISchema;
|
||||||
|
}) => {
|
||||||
const { params, context, currentLevel } = props;
|
const { params, context, currentLevel } = props;
|
||||||
|
|
||||||
const componentSchema = {
|
const componentSchema = {
|
||||||
@ -203,7 +214,7 @@ export const insertChildToParentSchema = (childSchema: ISchema, props: PopupProp
|
|||||||
const nestedPopupKey = getRandomNestedSchemaKey(params.popupuid);
|
const nestedPopupKey = getRandomNestedSchemaKey(params.popupuid);
|
||||||
|
|
||||||
if (parentSchema.properties) {
|
if (parentSchema.properties) {
|
||||||
const popupSchema = _.get(parentSchema.properties, Object.keys(parentSchema.properties)[0]);
|
const popupSchema = getPopupSchema(parentSchema);
|
||||||
if (_.isEmpty(_.get(popupSchema, `properties.${nestedPopupKey}`))) {
|
if (_.isEmpty(_.get(popupSchema, `properties.${nestedPopupKey}`))) {
|
||||||
_.set(popupSchema, `properties.${nestedPopupKey}`, componentSchema);
|
_.set(popupSchema, `properties.${nestedPopupKey}`, componentSchema);
|
||||||
}
|
}
|
||||||
@ -211,11 +222,13 @@ export const insertChildToParentSchema = (childSchema: ISchema, props: PopupProp
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const PagePopups = (props: { paramsList?: PopupParams[] }) => {
|
export const PagePopups = (props: { paramsList?: PopupParams[] }) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const popupParams = props.paramsList || getPopupParamsFromPath(getPopupPath(location));
|
const popupParams = props.paramsList || getPopupParamsFromPath(getPopupPath(location));
|
||||||
const { requestSchema } = useRequestSchema();
|
const { requestSchema } = useRequestSchema();
|
||||||
const [rootSchema, setRootSchema] = useState<ISchema>(null);
|
const [rootSchema, setRootSchema] = useState<ISchema>(null);
|
||||||
const popupPropsRef = useRef<PopupProps[]>([]);
|
const popupPropsRef = useRef<PopupProps[]>([]);
|
||||||
|
const { savePopupSchemaToSchema, getPopupSchemaFromSchema } = usePopupUtils();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
@ -223,13 +236,23 @@ export const PagePopups = (props: { paramsList?: PopupParams[] }) => {
|
|||||||
(params) => getStoredPopupContext(params.popupuid)?.schema || requestSchema(params.popupuid),
|
(params) => getStoredPopupContext(params.popupuid)?.schema || requestSchema(params.popupuid),
|
||||||
);
|
);
|
||||||
const schemas = await Promise.all(waitList);
|
const schemas = await Promise.all(waitList);
|
||||||
const clonedSchemas = schemas.map((schema) => {
|
const clonedSchemas = schemas.map((schema, index) => {
|
||||||
if (_.isEmpty(schema)) {
|
if (_.isEmpty(schema)) {
|
||||||
return get404Schema();
|
return get404Schema();
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = _.cloneDeep(_.omit(schema, 'parent'));
|
const params = popupParams[index];
|
||||||
|
|
||||||
|
if (params.puid) {
|
||||||
|
const popupSchema = findSchemaByUid(params.puid, fieldSchema.root);
|
||||||
|
if (popupSchema) {
|
||||||
|
savePopupSchemaToSchema(_.omit(popupSchema, 'parent'), schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = _.cloneDeep(_.omit(schema, 'parent')) as Schema;
|
||||||
result['x-read-pretty'] = true;
|
result['x-read-pretty'] = true;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
popupPropsRef.current = clonedSchemas.map((schema, index, items) => {
|
popupPropsRef.current = clonedSchemas.map((schema, index, items) => {
|
||||||
@ -254,12 +277,22 @@ export const PagePopups = (props: { paramsList?: PopupParams[] }) => {
|
|||||||
});
|
});
|
||||||
const rootSchema = clonedSchemas[0];
|
const rootSchema = clonedSchemas[0];
|
||||||
for (let i = 1; i < clonedSchemas.length; i++) {
|
for (let i = 1; i < clonedSchemas.length; i++) {
|
||||||
insertChildToParentSchema(clonedSchemas[i], popupPropsRef.current[i], clonedSchemas[i - 1]);
|
insertChildToParentSchema({
|
||||||
|
childSchema: clonedSchemas[i],
|
||||||
|
props: popupPropsRef.current[i],
|
||||||
|
parentSchema: clonedSchemas[i - 1],
|
||||||
|
getPopupSchema: (currentSchema) => {
|
||||||
|
return (
|
||||||
|
getPopupSchemaFromSchema(currentSchema) ||
|
||||||
|
_.get(currentSchema.properties, Object.keys(currentSchema.properties)[0])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setRootSchema(rootSchema);
|
setRootSchema(rootSchema);
|
||||||
};
|
};
|
||||||
run();
|
run();
|
||||||
}, [popupParams, requestSchema]);
|
}, [fieldSchema.root, getPopupSchemaFromSchema, popupParams, requestSchema, savePopupSchemaToSchema]);
|
||||||
|
|
||||||
const components = useMemo(() => ({ PagePopupsItemProvider }), []);
|
const components = useMemo(() => ({ PagePopupsItemProvider }), []);
|
||||||
|
|
||||||
@ -406,3 +439,17 @@ function get404Schema() {
|
|||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findSchemaByUid(uid: string, rootSchema: Schema, resultRef: { value: Schema } = { value: null }) {
|
||||||
|
resultRef = resultRef || {
|
||||||
|
value: null,
|
||||||
|
};
|
||||||
|
rootSchema.mapProperties((schema) => {
|
||||||
|
if (schema['x-uid'] === uid) {
|
||||||
|
resultRef.value = schema;
|
||||||
|
} else {
|
||||||
|
findSchemaByUid(uid, schema, resultRef);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return resultRef.value;
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@ describe('insertToPopupSchema', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
insertChildToParentSchema(childSchema, { params, context }, parentSchema);
|
insertChildToParentSchema({ childSchema, props: { params, context } as any, parentSchema });
|
||||||
|
|
||||||
expect(parentSchema).toEqual({
|
expect(parentSchema).toEqual({
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -37,6 +37,8 @@ export interface PopupParams {
|
|||||||
tab?: string;
|
tab?: string;
|
||||||
/** collection name */
|
/** collection name */
|
||||||
collection?: string;
|
collection?: string;
|
||||||
|
/** popup uid */
|
||||||
|
puid?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PopupContextStorage extends PopupContext {
|
export interface PopupContextStorage extends PopupContext {
|
||||||
@ -103,9 +105,11 @@ export const getPopupParamsFromPath = _.memoize((path: string) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const getPopupPathFromParams = (params: PopupParams) => {
|
export const getPopupPathFromParams = (params: PopupParams) => {
|
||||||
const { popupuid: popupUid, tab, filterbytk, sourceid, collection } = params;
|
const { popupuid: popupUid, tab, filterbytk, sourceid, collection, puid } = params;
|
||||||
const popupPath = [
|
const popupPath = [
|
||||||
popupUid,
|
popupUid,
|
||||||
|
puid && 'puid',
|
||||||
|
puid,
|
||||||
collection && 'collection',
|
collection && 'collection',
|
||||||
collection,
|
collection,
|
||||||
filterbytk && 'filterbytk',
|
filterbytk && 'filterbytk',
|
||||||
@ -123,7 +127,7 @@ export const getPopupPathFromParams = (params: PopupParams) => {
|
|||||||
* Note: use this hook in a plugin is not recommended
|
* Note: use this hook in a plugin is not recommended
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const usePagePopup = () => {
|
export const usePopupUtils = () => {
|
||||||
const navigate = useNavigateNoUpdate();
|
const navigate = useNavigateNoUpdate();
|
||||||
const location = useLocationNoUpdate();
|
const location = useLocationNoUpdate();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
@ -153,16 +157,23 @@ export const usePagePopup = () => {
|
|||||||
recordData,
|
recordData,
|
||||||
sourceId,
|
sourceId,
|
||||||
collection: _collection,
|
collection: _collection,
|
||||||
|
puid,
|
||||||
}: {
|
}: {
|
||||||
|
/**
|
||||||
|
* this is the schema uid of the button that triggers the popup, while puid is the schema uid of the popup, they are different;
|
||||||
|
*/
|
||||||
popupUid: string;
|
popupUid: string;
|
||||||
recordData: Record<string, any>;
|
recordData: Record<string, any>;
|
||||||
sourceId: string;
|
sourceId: string;
|
||||||
tabKey?: string;
|
tabKey?: string;
|
||||||
collection?: string;
|
collection?: string;
|
||||||
|
/** popup uid */
|
||||||
|
puid?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const filterByTK = cm.getFilterByTK(association || collection, recordData);
|
const filterByTK = cm.getFilterByTK(association || collection, recordData);
|
||||||
return getPopupPathFromParams({
|
return getPopupPathFromParams({
|
||||||
popupuid: popupUid,
|
popupuid: popupUid,
|
||||||
|
puid,
|
||||||
collection: _collection,
|
collection: _collection,
|
||||||
filterbytk: filterByTK,
|
filterbytk: filterByTK,
|
||||||
sourceid: sourceId,
|
sourceid: sourceId,
|
||||||
@ -187,11 +198,14 @@ export const usePagePopup = () => {
|
|||||||
recordData,
|
recordData,
|
||||||
parentRecordData,
|
parentRecordData,
|
||||||
collectionNameUsedInURL,
|
collectionNameUsedInURL,
|
||||||
|
popupUidUsedInURL,
|
||||||
}: {
|
}: {
|
||||||
recordData?: Record<string, any>;
|
recordData?: Record<string, any>;
|
||||||
parentRecordData?: Record<string, any>;
|
parentRecordData?: Record<string, any>;
|
||||||
/** if this value exists, it will be saved in the URL */
|
/** if this value exists, it will be saved in the URL */
|
||||||
collectionNameUsedInURL?: string;
|
collectionNameUsedInURL?: string;
|
||||||
|
/** if this value exists, it will be saved in the URL */
|
||||||
|
popupUidUsedInURL?: string;
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
if (!isPopupVisibleControlledByURL()) {
|
if (!isPopupVisibleControlledByURL()) {
|
||||||
return setVisibleFromAction?.(true);
|
return setVisibleFromAction?.(true);
|
||||||
@ -205,6 +219,7 @@ export const usePagePopup = () => {
|
|||||||
recordData,
|
recordData,
|
||||||
sourceId,
|
sourceId,
|
||||||
collection: collectionNameUsedInURL,
|
collection: collectionNameUsedInURL,
|
||||||
|
puid: popupUidUsedInURL,
|
||||||
});
|
});
|
||||||
let url = location.pathname;
|
let url = location.pathname;
|
||||||
if (_.last(url) === '/') {
|
if (_.last(url) === '/') {
|
||||||
@ -283,6 +298,14 @@ export const usePagePopup = () => {
|
|||||||
[getNewPathname, navigate, popupParams?.popupuid, record?.data, location],
|
[getNewPathname, navigate, popupParams?.popupuid, record?.data, location],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const savePopupSchemaToSchema = useCallback((popupSchema: ISchema, targetSchema: ISchema) => {
|
||||||
|
targetSchema['__popup'] = popupSchema;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getPopupSchemaFromSchema = useCallback((schema: ISchema) => {
|
||||||
|
return schema['__popup'];
|
||||||
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* used to open popup by changing the url
|
* used to open popup by changing the url
|
||||||
@ -292,10 +315,32 @@ export const usePagePopup = () => {
|
|||||||
* used to close popup by changing the url
|
* used to close popup by changing the url
|
||||||
*/
|
*/
|
||||||
closePopup,
|
closePopup,
|
||||||
|
savePopupSchemaToSchema,
|
||||||
|
getPopupSchemaFromSchema,
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* TODO: remove this
|
||||||
|
*/
|
||||||
visibleWithURL: visible,
|
visibleWithURL: visible,
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* TODO: remove this
|
||||||
|
*/
|
||||||
setVisibleWithURL: setVisible,
|
setVisibleWithURL: setVisible,
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* TODO: remove this
|
||||||
|
*/
|
||||||
popupParams,
|
popupParams,
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* TODO: remove this
|
||||||
|
*/
|
||||||
changeTab,
|
changeTab,
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* TODO: remove this
|
||||||
|
*/
|
||||||
getPopupContext,
|
getPopupContext,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@ import { useTreeParentRecord } from '../../modules/blocks/data-blocks/table/Tree
|
|||||||
import { useRecord } from '../../record-provider';
|
import { useRecord } from '../../record-provider';
|
||||||
import { useCompile } from '../../schema-component';
|
import { useCompile } from '../../schema-component';
|
||||||
import { linkageAction } from '../../schema-component/antd/action/utils';
|
import { linkageAction } from '../../schema-component/antd/action/utils';
|
||||||
import { usePagePopup } from '../../schema-component/antd/page/pagePopupUtils';
|
import { usePopupUtils } from '../../schema-component/antd/page/pagePopupUtils';
|
||||||
import { parseVariables } from '../../schema-component/common/utils/uitls';
|
import { parseVariables } from '../../schema-component/common/utils/uitls';
|
||||||
import { useLocalVariables, useVariables } from '../../variables';
|
import { useLocalVariables, useVariables } from '../../variables';
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ const InternalCreateRecordAction = (props: any, ref) => {
|
|||||||
const values = useRecord();
|
const values = useRecord();
|
||||||
const variables = useVariables();
|
const variables = useVariables();
|
||||||
const localVariables = useLocalVariables({ currentForm: { values } as any });
|
const localVariables = useLocalVariables({ currentForm: { values } as any });
|
||||||
const { openPopup } = usePagePopup();
|
const { openPopup } = usePopupUtils();
|
||||||
const treeRecordData = useTreeParentRecord();
|
const treeRecordData = useTreeParentRecord();
|
||||||
const cm = useCollectionManager();
|
const cm = useCollectionManager();
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ describe('action', () => {
|
|||||||
expect(model.toJSON()).toMatchObject(matcher);
|
expect(model.toJSON()).toMatchObject(matcher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('should be custom values', async () => {
|
it('should be custom values', async () => {
|
||||||
const Plugin = app.pm.get(PluginFileManagerServer) as PluginFileManagerServer;
|
const Plugin = app.pm.get(PluginFileManagerServer) as PluginFileManagerServer;
|
||||||
const model = await Plugin.createFileRecord({
|
const model = await Plugin.createFileRecord({
|
||||||
collectionName: 'attachments',
|
collectionName: 'attachments',
|
||||||
@ -117,6 +117,22 @@ describe('action', () => {
|
|||||||
expect(model.toJSON()).toMatchObject(matcher);
|
expect(model.toJSON()).toMatchObject(matcher);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be upload file', async () => {
|
||||||
|
const Plugin = app.pm.get(PluginFileManagerServer) as PluginFileManagerServer;
|
||||||
|
const data = await Plugin.uploadFile({
|
||||||
|
filePath: path.resolve(__dirname, './files/text.txt'),
|
||||||
|
documentRoot: 'storage/backups/test',
|
||||||
|
});
|
||||||
|
const matcher = {
|
||||||
|
title: 'text',
|
||||||
|
extname: '.txt',
|
||||||
|
path: '',
|
||||||
|
meta: {},
|
||||||
|
storageId: 1,
|
||||||
|
};
|
||||||
|
expect(data).toMatchObject(matcher);
|
||||||
|
});
|
||||||
|
|
||||||
it('upload file should be ok', async () => {
|
it('upload file should be ok', async () => {
|
||||||
const { body } = await agent.resource('attachments').create({
|
const { body } = await agent.resource('attachments').create({
|
||||||
[FILE_FIELD_NAME]: path.resolve(__dirname, './files/text.txt'),
|
[FILE_FIELD_NAME]: path.resolve(__dirname, './files/text.txt'),
|
||||||
|
@ -36,6 +36,12 @@ export type FileRecordOptions = {
|
|||||||
values?: any;
|
values?: any;
|
||||||
} & Transactionable;
|
} & Transactionable;
|
||||||
|
|
||||||
|
export type UploadFileOptions = {
|
||||||
|
filePath: string;
|
||||||
|
storageName?: string;
|
||||||
|
documentRoot?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default class PluginFileManagerServer extends Plugin {
|
export default class PluginFileManagerServer extends Plugin {
|
||||||
storageTypes = new Registry<IStorage>();
|
storageTypes = new Registry<IStorage>();
|
||||||
storagesCache = new Map<number, StorageModel>();
|
storagesCache = new Map<number, StorageModel>();
|
||||||
@ -46,15 +52,21 @@ export default class PluginFileManagerServer extends Plugin {
|
|||||||
if (!collection) {
|
if (!collection) {
|
||||||
throw new Error(`collection does not exist`);
|
throw new Error(`collection does not exist`);
|
||||||
}
|
}
|
||||||
const storageRepository = this.db.getRepository('storages');
|
|
||||||
const collectionRepository = this.db.getRepository(collectionName);
|
const collectionRepository = this.db.getRepository(collectionName);
|
||||||
const name = storageName || collection.options.storage;
|
const name = storageName || collection.options.storage;
|
||||||
|
const data = await this.uploadFile({ storageName: name, filePath });
|
||||||
|
return await collectionRepository.create({ values: { ...data, ...values }, transaction });
|
||||||
|
}
|
||||||
|
|
||||||
|
async uploadFile(options: UploadFileOptions) {
|
||||||
|
const { storageName, filePath, documentRoot } = options;
|
||||||
|
const storageRepository = this.db.getRepository('storages');
|
||||||
let storageInstance;
|
let storageInstance;
|
||||||
if (name) {
|
|
||||||
|
if (storageName) {
|
||||||
storageInstance = await storageRepository.findOne({
|
storageInstance = await storageRepository.findOne({
|
||||||
filter: {
|
filter: {
|
||||||
name,
|
name: storageName,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -73,6 +85,10 @@ export default class PluginFileManagerServer extends Plugin {
|
|||||||
throw new Error('[file-manager] no linked or default storage provided');
|
throw new Error('[file-manager] no linked or default storage provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (documentRoot) {
|
||||||
|
storageInstance.options['documentRoot'] = documentRoot;
|
||||||
|
}
|
||||||
|
|
||||||
const storageConfig = this.storageTypes.get(storageInstance.type);
|
const storageConfig = this.storageTypes.get(storageInstance.type);
|
||||||
|
|
||||||
if (!storageConfig) {
|
if (!storageConfig) {
|
||||||
@ -97,8 +113,7 @@ export default class PluginFileManagerServer extends Plugin {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = getFileData({ app: this.app, file, storage: storageInstance, request: { body: {} } } as any);
|
return getFileData({ app: this.app, file, storage: storageInstance, request: { body: {} } } as any);
|
||||||
return await collectionRepository.create({ values: { ...data, ...values }, transaction });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadStorages(options?: { transaction: any }) {
|
async loadStorages(options?: { transaction: any }) {
|
||||||
|
@ -9,19 +9,21 @@
|
|||||||
|
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { FormLayout } from '@formily/antd-v5';
|
import { FormLayout } from '@formily/antd-v5';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
import { observer, RecursionField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, useFieldSchema } from '@formily/react';
|
||||||
import {
|
import {
|
||||||
ActionContextProvider,
|
|
||||||
DndContext,
|
DndContext,
|
||||||
RecordProvider,
|
FormProvider,
|
||||||
|
PopupContextProvider,
|
||||||
useCollection,
|
useCollection,
|
||||||
useCollectionParentRecordData,
|
useCollectionRecordData,
|
||||||
|
usePopupUtils,
|
||||||
VariablePopupRecordProvider,
|
VariablePopupRecordProvider,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
|
import { Schema } from '@nocobase/utils';
|
||||||
import { Card } from 'antd';
|
import { Card } from 'antd';
|
||||||
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
import React, { useCallback, useContext, useMemo } from 'react';
|
||||||
import { KanbanCardContext } from './context';
|
import { KanbanCardContext } from './context';
|
||||||
import { useKanbanTranslation } from './locale';
|
|
||||||
|
|
||||||
const cardCss = css`
|
const cardCss = css`
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
@ -72,23 +74,27 @@ MemorizedRecursionField.displayName = 'MemorizedRecursionField';
|
|||||||
|
|
||||||
export const KanbanCard: any = observer(
|
export const KanbanCard: any = observer(
|
||||||
() => {
|
() => {
|
||||||
const { t } = useKanbanTranslation();
|
|
||||||
const collection = useCollection();
|
const collection = useCollection();
|
||||||
const { setDisableCardDrag, cardViewerSchema, card, cardField, columnIndex, cardIndex } =
|
const { setDisableCardDrag } = useContext(KanbanCardContext) || {};
|
||||||
useContext(KanbanCardContext);
|
|
||||||
const parentRecordData = useCollectionParentRecordData();
|
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const [visible, setVisible] = useState(false);
|
const { openPopup, getPopupSchemaFromSchema } = usePopupUtils();
|
||||||
const handleCardClick = useCallback((e: React.MouseEvent) => {
|
const recordData = useCollectionRecordData();
|
||||||
const targetElement = e.target as Element; // 将事件目标转换为Element类型
|
const popupSchema = getPopupSchemaFromSchema(fieldSchema) || getPopupSchemaFromParent(fieldSchema);
|
||||||
const currentTargetElement = e.currentTarget as Element;
|
const handleCardClick = useCallback(
|
||||||
if (currentTargetElement.contains(targetElement)) {
|
(e: React.MouseEvent) => {
|
||||||
setVisible(true);
|
const targetElement = e.target as Element; // 将事件目标转换为Element类型
|
||||||
e.stopPropagation();
|
const currentTargetElement = e.currentTarget as Element;
|
||||||
} else {
|
if (currentTargetElement.contains(targetElement)) {
|
||||||
e.stopPropagation();
|
openPopup({
|
||||||
}
|
popupUidUsedInURL: popupSchema?.['x-uid'],
|
||||||
}, []);
|
});
|
||||||
|
e.stopPropagation();
|
||||||
|
} else {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[openPopup, popupSchema],
|
||||||
|
);
|
||||||
const cardStyle = useMemo(() => {
|
const cardStyle = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
@ -96,51 +102,70 @@ export const KanbanCard: any = observer(
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const form = useMemo(() => {
|
||||||
|
return createForm({
|
||||||
|
values: recordData,
|
||||||
|
});
|
||||||
|
}, [recordData]);
|
||||||
|
|
||||||
const onDragStart = useCallback(() => {
|
const onDragStart = useCallback(() => {
|
||||||
setDisableCardDrag(true);
|
setDisableCardDrag?.(true);
|
||||||
}, []);
|
}, [setDisableCardDrag]);
|
||||||
const onDragEnd = useCallback(() => {
|
const onDragEnd = useCallback(() => {
|
||||||
setDisableCardDrag(false);
|
setDisableCardDrag?.(false);
|
||||||
}, []);
|
}, [setDisableCardDrag]);
|
||||||
|
|
||||||
const actionContextValue = useMemo(() => {
|
// if not wrapped, only Tab component's content will be rendered, Drawer component's content will not be rendered
|
||||||
|
const wrappedPopupSchema = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
openMode: fieldSchema['x-component-props']?.['openMode'] || 'drawer',
|
type: 'void',
|
||||||
openSize: fieldSchema['x-component-props']?.['openSize'],
|
properties: {
|
||||||
visible,
|
drawer: popupSchema,
|
||||||
setVisible,
|
},
|
||||||
};
|
};
|
||||||
}, [fieldSchema, visible]);
|
}, [popupSchema]);
|
||||||
|
|
||||||
const basePath = useMemo(
|
|
||||||
() => cardField.address.concat(`${columnIndex}.cards.${cardIndex}`),
|
|
||||||
[cardField, columnIndex, cardIndex],
|
|
||||||
);
|
|
||||||
const cardViewerBasePath = useMemo(
|
|
||||||
() => cardField.address.concat(`${columnIndex}.cardViewer.${cardIndex}`),
|
|
||||||
[cardField, columnIndex, cardIndex],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card onClick={handleCardClick} bordered={false} hoverable style={cardStyle} className={cardCss}>
|
<Card onClick={handleCardClick} bordered={false} hoverable style={cardStyle} className={cardCss}>
|
||||||
<DndContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
<DndContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
<MemorizedRecursionField basePath={basePath} schema={fieldSchema} onlyRenderProperties />
|
<FormProvider form={form}>
|
||||||
|
<MemorizedRecursionField schema={fieldSchema} onlyRenderProperties />
|
||||||
|
</FormProvider>
|
||||||
</FormLayout>
|
</FormLayout>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
</Card>
|
</Card>
|
||||||
{cardViewerSchema && (
|
<PopupContextProvider>
|
||||||
<ActionContextProvider value={actionContextValue}>
|
<VariablePopupRecordProvider recordData={recordData} collection={collection}>
|
||||||
<RecordProvider record={card} parent={parentRecordData}>
|
<MemorizedRecursionField schema={wrappedPopupSchema} />
|
||||||
<VariablePopupRecordProvider recordData={card} collection={collection}>
|
</VariablePopupRecordProvider>
|
||||||
<MemorizedRecursionField basePath={cardViewerBasePath} schema={cardViewerSchema} onlyRenderProperties />
|
</PopupContextProvider>
|
||||||
</VariablePopupRecordProvider>
|
|
||||||
</RecordProvider>
|
|
||||||
</ActionContextProvider>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{ displayName: 'KanbanCard' },
|
{ displayName: 'KanbanCard' },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function getPopupSchemaFromParent(fieldSchema: Schema) {
|
||||||
|
if (fieldSchema.parent?.properties?.cardViewer?.properties?.drawer) {
|
||||||
|
return fieldSchema.parent.properties.cardViewer.properties.drawer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardSchema = findSchemaByUid(fieldSchema['x-uid'], fieldSchema.root);
|
||||||
|
return cardSchema.parent.properties.cardViewer.properties.drawer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findSchemaByUid(uid: string, rootSchema: Schema, resultRef: { value: Schema } = { value: null }) {
|
||||||
|
resultRef = resultRef || {
|
||||||
|
value: null,
|
||||||
|
};
|
||||||
|
rootSchema.mapProperties((schema) => {
|
||||||
|
if (schema['x-uid'] === uid) {
|
||||||
|
resultRef.value = schema;
|
||||||
|
} else {
|
||||||
|
findSchemaByUid(uid, schema, resultRef);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return resultRef.value;
|
||||||
|
}
|
||||||
|
@ -136,7 +136,7 @@ export const Kanban: any = withDynamicSchemaProps(
|
|||||||
<Tag color={color}>{title}</Tag>
|
<Tag color={color}>{title}</Tag>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
renderCard={(card, { column, dragging }) => {
|
renderCard={(card, { column }) => {
|
||||||
const columnIndex = dataSource?.indexOf(column);
|
const columnIndex = dataSource?.indexOf(column);
|
||||||
const cardIndex = column?.cards?.indexOf(card);
|
const cardIndex = column?.cards?.indexOf(card);
|
||||||
const { ref, inView } = useInView({
|
const { ref, inView } = useInView({
|
||||||
@ -144,24 +144,18 @@ export const Kanban: any = withDynamicSchemaProps(
|
|||||||
triggerOnce: true,
|
triggerOnce: true,
|
||||||
initialInView: lastDraggedCard.current && lastDraggedCard.current === card[primaryKey],
|
initialInView: lastDraggedCard.current && lastDraggedCard.current === card[primaryKey],
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
schemas.card && (
|
schemas.card && (
|
||||||
<RecordProvider record={card} parent={parentRecordData}>
|
<RecordProvider record={card} parent={parentRecordData}>
|
||||||
<KanbanCardContext.Provider
|
<KanbanCardContext.Provider
|
||||||
value={{
|
value={{
|
||||||
setDisableCardDrag,
|
setDisableCardDrag,
|
||||||
cardViewerSchema: schemas.cardViewer,
|
|
||||||
cardField: field,
|
|
||||||
card,
|
|
||||||
column,
|
|
||||||
dragging,
|
|
||||||
columnIndex,
|
|
||||||
cardIndex,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
{inView ? (
|
{inView ? (
|
||||||
<MemorizedRecursionField name={schemas.card.name} schema={schemas.card} />
|
<MemorizedRecursionField name={'card'} schema={fieldSchema.properties.card} />
|
||||||
) : (
|
) : (
|
||||||
<Card bordered={false}>
|
<Card bordered={false}>
|
||||||
<Skeleton paragraph={{ rows: 4 }} />
|
<Skeleton paragraph={{ rows: 4 }} />
|
||||||
|
@ -0,0 +1,755 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const kanbanURL = {
|
||||||
|
collections: [
|
||||||
|
{
|
||||||
|
name: 'kanban',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'select',
|
||||||
|
interface: 'select',
|
||||||
|
uiSchema: {
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
value: 'option1',
|
||||||
|
label: 'Option1',
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'option2',
|
||||||
|
label: 'Option2',
|
||||||
|
color: 'green',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'option3',
|
||||||
|
label: 'Option3',
|
||||||
|
color: 'blue',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Select',
|
||||||
|
title: 'Single select',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sort',
|
||||||
|
interface: 'sort',
|
||||||
|
scopeKey: 'select',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pageSchema: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Page',
|
||||||
|
properties: {
|
||||||
|
eehnoq75dyp: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'page:addBlock',
|
||||||
|
properties: {
|
||||||
|
qy13k7twlgr: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
z2zx32gyeno: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
'6h3p53u5ek7': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action': 'kanban:list',
|
||||||
|
'x-decorator': 'KanbanBlockProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
collection: 'kanban',
|
||||||
|
dataSource: 'main',
|
||||||
|
action: 'list',
|
||||||
|
groupField: 'select',
|
||||||
|
sortField: 'sort',
|
||||||
|
params: {
|
||||||
|
paginate: false,
|
||||||
|
sort: ['sort'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-toolbar': 'BlockSchemaToolbar',
|
||||||
|
'x-settings': 'blockSettings:kanban',
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer': 'kanban:configureActions',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 'var(--nb-spacing)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
'x-uid': 'zb0mo93az5z',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
ms2kyy843uc: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'Kanban',
|
||||||
|
'x-use-component-props': 'useKanbanBlockProps',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
card: {
|
||||||
|
'x-uid': '1y1b9kliqui',
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-label-disabled': true,
|
||||||
|
'x-decorator': 'BlockItem',
|
||||||
|
'x-component': 'Kanban.Card',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
},
|
||||||
|
'x-designer': 'Kanban.Card.Designer',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
'x-action-context': {
|
||||||
|
dataSource: 'main',
|
||||||
|
collection: 'kanban',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-component-props': {
|
||||||
|
dndContext: false,
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
'8evl3dcvt86': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
properties: {
|
||||||
|
'36yop5rgpyi': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
properties: {
|
||||||
|
select: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'string',
|
||||||
|
'x-toolbar': 'FormItemSchemaToolbar',
|
||||||
|
'x-settings': 'fieldSettings:FormItem',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'kanban.select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-uid': '8a20gaw8qdh',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'pzvcxvven6y',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'xd4gdx5j0qm',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'zx1rf8qfane',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
cardViewer: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("View") }}',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-component': 'Kanban.CardViewer',
|
||||||
|
'x-action': 'view',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("View record") }}',
|
||||||
|
'x-component': 'Action.Container',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'popup:addTab',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Details")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'popup:common:addBlock',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
'8bv7l5hiazu': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
torszg5y5zd: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
d4p7lp86m03: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action': 'kanban:get',
|
||||||
|
'x-decorator': 'DetailsBlockProvider',
|
||||||
|
'x-use-decorator-props': 'useDetailsDecoratorProps',
|
||||||
|
'x-decorator-props': {
|
||||||
|
dataSource: 'main',
|
||||||
|
collection: 'kanban',
|
||||||
|
readPretty: true,
|
||||||
|
action: 'get',
|
||||||
|
},
|
||||||
|
'x-toolbar': 'BlockSchemaToolbar',
|
||||||
|
'x-settings': 'blockSettings:details',
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
'1oxl6q1ktkh': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Details',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-use-component-props': 'useDetailsProps',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
r27t49cfoo5: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer': 'details:configureActions',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
uya6ulpeavl: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Edit") }}',
|
||||||
|
'x-action': 'update',
|
||||||
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
|
'x-settings': 'actionSettings:edit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
'x-action-context': {
|
||||||
|
dataSource: 'main',
|
||||||
|
collection: 'kanban',
|
||||||
|
},
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Edit record") }}',
|
||||||
|
'x-component': 'Action.Container',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'popup:addTab',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Edit")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer':
|
||||||
|
'popup:common:addBlock',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
etzmlia85gh: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
'6dn14wki0e5': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
cruqx5ulnow: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: false,
|
||||||
|
},
|
||||||
|
'x-acl-action':
|
||||||
|
'kanban:update',
|
||||||
|
'x-decorator':
|
||||||
|
'FormBlockProvider',
|
||||||
|
'x-use-decorator-props':
|
||||||
|
'useEditFormBlockDecoratorProps',
|
||||||
|
'x-decorator-props': {
|
||||||
|
action: 'get',
|
||||||
|
dataSource: 'main',
|
||||||
|
collection: 'kanban',
|
||||||
|
},
|
||||||
|
'x-toolbar':
|
||||||
|
'BlockSchemaToolbar',
|
||||||
|
'x-settings':
|
||||||
|
'blockSettings:editForm',
|
||||||
|
'x-component':
|
||||||
|
'CardItem',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
y0q5ei7mma2: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component':
|
||||||
|
'FormV2',
|
||||||
|
'x-use-component-props':
|
||||||
|
'useEditFormBlockProps',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component':
|
||||||
|
'Grid',
|
||||||
|
'x-initializer':
|
||||||
|
'form:configureFields',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
rjbvqpp7xmu: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version:
|
||||||
|
'2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component':
|
||||||
|
'Grid.Row',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties:
|
||||||
|
{
|
||||||
|
cxiykvzwfv1:
|
||||||
|
{
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version:
|
||||||
|
'2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component':
|
||||||
|
'Grid.Col',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties:
|
||||||
|
{
|
||||||
|
select:
|
||||||
|
{
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version:
|
||||||
|
'2.0',
|
||||||
|
type: 'string',
|
||||||
|
'x-toolbar':
|
||||||
|
'FormItemSchemaToolbar',
|
||||||
|
'x-settings':
|
||||||
|
'fieldSettings:FormItem',
|
||||||
|
'x-component':
|
||||||
|
'CollectionField',
|
||||||
|
'x-decorator':
|
||||||
|
'FormItem',
|
||||||
|
'x-collection-field':
|
||||||
|
'kanban.select',
|
||||||
|
'x-component-props':
|
||||||
|
{
|
||||||
|
style:
|
||||||
|
{
|
||||||
|
width:
|
||||||
|
'100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
'x-uid':
|
||||||
|
'eo2xh4adfaz',
|
||||||
|
'x-async':
|
||||||
|
false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid':
|
||||||
|
'walnc8ivgzp',
|
||||||
|
'x-async':
|
||||||
|
false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid':
|
||||||
|
'3san45vkk32',
|
||||||
|
'x-async':
|
||||||
|
false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid':
|
||||||
|
'opiixrhoo0z',
|
||||||
|
'x-async':
|
||||||
|
false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
'5j12oi9pvf3': {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer':
|
||||||
|
'editForm:configureActions',
|
||||||
|
'x-component':
|
||||||
|
'ActionBar',
|
||||||
|
'x-component-props':
|
||||||
|
{
|
||||||
|
layout:
|
||||||
|
'one-column',
|
||||||
|
},
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
m9e7qxjys7o: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version:
|
||||||
|
'2.0',
|
||||||
|
title:
|
||||||
|
'{{ t("Submit") }}',
|
||||||
|
'x-action':
|
||||||
|
'submit',
|
||||||
|
'x-component':
|
||||||
|
'Action',
|
||||||
|
'x-use-component-props':
|
||||||
|
'useUpdateActionProps',
|
||||||
|
'x-toolbar':
|
||||||
|
'ActionSchemaToolbar',
|
||||||
|
'x-settings':
|
||||||
|
'actionSettings:updateSubmit',
|
||||||
|
'x-component-props':
|
||||||
|
{
|
||||||
|
type: 'primary',
|
||||||
|
htmlType:
|
||||||
|
'submit',
|
||||||
|
},
|
||||||
|
'x-action-settings':
|
||||||
|
{
|
||||||
|
triggerWorkflows:
|
||||||
|
[],
|
||||||
|
},
|
||||||
|
type: 'void',
|
||||||
|
'x-app-version':
|
||||||
|
'1.3.0-alpha',
|
||||||
|
'x-uid':
|
||||||
|
'5sc8g3215j4',
|
||||||
|
'x-async':
|
||||||
|
false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid':
|
||||||
|
'2v1zlgnh0lp',
|
||||||
|
'x-async':
|
||||||
|
false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid':
|
||||||
|
'u5viek4cakp',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'z38sbx5yocb',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'y0wdbxagcre',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'dn2spxvle3x',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'fsmyjuyc0mc',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'x27vohz57u1',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'uxbmlytgowr',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'p108r8s8pjh',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'detjnjixd9n',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'i9622c7n8nv',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'details:configureFields',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
cylu3xjywvu: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
z1eb85u2n4n: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
properties: {
|
||||||
|
select: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'string',
|
||||||
|
'x-toolbar': 'FormItemSchemaToolbar',
|
||||||
|
'x-settings': 'fieldSettings:FormItem',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'kanban.select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-app-version': '1.3.0-alpha',
|
||||||
|
'x-uid': 'mfz4c6l4ft9',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'lt4bp9emb4z',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'ny6e5q4fhww',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'yfunnpaf97c',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'pegqhin3s88',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'wpafritzh4d',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '2vjqy76fds6',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'avlvzb0yl0s',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'm5x3kz75nm2',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '6wb8grmdenj',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'uybfp4br16z',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '4dwpi8dug9d',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'x0dusy43fhl',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '6vpzr0nsxjs',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'f1eqli5bc07',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '4exwrzlac4i',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'edzxlnh6nx4',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 's95fpawrrle',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '57xhoz3sfzq',
|
||||||
|
'x-async': true,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { expect, test } from '@nocobase/test/e2e';
|
||||||
|
import { kanbanURL } from './templates';
|
||||||
|
|
||||||
|
test.describe('kanban: open popup via URL', () => {
|
||||||
|
test('basic', async ({ page, mockPage, mockRecords }) => {
|
||||||
|
const nocoPage = await mockPage(kanbanURL).waitForInit();
|
||||||
|
await mockRecords('kanban', [{ select: 'option1' }, { select: 'option2' }, { select: 'option3' }]);
|
||||||
|
await nocoPage.goto();
|
||||||
|
|
||||||
|
// 1. click a card to open a popup
|
||||||
|
await page.getByLabel('block-item-CollectionField-').filter({ hasText: 'option1' }).click();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('drawer-Action.Container-kanban-View record').getByLabel('block-item-CollectionField-'),
|
||||||
|
).toHaveText('Single select:Option1');
|
||||||
|
|
||||||
|
// 2. then reload the page, the popup should be opened
|
||||||
|
await page.reload();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('drawer-Action.Container-kanban-View record').getByLabel('block-item-CollectionField-'),
|
||||||
|
).toHaveText('Single select:Option1');
|
||||||
|
|
||||||
|
// 3. click the `Edit` button to open another popup
|
||||||
|
await page.getByLabel('action-Action-Edit-update-').click();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('drawer-Action.Container-kanban-Edit record').getByLabel('block-item-CollectionField-'),
|
||||||
|
).toHaveText('Single select:Option1');
|
||||||
|
|
||||||
|
// 4. then reload the page, the second popup should be opened
|
||||||
|
await page.reload();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('drawer-Action.Container-kanban-Edit record').getByLabel('block-item-CollectionField-'),
|
||||||
|
).toHaveText('Single select:Option1');
|
||||||
|
|
||||||
|
// 5. change the `Option` then close, the previous popup's content should be updated
|
||||||
|
await page.getByTestId('select-single').click();
|
||||||
|
await page.getByRole('option', { name: 'Option2' }).click();
|
||||||
|
await page.getByLabel('action-Action-Submit-submit-').click();
|
||||||
|
await page.mouse.move(300, 0);
|
||||||
|
|
||||||
|
await expect(page.getByLabel('block-item-CollectionField-kanban-details-kanban.select-Single select')).toHaveText(
|
||||||
|
'Single select:Option2',
|
||||||
|
);
|
||||||
|
|
||||||
|
// close the first popup
|
||||||
|
// await page.locator('.ant-drawer-mask').click();
|
||||||
|
// await expect(page.getByLabel('block-item-CollectionField-').filter({ hasText: 'option2' })).toHaveCount(2);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user