Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ You can override their values if you wish to do so. Included below are their des
| `/dispatch-add-timeline-event` | Opens a modal to add an event to the incident timeline. |
| `/dispatch-assign-role` | Opens a modal for assigning a role to a participant. |
| `/dispatch-engage-oncall` | Opens a modal to engage an on-call person. |
| `/dispatch-list-incidents` | Lists current active and stable incidents and closed incidents in the last 24 hours. |
| `/dispatch-list-incidents [project name]` | Lists current active and stable incidents and closed incidents in the last 24 hours, for one project or for all of them. |
| `/dispatch-list-my-tasks` | Opens a modal with the list of your open and resolved incident tasks. |
| `/dispatch-list-participants` | Opens a modal with the list of incident participants. |
| `/dispatch-list-signals` | Opens a modal with the list of signal definitions configured for the conversation from where command was ran. |
Expand Down
6 changes: 4 additions & 2 deletions docs/docs/user-guide/incidents/commander.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,11 @@ Pick the person and edit the message they will see, or accept the default. Dispa

### /dispatch-list-incidents

Use `/dispatch-list-incidents` to open a modal listing every incident across every project that is currently active or stable, plus any incident closed in the last 24 hours. Each entry links to the incident in Dispatch and shows its commander, project, status, type, severity, and priority.
Use `/dispatch-list-incidents` to open a modal listing every incident that is currently active or stable, plus any incident closed in the last 24 hours. Each entry links to the incident in Dispatch and shows its commander, project, status, type, severity, and priority.

The command takes no arguments and can be run outside an incident channel as well as inside one. Restricted incidents are never listed, and the modal shows at most 49 incidents; use the Dispatch web interface if your deployment has more.
Run inside an incident channel, it lists that incident's project. Run anywhere else, it lists every project, or just one if you name it — `/dispatch-list-incidents Corporate Security` — where the name is the project's, exactly as Dispatch spells it. Only projects in the organization you are running the command from can be listed; there is no argument for naming another one.

Restricted incidents are never listed, and the modal shows at most 49 incidents; use the Dispatch web interface if your deployment has more.

### /dispatch-list-signals

Expand Down
28 changes: 20 additions & 8 deletions src/dispatch/plugins/dispatch_slack/incident/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
is_bot,
message_context_middleware,
modal_submit_middleware,
optional_command_context_middleware,
reaction_context_middleware,
restricted_command_middleware,
subject_middleware,
Expand Down Expand Up @@ -177,9 +178,14 @@ def configure(app: App, config) -> None:
app.command(config.slack_command_report_incident, middleware=middleware)(
handle_report_incident_command
)
app.command(config.slack_command_list_incidents, middleware=middleware)(
handle_list_incidents_command
)
# Resolves a subject when the command is run in an incident or case channel,
# so the listing can be scoped to that conversation's project and read that
# conversation's organization; still runs outside one, where it lists the
# default organization.
app.command(
config.slack_command_list_incidents,
middleware=middleware + [optional_command_context_middleware],
)(handle_list_incidents_command)

# non-sensitive-commands
middleware = [
Expand Down Expand Up @@ -361,17 +367,23 @@ def handle_list_incidents_command(
)
projects.append(incident.project)
else:
# command was run in a non-incident conversation
args = payload["command"].split(" ")
# command was run in a non-incident conversation. Slack puts whatever
# was typed after the command in `text`; `command` is the command name
# itself, and only ever the one this listener is registered for. Not
# split on whitespace: a project name may contain spaces, and the
# organization is fixed by the request's own route, never by an
# argument.
project_name = payload.get("text", "").strip()

if len(args) == 2:
project = project_service.get_by_name(db_session=db_session, name=args[1])
if project_name:
project = project_service.get_by_name(db_session=db_session, name=project_name)

if project:
projects.append(project)
else:
raise CommandError(
f"Project name '{args[1]}' in organization '{args[0]}' not found. Check your spelling.",
f"Project name '{project_name}' in organization "
f"'{context['subject'].organization_slug}' not found. Check your spelling.",
)
else:
projects = project_service.get_all(db_session=db_session)
Expand Down
14 changes: 14 additions & 0 deletions src/dispatch/plugins/dispatch_slack/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,20 @@ def command_context_middleware(
next()


def optional_command_context_middleware(context: BoltContext, next: Callable) -> None:
"""Resolves the conversation's subject for commands that run anywhere.

Unlike `command_context_middleware` a conversation that resolves to nothing
is not an error, so the default subject `subject_middleware` installed
stands. Where it does resolve it also replaces the default organization's
session with the conversation's own, so the command reads the tenant it was
run in rather than the default one.
"""
if subject := resolve_context_from_conversation(channel_id=context.channel_id):
context.update(subject._asdict())
next()


def add_user_middleware(payload: dict, context: BoltContext, next: Callable):
"""Attempts to determine the user to add to the incident."""
value = payload.get("value")
Expand Down
Loading
Loading