Browse Source

feat(gui-v2): add pagination

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2716/head
Pranav C 2 years ago
parent
commit
34d3d36a7b
  1. 8
      packages/nc-gui-v2/components/index.ts
  2. 337
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  3. 24
      packages/nc-gui-v2/components/smartsheet/Pagination.vue
  4. 10
      packages/nc-gui-v2/composables/useViewData.ts

8
packages/nc-gui-v2/components/index.ts

@ -1,6 +1,12 @@
import type { ColumnType, TableType } from 'nocodb-sdk'
import type { ColumnType, PaginatedType, TableType } from 'nocodb-sdk'
import type { InjectionKey, Ref } from 'vue'
import type useViewData from '~/composables/useViewData'
export const ColumnInj: InjectionKey<ColumnType> = Symbol('column-injection')
export const MetaInj: InjectionKey<Ref<TableType>> = Symbol('meta-injection')
export const TabMetaInj: InjectionKey<any> = Symbol('tab-meta-injection')
export const PaginationDataInj: InjectionKey<Ref<PaginatedType>> = Symbol('pagination-data-injection')
export const ChangePageInj: InjectionKey<ReturnType<typeof useViewData>['changePage']> = Symbol('pagination-data-injection')
export const IsFormInj: InjectionKey<boolean> = Symbol('is-form-injection')
export const IsGridInj: InjectionKey<boolean> = Symbol('is-grid-injection')
export const ValueInj: InjectionKey<any> = Symbol('value-injection')

