add device flow

git4refactor
filip mertens 7 months ago
parent 777f635f75
commit c4dce2d804
  1. 35
      apps/remix-ide/src/app/files/dgitProvider.ts
  2. 154
      libs/remix-ui/git/src/components/github/devicecode.tsx
  3. 88
      libs/remix-ui/git/src/components/github/repositoryselect.tsx
  4. 4
      libs/remix-ui/git/src/components/gitui.tsx
  5. 21
      libs/remix-ui/git/src/components/panels/repositories.tsx

@ -273,29 +273,29 @@ class DGitProvider extends Plugin {
return status
}
async compareBranches({branch, remote}:{branch: branch, remote: remote}) {
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,
@ -1028,7 +1028,7 @@ class DGitProvider extends Plugin {
}
}
async remotecommits(input: { owner: string, repo: string, token: string, branch: string, length: number,page: number }): Promise<pagedCommits[]> {
async remotecommits(input: { owner: string, repo: string, token: string, branch: string, length: number, page: number }): Promise<pagedCommits[]> {
const octokit = new Octokit({
auth: input.token
})
@ -1091,20 +1091,19 @@ class DGitProvider extends Plugin {
}
async repositories(input: { token: string }) {
console.log(input)
const octokit = new Octokit({
auth: input.token
})
console.log('octokit', input.token)
// Set your access token
const accessToken = input.token;
const data = await octokit.request('GET /user/repos', {
per_page: 200,
page: 2
})
// Set headers for the request
const headers = {
'Authorization': `Bearer ${accessToken}`, // Include your GitHub access token
'Accept': 'application/vnd.github.v3+json', // GitHub API v3 media type
};
console.log(data.data)
return data.data
// Make the GET request with Axios
const response = await axios.get('https://api.github.com/user/repos?visibility=private,public', { headers })
return response.data
}
}

@ -1,30 +1,144 @@
import React, { useState } from 'react';
import React, { useEffect } from "react";
import { gitActionsContext, pluginActionsContext } from "../../state/context";
import { gitPluginContext } from "../gitui";
import axios from "axios";
import { CopyToClipboard } from "@remix-ui/clipboard";
import { Card } from "react-bootstrap";
const GetDeviceCode = () => {
const [userCode, setUserCode] = useState(null);
const requestDeviceCode = async () => {
const response = await fetch('http://localhost:3000/github.com/login/device/code', {
method: 'POST',
export const GetDeviceCode = () => {
const context = React.useContext(gitPluginContext)
const actions = React.useContext(gitActionsContext)
const pluginActions = React.useContext(pluginActionsContext)
const [gitHubResponse, setGitHubResponse] = React.useState<any>(null)
const [authorized, setAuthorized] = React.useState<boolean>(false)
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: 'dccbc48453f7afa34fad',
scope: 'repo'
},
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
});
// 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: 'dccbc48453f7afa34fad',
scope: 'repo', // or another appropriate scope
}),
device_code: gitHubResponse.device_code,
grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
},
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
});
const data = await response.json();
setUserCode(data.user_code); // Store user code to show to the user
};
// 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)
}
const checkConnection = async () => {
//await actions.getGitHubUser()
}
useEffect(() => {
},[])
useEffect(() => {
console.log('context.rateLimit', context.rateLimit)
}, [context.rateLimit])
return (
<div>
<button onClick={requestDeviceCode}>Get Device Code</button>
{userCode && <div>User Code: {userCode}</div>}
</div>
);
};
export default GetDeviceCode;
<>
{(context.gitHubUser && context.gitHubUser.login) ? null :
<button className='btn btn-primary mt-1 w-100' onClick={async () => {
getDeviceCodeFromGitHub();
}}>Login in with github</button>
}
{gitHubResponse && !authorized &&
<div className="pt-2">
Step 1: Copy this code:
<div className="input-group text-secondary mb-0 h6">
<input disabled type="text" className="form-control" value={gitHubResponse.user_code} />
<div className="input-group-append">
<CopyToClipboard content={gitHubResponse.user_code} data-id='copyToClipboardCopyIcon' className='far fa-copy ml-1 p-2 mt-1' direction={"top"} />
</div>
</div>
<br></br>
Step 2: Authorize the app here
<br></br><a target="_blank" href={gitHubResponse.verification_uri}>{gitHubResponse.verification_uri}</a>
<br /><br></br>
Step 3: When you are done, click on the button below:
<button className='btn btn-primary mt-1 w-100' onClick={async () => {
connectApp()
}}>Connect</button>
</div>
}
{
(context.gitHubUser && context.gitHubUser.login) ?
<div className="pt-2">
<button className='btn btn-primary mt-1 w-100' onClick={async () => {
disconnect()
}}>Disconnect</button>
</div>: null
}
{
(context.gitHubUser && context.gitHubUser.login) ?
<div className="pt-2">
<Card>
<Card.Body>
<Card.Title>Connected as {context.gitHubUser.login}</Card.Title>
<Card.Text>
<img src={context.gitHubUser.avatar_url} className="w-100" />
<a target="_blank" href={context.gitHubUser.html_url}>{context.gitHubUser.html_url}</a>
</Card.Text>
</Card.Body>
</Card>
</div>: null
}
</>)
}

