mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-25 22:11:35 -08:00
refactor: Create workspace page
This commit is contained in:
parent
6114794732
commit
346e963122
30 changed files with 137 additions and 112 deletions
63
src/components/github/git-token-form.tsx
Normal file
63
src/components/github/git-token-form.tsx
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
|
||||
import GitHubLogin from './github-login';
|
||||
import type { IAuthingUserInfo, IAuthingResponse } from '@services/types';
|
||||
|
||||
const GitTokenInput = styled(TextField)``;
|
||||
|
||||
export const setGithubToken = async (token: string | undefined): Promise<void> => await window.service.auth.set('github-token', token);
|
||||
export const getGithubToken = async (): Promise<string | undefined> => await window.service.auth.get('github-token');
|
||||
|
||||
export function GithubTokenForm(props: {
|
||||
accessTokenSetter: (token?: string) => void;
|
||||
userInfoSetter: (info?: IAuthingUserInfo) => void;
|
||||
accessToken: string;
|
||||
children: JSX.Element;
|
||||
}): JSX.Element {
|
||||
const { accessToken, children } = props;
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<GitHubLogin
|
||||
onSuccess={(response: IAuthingResponse) => {
|
||||
const accessTokenToSet = response?.userInfo?.thirdPartyIdentity?.accessToken;
|
||||
const authDataString = response?.userInfo?.oauth;
|
||||
if (accessTokenToSet !== undefined) {
|
||||
props.accessTokenSetter(accessTokenToSet);
|
||||
}
|
||||
// all data we need
|
||||
if (accessTokenToSet !== undefined && authDataString !== undefined) {
|
||||
const authData = JSON.parse(authDataString);
|
||||
const nextUserInfo = {
|
||||
...response.userInfo,
|
||||
...authData,
|
||||
...response.userInfo.thirdPartyIdentity,
|
||||
};
|
||||
delete nextUserInfo.oauth;
|
||||
delete nextUserInfo.thirdPartyIdentity;
|
||||
props.userInfoSetter(nextUserInfo as IAuthingUserInfo);
|
||||
}
|
||||
}}
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
onLogout={(response: any) => props.accessTokenSetter()}
|
||||
onFailure={(response: any) => {
|
||||
props.accessTokenSetter();
|
||||
props.userInfoSetter();
|
||||
}}
|
||||
/>
|
||||
<GitTokenInput
|
||||
helperText={t('AddWorkspace.GitTokenDescription')}
|
||||
fullWidth
|
||||
onChange={(event) => {
|
||||
props.accessTokenSetter(event.target.value);
|
||||
}}
|
||||
value={accessToken ?? ''}
|
||||
/>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
113
src/components/github/github-login.tsx
Normal file
113
src/components/github/github-login.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* eslint-disable promise/no-nesting */
|
||||
import React, { Component } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import GithubIcon from '@material-ui/icons/GitHub';
|
||||
import AuthingSSO from '@authing/sso';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
|
||||
import { APP_DOMAIN, APP_ID } from '../../constants/auth';
|
||||
|
||||
const SyncToGithubButton = styled(Button)`
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
t: (x: string) => string;
|
||||
onRequest: Function;
|
||||
onSuccess: Function;
|
||||
onLogout: Function;
|
||||
onFailure: Function;
|
||||
}
|
||||
interface State {
|
||||
isLogin: boolean;
|
||||
}
|
||||
class GitHubLogin extends Component<Props, State> {
|
||||
static defaultProps = {
|
||||
onRequest: () => {},
|
||||
onSuccess: () => {},
|
||||
onLogout: () => {},
|
||||
onFailure: () => {},
|
||||
};
|
||||
|
||||
auth: typeof AuthingSSO;
|
||||
intervalHandel: IntervalID;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLogin: false,
|
||||
};
|
||||
this.auth = new AuthingSSO({
|
||||
appId: APP_ID,
|
||||
appDomain: APP_DOMAIN,
|
||||
redirectUrl: 'http://localhost:3000',
|
||||
});
|
||||
this.updateLoginState();
|
||||
}
|
||||
|
||||
async isLogin(): boolean {
|
||||
const { onSuccess, onLogout } = this.props;
|
||||
const { session, ...rest } = await this.auth.trackSession();
|
||||
const isLogin = session !== null && session !== undefined;
|
||||
if (isLogin) {
|
||||
onSuccess(rest);
|
||||
} else {
|
||||
onLogout();
|
||||
}
|
||||
return isLogin;
|
||||
}
|
||||
|
||||
updateLoginState(): void {
|
||||
this.intervalHandel = setInterval(() => {
|
||||
// eslint-disable-next-line promise/catch-or-return, promise/always-return
|
||||
this.isLogin().then((isLogin) => {
|
||||
this.setState({ isLogin });
|
||||
clearInterval(this.intervalHandel);
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const { onRequest, onLogout, onFailure, t } = this.props;
|
||||
const { isLogin } = this.state;
|
||||
return isLogin ? (
|
||||
<SyncToGithubButton
|
||||
onClick={async () => {
|
||||
const { code, message } = await this.auth.logout();
|
||||
await window.service.window.clearStorageData();
|
||||
if (code === 200) {
|
||||
this.setState({ isLogin: false });
|
||||
this.updateLoginState();
|
||||
onLogout();
|
||||
} else {
|
||||
console.error(message);
|
||||
}
|
||||
}}
|
||||
color="secondary"
|
||||
endIcon={<GithubIcon />}>
|
||||
{t('AddWorkspace.LogoutGithubAccount')}
|
||||
</SyncToGithubButton>
|
||||
) : (
|
||||
<SyncToGithubButton
|
||||
onClick={() => {
|
||||
// clear token first, otherwise github login window won't give us a chance to see the form
|
||||
// void this.auth.logout();
|
||||
// window.remote.clearStorageData();
|
||||
try {
|
||||
onRequest();
|
||||
this.auth.login();
|
||||
} catch (error) {
|
||||
onFailure(error);
|
||||
}
|
||||
}}
|
||||
color="secondary"
|
||||
endIcon={<GithubIcon />}>
|
||||
{t('AddWorkspace.LoginGithubAccount')}
|
||||
</SyncToGithubButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTranslation()(GitHubLogin);
|
||||
57
src/components/github/stated-menu.tsx
Normal file
57
src/components/github/stated-menu.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import React from 'react';
|
||||
import Menu from '@material-ui/core/Menu';
|
||||
interface Props {
|
||||
buttonElement: React.ReactElement;
|
||||
id: string;
|
||||
}
|
||||
type State = any;
|
||||
class StatedMenu extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
anchorEl: undefined,
|
||||
open: false,
|
||||
};
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleRequestClose = this.handleRequestClose.bind(this);
|
||||
}
|
||||
|
||||
handleClick(event: any) {
|
||||
this.setState({ open: true, anchorEl: event.currentTarget });
|
||||
}
|
||||
|
||||
handleRequestClose() {
|
||||
this.setState({ open: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { buttonElement, children, id } = this.props;
|
||||
const { anchorEl, open } = this.state;
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(buttonElement, {
|
||||
'aria-owns': id,
|
||||
'aria-haspopup': true,
|
||||
onClick: this.handleClick,
|
||||
})}
|
||||
<Menu id={id} anchorEl={anchorEl} open={open} onClose={this.handleRequestClose} anchorOrigin={{ vertical: 'top', horizontal: 'center' }}>
|
||||
{React.Children.map(
|
||||
children,
|
||||
(child) =>
|
||||
child &&
|
||||
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
|
||||
React.cloneElement(child, {
|
||||
onClick: () => {
|
||||
if ((child as any).props.onClick) {
|
||||
(child as any).props.onClick();
|
||||
}
|
||||
this.handleRequestClose();
|
||||
},
|
||||
}),
|
||||
)}
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default StatedMenu;
|
||||
Loading…
Add table
Add a link
Reference in a new issue