feat: group timeline changes

This commit is contained in:
Shariq Ansari 2023-09-27 17:10:57 +05:30
parent 463ead3671
commit 4eb8a5aa77
4 changed files with 149 additions and 27 deletions

View File

@ -93,5 +93,39 @@ def get_activities(name):
activities.append(activity)
activities.sort(key=lambda x: x["creation"], reverse=True)
activities = handle_multiple_versions(activities)
return activities
return activities
def handle_multiple_versions(versions):
activities = []
grouped_versions = []
old_version = None
for version in versions:
is_version = version["activity_type"] in ["changed", "added", "removed"]
if not is_version:
activities.append(version)
if not old_version:
old_version = version
if is_version: grouped_versions.append(version)
continue
if is_version and old_version.get("owner") and version["owner"] == old_version["owner"]:
grouped_versions.append(version)
else:
if grouped_versions:
activities.append(parse_grouped_versions(grouped_versions))
grouped_versions = []
if is_version: grouped_versions.append(version)
old_version = version
if version == versions[-1] and grouped_versions:
activities.append(parse_grouped_versions(grouped_versions))
return activities
def parse_grouped_versions(versions):
version = versions[0]
if len(versions) == 1:
return version
other_versions = versions[1:]
version["other_versions"] = other_versions
return version

View File

