Browse Source

feat(gui-v2): excluded child list modal

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2990/head
Pranav C 2 years ago
parent
commit
29e430fd69
  1. 12
      packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue
  2. 84
      packages/nc-gui-v2/components/virtual-cell/components/ListItems.vue
  3. 168
      packages/nc-gui-v2/composables/useLTARStore.ts

12
packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue

@ -1,8 +1,8 @@
<script setup lang="ts">
import type { ColumnType } from 'nocodb-sdk'
import ItemChip from './components/ItemChip.vue'
import ListItems from './components/ListItems.vue'
import { ColumnInj, ValueInj, RowInj } from '~/context'
import { useBelongsTo } from '#imports'
import { useProvideLTARStore } from '#imports'
import MdiExpandIcon from '~icons/mdi/arrow-expand'
@ -11,10 +11,13 @@ const value = inject(ValueInj)
const row = inject(RowInj)
const active = false
const localState = null
const listItemsDlg = ref(false)
const { relatedTableMeta, loadRelatedTableMeta, relatedTablePrimaryValueProp,childrenExcludedList } = useProvideLTARStore(column as ColumnType, row)
const { relatedTableMeta, loadRelatedTableMeta, relatedTablePrimaryValueProp } = useProvideLTARStore(
column as Required<ColumnType>,
row,
)
await loadRelatedTableMeta()
const data = await childrenExcludedList()
</script>
<template>
@ -25,6 +28,7 @@ const data = await childrenExcludedList()
</template>
</div>
<div class="flex-1" />
<MdiExpandIcon class="hidden group-hover:inline text-xs text-gray-500/50 hover:text-gray-500" />
<MdiExpandIcon class="hidden group-hover:inline text-xs text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
<ListItems v-model="listItemsDlg" />
</div>
</template>

84
packages/nc-gui-v2/components/virtual-cell/components/ListItems.vue

