Browse Source

fix: Links modal for mobile

pull/6558/head
Muhammed Mustafa 1 year ago
parent
commit
5f7db89c9b
  1. 2
      packages/nc-gui/components/nc/Modal.vue
  2. 62
      packages/nc-gui/components/virtual-cell/components/Header.vue
  3. 178
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  4. 136
      packages/nc-gui/components/virtual-cell/components/ListItems.vue

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,
}" }"

62
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(() => {
@ -51,16 +53,14 @@ const relationMeta = computed(() => {
<template> <template>
<div class="flex justify-between relative pb-2 items-center"> <div class="flex 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 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 flex-grow items-center justify-center gap-2 xs:h-full">
<div class="flex justify-end"> <div class="flex justify-end w-[calc(50%-4rem)] xs:(w-[calc(50%-1rem)] 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 class="flex flex-shrink-0 xs:(flex-grow h-full) rounded-md gap-1 text-brand-500 items-center bg-gray-100 px-2 py-1">
<FileIcon class="w-4 h-4" /> <FileIcon class="w-4 h-4 min-w-4" />
<GeneralTruncateText placement="top" length="25"> {{ displayValue }}
{{ displayValue }}
</GeneralTruncateText>
</div> </div>
</div> </div>
<NcTooltip class="flex-shrink-0"> <NcTooltip class="flex-shrink-0">
@ -75,9 +75,9 @@ const relationMeta = computed(() => {
}" }"
/> />
</NcTooltip> </NcTooltip>
<div class="flex justify-start"> <div class="flex justify-start xs:w-[calc(50%-1rem)] w-[calc(50%-4rem)] xs:justify-start">
<div <div
class="flex rounded-md flex-shrink-0 gap-1 items-center px-2 py-1" class="flex rounded-md flex-shrink-0 gap-1 items-center px-2 py-1 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,34 +85,36 @@ 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>
<NcTooltip class="z-10" placement="bottom"> <div v-if="!isMobileMode" class="flex flex-row justify-end w-36">
<template #title> <NcTooltip class="z-10" placement="bottom">
<div class="p-1"> <template #title>
<h1 class="text-white font-bold">{{ relationMeta.title }}</h1> <div class="p-1">
<div class="text-white"> <h1 class="text-white font-bold">{{ relationMeta.title }}</h1>
{{ relationMeta.tooltip_desc }} <div class="text-white">
<span class="bg-gray-700 px-2 rounded-md"> {{ relationMeta.tooltip_desc }}
{{ tableTitle }} <span class="bg-gray-700 px-2 rounded-md">
</span> {{ tableTitle }}
{{ relationMeta.tooltip_desc2 }} </span>
<span class="bg-gray-700 px-2 rounded-md"> {{ relationMeta.tooltip_desc2 }}
{{ relatedTableTitle }} <span class="bg-gray-700 px-2 rounded-md">
</span> {{ relatedTableTitle }}
</span>
</div>
</div> </div>
</div> </template>
</template> <InfoIcon class="w-4 h-4" />
<InfoIcon class="w-4 h-4 mt-2" /> </NcTooltip>
</NcTooltip> </div>
</div> </div>
</template> </template>

178
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))
@ -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
@ -199,95 +202,98 @@ 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">
<div <template v-if="(isNew && state?.[colTitle]?.length) || childrenList?.pageInfo?.totalRows">
:class="{ <div class="mt-2 mb-2">
'h-[420px]': !isForm, <div class="nc-scrollbar-md cursor-pointer pr-1">
'h-[250px]': isForm, <template v-if="isChildrenLoading">
}" <div
class="overflow-scroll nc-scrollbar-md cursor-pointer pr-1" v-for="(x, i) in Array.from({ length: 10 })"
> :key="i"
<template v-if="isChildrenLoading"> class="!border-2 flex flex-row gap-2 mb-2 transition-all !rounded-xl relative !border-gray-200 hover:bg-gray-50"
<div >
v-for="(x, i) in Array.from({ length: skeltonAmountToShow })" <a-skeleton-image class="h-24 w-24 !rounded-xl" />
:key="i" <div class="flex flex-col m-[.5rem] gap-2 flex-grow justify-center">
class="border-2 flex flex-row gap-2 mb-2 transition-all rounded-xl relative border-gray-200 hover:bg-gray-50" <a-skeleton-input class="!w-48 !rounded-xl" active size="small" />
> <div class="flex flex-row gap-6 w-10/12">
<a-skeleton-image class="h-24 w-24 !rounded-xl" /> <div class="flex flex-col gap-0.5">
<div class="flex flex-col m-[.5rem] gap-2 flex-grow justify-center"> <a-skeleton-input class="!h-4 !w-12" active size="small" />
<a-skeleton-input class="!w-48 !rounded-xl" active size="small" /> <a-skeleton-input class="!h-4 !w-24" active size="small" />
<div class="flex flex-row gap-6 w-10/12"> </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="!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="!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="!h-4 !w-24" active size="small" />
</div> </div>
<div class="flex flex-col gap-0.5"> </div>
<a-skeleton-input class="!h-4 !w-12" active size="small" />
<a-skeleton-input class="!h-4 !w-24" active size="small" />
</div> </div>
</div> </div>
</div> </template>
<template v-else>
<LazyVirtualCellComponentsListItem
v-for="(refRow, id) in childrenList?.list ?? state?.[colTitle] ?? []"
:key="id"
:row="refRow"
:fields="fields"
data-testid="nc-child-list-item"
:attachment="attachmentCol"
:related-table-display-value-prop="relatedTableDisplayValueProp"
:is-linked="childrenList?.list ? isChildrenListLinked[Number.parseInt(id)] : true"
:is-loading="isChildrenListLoading[Number.parseInt(id)]"
@expand="onClick(refRow)"
@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>
</div> </div>
</template> </div>
<template v-else> </template>
<LazyVirtualCellComponentsListItem <div v-else class="pt-1 flex flex-col gap-3 my-auto items-center justify-center text-gray-500">
v-for="(refRow, id) in childrenList?.list ?? state?.[colTitle] ?? []" <InboxIcon class="w-16 h-16 mx-auto" />
:key="id" <p>
:row="refRow" {{ $t('msg.noRecordsAreLinkedFromTable') }}
:fields="fields" {{ relatedTableMeta?.title }}
data-testid="nc-child-list-item" </p>
:attachment="attachmentCol" <NcButton
:related-table-display-value-prop="relatedTableDisplayValueProp" v-if="!readonly && childrenListCount < 1"
:is-linked="childrenList?.list ? isChildrenListLinked[Number.parseInt(id)] : true" v-e="['c:links:link']"
:is-loading="isChildrenListLoading[Number.parseInt(id)]" data-testid="nc-child-list-button-link-to"
@expand="onClick(refRow)" @click="emit('attachRecord')"
@click="linkOrUnLink(refRow, id)" >
/> <div class="flex items-center gap-1"><MdiPlus /> {{ $t('title.linkMoreRecords') }}</div>
</template> </NcButton>
</div> </div>
</div> </div>
<div
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" />
<p>
{{ $t('msg.noRecordsAreLinkedFromTable') }}
{{ relatedTableMeta?.title }}
</p>
<NcButton
v-if="!readonly && childrenListCount < 1"
v-e="['c:links:link']"
data-testid="nc-child-list-button-link-to"
@click="emit('attachRecord')"
>
<div class="flex items-center gap-1"><MdiPlus /> {{ $t('title.linkMoreRecords') }}</div>
</NcButton>
</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">
{{ state?.[colTitle]?.length || 0 }} {{ $t('objects.records') }} <span class="">
{{ state?.[colTitle]?.length !== 0 ? $t('general.are') : '' }} {{ state?.[colTitle]?.length || 0 }} {{ $t('objects.records') }}
{{ $t('general.linked') }} {{ state?.[colTitle]?.length !== 0 ? $t('general.are') : '' }}
{{ $t('general.linked') }}
</span>
</div> </div>
<div class="flex absolute items-center py-2 justify-center w-full"> <div class="flex absolute items-center py-2 justify-center w-full">
<a-pagination <a-pagination
@ -310,7 +316,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 ? 'Link More' : $t('title.linkMoreRecords') }}
</div>
</NcButton> </NcButton>
</div> </div>
</div> </div>
@ -333,11 +341,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>

