mirror of
				https://github.com/Azure/cosmos-explorer.git
				synced 2025-10-30 22:50:32 +00:00 
			
		
		
		
	Refactor GenericRightPaneComponent to accept a ReactComponent as its content (#146)
This commit is contained in:
		
							parent
							
								
									455722c316
								
							
						
					
					
						commit
						fb71fb4e82
					
				| @ -6,17 +6,8 @@ import { JunoClient, IPinnedRepo } from "../../Juno/JunoClient"; | |||||||
| import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils"; | import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils"; | ||||||
| import Explorer from "../Explorer"; | import Explorer from "../Explorer"; | ||||||
| import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent"; | import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent"; | ||||||
| import { | import { CopyNotebookPaneComponent, CopyNotebookPaneProps } from "./CopyNotebookPaneComponent"; | ||||||
|   Stack, | import { IDropdownOption } from "office-ui-fabric-react"; | ||||||
|   Label, |  | ||||||
|   Text, |  | ||||||
|   Dropdown, |  | ||||||
|   IDropdownProps, |  | ||||||
|   IDropdownOption, |  | ||||||
|   SelectableOptionMenuItemType, |  | ||||||
|   IRenderFunction, |  | ||||||
|   ISelectableOption |  | ||||||
| } from "office-ui-fabric-react"; |  | ||||||
| import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService"; | import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService"; | ||||||
| import { HttpStatusCodes } from "../../Common/Constants"; | import { HttpStatusCodes } from "../../Common/Constants"; | ||||||
| import * as GitHubUtils from "../../Utils/GitHubUtils"; | import * as GitHubUtils from "../../Utils/GitHubUtils"; | ||||||
| @ -60,9 +51,8 @@ export class CopyNotebookPaneAdapter implements ReactAdapter { | |||||||
|       return undefined; |       return undefined; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const props: GenericRightPaneProps = { |     const genericPaneProps: GenericRightPaneProps = { | ||||||
|       container: this.container, |       container: this.container, | ||||||
|       content: this.createContent(), |  | ||||||
|       formError: this.formError, |       formError: this.formError, | ||||||
|       formErrorDetail: this.formErrorDetail, |       formErrorDetail: this.formErrorDetail, | ||||||
|       id: "copynotebookpane", |       id: "copynotebookpane", | ||||||
| @ -73,7 +63,17 @@ export class CopyNotebookPaneAdapter implements ReactAdapter { | |||||||
|       onSubmit: () => this.submit() |       onSubmit: () => this.submit() | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return <GenericRightPaneComponent {...props} />; |     const copyNotebookPaneProps: CopyNotebookPaneProps = { | ||||||
|  |       name: this.name, | ||||||
|  |       pinnedRepos: this.pinnedRepos, | ||||||
|  |       onDropDownChange: this.onDropDownChange | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <GenericRightPaneComponent {...genericPaneProps}> | ||||||
|  |         <CopyNotebookPaneComponent {...copyNotebookPaneProps} /> | ||||||
|  |       </GenericRightPaneComponent> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public triggerRender(): void { |   public triggerRender(): void { | ||||||
| @ -181,91 +181,6 @@ export class CopyNotebookPaneAdapter implements ReactAdapter { | |||||||
|     return this.container.uploadFile(this.name, this.content, parent); |     return this.container.uploadFile(this.name, this.content, parent); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   private createContent = (): JSX.Element => { |  | ||||||
|     const dropDownProps: IDropdownProps = { |  | ||||||
|       label: "Location", |  | ||||||
|       ariaLabel: "Location", |  | ||||||
|       placeholder: "Select an option", |  | ||||||
|       onRenderTitle: this.onRenderDropDownTitle, |  | ||||||
|       onRenderOption: this.onRenderDropDownOption, |  | ||||||
|       options: this.getDropDownOptions(), |  | ||||||
|       onChange: this.onDropDownChange |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     return ( |  | ||||||
|       <div className="paneMainContent"> |  | ||||||
|         <Stack tokens={{ childrenGap: 10 }}> |  | ||||||
|           <Stack.Item> |  | ||||||
|             <Label htmlFor="notebookName">Name</Label> |  | ||||||
|             <Text id="notebookName">{this.name}</Text> |  | ||||||
|           </Stack.Item> |  | ||||||
| 
 |  | ||||||
|           <Dropdown {...dropDownProps} /> |  | ||||||
|         </Stack> |  | ||||||
|       </div> |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private onRenderDropDownTitle: IRenderFunction<IDropdownOption[]> = (options: IDropdownOption[]): JSX.Element => { |  | ||||||
|     return <span>{options.length && options[0].title}</span>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private onRenderDropDownOption: IRenderFunction<ISelectableOption> = (option: ISelectableOption): JSX.Element => { |  | ||||||
|     return <span style={{ whiteSpace: "pre-wrap" }}>{option.text}</span>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private getDropDownOptions = (): IDropdownOption[] => { |  | ||||||
|     const options: IDropdownOption[] = []; |  | ||||||
| 
 |  | ||||||
|     options.push({ |  | ||||||
|       key: "MyNotebooks-Item", |  | ||||||
|       text: ResourceTreeAdapter.MyNotebooksTitle, |  | ||||||
|       title: ResourceTreeAdapter.MyNotebooksTitle, |  | ||||||
|       data: { |  | ||||||
|         type: "MyNotebooks" |  | ||||||
|       } as Location |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     if (this.pinnedRepos && this.pinnedRepos.length > 0) { |  | ||||||
|       options.push({ |  | ||||||
|         key: "GitHub-Header-Divider", |  | ||||||
|         text: undefined, |  | ||||||
|         itemType: SelectableOptionMenuItemType.Divider |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       options.push({ |  | ||||||
|         key: "GitHub-Header", |  | ||||||
|         text: ResourceTreeAdapter.GitHubReposTitle, |  | ||||||
|         itemType: SelectableOptionMenuItemType.Header |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       this.pinnedRepos.forEach(pinnedRepo => { |  | ||||||
|         const repoFullName = GitHubUtils.toRepoFullName(pinnedRepo.owner, pinnedRepo.name); |  | ||||||
|         options.push({ |  | ||||||
|           key: `GitHub-Repo-${repoFullName}`, |  | ||||||
|           text: repoFullName, |  | ||||||
|           disabled: true |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         pinnedRepo.branches.forEach(branch => |  | ||||||
|           options.push({ |  | ||||||
|             key: `GitHub-Repo-${repoFullName}-${branch.name}`, |  | ||||||
|             text: `${CopyNotebookPaneAdapter.BranchNameWhiteSpace}${branch.name}`, |  | ||||||
|             title: `${repoFullName} - ${branch.name}`, |  | ||||||
|             data: { |  | ||||||
|               type: "GitHub", |  | ||||||
|               owner: pinnedRepo.owner, |  | ||||||
|               repo: pinnedRepo.name, |  | ||||||
|               branch: branch.name |  | ||||||
|             } as Location |  | ||||||
|           }) |  | ||||||
|         ); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return options; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private onDropDownChange = (_: React.FormEvent<HTMLDivElement>, option?: IDropdownOption): void => { |   private onDropDownChange = (_: React.FormEvent<HTMLDivElement>, option?: IDropdownOption): void => { | ||||||
|     this.selectedLocation = option?.data; |     this.selectedLocation = option?.data; | ||||||
|   }; |   }; | ||||||
|  | |||||||
							
								
								
									
										119
									
								
								src/Explorer/Panes/CopyNotebookPaneComponent.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/Explorer/Panes/CopyNotebookPaneComponent.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | |||||||
|  | import * as GitHubUtils from "../../Utils/GitHubUtils"; | ||||||
|  | import * as React from "react"; | ||||||
|  | import { IPinnedRepo } from "../../Juno/JunoClient"; | ||||||
|  | import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter"; | ||||||
|  | import { | ||||||
|  |   Stack, | ||||||
|  |   Label, | ||||||
|  |   Text, | ||||||
|  |   Dropdown, | ||||||
|  |   IDropdownProps, | ||||||
|  |   IDropdownOption, | ||||||
|  |   SelectableOptionMenuItemType, | ||||||
|  |   IRenderFunction, | ||||||
|  |   ISelectableOption | ||||||
|  | } from "office-ui-fabric-react"; | ||||||
|  | 
 | ||||||
|  | interface Location { | ||||||
|  |   type: "MyNotebooks" | "GitHub"; | ||||||
|  | 
 | ||||||
|  |   // GitHub
 | ||||||
|  |   owner?: string; | ||||||
|  |   repo?: string; | ||||||
|  |   branch?: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface CopyNotebookPaneProps { | ||||||
|  |   name: string; | ||||||
|  |   pinnedRepos: IPinnedRepo[]; | ||||||
|  |   onDropDownChange: (_: React.FormEvent<HTMLDivElement>, option?: IDropdownOption) => void; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class CopyNotebookPaneComponent extends React.Component<CopyNotebookPaneProps> { | ||||||
|  |   private static readonly BranchNameWhiteSpace = "   "; | ||||||
|  | 
 | ||||||
|  |   public render(): JSX.Element { | ||||||
|  |     const dropDownProps: IDropdownProps = { | ||||||
|  |       label: "Location", | ||||||
|  |       ariaLabel: "Location", | ||||||
|  |       placeholder: "Select an option", | ||||||
|  |       onRenderTitle: this.onRenderDropDownTitle, | ||||||
|  |       onRenderOption: this.onRenderDropDownOption, | ||||||
|  |       options: this.getDropDownOptions(), | ||||||
|  |       onChange: this.props.onDropDownChange | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <div className="paneMainContent"> | ||||||
|  |         <Stack tokens={{ childrenGap: 10 }}> | ||||||
|  |           <Stack.Item> | ||||||
|  |             <Label htmlFor="notebookName">Name</Label> | ||||||
|  |             <Text id="notebookName">{this.props.name}</Text> | ||||||
|  |           </Stack.Item> | ||||||
|  | 
 | ||||||
|  |           <Dropdown {...dropDownProps} /> | ||||||
|  |         </Stack> | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private onRenderDropDownTitle: IRenderFunction<IDropdownOption[]> = (options: IDropdownOption[]): JSX.Element => { | ||||||
|  |     return <span>{options.length && options[0].title}</span>; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   private onRenderDropDownOption: IRenderFunction<ISelectableOption> = (option: ISelectableOption): JSX.Element => { | ||||||
|  |     return <span style={{ whiteSpace: "pre-wrap" }}>{option.text}</span>; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   private getDropDownOptions = (): IDropdownOption[] => { | ||||||
|  |     const options: IDropdownOption[] = []; | ||||||
|  | 
 | ||||||
|  |     options.push({ | ||||||
|  |       key: "MyNotebooks-Item", | ||||||
|  |       text: ResourceTreeAdapter.MyNotebooksTitle, | ||||||
|  |       title: ResourceTreeAdapter.MyNotebooksTitle, | ||||||
|  |       data: { | ||||||
|  |         type: "MyNotebooks" | ||||||
|  |       } as Location | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (this.props.pinnedRepos && this.props.pinnedRepos.length > 0) { | ||||||
|  |       options.push({ | ||||||
|  |         key: "GitHub-Header-Divider", | ||||||
|  |         text: undefined, | ||||||
|  |         itemType: SelectableOptionMenuItemType.Divider | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       options.push({ | ||||||
|  |         key: "GitHub-Header", | ||||||
|  |         text: ResourceTreeAdapter.GitHubReposTitle, | ||||||
|  |         itemType: SelectableOptionMenuItemType.Header | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       this.props.pinnedRepos.forEach(pinnedRepo => { | ||||||
|  |         const repoFullName = GitHubUtils.toRepoFullName(pinnedRepo.owner, pinnedRepo.name); | ||||||
|  |         options.push({ | ||||||
|  |           key: `GitHub-Repo-${repoFullName}`, | ||||||
|  |           text: repoFullName, | ||||||
|  |           disabled: true | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         pinnedRepo.branches.forEach(branch => | ||||||
|  |           options.push({ | ||||||
|  |             key: `GitHub-Repo-${repoFullName}-${branch.name}`, | ||||||
|  |             text: `${CopyNotebookPaneComponent.BranchNameWhiteSpace}${branch.name}`, | ||||||
|  |             title: `${repoFullName} - ${branch.name}`, | ||||||
|  |             data: { | ||||||
|  |               type: "GitHub", | ||||||
|  |               owner: pinnedRepo.owner, | ||||||
|  |               repo: pinnedRepo.name, | ||||||
|  |               branch: branch.name | ||||||
|  |             } as Location | ||||||
|  |           }) | ||||||
|  |         ); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return options; | ||||||
|  |   }; | ||||||
|  | } | ||||||
| @ -8,7 +8,6 @@ import Explorer from "../Explorer"; | |||||||
| 
 | 
 | ||||||
| export interface GenericRightPaneProps { | export interface GenericRightPaneProps { | ||||||
|   container: Explorer; |   container: Explorer; | ||||||
|   content: JSX.Element; |  | ||||||
|   formError: string; |   formError: string; | ||||||
|   formErrorDetail: string; |   formErrorDetail: string; | ||||||
|   id: string; |   id: string; | ||||||
| @ -57,18 +56,18 @@ export class GenericRightPaneComponent extends React.Component<GenericRightPaneP | |||||||
|           onKeyDown={this.onKeyDown} |           onKeyDown={this.onKeyDown} | ||||||
|         > |         > | ||||||
|           <div className="panelContentWrapper"> |           <div className="panelContentWrapper"> | ||||||
|             {this.createPanelHeader()} |             {this.renderPanelHeader()} | ||||||
|             {this.createErrorSection()} |             {this.renderErrorSection()} | ||||||
|             {this.props.content} |             {this.props.children} | ||||||
|             {this.createPanelFooter()} |             {this.renderPanelFooter()} | ||||||
|           </div> |           </div> | ||||||
|           {this.createLoadingScreen()} |           {this.renderLoadingScreen()} | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private createPanelHeader = (): JSX.Element => { |   private renderPanelHeader = (): JSX.Element => { | ||||||
|     return ( |     return ( | ||||||
|       <div className="firstdivbg headerline"> |       <div className="firstdivbg headerline"> | ||||||
|         <span id="databaseTitle">{this.props.title}</span> |         <span id="databaseTitle">{this.props.title}</span> | ||||||
| @ -84,7 +83,7 @@ export class GenericRightPaneComponent extends React.Component<GenericRightPaneP | |||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   private createErrorSection = (): JSX.Element => { |   private renderErrorSection = (): JSX.Element => { | ||||||
|     return ( |     return ( | ||||||
|       <div className="warningErrorContainer" aria-live="assertive" hidden={!this.props.formError}> |       <div className="warningErrorContainer" aria-live="assertive" hidden={!this.props.formError}> | ||||||
|         <div className="warningErrorContent"> |         <div className="warningErrorContent"> | ||||||
| @ -104,7 +103,7 @@ export class GenericRightPaneComponent extends React.Component<GenericRightPaneP | |||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   private createPanelFooter = (): JSX.Element => { |   private renderPanelFooter = (): JSX.Element => { | ||||||
|     return ( |     return ( | ||||||
|       <div className="paneFooter"> |       <div className="paneFooter"> | ||||||
|         <div className="leftpanel-okbut"> |         <div className="leftpanel-okbut"> | ||||||
| @ -122,7 +121,7 @@ export class GenericRightPaneComponent extends React.Component<GenericRightPaneP | |||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   private createLoadingScreen = (): JSX.Element => { |   private renderLoadingScreen = (): JSX.Element => { | ||||||
|     return ( |     return ( | ||||||
|       <div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer" hidden={!this.props.isExecuting}> |       <div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer" hidden={!this.props.isExecuting}> | ||||||
|         <img className="dataExplorerLoader" src={LoadingIndicatorIcon} /> |         <img className="dataExplorerLoader" src={LoadingIndicatorIcon} /> | ||||||
|  | |||||||
| @ -44,7 +44,6 @@ export class PublishNotebookPaneAdapter implements ReactAdapter { | |||||||
| 
 | 
 | ||||||
|     const props: GenericRightPaneProps = { |     const props: GenericRightPaneProps = { | ||||||
|       container: this.container, |       container: this.container, | ||||||
|       content: this.createContent(), |  | ||||||
|       formError: this.formError, |       formError: this.formError, | ||||||
|       formErrorDetail: this.formErrorDetail, |       formErrorDetail: this.formErrorDetail, | ||||||
|       id: "publishnotebookpane", |       id: "publishnotebookpane", | ||||||
| @ -56,7 +55,39 @@ export class PublishNotebookPaneAdapter implements ReactAdapter { | |||||||
|       isSubmitButtonVisible: this.isCodeOfConductAccepted |       isSubmitButtonVisible: this.isCodeOfConductAccepted | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return <GenericRightPaneComponent {...props} />; |     const publishNotebookPaneProps: PublishNotebookPaneProps = { | ||||||
|  |       notebookName: this.name, | ||||||
|  |       notebookDescription: "", | ||||||
|  |       notebookTags: "", | ||||||
|  |       notebookAuthor: this.author, | ||||||
|  |       notebookCreatedDate: new Date().toISOString(), | ||||||
|  |       notebookObject: this.notebookObject, | ||||||
|  |       notebookParentDomElement: this.parentDomElement, | ||||||
|  |       onChangeName: (newValue: string) => (this.name = newValue), | ||||||
|  |       onChangeDescription: (newValue: string) => (this.description = newValue), | ||||||
|  |       onChangeTags: (newValue: string) => (this.tags = newValue), | ||||||
|  |       onChangeImageSrc: (newValue: string) => (this.imageSrc = newValue), | ||||||
|  |       onError: this.createFormErrorForLargeImageSelection, | ||||||
|  |       clearFormError: this.clearFormError | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <GenericRightPaneComponent {...props}> | ||||||
|  |         {!this.isCodeOfConductAccepted ? ( | ||||||
|  |           <div style={{ padding: "15px", marginTop: "10px" }}> | ||||||
|  |             <CodeOfConductComponent | ||||||
|  |               junoClient={this.junoClient} | ||||||
|  |               onAcceptCodeOfConduct={() => { | ||||||
|  |                 this.isCodeOfConductAccepted = true; | ||||||
|  |                 this.triggerRender(); | ||||||
|  |               }} | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
|  |         ) : ( | ||||||
|  |           <PublishNotebookPaneComponent {...publishNotebookPaneProps} /> | ||||||
|  |         )} | ||||||
|  |       </GenericRightPaneComponent> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public triggerRender(): void { |   public triggerRender(): void { | ||||||
| @ -166,38 +197,6 @@ export class PublishNotebookPaneAdapter implements ReactAdapter { | |||||||
|     this.triggerRender(); |     this.triggerRender(); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   private createContent = (): JSX.Element => { |  | ||||||
|     const publishNotebookPaneProps: PublishNotebookPaneProps = { |  | ||||||
|       notebookName: this.name, |  | ||||||
|       notebookDescription: "", |  | ||||||
|       notebookTags: "", |  | ||||||
|       notebookAuthor: this.author, |  | ||||||
|       notebookCreatedDate: new Date().toISOString(), |  | ||||||
|       notebookObject: this.notebookObject, |  | ||||||
|       notebookParentDomElement: this.parentDomElement, |  | ||||||
|       onChangeName: (newValue: string) => (this.name = newValue), |  | ||||||
|       onChangeDescription: (newValue: string) => (this.description = newValue), |  | ||||||
|       onChangeTags: (newValue: string) => (this.tags = newValue), |  | ||||||
|       onChangeImageSrc: (newValue: string) => (this.imageSrc = newValue), |  | ||||||
|       onError: this.createFormErrorForLargeImageSelection, |  | ||||||
|       clearFormError: this.clearFormError |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     return !this.isCodeOfConductAccepted ? ( |  | ||||||
|       <div style={{ padding: "15px", marginTop: "10px" }}> |  | ||||||
|         <CodeOfConductComponent |  | ||||||
|           junoClient={this.junoClient} |  | ||||||
|           onAcceptCodeOfConduct={() => { |  | ||||||
|             this.isCodeOfConductAccepted = true; |  | ||||||
|             this.triggerRender(); |  | ||||||
|           }} |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
|     ) : ( |  | ||||||
|       <PublishNotebookPaneComponent {...publishNotebookPaneProps} /> |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private reset = (): void => { |   private reset = (): void => { | ||||||
|     this.isOpened = false; |     this.isOpened = false; | ||||||
|     this.isExecuting = false; |     this.isExecuting = false; | ||||||
|  | |||||||
| @ -1,15 +1,13 @@ | |||||||
| import * as Constants from "../../Common/Constants"; |  | ||||||
| import * as ErrorParserUtility from "../../Common/ErrorParserUtility"; | import * as ErrorParserUtility from "../../Common/ErrorParserUtility"; | ||||||
| import * as ko from "knockout"; | import * as ko from "knockout"; | ||||||
|  | import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils"; | ||||||
| import * as React from "react"; | import * as React from "react"; | ||||||
| import * as ViewModels from "../../Contracts/ViewModels"; | import * as ViewModels from "../../Contracts/ViewModels"; | ||||||
| import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; | import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent"; | ||||||
| import { IconButton } from "office-ui-fabric-react/lib/Button"; |  | ||||||
| import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent"; | import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent"; | ||||||
| import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils"; |  | ||||||
| import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; | import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; | ||||||
| import { UploadDetailsRecord, UploadDetails } from "../../workers/upload/definitions"; | import { UploadDetailsRecord, UploadDetails } from "../../workers/upload/definitions"; | ||||||
| import InfoBubbleIcon from "../../../images/info-bubble.svg"; | import { UploadItemsPaneComponent, UploadItemsPaneProps } from "./UploadItemsPaneComponent"; | ||||||
| import Explorer from "../Explorer"; | import Explorer from "../Explorer"; | ||||||
| 
 | 
 | ||||||
| const UPLOAD_FILE_SIZE_LIMIT = 2097152; | const UPLOAD_FILE_SIZE_LIMIT = 2097152; | ||||||
| @ -35,19 +33,30 @@ export class UploadItemsPaneAdapter implements ReactAdapter { | |||||||
|       return undefined; |       return undefined; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const props: GenericRightPaneProps = { |     const genericPaneProps: GenericRightPaneProps = { | ||||||
|       container: this.container, |       container: this.container, | ||||||
|       content: this.createContent(), |  | ||||||
|       formError: this.formError, |       formError: this.formError, | ||||||
|       formErrorDetail: this.formErrorDetail, |       formErrorDetail: this.formErrorDetail, | ||||||
|       id: "uploaditemspane", |       id: "uploaditemspane", | ||||||
|       isExecuting: this.isExecuting, |       isExecuting: this.isExecuting, | ||||||
|  |       isSubmitButtonVisible: true, | ||||||
|       title: "Upload Items", |       title: "Upload Items", | ||||||
|       submitButtonText: "Upload", |       submitButtonText: "Upload", | ||||||
|       onClose: () => this.close(), |       onClose: () => this.close(), | ||||||
|       onSubmit: () => this.submit() |       onSubmit: () => this.submit() | ||||||
|     }; |     }; | ||||||
|     return <GenericRightPaneComponent {...props} />; | 
 | ||||||
|  |     const uploadItemsPaneProps: UploadItemsPaneProps = { | ||||||
|  |       selectedFilesTitle: this.selectedFilesTitle, | ||||||
|  |       updateSelectedFiles: this.updateSelectedFiles, | ||||||
|  |       uploadFileData: this.uploadFileData | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <GenericRightPaneComponent {...genericPaneProps}> | ||||||
|  |         <UploadItemsPaneComponent {...uploadItemsPaneProps} /> | ||||||
|  |       </GenericRightPaneComponent> | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public triggerRender(): void { |   public triggerRender(): void { | ||||||
| @ -110,77 +119,6 @@ export class UploadItemsPaneAdapter implements ReactAdapter { | |||||||
|         }); |         }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private createContent = (): JSX.Element => { |  | ||||||
|     return <div className="panelContent">{this.createMainContentSection()}</div>; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private createMainContentSection = (): JSX.Element => { |  | ||||||
|     return ( |  | ||||||
|       <div className="paneMainContent"> |  | ||||||
|         <div className="renewUploadItemsHeader"> |  | ||||||
|           <span> Select JSON Files </span> |  | ||||||
|           <span className="infoTooltip" role="tooltip" tabIndex={0}> |  | ||||||
|             <img className="infoImg" src={InfoBubbleIcon} alt="More information" /> |  | ||||||
|             <span className="tooltiptext infoTooltipWidth"> |  | ||||||
|               Select one or more JSON files to upload. Each file can contain a single JSON document or an array of JSON |  | ||||||
|               documents. The combined size of all files in an individual upload operation must be less than 2 MB. You |  | ||||||
|               can perform multiple upload operations for larger data sets. |  | ||||||
|             </span> |  | ||||||
|           </span> |  | ||||||
|         </div> |  | ||||||
|         <input |  | ||||||
|           className="importFilesTitle" |  | ||||||
|           type="text" |  | ||||||
|           disabled |  | ||||||
|           value={this.selectedFilesTitle} |  | ||||||
|           aria-label="Select JSON Files" |  | ||||||
|         /> |  | ||||||
|         <input |  | ||||||
|           type="file" |  | ||||||
|           id="importDocsInput" |  | ||||||
|           title="Upload Icon" |  | ||||||
|           multiple |  | ||||||
|           accept="application/json" |  | ||||||
|           role="button" |  | ||||||
|           tabIndex={0} |  | ||||||
|           style={{ display: "none" }} |  | ||||||
|           onChange={this.updateSelectedFiles} |  | ||||||
|         /> |  | ||||||
|         <IconButton |  | ||||||
|           iconProps={{ iconName: "FolderHorizontal" }} |  | ||||||
|           className="fileImportButton" |  | ||||||
|           alt="Select JSON files to upload" |  | ||||||
|           title="Select JSON files to upload" |  | ||||||
|           onClick={this.onImportButtonClick} |  | ||||||
|           onKeyPress={this.onImportButtonKeyPress} |  | ||||||
|         /> |  | ||||||
|         <div className="fileUploadSummaryContainer" hidden={this.uploadFileData.length === 0}> |  | ||||||
|           <b>File upload status</b> |  | ||||||
|           <table className="fileUploadSummary"> |  | ||||||
|             <thead> |  | ||||||
|               <tr className="fileUploadSummaryHeader fileUploadSummaryTuple"> |  | ||||||
|                 <th>FILE NAME</th> |  | ||||||
|                 <th>STATUS</th> |  | ||||||
|               </tr> |  | ||||||
|             </thead> |  | ||||||
|             <tbody> |  | ||||||
|               {this.uploadFileData.map( |  | ||||||
|                 (data: UploadDetailsRecord): JSX.Element => { |  | ||||||
|                   return ( |  | ||||||
|                     <tr className="fileUploadSummaryTuple" key={data.fileName}> |  | ||||||
|                       <td>{data.fileName}</td> |  | ||||||
|                       <td>{this.fileUploadSummaryText(data.numSucceeded, data.numFailed)}</td> |  | ||||||
|                     </tr> |  | ||||||
|                   ); |  | ||||||
|                 } |  | ||||||
|               )} |  | ||||||
|             </tbody> |  | ||||||
|           </table> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private updateSelectedFiles = (event: React.ChangeEvent<HTMLInputElement>): void => { |   private updateSelectedFiles = (event: React.ChangeEvent<HTMLInputElement>): void => { | ||||||
|     this.selectedFiles = event.target.files; |     this.selectedFiles = event.target.files; | ||||||
|     this._updateSelectedFilesTitle(); |     this._updateSelectedFilesTitle(); | ||||||
| @ -212,21 +150,6 @@ export class UploadItemsPaneAdapter implements ReactAdapter { | |||||||
|     return totalFileSize; |     return totalFileSize; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private fileUploadSummaryText = (numSucceeded: number, numFailed: number): string => { |  | ||||||
|     return `${numSucceeded} items created, ${numFailed} errors`; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private onImportButtonClick = (): void => { |  | ||||||
|     document.getElementById("importDocsInput").click(); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private onImportButtonKeyPress = (event: React.KeyboardEvent<HTMLButtonElement>): void => { |  | ||||||
|     if (event.charCode === Constants.KeyCodes.Enter || event.charCode === Constants.KeyCodes.Space) { |  | ||||||
|       this.onImportButtonClick(); |  | ||||||
|       event.stopPropagation(); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   private reset = (): void => { |   private reset = (): void => { | ||||||
|     this.isOpened = false; |     this.isOpened = false; | ||||||
|     this.isExecuting = false; |     this.isExecuting = false; | ||||||
|  | |||||||
							
								
								
									
										97
									
								
								src/Explorer/Panes/UploadItemsPaneComponent.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/Explorer/Panes/UploadItemsPaneComponent.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | |||||||
|  | import * as Constants from "../../Common/Constants"; | ||||||
|  | import * as React from "react"; | ||||||
|  | import { IconButton } from "office-ui-fabric-react/lib/Button"; | ||||||
|  | import { UploadDetailsRecord } from "../../workers/upload/definitions"; | ||||||
|  | import InfoBubbleIcon from "../../../images/info-bubble.svg"; | ||||||
|  | 
 | ||||||
|  | export interface UploadItemsPaneProps { | ||||||
|  |   selectedFilesTitle: string; | ||||||
|  |   updateSelectedFiles: (event: React.ChangeEvent<HTMLInputElement>) => void; | ||||||
|  |   uploadFileData: UploadDetailsRecord[]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class UploadItemsPaneComponent extends React.Component<UploadItemsPaneProps> { | ||||||
|  |   public render(): JSX.Element { | ||||||
|  |     return ( | ||||||
|  |       <div className="panelContent"> | ||||||
|  |         <div className="paneMainContent"> | ||||||
|  |           <div className="renewUploadItemsHeader"> | ||||||
|  |             <span> Select JSON Files </span> | ||||||
|  |             <span className="infoTooltip" role="tooltip" tabIndex={0}> | ||||||
|  |               <img className="infoImg" src={InfoBubbleIcon} alt="More information" /> | ||||||
|  |               <span className="tooltiptext infoTooltipWidth"> | ||||||
|  |                 Select one or more JSON files to upload. Each file can contain a single JSON document or an array of | ||||||
|  |                 JSON documents. The combined size of all files in an individual upload operation must be less than 2 MB. | ||||||
|  |                 You can perform multiple upload operations for larger data sets. | ||||||
|  |               </span> | ||||||
|  |             </span> | ||||||
|  |           </div> | ||||||
|  |           <input | ||||||
|  |             className="importFilesTitle" | ||||||
|  |             type="text" | ||||||
|  |             disabled | ||||||
|  |             value={this.props.selectedFilesTitle} | ||||||
|  |             aria-label="Select JSON Files" | ||||||
|  |           /> | ||||||
|  |           <input | ||||||
|  |             type="file" | ||||||
|  |             id="importDocsInput" | ||||||
|  |             title="Upload Icon" | ||||||
|  |             multiple | ||||||
|  |             accept="application/json" | ||||||
|  |             role="button" | ||||||
|  |             tabIndex={0} | ||||||
|  |             style={{ display: "none" }} | ||||||
|  |             onChange={this.props.updateSelectedFiles} | ||||||
|  |           /> | ||||||
|  |           <IconButton | ||||||
|  |             iconProps={{ iconName: "FolderHorizontal" }} | ||||||
|  |             className="fileImportButton" | ||||||
|  |             alt="Select JSON files to upload" | ||||||
|  |             title="Select JSON files to upload" | ||||||
|  |             onClick={this.onImportButtonClick} | ||||||
|  |             onKeyPress={this.onImportButtonKeyPress} | ||||||
|  |           /> | ||||||
|  |           <div className="fileUploadSummaryContainer" hidden={this.props.uploadFileData.length === 0}> | ||||||
|  |             <b>File upload status</b> | ||||||
|  |             <table className="fileUploadSummary"> | ||||||
|  |               <thead> | ||||||
|  |                 <tr className="fileUploadSummaryHeader fileUploadSummaryTuple"> | ||||||
|  |                   <th>FILE NAME</th> | ||||||
|  |                   <th>STATUS</th> | ||||||
|  |                 </tr> | ||||||
|  |               </thead> | ||||||
|  |               <tbody> | ||||||
|  |                 {this.props.uploadFileData.map( | ||||||
|  |                   (data: UploadDetailsRecord): JSX.Element => { | ||||||
|  |                     return ( | ||||||
|  |                       <tr className="fileUploadSummaryTuple" key={data.fileName}> | ||||||
|  |                         <td>{data.fileName}</td> | ||||||
|  |                         <td>{this.fileUploadSummaryText(data.numSucceeded, data.numFailed)}</td> | ||||||
|  |                       </tr> | ||||||
|  |                     ); | ||||||
|  |                   } | ||||||
|  |                 )} | ||||||
|  |               </tbody> | ||||||
|  |             </table> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private fileUploadSummaryText = (numSucceeded: number, numFailed: number): string => { | ||||||
|  |     return `${numSucceeded} items created, ${numFailed} errors`; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   private onImportButtonClick = (): void => { | ||||||
|  |     document.getElementById("importDocsInput").click(); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   private onImportButtonKeyPress = (event: React.KeyboardEvent<HTMLButtonElement>): void => { | ||||||
|  |     if (event.charCode === Constants.KeyCodes.Enter || event.charCode === Constants.KeyCodes.Space) { | ||||||
|  |       this.onImportButtonClick(); | ||||||
|  |       event.stopPropagation(); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user