Skip to content

Commit 7b8ec0f

Browse files
author
埃博拉酱
committed
feat: add sidebar panel, i18n, token validation, and UX improvements
- Add sidebar.js: full actionable sidebar panel with 6 GitHub operations (Open Repo, Open Gist, Delete Gist, Delete Gist File, Update Token, Clear Cache) - Add Chinese/English i18n based on device locale detection (navigator.languages) - Token handling: normalize input (strip Bearer/token prefix, trim whitespace), validate format, and immediately verify against GitHub /user API on save - Enhanced API error messages: include GitHub's response message and documentation URL - Fix stale gh:// filesystem handlers from old plugin instances via global registry pattern (window.__acodeGithubFsTests__) for proper cleanup across plugin reloads - Prefetch repos/branches before opening palette to avoid misleading empty results - Show toast after opening repo folder guiding user to check file browser sidebar - Pass listFiles:false to openFolder to skip 'list all files may crash' prompt - Localize all user-facing strings: tutorial, commands, dialogs, toasts, settings - Update .gitignore to exclude pem files, debug server, and package-lock.json
1 parent 3430ec6 commit 7b8ec0f

File tree

5 files changed

+422
-55
lines changed

5 files changed

+422
-55
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
node_modules
22
yarn.lock
33
dist.zip
4-
dist
4+
dist
5+
*.pem
6+
debug-server.js
7+
package-lock.json

src/GitHubAPI/Requestable.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,23 @@ class Requestable {
5050
* @param {string} [AcceptHeader=v3] - the accept header for the requests
5151
*/
5252
constructor(auth, apiBase, AcceptHeader) {
53+
const normalizedToken = auth && auth.token
54+
? String(auth.token)
55+
.trim()
56+
.replace(/^Bearer\s+/i, '')
57+
.replace(/^token\s+/i, '')
58+
: auth.token;
59+
5360
this.__apiBase = apiBase || 'https://api.github.com';
5461
this.__auth = {
55-
token: auth.token,
62+
token: normalizedToken,
5663
username: auth.username,
5764
password: auth.password,
5865
};
5966
this.__AcceptHeader = AcceptHeader || 'v3';
6067

61-
if (auth.token) {
62-
this.__authorizationHeader = 'token ' + auth.token;
68+
if (normalizedToken) {
69+
this.__authorizationHeader = 'token ' + normalizedToken;
6370
} else if (auth.username && auth.password) {
6471
this.__authorizationHeader =
6572
'Basic ' + Base64.encode(auth.username + ':' + auth.password);
@@ -327,11 +334,22 @@ function callbackErrorOrThrow(cb, path) {
327334
return function handler(object) {
328335
let error;
329336
if (object.hasOwnProperty('config')) {
330-
const {
331-
response: { status, statusText },
332-
config: { method, url },
333-
} = object;
337+
const response = object.response || {};
338+
const config = object.config || {};
339+
const status = response.status;
340+
const statusText = response.statusText || '';
341+
const method = config.method || 'UNKNOWN';
342+
const url = config.url || 'UNKNOWN_URL';
343+
const ghMessage = response.data && response.data.message ? response.data.message : '';
344+
const docsUrl = response.data && response.data.documentation_url
345+
? ` (${response.data.documentation_url})`
346+
: '';
347+
334348
let message = `${status} error making request ${method} ${url}: "${statusText}"`;
349+
if (ghMessage) {
350+
message += ` | GitHub: ${ghMessage}${docsUrl}`;
351+
}
352+
335353
error = new ResponseError(message, path, object);
336354
log(`${message} ${JSON.stringify(object.data)}`);
337355
} else {

src/githubFs.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,33 @@ const prompt = acode.require('prompt');
1010
const encodings = acode.require('encodings');
1111

1212
const test = (url) => /^gh:/.test(url);
13+
const REGISTRY_KEY = '__acodeGithubFsTests__';
14+
15+
function _isZh() {
16+
try {
17+
const langs = [].concat(navigator.languages || [], navigator.language || []);
18+
return langs.some((l) => /^zh(?:-|$)/i.test(String(l || '')));
19+
} catch (_) { return false; }
20+
}
21+
function _t(en, zh) { return _isZh() ? zh : en; }
22+
23+
function getRegistry() {
24+
if (!window[REGISTRY_KEY]) {
25+
window[REGISTRY_KEY] = [];
26+
}
27+
return window[REGISTRY_KEY];
28+
}
29+
30+
function removeAllGithubFsHandlers() {
31+
const registry = getRegistry();
32+
registry.forEach((registeredTest) => {
33+
try { fsOperation.remove(registeredTest); } catch (_) {}
34+
});
35+
registry.length = 0;
36+
}
1337

1438
githubFs.remove = () => {
15-
fsOperation.remove(test);
39+
removeAllGithubFsHandlers();
1640
};
1741

1842
/**
@@ -41,6 +65,10 @@ githubFs.constructUrl = (type, user, repo, path, branch) => {
4165
};
4266

4367
export default function githubFs(token, settings) {
68+
// Ensure only one active gh:// handler even after plugin hot-reloads.
69+
removeAllGithubFsHandlers();
70+
getRegistry().push(test);
71+
4472
fsOperation.extend(test, (url) => {
4573
const { user, type, repo, path, gist } = parseUrl(url);
4674
if (type === 'repo') {
@@ -92,9 +120,9 @@ export default function githubFs(token, settings) {
92120
*/
93121
async function getCommitMessage(message) {
94122
if (settings.askCommitMessage) {
95-
const res = await prompt('Commit message', message, 'text');
123+
const res = await prompt(_t('Commit message', '提交信息'), message, 'text');
96124
if (!res) {
97-
const error = new Error('Commit aborted');
125+
const error = new Error(_t('Commit aborted', '提交已取消'));
98126
error.code = 0;
99127
error.toString = () => error.message;
100128
throw error;

0 commit comments

Comments
 (0)