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

Webviews: Two-way messaging #46

Merged
merged 7 commits into from
Oct 27, 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
8 changes: 7 additions & 1 deletion resources/instructions/briefcase.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand All @@ -20,6 +20,12 @@
If you've already configured a briefcase, move on to the next step.
</p>
<button id="okButton">OK</button>
<script>
const okButtonElement = document.getElementById('okButton');
okButtonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest('okButton');
});
</script>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>
</html>
44 changes: 27 additions & 17 deletions resources/instructions/landingpage.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
<!DOCTYPE html>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't give this page too much scrutiny, as it's going away imminently. I just updated for completeness sake.

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Landing Page Customization</title>
</head>

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Landing Page Customization</title>
</head>

<body>
<p id="message">A default landing page file (landing_page.json) has been created in the staticresources directory.
See <a href="https://help.salesforce.com/s/articleView?id=sf.salesforce_app_plus_offline_landing_page.htm&type=5">Customize The Landing Page</a>
for more information on how to modify the landing page file.
</p>
<button id="okButton">OK</button>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>

</html>
<body>
<p id="message">
A default landing page file (landing_page.json) has been created in
the staticresources directory. See
<a
href="https://help.salesforce.com/s/articleView?id=sf.salesforce_app_plus_offline_landing_page.htm&type=5"
>
Customize The Landing Page
</a>
for more information on how to modify the landing page file.
</p>
<button id="okButton">OK</button>
<script>
const okButtonElement = document.getElementById('okButton');
okButtonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest('okButton');
});
</script>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>
</html>
8 changes: 7 additions & 1 deletion resources/instructions/projectBootstrapAcknowledgment.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand All @@ -13,6 +13,12 @@
time to resume.
</p>
<button id="okButton">OK</button>
<script>
const okButtonElement = document.getElementById('okButton');
okButtonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest('okButton');
});
</script>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>
</html>
10 changes: 9 additions & 1 deletion resources/instructions/projectBootstrapChoice.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand All @@ -14,6 +14,14 @@ <h1>Welcome to the Offline App Onboarding Wizard</h1>
</p>
<button id="createNewButton">Create New Project</button>
<button id="openExistingButton">Open Existing Project</button>
<script>
for (const buttonId of ['createNewButton', 'openExistingButton']) {
const buttonElement = document.getElementById(buttonId);
buttonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest(buttonId);
});
}
</script>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>
</html>
8 changes: 7 additions & 1 deletion resources/instructions/salesforcemobileapp.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand All @@ -21,6 +21,12 @@
own.
</p>
<button id="okButton">OK</button>
<script>
const okButtonElement = document.getElementById('okButton');
okButtonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest('okButton');
});
</script>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>
</html>
68 changes: 49 additions & 19 deletions resources/instructions/webviewMessaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,53 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/

