Skip to content

Commit 249da31

Browse files
committed
Improve Login to DevSandbox button workflow
Signed-off-by: Jessica He <jhe@redhat.com>
1 parent 9815ad2 commit 249da31

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

src/openshift/cluster.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,11 @@ export class Cluster extends OpenShiftItem {
500500
);
501501
}
502502

503+
static validateLoginToken(token: string): boolean {
504+
const sha256Regex = new RegExp('^sha256~([A-Za-z0-9_]+)');
505+
return sha256Regex.test(token);
506+
}
507+
503508
@vsCommand('openshift.explorer.login.clipboard')
504509
static async loginUsingClipboardToken(apiEndpointUrl: string, oauthRequestTokenUrl: string): Promise<string | null> {
505510
const clipboard = await Cluster.readFromClipboard();

src/webview/cluster/app/clusterView.scss

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,27 @@
7979
.buttonSecondary:disabled {
8080
opacity: 0.4 !important;
8181
}
82+
83+
.buttonRed {
84+
white-space: nowrap !important;
85+
display: inline-block !important;
86+
margin-top: 8px !important;
87+
margin-right: 8px !important;
88+
background-color: #EE0000 !important;
89+
color: white !important;
90+
}
91+
92+
.buttonRed:hover {
93+
color: white !important;
94+
background-color: #BE0000 !important;
95+
cursor: pointer !important;
96+
}
97+
98+
.buttonRed:focus {
99+
background-color: #BE0000 !important;
100+
cursor: pointer !important;
101+
}
102+
103+
.buttonRed:disabled {
104+
opacity: 0.4 !important;
105+
}

src/webview/cluster/app/sandboxView.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ export default function addSandboxView(props): JSX.Element {
382382
postMessage('sandboxLoginUsingDataInClipboard', {apiEndpointUrl: currentState.apiEndpoint, oauthRequestTokenUrl: `${currentState.oauthTokenEndpoint}/request`});
383383
};
384384

385+
const invalidToken = currentState.errorCode === 'invalidToken';
386+
const loginSandboxTitle = !invalidToken ? 'Login to DevSandbox OpenShift cluster with token from clipboard' : 'Token in clipboard is invalid. Select the Get Token option and copy to clipboard';
387+
385388
return (
386389
<>
387390
{( currentState.action === 'sandboxPageProvisioned' ) && (
@@ -410,11 +413,11 @@ export default function addSandboxView(props): JSX.Element {
410413
<Tooltip title='Launch your DevSandbox console in browser' placement='bottom'>
411414
<Button variant='contained' className='button' href={currentState.consoleDashboard}>Open Dashboard</Button>
412415
</Tooltip>
413-
<Tooltip title='Copy token from DevSandbox console page in browser' placement='bottom'>
416+
<Tooltip title='Open the DevSandbox console page and copy the login token' placement='bottom'>
414417
<Button variant='contained' className='button' href={`${currentState.oauthTokenEndpoint}/request`}>Get token</Button>
415418
</Tooltip>
416-
<Tooltip title='Login to DevSandbox OpenShift cluster with token from clipboard' placement='bottom'>
417-
<Button variant='contained' className='buttonSecondary' onClick={handleLoginButton}>Login to DevSandbox</Button>
419+
<Tooltip title={loginSandboxTitle} placement='bottom'>
420+
<span><Button variant='contained' disabled={invalidToken} className='buttonRed' onClick={handleLoginButton}>Login to DevSandbox</Button></span>
418421
</Tooltip>
419422
</div>
420423
)}

src/webview/cluster/clusterViewLoader.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,12 @@ async function clusterEditorMessageListener (event: any ): Promise<any> {
110110
} else {
111111
if (signupStatus.status.ready) {
112112
const oauthInfo = await sandboxAPI.getOauthServerInfo(signupStatus.apiEndpoint);
113-
panel.webview.postMessage({action: 'sandboxPageProvisioned', statusInfo: signupStatus.username, consoleDashboard: signupStatus.consoleURL, apiEndpoint: signupStatus.apiEndpoint, oauthTokenEndpoint: oauthInfo.token_endpoint });
113+
let errCode = '';
114+
if (!Cluster.validateLoginToken(await vscode.env.clipboard.readText())) {
115+
errCode = 'invalidToken';
116+
}
117+
panel.webview.postMessage({ action: 'sandboxPageProvisioned', statusInfo: signupStatus.username, consoleDashboard: signupStatus.consoleURL, apiEndpoint: signupStatus.apiEndpoint, oauthTokenEndpoint: oauthInfo.token_endpoint, errorCode: errCode });
118+
pollClipboard(signupStatus);
114119
} else {
115120
// cluster is not ready and the reason is
116121
if (signupStatus.status.verificationRequired) {
@@ -185,6 +190,22 @@ async function clusterEditorMessageListener (event: any ): Promise<any> {
185190
}
186191
}
187192

193+
async function pollClipboard(signupStatus) {
194+
const oauthInfo = await sandboxAPI.getOauthServerInfo(signupStatus.apiEndpoint);
195+
while (panel) {
196+
const previousContent = await vscode.env.clipboard.readText();
197+
await new Promise(r => setTimeout(r, 500));
198+
const currentContent = await vscode.env.clipboard.readText();
199+
if (previousContent && previousContent !== currentContent) {
200+
let errCode = '';
201+
if (!Cluster.validateLoginToken(currentContent)){
202+
errCode = 'invalidToken';
203+
}
204+
panel.webview.postMessage({action: 'sandboxPageProvisioned', statusInfo: signupStatus.username, consoleDashboard: signupStatus.consoleURL, apiEndpoint: signupStatus.apiEndpoint, oauthTokenEndpoint: oauthInfo.token_endpoint, errorCode: errCode});
205+
}
206+
}
207+
}
208+
188209
export default class ClusterViewLoader {
189210
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
190211
static get extensionPath() {

0 commit comments

Comments
 (0)