@ -1,5 +1,23 @@
<script>
import Pagination from '~/components/project/spreadsheet/components/Pagination'
<script lang="ts" setup>
import { useVModel } from '@vueuse/core'
import { useLTARStoreOrThrow } from '~/composables'
const props = defineProps<{ modelValue: boolean }>()
const emit = defineEmits(['update:modelValue'])
const vModel = useVModel(props, 'modelValue', emit)
const {
childrenExcludedList,
loadChildrenExcludedList,
childrenExcludedListPagination,
relatedTablePrimaryValueProp,
link
} =
useLTARStoreOrThrow()
await loadChildrenExcludedList()
/* import Pagination from '~/components/project/spreadsheet/components/Pagination'
import { NOCO } from '~/lib/constants'
export default {
@ -100,14 +118,30 @@ export default {
}
},
},
}
} */
</script>
<template>
<v-dialog v-model="show" width="600" content-class="dialog">
<a-modal v-model:visible="vModel" :footer="null" title="Related table rows">
<div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col">
<div class="flex-1 overflow-auto min-h-0">
<a-card v-for="row in childrenExcludedList.list" class="my-1 cursor-pointer" @click="link(row)">
{{ row[relatedTablePrimaryValueProp] }}
</a-card>
</div>
<a-pagination class="mt-2 mx-auto"
size="small"
v-model:current="childrenExcludedListPagination.page"
v-model:page-size="childrenExcludedListPagination.size"
:total="childrenExcludedList.pageInfo.totalRows"
show-less-items />
</div>
</a-modal>
<!-- <v-dialog v-model="show" width="600" content-class="dialog">
<v-icon small class="close-icon" @click="$emit('input', false)"> mdi-close </v-icon>
<v-card width="600">
<v-card-title class="textColor--text mx-2 justify-center">
<v-card-title class="textColor&#45;&#45;text mx-2 justify-center">
{{ title }}
</v-card-title>
@ -137,9 +171,9 @@ export default {
<div class="items-container">
<template v-if="data && data.list && data.list.length">
<v-card v-for="(ch, i) in data.list" :key="i" v-ripple class="ma-2 child-card" outlined @click="$emit('add', ch)">
<v-card-text class="primary-value textColor--text text--lighten-2 d-flex">
<v-card-text class="primary-value textColor&#45;&#45;text text&#45;&#45;lighten-2 d-flex">
<span class="font-weight-bold"> {{ ch[primaryCol] || (ch && Object.values(ch).slice(0, 1).join()) }}&nbsp;</span>
<span v-if="primaryKey" class="grey--text caption primary-key">(Primary Key : {{ ch[primaryKey] }})</span>
<span v-if="primaryKey" class="grey&#45;&#45;text caption primary-key">(Primary Key : {{ ch[primaryKey] }})</span>
<v-spacer />
<v-chip v-if="hm && ch[`${hm._rtn}Read`] && ch[`${hm._rtn}Read`][hmParentPrimaryValCol]" x-small>
{{ ch[`${hm._rtn}Read`][hmParentPrimaryValCol] }}
@ -148,8 +182,8 @@ export default {
</v-card>
</template>
<div v-else-if="data" class="text-center py-15 textLight--text">
<!-- No items found -->
<div v-else-if="data" class="text-center py-15 textLight&#45;&#45;text">
&lt;!&ndash; No items found &ndash;&gt;
{{ $t('placeholder.noItemsFound') }}
</div>
</div>
@ -165,11 +199,11 @@ export default {
/>
</v-card-actions>
</v-card>
</v-dialog>
</v-dialog> -->
</template>
<style scoped lang="scss">
.child-list-modal {
/*.child-list-modal {
position: relative;
.remove-child-icon {
@ -222,29 +256,9 @@ export default {
z-index: 9;
}
}
}*/
:deep(.ant-pagination-item a) {
line-height: 21px !important;
}
</style>
<!--
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-->

168
packages/nc-gui-v2/composables/useLTARStore.ts

@ -1,14 +1,34 @@
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import type { ColumnType, LinkToAnotherRecordType, PaginatedType, TableType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { useMetas } from './useMetas'
import { useInjectionState } from '#imports'
import { useProject } from '~/composables/useProject'
import { NOCO } from '~/lib'
const [useProvideLTARStore, useLTARStore] = useInjectionState((column: ColumnType, row?: Record<string, any>) => {
interface DataApiResponse {
list: Record<string, any>
pageInfo: PaginatedType
}
const [useProvideLTARStore, useLTARStore] = useInjectionState((column: Required<ColumnType>, row?: Record<string, any>) => {
// state
const { metas, getMeta } = useMetas()
const { project } = useProject()
const { $api } = useNuxtApp()
const childrenExcludedList: Ref<DataApiResponse | undefined> = ref()
const childrenList: Ref<DataApiResponse | undefined> = ref()
const childrenExcludedListPagination = reactive({
page: 1,
query: '',
size: 10,
})
const childrenListPagination = reactive({
page: 1,
query: '',
size: 10,
})
const colOptions = column.colOptions as LinkToAnotherRecordType
// getters
const meta = computed(() => metas?.value?.[column.fk_model_id as string])
@ -18,12 +38,19 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState((column: ColumnTyp
const rowId = computed(() =>
meta.value.columns
.filter((c) => c.pk)
.map((c) => row?.[c.title])
.filter((c: Required<ColumnType>) => c.pk)
.map((c: Required<ColumnType>) => row?.[c.title])
.join('___'),
)
// actions
const getRelatedTableRowId = (row: Record<string, any>) => {
return relatedTableMeta.value?.columns
?.filter((c) => c.pk)
.map((c) => row?.[c.title as string])
.join('___')
}
const loadRelatedTableMeta = async () => {
await getMeta((column.colOptions as any)?.fk_related_model_id as string)
}
@ -31,29 +58,138 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState((column: ColumnTyp
const relatedTablePrimaryValueProp = computed(() => {
return (relatedTableMeta?.value?.columns?.find((c) => c.pv) || relatedTableMeta?.value?.columns?.[0])?.title
})
const primaryValueProp = computed(() => {
return (meta?.value?.columns?.find((c) => c.pv) || relatedTableMeta?.value?.columns?.[0])?.title
})
const size = 25
const query = ''
const page = 1
const childrenExcludedList = async () => {
// this.data =
return await $api.dbTableRow.nestedChildrenExcludedList(
const loadChildrenExcludedList = async () => {
childrenExcludedList.value = await $api.dbTableRow.nestedChildrenExcludedList(
NOCO,
project.value.id as string,
meta.value.title,
meta.value.id,
rowId.value,
(column.colOptions as LinkToAnotherRecordType).type as 'mm' | 'hm',
column.title as string,
column.title,
// todo: swagger type correction
{
limit: childrenExcludedListPagination.size,
offset: childrenExcludedListPagination.size * (childrenExcludedListPagination.page - 1),
where:
childrenExcludedListPagination.query &&
`(${relatedTablePrimaryValueProp.value},like,${childrenExcludedListPagination.query})`,
} as any,
)
}
const loadChildrenList = async () => {
childrenList.value = await $api.dbTableRow.nestedList(
NOCO,
project.value.id as string,
meta.value.id,
rowId.value,
colOptions.type as 'mm' | 'hm',
column.title,
// todo: swagger type correction
{
limit: size,
offset: size * (page - 1),
where: query && `(${relatedTablePrimaryValueProp.value},like,${query})`,
limit: childrenListPagination.size,
offset: childrenListPagination.size * (childrenListPagination.page - 1),
where: childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`,
} as any,
)
}
const unlink = async (row: Record<string, any>) => {
// const column = meta.columns.find(c => c.id === this.column.colOptions.fk_child_column_id);
// todo: handle if new record
// if (this.isNew) {
// this.$emit('updateCol', this.row, _cn, null);
// this.localState = null;
// this.$emit('update:localState', this.localState);
// return;
// }
// todo: handle bt column if required
// if (column.rqd) {
// this.$toast.info('Unlink is not possible, instead map to another parent.').goAway(3000);
// return;
// }
return { relatedTableMeta, loadRelatedTableMeta, relatedTablePrimaryValueProp, childrenExcludedList, rowId }
// todo: audit
await $api.dbTableRow.nestedRemove(
NOCO,
project.value.title as string,
meta.value.title,
rowId.value,
colOptions.type as 'mm' | 'hm',
column.title,
getRelatedTableRowId(row) as string,
)
// todo: reload table data and children list
// this.$emit('loadTableData');
// if (this.isForm && this.$refs.childList) {
// this.$refs.childList.loadData();
// }
}
const link = async (row: Record<string, any>) => {
// todo: handle new record
// const pid = this._extractRowId(parent, this.parentMeta);
// const id = this._extractRowId(this.row, this.meta);
// const _cn = this.meta.columns.find(c => c.id === this.column.colOptions.fk_child_column_id).title;
//
// if (this.isNew) {
// const _rcn = this.parentMeta.columns.find(c => c.id === this.column.colOptions.fk_parent_column_id).title;
// this.localState = parent;
// this.$emit('update:localState', this.localState);
// this.$emit('updateCol', this.row, _cn, parent[_rcn]);
// this.newRecordModal = false;
// return;
// }
await $api.dbTableRow.nestedAdd(
NOCO,
project.value.title as string,
meta.value.title as string,
rowId.value,
colOptions.type as 'mm' | 'hm',
column.title,
getRelatedTableRowId(row) as string,
)
// todo: reload table data and child list
// this.pid = pid;
//
// this.newRecordModal = false;
//
// this.$emit('loadTableData');
// if (this.isForm && this.$refs.childList) {
// this.$refs.childList.loadData();
// }
}
// watchers
watch(childrenExcludedListPagination, async () => {
await loadChildrenExcludedList()
})
watch(childrenListPagination, async () => {
await loadChildrenList()
})
return {
relatedTableMeta,
loadRelatedTableMeta,
relatedTablePrimaryValueProp,
childrenExcludedList,
childrenList,
rowId,
childrenExcludedListPagination,
childrenListPagination,
primaryValueProp,
meta,
unlink,
link,
loadChildrenExcludedList,
loadChildrenList,
}
}, 'ltar-store')
export { useProvideLTARStore }

Loading…
Cancel
Save