1
0
forked from test/crm

Merge pull request #54 from shariquerik/pagination

feat: List View Footer to control pagination
This commit is contained in:
Shariq Ansari 2024-01-07 17:37:54 +05:30 committed by GitHub
commit 3afef2e45b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 200 additions and 12 deletions

View File

@ -56,9 +56,24 @@ def get_filterable_fields(doctype: str):
@frappe.whitelist()
def get_list_data(doctype: str, filters: dict, order_by: str, columns=None , rows=None, custom_view_name=None):
def get_list_data(
doctype: str,
filters: dict,
order_by: str,
page_length=20,
page_length_count=20,
columns=None,
rows=None,
custom_view_name=None,
default_filters=None,
):
custom_view = False
filters = frappe._dict(filters)
if default_filters:
default_filters = frappe.parse_json(default_filters)
filters.update(default_filters)
is_default = True
if columns or rows:
custom_view = True
@ -97,7 +112,7 @@ def get_list_data(doctype: str, filters: dict, order_by: str, columns=None , row
fields=rows,
filters=filters,
order_by=order_by,
page_length=20,
page_length=page_length,
) or []
fields = frappe.get_meta(doctype).fields
@ -141,8 +156,12 @@ def get_list_data(doctype: str, filters: dict, order_by: str, columns=None , row
"columns": columns,
"rows": rows,
"fields": fields,
"page_length": page_length,
"page_length_count": page_length_count,
"is_default": is_default,
"views": get_views(doctype),
"total_count": frappe.client.get_count(doctype, filters=filters),
"row_count": len(data),
}
def get_views(doctype):

@ -1 +1 @@
Subproject commit 0f4b6650598831d4382549c4ee22c360e01e35f0
Subproject commit f5f5665e944bef20a79ece6ad7223db09984c6a6

View File

@ -13,7 +13,7 @@
"@vueuse/core": "^10.3.0",
"@vueuse/integrations": "^10.3.0",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.17",
"frappe-ui": "^0.1.22",
"mime": "^4.0.1",
"pinia": "^2.0.33",
"socket.io-client": "^4.7.2",

View File

