box-ui-elements 23.3.1-beta.1 → 23.4.0-beta.2

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 (92) hide show
  1. package/dist/explorer.js +1 -1
  2. package/dist/preview.js +1 -1
  3. package/dist/sharing.js +1 -1
  4. package/dist/sharing.js.LICENSE.txt +10 -0
  5. package/dist/sidebar.js +1 -1
  6. package/es/common/types/metadata.js.flow +1 -0
  7. package/es/common/types/metadata.js.map +1 -1
  8. package/es/components/notification/Notification.js +17 -8
  9. package/es/components/notification/Notification.js.flow +15 -8
  10. package/es/components/notification/Notification.js.map +1 -1
  11. package/es/features/metadata-instance-editor/CascadePolicy.js +6 -2
  12. package/es/features/metadata-instance-editor/CascadePolicy.js.flow +19 -12
  13. package/es/features/metadata-instance-editor/CascadePolicy.js.map +1 -1
  14. package/es/features/metadata-instance-editor/Instance.js +31 -9
  15. package/es/features/metadata-instance-editor/Instance.js.flow +41 -9
  16. package/es/features/metadata-instance-editor/Instance.js.map +1 -1
  17. package/es/features/metadata-instance-editor/Instances.js +2 -0
  18. package/es/features/metadata-instance-editor/Instances.js.flow +3 -0
  19. package/es/features/metadata-instance-editor/Instances.js.map +1 -1
  20. package/es/features/metadata-instance-editor/MetadataInstanceEditor.js +2 -0
  21. package/es/features/metadata-instance-editor/MetadataInstanceEditor.js.flow +3 -0
  22. package/es/features/metadata-instance-editor/MetadataInstanceEditor.js.map +1 -1
  23. package/es/features/metadata-instance-editor/TemplateDropdown.js +1 -1
  24. package/es/features/metadata-instance-editor/TemplateDropdown.js.flow +1 -1
  25. package/es/features/metadata-instance-editor/TemplateDropdown.js.map +1 -1
  26. package/es/features/metadata-instance-editor/TemplatedInstance.js +2 -0
  27. package/es/features/metadata-instance-editor/TemplatedInstance.js.flow +11 -1
  28. package/es/features/metadata-instance-editor/TemplatedInstance.js.map +1 -1
  29. package/es/features/metadata-instance-editor/constants.js +2 -1
  30. package/es/features/metadata-instance-editor/constants.js.flow +3 -1
  31. package/es/features/metadata-instance-editor/constants.js.map +1 -1
  32. package/es/features/metadata-instance-fields/DateMetadataField.js +30 -25
  33. package/es/features/metadata-instance-fields/DateMetadataField.js.flow +31 -27
  34. package/es/features/metadata-instance-fields/DateMetadataField.js.map +1 -1
  35. package/es/features/metadata-instance-fields/EnumMetadataField.js +8 -5
  36. package/es/features/metadata-instance-fields/EnumMetadataField.js.flow +8 -6
  37. package/es/features/metadata-instance-fields/EnumMetadataField.js.map +1 -1
  38. package/es/features/metadata-instance-fields/FloatMetadataField.js +2 -0
  39. package/es/features/metadata-instance-fields/FloatMetadataField.js.flow +3 -0
  40. package/es/features/metadata-instance-fields/FloatMetadataField.js.map +1 -1
  41. package/es/features/metadata-instance-fields/IntegerMetadataField.js +2 -0
  42. package/es/features/metadata-instance-fields/IntegerMetadataField.js.flow +3 -0
  43. package/es/features/metadata-instance-fields/IntegerMetadataField.js.map +1 -1
  44. package/es/features/metadata-instance-fields/MetadataField.js +7 -0
  45. package/es/features/metadata-instance-fields/MetadataField.js.flow +8 -0
  46. package/es/features/metadata-instance-fields/MetadataField.js.map +1 -1
  47. package/es/features/metadata-instance-fields/MultiSelectMetadataField.js +2 -0
  48. package/es/features/metadata-instance-fields/MultiSelectMetadataField.js.flow +3 -0
  49. package/es/features/metadata-instance-fields/MultiSelectMetadataField.js.map +1 -1
  50. package/es/features/metadata-instance-fields/TextMetadataField.js +8 -5
  51. package/es/features/metadata-instance-fields/TextMetadataField.js.flow +8 -6
  52. package/es/features/metadata-instance-fields/TextMetadataField.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/common/types/metadata.js +1 -0
  55. package/src/components/notification/Notification.js +15 -8
  56. package/src/components/notification/__tests__/Notification.test.js +21 -1
  57. package/src/features/metadata-instance-editor/CascadePolicy.js +19 -12
  58. package/src/features/metadata-instance-editor/Instance.js +41 -9
  59. package/src/features/metadata-instance-editor/Instances.js +3 -0
  60. package/src/features/metadata-instance-editor/MetadataInstanceEditor.js +3 -0
  61. package/src/features/metadata-instance-editor/TemplateDropdown.js +1 -1
  62. package/src/features/metadata-instance-editor/TemplatedInstance.js +11 -1
  63. package/src/features/metadata-instance-editor/__tests__/CascadePolicy.test.js +92 -1
  64. package/src/features/metadata-instance-editor/__tests__/Instance.test.js +207 -2
  65. package/src/features/metadata-instance-editor/__tests__/Instances.test.js +92 -3
  66. package/src/features/metadata-instance-editor/__tests__/MetadataInstanceEditor.test.js +105 -0
  67. package/src/features/metadata-instance-editor/__tests__/TemplatedInstance.test.js +83 -1
  68. package/src/features/metadata-instance-editor/__tests__/__snapshots__/CascadePolicy.test.js.snap +1 -0
  69. package/src/features/metadata-instance-editor/__tests__/__snapshots__/Instance.test.js.snap +16 -5
  70. package/src/features/metadata-instance-editor/__tests__/__snapshots__/Instances.test.js.snap +4 -2
  71. package/src/features/metadata-instance-editor/__tests__/__snapshots__/MetadataInstanceEditor.test.js.snap +1 -0
  72. package/src/features/metadata-instance-editor/__tests__/__snapshots__/TemplatedInstance.test.js.snap +2 -2
  73. package/src/features/metadata-instance-editor/constants.js +3 -1
  74. package/src/features/metadata-instance-fields/DateMetadataField.js +31 -27
  75. package/src/features/metadata-instance-fields/EnumMetadataField.js +8 -6
  76. package/src/features/metadata-instance-fields/FloatMetadataField.js +3 -0
  77. package/src/features/metadata-instance-fields/IntegerMetadataField.js +3 -0
  78. package/src/features/metadata-instance-fields/MetadataField.js +8 -0
  79. package/src/features/metadata-instance-fields/MultiSelectMetadataField.js +3 -0
  80. package/src/features/metadata-instance-fields/TextMetadataField.js +8 -6
  81. package/src/features/metadata-instance-fields/__tests__/DateMetadataField.test.js +59 -8
  82. package/src/features/metadata-instance-fields/__tests__/EnumMetadataField.test.js +63 -18
  83. package/src/features/metadata-instance-fields/__tests__/FloatMetadataField.test.js +68 -4
  84. package/src/features/metadata-instance-fields/__tests__/IntegerMetadataField.test.js +90 -4
  85. package/src/features/metadata-instance-fields/__tests__/MultiSelectMetadataField.test.js +95 -7
  86. package/src/features/metadata-instance-fields/__tests__/TextMetadataField.test.js +107 -14
  87. package/src/features/metadata-instance-fields/__tests__/__snapshots__/DateMetadataField.test.js.snap +0 -18
  88. package/src/features/metadata-instance-fields/__tests__/__snapshots__/EnumMetadataField.test.js.snap +0 -84
  89. package/src/features/metadata-instance-fields/__tests__/__snapshots__/FloatMetadataField.test.js.snap +0 -8
  90. package/src/features/metadata-instance-fields/__tests__/__snapshots__/IntegerMetadataField.test.js.snap +0 -8
  91. package/src/features/metadata-instance-fields/__tests__/__snapshots__/MultiSelectMetadataField.test.js.snap +0 -58
  92. package/src/features/metadata-instance-fields/__tests__/__snapshots__/TextMetadataField.test.js.snap +0 -31
