Skip to content

Commit

Permalink
feat(Slack Node): Update wait for approval to use markdown (#11754)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joffcom authored Nov 20, 2024
1 parent b3a99a2 commit 40dd02f
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 9 deletions.
3 changes: 2 additions & 1 deletion packages/nodes-base/nodes/Slack/Slack.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ export class Slack extends VersionedNodeType {
group: ['output'],
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Slack API',
defaultVersion: 2.2,
defaultVersion: 2.3,
};

const nodeVersions: IVersionedNodeType['nodeVersions'] = {
1: new SlackV1(baseDescription),
2: new SlackV2(baseDescription),
2.1: new SlackV2(baseDescription),
2.2: new SlackV2(baseDescription),
2.3: new SlackV2(baseDescription),
};

super(nodeVersions, baseDescription);
Expand Down
12 changes: 8 additions & 4 deletions packages/nodes-base/nodes/Slack/V2/GenericFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import get from 'lodash/get';
import type {
IDataObject,
IExecuteFunctions,
Expand All @@ -7,10 +8,9 @@ import type {
IRequestOptions,
IWebhookFunctions,
} from 'n8n-workflow';

import { NodeOperationError } from 'n8n-workflow';

import get from 'lodash/get';
import type { SendAndWaitMessageBody } from './MessageInterface';
import { getSendAndWaitConfig } from '../../../utils/sendAndWait/utils';

export async function slackApiRequest(
Expand Down Expand Up @@ -265,7 +265,7 @@ export function createSendAndWaitMessageBody(context: IExecuteFunctions) {

const config = getSendAndWaitConfig(context);

const body: IDataObject = {
const body: SendAndWaitMessageBody = {
channel: target,
blocks: [
{
Expand All @@ -274,7 +274,7 @@ export function createSendAndWaitMessageBody(context: IExecuteFunctions) {
{
type: 'section',
text: {
type: 'plain_text',
type: context.getNode().typeVersion > 2.2 ? 'mrkdwn' : 'plain_text',
text: config.message,
emoji: true,
},
Expand Down Expand Up @@ -307,5 +307,9 @@ export function createSendAndWaitMessageBody(context: IExecuteFunctions) {
],
};

if (context.getNode().typeVersion > 2.2 && body.blocks?.[1]?.type === 'section') {
delete body.blocks[1].text.emoji;
}

return body;
}
33 changes: 33 additions & 0 deletions packages/nodes-base/nodes/Slack/V2/MessageInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,36 @@ export interface IAttachment {
item?: object[];
};
}

// Used for SendAndWaitMessage
export interface TextBlock {
type: string;
text: string;
emoji?: boolean;
}

export interface SectionBlock {
type: 'section';
text: TextBlock;
}

export interface DividerBlock {
type: 'divider';
}

export interface ButtonElement {
type: 'button';
style?: 'primary';
text: TextBlock;
url: string;
}

export interface ActionsBlock {
type: 'actions';
elements: ButtonElement[];
}

export interface SendAndWaitMessageBody {
channel: string;
blocks: Array<DividerBlock | SectionBlock | ActionsBlock>;
}
2 changes: 1 addition & 1 deletion packages/nodes-base/nodes/Slack/V2/SlackV2.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class SlackV2 implements INodeType {
constructor(baseDescription: INodeTypeBaseDescription) {
this.description = {
...baseDescription,
version: [2, 2.1, 2.2],
version: [2, 2.1, 2.2, 2.3],
defaults: {
name: 'Slack',
},
Expand Down
125 changes: 122 additions & 3 deletions packages/nodes-base/nodes/Slack/test/v2/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type MockProxy, mock } from 'jest-mock-extended';
import type { IExecuteFunctions } from 'n8n-workflow';

import { getTarget, createSendAndWaitMessageBody } from '../../V2/GenericFunctions';

describe('Slack Utility Functions', () => {
Expand All @@ -12,7 +13,7 @@ describe('Slack Utility Functions', () => {
});

describe('getTarget', () => {
it('should return corect target id', () => {
it('should return correct target id', () => {
mockExecuteFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
if (parameterName === 'user') {
return 'testUser';
Expand All @@ -26,7 +27,7 @@ describe('Slack Utility Functions', () => {
});

describe('createSendAndWaitMessageBody', () => {
it('should create message with single button', () => {
it('should create message with single button - pre 2.3 plain_text', () => {
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channel');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channelID');

Expand Down Expand Up @@ -79,7 +80,7 @@ describe('Slack Utility Functions', () => {
});
});

it('should create message with double buttona', () => {
it('should create message with double buttons - pre 2.3 plain_text', () => {
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channel');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channelID');

Expand Down Expand Up @@ -142,5 +143,123 @@ describe('Slack Utility Functions', () => {
channel: 'channelID',
});
});

it('should create message with single button - 2.3+ mrkdwn', () => {
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channel');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channelID');

mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('message');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('subject');
mockExecuteFunctions.evaluateExpression.mockReturnValueOnce('localhost');
mockExecuteFunctions.evaluateExpression.mockReturnValueOnce('node123');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({});
mockExecuteFunctions.getNode.mockReturnValue({ name: 'Slack', typeVersion: 2.3 } as any);

expect(createSendAndWaitMessageBody(mockExecuteFunctions)).toEqual({
blocks: [
{
type: 'divider',
},
{
text: {
text: 'message',
type: 'mrkdwn',
},
type: 'section',
},
{
text: {
text: ' ',
type: 'plain_text',
},
type: 'section',
},
{
type: 'divider',
},
{
elements: [
{
style: 'primary',
text: {
emoji: true,
text: 'Approve',
type: 'plain_text',
},
type: 'button',
url: 'localhost/node123?approved=true',
},
],
type: 'actions',
},
],
channel: 'channelID',
});
});

it('should create message with double buttons - 2.3+ mrkdwn', () => {
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channel');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('channelID');

mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('message');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('subject');
mockExecuteFunctions.evaluateExpression.mockReturnValueOnce('localhost');
mockExecuteFunctions.evaluateExpression.mockReturnValueOnce('node123');
mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({ approvalType: 'double' });

mockExecuteFunctions.getNode.mockReturnValue({ name: 'Slack', typeVersion: 2.3 } as any);

expect(createSendAndWaitMessageBody(mockExecuteFunctions)).toEqual({
blocks: [
{
type: 'divider',
},
{
text: {
text: 'message',
type: 'mrkdwn',
},
type: 'section',
},
{
text: {
text: ' ',
type: 'plain_text',
},
type: 'section',
},
{
type: 'divider',
},
{
elements: [
{
style: undefined,
text: {
emoji: true,
text: 'Disapprove',
type: 'plain_text',
},
type: 'button',
url: 'localhost/node123?approved=false',
},

{
style: 'primary',
text: {
emoji: true,
text: 'Approve',
type: 'plain_text',
},
type: 'button',
url: 'localhost/node123?approved=true',
},
],
type: 'actions',
},
],
channel: 'channelID',
});
});
});
});

0 comments on commit 40dd02f

Please sign in to comment.