-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GitGraph and GitNode UI updates (#331)
* GitGraph limits graph size to 50 nodes * Bump electron from 11.1.1 to 11.2.3 (#330) Bumps [electron](https://github.com/electron/electron) from 11.1.1 to 11.2.3. - [Release notes](https://github.com/electron/electron/releases) - [Changelog](https://github.com/electron/electron/blob/master/docs/breaking-changes.md) - [Commits](electron/electron@v11.1.1...v11.2.3) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/eslint-plugin from 4.14.1 to 4.14.2 (#324) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 4.14.1 to 4.14.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.14.2/packages/eslint-plugin) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nicholas Nelson <nelsonni@oregonstate.edu> * Bump ts-loader from 8.0.14 to 8.0.15 (#325) Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.0.14 to 8.0.15. - [Release notes](https://github.com/TypeStrong/ts-loader/releases) - [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md) - [Commits](TypeStrong/ts-loader@v8.0.14...v8.0.15) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/parser from 4.14.1 to 4.14.2 (#326) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 4.14.1 to 4.14.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v4.14.2/packages/parser) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @testing-library/user-event from 12.6.2 to 12.6.3 (#327) Bumps [@testing-library/user-event](https://github.com/testing-library/user-event) from 12.6.2 to 12.6.3. - [Release notes](https://github.com/testing-library/user-event/releases) - [Changelog](https://github.com/testing-library/user-event/blob/master/CHANGELOG.md) - [Commits](testing-library/user-event@v12.6.2...v12.6.3) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump eslint from 7.18.0 to 7.19.0 (#328) Bumps [eslint](https://github.com/eslint/eslint) from 7.18.0 to 7.19.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](eslint/eslint@v7.18.0...v7.19.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @testing-library/react from 11.2.3 to 11.2.5 (#329) Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 11.2.3 to 11.2.5. - [Release notes](https://github.com/testing-library/react-testing-library/releases) - [Changelog](https://github.com/testing-library/react-testing-library/blob/master/CHANGELOG.md) - [Commits](testing-library/react-testing-library@v11.2.3...v11.2.5) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * useGitHistory hook updated to provide git information with scope and branch * ESLint max-len rule updated to ignore long import lines * Fixed incorrect branch scoping in useGitHistory hook * GitNode colors dynamically set from colors palette * GitGraph centered on graph element updates * GitNode opacity, border-style, and Tooltip dynamically set via props * layoutOptimizer separates nodes and reduces GitNode height/width * GitGraph adds staged future commits to end of branches, adds branch Tooltips Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
- Loading branch information
1 parent
73ccfa0
commit cb423ca
Showing
6 changed files
with
168 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,115 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import ReactFlow, { addEdge, ArrowHeadType, Connection, Edge, FlowElement, Node } from 'react-flow-renderer'; | ||
import ReactFlow, { addEdge, ArrowHeadType, Connection, Edge, FlowElement, Node, OnLoadFunc, OnLoadParams } from 'react-flow-renderer'; | ||
|
||
import type { Repository } from '../types'; | ||
import { nodeTypes } from './GitNode'; | ||
import { useGitHistory } from '../store/hooks/useGitHistory'; | ||
import { ReadCommitResult } from 'isomorphic-git'; | ||
import { CommitInfo, useGitHistory } from '../store/hooks/useGitHistory'; | ||
import { layoutOptimizer } from '../containers/layout'; | ||
import { colorSets } from '../containers/colors'; | ||
import { currentBranch, getStatus } from '../containers/git'; | ||
import { flattenArray } from '../containers/flatten'; | ||
|
||
const getGitNode = (commit: CommitInfo, branchHead: string | undefined): Node => ({ | ||
id: commit.oid, | ||
type: 'gitNode', | ||
data: { | ||
text: '', | ||
tooltip: '', | ||
color: colorSets[5], | ||
border: '', | ||
branch: branchHead && branchHead === commit.oid ? `${commit.scope}/${commit.branch}` : undefined | ||
}, | ||
position: { x: 0, y: 0 } | ||
}); | ||
|
||
const getGitEdge = (commit: CommitInfo): Edge[] => { | ||
return commit.commit.parent.map(parent => { | ||
return { | ||
id: `e${parent.slice(0, 7)}-${commit.oid.slice(0, 7)}`, | ||
source: parent, | ||
target: commit.oid, | ||
arrowHeadType: ArrowHeadType.ArrowClosed | ||
}; | ||
}); | ||
}; | ||
|
||
const getGitStaged = async (commit: CommitInfo, repo: Repository): Promise<(Node | Edge)[]> => { | ||
const currentBranchStatus = await getStatus(repo.root); | ||
if (currentBranchStatus && !['ignored', 'unmodified'].includes(currentBranchStatus)) { | ||
return [{ | ||
id: `${commit.oid}*`, | ||
type: 'gitNode', | ||
data: { | ||
text: '', | ||
tooltip: '', | ||
color: colorSets[5], | ||
border: 'dashed', | ||
opacity: '0.6', | ||
branch: `${commit.scope}/${commit.branch}*` | ||
}, | ||
position: { x: 0, y: 0 } | ||
}, | ||
{ | ||
id: `e${commit.oid.slice(0, 7)}-${commit.oid.slice(0, 7)}*`, | ||
source: commit.oid, | ||
target: `${commit.oid}*`, | ||
animated: true, | ||
arrowHeadType: ArrowHeadType.ArrowClosed | ||
} | ||
]; | ||
} else { | ||
return []; | ||
} | ||
}; | ||
|
||
export const GitGraph: React.FunctionComponent<{ repo: Repository }> = props => { | ||
const [elements, setElements] = useState<Array<FlowElement>>([]); | ||
const [reactFlowState, setReactFlowState] = useState<OnLoadParams>(); | ||
const onConnect = (params: Edge | Connection) => setElements((els) => addEdge(params, els)); | ||
const { commits, heads, update } = useGitHistory(props.repo); | ||
const onLoad: OnLoadFunc = (rf) => { setReactFlowState(rf) }; | ||
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
useEffect(() => { update() }, [props.repo]); | ||
|
||
useEffect(() => { | ||
if (commits.size > 0 && heads.size > 0) { | ||
console.log(`REPO => repo: ${props.repo.name}, commits: ${commits.size}`); | ||
console.log(JSON.stringify([...heads.entries()], null, 2)); | ||
if (reactFlowState && elements.length) { | ||
reactFlowState.fitView(); | ||
} | ||
}, [commits, heads, props.repo.name]); | ||
}, [elements, reactFlowState]); | ||
|
||
useEffect(() => { | ||
const newElements = [...commits.values()].reduce((prev: Array<FlowElement>, curr: ReadCommitResult): Array<FlowElement> => { | ||
const node: Node = { | ||
id: curr.oid, | ||
type: 'gitNode', | ||
data: { text: '', tooltip: `${curr.oid.slice(0, 7)}\n${curr.commit.message}` }, | ||
position: { x: 0, y: 0 } | ||
}; | ||
const edges: Edge[] = curr.commit.parent.map(parent => { | ||
return { | ||
id: `e${parent.slice(0, 7)}-${curr.oid.slice(0, 7)}`, | ||
source: parent, | ||
target: curr.oid, | ||
arrowHeadType: ArrowHeadType.ArrowClosed | ||
}; | ||
}); | ||
return [node, ...prev, ...edges]; | ||
}, []); | ||
const optimizedNewElements = layoutOptimizer(newElements); | ||
setElements(optimizedNewElements); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [commits, heads]); | ||
const asyncGraphConstruction = async () => { | ||
const currentCommits = [...commits.values()].slice(Math.max(commits.size - 50, 0)) // limited to 50 most recent commits | ||
const newElements = currentCommits.reduce((prev: Array<FlowElement>, curr: CommitInfo): Array<FlowElement> => { | ||
const branchHead = heads.get(`${curr.scope}/${curr.branch}`); | ||
const node: Node = getGitNode(curr, branchHead); | ||
const edges: Edge[] = getGitEdge(curr); | ||
return [node, ...prev, ...edges]; | ||
}, []); | ||
const headsHashes = [...heads.values()]; | ||
const headCommits = currentCommits.filter(commit => headsHashes.includes(commit.oid)); | ||
// TODO: Until we have copied repositories that exist in a cache (probably in within .syn or .git directory), we will need to | ||
// check through all the open cards on the canvas to determine if any of them are associated with a branch and have changes | ||
// compared to the latest version in the branch. The following line has to wait until this is implemented: | ||
// | ||
// const staged = flattenArray(await Promise.all(headCommits.map(headCommit => getGitStaged(headCommit, props.repo)))); | ||
const currentBranchName = await currentBranch({ dir: props.repo.root.toString() }); | ||
const currentBranchHash = heads.get(`local/${currentBranchName}`); | ||
const staged = flattenArray(await Promise.all(headCommits | ||
.filter(commit => commit.oid === currentBranchHash) | ||
.map(currentBranchCommit => getGitStaged(currentBranchCommit, props.repo)))); | ||
const optimizedNewElements = layoutOptimizer([...newElements, ...staged]); | ||
setElements(optimizedNewElements); | ||
} | ||
asyncGraphConstruction(); | ||
}, [commits, heads, props.repo]); | ||
|
||
return (<ReactFlow | ||
elements={elements} | ||
nodeTypes={nodeTypes} | ||
onConnect={onConnect} | ||
onLoad={onLoad} | ||
onNodeMouseEnter={(_event, node) => console.log(node.id)} | ||
className='git-flow' />); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
export type ColorSet = { | ||
name: string, | ||
primary: string, | ||
secondary: string | ||
} | ||
|
||
// colors from http://clrs.cc/ | ||
export const colorSets: Array<ColorSet> = [ | ||
{ name: 'navy', primary: '#001f3f', secondary: '#80b5ff' }, | ||
{ name: 'blue', primary: '#0074d9', secondary: '#b3dbff' }, | ||
{ name: 'aqua', primary: '#7fdbff', secondary: '#004966' }, | ||
{ name: 'teal', primary: '#39cccc', secondary: '#000000' }, | ||
{ name: 'olive', primary: '#3d9970', secondary: '#163728' }, | ||
{ name: 'green', primary: '#2ecc40', secondary: '#0e3e14' }, | ||
{ name: 'lime', primary: '#01ff70', secondary: '#00662c' }, | ||
{ name: 'yellow', primary: '#ffdc00', secondary: '#665800' }, | ||
{ name: 'orange', primary: '#ff851b', secondary: '#663000' }, | ||
{ name: 'red', primary: '#ff4136', secondary: '#800600' }, | ||
{ name: 'maroon', primary: '#85144b', secondary: '#eb7ab1' }, | ||
{ name: 'fuchsia', primary: '#f012be', secondary: '#65064f' }, | ||
{ name: 'purple', primary: '#b10dc9', secondary: '#efa9f9' }, | ||
{ name: 'black', primary: '#111111', secondary: '#dddddd' }, | ||
{ name: 'gray', primary: '#aaaaaa', secondary: '#000000' }, | ||
{ name: 'silver', primary: '#dddddd', secondary: '#000000' }, | ||
{ name: 'white', primary: '#ffffff', secondary: '#444444' } | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters