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: implement loading indicator #1

Merged
merged 1 commit into from
Apr 3, 2023
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
40 changes: 25 additions & 15 deletions src/controllers/requestController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ExtensionContext, Range, TextDocument, ViewColumn, window } from 'vscod
import Logger from '../logger';
import { IRestClientSettings, RequestSettings, RestClientSettings } from '../models/configurationSettings';
import { HistoricalHttpRequest, HttpRequest } from '../models/httpRequest';
import { HttpResponse } from '../models/httpResponse';
import { RequestMetadata } from '../models/requestMetadata';
import { RequestParserFactory } from '../models/requestParserFactory';
import { trace } from "../utils/decorator";
Expand Down Expand Up @@ -92,7 +93,9 @@ export class RequestController {
private async runCore(httpRequest: HttpRequest, settings: IRestClientSettings, document?: TextDocument) {
// clear status bar
this._requestStatusEntry.update({ state: RequestState.Pending });

const previewColumn = this.getPreviewColumn(settings);
this.renderView(settings, httpRequest, previewColumn);

// set last request and last pending request
this._lastPendingRequest = httpRequest;
this._lastRequestSettingTuple = [httpRequest, settings];
Expand All @@ -112,20 +115,7 @@ export class RequestController {
RequestVariableCache.add(document, httpRequest.name, response);
}

try {
const activeColumn = window.activeTextEditor!.viewColumn;
const previewColumn = settings.previewColumn === ViewColumn.Active
? activeColumn
: ((activeColumn as number) + 1) as ViewColumn;
if (settings.previewResponseInUntitledDocument) {
this._textDocumentView.render(response, previewColumn);
} else if (previewColumn) {
this._webview.render(response, previewColumn);
}
} catch (reason) {
Logger.error('Unable to preview response:', reason);
window.showErrorMessage(reason);
}
this.renderView(settings, response, previewColumn);

// persist to history json file
await UserDataManager.addToRequestHistory(HistoricalHttpRequest.convertFromHttpRequest(httpRequest));
Expand All @@ -152,6 +142,26 @@ export class RequestController {
}
}

private getPreviewColumn(settings: IRestClientSettings) {
const activeColumn = window.activeTextEditor!.viewColumn;
return settings.previewColumn === ViewColumn.Active
? activeColumn
: ((activeColumn as number) + 1) as ViewColumn;
}

private renderView(settings: IRestClientSettings, responseOrRequest: HttpResponse | HttpRequest, previewColumn?: ViewColumn) {
try {
if (settings.previewResponseInUntitledDocument) {
this._textDocumentView.render(responseOrRequest, previewColumn);
} else if (previewColumn) {
this._webview.render(responseOrRequest, previewColumn);
}
} catch (reason) {
Logger.error('Unable to preview response:', reason);
window.showErrorMessage(reason);
}
}

public dispose() {
this._requestStatusEntry.dispose();
this._webview.dispose();
Expand Down
24 changes: 14 additions & 10 deletions src/views/httpResponseTextDocumentView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { EOL } from 'os';
import { languages, Position, Range, TextDocument, ViewColumn, window, workspace } from 'vscode';
import { RequestHeaders, ResponseHeaders } from '../models/base';
import { SystemSettings } from '../models/configurationSettings';
import { HttpRequest } from '../models/httpRequest';
import { HttpResponse } from '../models/httpResponse';
import { PreviewOption } from '../models/previewOption';
import { MimeUtility } from '../utils/mimeUtility';
Expand All @@ -22,9 +23,9 @@ export class HttpResponseTextDocumentView {
});
}

public async render(response: HttpResponse, column?: ViewColumn) {
const content = this.getTextDocumentContent(response);
const language = this.getVSCodeDocumentLanguageId(response);
public async render(responseOrRequest: HttpResponse | HttpRequest, column?: ViewColumn) {
const content = this.getTextDocumentContent(responseOrRequest);
const language = this.getVSCodeDocumentLanguageId(responseOrRequest);
let document: TextDocument;
if (this.settings.showResponseInDifferentTab || this.documents.length === 0) {
document = await workspace.openTextDocument({ language, content });
Expand All @@ -42,12 +43,15 @@ export class HttpResponseTextDocumentView {
}
}

private getTextDocumentContent(response: HttpResponse): string {
private getTextDocumentContent(responseOrRequest: HttpResponse | HttpRequest): string {
if (responseOrRequest instanceof HttpRequest) {
return `Loading ${responseOrRequest.method} ${responseOrRequest.url}`;
}
let content = '';
const previewOption = this.settings.previewOption;
if (previewOption === PreviewOption.Exchange) {
// for add request details
const request = response.request;
const request = responseOrRequest.request;
content += `${request.method} ${request.url} HTTP/1.1${EOL}`;
content += this.formatHeaders(request.headers);
if (request.body) {
Expand All @@ -61,13 +65,13 @@ export class HttpResponseTextDocumentView {
}

if (previewOption !== PreviewOption.Body) {
content += `HTTP/${response.httpVersion} ${response.statusCode} ${response.statusMessage}${EOL}`;
content += this.formatHeaders(response.headers);
content += `HTTP/${responseOrRequest.httpVersion} ${responseOrRequest.statusCode} ${responseOrRequest.statusMessage}${EOL}`;
content += this.formatHeaders(responseOrRequest.headers);
}

if (previewOption !== PreviewOption.Headers) {
const prefix = previewOption === PreviewOption.Body ? '' : EOL;
content += `${prefix}${ResponseFormatUtility.formatBody(response.body, response.contentType, true)}`;
content += `${prefix}${ResponseFormatUtility.formatBody(responseOrRequest.body, responseOrRequest.contentType, true)}`;
}

return content;
Expand All @@ -82,9 +86,9 @@ export class HttpResponseTextDocumentView {
return headerString;
}

private getVSCodeDocumentLanguageId(response: HttpResponse) {
private getVSCodeDocumentLanguageId(responseOrRequest: HttpResponse | HttpRequest) {
if (this.settings.previewOption === PreviewOption.Body) {
const contentType = response.contentType;
const contentType = responseOrRequest.contentType;
if (MimeUtility.isJSON(contentType)) {
return 'json';
} else if (MimeUtility.isJavaScript(contentType)) {
Expand Down
51 changes: 37 additions & 14 deletions src/views/httpResponseWebview.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from 'fs-extra';
import * as os from 'os';
import { Readable } from 'stream';
import { Clipboard, commands, env, ExtensionContext, Uri, ViewColumn, WebviewPanel, window, workspace } from 'vscode';
import { RequestHeaders, ResponseHeaders } from '../models/base';
import { SystemSettings } from '../models/configurationSettings';
Expand Down Expand Up @@ -70,12 +71,12 @@ export class HttpResponseWebview extends BaseWebview {
this.context.subscriptions.push(commands.registerCommand('rest-client.save-response-body', this.saveBody, this));
}

public async render(response: HttpResponse, column: ViewColumn) {
public async render(responseOrRequest: HttpResponse | HttpRequest, column: ViewColumn) {
let panel: WebviewPanel;
if (this.settings.showResponseInDifferentTab || this.panels.length === 0) {
panel = window.createWebviewPanel(
this.viewType,
this.getTitle(response),
this.getTitle(responseOrRequest),
{ viewColumn: column, preserveFocus: !this.settings.previewResponsePanelTakeFocus },
{
enableFindWidget: true,
Expand Down Expand Up @@ -112,16 +113,18 @@ export class HttpResponseWebview extends BaseWebview {
this.panels.push(panel);
} else {
panel = this.panels[this.panels.length - 1];
panel.title = this.getTitle(response);
panel.title = this.getTitle(responseOrRequest);
}

panel.webview.html = this.getHtmlForWebview(panel, response);

panel.webview.html = this.getHtmlForWebview(panel, responseOrRequest);
this.setPreviewActiveContext(this.settings.previewResponsePanelTakeFocus);

panel.reveal(column, !this.settings.previewResponsePanelTakeFocus);

this.panelResponses.set(panel, response);
if (responseOrRequest instanceof HttpResponse) {
this.panelResponses.set(panel, responseOrRequest);
}


this.activePanel = panel;

this.setIsHTMLResponse(this.activeResponse);
Expand Down Expand Up @@ -206,9 +209,12 @@ export class HttpResponseWebview extends BaseWebview {
return defaultFileName;
}

private getTitle(response: HttpResponse): string {
const prefix = (this.settings.requestNameAsResponseTabTitle && response.request.name) || 'Response';
return `${prefix}(${response.timingPhases.total ?? 0}ms)`;
private getTitle(responseOrrequest: HttpResponse | HttpRequest): string {
if (responseOrrequest instanceof HttpRequest) {
return `Running request...`;
}
const prefix = (this.settings.requestNameAsResponseTabTitle && responseOrrequest.request.name) || 'Response';
return `${prefix}(${responseOrrequest.timingPhases.total ?? 0}ms)`;
}

private getFullResponseString(response: HttpResponse): string {
Expand All @@ -234,7 +240,20 @@ export class HttpResponseWebview extends BaseWebview {
}
}

private getHtmlForWebview(panel: WebviewPanel, response: HttpResponse): string {
private getHtmlForWebview(panel: WebviewPanel, responseOrRequest: HttpResponse | HttpRequest): string {
if (responseOrRequest instanceof HttpRequest) {
var message = 'Running...\n'
+ `${responseOrRequest.method} ${responseOrRequest.url}`
+ '\n';
if (typeof responseOrRequest.body === 'string') {
message += `Body-Length: ${responseOrRequest.body.length} bytes`;
}
if (responseOrRequest.body instanceof Readable) {
message += `Body-Length: ${responseOrRequest.body.readableLength} bytes`;
}
return this.getHtml(panel, `<pre><code>${this.addUrlLinks(this.addLineNums(message))}</code></pre>`, 1);
}
let response = responseOrRequest;
let innerHtml: string;
let width = 2;
let contentType = response.contentType;
Expand All @@ -249,6 +268,12 @@ export class HttpResponseWebview extends BaseWebview {
innerHtml = `<pre><code>${this.addLineNums(code)}</code></pre>`;
}

return this.getHtml(panel, this.settings.disableAddingHrefLinkForLargeResponse && response.bodySizeInBytes > this.settings.largeResponseBodySizeLimitInMB * 1024 * 1024
? innerHtml
: this.addUrlLinks(innerHtml), width);
}

private getHtml(panel: WebviewPanel, body: string, width: number) {
// Content Security Policy
const nonce = new Date().getTime() + '' + new Date().getMilliseconds();
const csp = this.getCsp(nonce);
Expand All @@ -268,9 +293,7 @@ export class HttpResponseWebview extends BaseWebview {
</head>
<body>
<div>
${this.settings.disableAddingHrefLinkForLargeResponse && response.bodySizeInBytes > this.settings.largeResponseBodySizeLimitInMB * 1024 * 1024
? innerHtml
: this.addUrlLinks(innerHtml)}
${body}
<a id="scroll-to-top" role="button" aria-label="scroll to top" title="Scroll To Top"><span class="icon"></span></a>
</div>
<script type="text/javascript" src="${panel.webview.asWebviewUri(this.scriptFilePath)}" nonce="${nonce}" charset="UTF-8"></script>
Expand Down