import { Button, Callout, Dialog, InputGroup, Intent } from '@blueprintjs/core'; import { clipboard, shell } from 'electron'; import { observer } from 'mobx-react'; import * as React from 'react'; import { getOctokit } from '../../utils/octokit'; import { AppState } from '../state'; interface TokenDialogProps { appState: AppState; } interface TokenDialogState { tokenInput: string; verifying: boolean; error: boolean; } const TOKEN_SCOPES = ['gist'].join(); const TOKEN_DESCRIPTION = encodeURIComponent('Fiddle Gist Token'); const GENERATE_TOKEN_URL = `https://github.com/settings/tokens/new?scopes=${TOKEN_SCOPES}&description=${TOKEN_DESCRIPTION}`; /** * The token dialog asks the user for a GitHub Personal Access Token. * It's also responsible for checking if the token is correct. * * @export * @class TokenDialog * @extends {React.Component} */ @observer export class TokenDialog extends React.Component< TokenDialogProps, TokenDialogState > { constructor(props: TokenDialogProps) { super(props); this.state = { verifying: false, error: false, tokenInput: '', }; this.onSubmitToken = this.onSubmitToken.bind(this); this.openGenerateTokenExternal = this.openGenerateTokenExternal.bind(this); this.onTokenInputFocused = this.onTokenInputFocused.bind(this); this.handleChange = this.handleChange.bind(this); this.onClose = this.onClose.bind(this); } /** * Handles the submission of a token * * @returns {Promise} * @memberof TokenDialog */ public async onSubmitToken(): Promise { if (!this.state.tokenInput) return; this.setState({ verifying: true }); this.props.appState.gitHubToken = this.state.tokenInput; const octo = await getOctokit(this.props.appState); try { const { data } = await octo.users.getAuthenticated(); this.props.appState.gitHubAvatarUrl = data.avatar_url; this.props.appState.gitHubLogin = data.login; this.props.appState.gitHubName = data.name; this.setState({ verifying: false, error: false }); } catch (error) { console.warn(`Authenticating against GitHub failed`, error); this.setState({ verifying: false, error: true }); this.props.appState.gitHubToken = null; return; } this.props.appState.isTokenDialogShowing = false; } /** * Closes the dialog */ public onClose() { this.props.appState.isTokenDialogShowing = false; this.reset(); } /** * Reset this component's state */ public reset(): void { this.setState({ verifying: false, error: false, tokenInput: '', }); } /** * Opens GitHub's page for token generation * * @memberof TokenDialog */ public openGenerateTokenExternal() { shell.openExternal(GENERATE_TOKEN_URL); } /** * When the input field receives focus, we check the clipboard. * Maybe there's already something token-like there! * * @returns * @memberof TokenDialog */ public onTokenInputFocused() { const text = (clipboard.readText() || '').trim(); if (text.length !== 40) return; if (!/^[a-z0-9]+$/.test(text)) return; this.setState({ tokenInput: text }); } /** * Handle the change event, which usually just updates the address bar's value * * @param {React.ChangeEvent} event * @memberof AddressBar */ public handleChange(event: React.ChangeEvent) { this.setState({ tokenInput: event.target.value }); } get buttons() { const canSubmit = !!this.state.tokenInput; return [