branch diffs

git4refactor
filip mertens 7 months ago
parent 59ac71f571
commit ede22d886a
  1. 31
      apps/remix-ide/src/app/files/dgitProvider.ts
  2. 16
      libs/remix-ui/git/src/components/gitui.tsx
  3. 32
      libs/remix-ui/git/src/components/navigation/commits.tsx
  4. 2
      libs/remix-ui/git/src/components/navigation/remotesdetails.tsx
  5. 7
      libs/remix-ui/git/src/components/panels/branches.tsx
  6. 108
      libs/remix-ui/git/src/components/panels/branches/branchCommits.tsx
  7. 47
      libs/remix-ui/git/src/components/panels/branches/branchdifferences.tsx
  8. 77
      libs/remix-ui/git/src/components/panels/branches/localbranchdetails.tsx
  9. 3
      libs/remix-ui/git/src/components/panels/branches/remotebranchedetails.tsx
  10. 4
      libs/remix-ui/git/src/components/panels/remoteselect.tsx
  11. 25
      libs/remix-ui/git/src/lib/gitactions.ts
  12. 36
      libs/remix-ui/git/src/state/gitpayload.ts
  13. 30
      libs/remix-ui/git/src/state/gitreducer.tsx
  14. 34
      libs/remix-ui/git/src/types/index.ts

