box-ui-elements 24.0.0-beta.4 → 24.0.0-beta.5

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 (98) hide show
  1. package/dist/explorer.js +1 -1
  2. package/dist/openwith.js +1 -1
  3. package/dist/picker.js +1 -1
  4. package/dist/preview.js +1 -1
  5. package/dist/sharing.js +1 -1
  6. package/dist/sidebar.js +1 -1
  7. package/dist/uploader.js +1 -1
  8. package/es/api/Metadata.js +98 -13
  9. package/es/api/Metadata.js.flow +110 -12
  10. package/es/api/Metadata.js.map +1 -1
  11. package/es/elements/common/messages.js +16 -0
  12. package/es/elements/common/messages.js.flow +25 -0
  13. package/es/elements/common/messages.js.map +1 -1
  14. package/es/elements/content-explorer/Content.js +2 -1
  15. package/es/elements/content-explorer/Content.js.map +1 -1
  16. package/es/elements/content-explorer/ContentExplorer.js +19 -5
  17. package/es/elements/content-explorer/ContentExplorer.js.map +1 -1
  18. package/es/elements/content-explorer/MetadataQueryAPIHelper.js +61 -4
  19. package/es/elements/content-explorer/MetadataQueryAPIHelper.js.map +1 -1
  20. package/es/elements/content-explorer/MetadataSidePanel.js +40 -14
  21. package/es/elements/content-explorer/MetadataSidePanel.js.map +1 -1
  22. package/es/elements/content-explorer/MetadataViewContainer.js +55 -4
  23. package/es/elements/content-explorer/MetadataViewContainer.js.map +1 -1
  24. package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js +61 -13
  25. package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js.map +1 -1
  26. package/es/elements/content-explorer/utils.js +140 -12
  27. package/es/elements/content-explorer/utils.js.map +1 -1
  28. package/es/src/elements/content-explorer/ContentExplorer.d.ts +11 -3
  29. package/es/src/elements/content-explorer/MetadataQueryAPIHelper.d.ts +11 -1
  30. package/es/src/elements/content-explorer/MetadataSidePanel.d.ts +6 -3
  31. package/es/src/elements/content-explorer/MetadataViewContainer.d.ts +3 -1
  32. package/es/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.d.ts +1 -0
  33. package/es/src/elements/content-explorer/utils.d.ts +9 -3
  34. package/i18n/bn-IN.js +4 -0
  35. package/i18n/bn-IN.properties +4 -0
  36. package/i18n/da-DK.js +4 -0
  37. package/i18n/da-DK.properties +4 -0
  38. package/i18n/de-DE.js +5 -1
  39. package/i18n/de-DE.properties +4 -0
  40. package/i18n/en-AU.js +4 -0
  41. package/i18n/en-AU.properties +4 -0
  42. package/i18n/en-CA.js +4 -0
  43. package/i18n/en-CA.properties +4 -0
  44. package/i18n/en-GB.js +4 -0
  45. package/i18n/en-GB.properties +4 -0
  46. package/i18n/en-US.js +4 -0
  47. package/i18n/en-US.properties +8 -0
  48. package/i18n/en-x-pseudo.js +4 -0
  49. package/i18n/es-419.js +5 -1
  50. package/i18n/es-419.properties +4 -0
  51. package/i18n/es-ES.js +5 -1
  52. package/i18n/es-ES.properties +4 -0
  53. package/i18n/fi-FI.js +4 -0
  54. package/i18n/fi-FI.properties +4 -0
  55. package/i18n/fr-CA.js +4 -0
  56. package/i18n/fr-CA.properties +4 -0
  57. package/i18n/fr-FR.js +4 -0
  58. package/i18n/fr-FR.properties +4 -0
  59. package/i18n/hi-IN.js +4 -0
  60. package/i18n/hi-IN.properties +4 -0
  61. package/i18n/it-IT.js +4 -0
  62. package/i18n/it-IT.properties +4 -0
  63. package/i18n/ja-JP.js +6 -2
  64. package/i18n/ja-JP.properties +6 -2
  65. package/i18n/ko-KR.js +4 -0
  66. package/i18n/ko-KR.properties +4 -0
  67. package/i18n/nb-NO.js +4 -0
  68. package/i18n/nb-NO.properties +4 -0
  69. package/i18n/nl-NL.js +4 -0
  70. package/i18n/nl-NL.properties +4 -0
  71. package/i18n/pl-PL.js +4 -0
  72. package/i18n/pl-PL.properties +4 -0
  73. package/i18n/pt-BR.js +4 -0
  74. package/i18n/pt-BR.properties +4 -0
  75. package/i18n/ru-RU.js +5 -1
  76. package/i18n/ru-RU.properties +4 -0
  77. package/i18n/sv-SE.js +4 -0
  78. package/i18n/sv-SE.properties +4 -0
  79. package/i18n/tr-TR.js +5 -1
  80. package/i18n/tr-TR.properties +4 -0
  81. package/i18n/zh-CN.js +4 -0
  82. package/i18n/zh-CN.properties +4 -0
  83. package/i18n/zh-TW.js +4 -0
  84. package/i18n/zh-TW.properties +4 -0
  85. package/package.json +1 -1
  86. package/src/api/Metadata.js +110 -12
  87. package/src/api/__tests__/Metadata.test.js +120 -0
  88. package/src/elements/common/messages.js +25 -0
  89. package/src/elements/content-explorer/Content.tsx +1 -0
  90. package/src/elements/content-explorer/ContentExplorer.tsx +220 -181
  91. package/src/elements/content-explorer/MetadataQueryAPIHelper.ts +89 -4
  92. package/src/elements/content-explorer/MetadataSidePanel.tsx +55 -14
  93. package/src/elements/content-explorer/MetadataViewContainer.tsx +61 -1
  94. package/src/elements/content-explorer/__tests__/ContentExplorer.test.tsx +36 -2
  95. package/src/elements/content-explorer/__tests__/MetadataQueryAPIHelper.test.ts +8 -5
  96. package/src/elements/content-explorer/__tests__/MetadataSidePanel.test.tsx +145 -3
  97. package/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx +54 -8
  98. package/src/elements/content-explorer/utils.ts +150 -13
