diff --git a/apps/remix-ide-e2e/src/tests/dgit_github.test.ts b/apps/remix-ide-e2e/src/tests/dgit_github.test.ts index 9b67794bab..daa7d17baa 100644 --- a/apps/remix-ide-e2e/src/tests/dgit_github.test.ts +++ b/apps/remix-ide-e2e/src/tests/dgit_github.test.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') diff --git a/apps/remix-ide-e2e/src/tests/dgit_local.test.ts b/apps/remix-ide-e2e/src/tests/dgit_local.test.ts index b6ee642a27..659b20767a 100644 --- a/apps/remix-ide-e2e/src/tests/dgit_local.test.ts +++ b/apps/remix-ide-e2e/src/tests/dgit_local.test.ts @@ -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"]') diff --git a/apps/remix-ide-e2e/src/tests/workspace_git.test.ts b/apps/remix-ide-e2e/src/tests/workspace_git.test.ts index 0661eb31ee..467d97e620 100644 --- a/apps/remix-ide-e2e/src/tests/workspace_git.test.ts +++ b/apps/remix-ide-e2e/src/tests/workspace_git.test.ts @@ -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' diff --git a/apps/remix-ide/src/app/files/dgitProvider.ts b/apps/remix-ide/src/app/files/dgitProvider.ts index 87cb4c3c8c..9d4b01091c 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.ts +++ b/apps/remix-ide/src/app/files/dgitProvider.ts @@ -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 diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 6932ae3e04..affee6c134 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -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." } diff --git a/apps/remix-ide/src/app/tabs/locales/en/git.json b/apps/remix-ide/src/app/tabs/locales/en/git.json index c5f4fa6a09..ea64a5b02d 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/git.json +++ b/apps/remix-ide/src/app/tabs/locales/en/git.json @@ -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" } \ No newline at end of file diff --git a/libs/remix-ui/app/src/index.ts b/libs/remix-ui/app/src/index.ts index e686172a78..b18c36cb9a 100644 --- a/libs/remix-ui/app/src/index.ts +++ b/libs/remix-ui/app/src/index.ts @@ -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' diff --git a/libs/remix-ui/app/src/lib/remix-app/actions/app.ts b/libs/remix-ui/app/src/lib/remix-app/actions/app.ts new file mode 100644 index 0000000000..20932eef6c --- /dev/null +++ b/libs/remix-ui/app/src/lib/remix-app/actions/app.ts @@ -0,0 +1,25 @@ +import { GitHubUser } from '@remix-ui/git'; +import { AppModal } from '../interface' + +type ActionMap = { + [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[keyof ActionMap< + AppPayload +>] diff --git a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx index 9fcf53d4a7..8f3fd119ed 100644 --- a/libs/remix-ui/app/src/lib/remix-app/context/context.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/context/context.tsx @@ -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 } export enum appPlatformTypes { diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts index 5dacecdf4d..dc6e453edc 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -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 +} + diff --git a/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts new file mode 100644 index 0000000000..2fce1a56cf --- /dev/null +++ b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts @@ -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 + } + } + } +} \ No newline at end of file diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index 24c42a4318..07e57d5051 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -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) => { diff --git a/libs/remix-ui/app/src/lib/remix-app/state/app.ts b/libs/remix-ui/app/src/lib/remix-app/state/app.ts new file mode 100644 index 0000000000..417911ae0c --- /dev/null +++ b/libs/remix-ui/app/src/lib/remix-app/state/app.ts @@ -0,0 +1,6 @@ +import { GitHubUser } from "@remix-ui/git"; +import { AppState } from "../interface"; + +export const appInitialState: AppState = { + gitHubUser: {} as GitHubUser, +} \ No newline at end of file diff --git a/libs/remix-ui/git/src/components/github/devicecode.tsx b/libs/remix-ui/git/src/components/github/devicecode.tsx index 85922441fd..3af8ab06df 100644 --- a/libs/remix-ui/git/src/components/github/devicecode.tsx +++ b/libs/remix-ui/git/src/components/github/devicecode.tsx @@ -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 : <> + }}>Login with GitHub } {gitHubResponse && !authorized &&
@@ -105,15 +104,15 @@ export const GetDeviceCode = () => {
} { - (context.gitHubUser && context.gitHubUser.login) ? + (context.gitHubUser && context.gitHubUser.isConnected) ?
-
: null } { - (context.gitHubUser && context.gitHubUser.login) ? + (context.gitHubUser && context.gitHubUser.isConnected) ?
Connected as {context.gitHubUser.login}
diff --git a/libs/remix-ui/git/src/components/gitui.tsx b/libs/remix-ui/git/src/components/gitui.tsx index 7072165169..b3d31fcc1f 100644 --- a/libs/remix-ui/git/src/components/gitui.tsx +++ b/libs/remix-ui/git/src/components/gitui.tsx @@ -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(defaultGitState) export const loaderContext = React.createContext(defaultLoaderState) -interface IGitUi { - plugin: Plugin -} - 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(false) const [needsInit, setNeedsInit] = useState(true) const [appLoaded, setAppLoaded] = useState(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) => { - - {setup && !needsInit ? : null} - {needsInit ? : null} - {!setup && !needsInit ? - + {setup ? : null} + + {!setup && !needsInit ? <> -
@@ -225,30 +217,32 @@ export const GitUI = (props: IGitUi) => {

- - -
-
-
-
- - -
- -
- -
-
-
- - -
- -
-
- -
- : null} + : null} + {needsInit ? <> + : null} + + +
+
+
+
+ + + +
+ +
+ +
+
+
+ + +
+ +
+
+
diff --git a/libs/remix-ui/git/src/components/panels/githubcredentials.tsx b/libs/remix-ui/git/src/components/panels/githubcredentials.tsx index 3635fbe988..e466aeeaf9 100644 --- a/libs/remix-ui/git/src/components/panels/githubcredentials.tsx +++ b/libs/remix-ui/git/src/components/panels/githubcredentials.tsx @@ -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 = () => {
{scopeWarning ? -
Your GitHub token may not have the correct permissions. Please use the login with GitHub feature.
: null} +
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.
: null}
); diff --git a/libs/remix-ui/git/src/components/panels/init.tsx b/libs/remix-ui/git/src/components/panels/init.tsx index 37969cfb0b..37996deddd 100644 --- a/libs/remix-ui/git/src/components/panels/init.tsx +++ b/libs/remix-ui/git/src/components/panels/init.tsx @@ -27,9 +27,6 @@ export const Init = () => { > -
-
CLONE
- ) } \ No newline at end of file diff --git a/libs/remix-ui/git/src/components/panels/setup.tsx b/libs/remix-ui/git/src/components/panels/setup.tsx index 71b35f1499..184a46eadf 100644 --- a/libs/remix-ui/git/src/components/panels/setup.tsx +++ b/libs/remix-ui/git/src/components/panels/setup.tsx @@ -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 ( - <> -
SETUP
-
-
- 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. -
- -
- -
-
CLONE
- - - ) - } else if (screen === 1) { - return ( - <> -
SETUP
-
Step 2
-
- To ensure that your commits are properly attributed in Git, you need to configure your username and email address. - + return ( + <> +
SETUP REQUIRED
+
+
+ To ensure that your commits are properly attributed in Git, you need to configure a username and email address or connect to GitHub. + These credentials will be used to identify the author of the commit. + + +
- - ) - } +
+
+ + ) + } \ 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 aa6997877a..b884091d6b 100644 --- a/libs/remix-ui/git/src/lib/gitactions.ts +++ b/libs/remix-ui/git/src/lib/gitactions.ts @@ -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, dispatch: React.Dispatch +let plugin: Plugin, dispatch: React.Dispatch, appDispatcher: React.Dispatch -export const setPlugin = (p: Plugin, dispatcher: React.Dispatch) => { +export const setPlugin = (p: Plugin, dispatcher: React.Dispatch, appDispatch: React.Dispatch) => { 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) { diff --git a/libs/remix-ui/git/src/lib/listeners.ts b/libs/remix-ui/git/src/lib/listeners.ts index 161bfd5af2..902a6b5c81 100644 --- a/libs/remix-ui/git/src/lib/listeners.ts +++ b/libs/remix-ui/git/src/lib/listeners.ts @@ -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, gitDispatch: React.Dispatch, loaderDispatch: React.Dispatch, loadFileQueue: AsyncDebouncedQueue let callBackEnabled: boolean = false @@ -34,13 +35,13 @@ class AsyncDebouncedQueue { } } -export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch, loaderDispatcher: React.Dispatch, setAtivePanel: React.Dispatch>) => { +export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch, appDispatcher: React.Dispatch, loaderDispatcher: React.Dispatch, setAtivePanel: React.Dispatch>) => { 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 () => { diff --git a/libs/remix-ui/git/src/types/index.ts b/libs/remix-ui/git/src/types/index.ts index f872203e79..9e846782ad 100644 --- a/libs/remix-ui/git/src/types/index.ts +++ b/libs/remix-ui/git/src/types/index.ts @@ -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 +import { CustomRemixApi } from "@remix-api"; +import { Plugin } from "@remixproject/engine"; + +export type GitHubUser = Partial & { + isConnected: boolean +} + export type userEmails = Endpoints["GET /user/emails"]["response"]["data"] +export interface IGitUi { + plugin: Plugin +} + export interface IGitApi { events: { "checkout": () => void diff --git a/libs/remix-ui/workspace/src/lib/css/file-explorer.css b/libs/remix-ui/workspace/src/lib/css/file-explorer.css index 4ccf2096c7..4e26ca94eb 100644 --- a/libs/remix-ui/workspace/src/lib/css/file-explorer.css +++ b/libs/remix-ui/workspace/src/lib/css/file-explorer.css @@ -70,6 +70,10 @@ ul { color: var(--text); } +.remixui_avatar_user { + border-radius: 50% !important; +} + .remixui_selected { } diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 6a7da22b21..f6bf6d4184 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -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({ 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 (
) : null} - - - {selectedWorkspace && selectedWorkspace.name === 'code-sample' && } - > - saveSampleCodeWorkspace()} className="far fa-exclamation-triangle text-warning ml-2 align-self-center" aria-hidden="true"> - } - - {selectedWorkspace && selectedWorkspace.isGist && selectedWorkspace.isGist} direction="bottom" icon="far fa-copy"> - - - } - - +
+ + + {selectedWorkspace && selectedWorkspace.name === 'code-sample' && } + > + saveSampleCodeWorkspace()} className="far fa-exclamation-triangle text-warning ml-2 align-self-center" aria-hidden="true"> + } + + {selectedWorkspace && selectedWorkspace.isGist && selectedWorkspace.isGist} direction="bottom" icon="far fa-copy"> + + + } + + + { + (!appContext.appState.gitHubUser || !appContext.appState.gitHubUser.isConnected) && } + > +
+ logInGithub() } className="fa-brands fa-github-alt ml-2 align-self-center" style={{ fontSize: '1.1rem', cursor: 'pointer' }} aria-hidden="true"> + logInGithub() } className="ml-1 style={{ cursor: 'pointer' }} "> Sign in +
+
+ } + { + appContext.appState.gitHubUser && appContext.appState.gitHubUser.isConnected && + + + } +
+
{(platform !== appPlatformTypes.desktop) ? ( diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts index 9f21c799bf..32e4d05d98 100644 --- a/libs/remix-ui/workspace/src/lib/types/index.ts +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -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, path?: string[], extension?: string[], pattern?: string[], id: string, multiselect: boolean, label: string, sticky?: boolean, group: number, platform?: appPlatformTypes } export interface JSONStandardInput {