kestra-io / kestra-io/plugin-slack
Add Slack views (open/publish) tasks for Slack Plugin
- Dominant language
- Java
- Stars
- 2
- Forks
- 4
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 7
Description
## Summary
Add two Slack Web API tasks — `views.open` and `views.publish` — to `plugin-slack`, so flows
can open a modal (`views.open`) in response to a Slack interaction and render an App Home tab
(`views.publish`). These are the only Slack methods still missing from the plugin: the message,
file, user, conversation, reaction and interaction-trigger surfaces already exist.
## Motivation
- **What users do today**: nothing — there is no way to surface a modal or an App Home view from a
Kestra flow. Everything up to messaging, reactions and conversations is covered by existing
`app/*` tasks, but interactive views are the one gap left.
- **Who benefits**: flows that already use the interaction `Trigger` (`app/core/Trigger.java`) and
want to respond by opening a modal, and flows that want to keep an App Home tab in sync with
pipeline state.
- **Ecosystem fit**: closes out the Slack surface in the same repo and with the same auth/base
class as every other task — no new plugin, no new dependency.
## Context
Final remaining item from **kestra-ee #10920** ("Slack Web API tasks"), part of **EPIC
kestra-ee #10821** (Finance, People & Ops connectors). That issue proposed 16 methods against the
then-current (now archived) `plugin-notifications`; 15 already ship in `plugin-slack`
(`chat.*`, `files.*`, `users.*`, `conversations.*`, `reactions.*`, interaction `Trigger`). Only
`views.open` / `views.publish` are unimplemented — there is no `views` package. This issue tracks
just those two.
Model the new tasks on the existing `app/reactions/Add.java`:
- extend `io.kestra.plugin.slack.AbstractSlackClientConnection` (bot-token auth, `token` secret),
- carry the five Lombok annotations and `@Schema` on every property/output,
- use the Slack Java SDK already on the classpath (`com.slack.api.methods.*`) rather than
hand-rolled HTTP — this repo standardised on that SDK.
## API Reference
- **Official docs**: https://docs.slack.dev/reference/methods/views.open and
https://docs.slack.dev/reference/methods/views.publish
- **Authentication**: bot token (`xoxb-…`) as `Authorization: Bearer ` — already handled by
`AbstractSlackClientConnection` (`token` is a secret).
- **SDK**: the Slack Java SDK is already a dependency of this repo — use
`com.slack.api.methods.request.views.ViewsOpenRequest` and `ViewsPublishRequest` via
`Slack.getInstance().methods(token)`, exactly as the existing tasks do. No new dependency.
- **Notes / gotchas** (from #10920):
- `views.open` needs a valid **`trigger_id`** from an interaction payload, so it is only useful
downstream of the interaction `Trigger` (`trigger.body`); the `trigger_id` expires after ~3s,
so the flow must open the view promptly.
- `views.publish` needs the **App Home tab enabled** in the Slack app config and a `user`
(the App Home owner) plus the `view` payload.
## Gradle Dependencies
None. The Slack Java SDK is already declared in `build.gradle`, and Kestra's HTTP client / Jackson
are provided by the framework.
## Plugin Structure
- **Repository**: `plugin-slack` (exists)
- **Namespace**: `io.kestra.plugin.slack.app.views`
- **Sub-plugins**: new `views` sub-package under `app/`
- **Category**: `BUSINESS` (matches the existing `app` `@PluginSubGroup`)
> **Task class naming**: name the classes `Open` and `Publish` — not `ViewsOpen` / `OpenView`.
> The fully-qualified type (`io.kestra.plugin.slack.app.views.Open`) already carries the context.
## Suggested Tasks
1. `app/views/Open` — call `views.open` with `triggerId` + `view` (JSON), extend
`AbstractSlackClientConnection`, `RunnableTask`.
2. `app/views/Publish` — call `views.publish` with `userId` + `view` (JSON) + optional `hash`.
3. Output the returned view (id, hash) via a small `@Getter @Builder` output record, consistent
with `app/models/*Output`.
4. `package-info.java` for `io.kestra.plugin.slack.app.views` with
`@PluginSubGroup(categories = PluginSubGroup.PluginCategory.BUSINESS)`.
5. Unit tests mirroring the existing `app/*` task tests.
## YAML Examples
### Example 1 — Open a modal in response to a Slack interaction
```yaml
id: slack_open_modal
namespace: company.team
triggers:
- id: on_interaction
type: io.kestra.plugin.slack.app.core.Trigger
token: "{{ secret('SLACK_TOKEN') }}"
signingSecret: "{{ secret('SLACK_SIGNING_SECRET') }}"
tasks:
- id: open_view
type: io.kestra.plugin.slack.app.views.Open
token: "{{ secret('SLACK_TOKEN') }}"
triggerId: "{{ trigger.body.trigger_id }}"
view: |
{
"type": "modal",
"title": { "type": "plain_text", "text": "Approve run" },
"blocks": [
{ "type": "section", "text": { "type": "mrkdwn", "text": "Approve this deployment?" } }
]
}
```
### Example 2 — Publish an App Home tab for a user
```yaml
id: slack_publish_home
namespace: company.team
inputs:
- id: user_id
type: STRING
tasks:
- id: publish_home
type: io.kestra.plugin.slack.app.views.Publish
token: "{{ secret('SLACK_TOKEN') }}"
userId: "{{ inputs.user_id }}"
view: |
{
"type": "home",
"blocks": [
{ "type": "section", "text": { "type": "mrkdwn", "text": "*Latest pipeline status:* ✅" } }
]
}
```
### Example 3 — Open a modal, then log the returned view id
```yaml
id: slack_open_and_log
namespace: company.team
triggers:
- id: on_interaction
type: io.kestra.plugin.slack.app.core.Trigger
token: "{{ secret('SLACK_TOKEN') }}"
signingSecret: "{{ secret('SLACK_SIGNING_SECRET') }}"
tasks:
- id: open_view
type: io.kestra.plugin.slack.app.views.Open
token: "{{ secret('SLACK_TOKEN') }}"
triggerId: "{{ trigger.body.trigger_id }}"
view: "{{ read('modal.json') }}"
- id: log_view
type: io.kestra.plugin.core.log.Log
message: "Opened view {{ outputs.open_view.viewId }}"
```
## Acceptance Criteria
### Functional
- [ ] `app/views/Open` implemented (`views.open`, requires `triggerId` + `view`)
- [ ] `app/views/Publish` implemented (`views.publish`, requires `userId` + `view`)
- [ ] Both return the Slack view id/hash as task output
- [ ] Unit tests pass (`./gradlew test`) and build passes (`./gradlew build`)
### Kestra Plugin Coding Standards
- [ ] Extend `AbstractSlackClientConnection` and reuse the Slack Java SDK (`com.slack.api.methods.*`) as the other `app/*` tasks do — no hand-rolled HTTP
- [ ] All new properties use `Property`
- [ ] Every property and output has a `@Schema` annotation
- [ ] Task classes carry the five mandatory Lombok annotations (`@SuperBuilder`, `@ToString`, `@EqualsAndHashCode`, `@Getter`, `@NoArgsConstructor`)
- [ ] Logging via `runContext.logger()` only
### Documentation & Structure
- [ ] `@Plugin(examples = ...)` entries each set `full = true` with a complete runnable flow
- [ ] Sensitive values in examples use `{{ secret('SECRET_NAME') }}`
- [ ] `package-info.java` for `app/views` with `@PluginSubGroup(categories = PluginSubGroup.PluginCategory.BUSINESS)`
---
*[View as Artifact](https://claude.ai/artifact/HNczpojuPv29eApVoSzWZ3)*
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with app/reactions/Add.java and app/core/Trigger.java to follow the shared connection, SDK, and interaction patterns. Add app/views/Open, app/views/Publish, package-info.java, and unit tests mirroring the existing app task tests. Done means both tasks return the Slack view id/hash and ./gradlew test and ./gradlew build pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 75/100