sfdx-browserforce-plugin 6.2.1 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -197,7 +197,7 @@ FLAG DESCRIPTIONS
197
197
  The trace file can be viewed with "sf browserforce playwright -- show-trace trace-<date>.zip".
198
198
  ```
199
199
 
200
- _See code: [src/commands/browserforce/apply.ts](https://github.com/amtrack/sfdx-browserforce-plugin/blob/v6.2.1/src/commands/browserforce/apply.ts)_
200
+ _See code: [src/commands/browserforce/apply.ts](https://github.com/amtrack/sfdx-browserforce-plugin/blob/v6.3.0/src/commands/browserforce/apply.ts)_
201
201
 
202
202
  ## `sf browserforce playwright`
203
203
 
@@ -220,7 +220,7 @@ EXAMPLES
220
220
  $ sf browserforce playwright -- install chromium
221
221
  ```
222
222
 
223
- _See code: [src/commands/browserforce/playwright.ts](https://github.com/amtrack/sfdx-browserforce-plugin/blob/v6.2.1/src/commands/browserforce/playwright.ts)_
223
+ _See code: [src/commands/browserforce/playwright.ts](https://github.com/amtrack/sfdx-browserforce-plugin/blob/v6.3.0/src/commands/browserforce/playwright.ts)_
224
224
  <!-- commandsstop -->
225
225
 
226
226
  ## Playwright
@@ -8,6 +8,7 @@ import { HighVelocitySalesSettings as highVelocitySalesSettings } from './high-v
8
8
  import { HistoryTracking as historyTracking } from './history-tracking/index.js';
9
9
  import { HomePageLayouts as homePageLayouts } from './home-page-layouts/index.js';
10
10
  import { LightningExperienceSettings as lightningExperienceSettings } from './lightning-experience-settings/index.js';
11
+ import { ListViewCustomButtons as listViewCustomButtons } from './list-view-custom-buttons/index.js';
11
12
  import { LinkedInSalesNavigatorSettings as linkedInSalesNavigatorSettings } from './linkedin-sales-navigator-settings/index.js';
12
13
  import { OmniChannelSettings as omniChannelSettings } from './omni-channel-settings/index.js';
13
14
  import { OpportunitySplits as opportunitySplits } from './opportunity-splits/index.js';
@@ -22,4 +23,4 @@ import { Security as security } from './security/index.js';
22
23
  import { ServiceChannels as serviceChannels } from './service-channels/index.js';
23
24
  import { Slack as slack } from './slack/index.js';
24
25
  import { UserAccessPolicies as userAccessPolicies } from './user-access-policies/index.js';
25
- export { activitySettings, authProviders, companyInformation, customerPortal, densitySettings, emailDeliverability, highVelocitySalesSettings, historyTracking, homePageLayouts, lightningExperienceSettings, linkedInSalesNavigatorSettings, omniChannelSettings, opportunitySplits, permissionSets, picklists, recordTypes, relateContactToMultipleAccounts, reportsAndDashboards, salesforceCpqConfig, salesforceToSalesforce, security, serviceChannels, slack, userAccessPolicies, };
26
+ export { activitySettings, authProviders, companyInformation, customerPortal, densitySettings, emailDeliverability, highVelocitySalesSettings, historyTracking, homePageLayouts, lightningExperienceSettings, listViewCustomButtons, linkedInSalesNavigatorSettings, omniChannelSettings, opportunitySplits, permissionSets, picklists, recordTypes, relateContactToMultipleAccounts, reportsAndDashboards, salesforceCpqConfig, salesforceToSalesforce, security, serviceChannels, slack, userAccessPolicies, };
@@ -8,6 +8,7 @@ import { HighVelocitySalesSettings as highVelocitySalesSettings } from './high-v
8
8
  import { HistoryTracking as historyTracking } from './history-tracking/index.js';
9
9
  import { HomePageLayouts as homePageLayouts } from './home-page-layouts/index.js';
10
10
  import { LightningExperienceSettings as lightningExperienceSettings } from './lightning-experience-settings/index.js';
11
+ import { ListViewCustomButtons as listViewCustomButtons } from './list-view-custom-buttons/index.js';
11
12
  import { LinkedInSalesNavigatorSettings as linkedInSalesNavigatorSettings } from './linkedin-sales-navigator-settings/index.js';
12
13
  import { OmniChannelSettings as omniChannelSettings } from './omni-channel-settings/index.js';
13
14
  import { OpportunitySplits as opportunitySplits } from './opportunity-splits/index.js';
@@ -22,5 +23,5 @@ import { Security as security } from './security/index.js';
22
23
  import { ServiceChannels as serviceChannels } from './service-channels/index.js';
23
24
  import { Slack as slack } from './slack/index.js';
24
25
  import { UserAccessPolicies as userAccessPolicies } from './user-access-policies/index.js';
25
- export { activitySettings, authProviders, companyInformation, customerPortal, densitySettings, emailDeliverability, highVelocitySalesSettings, historyTracking, homePageLayouts, lightningExperienceSettings, linkedInSalesNavigatorSettings, omniChannelSettings, opportunitySplits, permissionSets, picklists, recordTypes, relateContactToMultipleAccounts, reportsAndDashboards, salesforceCpqConfig, salesforceToSalesforce, security, serviceChannels, slack, userAccessPolicies, };
26
+ export { activitySettings, authProviders, companyInformation, customerPortal, densitySettings, emailDeliverability, highVelocitySalesSettings, historyTracking, homePageLayouts, lightningExperienceSettings, listViewCustomButtons, linkedInSalesNavigatorSettings, omniChannelSettings, opportunitySplits, permissionSets, picklists, recordTypes, relateContactToMultipleAccounts, reportsAndDashboards, salesforceCpqConfig, salesforceToSalesforce, security, serviceChannels, slack, userAccessPolicies, };
26
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,IAAI,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,IAAI,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,kBAAkB,IAAI,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,cAAc,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,mBAAmB,IAAI,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,yBAAyB,IAAI,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACjH,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,2BAA2B,IAAI,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACtH,OAAO,EAAE,8BAA8B,IAAI,8BAA8B,EAAE,MAAM,8CAA8C,CAAC;AAChI,OAAO,EAAE,mBAAmB,IAAI,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC9F,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,cAAc,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,SAAS,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,+BAA+B,IAAI,+BAA+B,EAAE,MAAM,gDAAgD,CAAC;AACpI,OAAO,EAAE,oBAAoB,IAAI,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,mBAAmB,IAAI,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC9F,OAAO,EAAE,sBAAsB,IAAI,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AACvG,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,IAAI,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE3F,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,eAAe,EACf,2BAA2B,EAC3B,8BAA8B,EAC9B,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,WAAW,EACX,+BAA+B,EAC/B,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,KAAK,EACL,kBAAkB,GACnB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,IAAI,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,aAAa,IAAI,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,kBAAkB,IAAI,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,cAAc,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,mBAAmB,IAAI,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC7F,OAAO,EAAE,yBAAyB,IAAI,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACjH,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,2BAA2B,IAAI,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACtH,OAAO,EAAE,qBAAqB,IAAI,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACrG,OAAO,EAAE,8BAA8B,IAAI,8BAA8B,EAAE,MAAM,8CAA8C,CAAC;AAChI,OAAO,EAAE,mBAAmB,IAAI,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC9F,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,cAAc,IAAI,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,SAAS,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,+BAA+B,IAAI,+BAA+B,EAAE,MAAM,gDAAgD,CAAC;AACpI,OAAO,EAAE,oBAAoB,IAAI,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,EAAE,mBAAmB,IAAI,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC9F,OAAO,EAAE,sBAAsB,IAAI,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AACvG,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,IAAI,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE3F,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,eAAe,EACf,2BAA2B,EAC3B,qBAAqB,EACrB,8BAA8B,EAC9B,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,WAAW,EACX,+BAA+B,EAC/B,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,QAAQ,EACR,eAAe,EACf,KAAK,EACL,kBAAkB,GACnB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { BrowserforcePlugin } from '../../plugin.js';
2
+ type ListViewCustomButtonsConfig = {
3
+ objectApiName: string;
4
+ buttons: string[];
5
+ removeOtherButtons?: boolean | false;
6
+ };
7
+ export declare class ListViewCustomButtons extends BrowserforcePlugin {
8
+ retrieve(definition?: ListViewCustomButtonsConfig[]): Promise<ListViewCustomButtonsConfig[]>;
9
+ apply(plan: ListViewCustomButtonsConfig[]): Promise<void>;
10
+ private queryWebLinks;
11
+ }
12
+ export {};
@@ -0,0 +1,89 @@
1
+ import assert from 'assert';
2
+ import * as child from 'child_process';
3
+ import { fileURLToPath } from 'node:url';
4
+ import * as path from 'path';
5
+ import { ListViewCustomButtons } from './index.js';
6
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
7
+ describe(ListViewCustomButtons.name, function () {
8
+ let plugin;
9
+ before(() => {
10
+ plugin = new ListViewCustomButtons(global.browserforce);
11
+ });
12
+ const enableButtons = [
13
+ {
14
+ objectApiName: 'Task',
15
+ buttons: ['TestListButton', 'TestListButton2'],
16
+ removeOtherButtons: false,
17
+ },
18
+ {
19
+ objectApiName: 'Event',
20
+ buttons: ['TestListButton', 'TestListButton2'],
21
+ removeOtherButtons: false,
22
+ },
23
+ ];
24
+ const enableSingleButton = [
25
+ {
26
+ objectApiName: 'Task',
27
+ buttons: ['TestListButton'],
28
+ removeOtherButtons: false,
29
+ },
30
+ ];
31
+ const disableButtons = [
32
+ {
33
+ objectApiName: 'Task',
34
+ buttons: [],
35
+ removeOtherButtons: true,
36
+ },
37
+ ];
38
+ const missingButton = [
39
+ {
40
+ objectApiName: 'Task',
41
+ buttons: ['TestListButton', 'NonExistentButton'],
42
+ removeOtherButtons: false,
43
+ },
44
+ ];
45
+ it('should deploy test WebLink buttons as a prerequisite', () => {
46
+ const sourceDeployCmd = child.spawnSync('sf', [
47
+ 'project',
48
+ 'deploy',
49
+ 'start',
50
+ '-d',
51
+ path.join(__dirname, 'sfdx-source'),
52
+ '--json',
53
+ ]);
54
+ assert.deepStrictEqual(sourceDeployCmd.status, 0, sourceDeployCmd.output.toString());
55
+ });
56
+ it('should add both custom buttons to the list view', async () => {
57
+ await plugin.apply(enableButtons);
58
+ const res = await plugin.retrieve(enableButtons);
59
+ assert.deepStrictEqual(res, enableButtons);
60
+ });
61
+ it('should be idempotent when buttons are already selected', async () => {
62
+ const result = await plugin.run(enableButtons);
63
+ assert.deepStrictEqual(result, { message: 'no action necessary' });
64
+ });
65
+ it('should remove other buttons when removeOtherButtons is true', async () => {
66
+ await plugin.apply([{ objectApiName: 'Task', buttons: ['TestListButton'], removeOtherButtons: true }]);
67
+ const res = await plugin.retrieve([
68
+ { objectApiName: 'Task', buttons: ['TestListButton'], removeOtherButtons: true },
69
+ ]);
70
+ assert.deepStrictEqual(res, [{ objectApiName: 'Task', buttons: ['TestListButton'], removeOtherButtons: true }]);
71
+ });
72
+ it('should remove one button and keep the other', async () => {
73
+ await plugin.apply(enableSingleButton);
74
+ const res = await plugin.retrieve(enableSingleButton);
75
+ assert.deepStrictEqual(res, enableSingleButton);
76
+ });
77
+ it('should remove all custom buttons', async () => {
78
+ await plugin.apply(disableButtons);
79
+ const res = await plugin.retrieve(disableButtons);
80
+ assert.deepStrictEqual(res, disableButtons);
81
+ });
82
+ it('should add found button and warn about missing button without failing', async () => {
83
+ await plugin.apply(missingButton);
84
+ const res = await plugin.retrieve([{ objectApiName: 'Task', buttons: ['TestListButton'] }]);
85
+ assert.strictEqual(res[0].buttons.length, 1);
86
+ assert.strictEqual(res[0].buttons[0], 'TestListButton');
87
+ });
88
+ });
89
+ //# sourceMappingURL=index.e2e-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.e2e-spec.js","sourceRoot":"","sources":["../../../src/plugins/list-view-custom-buttons/index.e2e-spec.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,KAAK,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,QAAQ,CAAC,qBAAqB,CAAC,IAAI,EAAE;IACnC,IAAI,MAA6B,CAAC;IAClC,MAAM,CAAC,GAAG,EAAE;QACV,MAAM,GAAG,IAAI,qBAAqB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG;QACpB;YACE,aAAa,EAAE,MAAM;YACrB,OAAO,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;YAC9C,kBAAkB,EAAE,KAAK;SAC1B;QACD;YACE,aAAa,EAAE,OAAO;YACtB,OAAO,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;YAC9C,kBAAkB,EAAE,KAAK;SAC1B;KACF,CAAC;IAEF,MAAM,kBAAkB,GAAG;QACzB;YACE,aAAa,EAAE,MAAM;YACrB,OAAO,EAAE,CAAC,gBAAgB,CAAC;YAC3B,kBAAkB,EAAE,KAAK;SAC1B;KACF,CAAC;IAEF,MAAM,cAAc,GAAG;QACrB;YACE,aAAa,EAAE,MAAM;YACrB,OAAO,EAAE,EAAE;YACX,kBAAkB,EAAE,IAAI;SACzB;KACF,CAAC;IAEF,MAAM,aAAa,GAAG;QACpB;YACE,aAAa,EAAE,MAAM;YACrB,OAAO,EAAE,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;YAChD,kBAAkB,EAAE,KAAK;SAC1B;KACF,CAAC;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE;YAC5C,SAAS;YACT,QAAQ;YACR,OAAO;YACP,IAAI;YACJ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC;YACnC,QAAQ;SACT,CAAC,CAAC;QACH,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC/C,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvG,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;YAChC,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE;SACjF,CAAC,CAAC;QACH,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAClH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;QACtD,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAClD,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5F,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,101 @@
1
+ import { waitForPageErrors } from '../../browserforce.js';
2
+ import { BrowserforcePlugin } from '../../plugin.js';
3
+ const AVAILABLE_LISTBOX_NAME = 'Available Buttons';
4
+ const SELECTED_LISTBOX_NAME = 'Selected Buttons';
5
+ const SAVE_BUTTON_SELECTOR = 'input[name="save"]';
6
+ function buildPagePath(objectApiName) {
7
+ let pageObjApiName = objectApiName;
8
+ if (objectApiName === 'Task' || objectApiName === 'Event') {
9
+ pageObjApiName = 'Activity';
10
+ }
11
+ return `/p/setup/layout/ListButtonsEdit?LayoutEntity=${pageObjApiName}&retURL=${encodeURIComponent('/setup/forcecomHomepage.apexp')}`;
12
+ }
13
+ export class ListViewCustomButtons extends BrowserforcePlugin {
14
+ async retrieve(definition) {
15
+ const results = [];
16
+ for (const entry of definition) {
17
+ const page = await this.browserforce.openPage(buildPagePath(entry.objectApiName));
18
+ const selectedListbox = page.getByRole('listbox', { name: SELECTED_LISTBOX_NAME });
19
+ await selectedListbox.waitFor();
20
+ const buttonIds = (await Promise.all((await selectedListbox.locator('option').all()).map((opt) => opt.getAttribute('value'))))
21
+ .filter((b) => b?.trim() !== '')
22
+ .map((b) => `'${b?.trim()}'`);
23
+ const result = buttonIds.length > 0
24
+ ? await this.browserforce.connection.query(`SELECT Id, Name, NamespacePrefix FROM WebLink WHERE Id IN (${buttonIds.join(',')}) AND PageOrSobjectType = '${entry.objectApiName}'`)
25
+ : { records: [] };
26
+ const buttons = [];
27
+ for (const record of result.records) {
28
+ const fullApiName = record.NamespacePrefix ? `${record.NamespacePrefix}__${record.Name}` : record.Name;
29
+ buttons.push(fullApiName);
30
+ }
31
+ results.push({
32
+ objectApiName: entry.objectApiName,
33
+ buttons: buttons.sort(),
34
+ removeOtherButtons: entry.removeOtherButtons,
35
+ });
36
+ }
37
+ return results;
38
+ }
39
+ async apply(plan) {
40
+ for (const entry of plan) {
41
+ const buttons = await this.queryWebLinks(entry.buttons, entry.objectApiName);
42
+ const buttonApiNames = new Set(buttons.map((b) => (b.NamespacePrefix ? `${b.NamespacePrefix}__${b.Name}` : b.Name)));
43
+ const missingButtons = entry.buttons.filter((b) => !buttonApiNames.has(b));
44
+ if (missingButtons.length > 0) {
45
+ this.browserforce.logger?.warn(`[${entry.objectApiName}] WebLink(s) not found for button API name(s): ${missingButtons.map((b) => `"${b}"`).join(', ')}. Skipping missing buttons.`);
46
+ }
47
+ const targetButtonIds = buttons.map((b) => b.Id.slice(0, 15));
48
+ const page = await this.browserforce.openPage(buildPagePath(entry.objectApiName));
49
+ const availableListbox = page.getByRole('listbox', { name: AVAILABLE_LISTBOX_NAME });
50
+ const selectedListbox = page.getByRole('listbox', { name: SELECTED_LISTBOX_NAME });
51
+ await availableListbox.waitFor();
52
+ const availableButtonIds = (await Promise.all((await availableListbox.locator('option').all()).map((opt) => opt.getAttribute('value')))).map((b) => b?.trim() ?? '');
53
+ const selectedButtonIds = (await Promise.all((await selectedListbox.locator('option').all()).map((opt) => opt.getAttribute('value'))))
54
+ .map((b) => b?.trim() ?? '')
55
+ .filter((b) => b !== '');
56
+ const addButton = page.locator('img.rightArrowIcon');
57
+ const removeButton = page.locator('img.leftArrowIcon');
58
+ for (const buttonId of targetButtonIds) {
59
+ if (availableButtonIds.includes(buttonId) && !selectedButtonIds.includes(buttonId)) {
60
+ await availableListbox.selectOption({ value: buttonId });
61
+ await addButton.click();
62
+ await selectedListbox.locator(`option[value="${buttonId}"]`).waitFor();
63
+ }
64
+ }
65
+ if (entry.removeOtherButtons) {
66
+ for (const buttonId of selectedButtonIds) {
67
+ if (!targetButtonIds.includes(buttonId)) {
68
+ await selectedListbox.selectOption({ value: buttonId });
69
+ await removeButton.click();
70
+ await availableListbox.locator(`option[value="${buttonId}"]`).waitFor();
71
+ }
72
+ }
73
+ }
74
+ await page.locator(SAVE_BUTTON_SELECTOR).click();
75
+ await Promise.race([
76
+ page.waitForURL((url) => url.pathname === '/setup/forcecomHomepage.apexp'),
77
+ waitForPageErrors(page),
78
+ ]);
79
+ }
80
+ }
81
+ async queryWebLinks(apiNames, objectApiName) {
82
+ if (!apiNames?.length) {
83
+ return [];
84
+ }
85
+ const conditions = [];
86
+ for (const name of apiNames) {
87
+ const parts = name.split('__');
88
+ if (parts.length > 1) {
89
+ const namespace = parts[0];
90
+ const devName = parts.slice(1).join('__');
91
+ conditions.push(`(Name = '${devName}' AND NamespacePrefix = '${namespace}')`);
92
+ }
93
+ else {
94
+ conditions.push(`(Name = '${name}' AND NamespacePrefix = NULL)`);
95
+ }
96
+ }
97
+ const result = await this.browserforce.connection.query(`SELECT Id, Name, NamespacePrefix FROM WebLink WHERE (${conditions.join(' OR ')}) AND PageOrSobjectType = '${objectApiName}'`);
98
+ return result.records;
99
+ }
100
+ }
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/list-view-custom-buttons/index.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AACnD,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACjD,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AAclD,SAAS,aAAa,CAAC,aAAqB;IAC1C,IAAI,cAAc,GAAG,aAAa,CAAC;IACnC,IAAI,aAAa,KAAK,MAAM,IAAI,aAAa,KAAK,OAAO,EAAE,CAAC;QAC1D,cAAc,GAAG,UAAU,CAAC;IAC9B,CAAC;IAED,OAAO,gDAAgD,cAAc,WAAW,kBAAkB,CAAC,+BAA+B,CAAC,EAAE,CAAC;AACxI,CAAC;AAED,MAAM,OAAO,qBAAsB,SAAQ,kBAAkB;IACpD,KAAK,CAAC,QAAQ,CAAC,UAA0C;QAC9D,MAAM,OAAO,GAAkC,EAAE,CAAC;QAElD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;YAClF,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACnF,MAAM,eAAe,CAAC,OAAO,EAAE,CAAC;YAEhC,MAAM,SAAS,GAAG,CAChB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAC3G;iBACE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YAEhC,MAAM,MAAM,GACV,SAAS,CAAC,MAAM,GAAG,CAAC;gBAClB,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CACtC,8DAA8D,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,aAAa,GAAG,CACtI;gBACH,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAEtB,MAAM,OAAO,GAAG,EAAE,CAAC;YAEnB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,MAAM,WAAW,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,eAAe,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;gBACvG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC5B,CAAC;YAED,OAAO,CAAC,IAAI,CAAC;gBACX,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;gBACvB,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;aAC7C,CAAC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEM,KAAK,CAAC,KAAK,CAAC,IAAmC;QACpD,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAE7E,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,eAAe,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CACrF,CAAC;YACF,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAE3E,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAC5B,IAAI,KAAK,CAAC,aAAa,kDAAkD,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B,CACrJ,CAAC;YACJ,CAAC;YAED,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC;YAE/D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;YAClF,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;YACrF,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACnF,MAAM,gBAAgB,CAAC,OAAO,EAAE,CAAC;YAEjC,MAAM,kBAAkB,GAAG,CACzB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAC5G,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9B,MAAM,iBAAiB,GAAG,CACxB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAC3G;iBACE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;iBAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAE3B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;YACrD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;YAEvD,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;gBACvC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACnF,MAAM,gBAAgB,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;oBACzD,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;oBACxB,MAAM,eAAe,CAAC,OAAO,CAAC,iBAAiB,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBACzE,CAAC;YACH,CAAC;YAED,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;gBAC7B,KAAK,MAAM,QAAQ,IAAI,iBAAiB,EAAE,CAAC;oBACzC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACxC,MAAM,eAAe,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;wBACxD,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC;wBAC3B,MAAM,gBAAgB,CAAC,OAAO,CAAC,iBAAiB,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;oBAC1E,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,KAAK,EAAE,CAAC;YACjD,MAAM,OAAO,CAAC,IAAI,CAAC;gBACjB,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,+BAA+B,CAAC;gBAC1E,iBAAiB,CAAC,IAAI,CAAC;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,QAAkB,EAAE,aAAqB;QACnE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1C,UAAU,CAAC,IAAI,CAAC,YAAY,OAAO,4BAA4B,SAAS,IAAI,CAAC,CAAC;YAChF,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,IAAI,CAAC,YAAY,IAAI,+BAA+B,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CACrD,wDAAwD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,8BAA8B,aAAa,GAAG,CAC9H,CAAC;QAEF,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;CACF"}
@@ -173,5 +173,5 @@
173
173
  ]
174
174
  }
175
175
  },
176
- "version": "6.2.1"
176
+ "version": "6.3.0"
177
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sfdx-browserforce-plugin",
3
- "version": "6.2.1",
3
+ "version": "6.3.0",
4
4
  "description": "sfdx plugin for browser automation",
5
5
  "author": "Matthias Rolke <mr.amtrack@gmail.com>",
6
6
  "type": "module",