From e1f80b570669f3229f6b39c71daf64131fdd7bb5 Mon Sep 17 00:00:00 2001 From: Matthias Rolke Date: Fri, 18 Oct 2024 19:34:19 +0200 Subject: [PATCH 1/2] chore: update Salesforce API version to 62.0 --- sfdx-project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sfdx-project.json b/sfdx-project.json index a6aeac3b..3ddf71b2 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -7,5 +7,5 @@ ], "namespace": "", "sfdcLoginUrl": "https://login.salesforce.com", - "sourceApiVersion": "60.0" + "sourceApiVersion": "62.0" } From c4cbc9f37f36770d06d63b021fd224e59ef89bda Mon Sep 17 00:00:00 2001 From: Matthias Rolke Date: Fri, 18 Oct 2024 19:34:19 +0200 Subject: [PATCH 2/2] feat: add basic Slack Apps Setup --- src/plugins/index.ts | 2 + src/plugins/schema.json | 3 ++ src/plugins/slack/disable-sales.json | 9 +++++ src/plugins/slack/enable.json | 9 +++++ src/plugins/slack/index.e2e-spec.ts | 47 ++++++++++++++++++++++++ src/plugins/slack/index.ts | 55 ++++++++++++++++++++++++++++ src/plugins/slack/schema.json | 17 +++++++++ 7 files changed, 142 insertions(+) create mode 100644 src/plugins/slack/disable-sales.json create mode 100644 src/plugins/slack/enable.json create mode 100644 src/plugins/slack/index.e2e-spec.ts create mode 100644 src/plugins/slack/index.ts create mode 100644 src/plugins/slack/schema.json diff --git a/src/plugins/index.ts b/src/plugins/index.ts index dd88d161..3324a778 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -14,6 +14,7 @@ import { RelateContactToMultipleAccounts as relateContactToMultipleAccounts } fr import { ReportsAndDashboards as reportsAndDashboards } from './reports-and-dashboards'; import { SalesforceToSalesforce as salesforceToSalesforce } from './salesforce-to-salesforce'; import { Security as security } from './security'; +import { Slack as slack } from './slack'; import { CompanyInformation as companyInformation } from './company-information'; import { LinkedInSalesNavigatorSettings as linkedInSalesNavigatorSettings } from './linkedin-sales-navigator-settings'; @@ -34,6 +35,7 @@ export { reportsAndDashboards, salesforceToSalesforce, security, + slack, companyInformation, linkedInSalesNavigatorSettings }; diff --git a/src/plugins/schema.json b/src/plugins/schema.json index 556ed164..e15be492 100644 --- a/src/plugins/schema.json +++ b/src/plugins/schema.json @@ -54,6 +54,9 @@ }, "security": { "$ref": "./security/schema.json" + }, + "slack": { + "$ref": "./slack/schema.json" } } } diff --git a/src/plugins/slack/disable-sales.json b/src/plugins/slack/disable-sales.json new file mode 100644 index 00000000..708d68aa --- /dev/null +++ b/src/plugins/slack/disable-sales.json @@ -0,0 +1,9 @@ +{ + "$schema": "../schema.json", + "settings": { + "slack": { + "agreeToTermsAndConditions": true, + "enableSalesCloudForSlack": false + } + } +} diff --git a/src/plugins/slack/enable.json b/src/plugins/slack/enable.json new file mode 100644 index 00000000..d516ec5d --- /dev/null +++ b/src/plugins/slack/enable.json @@ -0,0 +1,9 @@ +{ + "$schema": "../schema.json", + "settings": { + "slack": { + "agreeToTermsAndConditions": true, + "enableSalesCloudForSlack": true + } + } +} diff --git a/src/plugins/slack/index.e2e-spec.ts b/src/plugins/slack/index.e2e-spec.ts new file mode 100644 index 00000000..788908f3 --- /dev/null +++ b/src/plugins/slack/index.e2e-spec.ts @@ -0,0 +1,47 @@ +import assert from 'assert'; +import { type Config, Slack } from '.'; + +describe(Slack.name, function () { + let plugin: Slack; + before(() => { + plugin = new Slack(global.bf); + }); + + const configEnable: Config = { + agreeToTermsAndConditions: true, + enableSalesCloudForSlack: true + }; + const configDisabledSalesCloud: Config = { + agreeToTermsAndConditions: true, + enableSalesCloudForSlack: false + }; + const configDisabled: Config = { + agreeToTermsAndConditions: false, + enableSalesCloudForSlack: false + }; + it('should accept terms and conditions', async () => { + await plugin.run(configEnable); + }); + it('should already be accepted', async () => { + const res = await plugin.run(configEnable); + assert.deepStrictEqual(res, { message: 'no action necessary' }); + }); + it('should disable Sales Cloud for Slack', async () => { + await plugin.run(configDisabledSalesCloud); + }); + it('should already be disabled', async () => { + const res = await plugin.run(configDisabledSalesCloud); + assert.deepStrictEqual(res, { message: 'no action necessary' }); + }); + it('should fail to unaccept terms and conditions', async () => { + let err; + try { + await plugin.apply(configDisabled); + } catch (e) { + err = e; + } + assert.throws(() => { + throw err; + }, /cannot be unaccepted/); + }); +}); diff --git a/src/plugins/slack/index.ts b/src/plugins/slack/index.ts new file mode 100644 index 00000000..b76a74a5 --- /dev/null +++ b/src/plugins/slack/index.ts @@ -0,0 +1,55 @@ +import { BrowserforcePlugin } from '../../plugin'; + +const PATHS = { + BASE: 'lightning/setup/SlackSetupAssistant/home' +}; +const SELECTORS = { + TOS_LIGHTNING_INPUT: + 'pierce/setup_service-slack-setup-assistant-container setup_service-slack-agree-to-terms lightning-input', + SALES_CLOUD_FOR_SLACK_TOGGLE: + 'pierce/setup_service-slack-setup-assistant-container setup_service-stage setup_service-steps setup_service-step lightning-input:has(lightning-primitive-input-toggle input[name="SlkSetupStepSalesCloudForSlack"])', + TOAST_MESSAGE: 'div[id^="toastDescription"]' +}; + +export type Config = { + agreeToTermsAndConditions: boolean; + enableSalesCloudForSlack: boolean; +}; + +export class Slack extends BrowserforcePlugin { + public async retrieve(definition?: Config): Promise { + const page = await this.browserforce.openPage(PATHS.BASE); + await page.waitForSelector(SELECTORS.TOS_LIGHTNING_INPUT, { visible: true }); + await page.waitForSelector(SELECTORS.SALES_CLOUD_FOR_SLACK_TOGGLE, { visible: true }); + const response = { + agreeToTermsAndConditions: await page.$eval(SELECTORS.TOS_LIGHTNING_INPUT, (el) => el.hasAttribute('checked')), + enableSalesCloudForSlack: await page.$eval(SELECTORS.SALES_CLOUD_FOR_SLACK_TOGGLE, (el) => + el.hasAttribute('checked') + ) + }; + await page.close(); + return response; + } + + public async apply(config: Config): Promise { + if (config.agreeToTermsAndConditions === false) { + throw new Error('terms and conditions cannot be unaccepted once accepted'); + } + const state = await this.retrieve(); + const page = await this.browserforce.openPage(PATHS.BASE); + await page.waitForSelector(SELECTORS.TOS_LIGHTNING_INPUT, { visible: true }); + if (state.agreeToTermsAndConditions !== config.agreeToTermsAndConditions) { + await Promise.all([page.waitForSelector(SELECTORS.TOAST_MESSAGE), page.click(SELECTORS.TOS_LIGHTNING_INPUT)]); + await page.waitForSelector(SELECTORS.TOAST_MESSAGE, { hidden: true }); + } + await page.waitForSelector(SELECTORS.SALES_CLOUD_FOR_SLACK_TOGGLE, { visible: true }); + if (state.enableSalesCloudForSlack !== config.enableSalesCloudForSlack) { + await Promise.all([ + page.waitForSelector(SELECTORS.TOAST_MESSAGE), + page.click(SELECTORS.SALES_CLOUD_FOR_SLACK_TOGGLE) + ]); + await page.waitForSelector(SELECTORS.TOAST_MESSAGE, { hidden: true }); + } + await page.close(); + } +} diff --git a/src/plugins/slack/schema.json b/src/plugins/slack/schema.json new file mode 100644 index 00000000..2ea68ed0 --- /dev/null +++ b/src/plugins/slack/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://github.com/amtrack/sfdx-browserforce-plugin/src/plugins/slack/schema.json", + "title": "Slack Apps Setup", + "type": "object", + "properties": { + "agreeToTermsAndConditions": { + "title": "Agree to Termns and Conditions", + "description": "Once the terms have been accepted, this cannot be reverted.", + "type": "boolean" + }, + "enableSalesCloudForSlack": { + "title": "Enable the 'Sales Cloud for Slack' Slack App", + "type": "boolean" + } + } +}