| 1 | <template> |
| 2 | <n-spin :show="loading" class="flex grow flex-col" content-class="flex grow flex-col"> |
| 3 | <div class="flex grow flex-col justify-between gap-4"> |
| 4 | <div class="content-box flex flex-col gap-4 py-3"> |
| 5 | <div class="flex flex-col gap-4 px-7 sm:flex-row!"> |
| 6 | <CardKV :color="query.active ? 'success' : undefined" size="lg" class="w-full grow"> |
| 7 | <template #key> |
| 8 | <div class="flex items-center gap-2"> |
| 9 | <Icon :name="query.active ? EnabledIcon : DisabledIcon" /> |
| 10 | <span>Status</span> |
| 11 | </div> |
| 12 | </template> |
| 13 | <template #value> |
| 14 | <div class="flex"> |
| 15 | <QueryActiveForm |
| 16 | v-slot="{ loading: loadingActive, togglePopup: toggleActivePopup }" |
| 17 | :query |
| 18 | @updated="updateQuery($event)" |
| 19 | > |
| 20 | <div |
| 21 | class="flex items-center gap-3" |
| 22 | :class="{ |
| 23 | 'cursor-not-allowed': loadingActive, |
| 24 | 'cursor-pointer': !loadingActive |
| 25 | }" |
| 26 | @click.stop="toggleActivePopup()" |
| 27 | > |
| 28 | <span>{{ query.active ? "Active" : "Inactive" }}</span> |
| 29 | <n-spin |
| 30 | :size="14" |
| 31 | :show="loadingActive" |
| 32 | content-class="flex flex-col justify-center" |
| 33 | > |
| 34 | <Icon :name="EditIcon" /> |
| 35 | </n-spin> |
| 36 | </div> |
| 37 | </QueryActiveForm> |
| 38 | </div> |
| 39 | </template> |
| 40 | </CardKV> |
| 41 | |
| 42 | <CardKV size="lg" class="w-full grow"> |
| 43 | <template #key> |
| 44 | <div class="flex items-center gap-2"> |
| 45 | <Icon :name="TimeIntervalIcon" /> |
| 46 | <span>Time Interval</span> |
| 47 | </div> |
| 48 | </template> |
| 49 | <template #value> |
| 50 | <div class="flex"> |
| 51 | <QueryTimeIntervalForm |
| 52 | v-slot="{ loading: loadingTimeInterval, togglePopup: toggleTimeIntervalPopup }" |
| 53 | :query |
| 54 | @updated="updateQuery($event)" |
| 55 | > |
| 56 | <div |
| 57 | class="flex items-center gap-3" |
| 58 | :class="{ |
| 59 | 'cursor-not-allowed': loadingTimeInterval, |
| 60 | 'cursor-pointer': !loadingTimeInterval |
| 61 | }" |
| 62 | @click.stop="toggleTimeIntervalPopup()" |
| 63 | > |
| 64 | <span>{{ query.time_interval || "n/d" }}</span> |
| 65 | <n-spin |
| 66 | :size="14" |
| 67 | :show="loadingTimeInterval" |
| 68 | content-class="flex flex-col justify-center" |
| 69 | > |
| 70 | <Icon :name="EditIcon" /> |
| 71 | </n-spin> |
| 72 | </div> |
| 73 | </QueryTimeIntervalForm> |
| 74 | </div> |
| 75 | </template> |
| 76 | </CardKV> |
| 77 | </div> |
| 78 | |
| 79 | <div class="px-7"> |
| 80 | <CardKV> |
| 81 | <template #key>name</template> |
| 82 | <template #value> |
| 83 | {{ query.rule_name ?? "-" }} |
| 84 | </template> |
| 85 | </CardKV> |
| 86 | </div> |
| 87 | |
| 88 | <div class="grid-auto-fit-250 grid gap-2 px-7"> |
| 89 | <CardKV> |
| 90 | <template #key>last execution time</template> |
| 91 | <template #value> |
| 92 | {{ |
| 93 | query.last_execution_time |
| 94 | ? formatDate(query.last_execution_time, dFormats.datetimesec) |
| 95 | : "n/d" |
| 96 | }} |
| 97 | </template> |
| 98 | </CardKV> |
| 99 | |
| 100 | <CardKV> |
| 101 | <template #key>last updated</template> |
| 102 | <template #value> |
| 103 | {{ query.last_updated ? formatDate(query.last_updated, dFormats.datetimesec) : "n/d" }} |
| 104 | </template> |
| 105 | </CardKV> |
| 106 | </div> |
| 107 | </div> |
| 108 | |
| 109 | <div class="footer-box bg-secondary flex items-center gap-2 px-7 py-4"> |
| 110 | <div class="grow"></div> |
| 111 | |
| 112 | <QueryDeleteOne |
| 113 | v-slot="{ loading: loadingDelete, togglePopup: toggleDeletePopup }" |
| 114 | :query |
| 115 | @deleted="emit('deleted', query)" |
| 116 | > |
| 117 | <n-button type="error" secondary :loading="loadingDelete" @click.stop="toggleDeletePopup()"> |
| 118 | <template #icon> |
| 119 | <Icon :name="TrashIcon" /> |
| 120 | </template> |
| 121 | Delete |
| 122 | </n-button> |
| 123 | </QueryDeleteOne> |
| 124 | </div> |
| 125 | </div> |
| 126 | </n-spin> |
| 127 | </template> |
| 128 | |
| 129 | <script setup lang="ts"> |
| 130 | import type { SigmaQuery } from "@/types/sigma.d" |
| 131 | import { NButton, NSpin } from "naive-ui" |
| 132 | import { ref, toRefs } from "vue" |
| 133 | import CardKV from "@/components/common/cards/CardKV.vue" |
| 134 | import Icon from "@/components/common/Icon.vue" |
| 135 | import { useSettingsStore } from "@/stores/settings" |
| 136 | import { formatDate } from "@/utils/format" |
| 137 | import QueryActiveForm from "./actionsProviders/QueryActiveForm.vue" |
| 138 | import QueryDeleteOne from "./actionsProviders/QueryDeleteOne.vue" |
| 139 | import QueryTimeIntervalForm from "./actionsProviders/QueryTimeIntervalForm.vue" |
| 140 | |
| 141 | const props = defineProps<{ query: SigmaQuery }>() |
| 142 | |
| 143 | const emit = defineEmits<{ |
| 144 | (e: "deleted", value: SigmaQuery): void |
| 145 | (e: "updated", value: SigmaQuery): void |
| 146 | }>() |
| 147 | |
| 148 | const { query } = toRefs(props) |
| 149 | |
| 150 | const TrashIcon = "carbon:trash-can" |
| 151 | const TimeIntervalIcon = "material-symbols:autoplay" |
| 152 | const EditIcon = "uil:edit-alt" |
| 153 | const EnabledIcon = "carbon:circle-solid" |
| 154 | const DisabledIcon = "carbon:subtract-alt" |
| 155 | |
| 156 | const dFormats = useSettingsStore().dateFormat |
| 157 | const loading = ref(false) |
| 158 | |
| 159 | function updateQuery(updatedQuery: SigmaQuery) { |
| 160 | emit("updated", updatedQuery) |
| 161 | } |
| 162 | </script> |
| 163 | |
| 164 | <style lang="scss" scoped> |
| 165 | .footer-box { |
| 166 | border-top: 1px solid var(--border-color); |
| 167 | } |
| 168 | </style> |