diff --git a/crm/api/activities.py b/crm/api/activities.py new file mode 100644 index 000000000..4f81074a2 --- /dev/null +++ b/crm/api/activities.py @@ -0,0 +1,226 @@ +import json + +import frappe +from frappe import _ +from frappe.desk.form.load import get_docinfo + +@frappe.whitelist() +def get_activities(name): + if frappe.db.exists("CRM Deal", name): + return get_deal_activities(name) + elif frappe.db.exists("CRM Lead", name): + return get_lead_activities(name) + else: + frappe.throw(_("Document not found"), frappe.DoesNotExistError) + +def get_deal_activities(name): + get_docinfo('', "CRM Deal", name) + docinfo = frappe.response["docinfo"] + deal_fields_meta = frappe.get_meta("CRM Deal").fields + + doc = frappe.db.get_values("CRM Deal", name, ["creation", "owner", "lead"])[0] + lead = doc[2] + + activities = [] + creation_text = "created this deal" + + if lead: + activities = get_lead_activities(lead) + creation_text = "converted the lead to this deal" + + activities.append({ + "activity_type": "creation", + "creation": doc[0], + "owner": doc[1], + "data": creation_text, + "is_lead": False, + }) + + docinfo.versions.reverse() + + for version in docinfo.versions: + data = json.loads(version.data) + if not data.get("changed"): + continue + + field_option = None + + if change := data.get("changed")[0]: + field_label, field_option = next(((f.label, f.options) for f in deal_fields_meta if f.fieldname == change[0]), None) + + if field_label == "Lead" or (not change[1] and not change[2]): + continue + + activity_type = "changed" + data = { + "field": change[0], + "field_label": field_label, + "old_value": change[1], + "value": change[2], + } + + if not change[1] and change[2]: + activity_type = "added" + data = { + "field": change[0], + "field_label": field_label, + "value": change[2], + } + elif change[1] and not change[2]: + activity_type = "removed" + data = { + "field": change[0], + "field_label": field_label, + "value": change[1], + } + + activity = { + "activity_type": activity_type, + "creation": version.creation, + "owner": version.owner, + "data": data, + "is_lead": False, + "options": field_option, + } + 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, + }, + "is_lead": False, + } + activities.append(activity) + + activities.sort(key=lambda x: x["creation"], reverse=True) + activities = handle_multiple_versions(activities) + + return activities + +def get_lead_activities(name): + get_docinfo('', "CRM Lead", name) + docinfo = frappe.response["docinfo"] + lead_fields_meta = frappe.get_meta("CRM Lead").fields + + doc = frappe.db.get_values("CRM Lead", name, ["creation", "owner"])[0] + activities = [{ + "activity_type": "creation", + "creation": doc[0], + "owner": doc[1], + "data": "created this lead", + "is_lead": True, + }] + + docinfo.versions.reverse() + + for version in docinfo.versions: + data = json.loads(version.data) + if not data.get("changed"): + continue + + field_option = None + + if change := data.get("changed")[0]: + field_label, field_option = next(((f.label, f.options) for f in lead_fields_meta if f.fieldname == change[0]), None) + + if field_label == "Converted" or (not change[1] and not change[2]): + continue + + activity_type = "changed" + data = { + "field": change[0], + "field_label": field_label, + "old_value": change[1], + "value": change[2], + } + + if not change[1] and change[2]: + activity_type = "added" + data = { + "field": change[0], + "field_label": field_label, + "value": change[2], + } + elif change[1] and not change[2]: + activity_type = "removed" + data = { + "field": change[0], + "field_label": field_label, + "value": change[1], + } + + activity = { + "activity_type": activity_type, + "creation": version.creation, + "owner": version.owner, + "data": data, + "is_lead": True, + "options": field_option, + } + 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, + }, + "is_lead": True, + } + activities.append(activity) + + activities.sort(key=lambda x: x["creation"], reverse=True) + activities = handle_multiple_versions(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 \ No newline at end of file diff --git a/crm/fcrm/doctype/crm_call_log/crm_call_log.json b/crm/fcrm/doctype/crm_call_log/crm_call_log.json index 469c1127c..55b077f22 100644 --- a/crm/fcrm/doctype/crm_call_log/crm_call_log.json +++ b/crm/fcrm/doctype/crm_call_log/crm_call_log.json @@ -14,7 +14,8 @@ "duration", "medium", "start_time", - "lead", + "reference_doctype", + "reference_docname", "column_break_ufnp", "to", "type", @@ -89,12 +90,6 @@ "fieldtype": "Datetime", "label": "End Time" }, - { - "fieldname": "lead", - "fieldtype": "Link", - "label": "Lead/Deal", - "options": "CRM Lead" - }, { "fieldname": "note", "fieldtype": "Link", @@ -114,11 +109,24 @@ "fieldtype": "Link", "label": "Caller", "options": "User" + }, + { + "default": "CRM Lead", + "fieldname": "reference_doctype", + "fieldtype": "Link", + "label": "Reference Document Type", + "options": "DocType" + }, + { + "fieldname": "reference_docname", + "fieldtype": "Dynamic Link", + "label": "Reference Name", + "options": "reference_doctype" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-08-30 15:39:46.613734", + "modified": "2023-11-07 13:52:40.504747", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Call Log", diff --git a/crm/fcrm/doctype/crm_deal/__init__.py b/crm/fcrm/doctype/crm_deal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/crm/fcrm/doctype/crm_deal/api.py b/crm/fcrm/doctype/crm_deal/api.py new file mode 100644 index 000000000..0dc14355c --- /dev/null +++ b/crm/fcrm/doctype/crm_deal/api.py @@ -0,0 +1,25 @@ +import json + +import frappe +from frappe import _ +from frappe.desk.form.load import get_docinfo +from crm.fcrm.doctype.crm_lead.api import get_activities as get_lead_activities + + +@frappe.whitelist() +def get_deal(name): + Deal = frappe.qb.DocType("CRM Deal") + + query = ( + frappe.qb.from_(Deal) + .select("*") + .where(Deal.name == name) + .limit(1) + ) + + deal = query.run(as_dict=True) + if not len(deal): + frappe.throw(_("Deal not found"), frappe.DoesNotExistError) + deal = deal.pop() + + return deal diff --git a/crm/fcrm/doctype/crm_deal/crm_deal.js b/crm/fcrm/doctype/crm_deal/crm_deal.js new file mode 100644 index 000000000..1b305ae09 --- /dev/null +++ b/crm/fcrm/doctype/crm_deal/crm_deal.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("CRM Deal", { +// refresh(frm) { + +// }, +// }); diff --git a/crm/fcrm/doctype/crm_deal/crm_deal.json b/crm/fcrm/doctype/crm_deal/crm_deal.json new file mode 100644 index 000000000..41289ef09 --- /dev/null +++ b/crm/fcrm/doctype/crm_deal/crm_deal.json @@ -0,0 +1,145 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "naming_series:", + "creation": "2023-11-06 17:56:25.210449", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "naming_series", + "organization", + "website", + "annual_revenue", + "column_break_afce", + "deal_owner", + "close_date", + "status", + "probability", + "next_step", + "section_break_eepu", + "lead", + "column_break_bqvs", + "contacts_tab", + "email", + "mobile_no" + ], + "fields": [ + { + "fieldname": "organization", + "fieldtype": "Link", + "label": "Organization", + "options": "CRM Organization" + }, + { + "fieldname": "probability", + "fieldtype": "Percent", + "label": "Probability" + }, + { + "fetch_from": "organization.annual_revenue", + "fieldname": "annual_revenue", + "fieldtype": "Int", + "label": "Annual Revenue" + }, + { + "fieldname": "column_break_afce", + "fieldtype": "Column Break" + }, + { + "fetch_from": "organization.website", + "fieldname": "website", + "fieldtype": "Data", + "label": "Website", + "options": "URL" + }, + { + "fieldname": "close_date", + "fieldtype": "Date", + "label": "Close Date" + }, + { + "fieldname": "next_step", + "fieldtype": "Data", + "label": "Next Step" + }, + { + "fieldname": "lead", + "fieldtype": "Link", + "label": "Lead", + "options": "CRM Lead" + }, + { + "fieldname": "section_break_eepu", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_bqvs", + "fieldtype": "Column Break" + }, + { + "fieldname": "deal_owner", + "fieldtype": "Link", + "label": "Deal Owner", + "options": "User" + }, + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Naming Series", + "options": "CRM-DEAL-.YYYY.-" + }, + { + "fieldname": "contacts_tab", + "fieldtype": "Tab Break", + "label": "Contacts" + }, + { + "fieldname": "email", + "fieldtype": "Data", + "label": "Email", + "options": "Email" + }, + { + "fieldname": "mobile_no", + "fieldtype": "Data", + "label": "Mobile No", + "options": "Phone" + }, + { + "default": "Qualification", + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Status", + "options": "Qualification\nDemo/Making\nProposal/Quotation\nNegotiation\nReady to Close\nWon\nLost", + "reqd": 1, + "search_index": 1 + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-11-06 21:53:50.442404", + "modified_by": "Administrator", + "module": "FCRM", + "name": "CRM Deal", + "naming_rule": "By \"Naming Series\" field", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "track_changes": 1 +} \ No newline at end of file diff --git a/crm/fcrm/doctype/crm_deal/crm_deal.py b/crm/fcrm/doctype/crm_deal/crm_deal.py new file mode 100644 index 000000000..3cfcf3479 --- /dev/null +++ b/crm/fcrm/doctype/crm_deal/crm_deal.py @@ -0,0 +1,19 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class CRMDeal(Document): + @staticmethod + def sort_options(): + return [ + { "label": 'Created', "value": 'creation' }, + { "label": 'Modified', "value": 'modified' }, + { "label": 'Status', "value": 'status' }, + { "label": 'Deal owner', "value": 'deal_owner' }, + { "label": 'Organization', "value": 'organization' }, + { "label": 'Email', "value": 'email' }, + { "label": 'Mobile no', "value": 'mobile_no' }, + ] diff --git a/crm/fcrm/doctype/crm_deal/test_crm_deal.py b/crm/fcrm/doctype/crm_deal/test_crm_deal.py new file mode 100644 index 000000000..b9ecc378a --- /dev/null +++ b/crm/fcrm/doctype/crm_deal/test_crm_deal.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestCRMDeal(FrappeTestCase): + pass diff --git a/crm/fcrm/doctype/crm_lead/api.py b/crm/fcrm/doctype/crm_lead/api.py index 5f22efb42..4abd959a3 100644 --- a/crm/fcrm/doctype/crm_lead/api.py +++ b/crm/fcrm/doctype/crm_lead/api.py @@ -22,126 +22,3 @@ def get_lead(name): lead = lead.pop() return lead - -@frappe.whitelist() -def get_activities(name): - get_docinfo('', "CRM Lead", name) - docinfo = frappe.response["docinfo"] - lead_fields_meta = frappe.get_meta("CRM Lead").fields - - doc = frappe.db.get_values("CRM Lead", name, ["creation", "owner", "created_as_deal"])[0] - created_as_deal = doc[2] - is_lead = False if created_as_deal else True - activities = [{ - "activity_type": "creation", - "creation": doc[0], - "owner": doc[1], - "data": "created this " + ("deal" if created_as_deal else "lead"), - "is_lead": is_lead, - }] - - docinfo.versions.reverse() - - for version in docinfo.versions: - data = json.loads(version.data) - if not data.get("changed"): - continue - - field_option = None - - if change := data.get("changed")[0]: - field_label, field_option = next(((f.label, f.options) for f in lead_fields_meta if f.fieldname == change[0]), None) - activity_type = "changed" - if field_label == "Lead Owner" and (created_as_deal or not is_lead): - field_label = "Deal Owner" - data = { - "field": change[0], - "field_label": field_label, - "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], - "field_label": field_label, - "value": change[2], - } - if field_label == "Is Deal" and change[2] and is_lead: - activity_type = "deal" - is_lead = False - elif change[1] and not change[2]: - activity_type = "removed" - data = { - "field": change[0], - "field_label": field_label, - "value": change[1], - } - - activity = { - "activity_type": activity_type, - "creation": version.creation, - "owner": version.owner, - "data": data, - "is_lead": is_lead, - "options": field_option, - } - 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, - }, - "is_lead": is_lead, - } - activities.append(activity) - - activities.sort(key=lambda x: x["creation"], reverse=True) - activities = handle_multiple_versions(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 \ No newline at end of file diff --git a/crm/fcrm/doctype/crm_lead/crm_lead.json b/crm/fcrm/doctype/crm_lead/crm_lead.json index bfe7dbbd4..8257a2e5f 100644 --- a/crm/fcrm/doctype/crm_lead/crm_lead.json +++ b/crm/fcrm/doctype/crm_lead/crm_lead.json @@ -13,20 +13,15 @@ "first_name", "middle_name", "last_name", - "is_deal", - "created_as_deal", "column_break_izjs", "lead_name", "gender", - "lead_owner", - "status", "image", "column_break_lcuv", + "lead_owner", + "status", "source", - "deal_status", - "close_date", - "probability", - "next_step", + "converted", "organization_tab", "section_break_uixv", "organization", @@ -93,7 +88,7 @@ "fieldname": "status", "fieldtype": "Select", "in_list_view": 1, - "label": "Lead Status", + "label": "Status", "options": "Open\nContacted\nNurture\nQualified\nUnqualified\nJunk", "reqd": 1, "search_index": 1 @@ -123,8 +118,9 @@ }, { "fieldname": "mobile_no", - "fieldtype": "Phone", - "label": "Mobile No" + "fieldtype": "Data", + "label": "Mobile No", + "options": "Phone" }, { "fieldname": "column_break_sjtw", @@ -132,8 +128,9 @@ }, { "fieldname": "phone", - "fieldtype": "Phone", - "label": "Phone" + "fieldtype": "Data", + "label": "Phone", + "options": "Phone" }, { "fieldname": "section_break_uixv", @@ -189,25 +186,6 @@ "label": "Full Name", "search_index": 1 }, - { - "default": "Qualification", - "fieldname": "deal_status", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Deal Status", - "options": "Qualification\nDemo/Making\nProposal/Quotation\nNegotiation\nReady to Close\nWon\nLost", - "reqd": 1, - "search_index": 1 - }, - { - "default": "0", - "fieldname": "is_deal", - "fieldtype": "Check", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Is Deal", - "search_index": 1 - }, { "fetch_from": "organization.job_title", "fieldname": "job_title", @@ -225,21 +203,6 @@ "fieldtype": "Tab Break", "label": "Contact" }, - { - "fieldname": "close_date", - "fieldtype": "Date", - "label": "Close Date" - }, - { - "fieldname": "probability", - "fieldtype": "Data", - "label": "Probability" - }, - { - "fieldname": "next_step", - "fieldtype": "Data", - "label": "Next Step" - }, { "fieldname": "contacts", "fieldtype": "Table", @@ -250,24 +213,25 @@ "fieldname": "section_break_jyxr", "fieldtype": "Section Break" }, - { - "default": "0", - "fieldname": "created_as_deal", - "fieldtype": "Check", - "hidden": 1, - "label": "Created as Deal" - }, { "fieldname": "organization", "fieldtype": "Link", "label": "Organization", "options": "CRM Organization" + }, + { + "default": "0", + "fieldname": "converted", + "fieldtype": "Check", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Converted" } ], "image_field": "image", "index_web_pages_for_search": 1, "links": [], - "modified": "2023-11-06 15:29:56.868755", + "modified": "2023-11-06 21:53:32.542503", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Lead", diff --git a/crm/fcrm/doctype/crm_note/crm_note.json b/crm/fcrm/doctype/crm_note/crm_note.json index f17f84c71..844100266 100644 --- a/crm/fcrm/doctype/crm_note/crm_note.json +++ b/crm/fcrm/doctype/crm_note/crm_note.json @@ -9,7 +9,8 @@ "field_order": [ "title", "content", - "lead" + "reference_doctype", + "reference_docname" ], "fields": [ { @@ -27,10 +28,17 @@ "label": "Content" }, { - "fieldname": "lead", + "default": "CRM Lead", + "fieldname": "reference_doctype", "fieldtype": "Link", - "label": "Lead", - "options": "CRM Lead" + "label": "Reference Document Type", + "options": "DocType" + }, + { + "fieldname": "reference_docname", + "fieldtype": "Dynamic Link", + "label": "Reference Doc", + "options": "reference_doctype" } ], "index_web_pages_for_search": 1, @@ -40,7 +48,7 @@ "link_fieldname": "note" } ], - "modified": "2023-08-28 11:48:42.100802", + "modified": "2023-11-07 13:41:11.249515", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Note", diff --git a/crm/fcrm/doctype/crm_task/crm_task.json b/crm/fcrm/doctype/crm_task/crm_task.json index cf7dbe524..fa0ce47f8 100644 --- a/crm/fcrm/doctype/crm_task/crm_task.json +++ b/crm/fcrm/doctype/crm_task/crm_task.json @@ -10,7 +10,8 @@ "title", "priority", "start_date", - "lead", + "reference_doctype", + "reference_docname", "column_break_cqua", "assigned_to", "status", @@ -70,15 +71,22 @@ "label": "Description" }, { - "fieldname": "lead", + "default": "CRM Lead", + "fieldname": "reference_doctype", "fieldtype": "Link", - "label": "Lead", - "options": "CRM Lead" + "label": "Reference Document Type", + "options": "DocType" + }, + { + "fieldname": "reference_docname", + "fieldtype": "Dynamic Link", + "label": "Reference Doc", + "options": "reference_doctype" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-09-28 15:05:27.986420", + "modified": "2023-11-07 13:41:18.277998", "modified_by": "Administrator", "module": "FCRM", "name": "CRM Task", diff --git a/crm/twilio/api.py b/crm/twilio/api.py index 4297e5a7f..93d2a5359 100644 --- a/crm/twilio/api.py +++ b/crm/twilio/api.py @@ -86,9 +86,10 @@ def update_call_log(call_sid, status=None): call_log.duration = call_details.duration call_log.start_time = get_datetime_from_timestamp(call_details.start_time) call_log.end_time = get_datetime_from_timestamp(call_details.end_time) - call_log.lead = get_lead_from_number(call_log) - if call_log.note and call_log.lead: - frappe.db.set_value("CRM Note", call_log.note, "lead", call_log.lead) + call_log.reference_docname, call_log.reference_doctype = get_lead_or_deal_from_number(call_log) + if call_log.note and call_log.reference_docname: + frappe.db.set_value("CRM Note", call_log.note, "reference_doctype", call_log.reference_doctype) + frappe.db.set_value("CRM Note", call_log.note, "reference_docname", call_log.reference_docname) call_log.flags.ignore_permissions = True call_log.save() frappe.db.commit() @@ -145,13 +146,20 @@ def add_note_to_call_log(call_sid, note): frappe.db.set_value("CRM Call Log", call_details.parent_call_sid, "note", note) frappe.db.commit() -def get_lead_from_number(call): - """Get lead from the given number. +def get_lead_or_deal_from_number(call): + """Get lead/deal from the given number. """ - lead = None + doctype = "CRM Lead" + doc = None if call.type == 'Outgoing': - lead = frappe.db.get_value("CRM Lead", { "mobile_no": call.get('to') }) + doc = frappe.get_cached_value(doctype, { "mobile_no": call.get('to') }) + if not doc: + doctype = "CRM Deal" + doc = frappe.get_cached_value(doctype, { "mobile_no": call.get('to') }) else: - lead = frappe.db.get_value("CRM Lead", { "mobile_no": call.get('from') }) + doc = frappe.get_cached_value(doctype, { "mobile_no": call.get('from') }) + if not doc: + doctype = "CRM Deal" + doc = frappe.get_cached_value(doctype, { "mobile_no": call.get('from') }) - return lead \ No newline at end of file + return doc, doctype \ No newline at end of file diff --git a/frontend/src/components/Activities.vue b/frontend/src/components/Activities.vue index ab059e89c..369936228 100644 --- a/frontend/src/components/Activities.vue +++ b/frontend/src/components/Activities.vue @@ -6,7 +6,7 @@