337
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -1,10 +1,7 @@
<script lang="ts" setup>
import type { Ref } from 'vue'
import { inject, onMounted } from 'vue'
import { isVirtualCol } from 'nocodb-sdk'
import type { TableType } from 'nocodb-sdk'
import { MetaInj } from '~/components'
import Smartsheet from '~/components/tabs/Smartsheet.vue'
import { ChangePageInj, MetaInj, PaginationDataInj } from '~/components'
import useViewData from '~/composables/useViewData'
const meta = inject(MetaInj)
@ -15,11 +12,12 @@ const isPublicView = false
const selected = reactive<{ row?: number | null; col?: number | null }>({})
const editEnabled = ref(false)
const { loadData, paginationData, formattedData: data, updateRowProperty } = useViewData(meta)
const { loadData, paginationData, formattedData: data, updateRowProperty, changePage } = useViewData(meta)
provide('isForm', false)
provide('isGrid', true)
provide('paginationData', paginationData)
provide(PaginationDataInj, paginationData)
provide(ChangePageInj, changePage)
onMounted(() => loadData({}))
@ -36,174 +34,181 @@ onKeyStroke(['Enter'], (e) => {
</script>
<template>
<table class="xc-row-table nc-grid backgroundColorDefault">
<thead>
<tr>
<th>#</th>
<th v-for="col in meta.columns" :key="col.title">
{{ col.title }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="({ row }, rowIndex) in data" :key="rowIndex" class="nc-grid-row">
<td key="row-index" style="width: 65px" class="caption nc-grid-cell">
<div class="d-flex align-center">
{{ rowIndex + 1 }}
</div>
</td>
<td
v-for="(columnObj, colIndex) in meta.columns"
:key="rowIndex + columnObj.title"
class="cell pointer nc-grid-cell"
:class="{
active: !isPublicView && selected.col === colIndex && selected.row === rowIndex,
// 'primary-column': primaryValueColumn === columnObj.title,
// 'text-center': isCentrallyAligned(columnObj),
// 'required': isRequired(columnObj, rowObj),
}"
:data-col="columnObj.title"
@click="selectCell(rowIndex, colIndex)"
@dblclick="editEnabled = true"
>
<!-- @contextmenu=" -->
<!-- showRowContextMenu($event, rowObj, rowMeta, row, col, columnObj) -->
<!-- " -->
<!-- > -->
<!-- <virtual-cell -->
<!-- v-if="isVirtualCol(columnObj)" -->
<!-- :password="password" -->
<!-- :is-public="isPublicView" -->
<!-- :metas="metas" -->
<!-- :is-locked="isLocked" -->
<!-- :column="columnObj" -->
<!-- :row="rowObj" -->
<!-- :nodes="nodes" -->
<!-- :meta="meta" -->
<!-- :api="api" -->
<!-- :active="selected.col === col && selected.row === row" -->
<!-- :sql-ui="sqlUi" -->
<!-- :is-new="rowMeta.new" -->
<!-- v-on="$listeners" -->
<!-- @updateCol=" -->
<!-- (...args) => -->
<!-- updateCol( -->
<!-- ...args, -->
<!-- columnObj.bt -->
<!-- && meta.columns.find( -->
<!-- (c) => c.column_name === columnObj.bt.column_name, -->
<!-- ), -->
<!-- col, -->
<!-- row, -->
<!-- ) -->
<!-- " -->
<!-- @saveRow="onCellValueChange(col, row, columnObj, true)" -->
<!-- /> -->
<!-- <editable-cell -->
<!-- v-else-if=" -->
<!-- ((isPkAvail || rowMeta.new) -->
<!-- && !isView -->
<!-- && !isLocked -->
<!-- && !isPublicView -->
<!-- && editEnabled.col === col -->
<!-- && editEnabled.row === row) -->
<!-- || enableEditable(columnObj) -->
<!-- " -->
<!-- v-model="rowObj[columnObj.title]" -->
<!-- :column="columnObj" -->
<!-- :meta="meta" -->
<!-- :active="selected.col === col && selected.row === row" -->
<!-- :sql-ui="sqlUi" -->
<!-- :db-alias="nodes.dbAlias" -->
<!-- :is-locked="isLocked" -->
<!-- :is-public="isPublicView" -->
<!-- :view-id="viewId" -->
<!-- @save="editEnabled = {}; onCellValueChange(col, row, columnObj, true);" -->
<!-- @cancel="editEnabled = {}" -->
<!-- @update="onCellValueChange(col, row, columnObj, false)" -->
<!-- @blur="onCellValueChange(col, row, columnObj, true)" -->
<!-- @input="unsaved = true" -->
<!-- @navigateToNext="navigateToNext" -->
<!-- @navigateToPrev="navigateToPrev" -->
<!-- /> -->
<SmartsheetVirtualCell v-if="isVirtualCol(columnObj)" v-model="row[columnObj.title]" :column="columnObj" />
<SmartsheetCell
v-else
v-model="row[columnObj.title]"
:column="columnObj"
:edit-enabled="editEnabled && selected.col === colIndex && selected.row === rowIndex"
@update:model-value="updateRowProperty(row, columnObj.title)"
/>
<!-- <SmartsheetCell v-else :column="columnObj" :value="row[columnObj.title]" /> -->
<!-- :selected="selected.col === col && selected.row === row" -->
<!-- :is-locked="isLocked" -->
<!-- :column="columnObj" -->
<!-- :meta="meta" -->
<!-- :db-alias="nodes.dbAlias" -->
<!-- :value="rowObj[columnObj.title]" -->
<!-- :sql-ui="sqlUi" -->
<!-- @enableedit=" -->
<!-- makeSelected(col, row); -->
<!-- makeEditable(col, row, columnObj.ai, rowMeta); -->
<!-- " -->
<!-- /> -->
</td>
</tr>
</tbody>
</table>
<!-- <SmartsheetPagination /> -->
<div class="nc-grid-wrapper">
<table class="xc-row-table nc-grid backgroundColorDefault">
<thead>
<tr>
<th>#</th>
<th v-for="col in meta.columns" :key="col.title">
{{ col.title }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="({ row }, rowIndex) in data" :key="rowIndex" class="nc-grid-row">
<td key="row-index" style="width: 65px" class="caption nc-grid-cell">
<div class="d-flex align-center">
{{ rowIndex + 1 }}
</div>
</td>
<td
v-for="(columnObj, colIndex) in meta.columns"
:key="rowIndex + columnObj.title"
class="cell pointer nc-grid-cell"
:class="{
active: !isPublicView && selected.col === colIndex && selected.row === rowIndex,
// 'primary-column': primaryValueColumn === columnObj.title,
// 'text-center': isCentrallyAligned(columnObj),
// 'required': isRequired(columnObj, rowObj),
}"
:data-col="columnObj.title"
@click="selectCell(rowIndex, colIndex)"
@dblclick="editEnabled = true"
>
<!-- @contextmenu=" -->
<!-- showRowContextMenu($event, rowObj, rowMeta, row, col, columnObj) -->
<!-- " -->
<!-- > -->
<!-- <virtual-cell -->
<!-- v-if="isVirtualCol(columnObj)" -->
<!-- :password="password" -->
<!-- :is-public="isPublicView" -->
<!-- :metas="metas" -->
<!-- :is-locked="isLocked" -->
<!-- :column="columnObj" -->
<!-- :row="rowObj" -->
<!-- :nodes="nodes" -->
<!-- :meta="meta" -->
<!-- :api="api" -->
<!-- :active="selected.col === col && selected.row === row" -->
<!-- :sql-ui="sqlUi" -->
<!-- :is-new="rowMeta.new" -->
<!-- v-on="$listeners" -->
<!-- @updateCol=" -->
<!-- (...args) => -->
<!-- updateCol( -->
<!-- ...args, -->
<!-- columnObj.bt -->
<!-- && meta.columns.find( -->
<!-- (c) => c.column_name === columnObj.bt.column_name, -->
<!-- ), -->
<!-- col, -->
<!-- row, -->
<!-- ) -->
<!-- " -->
<!-- @saveRow="onCellValueChange(col, row, columnObj, true)" -->
<!-- /> -->
<!-- <editable-cell -->
<!-- v-else-if=" -->
<!-- ((isPkAvail || rowMeta.new) -->
<!-- && !isView -->
<!-- && !isLocked -->
<!-- && !isPublicView -->
<!-- && editEnabled.col === col -->
<!-- && editEnabled.row === row) -->
<!-- || enableEditable(columnObj) -->
<!-- " -->
<!-- v-model="rowObj[columnObj.title]" -->
<!-- :column="columnObj" -->
<!-- :meta="meta" -->
<!-- :active="selected.col === col && selected.row === row" -->
<!-- :sql-ui="sqlUi" -->
<!-- :db-alias="nodes.dbAlias" -->
<!-- :is-locked="isLocked" -->
<!-- :is-public="isPublicView" -->
<!-- :view-id="viewId" -->
<!-- @save="editEnabled = {}; onCellValueChange(col, row, columnObj, true);" -->
<!-- @cancel="editEnabled = {}" -->
<!-- @update="onCellValueChange(col, row, columnObj, false)" -->
<!-- @blur="onCellValueChange(col, row, columnObj, true)" -->
<!-- @input="unsaved = true" -->
<!-- @navigateToNext="navigateToNext" -->
<!-- @navigateToPrev="navigateToPrev" -->
<!-- /> -->
<SmartsheetVirtualCell v-if="isVirtualCol(columnObj)" v-model="row[columnObj.title]" :column="columnObj" />
<SmartsheetCell
v-else
v-model="row[columnObj.title]"
:column="columnObj"
:edit-enabled="editEnabled && selected.col === colIndex && selected.row === rowIndex"
@update:model-value="updateRowProperty(row, columnObj.title)"
/>
<!-- <SmartsheetCell v-else :column="columnObj" :value="row[columnObj.title]" /> -->
<!-- :selected="selected.col === col && selected.row === row" -->
<!-- :is-locked="isLocked" -->
<!-- :column="columnObj" -->
<!-- :meta="meta" -->
<!-- :db-alias="nodes.dbAlias" -->
<!-- :value="rowObj[columnObj.title]" -->
<!-- :sql-ui="sqlUi" -->
<!-- @enableedit=" -->
<!-- makeSelected(col, row); -->
<!-- makeEditable(col, row, columnObj.ai, rowMeta); -->
<!-- " -->
<!-- /> -->
</td>
</tr>
</tbody>
</table>
</div>
<SmartsheetPagination />
</template>
<style scoped lang="scss">
td,
tr {
min-height: 31px !important;
position: relative;
padding: 0 5px !important;
min-width: 200px;
}
.nc-grid-wrapper {
width: 100%;
// todo : proper height calculation
height: calc(100vh - 250px);
overflow: auto;
td,
tr {
min-height: 31px !important;
position: relative;
padding: 0 5px !important;
min-width: 200px;
}
table,
td,
th {
border-right: 1px solid #7f828b33 !important;
border-left: 1px solid #7f828b33 !important;
border-bottom: 1px solid #7f828b33 !important;
border-top: 1px solid #7f828b33 !important;
border-collapse: collapse;
table,
td,
th {
border-right: 1px solid #7f828b33 !important;
border-left: 1px solid #7f828b33 !important;
border-bottom: 1px solid #7f828b33 !important;
border-top: 1px solid #7f828b33 !important;
border-collapse: collapse;
font-size: 0.8rem;
}
font-size: 0.8rem;
}
td {
text-overflow: ellipsis;
white-space: nowrap;
}
td {
text-overflow: ellipsis;
white-space: nowrap;
}
td.active::after,
td.active::before {
content: '';
position: absolute;
z-index: 3;
height: calc(100% + 2px);
width: calc(100% + 2px);
left: -1px;
top: -1px;
pointer-events: none;
}
td.active::after,
td.active::before {
content: '';
position: absolute;
z-index: 3;
height: calc(100% + 2px);
width: calc(100% + 2px);
left: -1px;
top: -1px;
pointer-events: none;
}
// todo: replace with css variable
td.active::after {
border: 2px solid #0040bc; /*var(--v-primary-lighten1);*/
}
// todo: replace with css variable
td.active::after {
border: 2px solid #0040bc; /*var(--v-primary-lighten1);*/
}
td.active::before {
background: #0040bc /*var(--v-primary-base)*/;
opacity: 0.1;
td.active::before {
background: #0040bc /*var(--v-primary-base)*/;
opacity: 0.1;
}
}
</style>

24
packages/nc-gui-v2/components/smartsheet/Pagination.vue

@ -1,17 +1,22 @@
<script setup lang="ts">
import type { PaginatedType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { computed, inject } from 'vue'
import { ChangePageInj, PaginationDataInj } from '~/components'
const paginatedData = inject<Ref<PaginatedType>>('paginatedData')
const paginatedData = inject(PaginationDataInj)
const changePage = inject(ChangePageInj)
const count = computed<number>(() => {
return paginatedData?.value?.totalRows ?? Infinity
})
const size = computed<number>(() => {
return paginatedData?.value?.pageSize ?? 25
})
const page = computed<number>(() => {
return paginatedData?.value?.page ?? 1
const page = computed<number>({
get() {
return paginatedData?.value?.page ?? 1
},
set(p) {
changePage?.(p)
},
})
/*
export default {
@ -43,8 +48,6 @@ export default {
</script>
<template>
{{ paginatedData }}
<div class="d-flex align-center">
<span v-if="count !== null && count !== Infinity" class="caption ml-2"> {{ count }} record{{ count !== 1 ? 's' : '' }} </span>
<v-spacer />
@ -56,22 +59,21 @@ export default {
:total-visible="8"
color="primary lighten-2"
class="nc-pagination"
@input="$emit('input', page)"
/>
<div v-else class="mx-auto d-flex align-center mt-n1" style="max-width: 250px">
<span class="caption" style="white-space: nowrap"> Change page:</span>
<v-text-field
v-model="page"
:value="page"
class="ml-1 caption"
:full-width="false"
outlined
dense
hide-details
type="number"
@keydown.enter="$emit('input', page)"
@keydown.enter="changePage(page)"
>
<template #append>
<x-icon tooltip="Change page" small icon.class="mt-1" @click="$emit('input', page)"> mdi-keyboard-return </x-icon>
<x-icon tooltip="Change page" small icon.class="mt-1" @click="changePage(page)"> mdi-keyboard-return </x-icon>
</template>
</v-text-field>
</div>

10
packages/nc-gui-v2/composables/useViewData.ts

@ -13,7 +13,7 @@ const formatData = (list: Array<Record<string, any>>) =>
export default (meta: Ref<TableType> | ComputedRef<TableType> | undefined) => {
const data = ref<Array<Record<string, any>>>()
const formattedData = ref<Array<{ row: Record<string, any>; oldRow: Record<string, any>; rowMeta?: any }>>()
const paginationData = ref<PaginatedType>()
const paginationData = ref<PaginatedType>({ page: 1, pageSize: 25 })
const { project } = useProject()
const { $api } = useNuxtApp()
@ -23,6 +23,7 @@ export default (meta: Ref<TableType> | ComputedRef<TableType> | undefined) => {
const response = await $api.dbTableRow.list('noco', project.value.id, meta.value.id, params)
data.value = response.list
formattedData.value = formatData(response.list)
paginationData.value = response.pageInfo
}
const updateRowProperty = async (row: Record<string, any>, property: string) => {
@ -80,5 +81,10 @@ export default (meta: Ref<TableType> | ComputedRef<TableType> | undefined) => {
})
}
return { data, loadData, paginationData, formattedData, insertRow, updateRowProperty }
const changePage = async (page: number) => {
paginationData.value.page = page
await loadData({ offset: (page - 1) * (paginationData.value.pageSize || 25) } as any)
}
return { data, loadData, paginationData, formattedData, insertRow, updateRowProperty, changePage }
}

Loading…
Cancel
Save