Skip to content

Commit 0c6f832

Browse files
authored
Merge pull request #1980 from Ateina/921-filepicker-order-of-tabs
921 FilePicker order of tabs and default tab
2 parents b3a47a7 + 2d7f581 commit 0c6f832

File tree

5 files changed

+114
-50
lines changed

5 files changed

+114
-50
lines changed

docs/documentation/docs/controls/FilePicker.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,10 @@ The FilePicker component can be configured with the following properties:
107107
| includePageLibraries | boolean | no | Specifies if Site Pages library to be visible on Sites tab |
108108
| allowExternalLinks | boolean | no | Specifies if external links should be allowed. |
109109
| checkIfFileExists | boolean | no | When using file links, this property allows the user to choose if the control should check if the link point to a file that exists or not. |
110+
| tabOrder | FilePickerTab[]| no | Defines a custom display order for the tabs. Tabs not listed will follow their default order. |
111+
| defaultSelectedTab | FilePickerTab | no | Sets the default selected tab. If not specified, the first visible tab is used. |
110112

111-
interface `IFilePickerResult`
113+
Interface `IFilePickerResult`
112114

113115
Provides options for carousel buttons ___location.
114116

@@ -120,4 +122,20 @@ Provides options for carousel buttons ___location.
120122
| fileSize | number | Size of the result (in bytes). Set only for file upload |
121123
| downloadFileContent | () => Promise<File> | Function allows to download file content. Returns File object. |
122124

125+
Enum `FilePickerTab`
126+
127+
Represents the available tabs in the File Picker component. Each tab corresponds to a different source from which users can select files.
128+
129+
| Name | Description |
130+
|-----------------|-------------------------------------------------------|
131+
| Recent | Displays recently used files. |
132+
| StockImages | Shows stock image selection. |
133+
| Web | Allows searching files from the web. |
134+
| OrgAssets | Displays organizational assets. |
135+
| OneDrive | Allows file selection from OneDrive. |
136+
| Site | Enables browsing site files. |
137+
| Upload | Provides option to upload local files. |
138+
| Link | Lets the user add a file via a URL. |
139+
| MultipleUpload | Supports uploading multiple files at once. |
140+
123141
![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/filePicker/FilePicker)

src/controls/filePicker/FilePicker.tsx

Lines changed: 72 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { StockImages } from "./StockImagesTab/StockImages";
3636
import UploadFilePickerTab from "./UploadFilePickerTab/UploadFilePickerTab";
3737
import MultipleUploadFilePickerTab from "./MultipleUploadFilePickerTab/MultipleUploadFilePickerTab";
3838
import WebSearchTab from "./WebSearchTab/WebSearchTab";
39+
import { FilePickerTab } from "./FilePickerTab";
3940

4041

4142
export class FilePicker extends React.Component<
@@ -89,7 +90,7 @@ export class FilePicker extends React.Component<
8990

