From f48d4208539836b1e2a3535aba214e635b21863e Mon Sep 17 00:00:00 2001 From: WangQianliang Date: Wed, 27 Feb 2019 04:35:01 +0800 Subject: [PATCH] feature(code/frontend): implement new breadcrumb design (#31247) --- .../public/components/main/breadcrumb.tsx | 25 +-- .../code/public/components/main/content.tsx | 8 +- .../code/public/components/main/top_bar.tsx | 42 ++++- .../components/main/version_dropdown.tsx | 144 ------------------ x-pack/plugins/code/public/sagas/editor.ts | 10 ++ 5 files changed, 57 insertions(+), 172 deletions(-) delete mode 100644 x-pack/plugins/code/public/components/main/version_dropdown.tsx diff --git a/x-pack/plugins/code/public/components/main/breadcrumb.tsx b/x-pack/plugins/code/public/components/main/breadcrumb.tsx index 3965e04e839226..035b6b6a628b33 100644 --- a/x-pack/plugins/code/public/components/main/breadcrumb.tsx +++ b/x-pack/plugins/code/public/components/main/breadcrumb.tsx @@ -8,43 +8,26 @@ import { EuiBreadcrumbs } from '@elastic/eui'; import React from 'react'; import { MainRouteParams } from '../../common/types'; -import { VersionDropDown } from './version_dropdown'; interface Props { routeParams: MainRouteParams; } export class Breadcrumb extends React.PureComponent { public render() { - const { resource, org, repo, revision, path, pathType } = this.props.routeParams; + const { resource, org, repo, revision, path } = this.props.routeParams; const repoUri = `${resource}/${org}/${repo}`; - const breadcrumbs = [ - { - text: resource, - href: '#', - }, - { - text: org, - href: '#', - }, - { - text: repo, - href: `#${resource}/${org}/${repo}/tree/master`, - }, - { - text: , - }, - ]; + const breadcrumbs: Array<{ text: string; href: string }> = []; const pathSegments = path ? path.split('/') : []; pathSegments.forEach((p, index) => { const paths = pathSegments.slice(0, index + 1); - const href = `#${resource}/${org}/${repo}/tree/master/${paths.join('/')}`; + const href = `#${repoUri}/tree/${revision}/${paths.join('/')}`; breadcrumbs.push({ text: p, href, }); }); - return ; + return ; } } diff --git a/x-pack/plugins/code/public/components/main/content.tsx b/x-pack/plugins/code/public/components/main/content.tsx index aff20fe1ac3178..81c19aeae91a26 100644 --- a/x-pack/plugins/code/public/components/main/content.tsx +++ b/x-pack/plugins/code/public/components/main/content.tsx @@ -18,7 +18,7 @@ import styled from 'styled-components'; import { RepositoryUtils } from '../../../common/repository_utils'; import { FileTree, FileTreeItemType, SearchScope, WorkerReservedProgress } from '../../../model'; -import { CommitInfo } from '../../../model/commit'; +import { CommitInfo, ReferenceInfo } from '../../../model/commit'; import { changeSearchScope, FetchFileResponse, fetchMoreCommits } from '../../actions'; import { MainRouteParams, PathTypes } from '../../common/types'; import { RepoState, RepoStatus, RootState } from '../../reducers'; @@ -75,6 +75,7 @@ interface Props extends RouteComponentProps { file: FetchFileResponse | undefined; currentTree: FileTree | undefined; commits: CommitInfo[]; + branches: ReferenceInfo[]; hasMoreCommits: boolean; loadingCommits: boolean; onSearchScopeChanged: (s: SearchScope) => void; @@ -180,6 +181,7 @@ class CodeContent extends React.PureComponent { return ( { onChange={this.switchButton} /> { return ( { onSearchScopeChanged={this.props.onSearchScopeChanged} buttons={this.renderButtons()} repoScope={this.props.repoScope} + branches={this.props.branches} /> {this.renderContent()} @@ -373,6 +378,7 @@ const mapStateToProps = (state: RootState) => ({ tree: state.file.tree, currentTree: currentTreeSelector(state), commits: treeCommitsSelector(state), + branches: state.file.branches, hasMoreCommits: hasMoreCommitsSelector(state), loadingCommits: state.file.loadingCommits, repoStatus: statusSelector(state, repoUriSelector(state)), diff --git a/x-pack/plugins/code/public/components/main/top_bar.tsx b/x-pack/plugins/code/public/components/main/top_bar.tsx index 9857b0c30df8f6..50f9face20cbb8 100644 --- a/x-pack/plugins/code/public/components/main/top_bar.tsx +++ b/x-pack/plugins/code/public/components/main/top_bar.tsx @@ -4,21 +4,43 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; +import theme from '@elastic/eui/dist/eui_theme_light.json'; +import React, { ChangeEvent } from 'react'; +import styled from 'styled-components'; import { SearchScope } from '../../../model'; +import { ReferenceInfo } from '../../../model/commit'; import { MainRouteParams } from '../../common/types'; +import { history } from '../../utils/url'; import { Breadcrumb } from './breadcrumb'; import { SearchBar } from './search_bar'; +const SelectContainer = styled(EuiFlexItem)` + margin-right: ${theme.euiSizeS}; +`; + interface Props { routeParams: MainRouteParams; onSearchScopeChanged: (s: SearchScope) => void; buttons: React.ReactNode; repoScope: string[]; + branches: ReferenceInfo[]; } -export class TopBar extends React.Component { +export class TopBar extends React.Component { + public state = { + value: 'master', + }; + + public onChange = (e: ChangeEvent) => { + const { resource, org, repo, path = '', pathType } = this.props.routeParams; + this.setState({ + value: e.target.value, + }); + const revision = this.props.branches.find(b => b.name === e.target.value)!.commit.id; + history.push(`/${resource}/${org}/${repo}/${pathType}/${revision}/${path}`); + }; + public render() { return (
@@ -26,9 +48,17 @@ export class TopBar extends React.Component { onSearchScopeChanged={this.props.onSearchScopeChanged} repoScope={this.props.repoScope} /> - - - + + + + + ({ value: b.name, text: b.name }))} + onChange={this.onChange} + /> + + + {this.props.buttons} diff --git a/x-pack/plugins/code/public/components/main/version_dropdown.tsx b/x-pack/plugins/code/public/components/main/version_dropdown.tsx deleted file mode 100644 index 210607d48b7d34..00000000000000 --- a/x-pack/plugins/code/public/components/main/version_dropdown.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { EuiBadge, EuiLink, EuiPopover, EuiSpacer, EuiTabbedContent } from '@elastic/eui'; -import React, { Fragment } from 'react'; -import { connect } from 'react-redux'; -import { CommitInfo, ReferenceInfo } from '../../../model/commit'; -import { - fetchRepoBranches, - fetchRepoCommits, - FetchRepoPayload, - FetchRepoPayloadWithRevision, -} from '../../actions'; -import { RootState } from '../../reducers'; - -interface Props { - repoUri: string; - head: string; - path: string; - pathType: string; - branches: ReferenceInfo[]; - tags: ReferenceInfo[]; - commits: CommitInfo[]; - fetchRepoBranches(payload: FetchRepoPayload): void; - fetchRepoCommits(payload: FetchRepoPayloadWithRevision): void; -} - -interface State { - isOpen: boolean; -} - -export class VersionDropDownComponent extends React.Component { - constructor(props: Props) { - super(props); - this.state = { - isOpen: false, - }; - } - - public onClick = (e: Event) => { - this.setState({ isOpen: true }); - e.preventDefault(); - }; - - public close = () => { - this.setState({ isOpen: false }); - }; - - public componentDidMount() { - this.props.fetchRepoBranches({ uri: this.props.repoUri }); - this.props.fetchRepoCommits({ uri: this.props.repoUri, revision: this.props.head }); - } - - public componentDidUpdate(prevProps: Readonly): void { - if (this.props.repoUri !== prevProps.repoUri) { - this.props.fetchRepoBranches({ uri: this.props.repoUri }); - this.props.fetchRepoCommits({ uri: this.props.repoUri, revision: this.props.head }); - } else if (prevProps.head !== this.props.head) { - this.props.fetchRepoCommits({ uri: this.props.repoUri, revision: this.props.head }); - } - } - - public renderReference(ref: ReferenceInfo) { - const { repoUri, path, pathType } = this.props; - const url = `#/${repoUri}/${pathType}/${ref.commit.id}/${path}`; - return ( -
- - {ref.name} - {`${ref.commit.committer} update ${ref.commit.updated}`} - - -
- ); - } - - public renderCommit(commit: CommitInfo) { - const { repoUri, path, pathType } = this.props; - const url = `#/${repoUri}/${pathType}/${commit.id}/${path}`; - return ( -
- - {commit.id} - {`${commit.message}`} - - -
- ); - } - - public render() { - const tabs = [ - { - id: 'branches', - name: 'Branch', - content: {this.props.branches.map(br => this.renderReference(br))}, - }, - { - id: 'tags', - name: 'Tag', - content: {this.props.tags.map(t => this.renderReference(t))}, - }, - { - id: 'commits', - name: 'Commit', - content: {this.props.commits.map(c => this.renderCommit(c))}, - }, - ]; - const button = ( - - {this.props.head} - - ); - return ( - - - - ); - } -} - -const mapStateToProps = (state: RootState) => ({ - commits: state.file.commits, - branches: state.file.branches, - tags: state.file.tags, -}); - -const mapDispatchToProps = { - fetchRepoCommits, - fetchRepoBranches, -}; - -export const VersionDropDown = connect( - mapStateToProps, - mapDispatchToProps -)(VersionDropDownComponent); diff --git a/x-pack/plugins/code/public/sagas/editor.ts b/x-pack/plugins/code/public/sagas/editor.ts index f4d74b8a328e63..af28d1190f21fc 100644 --- a/x-pack/plugins/code/public/sagas/editor.ts +++ b/x-pack/plugins/code/public/sagas/editor.ts @@ -7,6 +7,7 @@ import queryString from 'querystring'; import { Action } from 'redux-actions'; import { call, put, select, takeEvery, takeLatest } from 'redux-saga/effects'; +import chrome from 'ui/chrome'; import { kfetch } from 'ui/kfetch'; import { TextDocumentPositionParams } from 'vscode-languageserver'; import { parseGoto, parseLspUrl, toCanonicalUrl } from '../../common/uri_util'; @@ -15,6 +16,7 @@ import { closeReferences, fetchFile, FetchFileResponse, + fetchRepoBranches, fetchRepoTree, fetchTreeCommits, findReferences, @@ -144,6 +146,14 @@ function* handleMainRouteChange(action: Action) { position = parseGoto(goto); } yield put(loadRepo(repoUri)); + yield put(fetchRepoBranches({ uri: repoUri })); + chrome.breadcrumbs.set([ + { + text: 'Code', + href: '', + }, + { text: `${org} → ${repo}` }, + ]); if (file) { if ([PathTypes.blob, PathTypes.blame].includes(pathType as PathTypes)) { yield call(handleFile, repoUri, file, revision);