Browse Source

Merge pull request #6558 from nocodb/nc-fix/mobile-links-modal

Mobile links modal
pull/6566/head
Muhammed Mustafa 1 year ago committed by GitHub
parent
commit
b36af1498b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui/components/nc/Modal.vue
  2. 9
      packages/nc-gui/components/nc/Pagination.vue
  3. 4
      packages/nc-gui/components/smartsheet/Gallery.vue
  4. 2
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  5. 34
      packages/nc-gui/components/virtual-cell/components/Header.vue
  6. 89
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  7. 25
      packages/nc-gui/components/virtual-cell/components/ListItem.vue
  8. 76
      packages/nc-gui/components/virtual-cell/components/ListItems.vue
  9. 1
      packages/nc-gui/lang/en.json

2
packages/nc-gui/components/nc/Modal.vue

@ -83,7 +83,7 @@ const slots = useSlots()
@keydown.esc="visible = false" @keydown.esc="visible = false"
> >
<div <div
class="flex flex-col nc-modal p-6" class="flex flex-col nc-modal p-6 h-full"
:style="{ :style="{
maxHeight: height, maxHeight: height,
}" }"

9
packages/nc-gui/components/nc/Pagination.vue

@ -4,6 +4,7 @@ const props = defineProps<{
total: number total: number
pageSize: number pageSize: number
entityName?: string entityName?: string
mode: 'simple' | 'full'
}>() }>()
const emits = defineEmits(['update:current', 'update:pageSize']) const emits = defineEmits(['update:current', 'update:pageSize'])
@ -20,6 +21,8 @@ const totalPages = computed(() => Math.max(Math.ceil(total.value / pageSize.valu
const { isMobileMode } = useGlobal() const { isMobileMode } = useGlobal()
const mode = computed(() => props.mode || (isMobileMode.value ? 'simple' : 'full'))
const changePage = ({ increase }: { increase: boolean }) => { const changePage = ({ increase }: { increase: boolean }) => {
if (increase && current.value < totalPages.value) { if (increase && current.value < totalPages.value) {
current.value = current.value + 1 current.value = current.value + 1
@ -40,7 +43,7 @@ const goToFirstPage = () => {
<template> <template>
<div class="nc-pagination flex flex-row items-center gap-x-2"> <div class="nc-pagination flex flex-row items-center gap-x-2">
<NcButton <NcButton
v-if="!isMobileMode" v-if="mode === 'full'"
v-e="[`a:pagination:${entityName}:first-page`]" v-e="[`a:pagination:${entityName}:first-page`]"
class="first-page" class="first-page"
type="secondary" type="secondary"
@ -63,7 +66,7 @@ const goToFirstPage = () => {
</NcButton> </NcButton>
<div class="text-gray-600"> <div class="text-gray-600">
<span class="active"> {{ current }} </span> <span class="active"> {{ current }} </span>
<span class="mx-1"> {{ isMobileMode ? '/' : 'of' }} </span> <span class="mx-1"> {{ mode !== 'full' ? '/' : 'of' }} </span>
<span class="total"> <span class="total">
{{ totalPages }} {{ totalPages }}
</span> </span>
@ -81,7 +84,7 @@ const goToFirstPage = () => {
</NcButton> </NcButton>
<NcButton <NcButton
v-if="!isMobileMode" v-if="mode === 'full'"
v-e="[`a:pagination:${entityName}:last-page`]" v-e="[`a:pagination:${entityName}:last-page`]"
class="last-page" class="last-page"
type="secondary" type="secondary"

4
packages/nc-gui/components/smartsheet/Gallery.vue

@ -347,9 +347,7 @@ watch(
:read-only="true" :read-only="true"
/> />
</div> </div>
<div v-else class="flex flex-row w-full h-[1.375rem] pl-1 items-center justify-start"> <div v-else class="flex flex-row w-full h-[1.375rem] pl-1 items-center justify-start">-</div>
<span class="bg-gray-200 h-2 w-16 rounded-md"></span>
</div>
</div> </div>
</div> </div>
</a-card> </a-card>

2
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -464,7 +464,7 @@ export default {
<div>{{ meta.title }}</div> <div>{{ meta.title }}</div>
</div> </div>
<NcButton <NcButton
v-if="!props.lastRow" v-if="props.showNextPrevIcons && !props.lastRow"
v-e="['c:row-expand:next']" v-e="['c:row-expand:next']"
type="secondary" type="secondary"
class="nc-next-arrow !w-10" class="nc-next-arrow !w-10"

34
packages/nc-gui/components/virtual-cell/components/Header.vue

@ -13,6 +13,8 @@ const { relation, relatedTableTitle, displayValue, showHeader, tableTitle } = de
displayValue?: string displayValue?: string
}>() }>()
const { isMobileMode } = useGlobal()
const { t } = useI18n() const { t } = useI18n()
const relationMeta = computed(() => { const relationMeta = computed(() => {
@ -50,17 +52,19 @@ const relationMeta = computed(() => {
</script> </script>
<template> <template>
<div class="flex justify-between relative pb-2 items-center"> <div class="flex sm:justify-between relative pb-2 items-center">
<span class="text-base font-bold flex mt-2 justify-center"> <div v-if="!isMobileMode" class="flex text-base font-bold justify-start items-center min-w-36">
{{ showHeader ? 'Linked Records' : '' }} {{ showHeader ? 'Linked Records' : '' }}
</span> </div>
<div class="grid grid-cols-[1fr,auto,1fr] justify-center items-center gap-2 absolute inset-0 m-auto"> <div class="flex flex-row sm:w-[calc(100%-16rem)] xs:w-full items-center justify-center gap-2 xs:(h-full)">
<div class="flex justify-end"> <div class="flex sm:justify-end w-[calc(50%-1.5rem)] xs:(w-[calc(50%-1.5rem)] h-full)">
<div class="flex flex-shrink-0 rounded-md gap-1 text-brand-500 items-center bg-gray-100 px-2 py-1"> <div
<FileIcon class="w-4 h-4" /> class="flex max-w-full xs:w-full flex-shrink-0 xs:(h-full) rounded-md gap-1 text-brand-500 items-center bg-gray-100 px-2 py-1"
<GeneralTruncateText placement="top" length="25"> >
<FileIcon class="w-4 h-4 min-w-4" />
<span class="truncate">
{{ displayValue }} {{ displayValue }}
</GeneralTruncateText> </span>
</div> </div>
</div> </div>
<NcTooltip class="flex-shrink-0"> <NcTooltip class="flex-shrink-0">
@ -75,9 +79,9 @@ const relationMeta = computed(() => {
}" }"
/> />
</NcTooltip> </NcTooltip>
<div class="flex justify-start"> <div class="flex justify-start xs:w-[calc(50%-1.5rem)] w-[calc(50%-1.5rem)] xs:justify-start">
<div <div
class="flex rounded-md flex-shrink-0 gap-1 items-center px-2 py-1" class="flex rounded-md max-w-full flex-shrink-0 gap-1 items-center px-2 py-1 xs:w-full overflow-hidden"
:class="{ :class="{
'!bg-orange-50 !text-orange-500': relation === 'hm', '!bg-orange-50 !text-orange-500': relation === 'hm',
'!bg-pink-50 !text-pink-500': relation === 'mm', '!bg-pink-50 !text-pink-500': relation === 'mm',
@ -85,17 +89,18 @@ const relationMeta = computed(() => {
}" }"
> >
<MdiFileDocumentMultipleOutline <MdiFileDocumentMultipleOutline
class="w-4 h-4" class="w-4 h-4 min-w-4"
:class="{ :class="{
'!text-orange-500': relation === 'hm', '!text-orange-500': relation === 'hm',
'!text-pink-500': relation === 'mm', '!text-pink-500': relation === 'mm',
'!text-blue-500': relation === 'bt', '!text-blue-500': relation === 'bt',
}" }"
/> />
{{ relatedTableTitle }} Records <span class="truncate"> {{ relatedTableTitle }} Records </span>
</div> </div>
</div> </div>
</div> </div>
<div v-if="!isMobileMode" class="flex flex-row justify-end w-36">
<NcTooltip class="z-10" placement="bottom"> <NcTooltip class="z-10" placement="bottom">
<template #title> <template #title>
<div class="p-1"> <div class="p-1">
@ -112,7 +117,8 @@ const relationMeta = computed(() => {
</div> </div>
</div> </div>
</template> </template>
<InfoIcon class="w-4 h-4 mt-2" /> <InfoIcon class="w-4 h-4" />
</NcTooltip> </NcTooltip>
</div> </div>
</div>
</template> </template>

89
packages/nc-gui/components/virtual-cell/components/ListChildItems.vue

@ -24,6 +24,8 @@ const emit = defineEmits(['update:modelValue', 'attachRecord'])
const vModel = useVModel(props, 'modelValue', emit) const vModel = useVModel(props, 'modelValue', emit)
const { isMobileMode } = useGlobal()
const isForm = inject(IsFormInj, ref(false)) const isForm = inject(IsFormInj, ref(false))
const isPublic = inject(IsPublicInj, ref(false)) const isPublic = inject(IsPublicInj, ref(false))
@ -88,7 +90,7 @@ const isFocused = ref(false)
const fields = computedInject(FieldsInj, (_fields) => { const fields = computedInject(FieldsInj, (_fields) => {
return (relatedTableMeta.value.columns ?? []) return (relatedTableMeta.value.columns ?? [])
.filter((col) => !isSystemColumn(col) && !isPrimary(col) && !isLinksOrLTAR(col) && !isAttachment(col)) .filter((col) => !isSystemColumn(col) && !isPrimary(col) && !isLinksOrLTAR(col) && !isAttachment(col))
.slice(0, 4) .slice(0, isMobileMode.value ? 1 : 4)
}) })
const expandedFormDlg = ref(false) const expandedFormDlg = ref(false)
@ -159,13 +161,14 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
</script> </script>
<template> <template>
<a-modal <NcModal
v-model:visible="vModel" v-model:visible="vModel"
:class="{ active: vModel }" :class="{ active: vModel }"
:footer="null" :footer="null"
:closable="false" :closable="false"
size="medium"
:width="isForm ? 600 : 800" :width="isForm ? 600 : 800"
:body-style="{ 'padding': 0, 'margin': 0, 'min-height': isForm ? '300px' : '500px' }" :body-style="{ 'max-height': '640px', 'height': '85vh' }"
wrap-class-name="nc-modal-child-list" wrap-class-name="nc-modal-child-list"
> >
<LazyVirtualCellComponentsHeader <LazyVirtualCellComponentsHeader
@ -187,7 +190,7 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
ref="filterQueryRef" ref="filterQueryRef"
v-model:value="childrenListPagination.query" v-model:value="childrenListPagination.query"
:placeholder="`Search in ${relatedTableMeta?.title}`" :placeholder="`Search in ${relatedTableMeta?.title}`"
class="w-full !rounded-md" class="w-full !sm:rounded-md xs:min-h-8 !xs:rounded-xl"
size="small" size="small"
:bordered="false" :bordered="false"
@focus="isFocused = true" @focus="isFocused = true"
@ -199,19 +202,14 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
</div> </div>
</div> </div>
<div v-if="isDataExist || isChildrenLoading" class="mt-2 mb-2"> <div class="flex flex-col flex-grow nc-scrollbar-md">
<div <template v-if="(isNew && state?.[colTitle]?.length) || childrenList?.pageInfo?.totalRows">
:class="{ <div class="cursor-pointer pr-1">
'h-[420px]': !isForm,
'h-[250px]': isForm,
}"
class="overflow-scroll nc-scrollbar-md cursor-pointer pr-1"
>
<template v-if="isChildrenLoading"> <template v-if="isChildrenLoading">
<div <div
v-for="(x, i) in Array.from({ length: skeltonAmountToShow })" v-for="(x, i) in Array.from({ length: 10 })"
:key="i" :key="i"
class="border-2 flex flex-row gap-2 mb-2 transition-all rounded-xl relative border-gray-200 hover:bg-gray-50" class="!border-2 flex flex-row gap-2 mb-2 transition-all !rounded-xl relative !border-gray-200 hover:bg-gray-50"
> >
<a-skeleton-image class="h-24 w-24 !rounded-xl" /> <a-skeleton-image class="h-24 w-24 !rounded-xl" />
<div class="flex flex-col m-[.5rem] gap-2 flex-grow justify-center"> <div class="flex flex-col m-[.5rem] gap-2 flex-grow justify-center">
@ -249,19 +247,21 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
:is-linked="childrenList?.list ? isChildrenListLinked[Number.parseInt(id)] : true" :is-linked="childrenList?.list ? isChildrenListLinked[Number.parseInt(id)] : true"
:is-loading="isChildrenListLoading[Number.parseInt(id)]" :is-loading="isChildrenListLoading[Number.parseInt(id)]"
@expand="onClick(refRow)" @expand="onClick(refRow)"
@click="linkOrUnLink(refRow, id)" @click="
() => {
if (isPublic && !isForm) return
isNew
? unlinkRow(refRow, Number.parseInt(id))
: isChildrenListLinked[Number.parseInt(id)]
? unlinkRow(refRow, Number.parseInt(id))
: linkRow(refRow, Number.parseInt(id))
}
"
/> />
</template> </template>
</div> </div>
</div> </template>
<div <div v-else class="pt-1 flex flex-col gap-3 my-auto items-center justify-center text-gray-500">
v-else
:class="{
'h-[420px]': !isForm,
'h-[250px]': isForm,
}"
class="pt-1 flex flex-col gap-3 items-center justify-center text-gray-500"
>
<InboxIcon class="w-16 h-16 mx-auto" /> <InboxIcon class="w-16 h-16 mx-auto" />
<p> <p>
{{ $t('msg.noRecordsAreLinkedFromTable') }} {{ $t('msg.noRecordsAreLinkedFromTable') }}
@ -276,30 +276,39 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
<div class="flex items-center gap-1"><MdiPlus /> {{ $t('title.linkMoreRecords') }}</div> <div class="flex items-center gap-1"><MdiPlus /> {{ $t('title.linkMoreRecords') }}</div>
</NcButton> </NcButton>
</div> </div>
</div>
<div v-if="isMobileMode" class="flex flex-row justify-center items-center w-full my-2">
<NcPagination
v-if="!isNew && childrenList?.pageInfo"
v-model:current="childrenListPagination.page"
v-model:page-size="childrenListPagination.size"
:total="+childrenList.pageInfo.totalRows!"
/>
</div>
<div class="my-2 bg-gray-50 border-gray-50 border-b-2"></div> <div class="my-2 bg-gray-50 border-gray-50 border-b-2"></div>
<div class="flex flex-row justify-between bg-white relative pt-1"> <div class="flex flex-row justify-between bg-white relative pt-1">
<div v-if="!isForm" class="flex items-center justify-center px-2 rounded-md text-gray-500 bg-brand-50"> <div v-if="!isForm" class="flex items-center justify-center px-2 rounded-md text-gray-500 bg-brand-50">
{{ childrenListCount || 0 }} {{ $t('objects.records') }} {{ childrenListCount !== 0 ? $t('general.are') : '' }} {{ childrenListCount || 0 }} {{ !isMobileMode ? $t('objects.records') : '' }}
{{ !isMobileMode && childrenListCount !== 0 ? $t('general.are') : '' }}
{{ $t('general.linked') }} {{ $t('general.linked') }}
</div> </div>
<div v-else class="flex items-center justify-center px-2 rounded-md text-gray-500 bg-brand-50"> <div v-else class="flex items-center justify-center px-2 rounded-md text-gray-500 bg-brand-50">
<span class="">
{{ state?.[colTitle]?.length || 0 }} {{ $t('objects.records') }} {{ state?.[colTitle]?.length || 0 }} {{ $t('objects.records') }}
{{ state?.[colTitle]?.length !== 0 ? $t('general.are') : '' }} {{ state?.[colTitle]?.length !== 0 ? $t('general.are') : '' }}
{{ $t('general.linked') }} {{ $t('general.linked') }}
</span>
</div> </div>
<div class="flex absolute items-center py-2 justify-center w-full"> <div class="!xs:hidden flex absolute -mt-0.75 items-center py-2 justify-center w-full">
<a-pagination <NcPagination
v-if="!isNew && childrenList?.pageInfo" v-if="!isNew && childrenList?.pageInfo"
v-model:current="childrenListPagination.page" v-model:current="childrenListPagination.page"
v-model:page-size="childrenListPagination.size" v-model:page-size="childrenListPagination.size"
:total="+childrenList.pageInfo.totalRows!" :total="+childrenList.pageInfo.totalRows!"
:show-size-changer="false" mode="simple"
class="mt-2 mx-auto"
size="small"
hide-on-single-page
show-less-items
/> />
</div> </div>
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
@ -310,7 +319,9 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
data-testid="nc-child-list-button-link-to" data-testid="nc-child-list-button-link-to"
@click="emit('attachRecord')" @click="emit('attachRecord')"
> >
<div class="flex items-center gap-1"><MdiPlus /> {{ $t('title.linkMoreRecords') }}</div> <div class="flex items-center gap-1">
<MdiPlus class="!xs:hidden" /> {{ isMobileMode ? $t('title.linkMore') : $t('title.linkMoreRecords') }}
</div>
</NcButton> </NcButton>
</div> </div>
</div> </div>
@ -333,11 +344,21 @@ const linkOrUnLink = (rowRef: Record<string, string>, id: string) => {
use-meta-fields use-meta-fields
/> />
</Suspense> </Suspense>
</a-modal> </NcModal>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
:deep(.nc-nested-list-item .ant-card-body) { :deep(.nc-nested-list-item .ant-card-body) {
@apply !px-1 !py-0; @apply !px-1 !py-0;
} }
:deep(.ant-modal-content) {
@apply !p-0;
}
</style>
<style lang="scss">
.nc-modal-child-list > .ant-modal > .ant-modal-content {
@apply !p-0;
}
</style> </style>

25
packages/nc-gui/components/virtual-cell/components/ListItem.vue

@ -47,6 +47,13 @@ interface Attachment {
mimetype: string mimetype: string
} }
const isRowEmpty = (row: any, col: any) => {
const val = row[col.title]
if (!val) return true
return Array.isArray(val) && val.length === 0
}
const attachments: ComputedRef<Attachment[]> = computed(() => { const attachments: ComputedRef<Attachment[]> = computed(() => {
try { try {
if (props.attachment && row.value[props.attachment.title]) { if (props.attachment && row.value[props.attachment.title]) {
@ -87,9 +94,11 @@ const attachments: ComputedRef<Attachment[]> = computed(() => {
<div v-else-if="attachment" class="h-24 w-24 w-full !flex flex-row items-center !rounded-l-xl justify-center"> <div v-else-if="attachment" class="h-24 w-24 w-full !flex flex-row items-center !rounded-l-xl justify-center">
<img class="object-contain h-24 w-24" src="~assets/icons/FileIconImageBox.png" /> <img class="object-contain h-24 w-24" src="~assets/icons/FileIconImageBox.png" />
</div> </div>
<div class="flex flex-col m-[.75rem] gap-1 flex-grow justify-center"> <div class="flex flex-col m-[.75rem] gap-1 flex-grow justify-center overflow-hidden">
<div class="flex justify-between"> <div class="flex justify-between xs:gap-x-2">
<span class="font-semibold text-gray-800 nc-display-value"> {{ row[relatedTableDisplayValueProp] }} </span> <span class="font-semibold text-gray-800 nc-display-value xs:(truncate)">
{{ row[relatedTableDisplayValueProp] }}
</span>
<div <div
v-if="isLinked && !isLoading" v-if="isLinked && !isLoading"
class="text-brand-500 text-0.875" class="text-brand-500 text-0.875"
@ -109,8 +118,11 @@ const attachments: ComputedRef<Attachment[]> = computed(() => {
/> />
</div> </div>
<div v-if="fields.length > 0 && !isPublic && !isForm" class="flex ml-[-0.25rem] flex-row gap-4 w-10/12"> <div
<div v-for="field in fields" :key="field.id" :class="attachment ? 'w-1/3' : 'w-1/4'"> v-if="fields.length > 0 && !isPublic && !isForm"
class="flex ml-[-0.25rem] sm:flex-row xs:(flex-col mt-2) gap-4 w-10/12"
>
<div v-for="field in fields" :key="field.id" :class="attachment ? 'sm:w-1/3' : 'sm:w-1/4'">
<div class="flex flex-col gap-[-1] max-w-72"> <div class="flex flex-col gap-[-1] max-w-72">
<LazySmartsheetHeaderVirtualCell <LazySmartsheetHeaderVirtualCell
v-if="isVirtualCol(field)" v-if="isVirtualCol(field)"
@ -121,6 +133,7 @@ const attachments: ComputedRef<Attachment[]> = computed(() => {
/> />
<LazySmartsheetHeaderCell v-else class="!scale-70" :column="field" :hide-menu="true" :hide-icon="true" /> <LazySmartsheetHeaderCell v-else class="!scale-70" :column="field" :hide-menu="true" :hide-icon="true" />
<div v-if="!isRowEmpty(row, field)">
<LazySmartsheetVirtualCell v-if="isVirtualCol(field)" v-model="row[field.title]" :row="row" :column="field" /> <LazySmartsheetVirtualCell v-if="isVirtualCol(field)" v-model="row[field.title]" :row="row" :column="field" />
<LazySmartsheetCell <LazySmartsheetCell
v-else v-else
@ -131,6 +144,8 @@ const attachments: ComputedRef<Attachment[]> = computed(() => {
:read-only="true" :read-only="true"
/> />
</div> </div>
<div v-else class="flex flex-row w-full h-[1.375rem] pl-1 items-center justify-start">-</div>
</div>
</div> </div>
</div> </div>
</div> </div>

76
packages/nc-gui/components/virtual-cell/components/ListItems.vue

@ -21,6 +21,8 @@ const emit = defineEmits(['update:modelValue', 'addNewRecord'])
const vModel = useVModel(props, 'modelValue', emit) const vModel = useVModel(props, 'modelValue', emit)
const { isMobileMode } = useGlobal()
const injectedColumn = inject(ColumnInj) const injectedColumn = inject(ColumnInj)
const filterQueryRef = ref() const filterQueryRef = ref()
@ -138,7 +140,7 @@ const attachmentCol = computedInject(FieldsInj, (_fields) => {
const fields = computedInject(FieldsInj, (_fields) => { const fields = computedInject(FieldsInj, (_fields) => {
return (relatedTableMeta.value.columns ?? []) return (relatedTableMeta.value.columns ?? [])
.filter((col) => !isSystemColumn(col) && !isPrimary(col) && !isLinksOrLTAR(col) && !isAttachment(col)) .filter((col) => !isSystemColumn(col) && !isPrimary(col) && !isLinksOrLTAR(col) && !isAttachment(col))
.slice(0, 4) .slice(0, isMobileMode.value ? 1 : 4)
}) })
const relation = computed(() => { const relation = computed(() => {
@ -157,13 +159,13 @@ onKeyStroke('Escape', () => {
</script> </script>
<template> <template>
<a-modal <NcModal
v-model:visible="vModel" v-model:visible="vModel"
:class="{ active: vModel }" :class="{ active: vModel }"
:footer="null" :footer="null"
:width="isForm ? 600 : 800" :width="isForm ? 600 : 800"
:closable="false" :closable="false"
:body-style="{ 'padding': 0, 'margin': 0, 'min-height': '500px' }" :body-style="{ 'max-height': '640px', 'height': '85vh' }"
wrap-class-name="nc-modal-link-record" wrap-class-name="nc-modal-link-record"
> >
<LazyVirtualCellComponentsHeader <LazyVirtualCellComponentsHeader
@ -173,7 +175,7 @@ onKeyStroke('Escape', () => {
:related-table-title="relatedTableMeta?.title" :related-table-title="relatedTableMeta?.title"
:display-value="row.row[displayValueProp]" :display-value="row.row[displayValueProp]"
/> />
<div class="m-4 bg-gray-50 border-gray-50 border-b-2"></div> <div class="!xs:hidden my-3 bg-gray-50 border-gray-50 border-b-2"></div>
<div class="flex mt-2 mb-2 items-center gap-2"> <div class="flex mt-2 mb-2 items-center gap-2">
<div <div
class="flex items-center border-1 p-1 rounded-md w-full border-gray-200" class="flex items-center border-1 p-1 rounded-md w-full border-gray-200"
@ -184,7 +186,7 @@ onKeyStroke('Escape', () => {
ref="filterQueryRef" ref="filterQueryRef"
v-model:value="childrenExcludedListPagination.query" v-model:value="childrenExcludedListPagination.query"
:placeholder="`${$t('general.searchIn')} ${relatedTableMeta?.title}`" :placeholder="`${$t('general.searchIn')} ${relatedTableMeta?.title}`"
class="w-full !rounded-md nc-excluded-search" class="w-full !rounded-md nc-excluded-search xs:min-h-8"
size="small" size="small"
:bordered="false" :bordered="false"
@focus="isFocused = true" @focus="isFocused = true"
@ -202,7 +204,7 @@ onKeyStroke('Escape', () => {
v-if="!isPublic" v-if="!isPublic"
v-e="['c:row-expand:open']" v-e="['c:row-expand:open']"
type="secondary" type="secondary"
size="xl" :size="isMobileMode ? 'medium' : 'small'"
class="!text-brand-500" class="!text-brand-500"
@click=" @click="
() => { () => {
@ -211,13 +213,12 @@ onKeyStroke('Escape', () => {
} }
" "
> >
<div class="flex items-center gap-1"><MdiPlus /> {{ $t('activity.newRecord') }}</div> <div class="flex items-center gap-1 px-4"><MdiPlus v-if="!isMobileMode" /> {{ $t('activity.newRecord') }}</div>
</NcButton> </NcButton>
</div> </div>
<template v-if="childrenExcludedList?.pageInfo?.totalRows || isChildrenExcludedLoading"> <template v-if="childrenExcludedList?.pageInfo?.totalRows">
<div class="pb-2 pt-1"> <div class="overflow-scroll nc-scrollbar-md pr-1 cursor-pointer flex flex-col flex-grow">
<div class="h-[420px] overflow-scroll nc-scrollbar-md pr-1 cursor-pointer">
<template v-if="isChildrenExcludedLoading"> <template v-if="isChildrenExcludedLoading">
<div <div
v-for="(x, i) in Array.from({ length: 10 })" v-for="(x, i) in Array.from({ length: 10 })"
@ -226,23 +227,23 @@ onKeyStroke('Escape', () => {
> >
<a-skeleton-image class="h-24 w-24 !rounded-xl" /> <a-skeleton-image class="h-24 w-24 !rounded-xl" />
<div class="flex flex-col m-[.5rem] gap-2 flex-grow justify-center"> <div class="flex flex-col m-[.5rem] gap-2 flex-grow justify-center">
<a-skeleton-input class="!w-48 !rounded-xl" active size="small" /> <a-skeleton-input class="!xs:w-30 !w-48 !rounded-xl" active size="small" />
<div class="flex flex-row gap-6 w-10/12"> <div class="flex flex-row gap-6 w-10/12">
<div class="flex flex-col gap-0.5"> <div class="flex flex-col gap-0.5">
<a-skeleton-input class="!h-4 !w-12" active size="small" /> <a-skeleton-input class="!h-4 !w-12" active size="small" />
<a-skeleton-input class="!h-4 !w-24" active size="small" /> <a-skeleton-input class="!xs:hidden !h-4 !w-24" active size="small" />
</div> </div>
<div class="flex flex-col gap-0.5"> <div class="flex flex-col gap-0.5">
<a-skeleton-input class="!h-4 !w-12" active size="small" /> <a-skeleton-input class="!h-4 !w-12" active size="small" />
<a-skeleton-input class="!h-4 !w-24" active size="small" /> <a-skeleton-input class="!xs:hidden !h-4 !w-24" active size="small" />
</div> </div>
<div class="flex flex-col gap-0.5"> <div class="flex flex-col gap-0.5">
<a-skeleton-input class="!h-4 !w-12" active size="small" /> <a-skeleton-input class="!h-4 !w-12" active size="small" />
<a-skeleton-input class="!h-4 !w-24" active size="small" /> <a-skeleton-input class="!xs:hidden !h-4 !w-24" active size="small" />
</div> </div>
<div class="flex flex-col gap-0.5"> <div class="flex flex-col gap-0.5">
<a-skeleton-input class="!h-4 !w-12" active size="small" /> <a-skeleton-input class="!h-4 !w-12" active size="small" />
<a-skeleton-input class="!h-4 !w-24" active size="small" /> <a-skeleton-input class="!xs:hidden !h-4 !w-24" active size="small" />
</div> </div>
</div> </div>
</div> </div>
@ -274,36 +275,41 @@ onKeyStroke('Escape', () => {
/> />
</template> </template>
</div> </div>
</div>
</template> </template>
<div <div v-else class="my-auto py-2 flex flex-col gap-3 items-center justify-center text-gray-500">
v-if="!isChildrenExcludedLoading && !childrenExcludedList?.pageInfo?.totalRows"
class="py-2 h-[420px] flex flex-col gap-3 items-center justify-center text-gray-500"
>
<InboxIcon class="w-16 h-16 mx-auto" /> <InboxIcon class="w-16 h-16 mx-auto" />
<p> <p>
{{ $t('msg.thereAreNoRecordsInTable') }} {{ $t('msg.thereAreNoRecordsInTable') }}
{{ relatedTableMeta?.title }} {{ relatedTableMeta?.title }}
</p> </p>
</div> </div>
<div class="my-2 bg-gray-50 border-gray-50 border-b-2"></div>
<div class="flex flex-row justify-between bg-white relative pt-1"> <div v-if="isMobileMode" class="flex flex-row justify-center items-center w-full my-2">
<div v-if="!isForm" class="flex items-center justify-center px-2 rounded-md text-gray-500 bg-brand-50"> <NcPagination
v-if="childrenExcludedList?.pageInfo"
v-model:current="childrenExcludedListPagination.page"
v-model:page-size="childrenExcludedListPagination.size"
:total="+childrenExcludedList.pageInfo.totalRows"
entity-name="links-excluded-list"
/>
</div>
<div class="mb-2 bg-gray-50 border-gray-50 border-b-2"></div>
<div class="flex flex-row justify-between items-center bg-white relative pt-1">
<div v-if="!isForm" class="flex items-center justify-center px-2 rounded-md text-gray-500 bg-brand-50 h-9.5">
{{ relation === 'bt' ? (row.row[relatedTableMeta?.title] ? '1' : 0) : childrenListCount ?? 'No' }} {{ relation === 'bt' ? (row.row[relatedTableMeta?.title] ? '1' : 0) : childrenListCount ?? 'No' }}
{{ $t('objects.records') }} {{ childrenListCount !== 0 ? 'are' : '' }} {{ $t('general.linked') }} {{ !isMobileMode ? $t('objects.records') : '' }} {{ !isMobileMode && childrenListCount !== 0 ? 'are' : '' }}
{{ $t('general.linked') }}
</div> </div>
<div class="flex absolute items-center py-2 justify-center w-full"> <div class="!xs:hidden flex absolute -mt-0.75 items-center py-2 justify-center w-full">
<a-pagination <NcPagination
v-if="childrenExcludedList?.pageInfo" v-if="childrenExcludedList?.pageInfo"
v-model:current="childrenExcludedListPagination.page" v-model:current="childrenExcludedListPagination.page"
v-model:page-size="childrenExcludedListPagination.size" v-model:page-size="childrenExcludedListPagination.size"
:total="+childrenExcludedList.pageInfo.totalRows" :total="+childrenExcludedList.pageInfo.totalRows"
:show-size-changer="false" entity-name="links-excluded-list"
class="mt-2 mx-auto" mode="simple"
size="small"
hide-on-single-page
show-less-items
/> />
</div> </div>
<NcButton class="nc-close-btn ml-auto" type="ghost" @click="vModel = false"> {{ $t('general.finish') }} </NcButton> <NcButton class="nc-close-btn ml-auto" type="ghost" @click="vModel = false"> {{ $t('general.finish') }} </NcButton>
@ -327,5 +333,11 @@ onKeyStroke('Escape', () => {
use-meta-fields use-meta-fields
/> />
</Suspense> </Suspense>
</a-modal> </NcModal>
</template> </template>
<style lang="scss">
.nc-modal-link-record > .ant-modal > .ant-modal-content {
@apply !p-0;
}
</style>

1
packages/nc-gui/lang/en.json

@ -307,6 +307,7 @@
"hasMany": "Has Many", "hasMany": "Has Many",
"manyToMany": "Many to Many", "manyToMany": "Many to Many",
"virtualRelation": "Virtual Relation", "virtualRelation": "Virtual Relation",
"linkMore": "Link More",
"linkMoreRecords": "Link more records", "linkMoreRecords": "Link more records",
"downloadFile": "Download File", "downloadFile": "Download File",
"renameTable": "Rename Table", "renameTable": "Rename Table",

Loading…
Cancel
Save