@ -62,6 +62,15 @@
</ListRows>
<ListSelectBanner />
</ListView>
<ListFooter
class="border-t px-5 py-2"
v-model="pageLengthCount"
:options="{
rowCount: options.rowCount,
totalCount: options.totalCount,
}"
@loadMore="emit('loadMore')"
/>
</template>
<script setup>
import {
@ -72,6 +81,7 @@ import {
ListRow,
ListSelectBanner,
ListRowItem,
ListFooter,
} from 'frappe-ui'
const props = defineProps({
@ -87,7 +97,13 @@ const props = defineProps({
type: Object,
default: () => ({
selectable: true,
totalCount: 0,
rowCount: 0,
}),
},
})
const emit = defineEmits(['loadMore'])
const pageLengthCount = defineModel()
</script>

View File

@ -63,6 +63,15 @@
</ListRows>
<ListSelectBanner />
</ListView>
<ListFooter
class="border-t px-5 py-2"
v-model="pageLengthCount"
:options="{
rowCount: options.rowCount,
totalCount: options.totalCount,
}"
@loadMore="emit('loadMore')"
/>
</template>
<script setup>
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
@ -74,7 +83,7 @@ import {
ListRow,
ListSelectBanner,
ListRowItem,
FormControl,
ListFooter,
} from 'frappe-ui'
const props = defineProps({
@ -90,7 +99,13 @@ const props = defineProps({
type: Object,
default: () => ({
selectable: true,
totalCount: 0,
rowCount: 0,
}),
},
})
const emit = defineEmits(['loadMore'])
const pageLengthCount = defineModel()
</script>

View File

@ -86,6 +86,15 @@
</ListRows>
<ListSelectBanner />
</ListView>
<ListFooter
class="border-t px-5 py-2"
v-model="pageLengthCount"
:options="{
rowCount: options.rowCount,
totalCount: options.totalCount,
}"
@loadMore="emit('loadMore')"
/>
</template>
<script setup>
@ -100,6 +109,7 @@ import {
ListRow,
ListRowItem,
ListSelectBanner,
ListFooter,
} from 'frappe-ui'
const props = defineProps({
@ -115,7 +125,13 @@ const props = defineProps({
type: Object,
default: () => ({
selectable: true,
totalCount: 0,
rowCount: 0,
}),
},
})
const emit = defineEmits(['loadMore'])
const pageLengthCount = defineModel()
</script>

View File

@ -95,6 +95,15 @@
</ListRows>
<ListSelectBanner />
</ListView>
<ListFooter
class="border-t px-5 py-2"
v-model="pageLengthCount"
:options="{
rowCount: options.rowCount,
totalCount: options.totalCount,
}"
@loadMore="emit('loadMore')"
/>
</template>
<script setup>
@ -109,6 +118,7 @@ import {
ListRow,
ListSelectBanner,
ListRowItem,
ListFooter,
} from 'frappe-ui'
const props = defineProps({
@ -124,7 +134,13 @@ const props = defineProps({
type: Object,
default: () => ({
selectable: true,
totalCount: 0,
rowCount: 0,
}),
},
})
const emit = defineEmits(['loadMore'])
const pageLengthCount = defineModel()
</script>

View File

@ -51,6 +51,15 @@
</ListRows>
<ListSelectBanner />
</ListView>
<ListFooter
class="border-t px-5 py-2"
v-model="pageLengthCount"
:options="{
rowCount: options.rowCount,
totalCount: options.totalCount,
}"
@loadMore="emit('loadMore')"
/>
</template>
<script setup>
import {
@ -61,6 +70,7 @@ import {
ListRow,
ListSelectBanner,
ListRowItem,
ListFooter,
} from 'frappe-ui'
const props = defineProps({
@ -76,7 +86,13 @@ const props = defineProps({
type: Object,
default: () => ({
selectable: true,
totalCount: 0,
rowCount: 0,
}),
},
})
const emit = defineEmits(['loadMore'])
const pageLengthCount = defineModel()
</script>

View File

@ -96,6 +96,7 @@ const { $dialog } = globalStore()
const { reload: reloadView, getView } = viewsStore()
const list = defineModel()
const loadMore = defineModel('loadMore')
const route = useRoute()
const router = useRouter()
@ -116,7 +117,7 @@ const currentView = computed(() => {
const view = ref({
name: '',
label: '',
filters: props.filters,
filters: {},
order_by: 'modified desc',
columns: '',
rows: '',
@ -124,9 +125,25 @@ const view = ref({
pinned: false,
})
const pageLength = computed(() => list.value?.data?.page_length)
const pageLengthCount = computed(() => list.value?.data?.page_length_count)
watch(loadMore, (value) => {
if (!value) return
updatePageLength(value, true)
})
watch(
() => list.value?.data?.page_length_count,
(value) => {
if (!value) return
updatePageLength(value)
}
)
function getParams() {
let _view = getView(route.query.view)
const filters = (_view?.filters && JSON.parse(_view.filters)) || props.filters
const filters = (_view?.filters && JSON.parse(_view.filters)) || {}
const order_by = _view?.order_by || 'modified desc'
const columns = _view?.columns || ''
const rows = _view?.rows || ''
@ -147,7 +164,7 @@ function getParams() {
view.value = {
name: '',
label: '',
filters: props.filters,
filters: {},
order_by: 'modified desc',
columns: '',
rows: '',
@ -163,7 +180,10 @@ function getParams() {
order_by: order_by,
columns: columns,
rows: rows,
page_length: pageLength.value,
page_length_count: pageLengthCount.value,
custom_view_name: _view?.name || '',
default_filters: props.filters,
}
}
@ -178,9 +198,12 @@ list.value = createResource({
doctype: props.doctype,
filters: list.value.params.filters,
order_by: list.value.params.order_by,
page_length: list.value.params.page_length,
page_length_count: list.value.params.page_length_count,
columns: data.columns,
rows: data.rows,
custom_view_name: cv?.name || '',
default_filters: props.filters,
}
},
})
@ -285,6 +308,20 @@ function updateColumns(obj) {
viewUpdated.value = true
}
function updatePageLength(value, loadMore = false) {
if (!defaultParams.value) {
defaultParams.value = getParams()
}
list.value.params = defaultParams.value
if (loadMore) {
list.value.params.page_length += list.value.params.page_length_count
} else {
list.value.params.page_length = value
list.value.params.page_length_count = value
}
list.value.reload()
}
// View Actions
const viewActions = computed(() => {
let actions = [

View File

@ -4,11 +4,17 @@
<Breadcrumbs :items="breadcrumbs" />
</template>
</LayoutHeader>
<ViewControls v-model="callLogs" doctype="CRM Call Log" />
<ViewControls v-model="callLogs" v-model:loadMore="loadMore" doctype="CRM Call Log" />
<CallLogsListView
v-if="callLogs.data && rows.length"
v-model="callLogs.data.page_length_count"
:rows="rows"
:columns="callLogs.data.columns"
:options="{
rowCount: callLogs.data.row_count,
totalCount: callLogs.data.total_count,
}"
@loadMore="() => loadMore++"
/>
<div
v-else-if="callLogs.data"
@ -44,7 +50,9 @@ const { getContact } = contactsStore()
const breadcrumbs = [{ label: 'Call Logs', route: { name: 'Call Logs' } }]
// callLogs data is loaded in the ViewControls component
const callLogs = ref({})
const loadMore = ref(1)
const rows = computed(() => {
if (!callLogs.value?.data?.data) return []

View File

@ -9,11 +9,21 @@
</Button>
</template>
</LayoutHeader>
<ViewControls v-model="contacts" doctype="Contact" />
<ViewControls
v-model="contacts"
v-model:loadMore="loadMore"
doctype="Contact"
/>
<ContactsListView
v-if="contacts.data && rows.length"
v-model="contacts.data.page_length_count"
:rows="rows"
:columns="contacts.data.columns"
:options="{
rowCount: contacts.data.row_count,
totalCount: contacts.data.total_count,
}"
@loadMore="() => loadMore++"
/>
<div
v-else-if="contacts.data"
@ -68,7 +78,9 @@ const breadcrumbs = computed(() => {
return items
})
// contacts data is loaded in the ViewControls component
const contacts = ref({})
const loadMore = ref(1)
const rows = computed(() => {
if (!contacts.value?.data?.data) return []

View File

@ -9,11 +9,21 @@
</Button>
</template>
</LayoutHeader>
<ViewControls v-model="deals" doctype="CRM Deal" />
<ViewControls
v-model="deals"
v-model:loadMore="loadMore"
doctype="CRM Deal"
/>
<DealsListView
v-if="deals.data && rows.length"
v-model="deals.data.page_length_count"
:rows="rows"
:columns="deals.data.columns"
:options="{
rowCount: deals.data.row_count,
totalCount: deals.data.total_count,
}"
@loadMore="() => loadMore++"
/>
<div v-else-if="deals.data" class="flex h-full items-center justify-center">
<div
@ -75,6 +85,7 @@ const router = useRouter()
// deals data is loaded in the ViewControls component
const deals = ref({})
const loadMore = ref(1)
// Rows
const rows = computed(() => {

View File

@ -11,13 +11,20 @@
</LayoutHeader>
<ViewControls
v-model="leads"
v-model:loadMore="loadMore"
doctype="CRM Lead"
:filters="{ converted: 0 }"
/>
<LeadsListView
v-if="leads.data && rows.length"
v-model="leads.data.page_length_count"
:rows="rows"
:columns="leads.data.columns"
:options="{
rowCount: leads.data.row_count,
totalCount: leads.data.total_count,
}"
@loadMore="() => loadMore++"
/>
<div v-else-if="leads.data" class="flex h-full items-center justify-center">
<div
@ -73,6 +80,7 @@ const router = useRouter()
// leads data is loaded in the ViewControls component
const leads = ref({})
const loadMore = ref(1)
// Rows
const rows = computed(() => {

View File

@ -13,11 +13,21 @@
</Button>
</template>
</LayoutHeader>
<ViewControls v-model="organizations" doctype="CRM Organization" />
<ViewControls
v-model="organizations"
v-model:loadMore="loadMore"
doctype="CRM Organization"
/>
<OrganizationsListView
v-if="organizations.data && rows.length"
v-model="organizations.data.page_length_count"
:rows="rows"
:columns="organizations.data.columns"
:options="{
rowCount: organizations.data.row_count,
totalCount: organizations.data.total_count,
}"
@loadMore="() => loadMore++"
/>
<div
v-else-if="organizations.data"
@ -74,7 +84,9 @@ const breadcrumbs = computed(() => {
return items
})
// organizations data is loaded in the ViewControls component
const organizations = ref({})
const loadMore = ref(1)
const rows = computed(() => {
if (!organizations.value?.data?.data) return []

View File

@ -3565,6 +3565,7 @@ string-argv@0.3.2:
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
name string-width-cjs
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -3600,6 +3601,7 @@ stringify-entities@^4.0.0:
character-entities-legacy "^3.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
name strip-ansi-cjs
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==