Browse Source

fix(gui-v2): many to many

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2990/head
Pranav C 2 years ago
parent
commit
e9142983a2
  1. 1
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  2. 16
      packages/nc-gui-v2/components/smartsheet/VirtualCell.vue
  3. 370
      packages/nc-gui-v2/components/virtual-cell/HasMany.vue
  4. 34
      packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue
  5. 5
      packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue
  6. 238
      packages/nc-gui-v2/components/virtual-cell/components/ListItems.vue
  7. 6
      packages/nc-gui-v2/composables/useLTARStore.ts
  8. 3
      packages/nc-gui-v2/context/index.ts

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

@ -282,6 +282,7 @@ const onNavigate = (dir: NavigateDir) => {
:column="columnObj" :column="columnObj"
@navigate="onNavigate" @navigate="onNavigate"
:active="selected.col === colIndex && selected.row === rowIndex" :active="selected.col === colIndex && selected.row === rowIndex"
:row="row"
/> />
<SmartsheetCell <SmartsheetCell

16
packages/nc-gui-v2/components/smartsheet/VirtualCell.vue

@ -1,30 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from '@vue/reactivity'
import { Row } from 'ant-design-vue'
import type { ColumnType } from 'nocodb-sdk' import type { ColumnType } from 'nocodb-sdk'
import { provide, useVirtualCell } from '#imports' import { provide, toRef, useVirtualCell } from '#imports'
import { ColumnInj, ValueInj, ActiveCellInj, RowInj } from '~/context' import type { Row } from '~/composables'
import { ActiveCellInj, ColumnInj, RowInj, ValueInj } from '~/context'
import { NavigateDir } from '~/lib' import { NavigateDir } from '~/lib'
interface Props { interface Props {
column: ColumnType column: ColumnType
modelValue: any modelValue: any
row: Record<string, any> row: Row
active?: boolean active?: boolean
} }
const props = defineProps<Props>() const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue', 'navigate']) const emit = defineEmits(['update:modelValue', 'navigate'])
const { column, modelValue: value } = props
const { column, modelValue: value, row } = props
const active = toRef(props, 'active', false) const active = toRef(props, 'active', false)
const row = toRef(props, 'row')
provide(ColumnInj, column) provide(ColumnInj, column)
provide(ValueInj, value) provide(ValueInj, value)
provide(ActiveCellInj, active) provide(ActiveCellInj, active)
provide(RowInj, row) provide(RowInj, row)
provide('value', value) provide(ValueInj, value)
const { isLookup, isBt, isRollup, isMm, isHm, isFormula, isCount } = useVirtualCell(column) const { isLookup, isBt, isRollup, isMm, isHm, isFormula, isCount } = useVirtualCell(column)
</script> </script>

370
packages/nc-gui-v2/components/virtual-cell/HasMany.vue

@ -1,8 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ColumnType } from 'nocodb-sdk' import type { ColumnType } from 'nocodb-sdk'
import ItemChip from './components/ItemChip.vue' import ItemChip from './components/ItemChip.vue'
import { ColumnInj, ValueInj } from '~/context' import ListChildItems from './components/ListChildItems.vue'
import { useHasMany } from '#imports' import ListItems from './components/ListItems.vue'
import { useProvideLTARStore } from '~/composables'
import { ColumnInj, RowInj, ValueInj } from '~/context'
import MdiExpandIcon from '~icons/mdi/arrow-expand'
import MdiPlusIcon from '~icons/mdi/plus'
const column = inject(ColumnInj) const column = inject(ColumnInj)
const value = inject(ValueInj) const value = inject(ValueInj)
@ -16,371 +20,10 @@ const { relatedTableMeta, loadRelatedTableMeta, relatedTablePrimaryValueProp, un
row, row,
) )
await loadRelatedTableMeta() await loadRelatedTableMeta()
/* // import ApiFactory from '@/components/project/spreadsheet/apis/apiFactory'
import { RelationTypes, UITypes, isSystemColumn } from 'nocodb-sdk'
import DlgLabelSubmitCancel from '~/components/utils/DlgLabelSubmitCancel'
import Pagination from '~/components/project/spreadsheet/components/Pagination'
import ListItems from '~/components/project/spreadsheet/components/virtualCell/components/ListItems'
import ListChildItems from '~/components/project/spreadsheet/components/virtualCell/components/ListChildItems'
import listChildItemsModal from '~/components/project/spreadsheet/components/virtualCell/components/ListChildItemsModal'
import { parseIfInteger } from '@/helpers'
import ItemChip from '~/components/project/spreadsheet/components/virtualCell/components/ItemChip'
// todo: handling add new record for new row
export default {
name: 'HasManyCell',
components: {
ListChildItems,
ItemChip,
ListItems,
Pagination,
DlgLabelSubmitCancel,
ListChildItemsModal: listChildItemsModal,
},
props: {
isLocked: Boolean,
breadcrumbs: {
type: Array,
default() {
return []
},
},
value: [Object, Array],
meta: [Object],
nodes: [Object],
row: [Object],
active: Boolean,
isNew: Boolean,
isForm: Boolean,
required: Boolean,
isPublic: Boolean,
metas: Object,
password: String,
column: Object,
},
data: () => ({
newRecordModal: false,
childListModal: false,
// childMeta: null,
dialogShow: false,
confirmAction: null,
confirmMessage: '',
selectedChild: null,
expandFormModal: false,
isNewChild: false,
localState: [],
}),
computed: {
childMeta() {
return this.metas
? this.metas[this.column.colOptions.fk_related_model_id]
: this.$store.state.meta.metas[this.column.colOptions.fk_related_model_id]
},
// todo : optimize
childApi() {},
childPrimaryCol() {
return this.childMeta && (this.childMeta.columns.find((c) => c.pv) || {}).title
},
primaryCol() {
return this.meta && (this.meta.columns.find((c) => c.pv) || {}).title
},
childPrimaryKey() {
return this.childMeta && (this.childMeta.columns.find((c) => c.pk) || {}).title
},
childForeignKey() {
return (
this.childMeta && (this.childMeta.columns.find((c) => c.id === this.column.colOptions.fk_child_column_id) || {}).title
)
},
childForeignKeyVal() {
return this.meta && this.meta.columns
? this.meta.columns
.filter((c) => c.title === this.childForeignKey)
.map((c) => this.row[c.title] || '')
.join('___')
: ''
},
isVirtualRelation() {
return this.column && this.column.colOptions.virtual // (this.childMeta && (!!this.childMeta.columns.find(c => c.column_name === this.hm.column_name && this.hm.type === 'virtual'))) || false
},
isByPass() {
if (this.isVirtualRelation) {
return false
}
// if child fk references a column in parent which is not pk,
// then this column has to be filled
// if (((this.meta && this.meta.columns.find(c => !c.pk && c.id === this.hm.rcn)) || false)) {
// return this.childForeignKeyVal === ''
// }
if ((this.meta && this.meta.columns.find((c) => !c.pk && c.id === this.column.fk_parent_column_id)) || false) {
return this.childForeignKeyVal === ''
}
return false
},
disabledChildColumns() {
return { [this.childForeignKey]: true }
},
// todo:
form() {
return this.selectedChild && !this.isPublic
? () => import('~/components/project/spreadsheet/components/ExpandedForm')
: 'span'
},
childAvailableColumns() {
if (!this.childMeta) {
return []
}
const columns = []
if (this.childMeta.columns) {
columns.push(...this.childMeta.columns.filter((c) => !isSystemColumn(c)))
}
return columns
},
childQueryParams() {
if (!this.childMeta) {
return {}
}
// todo: use reduce
return {
hm:
(this.childMeta &&
this.childMeta.v &&
this.childMeta.v
.filter((v) => v.hm)
.map(({ hm }) => hm.table_name)
.join()) ||
'',
bt:
(this.childMeta &&
this.childMeta.v &&
this.childMeta.v
.filter((v) => v.bt)
.map(({ bt }) => bt.rtn)
.join()) ||
'',
mm:
(this.childMeta &&
this.childMeta.v &&
this.childMeta.v
.filter((v) => v.mm)
.map(({ mm }) => mm.rtn)
.join()) ||
'',
}
},
parentId() {
return (
(this.meta &&
this.meta.columns &&
(this.meta.columns
.filter((c) => c.title === this.childForeignKey)
.map((c) => this.row[c.title] || '')
.join('___') ||
this.meta.columns
.filter((c) => c.pk)
.map((c) => this.row[c.title])
.join('___'))) ||
''
)
},
},
watch: {
isNew(n, o) {
if (!n && o) {
this.saveLocalState()
}
},
},
async mounted() {
await this.loadChildMeta()
if (this.isNew && this.value) {
this.localState = [...this.value]
}
},
created() {
this.loadChildMeta()
},
methods: {
onChildSave() {
if (this.isNew) {
this.addChildToParent(this.selectedChild)
} else {
this.$emit('loadTableData')
}
},
async showChildListModal() {
await this.loadChildMeta()
this.childListModal = true
},
async deleteChild(child) {
this.dialogShow = true
this.confirmMessage = 'Do you want to delete the record?'
this.confirmAction = async (act) => {
if (act === 'hideDialog') {
this.dialogShow = false
} else {
const id = this.childMeta.columns
.filter((c) => c.pk)
.map((c) => child[c.title])
.join('___')
try {
await this.$api.data.delete(this.childMeta.id, id)
this.dialogShow = false
this.$emit('loadTableData')
if ((this.childListModal || this.isForm) && this.$refs.childList) {
this.$refs.childList.loadData()
}
} catch (e) {
this.$toast.error(await this._extractSdkResponseErrorMsg(e)).goAway(3000)
}
}
}
},
async unlinkChild(child) {
if (this.isNew) {
this.localState.splice(this.localState.indexOf(child), 1)
this.$emit('update:localState', [...this.localState])
return
}
await this.loadChildMeta()
const column = this.childMeta.columns.find((c) => c.id === this.column.colOptions.fk_child_column_id)
if (column.rqd) {
this.$toast.info('Unlink is not possible, instead add to another record.').goAway(3000)
return
}
const id = this.childMeta.columns
.filter((c) => c.pk)
.map((c) => child[c.title])
.join('___')
await this.$api.dbTableRow.nestedRemove(
NOCO,
this.projectName,
this.meta.title,
this.parentId,
RelationTypes.HAS_MANY,
this.column.title,
id,
)
this.$emit('loadTableData')
if ((this.childListModal || this.isForm) && this.$refs.childList) {
this.$refs.childList.loadData()
}
// }
// }
},
async loadChildMeta() {
// todo: optimize
if (!this.childMeta) {
await this.$store.dispatch('meta/ActLoadMeta', {
env: this.nodes.env,
dbAlias: this.nodes.dbAlias,
id: this.column.colOptions.fk_related_model_id,
})
}
},
async showNewRecordModal() {
await this.loadChildMeta()
this.newRecordModal = true
},
async addChildToParent(child) {
if (this.isNew && this.localState.every((it) => it[this.childForeignKey] !== child[this.childPrimaryKey])) {
this.localState.push(child)
this.$emit('update:localState', [...this.localState])
this.$emit('saveRow')
this.newRecordModal = false
return
}
const id = this.childMeta.columns
.filter((c) => c.pk)
.map((c) => child[c.title])
.join('___')
this.newRecordModal = false
await this.$api.dbTableRow.nestedAdd(NOCO, this.projectName, this.meta.title, this.parentId, 'hm', this.column.title, id)
this.$emit('loadTableData')
if ((this.childListModal || this.isForm) && this.$refs.childList) {
await this.$refs.childList.loadData()
}
},
async editChild(child) {
await this.loadChildMeta()
this.isNewChild = false
this.expandFormModal = true
this.selectedChild = child
setTimeout(() => {
this.$refs.expandedForm && this.$refs.expandedForm.reload()
}, 500)
},
async insertAndAddNewChildRecord() {
this.newRecordModal = false
await this.loadChildMeta()
this.isNewChild = true
this.selectedChild = {
[this.childForeignKey]: parseIfInteger(this.parentId),
[(
this.childMeta.columns.find(
(c) =>
c.uidt === UITypes.LinkToAnotherRecord &&
c.colOptions &&
this.column.colOptions &&
c.colOptions.fk_child_column_id === this.column.colOptions.fk_child_column_id &&
c.colOptions.fk_parent_column_id === this.column.colOptions.fk_parent_column_id &&
c.colOptions.type === RelationTypes.BELONGS_TO,
) || {}
).title]: this.row,
}
this.expandFormModal = true
if (!this.isNew) {
setTimeout(() => {
this.$refs.expandedForm &&
this.$refs.expandedForm.$set(this.$refs.expandedForm.changedColumns, this.childForeignKey, true)
}, 500)
}
},
getCellValue(cellObj) {
if (cellObj) {
if (this.childMeta && this.childPrimaryCol) {
return cellObj[this.childPrimaryCol]
}
return Object.values(cellObj)[1]
}
},
async saveLocalState(row) {
let child
// eslint-disable-next-line no-cond-assign
while ((child = this.localState.pop())) {
if (row) {
const pid = this.meta.columns
.filter((c) => c.pk)
.map((c) => row[c.title])
.join('___')
const id = this.childMeta.columns
.filter((c) => c.pk)
.map((c) => child[c.title])
.join('___')
await this.$api.dbTableRow.nestedAdd(NOCO, this.projectName, this.meta.title, pid, 'hm', this.column.title, id)
} else {
await this.addChildToParent(child)
}
}
this.$emit('newRecordsSaved')
},
},
} */
</script> </script>
<template> <template>
<div class="flex align-center gap-1 w-full chips-wrapper group"> <div class="flex align-center gap-1 w-full chips-wrapper group">
<!-- <template v-if="!isForm"> -->
<div class="chips flex align-center img-container flex-grow hm-items flex-nowrap min-w-0 overflow-hidden"> <div class="chips flex align-center img-container flex-grow hm-items flex-nowrap min-w-0 overflow-hidden">
<template v-if="value"> <template v-if="value">
<ItemChip v-for="(ch, i) in value" :key="i" :value="ch[relatedTablePrimaryValueProp]" @unlink="unlink(ch)" /> <ItemChip v-for="(ch, i) in value" :key="i" :value="ch[relatedTablePrimaryValueProp]" @unlink="unlink(ch)" />
@ -392,6 +35,5 @@ export default {
<MdiPlusIcon class="hidden group-hover:inline w-[20px] text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" /> <MdiPlusIcon class="hidden group-hover:inline w-[20px] text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
<ListItems v-model="listItemsDlg" /> <ListItems v-model="listItemsDlg" />
<ListChildItems v-model="childListDlg" /> <ListChildItems v-model="childListDlg" />
</div> </div>
</template> </template>

34
packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue

@ -1,30 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ColumnType } from 'nocodb-sdk' import type { ColumnType } from 'nocodb-sdk'
import { useProvideLTARStore } from '~/composables'
import ItemChip from './components/ItemChip.vue' import ItemChip from './components/ItemChip.vue'
import ListChildItems from './components/ListChildItems.vue' import ListChildItems from './components/ListChildItems.vue'
import ListItems from './components/ListItems.vue' import ListItems from './components/ListItems.vue'
import { useProvideLTARStore } from '~/composables'
import { ColumnInj, RowInj, ValueInj } from '~/context'
import MdiExpandIcon from '~icons/mdi/arrow-expand' import MdiExpandIcon from '~icons/mdi/arrow-expand'
import MdiPlusIcon from '~icons/mdi/plus' import MdiPlusIcon from '~icons/mdi/plus'
import { ColumnInj, RowInj, ValueInj } from '~/context'
const column = inject(ColumnInj) const column = inject(ColumnInj)
const row = inject(RowInj) const row = inject(RowInj)
const value = inject(ValueInj) const value = inject(ValueInj)
const listItemsDlg = ref(false) const listItemsDlg = ref(false)
const childListDlg = ref(false) const childListDlg = ref(false)
const { const { relatedTableMeta, loadRelatedTableMeta, relatedTablePrimaryValueProp, unlink } = useProvideLTARStore(
relatedTableMeta, column as Required<ColumnType>,
loadRelatedTableMeta, row,
relatedTablePrimaryValueProp, )
unlink
} = useProvideLTARStore(column as Required<ColumnType>, row)
await loadRelatedTableMeta() await loadRelatedTableMeta()
</script> </script>
<template> <template>
@ -33,8 +29,7 @@ await loadRelatedTableMeta()
<!-- <template v-if="!isForm"> --> <!-- <template v-if="!isForm"> -->
<div class="chips flex align-center img-container flex-grow hm-items flex-nowrap min-w-0 overflow-hidden"> <div class="chips flex align-center img-container flex-grow hm-items flex-nowrap min-w-0 overflow-hidden">
<template v-if="value"> <template v-if="value">
<ItemChip v-for="(ch, i) in value " :key="i" :value="ch[relatedTablePrimaryValueProp]" <ItemChip v-for="(ch, i) in value" :key="i" :value="ch[relatedTablePrimaryValueProp]" @unlink="unlink(ch)" />
@unlink="unlink(ch)" />
<!-- <!--
:active="active" :item="ch" :active="active" :item="ch"
@ -43,20 +38,17 @@ await loadRelatedTableMeta()
@edit="editChild" @edit="editChild"
@unlink="unlinkChild " --> @unlink="unlinkChild " -->
<span v-if="value?.length === 10" class="caption pointer ml-1 grey--text" <span v-if="value?.length === 10" class="caption pointer ml-1 grey--text" @click="childListDlg = true">more... </span>
@click="childListDlg = true">more... </span>
</template> </template>
</div> </div>
<MdiExpandIcon class="hidden group-hover:inline w-[20px] text-gray-500/50 hover:text-gray-500" <MdiExpandIcon
@click="childListDlg = true" /> class="hidden group-hover:inline w-[20px] text-gray-500/50 hover:text-gray-500"
<MdiPlusIcon class="hidden group-hover:inline w-[20px] text-gray-500/50 hover:text-gray-500" @click="childListDlg = true"
@click="listItemsDlg = true" /> />
<MdiPlusIcon class="hidden group-hover:inline w-[20px] text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
<ListItems v-model="listItemsDlg" /> <ListItems v-model="listItemsDlg" />
<ListChildItems v-model="childListDlg" /> <ListChildItems v-model="childListDlg" />
</div> </div>
</div> </div>
</template> </template>