const vscode = acquireVsCodeApi();
// ------------------
// Callback Messaging
// ------------------
//
// Async, callback-based messaging mechanism for clients
//
const webviewMessaging = (function () {
const vscode = acquireVsCodeApi();
let requestId = 0;
const asyncMessageCallbacks = {};

// Set up button event handlers and message passing.
const buttons = document.getElementsByTagName("button");
if (!buttons || buttons.length === 0) {
console.error("No buttons found! No event handlers will be created.");
} else {
for (const button of buttons) {
const buttonId = button.getAttribute("id");
if (!buttonId) {
console.error(
"Button has no id value! No event handler will be created."
);
} else {
button.addEventListener("click", () => {
vscode.postMessage({ button: buttonId });
});
}
}
}
// Receives messages from the backing TypeScript controller page that
// created the hosted webview. These messages will be linked back to
// originating requests, passing any response data back to the async
// caller.
window.addEventListener('message', (event) => {
const message = event.data;
if (message.callbackId && asyncMessageCallbacks[message.callbackId]) {
const callback = asyncMessageCallbacks[message.callbackId];
delete asyncMessageCallbacks[message.callbackId];
delete message.callbackId;
callback(message);
}
});

return {
/**
* Sends a message request to the backing TypeScript controller page that
* created the hosted webview.
* @param {string} type - A name representing the type of request. Basically
* the event key to which the controller page will subscribe.
* @param {object} [data] - An optional block of input data to pass to the
* controller.
* @param {Function} [callback] - An optional callback for receiving a
* response from the controller, if expected.
*/
sendMessageRequest: function (type, data, callback) {
let message;
if (callback) {
const asyncMessageRequestId = ++requestId;
asyncMessageCallbacks[asyncMessageRequestId] = callback;

message = { type, callbackId: asyncMessageRequestId, ...data };
} else {
message = { type, ...data };
}
vscode.postMessage(message);
}
};
})();
2 changes: 1 addition & 1 deletion src/commands/wizard/authorizeCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class AuthorizeCommand {
if (!result || result.title === l10n.t('No')) {
return Promise.resolve(false);
} else {
await commands.executeCommand('sfdx.force.auth.web.login');
await commands.executeCommand('sfdx.org.login.web');
Copy link
Collaborator Author

@khawkins khawkins Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually broken in the current code in main. 😔 Apparently the command names moved on and we didn't know it.

await window.showInformationMessage(
l10n.t(
"Once you've authorized your Org, click here to continue."
Expand Down
2 changes: 1 addition & 1 deletion src/commands/wizard/briefcaseCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { ProgressLocation, Uri, window, l10n } from 'vscode';
import { CommonUtils } from '@salesforce/lwc-dev-mobile-core/lib/common/CommonUtils';
import { InstructionsWebviewProvider } from '../../webviews';
import { InstructionsWebviewProvider } from '../../webviews/instructions';

export class BriefcaseCommand {
static readonly OPEN_ORG_BRIEFCASE_PAGE_CMD =
Expand Down
8 changes: 4 additions & 4 deletions src/commands/wizard/configureProjectCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { Uri, WebviewPanel, commands, l10n, window } from 'vscode';
import * as process from 'process';
import { CommonUtils } from '@salesforce/lwc-dev-mobile-core/lib/common/CommonUtils';
import { InstructionsWebviewProvider } from '../../webviews';
import { InstructionsWebviewProvider } from '../../webviews/instructions';

export type ProjectManagementChoiceAction = (panel?: WebviewPanel) => void;

Expand Down Expand Up @@ -41,7 +41,7 @@ export class DefaultProjectConfigurationProcessor
'resources/instructions/projectBootstrapAcknowledgment.html',
[
{
buttonId: 'okButton',
type: 'okButton',
action: async (panel) => {
panel.dispose();
return resolve();
Expand Down Expand Up @@ -98,13 +98,13 @@ export class DefaultProjectConfigurationProcessor
'resources/instructions/projectBootstrapChoice.html',
[
{
buttonId: 'createNewButton',
type: 'createNewButton',
action: (panel) => {
createChoice(panel);
}
},
{
buttonId: 'openExistingButton',
type: 'openExistingButton',
action: (panel) => {
openChoice(panel);
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/wizard/onboardingWizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { BriefcaseCommand } from './briefcaseCommand';
import { DeployToOrgCommand } from './deployToOrgCommand';
import { ConfigureProjectCommand } from './configureProjectCommand';
import { AuthorizeCommand } from './authorizeCommand';
import { InstructionsWebviewProvider } from '../../webviews';
import { InstructionsWebviewProvider } from '../../webviews/instructions';

const wizardCommand = 'salesforcedx-vscode-offline-app.onboardingWizard';
const onboardingWizardStateKey =
Expand Down
2 changes: 1 addition & 1 deletion src/commands/wizard/templateChooserCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { UIUtils } from '../../utils/uiUtils';
import { workspace } from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import { InstructionsWebviewProvider } from '../../webviews';
import { InstructionsWebviewProvider } from '../../webviews/instructions';

export interface TemplateQuickPickItem extends QuickPickItem {
filenamePrefix: string;
Expand Down
2 changes: 1 addition & 1 deletion src/test/suite/commands/wizard/briefcaseCommand.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { afterEach, beforeEach } from 'mocha';
import { BriefcaseCommand } from '../../../../commands/wizard/briefcaseCommand';
import { Uri, l10n, window, Progress, CancellationToken } from 'vscode';
import { CommonUtils } from '@salesforce/lwc-dev-mobile-core/lib/common/CommonUtils';
import { InstructionsWebviewProvider } from '../../../../webviews';
import { InstructionsWebviewProvider } from '../../../../webviews/instructions';

suite('Briefcase Command Test Suite', () => {
beforeEach(function () {});
Expand Down
Loading