diff --git a/crm/api/doc.py b/crm/api/doc.py
index ce611e15..bbafda0f 100644
--- a/crm/api/doc.py
+++ b/crm/api/doc.py
@@ -235,8 +235,8 @@ def get_list_data(
"page_length": page_length,
"page_length_count": page_length_count,
"is_default": is_default,
- "views": get_views(doctype, is_view=True),
- "total_count": frappe.client.get_count(doctype, filters=filters),
+ "views": get_views(doctype),
+ "total_count": len(frappe.get_all(doctype, filters=filters)),
"row_count": len(data),
}
diff --git a/crm/api/views.py b/crm/api/views.py
index ac69b46a..6a95adbf 100644
--- a/crm/api/views.py
+++ b/crm/api/views.py
@@ -3,7 +3,7 @@ from pypika import Criterion
@frappe.whitelist()
-def get_views(doctype, is_view=False):
+def get_views(doctype):
if frappe.session.user == "Guest":
frappe.throw("Authentication failed", exc=frappe.AuthenticationError)
@@ -13,8 +13,6 @@ def get_views(doctype, is_view=False):
.select("*")
.where(Criterion.any([View.user == '', View.user == frappe.session.user]))
)
- if is_view:
- query = query.where(View.is_view == True)
if doctype:
query = query.where(View.dt == doctype)
views = query.run(as_dict=True)
diff --git a/crm/fcrm/doctype/crm_view_settings/crm_view_settings.json b/crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
index 214d9d0d..e0ac969d 100644
--- a/crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
+++ b/crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
@@ -7,14 +7,12 @@
"field_order": [
"label",
"user",
- "user_list",
+ "is_default",
"column_break_zacm",
"dt",
"route_name",
"pinned",
"public",
- "default",
- "is_view",
"columns_tab",
"load_default_columns",
"columns",
@@ -31,7 +29,6 @@
"label": "Columns"
},
{
- "depends_on": "eval: doc.public == false",
"fieldname": "user",
"fieldtype": "Link",
"label": "User",
@@ -111,26 +108,14 @@
},
{
"default": "0",
- "fieldname": "default",
+ "fieldname": "is_default",
"fieldtype": "Check",
- "label": "Default"
- },
- {
- "default": "0",
- "fieldname": "is_view",
- "fieldtype": "Check",
- "label": "Is View"
- },
- {
- "depends_on": "eval: doc.public == true",
- "fieldname": "user_list",
- "fieldtype": "Text",
- "label": "User List"
+ "label": "Is Default"
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2024-01-22 21:44:41.733977",
+ "modified": "2024-02-03 18:38:09.412745",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM View Settings",
diff --git a/crm/fcrm/doctype/crm_view_settings/crm_view_settings.py b/crm/fcrm/doctype/crm_view_settings/crm_view_settings.py
index 9331bcc4..f7792250 100644
--- a/crm/fcrm/doctype/crm_view_settings/crm_view_settings.py
+++ b/crm/fcrm/doctype/crm_view_settings/crm_view_settings.py
@@ -21,10 +21,12 @@ def create(view):
view.rows = view.rows + default_rows if default_rows else view.rows
view.rows = remove_duplicates(view.rows)
+ if not view.columns:
+ view.columns = sync_default_list_columns(view.doctype)
+
doc = frappe.new_doc("CRM View Settings")
doc.name = view.label
doc.label = view.label
- doc.is_view = True
doc.dt = view.doctype
doc.user = frappe.session.user
doc.route_name = view.route_name or ""
@@ -50,7 +52,6 @@ def update(view):
doc = frappe.get_doc("CRM View Settings", view.name)
doc.label = view.label
- doc.is_view = True
doc.route_name = view.route_name or ""
doc.load_default_columns = view.load_default_columns or False
doc.filters = json.dumps(filters)
@@ -81,60 +82,6 @@ def pin(name, value):
doc.pinned = value
doc.save()
-@frappe.whitelist()
-def make_default(name, doctype, route_name):
- existing_default_view = frappe.db.exists("CRM View Settings", {
- "default": True,
- "user": frappe.session.user
- })
- if existing_default_view:
- frappe.db.set_value("CRM View Settings", existing_default_view, "default", False)
- else:
- public_default = frappe.db.exists("CRM View Settings", {
- "default": True,
- "public": True
- })
- if public_default:
- public_default_view = frappe.get_doc("CRM View Settings", public_default)
- user_list = json.loads(public_default_view.user_list)
- if frappe.session.user in user_list:
- updated_user_list = [user for user in user_list if user != frappe.session.user]
- if not updated_user_list:
- public_default_view.default = False
- public_default_view.user_list = None
- else:
- public_default_view.user_list = json.dumps(updated_user_list)
- public_default_view.save()
-
- if not name and doctype:
- exists = frappe.db.exists("CRM View Settings", {
- "dt": doctype,
- "is_view": False,
- "user": frappe.session.user
- })
- if not exists:
- doc = frappe.new_doc("CRM View Settings")
- doc.label = "List View"
- doc.default = True
- doc.dt = doctype
- doc.route_name = route_name
- doc.user = frappe.session.user
- doc.is_view = False
- doc.insert()
- else:
- frappe.db.set_value("CRM View Settings", exists, "default", True)
- elif frappe.db.get_value("CRM View Settings", name, "public"):
- doc = frappe.get_doc("CRM View Settings", name)
- doc.default = True
- doc.user_list = (
- json.dumps([frappe.session.user])
- if not doc.user_list
- else json.dumps(json.loads(doc.user_list) + [frappe.session.user])
- )
- doc.save()
- else:
- frappe.db.set_value("CRM View Settings", name, "default", True)
-
def remove_duplicates(l):
return list(dict.fromkeys(l))
@@ -146,3 +93,57 @@ def sync_default_list_rows(doctype):
rows = list.default_list_data().get("rows")
return rows
+
+def sync_default_list_columns(doctype):
+ list = get_controller(doctype)
+ columns = []
+
+ if hasattr(list, "default_list_data"):
+ columns = list.default_list_data().get("columns")
+
+ return columns
+
+
+@frappe.whitelist()
+def create_or_update_default_view(view):
+ view = frappe._dict(view)
+
+ filters = parse_json(view.filters) or {}
+ columns = parse_json(view.columns or '[]')
+ rows = parse_json(view.rows or '[]')
+
+ default_rows = sync_default_list_rows(view.doctype)
+ rows = rows + default_rows if default_rows else rows
+ rows = remove_duplicates(rows)
+
+ if not columns:
+ columns = sync_default_list_columns(view.doctype)
+
+ doc = frappe.db.exists(
+ "CRM View Settings",
+ {"dt": view.doctype, "is_default": True, "user": frappe.session.user},
+ )
+ if doc:
+ doc = frappe.get_doc("CRM View Settings", doc)
+ doc.label = view.label
+ doc.route_name = view.route_name or ""
+ doc.load_default_columns = view.load_default_columns or False
+ doc.filters = json.dumps(filters)
+ doc.order_by = view.order_by
+ doc.columns = json.dumps(columns)
+ doc.rows = json.dumps(rows)
+ doc.save()
+ else:
+ doc = frappe.new_doc("CRM View Settings")
+ doc.name = view.label or 'List View'
+ doc.label = view.label or 'List View'
+ doc.dt = view.doctype
+ doc.user = frappe.session.user
+ doc.route_name = view.route_name or ""
+ doc.load_default_columns = view.load_default_columns or False
+ doc.filters = json.dumps(filters)
+ doc.order_by = view.order_by
+ doc.columns = json.dumps(columns)
+ doc.rows = json.dumps(rows)
+ doc.is_default = True
+ doc.insert()
\ No newline at end of file
diff --git a/frontend/src/components/ViewControls.vue b/frontend/src/components/ViewControls.vue
index 3767b6e2..c59aafa9 100644
--- a/frontend/src/components/ViewControls.vue
+++ b/frontend/src/components/ViewControls.vue
@@ -26,14 +26,11 @@
-
+
{
}
})
let publicViews = list.value.data.views.filter((v) => v.public)
- let savedViews = list.value.data.views.filter((v) => !v.pinned && !v.public)
+ let savedViews = list.value.data.views.filter(
+ (v) => !v.pinned && !v.public && !v.is_default
+ )
let pinnedViews = list.value.data.views.filter((v) => v.pinned)
publicViews.length &&
@@ -300,6 +298,10 @@ function updateFilter(filters) {
list.value.params.filters = filters
view.value.filters = filters
list.value.reload()
+
+ if (!route.query.view) {
+ create_or_update_default_view()
+ }
}
function updateSort(order_by) {
@@ -311,6 +313,10 @@ function updateSort(order_by) {
list.value.params.order_by = order_by
view.value.order_by = order_by
list.value.reload()
+
+ if (!route.query.view) {
+ create_or_update_default_view()
+ }
}
function updateColumns(obj) {
@@ -330,6 +336,21 @@ function updateColumns(obj) {
list.value.reload()
}
viewUpdated.value = true
+
+ if (!route.query.view) {
+ create_or_update_default_view()
+ }
+}
+
+function create_or_update_default_view() {
+ if (route.query.view) return
+ view.value.doctype = props.doctype
+ call(
+ 'crm.fcrm.doctype.crm_view_settings.crm_view_settings.create_or_update_default_view',
+ {
+ view: view.value,
+ }
+ ).then(() => reloadView())
}
function updatePageLength(value, loadMore = false) {
@@ -362,20 +383,6 @@ const viewActions = computed(() => {
},
]
- let defaultView = getDefaultView()
- if (
- !defaultView ||
- (route.query.view && route.query.view != defaultView.name) ||
- (!route.query.view &&
- (defaultView.route_name != route.name || defaultView.is_view))
- ) {
- actions[0].items.push({
- label: 'Make Default',
- icon: () => h(FeatherIcon, { name: 'star', class: 'h-4 w-4' }),
- onClick: () => makeDefault(),
- })
- }
-
if (route.query.view && (!view.value.public || isManager())) {
actions[0].items.push(
{
@@ -431,24 +438,10 @@ const viewActions = computed(() => {
return actions
})
-function makeDefault() {
- call('crm.fcrm.doctype.crm_view_settings.crm_view_settings.make_default', {
- name: route.query.view || '',
- doctype: props.doctype,
- route_name: route.name,
- }).then(() => {
- createToast({
- title: 'Default View Set',
- icon: 'check',
- iconClasses: 'text-green-600',
- })
- reloadView()
- })
-}
-
function duplicateView() {
+ let label = getView(route.query.view)?.label || 'List View'
view.value.name = ''
- view.value.label = getView(route.query.view).label + ' New'
+ view.value.label = label + ' (New)'
showViewModal.value = true
}
diff --git a/frontend/src/pages/CallLog.vue b/frontend/src/pages/CallLog.vue
index 8f9250e5..64f46085 100644
--- a/frontend/src/pages/CallLog.vue
+++ b/frontend/src/pages/CallLog.vue
@@ -159,14 +159,12 @@ import {
} from 'frappe-ui'
import { usersStore } from '@/stores/users'
import { contactsStore } from '@/stores/contacts'
-import { viewsStore } from '@/stores/views'
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const { getUser } = usersStore()
const { contacts, getContact, getLeadContact } = contactsStore()
-const { getDefaultView } = viewsStore()
const props = defineProps({
callLogId: {
@@ -241,12 +239,7 @@ function createLead() {
}
const breadcrumbs = computed(() => {
- let defaultView = getDefaultView()
- let route = { name: 'Call Logs' }
- if (defaultView?.route_name == 'Call Logs' && defaultView?.is_view) {
- route = { name: 'Call Logs', query: { view: defaultView.name } }
- }
- let items = [{ label: 'Call Logs', route: route }]
+ let items = [{ label: 'Call Logs', route: { name: 'Call Logs' } }]
items.push({
label: callLog.data?.caller.label,
route: { name: 'Call Log', params: { callLogId: props.callLogId } },
diff --git a/frontend/src/pages/Contact.vue b/frontend/src/pages/Contact.vue
index 3b170623..7b219b20 100644
--- a/frontend/src/pages/Contact.vue
+++ b/frontend/src/pages/Contact.vue
@@ -226,7 +226,6 @@ import { usersStore } from '@/stores/users.js'
import { contactsStore } from '@/stores/contacts.js'
import { organizationsStore } from '@/stores/organizations.js'
import { statusesStore } from '@/stores/statuses'
-import { viewsStore } from '@/stores/views'
import { ref, computed, h } from 'vue'
import { useRouter } from 'vue-router'
@@ -236,7 +235,6 @@ const { getContactByName, contacts } = contactsStore()
const { getUser } = usersStore()
const { getOrganization } = organizationsStore()
const { getDealStatus } = statusesStore()
-const { getDefaultView } = viewsStore()
const props = defineProps({
contactId: {
@@ -253,12 +251,7 @@ const showContactModal = ref(false)
const detailMode = ref(false)
const breadcrumbs = computed(() => {
- let defaultView = getDefaultView()
- let route = { name: 'Contacts' }
- if (defaultView?.route_name == 'Contacts' && defaultView?.is_view) {
- route = { name: 'Contacts', query: { view: defaultView.name } }
- }
- let items = [{ label: 'Contacts', route: route }]
+ let items = [{ label: 'Contacts', route: { name: 'Contacts' } }]
items.push({
label: contact.value.full_name,
route: { name: 'Contact', params: { contactId: contact.value.name } },
diff --git a/frontend/src/pages/Deal.vue b/frontend/src/pages/Deal.vue
index 75f19c05..e6babe5e 100644
--- a/frontend/src/pages/Deal.vue
+++ b/frontend/src/pages/Deal.vue
@@ -316,7 +316,6 @@ import { globalStore } from '@/stores/global'
import { contactsStore } from '@/stores/contacts'
import { organizationsStore } from '@/stores/organizations'
import { statusesStore } from '@/stores/statuses'
-import { viewsStore } from '@/stores/views'
import {
createResource,
Dropdown,
@@ -333,7 +332,6 @@ const { $dialog, makeCall } = globalStore()
const { getContactByName, contacts } = contactsStore()
const { organizations, getOrganization } = organizationsStore()
const { statusOptions, getDealStatus } = statusesStore()
-const { getDefaultView } = viewsStore()
const router = useRouter()
const props = defineProps({
@@ -422,12 +420,7 @@ function validateRequired(fieldname, value) {
}
const breadcrumbs = computed(() => {
- let defaultView = getDefaultView()
- let route = { name: 'Deals' }
- if (defaultView?.route_name == 'Deals' && defaultView?.is_view) {
- route = { name: 'Deals', query: { view: defaultView.name } }
- }
- let items = [{ label: 'Deals', route: route }]
+ let items = [{ label: 'Deals', route: { name: 'Deals' } }]
items.push({
label: organization.value?.name,
route: { name: 'Deal', params: { dealId: deal.data.name } },
diff --git a/frontend/src/pages/Lead.vue b/frontend/src/pages/Lead.vue
index 5ecb0262..1fd0b65c 100644
--- a/frontend/src/pages/Lead.vue
+++ b/frontend/src/pages/Lead.vue
@@ -279,7 +279,6 @@ import { globalStore } from '@/stores/global'
import { contactsStore } from '@/stores/contacts'
import { organizationsStore } from '@/stores/organizations'
import { statusesStore } from '@/stores/statuses'
-import { viewsStore } from '@/stores/views'
import {
createResource,
FileUploader,
@@ -298,7 +297,6 @@ const { $dialog, makeCall } = globalStore()
const { getContactByName, contacts } = contactsStore()
const { organizations } = organizationsStore()
const { statusOptions, getLeadStatus } = statusesStore()
-const { getDefaultView } = viewsStore()
const router = useRouter()
const props = defineProps({
@@ -380,12 +378,7 @@ function validateRequired(fieldname, value) {
}
const breadcrumbs = computed(() => {
- let defaultView = getDefaultView()
- let route = { name: 'Leads' }
- if (defaultView?.route_name == 'Leads' && defaultView?.is_view) {
- route = { name: 'Leads', query: { view: defaultView.name } }
- }
- let items = [{ label: 'Leads', route: route }]
+ let items = [{ label: 'Leads', route: { name: 'Leads' } }]
items.push({
label: lead.data.lead_name,
route: { name: 'Lead', params: { leadId: lead.data.name } },
diff --git a/frontend/src/pages/Organization.vue b/frontend/src/pages/Organization.vue
index 9d3e311f..0e988c28 100644
--- a/frontend/src/pages/Organization.vue
+++ b/frontend/src/pages/Organization.vue
@@ -236,7 +236,6 @@ import { globalStore } from '@/stores/global'
import { usersStore } from '@/stores/users'
import { organizationsStore } from '@/stores/organizations.js'
import { statusesStore } from '@/stores/statuses'
-import { viewsStore } from '@/stores/views'
import {
dateFormat,
dateTooltipFormat,
@@ -256,7 +255,6 @@ const props = defineProps({
const { $dialog } = globalStore()
const { organizations, getOrganization } = organizationsStore()
const { getDealStatus } = statusesStore()
-const { getDefaultView } = viewsStore()
const showOrganizationModal = ref(false)
const detailMode = ref(false)
@@ -265,12 +263,7 @@ const router = useRouter()
const organization = computed(() => getOrganization(props.organizationId))
const breadcrumbs = computed(() => {
- let defaultView = getDefaultView()
- let route = { name: 'Organizations' }
- if (defaultView?.route_name == 'Organizations' && defaultView?.is_view) {
- route = { name: 'Organizations', query: { view: defaultView.name } }
- }
- let items = [{ label: 'Organizations', route: route }]
+ let items = [{ label: 'Organizations', route: { name: 'Organizations' } }]
items.push({
label: props.organizationId,
route: {
diff --git a/frontend/src/router.js b/frontend/src/router.js
index 32ca69db..adc3f17f 100644
--- a/frontend/src/router.js
+++ b/frontend/src/router.js
@@ -1,11 +1,11 @@
import { createRouter, createWebHistory } from 'vue-router'
import { usersStore } from '@/stores/users'
import { sessionStore } from '@/stores/session'
-import { viewsStore } from '@/stores/views'
const routes = [
{
path: '/',
+ redirect: { name: 'Leads' },
name: 'Home',
},
{
@@ -130,30 +130,14 @@ let router = createRouter({
router.beforeEach(async (to, from, next) => {
const { users } = usersStore()
const { isLoggedIn } = sessionStore()
- const { views, getDefaultView } = viewsStore()
await users.promise
- await views.promise
if (from.meta?.scrollPos) {
from.meta.scrollPos.top = document.querySelector('#list-rows')?.scrollTop
}
- if (to.path === '/') {
- const defaultView = getDefaultView()
- if (defaultView?.route_name) {
- if (defaultView.is_view) {
- next({
- name: defaultView.route_name,
- query: { view: defaultView.name },
- })
- } else {
- next({ name: defaultView.route_name })
- }
- } else {
- next({ name: 'Leads' })
- }
- } else if (to.name === 'Login' && isLoggedIn) {
+ if (to.name === 'Login' && isLoggedIn) {
next({ name: 'Leads' })
} else if (to.name !== 'Login' && !isLoggedIn) {
next({ name: 'Login' })
diff --git a/frontend/src/stores/views.js b/frontend/src/stores/views.js
index 35d66a71..b08d290f 100644
--- a/frontend/src/stores/views.js
+++ b/frontend/src/stores/views.js
@@ -1,5 +1,4 @@
import { defineStore } from 'pinia'
-import { sessionStore } from '@/stores/session'
import { createResource } from 'frappe-ui'
import { reactive, ref } from 'vue'
@@ -7,9 +6,7 @@ export const viewsStore = defineStore('crm-views', (doctype) => {
let viewsByName = reactive({})
let pinnedViews = ref([])
let publicViews = ref([])
- let defaultView = ref(null)
-
- const { user } = sessionStore()
+ let defaultView = ref({})
// Views
const views = createResource({
@@ -29,22 +26,18 @@ export const viewsStore = defineStore('crm-views', (doctype) => {
if (view.public) {
publicViews.value?.push(view)
}
-
- if (
- (!view.public && view.default) ||
- (view.public &&
- view.default &&
- JSON.parse(view.user_list).includes(user))
- ) {
- defaultView.value = view
+ if (view.is_default && view.dt) {
+ defaultView.value[view.dt] = view
}
}
return views
},
})
- function getView(view) {
- if (!view) return null
+ function getView(view, doctype = null) {
+ if (!view && doctype) {
+ return defaultView.value?.[doctype] || null
+ }
return viewsByName[view]
}
@@ -58,19 +51,15 @@ export const viewsStore = defineStore('crm-views', (doctype) => {
return publicViews.value
}
- function getDefaultView() {
- return defaultView.value
- }
-
async function reload() {
await views.reload()
}
return {
views,
+ defaultView,
getPinnedViews,
getPublicViews,
- getDefaultView,
reload,
getView,
}