Merge pull request #4979 from ethereum/github_fe

Show log in github from FE
pull/5146/head
bunsenstraat 3 months ago committed by GitHub
commit 74057bd75f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 45
      apps/remix-ide-e2e/src/tests/dgit_github.test.ts
  2. 3
      apps/remix-ide-e2e/src/tests/dgit_local.test.ts
  3. 5
      apps/remix-ide-e2e/src/tests/workspace_git.test.ts
  4. 13
      apps/remix-ide/src/app/files/dgitProvider.ts
  5. 2
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  6. 3
      apps/remix-ide/src/app/tabs/locales/en/git.json
  7. 1
      libs/remix-ui/app/src/index.ts
  8. 25
      libs/remix-ui/app/src/lib/remix-app/actions/app.ts
  9. 5
      libs/remix-ui/app/src/lib/remix-app/context/context.tsx
  10. 5
      libs/remix-ui/app/src/lib/remix-app/interface/index.ts
  11. 13
      libs/remix-ui/app/src/lib/remix-app/reducer/app.ts
  12. 11
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  13. 6
      libs/remix-ui/app/src/lib/remix-app/state/app.ts
  14. 11
      libs/remix-ui/git/src/components/github/devicecode.tsx
  15. 74
      libs/remix-ui/git/src/components/gitui.tsx
  16. 8
      libs/remix-ui/git/src/components/panels/githubcredentials.tsx
  17. 3
      libs/remix-ui/git/src/components/panels/init.tsx
  18. 55
      libs/remix-ui/git/src/components/panels/setup.tsx
  19. 13
      libs/remix-ui/git/src/lib/gitactions.ts
  20. 5
      libs/remix-ui/git/src/lib/listeners.ts
  21. 12
      libs/remix-ui/git/src/types/index.ts
  22. 4
      libs/remix-ui/workspace/src/lib/css/file-explorer.css
  23. 82
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  24. 2
      libs/remix-ui/workspace/src/lib/types/index.ts

