mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 17:30:46 +00:00
Initial Move from Azure DevOps to GitHub
This commit is contained in:
132
src/Explorer/Controls/GitHub/AddRepoComponent.tsx
Normal file
132
src/Explorer/Controls/GitHub/AddRepoComponent.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { DefaultButton, IButtonProps, ITextFieldProps, TextField } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import { Areas } from "../../../Common/Constants";
|
||||
import { RepoListItem } from "./GitHubReposComponent";
|
||||
import { ChildrenMargin } from "./GitHubStyleConstants";
|
||||
import { GitHubUtils } from "../../../Utils/GitHubUtils";
|
||||
import { IGitHubRepo } from "../../../GitHub/GitHubClient";
|
||||
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
export interface AddRepoComponentProps {
|
||||
container: ViewModels.Explorer;
|
||||
getRepo: (owner: string, repo: string) => Promise<IGitHubRepo>;
|
||||
pinRepo: (item: RepoListItem) => void;
|
||||
}
|
||||
|
||||
interface AddRepoComponentState {
|
||||
textFieldValue: string;
|
||||
textFieldErrorMessage: string;
|
||||
}
|
||||
|
||||
export class AddRepoComponent extends React.Component<AddRepoComponentProps, AddRepoComponentState> {
|
||||
private static readonly DescriptionText =
|
||||
"Don't see what you're looking for? Add your repo/branch, or any public repo (read-access only) by entering the URL: ";
|
||||
private static readonly ButtonText = "Add";
|
||||
private static readonly TextFieldPlaceholder = "https://github.com/owner/repo/tree/branch";
|
||||
private static readonly TextFieldErrorMessage = "Invalid url";
|
||||
private static readonly DefaultBranchName = "master";
|
||||
|
||||
constructor(props: AddRepoComponentProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
textFieldValue: "",
|
||||
textFieldErrorMessage: undefined
|
||||
};
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const textFieldProps: ITextFieldProps = {
|
||||
placeholder: AddRepoComponent.TextFieldPlaceholder,
|
||||
autoFocus: true,
|
||||
value: this.state.textFieldValue,
|
||||
errorMessage: this.state.textFieldErrorMessage,
|
||||
onChange: this.onTextFieldChange
|
||||
};
|
||||
|
||||
const buttonProps: IButtonProps = {
|
||||
text: AddRepoComponent.ButtonText,
|
||||
ariaLabel: AddRepoComponent.ButtonText,
|
||||
onClick: this.onAddRepoButtonClick
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<p style={{ marginBottom: ChildrenMargin }}>{AddRepoComponent.DescriptionText}</p>
|
||||
<TextField {...textFieldProps} />
|
||||
<DefaultButton style={{ marginTop: ChildrenMargin }} {...buttonProps} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private onTextFieldChange = (
|
||||
event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
newValue?: string
|
||||
): void => {
|
||||
this.setState({
|
||||
textFieldValue: newValue || "",
|
||||
textFieldErrorMessage: undefined
|
||||
});
|
||||
};
|
||||
|
||||
private onAddRepoButtonClick = async (): Promise<void> => {
|
||||
const startKey: number = TelemetryProcessor.traceStart(Action.NotebooksGitHubManualRepoAdd, {
|
||||
databaseAccountName: this.props.container.databaseAccount() && this.props.container.databaseAccount().name,
|
||||
defaultExperience: this.props.container.defaultExperience && this.props.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Notebook
|
||||
});
|
||||
let enteredUrl = this.state.textFieldValue;
|
||||
if (enteredUrl.indexOf("/tree/") === -1) {
|
||||
enteredUrl = `${enteredUrl}/tree/${AddRepoComponent.DefaultBranchName}`;
|
||||
}
|
||||
|
||||
const gitHubInfo = GitHubUtils.fromGitHubUri(enteredUrl);
|
||||
if (gitHubInfo) {
|
||||
this.setState({
|
||||
textFieldValue: "",
|
||||
textFieldErrorMessage: undefined
|
||||
});
|
||||
|
||||
const repo = await this.props.getRepo(gitHubInfo.owner, gitHubInfo.repo);
|
||||
if (repo) {
|
||||
const item: RepoListItem = {
|
||||
key: GitHubUtils.toRepoFullName(repo.owner.login, repo.name),
|
||||
repo,
|
||||
branches: [
|
||||
{
|
||||
name: gitHubInfo.branch
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.NotebooksGitHubManualRepoAdd,
|
||||
{
|
||||
databaseAccountName: this.props.container.databaseAccount() && this.props.container.databaseAccount().name,
|
||||
defaultExperience: this.props.container.defaultExperience && this.props.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Notebook
|
||||
},
|
||||
startKey
|
||||
);
|
||||
return this.props.pinRepo(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
textFieldErrorMessage: AddRepoComponent.TextFieldErrorMessage
|
||||
});
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.NotebooksGitHubManualRepoAdd,
|
||||
{
|
||||
databaseAccountName: this.props.container.databaseAccount() && this.props.container.databaseAccount().name,
|
||||
defaultExperience: this.props.container.defaultExperience && this.props.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Notebook,
|
||||
error: AddRepoComponent.TextFieldErrorMessage
|
||||
},
|
||||
startKey
|
||||
);
|
||||
};
|
||||
}
|
||||
91
src/Explorer/Controls/GitHub/AuthorizeAccessComponent.tsx
Normal file
91
src/Explorer/Controls/GitHub/AuthorizeAccessComponent.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import {
|
||||
ChoiceGroup,
|
||||
IButtonProps,
|
||||
IChoiceGroupProps,
|
||||
PrimaryButton,
|
||||
IChoiceGroupOption
|
||||
} from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { ChildrenMargin } from "./GitHubStyleConstants";
|
||||
|
||||
export interface AuthorizeAccessComponentProps {
|
||||
scope: string;
|
||||
authorizeAccess: (scope: string) => void;
|
||||
}
|
||||
|
||||
export interface AuthorizeAccessComponentState {
|
||||
scope: string;
|
||||
}
|
||||
|
||||
export class AuthorizeAccessComponent extends React.Component<
|
||||
AuthorizeAccessComponentProps,
|
||||
AuthorizeAccessComponentState
|
||||
> {
|
||||
// Scopes supported by GitHub OAuth. We're only interested in ones which allow us access to repos.
|
||||
// https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/
|
||||
public static readonly Scopes = {
|
||||
Public: {
|
||||
key: "public_repo",
|
||||
text: "Public repos only"
|
||||
},
|
||||
PublicAndPrivate: {
|
||||
key: "repo",
|
||||
text: "Public and private repos"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly DescriptionPara1 =
|
||||
"Connect your notebooks workspace to GitHub. You'll be able to view, edit, and run notebooks stored in your GitHub repositories in Data Explorer.";
|
||||
private static readonly DescriptionPara2 =
|
||||
"Complete setup by authorizing Azure Cosmos DB to access the repositories in your GitHub account: ";
|
||||
private static readonly AuthorizeButtonText = "Authorize access";
|
||||
|
||||
private onChoiceGroupChange = (event: React.SyntheticEvent<HTMLElement>, option: IChoiceGroupOption): void =>
|
||||
this.setState({
|
||||
scope: option.key
|
||||
});
|
||||
|
||||
private onButtonClick = (): void => this.props.authorizeAccess(this.state.scope);
|
||||
|
||||
constructor(props: AuthorizeAccessComponentProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
scope: this.props.scope
|
||||
};
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const choiceGroupProps: IChoiceGroupProps = {
|
||||
options: [
|
||||
{
|
||||
key: AuthorizeAccessComponent.Scopes.Public.key,
|
||||
text: AuthorizeAccessComponent.Scopes.Public.text,
|
||||
ariaLabel: AuthorizeAccessComponent.Scopes.Public.text
|
||||
},
|
||||
{
|
||||
key: AuthorizeAccessComponent.Scopes.PublicAndPrivate.key,
|
||||
text: AuthorizeAccessComponent.Scopes.PublicAndPrivate.text,
|
||||
ariaLabel: AuthorizeAccessComponent.Scopes.PublicAndPrivate.text
|
||||
}
|
||||
],
|
||||
selectedKey: this.state.scope,
|
||||
onChange: this.onChoiceGroupChange
|
||||
};
|
||||
|
||||
const buttonProps: IButtonProps = {
|
||||
text: AuthorizeAccessComponent.AuthorizeButtonText,
|
||||
ariaLabel: AuthorizeAccessComponent.AuthorizeButtonText,
|
||||
onClick: this.onButtonClick
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>{AuthorizeAccessComponent.DescriptionPara1}</p>
|
||||
<p style={{ marginTop: ChildrenMargin }}>{AuthorizeAccessComponent.DescriptionPara2}</p>
|
||||
<ChoiceGroup style={{ marginTop: ChildrenMargin }} {...choiceGroupProps} />
|
||||
<PrimaryButton style={{ marginTop: ChildrenMargin }} {...buttonProps} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
82
src/Explorer/Controls/GitHub/GitHubReposComponent.tsx
Normal file
82
src/Explorer/Controls/GitHub/GitHubReposComponent.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { DefaultButton, IButtonProps, Link, PrimaryButton } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { IGitHubBranch, IGitHubRepo } from "../../../GitHub/GitHubClient";
|
||||
import { AddRepoComponent, AddRepoComponentProps } from "./AddRepoComponent";
|
||||
import { AuthorizeAccessComponent, AuthorizeAccessComponentProps } from "./AuthorizeAccessComponent";
|
||||
import { ChildrenMargin, ButtonsFooterStyle, ContentFooterStyle } from "./GitHubStyleConstants";
|
||||
import { ReposListComponent, ReposListComponentProps } from "./ReposListComponent";
|
||||
|
||||
export interface GitHubReposComponentProps {
|
||||
showAuthorizeAccess: boolean;
|
||||
authorizeAccessProps: AuthorizeAccessComponentProps;
|
||||
reposListProps: ReposListComponentProps;
|
||||
addRepoProps: AddRepoComponentProps;
|
||||
resetConnection: () => void;
|
||||
onOkClick: () => void;
|
||||
onCancelClick: () => void;
|
||||
}
|
||||
|
||||
export interface RepoListItem {
|
||||
key: string;
|
||||
repo: IGitHubRepo;
|
||||
branches: IGitHubBranch[];
|
||||
}
|
||||
|
||||
export class GitHubReposComponent extends React.Component<GitHubReposComponentProps> {
|
||||
public static readonly ConnectToGitHubTitle = "Connect to GitHub";
|
||||
public static readonly ManageGitHubRepoTitle = "Manage GitHub settings";
|
||||
private static readonly ManageGitHubRepoDescription =
|
||||
"Select your GitHub repos and branch(es) to pin to your notebooks workspace.";
|
||||
private static readonly ManageGitHubRepoResetConnection = "View or change your GitHub authorization settings.";
|
||||
private static readonly OKButtonText = "OK";
|
||||
private static readonly CancelButtonText = "Cancel";
|
||||
|
||||
public render(): JSX.Element {
|
||||
const header: JSX.Element = (
|
||||
<p>
|
||||
{this.props.showAuthorizeAccess
|
||||
? GitHubReposComponent.ConnectToGitHubTitle
|
||||
: GitHubReposComponent.ManageGitHubRepoTitle}
|
||||
</p>
|
||||
);
|
||||
|
||||
const content: JSX.Element = this.props.showAuthorizeAccess ? (
|
||||
<AuthorizeAccessComponent {...this.props.authorizeAccessProps} />
|
||||
) : (
|
||||
<>
|
||||
<p>{GitHubReposComponent.ManageGitHubRepoDescription}</p>
|
||||
<ReposListComponent {...this.props.reposListProps} />
|
||||
</>
|
||||
);
|
||||
|
||||
const okProps: IButtonProps = {
|
||||
text: GitHubReposComponent.OKButtonText,
|
||||
ariaLabel: GitHubReposComponent.OKButtonText,
|
||||
onClick: this.props.onOkClick
|
||||
};
|
||||
|
||||
const cancelProps: IButtonProps = {
|
||||
text: GitHubReposComponent.CancelButtonText,
|
||||
ariaLabel: GitHubReposComponent.CancelButtonText,
|
||||
onClick: this.props.onCancelClick
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={"firstdivbg headerline"}>{header}</div>
|
||||
<div className={"paneMainContent"}>{content}</div>
|
||||
{!this.props.showAuthorizeAccess && (
|
||||
<>
|
||||
<div className={"paneFooter"} style={ContentFooterStyle}>
|
||||
<AddRepoComponent {...this.props.addRepoProps} />
|
||||
</div>
|
||||
<div className={"paneFooter"} style={ButtonsFooterStyle}>
|
||||
<PrimaryButton {...okProps} />
|
||||
<DefaultButton style={{ marginLeft: ChildrenMargin }} {...cancelProps} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
20
src/Explorer/Controls/GitHub/GitHubReposComponentAdapter.tsx
Normal file
20
src/Explorer/Controls/GitHub/GitHubReposComponentAdapter.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import ko from "knockout";
|
||||
import * as React from "react";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import { GitHubReposComponent, GitHubReposComponentProps } from "./GitHubReposComponent";
|
||||
|
||||
export class GitHubReposComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<number>;
|
||||
|
||||
constructor(private props: GitHubReposComponentProps) {
|
||||
this.parameters = ko.observable<number>(Date.now());
|
||||
}
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
return <GitHubReposComponent {...this.props} />;
|
||||
}
|
||||
|
||||
public triggerRender(): void {
|
||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||
}
|
||||
}
|
||||
58
src/Explorer/Controls/GitHub/GitHubStyleConstants.ts
Normal file
58
src/Explorer/Controls/GitHub/GitHubStyleConstants.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
IStyleFunctionOrObject,
|
||||
ICheckboxStyleProps,
|
||||
ICheckboxStyles,
|
||||
IDropdownStyles,
|
||||
IDropdownStyleProps
|
||||
} from "office-ui-fabric-react";
|
||||
|
||||
export const ButtonsFooterStyle: React.CSSProperties = {
|
||||
padding: 14,
|
||||
height: "auto"
|
||||
};
|
||||
|
||||
export const ContentFooterStyle: React.CSSProperties = {
|
||||
padding: "10px 24px 10px 24px",
|
||||
height: "auto"
|
||||
};
|
||||
|
||||
export const ChildrenMargin = 10;
|
||||
export const FontSize = 12;
|
||||
|
||||
export const ReposListCheckboxStyles: IStyleFunctionOrObject<ICheckboxStyleProps, ICheckboxStyles> = {
|
||||
label: {
|
||||
margin: 0,
|
||||
padding: "2 0 2 0"
|
||||
},
|
||||
text: {
|
||||
fontSize: FontSize
|
||||
}
|
||||
};
|
||||
|
||||
export const BranchesDropdownCheckboxStyles: IStyleFunctionOrObject<ICheckboxStyleProps, ICheckboxStyles> = {
|
||||
label: {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: FontSize
|
||||
},
|
||||
root: {
|
||||
padding: 0
|
||||
},
|
||||
text: {
|
||||
fontSize: FontSize
|
||||
}
|
||||
};
|
||||
|
||||
export const BranchesDropdownStyles: IStyleFunctionOrObject<IDropdownStyleProps, IDropdownStyles> = {
|
||||
title: {
|
||||
fontSize: FontSize
|
||||
}
|
||||
};
|
||||
|
||||
export const BranchesDropdownOptionContainerStyle: React.CSSProperties = {
|
||||
padding: 8
|
||||
};
|
||||
|
||||
export const ReposListRepoColumnMinWidth = 192;
|
||||
export const ReposListBranchesColumnWidth = 116;
|
||||
export const BranchesDropdownWidth = 200;
|
||||
301
src/Explorer/Controls/GitHub/ReposListComponent.tsx
Normal file
301
src/Explorer/Controls/GitHub/ReposListComponent.tsx
Normal file
@@ -0,0 +1,301 @@
|
||||
import {
|
||||
Checkbox,
|
||||
DetailsList,
|
||||
DetailsRow,
|
||||
Dropdown,
|
||||
ICheckboxProps,
|
||||
IDetailsFooterProps,
|
||||
IDetailsListProps,
|
||||
IDetailsRowBaseProps,
|
||||
IDropdown,
|
||||
IDropdownOption,
|
||||
IDropdownProps,
|
||||
ILinkProps,
|
||||
ISelectableDroppableTextProps,
|
||||
Link,
|
||||
ResponsiveMode,
|
||||
SelectionMode,
|
||||
Text
|
||||
} from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { IGitHubBranch } from "../../../GitHub/GitHubClient";
|
||||
import { GitHubUtils } from "../../../Utils/GitHubUtils";
|
||||
import { RepoListItem } from "./GitHubReposComponent";
|
||||
import {
|
||||
BranchesDropdownCheckboxStyles,
|
||||
BranchesDropdownOptionContainerStyle,
|
||||
ReposListCheckboxStyles,
|
||||
ReposListRepoColumnMinWidth,
|
||||
ReposListBranchesColumnWidth,
|
||||
BranchesDropdownWidth,
|
||||
BranchesDropdownStyles
|
||||
} from "./GitHubStyleConstants";
|
||||
|
||||
export interface ReposListComponentProps {
|
||||
branchesProps: Record<string, BranchesProps>; // key'd by repo key
|
||||
pinnedReposProps: PinnedReposProps;
|
||||
unpinnedReposProps: UnpinnedReposProps;
|
||||
pinRepo: (repo: RepoListItem) => void;
|
||||
unpinRepo: (repo: RepoListItem) => void;
|
||||
}
|
||||
|
||||
export interface BranchesProps {
|
||||
branches: IGitHubBranch[];
|
||||
hasMore: boolean;
|
||||
isLoading: boolean;
|
||||
loadMore: () => void;
|
||||
}
|
||||
|
||||
export interface PinnedReposProps {
|
||||
repos: RepoListItem[];
|
||||
}
|
||||
|
||||
export interface UnpinnedReposProps {
|
||||
repos: RepoListItem[];
|
||||
hasMore: boolean;
|
||||
isLoading: boolean;
|
||||
loadMore: () => void;
|
||||
}
|
||||
|
||||
export class ReposListComponent extends React.Component<ReposListComponentProps> {
|
||||
private static readonly PinnedReposColumnName = "Pinned repos";
|
||||
private static readonly UnpinnedReposColumnName = "Unpinned repos";
|
||||
private static readonly BranchesColumnName = "Branches";
|
||||
private static readonly LoadingText = "Loading...";
|
||||
private static readonly LoadMoreText = "Load more";
|
||||
private static readonly DefaultBranchName = "master";
|
||||
private static readonly FooterIndex = -1;
|
||||
|
||||
public render(): JSX.Element {
|
||||
const pinnedReposListProps: IDetailsListProps = {
|
||||
styles: {
|
||||
contentWrapper: {
|
||||
height: this.props.pinnedReposProps.repos.length ? undefined : 0
|
||||
}
|
||||
},
|
||||
items: this.props.pinnedReposProps.repos,
|
||||
getKey: ReposListComponent.getKey,
|
||||
selectionMode: SelectionMode.none,
|
||||
compact: true,
|
||||
columns: [
|
||||
{
|
||||
key: ReposListComponent.PinnedReposColumnName,
|
||||
name: ReposListComponent.PinnedReposColumnName,
|
||||
ariaLabel: ReposListComponent.PinnedReposColumnName,
|
||||
minWidth: ReposListRepoColumnMinWidth,
|
||||
onRender: this.onRenderPinnedReposColumnItem
|
||||
},
|
||||
{
|
||||
key: ReposListComponent.BranchesColumnName,
|
||||
name: ReposListComponent.BranchesColumnName,
|
||||
ariaLabel: ReposListComponent.BranchesColumnName,
|
||||
minWidth: ReposListBranchesColumnWidth,
|
||||
maxWidth: ReposListBranchesColumnWidth,
|
||||
onRender: this.onRenderPinnedReposBranchesColumnItem
|
||||
}
|
||||
],
|
||||
onRenderDetailsFooter: this.props.pinnedReposProps.repos.length ? undefined : this.onRenderReposFooter
|
||||
};
|
||||
|
||||
const unpinnedReposListProps: IDetailsListProps = {
|
||||
items: this.props.unpinnedReposProps.repos,
|
||||
getKey: ReposListComponent.getKey,
|
||||
selectionMode: SelectionMode.none,
|
||||
compact: true,
|
||||
columns: [
|
||||
{
|
||||
key: ReposListComponent.UnpinnedReposColumnName,
|
||||
name: ReposListComponent.UnpinnedReposColumnName,
|
||||
ariaLabel: ReposListComponent.UnpinnedReposColumnName,
|
||||
minWidth: ReposListRepoColumnMinWidth,
|
||||
onRender: this.onRenderUnpinnedReposColumnItem
|
||||
},
|
||||
{
|
||||
key: ReposListComponent.BranchesColumnName,
|
||||
name: ReposListComponent.BranchesColumnName,
|
||||
ariaLabel: ReposListComponent.BranchesColumnName,
|
||||
minWidth: ReposListBranchesColumnWidth,
|
||||
maxWidth: ReposListBranchesColumnWidth,
|
||||
onRender: this.onRenderUnpinnedReposBranchesColumnItem
|
||||
}
|
||||
],
|
||||
onRenderDetailsFooter:
|
||||
this.props.unpinnedReposProps.isLoading || this.props.unpinnedReposProps.hasMore
|
||||
? this.onRenderReposFooter
|
||||
: undefined
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DetailsList {...pinnedReposListProps} />
|
||||
<DetailsList {...unpinnedReposListProps} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private onRenderPinnedReposColumnItem = (item: RepoListItem, index: number): JSX.Element => {
|
||||
if (index === ReposListComponent.FooterIndex) {
|
||||
return <Text>None</Text>;
|
||||
}
|
||||
|
||||
const checkboxProps: ICheckboxProps = {
|
||||
...ReposListComponent.getCheckboxPropsForLabel(GitHubUtils.toRepoFullName(item.repo.owner.login, item.repo.name)),
|
||||
styles: ReposListCheckboxStyles,
|
||||
defaultChecked: true,
|
||||
onChange: () => this.props.unpinRepo(item)
|
||||
};
|
||||
|
||||
return <Checkbox {...checkboxProps} />;
|
||||
};
|
||||
|
||||
private onRenderPinnedReposBranchesColumnItem = (item: RepoListItem, index: number): JSX.Element => {
|
||||
if (index === ReposListComponent.FooterIndex) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const branchesProps = this.props.branchesProps[GitHubUtils.toRepoFullName(item.repo.owner.login, item.repo.name)];
|
||||
const options: IDropdownOption[] = branchesProps.branches.map(branch => ({
|
||||
key: branch.name,
|
||||
text: branch.name,
|
||||
data: item,
|
||||
disabled: item.branches.length === 1 && branch.name === item.branches[0].name,
|
||||
selected: item.branches.findIndex(element => element.name === branch.name) !== -1
|
||||
}));
|
||||
|
||||
if (branchesProps.hasMore || branchesProps.isLoading) {
|
||||
const text = branchesProps.isLoading ? ReposListComponent.LoadingText : ReposListComponent.LoadMoreText;
|
||||
options.push({
|
||||
key: text,
|
||||
text,
|
||||
data: item,
|
||||
index: ReposListComponent.FooterIndex
|
||||
});
|
||||
}
|
||||
|
||||
const dropdownProps: IDropdownProps = {
|
||||
styles: BranchesDropdownStyles,
|
||||
dropdownWidth: BranchesDropdownWidth,
|
||||
responsiveMode: ResponsiveMode.large,
|
||||
options,
|
||||
onRenderList: this.onRenderBranchesDropdownList
|
||||
};
|
||||
|
||||
if (item.branches.length === 1) {
|
||||
dropdownProps.placeholder = item.branches[0].name;
|
||||
} else if (item.branches.length > 1) {
|
||||
dropdownProps.placeholder = `${item.branches.length} branches`;
|
||||
}
|
||||
|
||||
return <Dropdown {...dropdownProps} />;
|
||||
};
|
||||
|
||||
private onRenderUnpinnedReposBranchesColumnItem = (item: RepoListItem, index: number): JSX.Element => {
|
||||
if (index === ReposListComponent.FooterIndex) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const dropdownProps: IDropdownProps = {
|
||||
styles: BranchesDropdownStyles,
|
||||
options: [],
|
||||
placeholder: ReposListComponent.DefaultBranchName,
|
||||
disabled: true
|
||||
};
|
||||
|
||||
return <Dropdown {...dropdownProps} />;
|
||||
};
|
||||
|
||||
private onRenderBranchesDropdownList = (props: ISelectableDroppableTextProps<IDropdown, IDropdown>): JSX.Element => {
|
||||
const renderedList: JSX.Element[] = [];
|
||||
props.options.forEach((option: IDropdownOption) => {
|
||||
const item = (
|
||||
<div key={option.key} style={BranchesDropdownOptionContainerStyle}>
|
||||
{this.onRenderPinnedReposBranchesDropdownOption(option)}
|
||||
</div>
|
||||
);
|
||||
renderedList.push(item);
|
||||
});
|
||||
|
||||
return <>{renderedList}</>;
|
||||
};
|
||||
|
||||
private onRenderPinnedReposBranchesDropdownOption(option: IDropdownOption): JSX.Element {
|
||||
const item: RepoListItem = option.data;
|
||||
const branchesProps = this.props.branchesProps[GitHubUtils.toRepoFullName(item.repo.owner.login, item.repo.name)];
|
||||
|
||||
if (option.index === ReposListComponent.FooterIndex) {
|
||||
const linkProps: ILinkProps = {
|
||||
disabled: branchesProps.isLoading,
|
||||
onClick: branchesProps.loadMore
|
||||
};
|
||||
|
||||
return <Link {...linkProps}>{option.text}</Link>;
|
||||
}
|
||||
|
||||
const checkboxProps: ICheckboxProps = {
|
||||
...ReposListComponent.getCheckboxPropsForLabel(option.text),
|
||||
styles: BranchesDropdownCheckboxStyles,
|
||||
defaultChecked: option.selected,
|
||||
disabled: option.disabled,
|
||||
onChange: (event, checked) => {
|
||||
const repoListItem = { ...item };
|
||||
const branch: IGitHubBranch = { name: option.text };
|
||||
repoListItem.branches = repoListItem.branches.filter(element => element.name !== branch.name);
|
||||
if (checked) {
|
||||
repoListItem.branches.push(branch);
|
||||
}
|
||||
|
||||
this.props.pinRepo(repoListItem);
|
||||
}
|
||||
};
|
||||
|
||||
return <Checkbox {...checkboxProps} />;
|
||||
}
|
||||
|
||||
private onRenderUnpinnedReposColumnItem = (item: RepoListItem, index: number): JSX.Element => {
|
||||
if (index === ReposListComponent.FooterIndex) {
|
||||
const linkProps: ILinkProps = {
|
||||
disabled: this.props.unpinnedReposProps.isLoading,
|
||||
onClick: this.props.unpinnedReposProps.loadMore
|
||||
};
|
||||
|
||||
const linkText = this.props.unpinnedReposProps.isLoading
|
||||
? ReposListComponent.LoadingText
|
||||
: ReposListComponent.LoadMoreText;
|
||||
return <Link {...linkProps}>{linkText}</Link>;
|
||||
}
|
||||
|
||||
const checkboxProps: ICheckboxProps = {
|
||||
...ReposListComponent.getCheckboxPropsForLabel(GitHubUtils.toRepoFullName(item.repo.owner.login, item.repo.name)),
|
||||
styles: ReposListCheckboxStyles,
|
||||
onChange: () => {
|
||||
const repoListItem = { ...item };
|
||||
repoListItem.branches = [{ name: ReposListComponent.DefaultBranchName }];
|
||||
this.props.pinRepo(repoListItem);
|
||||
}
|
||||
};
|
||||
|
||||
return <Checkbox {...checkboxProps} />;
|
||||
};
|
||||
|
||||
private onRenderReposFooter = (detailsFooterProps: IDetailsFooterProps): JSX.Element => {
|
||||
const props: IDetailsRowBaseProps = {
|
||||
...detailsFooterProps,
|
||||
item: {},
|
||||
itemIndex: ReposListComponent.FooterIndex
|
||||
};
|
||||
|
||||
return <DetailsRow {...props} />;
|
||||
};
|
||||
|
||||
private static getCheckboxPropsForLabel(label: string): ICheckboxProps {
|
||||
return {
|
||||
label,
|
||||
title: label,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static getKey(item: RepoListItem): string {
|
||||
return item.key;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user