-
Notifications
You must be signed in to change notification settings - Fork 154
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: rendered versions on activity tab
- Loading branch information
1 parent
762f487
commit d3a2d8f
Showing
4 changed files
with
292 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import json | ||
|
||
import frappe | ||
from frappe import _ | ||
from frappe.desk.form.load import get_docinfo | ||
|
||
|
||
@frappe.whitelist() | ||
def get_lead(name): | ||
Lead = frappe.qb.DocType("CRM Lead") | ||
|
||
query = ( | ||
frappe.qb.from_(Lead) | ||
.select("*") | ||
.where(Lead.name == name) | ||
.limit(1) | ||
) | ||
|
||
lead = query.run(as_dict=True) | ||
if not len(lead): | ||
frappe.throw(_("Lead not found"), frappe.DoesNotExistError) | ||
lead = lead.pop() | ||
|
||
get_docinfo('', "CRM Lead", name) | ||
docinfo = frappe.response["docinfo"] | ||
activities = get_activities(lead, docinfo) | ||
|
||
return { **lead, 'activities': activities } | ||
|
||
def get_activities(doc, docinfo): | ||
activities = [{ | ||
"activity_type": "creation", | ||
"creation": doc.creation, | ||
"owner": doc.owner, | ||
"data": "created this lead", | ||
}] | ||
|
||
for version in docinfo.versions: | ||
data = json.loads(version.data) | ||
if change := data.get("changed")[0]: | ||
activity_type = "changed" | ||
data = { | ||
"field": change[0], | ||
"old_value": change[1], | ||
"value": change[2], | ||
} | ||
if not change[1] and not change[2]: | ||
continue | ||
if not change[1] and change[2]: | ||
activity_type = "added" | ||
data = { | ||
"field": change[0], | ||
"value": change[2], | ||
} | ||
elif change[1] and not change[2]: | ||
activity_type = "removed" | ||
data = { | ||
"field": change[0], | ||
"value": change[1], | ||
} | ||
|
||
activity = { | ||
"activity_type": activity_type, | ||
"creation": version.creation, | ||
"owner": version.owner, | ||
"data": data, | ||
} | ||
activities.append(activity) | ||
|
||
for comment in docinfo.comments: | ||
activity = { | ||
"activity_type": "comment", | ||
"creation": comment.creation, | ||
"owner": comment.owner, | ||
"data": comment.content, | ||
} | ||
activities.append(activity) | ||
|
||
for communication in docinfo.communications: | ||
activity = { | ||
"activity_type": "communication", | ||
"creation": communication.creation, | ||
"data": { | ||
"subject": communication.subject, | ||
"content": communication.content, | ||
"sender_full_name": communication.sender_full_name, | ||
"sender": communication.sender, | ||
"recipients": communication.recipients, | ||
"cc": communication.cc, | ||
"bcc": communication.bcc, | ||
"read_by_recipient": communication.read_by_recipient, | ||
}, | ||
} | ||
activities.append(activity) | ||
|
||
activities.sort(key=lambda x: x["creation"], reverse=True) | ||
|
||
return activities |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,127 @@ | ||
<template> | ||
<div class="p-6"> | ||
<div v-for="activity in activities"> | ||
<div>{{ activity.value }}</div> | ||
<div class="p-5 flex items-center justify-between font-medium text-lg"> | ||
<div>{{ title }}</div> | ||
</div> | ||
<div> | ||
<div v-for="(activity, i) in activities"> | ||
<div class="grid grid-cols-[30px_minmax(auto,_1fr)] gap-4 px-5"> | ||
<div | ||
class="relative flex justify-center" | ||
:class="{ | ||
'after:absolute after:border-l after:border-gray-300 after:top-0 after:left-[50%] after:h-full after:-z-10': | ||
i != activities.length - 1, | ||
}" | ||
> | ||
<div | ||
class="flex items-center justify-center rounded-full outline outline-4 outline-white w-6 h-6 bg-gray-200 z-10" | ||
> | ||
<FeatherIcon | ||
:name="timelineIcon(activity.activity_type)" | ||
class="w-3.5 h-3.5 text-gray-600" | ||
/> | ||
</div> | ||
</div> | ||
<div class="flex flex-col gap-3 pb-6"> | ||
<div | ||
class="flex items-start justify-stretch gap-2 text-base leading-6" | ||
> | ||
<Avatar | ||
:image="getUser(activity.owner).user_image" | ||
:label="getUser(activity.owner).full_name" | ||
size="md" | ||
/> | ||
|
||
<div class="flex items-center gap-1"> | ||
<div>{{ getUser(activity.owner).full_name }}</div> | ||
<div | ||
v-if="activity.activity_type == 'creation'" | ||
class="text-gray-600" | ||
> | ||
{{ activity.data }} | ||
</div> | ||
<div | ||
v-else-if="activity.activity_type == 'added'" | ||
class="inline-flex gap-1 text-gray-600" | ||
> | ||
<span>added</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.field }} | ||
</span> | ||
<span>value as</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.value }} | ||
</span> | ||
</div> | ||
<div | ||
v-else-if="activity.activity_type == 'removed'" | ||
class="inline-flex gap-1 text-gray-600" | ||
> | ||
<span>removed</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.field }} | ||
</span> | ||
<span>value</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.value }} | ||
</span> | ||
</div> | ||
<div | ||
v-else-if="activity.activity_type == 'changed'" | ||
class="inline-flex gap-1 text-gray-600" | ||
> | ||
<span>changed</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.field }} | ||
</span> | ||
<span>value from</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.old_value }} | ||
</span> | ||
<span>to</span> | ||
<span class="text-gray-900 truncate max-w-xs"> | ||
{{ activity.data.value }} | ||
</span> | ||
</div> | ||
</div> | ||
|
||
<div class="ml-auto whitespace-nowrap"> | ||
<Tooltip | ||
:text="dateFormat(activity.creation, dateTooltipFormat)" | ||
class="text-sm text-gray-600 leading-6" | ||
> | ||
{{ timeAgo(activity.creation) }} | ||
</Tooltip> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
<script setup> | ||
import { Avatar, FeatherIcon, Tooltip, Button } from 'frappe-ui' | ||
import { timeAgo, dateFormat, dateTooltipFormat } from '@/utils' | ||
import { usersStore } from '@/stores/users' | ||
const { getUser } = usersStore() | ||
const props = defineProps({ | ||
title: { | ||
type: String, | ||
default: 'Activity', | ||
}, | ||
activities: { | ||
type: Array, | ||
default: [], | ||
}, | ||
}) | ||
function timelineIcon(activity_type) { | ||
if (activity_type == 'creation') { | ||
return 'plus' | ||
} else if (activity_type == 'removed') { | ||
return 'trash-2' | ||
} | ||
return 'edit' | ||
} | ||
</script> |
Oops, something went wrong.