Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.

Commit bf7ef3e

Browse files
authored
Adds tab for incident tasks in incident details (#2989)
* Adds tab for incident tasks in incident details * makes eslint happy * replaces assignee with item in filter * only truncate if string longer than 100 chars * replaces truncate filter with text-truncate class * Participant component no longer needed
1 parent 4bfa84f commit bf7ef3e

File tree

5 files changed

+88
-17
lines changed

5 files changed

+88
-17
lines changed

src/dispatch/incident/models.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
from datetime import datetime
33
from typing import ForwardRef, List, Optional
44

5-
from pydantic import validator
5+
from pydantic import validator, Field
6+
67
from sqlalchemy import Column, DateTime, ForeignKey, Integer, PrimaryKeyConstraint, String, Table
78
from sqlalchemy.ext.hybrid import hybrid_property
89
from sqlalchemy.orm import relationship
@@ -46,6 +47,7 @@
4647
from dispatch.report.models import ReportRead
4748
from dispatch.storage.models import StorageRead
4849
from dispatch.tag.models import TagRead, TagReadMinimal
50+
from dispatch.task.enums import TaskStatus
4951
from dispatch.term.models import TermRead
5052
from dispatch.ticket.models import TicketRead
5153
from dispatch.workflow.models import WorkflowInstanceRead
@@ -235,6 +237,15 @@ class CaseRead(DispatchBase):
235237
name: Optional[NameStr]
236238

237239

240+
class TaskRead(DispatchBase):
241+
id: PrimaryKey
242+
assignees: List[Optional[ParticipantRead]] = []
243+
created_at: Optional[datetime]
244+
description: Optional[str] = Field(None, nullable=True)
245+
status: TaskStatus = TaskStatus.open
246+
weblink: Optional[str]
247+
248+
238249
# Pydantic models...
239250
class IncidentBase(DispatchBase):
240251
title: str
@@ -327,37 +338,38 @@ def find_exclusive(cls, v):
327338

328339
class IncidentRead(IncidentBase):
329340
id: PrimaryKey
341+
cases: Optional[List[CaseRead]] = []
330342
closed_at: Optional[datetime] = None
331343
commander: Optional[ParticipantRead]
332344
commanders_location: Optional[str]
345+
conference: Optional[ConferenceRead] = None
346+
conversation: Optional[ConversationRead] = None
333347
created_at: Optional[datetime] = None
348+
documents: Optional[List[DocumentRead]] = []
349+
duplicates: Optional[List[IncidentReadMinimal]] = []
334350
duplicates: Optional[List[IncidentReadMinimal]] = []
351+
events: Optional[List[EventRead]] = []
335352
incident_costs: Optional[List[IncidentCostRead]] = []
336353
incident_priority: IncidentPriorityRead
337354
incident_severity: IncidentSeverityRead
338355
incident_type: IncidentTypeRead
356+
last_executive_report: Optional[ReportRead]
357+
last_tactical_report: Optional[ReportRead]
339358
name: Optional[NameStr]
359+
participants: Optional[List[ParticipantRead]] = []
340360
participants_location: Optional[str]
341361
participants_team: Optional[str]
342362
project: ProjectRead
343363
reported_at: Optional[datetime] = None
344364
reporter: Optional[ParticipantRead]
345365
reporters_location: Optional[str]
346366
stable_at: Optional[datetime] = None
347-
tags: Optional[List[TagRead]] = []
348-
total_cost: Optional[float]
349-
cases: Optional[List[CaseRead]] = []
350-
conference: Optional[ConferenceRead] = None
351-
conversation: Optional[ConversationRead] = None
352-
documents: Optional[List[DocumentRead]] = []
353-
duplicates: Optional[List[IncidentReadMinimal]] = []
354-
events: Optional[List[EventRead]] = []
355-
last_executive_report: Optional[ReportRead]
356-
last_tactical_report: Optional[ReportRead]
357-
participants: Optional[List[ParticipantRead]] = []
358367
storage: Optional[StorageRead] = None
368+
tasks: Optional[List[TaskRead]] = []
369+
tags: Optional[List[TagRead]] = []
359370
terms: Optional[List[TermRead]] = []
360371
ticket: Optional[TicketRead] = None
372+
total_cost: Optional[float]
361373
workflow_instances: Optional[List[WorkflowInstanceRead]] = []
362374

363375

src/dispatch/static/dispatch/src/filters.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,13 @@ export const activeRoles = function (value) {
117117
}
118118

119119
Vue.filter("activeRoles", activeRoles)
120+
121+
Vue.filter("individualNames", function (value) {
122+
if (value) {
123+
return value
124+
.map(function (item) {
125+
return item.individual.name
126+
})
127+
.join(", ")
128+
}
129+
})

src/dispatch/static/dispatch/src/incident/EditSheet.vue

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<v-tab key="resources"> Resources </v-tab>
3232
<v-tab key="participants"> Participants </v-tab>
3333
<v-tab key="timeline"> Timeline </v-tab>
34+
<v-tab key="tasks"> Tasks </v-tab>
3435
<v-tab key="workflows"> Workflows </v-tab>
3536
<v-tab key="costs"> Costs </v-tab>
3637
</v-tabs>
@@ -47,6 +48,9 @@
4748
<v-tab-item key="timeline">
4849
<incident-timeline-tab />
4950
</v-tab-item>
51+
<v-tab-item key="tasks">
52+
<incident-tasks-tab />
53+
</v-tab-item>
5054
<v-tab-item key="workflow_instances">
5155
<workflow-instance-tab v-model="workflow_instances" />
5256
</v-tab-item>
@@ -63,23 +67,25 @@ import { mapFields } from "vuex-map-fields"
6367
import { mapActions } from "vuex"
6468
import { ValidationObserver } from "vee-validate"
6569
70+
import IncidentCostsTab from "@/incident/CostsTab.vue"
6671
import IncidentDetailsTab from "@/incident/DetailsTab.vue"
67-
import IncidentResourcesTab from "@/incident/ResourcesTab.vue"
6872
import IncidentParticipantsTab from "@/incident/ParticipantsTab.vue"
73+
import IncidentResourcesTab from "@/incident/ResourcesTab.vue"
74+
import IncidentTasksTab from "@/incident/TasksTab.vue"
6975
import IncidentTimelineTab from "@/incident/TimelineTab.vue"
70-
import IncidentCostsTab from "@/incident/CostsTab.vue"
7176
import WorkflowInstanceTab from "@/workflow/WorkflowInstanceTab.vue"
7277
7378
export default {
7479
name: "IncidentEditSheet",
7580
7681
components: {
77-
ValidationObserver,
82+
IncidentCostsTab,
7883
IncidentDetailsTab,
79-
IncidentResourcesTab,
8084
IncidentParticipantsTab,
85+
IncidentResourcesTab,
86+
IncidentTasksTab,
8187
IncidentTimelineTab,
82-
IncidentCostsTab,
88+
ValidationObserver,
8389
WorkflowInstanceTab,
8490
},
8591
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<template>
2+
<div>
3+
<div v-if="tasks && tasks.length">
4+
<span v-for="task in tasks" :key="task.id">
5+
<v-list-item :href="task.weblink" target="_blank">
6+
<v-list-item-content>
7+
<v-list-item-title style="width: 200px" class="text-truncate">
8+
{{ task.description }}
9+
</v-list-item-title>
10+
<v-list-item-subtitle>
11+
<strong>Created:</strong> {{ task.created_at | formatRelativeDate }}
12+
| <strong>Status:</strong> {{ task.status }}
13+
| <strong>Assignees:</strong> {{ task.assignees | individualNames }}
14+
</v-list-item-subtitle>
15+
</v-list-item-content>
16+
<v-list-item-action>
17+
<v-list-item-icon>
18+
<v-icon>open_in_new</v-icon>
19+
</v-list-item-icon>
20+
</v-list-item-action>
21+
</v-list-item>
22+
<v-divider />
23+
</span>
24+
</div>
25+
<div v-else>
26+
<p class="text-center">No tasks have been created for this incident.</p>
27+
</div>
28+
</div>
29+
</template>
30+
31+
<script>
32+
import map from "lodash"
33+
import { mapFields } from "vuex-map-fields"
34+
35+
export default {
36+
name: "IncidentTasksTab",
37+
38+
computed: {
39+
...mapFields("incident", ["selected.tasks"]),
40+
},
41+
}
42+
</script>

src/dispatch/static/dispatch/src/incident/store.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const getDefaultSelectedState = () => {
3131
status: null,
3232
storage: null,
3333
tags: [],
34+
tasks: [],
3435
terms: [],
3536
ticket: null,
3637
title: null,

0 commit comments

Comments
 (0)