Skip to content

Commit

Permalink
Add /critical shortcut to create new incident more efficiently
Browse files Browse the repository at this point in the history
  • Loading branch information
jennafauconnier committed Nov 8, 2024
1 parent 60a7836 commit c78d24f
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 4 deletions.
8 changes: 5 additions & 3 deletions src/firefighter/incidents/forms/create_incident.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,16 @@ class CreateIncidentForm(CreateIncidentFormBase):
def trigger_incident_workflow(
self,
creator: User,
impacts_data: dict[str, ImpactLevel],
impacts_data: dict[str, ImpactLevel] | None,
*args: Any,
**kwargs: Any,
) -> None:
incident = Incident.objects.declare(created_by=creator, **self.cleaned_data)
impacts_form = SelectImpactForm(impacts_data)

impacts_form.save(incident=incident)
if impacts_data is not None:
impacts_form = SelectImpactForm(impacts_data)
impacts_form.save(incident=incident)

create_incident_conversation.send(
"create_incident_form",
incident=incident,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def get_manifest(
"command": command,
"url": f"{public_base_url}/api/v2/firefighter/slack/incident/",
"description": "Manage Incidents 🚨",
"usage_hint": "[open|update|close|status|help]",
"usage_hint": "[open|critical|update|close|status|help]",
"should_escape": False,
}
for command in [main_command, *command_aliases]
Expand Down
3 changes: 3 additions & 0 deletions src/firefighter/slack/views/events/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
)
from firefighter.slack.views.modals import (
modal_close,
modal_critical,
modal_dowgrade_workflow,
modal_edit,
modal_open,
Expand Down Expand Up @@ -111,6 +112,8 @@ def manage_incident(ack: Ack, respond: Respond, body: dict[str, Any]) -> None:
modal_edit.open_modal_aio(ack, body)
elif command == "close":
modal_close.open_modal_aio(ack=ack, body=body)
elif command == "critical":
modal_critical.open_modal_aio(ack=ack, body=body)
elif command == "status":
modal_status.open_modal_aio(ack=ack, body=body)
elif command in {"oncall", "on-call"}:
Expand Down
2 changes: 2 additions & 0 deletions src/firefighter/slack/views/modals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import TYPE_CHECKING

from firefighter.slack.views.modals.close import CloseModal, modal_close
from firefighter.slack.views.modals.critical import CriticalModal, modal_critical
from firefighter.slack.views.modals.downgrade_workflow import (
DowngradeWorkflowModal,
modal_dowgrade_workflow,
Expand Down Expand Up @@ -48,4 +49,5 @@
StatusModal,
SendSosModal,
DowngradeWorkflowModal,
CriticalModal
]
120 changes: 120 additions & 0 deletions src/firefighter/slack/views/modals/critical.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any

from django.conf import settings
from slack_sdk.models.blocks.blocks import SectionBlock
from slack_sdk.models.views import View

from firefighter.incidents.forms.create_incident import CreateIncidentForm
from firefighter.slack.slack_app import SlackApp
from firefighter.slack.views.modals.base_modal.base import ModalForm

if TYPE_CHECKING:
from slack_bolt.context.ack.ack import Ack

from firefighter.incidents.models.incident import Priority, Severity
from firefighter.incidents.models.user import User
from firefighter.slack.views.modals.base_modal.form_utils import (
SlackFormAttributesDict,
)

app = SlackApp()
logger = logging.getLogger(__name__)


def priority_label(obj: Severity | Priority) -> str:
return f"{obj.emoji} {obj.name} - {obj.description}"


class CriticalFormSlack(CreateIncidentForm):
slack_fields: SlackFormAttributesDict = {
"title": {
"input": {
"multiline": False,
"placeholder": "Short, punchy description of what's happening.",
},
"block": {"hint": None},
},
"description": {
"input": {
"multiline": True,
"placeholder": "Help people responding to the incident. This will be posted to #tech-incidents and on our internal status page.\nThis description can be edited later.",
},
"block": {"hint": None},
},
"component": {
"input": {
"placeholder": "Select affected component",
}
},
"priority": {
"input": {
"placeholder": "Select a priority",
},
"widget": {
"post_block": (
SectionBlock(
text=f"_<{settings.SLACK_SEVERITY_HELP_GUIDE_URL}|How to choose the priority?>_"
)
if settings.SLACK_SEVERITY_HELP_GUIDE_URL
else None
),
"label_from_instance": priority_label,
},
},
}


class CriticalModal(ModalForm[CriticalFormSlack]):
open_action: str = "open_modal_incident_critical"
open_shortcut = "modal_critical"
callback_id: str = "incident_critical"

form_class = CriticalFormSlack

def build_modal_fn(self, **kwargs: Any) -> View:
form_instance = self.get_form_class()()
blocks = form_instance.slack_blocks()

return View(
type="modal",
title="Open a critical incident"[:24],
submit="Create the incident"[:24],
callback_id=self.callback_id,
blocks=blocks,
clear_on_close=False,
close=None,
)

def handle_modal_fn( # type: ignore
self, ack: Ack, body: dict[str, Any], user: User
) -> None :
slack_form = self.handle_form_errors(
ack, body, forms_kwargs={},
)

if slack_form is None:
return

form = slack_form.form

try:
if hasattr(form, "trigger_incident_workflow") and callable(
form.trigger_incident_workflow
):
form.trigger_incident_workflow(
creator=user,
impacts_data=None,
)
except: # noqa: E722
logger.exception("Error triggering incident workflow")
# XXX warn the user via DM!

if len(form.cleaned_data) == 0:
logger.warning("Form is empty, no data captured.")
return


modal_critical = CriticalModal()

0 comments on commit c78d24f

Please sign in to comment.