@gisce/react-ooui 2.0.0-rc.0 → 2.0.0-rc.11

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.
Files changed (72) hide show
  1. package/dist/actionbar/TreeActionBar.d.ts.map +1 -1
  2. package/dist/common/SelectAllRecordsRow.d.ts +10 -0
  3. package/dist/common/SelectAllRecordsRow.d.ts.map +1 -0
  4. package/dist/context/ContentRootContext.d.ts.map +1 -1
  5. package/dist/helpers/dynamicColumnsHelper.d.ts +9 -1
  6. package/dist/helpers/dynamicColumnsHelper.d.ts.map +1 -1
  7. package/dist/helpers/formHelper.d.ts +1 -0
  8. package/dist/helpers/formHelper.d.ts.map +1 -1
  9. package/dist/helpers/treeHelper.d.ts +2 -1
  10. package/dist/helpers/treeHelper.d.ts.map +1 -1
  11. package/dist/hooks/useSearch.d.ts +1 -0
  12. package/dist/hooks/useSearch.d.ts.map +1 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/locales/ca_ES.d.ts +4 -0
  16. package/dist/locales/ca_ES.d.ts.map +1 -1
  17. package/dist/locales/en_US.d.ts +4 -0
  18. package/dist/locales/en_US.d.ts.map +1 -1
  19. package/dist/locales/es_ES.d.ts +4 -0
  20. package/dist/locales/es_ES.d.ts.map +1 -1
  21. package/dist/react-ooui.es.js +5621 -5204
  22. package/dist/react-ooui.es.js.map +1 -1
  23. package/dist/react-ooui.umd.js +19 -14
  24. package/dist/react-ooui.umd.js.map +1 -1
  25. package/dist/types/index.d.ts +30 -29
  26. package/dist/types/index.d.ts.map +1 -1
  27. package/dist/views/actionViews/GraphActionView.d.ts.map +1 -1
  28. package/dist/widgets/WidgetFactory.d.ts.map +1 -1
  29. package/dist/widgets/base/Integer.d.ts.map +1 -1
  30. package/dist/widgets/base/many2one/Many2oneSuffix.d.ts.map +1 -1
  31. package/dist/widgets/base/one2many/One2manyInput.d.ts.map +1 -1
  32. package/dist/widgets/custom/Avatar.d.ts.map +1 -1
  33. package/dist/widgets/custom/Comments.d.ts +35 -0
  34. package/dist/widgets/custom/Comments.d.ts.map +1 -0
  35. package/dist/widgets/views/Form.d.ts +2 -2
  36. package/dist/widgets/views/Form.d.ts.map +1 -1
  37. package/dist/widgets/views/SearchTree.d.ts.map +1 -1
  38. package/dist/widgets/views/Tree.d.ts +1 -0
  39. package/dist/widgets/views/Tree.d.ts.map +1 -1
  40. package/dist/widgets/views/searchFilter/SearchFilter.d.ts +0 -1
  41. package/dist/widgets/views/searchFilter/SearchFilter.d.ts.map +1 -1
  42. package/package.json +5 -3
  43. package/src/actionbar/FormActionBar.tsx +1 -1
  44. package/src/actionbar/TreeActionBar.tsx +84 -82
  45. package/src/common/SelectAllRecordsRow.tsx +95 -0
  46. package/src/context/ContentRootContext.tsx +5 -3
  47. package/src/helpers/dynamicColumnsHelper.ts +1 -1
  48. package/src/helpers/formHelper.ts +5 -0
  49. package/src/helpers/iconMapper.ts +1 -2
  50. package/src/helpers/treeHelper.ts +14 -3
  51. package/src/hooks/useExport.ts +2 -3
  52. package/src/hooks/useSearch.ts +16 -3
  53. package/src/index.ts +2 -0
  54. package/src/locales/ca_ES.tsx +5 -0
  55. package/src/locales/en_US.tsx +5 -0
  56. package/src/locales/es_ES.tsx +5 -0
  57. package/src/stories/custom/Comments.stories.tsx +190 -0
  58. package/src/stories/dashboard/DashboardGrid.stories.tsx +13 -0
  59. package/src/stories/mocks/models/cups.ts +16 -3
  60. package/src/types/index.ts +92 -41
  61. package/src/views/actionViews/GraphActionView.tsx +0 -1
  62. package/src/widgets/WidgetFactory.tsx +3 -0
  63. package/src/widgets/base/Integer.tsx +14 -1
  64. package/src/widgets/base/many2one/Many2oneSuffix.tsx +24 -12
  65. package/src/widgets/base/one2many/One2manyInput.tsx +11 -3
  66. package/src/widgets/custom/Avatar.tsx +0 -1
  67. package/src/widgets/custom/Comments.tsx +144 -0
  68. package/src/widgets/views/Form.tsx +83 -9
  69. package/src/widgets/views/Graph/GraphIndicator.tsx +3 -3
  70. package/src/widgets/views/SearchTree.tsx +12 -8
  71. package/src/widgets/views/Tree.tsx +62 -48
  72. package/src/widgets/views/searchFilter/SearchFilter.tsx +1 -3
