Browse Source

feat(gui-v2): children list modal functionalities

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2990/head
Pranav C 2 years ago
parent
commit
05c10b78e8
  1. 1
      packages/nc-gui-v2/components.d.ts
  2. 11
      packages/nc-gui-v2/components/virtual-cell/BelongsTo.vue
  3. 17
      packages/nc-gui-v2/components/virtual-cell/HasMany.vue
  4. 15
      packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue
  5. 65
      packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue
  6. 43
      packages/nc-gui-v2/components/virtual-cell/components/ListItems.vue
  7. 21
      packages/nc-gui-v2/composables/useLTARStore.ts

1
packages/nc-gui-v2/components.d.ts vendored

@ -20,6 +20,7 @@ declare module '@vue/runtime-core' {
ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']

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

@ -29,16 +29,21 @@ await loadRelatedTableMeta()
<ItemChip :item="value" :value="value[relatedTablePrimaryValueProp]" @unlink="unlink(value || localState)" />
</template>
</div>
<div class="flex-1" />
<MdiExpandIcon class="nc-action-icon text-md text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
<div class="flex-1 flex justify-end gap-1">
<MdiExpandIcon
class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 select-none transform group-hover:(text-pink-500 scale-120)"
@click="listItemsDlg = true"
/>
</div>
<ListItems v-model="listItemsDlg" />
</div>
</template>
<style scoped>
.nc-action-icon {
@apply hidden;
@apply hidden cursor-pointer;
}
.chips-wrapper:hover .nc-action-icon {
@apply inline-block;
}

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

@ -32,19 +32,24 @@ await loadRelatedTableMeta()
<span v-if="value?.length === 10" class="caption pointer ml-1 grey--text" @click="childListDlg = true">more... </span>
</template>
</div>
<MdiExpandIcon class="nc-action-icon w-[20px] text-gray-500/50 hover:text-gray-500" @click="childListDlg = true" />
<MdiPlusIcon class="nc-action-icon w-[20px] text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
<div class="flex-1 flex justify-end gap-1">
<MdiExpandIcon
class="select-none transform group-hover:(text-pink-500 scale-120) text-sm nc-action-icon text-gray-500/50 hover:text-gray-500"
@click="childListDlg = true"
/>
<MdiPlusIcon class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
</div>
<ListItems v-model="listItemsDlg" />
<ListChildItems v-model="childListDlg" />
<ListChildItems @attachRecord="childListDlg=false,listItemsDlg=true" v-model="childListDlg" />
</div>
</template>
<style scoped>
.nc-action-icon {
@apply hidden;
@apply hidden cursor-pointer;
}
.chips-wrapper:hover .nc-action-icon {
@apply inline-block;
@apply flex;
}
</style>

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

@ -32,21 +32,24 @@ await loadRelatedTableMeta()
<template v-if="value">
<ItemChip v-for="(ch, i) in value" :key="i" :value="ch[relatedTablePrimaryValueProp]" @unlink="unlink(ch)" />
<span v-if="value?.length === 10" class="caption pointer ml-1 grey--text" @click="childListDlg = true">more... </span>
<span v-if="value?.length === 10" class="caption pointer ml-1 grey--text"
@click="childListDlg = true">more... </span>
</template>
</div>
<div class="flex-1" />
<MdiExpandIcon class="nc-action-icon text-gray-500/50 hover:text-gray-500" @click="childListDlg = true" />
<MdiPlusIcon class="nc-action-icon w-[20px] text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
<div class="flex-1 flex justify-end gap-1">
<MdiExpandIcon class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500" @click="childListDlg = true" />
<MdiPlusIcon class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500" @click="listItemsDlg = true" />
</div>
<ListItems v-model="listItemsDlg" />
<ListChildItems v-model="childListDlg" />
<ListChildItems @attachRecord="childListDlg=false,listItemsDlg=true" v-model="childListDlg" />
</div>
</template>
<style scoped>
.nc-action-icon {
@apply hidden;
@apply hidden cursor-pointer;
}
.chips-wrapper:hover .nc-action-icon {
@apply inline-block;
}

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

@ -1,13 +1,25 @@
<script lang="ts" setup>
import { useVModel } from '@vueuse/core'
import { useLTARStoreOrThrow } from '~/composables'
import MdiReloadIcon from '~icons/mdi/reload'
import MdiDeleteIcon from '~icons/mdi/delete-outline'
import MdiUnlinkIcon from '~icons/mdi/link-variant-remove'
const props = defineProps<{ modelValue?: boolean }>()
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(['update:modelValue', 'attachRecord'])
const vModel = useVModel(props, 'modelValue', emit)
const { childrenList, loadChildrenList, childrenListPagination, relatedTablePrimaryValueProp, unlink } = useLTARStoreOrThrow()
const {
childrenList,
meta,
deleteRelatedRow,
loadChildrenList,
childrenListPagination,
relatedTablePrimaryValueProp,
unlink,
} =
useLTARStoreOrThrow()
watch(vModel, () => {
if (vModel.value) {
@ -24,20 +36,43 @@ const unlinkRow = async (row: Record<string, any>) => {
<template>
<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="flex-1 overflow-auto min-h-0">
<a-card v-for="(row, i) of childrenList?.list ?? []" :key="i" class="my-1 cursor-pointer" @click="unlinkRow(row)">
{{ row[relatedTablePrimaryValueProp] }}
</a-card>
<div class="flex mb-4 align-center gap-2">
<!-- <a-input v-model:value="childrenListPagination.query" class="max-w-[200px]" size="small"></a-input> -->
<div class="flex-1" />
<MdiReloadIcon class="cursor-pointer text-gray-500" @click="loadChildrenList" />
<a-button type="primary" size="small" @click="emit('attachRecord')">
<div class="flex align-center gap-1">
<MdiUnlinkIcon class="text-xs text-white" @click="unlinkRow(row)" />
Link to '{{ meta.title }}'
</div>
</a-button>
</div>
<a-pagination
v-if="childrenList?.pageInfo"
v-model:current="childrenListPagination.page"
v-model:page-size="childrenListPagination.size"
class="mt-2 mx-auto"
size="small"
:total="childrenList.pageInfo.totalRows"
show-less-items
/>
<template v-if="childrenList?.pageInfo?.totalRows">
<div class="flex-1 overflow-auto min-h-0">
<a-card v-for="(row, i) of childrenList?.list ?? []" :key="i" class="ma-2 hover:(!bg-gray-200/50 shadow-md)">
<div class="flex align-center">
<div class="flex-grow overflow-hidden min-w-0">
{{ row[relatedTablePrimaryValueProp] }}
</div>
<div class="flex gap-2">
<MdiUnlinkIcon class="text-xs text-grey hover:(!text-red-500) cursor-pointer" @click="unlinkRow(row)" />
<MdiDeleteIcon class="text-xs text-grey hover:(!text-red-500) cursor-pointer"
@click="deleteRelatedRow(row)" />
</div>
</div>
</a-card>
</div>
<a-pagination
v-if="childrenList?.pageInfo"
v-model:current="childrenListPagination.page"
v-model:page-size="childrenListPagination.size"
class="mt-2 mx-auto"
size="small"
:total="childrenList.pageInfo.totalRows"
show-less-items
/>
</template>
<a-empty class="my-10" v-else />
</div>
</a-modal>
</template>

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

@ -20,7 +20,8 @@ watch(vModel, () => {
const linkRow = async (row: Record<string, any>) => {
await link(row)
await loadChildrenExcludedList()
vModel.value= false
// await loadChildrenExcludedList()
}
</script>
@ -28,25 +29,33 @@ const linkRow = async (row: Record<string, any>) => {
<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 mb-4 align-center gap-2">
<a-input v-model:value="childrenExcludedListPagination.query" class="max-w-[200px]" size="small"></a-input>
<a-input v-model:value="childrenExcludedListPagination.query" placeholder="Filter query" class="max-w-[200px]" size="small"></a-input>
<div class="flex-1" />
<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 class="flex-1 overflow-auto min-h-0">
<a-card v-for="(row, i) in childrenExcludedList?.list ?? []" :key="i" class="my-1 cursor-pointer" @click="linkRow(row)">
{{ row[relatedTablePrimaryValueProp] }}
</a-card>
</div>
<a-pagination
v-if="childrenExcludedList?.pageInfo"
v-model:current="childrenExcludedListPagination.page"
v-model:page-size="childrenExcludedListPagination.size"
class="mt-2 mx-auto !text-xs"
size="small"
:total="childrenExcludedList.pageInfo.totalRows"
show-less-items
/>
<template v-if="childrenExcludedList?.pageInfo?.totalRows">
<div class="flex-1 overflow-auto min-h-0">
<a-card
v-for="(row, i) in childrenExcludedList?.list ?? []"
:key="i"
class="ma-2 cursor-pointer hover:(!bg-gray-200/50 shadow-md)"
@click="linkRow(row)"
>
{{ row[relatedTablePrimaryValueProp] }}
</a-card>
</div>
<a-pagination
v-if="childrenExcludedList?.pageInfo"
v-model:current="childrenExcludedListPagination.page"
v-model:page-size="childrenExcludedListPagination.size"
class="mt-2 mx-auto !text-xs"
size="small"
:total="childrenExcludedList.pageInfo.totalRows"
show-less-items
/>
</template>
<a-empty class="my-10" v-else />
</div>
</a-modal>
</template>

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

@ -1,8 +1,10 @@
import type { ColumnType, LinkToAnotherRecordType, PaginatedType, TableType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { Modal, notification } from 'ant-design-vue'
import { useInjectionState, useMetas, useProject } from '#imports'
import { NOCO } from '~/lib'
import type { Row } from '~/composables'
import { extractSdkResponseErrorMsg } from '~/utils'
interface DataApiResponse {
list: Record<string, any>
@ -97,6 +99,24 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
} as any,
)
}
const deleteRelatedRow = async (row: Record<string, any>) => {
Modal.confirm({
title: 'Do you want to delete the record?',
type: 'warning',
onOk: async () => {
const id = getRelatedTableRowId(row)
try {
$api.dbTableRow.delete(NOCO, project.value.id as string, relatedTableMeta.value.id as string, id as string)
reloadData?.()
await loadChildrenList()
} catch (e) {
notification.error(await extractSdkResponseErrorMsg(e))
}
},
})
}
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
@ -192,6 +212,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
loadChildrenExcludedList,
loadChildrenList,
row,
deleteRelatedRow,
}
},
'ltar-store',

Loading…
Cancel
Save