@ -18,20 +18,36 @@ module.exports = {
clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="initgit-btn"]')
.click('*[data-id="initgit-btn"]')
},
'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.waitForElementVisible('*[data-id="filepanel-login-github"]')
.click('*[data-id="filepanel-login-github"]')
},
'login to github #group1 #group2': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="github-panel"]')
.waitForElementVisible('*[data-id="gitubUsername"]')
.setValue('*[data-id="githubToken"]', process.env.dgit_token)
.setValue('*[data-id="gitubUsername"]', 'git')
.setValue('*[data-id="githubEmail"]', 'git@example.com')
.click('*[data-id="saveGitHubCredentials"]')
},
'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) {
browser.
click('*[data-id="github-panel"]')
browser
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]')
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]')
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]')
},
'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]')
},
'clone a repository #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('dgit')
.click('*[data-id="clone-panel"]')
.click({
selector: '//*[@data-id="clone-panel-content"]//*[@data-id="fetch-repositories"]',
@ -191,10 +207,25 @@ module.exports = {
locateStrategy: 'xpath'
})
},
'disconnect github #group1': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="github-panel"]')
.click('*[data-id="github-panel"]')
.waitForElementVisible('*[data-id="disconnect-github"]')
.click('*[data-id="disconnect-github"]')
.waitForElementNotPresent('*[data-id="connected-as-bunsenstraat"]')
},
'check the FE for the disconnected auth user #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.waitForElementNotPresent('*[data-id="filepanel-connected-img-bunsenstraat"]')
.waitForElementVisible('*[data-id="filepanel-login-github"]')
},
'add a remote #group2': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="remotes-panel"]')
.click('*[data-id="remotes-panel"]')
.click({
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="fetch-repositories"]',
@ -312,8 +343,10 @@ module.exports = {
},
// pagination test
'clone repo #group3': function (browser: NightwatchBrowser) {
browser.
clickLaunchIcon('dgit')
browser
.clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="clone-panel"]')
.click('*[data-id="clone-panel"]')
.waitForElementVisible('*[data-id="clone-url"]')
.setValue('*[data-id="clone-url"]', 'https://github.com/ethereum/awesome-remix')
.waitForElementVisible('*[data-id="clone-branch"]')
@ -326,6 +359,8 @@ module.exports = {
'Update settings for git #group3': function (browser: NightwatchBrowser) {
browser.
clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="github-panel"]')
.click('*[data-id="github-panel"]')
.setValue('*[data-id="githubToken"]', 'invalidtoken')
.setValue('*[data-id="gitubUsername"]', 'git')
.setValue('*[data-id="githubEmail"]', 'git@example.com')

@ -36,6 +36,9 @@ module.exports = {
clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="initgit-btn"]')
.click('*[data-id="initgit-btn"]')
.waitForElementVisible('*[data-id="github-panel"]')
.click('*[data-id="github-panel"]')
.waitForElementVisible('*[data-id="gitubUsername"]')
.setValue('*[data-id="gitubUsername"]', 'git')
.setValue('*[data-id="githubEmail"]', 'git@example.com')
.click('*[data-id="saveGitHubCredentials"]')

@ -423,6 +423,9 @@ module.exports = {
clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="initgit-btn"]')
.click('*[data-id="initgit-btn"]')
.waitForElementVisible('*[data-id="github-panel"]')
.click('*[data-id="github-panel"]')
.waitForElementVisible('*[data-id="gitubUsername"]')
.setValue('*[data-id="gitubUsername"]', 'git')
.setValue('*[data-id="githubEmail"]', 'git@example.com')
.click('*[data-id="saveGitHubCredentials"]')
@ -430,6 +433,8 @@ module.exports = {
},
'check source controle panel #group5': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="sourcecontrol-panel"]')
.click('*[data-id="sourcecontrol-panel"]')
.waitForElementVisible({
selector: "//*[@data-status='new-untracked' and @data-file='/tests/MyToken_test.sol']",
locateStrategy: 'xpath'

@ -1056,15 +1056,22 @@ class DGitProvider extends Plugin {
auth: input.token
})
const user = await octokit.request('GET /user')
const user = await octokit.request('GET /user', {
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
})
const emails = await octokit.request('GET /user/emails')
const scopes = user.headers['x-oauth-scopes'] || ''
return {
user: user.data,
user: {
...user.data, isConnected:
user.data.login !== undefined && user.data.login !== null && user.data.login !== ''
},
emails: emails.data,
scopes: scopes && scopes.split(',')
scopes: scopes && scopes.split(',').map(scope => scope.trim())
}
} catch (e) {
return null

@ -142,5 +142,7 @@
"filePanel.movingFolderFailedMsg": "Unexpected error while moving folder: {src}",
"filePanel.workspaceActions": "Workspace actions",
"filePanel.saveCodeSample": "This code-sample workspace will not be persisted. Click here to save it.",
"filePanel.logInGithub": "Sign in to GitHub.",
"filePanel.gitHubLoggedAs": "Signed in as {githubuser}",
"filePanel.updateSubmodules": "Update all submodules of repository. Click to pull dependencies."
}

@ -16,5 +16,6 @@
"git.unstageall": "unstage all",
"git.stageall": "stage all",
"git.noremote": "this repo has no remotes",
"git.init": "Initialize repository"
"git.init": "Initialize repository",
"git.setup": "Setup git"
}

@ -4,3 +4,4 @@ export { ModalProvider, useDialogDispatchers } from './lib/remix-app/context/pro
export { AppModal } from './lib/remix-app/interface/index'
export { AlertModal } from './lib/remix-app/interface/index'
export { ModalTypes } from './lib/remix-app/types/index'
export { AppAction, appActionTypes } from './lib/remix-app/actions/app'

@ -0,0 +1,25 @@
import { GitHubUser } from '@remix-ui/git';
import { AppModal } from '../interface'
type ActionMap<M extends { [index: string]: any }> = {
[Key in keyof M]: M[Key] extends undefined
? {
type: Key;
}
: {
type: Key;
payload: M[Key];
}
}
export const enum appActionTypes {
setGitHubUser = 'SET_GITHUB_USER',
}
type AppPayload = {
[appActionTypes.setGitHubUser]: GitHubUser
}
export type AppAction = ActionMap<AppPayload>[keyof ActionMap<
AppPayload
>]

