diff --git a/apps/remix-ide/src/app/files/dgitProvider.ts b/apps/remix-ide/src/app/files/dgitProvider.ts index 12c9d35693..63ac21e868 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.ts +++ b/apps/remix-ide/src/app/files/dgitProvider.ts @@ -14,22 +14,27 @@ import JSZip from 'jszip' import path from 'path' import FormData from 'form-data' import axios from 'axios' -import {Registry} from '@remix-project/remix-lib' +import { Registry } from '@remix-project/remix-lib' import { Octokit, App } from "octokit" import { OctokitResponse } from '@octokit/types' import { Endpoints } from "@octokit/types" import { IndexedDBStorage } from './filesystems/indexedDB' import { GitHubUser, RateLimit, branch, commitChange, remote } from '@remix-ui/git' +import { LibraryProfile, StatusEvents } from '@remixproject/plugin-utils' +import { ITerminal } from '@remixproject/plugin-api/src/lib/terminal' + declare global { interface Window { remixFileSystemCallback: IndexedDBStorage; remixFileSystem: any; } } -const profile = { + + +const profile: LibraryProfile = { name: 'dGitProvider', displayName: 'Decentralized git', description: 'Decentralized git provider', icon: 'assets/img/fileManager.webp', 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', 'pin', 'pull', 'pinList', 'unPin', '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'], kind: 'file-system' } @@ -63,7 +68,7 @@ class DGitProvider extends Plugin { this.ipfsSources = [this.remixIPFS, this.globalIPFSConfig, this.ipfsconfig] } - async getGitConfig(dir = '') { + async addIsomorphicGitConfigFS(dir = '') { if ((Registry.getInstance().get('platform').api.isDesktop())) { return { @@ -81,14 +86,15 @@ class DGitProvider extends Plugin { } } - async parseInput(input) { + async addIsomorphicGitConfig(input) { + const token = await this.call('config' as any, 'getAppParameter', 'settings/gist-access-token') return { corsProxy: 'https://corsproxy.remixproject.org/', http, onAuth: url => { url const auth = { - username: input.token, + username: input.token || token, password: '' } return auth @@ -96,6 +102,33 @@ class DGitProvider extends Plugin { } } + async getCommandUser(input) { + const author = { + name: '', + email: '' + } + if (input && input.name && input.email) { + author.name = input.name + author.email = input.email + } else { + const username = await this.call('config' as any, 'getAppParameter', 'settings/github-user-name') + const email = await this.call('config' as any, 'getAppParameter', 'settings/github-email') + const token = await this.call('config' as any, 'getAppParameter', 'settings/gist-access-token') + if (username && email) { + author.name = username + author.email = email + } else if (token) { + console.log('token', token) + const gitHubUser = await this.getGitHubUser({ token }) + console.log('gitHubUser', gitHubUser) + if (gitHubUser) { + author.name = gitHubUser.user.login + } + } + } + return author + } + async init(input?) { if ((Registry.getInstance().get('platform').api.isDesktop())) { await this.call('isogit', 'init', { @@ -106,7 +139,7 @@ class DGitProvider extends Plugin { } await git.init({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), defaultBranch: (input && input.branch) || 'main' }) this.emit('init') @@ -131,7 +164,7 @@ class DGitProvider extends Plugin { const status = await git.statusMatrix({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) @@ -144,7 +177,7 @@ class DGitProvider extends Plugin { await this.call('isogit', 'add', cmd) } else { await git.add({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) } @@ -158,7 +191,7 @@ class DGitProvider extends Plugin { await this.call('isogit', 'rm', cmd) } else { await git.remove({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) this.emit('rm') @@ -172,7 +205,7 @@ class DGitProvider extends Plugin { await this.call('isogit', 'reset', cmd) } else { await git.resetIndex({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) this.emit('rm') @@ -187,7 +220,7 @@ class DGitProvider extends Plugin { } else { const gitmodules = await this.parseGitmodules() || [] await git.checkout({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) const newgitmodules = await this.parseGitmodules() || [] @@ -197,14 +230,14 @@ class DGitProvider extends Plugin { return newmodule.name === module.name }) }) - + for (const module of toRemove) { - const path = (await this.getGitConfig(module.path)).dir + const path = (await this.addIsomorphicGitConfigFS(module.path)).dir if (await window.remixFileSystem.exists(path)) { const stat = await window.remixFileSystem.stat(path) try { if (stat.isDirectory()) { - await window.remixFileSystem.unlink((await this.getGitConfig(module.path)).dir) + await window.remixFileSystem.unlink((await this.addIsomorphicGitConfigFS(module.path)).dir) } } catch (e) { // do nothing @@ -234,7 +267,7 @@ class DGitProvider extends Plugin { const status = await git.log({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd, depth: 10 }) @@ -244,7 +277,7 @@ class DGitProvider extends Plugin { async getCommitChanges(commitHash1, commitHash2): Promise { //console.log([git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })]) const result: commitChange[] = await git.walk({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), trees: [git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })], map: async function (filepath, [A, B]) { // ignore directories @@ -300,9 +333,9 @@ class DGitProvider extends Plugin { return await this.call('isogit', 'remotes', config) } - let remotes = [] + let remotes: remote[] = [] try { - remotes = await git.listRemotes({ ...config ? config : await this.getGitConfig() }) + remotes = await git.listRemotes({ ...config ? config : await this.addIsomorphicGitConfigFS() }) } catch (e) { // do nothing } @@ -316,7 +349,7 @@ class DGitProvider extends Plugin { status = await this.call('isogit', 'branch', cmd) } else { status = await git.branch({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) } @@ -331,14 +364,12 @@ class DGitProvider extends Plugin { async currentbranch(config) { - - if ((Registry.getInstance().get('platform').api.isDesktop())) { return await this.call('isogit', 'currentbranch') } try { - const defaultConfig = await this.getGitConfig() + const defaultConfig = await this.addIsomorphicGitConfigFS() const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig const name = await git.currentBranch(cmd) console.log('current branch', name) @@ -348,8 +379,7 @@ class DGitProvider extends Plugin { ...defaultConfig, path: `branch.${name}.remote` }) - if (remoteName) - { + if (remoteName) { const remoteUrl = await git.getConfig({ ...defaultConfig, path: `remote.${remoteName}.url` @@ -377,14 +407,14 @@ class DGitProvider extends Plugin { } try { - const defaultConfig = await this.getGitConfig() + const defaultConfig = await this.addIsomorphicGitConfigFS() const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig const remotes = await this.remotes(config) - let branches = [] + let branches: branch[] = [] branches = (await git.listBranches(cmd)).map((branch) => { return { remote: undefined, name: branch } }) for (const remote of remotes) { cmd.remote = remote.remote - const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote.remote, name: branch } }) + const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote, name: branch } }) branches = [...branches, ...remotebranches] } return branches @@ -409,7 +439,7 @@ class DGitProvider extends Plugin { await this.init() try { const sha = await git.commit({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) this.emit('commit') @@ -427,7 +457,7 @@ class DGitProvider extends Plugin { } const filesInStaging = await git.listFiles({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) return filesInStaging @@ -440,7 +470,7 @@ class DGitProvider extends Plugin { } const oid = await git.resolveRef({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) return oid @@ -452,7 +482,7 @@ class DGitProvider extends Plugin { return readBlobResult } const readBlobResult = await git.readBlob({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd }) @@ -481,7 +511,7 @@ class DGitProvider extends Plugin { await this.call('isogit', 'addremote', { url: input.url, remote: input.remote }) return } - await git.addRemote({ ...await this.getGitConfig(), url: input.url, remote: input.remote }) + await git.addRemote({ ...await this.addIsomorphicGitConfigFS(), url: input.url, remote: input.remote }) } async delremote(input) { @@ -489,7 +519,7 @@ class DGitProvider extends Plugin { await this.call('isogit', 'delremote', { remote: input.remote }) return } - await git.deleteRemote({ ...await this.getGitConfig(), remote: input.remote }) + await git.deleteRemote({ ...await this.addIsomorphicGitConfigFS(), remote: input.remote }) } async localStorageUsed() { @@ -510,11 +540,11 @@ class DGitProvider extends Plugin { input } this.call('terminal', 'logHtml', `Cloning ${input.url}... please wait...`) - try{ + try { const result = await this.call('isogit', 'clone', cmd) this.call('fs', 'openWindow', folder) return result - }catch(e){ + } catch (e) { this.call('notification', 'alert', { id: 'dgitAlert', message: 'Unexpected error while cloning the repository: \n' + e.toString(), @@ -530,8 +560,8 @@ class DGitProvider extends Plugin { singleBranch: input.singleBranch, ref: input.branch, depth: input.depth || 10, - ...await this.parseInput(input), - ...await this.getGitConfig() + ...await this.addIsomorphicGitConfig(input), + ...await this.addIsomorphicGitConfigFS() } this.call('terminal', 'logHtml', `Cloning ${input.url}...`) const result = await git.clone(cmd) @@ -545,12 +575,12 @@ class DGitProvider extends Plugin { } } - async parseGitmodules (dir = '') { + async parseGitmodules(dir = '') { try { const gitmodules = await this.call('fileManager', 'readFile', path.join(dir, '.gitmodules')) if (gitmodules) { const lines = gitmodules.split('\n') - let currentModule:any = {} + let currentModule: any = {} const modules = [] for (let line of lines) { line = line.trim() @@ -585,7 +615,7 @@ class DGitProvider extends Plugin { if (gitmodules) { for (const module of gitmodules) { const dir = path.join(currentDir, module.path) - const targetPath = (await this.getGitConfig(dir)).dir + const targetPath = (await this.addIsomorphicGitConfigFS(dir)).dir if (await window.remixFileSystem.exists(targetPath)) { const stat = await window.remixFileSystem.stat(targetPath) try { @@ -600,7 +630,7 @@ class DGitProvider extends Plugin { for (const module of gitmodules) { const dir = path.join(currentDir, module.path) // if url contains git@github.com: convert it - if(module.url && module.url.startsWith('git@github.com:')) { + if (module.url && module.url.startsWith('git@github.com:')) { module.url = module.url.replace('git@github.com:', 'https://github.com/') } try { @@ -608,51 +638,52 @@ class DGitProvider extends Plugin { url: module.url, singleBranch: true, depth: 1, - ...await this.parseInput(input), - ...await this.getGitConfig(dir) + ...await this.addIsomorphicGitConfig(input), + ...await this.addIsomorphicGitConfigFS(dir) } this.call('terminal', 'logHtml', `Cloning submodule ${dir}...`) await git.clone(cmd) this.call('terminal', 'logHtml', `Cloned successfully submodule ${dir}...`) - + const commitHash = await git.resolveRef({ - ...await this.getGitConfig(currentDir), + ...await this.addIsomorphicGitConfigFS(currentDir), ref: 'HEAD' }) const result = await git.walk({ - ...await this.getGitConfig(currentDir), + ...await this.addIsomorphicGitConfigFS(currentDir), trees: [git.TREE({ ref: commitHash })], map: async function (filepath, [A]) { - if(filepath === module.path) { + if (filepath === module.path) { return await A.oid() } } }) - if(result && result.length) { + if (result && result.length) { this.call('terminal', 'logHtml', `Checking out submodule ${dir} to ${result[0]} in directory ${dir}`) await git.fetch({ - ...await this.parseInput(input), - ...await this.getGitConfig(dir), + ...await this.addIsomorphicGitConfig(input), + ...await this.addIsomorphicGitConfigFS(dir), singleBranch: true, ref: result[0] }) await git.checkout({ - ...await this.getGitConfig(dir), + ...await this.addIsomorphicGitConfigFS(dir), ref: result[0] }) - + const log = await git.log({ - ...await this.getGitConfig(dir), + ...await this.addIsomorphicGitConfigFS(dir), }) - if(log[0].oid !== result[0]) { + if (log[0].oid !== result[0]) { this.call('terminal', 'log', { type: 'error', value: `Could not checkout submodule to ${result[0]}` - })} else { - this.call('terminal', 'logHtml',`Checked out submodule ${dir} to ${result[0]}`) + }) + } else { + this.call('terminal', 'logHtml', `Checked out submodule ${dir} to ${result[0]}`) } } @@ -682,10 +713,7 @@ class DGitProvider extends Plugin { ref: input.ref, remoteRef: input.remoteRef, remote: input.remote, - author: { - name: input.name, - email: input.email - }, + author: await this.getCommandUser(input), input, } if ((Registry.getInstance().get('platform').api.isDesktop())) { @@ -694,12 +722,14 @@ class DGitProvider extends Plugin { const cmd2 = { ...cmd, - ...await this.parseInput(input), + ...await this.addIsomorphicGitConfig(input), } - return await git.push({ - ...await this.getGitConfig(), + const result = await git.push({ + ...await this.addIsomorphicGitConfigFS(), ...cmd2 }) + console.log('push result', result) + return result } } @@ -708,10 +738,7 @@ class DGitProvider extends Plugin { const cmd = { ref: input.ref, remoteRef: input.remoteRef, - author: { - name: input.name, - email: input.email - }, + author: await this.getCommandUser(input), remote: input.remote, input, } @@ -722,13 +749,14 @@ class DGitProvider extends Plugin { else { const cmd2 = { ...cmd, - ...await this.parseInput(input), + ...await this.addIsomorphicGitConfig(input), } result = await git.pull({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), ...cmd2 }) } + console.log('pull result', result) setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) @@ -739,10 +767,7 @@ class DGitProvider extends Plugin { const cmd = { ref: input.ref, remoteRef: input.remoteRef, - author: { - name: input.name, - email: input.email - }, + author: await this.getCommandUser(input), remote: input.remote, input } @@ -752,13 +777,19 @@ class DGitProvider extends Plugin { } else { const cmd2 = { ...cmd, - ...await this.parseInput(input), + ...await this.addIsomorphicGitConfig(input), } result = await git.fetch({ - ...await this.getGitConfig(), + ...await this.addIsomorphicGitConfigFS(), + ...cmd2 + }) + console.log('fetch result', result) + console.log({ + ...await this.addIsomorphicGitConfigFS(), ...cmd2 }) } + setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) @@ -926,7 +957,7 @@ class DGitProvider extends Plugin { async remotebranches(input: { owner: string, repo: string, token: string }) { console.log(input) - + const octokit = new Octokit({ auth: input.token }) @@ -973,13 +1004,13 @@ class DGitProvider extends Plugin { auth: input.token }) - + const data = await octokit.request('GET /repos/{owner}/{repo}/commits', { owner: input.owner, repo: input.repo, sha: input.branch, - per_page: input.length + per_page: 100 }) @@ -991,15 +1022,15 @@ class DGitProvider extends Plugin { const octokit = new Octokit({ auth: input.token }) - + console.log('octokit', input.token) const data = await octokit.request('GET /user/repos', { - per_page: 100, - page: 1 + per_page: 200, + page: 2 }) - console.log(data.data) + console.log(data.data) return data.data } diff --git a/libs/remix-ui/git/src/components/navigation/branchedetails.tsx b/libs/remix-ui/git/src/components/navigation/branchedetails.tsx index 1b0f39c0c0..7a5537c577 100644 --- a/libs/remix-ui/git/src/components/navigation/branchedetails.tsx +++ b/libs/remix-ui/git/src/components/navigation/branchedetails.tsx @@ -1,4 +1,4 @@ -import { faCaretUp, faCaretDown, faCaretRight, faArrowUp, faArrowDown, faArrowRotateRight, faArrowsUpDown, faGlobe, faCheckCircle, faToggleOff, faToggleOn } from "@fortawesome/free-solid-svg-icons"; +import { faCaretUp, faCaretDown, faCaretRight, faArrowUp, faArrowDown, faArrowRotateRight, faArrowsUpDown, faGlobe, faCheckCircle, faToggleOff, faToggleOn, faSync } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React, { useContext, useEffect } from "react"; import { branch } from "../../types"; @@ -44,8 +44,10 @@ export const BrancheDetailsNavigation = (props: BrancheDetailsNavigationProps) = : checkout(branch)}> } - checkout(branch)}> - {branch.remote?.url && openRemote()}>} + + {branch.remote?.url && <> + checkout(branch)}> + openRemote()}>} ); diff --git a/libs/remix-ui/git/src/components/panels/commands/fetch.tsx b/libs/remix-ui/git/src/components/panels/commands/fetch.tsx index f73e7a04fe..88de01c27f 100644 --- a/libs/remix-ui/git/src/components/panels/commands/fetch.tsx +++ b/libs/remix-ui/git/src/components/panels/commands/fetch.tsx @@ -1,10 +1,11 @@ import React, { useEffect, useState } from "react"; +import { gitActionsContext } from "../../../state/context"; export const Fetch = () => { - + const actions = React.useContext(gitActionsContext) const fetch = async () => { - //gitservice.fetch(currentRemote, '', '') + await actions.fetch() } diff --git a/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx b/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx index ca6ed1c8ae..84f3cd041d 100644 --- a/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx +++ b/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx @@ -50,11 +50,11 @@ export const PushPull = () => { } const push = async () => { - //gitservice.push(currentRemote, branch || '', remoteBranch, force) + actions.push() } const pull = async () => { - //gitservice.pull(currentRemote, branch || '', remoteBranch) + actions.pull() } diff --git a/libs/remix-ui/git/src/components/panels/github.tsx b/libs/remix-ui/git/src/components/panels/github.tsx index 57ce6938b6..2eb386c464 100644 --- a/libs/remix-ui/git/src/components/panels/github.tsx +++ b/libs/remix-ui/git/src/components/panels/github.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from "react"; import { gitActionsContext, pluginActionsContext } from "../../state/context"; -import { gitPluginContext } from "../gitui"; +import { gitPluginContext, loaderContext } from "../gitui"; import axios from "axios"; import { CopyToClipboard } from "@remix-ui/clipboard"; import { Card } from "react-bootstrap"; @@ -9,80 +9,20 @@ import { Card } from "react-bootstrap"; export const GitHubAuth = () => { const context = React.useContext(gitPluginContext) const actions = React.useContext(gitActionsContext) + const loader = React.useContext(loaderContext) const pluginActions = React.useContext(pluginActionsContext) const [gitHubResponse, setGitHubResponse] = React.useState(null) const [authorized, setAuthorized] = React.useState(false) - - const client_id = 'Iv1.12fc02c69c512462'// 'e90cf20e6cafa2fd71ea' - const getDeviceCodeFromGitHub = async () => { - - setAuthorized(false) - // Send a POST request - const response = await axios({ - method: 'post', - url: 'http://0.0.0.0:3000/github.com/login/device/code', - data: { - client_id // : 'Iv1.12fc02c69c512462' - }, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - }); - - // convert response to json - const githubrespone = await response.data; - console.log('json', githubrespone) - - setGitHubResponse(githubrespone) - } - - const connectApp = async () => { - // poll https://github.com/login/oauth/access_token - const accestokenresponse = await axios({ - method: 'post', - url: 'http://0.0.0.0:3000/github.com/login/oauth/access_token', - data: { - client_id,// : 'Iv1.12fc02c69c512462', - device_code: gitHubResponse.device_code, - grant_type: 'urn:ietf:params:oauth:grant-type:device_code', - }, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - }); - - // convert response to json - const response = await accestokenresponse.data; - console.log('json2', response) - - if (response.error) { - - } - - if (response.access_token) { - setAuthorized(true) - await pluginActions.saveToken(response.access_token) - await actions.getGitHubUser() - } - - } - - const disconnect = async () => { - setAuthorized(false) - setGitHubResponse(null) - } + useEffect(() => { + checkConnection() + }, [context.gitHubAccessToken, loader.plugin]) const checkConnection = async () => { - //await actions.getGitHubUser() + console.log('checkConnection', context.gitHubAccessToken) + await actions.getGitHubUser() } - useEffect(() => { - - },[]) - useEffect(() => { console.log('context.rateLimit', context.rateLimit) }, [context.rateLimit]) @@ -91,37 +31,8 @@ export const GitHubAuth = () => { return ( <> {(context.gitHubUser && context.gitHubUser.login) ? null : - - } - {gitHubResponse && !authorized && -
- - Step 1: Copy this code: -
- -
- -
-
-

- Step 2: Authorize the app here -

{gitHubResponse.verification_uri} -


- Step 3: When you are done, click on the button below: - -
- } - { - (context.gitHubUser && context.gitHubUser.login) ? -
- -
: null +
  • + Not connected to GitHub. Add a valid token.
  • } { (context.gitHubUser && context.gitHubUser.login) ? diff --git a/libs/remix-ui/git/src/components/panels/githubcredentials.tsx b/libs/remix-ui/git/src/components/panels/githubcredentials.tsx index de7bb09d94..86216abbac 100644 --- a/libs/remix-ui/git/src/components/panels/githubcredentials.tsx +++ b/libs/remix-ui/git/src/components/panels/githubcredentials.tsx @@ -1,7 +1,7 @@ import { checkout, clone, ReadCommitResult } from "isomorphic-git"; -import React from "react"; -import { gitActionsContext } from "../../state/context"; -import { gitPluginContext } from "../gitui"; +import React, { useEffect } from "react"; +import { gitActionsContext, pluginActionsContext } from "../../state/context"; +import { gitPluginContext, loaderContext } from "../gitui"; import { CustomTooltip } from "@remix-ui/helper"; import { useIntl, FormattedMessage } from "react-intl"; @@ -11,46 +11,75 @@ import { FormControl, InputGroup } from "react-bootstrap"; export const GitHubCredentials = () => { const context = React.useContext(gitPluginContext) + const pluginactions = React.useContext(pluginActionsContext) + const loader = React.useContext(loaderContext) const [githubToken, setGithubToken] = React.useState('') const [githubUsername, setGithubUsername] = React.useState('') const [githubEmail, setGithubEmail] = React.useState('') const intl = useIntl() - const gitAccessTokenLink = 'https://github.com/settings/tokens/new?scopes=gist,repo&description=Remix%20IDE%20Token' + useEffect(() => { + refresh() + }, [loader.plugin, context.gitHubAccessToken]) function handleChangeTokenState(e: string): void { - throw new Error("Function not implemented."); + setGithubToken(e) } function handleChangeUserNameState(e: string): void { - throw new Error("Function not implemented."); + setGithubUsername(e) } function handleChangeEmailState(e: string): void { - throw new Error("Function not implemented."); + setGithubEmail(e) } - function saveGithubToken(): void { - throw new Error("Function not implemented."); + async function saveGithubToken() { + await pluginactions.saveGitHubCredentials({ + username: githubUsername, + email: githubEmail, + token: githubToken + }) + } + + async function refresh() { + const credentials = await pluginactions.getGitHubCredentials() + if(!credentials) return + console.log('credentials', credentials) + setGithubToken(credentials.token || '') + setGithubUsername(credentials.username || '') + setGithubEmail(credentials.email || '') } function removeToken(): void { - throw new Error("Function not implemented."); + setGithubToken('') + setGithubUsername('') + setGithubEmail('') + pluginactions.saveGitHubCredentials({ + username: '', + email: '', + token: '' + }) } return ( <> -
    -
    - + handleChangeTokenState(e.target.value)} />
    - +
    handleChangeUserNameState(e.target.value)} value={githubUsername} className="form-control mb-1" placeholder="GitHub username" type="text" id="githubUsername" /> handleChangeEmailState(e.target.value)} value={githubEmail} className="form-control mb-1" placeholder="GitHub email" type="text" id="githubEmail" /> +
    + + +

    ); diff --git a/libs/remix-ui/git/src/components/panels/remotesimport.tsx b/libs/remix-ui/git/src/components/panels/remotesimport.tsx index c39552b733..e0840e57fb 100644 --- a/libs/remix-ui/git/src/components/panels/remotesimport.tsx +++ b/libs/remix-ui/git/src/components/panels/remotesimport.tsx @@ -5,6 +5,7 @@ import { repository } from "../../types"; import { gitPluginContext } from "../gitui"; import Select from 'react-select' import { selectStyles, selectTheme } from "../../types/styles"; +import { TokenWarning } from "./tokenWarning"; export const RemotesImport = () => { @@ -18,17 +19,20 @@ export const RemotesImport = () => { useEffect(() => { console.log('context', context.repositories) - // map context.repositories to options - const options = context.repositories && context.repositories.length > 0 && context.repositories.map(repo => { - return { value: repo.id, label: repo.full_name } - }) + if (context.repositories && context.repositories.length > 0) { + // map context.repositories to options + const options = context.repositories && context.repositories.length > 0 && context.repositories.map(repo => { + return { value: repo.id, label: repo.full_name } + }) + setRepoOptions(options) + } else { + setRepoOptions(null) + setShow(false) + } setLoading(false) - setRepoOptions(options) }, [context.repositories]) - - const fetchRepositories = async () => { try { setShow(true) @@ -67,6 +71,7 @@ export const RemotesImport = () => { return ( <> + diff --git a/libs/remix-ui/git/src/components/panels/repositories.tsx b/libs/remix-ui/git/src/components/panels/repositories.tsx index f06a67100f..47af4e86e1 100644 --- a/libs/remix-ui/git/src/components/panels/repositories.tsx +++ b/libs/remix-ui/git/src/components/panels/repositories.tsx @@ -5,6 +5,7 @@ import { repository } from "../../types"; import { gitPluginContext } from "../gitui"; import Select from 'react-select' import { selectStyles, selectTheme } from "../../types/styles"; +import { TokenWarning } from "./tokenWarning"; interface RepositoriesProps { cloneDepth?: number @@ -24,12 +25,17 @@ export const Repositories = (props: RepositoriesProps) => { useEffect(() => { console.log('context', context.repositories) - // map context.repositories to options - const options = context.repositories && context.repositories.length > 0 && context.repositories.map(repo => { - return { value: repo.id, label: repo.full_name } - }) + if (context.repositories && context.repositories.length > 0) { + // map context.repositories to options + const options = context.repositories && context.repositories.length > 0 && context.repositories.map(repo => { + return { value: repo.id, label: repo.full_name } + }) + setRepoOptions(options) + } else { + setRepoOptions(null) + setShow(false) + } setLoading(false) - setRepoOptions(options) }, [context.repositories]) @@ -93,6 +99,7 @@ export const Repositories = (props: RepositoriesProps) => { return ( <> + diff --git a/libs/remix-ui/git/src/components/panels/tokenWarning.tsx b/libs/remix-ui/git/src/components/panels/tokenWarning.tsx new file mode 100644 index 0000000000..4188c07c93 --- /dev/null +++ b/libs/remix-ui/git/src/components/panels/tokenWarning.tsx @@ -0,0 +1,12 @@ +import { gitPluginContext } from "../gitui" +import React, { useEffect, useState } from "react"; +export const TokenWarning = () => { + const context = React.useContext(gitPluginContext) + return (<> + {(context.gitHubUser && context.gitHubUser.login) ? null : +
  • + To use add a GitHub token to the settings.
  • + } + + ) +} \ No newline at end of file diff --git a/libs/remix-ui/git/src/lib/gitactions.ts b/libs/remix-ui/git/src/lib/gitactions.ts index d9bc95baa8..5e89b1b92d 100644 --- a/libs/remix-ui/git/src/lib/gitactions.ts +++ b/libs/remix-ui/git/src/lib/gitactions.ts @@ -2,13 +2,17 @@ import { ViewPlugin } from "@remixproject/engine-web"; import { ReadBlobResult, ReadCommitResult } from "isomorphic-git"; import React from "react"; import { fileStatus, fileStatusMerge, setBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRateLimit, setRemoteBranches, setRemotes, setRepos, setUpstream } from "../state/gitpayload"; -import { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType } from '../types'; +import { GitHubUser, RateLimit, branch, commitChange, gitActionDispatch, statusMatrixType, gitState } from '../types'; import { removeSlash } from "../utils"; import { disableCallBacks, enableCallBacks } from "./listeners"; import { AlertModal, ModalTypes } from "@remix-ui/app"; import { gitActionsContext } from "../state/context"; import { gitPluginContext } from "../components/gitui"; import { setFileDecorators } from "./pluginActions"; +import { IDgitSystem, IRemixApi, RemixApi } from "@remixproject/plugin-api"; +import { Plugin } from "@remixproject/engine"; +import { AnyMxRecord } from "dns"; +import { StatusEvents } from "@remixproject/plugin-utils"; export const fileStatuses = [ ["new,untracked", 0, 2, 0], // new, untracked @@ -32,13 +36,48 @@ const statusmatrix: statusMatrixType[] = fileStatuses.map((x: any) => { status: x, }; }); +/* +interface customDGitSystem extends IDgitSystem{ + events: StatusEvents, + methods: { + getCommitChanges(oid1: string, oid2: string): Promise + getBranchCommits(branch: branch): Promise + fetchBranch(branch: branch): Promise + remotebranches(owner: string, repo: string): Promise + remoteCommits(url: string, branch: string, length: number): Promise + repositories(token: string): Promise + clone(url: string, branch: string, depth: number, singleBranch: boolean): Promise + getGitHubUser(token: string): Promise<{ user: GitHubUser, ratelimit: RateLimit }> + saveGitHubCredentials(credentials: { username: string, email: string, token: string }): Promise + getGitHubCredentials(): Promise<{ username: string, email: string, token: string }> + currentbranch(): Promise + } +} + +interface notificationSystem { + methods: { + toast(message: string): void + alert(message: { + title: string, + type: string + }): void + modal(modal: AlertModal): void + }, + events: StatusEvents +} -let plugin: ViewPlugin, dispatch: React.Dispatch +interface customApi extends IRemixApi { + dGitProvider: customDGitSystem + notification: notificationSystem +} +*/ +let plugin: Plugin, dispatch: React.Dispatch -export const setPlugin = (p: ViewPlugin, dispatcher: React.Dispatch) => { +export const setPlugin = (p: Plugin, dispatcher: React.Dispatch) => { plugin = p dispatch = dispatcher + console.log('setPlugin') } export const getBranches = async () => { @@ -101,7 +140,6 @@ export const gitlog = async () => { } dispatch(setCommits(commits)) await showCurrentBranch() - await getGitHubUser() } export const showCurrentBranch = async () => { @@ -133,7 +171,13 @@ export const currentBranch = async () => { // eslint-disable-next-line no-useless-catch try { const branch: branch = - (await plugin.call("dGitProvider", "currentbranch")) || ""; + (await plugin.call("dGitProvider", "currentbranch")) || { + name: "", + remote: { + remote: "", + url: "", + }, + }; return branch; } catch (e) { throw e; @@ -329,15 +373,36 @@ export const clone = async (url: string, branch: string, depth: number, singleBr dispatch(setLoading(false)) } +export const fetch = async(remote?: string, ref?: string, remoteRef?: string) => { + try { + await plugin.call('dGitProvider' as any, 'fetch', { remote, ref, remoteRef }) + await gitlog() + await getBranches() + } catch (e: any) { + await parseError(e) + } +} + +export const pull = async(remote?: string, ref?: string, remoteRef?: string) => { + try { + await plugin.call('dGitProvider' as any, 'pull', { remote, ref, remoteRef }) + await gitlog() + } catch (e: any) { + await parseError(e) + } +} + +export const push = async(remote?: string, ref?: string, remoteRef?: string, force?: boolean) => { + try { + await plugin.call('dGitProvider' as any, 'push', { remote, ref, remoteRef, force }) + } catch (e: any) { + await parseError(e) + } +} + const tokenWarning = async () => { const token = await plugin.call('config' as any, 'getAppParameter', 'settings/gist-access-token') if (!token) { - const modalContent: AlertModal = { - message: 'Please set a token first in the GitHub settings of REMIX', - title: 'No GitHub token set', - id: 'no-token-set', - } - //plugin.call('notification', 'alert', modalContent) return false; } else { return token; @@ -384,15 +449,18 @@ const parseError = async (e: any) => { } } - - - export const repositories = async () => { try { const token = await tokenWarning(); if (token) { const repos = await plugin.call('dGitProvider' as any, 'repositories', { token }); dispatch(setRepos(repos)) + } else { + plugin.call('notification', 'alert', { + title: 'Error getting repositories', + message: `Please check your GitHub token in the GitHub settings. It needs to have access to the repositories.` + }) + dispatch(setRepos([])) } } catch (e) { console.log(e) @@ -400,6 +468,7 @@ export const repositories = async () => { title: 'Error getting repositories', message: `${e.message}: Please check your GitHub token in the GitHub settings.` }) + dispatch(setRepos([])) } } @@ -409,6 +478,12 @@ export const remoteBranches = async (owner: string, repo: string) => { if (token) { const branches = await plugin.call('dGitProvider' as any, 'remotebranches', { token, owner, repo }); dispatch(setRemoteBranches(branches)) + } else { + plugin.call('notification', 'alert', { + title: 'Error getting branches', + message: `Please check your GitHub token in the GitHub settings. It needs to have access to the branches.` + }) + dispatch(setRemoteBranches([])) } } catch (e) { console.log(e) @@ -416,27 +491,33 @@ export const remoteBranches = async (owner: string, repo: string) => { title: 'Error', message: e.message }) + dispatch(setRemoteBranches([])) } } export const remoteCommits = async (url: string, branch: string, length: number) => { const urlParts = url.split("/"); - + console.log(urlParts, 'urlParts') // check if it's github - if(!urlParts[urlParts.length - 3].includes('github')) { + if (!urlParts[urlParts.length - 3].includes('github')) { return } - + const owner = urlParts[urlParts.length - 2]; const repo = urlParts[urlParts.length - 1].split(".")[0]; - + try { const token = await tokenWarning(); if (token) { console.log(token, owner, repo, branch, length) 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', + message: `Please check your GitHub token in the GitHub settings. It needs to have access to the commits.` + }) } } catch (e) { console.log(e) @@ -447,7 +528,34 @@ export const remoteCommits = async (url: string, branch: string, length: number) } } +export const saveGitHubCredentials = async (credentials: { username: string, email: string, token: string }) => { + try { + await plugin.call('config' as any, 'setAppParameter', 'settings/github-user-name', credentials.username) + await plugin.call('config' as any, 'setAppParameter', 'settings/github-email', credentials.email) + await plugin.call('config' as any, 'setAppParameter', 'settings/gist-access-token', credentials.token) + } catch (e) { + console.log(e) + } +} + +export const getGitHubCredentials = async () => { + if (!plugin) return + try { + const username = await plugin.call('config' as any, 'getAppParameter', 'settings/github-user-name') + const email = await plugin.call('config' as any, 'getAppParameter', 'settings/github-email') + const token = await plugin.call('config' as any, 'getAppParameter', 'settings/gist-access-token') + return { + username, + email, + token + } + } catch (e) { + console.log(e) + } +} + export const getGitHubUser = async () => { + if (!plugin) return try { const token = await tokenWarning(); if (token) { @@ -460,6 +568,8 @@ export const getGitHubUser = async () => { dispatch(setGitHubUser(data.user)) dispatch(setRateLimit(data.ratelimit)) + } else { + dispatch(setGitHubUser(null)) } } catch (e) { console.log(e) @@ -611,6 +721,7 @@ export const getBranchCommits = async (branch: branch) => { }) console.log(commits) dispatch(setBranchCommits({ branch, commits })) + await fetchBranch(branch) return commits } catch (e) { console.log(e) diff --git a/libs/remix-ui/git/src/lib/listeners.ts b/libs/remix-ui/git/src/lib/listeners.ts index 255e32d66a..d1cf8457f8 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 } from "../state/gitpayload"; +import { setCanUseApp, setLoading, setRepoName, setGItHubToken } from "../state/gitpayload"; import { gitActionDispatch } from "../types"; import { diffFiles, getBranches, getFileStatusMatrix, getGitHubUser, getRemotes, gitlog, setPlugin } from "./gitactions"; @@ -102,7 +102,7 @@ export const getGitConfig = async () => { const email = await plugin.call('settings', 'get', 'settings/github-email') const token = await plugin.call('settings', 'get', 'settings/gist-access-token') const config = { username, email, token } - //dispatch(setGitConfig(config)) + gitDispatch(setGItHubToken(config.token)) return config } diff --git a/libs/remix-ui/git/src/state/context.tsx b/libs/remix-ui/git/src/state/context.tsx index 38b5c6a094..373c29bbc9 100644 --- a/libs/remix-ui/git/src/state/context.tsx +++ b/libs/remix-ui/git/src/state/context.tsx @@ -8,9 +8,9 @@ export interface gitActions { rm(path: string): Promise commit(message: string): Promise addall(): Promise - //push(): Promise - //pull(): Promise - //fetch(): Promise + push(remote?: string, ref?: string, remoteRef?: string, force?: boolean): Promise + pull(remote?: string, ref?: string, remoteRef?: string): Promise + fetch(remote?: string, ref?: string, remoteRef?: string): Promise repositories(): Promise checkoutfile(file: string): Promise checkout(cmd: any): Promise @@ -34,6 +34,16 @@ export interface pluginActions { openFile(path: string): Promise openDiff(change: commitChange): Promise saveToken(token: string): Promise + saveGitHubCredentials({ + username, + email, + token + }): Promise + getGitHubCredentials(): Promise<{ + username: string + email: string + token: string + }> } export const pluginActionsContext = React.createContext(null) \ No newline at end of file diff --git a/libs/remix-ui/git/src/state/gitpayload.ts b/libs/remix-ui/git/src/state/gitpayload.ts index c1281fcd2f..cb1989c7c0 100644 --- a/libs/remix-ui/git/src/state/gitpayload.ts +++ b/libs/remix-ui/git/src/state/gitpayload.ts @@ -128,3 +128,10 @@ export const setBranchCommits =({branch, commits}) => { payload: { branch, commits } } } + +export const setGItHubToken = (token: string) => { + return { + type: 'SET_GITHUB_ACCESS_TOKEN', + payload: token + } +} diff --git a/libs/remix-ui/git/src/types/index.ts b/libs/remix-ui/git/src/types/index.ts index 8994199692..f4e1516143 100644 --- a/libs/remix-ui/git/src/types/index.ts +++ b/libs/remix-ui/git/src/types/index.ts @@ -39,6 +39,7 @@ export type loaderState = { remotes: boolean commits: boolean sourcecontrol: boolean + plugin: boolean } export type commitChangeTypes = { @@ -125,7 +126,8 @@ export const defaultLoaderState: loaderState = { branches: false, commits: false, sourcecontrol: false, - remotes: false + remotes: false, + plugin: false } export type fileStatusResult = { @@ -211,4 +213,9 @@ export interface setBranchCommitsAction { } } -export type gitActionDispatch = setUpstreamAction | setBranchCommitsAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction \ No newline at end of file +export interface setTokenAction { + type: string, + payload: string +} + +export type gitActionDispatch = setTokenAction | setUpstreamAction | setBranchCommitsAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction \ No newline at end of file