git4refactor
filip mertens 7 months ago
parent 86c877989a
commit e1fc893076
  1. 10
      apps/remix-ide/src/app/files/dgitProvider.ts
  2. 45
      libs/remix-ui/git/src/components/github/devicecode.tsx
  3. 16
      libs/remix-ui/git/src/components/gitui.tsx
  4. 87
      libs/remix-ui/git/src/components/navigation/log.tsx
  5. 39
      libs/remix-ui/git/src/components/panels/log.tsx
  6. 22
      libs/remix-ui/git/src/lib/gitactions.ts
  7. 14
      libs/remix-ui/git/src/lib/listeners.ts
  8. 4
      libs/remix-ui/git/src/state/context.tsx
  9. 22
      libs/remix-ui/git/src/state/gitpayload.ts
  10. 20
      libs/remix-ui/git/src/state/gitreducer.tsx
  11. 21
      libs/remix-ui/git/src/types/index.ts

@ -1001,9 +1001,12 @@ class DGitProvider extends Plugin {
return data.data return data.data
} }
async getGitHubUser(input: { token: string }): Promise<{ async getGitHubUser(input: { token: string }): Promise<{
user: GitHubUser, user: GitHubUser,
ratelimit: RateLimit ratelimit: RateLimit
scopes: string[]
}> { }> {
const octokit = new Octokit({ const octokit = new Octokit({
auth: input.token auth: input.token
@ -1023,9 +1026,14 @@ class DGitProvider extends Plugin {
const user = await octokit.request('GET /user') const user = await octokit.request('GET /user')
const scopes = user.headers['x-oauth-scopes'];
console.log('scopes', scopes)
return { return {
user: user.data, user: user.data,
ratelimit: ratelimit.data ratelimit: ratelimit.data,
scopes: scopes.split(',')
} }
} }

@ -13,8 +13,8 @@ export const GetDeviceCode = () => {
const [gitHubResponse, setGitHubResponse] = React.useState<any>(null) const [gitHubResponse, setGitHubResponse] = React.useState<any>(null)
const [authorized, setAuthorized] = React.useState<boolean>(false) const [authorized, setAuthorized] = React.useState<boolean>(false)
const getDeviceCodeFromGitHub = async () => { const getDeviceCodeFromGitHub = async () => {
setAuthorized(false) setAuthorized(false)
@ -24,7 +24,7 @@ export const GetDeviceCode = () => {
url: 'http://0.0.0.0:3000/github.com/login/device/code', url: 'http://0.0.0.0:3000/github.com/login/device/code',
data: { data: {
client_id: 'dccbc48453f7afa34fad', client_id: 'dccbc48453f7afa34fad',
scope: 'repo' scope: 'repo gist'
}, },
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -74,6 +74,8 @@ export const GetDeviceCode = () => {
const disconnect = async () => { const disconnect = async () => {
setAuthorized(false) setAuthorized(false)
setGitHubResponse(null) setGitHubResponse(null)
await pluginActions.saveToken(null)
await actions.getGitHubUser()
} }
const checkConnection = async () => { const checkConnection = async () => {
@ -82,7 +84,7 @@ export const GetDeviceCode = () => {
useEffect(() => { useEffect(() => {
},[]) }, [])
useEffect(() => { useEffect(() => {
console.log('context.rateLimit', context.rateLimit) console.log('context.rateLimit', context.rateLimit)
@ -94,7 +96,7 @@ export const GetDeviceCode = () => {
{(context.gitHubUser && context.gitHubUser.login) ? null : {(context.gitHubUser && context.gitHubUser.login) ? null :
<button className='btn btn-primary mt-1 w-100' onClick={async () => { <button className='btn btn-primary mt-1 w-100' onClick={async () => {
getDeviceCodeFromGitHub(); getDeviceCodeFromGitHub();
}}>Login in with github</button> }}><i className="fab fa-github mr-1"></i>Login in with github</button>
} }
{gitHubResponse && !authorized && {gitHubResponse && !authorized &&
<div className="pt-2"> <div className="pt-2">
@ -118,25 +120,26 @@ export const GetDeviceCode = () => {
} }
{ {
(context.gitHubUser && context.gitHubUser.login) ? (context.gitHubUser && context.gitHubUser.login) ?
<div className="pt-2"> <div className="pt-2">
<button className='btn btn-primary mt-1 w-100' onClick={async () => { <button className='btn btn-primary mt-1 w-100' onClick={async () => {
disconnect() disconnect()
}}>Disconnect</button> }}>Disconnect</button>
</div>: null </div> : null
} }
{ {
(context.gitHubUser && context.gitHubUser.login) ? (context.gitHubUser && context.gitHubUser.login) ?
<div className="pt-2"> <div className="pt-2">
<Card> <Card>
<Card.Body> <Card.Body>
<Card.Title>Connected as {context.gitHubUser.login}</Card.Title> <Card.Title>Connected as {context.gitHubUser.login}</Card.Title>
<Card.Text> <Card.Text>
<img src={context.gitHubUser.avatar_url} className="w-100" /> <img src={context.gitHubUser.avatar_url} className="w-100" />
<a target="_blank" href={context.gitHubUser.html_url}>{context.gitHubUser.html_url}</a> <a target="_blank" href={context.gitHubUser.html_url}>{context.gitHubUser.html_url}</a>
</Card.Text> </Card.Text>
</Card.Body> </Card.Body>
</Card> </Card>
</div>: null
</div> : null
} }

@ -1,5 +1,5 @@
import React, { useEffect, useReducer, useState } from 'react' import React, { useEffect, useReducer, useState } from 'react'
import { add, addall, checkout, checkoutfile, clone, commit, createBranch, remoteBranches, repositories, rm, getCommitChanges, diff, resolveRef, getBranchCommits, setUpstreamRemote, getGitHubUser, getBranches, getRemotes, remoteCommits, saveGitHubCredentials, getGitHubCredentials, fetch, pull, push, setDefaultRemote, addRemote, removeRemote } from '../lib/gitactions' import { add, addall, checkout, checkoutfile, clone, commit, createBranch, remoteBranches, repositories, rm, getCommitChanges, diff, resolveRef, getBranchCommits, setUpstreamRemote, getGitHubUser, getBranches, getRemotes, remoteCommits, saveGitHubCredentials, getGitHubCredentials, fetch, pull, push, setDefaultRemote, addRemote, removeRemote, sendToGitLog, clearGitLog } from '../lib/gitactions'
import { loadFiles, setCallBacks } from '../lib/listeners' import { loadFiles, setCallBacks } from '../lib/listeners'
import { openDiff, openFile, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions' import { openDiff, openFile, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions'
import { gitActionsContext, pluginActionsContext } from '../state/context' import { gitActionsContext, pluginActionsContext } from '../state/context'
@ -30,6 +30,8 @@ import { loaderReducer } from '../state/loaderReducer'
import { ApolloClient, ApolloProvider, NormalizedCacheObject } from '@apollo/client' import { ApolloClient, ApolloProvider, NormalizedCacheObject } from '@apollo/client'
import { GetDeviceCode } from './github/devicecode' import { GetDeviceCode } from './github/devicecode'
import { LogNavigation } from './navigation/log'
import LogViewer from './panels/log'
export const gitPluginContext = React.createContext<gitState>(defaultGitState) export const gitPluginContext = React.createContext<gitState>(defaultGitState)
export const loaderContext = React.createContext<loaderState>(defaultLoaderState) export const loaderContext = React.createContext<loaderState>(defaultLoaderState)
@ -110,7 +112,9 @@ export const GitUI = (props: IGitUi) => {
push, push,
setDefaultRemote, setDefaultRemote,
addRemote, addRemote,
removeRemote removeRemote,
sendToGitLog,
clearGitLog
} }
const pluginActionsProviderValue = { const pluginActionsProviderValue = {
@ -178,7 +182,13 @@ export const GitUI = (props: IGitUi) => {
<GetDeviceCode></GetDeviceCode> <GetDeviceCode></GetDeviceCode>
</> </>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr>
<LogNavigation eventKey="6" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="6">
<>
<LogViewer/>
</>
</Accordion.Collapse>
</Accordion> </Accordion>

@ -0,0 +1,87 @@
import { faBan, faCaretDown, faCaretRight, faCircleCheck, faCircleInfo, faInfo, faTrash, faTriangleExclamation, faWarning } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React, { useContext, useEffect, useState } from "react";
import { gitActionsContext, pluginActionsContext } from "../../state/context";
import { gitPluginContext } from "../gitui";
export const LogNavigation = ({ eventKey, activePanel, callback }) => {
const context = useContext(gitPluginContext)
const actions = React.useContext(gitActionsContext)
const [logState, setLogState] = useState({
errorCount: 0,
warningCount: 0,
infoCount: 0,
successCount: 0
});
const handleClick = () => {
if (!callback) return
if (activePanel === eventKey) {
callback('')
} else {
callback(eventKey)
}
}
useEffect(() => {
if(!context.log) return
// count different types of logs
const errorCount = context.log.filter(log => log.type === 'error').length
const warningCount = context.log.filter(log => log.type === 'warning').length
const infoCount = context.log.filter(log => log.type === 'info').length
const successCount = context.log.filter(log => log.type === 'success').length
// update the state
setLogState({
errorCount,
warningCount,
infoCount,
successCount
})
}, [context.log])
const clearLogs = () => {
actions.clearGitLog()
}
return (
<>
<div className={'d-flex justify-content-between pt-1 pb-1 ' + (activePanel === eventKey ? 'bg-light' : '')}>
<span onClick={() => handleClick()} role={'button'} className='nav d-flex justify-content-start align-items-center w-75'>
{
activePanel === eventKey ? <FontAwesomeIcon className='' icon={faCaretDown}></FontAwesomeIcon> : <FontAwesomeIcon className='' icon={faCaretRight}></FontAwesomeIcon>
}
<label className="pl-1 nav form-check-label mr-2">LOG</label>
{logState.errorCount > 0 && (
<div className="text-danger mr-1">
{logState.errorCount}
<FontAwesomeIcon className="ml-1" icon={faTriangleExclamation} />
</div>
)}
{logState.warningCount > 0 && (
<div className="text-warning mr-1">
{logState.warningCount}
<FontAwesomeIcon className="ml-1" icon={faWarning} />
</div>
)}
{logState.infoCount > 0 && (
<div className="text-info mr-1">
{logState.infoCount}
<FontAwesomeIcon className="ml-1" icon={faCircleInfo} />
</div>
)}
{logState.successCount > 0 && (
<div className="text-success">
{logState.successCount}
<FontAwesomeIcon className="ml-1" icon={faCircleCheck} />
</div>
)}
</span>
{context.log && context.log.length > 0 && (
<FontAwesomeIcon onClick={clearLogs} className='btn btn-sm' icon={faBan}></FontAwesomeIcon>)}
</div>
</>
);
}

@ -0,0 +1,39 @@
// src/LogViewer.tsx
import React, { useContext } from 'react';
import { gitPluginContext } from '../gitui';
const LogViewer = () => {
const context = useContext(gitPluginContext);
const typeToCssClass = (type: string) => {
switch (type) {
case 'error':
return 'text-danger';
case 'warning':
return 'text-warning';
case 'info':
return 'text-info';
case 'debug':
return 'text-secondary';
default:
return 'text-success';
}
};
if (context.log && context.log.length > 0) {
return (
<div className="p-1">
{context.log && context.log.map((log, index) => (
<div key={index} className={`log-entry ${typeToCssClass(log.type)}`}>
[{log.type.toUpperCase()}] {log.message}
</div>
))}
</div>
);
} else {
return <div className="p-1">No logs</div>
}
};
export default LogViewer;

@ -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, setLocalBranchCommits, setBranchDifferences, setRemoteAsDefault } from "../state/gitpayload"; import { fileStatus, fileStatusMerge, setRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRateLimit, setRemoteBranches, setRemotes, setRepos, setUpstream, setLocalBranchCommits, setBranchDifferences, setRemoteAsDefault, setScopes, setLog, clearLog } from "../state/gitpayload";
import { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote } from '../types'; import { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote, gitLog } 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";
@ -556,10 +556,14 @@ export const remoteCommits = async (url: string, branch: string, length: number)
const commits = await plugin.call('dGitProvider' as any, 'remotecommits', { token, owner, repo, branch, length }); const commits = await plugin.call('dGitProvider' as any, 'remotecommits', { token, owner, repo, branch, length });
console.log(commits, 'remote commits') console.log(commits, 'remote commits')
} else { } else {
plugin.call('notification', 'alert', { sendToGitLog({
title: 'Error getting commits', type: 'error',
message: `Please check your GitHub token in the GitHub settings. It needs to have access to the commits.` message: `Please check your GitHub token in the GitHub settings. It needs to have access to the commits.`
}) })
//plugin.call('notification', 'alert', {
// title: 'Error getting commits',
// message: `Please check your GitHub token in the GitHub settings. It needs to have access to the commits.`
//})
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@ -604,12 +608,14 @@ export const getGitHubUser = async () => {
const data: { const data: {
user: GitHubUser, user: GitHubUser,
ratelimit: RateLimit ratelimit: RateLimit
scopes: string[]
} = await plugin.call('dGitProvider' as any, 'getGitHubUser', { token }); } = await plugin.call('dGitProvider' as any, 'getGitHubUser', { token });
console.log('GET USER"', data) console.log('GET USER"', data)
dispatch(setGitHubUser(data.user)) dispatch(setGitHubUser(data.user))
dispatch(setRateLimit(data.ratelimit)) dispatch(setRateLimit(data.ratelimit))
dispatch(setScopes(data.scopes))
} else { } else {
dispatch(setGitHubUser(null)) dispatch(setGitHubUser(null))
} }
@ -871,4 +877,12 @@ export const removeRemote = async (remote: remote) => {
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
}
export const sendToGitLog = async (message: gitLog) => {
dispatch(setLog(message))
}
export const clearGitLog = async () => {
dispatch(clearLog())
} }

@ -1,7 +1,7 @@
import { ViewPlugin } from "@remixproject/engine-web"; import { ViewPlugin } from "@remixproject/engine-web";
import React from "react"; import React from "react";
import { setCanUseApp, setLoading, setRepoName, setGItHubToken } from "../state/gitpayload"; import { setCanUseApp, setLoading, setRepoName, setGItHubToken, setLog } from "../state/gitpayload";
import { gitActionDispatch } from "../types"; import { gitActionDispatch } from "../types";
import { diffFiles, getBranches, getFileStatusMatrix, getGitHubUser, getRemotes, gitlog, setPlugin } from "./gitactions"; import { diffFiles, getBranches, getFileStatusMatrix, getGitHubUser, getRemotes, gitlog, setPlugin } from "./gitactions";
@ -71,12 +71,24 @@ export const setCallBacks = (viewPlugin: ViewPlugin, gitDispatcher: React.Dispat
await loadFiles(); await loadFiles();
}) })
plugin.on('dGitProvider', 'commit', async () => { plugin.on('dGitProvider', 'commit', async () => {
gitDispatch(setLog({
message: 'Committed changes...',
type: 'success'
}))
await loadFiles(); await loadFiles();
}) })
plugin.on('dGitProvider', 'branch', async () => { plugin.on('dGitProvider', 'branch', async () => {
gitDispatch(setLog({
message: "Created Branch",
type: "success"
}))
await loadFiles(); await loadFiles();
}) })
plugin.on('dGitProvider', 'clone', async () => { plugin.on('dGitProvider', 'clone', async () => {
gitDispatch(setLog({
message: "Cloned Repository",
type: "success"
}))
await loadFiles(); await loadFiles();
}) })
plugin.on('manager', 'pluginActivated', async (p: Plugin) => { plugin.on('manager', 'pluginActivated', async (p: Plugin) => {

@ -1,6 +1,6 @@
import { ReadCommitResult } from "isomorphic-git" import { ReadCommitResult } from "isomorphic-git"
import React from "react" import React from "react"
import { branch, commitChange, remote } from "../types" import { branch, commitChange, gitLog, remote } from "../types"
export interface gitActions { export interface gitActions {
removeRemote(remote: remote): void removeRemote(remote: remote): void
@ -27,6 +27,8 @@ export interface gitActions {
getRemotes: () => Promise<void> getRemotes: () => Promise<void>
setDefaultRemote: (remote: remote) => Promise<void> setDefaultRemote: (remote: remote) => Promise<void>
addRemote: (remote: remote) => Promise<void> addRemote: (remote: remote) => Promise<void>
sendToGitLog: (message: gitLog) => Promise<void>
clearGitLog: () => Promise<void>
} }
export const gitActionsContext = React.createContext<gitActions>(null) export const gitActionsContext = React.createContext<gitActions>(null)

@ -1,5 +1,5 @@
import { ReadCommitResult } from "isomorphic-git" import { ReadCommitResult } from "isomorphic-git"
import { GitHubUser, branch, commitChange, fileStatusResult, remote, pagedCommits, branchDifference } from "../types" import { GitHubUser, branch, commitChange, fileStatusResult, remote, pagedCommits, branchDifference, gitLog } from "../types"
import { Endpoints } from "@octokit/types" import { Endpoints } from "@octokit/types"
export const fileStatus = (files: fileStatusResult[]) => { export const fileStatus = (files: fileStatusResult[]) => {
@ -58,6 +58,13 @@ export const setRateLimit = (rateLimit: any) => {
} }
} }
export const setScopes = (scopes: string[]) => {
return {
type: 'SET_SCOPES',
payload: scopes
}
}
export const setGitHubAccessToken = (token: string) => { export const setGitHubAccessToken = (token: string) => {
return { return {
type: 'SET_GITHUB_ACCESS_TOKEN', type: 'SET_GITHUB_ACCESS_TOKEN',
@ -179,3 +186,16 @@ export const setRemoteAsDefault = (remote: remote) => {
payload: remote payload: remote
} }
} }
export const setLog = (message: gitLog) => {
return {
type: 'SET_LOG',
payload: message
}
}
export const clearLog = () => {
return {
type: 'CLEAR_LOG'
}
}

@ -168,11 +168,31 @@ export const gitReducer = (state: gitState = defaultGitState, action: Action): g
...state, ...state,
gitHubAccessToken: action.payload gitHubAccessToken: action.payload
} }
case 'SET_SCOPES':
return {
...state,
gitHubScopes: action.payload
}
case 'SET_DEFAULT_REMOTE': case 'SET_DEFAULT_REMOTE':
return { return {
...state, ...state,
defaultRemote: (action as setDefaultRemoteAction).payload defaultRemote: (action as setDefaultRemoteAction).payload
} }
case 'SET_LOG':
return {
...state,
log: [...state.log, action.payload]
}
case 'CLEAR_LOG':
return {
...state,
log: []
}
} }
} }

@ -33,7 +33,13 @@ export type gitState = {
upstream: string upstream: string
gitHubUser: GitHubUser gitHubUser: GitHubUser
rateLimit: RateLimit rateLimit: RateLimit
gitHubScopes: string[]
gitHubAccessToken: string gitHubAccessToken: string
log: gitLog[]
}
export type gitLog = {
type: 'error' | 'warning' | 'info' |'success',
message: string
} }
export type remoteBranchIdentifier = `${string}/${string}` export type remoteBranchIdentifier = `${string}/${string}`
@ -140,7 +146,9 @@ export const defaultGitState: gitState = {
upstream: "", upstream: "",
gitHubUser: {} as GitHubUser, gitHubUser: {} as GitHubUser,
rateLimit: {} as RateLimit, rateLimit: {} as RateLimit,
gitHubAccessToken: "" gitHubScopes: [],
gitHubAccessToken: "",
log: []
} }
export const defaultLoaderState: loaderState = { export const defaultLoaderState: loaderState = {
@ -261,4 +269,13 @@ export interface setDefaultRemoteAction {
payload: remote payload: remote
} }
export type gitActionDispatch = setDefaultRemoteAction | setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setBranchDifferencesAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction export interface setLogAction {
type: string,
payload: gitLog
}
export interface clearLogAction {
type: string
}
export type gitActionDispatch = clearLogAction | setLogAction | setDefaultRemoteAction | setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setBranchDifferencesAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction
Loading…
Cancel
Save