@@ -13,12 +13,21 @@ type Props = {
13
13
  canEdit: boolean,
14
14
  data: MetadataFields,
15
15
  errors: { [string]: React.Node },
16
+ isDisabled?: boolean,
16
17
  onFieldChange?: (key: string, value: MetadataFieldValue, type: string) => void,
17
18
  onFieldRemove?: (key: string) => void,
18
19
  template: MetadataTemplate,
19
20
  };
20
21
 
21
- const TemplatedInstance = ({ canEdit, data = {}, errors, onFieldChange, onFieldRemove, template }: Props) => {
22
+ const TemplatedInstance = ({
23
+ canEdit,
24
+ data = {},
25
+ errors,
26
+ isDisabled,
27
+ onFieldChange,
28
+ onFieldRemove,
29
+ template,
30
+ }: Props) => {
22
31
  const { fields = [] } = template;
23
32
  const hasFields = fields.length > 0;
24
33
  const hasVisibleFields = hasFields && fields.some(field => !isHidden(field));
@@ -39,6 +48,7 @@ const TemplatedInstance = ({ canEdit, data = {}, errors, onFieldChange, onFieldR
39
48
  description={field.description}
40
49
  displayName={field.displayName}
41
50
  error={errors[field.key]}
51
+ isDisabled={isDisabled}
42
52
  isHidden={isHidden(field)} // Checking both isHidden and hidden attributes due to differences in V2 and V3 APIs
43
53
  onChange={(key: string, value: MetadataFieldValue) => {
44
54
  if (canEdit && onFieldChange) {
@@ -1,5 +1,7 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import userEvent from '@testing-library/user-event';
4
+
3
5
  import { screen, render, within } from '../../../test-utils/testing-library';
4
6
 
5
7
  import CascadePolicy from '../CascadePolicy';
@@ -95,8 +97,97 @@ describe('features/metadata-instance-editor/CascadePolicy', () => {
95
97
 
96
98
  describe('AI Agent Selector', () => {
97
99
  test('should render AI agent selector with default to basic when AI features are enabled', () => {
98
- render(<CascadePolicy canEdit canUseAIFolderExtraction shouldShowCascadeOptions />);
100
+ render(
101
+ <CascadePolicy
102
+ canEdit
103
+ canUseAIFolderExtraction
104
+ canUseAIFolderExtractionAgentSelector
105
+ shouldShowCascadeOptions
106
+ />,
107
+ );
99
108
  expect(screen.getByRole('button', { name: 'Agent Basic' })).toBeInTheDocument();
100
109
  });
110
+
111
+ test('should not render AI agent selector when canUseAIFolderExtractionAgentSelector is false', () => {
112
+ render(<CascadePolicy canEdit canUseAIFolderExtraction shouldShowCascadeOptions />);
113
+ expect(screen.queryByRole('button', { name: 'Agent Basic' })).not.toBeInTheDocument();
114
+ });
115
+ });
116
+
117
+ describe('AI Autofill Toggle', () => {
118
+ test('should disable toggle when isExistingAIExtractionCascadePolicy is true', () => {
119
+ render(
120
+ <CascadePolicy
121
+ canEdit
122
+ canUseAIFolderExtraction
123
+ shouldShowCascadeOptions
124
+ isExistingAIExtractionCascadePolicy
125
+ />,
126
+ );
127
+
128
+ const aiSection = screen.getByTestId('ai-folder-extraction');
129
+ const toggle = within(aiSection).getByRole('switch');
130
+
131
+ expect(toggle).toBeDisabled();
132
+ });
133
+
134
+ test('should enable toggle when isExistingAIExtractionCascadePolicy is false', () => {
135
+ render(
136
+ <CascadePolicy
137
+ canEdit
138
+ canUseAIFolderExtraction
139
+ shouldShowCascadeOptions
140
+ isExistingAIExtractionCascadePolicy={false}
141
+ />,
142
+ );
143
+
144
+ const aiSection = screen.getByTestId('ai-folder-extraction');
145
+ const toggle = within(aiSection).getByRole('switch');
146
+
147
+ expect(toggle).not.toBeDisabled();
148
+ });
149
+
150
+ test('should call onAIFolderExtractionToggle when toggle is clicked and enabled', async () => {
151
+ const onAIFolderExtractionToggle = jest.fn();
152
+
153
+ render(
154
+ <CascadePolicy
155
+ canEdit
156
+ canUseAIFolderExtraction
157
+ shouldShowCascadeOptions
158
+ isExistingAIExtractionCascadePolicy={false}
159
+ onAIFolderExtractionToggle={onAIFolderExtractionToggle}
160
+ />,
161
+ );
162
+
163
+ const aiSection = screen.getByTestId('ai-folder-extraction');
164
+ const toggle = within(aiSection).getByRole('switch');
165
+
166
+ await userEvent.click(toggle);
167
+
168
+ expect(onAIFolderExtractionToggle).toHaveBeenCalledTimes(1);
169
+ expect(onAIFolderExtractionToggle).toHaveBeenCalledWith(true);
170
+ });
171
+
172
+ test('should not call onAIFolderExtractionToggle when toggle is clicked but disabled', async () => {
173
+ const onAIFolderExtractionToggle = jest.fn();
174
+
175
+ render(
176
+ <CascadePolicy
177
+ canEdit
178
+ canUseAIFolderExtraction
179
+ shouldShowCascadeOptions
180
+ isExistingAIExtractionCascadePolicy={true}
181
+ onAIFolderExtractionToggle={onAIFolderExtractionToggle}
182
+ />,
183
+ );
184
+
185
+ const aiSection = screen.getByTestId('ai-folder-extraction');
186
+ const toggle = within(aiSection).getByRole('switch');
187
+
188
+ await userEvent.click(toggle);
189
+
190
+ expect(onAIFolderExtractionToggle).not.toHaveBeenCalled();
191
+ });
101
192
  });
102
193
  });
@@ -1,9 +1,13 @@
1
1
  import * as React from 'react';
2
-
3
- import TEMPLATE_CUSTOM_PROPERTIES from '../constants';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { createIntl } from 'react-intl';
4
+ import { render, screen, within } from '../../../test-utils/testing-library';
5
+ import { CASCADE_POLICY_TYPE_AI_EXTRACT, TEMPLATE_CUSTOM_PROPERTIES } from '../constants';
4
6
  import { InstanceBase as Instance } from '../Instance';
5
7
  import { isValidValue } from '../../metadata-instance-fields/validateMetadataField';
6
8
 
9
+ // Add RTL imports
10
+
7
11
  jest.mock('../../metadata-instance-fields/validateMetadataField');
8
12
 
9
13
  const data = {
@@ -718,3 +722,204 @@ describe('features/metadata-instance-editor/fields/Instance', () => {
718
722
  });
719
723
  });
720
724
  });
725
+
726
+ // New RTL tests
727
+ const testFields = [
728
+ {
729
+ id: 'field1',
730
+ type: 'string',
731
+ key: 'stringfield',
732
+ displayName: 'String Field',
733
+ description: 'example of a string field',
734
+ },
735
+ {
736
+ id: 'field2',
737
+ type: 'float',
738
+ key: 'floatfield',
739
+ displayName: 'Float Field',
740
+ description: 'example of a float field',
741
+ },
742
+ ];
743
+
744
+ const testData = {
745
+ stringfield: 'some string',
746
+ floatfield: 1.0,
747
+ };
748
+
749
+ const getBaseProps = (props = {}) => ({
750
+ id: 'test-instance',
751
+ canEdit: true,
752
+ data: { ...testData },
753
+ template: {
754
+ id: 'template-1',
755
+ displayName: 'Test Template',
756
+ fields: [...testFields],
757
+ templateKey: 'testTemplateKey',
758
+ },
759
+ intl: createIntl({ locale: 'en' }),
760
+ onSave: jest.fn(),
761
+ onModification: jest.fn(),
762
+ onRemove: jest.fn(),
763
+ isDirty: false,
764
+ hasError: false,
765
+ isCascadingPolicyApplicable: true,
766
+ cascadePolicy: {
767
+ id: 'policy-1',
768
+ canEdit: true,
769
+ isEnabled: true,
770
+ scope: 'enterprise_123',
771
+ cascadePolicyType: 'regular', // default to non-AI
772
+ },
773
+ canUseAIFolderExtraction: true, // Assume feature flag is on
774
+ canUseAIFolderExtractionAgentSelector: false,
775
+ ...props,
776
+ });
777
+
778
+ describe('Instance Component - React Testing Library', () => {
779
+ beforeEach(() => {
780
+ jest.clearAllMocks();
781
+ isValidValue.mockReturnValue(true); // Default mock for isValidValue
782
+ });
783
+
784
+ describe('Initialization based on cascadePolicy.cascadePolicyType', () => {
785
+ test('should initialize with AI folder extraction enabled and fields disabled if cascadePolicyType is "ai_extract"', async () => {
786
+ render(
787
+ <Instance
788
+ {...getBaseProps({
789
+ cascadePolicy: {
790
+ id: 'policy-ai',
791
+ canEdit: true,
792
+ isEnabled: true,
793
+ scope: 'enterprise_123',
794
+ cascadePolicyType: CASCADE_POLICY_TYPE_AI_EXTRACT,
795
+ },
796
+ })}
797
+ />,
798
+ );
799
+
800
+ // Click Edit button to enable editing
801
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' }); // Assuming 'Edit Metadata' is the rendered name
802
+ await userEvent.click(editButton);
803
+
804
+ // Fields should be disabled because AI extraction is on by default from policy
805
+ // Input fields are part of TemplatedInstance, which is only rendered if Collapsible is open.
806
+ // Default state has isOpen true if not specified or based on single field length.
807
+ // Let's assume it's open.
808
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).toBeDisabled();
809
+ expect(screen.getByRole('textbox', { name: 'Float Field example of a float field' })).toBeDisabled();
810
+ });
811
+
812
+ test('should initialize with AI folder extraction disabled and fields enabled if cascadePolicyType is not "ai_extract"', async () => {
813
+ render(<Instance {...getBaseProps()} />); // default policy is not 'ai_extract'
814
+
815
+ // Click Edit button to enable editing
816
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' }); // Assuming 'Edit Metadata' is the rendered name
817
+ await userEvent.click(editButton);
818
+
819
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).not.toBeDisabled();
820
+ expect(screen.getByRole('textbox', { name: 'Float Field example of a float field' })).not.toBeDisabled();
821
+ });
822
+
823
+ test('should initialize with AI folder extraction disabled if cascadePolicy is undefined', async () => {
824
+ render(<Instance {...getBaseProps({ cascadePolicy: undefined, isCascadingPolicyApplicable: false })} />);
825
+
826
+ // Click Edit button to enable editing
827
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' }); // Assuming 'Edit Metadata' is the rendered name
828
+ await userEvent.click(editButton);
829
+
830
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).not.toBeDisabled();
831
+ expect(screen.getByRole('textbox', { name: 'Float Field example of a float field' })).not.toBeDisabled();
832
+ });
833
+ });
834
+
835
+ describe('AI Folder Extraction Toggle Interaction', () => {
836
+ test('should toggle AI folder extraction, disable/enable fields', async () => {
837
+ render(<Instance {...getBaseProps()} />);
838
+
839
+ // Click Edit button to enable editing
840
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' }); // Assuming 'Edit Metadata' is the rendered name
841
+ await userEvent.click(editButton);
842
+
843
+ // Initially, fields are enabled as default policy is not 'ai_extract'
844
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).not.toBeDisabled();
845
+
846
+ const aiSection = screen.getByTestId('ai-folder-extraction');
847
+ const aiToggle = within(aiSection).getByRole('switch');
848
+
849
+ // Turn AI toggle ON
850
+ await userEvent.click(aiToggle);
851
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).toBeDisabled();
852
+
853
+ // Turn AI toggle OFF
854
+ await userEvent.click(aiToggle);
855
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).not.toBeDisabled();
856
+ });
857
+ });
858
+
859
+ describe('Props passed to CascadePolicy', () => {
860
+ test('should pass canUseAIFolderExtractionAgentSelector to CascadePolicy', async () => {
861
+ render(<Instance {...getBaseProps({ canUseAIFolderExtractionAgentSelector: true })} />);
862
+
863
+ const editButton = screen.queryByRole('button', { name: 'Edit Metadata' });
864
+ if (editButton) await userEvent.click(editButton); // Enter edit mode to ensure CascadePolicy options are visible
865
+
866
+ expect(screen.getByRole('button', { name: 'Agent Basic' })).toBeInTheDocument();
867
+ });
868
+
869
+ test('should pass isExistingAIExtractionCascadePolicy=true to CascadePolicy if policy is ai_extract', async () => {
870
+ render(
871
+ <Instance
872
+ {...getBaseProps({
873
+ cascadePolicy: {
874
+ id: 'policy-ai',
875
+ canEdit: true,
876
+ isEnabled: true,
877
+ scope: 'enterprise_123',
878
+ cascadePolicyType: CASCADE_POLICY_TYPE_AI_EXTRACT,
879
+ },
880
+ })}
881
+ />,
882
+ );
883
+ const editButton = screen.queryByRole('button', { name: 'Edit Metadata' });
884
+ if (editButton) await userEvent.click(editButton);
885
+
886
+ const aiSection = screen.getByTestId('ai-folder-extraction');
887
+ const aiToggle = within(aiSection).getByRole('switch');
888
+ expect(aiToggle).toBeDisabled();
889
+ });
890
+
891
+ test('should pass isExistingAIExtractionCascadePolicy=false to CascadePolicy if policy is not ai_extract', async () => {
892
+ render(<Instance {...getBaseProps()} />);
893
+ const editButton = screen.queryByRole('button', { name: 'Edit Metadata' });
894
+ if (editButton) await userEvent.click(editButton);
895
+
896
+ const aiSection = screen.getByTestId('ai-folder-extraction');
897
+ const aiToggle = within(aiSection).getByRole('switch');
898
+ expect(aiToggle).not.toBeDisabled();
899
+ });
900
+ });
901
+
902
+ describe('Props passed to TemplatedInstance', () => {
903
+ test('should pass isDisabled=true to TemplatedInstance when AI folder extraction is enabled', async () => {
904
+ render(<Instance {...getBaseProps()} />);
905
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' });
906
+ await userEvent.click(editButton);
907
+
908
+ const aiSection = screen.getByTestId('ai-folder-extraction');
909
+ const aiToggle = within(aiSection).getByRole('switch');
910
+
911
+ await userEvent.click(aiToggle); // Turn AI ON
912
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).toBeDisabled();
913
+ });
914
+
915
+ test('should pass isDisabled=false to TemplatedInstance when AI folder extraction is disabled', async () => {
916
+ render(<Instance {...getBaseProps()} />);
917
+ const editButton = screen.queryByRole('button', { name: 'Edit Metadata' });
918
+ // If instance starts in non-edit mode, fields might not be interactive until edit is clicked
919
+ if (editButton) await userEvent.click(editButton);
920
+
921
+ // AI is off by default
922
+ expect(screen.getByRole('textbox', { name: 'String Field example of a string field' })).not.toBeDisabled();
923
+ });
924
+ });
925
+ });
@@ -1,4 +1,6 @@
1
1
  import * as React from 'react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { render, screen } from '../../../test-utils/testing-library';