@ -1,6 +1,7 @@
import React from 'react'
import { AlertModal, AppModal } from '../interface'
import { AlertModal, AppModal, AppState } from '../interface'
import { ModalInitialState } from '../state/modals'
import { AppAction } from '../actions/app'
export type appProviderContextType = {
settings: any,
@ -8,6 +9,8 @@ export type appProviderContextType = {
showEnter: boolean,
appManager: any
modal: any
appState: AppState
appStateDispatch: React.Dispatch<AppAction>
}
export enum appPlatformTypes {

@ -1,3 +1,4 @@
import { GitHubUser } from '@remix-ui/git'
import { ModalTypes } from '../types'
export type ValidationResult = {
@ -45,3 +46,7 @@ export interface forceChoiceModal {
message: string | JSX.Element,
}
export interface AppState {
gitHubUser: GitHubUser
}

@ -0,0 +1,13 @@
import { AppAction, appActionTypes } from "../actions/app";
import { AppState } from "../interface";
export const appReducer = (state: AppState, action: AppAction): AppState => {
switch (action.type) {
case appActionTypes.setGitHubUser:{
return {
...state,
gitHubUser: action.payload
}
}
}
}

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from 'react'
import React, { useEffect, useReducer, useRef, useState } from 'react'
import './style/remix-app.css'
import { RemixUIMainPanel } from '@remix-ui/panel'
import MatomoDialog from './components/modals/matomo'
@ -12,6 +12,9 @@ import { appProviderContextType, onLineContext, platformContext } from './contex
import { FormattedMessage, IntlProvider } from 'react-intl'
import { CustomTooltip } from '@remix-ui/helper'
import { UsageTypes } from './types'
import { AppState } from './interface'
import { appReducer } from './reducer/app'
import { appInitialState } from './state/app'
declare global {
interface Window {
@ -40,6 +43,8 @@ const RemixApp = (props: IRemixAppUi) => {
const sidePanelRef = useRef(null)
const pinnedPanelRef = useRef(null)
const [appState, appStateDispatch] = useReducer(appReducer, appInitialState)
useEffect(() => {
async function activateApp() {
props.app.themeModule.initTheme(() => {
@ -133,7 +138,9 @@ const RemixApp = (props: IRemixAppUi) => {
showMatamo: props.app.showMatamo,
appManager: props.app.appManager,
showEnter: props.app.showEnter,
modal: props.app.notification
modal: props.app.notification,
appState: appState,
appStateDispatch: appStateDispatch
}
const handleUserChosenType = async (type) => {

@ -0,0 +1,6 @@
import { GitHubUser } from "@remix-ui/git";
import { AppState } from "../interface";
export const appInitialState: AppState = {
gitHubUser: {} as GitHubUser,
}

@ -65,7 +65,6 @@ export const GetDeviceCode = () => {
} else {
await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUBFAIL)
}
}
const disconnect = async () => {
@ -78,11 +77,11 @@ export const GetDeviceCode = () => {
return (
<>
{(context.gitHubUser && context.gitHubUser.login) ? null : <>
{(context.gitHubUser && context.gitHubUser.isConnected) ? null : <>
<label className="text-uppercase">Connect to GitHub</label>
<button className='btn btn-secondary mt-1 w-100' onClick={async () => {
await getDeviceCodeFromGitHub()
}}><i className="fab fa-github mr-1"></i>Login in with github</button></>
}}><i className="fab fa-github mr-1"></i>Login with GitHub</button></>
}
{gitHubResponse && !authorized &&
<div className="pt-2">
@ -105,15 +104,15 @@ export const GetDeviceCode = () => {
</div>
}
{
(context.gitHubUser && context.gitHubUser.login) ?
(context.gitHubUser && context.gitHubUser.isConnected) ?
<div className="pt-2">
<button className='btn btn-primary mt-1 w-100' onClick={async () => {
<button data-id='disconnect-github' className='btn btn-primary mt-1 w-100' onClick={async () => {
disconnect()
}}>Disconnect</button>
</div> : null
}
{
(context.gitHubUser && context.gitHubUser.login) ?
(context.gitHubUser && context.gitHubUser.isConnected) ?
<div className="pt-2">
<div className="mb-1" data-id={`connected-as-${context.gitHubUser.login}`}>Connected as {context.gitHubUser.login}</div>

@ -5,7 +5,7 @@ import { openDiff, openFile, saveToken, sendToMatomo, setModifiedDecorator, setP
import { gitActionsContext, pluginActionsContext } from '../state/context'
import { gitReducer } from '../state/gitreducer'
import { defaultGitState, defaultLoaderState, gitMatomoEventTypes, gitState, gitUIPanels, loaderState } from '../types'
import { Accordion } from "react-bootstrap";
import { Accordion, Button } from "react-bootstrap";
import { CommitMessage } from './buttons/commitmessage'
import { Commits } from './panels/commits'
import { Branches } from './panels/branches'
@ -19,7 +19,6 @@ import { Commands } from './panels/commands'
import { CommandsNavigation } from './navigation/commands'
import { RemotesNavigation } from './navigation/remotes'
import { Remotes } from './panels/remotes'
import { ViewPlugin } from '@remixproject/engine-web'
import { GitHubNavigation } from './navigation/github'
import { loaderReducer } from '../state/loaderReducer'
import { GetDeviceCode } from './github/devicecode'
@ -31,17 +30,12 @@ import { SourceControl } from './panels/sourcontrol'
import { GitHubCredentials } from './panels/githubcredentials'
import { Setup } from './panels/setup'
import { Init } from './panels/init'
import { CustomRemixApi } from "@remix-api"
import { Plugin } from "@remixproject/engine"
import { Disabled } from './disabled'
import { IGitUi } from '../types'
import { AppContext } from '@remix-ui/app'
export const gitPluginContext = React.createContext<gitState>(defaultGitState)
export const loaderContext = React.createContext<loaderState>(defaultLoaderState)
interface IGitUi {
plugin: Plugin<any, CustomRemixApi>
}
export const GitUI = (props: IGitUi) => {
const plugin = props.plugin
const [gitState, gitDispatch] = useReducer(gitReducer, defaultGitState)
@ -50,6 +44,7 @@ export const GitUI = (props: IGitUi) => {
const [setup, setSetup] = useState<boolean>(false)
const [needsInit, setNeedsInit] = useState<boolean>(true)
const [appLoaded, setAppLoaded] = useState<boolean>(false)
const appContext = useContext(AppContext)
useEffect(() => {
plugin.emit('statusChanged', {
@ -64,7 +59,7 @@ export const GitUI = (props: IGitUi) => {
useEffect(() => {
if (!appLoaded) return
setCallBacks(plugin, gitDispatch, loaderDispatch, setActivePanel)
setCallBacks(plugin, gitDispatch, appContext.appStateDispatch, loaderDispatch, setActivePanel)
setPlugin(plugin, gitDispatch, loaderDispatch)
loaderDispatch({ type: 'plugin', payload: true })
@ -183,13 +178,10 @@ export const GitUI = (props: IGitUi) => {
<gitActionsContext.Provider value={gitActionsProviderValue}>
<pluginActionsContext.Provider value={pluginActionsProviderValue}>
<BranchHeader />
{setup && !needsInit ? <Setup></Setup> : null}
{needsInit ? <Init></Init> : null}
{!setup && !needsInit ?
<Accordion activeKey={activePanel} defaultActiveKey="0" className="">
{setup ? <Setup callback={setActivePanel}></Setup> : null}
<Accordion activeKey={activePanel} defaultActiveKey="0" className="">
{!setup && !needsInit ? <>
<SourceControlNavigation eventKey={gitUIPanels.SOURCECONTROL} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.SOURCECONTROL}>
<div className="px-2 py-2">
<SourceControlBase><CommitMessage /></SourceControlBase>
@ -225,30 +217,32 @@ export const GitUI = (props: IGitUi) => {
</div>
</Accordion.Collapse>
<hr></hr>
<CloneNavigation eventKey={gitUIPanels.CLONE} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.CLONE}>
<div className="px-2 py-2">
<Clone /></div>
</Accordion.Collapse>
<hr></hr>
<GitHubNavigation eventKey={gitUIPanels.GITHUB} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.GITHUB}>
<div className="px-2 py-2">
<GetDeviceCode></GetDeviceCode>
<hr></hr>
<GitHubCredentials></GitHubCredentials>
</div>
</Accordion.Collapse>
<hr></hr>
<LogNavigation eventKey={gitUIPanels.LOG} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.LOG}>
<div className="px-2 py-2">
<LogViewer />
</div>
</Accordion.Collapse>
</Accordion>
: null}
</> : null}
{needsInit ? <>
<Init /></> : null}
<CloneNavigation eventKey={gitUIPanels.CLONE} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.CLONE}>
<div className="px-2 py-2">
<Clone /></div>
</Accordion.Collapse>
<hr></hr>
<GitHubNavigation eventKey={gitUIPanels.GITHUB} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.GITHUB}>
<div className="px-2 py-2">
<GetDeviceCode></GetDeviceCode>
<hr></hr>
<GitHubCredentials></GitHubCredentials>
</div>
</Accordion.Collapse>
<hr></hr>
<LogNavigation eventKey={gitUIPanels.LOG} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey={gitUIPanels.LOG}>
<div className="px-2 py-2">
<LogViewer />
</div>
</Accordion.Collapse>
</Accordion>
</pluginActionsContext.Provider>
</gitActionsContext.Provider>
</loaderContext.Provider>

@ -22,7 +22,11 @@ export const GitHubCredentials = () => {
useEffect(() => {
refresh()
if (context.gitHubUser) {
setScopeWarning(!(context.gitHubScopes && context.gitHubScopes.length > 0))
setScopeWarning(!(context.gitHubScopes
&& context.gitHubScopes.includes('repo')
&& context.gitHubScopes.includes('read:user')
&& context.gitHubScopes.includes('user:email')
&& context.gitHubScopes.includes('gist')))
} else {
setScopeWarning(false)
}
@ -92,7 +96,7 @@ export const GitHubCredentials = () => {
</button>
</div>
{scopeWarning ?
<div className="text-warning">Your GitHub token may not have the correct permissions. Please use the login with GitHub feature.</div> : null}
<div className="text-warning">Your GitHub token may or may not have the correct permissions. Remix can't verify the permissions when using your own token. Please use the login with GitHub feature.</div> : null}
<hr />
</>
);

@ -27,9 +27,6 @@ export const Init = () => {
><FormattedMessage id='git.init' /></GitUIButton>
</div>
</div>
<hr></hr>
<h5>CLONE</h5>
<Clone></Clone>
</>
)
}

@ -1,39 +1,28 @@
import React, { useEffect, useState } from 'react'
import { GetDeviceCode } from '../github/devicecode'
import { GitHubCredentials } from './githubcredentials'
import { Clone } from './clone'
import { gitUIPanels } from '../../types'
import GitUIButton from '../buttons/gituibutton'
import { FormattedMessage } from 'react-intl'
export const Setup = () => {
export const Setup = ({ callback }) => {
const [screen, setScreen] = useState(0)
const startSetingUp = () => {
callback(gitUIPanels.GITHUB)
}
if (screen === 0) {
return (
<>
<h5>SETUP</h5>
<div>
<div className='mt-1 mb-2'>
To ensure that your commits are properly attributed in Git, you need to configure a username and email address.
These will be used to identify the author of the commit.
</div>
<GetDeviceCode></GetDeviceCode>
<hr></hr>
<GitHubCredentials></GitHubCredentials>
</div>
<h5>CLONE</h5>
<Clone hideLoadFromGitHub={true}></Clone>
</>
)
} else if (screen === 1) {
return (
<>
<h5>SETUP</h5>
<h6>Step 2</h6>
<div>
To ensure that your commits are properly attributed in Git, you need to configure your username and email address.
<GitHubCredentials></GitHubCredentials>
return (
<>
<h5>SETUP REQUIRED</h5>
<div>
<div className='mt-1 mb-2'>
To ensure that your commits are properly attributed in Git, you need to <a href='#' onClick={startSetingUp} className='cursor-pointer mr-1'>configure a username and email address or connect to GitHub.</a>
These credentials will be used to identify the author of the commit.
<a href='#' onClick={startSetingUp} className='ml-1 cursor-pointer'>
<FormattedMessage id='git.setup' /></a>
</div>
</>
)
}
<hr></hr>
</div>
</>
)
}

@ -4,10 +4,11 @@ import { fileStatus, fileStatusMerge, setRemoteBranchCommits, resetRemoteBranchC
import { GitHubUser, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote, gitLog, fileStatusResult, customGitApi, IGitApi, cloneInputType, fetchInputType, pullInputType, pushInputType, checkoutInput, rmInput, addInput, repository, userEmails, storage, gitMatomoEventTypes } from '../types';
import { removeSlash } from "../utils";
import { disableCallBacks, enableCallBacks } from "./listeners";
import { ModalTypes } from "@remix-ui/app";
import { ModalTypes, appActionTypes, AppAction } from "@remix-ui/app";
import { sendToMatomo, setFileDecorators } from "./pluginActions";
import { Plugin } from "@remixproject/engine";
import { CustomRemixApi } from "@remix-api";
import { app } from "electron";
export const fileStatuses = [
["new,untracked", 0, 2, 0], // new, untracked
@ -31,11 +32,12 @@ const statusmatrix: statusMatrixType[] = fileStatuses.map((x: any) => {
};
});
let plugin: Plugin<any, CustomRemixApi>, dispatch: React.Dispatch<gitActionDispatch>
let plugin: Plugin<any, CustomRemixApi>, dispatch: React.Dispatch<gitActionDispatch>, appDispatcher: React.Dispatch<AppAction>
export const setPlugin = (p: Plugin, dispatcher: React.Dispatch<gitActionDispatch>) => {
export const setPlugin = (p: Plugin, dispatcher: React.Dispatch<gitActionDispatch>, appDispatch: React.Dispatch<AppAction>) => {
plugin = p
dispatch = dispatcher
appDispatcher = appDispatch
}
export const init = async () => {
@ -578,7 +580,9 @@ export const saveGitHubCredentials = async (credentials: { username: string, ema
}
dispatch(setGitHubUser({
login: credentials.username,
isConnected: false
}))
appDispatcher({ type: appActionTypes.setGitHubUser, payload: { login: credentials.username, isConnected: false } })
dispatch(setUserEmails([{
email: credentials.email,
primary: true,
@ -638,6 +642,7 @@ export const loadGitHubUserFromToken = async () => {
if (data.user && data.user.login && (storedUsername !== data.user.login)) await plugin.call('config', 'setAppParameter', 'settings/github-user-name', data.user.login)
dispatch(setGitHubUser(data.user))
appDispatcher({ type: appActionTypes.setGitHubUser, payload: data.user })
dispatch(setScopes(data.scopes))
dispatch(setUserEmails(data.emails))
sendToGitLog({
@ -653,6 +658,7 @@ export const loadGitHubUserFromToken = async () => {
message: `Please check your GitHub token in the GitHub settings.`
})
dispatch(setGitHubUser(null))
appDispatcher({ type: appActionTypes.setGitHubUser, payload: null })
return false
}
} else {
@ -661,6 +667,7 @@ export const loadGitHubUserFromToken = async () => {
message: `Please check your GitHub token in the GitHub settings.`
})
dispatch(setGitHubUser(null))
appDispatcher({ type: appActionTypes.setGitHubUser, payload: null })
return false
}
} catch (e) {

@ -7,6 +7,7 @@ import { getBranches, getFileStatusMatrix, loadGitHubUserFromToken, getRemotes,
import { Profile } from "@remixproject/plugin-utils";
import { CustomRemixApi } from "@remix-api";
import { statusChanged } from "./pluginActions";
import { AppAction } from "@remix-ui/app";
let plugin: Plugin<any, CustomRemixApi>, gitDispatch: React.Dispatch<gitActionDispatch>, loaderDispatch: React.Dispatch<any>, loadFileQueue: AsyncDebouncedQueue
let callBackEnabled: boolean = false
@ -34,13 +35,13 @@ class AsyncDebouncedQueue {
}
}
export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch<gitActionDispatch>, loaderDispatcher: React.Dispatch<any>, setAtivePanel: React.Dispatch<React.SetStateAction<string>>) => {
export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch<gitActionDispatch>, appDispatcher: React.Dispatch<AppAction>, loaderDispatcher: React.Dispatch<any>, setAtivePanel: React.Dispatch<React.SetStateAction<string>>) => {
plugin = viewPlugin
gitDispatch = gitDispatcher
loaderDispatch = loaderDispatcher
loadFileQueue = new AsyncDebouncedQueue()
setPlugin(viewPlugin, gitDispatcher)
setPlugin(viewPlugin, gitDispatcher, appDispatcher)
plugin.on("fileManager", "fileSaved", async (file: string) => {
loadFileQueue.enqueue(async () => {

@ -2,9 +2,19 @@ import { Endpoints } from "@octokit/types"
import { IRemixApi } from "@remixproject/plugin-api"
import { LibraryProfile, StatusEvents } from "@remixproject/plugin-utils"
import { CommitObject, ReadBlobResult, ReadCommitResult, StatusRow } from "isomorphic-git"
export type GitHubUser = Partial<Endpoints["GET /user"]["response"]['data']>
import { CustomRemixApi } from "@remix-api";
import { Plugin } from "@remixproject/engine";
export type GitHubUser = Partial<Endpoints["GET /user"]["response"]['data']> & {
isConnected: boolean
}
export type userEmails = Endpoints["GET /user/emails"]["response"]["data"]
export interface IGitUi {
plugin: Plugin<any, CustomRemixApi>
}
export interface IGitApi {
events: {
"checkout": () => void

@ -70,6 +70,10 @@ ul {
color: var(--text);
}
.remixui_avatar_user {
border-radius: 50% !important;
}
.remixui_selected {
}

@ -14,11 +14,10 @@ import { MenuItems, WorkSpaceState, WorkspaceMetadata } from './types'
import { contextMenuActions } from './utils'
import FileExplorerContextMenu from './components/file-explorer-context-menu'
import { customAction } from '@remixproject/plugin-api'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
import { AppContext, appPlatformTypes, platformContext } from '@remix-ui/app'
import { ElectronMenu } from './components/electron-menu'
import { ElectronWorkspaceName } from './components/electron-workspace-name'
import { branch } from '@remix-ui/git'
import { publishFilesToGist } from './actions'
import { branch, GitHubUser, gitUIPanels, userEmails } from '@remix-ui/git'
const _paq = (window._paq = window._paq || [])
@ -50,6 +49,8 @@ export function Workspace() {
const [canPaste, setCanPaste] = useState(false)
const appContext = useContext(AppContext)
const [state, setState] = useState<WorkSpaceState>({
ctrlKey: false,
cutShortcut: false,
@ -887,6 +888,13 @@ export function Workspace() {
</>
)
}
const logInGithub = async () => {
await global.plugin.call('menuicons', 'select', 'dgit');
await global.plugin.call('dgit', 'open', gitUIPanels.GITHUB)
_paq.push(['trackEvent', 'Workspace', 'GIT', 'login'])
}
return (
<div className="d-flex flex-column justify-content-between h-100">
<div
@ -936,27 +944,53 @@ export function Workspace() {
</Dropdown>
</span>
) : null}
<span className="d-flex">
<label className="pl-2 form-check-label" style={{ wordBreak: 'keep-all' }}>
{(platform == appPlatformTypes.desktop) ? (
<ElectronWorkspaceName plugin={global.plugin} path={global.fs.browser.currentLocalFilePath} />
) : <FormattedMessage id='filePanel.workspace' />}
</label>
{selectedWorkspace && selectedWorkspace.name === 'code-sample' && <CustomTooltip
placement="right"
tooltipId="saveCodeSample"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id="filePanel.saveCodeSample" />}
>
<i onClick={() => saveSampleCodeWorkspace()} className="far fa-exclamation-triangle text-warning ml-2 align-self-center" aria-hidden="true"></i>
</CustomTooltip>}
{selectedWorkspace && selectedWorkspace.isGist && <CopyToClipboard tip={'Copy Gist ID to clipboard'} getContent={() => selectedWorkspace.isGist} direction="bottom" icon="far fa-copy">
<i className="remixui_copyIcon ml-2 fab fa-github text-info" aria-hidden="true" style={{ fontSize: '1.1rem', cursor: 'pointer' }} ></i>
</CopyToClipboard>
}
</span>
<div className='d-flex w-100 justify-content-between'>
<span className="d-flex">
<label className="pl-2 form-check-label" style={{ wordBreak: 'keep-all' }}>
{(platform == appPlatformTypes.desktop) ? (
<ElectronWorkspaceName plugin={global.plugin} path={global.fs.browser.currentLocalFilePath} />
) : <FormattedMessage id='filePanel.workspace' />}
</label>
{selectedWorkspace && selectedWorkspace.name === 'code-sample' && <CustomTooltip
placement="right"
tooltipId="saveCodeSample"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id="filePanel.saveCodeSample" />}
>
<i onClick={() => saveSampleCodeWorkspace()} className="far fa-exclamation-triangle text-warning ml-2 align-self-center" aria-hidden="true"></i>
</CustomTooltip>}
{selectedWorkspace && selectedWorkspace.isGist && <CopyToClipboard tip={'Copy Gist ID to clipboard'} getContent={() => selectedWorkspace.isGist} direction="bottom" icon="far fa-copy">
<i className="remixui_copyIcon ml-2 fab fa-github text-info" aria-hidden="true" style={{ fontSize: '1.1rem', cursor: 'pointer' }} ></i>
</CopyToClipboard>
}
</span>
<span className="d-flex">
{
(!appContext.appState.gitHubUser || !appContext.appState.gitHubUser.isConnected) && <CustomTooltip
placement="right"
tooltipId="githubNotLogged"
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id="filePanel.logInGithub" />}
>
<div data-id='filepanel-login-github' className='d-flex'>
<i onClick={() => logInGithub() } className="fa-brands fa-github-alt ml-2 align-self-center" style={{ fontSize: '1.1rem', cursor: 'pointer' }} aria-hidden="true"></i>
<span onClick={() => logInGithub() } className="ml-1 style={{ cursor: 'pointer' }} "> Sign in </span>
</div>
</CustomTooltip>
}
{
appContext.appState.gitHubUser && appContext.appState.gitHubUser.isConnected && <CustomTooltip
placement="right"
tooltipId="githubLoggedIn"
tooltipClasses="text-nowrap"
tooltipText={appContext.appState.gitHubUser && intl.formatMessage({ id: 'filePanel.gitHubLoggedAs' }, { githubuser: appContext.appState.gitHubUser.login }) || ''}
>
<img width={20} height={20} data-id={`filepanel-connected-img-${appContext.appState.gitHubUser && appContext.appState.gitHubUser.login}`} src={appContext.appState.gitHubUser && appContext.appState.gitHubUser.avatar_url} className="remixui_avatar_user ml-2" />
</CustomTooltip>
}
</span>
</div>
</div>
<div className='mx-2'>
{(platform !== appPlatformTypes.desktop) ? (

@ -6,7 +6,7 @@ import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types'
import { ViewPlugin } from '@remixproject/engine-web'
import { appPlatformTypes } from '@remix-ui/app'
import { Placement } from 'react-bootstrap/esm/Overlay'
import { branch } from '@remix-ui/git'
import { branch, GitHubUser } from '@remix-ui/git'
export type action = { name: string, type?: Array<WorkspaceElement>, path?: string[], extension?: string[], pattern?: string[], id: string, multiselect: boolean, label: string, sticky?: boolean, group: number, platform?: appPlatformTypes }
export interface JSONStandardInput {

Loading…
Cancel
Save