chore: show fallback change warning
This commit is contained in:
@@ -18,6 +18,9 @@ type ModalFooterProps = {
|
|||||||
extra?: React.ReactNode;
|
extra?: React.ReactNode;
|
||||||
form?: any;
|
form?: any;
|
||||||
description?: React.ReactNode;
|
description?: React.ReactNode;
|
||||||
|
styles?: {
|
||||||
|
wrapper?: React.CSSProperties;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
@@ -38,6 +41,7 @@ const ModalFooter: React.FC<ModalFooterProps> = ({
|
|||||||
htmlType = 'button',
|
htmlType = 'button',
|
||||||
style,
|
style,
|
||||||
showOkBtn = true,
|
showOkBtn = true,
|
||||||
|
styles,
|
||||||
description,
|
description,
|
||||||
extra,
|
extra,
|
||||||
showCancelBtn = true,
|
showCancelBtn = true,
|
||||||
@@ -45,7 +49,7 @@ const ModalFooter: React.FC<ModalFooterProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper style={{ ...styles?.wrapper }}>
|
||||||
<div>{description}</div>
|
<div>{description}</div>
|
||||||
<Space size={20} style={{ ...style }}>
|
<Space size={20} style={{ ...style }}>
|
||||||
{showCancelBtn && (
|
{showCancelBtn && (
|
||||||
|
|||||||
@@ -21,5 +21,7 @@ export default {
|
|||||||
'routes.form.metadata.releaseDate': 'Release Date',
|
'routes.form.metadata.releaseDate': 'Release Date',
|
||||||
'routes.form.metadata.languages': 'Languages',
|
'routes.form.metadata.languages': 'Languages',
|
||||||
'routes.form.metadata.icons': 'Icon',
|
'routes.form.metadata.icons': 'Icon',
|
||||||
'routes.form.metadata.uploadIcon': 'Upload Icon'
|
'routes.form.metadata.uploadIcon': 'Upload Icon',
|
||||||
|
'routes.form.fallback.warning':
|
||||||
|
'Changes to fallback route target take effect after one minute.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,5 +21,7 @@ export default {
|
|||||||
'routes.form.metadata.releaseDate': 'Release Date',
|
'routes.form.metadata.releaseDate': 'Release Date',
|
||||||
'routes.form.metadata.languages': 'Languages',
|
'routes.form.metadata.languages': 'Languages',
|
||||||
'routes.form.metadata.icons': 'Icon',
|
'routes.form.metadata.icons': 'Icon',
|
||||||
'routes.form.metadata.uploadIcon': 'Upload Icon'
|
'routes.form.metadata.uploadIcon': 'Upload Icon',
|
||||||
|
'routes.form.fallback.warning':
|
||||||
|
'Changes to fallback route target take effect after one minute.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,5 +21,7 @@ export default {
|
|||||||
'routes.form.metadata.releaseDate': 'Release Date',
|
'routes.form.metadata.releaseDate': 'Release Date',
|
||||||
'routes.form.metadata.languages': 'Languages',
|
'routes.form.metadata.languages': 'Languages',
|
||||||
'routes.form.metadata.icons': 'Icon',
|
'routes.form.metadata.icons': 'Icon',
|
||||||
'routes.form.metadata.uploadIcon': 'Upload Icon'
|
'routes.form.metadata.uploadIcon': 'Upload Icon',
|
||||||
|
'routes.form.fallback.warning':
|
||||||
|
'Changes to fallback route target take effect after one minute.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,5 +21,6 @@ export default {
|
|||||||
'routes.form.metadata.releaseDate': '发布日期',
|
'routes.form.metadata.releaseDate': '发布日期',
|
||||||
'routes.form.metadata.languages': '语言',
|
'routes.form.metadata.languages': '语言',
|
||||||
'routes.form.metadata.icons': '图标',
|
'routes.form.metadata.icons': '图标',
|
||||||
'routes.form.metadata.uploadIcon': '上传图标'
|
'routes.form.metadata.uploadIcon': '上传图标',
|
||||||
|
'routes.form.fallback.warning': 'Fallback 路由目标的更改将在一分钟后生效。'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import TooltipList from '@/components/tooltip-list';
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import TransferInner from '@/pages/_components/transfer';
|
import TransferInner from '@/pages/_components/transfer';
|
||||||
|
import { RouteItem } from '@/pages/model-routes/config/types';
|
||||||
import { queryUsersList } from '@/pages/users/apis';
|
import { queryUsersList } from '@/pages/users/apis';
|
||||||
import { DownOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
import { DownOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
@@ -26,7 +27,7 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { queryModelAccessUserList } from '../../apis';
|
import { queryModelAccessUserList } from '../../apis';
|
||||||
import { AccessControlFormData, ListItem } from '../../config/types';
|
import { AccessControlFormData } from '../../config/types';
|
||||||
|
|
||||||
type TransferKey = string | number | bigint;
|
type TransferKey = string | number | bigint;
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ const Label = styled.div`
|
|||||||
|
|
||||||
interface AccessControlFormProps {
|
interface AccessControlFormProps {
|
||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem | null;
|
currentData?: RouteItem | null;
|
||||||
onFinish: (values: AccessControlFormData) => void;
|
onFinish: (values: AccessControlFormData) => void;
|
||||||
onValuesChange?: (changedValues: any, allValues: any) => void;
|
onValuesChange?: (changedValues: any, allValues: any) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import AlertBlockInfo from '@/components/alert-info/block';
|
||||||
|
import ModalFooter from '@/components/modal-footer';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import FormDrawer from '@/pages/_components/form-drawer';
|
import FormDrawer from '@/pages/_components/form-drawer';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { FormData, RouteItem as ListItem } from '../config/types';
|
import { FormData, RouteItem as ListItem } from '../config/types';
|
||||||
|
|
||||||
import ModelRouteForm from '../forms';
|
import ModelRouteForm from '../forms';
|
||||||
|
|
||||||
type AddModalProps = {
|
type AddModalProps = {
|
||||||
@@ -21,6 +23,8 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
onOk,
|
onOk,
|
||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [isChanged, setIsChanged] = React.useState(false);
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
@@ -45,12 +49,37 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
width={600}
|
width={600}
|
||||||
|
footer={
|
||||||
|
<div style={{ paddingInline: 24, paddingBottom: 8 }}>
|
||||||
|
{isChanged && (
|
||||||
|
<AlertBlockInfo
|
||||||
|
type="warning"
|
||||||
|
contentStyle={{ paddingInline: 0 }}
|
||||||
|
message={intl.formatMessage({
|
||||||
|
id: 'routes.form.fallback.warning'
|
||||||
|
})}
|
||||||
|
></AlertBlockInfo>
|
||||||
|
)}
|
||||||
|
<ModalFooter
|
||||||
|
onOk={handleSubmit}
|
||||||
|
onCancel={onCancel}
|
||||||
|
styles={{
|
||||||
|
wrapper: {
|
||||||
|
paddingTop: 16
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
></ModalFooter>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<ModelRouteForm
|
<ModelRouteForm
|
||||||
ref={form}
|
ref={form}
|
||||||
action={action}
|
action={action}
|
||||||
currentData={currentData}
|
currentData={currentData}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFallbackChange={(changed: boolean) => {
|
||||||
|
setIsChanged(changed);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { PageActionType } from '@/config/types';
|
||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
|
||||||
|
interface FormContextProps {
|
||||||
|
onFallbackChange?: (changed: boolean) => void;
|
||||||
|
action?: PageActionType;
|
||||||
|
currentData?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormContext = createContext<FormContextProps>({});
|
||||||
|
|
||||||
|
export const useFormContext = () => {
|
||||||
|
const context = useContext(FormContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('useFormContext must be used within a FormProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FormContext;
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import FormContext from '../config/form-context';
|
||||||
import { FormData, RouteItem as ListItem } from '../config/types';
|
import { FormData, RouteItem as ListItem } from '../config/types';
|
||||||
import useEditTargets from '../hooks/use-edit-targets';
|
import useEditTargets from '../hooks/use-edit-targets';
|
||||||
import Basic from './basic';
|
import Basic from './basic';
|
||||||
@@ -24,6 +25,7 @@ interface ProviderFormProps {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem; // Used when action is EDIT
|
currentData?: ListItem; // Used when action is EDIT
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFallbackChange?: (changed: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABKeysMap = {
|
const TABKeysMap = {
|
||||||
@@ -34,7 +36,7 @@ const TABKeysMap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||||
const { action, currentData, onFinish } = props;
|
const { action, currentData, onFinish, onFallbackChange } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { getScrollElementScrollableHeight } = useWrapperContext();
|
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||||
const [activeKey, setActiveKey] = useState<string[]>([TABKeysMap.BASIC]);
|
const [activeKey, setActiveKey] = useState<string[]>([TABKeysMap.BASIC]);
|
||||||
@@ -175,29 +177,31 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
}}
|
}}
|
||||||
getScrollElementScrollableHeight={getScrollElementScrollableHeight}
|
getScrollElementScrollableHeight={getScrollElementScrollableHeight}
|
||||||
>
|
>
|
||||||
<Form
|
<FormContext.Provider value={{ onFallbackChange, action, currentData }}>
|
||||||
form={form}
|
<Form
|
||||||
onFinish={handleOnFinish}
|
form={form}
|
||||||
initialValues={{
|
onFinish={handleOnFinish}
|
||||||
categories: [],
|
initialValues={{
|
||||||
meta: {}
|
categories: [],
|
||||||
}}
|
meta: {}
|
||||||
>
|
}}
|
||||||
<Basic />
|
>
|
||||||
<CollapsePanel
|
<Basic />
|
||||||
activeKey={activeKey}
|
<CollapsePanel
|
||||||
accordion={false}
|
activeKey={activeKey}
|
||||||
onChange={handleOnCollapseChange}
|
accordion={false}
|
||||||
items={[
|
onChange={handleOnCollapseChange}
|
||||||
{
|
items={[
|
||||||
key: TABKeysMap.TARGETS,
|
{
|
||||||
label: intl.formatMessage({ id: 'routes.form.target.title' }),
|
key: TABKeysMap.TARGETS,
|
||||||
forceRender: true,
|
label: intl.formatMessage({ id: 'routes.form.target.title' }),
|
||||||
children: <Targets ref={targetsRef}></Targets>
|
forceRender: true,
|
||||||
}
|
children: <Targets ref={targetsRef}></Targets>
|
||||||
]}
|
}
|
||||||
></CollapsePanel>
|
]}
|
||||||
</Form>
|
></CollapsePanel>
|
||||||
|
</Form>
|
||||||
|
</FormContext.Provider>
|
||||||
</ScrollSpyTabs>
|
</ScrollSpyTabs>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,21 +1,31 @@
|
|||||||
import MetadataList from '@/components/metadata-list';
|
import MetadataList from '@/components/metadata-list';
|
||||||
import SealCascader from '@/components/seal-form/seal-cascader';
|
import SealCascader from '@/components/seal-form/seal-cascader';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import { PageAction } from '@/config';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
import {
|
||||||
|
forwardRef,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
|
import { useFormContext } from '../config/form-context';
|
||||||
import { FormData } from '../config/types';
|
import { FormData } from '../config/types';
|
||||||
import useTargetSourceModels from '../hooks/use-target-source-models';
|
import useTargetSourceModels from '../hooks/use-target-source-models';
|
||||||
|
|
||||||
const TargetsForm = forwardRef((props, ref) => {
|
const TargetsForm = forwardRef((props, ref) => {
|
||||||
|
const { onFallbackChange, action } = useFormContext();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
const { sourceModels, fetchSourceModels } = useTargetSourceModels();
|
const { sourceModels, fetchSourceModels } = useTargetSourceModels();
|
||||||
const [validTriggered, setValidTriggered] = useState<boolean>(false);
|
const [validTriggered, setValidTriggered] = useState<boolean>(false);
|
||||||
const form = Form.useFormInstance<FormData>();
|
const form = Form.useFormInstance<FormData>();
|
||||||
const targets = Form.useWatch('targets', form) || [];
|
const targets = Form.useWatch('targets', form) || [];
|
||||||
|
const fallbackCacheRef = useRef<{ value: any[] }>({ value: [] });
|
||||||
const [fallbackValues, setFallbackValues] = useState<{ value: any[] }>({
|
const [fallbackValues, setFallbackValues] = useState<{ value: any[] }>({
|
||||||
value: []
|
value: []
|
||||||
});
|
});
|
||||||
@@ -29,6 +39,7 @@ const TargetsForm = forwardRef((props, ref) => {
|
|||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
initFallbackValues: (values: { value: any[] }) => {
|
initFallbackValues: (values: { value: any[] }) => {
|
||||||
setFallbackValues(values);
|
setFallbackValues(values);
|
||||||
|
fallbackCacheRef.current = values;
|
||||||
},
|
},
|
||||||
initDataList: (
|
initDataList: (
|
||||||
list: {
|
list: {
|
||||||
@@ -105,6 +116,10 @@ const TargetsForm = forwardRef((props, ref) => {
|
|||||||
setFallbackValues({
|
setFallbackValues({
|
||||||
value: value
|
value: value
|
||||||
});
|
});
|
||||||
|
if (action === PageAction.EDIT) {
|
||||||
|
const isEqual = _.isEqual(fallbackCacheRef.current.value, value);
|
||||||
|
onFallbackChange?.(!isEqual);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnWeightChange = (value: any, index: number) => {
|
const handleOnWeightChange = (value: any, index: number) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user