diff --git a/packages/backend/src/apps/slack/actions.ts b/packages/backend/src/apps/slack/actions.ts
index 7e44ebc4..e4063b76 100644
--- a/packages/backend/src/apps/slack/actions.ts
+++ b/packages/backend/src/apps/slack/actions.ts
@@ -1,12 +1,15 @@
import SendMessageToChannel from './actions/send-message-to-channel';
+import FindMessage from './actions/find-message';
import SlackClient from './client';
export default class Actions {
client: SlackClient;
sendMessageToChannel: SendMessageToChannel;
+ findMessage: FindMessage;
constructor(client: SlackClient) {
this.client = client;
this.sendMessageToChannel = new SendMessageToChannel(client);
+ this.findMessage = new FindMessage(client);
}
}
diff --git a/packages/backend/src/apps/slack/actions/find-message.ts b/packages/backend/src/apps/slack/actions/find-message.ts
new file mode 100644
index 00000000..4185d7b5
--- /dev/null
+++ b/packages/backend/src/apps/slack/actions/find-message.ts
@@ -0,0 +1,26 @@
+import SlackClient from '../client';
+
+export default class FindMessage {
+ client: SlackClient;
+
+ constructor(client: SlackClient) {
+ this.client = client;
+ }
+
+ async run() {
+ const parameters = this.client.step.parameters;
+ const query = parameters.query as string;
+ const sortBy = parameters.sortBy as string;
+ const sortDirection = parameters.sortDirection as string;
+ const count = 1;
+
+ const messages = await this.client.findMessages.run(
+ query,
+ sortBy,
+ sortDirection,
+ count,
+ );
+
+ return messages;
+ }
+}
diff --git a/packages/backend/src/apps/slack/client/endpoints/find-messages.ts b/packages/backend/src/apps/slack/client/endpoints/find-messages.ts
new file mode 100644
index 00000000..50d99819
--- /dev/null
+++ b/packages/backend/src/apps/slack/client/endpoints/find-messages.ts
@@ -0,0 +1,44 @@
+import SlackClient from '../index';
+
+export default class FindMessages {
+ client: SlackClient;
+
+ constructor(client: SlackClient) {
+ this.client = client;
+ }
+
+ async run(query: string, sortBy: string, sortDirection: string, count = 1) {
+ const headers = {
+ Authorization: `Bearer ${this.client.connection.formattedData.accessToken}`,
+ };
+
+ const params = {
+ query,
+ sort: sortBy,
+ sort_dir: sortDirection,
+ count,
+ };
+
+ const response = await this.client.httpClient.get('/search.messages', {
+ headers,
+ params,
+ });
+
+ const data = response.data;
+
+ if (!data.ok) {
+ if (data.error === 'missing_scope') {
+ throw new Error(
+ `Error occured while finding messages; ${data.error}: ${data.needed}`
+ );
+ }
+
+ throw new Error(`Error occured while finding messages; ${data.error}`);
+ }
+
+ const messages = data.messages.matches;
+ const message = messages?.[0];
+
+ return message;
+ }
+}
diff --git a/packages/backend/src/apps/slack/client/index.ts b/packages/backend/src/apps/slack/client/index.ts
index b3e9e17d..ba47be53 100644
--- a/packages/backend/src/apps/slack/client/index.ts
+++ b/packages/backend/src/apps/slack/client/index.ts
@@ -2,6 +2,7 @@ import { IFlow, IStep, IConnection } from '@automatisch/types';
import HttpClient from '../../../helpers/http-client';
import VerifyAccessToken from './endpoints/verify-access-token';
import PostMessageToChannel from './endpoints/post-message-to-channel';
+import FindMessages from './endpoints/find-messages';
export default class SlackClient {
flow: IFlow;
@@ -11,6 +12,7 @@ export default class SlackClient {
verifyAccessToken: VerifyAccessToken;
postMessageToChannel: PostMessageToChannel;
+ findMessages: FindMessages;
static baseUrl = 'https://slack.com/api';
@@ -22,5 +24,6 @@ export default class SlackClient {
this.httpClient = new HttpClient({ baseURL: SlackClient.baseUrl });
this.verifyAccessToken = new VerifyAccessToken(this);
this.postMessageToChannel = new PostMessageToChannel(this);
+ this.findMessages = new FindMessages(this);
}
}
diff --git a/packages/backend/src/apps/slack/info.json b/packages/backend/src/apps/slack/info.json
index 4e5cd4f8..d2ccc565 100644
--- a/packages/backend/src/apps/slack/info.json
+++ b/packages/backend/src/apps/slack/info.json
@@ -204,6 +204,73 @@
"name": "Test action"
}
]
+ },
+ {
+ "name": "Find message",
+ "key": "findMessage",
+ "description": "Find a Slack message using the Slack Search feature.",
+ "substeps": [
+ {
+ "key": "chooseConnection",
+ "name": "Choose connection"
+ },
+ {
+ "key": "setupAction",
+ "name": "Set up action",
+ "arguments": [
+ {
+ "label": "Search Query",
+ "key": "query",
+ "type": "string",
+ "required": true,
+ "description": "Search query to use for finding matching messages. See the Slack Search Documentation for more information on constructing a query.",
+ "variables": true
+ },
+ {
+ "label": "Sort by",
+ "key": "sortBy",
+ "type": "dropdown",
+ "description": "Sort messages by their match strength or by their date. Default is score.",
+ "required": true,
+ "value": "score",
+ "variables": false,
+ "options": [
+ {
+ "label": "Match strength",
+ "value": "score"
+ },
+ {
+ "label": "Message date time",
+ "value": "timestamp"
+ }
+ ]
+ },
+ {
+ "label": "Sort direction",
+ "key": "sortDirection",
+ "type": "dropdown",
+ "description": "Sort matching messages in ascending or descending order. Default is descending.",
+ "required": true,
+ "value": "desc",
+ "variables": false,
+ "options": [
+ {
+ "label": "Descending (newest or best match first)",
+ "value": "desc"
+ },
+ {
+ "label": "Ascending (oldest or worst match first)",
+ "value": "asc"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "key": "testStep",
+ "name": "Test action"
+ }
+ ]
}
]
}
diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql
index 4ec57ecc..d26c9bf9 100644
--- a/packages/backend/src/graphql/schema.graphql
+++ b/packages/backend/src/graphql/schema.graphql
@@ -73,6 +73,7 @@ type ActionSubstepArgument {
description: String
required: Boolean
variables: Boolean
+ options: [ActionSubstepArgumentOption]
source: ActionSubstepArgumentSource
dependsOn: [String]
}
@@ -83,6 +84,11 @@ type ActionSubstepArgumentSource {
arguments: [ActionSubstepArgumentSourceArgument]
}
+type ActionSubstepArgumentOption {
+ label: String
+ value: JSONObject
+}
+
type ActionSubstepArgumentSourceArgument {
name: String
value: String
diff --git a/packages/web/src/components/TestSubstep/index.tsx b/packages/web/src/components/TestSubstep/index.tsx
index de921f6e..6eb22e7b 100644
--- a/packages/web/src/components/TestSubstep/index.tsx
+++ b/packages/web/src/components/TestSubstep/index.tsx
@@ -73,7 +73,7 @@ function TestSubstep(props: TestSubstepProps): React.ReactElement {
{error?.graphQLErrors.map((error) => (<>{error.message}
>))}
}
- {called && !response && (
+ {called && !loading && !error && !response && (
{formatMessage('flowEditor.noTestDataTitle')}
diff --git a/packages/web/src/graphql/queries/get-apps.ts b/packages/web/src/graphql/queries/get-apps.ts
index a09cdf26..82ff70ec 100644
--- a/packages/web/src/graphql/queries/get-apps.ts
+++ b/packages/web/src/graphql/queries/get-apps.ts
@@ -95,6 +95,10 @@ export const GET_APPS = gql`
description
variables
dependsOn
+ options {
+ label
+ value
+ }
source {
type
name