Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:Added functionality to retrieve and save GitHub token (#812) #839

Merged
merged 10 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"mini-css-extract-plugin": "^2.7.2",
"mkdirp": "^1.0.4",
"prettier": "^3.3.3",
"pretty-quick": "^3.1.3",
"pretty-quick": "^4.0.0",
"querystring": "^0.2.1",
"sass": "^1.52.1",
"sass-loader": "^12.4.0",
Expand Down
19 changes: 19 additions & 0 deletions src/api/githubApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getToken, saveToken } from '../helpers/github-token';

export const githubRequest = async (endpoint: string, options: RequestInit = {}): Promise<any | null> => {
const token = getToken();
if (!token) {
return null;
}

try {
const response = await fetch(`https://api.github.com${endpoint}`, {
...options,
});
return response.json();
} catch (error) {
return null;
}
};

export { saveToken, getToken };
7 changes: 7 additions & 0 deletions src/helpers/github-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const saveToken = (token: string) => {
localStorage.setItem('github_token', token);
};

export const getToken = (): string => {
return localStorage.getItem('github_token') || '';
};
26 changes: 25 additions & 1 deletion src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,29 @@
"activity_icon": "activity",
"openrank_icon": "openrank",
"contributors_participants_icon": "contributors and participants",
"merged_lines_icon": "code lines change"
"merged_lines_icon": "code lines change",
"github_token_configuration": "GitHub Token Configuration",
"github_token_tooltip": "Enter your GitHub Token here for authentication.",
"github_token_description": "Providing a GitHub Token ensures that HyperCRX can securely and effectively access and operate on your GitHub data for personalized analysis.",
"github_token_how_to_generate": "How to generate a GitHub Token?",
"github_token_step1": "1. Log in to GitHub and go to Settings.",
"github_token_step2": "2. Select Developer settings.",
"github_token_step3": "3. Choose Personal access tokens, click Tokens(classic), then Generate a personal access token.",
"github_token_step4": "4. Set token details:",
"github_token_note": "Note",
"github_token_note_description": "A descriptive name, e.g., \"HyperCrx Token\".",
"github_token_expiration": "Expiration",
"github_token_expiration_description": "Choose the validity period.",
"github_token_scopes": "Scopes",
"github_token_scopes_description": "Select permission scopes, such as repo and workflow.",
"github_token_step5": "5. Click the Generate token button.",
"github_token_step6": "6. Copy the generated token and paste it into the input box below.",
"github_token_placeholder": "GitHub Token",
"github_token_save": "Save",
"github_token_edit": "Edit",
"github_token_test": "Test Token",
"github_token_error_empty": "Token cannot be empty",
"github_token_success_save": "Token saved successfully",
"github_token_success_valid": "Token is valid. Username: {{username}}",
"github_token_error_invalid": "Invalid token or request failed"
}
26 changes: 25 additions & 1 deletion src/locales/zh_CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,29 @@
"activity_icon": "activity数",
"openrank_icon": "openrank值",
"contributors_participants_icon": "contributors和participants数",
"merged_lines_icon": "代码变化量"
"merged_lines_icon": "代码变化量",
"github_token_configuration": "GitHub 令牌配置",
"github_token_tooltip": "在此输入您的 GitHub 令牌以进行身份验证。",
"github_token_description": "提供 GitHub 令牌可确保 HyperCRX 能够安全有效地访问和操作您的 GitHub 数据以进行个性化分析。",
"github_token_how_to_generate": "如何生成 GitHub 令牌?",
"github_token_step1": "1. 登录 GitHub 并进入设置。",
"github_token_step2": "2. 选择开发者设置。",
"github_token_step3": "3. 选择个人访问令牌,Tokens(classic),然后生成个人访问令牌。",
"github_token_step4": "4. 设置令牌详细信息:",
"github_token_note": "注意",
"github_token_note_description": "描述性名称,例如“HyperCrx Token",
"github_token_expiration": "过期时间",
"github_token_expiration_description": "选择有效期。",
"github_token_scopes": "权限范围",
"github_token_scopes_description": "选择权限范围,例如 repo 和 workflow。",
"github_token_step5": "5. 点击生成令牌按钮。",
"github_token_step6": "6. 复制生成的令牌并将其粘贴到下面的输入框中。",
"github_token_placeholder": "GitHub 令牌",
"github_token_save": "保存",
"github_token_edit": "编辑",
"github_token_test": "测试令牌",
"github_token_error_empty": "令牌不能为空",
"github_token_success_save": "令牌保存成功",
"github_token_success_valid": "令牌有效。用户名:{{username}}",
"github_token_error_invalid": "令牌无效或请求失败"
}
56 changes: 56 additions & 0 deletions src/pages/Options/Options.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,59 @@ li {
a {
color: blue;
}

.github-token-options {
width: 75vw;
min-width: 350px;
max-width: 600px;
background-color: white;
border: 1px solid #e1e4e8;
border-radius: 6px;
margin-top: -10px;
}

.github-token-options .Box-header {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
padding: 0 25px;
margin: -1px -1px 0;
background-color: #242a2e;
color: white;
border: 1px solid #e1e4e8;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}

.github-token-options .Box-title {
font-size: 18px;
font-weight: 600;
margin-right: 8px;
}

.github-token-options p {
padding: 0 25px;
}

.github-token-options input {
width: calc(100% - 50px);
padding: 8px;
margin: 10px 25px;
border: 1px solid #ccc;
border-radius: 4px;
}

.github-token-options button {
padding: 8px 16px;
margin: 0 25px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}

.github-token-options button:hover {
background-color: #0056b3;
}
22 changes: 17 additions & 5 deletions src/pages/Options/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import TooltipTrigger from '../../components/TooltipTrigger';
import './Options.css';
import { useTranslation } from 'react-i18next';
import '../../helpers/i18n';
import GitHubToken from './components/GitHubToken';

const stacksStyleOptions = {
headerStack: {
paddingBottom: '10px',
Expand All @@ -17,6 +19,9 @@ const stacksStyleOptions = {
settingStack: {
margin: '10px 25px',
},
tokenStack: {
margin: '10px 25px',
},
};

const Options = (): JSX.Element => {
Expand Down Expand Up @@ -64,11 +69,7 @@ const Options = (): JSX.Element => {
</Space>
</Row>

<Row
justify="center"
style={stacksStyleOptions.mainStack}
gutter={[30, 30]} // 设置间距
>
<Row justify="center" style={stacksStyleOptions.mainStack} gutter={[30, 30]}>
<Col
span={24}
style={{
Expand Down Expand Up @@ -146,6 +147,17 @@ const Options = (): JSX.Element => {
</div>
</div>
</Col>
<Col
span={24}
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
margin: stacksStyleOptions.tokenStack.margin,
}}
>
<GitHubToken /> {/* Add GitHubToken component */}
</Col>
</Row>
</Space>
</div>
Expand Down
134 changes: 134 additions & 0 deletions src/pages/Options/components/GitHubToken.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React, { useState, useEffect, useRef } from 'react';
import TooltipTrigger from '../../../components/TooltipTrigger';
import { saveToken, getToken, githubRequest } from '../../../api/githubApi';
import { message } from 'antd';
import { useTranslation } from 'react-i18next';

const GitHubToken = () => {
const [token, setToken] = useState('');
const [isCollapsed, setIsCollapsed] = useState(true);
const [isEditing, setIsEditing] = useState(false);
const { t } = useTranslation();
const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
const storedToken = getToken();
if (storedToken) {
setToken(storedToken);
}
}, []);

const handleSave = () => {
if (!token.trim()) {
showMessage(t('github_token_error_empty'), 'error');
return;
}
saveToken(token);
showMessage(t('github_token_success_save'), 'success');
setIsEditing(false);
};

const handleEdit = () => {
setIsEditing(true);
};

const handleTestToken = async () => {
const userData = await githubRequest('/user', {
headers: { Authorization: `Bearer ${token}` },
});

if (userData === null || userData.message) {
showMessage(t('github_token_error_invalid'), 'error');
} else {
showMessage(t('github_token_success_valid', { username: userData.login }), 'success');
}
};

const obfuscateToken = (token: string): string => {
if (token.length <= 4) return token;
return `${token[0]}${'*'.repeat(token.length - 2)}${token[token.length - 1]}`;
};

const showMessage = (content: string, type: 'success' | 'error') => {
if (inputRef.current) {
const rect = inputRef.current.getBoundingClientRect();
message.config({
top: rect.top - 50,
duration: 2,
maxCount: 3,
});
message[type](content);
}
};

return (
<div className="github-token-options Box">
<div className="Box-header">
<h2 className="Box-title">{t('github_token_configuration')}</h2>
<TooltipTrigger content={t('github_token_tooltip')} />
</div>
<p>{t('github_token_description')}</p>
<div className="collapsible-section">
<div
className="collapsible-header"
onClick={() => setIsCollapsed(!isCollapsed)}
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}
>
<p>{t('github_token_how_to_generate')}</p>
<span style={{ marginLeft: '5px' }}>{isCollapsed ? '▶' : '▼'}</span>
</div>
{!isCollapsed && (
<div className="instructions Box-body">
<ol>
<li>{t('github_token_step1')}</li>
<li>{t('github_token_step2')}</li>
<li>{t('github_token_step3')}</li>
<li>
{t('github_token_step4')}
<ul>
<li>
<strong>{t('github_token_note')}</strong>: {t('github_token_note_description')}
</li>
<li>
<strong>{t('github_token_expiration')}</strong>: {t('github_token_expiration_description')}
</li>
<li>
<strong>{t('github_token_scopes')}</strong>: {t('github_token_scopes_description')}
</li>
</ul>
</li>
<li>{t('github_token_step5')}</li>
<li>{t('github_token_step6')}</li>
</ol>
</div>
)}
</div>
<div style={{ marginBottom: '10px' }} id="message-container"></div>
<div style={{ display: 'flex', alignItems: 'center' }}>
<input
type="text"
ref={inputRef}
value={isEditing ? token : obfuscateToken(token)}
onChange={(e) => setToken(e.target.value)}
placeholder={t('github_token_placeholder')}
style={{ marginRight: '10px', flex: 1 }}
disabled={!isEditing}
/>
{isEditing ? (
<button onClick={handleSave} style={{ marginRight: '10px', marginTop: '17px' }}>
{t('github_token_save')}
</button>
) : (
<button onClick={handleEdit} style={{ marginRight: '10px', marginTop: '17px' }}>
{t('github_token_edit')}
</button>
)}
<button onClick={handleTestToken} style={{ marginTop: '17px' }}>
{t('github_token_test')}
</button>
</div>
</div>
);
};

export default GitHubToken;
Loading
Loading