@@ -1,12 +1,24 @@
1
- import { useMemo } from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
+ import isNil from 'lodash/isNil';
4
+ import xor from 'lodash/xor';
3
5
 
4
- import type { MetadataTemplate } from '@box/metadata-editor';
6
+ import {
7
+ MULTI_VALUE_DEFAULT_OPTION,
8
+ MULTI_VALUE_DEFAULT_VALUE,
9
+ type MetadataTemplate,
10
+ type MetadataFormFieldValue,
11
+ } from '@box/metadata-editor';
12
+ import type { MetadataFieldType } from '@box/metadata-view';
5
13
  import type { Selection } from 'react-aria-components';
6
14
  import type { BoxItem, Collection } from '../../common/types/core';
7
15
 
8
16
  import messages from '../common/messages';
9
17
 
18
+ // Specific type for metadata field value in the item
19
+ // Note: Item doesn't have field value in metadata object if that field is not set, so the value will be undefined in this case
20
+ type ItemMetadataFieldValue = string | number | Array<string> | null | undefined;
21
+
10
22
  // Get selected item text
11
23
  export function useSelectedItemText(currentCollection: Collection, selectedItemIds: Selection): string {
12
24
  const { formatMessage } = useIntl();
@@ -28,21 +40,146 @@ export function useSelectedItemText(currentCollection: Collection, selectedItemI
28
40
  }, [currentCollection.items, formatMessage, selectedItemIds]);
29
41
  }
30
42
 
43
+ // Check if the field value is empty.
44
+ // Note: 0 doesn't represent empty here because of float type field
45
+ export function isEmptyValue(value: ItemMetadataFieldValue) {
46
+ if (isNil(value)) {
47
+ return true;
48
+ }
49
+
50
+ // date, string, enum
51
+ if (value === '') {
52
+ return true;
53
+ }
54
+
55
+ // multiSelect
56
+ if (Array.isArray(value) && value.length === 0) {
57
+ return true;
58
+ }
59
+
60
+ // float
61
+ if (Number.isNaN(value)) {
62
+ return true;
63
+ }
64
+
65
+ return false;
66
+ }
67
+
68
+ // Check if the field values are equal based on the field types
69
+ export function areFieldValuesEqual(value1: ItemMetadataFieldValue, value2: ItemMetadataFieldValue) {
70
+ if (isEmptyValue(value1) && isEmptyValue(value2)) {
71
+ return true;
72
+ }
73
+
74
+ // Handle multiSelect arrays comparison
75
+ if (Array.isArray(value1) && Array.isArray(value2)) {
76
+ return xor(value1, value2).length === 0;
77
+ }
78
+
79
+ return value1 === value2;
80
+ }
81
+
82
+ // Return default form value by field type
83
+ function getDefaultValueByFieldType(fieldType: MetadataFieldType) {
84
+ if (fieldType === 'date' || fieldType === 'enum' || fieldType === 'float' || fieldType === 'string') {
85
+ return '';
86
+ }
87
+ if (fieldType === 'multiSelect') {
88
+ return [];
89
+ }
90
+ return undefined;
91
+ }
92
+
93
+ // Set the field value in Metadata Form based on the field type
94
+ function getFieldValue(fieldType: MetadataFieldType, fieldValue: ItemMetadataFieldValue) {
95
+ if (isNil(fieldValue)) {
96
+ return getDefaultValueByFieldType(fieldType);
97
+ }
98
+ return fieldValue;
99
+ }
100
+
101
+ // Check if the field value in Metadata Form is multi-values such as "Multiple values"
102
+ export function isMultiValuesField(fieldType: MetadataFieldType, fieldValue: MetadataFormFieldValue) {
103
+ if (fieldType === 'multiSelect') {
104
+ return Array.isArray(fieldValue) && fieldValue.length === 1 && fieldValue[0] === MULTI_VALUE_DEFAULT_VALUE;
105
+ }
106
+ if (fieldType === 'enum') {
107
+ return fieldValue === MULTI_VALUE_DEFAULT_VALUE;
108
+ }
109
+ return false;
110
+ }
111
+
31
112
  // Get template instance based on metadata template and selected items
