Skip to content

Commit 7f788e2

Browse files
committed
feat: add GitHub OAuth Token support
1 parent 13b5e54 commit 7f788e2

16 files changed

Lines changed: 556 additions & 74 deletions

File tree

Lines changed: 1 addition & 0 deletions
Loading

extensions/github1s/assets/main.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
(function () {
2+
const vscode = acquireVsCodeApi();
3+
4+
const updateState = (state) => {
5+
const prevState = vscode.getState();
6+
vscode.setState({ ...prevState, ...state });
7+
updatePage();
8+
};
9+
10+
window.addEventListener('message', ({ data }) => {
11+
if (data && data.type === 'update-state') {
12+
updateState(data.payload);
13+
}
14+
});
15+
vscode.postMessage({ type: 'initialization', payload: null });
16+
17+
const delegate = (element, selector, eventName, handler) => {
18+
if (!element) return null;
19+
element.addEventListener(eventName, function (event) {
20+
const children = element.querySelectorAll(selector);
21+
for (let i = 0, len = children.length; i < len; i++) {
22+
if (children[i] === event.target) {
23+
handler.call(this, event);
24+
}
25+
}
26+
});
27+
};
28+
29+
delegate(document.body, '#save-button', 'click', () => {
30+
const tokenInput = document.getElementById('token-input');
31+
vscode.postMessage({ type: 'update-token', payload: tokenInput ? tokenInput.value : '' });
32+
});
33+
34+
delegate(document.body, '#preview-button', 'click', () => {
35+
updateState({ pageType: 'PREVIEW' });
36+
});
37+
38+
delegate(document.body, '#validate-button', 'click', () => {
39+
const state = vscode.getState();
40+
vscode.postMessage({ type: 'validate-token', payload: state ? state.token : '' });
41+
});
42+
43+
delegate(document.body, '#edit-button', 'click', () => {
44+
updateState({ pageType: 'EDIT' });
45+
});
46+
47+
delegate(document.body, '#clear-button', 'click', () => {
48+
vscode.postMessage({ type: 'clear-token' });
49+
});
50+
51+
const updatePage = () => {
52+
const { token, pageType, valid, validating } = vscode.getState() || { token: '', preview: 'EDIT', valid: true, validating: true };
53+
if (validating) {
54+
document.querySelector('.loading-page').style.display = 'block';
55+
document.querySelector('.preview-page').style.display = 'none';
56+
document.querySelector('.edit-page').style.display = 'none';
57+
return;
58+
}
59+
60+
if (pageType === 'EDIT') {
61+
document.querySelector('.loading-page').style.display = 'none';
62+
document.querySelector('.preview-page').style.display = 'none';
63+
document.querySelector('.edit-page').style.display = 'block';
64+
document.querySelector('#preview-button').style.display = (token ? 'block' : 'none');
65+
return;
66+
}
67+
68+
document.querySelector('.loading-page').style.display = 'none';
69+
document.querySelector('.edit-page').style.display = 'none';
70+
document.querySelector('.preview-page').style.display = 'block';
71+
document.querySelector('.container .token-status .token-status-text').innerText = (valid ? ' VALID' : ' INVALID');
72+
document.querySelector('#token-text').innerText = token.slice(0, 7) + token.slice(7).replace(/./g, '*');
73+
document.querySelector('#token-text').style.color = (valid ? '#73c991' : '#f88070');
74+
};
75+
})();
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
html {
2+
box-sizing: border-box;
3+
font-size: 13px;
4+
}
5+
6+
*,
7+
*:before,
8+
*:after {
9+
box-sizing: inherit;
10+
}
11+
12+
body, h1, h2, h3, h4, h5, h6, p, ol, ul {
13+
margin: 0;
14+
padding: 0;
15+
font-weight: normal;
16+
}
17+
18+
body {
19+
background-color: transparent;
20+
}
21+
22+
input {
23+
display: block;
24+
width: 100%;
25+
height: 24px;
26+
border: none;
27+
margin-bottom: 10px;
28+
padding-left: 4px;
29+
padding-right: 4px;
30+
font-family: var(--vscode-font-family);
31+
color: var(--vscode-input-foreground);
32+
outline-color: var(--vscode-input-border);
33+
background-color: var(--vscode-input-background);
34+
}
35+
36+
button {
37+
border: none;
38+
width: 100%;
39+
height: 26px;
40+
margin-bottom: 10px;
41+
padding: var(--input-padding-vertical) var(--input-padding-horizontal);
42+
text-align: center;
43+
outline: 1px solid transparent;
44+
outline-offset: 2px !important;
45+
color: var(--vscode-button-foreground);
46+
background: var(--vscode-button-background);
47+
}
48+
49+
button:hover {
50+
cursor: pointer;
51+
background: var(--vscode-button-hoverBackground);
52+
}
53+
54+
button:focus {
55+
outline-color: var(--vscode-focusBorder);
56+
}
57+
58+
button.secondary {
59+
color: var(--vscode-button-secondaryForeground);
60+
background: var(--vscode-button-secondaryBackground);
61+
}
62+
63+
button.secondary:hover {
64+
background: var(--vscode-button-secondaryHoverBackground);
65+
}
66+
67+
.loading-page {
68+
width: 50px;
69+
height: 40px;
70+
margin: 60px auto;
71+
text-align: center;
72+
}
73+
74+
.loading-page span {
75+
width: 5px;
76+
height: 100%;
77+
margin-right: 4px;
78+
display: inline-block;
79+
background:#2b6298;
80+
animation: loading 1.2s infinite ease-in-out;
81+
-webkit-animation: loading 1.2s infinite ease-in-out;
82+
}
83+
84+
.loading-page >span:nth-child(2) {
85+
-webkit-animation-delay: -1.0s;
86+
animation-delay: -1.0s;
87+
}
88+
89+
.loading-page >span:nth-child(3) {
90+
-webkit-animation-delay: -0.9s;
91+
animation-delay: -0.9s;
92+
}
93+
94+
.loading-page >span:nth-child(4) {
95+
-webkit-animation-delay: -0.8s;
96+
animation-delay: -0.8s;
97+
}
98+
99+
.loading-page >span:nth-child(5) {
100+
-webkit-animation-delay: -0.7s;
101+
animation-delay: -0.7s;
102+
}
103+
104+
@keyframes loading {
105+
0% { transform: scaleY(0.4); }
106+
25% { transform: scaleY(1.0); }
107+
50% { transform: scaleY(0.4); }
108+
75% { transform: scaleY(0.4); }
109+
100% { transform: scaleY(0.4); }
110+
}
111+
112+
@-webkit-keyframes loading {
113+
0% { transform: scaleY(0.4); }
114+
25% { transform: scaleY(1.0); }
115+
50% { transform: scaleY(0.4); }
116+
75% { transform: scaleY(0.4); }
117+
100% { transform: scaleY(0.4); }
118+
}
119+
120+
.preview-page, .edit-page {
121+
display: none;
122+
}
123+
124+
.container {
125+
padding: 10px;
126+
}
127+
128+
.container .token-invalid {
129+
display: none;
130+
}
131+
132+
.page-title {
133+
font-size: 16px;
134+
font-weight: bold;
135+
margin-bottom: 10px;
136+
}
137+
138+
.description {
139+
margin-bottom: 10px;
140+
}
141+
142+
.description div {
143+
margin-bottom: 5px;
144+
}
145+
146+
.description div:last-child {
147+
margin-bottom: 0;
148+
}
149+
150+
.token-link {
151+
margin-bottom: 10px;
152+
}