@ -0,0 +1,88 @@
import { clearInstances } from 'libs/remix-ui/run-tab/src/lib/actions/actions';
import React, { useState, useCallback, useEffect } from 'react';
import { Button } from 'react-bootstrap';
import { OptionsOrGroups, GroupBase } from 'react-select';
import Select from 'react-select/async';
import { gitActionsContext } from '../../state/context';
import { selectStyles, selectTheme } from '../../types/styles';
import { gitPluginContext } from '../gitui';
import { TokenWarning } from '../panels/tokenWarning';
const RepositorySelect = () => {
const [page, setPage] = useState(1);
const [repoOtions, setRepoOptions] = useState<any>([]);
const context = React.useContext(gitPluginContext)
const actions = React.useContext(gitActionsContext)
const [loading, setLoading] = useState(false)
const [show, setShow] = useState(false)
useEffect(() => {
console.log('context', context.repositories)
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 }
})
console.log('options', options)
setRepoOptions(options)
} else {
setRepoOptions(null)
setShow(false)
}
setLoading(false)
}, [context.repositories])
useEffect(() => {
console.log('OTIONS', repoOtions)
},[repoOtions])
const selectRepo = async (value: number | string) => {
// find repo
console.log('setRepo', value, context.repositories)
const repo = context.repositories.find(repo => {
return repo.id.toString() === value.toString()
})
console.log('repo', repo)
if (repo) {
//setBranchOptions([])
//setBranch({ name: "" })
//setRepo(repo)
await actions.remoteBranches(repo.owner.login, repo.name)
}
}
const fetchRepositories = async () => {
try {
setShow(true)
setLoading(true)
//setRepoOptions([])
//setBranchOptions([])
console.log(await actions.repositories())
} catch (e) {
// do nothing
}
};
return (
<><TokenWarning /><Button onClick={fetchRepositories} className="w-100 mt-1">
<i className="fab fa-github mr-1"></i>Fetch Repositories from GitHub
</Button>
{
show ?
<Select
options={repoOtions}
className="mt-1"
onChange={(e: any) => e && selectRepo(e.value)}
theme={selectTheme}
styles={selectStyles}
isClearable={true}
placeholder="Type to search for a repository..."
isLoading={loading}
/> : null
}</>
);
};
export default RepositorySelect;

@ -29,7 +29,7 @@ import { GitHubCredentials } from './panels/githubcredentials'
import { loaderReducer } from '../state/loaderReducer'
import { ApolloClient, ApolloProvider, NormalizedCacheObject } from '@apollo/client'
import { client, getApolloLink } from '../state/apolloClient'
import GetDeviceCode from './github/devicecode'
import { GetDeviceCode } from './github/devicecode'
export const gitPluginContext = React.createContext<gitState>(defaultGitState)
export const loaderContext = React.createContext<loaderState>(defaultLoaderState)
@ -180,8 +180,6 @@ export const GitUI = (props: IGitUi) => {
<GitHubNavigation eventKey="7" activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="7">
<>
<GitHubAuth></GitHubAuth>
<GitHubCredentials></GitHubCredentials>
<GetDeviceCode></GetDeviceCode>
</>
</Accordion.Collapse>

@ -3,9 +3,10 @@ import { Alert, Button } from "react-bootstrap";
import { gitActionsContext } from "../../state/context";
import { repository } from "../../types";
import { gitPluginContext } from "../gitui";
import Select from 'react-select'
import AsyncSelect from 'react-select'
import { selectStyles, selectTheme } from "../../types/styles";
import { TokenWarning } from "./tokenWarning";
import RepositorySelect from "../github/repositoryselect";
interface RepositoriesProps {
cloneDepth?: number
@ -99,24 +100,10 @@ export const Repositories = (props: RepositoriesProps) => {
return (
<>
<TokenWarning/>
<Button onClick={fetchRepositories} className="w-100 mt-1">
<i className="fab fa-github mr-1"></i>Fetch Repositories from GitHub
</Button>
{show?
<Select
options={repoOtions}
className="mt-1"
onChange={(e: any) => e && selectRepo(e.value)}
theme={selectTheme}
styles={selectStyles}
isClearable={true}
placeholder="Type to search for a repository..."
isLoading={loading}
/>:null}
<RepositorySelect />
{branchOptions && branchOptions.length ?
<Select
<AsyncSelect
options={branchOptions}
className="mt-1"
onChange={(e: any) => e && selectRemoteBranch(e.value)}

Loading…
Cancel
Save