@dovetail-v2/refine 0.3.33 → 0.3.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,7 @@ export interface ConfirmModalProps {
17
17
  }
18
18
  export type FormModalProps = {
19
19
  id?: string;
20
- resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'apiVersion' | 'basePath' | 'formConfig'>;
20
+ resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'apiVersion' | 'basePath' | 'formConfig' | 'dataProviderName'>;
21
21
  yamlFormProps?: YamlFormProps;
22
22
  options?: {
23
23
  initialValues?: Record<string, unknown>;
@@ -4,7 +4,7 @@ import { ResourceConfig } from 'src/types';
4
4
  import { YamlFormProps } from './YamlForm';
5
5
  type RawYamlFormModalProps = {
6
6
  id?: string;
7
- resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'apiVersion' | 'basePath' | 'formConfig'>;
7
+ resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'apiVersion' | 'basePath' | 'formConfig' | 'dataProviderName'>;
8
8
  yamlFormProps?: YamlFormProps;
9
9
  onSuccess?: (data: UpdateResponse<BaseRecord> | CreateResponse<BaseRecord>) => void;
10
10
  };
@@ -7,7 +7,7 @@ import { YamlFormProps } from './YamlForm';
7
7
  interface RefineFormContainerProps {
8
8
  id: string;
9
9
  isYamlMode: boolean;
10
- resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'basePath' | 'formConfig'>;
10
+ resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'basePath' | 'formConfig' | 'dataProviderName'>;
11
11
  step: number;
12
12
  formConfig: (RefineFormConfig & CommonFormConfig) | undefined;
13
13
  customYamlFormProps?: YamlFormProps;
@@ -1,7 +1,6 @@
1
1
  import { BaseRecord, HttpError, UseFormProps as UseFormCoreProps, UseFormReturnType as UseFormReturnTypeCore } from '@refinedev/core';
2
2
  import React from 'react';
3
- import { DefaultValues } from 'react-hook-form';
4
- import { UseFormProps as UseHookFormProps, UseFormReturn, FieldValues } from 'react-hook-form';
3
+ import { DefaultValues, UseFormProps as UseHookFormProps, UseFormReturn, FieldValues } from 'react-hook-form';
5
4
  export type UseFormReturnType<TQueryFnData extends BaseRecord = BaseRecord, TError extends HttpError = HttpError, TVariables extends FieldValues = FieldValues, TContext extends object = object, TData extends BaseRecord = TQueryFnData, TResponse extends BaseRecord = TData, TResponseError extends HttpError = TError> = UseFormReturn<TVariables, TContext> & {
6
5
  transformedInitValues: TVariables | undefined;
7
6
  refineCore: UseFormReturnTypeCore<TQueryFnData, TError, TVariables, TData, TResponse, TResponseError>;
@@ -9,7 +9,7 @@ interface UseRefineFormOptions {
9
9
  export declare const useRefineForm: (props: {
10
10
  formConfig?: RefineFormConfig & CommonFormConfig;
11
11
  id?: string;
12
- resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'formConfig'>;
12
+ resourceConfig: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'formConfig' | 'dataProviderName'>;
13
13
  refineProps?: UseFormProps['refineCoreProps'];
14
14
  options?: UseRefineFormOptions;
15
15
  }) => {
@@ -0,0 +1,48 @@
1
+ import { Unstructured } from 'k8s-api-provider';
2
+ export type Retry409MetaOptions = {
3
+ /** 编辑表单打开时捕获的初始版本;通常由本 hook 自动捕获,外部一般不需要手动传入。 */
4
+ initialResource?: Unstructured;
5
+ /** provider 判断无法安全重试时抛出的本地化错误文案。 */
6
+ conflictMessage?: string;
7
+ };
8
+ type MutationMetaWith409Retry = Record<string, unknown> & {
9
+ /** 传给 k8s-api-provider 的 409 恢复内部参数。 */
10
+ resourceVersionConflictRetry?: Retry409MetaOptions;
11
+ };
12
+ type Use409RetryOptions = {
13
+ /** 当前表单动作;只有 edit 动作会启用 409 重试,create 会自动移除重试 meta。 */
14
+ action?: string;
15
+ /** 当前表单使用的数据源名称,用于找到对应 GlobalStore 并还原 raw YAML。 */
16
+ dataProviderName?: string;
17
+ /** 当前编辑资源的 id;部分调用链 action 不稳定时,用 id 作为 edit 场景的兜底判断。 */
18
+ id?: unknown;
19
+ /** 调用方原本要传给 refine useFormCore 的 mutationMeta,本 hook 会保留其它字段并覆盖内部 409 重试参数。 */
20
+ mutationMeta?: MutationMetaWith409Retry;
21
+ };
22
+ type Use409RetryResult = {
23
+ /** queryResult 拿到资源后调用,用来捕获打开编辑表单时的初始版本。 */
24
+ captureInitialResource: (resource?: Unstructured) => void;
25
+ /** 已合并 409 重试参数的 mutationMeta,应直接传给 refine useFormCore。 */
26
+ mutationMeta: Record<string, unknown>;
27
+ };
28
+ /**
29
+ * 为 D2 编辑表单接入 Kubernetes PUT 409 自动恢复能力。
30
+ *
31
+ * 背景:Kubernetes PUT 保存要求用户保存版本里的 `metadata.resourceVersion`
32
+ * 与服务端版本一致。如果用户编辑期间只有 status、managedFields 等运行时字段发生变化,
33
+ * D2 可以把打开表单时的初始版本交给 k8s-api-provider,由 provider 拉取服务端版本、
34
+ * 判断是否安全,并在安全时替换用户保存版本的 resourceVersion 后重试一次。
35
+ *
36
+ * 用法:FORM/YAML 表单在创建 refine useFormCore 前调用本 hook,把返回的 `mutationMeta`
37
+ * 传给 useFormCore;queryResult 首次拿到资源后调用 `captureInitialResource(data)`。
38
+ * D2 只负责捕获初始版本和传递本地化错误文案,比较、拉取服务端版本和重试都内聚在 provider。
39
+ *
40
+ * @param options - 409 重试接入配置。
41
+ * @param options.action - 当前表单动作;只有 edit 动作会启用 409 重试。
42
+ * @param options.dataProviderName - 当前表单使用的数据源名称,用于选择对应 GlobalStore。
43
+ * @param options.id - 当前编辑资源的 id,用作 edit 场景的兜底判断。
44
+ * @param options.mutationMeta - 调用方原本的 mutationMeta,本 hook 会保留其它字段并覆盖内部 409 重试参数。
45
+ * @returns 用于捕获初始版本的方法,以及应传给 useFormCore 的 mutationMeta。
46
+ */
47
+ export declare function use409Retry({ action, dataProviderName, id, mutationMeta, }: Use409RetryOptions): Use409RetryResult;
48
+ export {};
@@ -2,7 +2,7 @@ import { CreateResponse, UpdateResponse, BaseRecord } from '@refinedev/core';
2
2
  import { ResourceConfig } from 'src/types';
3
3
  interface OpenFormOptions {
4
4
  id?: string;
5
- resourceConfig?: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'apiVersion' | 'basePath' | 'formConfig'>;
5
+ resourceConfig?: Pick<ResourceConfig, 'name' | 'displayName' | 'kind' | 'initValue' | 'apiVersion' | 'basePath' | 'formConfig' | 'dataProviderName'>;
6
6
  resourceName?: string;
7
7
  initialValues?: Record<string, unknown>;
8
8
  customOptions?: Record<string, unknown>;
package/dist/i18n.d.ts CHANGED
@@ -187,6 +187,7 @@ export declare const resources: {
187
187
  data_expired: string;
188
188
  data_expired_body: string;
189
189
  data_expired_note: string;
190
+ resource_version_conflict: string;
190
191
  abandon_edit: string;
191
192
  exit_yaml_tip: string;
192
193
  value_optional: string;
@@ -473,6 +474,7 @@ export declare const resources: {
473
474
  data_expired: string;
474
475
  data_expired_body: string;
475
476
  data_expired_note: string;
477
+ resource_version_conflict: string;
476
478
  abandon_edit: string;
477
479
  exit_yaml_tip: string;
478
480
  form: string;
@@ -184,6 +184,7 @@ declare const _default: {
184
184
  data_expired: string;
185
185
  data_expired_body: string;
186
186
  data_expired_note: string;
187
+ resource_version_conflict: string;
187
188
  abandon_edit: string;
188
189
  exit_yaml_tip: string;
189
190
  value_optional: string;
@@ -186,6 +186,7 @@ declare const _default: {
186
186
  data_expired: string;
187
187
  data_expired_body: string;
188
188
  data_expired_note: string;
189
+ resource_version_conflict: string;
189
190
  abandon_edit: string;
190
191
  exit_yaml_tip: string;
191
192
  form: string;
package/dist/refine.cjs CHANGED
@@ -641,6 +641,7 @@ const edit_form$1 = "Edit form";
641
641
  const data_expired$1 = "Data expired";
642
642
  const data_expired_body$1 = "The data in this form is no longer the latest version. To avoid saving errors, please discard this edit and reopen the form to edit again.";
643
643
  const data_expired_note$1 = "Your current entries will not be saved.";
644
+ const resource_version_conflict$1 = "The data in this form is no longer the latest version. Please discard this edit and reopen the form to edit again.";
644
645
  const abandon_edit$1 = "Discard edit";
645
646
  const exit_yaml_tip$1 = "If you go back to the form, any changes made to the YAML file will be lost.";
646
647
  const value_optional$1 = "Value (optional)";
@@ -922,6 +923,7 @@ const dovetail$1 = {
922
923
  data_expired: data_expired$1,
923
924
  data_expired_body: data_expired_body$1,
924
925
  data_expired_note: data_expired_note$1,
926
+ resource_version_conflict: resource_version_conflict$1,
925
927
  abandon_edit: abandon_edit$1,
926
928
  exit_yaml_tip: exit_yaml_tip$1,
927
929
  value_optional: value_optional$1,
@@ -1205,6 +1207,7 @@ const edit_form = "编辑表单";
1205
1207
  const data_expired = "数据已过期";
1206
1208
  const data_expired_body = "当前表单中的数据已不是最新版。为避免保存失败,请放弃本次编辑,并重新打开表单进行编辑。";
1207
1209
  const data_expired_note = "当前已填写内容将不会保留。";
1210
+ const resource_version_conflict = "当前表单中的数据已不是最新版,请放弃本次编辑,并重新打开表单进行编辑。";
1208
1211
  const abandon_edit = "放弃编辑";
1209
1212
  const exit_yaml_tip = "返回编辑表单,不会保留对 YAML 文件做出的所有更改。";
1210
1213
  const form = "表单";
@@ -1485,6 +1488,7 @@ const dovetail = {
1485
1488
  data_expired,
1486
1489
  data_expired_body,
1487
1490
  data_expired_note,
1491
+ resource_version_conflict,
1488
1492
  abandon_edit,
1489
1493
  exit_yaml_tip,
1490
1494
  form,
@@ -10708,26 +10712,6 @@ function usePathMap(options) {
10708
10712
  transformApplyValues
10709
10713
  };
10710
10714
  }
10711
- const useResourceVersionCheck = ({
10712
- queryResult
10713
- }) => {
10714
- var _a, _b, _c;
10715
- const initialResourceVersionRef = React.useRef();
10716
- const [isExpired, setIsExpired] = React.useState(false);
10717
- const currentResourceVersion = (_c = (_b = (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data) == null ? void 0 : _b.metadata) == null ? void 0 : _c.resourceVersion;
10718
- React.useEffect(() => {
10719
- if (!currentResourceVersion)
10720
- return;
10721
- if (!initialResourceVersionRef.current) {
10722
- initialResourceVersionRef.current = currentResourceVersion;
10723
- return;
10724
- }
10725
- if (currentResourceVersion !== initialResourceVersionRef.current) {
10726
- setIsExpired(true);
10727
- }
10728
- }, [currentResourceVersion]);
10729
- return isExpired;
10730
- };
10731
10715
  function getInitialValues(resourceConfig) {
10732
10716
  return resourceConfig.initValue || {
10733
10717
  apiVersion: resourceConfig.apiVersion,
@@ -10736,42 +10720,6 @@ function getInitialValues(resourceConfig) {
10736
10720
  spec: {}
10737
10721
  };
10738
10722
  }
10739
- const button_1v659kh = "";
10740
- const WarningButtonStyle = "wwyz7ti";
10741
- const DataExpiredModal_eazxh6 = "";
10742
- const NoteStyle = "n609wlp";
10743
- function DataExpiredModal({
10744
- onAbandon
10745
- }) {
10746
- const {
10747
- t: t2
10748
- } = common.useTranslation();
10749
- return /* @__PURE__ */ common.jsxRuntimeExports.jsxs(eagle.SmallDialog, {
10750
- title: t2("dovetail.data_expired"),
10751
- closable: false,
10752
- maskClosable: false,
10753
- cancelButtonProps: {
10754
- style: {
10755
- display: "none"
10756
- }
10757
- },
10758
- okText: t2("dovetail.abandon_edit"),
10759
- okButtonProps: {
10760
- className: WarningButtonStyle
10761
- },
10762
- onOk: (popModal) => {
10763
- popModal();
10764
- onAbandon();
10765
- },
10766
- children: [/* @__PURE__ */ common.jsxRuntimeExports.jsx("div", {
10767
- className: eagle.Typo.Label.l2_regular,
10768
- children: t2("dovetail.data_expired_body")
10769
- }), /* @__PURE__ */ common.jsxRuntimeExports.jsx("div", {
10770
- className: `${eagle.Typo.Label.l2_regular} ${NoteStyle}`,
10771
- children: t2("dovetail.data_expired_note")
10772
- })]
10773
- });
10774
- }
10775
10723
  const index_az4wrx = "";
10776
10724
  const WrapperStyle$5 = "w1akirqw";
10777
10725
  const TitleStyle$2 = "t30srnq";
@@ -11101,6 +11049,52 @@ function copyToClipboard(text) {
11101
11049
  document.execCommand("copy");
11102
11050
  document.body.removeChild(input);
11103
11051
  }
11052
+ const useGlobalStore = (name2 = "default") => {
11053
+ const globalStores = React.useContext(GlobalStoreContext);
11054
+ return globalStores[name2];
11055
+ };
11056
+ function use409Retry({
11057
+ action,
11058
+ dataProviderName,
11059
+ id,
11060
+ mutationMeta
11061
+ }) {
11062
+ const { t: t2 } = common.useTranslation();
11063
+ const globalStore = useGlobalStore(dataProviderName);
11064
+ const initialResourceRef = React.useRef();
11065
+ const isEditAction = action === "edit" || !!id;
11066
+ const captureInitialResource = React.useCallback((resource) => {
11067
+ var _a;
11068
+ if (!isEditAction || initialResourceRef.current || !resource) {
11069
+ return;
11070
+ }
11071
+ const rawResource = (_a = globalStore == null ? void 0 : globalStore.restoreItem) == null ? void 0 : _a.call(globalStore, resource);
11072
+ if (!rawResource) {
11073
+ return;
11074
+ }
11075
+ initialResourceRef.current = lodashEs.cloneDeep(rawResource);
11076
+ }, [globalStore, isEditAction]);
11077
+ const retryMutationMeta = React.useMemo(() => {
11078
+ const restMutationMeta = lodashEs.omit(mutationMeta, "resourceVersionConflictRetry");
11079
+ if (!isEditAction) {
11080
+ return restMutationMeta;
11081
+ }
11082
+ return {
11083
+ ...restMutationMeta,
11084
+ resourceVersionConflictRetry: {
11085
+ // refine 的 mutationMeta 在 hook 创建时就会固定;用 getter 让 provider 在保存瞬间读取最新的初始版本。
11086
+ get initialResource() {
11087
+ return initialResourceRef.current;
11088
+ },
11089
+ conflictMessage: t2("dovetail.resource_version_conflict")
11090
+ }
11091
+ };
11092
+ }, [isEditAction, mutationMeta, t2]);
11093
+ return {
11094
+ captureInitialResource,
11095
+ mutationMeta: retryMutationMeta
11096
+ };
11097
+ }
11104
11098
  function useK8sYamlEditor() {
11105
11099
  const foldSymbol = React.useCallback(function(editor, symbol) {
11106
11100
  const model = editor.getModel();
@@ -11211,10 +11205,6 @@ function generateYamlBySchema(defaultValue, schema) {
11211
11205
  const content = yaml$2.dump(merged);
11212
11206
  return content.replace(/(')(#.+?)(')/g, "$2").replace(/( +)(#)/g, "$2$1");
11213
11207
  }
11214
- const useGlobalStore = (name2 = "default") => {
11215
- const globalStores = React.useContext(GlobalStoreContext);
11216
- return globalStores[name2];
11217
- };
11218
11208
  const useYamlForm = ({
11219
11209
  action: actionFromProps,
11220
11210
  resource,
@@ -11252,7 +11242,7 @@ const useYamlForm = ({
11252
11242
  onSubmitAbort,
11253
11243
  rules
11254
11244
  } = {}) => {
11255
- var _a;
11245
+ var _a, _b;
11256
11246
  const editor = React.useRef(null);
11257
11247
  const { t: t2 } = common.useTranslation();
11258
11248
  const [isYamlValid, setIsYamlValid] = React.useState(true);
@@ -11263,7 +11253,17 @@ const useYamlForm = ({
11263
11253
  const [beforeSubmitErrors, setBeforeSubmitErrors] = React.useState([]);
11264
11254
  const [errorResponseBody, setErrorResponseBody] = React.useState(null);
11265
11255
  const useResourceResult = core.useResource();
11266
- const globalStore = useGlobalStore();
11256
+ const globalStore = useGlobalStore(dataProviderName);
11257
+ const action = React.useMemo(
11258
+ () => actionFromProps || useResourceResult.action,
11259
+ [actionFromProps, useResourceResult.action]
11260
+ );
11261
+ const { captureInitialResource, mutationMeta: finalMutationMeta } = use409Retry({
11262
+ action,
11263
+ dataProviderName,
11264
+ id: idFromProps,
11265
+ mutationMeta
11266
+ });
11267
11267
  const {
11268
11268
  schema,
11269
11269
  loading: isLoadingSchema,
@@ -11300,7 +11300,7 @@ const useYamlForm = ({
11300
11300
  meta: core.pickNotDeprecated(meta, metaData),
11301
11301
  metaData: core.pickNotDeprecated(meta, metaData),
11302
11302
  queryMeta,
11303
- mutationMeta,
11303
+ mutationMeta: finalMutationMeta,
11304
11304
  liveMode,
11305
11305
  liveParams,
11306
11306
  mutationMode,
@@ -11315,12 +11315,12 @@ const useYamlForm = ({
11315
11315
  overtimeOptions
11316
11316
  });
11317
11317
  const { formLoading, onFinish, queryResult } = useFormCoreResult;
11318
+ React.useEffect(() => {
11319
+ var _a2;
11320
+ captureInitialResource((_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data);
11321
+ }, [captureInitialResource, (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data]);
11318
11322
  const { warnWhenUnsavedChanges: warnWhenUnsavedChangesRefine, setWarnWhen } = core.useWarnAboutChange();
11319
11323
  const warnWhenUnsavedChanges = warnWhenUnsavedChangesProp ?? warnWhenUnsavedChangesRefine;
11320
- const action = React.useMemo(
11321
- () => actionFromProps || useResourceResult.action,
11322
- [actionFromProps, useResourceResult.action]
11323
- );
11324
11324
  const initialValues = React.useMemo(() => {
11325
11325
  var _a2;
11326
11326
  const initialValues2 = (action === "edit" && ((_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data) ? initialValuesForEdit || (globalStore == null ? void 0 : globalStore.restoreItem(queryResult.data.data)) : initialValuesForCreate) || {};
@@ -11363,10 +11363,10 @@ const useYamlForm = ({
11363
11363
  }
11364
11364
  },
11365
11365
  onEditorCreate(editorInstance) {
11366
- var _a3, _b;
11366
+ var _a3, _b2;
11367
11367
  const editorValue = yaml$2.dump(initialValues);
11368
11368
  (_a3 = editor.current) == null ? void 0 : _a3.setEditorValue(editorValue);
11369
- (_b = editor.current) == null ? void 0 : _b.setValue(editorValue);
11369
+ (_b2 = editor.current) == null ? void 0 : _b2.setValue(editorValue);
11370
11370
  if (action === "edit") {
11371
11371
  fold2(editorInstance);
11372
11372
  }
@@ -11379,7 +11379,7 @@ const useYamlForm = ({
11379
11379
  initialValues,
11380
11380
  schemas,
11381
11381
  resource,
11382
- (_a = useResourceResult.resource) == null ? void 0 : _a.name,
11382
+ (_b = useResourceResult.resource) == null ? void 0 : _b.name,
11383
11383
  action,
11384
11384
  finalErrors,
11385
11385
  fold2
@@ -11419,7 +11419,7 @@ const useYamlForm = ({
11419
11419
  formProps: {
11420
11420
  ...formSF.formProps,
11421
11421
  onFinish: async (values) => {
11422
- var _a2, _b;
11422
+ var _a2, _b2;
11423
11423
  setBeforeSubmitErrors([]);
11424
11424
  onSubmitStart == null ? void 0 : onSubmitStart();
11425
11425
  const errors = [
@@ -11439,7 +11439,7 @@ const useYamlForm = ({
11439
11439
  return;
11440
11440
  }
11441
11441
  try {
11442
- const objectValues = editor.current ? yaml$2.load(((_b = editor.current) == null ? void 0 : _b.getEditorValue()) || "") : values;
11442
+ const objectValues = editor.current ? yaml$2.load(((_b2 = editor.current) == null ? void 0 : _b2.getEditorValue()) || "") : values;
11443
11443
  let finalValues = (transformApplyValues == null ? void 0 : transformApplyValues(objectValues)) || objectValues;
11444
11444
  if (beforeSubmit) {
11445
11445
  try {
@@ -11541,6 +11541,7 @@ function YamlForm(props) {
11541
11541
  id,
11542
11542
  action: actionFromProps,
11543
11543
  resource: resource == null ? void 0 : resource.name,
11544
+ dataProviderName: resourceConfig.dataProviderName,
11544
11545
  editorOptions: {
11545
11546
  isSkipSchema: schemaStrategy === "None"
11546
11547
  /* None */
@@ -11663,31 +11664,6 @@ function YamlFormContainer({
11663
11664
  onSaveButtonPropsChange
11664
11665
  }) {
11665
11666
  const action = id ? "edit" : "create";
11666
- const pushModal = eagle.usePushModal();
11667
- const popModal = eagle.usePopModal();
11668
- const hasShownExpiredRef = React.useRef(false);
11669
- const [isSubmitting, setIsSubmitting] = React.useState(false);
11670
- const queryResult = core.useOne({
11671
- resource: resourceConfig.name,
11672
- id,
11673
- liveMode: id ? "auto" : "off",
11674
- queryOptions: { enabled: !!id }
11675
- });
11676
- const isExpired = useResourceVersionCheck({ queryResult });
11677
- React.useEffect(() => {
11678
- if (!isExpired || isSubmitting || hasShownExpiredRef.current) {
11679
- return;
11680
- }
11681
- hasShownExpiredRef.current = true;
11682
- pushModal({
11683
- component: DataExpiredModal,
11684
- props: {
11685
- onAbandon: () => {
11686
- popModal();
11687
- }
11688
- }
11689
- });
11690
- }, [isExpired, isSubmitting, pushModal, popModal]);
11691
11667
  const { transformInitValues, transformApplyValues } = usePathMap({
11692
11668
  pathMap: formConfig == null ? void 0 : formConfig.pathMap,
11693
11669
  transformInitValues: formConfig == null ? void 0 : formConfig.transformInitValues,
@@ -11707,13 +11683,7 @@ function YamlFormContainer({
11707
11683
  action,
11708
11684
  isShowLayout: false,
11709
11685
  useFormProps: {
11710
- redirect: false,
11711
- onSubmitStart: () => {
11712
- setIsSubmitting(true);
11713
- },
11714
- onSubmitAbort: () => {
11715
- setIsSubmitting(false);
11716
- }
11686
+ redirect: false
11717
11687
  },
11718
11688
  rules: void 0,
11719
11689
  onSaveButtonPropsChange,
@@ -16068,6 +16038,8 @@ function ResourceShow(props) {
16068
16038
  }
16069
16039
  );
16070
16040
  }
16041
+ const button_1v659kh = "";
16042
+ const WarningButtonStyle = "wwyz7ti";
16071
16043
  const modal_1eijuvm = "";
16072
16044
  const SmallModalStyle = "s1nc293e";
16073
16045
  function FormModeSegmentControl({
@@ -16903,9 +16875,16 @@ const useForm = ({
16903
16875
  onSubmitAbort,
16904
16876
  ...rest
16905
16877
  } = {}) => {
16878
+ var _a;
16906
16879
  const { options } = core.useRefineContext();
16907
16880
  const disableServerSideValidation = (options == null ? void 0 : options.disableServerSideValidation) || disableServerSideValidationProp;
16908
16881
  const translate = core.useTranslate();
16882
+ const { captureInitialResource, mutationMeta } = use409Retry({
16883
+ action: refineCoreProps == null ? void 0 : refineCoreProps.action,
16884
+ dataProviderName: refineCoreProps == null ? void 0 : refineCoreProps.dataProviderName,
16885
+ id: refineCoreProps == null ? void 0 : refineCoreProps.id,
16886
+ mutationMeta: refineCoreProps == null ? void 0 : refineCoreProps.mutationMeta
16887
+ });
16909
16888
  const { warnWhenUnsavedChanges: warnWhenUnsavedChangesRefine, setWarnWhen } = core.useWarnAboutChange();
16910
16889
  const warnWhenUnsavedChanges = warnWhenUnsavedChangesProp ?? warnWhenUnsavedChangesRefine;
16911
16890
  const useHookFormResult = reactHookForm.useForm({
@@ -16925,10 +16904,11 @@ const useForm = ({
16925
16904
  } = useHookFormResult;
16926
16905
  const useFormCoreResult = core.useForm({
16927
16906
  ...refineCoreProps,
16907
+ mutationMeta,
16928
16908
  onMutationError: (error, _variables, _context) => {
16929
- var _a, _b;
16909
+ var _a2, _b;
16930
16910
  if (disableServerSideValidation) {
16931
- (_a = refineCoreProps == null ? void 0 : refineCoreProps.onMutationError) == null ? void 0 : _a.call(refineCoreProps, error, _variables, _context);
16911
+ (_a2 = refineCoreProps == null ? void 0 : refineCoreProps.onMutationError) == null ? void 0 : _a2.call(refineCoreProps, error, _variables, _context);
16932
16912
  return;
16933
16913
  }
16934
16914
  const errors = error == null ? void 0 : error.errors;
@@ -16961,10 +16941,14 @@ const useForm = ({
16961
16941
  });
16962
16942
  const { queryResult, onFinish, formLoading, onFinishAutoSave } = useFormCoreResult;
16963
16943
  React.useEffect(() => {
16964
- var _a;
16944
+ var _a2;
16945
+ captureInitialResource((_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data);
16946
+ }, [captureInitialResource, (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data]);
16947
+ React.useEffect(() => {
16948
+ var _a2;
16965
16949
  if (formState.isDirty)
16966
16950
  return;
16967
- const data2 = (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data;
16951
+ const data2 = (_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data;
16968
16952
  if (!data2)
16969
16953
  return;
16970
16954
  const transformedData = transformInitValues ? transformInitValues(data2) : data2;
@@ -16992,13 +16976,13 @@ const useForm = ({
16992
16976
  }, [watch]);
16993
16977
  const onValuesChange = React.useCallback(
16994
16978
  (changeValues) => {
16995
- var _a;
16979
+ var _a2;
16996
16980
  if (warnWhenUnsavedChanges) {
16997
16981
  setWarnWhen(true);
16998
16982
  }
16999
16983
  if (refineCoreProps == null ? void 0 : refineCoreProps.autoSave) {
17000
16984
  setWarnWhen(false);
17001
- const onFinishProps = (_a = refineCoreProps.autoSave) == null ? void 0 : _a.onFinish;
16985
+ const onFinishProps = (_a2 = refineCoreProps.autoSave) == null ? void 0 : _a2.onFinish;
17002
16986
  if (onFinishProps) {
17003
16987
  return onFinishAutoSave(onFinishProps(changeValues));
17004
16988
  }
@@ -17112,6 +17096,7 @@ const useRefineForm = (props) => {
17112
17096
  resource: resourceConfig.name,
17113
17097
  action: id ? "edit" : "create",
17114
17098
  id,
17099
+ dataProviderName: resourceConfig.dataProviderName,
17115
17100
  liveMode: id ? "auto" : "off",
17116
17101
  ...refineProps
17117
17102
  },
@@ -17125,10 +17110,11 @@ const useRefineForm = (props) => {
17125
17110
  ...formConfig == null ? void 0 : formConfig.useFormProps
17126
17111
  });
17127
17112
  React.useEffect(() => {
17128
- var _a, _b;
17113
+ var _a, _b, _c;
17129
17114
  const response = (_a = result.refineCore.mutationResult.error) == null ? void 0 : _a.response;
17115
+ const message2 = (_b = result.refineCore.mutationResult.error) == null ? void 0 : _b.message;
17130
17116
  if (response && !(response == null ? void 0 : response.bodyUsed)) {
17131
- (_b = response.json) == null ? void 0 : _b.call(response).then((body) => {
17117
+ (_c = response.json) == null ? void 0 : _c.call(response).then((body) => {
17132
17118
  var _a2;
17133
17119
  setResponseErrorMsgs(
17134
17120
  [].concat(
@@ -17136,8 +17122,10 @@ const useRefineForm = (props) => {
17136
17122
  )
17137
17123
  );
17138
17124
  });
17125
+ } else if (message2 && responseErrorMsgs[0] !== message2) {
17126
+ setResponseErrorMsgs([message2]);
17139
17127
  }
17140
- }, [formConfig, result, i18n2]);
17128
+ }, [formConfig, result, i18n2, responseErrorMsgs]);
17141
17129
  return {
17142
17130
  formResult: result,
17143
17131
  responseErrorMsgs,
@@ -17158,10 +17146,6 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17158
17146
  }, ref) {
17159
17147
  var _a, _b;
17160
17148
  const action = id ? "edit" : "create";
17161
- const pushModal = eagle.usePushModal();
17162
- const popModal = eagle.usePopModal();
17163
- const hasShownExpiredRef = React.useRef(false);
17164
- const [isSubmitting, setIsSubmitting] = React.useState(false);
17165
17149
  const refineFormResult = useRefineForm({
17166
17150
  resourceConfig,
17167
17151
  id,
@@ -17170,7 +17154,6 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17170
17154
  onSuccess == null ? void 0 : onSuccess(data2);
17171
17155
  },
17172
17156
  onMutationError() {
17173
- setIsSubmitting(false);
17174
17157
  onError == null ? void 0 : onError();
17175
17158
  },
17176
17159
  redirect: false,
@@ -17184,35 +17167,11 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17184
17167
  ...options,
17185
17168
  onBeforeSubmitError: (errors) => {
17186
17169
  if (errors.length) {
17187
- setIsSubmitting(false);
17188
17170
  onError == null ? void 0 : onError();
17189
17171
  }
17190
- },
17191
- onSubmitStart: () => {
17192
- setIsSubmitting(true);
17193
- },
17194
- onSubmitAbort: () => {
17195
- setIsSubmitting(false);
17196
17172
  }
17197
17173
  }
17198
17174
  });
17199
- const isExpired = useResourceVersionCheck({
17200
- queryResult: refineFormResult.formResult.refineCore.queryResult
17201
- });
17202
- React.useEffect(() => {
17203
- if (!isExpired || isSubmitting || hasShownExpiredRef.current) {
17204
- return;
17205
- }
17206
- hasShownExpiredRef.current = true;
17207
- pushModal({
17208
- component: DataExpiredModal,
17209
- props: {
17210
- onAbandon: () => {
17211
- popModal();
17212
- }
17213
- }
17214
- });
17215
- }, [isExpired, isSubmitting, pushModal, popModal]);
17216
17175
  const fieldsConfig = useFieldsConfig(
17217
17176
  resourceConfig,
17218
17177
  { fields: formConfig == null ? void 0 : formConfig.fields },
@@ -17244,13 +17203,7 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17244
17203
  action,
17245
17204
  isShowLayout: false,
17246
17205
  useFormProps: {
17247
- redirect: false,
17248
- onSubmitStart: () => {
17249
- setIsSubmitting(true);
17250
- },
17251
- onSubmitAbort: () => {
17252
- setIsSubmitting(false);
17253
- }
17206
+ redirect: false
17254
17207
  },
17255
17208
  rules: fieldsConfig == null ? void 0 : fieldsConfig.filter(
17256
17209
  (config) => "isSkipValidationInYaml" in config && !config.isSkipValidationInYaml
package/dist/refine.js CHANGED
@@ -7,13 +7,13 @@ var __publicField = (obj, key2, value2) => {
7
7
  import dayjs from "dayjs";
8
8
  import i18n from "i18next";
9
9
  import { w as warnOnce, g as getDefaults, a as warn, b as getI18n, s as setDefaults, d as setI18n, I as I18nContext, j as jsxRuntimeExports, u as useTranslation, c as cx_default, S as SocketStatus } from "./common-241b21f8.js";
10
- import { ResourceContext, matchResourceFromRoute, useResource, useDelete, useNavigation, useBreadcrumb, useList, CanAccess, useUpdate, useForm as useForm$2, pickNotDeprecated, useWarnAboutChange, useOne, useParsed, useGo, useCan, useTable, useDeleteMany, useShow, useRefineContext, useTranslate, flattenObjectKeys, useMenu, Refine } from "@refinedev/core";
10
+ import { ResourceContext, matchResourceFromRoute, useResource, useDelete, useNavigation, useBreadcrumb, useList, CanAccess, useUpdate, useForm as useForm$2, pickNotDeprecated, useWarnAboutChange, useParsed, useGo, useCan, useTable, useDeleteMany, useShow, useRefineContext, useTranslate, flattenObjectKeys, useMenu, Refine } from "@refinedev/core";
11
11
  import { parse, stringify } from "qs";
12
12
  import React, { createElement, isValidElement, cloneElement, Children, useContext, useCallback, createContext, useState, useEffect, useMemo, useRef, useImperativeHandle, forwardRef, Suspense, lazy, memo } from "react";
13
13
  import { useLocation, useHistory, useParams, matchPath, Link, Route, NavLink, Router } from "react-router-dom";
14
14
  import { usePushModal, usePopModal, DeleteDialog, Tag, RejectDialog, RejectDialogType, OverflowTooltip, Typo, Input, Select, AntdOption, Button, Form, Space, TextArea, kitContext, Loading, Table as Table$2, Pagination, Alert, ImmersiveDialog, SmallDialog, Fields, Units, Link as Link$1, Tooltip, Divider, Icon, Dropdown, Menu as Menu$1, LegacyModal, StatusCapsule, Popover, AntdTable, Upload, TableForm, ValidateTriggerType, AutoComplete, getOptions, DonutChart, SegmentControl, Checkbox, Tabs as Tabs$1, TabsTabPane, Col, Row, useMessage, SearchInput, Token, AntdSelectOptGroup, WizardDialog, MenuItemGroup, Layout as Layout$1, InputGroup, InputInteger, Time as Time$1, ModalStack, KitStoreProvider, ConfigProvider } from "@cloudtower/eagle";
15
15
  import { HierarchyTriangleRight16GrayIcon, HierarchyTriangleRight16BlueIcon, ClipboardCopy16GradientGrayIcon, ClipboardCopy16GradientBlueIcon, Retry16GradientGrayIcon, Retry16GradientBlueIcon, EditPen16GradientGrayIcon, EditPen16GradientBlueIcon, Showdiff16GradientGrayIcon, Showdiff16GradientBlueIcon, XmarkFailedSeriousWarningFill16RedIcon, EditPen16PrimaryIcon, Download16GradientBlueIcon, TrashBinDelete16Icon, MoreEllipsis324BoldSecondaryIcon, MoreEllipsis324BoldBlueIcon, MoreEllipsis316BoldBlueIcon, PlusAddCreateNew16BoldOntintIcon, ViewEye16GradientGrayIcon, EntityFilterIgnoreGradient16GrayIcon, InfoICircleFill16GrayIcon, InfoICircleFill16Gray70Icon, RecoverContinue16GradientBlueIcon, SuspendedPause16GradientBlueIcon, ArrowChevronLeft16BoldTertiaryIcon, ArrowChevronLeftSmall16BoldBlueIcon, OpenTerminal16GradientBlueIcon, ArrowChevronDown16BlueIcon, ArrowChevronUp16BlueIcon, Pause16GradientBlueIcon, EditPen16BlueIcon } from "@cloudtower/icons-react";
16
- import { first, get as get$2, cloneDeep, set, setWith, clone, debounce, isEqual as isEqual$1, isObject as isObject$4, uniq, omit as omit$1, merge, last, keyBy } from "lodash-es";
16
+ import { first, get as get$2, cloneDeep, set, setWith, clone, debounce, isEqual as isEqual$1, omit as omit$1, isObject as isObject$4, uniq, merge, last, keyBy } from "lodash-es";
17
17
  import yaml$2 from "js-yaml";
18
18
  import { useForm as useForm$1 } from "sunflower-antd";
19
19
  import { useLocalStorage } from "usehooks-ts";
@@ -622,6 +622,7 @@ const edit_form$1 = "Edit form";
622
622
  const data_expired$1 = "Data expired";
623
623
  const data_expired_body$1 = "The data in this form is no longer the latest version. To avoid saving errors, please discard this edit and reopen the form to edit again.";
624
624
  const data_expired_note$1 = "Your current entries will not be saved.";
625
+ const resource_version_conflict$1 = "The data in this form is no longer the latest version. Please discard this edit and reopen the form to edit again.";
625
626
  const abandon_edit$1 = "Discard edit";
626
627
  const exit_yaml_tip$1 = "If you go back to the form, any changes made to the YAML file will be lost.";
627
628
  const value_optional$1 = "Value (optional)";
@@ -903,6 +904,7 @@ const dovetail$1 = {
903
904
  data_expired: data_expired$1,
904
905
  data_expired_body: data_expired_body$1,
905
906
  data_expired_note: data_expired_note$1,
907
+ resource_version_conflict: resource_version_conflict$1,
906
908
  abandon_edit: abandon_edit$1,
907
909
  exit_yaml_tip: exit_yaml_tip$1,
908
910
  value_optional: value_optional$1,
@@ -1186,6 +1188,7 @@ const edit_form = "编辑表单";
1186
1188
  const data_expired = "数据已过期";
1187
1189
  const data_expired_body = "当前表单中的数据已不是最新版。为避免保存失败,请放弃本次编辑,并重新打开表单进行编辑。";
1188
1190
  const data_expired_note = "当前已填写内容将不会保留。";
1191
+ const resource_version_conflict = "当前表单中的数据已不是最新版,请放弃本次编辑,并重新打开表单进行编辑。";
1189
1192
  const abandon_edit = "放弃编辑";
1190
1193
  const exit_yaml_tip = "返回编辑表单,不会保留对 YAML 文件做出的所有更改。";
1191
1194
  const form = "表单";
@@ -1466,6 +1469,7 @@ const dovetail = {
1466
1469
  data_expired,
1467
1470
  data_expired_body,
1468
1471
  data_expired_note,
1472
+ resource_version_conflict,
1469
1473
  abandon_edit,
1470
1474
  exit_yaml_tip,
1471
1475
  form,
@@ -10689,26 +10693,6 @@ function usePathMap(options) {
10689
10693
  transformApplyValues
10690
10694
  };
10691
10695
  }
10692
- const useResourceVersionCheck = ({
10693
- queryResult
10694
- }) => {
10695
- var _a, _b, _c;
10696
- const initialResourceVersionRef = useRef();
10697
- const [isExpired, setIsExpired] = useState(false);
10698
- const currentResourceVersion = (_c = (_b = (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data) == null ? void 0 : _b.metadata) == null ? void 0 : _c.resourceVersion;
10699
- useEffect(() => {
10700
- if (!currentResourceVersion)
10701
- return;
10702
- if (!initialResourceVersionRef.current) {
10703
- initialResourceVersionRef.current = currentResourceVersion;
10704
- return;
10705
- }
10706
- if (currentResourceVersion !== initialResourceVersionRef.current) {
10707
- setIsExpired(true);
10708
- }
10709
- }, [currentResourceVersion]);
10710
- return isExpired;
10711
- };
10712
10696
  function getInitialValues(resourceConfig) {
10713
10697
  return resourceConfig.initValue || {
10714
10698
  apiVersion: resourceConfig.apiVersion,
@@ -10717,42 +10701,6 @@ function getInitialValues(resourceConfig) {
10717
10701
  spec: {}
10718
10702
  };
10719
10703
  }
10720
- const button_1v659kh = "";
10721
- const WarningButtonStyle = "wwyz7ti";
10722
- const DataExpiredModal_eazxh6 = "";
10723
- const NoteStyle = "n609wlp";
10724
- function DataExpiredModal({
10725
- onAbandon
10726
- }) {
10727
- const {
10728
- t: t2
10729
- } = useTranslation();
10730
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(SmallDialog, {
10731
- title: t2("dovetail.data_expired"),
10732
- closable: false,
10733
- maskClosable: false,
10734
- cancelButtonProps: {
10735
- style: {
10736
- display: "none"
10737
- }
10738
- },
10739
- okText: t2("dovetail.abandon_edit"),
10740
- okButtonProps: {
10741
- className: WarningButtonStyle
10742
- },
10743
- onOk: (popModal) => {
10744
- popModal();
10745
- onAbandon();
10746
- },
10747
- children: [/* @__PURE__ */ jsxRuntimeExports.jsx("div", {
10748
- className: Typo.Label.l2_regular,
10749
- children: t2("dovetail.data_expired_body")
10750
- }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", {
10751
- className: `${Typo.Label.l2_regular} ${NoteStyle}`,
10752
- children: t2("dovetail.data_expired_note")
10753
- })]
10754
- });
10755
- }
10756
10704
  const index_az4wrx = "";
10757
10705
  const WrapperStyle$5 = "w1akirqw";
10758
10706
  const TitleStyle$2 = "t30srnq";
@@ -11082,6 +11030,52 @@ function copyToClipboard(text) {
11082
11030
  document.execCommand("copy");
11083
11031
  document.body.removeChild(input);
11084
11032
  }
11033
+ const useGlobalStore = (name2 = "default") => {
11034
+ const globalStores = useContext(GlobalStoreContext);
11035
+ return globalStores[name2];
11036
+ };
11037
+ function use409Retry({
11038
+ action,
11039
+ dataProviderName,
11040
+ id,
11041
+ mutationMeta
11042
+ }) {
11043
+ const { t: t2 } = useTranslation();
11044
+ const globalStore = useGlobalStore(dataProviderName);
11045
+ const initialResourceRef = useRef();
11046
+ const isEditAction = action === "edit" || !!id;
11047
+ const captureInitialResource = useCallback((resource) => {
11048
+ var _a;
11049
+ if (!isEditAction || initialResourceRef.current || !resource) {
11050
+ return;
11051
+ }
11052
+ const rawResource = (_a = globalStore == null ? void 0 : globalStore.restoreItem) == null ? void 0 : _a.call(globalStore, resource);
11053
+ if (!rawResource) {
11054
+ return;
11055
+ }
11056
+ initialResourceRef.current = cloneDeep(rawResource);
11057
+ }, [globalStore, isEditAction]);
11058
+ const retryMutationMeta = useMemo(() => {
11059
+ const restMutationMeta = omit$1(mutationMeta, "resourceVersionConflictRetry");
11060
+ if (!isEditAction) {
11061
+ return restMutationMeta;
11062
+ }
11063
+ return {
11064
+ ...restMutationMeta,
11065
+ resourceVersionConflictRetry: {
11066
+ // refine 的 mutationMeta 在 hook 创建时就会固定;用 getter 让 provider 在保存瞬间读取最新的初始版本。
11067
+ get initialResource() {
11068
+ return initialResourceRef.current;
11069
+ },
11070
+ conflictMessage: t2("dovetail.resource_version_conflict")
11071
+ }
11072
+ };
11073
+ }, [isEditAction, mutationMeta, t2]);
11074
+ return {
11075
+ captureInitialResource,
11076
+ mutationMeta: retryMutationMeta
11077
+ };
11078
+ }
11085
11079
  function useK8sYamlEditor() {
11086
11080
  const foldSymbol = useCallback(function(editor, symbol) {
11087
11081
  const model = editor.getModel();
@@ -11192,10 +11186,6 @@ function generateYamlBySchema(defaultValue, schema) {
11192
11186
  const content = yaml$2.dump(merged);
11193
11187
  return content.replace(/(')(#.+?)(')/g, "$2").replace(/( +)(#)/g, "$2$1");
11194
11188
  }
11195
- const useGlobalStore = (name2 = "default") => {
11196
- const globalStores = useContext(GlobalStoreContext);
11197
- return globalStores[name2];
11198
- };
11199
11189
  const useYamlForm = ({
11200
11190
  action: actionFromProps,
11201
11191
  resource,
@@ -11233,7 +11223,7 @@ const useYamlForm = ({
11233
11223
  onSubmitAbort,
11234
11224
  rules
11235
11225
  } = {}) => {
11236
- var _a;
11226
+ var _a, _b;
11237
11227
  const editor = useRef(null);
11238
11228
  const { t: t2 } = useTranslation();
11239
11229
  const [isYamlValid, setIsYamlValid] = useState(true);
@@ -11244,7 +11234,17 @@ const useYamlForm = ({
11244
11234
  const [beforeSubmitErrors, setBeforeSubmitErrors] = useState([]);
11245
11235
  const [errorResponseBody, setErrorResponseBody] = useState(null);
11246
11236
  const useResourceResult = useResource();
11247
- const globalStore = useGlobalStore();
11237
+ const globalStore = useGlobalStore(dataProviderName);
11238
+ const action = useMemo(
11239
+ () => actionFromProps || useResourceResult.action,
11240
+ [actionFromProps, useResourceResult.action]
11241
+ );
11242
+ const { captureInitialResource, mutationMeta: finalMutationMeta } = use409Retry({
11243
+ action,
11244
+ dataProviderName,
11245
+ id: idFromProps,
11246
+ mutationMeta
11247
+ });
11248
11248
  const {
11249
11249
  schema,
11250
11250
  loading: isLoadingSchema,
@@ -11281,7 +11281,7 @@ const useYamlForm = ({
11281
11281
  meta: pickNotDeprecated(meta, metaData),
11282
11282
  metaData: pickNotDeprecated(meta, metaData),
11283
11283
  queryMeta,
11284
- mutationMeta,
11284
+ mutationMeta: finalMutationMeta,
11285
11285
  liveMode,
11286
11286
  liveParams,
11287
11287
  mutationMode,
@@ -11296,12 +11296,12 @@ const useYamlForm = ({
11296
11296
  overtimeOptions
11297
11297
  });
11298
11298
  const { formLoading, onFinish, queryResult } = useFormCoreResult;
11299
+ useEffect(() => {
11300
+ var _a2;
11301
+ captureInitialResource((_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data);
11302
+ }, [captureInitialResource, (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data]);
11299
11303
  const { warnWhenUnsavedChanges: warnWhenUnsavedChangesRefine, setWarnWhen } = useWarnAboutChange();
11300
11304
  const warnWhenUnsavedChanges = warnWhenUnsavedChangesProp ?? warnWhenUnsavedChangesRefine;
11301
- const action = useMemo(
11302
- () => actionFromProps || useResourceResult.action,
11303
- [actionFromProps, useResourceResult.action]
11304
- );
11305
11305
  const initialValues = useMemo(() => {
11306
11306
  var _a2;
11307
11307
  const initialValues2 = (action === "edit" && ((_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data) ? initialValuesForEdit || (globalStore == null ? void 0 : globalStore.restoreItem(queryResult.data.data)) : initialValuesForCreate) || {};
@@ -11344,10 +11344,10 @@ const useYamlForm = ({
11344
11344
  }
11345
11345
  },
11346
11346
  onEditorCreate(editorInstance) {
11347
- var _a3, _b;
11347
+ var _a3, _b2;
11348
11348
  const editorValue = yaml$2.dump(initialValues);
11349
11349
  (_a3 = editor.current) == null ? void 0 : _a3.setEditorValue(editorValue);
11350
- (_b = editor.current) == null ? void 0 : _b.setValue(editorValue);
11350
+ (_b2 = editor.current) == null ? void 0 : _b2.setValue(editorValue);
11351
11351
  if (action === "edit") {
11352
11352
  fold2(editorInstance);
11353
11353
  }
@@ -11360,7 +11360,7 @@ const useYamlForm = ({
11360
11360
  initialValues,
11361
11361
  schemas,
11362
11362
  resource,
11363
- (_a = useResourceResult.resource) == null ? void 0 : _a.name,
11363
+ (_b = useResourceResult.resource) == null ? void 0 : _b.name,
11364
11364
  action,
11365
11365
  finalErrors,
11366
11366
  fold2
@@ -11400,7 +11400,7 @@ const useYamlForm = ({
11400
11400
  formProps: {
11401
11401
  ...formSF.formProps,
11402
11402
  onFinish: async (values) => {
11403
- var _a2, _b;
11403
+ var _a2, _b2;
11404
11404
  setBeforeSubmitErrors([]);
11405
11405
  onSubmitStart == null ? void 0 : onSubmitStart();
11406
11406
  const errors = [
@@ -11420,7 +11420,7 @@ const useYamlForm = ({
11420
11420
  return;
11421
11421
  }
11422
11422
  try {
11423
- const objectValues = editor.current ? yaml$2.load(((_b = editor.current) == null ? void 0 : _b.getEditorValue()) || "") : values;
11423
+ const objectValues = editor.current ? yaml$2.load(((_b2 = editor.current) == null ? void 0 : _b2.getEditorValue()) || "") : values;
11424
11424
  let finalValues = (transformApplyValues == null ? void 0 : transformApplyValues(objectValues)) || objectValues;
11425
11425
  if (beforeSubmit) {
11426
11426
  try {
@@ -11522,6 +11522,7 @@ function YamlForm(props) {
11522
11522
  id,
11523
11523
  action: actionFromProps,
11524
11524
  resource: resource == null ? void 0 : resource.name,
11525
+ dataProviderName: resourceConfig.dataProviderName,
11525
11526
  editorOptions: {
11526
11527
  isSkipSchema: schemaStrategy === "None"
11527
11528
  /* None */
@@ -11644,31 +11645,6 @@ function YamlFormContainer({
11644
11645
  onSaveButtonPropsChange
11645
11646
  }) {
11646
11647
  const action = id ? "edit" : "create";
11647
- const pushModal = usePushModal();
11648
- const popModal = usePopModal();
11649
- const hasShownExpiredRef = useRef(false);
11650
- const [isSubmitting, setIsSubmitting] = useState(false);
11651
- const queryResult = useOne({
11652
- resource: resourceConfig.name,
11653
- id,
11654
- liveMode: id ? "auto" : "off",
11655
- queryOptions: { enabled: !!id }
11656
- });
11657
- const isExpired = useResourceVersionCheck({ queryResult });
11658
- useEffect(() => {
11659
- if (!isExpired || isSubmitting || hasShownExpiredRef.current) {
11660
- return;
11661
- }
11662
- hasShownExpiredRef.current = true;
11663
- pushModal({
11664
- component: DataExpiredModal,
11665
- props: {
11666
- onAbandon: () => {
11667
- popModal();
11668
- }
11669
- }
11670
- });
11671
- }, [isExpired, isSubmitting, pushModal, popModal]);
11672
11648
  const { transformInitValues, transformApplyValues } = usePathMap({
11673
11649
  pathMap: formConfig == null ? void 0 : formConfig.pathMap,
11674
11650
  transformInitValues: formConfig == null ? void 0 : formConfig.transformInitValues,
@@ -11688,13 +11664,7 @@ function YamlFormContainer({
11688
11664
  action,
11689
11665
  isShowLayout: false,
11690
11666
  useFormProps: {
11691
- redirect: false,
11692
- onSubmitStart: () => {
11693
- setIsSubmitting(true);
11694
- },
11695
- onSubmitAbort: () => {
11696
- setIsSubmitting(false);
11697
- }
11667
+ redirect: false
11698
11668
  },
11699
11669
  rules: void 0,
11700
11670
  onSaveButtonPropsChange,
@@ -16049,6 +16019,8 @@ function ResourceShow(props) {
16049
16019
  }
16050
16020
  );
16051
16021
  }
16022
+ const button_1v659kh = "";
16023
+ const WarningButtonStyle = "wwyz7ti";
16052
16024
  const modal_1eijuvm = "";
16053
16025
  const SmallModalStyle = "s1nc293e";
16054
16026
  function FormModeSegmentControl({
@@ -16884,9 +16856,16 @@ const useForm = ({
16884
16856
  onSubmitAbort,
16885
16857
  ...rest
16886
16858
  } = {}) => {
16859
+ var _a;
16887
16860
  const { options } = useRefineContext();
16888
16861
  const disableServerSideValidation = (options == null ? void 0 : options.disableServerSideValidation) || disableServerSideValidationProp;
16889
16862
  const translate = useTranslate();
16863
+ const { captureInitialResource, mutationMeta } = use409Retry({
16864
+ action: refineCoreProps == null ? void 0 : refineCoreProps.action,
16865
+ dataProviderName: refineCoreProps == null ? void 0 : refineCoreProps.dataProviderName,
16866
+ id: refineCoreProps == null ? void 0 : refineCoreProps.id,
16867
+ mutationMeta: refineCoreProps == null ? void 0 : refineCoreProps.mutationMeta
16868
+ });
16890
16869
  const { warnWhenUnsavedChanges: warnWhenUnsavedChangesRefine, setWarnWhen } = useWarnAboutChange();
16891
16870
  const warnWhenUnsavedChanges = warnWhenUnsavedChangesProp ?? warnWhenUnsavedChangesRefine;
16892
16871
  const useHookFormResult = useForm$3({
@@ -16906,10 +16885,11 @@ const useForm = ({
16906
16885
  } = useHookFormResult;
16907
16886
  const useFormCoreResult = useForm$2({
16908
16887
  ...refineCoreProps,
16888
+ mutationMeta,
16909
16889
  onMutationError: (error, _variables, _context) => {
16910
- var _a, _b;
16890
+ var _a2, _b;
16911
16891
  if (disableServerSideValidation) {
16912
- (_a = refineCoreProps == null ? void 0 : refineCoreProps.onMutationError) == null ? void 0 : _a.call(refineCoreProps, error, _variables, _context);
16892
+ (_a2 = refineCoreProps == null ? void 0 : refineCoreProps.onMutationError) == null ? void 0 : _a2.call(refineCoreProps, error, _variables, _context);
16913
16893
  return;
16914
16894
  }
16915
16895
  const errors = error == null ? void 0 : error.errors;
@@ -16942,10 +16922,14 @@ const useForm = ({
16942
16922
  });
16943
16923
  const { queryResult, onFinish, formLoading, onFinishAutoSave } = useFormCoreResult;
16944
16924
  useEffect(() => {
16945
- var _a;
16925
+ var _a2;
16926
+ captureInitialResource((_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data);
16927
+ }, [captureInitialResource, (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data]);
16928
+ useEffect(() => {
16929
+ var _a2;
16946
16930
  if (formState.isDirty)
16947
16931
  return;
16948
- const data2 = (_a = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a.data;
16932
+ const data2 = (_a2 = queryResult == null ? void 0 : queryResult.data) == null ? void 0 : _a2.data;
16949
16933
  if (!data2)
16950
16934
  return;
16951
16935
  const transformedData = transformInitValues ? transformInitValues(data2) : data2;
@@ -16973,13 +16957,13 @@ const useForm = ({
16973
16957
  }, [watch]);
16974
16958
  const onValuesChange = useCallback(
16975
16959
  (changeValues) => {
16976
- var _a;
16960
+ var _a2;
16977
16961
  if (warnWhenUnsavedChanges) {
16978
16962
  setWarnWhen(true);
16979
16963
  }
16980
16964
  if (refineCoreProps == null ? void 0 : refineCoreProps.autoSave) {
16981
16965
  setWarnWhen(false);
16982
- const onFinishProps = (_a = refineCoreProps.autoSave) == null ? void 0 : _a.onFinish;
16966
+ const onFinishProps = (_a2 = refineCoreProps.autoSave) == null ? void 0 : _a2.onFinish;
16983
16967
  if (onFinishProps) {
16984
16968
  return onFinishAutoSave(onFinishProps(changeValues));
16985
16969
  }
@@ -17093,6 +17077,7 @@ const useRefineForm = (props) => {
17093
17077
  resource: resourceConfig.name,
17094
17078
  action: id ? "edit" : "create",
17095
17079
  id,
17080
+ dataProviderName: resourceConfig.dataProviderName,
17096
17081
  liveMode: id ? "auto" : "off",
17097
17082
  ...refineProps
17098
17083
  },
@@ -17106,10 +17091,11 @@ const useRefineForm = (props) => {
17106
17091
  ...formConfig == null ? void 0 : formConfig.useFormProps
17107
17092
  });
17108
17093
  useEffect(() => {
17109
- var _a, _b;
17094
+ var _a, _b, _c;
17110
17095
  const response = (_a = result.refineCore.mutationResult.error) == null ? void 0 : _a.response;
17096
+ const message2 = (_b = result.refineCore.mutationResult.error) == null ? void 0 : _b.message;
17111
17097
  if (response && !(response == null ? void 0 : response.bodyUsed)) {
17112
- (_b = response.json) == null ? void 0 : _b.call(response).then((body) => {
17098
+ (_c = response.json) == null ? void 0 : _c.call(response).then((body) => {
17113
17099
  var _a2;
17114
17100
  setResponseErrorMsgs(
17115
17101
  [].concat(
@@ -17117,8 +17103,10 @@ const useRefineForm = (props) => {
17117
17103
  )
17118
17104
  );
17119
17105
  });
17106
+ } else if (message2 && responseErrorMsgs[0] !== message2) {
17107
+ setResponseErrorMsgs([message2]);
17120
17108
  }
17121
- }, [formConfig, result, i18n2]);
17109
+ }, [formConfig, result, i18n2, responseErrorMsgs]);
17122
17110
  return {
17123
17111
  formResult: result,
17124
17112
  responseErrorMsgs,
@@ -17139,10 +17127,6 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17139
17127
  }, ref) {
17140
17128
  var _a, _b;
17141
17129
  const action = id ? "edit" : "create";
17142
- const pushModal = usePushModal();
17143
- const popModal = usePopModal();
17144
- const hasShownExpiredRef = useRef(false);
17145
- const [isSubmitting, setIsSubmitting] = useState(false);
17146
17130
  const refineFormResult = useRefineForm({
17147
17131
  resourceConfig,
17148
17132
  id,
@@ -17151,7 +17135,6 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17151
17135
  onSuccess == null ? void 0 : onSuccess(data2);
17152
17136
  },
17153
17137
  onMutationError() {
17154
- setIsSubmitting(false);
17155
17138
  onError == null ? void 0 : onError();
17156
17139
  },
17157
17140
  redirect: false,
@@ -17165,35 +17148,11 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17165
17148
  ...options,
17166
17149
  onBeforeSubmitError: (errors) => {
17167
17150
  if (errors.length) {
17168
- setIsSubmitting(false);
17169
17151
  onError == null ? void 0 : onError();
17170
17152
  }
17171
- },
17172
- onSubmitStart: () => {
17173
- setIsSubmitting(true);
17174
- },
17175
- onSubmitAbort: () => {
17176
- setIsSubmitting(false);
17177
17153
  }
17178
17154
  }
17179
17155
  });
17180
- const isExpired = useResourceVersionCheck({
17181
- queryResult: refineFormResult.formResult.refineCore.queryResult
17182
- });
17183
- useEffect(() => {
17184
- if (!isExpired || isSubmitting || hasShownExpiredRef.current) {
17185
- return;
17186
- }
17187
- hasShownExpiredRef.current = true;
17188
- pushModal({
17189
- component: DataExpiredModal,
17190
- props: {
17191
- onAbandon: () => {
17192
- popModal();
17193
- }
17194
- }
17195
- });
17196
- }, [isExpired, isSubmitting, pushModal, popModal]);
17197
17156
  const fieldsConfig = useFieldsConfig(
17198
17157
  resourceConfig,
17199
17158
  { fields: formConfig == null ? void 0 : formConfig.fields },
@@ -17225,13 +17184,7 @@ const RefineFormContainer = React.forwardRef(function RefineFormContainer2({
17225
17184
  action,
17226
17185
  isShowLayout: false,
17227
17186
  useFormProps: {
17228
- redirect: false,
17229
- onSubmitStart: () => {
17230
- setIsSubmitting(true);
17231
- },
17232
- onSubmitAbort: () => {
17233
- setIsSubmitting(false);
17234
- }
17187
+ redirect: false
17235
17188
  },
17236
17189
  rules: fieldsConfig == null ? void 0 : fieldsConfig.filter(
17237
17190
  (config) => "isSkipValidationInYaml" in config && !config.isSkipValidationInYaml
package/dist/style.css CHANGED
@@ -1148,113 +1148,6 @@
1148
1148
  /* box shadow */
1149
1149
  /* fisheye */
1150
1150
  /* z-index */
1151
- .wwyz7ti.ant-btn.ant-btn.ant-btn-primary {
1152
- background-color: #fea008;
1153
- }
1154
- .wwyz7ti.ant-btn.ant-btn.ant-btn-primary:hover {
1155
- background-color: #feba33;
1156
- }
1157
-
1158
- .c1xsou5f.ant-btn {
1159
- border-radius: 6px;
1160
- border: 1px solid rgba(172, 186, 211, 0.6) !important;
1161
- }/* // basic */
1162
- /* FishEye Color Variables and Functions */
1163
- /*
1164
- --------------------------- Primary Color ---------------------------
1165
- */
1166
- /*
1167
- ---------------------------When necessary to add at any time---------------------------
1168
- */
1169
- /* computed */
1170
- /* blue */
1171
- /* green */
1172
- /* yellow */
1173
- /* red */
1174
- /* purple */
1175
- /* palette global token*/
1176
- /* color opaque */
1177
- /* color transparent */
1178
- /* blue transparent */
1179
- /* green transparent */
1180
- /* yellow transparent */
1181
- /* red transparent */
1182
- /* gray transparent */
1183
- /* white transparent */
1184
- /* gradient opaque */
1185
- /* blue radial gradient */
1186
- /* blue linear gradient */
1187
- /* green radial gradient */
1188
- /* yellow radial gradient */
1189
- /* red radial gradient */
1190
- /* gray radial gradient */
1191
- /* white to gray radial gradient */
1192
- /* white to gray linear gradient */
1193
- /* gradient transparent */
1194
- /* secondary palette */
1195
- /* purple radial gradient */
1196
- /* refine alias color */
1197
- /* text */
1198
- /* link */
1199
- /* fill */
1200
- /* fill element */
1201
- /* fill interaction */
1202
- /* stroke */
1203
- /* background */
1204
- /* dim */
1205
- /* box shadow */
1206
- /* fisheye */
1207
- /* z-index */
1208
- .n609wlp {
1209
- margin-top: 8px;
1210
- color: #2d3a56;
1211
- }/* // basic */
1212
- /* FishEye Color Variables and Functions */
1213
- /*
1214
- --------------------------- Primary Color ---------------------------
1215
- */
1216
- /*
1217
- ---------------------------When necessary to add at any time---------------------------
1218
- */
1219
- /* computed */
1220
- /* blue */
1221
- /* green */
1222
- /* yellow */
1223
- /* red */
1224
- /* purple */
1225
- /* palette global token*/
1226
- /* color opaque */
1227
- /* color transparent */
1228
- /* blue transparent */
1229
- /* green transparent */
1230
- /* yellow transparent */
1231
- /* red transparent */
1232
- /* gray transparent */
1233
- /* white transparent */
1234
- /* gradient opaque */
1235
- /* blue radial gradient */
1236
- /* blue linear gradient */
1237
- /* green radial gradient */
1238
- /* yellow radial gradient */
1239
- /* red radial gradient */
1240
- /* gray radial gradient */
1241
- /* white to gray radial gradient */
1242
- /* white to gray linear gradient */
1243
- /* gradient transparent */
1244
- /* secondary palette */
1245
- /* purple radial gradient */
1246
- /* refine alias color */
1247
- /* text */
1248
- /* link */
1249
- /* fill */
1250
- /* fill element */
1251
- /* fill interaction */
1252
- /* stroke */
1253
- /* background */
1254
- /* dim */
1255
- /* box shadow */
1256
- /* fisheye */
1257
- /* z-index */
1258
1151
  .w1akirqw {
1259
1152
  height: 100%;
1260
1153
  display: flex;
@@ -4376,6 +4269,63 @@
4376
4269
  /* box shadow */
4377
4270
  /* fisheye */
4378
4271
  /* z-index */
4272
+ .wwyz7ti.ant-btn.ant-btn.ant-btn-primary {
4273
+ background-color: #fea008;
4274
+ }
4275
+ .wwyz7ti.ant-btn.ant-btn.ant-btn-primary:hover {
4276
+ background-color: #feba33;
4277
+ }
4278
+
4279
+ .c1xsou5f.ant-btn {
4280
+ border-radius: 6px;
4281
+ border: 1px solid rgba(172, 186, 211, 0.6) !important;
4282
+ }/* // basic */
4283
+ /* FishEye Color Variables and Functions */
4284
+ /*
4285
+ --------------------------- Primary Color ---------------------------
4286
+ */
4287
+ /*
4288
+ ---------------------------When necessary to add at any time---------------------------
4289
+ */
4290
+ /* computed */
4291
+ /* blue */
4292
+ /* green */
4293
+ /* yellow */
4294
+ /* red */
4295
+ /* purple */
4296
+ /* palette global token*/
4297
+ /* color opaque */
4298
+ /* color transparent */
4299
+ /* blue transparent */
4300
+ /* green transparent */
4301
+ /* yellow transparent */
4302
+ /* red transparent */
4303
+ /* gray transparent */
4304
+ /* white transparent */
4305
+ /* gradient opaque */
4306
+ /* blue radial gradient */
4307
+ /* blue linear gradient */
4308
+ /* green radial gradient */
4309
+ /* yellow radial gradient */
4310
+ /* red radial gradient */
4311
+ /* gray radial gradient */
4312
+ /* white to gray radial gradient */
4313
+ /* white to gray linear gradient */
4314
+ /* gradient transparent */
4315
+ /* secondary palette */
4316
+ /* purple radial gradient */
4317
+ /* refine alias color */
4318
+ /* text */
4319
+ /* link */
4320
+ /* fill */
4321
+ /* fill element */
4322
+ /* fill interaction */
4323
+ /* stroke */
4324
+ /* background */
4325
+ /* dim */
4326
+ /* box shadow */
4327
+ /* fisheye */
4328
+ /* z-index */
4379
4329
  .fq4465w.ant-modal.fullscreen .ant-modal-header {
4380
4330
  padding: 60px 0 32px 0;
4381
4331
  max-width: var(--max-modal-width, 1024px);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dovetail-v2/refine",
3
- "version": "0.3.33",
3
+ "version": "0.3.34",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -30,7 +30,7 @@
30
30
  "dayjs": "^1.11.10",
31
31
  "i18next": "^23.2.3",
32
32
  "js-yaml": "^4.1.0",
33
- "k8s-api-provider": "^0.0.36",
33
+ "k8s-api-provider": "^0.0.37",
34
34
  "ky": "^0.33.3",
35
35
  "lodash-es": "^4.17.21",
36
36
  "mitt": "^3.0.1",