Skip to content

Commit

Permalink
feat: support chagne the ui form to yaml editor
Browse files Browse the repository at this point in the history
  • Loading branch information
MrWindlike committed Oct 11, 2024
1 parent 10180f7 commit 054d418
Show file tree
Hide file tree
Showing 24 changed files with 610 additions and 150 deletions.
5 changes: 5 additions & 0 deletions packages/refine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
"@linaria/core": "^4.5.4",
"@linaria/react": "^4.5.4",
"@linaria/vite": "^4.5.4",
"@linaria/babel-preset": "^4.5.4",
"@linaria/logger": "^4.5.0",
"@linaria/utils": "^4.5.3",
"@rollup/pluginutils": "^4.2.1",
"@playwright/test": "^1.39.0",
"@refinedev/cli": "^2.9.0",
"@types/body-parser": "^1.19.5",
Expand All @@ -73,6 +77,7 @@
"eslint-plugin-react-refresh": "^0.3.4",
"jest": "^29",
"kubernetes-types": "^1.26.0",
"sass": "1.51.0",
"ts-jest": "^29",
"vite": "^4.5.2",
"vite-plugin-commonjs": "^0.10.0"
Expand Down
3 changes: 2 additions & 1 deletion packages/refine/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function App() {
renderForm: (formProps: YamlFormProps) => (
<YamlForm
{...formProps}
initialValues={DEPLOYMENT_INIT_VALUE}
initialValuesForCreate={DEPLOYMENT_INIT_VALUE}
isShowLayout={false}
/>
),
Expand Down Expand Up @@ -107,6 +107,7 @@ function App() {
useFormProps: {
mode: 'onTouched',
},
isDisabledChangeMode: true,
fields: () => [
{
path: ['metadata', 'name'],
Expand Down
4 changes: 2 additions & 2 deletions packages/refine/src/components/EditField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FormErrorAlert } from 'src/components/FormErrorAlert';
import { AccessControlAuth } from 'src/constants/auth';
import { ModalStyle } from 'src/hooks/useDeleteModal';
import { SmallModalStyle } from 'src/styles/modal';
import { useSubmitForm } from 'src/hooks/useSubmitForm';

const EditButtonStyle = css`
Expand Down Expand Up @@ -49,7 +49,7 @@ export function EditFieldModal(props: EditFieldModalProps) {

return (
<Modal
className={ModalStyle}
className={SmallModalStyle}
title={title || i18n.t('dovetail.edit')}
confirmLoading={submitting}
onOk={onSubmit}
Expand Down
170 changes: 119 additions & 51 deletions packages/refine/src/components/Form/FormModal.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,67 @@
import { CloseCircleFilled } from '@ant-design/icons';
import { usePopModal, Modal } from '@cloudtower/eagle';
import { usePopModal, usePushModal, Modal, SegmentControl, Typo } from '@cloudtower/eagle';
import { ExclamationErrorCircleFill16RedIcon } from '@cloudtower/icons-react';
import { css, cx } from '@linaria/core';
import { useResource } from '@refinedev/core';
import React, { useState, useContext, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import ConfigsContext from 'src/contexts/configs';
import { WarningButtonStyle } from 'src/styles/button';
import { FullscreenModalStyle } from 'src/styles/modal';
import { SmallModalStyle } from 'src/styles/modal';
import { RefineFormContent } from './RefineFormContent';
import useFieldsConfig from './useFieldsConfig';
import { useRefineForm } from './useRefineForm';
import { YamlForm, YamlFormProps } from './YamlForm';

const FormDescStyle = css`
margin-bottom: 16px;
`;

const MaxWidthModalStyle = css`
.ant-modal-header {
max-width: 648px;
width: 100%;
padding: 60px 0 32px 0 !important;
margin: auto;
}
.ant-modal-body {
display: flex;
flex-direction: column;
width: 100%;
padding: 0 4px !important;
margin: auto;
}
.ant-modal-footer {
.footer-content {
max-width: 648px;
width: 100%;
margin: auto !important;
}
}
.${FormDescStyle} {
max-width: 648px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
max-width: var(--max-modal-width, 1024px);
width: 100%;
margin-left: auto;
margin-right: auto;
`;
const ErrorStyle = css`
display: flex;
align-items: center;
gap: 4px;
`;
const TitleWrapperStyle = css`
display: flex;
justify-content: space-between;
align-items: center;
`;

export interface ConfirmModalProps {
onOk?: () => void;
}

function ConfirmModal({ onOk }: ConfirmModalProps) {
const { t } = useTranslation();
const popModal = usePopModal();

return (
<Modal
className={SmallModalStyle}
width="414px"
title={t('dovetail.edit_form')}
okButtonProps={{
type: 'primary',
className: WarningButtonStyle,
}}
onOk={() => {
onOk?.();
popModal();
}}
onCancel={popModal}
destroyOnClose
>
<div className={Typo.Label.l2_regular}>
{t('dovetail.exit_yaml_tip')}
</div>
</Modal>
);
}

export type FormModalProps = {
resource?: string;
Expand All @@ -59,6 +70,11 @@ export type FormModalProps = {
renderForm?: (props: YamlFormProps) => React.ReactNode;
};

enum Mode {
Form = 'form',
Yaml = 'yaml'
}

export function FormModal(props: FormModalProps) {
const { resource: resourceFromProps, id, renderForm } = props;
const { i18n } = useTranslation();
Expand All @@ -69,23 +85,46 @@ export function FormModal(props: FormModalProps) {
onClick?: () => void;
}>({});
const [isError, setIsError] = useState<boolean>(false);
const [mode, setMode] = useState<Mode>(Mode.Form);
const isYamlMode = mode === Mode.Yaml;
const popModal = usePopModal();

const pushModal = usePushModal();
const config = configs[resourceFromProps || resource?.name || ''];
const isDisabledChangeMode = config.formConfig?.isDisabledChangeMode;
const okText = i18n.t(id ? 'dovetail.save' : 'dovetail.create');
const action = id ? 'edit' : 'create';
const fieldsConfig = useFieldsConfig(config, id);
const refineFormResult = useRefineForm({
config,
id,
refineProps: {
onMutationSuccess: () => {
popModal();
},
redirect: false,
...config.formConfig?.refineCoreProps,
},
});
const yamlFormProps: YamlFormProps = useMemo(
() => ({
...props.formProps,
transformInitValues: config.formConfig?.transformInitValues,
transformApplyValues: config.formConfig?.transformApplyValues,
initialValues: props.formProps?.initialValues || config?.initValue,
initialValuesForCreate: isYamlMode ?
refineFormResult.formResult.getValues() :
(props.formProps?.initialValuesForCreate || config?.initValue),
initialValuesForEdit: isYamlMode ?
refineFormResult.formResult.getValues() : undefined,
id,
action,
isShowLayout: false,
useFormProps: {
redirect: false,
},
rules: isYamlMode ? fieldsConfig?.map((config) => ({
path: config.path,
validators: config.validators,
})) : undefined,
onSaveButtonPropsChange: setYamlSaveButtonProps,
onErrorsChange(errors) {
setIsError(!!errors.length);
Expand All @@ -99,30 +138,21 @@ export function FormModal(props: FormModalProps) {
config?.initValue,
id,
action,
refineFormResult.formResult,
isYamlMode,
fieldsConfig,
popModal,
]
);

const refineFormResult = useRefineForm({
config,
id,
refineProps: {
onMutationSuccess: () => {
popModal();
},
redirect: false,
...config.formConfig?.refineCoreProps,
},
});

const isYamlForm = !config.formConfig?.fields;

const formEle = (() => {
if (renderForm) {
return renderForm(yamlFormProps);
}

if (isYamlForm) return <YamlForm {...yamlFormProps} />;
if (isYamlForm || isYamlMode) return <YamlForm {...yamlFormProps} />;

return (
<RefineFormContent
Expand All @@ -134,7 +164,7 @@ export function FormModal(props: FormModalProps) {
);
})();

const saveButtonProps = isYamlForm
const saveButtonProps = isYamlForm || isYamlMode
? yamlSaveButtonProps
: refineFormResult.formResult.saveButtonProps;

Expand All @@ -149,6 +179,20 @@ export function FormModal(props: FormModalProps) {
},
[saveButtonProps]
);
const onChangeMode = useCallback((value: Mode) => {
if (value === Mode.Form) {
pushModal<'ConfirmModal'>({
component: ConfirmModal,
props: {
onOk: () => {
setMode(Mode.Form);
},
},
});
} else {
setMode(value);
}
}, [pushModal]);

const errorText = (() => {
if (!!refineFormResult.responseErrorMsg || isError) {
Expand Down Expand Up @@ -180,9 +224,33 @@ export function FormModal(props: FormModalProps) {

return (
<Modal
className={cx(FullscreenModalStyle, isYamlForm ? '' : MaxWidthModalStyle)}
className={cx(
FullscreenModalStyle,
)}
style={{ '--max-modal-width': isYamlForm || !isDisabledChangeMode ? '1024px' : '648px' } as React.CSSProperties}
width="calc(100vw - 16px)"
title={title}
title={(
<div className={TitleWrapperStyle}>
<span>{title}</span>
{
!(isYamlForm || isDisabledChangeMode) ? (
<SegmentControl
value={mode}
options={[{
value: Mode.Form,
label: i18n.t('dovetail.form')
}, {
value: Mode.Yaml,
label: i18n.t('dovetail.yaml')
}]}
onChange={(val) => {
onChangeMode(val as Mode);
}}
/>
) : null
}
</div>
)}
error={
errorText ? (
<div className={ErrorStyle}>
Expand Down
25 changes: 4 additions & 21 deletions packages/refine/src/components/Form/RefineFormContent.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Fields, Form, Space, Typo } from '@cloudtower/eagle';
import { css, cx } from '@linaria/core';
import { useList, useShow } from '@refinedev/core';
import { UseFormReturnType } from '@refinedev/react-hook-form';
import React from 'react';
import { Controller } from 'react-hook-form';
import { ResourceModel } from '../../models';
import { ResourceConfig } from '../../types';
import { ResourceModel } from 'src/models';
import { ResourceConfig } from 'src/types';
import { FormErrorAlert } from '../FormErrorAlert';
import useFieldsConfig from './useFieldsConfig';

type Props<Model extends ResourceModel> = {
config?: ResourceConfig<Model>;
Expand All @@ -19,24 +19,8 @@ export const RefineFormContent = <Model extends ResourceModel>(props: Props<Mode
const { config, formResult, resourceId, errorMsg } = props;
const { control, getValues } = formResult;
const action = resourceId ? 'edit' : 'create';
const listQuery = useList<Model>({
resource: config?.name,
meta: { resourceBasePath: config?.basePath, kind: config?.kind },
pagination: {
mode: 'off',
},
});
const showQuery = useShow<Model>({
resource: config?.name,
meta: { resourceBasePath: config?.basePath, kind: config?.kind },
id: resourceId,
});

const formFieldsConfig = config?.formConfig?.fields?.({
record: showQuery.queryResult.data?.data,
records: listQuery.data?.data || [],
action,
});
const formFieldsConfig = useFieldsConfig(config, resourceId);

const fields = formFieldsConfig?.map(c => {
return (
Expand Down Expand Up @@ -136,7 +120,6 @@ export const RefineFormContent = <Model extends ResourceModel>(props: Props<Mode
size={16}
className={css`
flex-basis: 58%;
max-width: 648px;
width: 100%;
margin: 0 auto;
`}
Expand Down
Loading

0 comments on commit 054d418

Please sign in to comment.