box-ui-elements 23.5.0-beta.3 → 23.5.0-beta.4
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.
- package/dist/explorer.css +1 -1
- package/dist/explorer.js +1 -1
- package/dist/picker.js +1 -1
- package/dist/preview.js +1 -1
- package/dist/sidebar.js +1 -1
- package/es/elements/common/sub-header/SubHeader.js +3 -0
- package/es/elements/common/sub-header/SubHeader.js.map +1 -1
- package/es/elements/common/sub-header/SubHeaderLeftV2.js +3 -23
- package/es/elements/common/sub-header/SubHeaderLeftV2.js.map +1 -1
- package/es/elements/common/sub-header/SubHeaderRight.js +6 -2
- package/es/elements/common/sub-header/SubHeaderRight.js.map +1 -1
- package/es/elements/content-explorer/ContentExplorer.js +44 -5
- package/es/elements/content-explorer/ContentExplorer.js.map +1 -1
- package/es/elements/content-explorer/ContentExplorer.scss +12 -0
- package/es/elements/content-explorer/MetadataSidePanel.js +92 -0
- package/es/elements/content-explorer/MetadataSidePanel.js.map +1 -0
- package/es/elements/content-explorer/MetadataSidePanel.scss +12 -0
- package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js +30 -0
- package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js.map +1 -1
- package/es/elements/content-explorer/utils.js +67 -0
- package/es/elements/content-explorer/utils.js.map +1 -0
- package/es/src/elements/common/sub-header/SubHeader.d.ts +2 -1
- package/es/src/elements/common/sub-header/SubHeaderLeftV2.d.ts +1 -1
- package/es/src/elements/common/sub-header/SubHeaderRight.d.ts +4 -1
- package/es/src/elements/content-explorer/ContentExplorer.d.ts +15 -0
- package/es/src/elements/content-explorer/MetadataSidePanel.d.ts +13 -0
- package/es/src/elements/content-explorer/__tests__/MetadataSidePanel.test.d.ts +1 -0
- package/es/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.d.ts +1 -0
- package/es/src/elements/content-explorer/utils.d.ts +22 -0
- package/package.json +1 -1
- package/src/elements/common/sub-header/SubHeader.tsx +4 -0
- package/src/elements/common/sub-header/SubHeaderLeftV2.tsx +3 -22
- package/src/elements/common/sub-header/SubHeaderRight.tsx +8 -2
- package/src/elements/content-explorer/ContentExplorer.scss +12 -0
- package/src/elements/content-explorer/ContentExplorer.tsx +120 -71
- package/src/elements/content-explorer/MetadataSidePanel.scss +12 -0
- package/src/elements/content-explorer/MetadataSidePanel.tsx +126 -0
- package/src/elements/content-explorer/__tests__/ContentExplorer.test.tsx +80 -16
- package/src/elements/content-explorer/__tests__/MetadataSidePanel.test.tsx +127 -0
- package/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx +26 -0
- package/src/elements/content-explorer/utils.ts +58 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import { IconButton, SidePanel, Text } from '@box/blueprint-web';
|
|
4
|
+
import { XMark } from '@box/blueprint-web-assets/icons/Fill/index';
|
|
5
|
+
import { FileDefault } from '@box/blueprint-web-assets/icons/Line/index';
|
|
6
|
+
import { AutofillContextProvider, MetadataInstance, MetadataInstanceForm } from '@box/metadata-editor';
|
|
7
|
+
import { getTemplateInstance, useSelectedItemText } from './utils';
|
|
8
|
+
import messages from '../common/messages';
|
|
9
|
+
import './MetadataSidePanel.scss';
|
|
10
|
+
const MetadataSidePanel = ({
|
|
11
|
+
currentCollection,
|
|
12
|
+
onClose,
|
|
13
|
+
selectedItemIds,
|
|
14
|
+
metadataTemplate
|
|
15
|
+
}) => {
|
|
16
|
+
const {
|
|
17
|
+
formatMessage
|
|
18
|
+
} = useIntl();
|
|
19
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
20
|
+
const [isUnsavedChangesModalOpen, setIsUnsavedChangesModalOpen] = useState(false);
|
|
21
|
+
const selectedItemText = useSelectedItemText(currentCollection, selectedItemIds);
|
|
22
|
+
const selectedItems = selectedItemIds === 'all' ? currentCollection.items : currentCollection.items.filter(item => selectedItemIds.has(item.id));
|
|
23
|
+
const templateInstance = getTemplateInstance(metadataTemplate, selectedItems);
|
|
24
|
+
const handleMetadataInstanceEdit = () => {
|
|
25
|
+
setIsEditing(true);
|
|
26
|
+
};
|
|
27
|
+
const handleMetadataInstanceFormCancel = () => {
|
|
28
|
+
setIsEditing(false);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
32
|
+
const handleMetadataInstanceFormChange = values => {
|
|
33
|
+
// TODO: Implement on form change
|
|
34
|
+
};
|
|
35
|
+
const handleMetadataInstanceFormDiscardUnsavedChanges = () => {
|
|
36
|
+
setIsUnsavedChangesModalOpen(false);
|
|
37
|
+
setIsEditing(false);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
41
|
+
const handleMetadataInstanceFormSubmit = async (values, operations) => {
|
|
42
|
+
// TODO: Implement onSave callback
|
|
43
|
+
};
|
|
44
|
+
return /*#__PURE__*/React.createElement(SidePanel, {
|
|
45
|
+
variant: "persistent"
|
|
46
|
+
}, /*#__PURE__*/React.createElement(SidePanel.Header, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
|
|
47
|
+
as: "span",
|
|
48
|
+
variant: "titleLarge"
|
|
49
|
+
}, formatMessage(messages.sidebarMetadataTitle)), /*#__PURE__*/React.createElement("div", {
|
|
50
|
+
className: "bce-MetadataSidePanel-subtitle"
|
|
51
|
+
}, /*#__PURE__*/React.createElement(FileDefault, null), /*#__PURE__*/React.createElement(Text, {
|
|
52
|
+
as: "span",
|
|
53
|
+
color: "textOnLightSecondary",
|
|
54
|
+
variant: "subtitle"
|
|
55
|
+
}, selectedItemText))), /*#__PURE__*/React.createElement(IconButton, {
|
|
56
|
+
"aria-label": formatMessage(messages.close),
|
|
57
|
+
icon: XMark,
|
|
58
|
+
onClick: onClose,
|
|
59
|
+
size: "large"
|
|
60
|
+
})), /*#__PURE__*/React.createElement(SidePanel.ScrollableContainer, null, /*#__PURE__*/React.createElement("div", {
|
|
61
|
+
className: "bce-MetadataSidePanel-content"
|
|
62
|
+
}, /*#__PURE__*/React.createElement(AutofillContextProvider, {
|
|
63
|
+
fetchSuggestions: null,
|
|
64
|
+
isAiSuggestionsFeatureEnabled: false
|
|
65
|
+
}, isEditing ? /*#__PURE__*/React.createElement(MetadataInstanceForm, {
|
|
66
|
+
areAiSuggestionsAvailable: false,
|
|
67
|
+
isAiSuggestionsFeatureEnabled: false,
|
|
68
|
+
isBetaLanguageEnabled: false,
|
|
69
|
+
isDeleteButtonDisabled: true,
|
|
70
|
+
isDeleteConfirmationModalCheckboxEnabled: false,
|
|
71
|
+
isLargeFile: false,
|
|
72
|
+
isMultilevelTaxonomyFieldEnabled: false,
|
|
73
|
+
isUnsavedChangesModalOpen: isUnsavedChangesModalOpen,
|
|
74
|
+
selectedTemplateInstance: templateInstance,
|
|
75
|
+
onCancel: handleMetadataInstanceFormCancel,
|
|
76
|
+
onChange: handleMetadataInstanceFormChange,
|
|
77
|
+
onDelete: null,
|
|
78
|
+
onDiscardUnsavedChanges: handleMetadataInstanceFormDiscardUnsavedChanges,
|
|
79
|
+
onSubmit: handleMetadataInstanceFormSubmit,
|
|
80
|
+
setIsUnsavedChangesModalOpen: setIsUnsavedChangesModalOpen,
|
|
81
|
+
taxonomyOptionsFetcher: null
|
|
82
|
+
}) : /*#__PURE__*/React.createElement(MetadataInstance, {
|
|
83
|
+
areAiSuggestionsAvailable: false,
|
|
84
|
+
isAiSuggestionsFeatureEnabled: false,
|
|
85
|
+
isBetaLanguageEnabled: false,
|
|
86
|
+
onEdit: handleMetadataInstanceEdit,
|
|
87
|
+
templateInstance: templateInstance,
|
|
88
|
+
taxonomyNodeFetcher: null
|
|
89
|
+
})))));
|
|
90
|
+
};
|
|
91
|
+
export default MetadataSidePanel;
|
|
92
|
+
//# sourceMappingURL=MetadataSidePanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetadataSidePanel.js","names":["React","useState","useIntl","IconButton","SidePanel","Text","XMark","FileDefault","AutofillContextProvider","MetadataInstance","MetadataInstanceForm","getTemplateInstance","useSelectedItemText","messages","MetadataSidePanel","currentCollection","onClose","selectedItemIds","metadataTemplate","formatMessage","isEditing","setIsEditing","isUnsavedChangesModalOpen","setIsUnsavedChangesModalOpen","selectedItemText","selectedItems","items","filter","item","has","id","templateInstance","handleMetadataInstanceEdit","handleMetadataInstanceFormCancel","handleMetadataInstanceFormChange","values","handleMetadataInstanceFormDiscardUnsavedChanges","handleMetadataInstanceFormSubmit","operations","createElement","variant","Header","as","sidebarMetadataTitle","className","color","close","icon","onClick","size","ScrollableContainer","fetchSuggestions","isAiSuggestionsFeatureEnabled","areAiSuggestionsAvailable","isBetaLanguageEnabled","isDeleteButtonDisabled","isDeleteConfirmationModalCheckboxEnabled","isLargeFile","isMultilevelTaxonomyFieldEnabled","selectedTemplateInstance","onCancel","onChange","onDelete","onDiscardUnsavedChanges","onSubmit","taxonomyOptionsFetcher","onEdit","taxonomyNodeFetcher"],"sources":["../../../src/elements/content-explorer/MetadataSidePanel.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport { IconButton, SidePanel, Text } from '@box/blueprint-web';\nimport { XMark } from '@box/blueprint-web-assets/icons/Fill/index';\nimport { FileDefault } from '@box/blueprint-web-assets/icons/Line/index';\nimport {\n AutofillContextProvider,\n FormValues,\n JSONPatchOperations,\n MetadataInstance,\n MetadataInstanceForm,\n} from '@box/metadata-editor';\n\nimport type { Selection } from 'react-aria-components';\nimport type { Collection } from '../../common/types/core';\nimport type { MetadataTemplate } from '../../common/types/metadata';\nimport { getTemplateInstance, useSelectedItemText } from './utils';\n\nimport messages from '../common/messages';\n\nimport './MetadataSidePanel.scss';\n\nexport interface MetadataSidePanelProps {\n currentCollection: Collection;\n onClose: () => void;\n metadataTemplate: MetadataTemplate;\n selectedItemIds: Selection;\n}\n\nconst MetadataSidePanel = ({\n currentCollection,\n onClose,\n selectedItemIds,\n metadataTemplate,\n}: MetadataSidePanelProps) => {\n const { formatMessage } = useIntl();\n const [isEditing, setIsEditing] = useState<boolean>(false);\n const [isUnsavedChangesModalOpen, setIsUnsavedChangesModalOpen] = useState<boolean>(false);\n\n const selectedItemText = useSelectedItemText(currentCollection, selectedItemIds);\n const selectedItems =\n selectedItemIds === 'all'\n ? currentCollection.items\n : currentCollection.items.filter(item => selectedItemIds.has(item.id));\n const templateInstance = getTemplateInstance(metadataTemplate, selectedItems);\n\n const handleMetadataInstanceEdit = () => {\n setIsEditing(true);\n };\n\n const handleMetadataInstanceFormCancel = () => {\n setIsEditing(false);\n };\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const handleMetadataInstanceFormChange = (values: FormValues) => {\n // TODO: Implement on form change\n };\n\n const handleMetadataInstanceFormDiscardUnsavedChanges = () => {\n setIsUnsavedChangesModalOpen(false);\n setIsEditing(false);\n };\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const handleMetadataInstanceFormSubmit = async (values: FormValues, operations: JSONPatchOperations) => {\n // TODO: Implement onSave callback\n };\n\n return (\n <SidePanel variant=\"persistent\">\n <SidePanel.Header>\n <div>\n <Text as=\"span\" variant=\"titleLarge\">\n {formatMessage(messages.sidebarMetadataTitle)}\n </Text>\n <div className=\"bce-MetadataSidePanel-subtitle\">\n <FileDefault />\n <Text as=\"span\" color=\"textOnLightSecondary\" variant=\"subtitle\">\n {selectedItemText}\n </Text>\n </div>\n </div>\n <IconButton aria-label={formatMessage(messages.close)} icon={XMark} onClick={onClose} size=\"large\" />\n </SidePanel.Header>\n <SidePanel.ScrollableContainer>\n <div className=\"bce-MetadataSidePanel-content\">\n <AutofillContextProvider fetchSuggestions={null} isAiSuggestionsFeatureEnabled={false}>\n {isEditing ? (\n <MetadataInstanceForm\n areAiSuggestionsAvailable={false}\n isAiSuggestionsFeatureEnabled={false}\n isBetaLanguageEnabled={false}\n isDeleteButtonDisabled={true}\n isDeleteConfirmationModalCheckboxEnabled={false}\n isLargeFile={false}\n isMultilevelTaxonomyFieldEnabled={false}\n isUnsavedChangesModalOpen={isUnsavedChangesModalOpen}\n selectedTemplateInstance={templateInstance}\n onCancel={handleMetadataInstanceFormCancel}\n onChange={handleMetadataInstanceFormChange}\n onDelete={null}\n onDiscardUnsavedChanges={handleMetadataInstanceFormDiscardUnsavedChanges}\n onSubmit={handleMetadataInstanceFormSubmit}\n setIsUnsavedChangesModalOpen={setIsUnsavedChangesModalOpen}\n taxonomyOptionsFetcher={null}\n />\n ) : (\n <MetadataInstance\n areAiSuggestionsAvailable={false}\n isAiSuggestionsFeatureEnabled={false}\n isBetaLanguageEnabled={false}\n onEdit={handleMetadataInstanceEdit}\n templateInstance={templateInstance}\n taxonomyNodeFetcher={null}\n />\n )}\n </AutofillContextProvider>\n </div>\n </SidePanel.ScrollableContainer>\n </SidePanel>\n );\n};\n\nexport default MetadataSidePanel;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -177,6 +177,36 @@ export const metadataViewV2WithInitialFilterValues = {
|
|
|
177
177
|
expect(fileTypeChip).toHaveTextContent(/\+2/);
|
|
178
178
|
}
|
|
179
179
|
};
|
|
180
|
+
export const sidePanelOpenWithSingleItemSelected = {
|
|
181
|
+
args: _objectSpread(_objectSpread({}, metadataViewV2ElementProps), {}, {
|
|
182
|
+
metadataViewProps: {
|
|
183
|
+
columns,
|
|
184
|
+
tableProps: {
|
|
185
|
+
isSelectAllEnabled: true
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}),
|
|
189
|
+
play: async ({
|
|
190
|
+
canvas
|
|
191
|
+
}) => {
|
|
192
|
+
await waitFor(() => {
|
|
193
|
+
expect(canvas.getByRole('row', {
|
|
194
|
+
name: /Child 2/i
|
|
195
|
+
})).toBeInTheDocument();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Select the first row by clicking its checkbox
|
|
199
|
+
const firstRow = canvas.getByRole('row', {
|
|
200
|
+
name: /Child 2/i
|
|
201
|
+
});
|
|
202
|
+
const checkbox = within(firstRow).getByRole('checkbox');
|
|
203
|
+
await userEvent.click(checkbox);
|
|
204
|
+
const metadataButton = canvas.getByRole('button', {
|
|
205
|
+
name: 'Metadata'
|
|
206
|
+
});
|
|
207
|
+
await userEvent.click(metadataButton);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
180
210
|
const meta = {
|
|
181
211
|
title: 'Elements/ContentExplorer/tests/MetadataView/visual',
|
|
182
212
|
component: ContentExplorer,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetadataView-visual.stories.js","names":["http","HttpResponse","expect","userEvent","waitFor","within","Download","SignMeOthers","Sign","noop","ContentExplorer","DEFAULT_HOSTNAME_API","mockMetadata","mockSchema","mockRootFolder","scope","templateScope","templateKey","metadataScopeAndKey","metadataFieldNamePrefix","metadataQuery","from","ancestor_folder_id","sort_by","field_key","fields","key","direction","map","field","fieldsToShow","canEdit","displayName","columns","textValue","id","type","allowSorting","minWidth","maxWidth","defaultView","metadataView","args","metadataViewV2ElementProps","metadataViewProps","features","contentExplorer","metadataViewV2","metadataViewV2WithCustomActions","_objectSpread","tableProps","isSelectAllEnabled","itemActionMenuProps","actions","label","onClick","icon","subMenuTrigger","subMenuActions","play","canvas","getByRole","name","toBeInTheDocument","firstRow","ellipsesButton","click","initialFilterActionBarProps","initialFilterValues","value","metadataViewV2WithInitialFilterValues","actionBarProps","toHaveTextContent","contactRoleChip","fileTypeChip","meta","title","component","global","FEATURE_FLAGS","rootFolderId","FOLDER_ID","token","TOKEN","parameters","msw","handlers","post","json","get"],"sources":["../../../../../src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx"],"sourcesContent":["import type { Meta, StoryObj } from '@storybook/react';\nimport { http, HttpResponse } from 'msw';\nimport { expect, userEvent, waitFor, within } from 'storybook/test';\nimport { Download, SignMeOthers } from '@box/blueprint-web-assets/icons/Fill/index';\nimport { Sign } from '@box/blueprint-web-assets/icons/Line';\nimport noop from 'lodash/noop';\n\nimport ContentExplorer from '../../ContentExplorer';\nimport { DEFAULT_HOSTNAME_API } from '../../../../constants';\nimport { mockMetadata, mockSchema } from '../../../common/__mocks__/mockMetadata';\nimport { mockRootFolder } from '../../../common/__mocks__/mockRootFolder';\n\n// The intent behind relying on mockMetadata is to allow a developer to paste in their own metadata template schema for use with live API calls.\nconst { scope: templateScope, templateKey } = mockSchema;\n\nconst metadataScopeAndKey = `${templateScope}.${templateKey}`;\nconst metadataFieldNamePrefix = `metadata.${metadataScopeAndKey}`;\n\n// This is the body of the metadata query API call.\n// https://developer.box.com/guides/metadata/queries/syntax/\nconst metadataQuery = {\n from: metadataScopeAndKey,\n ancestor_folder_id: '0',\n sort_by: [\n {\n field_key: `${metadataFieldNamePrefix}.${mockSchema.fields[0].key}`, // Default to sorting by the first field in the schema\n direction: 'asc',\n },\n ],\n fields: [\n // Default to returning all fields in the metadata template schema, and name as a standalone (non-metadata) field\n ...mockSchema.fields.map(field => `${metadataFieldNamePrefix}.${field.key}`),\n 'name',\n ],\n};\n\n// Used for metadata view v1\nconst fieldsToShow = [\n { key: `${metadataFieldNamePrefix}.name`, canEdit: false, displayName: 'Alias' },\n { key: `${metadataFieldNamePrefix}.industry`, canEdit: true },\n { key: `${metadataFieldNamePrefix}.last_contacted_at`, canEdit: true },\n { key: `${metadataFieldNamePrefix}.role`, canEdit: true },\n];\n\n// Used for metadata view v2\nconst columns = [\n {\n // Always include the name column\n textValue: 'Name',\n id: 'name',\n type: 'string',\n allowSorting: true,\n minWidth: 150,\n maxWidth: 150,\n },\n ...mockSchema.fields.map(field => ({\n textValue: field.displayName,\n id: `${metadataFieldNamePrefix}.${field.key}`,\n type: field.type,\n allowSorting: true,\n minWidth: 150,\n maxWidth: 150,\n })),\n];\n\n// Switches ContentExplorer to use Metadata View over standard, folder-based view.\nconst defaultView = 'metadata';\n\ntype Story = StoryObj<typeof ContentExplorer>;\n\nexport const metadataView: Story = {\n args: {\n metadataQuery,\n fieldsToShow,\n defaultView,\n },\n};\n\nconst metadataViewV2ElementProps = {\n metadataViewProps: {\n columns,\n },\n metadataQuery,\n fieldsToShow,\n defaultView,\n features: {\n contentExplorer: {\n metadataViewV2: true,\n },\n },\n};\n\nexport const metadataViewV2: Story = {\n args: metadataViewV2ElementProps,\n};\n\nexport const metadataViewV2WithCustomActions: Story = {\n args: {\n ...metadataViewV2ElementProps,\n metadataViewProps: {\n columns,\n tableProps: {\n isSelectAllEnabled: true,\n },\n itemActionMenuProps: {\n actions: [\n {\n label: 'Download',\n onClick: noop,\n icon: Download,\n },\n ],\n subMenuTrigger: {\n label: 'Sign',\n icon: Sign,\n },\n subMenuActions: [\n {\n label: 'Request Signature',\n onClick: noop,\n icon: SignMeOthers,\n },\n ],\n },\n },\n },\n play: async ({ canvas }) => {\n await waitFor(() => {\n expect(canvas.getByRole('row', { name: /Child 2/i })).toBeInTheDocument();\n });\n const firstRow = canvas.getByRole('row', { name: /Child 2/i });\n const ellipsesButton = within(firstRow).getByRole('button', { name: 'Action menu' });\n userEvent.click(ellipsesButton);\n },\n};\n\nconst initialFilterActionBarProps = {\n initialFilterValues: {\n 'industry-filter': { value: ['Legal'] },\n 'mimetype-filter': { value: ['boxnoteType', 'documentType', 'threedType'] },\n 'role-filter': { value: ['Developer', 'Business Owner', 'Marketing'] },\n },\n};\n\nexport const metadataViewV2WithInitialFilterValues: Story = {\n args: {\n ...metadataViewV2ElementProps,\n metadataViewProps: {\n columns,\n actionBarProps: initialFilterActionBarProps,\n },\n },\n play: async ({ canvas }) => {\n // Wait for chips to update with initial values\n await waitFor(() => {\n expect(canvas.getByRole('button', { name: /Industry/i })).toHaveTextContent(/\\(1\\)/);\n });\n // Other chips should reflect initialized values\n const contactRoleChip = canvas.getByRole('button', { name: /Contact Role/i });\n expect(contactRoleChip).toHaveTextContent(/\\(3\\)/);\n\n const fileTypeChip = canvas.getByRole('button', { name: /Box Note/i });\n expect(fileTypeChip).toHaveTextContent(/\\+2/);\n },\n};\n\nconst meta: Meta<typeof ContentExplorer> = {\n title: 'Elements/ContentExplorer/tests/MetadataView/visual',\n component: ContentExplorer,\n args: {\n features: global.FEATURE_FLAGS,\n rootFolderId: global.FOLDER_ID,\n token: global.TOKEN,\n },\n parameters: {\n msw: {\n handlers: [\n http.post(`${DEFAULT_HOSTNAME_API}/2.0/metadata_queries/execute_read`, () => {\n return HttpResponse.json(mockMetadata);\n }),\n http.get(`${DEFAULT_HOSTNAME_API}/2.0/metadata_templates/enterprise/templateName/schema`, () => {\n return HttpResponse.json(mockSchema);\n }),\n http.get(`${DEFAULT_HOSTNAME_API}/2.0/folders/:id`, () => {\n return HttpResponse.json(mockRootFolder);\n }),\n ],\n },\n },\n};\n\nexport default meta;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"MetadataView-visual.stories.js","names":["http","HttpResponse","expect","userEvent","waitFor","within","Download","SignMeOthers","Sign","noop","ContentExplorer","DEFAULT_HOSTNAME_API","mockMetadata","mockSchema","mockRootFolder","scope","templateScope","templateKey","metadataScopeAndKey","metadataFieldNamePrefix","metadataQuery","from","ancestor_folder_id","sort_by","field_key","fields","key","direction","map","field","fieldsToShow","canEdit","displayName","columns","textValue","id","type","allowSorting","minWidth","maxWidth","defaultView","metadataView","args","metadataViewV2ElementProps","metadataViewProps","features","contentExplorer","metadataViewV2","metadataViewV2WithCustomActions","_objectSpread","tableProps","isSelectAllEnabled","itemActionMenuProps","actions","label","onClick","icon","subMenuTrigger","subMenuActions","play","canvas","getByRole","name","toBeInTheDocument","firstRow","ellipsesButton","click","initialFilterActionBarProps","initialFilterValues","value","metadataViewV2WithInitialFilterValues","actionBarProps","toHaveTextContent","contactRoleChip","fileTypeChip","sidePanelOpenWithSingleItemSelected","checkbox","metadataButton","meta","title","component","global","FEATURE_FLAGS","rootFolderId","FOLDER_ID","token","TOKEN","parameters","msw","handlers","post","json","get"],"sources":["../../../../../src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx"],"sourcesContent":["import type { Meta, StoryObj } from '@storybook/react';\nimport { http, HttpResponse } from 'msw';\nimport { expect, userEvent, waitFor, within } from 'storybook/test';\nimport { Download, SignMeOthers } from '@box/blueprint-web-assets/icons/Fill/index';\nimport { Sign } from '@box/blueprint-web-assets/icons/Line';\nimport noop from 'lodash/noop';\n\nimport ContentExplorer from '../../ContentExplorer';\nimport { DEFAULT_HOSTNAME_API } from '../../../../constants';\nimport { mockMetadata, mockSchema } from '../../../common/__mocks__/mockMetadata';\nimport { mockRootFolder } from '../../../common/__mocks__/mockRootFolder';\n\n// The intent behind relying on mockMetadata is to allow a developer to paste in their own metadata template schema for use with live API calls.\nconst { scope: templateScope, templateKey } = mockSchema;\n\nconst metadataScopeAndKey = `${templateScope}.${templateKey}`;\nconst metadataFieldNamePrefix = `metadata.${metadataScopeAndKey}`;\n\n// This is the body of the metadata query API call.\n// https://developer.box.com/guides/metadata/queries/syntax/\nconst metadataQuery = {\n from: metadataScopeAndKey,\n ancestor_folder_id: '0',\n sort_by: [\n {\n field_key: `${metadataFieldNamePrefix}.${mockSchema.fields[0].key}`, // Default to sorting by the first field in the schema\n direction: 'asc',\n },\n ],\n fields: [\n // Default to returning all fields in the metadata template schema, and name as a standalone (non-metadata) field\n ...mockSchema.fields.map(field => `${metadataFieldNamePrefix}.${field.key}`),\n 'name',\n ],\n};\n\n// Used for metadata view v1\nconst fieldsToShow = [\n { key: `${metadataFieldNamePrefix}.name`, canEdit: false, displayName: 'Alias' },\n { key: `${metadataFieldNamePrefix}.industry`, canEdit: true },\n { key: `${metadataFieldNamePrefix}.last_contacted_at`, canEdit: true },\n { key: `${metadataFieldNamePrefix}.role`, canEdit: true },\n];\n\n// Used for metadata view v2\nconst columns = [\n {\n // Always include the name column\n textValue: 'Name',\n id: 'name',\n type: 'string',\n allowSorting: true,\n minWidth: 150,\n maxWidth: 150,\n },\n ...mockSchema.fields.map(field => ({\n textValue: field.displayName,\n id: `${metadataFieldNamePrefix}.${field.key}`,\n type: field.type,\n allowSorting: true,\n minWidth: 150,\n maxWidth: 150,\n })),\n];\n\n// Switches ContentExplorer to use Metadata View over standard, folder-based view.\nconst defaultView = 'metadata';\n\ntype Story = StoryObj<typeof ContentExplorer>;\n\nexport const metadataView: Story = {\n args: {\n metadataQuery,\n fieldsToShow,\n defaultView,\n },\n};\n\nconst metadataViewV2ElementProps = {\n metadataViewProps: {\n columns,\n },\n metadataQuery,\n fieldsToShow,\n defaultView,\n features: {\n contentExplorer: {\n metadataViewV2: true,\n },\n },\n};\n\nexport const metadataViewV2: Story = {\n args: metadataViewV2ElementProps,\n};\n\nexport const metadataViewV2WithCustomActions: Story = {\n args: {\n ...metadataViewV2ElementProps,\n metadataViewProps: {\n columns,\n tableProps: {\n isSelectAllEnabled: true,\n },\n itemActionMenuProps: {\n actions: [\n {\n label: 'Download',\n onClick: noop,\n icon: Download,\n },\n ],\n subMenuTrigger: {\n label: 'Sign',\n icon: Sign,\n },\n subMenuActions: [\n {\n label: 'Request Signature',\n onClick: noop,\n icon: SignMeOthers,\n },\n ],\n },\n },\n },\n play: async ({ canvas }) => {\n await waitFor(() => {\n expect(canvas.getByRole('row', { name: /Child 2/i })).toBeInTheDocument();\n });\n const firstRow = canvas.getByRole('row', { name: /Child 2/i });\n const ellipsesButton = within(firstRow).getByRole('button', { name: 'Action menu' });\n userEvent.click(ellipsesButton);\n },\n};\n\nconst initialFilterActionBarProps = {\n initialFilterValues: {\n 'industry-filter': { value: ['Legal'] },\n 'mimetype-filter': { value: ['boxnoteType', 'documentType', 'threedType'] },\n 'role-filter': { value: ['Developer', 'Business Owner', 'Marketing'] },\n },\n};\n\nexport const metadataViewV2WithInitialFilterValues: Story = {\n args: {\n ...metadataViewV2ElementProps,\n metadataViewProps: {\n columns,\n actionBarProps: initialFilterActionBarProps,\n },\n },\n play: async ({ canvas }) => {\n // Wait for chips to update with initial values\n await waitFor(() => {\n expect(canvas.getByRole('button', { name: /Industry/i })).toHaveTextContent(/\\(1\\)/);\n });\n // Other chips should reflect initialized values\n const contactRoleChip = canvas.getByRole('button', { name: /Contact Role/i });\n expect(contactRoleChip).toHaveTextContent(/\\(3\\)/);\n\n const fileTypeChip = canvas.getByRole('button', { name: /Box Note/i });\n expect(fileTypeChip).toHaveTextContent(/\\+2/);\n },\n};\n\nexport const sidePanelOpenWithSingleItemSelected: Story = {\n args: {\n ...metadataViewV2ElementProps,\n metadataViewProps: {\n columns,\n tableProps: {\n isSelectAllEnabled: true,\n },\n },\n },\n\n play: async ({ canvas }) => {\n await waitFor(() => {\n expect(canvas.getByRole('row', { name: /Child 2/i })).toBeInTheDocument();\n });\n\n // Select the first row by clicking its checkbox\n const firstRow = canvas.getByRole('row', { name: /Child 2/i });\n const checkbox = within(firstRow).getByRole('checkbox');\n await userEvent.click(checkbox);\n\n const metadataButton = canvas.getByRole('button', { name: 'Metadata' });\n await userEvent.click(metadataButton);\n },\n};\n\nconst meta: Meta<typeof ContentExplorer> = {\n title: 'Elements/ContentExplorer/tests/MetadataView/visual',\n component: ContentExplorer,\n args: {\n features: global.FEATURE_FLAGS,\n rootFolderId: global.FOLDER_ID,\n token: global.TOKEN,\n },\n parameters: {\n msw: {\n handlers: [\n http.post(`${DEFAULT_HOSTNAME_API}/2.0/metadata_queries/execute_read`, () => {\n return HttpResponse.json(mockMetadata);\n }),\n http.get(`${DEFAULT_HOSTNAME_API}/2.0/metadata_templates/enterprise/templateName/schema`, () => {\n return HttpResponse.json(mockSchema);\n }),\n http.get(`${DEFAULT_HOSTNAME_API}/2.0/folders/:id`, () => {\n return HttpResponse.json(mockRootFolder);\n }),\n ],\n },\n },\n};\n\nexport default meta;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import messages from '../common/messages';
|
|
4
|
+
|
|
5
|
+
// Get selected item text
|
|
6
|
+
export function useSelectedItemText(currentCollection, selectedItemIds) {
|
|
7
|
+
const {
|
|
8
|
+
formatMessage
|
|
9
|
+
} = useIntl();
|
|
10
|
+
return useMemo(() => {
|
|
11
|
+
const selectedCount = selectedItemIds === 'all' ? currentCollection.items.length : selectedItemIds.size;
|
|
12
|
+
if (selectedCount === 0) return '';
|
|
13
|
+
|
|
14
|
+
// Case 1: Single selected item - show item name
|
|
15
|
+
if (selectedCount === 1) {
|
|
16
|
+
const selectedKey = selectedItemIds === 'all' ? currentCollection.items[0].id : selectedItemIds.values().next().value;
|
|
17
|
+
const selectedItem = currentCollection.items.find(item => item.id === selectedKey);
|
|
18
|
+
return selectedItem?.name ?? '';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Case 2: Multiple selected items - show count
|
|
22
|
+
return formatMessage(messages.numFilesSelected, {
|
|
23
|
+
numSelected: selectedCount
|
|
24
|
+
});
|
|
25
|
+
}, [currentCollection.items, formatMessage, selectedItemIds]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Get template instance based on metadata template and selected items
|
|
29
|
+
export function getTemplateInstance(metadataTemplate, selectedItems) {
|
|
30
|
+
const {
|
|
31
|
+
displayName,
|
|
32
|
+
fields,
|
|
33
|
+
hidden,
|
|
34
|
+
id,
|
|
35
|
+
scope,
|
|
36
|
+
templateKey,
|
|
37
|
+
type
|
|
38
|
+
} = metadataTemplate;
|
|
39
|
+
const selectedItemsFields = fields.map(({
|
|
40
|
+
displayName: fieldDisplayName,
|
|
41
|
+
hidden: fieldHidden,
|
|
42
|
+
id: fieldId,
|
|
43
|
+
key,
|
|
44
|
+
options,
|
|
45
|
+
type: fieldType
|
|
46
|
+
}) => ({
|
|
47
|
+
displayName: fieldDisplayName,
|
|
48
|
+
hidden: fieldHidden,
|
|
49
|
+
id: fieldId,
|
|
50
|
+
key,
|
|
51
|
+
options,
|
|
52
|
+
type: fieldType,
|
|
53
|
+
// TODO: Add support for multiple selected items
|
|
54
|
+
value: selectedItems[0].metadata[scope][templateKey][key]
|
|
55
|
+
}));
|
|
56
|
+
return {
|
|
57
|
+
canEdit: true,
|
|
58
|
+
displayName,
|
|
59
|
+
hidden,
|
|
60
|
+
id,
|
|
61
|
+
fields: selectedItemsFields,
|
|
62
|
+
scope,
|
|
63
|
+
templateKey,
|
|
64
|
+
type
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","names":["useMemo","useIntl","messages","useSelectedItemText","currentCollection","selectedItemIds","formatMessage","selectedCount","items","length","size","selectedKey","id","values","next","value","selectedItem","find","item","name","numFilesSelected","numSelected","getTemplateInstance","metadataTemplate","selectedItems","displayName","fields","hidden","scope","templateKey","type","selectedItemsFields","map","fieldDisplayName","fieldHidden","fieldId","key","options","fieldType","metadata","canEdit"],"sources":["../../../src/elements/content-explorer/utils.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { useIntl } from 'react-intl';\n\nimport type { MetadataTemplate } from '@box/metadata-editor';\nimport type { Selection } from 'react-aria-components';\nimport type { BoxItem, Collection } from '../../common/types/core';\n\nimport messages from '../common/messages';\n\n// Get selected item text\nexport function useSelectedItemText(currentCollection: Collection, selectedItemIds: Selection): string {\n const { formatMessage } = useIntl();\n\n return useMemo(() => {\n const selectedCount = selectedItemIds === 'all' ? currentCollection.items.length : selectedItemIds.size;\n if (selectedCount === 0) return '';\n\n // Case 1: Single selected item - show item name\n if (selectedCount === 1) {\n const selectedKey =\n selectedItemIds === 'all' ? currentCollection.items[0].id : selectedItemIds.values().next().value;\n const selectedItem = currentCollection.items.find(item => item.id === selectedKey);\n return selectedItem?.name ?? '';\n }\n\n // Case 2: Multiple selected items - show count\n return formatMessage(messages.numFilesSelected, { numSelected: selectedCount });\n }, [currentCollection.items, formatMessage, selectedItemIds]);\n}\n\n// Get template instance based on metadata template and selected items\nexport function getTemplateInstance(metadataTemplate: MetadataTemplate, selectedItems: BoxItem[]) {\n const { displayName, fields, hidden, id, scope, templateKey, type } = metadataTemplate;\n\n const selectedItemsFields = fields.map(\n ({ displayName: fieldDisplayName, hidden: fieldHidden, id: fieldId, key, options, type: fieldType }) => ({\n displayName: fieldDisplayName,\n hidden: fieldHidden,\n id: fieldId,\n key,\n options,\n type: fieldType,\n // TODO: Add support for multiple selected items\n value: selectedItems[0].metadata[scope][templateKey][key],\n }),\n );\n\n return {\n canEdit: true,\n displayName,\n hidden,\n id,\n fields: selectedItemsFields,\n scope,\n templateKey,\n type,\n };\n}\n"],"mappings":"AAAA,SAASA,OAAO,QAAQ,OAAO;AAC/B,SAASC,OAAO,QAAQ,YAAY;AAMpC,OAAOC,QAAQ,MAAM,oBAAoB;;AAEzC;AACA,OAAO,SAASC,mBAAmBA,CAACC,iBAA6B,EAAEC,eAA0B,EAAU;EACnG,MAAM;IAAEC;EAAc,CAAC,GAAGL,OAAO,CAAC,CAAC;EAEnC,OAAOD,OAAO,CAAC,MAAM;IACjB,MAAMO,aAAa,GAAGF,eAAe,KAAK,KAAK,GAAGD,iBAAiB,CAACI,KAAK,CAACC,MAAM,GAAGJ,eAAe,CAACK,IAAI;IACvG,IAAIH,aAAa,KAAK,CAAC,EAAE,OAAO,EAAE;;IAElC;IACA,IAAIA,aAAa,KAAK,CAAC,EAAE;MACrB,MAAMI,WAAW,GACbN,eAAe,KAAK,KAAK,GAAGD,iBAAiB,CAACI,KAAK,CAAC,CAAC,CAAC,CAACI,EAAE,GAAGP,eAAe,CAACQ,MAAM,CAAC,CAAC,CAACC,IAAI,CAAC,CAAC,CAACC,KAAK;MACrG,MAAMC,YAAY,GAAGZ,iBAAiB,CAACI,KAAK,CAACS,IAAI,CAACC,IAAI,IAAIA,IAAI,CAACN,EAAE,KAAKD,WAAW,CAAC;MAClF,OAAOK,YAAY,EAAEG,IAAI,IAAI,EAAE;IACnC;;IAEA;IACA,OAAOb,aAAa,CAACJ,QAAQ,CAACkB,gBAAgB,EAAE;MAAEC,WAAW,EAAEd;IAAc,CAAC,CAAC;EACnF,CAAC,EAAE,CAACH,iBAAiB,CAACI,KAAK,EAAEF,aAAa,EAAED,eAAe,CAAC,CAAC;AACjE;;AAEA;AACA,OAAO,SAASiB,mBAAmBA,CAACC,gBAAkC,EAAEC,aAAwB,EAAE;EAC9F,MAAM;IAAEC,WAAW;IAAEC,MAAM;IAAEC,MAAM;IAAEf,EAAE;IAAEgB,KAAK;IAAEC,WAAW;IAAEC;EAAK,CAAC,GAAGP,gBAAgB;EAEtF,MAAMQ,mBAAmB,GAAGL,MAAM,CAACM,GAAG,CAClC,CAAC;IAAEP,WAAW,EAAEQ,gBAAgB;IAAEN,MAAM,EAAEO,WAAW;IAAEtB,EAAE,EAAEuB,OAAO;IAAEC,GAAG;IAAEC,OAAO;IAAEP,IAAI,EAAEQ;EAAU,CAAC,MAAM;IACrGb,WAAW,EAAEQ,gBAAgB;IAC7BN,MAAM,EAAEO,WAAW;IACnBtB,EAAE,EAAEuB,OAAO;IACXC,GAAG;IACHC,OAAO;IACPP,IAAI,EAAEQ,SAAS;IACf;IACAvB,KAAK,EAAES,aAAa,CAAC,CAAC,CAAC,CAACe,QAAQ,CAACX,KAAK,CAAC,CAACC,WAAW,CAAC,CAACO,GAAG;EAC5D,CAAC,CACL,CAAC;EAED,OAAO;IACHI,OAAO,EAAE,IAAI;IACbf,WAAW;IACXE,MAAM;IACNf,EAAE;IACFc,MAAM,EAAEK,mBAAmB;IAC3BH,KAAK;IACLC,WAAW;IACXC;EACJ,CAAC;AACL","ignoreList":[]}
|
|
@@ -17,6 +17,7 @@ export interface SubHeaderProps {
|
|
|
17
17
|
onGridViewSliderChange?: (newSliderValue: number) => void;
|
|
18
18
|
onItemClick: (id: string | null, triggerNavigationEvent: boolean | null) => void;
|
|
19
19
|
onSortChange: (sortBy: string, sortDirection: string) => void;
|
|
20
|
+
onMetadataSidePanelToggle?: () => void;
|
|
20
21
|
onUpload: () => void;
|
|
21
22
|
onViewModeChange?: (viewMode: ViewMode) => void;
|
|
22
23
|
portalElement?: HTMLElement;
|
|
@@ -27,5 +28,5 @@ export interface SubHeaderProps {
|
|
|
27
28
|
view: View;
|
|
28
29
|
viewMode?: ViewMode;
|
|
29
30
|
}
|
|
30
|
-
declare const SubHeader: ({ canCreateNewFolder, canUpload, currentCollection, gridColumnCount, gridMaxColumns, gridMinColumns, maxGridColumnCountForWidth, onGridViewSliderChange, isSmall, onClearSelectedItemIds, onCreate, onItemClick, onSortChange, onUpload, onViewModeChange, portalElement, rootId, rootName, selectedItemIds, title, view, viewMode, }: SubHeaderProps) => React.JSX.Element;
|
|
31
|
+
declare const SubHeader: ({ canCreateNewFolder, canUpload, currentCollection, gridColumnCount, gridMaxColumns, gridMinColumns, maxGridColumnCountForWidth, onGridViewSliderChange, isSmall, onClearSelectedItemIds, onCreate, onItemClick, onSortChange, onMetadataSidePanelToggle, onUpload, onViewModeChange, portalElement, rootId, rootName, selectedItemIds, title, view, viewMode, }: SubHeaderProps) => React.JSX.Element;
|
|
31
32
|
export default SubHeader;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { Selection } from 'react-aria-components';
|
|
2
3
|
import type { ViewMode } from '../flowTypes';
|
|
3
4
|
import type { SortBy, SortDirection, View, Collection } from '../../../common/types/core';
|
|
4
5
|
import './SubHeaderRight.scss';
|
|
@@ -13,11 +14,13 @@ export interface SubHeaderRightProps {
|
|
|
13
14
|
onCreate: () => void;
|
|
14
15
|
onGridViewSliderChange: (newSliderValue: number) => void;
|
|
15
16
|
onSortChange: (sortBy: SortBy, sortDirection: SortDirection) => void;
|
|
17
|
+
onMetadataSidePanelToggle?: () => void;
|
|
16
18
|
onUpload: () => void;
|
|
17
19
|
onViewModeChange?: (viewMode: ViewMode) => void;
|
|
18
20
|
portalElement?: HTMLElement;
|
|
21
|
+
selectedItemIds?: Selection;
|
|
19
22
|
view: View;
|
|
20
23
|
viewMode: ViewMode;
|
|
21
24
|
}
|
|
22
|
-
declare const SubHeaderRight: ({ canCreateNewFolder, canUpload, currentCollection, gridColumnCount, gridMaxColumns, gridMinColumns, maxGridColumnCountForWidth, onCreate, onGridViewSliderChange, onSortChange, onUpload, onViewModeChange, portalElement, view, viewMode, }: SubHeaderRightProps) => React.JSX.Element;
|
|
25
|
+
declare const SubHeaderRight: ({ canCreateNewFolder, canUpload, currentCollection, gridColumnCount, gridMaxColumns, gridMinColumns, maxGridColumnCountForWidth, onCreate, onGridViewSliderChange, onSortChange, onMetadataSidePanelToggle, onUpload, onViewModeChange, portalElement, selectedItemIds, view, viewMode, }: SubHeaderRightProps) => React.JSX.Element;
|
|
23
26
|
export default SubHeaderRight;
|
|
@@ -86,6 +86,7 @@ type State = {
|
|
|
86
86
|
isCreateFolderModalOpen: boolean;
|
|
87
87
|
isDeleteModalOpen: boolean;
|
|
88
88
|
isLoading: boolean;
|
|
89
|
+
isMetadataSidePanelOpen: boolean;
|
|
89
90
|
isPreviewModalOpen: boolean;
|
|
90
91
|
isRenameModalOpen: boolean;
|
|
91
92
|
isShareModalOpen: boolean;
|
|
@@ -546,6 +547,20 @@ declare class ContentExplorer extends Component<ContentExplorerProps, State> {
|
|
|
546
547
|
updateMetadata: (item: BoxItem, field: string, oldValue?: MetadataFieldValue | null, newValue?: MetadataFieldValue | null) => void;
|
|
547
548
|
updateMetadataSuccessCallback: (item: BoxItem, field: string, newValue?: MetadataFieldValue | null) => void;
|
|
548
549
|
clearSelectedItemIds: () => void;
|
|
550
|
+
/**
|
|
551
|
+
* Toggle metadata side panel visibility
|
|
552
|
+
*
|
|
553
|
+
* @private
|
|
554
|
+
* @return {void}
|
|
555
|
+
*/
|
|
556
|
+
onMetadataSidePanelToggle: () => void;
|
|
557
|
+
/**
|
|
558
|
+
* Close metadata side panel
|
|
559
|
+
*
|
|
560
|
+
* @private
|
|
561
|
+
* @return {void}
|
|
562
|
+
*/
|
|
563
|
+
closeMetadataSidePanel: () => void;
|
|
549
564
|
/**
|
|
550
565
|
* Renders the file picker
|
|
551
566
|
*
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Selection } from 'react-aria-components';
|
|
3
|
+
import type { Collection } from '../../common/types/core';
|
|
4
|
+
import type { MetadataTemplate } from '../../common/types/metadata';
|
|
5
|
+
import './MetadataSidePanel.scss';
|
|
6
|
+
export interface MetadataSidePanelProps {
|
|
7
|
+
currentCollection: Collection;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
metadataTemplate: MetadataTemplate;
|
|
10
|
+
selectedItemIds: Selection;
|
|
11
|
+
}
|
|
12
|
+
declare const MetadataSidePanel: ({ currentCollection, onClose, selectedItemIds, metadataTemplate, }: MetadataSidePanelProps) => React.JSX.Element;
|
|
13
|
+
export default MetadataSidePanel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,5 +5,6 @@ export declare const metadataView: Story;
|
|
|
5
5
|
export declare const metadataViewV2: Story;
|
|
6
6
|
export declare const metadataViewV2WithCustomActions: Story;
|
|
7
7
|
export declare const metadataViewV2WithInitialFilterValues: Story;
|
|
8
|
+
export declare const sidePanelOpenWithSingleItemSelected: Story;
|
|
8
9
|
declare const meta: Meta<typeof ContentExplorer>;
|
|
9
10
|
export default meta;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MetadataTemplate } from '@box/metadata-editor';
|
|
2
|
+
import type { Selection } from 'react-aria-components';
|
|
3
|
+
import type { BoxItem, Collection } from '../../common/types/core';
|
|
4
|
+
export declare function useSelectedItemText(currentCollection: Collection, selectedItemIds: Selection): string;
|
|
5
|
+
export declare function getTemplateInstance(metadataTemplate: MetadataTemplate, selectedItems: BoxItem[]): {
|
|
6
|
+
canEdit: boolean;
|
|
7
|
+
displayName: string;
|
|
8
|
+
hidden: boolean;
|
|
9
|
+
id: string;
|
|
10
|
+
fields: {
|
|
11
|
+
displayName: string;
|
|
12
|
+
hidden: boolean;
|
|
13
|
+
id: string;
|
|
14
|
+
key: string;
|
|
15
|
+
options: import("@box/metadata-editor").MetadataTemplateFieldOption[];
|
|
16
|
+
type: import("@box/metadata-editor").MetadataTemplateFieldType;
|
|
17
|
+
value: any;
|
|
18
|
+
}[];
|
|
19
|
+
scope: string;
|
|
20
|
+
templateKey: string;
|
|
21
|
+
type: string;
|
|
22
|
+
};
|
package/package.json
CHANGED
|
@@ -28,6 +28,7 @@ export interface SubHeaderProps {
|
|
|
28
28
|
onGridViewSliderChange?: (newSliderValue: number) => void;
|
|
29
29
|
onItemClick: (id: string | null, triggerNavigationEvent: boolean | null) => void;
|
|
30
30
|
onSortChange: (sortBy: string, sortDirection: string) => void;
|
|
31
|
+
onMetadataSidePanelToggle?: () => void;
|
|
31
32
|
onUpload: () => void;
|
|
32
33
|
onViewModeChange?: (viewMode: ViewMode) => void;
|
|
33
34
|
portalElement?: HTMLElement;
|
|
@@ -53,6 +54,7 @@ const SubHeader = ({
|
|
|
53
54
|
onCreate,
|
|
54
55
|
onItemClick,
|
|
55
56
|
onSortChange,
|
|
57
|
+
onMetadataSidePanelToggle,
|
|
56
58
|
onUpload,
|
|
57
59
|
onViewModeChange,
|
|
58
60
|
portalElement,
|
|
@@ -109,9 +111,11 @@ const SubHeader = ({
|
|
|
109
111
|
onCreate={onCreate}
|
|
110
112
|
onGridViewSliderChange={onGridViewSliderChange}
|
|
111
113
|
onSortChange={onSortChange}
|
|
114
|
+
onMetadataSidePanelToggle={onMetadataSidePanelToggle}
|
|
112
115
|
onUpload={onUpload}
|
|
113
116
|
onViewModeChange={onViewModeChange}
|
|
114
117
|
portalElement={portalElement}
|
|
118
|
+
selectedItemIds={selectedItemIds}
|
|
115
119
|
view={view}
|
|
116
120
|
viewMode={viewMode}
|
|
117
121
|
/>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import { XMark } from '@box/blueprint-web-assets/icons/Fill/index';
|
|
4
4
|
import { IconButton, PageHeader, Text } from '@box/blueprint-web';
|
|
5
5
|
import type { Selection } from 'react-aria-components';
|
|
6
|
+
import { useSelectedItemText } from '../../content-explorer/utils';
|
|
6
7
|
import type { Collection } from '../../../common/types/core';
|
|
7
8
|
import messages from '../messages';
|
|
8
9
|
|
|
@@ -20,27 +21,7 @@ const SubHeaderLeftV2 = (props: SubHeaderLeftV2Props) => {
|
|
|
20
21
|
const { currentCollection, onClearSelectedItemIds, rootName, selectedItemIds, title } = props;
|
|
21
22
|
const { formatMessage } = useIntl();
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
const selectedItemText: string = useMemo(() => {
|
|
25
|
-
const selectedCount = selectedItemIds === 'all' ? currentCollection.items.length : selectedItemIds.size;
|
|
26
|
-
|
|
27
|
-
if (selectedCount === 0) {
|
|
28
|
-
return '';
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Case 1: Single selected item - show item name
|
|
32
|
-
if (selectedCount === 1) {
|
|
33
|
-
const selectedKey =
|
|
34
|
-
selectedItemIds === 'all' ? currentCollection.items[0].id : selectedItemIds.values().next().value;
|
|
35
|
-
const selectedItem = currentCollection.items.find(item => item.id === selectedKey);
|
|
36
|
-
return selectedItem?.name ?? '';
|
|
37
|
-
}
|
|
38
|
-
// Case 2: Multiple selected items - show count
|
|
39
|
-
if (selectedCount > 1) {
|
|
40
|
-
return formatMessage(messages.numFilesSelected, { numSelected: selectedCount });
|
|
41
|
-
}
|
|
42
|
-
return '';
|
|
43
|
-
}, [currentCollection.items, formatMessage, selectedItemIds]);
|
|
24
|
+
const selectedItemText = useSelectedItemText(currentCollection, selectedItemIds);
|
|
44
25
|
|
|
45
26
|
// Case 1 and 2: selected item text with X button
|
|
46
27
|
if (selectedItemText) {
|
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { Button } from '@box/blueprint-web';
|
|
3
3
|
import { Pencil } from '@box/blueprint-web-assets/icons/Fill';
|
|
4
4
|
import { useIntl } from 'react-intl';
|
|
5
|
+
import type { Selection } from 'react-aria-components';
|
|
5
6
|
import Sort from './Sort';
|
|
6
7
|
import Add from './Add';
|
|
7
8
|
import GridViewSlider from '../../../components/grid-view/GridViewSlider';
|
|
@@ -27,9 +28,11 @@ export interface SubHeaderRightProps {
|
|
|
27
28
|
onCreate: () => void;
|
|
28
29
|
onGridViewSliderChange: (newSliderValue: number) => void;
|
|
29
30
|
onSortChange: (sortBy: SortBy, sortDirection: SortDirection) => void;
|
|
31
|
+
onMetadataSidePanelToggle?: () => void;
|
|
30
32
|
onUpload: () => void;
|
|
31
33
|
onViewModeChange?: (viewMode: ViewMode) => void;
|
|
32
34
|
portalElement?: HTMLElement;
|
|
35
|
+
selectedItemIds?: Selection;
|
|
33
36
|
view: View;
|
|
34
37
|
viewMode: ViewMode;
|
|
35
38
|
}
|
|
@@ -45,9 +48,11 @@ const SubHeaderRight = ({
|
|
|
45
48
|
onCreate,
|
|
46
49
|
onGridViewSliderChange,
|
|
47
50
|
onSortChange,
|
|
51
|
+
onMetadataSidePanelToggle,
|
|
48
52
|
onUpload,
|
|
49
53
|
onViewModeChange,
|
|
50
54
|
portalElement,
|
|
55
|
+
selectedItemIds,
|
|
51
56
|
view,
|
|
52
57
|
viewMode,
|
|
53
58
|
}: SubHeaderRightProps) => {
|
|
@@ -60,6 +65,7 @@ const SubHeaderRight = ({
|
|
|
60
65
|
const showSort: boolean = isFolder && hasItems;
|
|
61
66
|
const showAdd: boolean = (!!canUpload || !!canCreateNewFolder) && isFolder;
|
|
62
67
|
const isMetadataView: boolean = view === VIEW_METADATA;
|
|
68
|
+
const hasSelectedItems: boolean = !!(selectedItemIds && (selectedItemIds === 'all' || selectedItemIds.size > 0));
|
|
63
69
|
return (
|
|
64
70
|
<div className="be-sub-header-right">
|
|
65
71
|
{!isMetadataView && (
|
|
@@ -90,8 +96,8 @@ const SubHeaderRight = ({
|
|
|
90
96
|
</>
|
|
91
97
|
)}
|
|
92
98
|
|
|
93
|
-
{isMetadataView && isMetadataViewV2Feature && (
|
|
94
|
-
<Button icon={Pencil} size="large" variant="primary">
|
|
99
|
+
{isMetadataView && isMetadataViewV2Feature && hasSelectedItems && (
|
|
100
|
+
<Button icon={Pencil} size="large" variant="primary" onClick={onMetadataSidePanelToggle}>
|
|
95
101
|
{formatMessage(messages.metadata)}
|
|
96
102
|
</Button>
|
|
97
103
|
)}
|
|
@@ -7,5 +7,17 @@
|
|
|
7
7
|
.bcpr {
|
|
8
8
|
z-index: 1; // Prevents overlay issues with list-item when a file is previewed
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
.be-app-element {
|
|
12
|
+
flex-direction: row;
|
|
13
|
+
gap: var(--space-4);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.bce-ContentExplorer-main {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex: 1;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
min-width: 0;
|
|
21
|
+
}
|
|
10
22
|
}
|
|
11
23
|
}
|