@@ -113,7 +113,6 @@ export const GraphActionView = (props: GraphActionViewProps) => {
113
113
  formView.search_fields,
114
114
  treeView.search_fields,
115
115
  ])}
116
- formXml={formView.arch}
117
116
  limit={limit!}
118
117
  onClear={clear}
119
118
  offset={offset}
@@ -33,6 +33,7 @@ import {
33
33
  Steps,
34
34
  Tag,
35
35
  CodeEditor,
36
+ CommentsTimelineField,
36
37
  } from "@/index";
37
38
  import { Image } from "./base/Image";
38
39
  import { FiberGrid } from "./custom/FiberGrid";
@@ -118,6 +119,8 @@ const getWidgetType = (type: string) => {
118
119
  return Steps;
119
120
  case "codeeditor":
120
121
  return CodeEditor;
122
+ case "comments_timeline":
123
+ return CommentsTimelineField;
121
124
  default:
122
125
  return undefined;
123
126
  }
@@ -27,7 +27,20 @@ export const Integer = (props: IntegerProps) => {
27
27
  className={"w-full "}
28
28
  disabled={readOnly}
29
29
  formatter={(value) => {
30
- return `${value}`.replace(/[^0-9\-]+/g, "");
30
+ // Check if value is not undefined and is a valid number
31
+ if (value === undefined) {
32
+ return "";
33
+ }
34
+
35
+ if (typeof value === "string" && !isNaN(parseFloat(value))) {
36
+ let truncatedValue = Math.trunc(parseFloat(value));
37
+ return `${truncatedValue}`.replace(/[^0-9\-]+/g, "");
38
+ } else if (typeof value === "number") {
39
+ let truncatedValue = Math.trunc(value);
40
+ return `${truncatedValue}`.replace(/[^0-9\-]+/g, "");
41
+ }
42
+
43
+ return "";
31
44
  }}
32
45
  onChange={(newValue: any) => {
33
46
  const newNumber = newValue as number;
@@ -20,6 +20,7 @@ import ConnectionProvider from "@/ConnectionProvider";
20
20
  import { processValues } from "@/helpers/formHelper";
21
21
  import showErrorDialog from "@/ui/ActionErrorDialog";
22
22
  import { LocaleContext, LocaleContextType } from "@/context/LocaleContext";
23
+ import { parseContextFields, parseDomainFields } from "@gisce/ooui";
23
24
 
24
25
  type Props = {
25
26
  id: number;
@@ -60,18 +61,29 @@ export const Many2oneSuffix = (props: Props) => {
60
61
  context,
61
62
  }) as FormView;
62
63
  setFormView(formView);
63
- const { fields, arch } = formView;
64
-
65
- const values = (
66
- await ConnectionProvider.getHandler().readObjects({
67
- model,
68
- ids: [id],
69
- fields,
70
- context,
71
- })
72
- )[0];
73
-
74
- setTargetValues({ ...processValues(values, fields), active_id: id });
64
+ let fields: string[] = [];
65
+ const { toolbar } = formView;
66
+ toolbar.action?.filter((item: any) => item.hasOwnProperty('context')).map((item: any) => fields.push(...parseContextFields(item.context)));
67
+ toolbar.action?.filter((item: any) => item.hasOwnProperty('domain')).map((item: any) => fields.push(...parseDomainFields(item.domain)));
68
+ toolbar.relate?.filter((item: any) => item.hasOwnProperty('context')).map((item: any) => fields.push(...parseContextFields(item.context)));
69
+ toolbar.relate?.filter((item: any) => item.hasOwnProperty('domain')).map((item: any) => fields.push(...parseDomainFields(item.domain)));
70
+ toolbar.print?.filter((item: any) => item.hasOwnProperty('context')).map((item: any) => fields.push(...parseContextFields(item.context)));
71
+ fields = fields.filter((i) => Object.keys(formView.fields).indexOf(i) > -1)
72
+
73
+ let values = {}
74
+
75
+ if (fields.length > 0) {
76
+ values = (
77
+ await ConnectionProvider.getHandler().readObjects({
78
+ model,
79
+ ids: [id],
80
+ fieldsToRetrieve: fields,
81
+ context,
82
+ })
83
+ )[0];
84
+ }
85
+ values = { ...processValues(values, fields), active_id: id };
86
+ setTargetValues(values);
75
87
 
76
88
  setIsLoading(false);
77
89
  } catch (err) {
@@ -437,11 +437,19 @@ const One2manyInput: React.FC<One2manyInputProps> = (
437
437
  const onFormModalSubmitSucceed = (
438
438
  id: number | undefined,
439
439
  _: any,
440
- values: any
440
+ values: any,
441
+ x2manyPendingLink: boolean = false
441
442
  ) => {
442
443
  let updatedItems: One2manyItem[];
443
444
 
444
- if (id) {
445
+ if (x2manyPendingLink) {
446
+ updatedItems = items.concat({
447
+ id,
448
+ operation: "pendingLink",
449
+ values: { ...values, id },
450
+ treeValues: { ...values, id },
451
+ });
452
+ } else if (id) {
445
453
  updatedItems = items.map((item: One2manyItem) => {
446
454
  if (item.id === id) {
447
455
  return {
@@ -683,7 +691,7 @@ const One2manyInput: React.FC<One2manyInputProps> = (
683
691
  formView={views.get("form")}
684
692
  model={relation}
685
693
  id={modalItem?.id}
686
- submitMode={"values"}
694
+ submitMode={"2many"}
687
695
  values={modalItem?.values}
688
696
  defaultValues={modalItem?.defaultValues}
689
697
  visible={showFormModal}
@@ -10,7 +10,6 @@ type AvatarProps = WidgetProps & {
10
10
  };
11
11
 
12
12
  const Avatar = (props: AvatarProps): React.ReactElement | null => {
13
- console.log("Avatar Props", props);
14
13
  const {ooui, value} = props;
15
14
  if (!value) {
16
15
  return null;
@@ -0,0 +1,144 @@
1
+ import React, {useContext} from "react";
2
+ import Field from "@/common/Field";
3
+ import { WidgetProps } from "@/types";
4
+ import {Card, Space, Typography, Avatar, Tag, Timeline, TimelineItemProps} from "antd"
5
+ import { LocaleContext, LocaleContextType } from "@/context/LocaleContext";
6
+
7
+ const { Meta } = Card;
8
+ const { Text} = Typography;
9
+
10
+ import dayjs from "dayjs";
11
+ import relativeTime from "dayjs/plugin/relativeTime";
12
+ import md5 from "md5";
13
+
14
+
15
+ dayjs.extend(relativeTime);
16
+
17
+ type GravatarProps = {
18
+ email: string,
19
+ size?: number,
20
+ theme: string,
21
+ }
22
+
23
+ type CommentDataType = {
24
+ id: number,
25
+ isSender: boolean,
26
+ isAuthor: boolean,
27
+ text: string,
28
+ email: string,
29
+ date: string,
30
+ author: string,
31
+ }
32
+
33
+ type CommentProps = {
34
+ data: CommentDataType,
35
+ style?: any,
36
+ }
37
+
38
+ type CommentsTypeProps = {
39
+ data: CommentDataType[],
40
+ }
41
+
42
+ type CommentsTimelineProps = {
43
+ value?: EventsType[],
44
+ }
45
+
46
+
47
+ type EventActionType = {
48
+ date: string,
49
+ action: string,
50
+ }
51
+
52
+ export type EventsType = {
53
+ type: "action" | "comment",
54
+ event: EventActionType | CommentDataType
55
+
56
+ }
57
+
58
+ const Gravatar = ({ email, size = 40, theme = '' } : GravatarProps) => {
59
+ // Genera el enlace de Gravatar utilizando el email
60
+ const gravatarUrl = `https://www.gravatar.com/avatar/${md5(email)}?s=${size}&d=${theme}`;
61
+
62
+ return (
63
+ <Avatar src={gravatarUrl} size={size} />
64
+ );
65
+ };
66
+
67
+
68
+ function TextWithNewlines({ text }:{text: string}) {
69
+ const textParts = text.split('\n');
70
+
71
+ return (
72
+ <div>
73
+ {textParts.map((part, index) => (
74
+ <React.Fragment key={index}>
75
+ {part}
76
+ {index !== textParts.length - 1 && <br />}
77
+ </React.Fragment>
78
+ ))}
79
+ </div>
80
+ );
81
+ }
82
+
83
+ export const Comment = (props: CommentProps) => {
84
+ const {data, style} = props;
85
+ const { t } = useContext(LocaleContext) as LocaleContextType;
86
+ return (
87
+ <Card key={data.id} style={{...style, ...{textAlign: 'start'}}}>
88
+ <Meta avatar={<Gravatar email={data.email} theme='mp'/>}
89
+ title={data.author}
90
+ description={(
91
+ <Space direction="horizontal">
92
+ <span title={data.date}>{dayjs(data.date).fromNow()}</span>
93
+ {data.isAuthor && <Tag color="blue">{t('author')}</Tag>}
94
+ </Space>
95
+ )} style={{marginBottom: '5px'}}/>
96
+ <Text>
97
+ <TextWithNewlines text={data.text} />
98
+ </Text>
99
+ </Card>
100
+ )
101
+ }
102
+
103
+ export const Comments = (props: CommentsTypeProps) => {
104
+ const { data = [] } = props;
105
+ const comments = data.map((c) => {
106
+ const style = {float: c.isSender ? 'right' : 'left', width: '60%'};
107
+ return <Comment data={c} style={style}/>
108
+ });
109
+ return (
110
+ <div>
111
+ <Space direction="vertical" size="middle" style={{ display: 'flex' }}>
112
+ {comments}
113
+ </Space>
114
+ </div>
115
+ )
116
+ }
117
+
118
+
119
+ export const CommentsTimeline = (props: CommentsTimelineProps) => {
120
+ const { value } = props;
121
+ const items = (value || []).map(i => {
122
+ if (i.type === 'action') {
123
+ return {
124
+ children: `${i.event.date} - ${(i.event as EventActionType).action}`
125
+ }
126
+ } else if (i.type === "comment") {
127
+ return {
128
+ color: 'gray',
129
+ position: (i.event as CommentDataType).isSender ? 'left' : 'right',
130
+ label: i.event.date,
131
+ children: <Comment data={i.event as CommentDataType} />,
132
+ }
133
+ }
134
+ })
135
+ return <Timeline mode="alternate" items={items as TimelineItemProps[]} />
136
+ }
137
+
138
+ export const CommentsTimelineField = (props: WidgetProps) => {
139
+ return (
140
+ <Field {...props}>
141
+ <CommentsTimeline />
142
+ </Field>
143
+ );
144
+ }
@@ -67,8 +67,13 @@ export type FormProps = {
67
67
  showFooter?: boolean;
68
68
  getDataFromAction?: boolean;
69
69
  mustClearAfterSave?: boolean;
70
- submitMode?: "api" | "values";
71
- onSubmitSucceed?: (id?: number, values?: any, formValues?: any) => void;
70
+ submitMode?: "api" | "values" | "2many";
71
+ onSubmitSucceed?: (
72
+ id?: number,
73
+ values?: any,
74
+ formValues?: any,
75
+ x2manyPendingLink?: boolean
76
+ ) => void;
72
77
  onSubmitError?: (error: any) => void;
73
78
  onCancel?: () => void;
74
79
  onFieldsChange?: (values: any) => void;
@@ -127,6 +132,7 @@ function Form(props: FormProps, ref: any) {
127
132
  const lastAssignedValues = useRef<any>({});
128
133
  const warningIsShown = useRef<boolean>(false);
129
134
  const formSubmitting = useRef<boolean>(false);
135
+ const x2manyPendingLink = useRef<boolean>(false);
130
136
 
131
137
  const widthToEvaluate =
132
138
  parentWidth !== undefined ? parentWidth : containerWidth;
@@ -203,10 +209,15 @@ function Form(props: FormProps, ref: any) {
203
209
  }
204
210
  }, [defaultGetCalled]);
205
211
 
206
- const onSubmitSucceed = (id?: number, values?: any, formValues?: any) => {
212
+ const onSubmitSucceed = (
213
+ id?: number,
214
+ values?: any,
215
+ formValues?: any,
216
+ x2manyPendingLink?: boolean
217
+ ) => {
207
218
  setFormHasChanges?.(false);
208
219
  setFormIsSaving?.(false);
209
- propsOnSubmitSucceed?.(id, values, formValues);
220
+ propsOnSubmitSucceed?.(id, values, formValues, x2manyPendingLink);
210
221
  setCurrentId?.(id);
211
222
  };
212
223
 
@@ -294,6 +305,15 @@ function Form(props: FormProps, ref: any) {
294
305
  return { ...parentContext, ...formOoui?.context };
295
306
  }
296
307
 
308
+ function getActiveIdsContext() {
309
+ const currentId = getCurrentId()!;
310
+
311
+ if (!currentId) {
312
+ return {};
313
+ }
314
+ return { active_id: getCurrentId()!, active_ids: [getCurrentId()!] };
315
+ }
316
+
297
317
  function getAdditionalValues() {
298
318
  return {
299
319
  id: getCurrentId()!,
@@ -608,6 +628,32 @@ function Form(props: FormProps, ref: any) {
608
628
  formSubmitting.current = true;
609
629
 
610
630
  setError(undefined);
631
+
632
+ if (
633
+ x2manyPendingLink.current &&
634
+ !formHasChanges() &&
635
+ getCurrentId()! &&
636
+ callOnSubmitSucceed
637
+ ) {
638
+ formSubmitting.current = false;
639
+ setFormHasChanges?.(false);
640
+ onSubmitSucceed?.(
641
+ getCurrentId(),
642
+ getValues(),
643
+ getFormValues(),
644
+ x2manyPendingLink.current
645
+ );
646
+ x2manyPendingLink.current = false;
647
+ const currentId = getCurrentId()!;
648
+
649
+ if (mustClearAfterSave) {
650
+ createdId.current = undefined;
651
+ assignNewValuesToForm({ values: {}, fields, reset: true });
652
+ }
653
+
654
+ return { succeed: true, id: currentId };
655
+ }
656
+
611
657
  if (!formHasChanges() && getCurrentId()! && callOnSubmitSucceed) {
612
658
  formSubmitting.current = false;
613
659
  setFormHasChanges?.(false);
@@ -659,15 +705,17 @@ function Form(props: FormProps, ref: any) {
659
705
  fields,
660
706
  arch,
661
707
  values,
708
+ operationInProgress = false,
662
709
  }: {
663
710
  arch: string;
664
711
  fields: any;
665
712
  values: any;
713
+ operationInProgress?: boolean;
666
714
  }) => {
667
715
  const ooui = new FormOoui(fields);
668
716
  // TODO: Here we must inject `values` to the ooui parser in order to evaluate arch+values and get the new form container
669
717
  ooui.parse(arch, {
670
- readOnly,
718
+ readOnly: readOnly || operationInProgress,
671
719
  values: convertToPlain2ManyValues(
672
720
  {
673
721
  ...values,
@@ -833,9 +881,9 @@ function Form(props: FormProps, ref: any) {
833
881
  action,
834
882
  payload: [getCurrentId()!],
835
883
  context: {
836
- ...context,
837
884
  ...formOoui?.context,
838
885
  ...parentContext,
886
+ ...context,
839
887
  },
840
888
  });
841
889
 
@@ -934,6 +982,15 @@ function Form(props: FormProps, ref: any) {
934
982
  checkFieldsChanges({ elementHasLostFocus: true });
935
983
  }
936
984
 
985
+ function updateOperationInProgress(value: boolean) {
986
+ parseForm({
987
+ fields,
988
+ arch: arch!,
989
+ values: getCurrentValues(fields),
990
+ operationInProgress: value,
991
+ });
992
+ }
993
+
937
994
  async function executeButtonAction({
938
995
  type,
939
996
  action,
@@ -955,19 +1012,36 @@ function Form(props: FormProps, ref: any) {
955
1012
  return;
956
1013
  }
957
1014
 
1015
+ let mustBlockButtons = false;
1016
+
958
1017
  try {
959
1018
  if (formHasChanges() || getCurrentId() === undefined) {
960
- await submitForm({ callOnSubmitSucceed: false });
1019
+ mustBlockButtons = true;
1020
+ updateOperationInProgress(true);
1021
+ if (submitMode === "2many") {
1022
+ await submitApi({ callOnSubmitSucceed: false });
1023
+ x2manyPendingLink.current = true;
1024
+ } else {
1025
+ await submitForm({ callOnSubmitSucceed: false });
1026
+ }
961
1027
  }
962
1028
 
1029
+ const additionalContext = x2manyPendingLink.current
1030
+ ? getActiveIdsContext()
1031
+ : {};
1032
+
1033
+ const updatedContext = { ...context, ...additionalContext };
1034
+
963
1035
  if (type === "object") {
964
- await runObjectButton({ action, context });
1036
+ await runObjectButton({ action, context: updatedContext });
965
1037
  } else if (type === "workflow") {
966
1038
  await runWorkflowButton({ action });
967
1039
  } else if (type === "action") {
968
- await runActionButton({ action, context });
1040
+ await runActionButton({ action, context: updatedContext });
969
1041
  }
1042
+ mustBlockButtons && updateOperationInProgress(false);
970
1043
  } catch (err) {
1044
+ mustBlockButtons && updateOperationInProgress(false);
971
1045
  showErrorDialog(err);
972
1046
  }
973
1047
  }
@@ -297,7 +297,7 @@ function CommonIndicator({
297
297
  fontSize = maxFontSize;
298
298
  }
299
299
 
300
- const IconElement: any = icon && iconMapper(icon);
300
+ const IconElement: any = icon && iconMapper(icon, {style: {fontSize: fontSize * 0.7}});
301
301
 
302
302
  return (
303
303
  <div
@@ -373,13 +373,13 @@ function PercentageIndicator({
373
373
  tw = tw * 1.5;
374
374
  }
375
375
 
376
- const IconElement: any = icon && iconMapper(icon);
377
-
378
376
  if (tw >= width * 0.85 || fontSize * 2 < twoLinesHeight) {
379
377
  const maxFontSize = ((width * 0.85) / tw) * fontSize;
380
378
  fontSize = maxFontSize;
381
379
  }
382
380
 
381
+ const IconElement: any = icon && iconMapper(icon, {style: {fontSize}});
382
+
383
383
  return (
384
384
  <div
385
385
  ref={measureRef}
@@ -125,10 +125,11 @@ function SearchTree(props: Props, ref: any) {
125
125
  colorsForResults,
126
126
  statusForResults,
127
127
  totalItems,
128
+ getAllIds,
128
129
  } = useSearch({
129
130
  model: currentModel!,
130
131
  setSearchTreeNameSearch,
131
- setSelectedRowItems,
132
+ setSelectedRowItems: changeSelectedRowKeys,
132
133
  setSearchParams,
133
134
  setSearchValues,
134
135
  searchParams,
@@ -182,9 +183,9 @@ function SearchTree(props: Props, ref: any) {
182
183
  setInitialFetchDone(true);
183
184
  } catch (error) {
184
185
  setInitialError(error);
186
+ setTreeIsLoading?.(false);
185
187
  } finally {
186
188
  setIsLoading(false);
187
- setTreeIsLoading?.(false);
188
189
  }
189
190
  };
190
191
 
@@ -269,13 +270,16 @@ function SearchTree(props: Props, ref: any) {
269
270
  };
270
271
 
271
272
  function changeSelectedRowKeys(selectedRowKeys: any[]) {
272
- const selectedRowItems = getResults().filter((entry: any) =>
273
- selectedRowKeys.includes(entry.id)
274
- );
275
- setSelectedRowItems?.(selectedRowItems);
273
+ setSelectedRowItems?.(selectedRowKeys.map((id: number) => ({ id })));
276
274
  onChangeSelectedRowKeys?.(selectedRowKeys);
277
275
  }
278
276
 
277
+ async function selectAllRecords() {
278
+ const allIds = await getAllIds();
279
+ setSelectedRowItems?.(allIds.map((id: number) => ({ id })));
280
+ onChangeSelectedRowKeys?.(allIds);
281
+ }
282
+
279
283
  function calculateTableHeight() {
280
284
  if (treeView?.isExpandable) {
281
285
  return height - 160;
@@ -291,12 +295,11 @@ function SearchTree(props: Props, ref: any) {
291
295
  return (
292
296
  <>
293
297
  <SearchFilter
294
- fields={{ ...treeView.fields, ...formView.fields }}
298
+ fields={{ ...formView.fields, ...treeView.fields }}
295
299
  searchFields={mergeSearchFields([
296
300
  formView.search_fields,
297
301
  treeView.search_fields,
298
302
  ])}
299
- formXml={formView.arch}
300
303
  onClear={clear}
301
304
  limit={limit}
302
305
  offset={offset}
@@ -332,6 +335,7 @@ function SearchTree(props: Props, ref: any) {
332
335
  }
333
336
  childField={treeView.field_parent}
334
337
  rootTree={rootTree}
338
+ onSelectAllRecords={selectAllRecords}
335
339
  />
336
340
  </>
337
341
  );