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

Checks for a list of sobjects and the corresponding create/edit/view qa directories. #50

Merged
merged 8 commits into from
Nov 8, 2023
183 changes: 106 additions & 77 deletions resources/instructions/createSObjectLwcQuickActions.html
Original file line number Diff line number Diff line change
@@ -1,81 +1,110 @@
<!doctype html>
<html lang="en">
<head>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, most of the changes is just the addition of the scripts in the html. I made mistake of reformatting doc without realizing.

<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Offline Starter Kit: Create sObject LWC Quick Actions</title>
</head>
<style>
h1 {
font-size: 16px;
}
h2 {
font-size: 14px;
}
table {
border-collapse: collapse;
}
table,
th,
td {
border-width: 1px;
border-style: solid;
}
th,
td {
text-align: center;
}
</style>
<body>
<h1>Create sObject LWC Quick Actions</h1>

<p>
The following sObjects are present in your configured landing page:
</p>

<table>
<thead>
<tr>
<th>sObject</th>
<th>LWC Quick Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>Contact</td>
<td>✅</td>
</tr>
<tr>
<td>Account</td>
<td>✅</td>
</tr>
<tr>
<td>Opportunity</td>
<td>❌</td>
</tr>
</tbody>
</table>

<label
style="display: block; margin-top: 10px; margin-bottom: 8px"
for="generateLwcQuickActionsButton"
>
Click 'Generate LWC Quick Actions' to create the missing LWC Quick
Actions:
</label>
<button id="generateLwcQuickActionsButton">
Generate LWC Quick Actions
</button>
<script>
const generateQuickActionsButtonElement = document.getElementById(

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Offline Starter Kit: Create sObject LWC Quick Actions</title>
</head>
<style>
h1 {
font-size: 16px;
}

h2 {
font-size: 14px;
}

table {
border-collapse: collapse;
}

table,
th,
td {
border-width: 1px;
border-style: solid;
}

th,
td {
text-align: center;
}
</style>

<body>
<h1>Create sObject LWC Quick Actions</h1>

<p>
The following sObjects are present in your configured landing page:
</p>

<table id="quickActionStatusTable">
<thead>
<tr>
<th rowspan="2">sObject</th>
<th colspan="3">LWC Quick Actions</th>
</tr>
<tr>
<th>view</th>
<th>edit</th>
<th>create</th>
</tr>
</thead>
<tbody>
<!-- will be filled in programatically below -->
</tbody>
</table>

<label style="display: block; margin-top: 10px; margin-bottom: 8px" for="generateLwcQuickActionsButton">
Click 'Generate LWC Quick Actions' to create the missing LWC Quick
Actions:
</label>
<button id="generateLwcQuickActionsButton">
Generate LWC Quick Actions
</button>
<script>
const generateQuickActionsButtonElement = document.getElementById(
'generateLwcQuickActionsButton'
);
generateQuickActionsButtonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest(
'generateLwcQuickActionsButton'
);
generateQuickActionsButtonElement.addEventListener('click', () => {
webviewMessaging.sendMessageRequest(
'generateLwcQuickActionsButton'
);
});
</script>
<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>
</html>
});

// Wait until all scripts are loaded, before engaging with e.g.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the meat of the change here -- makes a call to new function and dynamically generates table rows.

// messaging functionality.
window.addEventListener('load', () => {
// What's the status of the various sobject quick actions in the landing_page.json?
webviewMessaging.sendMessageRequest(
'getQuickActionStatus',
{},
handleQuickActionStatusResponse
);

});

function handleQuickActionStatusResponse(response) {
const table = document.getElementById('quickActionStatusTable');
for (const sobject in response.sobjects) {
const quickActions = response.sobjects[sobject];

const sobjectRow = table.insertRow();
const name = sobjectRow.insertCell(0);
const view = sobjectRow.insertCell(1);
const edit = sobjectRow.insertCell(2);
const create = sobjectRow.insertCell(3);

name.innerText = sobject;
view.innerHTML = quickActions.view == true ? "✅" : "❌";
edit.innerHTML = quickActions.edit == true ? "✅" : "❌";
create.innerHTML = quickActions.create == true ? "✅" : "❌";
}
}
</script>

<script src="--- MESSAGING_SCRIPT_SRC ---"></script>
</body>

</html>
85 changes: 85 additions & 0 deletions src/commands/wizard/lwcGenerationCommand.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import { Uri, l10n } from 'vscode';
import { InstructionsWebviewProvider } from '../../webviews/instructions';
import * as fs from 'fs';

export type QuickActionStatus = {
view: boolean;
edit: boolean;
create: boolean;
};