@ -170,8 +170,13 @@
<div v-else v-for="(activity, i) in activities">
<div class="grid grid-cols-[30px_minmax(auto,_1fr)] gap-4 px-10">
<div
class="relative flex justify-center after:absolute after:left-[50%] after:top-0 after:-z-10 after:border-l after:border-gray-200"
:class="i != activities.length - 1 ? 'after:h-full' : 'after:h-4'"
class="relative flex justify-center before:absolute before:left-[50%] before:top-0 before:-z-10 before:border-l before:border-gray-200"
:class="[
i != activities.length - 1 ? 'before:h-full' : 'before:h-4',
activity.other_versions
? 'after:translate-y-[calc(-50% - 4px)] after:absolute after:bottom-9 after:left-[50%] after:top-0 after:-z-10 after:w-8 after:rounded-bl-xl after:border-b after:border-l after:border-gray-200'
: '',
]"
>
<div
class="z-10 flex h-7 w-7 items-center justify-center rounded-full bg-gray-100"
@ -308,7 +313,7 @@
</div>
</div>
</div>
<div v-else class="mb-4 flex flex-col gap-3 py-1.5">
<div v-else class="mb-4 flex flex-col gap-5 py-1.5">
<div class="flex items-start justify-stretch gap-2 text-base">
<div class="inline-flex flex-wrap gap-1 text-gray-600">
<span class="font-medium text-gray-800">{{
@ -346,6 +351,60 @@
</Tooltip>
</div>
</div>
<div
v-if="activity.other_versions && activity.show_others"
v-for="activity in activity.other_versions"
class="flex items-start justify-stretch gap-2 text-base"
>
<div class="inline-flex flex-wrap gap-1 text-gray-600">
<span v-if="activity.type">{{ activity.type }}</span>
<span
v-if="activity.data.field_label"
class="max-w-xs truncate font-medium text-gray-800"
>
{{ activity.data.field_label }}
</span>
<span v-if="activity.value">{{ activity.value }}</span>
<span
v-if="activity.data.old_value"
class="max-w-xs truncate font-medium text-gray-800"
>
{{ activity.data.old_value }}
</span>
<span v-if="activity.to">to</span>
<span
v-if="activity.data.value"
class="max-w-xs truncate font-medium text-gray-800"
>
{{ activity.data.value }}
</span>
</div>
<div class="ml-auto whitespace-nowrap">
<Tooltip
:text="dateFormat(activity.creation, dateTooltipFormat)"
class="text-gray-600"
>
{{ timeAgo(activity.creation) }}
</Tooltip>
</div>
</div>
<div v-if="activity.other_versions">
<Button
:label="
activity.show_others ? 'Hide all changes' : 'Show all changes'
"
variant="outline"
@click="activity.show_others = !activity.show_others"
>
<template #suffix>
<FeatherIcon
:name="activity.show_others ? 'chevron-up' : 'chevron-down'"
class="h-4 text-gray-600"
/>
</template>
</Button>
</div>
</div>
</div>
</div>
@ -415,7 +474,7 @@ import {
createListResource,
call,
} from 'frappe-ui'
import { ref, computed, h, defineModel, markRaw } from 'vue'
import { ref, computed, h, defineModel, markRaw, watch } from 'vue'
const { getUser } = usersStore()
const { getContact } = contactsStore()
@ -425,13 +484,10 @@ const props = defineProps({
type: String,
default: 'Activity',
},
activities: {
type: Array,
default: [],
},
})
const lead = defineModel()
const reload = defineModel('reload')
const versions = createResource({
url: 'crm.fcrm.doctype.crm_lead.api.get_activities',
@ -535,28 +591,39 @@ const activities = computed(() => {
)
return
activity.owner_name = getUser(activity.owner).full_name
activity.type = ''
activity.value = ''
activity.to = ''
update_activities_details(activity)
if (activity.activity_type == 'creation') {
activity.type = activity.data
} else if (activity.activity_type == 'added') {
activity.type = 'added'
activity.value = 'value as'
} else if (activity.activity_type == 'removed') {
activity.type = 'removed'
activity.value = 'value'
} else if (activity.activity_type == 'changed') {
activity.type = 'changed'
activity.value = 'value from'
activity.to = 'to'
if (activity.other_versions) {
activity.show_others = false
activity.other_versions.forEach((other_version) => {
update_activities_details(other_version)
})
}
})
return activities
})
function update_activities_details(activity) {
activity.owner_name = getUser(activity.owner).full_name
activity.type = ''
activity.value = ''
activity.to = ''
if (activity.activity_type == 'creation') {
activity.type = activity.data
} else if (activity.activity_type == 'added') {
activity.type = 'added'
activity.value = 'as'
} else if (activity.activity_type == 'removed') {
activity.type = 'removed'
activity.value = 'value'
} else if (activity.activity_type == 'changed') {
activity.type = 'changed'
activity.value = 'from'
activity.to = 'to'
}
}
const emptyText = computed(() => {
let text = 'No emails communications'
if (props.title == 'Calls') {
@ -645,6 +712,13 @@ async function updateNote(note) {
}
}
}
watch(reload, (value) => {
if (value) {
versions.reload()
reload.value = false
}
})
</script>
<style scoped>

View File

@ -65,7 +65,11 @@
v-for="tab in tabs"
:key="tab.label"
>
<Activities :title="tab.label" v-model="deal" />
<Activities
:title="tab.label"
v-model:reload="reload"
v-model="deal"
/>
</TabPanel>
</TabPanels>
</TabGroup>
@ -387,6 +391,8 @@ const deal = createResource({
auto: true,
})
const reload = ref(false)
function updateDeal(fieldname, value) {
createResource({
url: 'frappe.client.set_value',
@ -400,6 +406,7 @@ function updateDeal(fieldname, value) {
onSuccess: () => {
deal.reload()
contacts.reload()
reload.value = true
createToast({
title: 'Deal updated',
icon: 'check',

View File

@ -68,7 +68,11 @@
v-for="tab in tabs"
:key="tab.label"
>
<Activities :title="tab.label" v-model="lead" />
<Activities
:title="tab.label"
v-model:reload="reload"
v-model="lead"
/>
</TabPanel>
</TabPanels>
</TabGroup>
@ -361,6 +365,8 @@ const lead = createResource({
auto: true,
})
const reload = ref(false)
function updateLead(fieldname, value) {
createResource({
url: 'frappe.client.set_value',
@ -374,6 +380,7 @@ function updateLead(fieldname, value) {
onSuccess: () => {
lead.reload()
contacts.reload()
reload.value = true
createToast({
title: 'Lead updated',
icon: 'check',