136
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()
@ -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="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"
@ -215,83 +217,79 @@ onKeyStroke('Escape', () => {
</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 })" :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"> <a-skeleton-input class="!w-48 !rounded-xl" active size="small" />
<a-skeleton-input class="!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="!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="!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="!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="!h-4 !w-24" active size="small" />
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </div>
<template v-else> </template>
<LazyVirtualCellComponentsListItem <template v-else>
v-for="(refRow, id) in childrenExcludedList?.list ?? []" <LazyVirtualCellComponentsListItem
:key="id" v-for="(refRow, id) in childrenExcludedList?.list ?? []"
data-testid="nc-excluded-list-item" :key="id"
:row="refRow" data-testid="nc-excluded-list-item"
:fields="fields" :row="refRow"
:attachment="attachmentCol" :fields="fields"
:related-table-display-value-prop="relatedTableDisplayValueProp" :attachment="attachmentCol"
:is-loading="isChildrenExcludedListLoading[Number.parseInt(id)]" :related-table-display-value-prop="relatedTableDisplayValueProp"
:is-linked="isChildrenExcludedListLinked[Number.parseInt(id)]" :is-loading="isChildrenExcludedListLoading[Number.parseInt(id)]"
@expand=" :is-linked="isChildrenExcludedListLinked[Number.parseInt(id)]"
() => { @expand="
expandedFormRow = refRow () => {
expandedFormDlg = true expandedFormRow = refRow
} expandedFormDlg = true
" }
@click=" "
() => { @click="
if (isChildrenExcludedListLinked[Number.parseInt(id)]) unlinkRow(refRow, Number.parseInt(id)) () => {
else linkRow(refRow, Number.parseInt(id)) if (isChildrenExcludedListLinked[Number.parseInt(id)]) unlinkRow(refRow, Number.parseInt(id))
} else linkRow(refRow, Number.parseInt(id))
" }
/> "
</template> />
</div> </template>
</div> </div>
</template> </template>
<div <div v-else class="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="mb-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">
{{ 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="flex absolute items-center py-2 justify-center w-full">
<a-pagination <a-pagination
@ -327,5 +325,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>

Loading…
Cancel
Save