Merge pull request #54 from shariquerik/pagination
feat: List View Footer to control pagination
This commit is contained in:
commit
3afef2e45b
@ -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
|
||||
@ -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",
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 = [
|
||||
|
||||
@ -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 []
|
||||
|
||||
@ -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 []
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
@ -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 []
|
||||
|
||||
@ -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==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user