mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-25 23:16:56 +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…
Reference in New Issue
Block a user