export type SObjectQuickActionStatus = {
sobjects: {
[name: string]: QuickActionStatus;
};
};

export class LwcGenerationCommand {
extensionUri: Uri;
Expand All @@ -22,9 +35,81 @@ export class LwcGenerationCommand {
panel.dispose();
return resolve();
}
},
{
type: 'getQuickActionStatus',
action: async (_panel, data, callback) => {
dbreese marked this conversation as resolved.
Show resolved Hide resolved
// TODO: Hook this up to function that parses landing_page.json.
const sobjects = [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just a hard-coded list for now.

'Account',
'Contact',
'Opportunity',
'SomeOther'
];
if (callback) {
const quickActionStatus =
await LwcGenerationCommand.checkForExistingQuickActions(
sobjects
);
callback(quickActionStatus);
}
}
}
]
);
});
}

static async checkForExistingQuickActions(
sobjects: string[]
): Promise<SObjectQuickActionStatus> {
return new Promise<SObjectQuickActionStatus>(async (resolve) => {
const results: SObjectQuickActionStatus = { sobjects: {} };
results.sobjects = {};
dbreese marked this conversation as resolved.
Show resolved Hide resolved

sobjects.forEach((sobject) => {
const quickActionStatus: QuickActionStatus = {
view: false,
edit: false,
create: false
};
quickActionStatus.view =
LwcGenerationCommand.checkForExistingQuickAction(
sobject,
'view'
);
quickActionStatus.edit =
LwcGenerationCommand.checkForExistingQuickAction(
sobject,
'edit'
);
quickActionStatus.create =
LwcGenerationCommand.checkForExistingQuickAction(
sobject,
'create'
);

results.sobjects[sobject] = quickActionStatus;
});

return resolve(results);
});
}

private static checkForExistingQuickAction(
sobject: string,
qaName: string
): boolean {
const expectedDirName = `${sobject}.${qaName}.quickAction-meta.xml`;
dbreese marked this conversation as resolved.
Show resolved Hide resolved
try {
// Check if the qa directory exists
const stats = fs.statSync(
`force-app/main/default/quickActions/${expectedDirName}`
);
return stats.isFile();
} catch (error) {
// If an error occurs, the directory does not exist
return false;
}
}
}
90 changes: 90 additions & 0 deletions src/test/suite/commands/wizard/lwcGenerationCommand.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/

import * as assert from 'assert';
import * as sinon from 'sinon';
import * as fs from 'fs';
import { afterEach, beforeEach } from 'mocha';
import {
LwcGenerationCommand,
SObjectQuickActionStatus,
QuickActionStatus
} from '../../../../commands/wizard/lwcGenerationCommand';

suite('LWC Generation Command Test Suite', () => {
beforeEach(function () {});

afterEach(function () {
sinon.restore();
});

test('Quick Action directories check', async () => {
const baseDir = 'force-app/main/default/quickActions';
const statSyncStub = sinon.stub(fs, 'statSync');
const statsStub = sinon.createStubInstance(fs.Stats);
statsStub.isFile.returns(true);

// stub the file system responses - any return value is a positive hit, an exception is a negative hit
statSyncStub
.withArgs(`${baseDir}/sobject1.view.quickAction-meta.xml`)
.returns(statsStub);
statSyncStub
.withArgs(`${baseDir}/sobject1.edit.quickAction-meta.xml`)
.returns(statsStub);
statSyncStub
.withArgs(`${baseDir}/sobject1.create.quickAction-meta.xml`)
.returns(statsStub);

statSyncStub
.withArgs(`${baseDir}/sobject2.view.quickAction-meta.xml`)
.throws('error');
statSyncStub
.withArgs(`${baseDir}/sobject2.edit.quickAction-meta.xml`)
.throws('error');
statSyncStub
.withArgs(`${baseDir}/sobject2.create.quickAction-meta.xml`)
.throws('error');

const result: SObjectQuickActionStatus =
await LwcGenerationCommand.checkForExistingQuickActions([
'sobject1',
'sobject2'
]);

assert.equal(
result.sobjects['sobject1'].view,
true,
'sobject1.view should exist'
);
assert.equal(
result.sobjects['sobject1'].edit,
true,
'sobject1.edit should exist'
);
assert.equal(
result.sobjects['sobject1'].create,
true,
'sobject1.create should exist'
);

assert.equal(
result.sobjects['sobject2'].view,
false,
'sobject2.view should NOT exist'
);
assert.equal(
result.sobjects['sobject2'].edit,
false,
'sobject2.edit should NOT exist'
);
assert.equal(
result.sobjects['sobject2'].create,
false,
'sobject2.create should NOT exist'
);
});
});