Browse Source

Merge pull request #6561 from nocodb/nc-fix/expanded-form-lazy-loading

Expanded form lazy loading for mobile
pull/6567/head
Muhammed Mustafa 11 months ago committed by GitHub
parent
commit
cb9a85add8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      packages/nc-gui/components/cell/attachment/index.vue
  2. 2
      packages/nc-gui/components/project/AllTables.vue
  3. 10
      packages/nc-gui/components/smartsheet/column/LookupOptions.vue
  4. 149
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  5. 7
      packages/nc-gui/components/smartsheet/grid/Table.vue
  6. 2
      packages/nc-gui/components/virtual-cell/Links.vue
  7. 1
      packages/nc-gui/lib/acl.ts
  8. 4
      tests/playwright/tests/db/columns/columnLtarDragdrop.spec.ts

30
packages/nc-gui/components/cell/attachment/index.vue

@ -50,7 +50,9 @@ const isExpandedForm = inject(IsExpandedFormOpenInj, ref(false))
const { isSharedForm } = useSmartsheetStoreOrThrow()!
const { getPossibleAttachmentSrc, openAttachment } = useAttachment()
const { isMobileMode } = useGlobal()
const { getPossibleAttachmentSrc, openAttachment: _openAttachment } = useAttachment()
const {
isPublic,
@ -61,7 +63,7 @@ const {
visibleItems,
onDrop,
isLoading,
open,
open: _open,
FileIcon,
selectedImage,
isReadonly: _isReadonly,
@ -136,7 +138,7 @@ watch(
useSelectedCellKeyupListener(inject(ActiveCellInj, ref(false)), (e) => {
if (e.key === 'Enter' && !isReadonly.value) {
e.stopPropagation()
if (!modalVisible.value) {
if (!modalVisible.value && !isMobileMode.value) {
modalVisible.value = true
} else {
// click Attach File button
@ -146,6 +148,24 @@ useSelectedCellKeyupListener(inject(ActiveCellInj, ref(false)), (e) => {
})
const rowHeight = inject(RowHeightInj, ref())
const open = () => {
if (isMobileMode.value) return (isExpandedForm.value = true)
_open()
}
const openAttachment = (item: any) => {
if (isMobileMode.value) return
_openAttachment(item)
}
const onExpand = () => {
if (isMobileMode.value) return
modalVisible.value = true
}
</script>
<template>
@ -220,7 +240,7 @@ const rowHeight = inject(RowHeightInj, ref())
:class="{ 'ml-2': active }"
@click="
() => {
if (isGallery) return
if (isGallery || isMobileMode) return
selectedImage = item
}
"
@ -264,7 +284,7 @@ const rowHeight = inject(RowHeightInj, ref())
<component
:is="iconMap.expand"
class="transform dark:(!text-white) group-hover:(!text-grey-800 scale-120) text-gray-500 text-[0.75rem]"
@click.stop="modalVisible = true"
@click.stop="onExpand"
/>
</NcTooltip>
</div>

2
packages/nc-gui/components/project/AllTables.vue

@ -9,7 +9,7 @@ const { openedProject } = storeToRefs(useBases())
const isNewBaseModalOpen = ref(false)
const isDataSourceLimitReached = computed(() => Number(openedProject.value?.bases?.length) > 1)
const isDataSourceLimitReached = computed(() => Number(openedProject.value?.sources?.length) > 1)
const { isUIAllowed } = useRoles()

10
packages/nc-gui/components/smartsheet/column/LookupOptions.vue

@ -16,6 +16,8 @@ const meta = inject(MetaInj, ref())
const { t } = useI18n()
const { appInfo } = useGlobal()
const { setAdditionalValidations, validateInfos, onDataTypeChange, isEdit } = useColumnCreateStoreOrThrow()
const baseStore = useBase()
@ -37,7 +39,13 @@ const refTables = computed(() => {
}
const _refTables = meta.value.columns
.filter((column) => isLinksOrLTAR(column) && !column.system && column.source_id === meta.value?.source_id)
.filter(
(column) =>
isLinksOrLTAR(column) &&
!column.system &&
column.source_id === meta.value?.source_id &&
(!appInfo.value.ee || (column?.colOptions as any)?.type === 'bt'),
)
.map((column) => ({
col: column.colOptions,
column,

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

@ -99,6 +99,8 @@ const isKanban = inject(IsKanbanInj, ref(false))
provide(MetaInj, meta)
const isLoading = ref(true)
const {
commentsDrawer,
changedColumns,
@ -117,22 +119,6 @@ const {
const duplicatingRowInProgress = ref(false)
if (props.loadRow) {
await _loadRow(rowId.value)
}
if (rowId.value) {
try {
await _loadRow(rowId.value)
} catch (e: any) {
if (e.response?.status === 404) {
// todo: i18n
message.error('Record not found')
router.replace({ query: {} })
} else throw e
}
}
useProvideSmartsheetStore(ref({}) as Ref<ViewType>, meta)
watch(
@ -232,7 +218,26 @@ provide(IsExpandedFormOpenInj, isExpanded)
const cellWrapperEl = ref()
onMounted(() => {
onMounted(async () => {
isLoading.value = true
if (props.loadRow) {
await _loadRow()
}
if (props.rowId) {
try {
await _loadRow(props.rowId)
} catch (e: any) {
if (e.response?.status === 404) {
// todo: i18n
message.error('Record not found')
router.replace({ query: {} })
} else throw e
}
}
isLoading.value = false
setTimeout(() => {
cellWrapperEl.value?.$el?.querySelector('input,select,textarea')?.focus()
}, 300)
@ -389,10 +394,10 @@ export default {
<MdiChevronDown class="text-md" />
</NcButton>
</div>
<div
v-if="displayValue && !row.rowMeta?.new"
class="flex items-center truncate w-32 hover:w-64 transition-all font-bold text-gray-800 text-xl"
>
<div v-if="isLoading">
<a-skeleton-input class="!h-8 !sm:mr-14 !w-52 mt-1 !rounded-md !overflow-hidden" active size="small" />
</div>
<div v-else-if="displayValue && !row.rowMeta?.new" class="flex items-center font-bold text-gray-800 text-xl w-64">
<span class="truncate">
{{ displayValue }}
</span>
@ -495,7 +500,7 @@ export default {
:col-id="col.id"
:data-testid="`nc-expand-col-${col.title}`"
>
<div class="flex items-start flex-row xs:(flex-col w-full) nc-expanded-cell">
<div class="flex items-start flex-row xs:(flex-col w-full) nc-expanded-cell min-h-10">
<div class="w-[12rem] xs:(w-full) mt-1.5 !h-[35px]">
<LazySmartsheetHeaderVirtualCell
v-if="isVirtualCol(col)"
@ -506,23 +511,37 @@ export default {
<LazySmartsheetHeaderCell v-else class="nc-expanded-cell-header !text-gray-600" :column="col" />
</div>
<LazySmartsheetDivDataCell
v-if="col.title"
:ref="i ? null : (el: any) => (cellWrapperEl = el)"
class="!bg-white rounded-lg !w-[20rem] !xs:w-full border-1 overflow-hidden border-gray-200 px-1 min-h-[35px] flex items-center relative"
>
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="_row.row[col.title]" :row="_row" :column="col" />
<LazySmartsheetCell
<template v-if="isLoading">
<div
v-if="isMobileMode"
class="!h-8.5 !xs:h-12 !xs:bg-white !sm:mr-21 !w-60 mt-0.75 !rounded-lg !overflow-hidden"
></div>
<a-skeleton-input
v-else
v-model="_row.row[col.title]"
:column="col"
:edit-enabled="true"
:active="true"
:read-only="isPublic"
@update:model-value="changedColumns.add(col.title)"
class="!h-8.5 !xs:h-9.5 !xs:bg-white !sm:mr-21 !w-60 mt-0.75 !rounded-lg !overflow-hidden"
active
size="small"
/>
</LazySmartsheetDivDataCell>
</template>
<template v-else>
<SmartsheetDivDataCell
v-if="col.title"
:ref="i ? null : (el: any) => (cellWrapperEl = el)"
class="!bg-white rounded-lg !w-[20rem] !xs:w-full border-1 border-gray-200 overflow-hidden px-1 min-h-[35px] flex items-center relative"
>
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="_row.row[col.title]" :row="_row" :column="col" />
<LazySmartsheetCell
v-else
v-model="_row.row[col.title]"
:column="col"
:edit-enabled="true"
:active="true"
:read-only="isPublic"
@update:model-value="changedColumns.add(col.title)"
/>
</SmartsheetDivDataCell>
</template>
</div>
</div>
<div v-if="hiddenFields.length > 0" class="flex w-full px-12 items-center py-3">
@ -543,34 +562,54 @@ export default {
:class="`nc-expand-col-${col.title}`"
:data-testid="`nc-expand-col-${col.title}`"
>
<div class="flex flex-row items-start">
<div class="flex flex-row items-start min-h-10">
<div class="w-[12rem] scale-110 !h-[35px] mt-2.5">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" class="!text-gray-600" :column="col" />
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" class="!text-gray-600" />
<LazySmartsheetHeaderCell v-else class="!text-gray-600" :column="col" />
</div>
<LazySmartsheetDivDataCell
v-if="col.title"
:ref="i ? null : (el: any) => (cellWrapperEl = el)"
class="!bg-white rounded-lg !w-[20rem] border-1 overflow-hidden border-gray-200 px-1 min-h-[35px] flex items-center relative"
>
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="_row.row[col.title]" :row="_row" :column="col" />
<LazySmartsheetCell
<template v-if="isLoading">
<div
v-if="isMobileMode"
class="!h-8.5 !xs:h-9.5 !xs:bg-white !sm:mr-21 !w-60 mt-0.75 !rounded-lg !overflow-hidden"
></div>
<a-skeleton-input
v-else
v-model="_row.row[col.title]"
:column="col"
:edit-enabled="true"
:active="true"
:read-only="isPublic"
@update:model-value="changedColumns.add(col.title)"
class="!h-8.5 !xs:h-12 !xs:bg-white !sm:mr-21 !w-60 mt-0.75 !rounded-lg !overflow-hidden"
active
size="small"
/>
</LazySmartsheetDivDataCell>
</template>
<template v-else>
<LazySmartsheetDivDataCell
v-if="col.title"
:ref="i ? null : (el: any) => (cellWrapperEl = el)"
class="!bg-white rounded-lg !w-[20rem] border-1 overflow-hidden border-gray-200 px-1 min-h-[35px] flex items-center relative"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(col)"
v-model="_row.row[col.title]"
:row="_row"
:column="col"
/>
<LazySmartsheetCell
v-else
v-model="_row.row[col.title]"
:column="col"
:edit-enabled="true"
:active="true"
:read-only="isPublic"
@update:model-value="changedColumns.add(col.title)"
/>
</LazySmartsheetDivDataCell>
</template>
</div>
</div>
</div>
</div>
<div
v-if="isUIAllowed('dataEdit')"
class="w-full h-16 border-t-1 border-gray-200 bg-white flex items-center justify-end p-3 xs:(p-0 mt-4 border-t-0 gap-x-4 justify-between)"
@ -633,7 +672,7 @@ export default {
class="nc-comments-drawer border-1 relative border-gray-200 w-1/3 max-w-125 bg-gray-50 rounded-xl min-w-0 overflow-hidden h-full xs:hidden"
:class="{ active: commentsDrawer && isUIAllowed('commentList') }"
>
<LazySmartsheetExpandedFormComments />
<SmartsheetExpandedFormComments />
</div>
</div>
</div>

7
packages/nc-gui/components/smartsheet/grid/Table.vue

@ -140,6 +140,7 @@ const { getMeta } = useMetas()
const { addUndo, clone, defineViewScope } = useUndoRedo()
const {
predictingNextColumn,
predictedNextColumn,
@ -1357,7 +1358,7 @@ const handleCellClick = (event: MouseEvent, row: number, col: number) => {
>
<div class="items-center flex gap-1 min-w-[60px]">
<div
v-if="!readOnly || !isLocked"
v-if="!readOnly || !isLocked || isMobileMode"
class="nc-row-no text-xs text-gray-500"
:class="{ toggle: !readOnly, hidden: row.rowMeta.selected }"
>
@ -1864,7 +1865,7 @@ const handleCellClick = (event: MouseEvent, row: number, col: number) => {
.nc-grid-row {
.nc-row-expand-and-checkbox {
@apply w-full items-center justify-between;
@apply !xs:hidden w-full items-center justify-between;
}
.nc-expand {
@ -1887,7 +1888,7 @@ const handleCellClick = (event: MouseEvent, row: number, col: number) => {
}
.nc-row-expand-and-checkbox {
@apply flex;
@apply !xs:hidden flex;
}
}
}

2
packages/nc-gui/components/virtual-cell/Links.vue

@ -109,7 +109,7 @@ const localCellValue = computed<any[]>(() => {
</div>
<div class="flex-grow" />
<div v-if="!isLocked && !isUnderLookup" class="flex justify-end hidden group-hover:flex items-center">
<div v-if="!isLocked && !isUnderLookup" class="!xs:hidden flex justify-end hidden group-hover:flex items-center">
<MdiPlus
v-if="(!readOnly && isUIAllowed('dataEdit')) || isForm"
class="select-none !text-md text-gray-700 nc-action-icon nc-plus"

1
packages/nc-gui/lib/acl.ts

@ -70,6 +70,7 @@ const rolePermissions = {
csvImport: true,
baseRename: true,
baseDuplicate: true,
sourceCreate: true,
},
},
[ProjectRoles.EDITOR]: {

4
tests/playwright/tests/db/columns/columnLtarDragdrop.spec.ts

@ -4,6 +4,7 @@ import { Api, UITypes } from 'nocodb-sdk';
import { DashboardPage } from '../../../pages/Dashboard';
import { GridPage } from '../../../pages/Dashboard/Grid';
import { getTextExcludeIconText } from '../../../tests/utils/general';
import { isEE } from '../../../setup/db';
let api: Api<any>;
const recordCount = 10;
@ -99,6 +100,9 @@ test.describe('Links', () => {
const linkField = await getTextExcludeIconText(columnAddModal.locator(`.ant-form-item-control-input`).nth(2));
const childColumn = await getTextExcludeIconText(columnAddModal.locator(`.ant-form-item-control-input`).nth(3));
// TODO: Handle this in EE
if (isEE()) return;
// validate
expect(columnType).toContain('Lookup');
expect(linkField).toContain('Table1List');

Loading…
Cancel
Save