9091
this.setState({
9192
organisationAssetsEnabled: orgAssetsEnabled,
92-
selectedTab: this.getDefaultSelectedTabKey(this.props, orgAssetsEnabled),
93+
selectedTab: this._getDefaultSelectedTabKey(this.props, orgAssetsEnabled),
9394
});
9495
if (!!this.props.context && !!this.props.webAbsoluteUrl) {
9596
const { title, id } = await this.fileBrowserService.getSiteTitleAndId();
@@ -190,7 +191,7 @@ export class FilePicker extends React.Component<
190191
/>
191192
</div>
192193
<div className={styles.tabsContainer}>
193-
{this.state.selectedTab === "keyLink" && (
194+
{this.state.selectedTab === FilePickerTab.Link && (
194195
<LinkFilePickerTab
195196
fileSearchService={this.fileSearchService}
196197
renderCustomLinkTabContent={
@@ -201,7 +202,7 @@ export class FilePicker extends React.Component<
201202
{...linkTabProps}
202203
/>
203204
)}
204-
{this.state.selectedTab === "keyUpload" && (
205+
{this.state.selectedTab === FilePickerTab.Upload && (
205206
<UploadFilePickerTab
206207
renderCustomUploadTabContent={
207208
this.props.renderCustomUploadTabContent
@@ -210,7 +211,7 @@ export class FilePicker extends React.Component<
210211
onChange={this._handleOnChange}
211212
/>
212213
)}
213-
{this.state.selectedTab === "keyMultipleUpload" && (
214+
{this.state.selectedTab === FilePickerTab.MultipleUpload && (
214215
<MultipleUploadFilePickerTab
215216
renderCustomMultipleUploadTabContent={
216217
this.props.renderCustomMultipleUploadTabContent
@@ -219,7 +220,7 @@ export class FilePicker extends React.Component<
219220
onChange={this._handleOnChange}
220221
/>
221222
)}
222-
{this.state.selectedTab === "keySite" && (
223+
{this.state.selectedTab === FilePickerTab.Site && (
223224
<SiteFilePickerTab
224225
fileBrowserService={this.fileBrowserService}
225226
includePageLibraries={this.props.includePageLibraries}
@@ -230,37 +231,37 @@ export class FilePicker extends React.Component<
230231
{...linkTabProps}
231232
/>
232233
)}
233-
{this.state.selectedTab === "keyOrgAssets" && (
234+
{this.state.selectedTab === FilePickerTab.OrgAssets && (
234235
<SiteFilePickerTab
235236
breadcrumbFirstNode={{
236237
isCurrentItem: true,
237238
text: strings.OrgAssetsTabLabel,
238-
key: "keyOrgAssets",
239+
key: FilePickerTab.OrgAssets,
239240
}}
240241
fileBrowserService={this.orgAssetsService}
241242
webTitle={this.state.webTitle}
242243
{...linkTabProps}
243244
/>
244245
)}
245-
{this.state.selectedTab === "keyWeb" && (
246+
{this.state.selectedTab === FilePickerTab.Web && (
246247
<WebSearchTab
247248
bingSearchService={this.fileSearchService}
248249
{...linkTabProps}
249250
/>
250251
)}
251-
{this.state.selectedTab === "keyOneDrive" && (
252+
{this.state.selectedTab === FilePickerTab.OneDrive && (
252253
<OneDriveFilesTab
253254
oneDriveService={this.oneDriveService}
254255
{...linkTabProps}
255256
/>
256257
)}
257-
{this.state.selectedTab === "keyRecent" && (
258+
{this.state.selectedTab === FilePickerTab.Recent && (
258259
<RecentFilesTab
259260
fileSearchService={this.fileSearchService}
260261
{...linkTabProps}
261262
/>
262263
)}
263-
{this.state.selectedTab === "keyStockImages" && (
264+
{this.state.selectedTab === FilePickerTab.StockImages && (
264265
<StockImages
265266
language={
266267
this.props.context.pageContext.cultureInfo.currentCultureName
@@ -294,7 +295,7 @@ export class FilePicker extends React.Component<
294295
private _handleOpenPanel = (): void => {
295296
this.setState({
296297
panelOpen: true,
297-
selectedTab: this.getDefaultSelectedTabKey(
298+
selectedTab: this._getDefaultSelectedTabKey(
298299
this.props,
299300
this.state.organisationAssetsEnabled
300301
),
@@ -344,29 +345,29 @@ export class FilePicker extends React.Component<
344345
*/
345346
private _getNavPanelOptions = (): INavLinkGroup[] => {
346347
const addUrl = this.props.storeLastActiveTab !== false;
347-
const links = [];
348+
let links = [];
348349

349350
if (!this.props.hideRecentTab) {
350351
links.push({
351352
name: strings.RecentLinkLabel,
352353
url: addUrl ? "#recent" : undefined,
353354
icon: "Recent",
354-
key: "keyRecent",
355+
key: FilePickerTab.Recent,
355356
});
356357
}
357358
if (!this.props.hideStockImages) {
358359
links.push({
359360
name: strings.StockImagesLinkLabel,
360361
url: addUrl ? "#stockImages" : undefined,
361-
key: "keyStockImages",
362+
key: FilePickerTab.StockImages,
362363
icon: "ImageSearch",
363364
});
364365
}
365366
if (this.props.bingAPIKey && !this.props.hideWebSearchTab) {
366367
links.push({
367368
name: strings.WebSearchLinkLabel,
368369
url: addUrl ? "#search" : undefined,
369-
key: "keyWeb",
370+
key: FilePickerTab.Web,
370371
icon: "Search",
371372
});
372373
}
@@ -378,85 +379,107 @@ export class FilePicker extends React.Component<
378379
name: strings.OrgAssetsLinkLabel,
379380
url: addUrl ? "#orgAssets" : undefined,
380381
icon: "FabricFolderConfirm",
381-
key: "keyOrgAssets",
382+
key: FilePickerTab.OrgAssets,
382383
});
383384
}
384385
if (!this.props.hideOneDriveTab) {
385386
links.push({
386387
name: "OneDrive",
387388
url: addUrl ? "#onedrive" : undefined,
388-
key: "keyOneDrive",
389+
key: FilePickerTab.OneDrive,
389390
icon: "OneDrive",
390391
});
391392
}
392393
if (!this.props.hideSiteFilesTab) {
393394
links.push({
394395
name: strings.SiteLinkLabel,
395396
url: addUrl ? "#globe" : undefined,
396-
key: "keySite",
397+
key: FilePickerTab.Site,
397398
icon: "Globe",
398399
});
399400
}
400401
if (!this.props.hideLocalUploadTab) {
401402
links.push({
402403
name: strings.UploadLinkLabel,
403404
url: addUrl ? "#upload" : undefined,
404-
key: "keyUpload",
405+
key: FilePickerTab.Upload,
405406
icon: "System",
406407
});
407408
}
408409
if (!this.props.hideLocalMultipleUploadTab) {
409410
links.push({
410411
name: strings.UploadLinkLabel + " " + strings.OneDriveRootFolderName,
411412
url: addUrl ? "#Multipleupload" : undefined,
412-
key: "keyMultipleUpload",
413+
key: FilePickerTab.MultipleUpload,
413414
icon: "BulkUpload",
414415
});
415416
}
416417
if (!this.props.hideLinkUploadTab) {
417418
links.push({
418419
name: strings.FromLinkLinkLabel,
419420
url: addUrl ? "#link" : undefined,
420-
key: "keyLink",
421+
key: FilePickerTab.Link,
421422
icon: "Link",
422423
});
423424
}
424425

426+
if(this.props.tabOrder) {
427+
links = this._getTabOrder(links);
428+
}
429+
425430
const groups: INavLinkGroup[] = [{ links }];
426431
return groups;
427432
}
428433

429-
private getDefaultSelectedTabKey = (
434+
/**
435+
* Sorts navigation tabs based on the tabOrder prop
436+
*/
437+
private _getTabOrder = (links): INavLink[] => {
438+
const sortedKeys = [
439+
...this.props.tabOrder,
440+
...links.map(l => l.key).filter(key => !this.props.tabOrder.includes(key)),
441+
];
442+
443+
links.sort((a, b) => {
444+
return sortedKeys.indexOf(a.key) - sortedKeys.indexOf(b.key);
445+
});
446+
447+
return links;
448+
};
449+
450+
/**
451+
* Returns the default selected tab key
452+
*/
453+
private _getDefaultSelectedTabKey = (
430454
props: IFilePickerProps,
431455
orgAssetsEnabled: boolean
432456
): string => {
433-
if (!props.hideRecentTab) {
434-
return "keyRecent";
435-
}
436-
if (!props.hideStockImages) {
437-
return "keyStockImages";
438-
}
439-
if (props.bingAPIKey && !props.hideWebSearchTab) {
440-
return "keyWeb";
441-
}
442-
if (!props.hideOrganisationalAssetTab && orgAssetsEnabled) {
443-
return "keyOrgAssets";
444-
}
445-
if (!props.hideOneDriveTab) {
446-
return "keyOneDrive";
447-
}
448-
if (!props.hideSiteFilesTab) {
449-
return "keySite";
450-
}
451-
if (!props.hideLocalUploadTab) {
452-
return "keyUpload";
453-
}
454-
if (!props.hideLinkUploadTab) {
455-
return "keyLink";
456-
}
457-
if (!props.hideLocalMultipleUploadTab) {
458-
return "keyMultipleUpload";
457+
const tabsConfig = [
458+
{ isTabVisible: !props.hideRecentTab, tabKey: FilePickerTab.Recent },
459+
{ isTabVisible: !props.hideStockImages, tabKey: FilePickerTab.StockImages },
460+
{ isTabVisible: props.bingAPIKey && !props.hideWebSearchTab, tabKey: FilePickerTab.Web },
461+
{ isTabVisible: !props.hideOrganisationalAssetTab && orgAssetsEnabled, tabKey: FilePickerTab.OrgAssets },
462+
{ isTabVisible: !props.hideOneDriveTab, tabKey: FilePickerTab.OneDrive },
463+
{ isTabVisible: !props.hideSiteFilesTab, tabKey: FilePickerTab.Site },
464+
{ isTabVisible: !props.hideLocalUploadTab, tabKey: FilePickerTab.Upload },
465+
{ isTabVisible: !props.hideLinkUploadTab, tabKey: FilePickerTab.Link },
466+
{ isTabVisible: !props.hideLocalMultipleUploadTab, tabKey: FilePickerTab.MultipleUpload }
467+
];
468+
469+
const visibleTabs = tabsConfig.filter(tab => tab.isTabVisible);
470+
const visibleTabKeys = visibleTabs.map(tab => tab.tabKey);
471+
472+
// If defaultSelectedTab is provided and is visible, then return tabKey
473+
if(this.props.defaultSelectedTab && visibleTabKeys.includes(this.props.defaultSelectedTab)) {
474+
return this.props.defaultSelectedTab;
459475
}
460476

477+
// If no valid default tab is provided, find the first visible tab in the order
478+
if (this.props.tabOrder) {
479+
const visibleTabSet = new Set(visibleTabKeys);
480+
return this.props.tabOrder.find(key => visibleTabSet.has(key));
481+
} else {
482+
return visibleTabKeys[0]; // first visible tab from default order
483+
}
461484
}
462485
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export enum FilePickerTab {
2+
Recent = "keyRecent",
3+
StockImages = "keyStockImages",
4+
Web = "keyWeb",
5+
OrgAssets = "keyOrgAssets",
6+
OneDrive = "keyOneDrive",
7+
Site = "keySite",
8+
Upload = "keyUpload",
9+
Link = "keyLink",
10+
MultipleUpload = "keyMultipleUpload"
11+
}

src/controls/filePicker/IFilePickerProps.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IIconProps } from "@fluentui/react/lib/Icon";
33
import { BaseComponentContext } from '@microsoft/sp-component-base';
44

55
import { IFilePickerResult } from "./FilePicker.types";
6+
import { FilePickerTab } from "./FilePickerTab";
67

78
export interface IFilePickerProps {
89
/**
@@ -175,4 +176,14 @@ export interface IFilePickerProps {
175176
* Specifies if file check should be done
176177
*/
177178
checkIfFileExists?: boolean;
179+
/**
180+
* Specifies tab order
181+
* Default [FilePickerTab.Recent, FilePickerTab.StockImages, FilePickerTab.Web, FilePickerTab.OrgAssets, FilePickerTab.OneDrive, FilePickerTab.Site, FilePickerTab.Upload, FilePickerTab.Link, FilePickerTab.MultipleUpload]
182+
*/
183+
tabOrder?: FilePickerTab[];
184+
/**
185+
* Specifies default selected tab
186+
* One of the values from the FilePickerTab enum: Recent, StockImages, Web, OrgAssets, OneDrive, Site, Upload, Link, or MultipleUpload.
187+
*/
188+
defaultSelectedTab?: FilePickerTab;
178189
}

src/controls/filePicker/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from "./FilePicker";
22
export * from "./FilePicker.types";
33
export * from "./IFilePickerProps";
44
export * from "./IFilePickerState";
5+
export * from "./FilePickerTab";

0 commit comments

Comments
 (0)