feat: use github token to load repo list

This commit is contained in:
Lin Onetwo 2020-07-04 01:10:27 +08:00
parent cb2428fb70
commit 758f10e469
7 changed files with 363 additions and 211 deletions

View file

@ -7,9 +7,6 @@
[lints]
[options]
module.name_mapper='^[~]\/\(.*\)$' -> '<PROJECT_ROOT>/app/src/\1'
module.name_mapper='^constants\/\(.*\)$' -> '<PROJECT_ROOT>/app/src/constants/\1'
module.name_mapper='^components\/\(.*\)$' -> '<PROJECT_ROOT>/app/src/components/\1'
module.name_mapper='^libs\/\(.*\)$' -> '<PROJECT_ROOT>/app/libs/\1'
esproposal.optional_chaining=enable
[strict]

19
package-lock.json generated
View file

@ -7459,6 +7459,11 @@
"integrity": "sha1-Y2jL20Cr8zc7UlrIfkomDDpwCRk=",
"dev": true
},
"dequal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-1.0.0.tgz",
"integrity": "sha512-/Nd1EQbQbI9UbSHrMiKZjFLrXSnU328iQdZKPQf78XQI6C+gutkFUeoHpG5J08Ioa6HeRbRNFpSIclh1xyG0mw=="
},
"des.js": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/des.js/download/des.js-1.0.1.tgz",
@ -9480,6 +9485,11 @@
}
}
},
"extract-files": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/extract-files/-/extract-files-8.1.0.tgz",
"integrity": "sha512-PTGtfthZK79WUMk+avLmwx3NGdU8+iVFXC2NMGxKsn0MnihOG2lvumj+AZo8CTwTrwjXDgZ5tztbRlEdRjBonQ=="
},
"extract-zip": {
"version": "1.7.0",
"resolved": "https://registry.npm.taobao.org/extract-zip/download/extract-zip-1.7.0.tgz?cache=0&sync_timestamp=1591773082587&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fextract-zip%2Fdownload%2Fextract-zip-1.7.0.tgz",
@ -10750,6 +10760,15 @@
"resolved": "https://registry.npm.taobao.org/graceful-readlink/download/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
},
"graphql-hooks": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/graphql-hooks/-/graphql-hooks-4.5.0.tgz",
"integrity": "sha512-xwOHJssNrcS9RWQz8nTEY2SBXzMWE6GcoAgN8A1tPwQI0VBFKcRtpK2XAm7+g34bF6uJuJl5QP9bSZy0F9BN6w==",
"requires": {
"dequal": "^1.0.0",
"extract-files": "^8.0.0"
}
},
"growly": {
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/growly/download/growly-1.3.0.tgz",

View file

@ -38,6 +38,7 @@
"electron-window-state": "5.0.3",
"follow-redirects": "1.11.0",
"fs-extra": "9.0.1",
"graphql-hooks": "^4.5.0",
"is-url": "1.2.4",
"jimp": "0.13.0",
"menubar": "8.0.2",

View file

@ -1,7 +1,8 @@
// @flow
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { GraphQLClient, ClientContext, useQuery } from 'graphql-hooks';
import Paper from '@material-ui/core/Paper';
import FormControlLabel from '@material-ui/core/FormControlLabel';
@ -15,7 +16,15 @@ import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import FolderIcon from '@material-ui/icons/Folder';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import { GITHUB_GRAPHQL_API } from '../../constants/auth';
import GitHubLogin from '../github-login';
import SearchRepo from './search-repo';
import connectComponent from '../../helpers/connect-component';
import { updateForm, save, setWikiCreationMessage } from '../../state/dialog-add-workspace/actions';
@ -23,17 +32,27 @@ import { updateForm, save, setWikiCreationMessage } from '../../state/dialog-add
import {
requestCopyWikiTemplate,
requestCreateSubWiki,
requestSetPreference,
getPreference,
getIconPath,
getDesktopPath,
getWorkspaces,
countWorkspace,
} from '../../senders';
const graphqlClient = new GraphQLClient({
url: GITHUB_GRAPHQL_API,
});
const Container = styled.main`
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
overflow: scroll;
&::-webkit-scrollbar {
width: 0;
}
padding-bottom: 35px;
`;
const Description = styled(Paper)`
padding: 10px;
@ -67,12 +86,29 @@ const SoftLinkToMainWikiSelectInputLabel = styled(InputLabel)`
margin-top: 5px;
`;
const setGithubToken = (token: string) => requestSetPreference('github-token', token);
const getGithubToken = () => getPreference<string | null>('github-token');
const setGithubUsername = (username: string) => requestSetPreference('github-username', username);
const getGithubUsername = () => getPreference<string | null>('github-username');
function AddWorkspace({ wikiCreationMessage, onUpdateForm, onSave, onSetWikiCreationMessage }) {
const [isCreateMainWorkspace, isCreateMainWorkspaceSetter] = useState(countWorkspace() === 0);
const [parentFolderLocation, parentFolderLocationSetter] = useState(getDesktopPath());
const [wikiFolderLocation, wikiFolderLocationSetter] = useState('');
const [wikiPort, wikiPortSetter] = useState(5212 + countWorkspace());
// try get token from local storage, and set to state for gql to use
const setGraphqlClientHeader = useCallback((accessToken: string) => {
graphqlClient.setHeader('Authorization', `bearer ${accessToken}`);
setGithubToken(accessToken);
}, []);
useEffect(() => {
const accessToken = getGithubToken();
if (accessToken) {
setGraphqlClientHeader(accessToken);
}
}, [setGraphqlClientHeader]);
const [workspaces, workspacesSetter] = useState({});
useEffect(() => {
workspacesSetter(getWorkspaces());
@ -91,6 +127,7 @@ function AddWorkspace({ wikiCreationMessage, onUpdateForm, onSave, onSetWikiCrea
picturePath: getIconPath(),
};
return (
<ClientContext.Provider value={graphqlClient}>
<Container>
<Description elevation={0} square>
<FormControlLabel
@ -118,9 +155,15 @@ function AddWorkspace({ wikiCreationMessage, onUpdateForm, onSave, onSetWikiCrea
clientSecret="6015d1ca4ded86b4778ed39109193ff20c630bdd"
redirectUri="http://localhost"
scope="repo"
onSuccess={response => console.log(response)}
onSuccess={response => {
const accessToken = response?.userInfo?.thirdPartyIdentity?.accessToken;
if (accessToken) {
setGraphqlClientHeader(accessToken);
}
}}
onFailure={response => console.log(response)}
/>
{Object.keys(graphqlClient.headers).length > 0 && <SearchRepo />}
</SyncContainer>
<CreateContainer elevation={2} square>
@ -239,7 +282,7 @@ function AddWorkspace({ wikiCreationMessage, onUpdateForm, onSave, onSetWikiCrea
<Typography
variant="body2"
noWrap
display="inline-block"
display="inline"
align="center"
style={{ direction: 'rtl', textTransform: 'none' }}
>
@ -274,7 +317,7 @@ function AddWorkspace({ wikiCreationMessage, onUpdateForm, onSave, onSetWikiCrea
<Typography
variant="body2"
noWrap
display="inline-block"
display="inline"
align="center"
style={{ direction: 'rtl', textTransform: 'none' }}
>
@ -291,6 +334,7 @@ function AddWorkspace({ wikiCreationMessage, onUpdateForm, onSave, onSetWikiCrea
</CloseButton>
)}
</Container>
</ClientContext.Provider>
);
}

View file

@ -0,0 +1,77 @@
// @flow
import React, { useState } from 'react';
import styled from 'styled-components';
import { useQuery } from 'graphql-hooks';
import TextField from '@material-ui/core/TextField';
import FolderIcon from '@material-ui/icons/Folder';
import LinearProgress from '@material-ui/core/LinearProgress';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
const RepoSearchInput = styled(TextField)``;
const SEARCH_REPO_QUERY = `
query SearchRepo($queryString: String!) {
search(query: $queryString, type: REPOSITORY, first: 10) {
repositoryCount
edges {
node {
... on Repository {
name
url
}
}
}
}
}
`;
export default function SearchRepo() {
const [githubRepoSearchString, githubRepoSearchStringSetter] = useState('wiki');
const loadCount = 10;
const { loading, error, data } = useQuery(SEARCH_REPO_QUERY, {
variables: {
first: loadCount,
queryString: `user:linonetwo ${githubRepoSearchString}`,
},
});
const repositoryCount = data?.search?.repositoryCount;
let repoList = [];
if (repositoryCount) {
repoList = data.search.edges.map(({ node }) => node);
}
let helperText = '';
if (error) {
helperText = '无法加载仓库列表,网络不佳';
}
if (repositoryCount > loadCount) {
helperText = `仅展示前${loadCount}个结果`;
}
return (
<>
<RepoSearchInput
fullWidth
onChange={event => {
githubRepoSearchStringSetter(event.target.value);
}}
label="搜索Github仓库名"
value={githubRepoSearchString}
helperText={helperText}
/>
{loading && <LinearProgress variant="query" />}
<List component="nav" aria-label="main mailbox folders">
{repoList.map(({ name, url }) => (
<ListItem button key={url}>
<ListItemIcon>
<FolderIcon />
</ListItemIcon>
<ListItemText primary={name} />
</ListItem>
))}
</List>
</>
);
}

View file

@ -1,2 +1,3 @@
export const APP_ID = '5efdd30e56a87fb76b52809d'
export const APP_DOMAIN = 'tiddlygit-desktop.authing.cn'
export const APP_ID = '5efdd30e56a87fb76b52809d';
export const APP_DOMAIN = 'tiddlygit-desktop.authing.cn';
export const GITHUB_GRAPHQL_API = 'https://api.github.com/graphql';

View file

@ -1,9 +1,13 @@
// @flow
const { ipcRenderer } = window.require('electron');
export const requestCopyWikiTemplate = (newFolderPath, folderName) => ipcRenderer.invoke('copy-wiki-template', newFolderPath, folderName);
export const requestCreateSubWiki = (newFolderPath, folderName, mainWikiToLink) => ipcRenderer.invoke('create-sub-wiki', newFolderPath, folderName, mainWikiToLink);
export const requestStartTiddlyWiki = (wikiPath, port, userName) => ipcRenderer.send('request-start-tiddlywiki', wikiPath, port, userName);
export const requestOpenInBrowser = (url) => ipcRenderer.send('request-open-in-browser', url);
export const requestCopyWikiTemplate = (newFolderPath, folderName) =>
ipcRenderer.invoke('copy-wiki-template', newFolderPath, folderName);
export const requestCreateSubWiki = (newFolderPath, folderName, mainWikiToLink) =>
ipcRenderer.invoke('create-sub-wiki', newFolderPath, folderName, mainWikiToLink);
export const requestStartTiddlyWiki = (wikiPath, port, userName) =>
ipcRenderer.send('request-start-tiddlywiki', wikiPath, port, userName);
export const requestOpenInBrowser = url => ipcRenderer.send('request-open-in-browser', url);
export const requestShowMessageBox = (message, type) => ipcRenderer.send('request-show-message-box', message, type);
export const requestLoadUrl = (url, id) => ipcRenderer.send('request-load-url', url, id);
@ -13,67 +17,76 @@ export const requestGoForward = () => ipcRenderer.send('request-go-forward');
export const requestReload = () => ipcRenderer.send('request-reload');
export const requestQuit = () => ipcRenderer.send('request-quit');
export const requestCheckForUpdates = (isSilent) => ipcRenderer.send('request-check-for-updates', isSilent);
export const requestCheckForUpdates = isSilent => ipcRenderer.send('request-check-for-updates', isSilent);
export const requestShowAboutWindow = () => ipcRenderer.send('request-show-about-window');
export const requestShowAddWorkspaceWindow = () => ipcRenderer.send('request-show-add-workspace-window');
export const requestShowCodeInjectionWindow = (type) => ipcRenderer.send('request-show-code-injection-window', type);
export const requestShowCodeInjectionWindow = type => ipcRenderer.send('request-show-code-injection-window', type);
export const requestShowCustomUserAgentWindow = () => ipcRenderer.send('request-show-custom-user-agent-window');
export const requestShowEditWorkspaceWindow = (id) => ipcRenderer.send('request-show-edit-workspace-window', id);
export const requestShowEditWorkspaceWindow = id => ipcRenderer.send('request-show-edit-workspace-window', id);
export const requestShowLicenseRegistrationWindow = () => ipcRenderer.send('request-show-license-registration-window');
export const requestShowNotificationsWindow = () => ipcRenderer.send('request-show-notifications-window');
export const requestShowPreferencesWindow = (scrollTo) => ipcRenderer.send('request-show-preferences-window', scrollTo);
export const requestShowPreferencesWindow = scrollTo => ipcRenderer.send('request-show-preferences-window', scrollTo);
export const requestShowProxyWindow = () => ipcRenderer.send('request-show-proxy-window');
export const requestShowSpellcheckLanguagesWindow = () => ipcRenderer.send('request-show-spellcheck-languages-window');
// Notifications
export const requestShowNotification = (opts) => ipcRenderer.send('request-show-notification', opts);
export const requestShowNotification = opts => ipcRenderer.send('request-show-notification', opts);
export const requestUpdatePauseNotificationsInfo = () => ipcRenderer.send('request-update-pause-notifications-info');
export const getPauseNotificationsInfo = () => ipcRenderer.sendSync('get-pause-notifications-info');
// Preferences
export const getPreference = (name) => ipcRenderer.sendSync('get-preference', name);
// eslint-disable-next-line no-use-before-define
type JsonValue = string | number | boolean | null | JsonArray | JsonObject;
interface JsonObject {
[x: string]: JsonValue;
}
interface JsonArray extends Array<JsonValue> {} // tslint:disable-line no-empty-interface
export function getPreference<T=JsonValue>(name: string): T {
return ipcRenderer.sendSync('get-preference', name);
}
export const getPreferences = () => ipcRenderer.sendSync('get-preferences');
export const requestSetPreference = (name, value) => ipcRenderer.send('request-set-preference', name, value);
export const requestSetPreference = (name: string, value: JsonValue) =>
ipcRenderer.send('request-set-preference', name, value);
export const requestResetPreferences = () => ipcRenderer.send('request-reset-preferences');
export const requestShowRequireRestartDialog = () => ipcRenderer.send('request-show-require-restart-dialog');
// System Preferences
export const getSystemPreference = (name) => ipcRenderer.sendSync('get-system-preference', name);
export const getSystemPreferences = () => ipcRenderer.sendSync('get-system-preferences');
export const requestSetSystemPreference = (name, value) =>
export const getSystemPreference = (name: string): JsonValue => ipcRenderer.sendSync('get-system-preference', name);
export const getSystemPreferences = (): JsonObject => ipcRenderer.sendSync('get-system-preferences');
export const requestSetSystemPreference = (name: string, value: JsonValue) =>
ipcRenderer.send('request-set-system-preference', name, value);
// Workspace
export const countWorkspace = () => ipcRenderer.sendSync('count-workspace');
export const getWorkspace = (id) => ipcRenderer.sendSync('get-workspace', id);
export const getWorkspace = (id: string) => ipcRenderer.sendSync('get-workspace', id);
export const getWorkspaces = () => ipcRenderer.sendSync('get-workspaces');
export const requestClearBrowsingData = () => ipcRenderer.send('request-clear-browsing-data');
export const requestCreateWorkspace = (name, isSubWiki, port, homeUrl, picture, transparentBackground) =>
ipcRenderer.send('request-create-workspace', name, isSubWiki, port, homeUrl, picture, transparentBackground);
export const requestHibernateWorkspace = (id) => ipcRenderer.send('request-hibernate-workspace', id);
export const requestHibernateWorkspace = id => ipcRenderer.send('request-hibernate-workspace', id);
export const requestOpenUrlInWorkspace = (url, id) => ipcRenderer.send('request-open-url-in-workspace', url, id);
export const requestRealignActiveWorkspace = () => ipcRenderer.send('request-realign-active-workspace');
export const requestRemoveWorkspace = (id) => ipcRenderer.send('request-remove-workspace', id);
export const requestRemoveWorkspacePicture = (id) => ipcRenderer.send('request-remove-workspace-picture', id);
export const requestSetActiveWorkspace = (id) => ipcRenderer.send('request-set-active-workspace', id);
export const requestRemoveWorkspace = id => ipcRenderer.send('request-remove-workspace', id);
export const requestRemoveWorkspacePicture = id => ipcRenderer.send('request-remove-workspace-picture', id);
export const requestSetActiveWorkspace = id => ipcRenderer.send('request-set-active-workspace', id);
export const requestSetWorkspace = (id, opts) => ipcRenderer.send('request-set-workspace', id, opts);
export const requestSetWorkspaces = (workspaces) => ipcRenderer.send('request-set-workspaces', workspaces);
export const requestSetWorkspaces = workspaces => ipcRenderer.send('request-set-workspaces', workspaces);
export const requestSetWorkspacePicture = (id, picturePath) =>
ipcRenderer.send('request-set-workspace-picture', id, picturePath);
export const requestWakeUpWorkspace = (id) => ipcRenderer.send('request-wake-up-workspace', id);
export const requestWakeUpWorkspace = id => ipcRenderer.send('request-wake-up-workspace', id);
export const getIconPath = () => ipcRenderer.sendSync('get-constant', 'ICON_PATH');
export const getReactPath = () => ipcRenderer.sendSync('get-constant', 'REACT_PATH');
export const getDesktopPath = () => ipcRenderer.sendSync('get-constant', 'DESKTOP_PATH');
// Workspace Meta
export const getWorkspaceMeta = (id) => ipcRenderer.sendSync('get-workspace-meta', id);
export const getWorkspaceMeta = id => ipcRenderer.sendSync('get-workspace-meta', id);
export const getWorkspaceMetas = () => ipcRenderer.sendSync('get-workspace-metas');
// Find In Page
export const requestFindInPage = (text, forward) => ipcRenderer.send('request-find-in-page', text, forward);
export const requestStopFindInPage = (close) => ipcRenderer.send('request-stop-find-in-page', close);
export const requestStopFindInPage = close => ipcRenderer.send('request-stop-find-in-page', close);
// Auth
export const requestValidateAuthIdentity = (windowId, username, password) =>
@ -83,4 +96,4 @@ export const requestValidateAuthIdentity = (windowId, username, password) =>
export const getShouldUseDarkColors = () => ipcRenderer.sendSync('get-should-use-dark-colors');
// Online Status
export const signalOnlineStatusChanged = (online) => ipcRenderer.send('online-status-changed', online);
export const signalOnlineStatusChanged = online => ipcRenderer.send('online-status-changed', online);