5
packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue

@ -10,7 +10,7 @@ const vModel = useVModel(props, 'modelValue', emit)
const { childrenList, loadChildrenList, childrenListPagination, relatedTablePrimaryValueProp, link } = useLTARStoreOrThrow() const { childrenList, loadChildrenList, childrenListPagination, relatedTablePrimaryValueProp, link } = useLTARStoreOrThrow()
watchEffect(() => { watch(vModel, () => {
if (vModel.value) { if (vModel.value) {
loadChildrenList() loadChildrenList()
} }
@ -21,11 +21,12 @@ watchEffect(() => {
<a-modal v-model:visible="vModel" :footer="null" title="Child list"> <a-modal v-model:visible="vModel" :footer="null" title="Child list">
<div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col"> <div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col">
<div class="flex-1 overflow-auto min-h-0"> <div class="flex-1 overflow-auto min-h-0">
<a-card v-for="row in childrenList.list" class="my-1 cursor-pointer" @click="link(row)"> <a-card v-for="row in childrenList?.list ?? []" class="my-1 cursor-pointer" @click="link(row)">
{{ row[relatedTablePrimaryValueProp] }} {{ row[relatedTablePrimaryValueProp] }}
</a-card> </a-card>
</div> </div>
<a-pagination <a-pagination
v-if="childrenList?.pageInfo"
v-model:current="childrenListPagination.page" v-model:current="childrenListPagination.page"
v-model:page-size="childrenListPagination.size" v-model:page-size="childrenListPagination.size"
class="mt-2 mx-auto" class="mt-2 mx-auto"

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

@ -9,140 +9,32 @@ const emit = defineEmits(['update:modelValue'])
const vModel = useVModel(props, 'modelValue', emit) const vModel = useVModel(props, 'modelValue', emit)
const { const { childrenExcludedList, loadChildrenExcludedList, childrenExcludedListPagination, relatedTablePrimaryValueProp, link } =
childrenExcludedList,
loadChildrenExcludedList,
childrenExcludedListPagination,
relatedTablePrimaryValueProp,
link,
} =
useLTARStoreOrThrow() useLTARStoreOrThrow()
watchEffect(() => { watch(vModel, () => {
if (vModel.value) { if (vModel.value) {
loadChildrenExcludedList() loadChildrenExcludedList()
} }
}) })
/* import Pagination from '~/components/project/spreadsheet/components/Pagination'
import { NOCO } from '~/lib/constants'
export default {
name: 'ListItems',
components: { Pagination },
props: {
value: Boolean,
tn: String,
hm: [Object, Function, Boolean],
title: {
type: String,
default: 'Link Record',
},
queryParams: {
type: Object,
default() {
return {}
},
},
primaryKey: String,
primaryCol: String,
meta: Object,
size: Number,
api: [Object, Function],
mm: [Object, Function],
parentId: [String, Number],
parentMeta: [Object],
isPublic: Boolean,
password: String,
column: Object,
rowId: [Number, String],
},
emits: ['input', 'add', 'addNewRecord'],
data: () => ({
data: null,
page: 1,
query: '',
}),
computed: {
show: {
set(v) {
this.$emit('input', v)
},
get() {
return this.value
},
},
hmParentPrimaryValCol() {
return this.hm && this.parentMeta && this.parentMeta.columns.find((v) => v.pv).title
},
},
mounted() {
this.loadData()
},
methods: {
async loadData() {
if (this.isPublic) {
this.data = await this.$api.public.dataRelationList(
this.$route.params.id,
this.column.id,
{},
{
headers: {
'xc-password': this.password,
},
query: {
limit: this.size,
offset: this.size * (this.page - 1),
...this.queryParams,
},
},
)
} else {
const where = `(${this.primaryCol},like,%${this.query}%)`
if (this.column && this.column.colOptions && this.rowId) {
this.data = await this.$api.dbTableRow.nestedChildrenExcludedList(
NOCO,
this.projectName,
this.parentMeta.title,
this.rowId,
this.column.colOptions.type,
this.column.title,
{
limit: this.size,
offset: this.size * (this.page - 1),
where: this.query && `(${this.primaryCol},like,${this.query})`,
},
)
} else {
this.data = await this.$api.dbTableRow.list(NOCO, this.projectName, this.meta.title, {
limit: this.size,
offset: this.size * (this.page - 1),
...this.queryParams,
where,
})
}
}
},
},
} */
</script> </script>
<template> <template>
<a-modal v-model:visible="vModel" :footer="null" title="Related table rows"> <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="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col">
<div class="flex mb-4 align-center gap-2"> <div class="flex mb-4 align-center gap-2">
<a-input <a-input v-model:value="childrenExcludedListPagination.query" class="max-w-[200px]" size="small"></a-input>
v-model:value="childrenExcludedListPagination.query" class="max-w-[200px]" size="small"></a-input>
<div class="flex-1" /> <div class="flex-1" />
<MdiReloadIcon class="cursor-pointer text-gray-500" @click="loadChildrenExcludedList" /> <MdiReloadIcon class="cursor-pointer text-gray-500" @click="loadChildrenExcludedList" />
<a-button type="primary" size="small" @click="$emit('addNewRecord')">Add new record</a-button> <a-button type="primary" size="small" @click="$emit('addNewRecord')">Add new record</a-button>
</div> </div>
<div class="flex-1 overflow-auto min-h-0"> <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)"> <a-card v-for="row in childrenExcludedList?.list ?? []" class="my-1 cursor-pointer" @click="link(row)">
{{ row[relatedTablePrimaryValueProp] }} {{ row[relatedTablePrimaryValueProp] }}
</a-card> </a-card>
</div> </div>
<a-pagination <a-pagination
v-if="childrenList?.pageInfo"
v-model:current="childrenExcludedListPagination.page" v-model:current="childrenExcludedListPagination.page"
v-model:page-size="childrenExcludedListPagination.size" v-model:page-size="childrenExcludedListPagination.size"
class="mt-2 mx-auto !text-xs" class="mt-2 mx-auto !text-xs"
@ -152,127 +44,9 @@ export default {
/> />
</div> </div>
</a-modal> </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&#45;&#45;text mx-2 justify-center">
{{ title }}
</v-card-title>
<v-card-title>
<v-text-field
v-model="query"
hide-details
dense
outlined
placeholder="Filter query"
class="caption search-field ml-2"
@keydown.enter="loadData"
>
<template #append>
<x-icon tooltip="Apply filter" small icon class="mt-1" @click="loadData"> mdi-keyboard-return </x-icon>
</template>
</v-text-field>
<v-spacer />
<v-icon small class="mr-1" @click="loadData()"> mdi-reload </v-icon>
<v-btn v-if="!isPublic" small class="caption mr-2" color="primary" @click="$emit('addNewRecord')">
<v-icon small> mdi-plus </v-icon>&nbsp; New Record
</v-btn>
</v-card-title>
<v-card-text>
<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&#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&#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] }}
</v-chip>
</v-card-text>
</v-card>
</template> </template>
<div v-else-if="data" class="text-center py-15 textLight&#45;&#45;text"> <style scoped>
&lt;!&ndash; No items found &ndash;&gt;
{{ $t('placeholder.noItemsFound') }}
</div>
</div>
</v-card-text>
<v-card-actions class="justify-center py-2 flex-column">
<Pagination
v-if="data && data.list && data.list.length"
v-model="page"
:size="size"
:count="data && data.pageInfo && data.pageInfo.totalRows"
class="mb-3"
@input="loadData"
/>
</v-card-actions>
</v-card>
</v-dialog> -->
</template>
<style scoped lang="scss">
/*.child-list-modal {
position: relative;
.remove-child-icon {
position: absolute;
right: 10px;
top: 10px;
bottom: 10px;
opacity: 0;
}
&:hover .remove-child-icon {
opacity: 1;
}
}
.child-card {
cursor: pointer;
&:hover {
box-shadow: 0 0 0.2em var(--v-textColor-lighten5);
}
}
.primary-value {
.primary-key {
display: none;
margin-left: 0.5em;
}
&:hover .primary-key {
display: inline;
}
}
.items-container {
overflow-x: visible;
max-height: min(500px, 60vh);
overflow-y: auto;
}
::v-deep {
.dialog {
position: relative;
.close-icon {
width: auto;
position: absolute;
right: 10px;
top: 10px;
z-index: 9;
}
}
}*/
:deep(.ant-pagination-item a) { :deep(.ant-pagination-item a) {
line-height: 21px !important; line-height: 21px !important;
} }

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

@ -4,13 +4,14 @@ import { useMetas } from './useMetas'
import { useInjectionState } from '#imports' import { useInjectionState } from '#imports'
import { useProject } from '~/composables/useProject' import { useProject } from '~/composables/useProject'
import { NOCO } from '~/lib' import { NOCO } from '~/lib'
import type { Row } from '~/composables'
interface DataApiResponse { interface DataApiResponse {
list: Record<string, any> list: Record<string, any>
pageInfo: PaginatedType pageInfo: PaginatedType
} }
const [useProvideLTARStore, useLTARStore] = useInjectionState((column: Required<ColumnType>, row?: Record<string, any>) => { const [useProvideLTARStore, useLTARStore] = useInjectionState((column: Required<ColumnType>, row?: Ref<Row>) => {
// state // state
const { metas, getMeta } = useMetas() const { metas, getMeta } = useMetas()
const { project } = useProject() const { project } = useProject()
@ -39,7 +40,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState((column: Required<
const rowId = computed(() => const rowId = computed(() =>
meta.value.columns meta.value.columns
.filter((c: Required<ColumnType>) => c.pk) .filter((c: Required<ColumnType>) => c.pk)
.map((c: Required<ColumnType>) => row?.[c.title]) .map((c: Required<ColumnType>) => row?.value?.row?.[c.title])
.join('___'), .join('___'),
) )
@ -188,6 +189,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState((column: Required<
link, link,
loadChildrenExcludedList, loadChildrenExcludedList,
loadChildrenList, loadChildrenList,
row,
} }
}, 'ltar-store') }, 'ltar-store')

3
packages/nc-gui-v2/context/index.ts

@ -2,11 +2,12 @@ import type { ColumnType, FormType, GalleryType, GridType, KanbanType, TableType
import type { ComputedRef, InjectionKey, Ref } from 'vue' import type { ComputedRef, InjectionKey, Ref } from 'vue'
import type { EventHook } from '@vueuse/core' import type { EventHook } from '@vueuse/core'
import type { useViewData } from '#imports' import type { useViewData } from '#imports'
import type { Row } from '~/composables'
import type { TabItem } from '~/composables/useTabs' import type { TabItem } from '~/composables/useTabs'
export const EditEnabledInj: InjectionKey<boolean> = Symbol('edit-enabled') export const EditEnabledInj: InjectionKey<boolean> = Symbol('edit-enabled')
export const ActiveCellInj: InjectionKey<Ref<boolean>> = Symbol('active-cell') export const ActiveCellInj: InjectionKey<Ref<boolean>> = Symbol('active-cell')
export const RowInj: InjectionKey<Ref<Record<string, any>>> = Symbol('row') export const RowInj: InjectionKey<Ref<Row>> = Symbol('row')
export const ColumnInj: InjectionKey<ColumnType & { meta: any }> = Symbol('column-injection') export const ColumnInj: InjectionKey<ColumnType & { meta: any }> = Symbol('column-injection')
export const MetaInj: InjectionKey<ComputedRef<TableType>> = Symbol('meta-injection') export const MetaInj: InjectionKey<ComputedRef<TableType>> = Symbol('meta-injection')
export const TabMetaInj: InjectionKey<ComputedRef<TabItem>> = Symbol('tab-meta-injection') export const TabMetaInj: InjectionKey<ComputedRef<TabItem>> = Symbol('tab-meta-injection')

Loading…
Cancel
Save