@ -35,7 +35,7 @@ const profile: LibraryProfile = {
icon: 'assets/img/fileManager.webp', icon: 'assets/img/fileManager.webp',
version: '0.0.1', version: '0.0.1',
methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'reset', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pull', 'setIpfsConfig', 'zip', 'setItem', 'getItem', 'version', 'updateSubmodules' methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'reset', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pull', 'setIpfsConfig', 'zip', 'setItem', 'getItem', 'version', 'updateSubmodules'
, 'getGitHubUser', 'remotebranches', 'remotecommits', 'repositories', 'getCommitChanges'], , 'getGitHubUser', 'remotebranches', 'remotecommits', 'repositories', 'getCommitChanges', 'compareBranches'],
kind: 'file-system' kind: 'file-system'
} }
class DGitProvider extends Plugin { class DGitProvider extends Plugin {
@ -273,6 +273,35 @@ class DGitProvider extends Plugin {
return status return status
} }
async compareBranches({branch, remote}:{branch: branch, remote: remote}) {
// Get current branch commits
const headCommits = await git.log({
...await this.addIsomorphicGitConfigFS(),
ref: branch.name,
});
// Get remote branch commits
const remoteCommits = await git.log({
...await this.addIsomorphicGitConfigFS(),
ref: `${remote.remote}/${branch.name}`,
});
// Convert arrays of commit objects to sets of commit SHAs
const headCommitSHAs = new Set(headCommits.map(commit => commit.oid));
const remoteCommitSHAs = new Set(remoteCommits.map(commit => commit.oid));
// Filter out commits that are only in the remote branch
const uniqueRemoteCommits = remoteCommits.filter(commit => !headCommitSHAs.has(commit.oid));
// filter out commits that are only in the local branch
const uniqueHeadCommits = headCommits.filter(commit => !remoteCommitSHAs.has(commit.oid));
return {
uniqueHeadCommits,
uniqueRemoteCommits,
};
}
async getCommitChanges(commitHash1, commitHash2): Promise<commitChange[]> { async getCommitChanges(commitHash1, commitHash2): Promise<commitChange[]> {
//console.log([git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })]) //console.log([git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })])
const result: commitChange[] = await git.walk({ const result: commitChange[] = await git.walk({

@ -12,7 +12,7 @@ import { Commits } from './panels/commits'
import { Branches } from './panels/branches' import { Branches } from './panels/branches'
import { SourceControlNavigation } from './navigation/sourcecontrol' import { SourceControlNavigation } from './navigation/sourcecontrol'
import { BranchesNavigation } from './navigation/branches' import { BranchesNavigation } from './navigation/branches'
import { CommitslNavigation } from './navigation/commits' import { CommitsNavigation } from './navigation/commits'
import '../style/index.css' import '../style/index.css'
import { CloneNavigation } from './navigation/clone' import { CloneNavigation } from './navigation/clone'
import { Clone } from './panels/clone' import { Clone } from './panels/clone'
@ -149,7 +149,7 @@ export const GitUI = (props: IGitUi) => {
</> </>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<CommitslNavigation eventKey="3" activePanel={activePanel} callback={setActivePanel} /> <CommitsNavigation title={`COMMITS`} eventKey="3" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="3"> <Accordion.Collapse className='bg-light' eventKey="3">
<> <>
<Commits /> <Commits />
@ -162,12 +162,6 @@ export const GitUI = (props: IGitUi) => {
<Branches /></> <Branches /></>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<CloneNavigation eventKey="4" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="4">
<>
<Clone /></>
</Accordion.Collapse>
<hr></hr>
<RemotesNavigation eventKey="5" activePanel={activePanel} callback={setActivePanel} /> <RemotesNavigation eventKey="5" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="5"> <Accordion.Collapse className='bg-light' eventKey="5">
<> <>
@ -175,6 +169,12 @@ export const GitUI = (props: IGitUi) => {
</> </>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<CloneNavigation eventKey="4" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="4">
<>
<Clone /></>
</Accordion.Collapse>
<hr></hr>
<GitHubNavigation eventKey="7" activePanel={activePanel} callback={setActivePanel} /> <GitHubNavigation eventKey="7" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="7"> <Accordion.Collapse className='bg-light' eventKey="7">
<> <>

@ -1,12 +1,25 @@
import { faCaretDown, faArrowUp, faArrowDown, faArrowRotateRight, faCaretRight, faArrowsUpDown } from "@fortawesome/free-solid-svg-icons"; import { faCaretDown, faArrowUp, faArrowDown, faArrowRotateRight, faCaretRight, faArrowsUpDown } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { CustomTooltip } from "@remix-ui/helper"; import { CustomTooltip } from "@remix-ui/helper";
import React, { } from "react"; import React, { useEffect } from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { pluginActionsContext } from "../../state/context"; import { pluginActionsContext } from "../../state/context";
import { gitPluginContext } from "../gitui";
export const CommitslNavigation = ({ eventKey, activePanel, callback }) => { export interface CommitsNavigationProps {
title: string,
eventKey: string,
activePanel: string,
callback: (eventKey: string) => void
}
export const CommitsNavigation = ({ eventKey, activePanel, callback, title }: CommitsNavigationProps) => {
const pluginactions = React.useContext(pluginActionsContext) const pluginactions = React.useContext(pluginActionsContext)
const [pullEnabled, setPullEnabled] = React.useState(true)
const [pushEnabled, setPushEnabled] = React.useState(true)
const [syncEnabled, setSyncEnabled] = React.useState(false)
const [fetchEnabled, setFetchEnabled] = React.useState(true)
const context = React.useContext(gitPluginContext)
const handleClick = () => { const handleClick = () => {
if (!callback) return if (!callback) return
@ -24,22 +37,29 @@ export const CommitslNavigation = ({ eventKey, activePanel, callback }) => {
{ {
activePanel === eventKey ? <FontAwesomeIcon className='' icon={faCaretDown}></FontAwesomeIcon> : <FontAwesomeIcon className='' icon={faCaretRight}></FontAwesomeIcon> activePanel === eventKey ? <FontAwesomeIcon className='' icon={faCaretDown}></FontAwesomeIcon> : <FontAwesomeIcon className='' icon={faCaretRight}></FontAwesomeIcon>
} }
<label className="pl-1 nav form-check-label">COMMITS</label> <label className="pl-1 nav form-check-label">{title}</label>
</span> </span>
{ {
activePanel === eventKey ? activePanel === eventKey ?
<span className='d-flex justify-content-end align-items-center w-25'> <span className='d-flex justify-content-end align-items-center w-25'>
{pullEnabled ?
<CustomTooltip tooltipText={<FormattedMessage id="git.pull" />}> <CustomTooltip tooltipText={<FormattedMessage id="git.pull" />}>
<button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowDown} className="" /></button> <button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowDown} className="" /></button>
</CustomTooltip> </CustomTooltip>: null}
{pushEnabled ?
<CustomTooltip tooltipText={<FormattedMessage id="git.push" />}> <CustomTooltip tooltipText={<FormattedMessage id="git.push" />}>
<button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowUp} className="" /></button> <button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowUp} className="" /></button>
</CustomTooltip> </CustomTooltip>: null}
{syncEnabled ?
<CustomTooltip tooltipText={<FormattedMessage id="git.sync" />}> <CustomTooltip tooltipText={<FormattedMessage id="git.sync" />}>
<button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowsUpDown} className="" /></button> <button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowsUpDown} className="" /></button>
</CustomTooltip> </CustomTooltip>: null}
{fetchEnabled ?
<CustomTooltip tooltipText={<FormattedMessage id="git.fetch" />}>
<button onClick={async () => { await pluginactions.loadFiles() }} className='btn btn-sm'><FontAwesomeIcon icon={faArrowRotateRight} className="" /></button>
</CustomTooltip>: null}
</span> : null </span> : null
} }

@ -34,7 +34,7 @@ export const RemotesDetailsNavigation = (props: RemotesDetailsNavigationProps) =
{ {
activePanel === eventKey ? <FontAwesomeIcon className='' icon={faCaretDown}></FontAwesomeIcon> : <FontAwesomeIcon className='' icon={faCaretRight}></FontAwesomeIcon> activePanel === eventKey ? <FontAwesomeIcon className='' icon={faCaretDown}></FontAwesomeIcon> : <FontAwesomeIcon className='' icon={faCaretRight}></FontAwesomeIcon>
} }
<div className="long-and-truncated"> <div className="long-and-truncated pl-1">
{remote.remote} <FontAwesomeIcon className='' icon={faArrowRightArrowLeft}></FontAwesomeIcon> {remote.url} {remote.remote} <FontAwesomeIcon className='' icon={faArrowRightArrowLeft}></FontAwesomeIcon> {remote.url}
</div> </div>

@ -3,7 +3,8 @@ import { Alert } from "react-bootstrap";
import { gitActionsContext } from "../../state/context"; import { gitActionsContext } from "../../state/context";
import { remote } from "../../types"; import { remote } from "../../types";
import { gitPluginContext } from "../gitui"; import { gitPluginContext } from "../gitui";
import { BranchDetails } from "./branches/branchedetails"; import { LocalBranchDetails } from "./branches/localbranchdetails";
import { RemoteBranchDetails } from "./branches/remotebranchedetails";
export const Branches = () => { export const Branches = () => {
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)
@ -26,9 +27,9 @@ export const Branches = () => {
<div className="pt-1"> <div className="pt-1">
{context.branches && context.branches.length ? {context.branches && context.branches.length ?
<div> <div>
{context.branches && context.branches.map((branch, index) => { {context.branches && context.branches.filter((branch, index) => !branch.remote).map((branch, index) => {
return ( return (
<BranchDetails key={index} branch={branch}></BranchDetails> <LocalBranchDetails key={index} branch={branch}></LocalBranchDetails>
); );
})} })}
<hr /> <hr />

@ -1,108 +0,0 @@
import React, { useEffect } from 'react';
import { gql, useQuery } from '@apollo/client';
const GET_COMMITS = gql(/* GraphQL */`
query GetCommits($name: String!, $owner: String!, $cursor: String, $limit: Int = 10) {
repository(name: $name, owner: $owner) {
ref(qualifiedName: "master") {
target {
... on Commit {
history(first: $limit, after: $cursor) {
pageInfo {
endCursor
hasNextPage
}
edges {
node {
oid
messageHeadline
message
committedDate
author {
name
email
date
}
parents(first: 1) {
edges {
node {
oid
}
}
}
tree {
oid
}
}
}
}
}
}
}
}
}
`);
export const BranchCommits = ({ owner, name }) => {
const { data, loading, fetchMore } = useQuery(GET_COMMITS, {
variables: { owner, name },
});
if (loading) return <p>Loading...</p>;
const { edges, pageInfo } = (data.repository.ref.target.__typename === "Commit")? data.repository.ref.target.history : { edges: [], pageInfo: { endCursor: null, hasNextPage: false } };
const loadNextPage= ()=>{
fetchMore({
variables: {
cursor: pageInfo.endCursor,
},
updateQuery: (prevResult, { fetchMoreResult }) => {
const newEdges = (fetchMoreResult.repository.ref.target.__typename === "Commit"? fetchMoreResult.repository.ref.target.history.edges : [])
const pageInfo = (fetchMoreResult.repository.ref.target.__typename === "Commit"? fetchMoreResult.repository.ref.target.history.pageInfo : {})
return newEdges.length && prevResult.repository.ref.target.__typename === "Commit"
? {
repository: {
__typename: prevResult.repository.__typename,
ref: {
__typename: prevResult.repository.ref.__typename,
target: {
__typename: prevResult.repository.ref.target.__typename,
history: {
__typename: prevResult.repository.ref.target.history.__typename,
edges: [...prevResult.repository.ref.target.history.edges, ...newEdges],
pageInfo,
},
},
},
},
} as any
: prevResult;
},
});
}
return (
<div>
<ul>
{edges.map(({ node }) => {
console.log(node)
return(
<li key={node.oid}>
<p>{node.messageHeadline} - {node.author.name} ({new Date(node.author.date).toLocaleDateString()})</p>
</li>
)
})}
</ul>
{pageInfo.hasNextPage && (
<button
onClick={() => loadNextPage()}
>
Load More
</button>
)}
</div>
);
};

@ -0,0 +1,47 @@
import { branch, remote } from "../../../types";
import React, { useEffect, useState } from "react";
import { gitPluginContext } from "../../gitui";
import { CommitDetails } from "../commits/commitdetails";
export interface BrancheDetailsProps {
branch: branch;
}
export const BranchDifferences = (props: BrancheDetailsProps) => {
const { branch } = props;
const context = React.useContext(gitPluginContext)
useEffect(() => {
console.log('GET BRANCH DIFF', branch)
}, [])
useEffect(() => {
console.log('BRANCH DIFF', context.branchDifferences)
}, [context.branchDifferences])
const commitsAhead = (remote: remote) => {
return context.branchDifferences[`${remote.remote}/${branch.name}`]?.uniqueHeadCommits || [];
}
const commitsBehind = (remote: remote) => {
return context.branchDifferences[`${remote.remote}/${branch.name}`]?.uniqueRemoteCommits || [];
}
return (
<div>
<div>
{context.remotes.map((remote, index) => {
return (
<div key={index}>
<h5>{remote.remote}</h5>
<ul>
<li>ahead by {commitsAhead(remote).length} commit(s)</li>
<li>behind by {commitsBehind(remote).length} commits(s)</li>
</ul>
</div>
);
})}
</div>
</div>
);
}

@ -0,0 +1,77 @@
import { ReadCommitResult } from "isomorphic-git"
import React, { useEffect, useState } from "react";
import { Accordion } from "react-bootstrap";
import { CommitDetailsNavigation } from "../../navigation/commitdetails";
import { gitActionsContext } from "../../../state/context";
import { gitPluginContext } from "../../gitui";
import { branch } from "../../../types";
import { BrancheDetailsNavigation } from "../../navigation/branchedetails";
import { CommitDetailsItems } from "../commits/commitdetailsitem";
import { CommitDetails } from "../commits/commitdetails";
import { BranchDifferences } from "./branchdifferences";
export interface BrancheDetailsProps {
branch: branch;
}
export const LocalBranchDetails = (props: BrancheDetailsProps) => {
const { branch } = props;
const actions = React.useContext(gitActionsContext)
const context = React.useContext(gitPluginContext)
const [activePanel, setActivePanel] = useState<string>("");
const [hasNextPage, setHasNextPage] = useState<boolean>(false)
const [lastPageNumber, setLastPageNumber] = useState<number>(0)
useEffect(() => {
if (activePanel === "0") {
console.log('GET BRANCH COMMITS', branch)
if(lastPageNumber === 0)
actions.getBranchCommits(branch, 1)
}
}, [activePanel])
const checkout = (branch: branch) => {
actions.checkout({
ref: branch.name,
remote: branch.remote && branch.remote.remote || null
});
}
const loadNextPage = () => {
console.log('LOAD NEXT PAGE', lastPageNumber+1)
actions.getBranchCommits(branch, lastPageNumber+1)
}
const checkoutCommit = async (oid: string) => {
try {
//await ModalRef.current?.show();
actions.checkout({ ref: oid })
//Utils.log("yes");
} catch (e) {
//Utils.log("no");
}
};
return (<Accordion activeKey={activePanel} defaultActiveKey="">
<BrancheDetailsNavigation checkout={checkout} branch={branch} eventKey="0" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className="pl-2 border-left ml-1" eventKey="0">
<>
<div className="ml-1">
<BranchDifferences branch={branch}></BranchDifferences>
{context.localBranchCommits && Object.entries(context.localBranchCommits).map(([key, value]) => {
if(key == branch.name){
return value.map((commit, index) => {
return(<CommitDetails key={index} checkout={checkoutCommit} commit={commit}></CommitDetails>)
})
}
})}
</div>
{hasNextPage && <a href="#" className="cursor-pointer mb-1 ml-2" onClick={loadNextPage}>Load more</a>}
</>
</Accordion.Collapse>
</Accordion>)
}

@ -8,13 +8,12 @@ import { branch } from "../../../types";
import { BrancheDetailsNavigation } from "../../navigation/branchedetails"; import { BrancheDetailsNavigation } from "../../navigation/branchedetails";
import { CommitDetailsItems } from "../commits/commitdetailsitem"; import { CommitDetailsItems } from "../commits/commitdetailsitem";
import { CommitDetails } from "../commits/commitdetails"; import { CommitDetails } from "../commits/commitdetails";
import { BranchCommits } from "./branchCommits";
export interface BrancheDetailsProps { export interface BrancheDetailsProps {
branch: branch; branch: branch;
} }
export const BranchDetails = (props: BrancheDetailsProps) => { export const RemoteBranchDetails = (props: BrancheDetailsProps) => {
const { branch } = props; const { branch } = props;
const actions = React.useContext(gitActionsContext) const actions = React.useContext(gitActionsContext)
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)

@ -6,7 +6,7 @@ import { default as dateFormat } from "dateformat";
import { RemotesDetailsNavigation } from "../navigation/remotesdetails"; import { RemotesDetailsNavigation } from "../navigation/remotesdetails";
import { Accordion } from "react-bootstrap"; import { Accordion } from "react-bootstrap";
import { remote } from "../../types"; import { remote } from "../../types";
import { BranchDetails } from "./branches/branchedetails"; import { RemoteBranchDetails } from "./branches/remotebranchedetails";
export interface RemoteSelectProps { export interface RemoteSelectProps {
remote: remote remote: remote
@ -36,7 +36,7 @@ export const Remoteselect = (props: RemoteSelectProps) => {
<> <>
{context.branches && context.branches.filter((branch, index) => branch.remote && branch.remote.remote === remote.remote ).map((branch, index) => { {context.branches && context.branches.filter((branch, index) => branch.remote && branch.remote.remote === remote.remote ).map((branch, index) => {
return ( return (
<BranchDetails key={index} branch={branch}></BranchDetails> <RemoteBranchDetails key={index} branch={branch}></RemoteBranchDetails>
); );
})}</> })}</>

@ -1,8 +1,8 @@
import { ViewPlugin } from "@remixproject/engine-web"; import { ViewPlugin } from "@remixproject/engine-web";
import { ReadBlobResult, ReadCommitResult } from "isomorphic-git"; import { ReadBlobResult, ReadCommitResult } from "isomorphic-git";
import React from "react"; import React from "react";
import { fileStatus, fileStatusMerge, setRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRateLimit, setRemoteBranches, setRemotes, setRepos, setUpstream } from "../state/gitpayload"; import { fileStatus, fileStatusMerge, setRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRateLimit, setRemoteBranches, setRemotes, setRepos, setUpstream, setLocalBranchCommits, setBranchDifferences } from "../state/gitpayload";
import { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType, gitState } from '../types'; import { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference } from '../types';
import { removeSlash } from "../utils"; import { removeSlash } from "../utils";
import { disableCallBacks, enableCallBacks } from "./listeners"; import { disableCallBacks, enableCallBacks } from "./listeners";
import { AlertModal, ModalTypes } from "@remix-ui/app"; import { AlertModal, ModalTypes } from "@remix-ui/app";
@ -762,7 +762,7 @@ export const fetchBranch = async (branch: branch, page: number) => {
console.log(mergeCommits) console.log(mergeCommits)
//console.log(r, commits) //console.log(r, commits)
dispatch(setRemoteBranchCommits({ branch, commits: mergeCommits })) //dispatch(setRemoteBranchCommits({ branch, commits: mergeCommits }))
} }
export const getBranchCommits = async (branch: branch, page: number) => { export const getBranchCommits = async (branch: branch, page: number) => {
@ -772,8 +772,23 @@ export const getBranchCommits = async (branch: branch, page: number) => {
const commits: ReadCommitResult[] = await plugin.call('dGitProvider', 'log', { const commits: ReadCommitResult[] = await plugin.call('dGitProvider', 'log', {
ref: branch.name, ref: branch.name,
}) })
console.log(commits)
//dispatch(setRemoteBranchCommits({ branch, commits })) const branchDifference: branchDifference = await plugin.call('dGitProvider', 'compareBranches', {
branch,
remote: {
remote: 'origin',
url: ''
}
})
console.log(commits, branchDifference)
dispatch(setBranchDifferences(
{
branch,
remote:
{ remote: 'origin', url: '' },
branchDifference: branchDifference
}))
dispatch(setLocalBranchCommits({ branch, commits }))
} else { } else {
await fetchBranch(branch, page) await fetchBranch(branch, page)
} }

@ -1,5 +1,5 @@
import { ReadCommitResult } from "isomorphic-git" import { ReadCommitResult } from "isomorphic-git"
import { GitHubUser, branch, commitChange, fileStatusResult, remote } from "../types" import { GitHubUser, branch, commitChange, fileStatusResult, remote, pagedCommits, branchDifference } from "../types"
import { Endpoints } from "@octokit/types" import { Endpoints } from "@octokit/types"
export const fileStatus = (files: fileStatusResult[]) => { export const fileStatus = (files: fileStatusResult[]) => {
@ -122,17 +122,47 @@ export const setCommitChanges = (commitChanges: commitChange[]) => {
} }
} }
export const setRemoteBranchCommits =({branch, commits}) => { export const setRemoteBranchCommits = ({ branch, commits }:{
branch: branch,
commits: pagedCommits[]
}):{
type: string;
payload: { branch: branch; commits: pagedCommits[] };
} => {
return { return {
type: 'SET_REMOTE_BRANCH_COMMITS', type: 'SET_REMOTE_BRANCH_COMMITS',
payload: { branch, commits } payload: { branch, commits }
} }
} }
export const setLocalBranchCommits = ({branch, commits}) => { export const setLocalBranchCommits = ({
branch,
commits
}: {
branch: branch;
commits: ReadCommitResult[];
}): {
type: string;
payload: { branch: branch; commits: ReadCommitResult[] };
} => {
return { return {
type: 'SET_LOCAL_BRANCH_COMMITS', type: 'SET_LOCAL_BRANCH_COMMITS',
payload: { branch, commits } payload: { branch, commits }
};
};
export const setBranchDifferences = ({
branch,
remote,
branchDifference
}:{
branch: branch;
remote: remote;
branchDifference: branchDifference;
}) => {
return {
type: 'SET_BRANCH_DIFFERENCES',
payload: { branch, remote, branchDifference }
} }
} }

@ -1,6 +1,6 @@
import { ReadCommitResult } from "isomorphic-git" import { ReadCommitResult } from "isomorphic-git"
import { allChangedButNotStagedFiles, getFilesByStatus, getFilesWithNotModifiedStatus } from "../lib/fileHelpers" import { allChangedButNotStagedFiles, getFilesByStatus, getFilesWithNotModifiedStatus } from "../lib/fileHelpers"
import { branch, commitChange, defaultGitState, fileStatusResult, gitState, setRemoteBranchCommitsAction, setLocalBranchCommitsAction } from "../types" import { branch, commitChange, defaultGitState, fileStatusResult, gitState, setRemoteBranchCommitsAction, setLocalBranchCommitsAction, setBranchDifferencesAction } from "../types"
interface Action { interface Action {
type: string type: string
@ -25,16 +25,17 @@ export const gitReducer = (state: gitState = defaultGitState, action: Action): g
case 'FILE_STATUS_MERGE': case 'FILE_STATUS_MERGE':
const filesStatusResults: fileStatusResult[] = action.payload const filesStatusResults: fileStatusResult[] = action.payload
filesStatusResults.map((fileStatusResult: fileStatusResult) => { filesStatusResults.map((fileStatusResult: fileStatusResult) => {
const file = state.fileStatusResult.find( stateFile => { const file = state.fileStatusResult.find(stateFile => {
return stateFile.filename === fileStatusResult.filename return stateFile.filename === fileStatusResult.filename
}) })
if(file){ if (file) {
file.status = fileStatusResult.status file.status = fileStatusResult.status
file.statusNames = fileStatusResult.statusNames file.statusNames = fileStatusResult.statusNames
} }
}) })
return {...state, return {
...state,
staged: getFilesByStatus("staged", state.fileStatusResult), staged: getFilesByStatus("staged", state.fileStatusResult),
modified: getFilesByStatus("modified", state.fileStatusResult), modified: getFilesByStatus("modified", state.fileStatusResult),
untracked: getFilesByStatus("untracked", state.fileStatusResult), untracked: getFilesByStatus("untracked", state.fileStatusResult),
@ -119,25 +120,32 @@ export const gitReducer = (state: gitState = defaultGitState, action: Action): g
} }
case 'SET_REMOTE_BRANCH_COMMITS': case 'SET_REMOTE_BRANCH_COMMITS':
if(state.remoteBranchCommits[(action as setRemoteBranchCommitsAction).payload.branch.name]){ if (state.remoteBranchCommits[(action as setRemoteBranchCommitsAction).payload.branch.name]) {
state.remoteBranchCommits[(action as setRemoteBranchCommitsAction).payload.branch.name].push(...(action as setRemoteBranchCommitsAction).payload.commits) state.remoteBranchCommits[(action as setRemoteBranchCommitsAction).payload.branch.name].push(...(action as setRemoteBranchCommitsAction).payload.commits)
}else{ } else {
state.remoteBranchCommits[(action as setRemoteBranchCommitsAction).payload.branch.name] = (action as setRemoteBranchCommitsAction).payload.commits state.remoteBranchCommits[(action as setRemoteBranchCommitsAction).payload.branch.name] = (action as setRemoteBranchCommitsAction).payload.commits
} }
return { return {
...state, ...state,
remoteBranchCommits: {...state.remoteBranchCommits} remoteBranchCommits: { ...state.remoteBranchCommits }
} }
case 'SET_LOCAL_BRANCH_COMMITS': case 'SET_LOCAL_BRANCH_COMMITS':
if(state.localBranchCommits[(action as setLocalBranchCommitsAction).payload.branch.name]){
state.localBranchCommits[(action as setLocalBranchCommitsAction).payload.branch.name].push(...(action as setLocalBranchCommitsAction).payload.commits)
}else{
state.localBranchCommits[(action as setLocalBranchCommitsAction).payload.branch.name] = (action as setLocalBranchCommitsAction).payload.commits state.localBranchCommits[(action as setLocalBranchCommitsAction).payload.branch.name] = (action as setLocalBranchCommitsAction).payload.commits
return {
...state,
localBranchCommits: { ...state.localBranchCommits }
} }
case 'SET_BRANCH_DIFFERENCES':
state.branchDifferences[`${(action as setBranchDifferencesAction).payload.remote.remote}/${(action as setBranchDifferencesAction).payload.branch.name}`] = (action as setBranchDifferencesAction).payload.branchDifference
return { return {
...state, ...state,
localBranchCommits: {...state.localBranchCommits} branchDifferences: { ...state.branchDifferences }
} }
case 'SET_GITHUB_ACCESS_TOKEN': case 'SET_GITHUB_ACCESS_TOKEN':

@ -26,7 +26,8 @@ export type gitState = {
remoteBranches: remoteBranch[] remoteBranches: remoteBranch[]
commitChanges: commitChange[] commitChanges: commitChange[]
remoteBranchCommits: Record<string, pagedCommits[]> remoteBranchCommits: Record<string, pagedCommits[]>
localBranchCommits: Record<string, pagedCommits[]> localBranchCommits: Record<string, ReadCommitResult[]>
branchDifferences: Record<remoteBranchIdentifier, branchDifference>
syncStatus: syncStatus, syncStatus: syncStatus,
localCommitCount: number localCommitCount: number
remoteCommitCount: number remoteCommitCount: number
@ -36,6 +37,13 @@ export type gitState = {
gitHubAccessToken: string gitHubAccessToken: string
} }
export type remoteBranchIdentifier = `${string}/${string}`
export type branchDifference = {
uniqueHeadCommits: ReadCommitResult[],
uniqueRemoteCommits: ReadCommitResult[],
}
export type pagedCommits = { export type pagedCommits = {
page: number, page: number,
perPage: number, perPage: number,
@ -70,8 +78,8 @@ export type commitChangeType = keyof commitChangeTypes
export type commitChange = { export type commitChange = {
type: commitChangeType type: commitChangeType
path: string, path: string,
hashModified : string, hashModified: string,
hashOriginal : string, hashOriginal: string,
original?: string, original?: string,
modified?: string, modified?: string,
readonly?: boolean readonly?: boolean
@ -124,6 +132,7 @@ export const defaultGitState: gitState = {
commitChanges: [], commitChanges: [],
remoteBranchCommits: {}, remoteBranchCommits: {},
localBranchCommits: {}, localBranchCommits: {},
branchDifferences: {},
syncStatus: syncStatus.none, syncStatus: syncStatus.none,
localCommitCount: 0, localCommitCount: 0,
remoteCommitCount: 0, remoteCommitCount: 0,
@ -142,12 +151,12 @@ export const defaultLoaderState: loaderState = {
} }
export type fileStatusResult = { export type fileStatusResult = {
filename:string, filename: string,
status?: fileStatus status?: fileStatus
statusNames?:string[] statusNames?: string[]
} }
export type fileStatus =[string, 0 | 1, 0 | 1 | 2, 0 | 1 | 2 | 3] export type fileStatus = [string, 0 | 1, 0 | 1 | 2, 0 | 1 | 2 | 3]
export type statusMatrixType = { matrix: string[] | undefined; status: string[] } export type statusMatrixType = { matrix: string[] | undefined; status: string[] }
@ -228,7 +237,16 @@ export interface setLocalBranchCommitsAction {
type: string, type: string,
payload: { payload: {
branch: branch, branch: branch,
commits: pagedCommits[] commits: ReadCommitResult[]
}
}
export interface setBranchDifferencesAction {
type: string,
payload: {
branch: branch,
remote: remote,
branchDifference: branchDifference
} }
} }
@ -237,4 +255,4 @@ export interface setTokenAction {
payload: string payload: string
} }
export type gitActionDispatch = setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction export type gitActionDispatch = setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setBranchDifferencesAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction
Loading…
Cancel
Save