Skip to content

Commit

Permalink
Merge branch 'incident-management' of https://github.com/socfortress/…
Browse files Browse the repository at this point in the history
…CoPilot into incident-management
  • Loading branch information
taylorwalton committed Aug 19, 2024
2 parents 419ed75 + c0047b8 commit 596a1fb
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 89 deletions.
9 changes: 9 additions & 0 deletions frontend/src/api/endpoints/incidentManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ export default {
}
)
},
linkCase(alertId: number, caseId: number) {
return HttpClient.post<FlaskBaseResponse & { case_alert_link: { case_id: number; alert_id: number } }>(
`/incidents/db_operations/case/alert-link`,
{
alert_id: alertId,
case_id: caseId
}
)
},
updateCaseStatus(caseId: number, status: AlertStatus) {
return HttpClient.put<FlaskBaseResponse>(`/incidents/db_operations/case/status`, {
case_id: caseId,
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/agents/agentFlow/AgentFlowItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</div>
</div>
<div class="time">
<n-popover overlap placement="top-end" style="max-height: 240px" scrollable to="body">
<n-popover overlap placement="top-end" class="max-h-64" scrollable to="body">
<template #trigger>
<div class="flex items-center gap-2 cursor-help">
<span>
Expand Down Expand Up @@ -74,7 +74,7 @@
<div class="grid gap-2 grid-auto-fit-200 p-7 pt-4" v-if="properties">
<KVCard v-for="(value, key) of properties" :key="key">
<template #key>{{ key }}</template>
<template #value>{{ value === "" ? "-" : value ?? "-" }}</template>
<template #value>{{ value === "" ? "-" : (value ?? "-") }}</template>
</KVCard>
</div>
</n-tab-pane>
Expand Down Expand Up @@ -138,6 +138,7 @@
</div>
</n-tab-pane>
<n-tab-pane name="Collect" tab="Collect" display-directive="show:lazy">
<!-- TODO: replace max-height or similar with TailWind classes -->
<n-scrollbar style="max-height: 430px" trigger="none">
<div class="px-7">
<AgentFlowCollectList :flow="flow" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template>
<n-button secondary type="primary" @click="createCase()" :loading="creating">
<template #icon><Icon :name="DangerIcon" /></template>
Create case
</n-button>
</template>

<script setup lang="ts">
import { ref, toRefs } from "vue"
import { NButton, useMessage } from "naive-ui"
import Icon from "@/components/common/Icon.vue"
import Api from "@/api"
import type { Alert } from "@/types/incidentManagement/alerts.d"
const props = defineProps<{ alert: Alert }>()
const { alert } = toRefs(props)
const emit = defineEmits<{
(e: "updated", value: Alert): void
}>()
const DangerIcon = "majesticons:exclamation-line"
const message = useMessage()
const creating = ref(false)
function updateAlert(updatedAlert: Alert) {
emit("updated", updatedAlert)
}
function createCase() {
creating.value = true
Api.incidentManagement
.createCase(alert.value.id)
.then(res => {
if (res.data.success) {
updateAlert({
...alert.value,
linked_cases: [
{
id: res.data.case_alert_link.case_id,
case_name: "",
case_description: "",
case_creation_time: new Date(),
assigned_to: null,
case_status: null
}
]
})
message.success(res.data?.message || "Case created successfully")
} else {
message.warning(res.data?.message || "An error occurred. Please try again later.")
}
})
.catch(err => {
message.error(err.response?.data?.message || "An error occurred. Please try again later.")
})
.finally(() => {
creating.value = false
})
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
<n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex flex-col grow">
<div class="pt-1">
<AlertOverview :alert :mergeCases @updated="updateAlert($event)" @deleted="emit('deleted')" />
<AlertOverview :alert @updated="updateAlert($event)" @deleted="emit('deleted')" />
</div>
</n-tab-pane>
<n-tab-pane name="Timeline" tab="Timeline" display-directive="show:lazy">
Expand Down Expand Up @@ -46,14 +46,12 @@ import AlertAssetsList from "./AlertAssetsList.vue"
import AlertCommentsList from "./AlertCommentsList.vue"
import AlertOverview from "./AlertOverview.vue"
import type { Alert, AlertComment } from "@/types/incidentManagement/alerts.d"
import type { Case } from "@/types/incidentManagement/cases.d"
const props = defineProps<{
alertData?: Alert
alertId?: number
mergeCases?: Case[]
}>()
const { alertData, alertId, mergeCases } = toRefs(props)
const { alertData, alertId } = toRefs(props)
const emit = defineEmits<{
(e: "deleted"): void
Expand Down
12 changes: 2 additions & 10 deletions frontend/src/components/incidentManagement/alerts/AlertItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,7 @@
segmented
role="modal"
>
<AlertDetails
v-if="alert"
:alertData="alert"
:mergeCases
@deleted="emitDelete()"
@updated="updateAlert($event)"
/>
<AlertDetails v-if="alert" :alertData="alert" @deleted="emitDelete()" @updated="updateAlert($event)" />
</n-card>
</n-modal>
</div>
Expand All @@ -253,16 +247,14 @@ import AlertDetails from "./AlertDetails.vue"
import { handleDeleteAlert } from "./utils"
import _truncate from "lodash/truncate"
import type { Alert } from "@/types/incidentManagement/alerts.d"
import type { Case } from "@/types/incidentManagement/cases.d"

const props = defineProps<{
alertData?: Alert
alertId?: number
mergeCases?: Case[]
compact?: boolean
embedded?: boolean
}>()
const { alertData, alertId, mergeCases, compact, embedded } = toRefs(props)
const { alertData, alertId, compact, embedded } = toRefs(props)

const emit = defineEmits<{
(e: "deleted"): void
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<code
class="cursor-pointer text-primary-color"
v-for="linkedCase of linkedCases"
:key="linkedCase.id"
@click="gotoIncidentManagementCases(linkedCase.id)"
>
#{{ linkedCase.id }}
<Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
</code>
</template>

<script setup lang="ts">
import { computed, toRefs } from "vue"
import Icon from "@/components/common/Icon.vue"
import { useGoto } from "@/composables/useGoto"
import type { Alert } from "@/types/incidentManagement/alerts.d"
const props = defineProps<{ alert: Alert }>()
const { alert } = toRefs(props)
const LinkIcon = "carbon:launch"
const { gotoIncidentManagementCases } = useGoto()
const linkedCases = computed(() => alert.value.linked_cases)
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<template>
<n-button secondary @click="openDialog()" :loading="merging">
<template #icon><Icon :name="MergeIcon" /></template>
Merge into Case
</n-button>

<n-modal
v-model:show="showMergeBox"
display-directive="show"
preset="card"
title="Select the case you want to merge it with"
:style="{ maxWidth: 'min(850px, 90vw)', minHeight: 'min(540px, 90vh)', maxHeight: '80vh' }"
content-class="overflow-hidden flex flex-col !px-2"
segmented
>
<n-spin
:show="loadingCases"
class="grow overflow-hidden flex flex-col"
content-class="grow overflow-hidden flex flex-col"
>
<n-scrollbar class="grow flex flex-col" content-class="grow" trigger="none">
<div class="flex flex-col gap-2 px-5 py-2">
<template v-if="linkableCases.length">
<CaseItem
v-for="item of linkableCases"
:key="item.id"
:caseData="item"
compact
embedded
@click="toggleSelectedCase(item)"
:class="{ active: selectedCase?.id === item.id }"
/>
</template>
<template v-else>
<n-empty description="No items found" class="justify-center h-48" v-if="!loadingCases" />
</template>
</div>
</n-scrollbar>
</n-spin>
<template #footer>
<div class="flex justify-end">
<n-button type="success" :disabled="!selectedCase" :loading="merging" @click="linkCase()">
<template #icon><Icon :name="MergeIcon" /></template>
Confirm Merge {{ selectedCase ? `with Case #${selectedCase.id}` : "" }}
</n-button>
</div>
</template>
</n-modal>
</template>
<script setup lang="ts">
import { inject, ref, toRefs, watch, type Ref } from "vue"
import { NButton, NModal, NSpin, NEmpty, NScrollbar, useMessage } from "naive-ui"
import Icon from "@/components/common/Icon.vue"
import CaseItem from "../cases/CaseItem.vue"
import _orderBy from "lodash/orderBy"
import Api from "@/api"
import type { Alert } from "@/types/incidentManagement/alerts.d"
import type { Case } from "@/types/incidentManagement/cases.d"
const props = defineProps<{ alert: Alert }>()
const { alert } = toRefs(props)
const emit = defineEmits<{
(e: "updated", value: Alert): void
}>()
const MergeIcon = "carbon:ibm-cloud-direct-link-1-connect"
const message = useMessage()
const merging = ref(false)
const showMergeBox = ref(false)
const loadingCases = ref(false)
const linkableCases = inject<Ref<Case[]>>("linkable-cases", ref([]))
const selectedCase = ref<Case | null>(null)
watch(showMergeBox, val => {
if (val && !linkableCases.value.length) {
getCasesList()
}
})
function updateAlert(updatedAlert: Alert) {
emit("updated", updatedAlert)
}
function openDialog() {
showMergeBox.value = true
}
function closeDialog() {
showMergeBox.value = false
}
function toggleSelectedCase(caseEntity: Case) {
if (selectedCase.value?.id === caseEntity.id) {
selectedCase.value = null
} else {
selectedCase.value = caseEntity
}
}
function getCasesList() {
loadingCases.value = true
Api.incidentManagement
.getCasesList()
.then(res => {
if (res.data.success) {
linkableCases.value = _orderBy(res.data?.cases || [], ["id"], ["desc"])
} else {
message.warning(res.data?.message || "An error occurred. Please try again later.")
}
})
.catch(err => {
message.error(err.response?.data?.message || "An error occurred. Please try again later.")
})
.finally(() => {
loadingCases.value = false
})
}
function linkCase() {
if (selectedCase.value?.id) {
merging.value = true
Api.incidentManagement
.linkCase(alert.value.id, selectedCase.value.id)
.then(res => {
if (res.data.success) {
closeDialog()
updateAlert({
...alert.value,
linked_cases: [
{
id: res.data.case_alert_link.case_id,
case_name: "",
case_description: "",
case_creation_time: new Date(),
assigned_to: null,
case_status: null
}
]
})
message.success(res.data?.message || "Case linked successfully")
} else {
message.warning(res.data?.message || "An error occurred. Please try again later.")
}
})
.catch(err => {
message.error(err.response?.data?.message || "An error occurred. Please try again later.")
})
.finally(() => {
merging.value = false
})
}
}
</script>
<style lang="scss" scoped>
.active {
box-shadow: 0px 0px 0px 2px var(--success-color) !important;
}
</style>
Loading

0 comments on commit 596a1fb

Please sign in to comment.