extensions/github1s/package.json

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "github1s-vscode-extension",
2+
"name": "github1s",
33
"version": "0.0.0",
44
"publisher": "github1s",
55
"description": "",
@@ -16,7 +16,26 @@
1616
"engines": {
1717
"vscode": "^1.48.0"
1818
},
19-
"contributes": {},
19+
"contributes": {
20+
"viewsContainers": {
21+
"activitybar": [
22+
{
23+
"id": "github1s",
24+
"title": "GitHub1s",
25+
"icon": "assets/github1s.svg"
26+
}
27+
]
28+
},
29+
"views": {
30+
"github1s": [
31+
{
32+
"id": "github1s-settings",
33+
"name": "Settings",
34+
"type": "webview"
35+
}
36+
]
37+
}
38+
},
2039
"scripts": {
2140
"clean": "rm -rf dist out",
2241
"build": "webpack --config extension.webpack.config.js --mode production",

extensions/github1s/src/api.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @file GitHub1s APIs
3+
* @author netcon
4+
*/
5+
6+
import * as vscode from 'vscode';
7+
import { fetch } from './util';
8+
9+
interface UriState {
10+
owner: string;
11+
repo: string;
12+
branch: string;
13+
path: string;
14+
};
15+
16+
const parseUri = (uri: vscode.Uri): UriState => {
17+
const [owner, repo, branch] = (uri.authority || '').split('+').filter(Boolean);
18+
return {
19+
owner,
20+
repo,
21+
branch,
22+
path: uri.path,
23+
};
24+
};
25+
26+
export const readGitHubDirectory = (uri: vscode.Uri) => {
27+
const state: UriState = parseUri(uri);
28+
return fetch(`https://api.github.com/repos/${state.owner}/${state.repo}/git/trees/${state.branch}${state.path.replace(/^\//, ':')}`);
29+
};
30+
31+
export const readGitHubFile = (uri: vscode.Uri, fileSha: string) => {
32+
const state: UriState = parseUri(uri);
33+
return fetch(`https://api.github.com/repos/${state.owner}/${state.repo}/git/blobs/${fileSha}`);
34+
};
35+
36+
export const validateToken = (token) => {
37+
return self.fetch(`https://api.github.com`, { headers: { Authorization: `token ${token}` } })
38+
.then(response => (+response.status < 400));
39+
};

extensions/github1s/src/extension.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
*/
55

66
import * as vscode from 'vscode';
7-
import { Github1sFS } from './githubfs';
8-
import { prop } from './util';
9-
import { RepoState } from './types';
7+
import { GitHub1sFS } from './github1sfs';
8+
import { SettingsView } from './settings-view';
9+
import { setExtensionContext } from './util';
1010

1111
export function activate(context: vscode.ExtensionContext) {
12-
const authority = prop(vscode.workspace, ['workspaceFolders', 0, 'uri', 'authority']) as string || '';
13-
const [owner, repo, branch] = authority.split('/');
14-
const repoState: RepoState = { owner, repo, branch };
15-
context.subscriptions.push(new Github1sFS(repoState));
12+
setExtensionContext(context);
13+
context.subscriptions.push(new GitHub1sFS());
14+
context.subscriptions.push(
15+
vscode.window.registerWebviewViewProvider(SettingsView.viewType, new SettingsView())
16+
);
1617
};

0 commit comments

Comments
 (0)