fix(sla): freeze misses after resolution
This commit is contained in:
+36
-7
@@ -1,6 +1,10 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { evaluateSLAStatus } from 'dashboard/helper/slaHelper';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {
|
||||
evaluateSLAStatus,
|
||||
shouldRefreshSLAStatus,
|
||||
} from 'dashboard/helper/slaHelper';
|
||||
|
||||
const props = defineProps({
|
||||
conversation: {
|
||||
@@ -12,6 +16,7 @@ const props = defineProps({
|
||||
const REFRESH_INTERVAL = 60000;
|
||||
|
||||
const timer = ref(null);
|
||||
const { t } = useI18n();
|
||||
const slaStatus = ref({
|
||||
threshold: null,
|
||||
isSlaMissed: false,
|
||||
@@ -24,12 +29,15 @@ const slaEvents = computed(() => props.conversation?.slaEvents);
|
||||
const isSlaMissed = computed(() => slaStatus.value?.isSlaMissed);
|
||||
|
||||
const hasSlaThreshold = computed(() => {
|
||||
return slaStatus.value?.threshold && appliedSLA.value?.id;
|
||||
return slaStatus.value?.type && appliedSLA.value?.id;
|
||||
});
|
||||
|
||||
const slaStatusText = computed(() => {
|
||||
return slaStatus.value?.type?.toUpperCase();
|
||||
});
|
||||
const slaValueText = computed(
|
||||
() => slaStatus.value?.threshold || t('CONVERSATION.HEADER.SLA_STATUS.MISSED')
|
||||
);
|
||||
|
||||
const updateSlaStatus = () => {
|
||||
slaStatus.value = evaluateSLAStatus({
|
||||
@@ -39,7 +47,24 @@ const updateSlaStatus = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const clearTimer = () => {
|
||||
if (timer.value) {
|
||||
clearTimeout(timer.value);
|
||||
timer.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const createTimer = () => {
|
||||
clearTimer();
|
||||
if (
|
||||
!shouldRefreshSLAStatus({
|
||||
appliedSla: appliedSLA.value,
|
||||
chat: props.conversation,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
timer.value = setTimeout(() => {
|
||||
updateSlaStatus();
|
||||
createTimer();
|
||||
@@ -52,12 +77,16 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer.value) {
|
||||
clearTimeout(timer.value);
|
||||
}
|
||||
clearTimer();
|
||||
});
|
||||
|
||||
watch(() => props.conversation, updateSlaStatus);
|
||||
watch(
|
||||
() => props.conversation,
|
||||
() => {
|
||||
updateSlaStatus();
|
||||
createTimer();
|
||||
}
|
||||
);
|
||||
|
||||
// This expose is to provide context to the parent component, so that it can decided weather
|
||||
// a new row has to be added to the conversation card or not
|
||||
@@ -96,7 +125,7 @@ defineExpose({
|
||||
class="text-sm truncate"
|
||||
:class="isSlaMissed ? 'text-n-ruby-11' : 'text-n-slate-11'"
|
||||
>
|
||||
{{ `${slaStatusText}: ${slaStatus.threshold}` }}
|
||||
{{ `${slaStatusText}: ${slaValueText}` }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { evaluateSLAStatus } from 'dashboard/helper/slaHelper';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {
|
||||
evaluateSLAStatus,
|
||||
shouldRefreshSLAStatus,
|
||||
} from 'dashboard/helper/slaHelper';
|
||||
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
import Label from 'dashboard/components-next/label/Label.vue';
|
||||
@@ -15,6 +19,7 @@ const props = defineProps({
|
||||
const REFRESH_INTERVAL = 60000;
|
||||
|
||||
const timer = ref(null);
|
||||
const { t } = useI18n();
|
||||
const slaStatus = ref({
|
||||
threshold: null,
|
||||
isSlaMissed: false,
|
||||
@@ -28,8 +33,18 @@ defineOptions({
|
||||
|
||||
const appliedSLA = computed(() => props.chat?.applied_sla);
|
||||
const slaEvents = computed(() => props.chat?.sla_events);
|
||||
const hasSlaThreshold = computed(() => slaStatus.value?.threshold);
|
||||
const hasSlaThreshold = computed(() => slaStatus.value?.type);
|
||||
const isSlaMissed = computed(() => slaStatus.value?.isSlaMissed);
|
||||
const slaLabel = computed(() => {
|
||||
if (slaStatus.value?.threshold) return slaStatus.value.threshold;
|
||||
|
||||
const status = t('CONVERSATION.HEADER.SLA_STATUS.MISSED');
|
||||
return {
|
||||
FRT: t('CONVERSATION.HEADER.SLA_STATUS.FRT', { status }),
|
||||
NRT: t('CONVERSATION.HEADER.SLA_STATUS.NRT', { status }),
|
||||
RT: t('CONVERSATION.HEADER.SLA_STATUS.RT', { status }),
|
||||
}[slaStatus.value.type];
|
||||
});
|
||||
|
||||
const updateSlaStatus = () => {
|
||||
slaStatus.value = evaluateSLAStatus({
|
||||
@@ -39,7 +54,24 @@ const updateSlaStatus = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const clearTimer = () => {
|
||||
if (timer.value) {
|
||||
clearTimeout(timer.value);
|
||||
timer.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const createTimer = () => {
|
||||
clearTimer();
|
||||
if (
|
||||
!shouldRefreshSLAStatus({
|
||||
appliedSla: appliedSLA.value,
|
||||
chat: props.chat,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
timer.value = setTimeout(() => {
|
||||
updateSlaStatus();
|
||||
createTimer();
|
||||
@@ -52,12 +84,16 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer.value) {
|
||||
clearTimeout(timer.value);
|
||||
}
|
||||
clearTimer();
|
||||
});
|
||||
|
||||
watch(() => props.chat, updateSlaStatus);
|
||||
watch(
|
||||
() => props.chat,
|
||||
() => {
|
||||
updateSlaStatus();
|
||||
createTimer();
|
||||
}
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
hasSlaThreshold,
|
||||
@@ -70,11 +106,7 @@ defineExpose({
|
||||
v-bind="$attrs"
|
||||
class="relative flex items-center cursor-pointer min-w-fit group"
|
||||
>
|
||||
<Label
|
||||
:label="slaStatus.threshold"
|
||||
:color="isSlaMissed ? 'ruby' : 'amber'"
|
||||
compact
|
||||
>
|
||||
<Label :label="slaLabel" :color="isSlaMissed ? 'ruby' : 'amber'" compact>
|
||||
<template #icon>
|
||||
<Icon icon="i-lucide-flame" class="flex-shrink-0 size-3.5" />
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user