diff --git a/x-pack/plugins/code/public/actions/file.ts b/x-pack/plugins/code/public/actions/file.ts index 828f094bc28a1..2ddfb417d0050 100644 --- a/x-pack/plugins/code/public/actions/file.ts +++ b/x-pack/plugins/code/public/actions/file.ts @@ -20,6 +20,7 @@ export interface FetchFilePayload extends FetchRepoPayloadWithRevision { } export interface FetchRepoTreePayload extends FetchFilePayload { limit?: number; + parents?: boolean; } export interface FetchFileResponse { diff --git a/x-pack/plugins/code/public/actions/repository.ts b/x-pack/plugins/code/public/actions/repository.ts index 9842491740e60..cd2909cae20b7 100644 --- a/x-pack/plugins/code/public/actions/repository.ts +++ b/x-pack/plugins/code/public/actions/repository.ts @@ -21,9 +21,11 @@ export const indexRepo = createAction('INDEX REPOS'); export const indexRepoSuccess = createAction('INDEX REPOS SUCCESS'); export const indexRepoFailed = createAction('INDEX REPOS FAILED'); -export const importRepo = createAction('IMPORT REPOS'); -export const importRepoSuccess = createAction('IMPORT REPOS SUCCESS'); -export const importRepoFailed = createAction('IMPORT REPOS FAILED'); +export const importRepo = createAction('IMPORT REPO'); +export const importRepoSuccess = createAction('IMPORT REPO SUCCESS'); +export const importRepoFailed = createAction('IMPORT REPO FAILED'); + +export const hideCallOut = createAction('HIDE CALL OUT'); export const fetchRepoConfigs = createAction('FETCH REPO CONFIGS'); export const fetchRepoConfigSuccess = createAction('FETCH REPO CONFIGS SUCCESS'); diff --git a/x-pack/plugins/code/public/components/file_tree/__snapshots__/file_tree.test.tsx.snap b/x-pack/plugins/code/public/components/file_tree/__snapshots__/file_tree.test.tsx.snap index 0177d103367a9..1927f60297d83 100644 --- a/x-pack/plugins/code/public/components/file_tree/__snapshots__/file_tree.test.tsx.snap +++ b/x-pack/plugins/code/public/components/file_tree/__snapshots__/file_tree.test.tsx.snap @@ -79,6 +79,9 @@ exports[`render correctly 1`] = ` onClick={[Function]} role="button" > + - - - - - android/ + + android/ +
+ - - - - - futures/ + + futures/ +
+ - - - - - guava/ + + guava/ +
+ - - - - - javadoc-link/ + + javadoc-link/ +
- pom.xml + + + + + + + + pom.xml +
+ - - - - - src/com/google/ + + src/com/google/ +
+ - - - - - common/ + + common/ +
+ - - - - - thirdparty/publicsuffix/ + + thirdparty/publicsuffix/ +
@@ -323,11 +335,35 @@ exports[`render correctly 1`] = ` className="euiSideNavItem euiSideNavItem--trunk" >
- guava-bom/pom.xml + + + + + + + + guava-bom/pom.xml +
+ - - - - - guava-gwt/ + + guava-gwt/ +
+ - - - - - guava-testlib/ + + guava-testlib/ +
+ - - - - - guava-tests/ + + guava-tests/ +
+ - - - - - refactorings/ + + refactorings/ +
+ - - - - - util/ + + util/ +
- .gitattributes + + + + + + + + .gitattributes +
- .gitignore + + + + + + + + .gitignore +
- .travis.yml + + + + + + + + .travis.yml +
- CONTRIBUTING.md + + + + + + + + CONTRIBUTING.md +
- CONTRIBUTORS + + + + + + + + CONTRIBUTORS +
- COPYING + + + + + + + + COPYING +
- README.md + + + + + + + + README.md +
- cycle_whitelist.txt + + + + + + + + cycle_whitelist.txt +
- javadoc-stylesheet.css + + + + + + + + javadoc-stylesheet.css +
- pom.xml + + + + + + + + pom.xml +
diff --git a/x-pack/plugins/code/public/components/file_tree/file_tree.scss b/x-pack/plugins/code/public/components/file_tree/file_tree.scss index cf5cffa8869b6..a801c73578c45 100644 --- a/x-pack/plugins/code/public/components/file_tree/file_tree.scss +++ b/x-pack/plugins/code/public/components/file_tree/file_tree.scss @@ -1,7 +1,8 @@ %fileNode { - padding: 4px; + padding: 4px 4px 4px 16px; cursor: pointer; white-space: nowrap; + margin-left: 5px; } .fileNode { @@ -10,5 +11,9 @@ .activeFileNode { @extend %fileNode; - background: #0079a5; + background: #D9D9D9;; } + +.fileTreeFile { + margin-left: 20px; +} \ No newline at end of file diff --git a/x-pack/plugins/code/public/components/file_tree/file_tree.tsx b/x-pack/plugins/code/public/components/file_tree/file_tree.tsx index c05c3c9a55db8..3a93a795dc65e 100644 --- a/x-pack/plugins/code/public/components/file_tree/file_tree.tsx +++ b/x-pack/plugins/code/public/components/file_tree/file_tree.tsx @@ -6,13 +6,44 @@ import React from 'react'; import { EuiIcon, EuiSideNav } from '@elastic/eui'; +import classes from 'classnames'; import { connect } from 'react-redux'; import { RouteComponentProps, withRouter } from 'react-router-dom'; +import styled from 'styled-components'; import { FileTree as Tree, FileTreeItemType } from '../../../model'; import { closeTreePath, fetchRepoTree, FetchRepoTreePayload } from '../../actions'; import { EuiSideNavItem, MainRouteParams, PathTypes } from '../../common/types'; import { RootState } from '../../reducers'; + +const FolderClosedTriangle = styled.span` + display: inline-block; + width: 0; + height: 0; + margin-right: 4px; + border: 6px solid transparent; + border-left: 6px solid grey; + border-right: 6px solid transparent; + vertical-align: middle; +`; + +const FolderOpenTriangle = styled.span` + display: inline-block; + width: 0; + height: 0; + margin-right: 4px; + margin-top: 3px; + border: 6px solid transparent; + border-top: 6px solid grey; + border-bottom: none; + vertical-align: middle; +`; + +const DirectoryNode = styled.span` + margin-left: 4px; + vertical-align: middle; +`; + interface Props extends RouteComponentProps { node?: Tree; closeTreePath: (path: string) => void; @@ -69,8 +100,9 @@ export class CodeFileTree extends React.Component { }; return (
- - {`${node.name}/`} + {forceOpen ? : } + + {`${node.name}/`}
); } @@ -83,8 +115,9 @@ export class CodeFileTree extends React.Component { } case FileTreeItemType.File: { return ( -
- {node.name} +
+ + {node.name}
); } diff --git a/x-pack/plugins/code/public/components/file_tree/override_eui_side_nav_styles.scss b/x-pack/plugins/code/public/components/file_tree/override_eui_side_nav_styles.scss index b65c47d5e23dc..736aac561e200 100644 --- a/x-pack/plugins/code/public/components/file_tree/override_eui_side_nav_styles.scss +++ b/x-pack/plugins/code/public/components/file_tree/override_eui_side_nav_styles.scss @@ -1,3 +1,11 @@ .euiSideNavItem--root + .euiSideNavItem--root { margin-top: 1rem; +} + +.euiSideNavItem__items:after { + width: 0; +} + +.euiSideNavItem--trunk > .euiSideNavItem__items { + margin-left: 18px; } \ No newline at end of file diff --git a/x-pack/plugins/code/public/reducers/file.ts b/x-pack/plugins/code/public/reducers/file.ts index c59633f6444c8..36441dc498ad8 100644 --- a/x-pack/plugins/code/public/reducers/file.ts +++ b/x-pack/plugins/code/public/reducers/file.ts @@ -42,6 +42,7 @@ export interface FileState { isNotFound: boolean; treeCommits: { [path: string]: CommitInfo[] }; currentPath: string; + requestedPaths: string[]; } const initialState: FileState = { @@ -59,19 +60,18 @@ const initialState: FileState = { treeCommits: {}, isNotFound: false, currentPath: '', + requestedPaths: [], }; function mergeTree(draft: FileState, tree: FileTree, path: string) { const pathSegments = path.split('/'); let current = draft.tree; - let node = tree; + const node = tree; if (path && current.children != null) { const pLastIndex = pathSegments.length - 1; - pathSegments.forEach((p, pidx, arr) => { + pathSegments.forEach((p, pidx) => { const idx = current.children!.findIndex(child => child.name === p); - const index = node.children!.findIndex(child => child.name === p); - if (idx >= 0 && index >= 0) { - node = node.children![index]; + if (idx >= 0) { if (pidx === pLastIndex) { current.children![idx!] = node; } @@ -99,6 +99,7 @@ export const file = handleActions( if (draft.openedPaths.indexOf(path) < 0) { draft.openedPaths.push(path); } + draft.requestedPaths.push(path); }), [String(resetRepoTree)]: (state: FileState) => produce(state, draft => { diff --git a/x-pack/plugins/code/public/reducers/repository.ts b/x-pack/plugins/code/public/reducers/repository.ts index fc65709245885..bb33088566486 100644 --- a/x-pack/plugins/code/public/reducers/repository.ts +++ b/x-pack/plugins/code/public/reducers/repository.ts @@ -15,6 +15,7 @@ import { fetchRepos, fetchReposFailed, fetchReposSuccess, + hideCallOut, importRepo, importRepoFailed, importRepoSuccess, @@ -23,6 +24,7 @@ import { export enum CallOutType { danger = 'danger', success = 'success', + warning = 'warning', } export interface RepositoryState { @@ -83,12 +85,23 @@ export const repository = handleActions( [String(importRepoFailed)]: (state: RepositoryState, action: Action) => produce(state, draft => { if (action.payload) { - draft.callOutMessage = action.payload.body.message; - draft.showCallOut = true; - draft.callOutType = CallOutType.danger; - draft.importLoading = false; + if (action.payload.res.status === 304) { + draft.callOutMessage = 'This Repository has already been imported!'; + draft.showCallOut = true; + draft.callOutType = CallOutType.warning; + draft.importLoading = false; + } else { + draft.callOutMessage = action.payload.body.message; + draft.showCallOut = true; + draft.callOutType = CallOutType.danger; + draft.importLoading = false; + } } }), + [String(hideCallOut)]: (state: RepositoryState, action: Action) => + produce(state, draft => { + draft.showCallOut = false; + }), [String(fetchRepoConfigSuccess)]: (state: RepositoryState, action: Action) => produce(state, draft => { draft.repoConfigs = action.payload; diff --git a/x-pack/plugins/code/public/sagas/editor.ts b/x-pack/plugins/code/public/sagas/editor.ts index f750abaa4d8b1..ccf46b273f554 100644 --- a/x-pack/plugins/code/public/sagas/editor.ts +++ b/x-pack/plugins/code/public/sagas/editor.ts @@ -170,6 +170,7 @@ function* handleMainRouteChange(action: Action) { uri: repoUri, revision, path: file || '', + parents: true, }) ); if (file && pathType === PathTypes.blob) { diff --git a/x-pack/plugins/code/public/sagas/file.ts b/x-pack/plugins/code/public/sagas/file.ts index d184fb444ca12..fe7a5804da86e 100644 --- a/x-pack/plugins/code/public/sagas/file.ts +++ b/x-pack/plugins/code/public/sagas/file.ts @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { some } from 'lodash'; import { Action } from 'redux-actions'; -import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'; +import { call, put, select, takeEvery, takeLatest } from 'redux-saga/effects'; import { kfetch } from 'ui/kfetch'; import { FileTree } from '../../model'; import { @@ -37,13 +38,18 @@ import { openTreePath, setNotFound, } from '../actions'; +import { requestedPathsSelector } from '../selectors'; import { repoRoutePattern } from './patterns'; function* handleFetchRepoTree(action: Action) { try { const { uri, revision, path } = action.payload!; if (path) { - yield call(fetchPath, { uri, revision, path }); + const requestedPaths: string[] = yield select(requestedPathsSelector); + const shouldFetch = !some(requestedPaths, p => p.startsWith(path)); + if (shouldFetch) { + yield call(fetchPath, { uri, revision, path }); + } const pathSegments = path.split('/'); let currentPath = ''; // open all directories on the path @@ -74,10 +80,27 @@ function* fetchPath(payload: FetchRepoTreePayload) { return update; } -function requestRepoTree({ uri, revision, path, limit = 50 }: FetchRepoTreePayload) { +interface FileTreeQuery { + parents?: boolean; + limit: number; + flatten: boolean; + [key: string]: string | number | boolean | undefined; +} + +function requestRepoTree({ + uri, + revision, + path, + limit = 50, + parents = false, +}: FetchRepoTreePayload) { + const query: FileTreeQuery = { limit, flatten: true }; + if (parents) { + query.parents = true; + } return kfetch({ pathname: `../api/code/repo/${uri}/tree/${revision}/${path}`, - query: { parents: true, limit, flatten: true }, + query, }); } diff --git a/x-pack/plugins/code/public/selectors/index.ts b/x-pack/plugins/code/public/selectors/index.ts index cdb7c2444d2d3..ab7dd5a05560d 100644 --- a/x-pack/plugins/code/public/selectors/index.ts +++ b/x-pack/plugins/code/public/selectors/index.ts @@ -57,3 +57,5 @@ export const treeCommitsSelector = (state: RootState) => { return state.file.treeCommits[path]; } }; + +export const requestedPathsSelector = (state: RootState) => state.file.requestedPaths; diff --git a/x-pack/plugins/code/server/queue/index_worker.test.ts b/x-pack/plugins/code/server/queue/index_worker.test.ts index 188538c346f73..05c5441c6fa1c 100644 --- a/x-pack/plugins/code/server/queue/index_worker.test.ts +++ b/x-pack/plugins/code/server/queue/index_worker.test.ts @@ -5,7 +5,6 @@ */ import sinon from 'sinon'; - import { IndexerFactory } from '../indexer'; import { AnyObject, CancellationToken, EsClient, Esqueue } from '../lib/esqueue'; import { Log } from '../log'; diff --git a/x-pack/plugins/code/server/queue/update_worker.test.ts b/x-pack/plugins/code/server/queue/update_worker.test.ts index 4ddcbe760fd16..a8fd880e0345d 100644 --- a/x-pack/plugins/code/server/queue/update_worker.test.ts +++ b/x-pack/plugins/code/server/queue/update_worker.test.ts @@ -5,7 +5,6 @@ */ import sinon from 'sinon'; - import { AnyObject, EsClient, Esqueue } from '../lib/esqueue'; import { Log } from '../log'; import { RepositoryServiceFactory } from '../repository_service_factory';