2
4
 
3
5
  import Instances from '../Instances';
4
6
 
@@ -182,6 +184,50 @@ const editor2 = {
182
184
  // State of editors from server
183
185
  const editorsOnServer = [editor1, editor2];
184
186
 
187
+ const testInstanceFields = [
188
+ {
189
+ id: 'field1',
190
+ type: 'string',
191
+ key: 'stringfield',
192
+ displayName: 'String Field',
193
+ description: 'example of a string field',
194
+ },
195
+ ];
196
+
197
+ const getInstancesBaseProps = (props = {}) => ({
198
+ editors: [
199
+ {
200
+ instance: {
201
+ id: 'test-instance-1',
202
+ canEdit: true,
203
+ data: { stringfield: 'value1' },
204
+ isDirty: false,
205
+ hasError: false,
206
+ isCascadingPolicyApplicable: true,
207
+ cascadePolicy: {
208
+ id: 'policy-1',
209
+ canEdit: true,
210
+ isEnabled: true,
211
+ scope: 'enterprise_123',
212
+ cascadePolicyType: 'regular',
213
+ },
214
+ },
215
+ template: {
216
+ id: 'template-1',
217
+ displayName: 'Test Template Editor',
218
+ fields: testInstanceFields,
219
+ templateKey: 'editorTemplateKey',
220
+ },
221
+ },
222
+ ],
223
+ onSave: jest.fn(),
224
+ onModification: jest.fn(),
225
+ onRemove: jest.fn(),
226
+ canUseAIFolderExtraction: true,
227
+ isCascadingPolicyApplicable: true,
228
+ ...props,
229
+ });
230
+
185
231
  describe('features/metadata-editor-editor/Instances', () => {
186
232
  test('should correctly render editors', () => {
187
233
  const wrapper = shallow(<Instances editors={editorsOnServer} />);
@@ -190,18 +236,61 @@ describe('features/metadata-editor-editor/Instances', () => {
190
236
 
191
237
  test('should correctly render instances with editors and a selected template', () => {
192
238
  const wrapper = shallow(<Instances editors={editorsOnServer} selectedTemplateKey="template1" />);
193
- const selectedTemplate = wrapper.find('Instance').at(0);
239
+ const selectedTemplate = wrapper.find('injectIntl(Instance)').at(0);
194
240
  expect(selectedTemplate.prop('isOpen')).toBe(true);
195
241
  expect(selectedTemplate.prop('id')).toBe('editor1');
196
242
  });
197
243
 
198
244
  test('should correctly render instances with a selected template and multiple editors', () => {
199
245
  const wrapper = shallow(<Instances editors={editorsOnServer} selectedTemplateKey="template2" />);
200
- const selectedTemplate = wrapper.find('Instance').at(1);
246
+ const selectedTemplate = wrapper.find('injectIntl(Instance)').at(1);
201
247
  expect(selectedTemplate.prop('isOpen')).toBe(true);
202
248
  expect(selectedTemplate.prop('id')).toBe('editor2');
203
- const unselectedTemplate = wrapper.find('Instance').at(0);
249
+ const unselectedTemplate = wrapper.find('injectIntl(Instance)').at(0);
204
250
  expect(unselectedTemplate.prop('isOpen')).toBe(false);
205
251
  expect(unselectedTemplate.prop('id')).toBe('editor1');
206
252
  });
207
253
  });
254
+
255
+ describe('Instances component - canUseAIFolderExtractionAgentSelector prop', () => {
256
+ test('should pass canUseAIFolderExtractionAgentSelector to child Instance components, showing agent selector', async () => {
257
+ render(
258
+ <Instances
259
+ {...getInstancesBaseProps({
260
+ canUseAIFolderExtractionAgentSelector: true,
261
+ })}
262
+ />,
263
+ );
264
+
265
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' });
266
+ await userEvent.click(editButton);
267
+
268
+ expect(screen.getByRole('button', { name: 'Agent Basic' })).toBeInTheDocument();
269
+ });
270
+
271
+ test('should not show agent selector in child Instance if canUseAIFolderExtractionAgentSelector is false', async () => {
272
+ render(
273
+ <Instances
274
+ {...getInstancesBaseProps({
275
+ canUseAIFolderExtractionAgentSelector: false,
276
+ })}
277
+ />,
278
+ );
279
+
280
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' });
281
+ await userEvent.click(editButton);
282
+
283
+ expect(screen.queryByRole('button', { name: 'Agent Basic' })).not.toBeInTheDocument();
284
+ });
285
+
286
+ test('should not show agent selector in child Instance if canUseAIFolderExtractionAgentSelector is undefined', async () => {
287
+ const props = getInstancesBaseProps();
288
+ delete props.canUseAIFolderExtractionAgentSelector;
289
+ render(<Instances {...props} />);
290
+
291
+ const editButton = screen.getByRole('button', { name: 'Edit Metadata' });
292
+ await userEvent.click(editButton);
293
+
294
+ expect(screen.queryByRole('button', { name: 'Agent Basic' })).not.toBeInTheDocument();
295
+ });
296
+ });
@@ -1,4 +1,6 @@
1
1
  import * as React from 'react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { render, screen } from '../../../test-utils/testing-library';
2
4
 
3
5
  import MetadataInstanceEditor from '../MetadataInstanceEditor';
4
6
  import Instances from '../Instances';
@@ -443,6 +445,66 @@ const templatesOnServer = [template1, template2, template3, template4, template5
443
445
  // State of editors from server
444
446
  const editorsOnServer = [editor1, editor2, editor3, editor4, editor5];
445
447
 
448
+ const testGrandchildInstanceFields = [
449
+ {
450
+ id: 'field1',
451
+ type: 'string',
452
+ key: 'stringfield',
453
+ displayName: 'String Field',
454
+ description: 'example of a string field',
455
+ },
456
+ ];
457
+
458
+ const getMetadataEditorBaseProps = (props = {}) => ({
459
+ editors: [
460
+ {
461
+ instance: {
462
+ id: 'test-instance-editor-child-1',
463
+ canEdit: true,
464
+ data: { stringfield: 'valueForEditor' },
465
+ isDirty: false,
466
+ hasError: false,
467
+ isCascadingPolicyApplicable: true,
468
+ cascadePolicy: {
469
+ id: 'policy-for-editor-1',
470
+ canEdit: true,
471
+ isEnabled: true,
472
+ scope: 'enterprise_123',
473
+ cascadePolicyType: 'regular',
474
+ },
475
+ },
476
+ template: {
477
+ id: 'template-for-editor-1',
478
+ displayName: 'Test Template In Editor',
479
+ fields: testGrandchildInstanceFields,
480
+ templateKey: 'editorChildTemplateKey',
481
+ },
482
+ },
483
+ ],
484
+ templates: [
485
+ {
486
+ id: 'template-for-editor-1',
487
+ templateKey: 'editorChildTemplateKey',
488
+ displayName: 'Test Template In Editor',
489
+ fields: testGrandchildInstanceFields,
490
+ },
491
+ {
492
+ id: 'template-for-editor-2',
493
+ templateKey: 'anotherEditorTemplateKey',
494
+ displayName: 'Another Test Template',
495
+ fields: [],
496
+ },
497
+ ],
498
+ onSave: jest.fn(),
499
+ onModification: jest.fn(),
500
+ onRemove: jest.fn(),
501
+ onAdd: jest.fn(),
502
+ canAdd: true,
503
+ canUseAIFolderExtraction: true,
504
+ isCascadingPolicyApplicable: true,
505
+ ...props,
506
+ });
507
+
446
508
  describe('features/metadata-editor-editor/MetadataInstanceEditor', () => {
447
509
  test('should correctly render editors', () => {
448
510
  const wrapper = shallow(<MetadataInstanceEditor editors={editorsOnServer} templates={templatesOnServer} />);
@@ -471,3 +533,46 @@ describe('features/metadata-editor-editor/MetadataInstanceEditor', () => {
471
533
  expect(instances.prop('selectedTemplateKey')).toBe(selectedTemplateKey);
472
534
  });
473
535
  });
536
+
537
+ describe('MetadataInstanceEditor - canUseAIFolderExtractionAgentSelector prop', () => {
538
+ test('should propagate canUseAIFolderExtractionAgentSelector, showing agent selector', async () => {
539
+ render(
540
+ <MetadataInstanceEditor
541
+ {...getMetadataEditorBaseProps({
542
+ canUseAIFolderExtractionAgentSelector: true,
543
+ })}
544
+ />,
545
+ );
546
+
547
+ const editButton = await screen.findByRole('button', { name: 'Edit Metadata' }, { timeout: 3000 });
548
+ await userEvent.click(editButton);
549
+
550
+ expect(screen.getByRole('button', { name: 'Agent Basic' })).toBeInTheDocument();
551
+ });
552
+
553
+ test('should not show agent selector if canUseAIFolderExtractionAgentSelector is false', async () => {
554
+ render(
555
+ <MetadataInstanceEditor
556
+ {...getMetadataEditorBaseProps({
557
+ canUseAIFolderExtractionAgentSelector: false,
558
+ })}
559
+ />,
560
+ );
561
+
562
+ const editButton = await screen.findByRole('button', { name: 'Edit Metadata' });
563
+ await userEvent.click(editButton);
564
+
565
+ expect(screen.queryByRole('button', { name: 'Agent Basic' })).not.toBeInTheDocument();
566
+ });
567
+
568
+ test('should not show agent selector if canUseAIFolderExtractionAgentSelector is undefined', async () => {
569
+ const props = getMetadataEditorBaseProps();
570
+ delete props.canUseAIFolderExtractionAgentSelector;
571
+ render(<MetadataInstanceEditor {...props} />);
572
+
573
+ const editButton = await screen.findByRole('button', { name: 'Edit Metadata' });
574
+ await userEvent.click(editButton);
575
+
576
+ expect(screen.queryByRole('button', { name: 'Agent Basic' })).not.toBeInTheDocument();
577
+ });
578
+ });