32
- export function getTemplateInstance(metadataTemplate: MetadataTemplate, selectedItems: BoxItem[]) {
113
+ export function useTemplateInstance(metadataTemplate: MetadataTemplate, selectedItems: BoxItem[], isEditing: boolean) {
114
+ const { formatMessage } = useIntl();
33
115
  const { displayName, fields, hidden, id, scope, templateKey, type } = metadataTemplate;
34
116
 
35
117
  const selectedItemsFields = fields.map(
36
- ({ displayName: fieldDisplayName, hidden: fieldHidden, id: fieldId, key, options, type: fieldType }) => ({
37
- displayName: fieldDisplayName,
38
- hidden: fieldHidden,
39
- id: fieldId,
40
- key,
41
- options,
42
- type: fieldType,
43
- // TODO: Add support for multiple selected items
44
- value: selectedItems[0].metadata[scope][templateKey][key],
45
- }),
118
+ ({ displayName: fieldDisplayName, hidden: fieldHidden, id: fieldId, key, options, type: fieldType }) => {
119
+ const defaultItemField = {
120
+ displayName: fieldDisplayName,
121
+ hidden: fieldHidden,
122
+ id: fieldId,
123
+ key,
124
+ options,
125
+ type: fieldType,
126
+ value: getFieldValue(fieldType as MetadataFieldType, undefined),
127
+ };
128
+
129
+ const firstSelectedItem = selectedItems[0];
130
+ const firstSelectedItemFieldValue = firstSelectedItem.metadata[scope][templateKey][key];
131
+
132
+ // Case 1: Single selected item
133
+ if (selectedItems.length <= 1) {
134
+ return {
135
+ ...defaultItemField,
136
+ value: firstSelectedItemFieldValue,
137
+ };
138
+ }
139
+
140
+ // Case 2.1: Multiple selected items, but all have the same initial value
141
+ const allItemsHaveSameInitialValue = selectedItems.every(selectedItem =>
142
+ areFieldValuesEqual(selectedItem.metadata[scope][templateKey][key], firstSelectedItemFieldValue),
143
+ );
144
+
145
+ if (allItemsHaveSameInitialValue) {
146
+ return {
147
+ ...defaultItemField,
148
+ value: getFieldValue(fieldType as MetadataFieldType, firstSelectedItemFieldValue),
149
+ };
150
+ }
151
+
152
+ // Case 2.2: Multiple selected items, but some have different initial values
153
+ // Case 2.2.1: Edit Mode
154
+ if (isEditing) {
155
+ let fieldValue = getFieldValue(fieldType as MetadataFieldType, undefined);
156
+ // Add MultiValue Option if the field is multiSelect or enum
157
+ if (fieldType === 'multiSelect' || fieldType === 'enum') {
158
+ fieldValue = fieldType === 'enum' ? MULTI_VALUE_DEFAULT_VALUE : [MULTI_VALUE_DEFAULT_VALUE];
159
+ const multiValueOption = options?.find(option => option.key === MULTI_VALUE_DEFAULT_VALUE);
160
+ if (!multiValueOption) {
161
+ options?.push(MULTI_VALUE_DEFAULT_OPTION);
162
+ }
163
+ }
164
+ return {
165
+ ...defaultItemField,
166
+ value: fieldValue,
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Case: 2.2.2 View Mode
172
+ *
173
+ * We want to show "Multiple values" label for multiple dates across files selection.
174
+ * We use fragment here to bypass check in shared feature.
175
+ * This feature tries to parse string as date if the string is passed as value.
176
+ */
177
+ const multipleValuesText = formatMessage(messages.multipleValues);
178
+ return {
179
+ ...defaultItemField,
180
+ value: React.createElement(React.Fragment, null, multipleValuesText),
181
+ };
182
+ },
46
183
  );
47
184
 
48
185
  return {