diff --git a/apps/remix-ide/src/app/files/dgitProvider.ts b/apps/remix-ide/src/app/files/dgitProvider.ts index 7473afbcb6..d754bc2b2d 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.ts +++ b/apps/remix-ide/src/app/files/dgitProvider.ts @@ -1001,9 +1001,12 @@ class DGitProvider extends Plugin { return data.data } + + async getGitHubUser(input: { token: string }): Promise<{ user: GitHubUser, ratelimit: RateLimit + scopes: string[] }> { const octokit = new Octokit({ auth: input.token @@ -1023,9 +1026,14 @@ class DGitProvider extends Plugin { const user = await octokit.request('GET /user') + const scopes = user.headers['x-oauth-scopes']; + + console.log('scopes', scopes) + return { user: user.data, - ratelimit: ratelimit.data + ratelimit: ratelimit.data, + scopes: scopes.split(',') } } diff --git a/libs/remix-ui/git/src/components/github/devicecode.tsx b/libs/remix-ui/git/src/components/github/devicecode.tsx index d40127e31c..3b36227366 100644 --- a/libs/remix-ui/git/src/components/github/devicecode.tsx +++ b/libs/remix-ui/git/src/components/github/devicecode.tsx @@ -13,8 +13,8 @@ export const GetDeviceCode = () => { const [gitHubResponse, setGitHubResponse] = React.useState(null) const [authorized, setAuthorized] = React.useState(false) - - + + const getDeviceCodeFromGitHub = async () => { setAuthorized(false) @@ -24,7 +24,7 @@ export const GetDeviceCode = () => { url: 'http://0.0.0.0:3000/github.com/login/device/code', data: { client_id: 'dccbc48453f7afa34fad', - scope: 'repo' + scope: 'repo gist' }, headers: { 'Content-Type': 'application/json', @@ -74,6 +74,8 @@ export const GetDeviceCode = () => { const disconnect = async () => { setAuthorized(false) setGitHubResponse(null) + await pluginActions.saveToken(null) + await actions.getGitHubUser() } const checkConnection = async () => { @@ -82,7 +84,7 @@ export const GetDeviceCode = () => { useEffect(() => { - },[]) + }, []) useEffect(() => { console.log('context.rateLimit', context.rateLimit) @@ -94,7 +96,7 @@ export const GetDeviceCode = () => { {(context.gitHubUser && context.gitHubUser.login) ? null : + }}>Login in with github } {gitHubResponse && !authorized &&
@@ -118,25 +120,26 @@ export const GetDeviceCode = () => { } { (context.gitHubUser && context.gitHubUser.login) ? -
- -
: null +
+ +
: null } { (context.gitHubUser && context.gitHubUser.login) ? -
- - - Connected as {context.gitHubUser.login} - - - {context.gitHubUser.html_url} - - - -
: null +
+ + + Connected as {context.gitHubUser.login} + + + {context.gitHubUser.html_url} + + + + +
: null } diff --git a/libs/remix-ui/git/src/components/gitui.tsx b/libs/remix-ui/git/src/components/gitui.tsx index fe4384c67b..cc255797d6 100644 --- a/libs/remix-ui/git/src/components/gitui.tsx +++ b/libs/remix-ui/git/src/components/gitui.tsx @@ -1,5 +1,5 @@ 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 { openDiff, openFile, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions' import { gitActionsContext, pluginActionsContext } from '../state/context' @@ -30,6 +30,8 @@ import { loaderReducer } from '../state/loaderReducer' import { ApolloClient, ApolloProvider, NormalizedCacheObject } from '@apollo/client' import { GetDeviceCode } from './github/devicecode' +import { LogNavigation } from './navigation/log' +import LogViewer from './panels/log' export const gitPluginContext = React.createContext(defaultGitState) export const loaderContext = React.createContext(defaultLoaderState) @@ -110,7 +112,9 @@ export const GitUI = (props: IGitUi) => { push, setDefaultRemote, addRemote, - removeRemote + removeRemote, + sendToGitLog, + clearGitLog } const pluginActionsProviderValue = { @@ -178,7 +182,13 @@ export const GitUI = (props: IGitUi) => { - +
+ + + <> + + + diff --git a/libs/remix-ui/git/src/components/navigation/log.tsx b/libs/remix-ui/git/src/components/navigation/log.tsx new file mode 100644 index 0000000000..d3d3fca90a --- /dev/null +++ b/libs/remix-ui/git/src/components/navigation/log.tsx @@ -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 ( + <> +
+ handleClick()} role={'button'} className='nav d-flex justify-content-start align-items-center w-75'> + { + activePanel === eventKey ? : + } + + {logState.errorCount > 0 && ( +
+ {logState.errorCount} + +
+ )} + + {logState.warningCount > 0 && ( +
+ {logState.warningCount} + +
+ )} + + {logState.infoCount > 0 && ( +
+ {logState.infoCount} + +
+ )} + + {logState.successCount > 0 && ( +
+ {logState.successCount} + +
+ )} +
+ {context.log && context.log.length > 0 && ( + )} +
+ + ); +} \ No newline at end of file diff --git a/libs/remix-ui/git/src/components/panels/log.tsx b/libs/remix-ui/git/src/components/panels/log.tsx new file mode 100644 index 0000000000..be3de769fe --- /dev/null +++ b/libs/remix-ui/git/src/components/panels/log.tsx @@ -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 ( +
+ {context.log && context.log.map((log, index) => ( +
+ [{log.type.toUpperCase()}] {log.message} +
+ ))} +
+ ); + } else { + return
No logs
+ } +}; + +export default LogViewer; diff --git a/libs/remix-ui/git/src/lib/gitactions.ts b/libs/remix-ui/git/src/lib/gitactions.ts index 1a15191fa5..91587220d0 100644 --- a/libs/remix-ui/git/src/lib/gitactions.ts +++ b/libs/remix-ui/git/src/lib/gitactions.ts @@ -1,8 +1,8 @@ import { ViewPlugin } from "@remixproject/engine-web"; import { ReadBlobResult, ReadCommitResult } from "isomorphic-git"; 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 { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote } from '../types'; +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, gitLog } from '../types'; import { removeSlash } from "../utils"; import { disableCallBacks, enableCallBacks } from "./listeners"; 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 }); console.log(commits, 'remote commits') } else { - plugin.call('notification', 'alert', { - title: 'Error getting commits', + sendToGitLog({ + type: 'error', 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) { console.log(e) @@ -604,12 +608,14 @@ export const getGitHubUser = async () => { const data: { user: GitHubUser, ratelimit: RateLimit + scopes: string[] } = await plugin.call('dGitProvider' as any, 'getGitHubUser', { token }); console.log('GET USER"', data) dispatch(setGitHubUser(data.user)) dispatch(setRateLimit(data.ratelimit)) + dispatch(setScopes(data.scopes)) } else { dispatch(setGitHubUser(null)) } @@ -871,4 +877,12 @@ export const removeRemote = async (remote: remote) => { } catch (e) { console.log(e) } +} + +export const sendToGitLog = async (message: gitLog) => { + dispatch(setLog(message)) +} + +export const clearGitLog = async () => { + dispatch(clearLog()) } \ No newline at end of file diff --git a/libs/remix-ui/git/src/lib/listeners.ts b/libs/remix-ui/git/src/lib/listeners.ts index 5e012be2e4..f176588828 100644 --- a/libs/remix-ui/git/src/lib/listeners.ts +++ b/libs/remix-ui/git/src/lib/listeners.ts @@ -1,7 +1,7 @@ import { ViewPlugin } from "@remixproject/engine-web"; 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 { diffFiles, getBranches, getFileStatusMatrix, getGitHubUser, getRemotes, gitlog, setPlugin } from "./gitactions"; @@ -71,12 +71,24 @@ export const setCallBacks = (viewPlugin: ViewPlugin, gitDispatcher: React.Dispat await loadFiles(); }) plugin.on('dGitProvider', 'commit', async () => { + gitDispatch(setLog({ + message: 'Committed changes...', + type: 'success' + })) await loadFiles(); }) plugin.on('dGitProvider', 'branch', async () => { + gitDispatch(setLog({ + message: "Created Branch", + type: "success" + })) await loadFiles(); }) plugin.on('dGitProvider', 'clone', async () => { + gitDispatch(setLog({ + message: "Cloned Repository", + type: "success" + })) await loadFiles(); }) plugin.on('manager', 'pluginActivated', async (p: Plugin) => { diff --git a/libs/remix-ui/git/src/state/context.tsx b/libs/remix-ui/git/src/state/context.tsx index 69341038a1..6730ef657c 100644 --- a/libs/remix-ui/git/src/state/context.tsx +++ b/libs/remix-ui/git/src/state/context.tsx @@ -1,6 +1,6 @@ import { ReadCommitResult } from "isomorphic-git" import React from "react" -import { branch, commitChange, remote } from "../types" +import { branch, commitChange, gitLog, remote } from "../types" export interface gitActions { removeRemote(remote: remote): void @@ -27,6 +27,8 @@ export interface gitActions { getRemotes: () => Promise setDefaultRemote: (remote: remote) => Promise addRemote: (remote: remote) => Promise + sendToGitLog: (message: gitLog) => Promise + clearGitLog: () => Promise } export const gitActionsContext = React.createContext(null) diff --git a/libs/remix-ui/git/src/state/gitpayload.ts b/libs/remix-ui/git/src/state/gitpayload.ts index 8bcf16e32a..aef51b2574 100644 --- a/libs/remix-ui/git/src/state/gitpayload.ts +++ b/libs/remix-ui/git/src/state/gitpayload.ts @@ -1,5 +1,5 @@ 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" 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) => { return { type: 'SET_GITHUB_ACCESS_TOKEN', @@ -179,3 +186,16 @@ export const setRemoteAsDefault = (remote: remote) => { payload: remote } } + +export const setLog = (message: gitLog) => { + return { + type: 'SET_LOG', + payload: message + } +} + +export const clearLog = () => { + return { + type: 'CLEAR_LOG' + } +} diff --git a/libs/remix-ui/git/src/state/gitreducer.tsx b/libs/remix-ui/git/src/state/gitreducer.tsx index ab2a796cf3..400d3052b3 100644 --- a/libs/remix-ui/git/src/state/gitreducer.tsx +++ b/libs/remix-ui/git/src/state/gitreducer.tsx @@ -168,11 +168,31 @@ export const gitReducer = (state: gitState = defaultGitState, action: Action): g ...state, gitHubAccessToken: action.payload } + + case 'SET_SCOPES': + return { + ...state, + gitHubScopes: action.payload + } case 'SET_DEFAULT_REMOTE': return { ...state, defaultRemote: (action as setDefaultRemoteAction).payload } + + case 'SET_LOG': + return { + ...state, + log: [...state.log, action.payload] + } + + case 'CLEAR_LOG': + return { + ...state, + log: [] + } + + } } \ No newline at end of file diff --git a/libs/remix-ui/git/src/types/index.ts b/libs/remix-ui/git/src/types/index.ts index 8519697841..8b6d8dbb1c 100644 --- a/libs/remix-ui/git/src/types/index.ts +++ b/libs/remix-ui/git/src/types/index.ts @@ -33,7 +33,13 @@ export type gitState = { upstream: string gitHubUser: GitHubUser rateLimit: RateLimit + gitHubScopes: string[] gitHubAccessToken: string + log: gitLog[] +} +export type gitLog = { + type: 'error' | 'warning' | 'info' |'success', + message: string } export type remoteBranchIdentifier = `${string}/${string}` @@ -140,7 +146,9 @@ export const defaultGitState: gitState = { upstream: "", gitHubUser: {} as GitHubUser, rateLimit: {} as RateLimit, - gitHubAccessToken: "" + gitHubScopes: [], + gitHubAccessToken: "", + log: [] } export const defaultLoaderState: loaderState = { @@ -261,4 +269,13 @@ export interface setDefaultRemoteAction { payload: remote } -export type gitActionDispatch = setDefaultRemoteAction | setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setBranchDifferencesAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction \ No newline at end of file +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 \ No newline at end of file