Browse Source

Merge pull request #6554 from nocodb/nc-fix/exp-modal

Fix: Expanded Records
pull/6559/head
Anbarasu 1 year ago committed by GitHub
parent
commit
7f65cd6650
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      packages/nc-gui/components/smartsheet/Gallery.vue
  2. 1
      packages/nc-gui/components/smartsheet/Map.vue
  3. 12
      packages/nc-gui/components/smartsheet/expanded-form/Comments.vue
  4. 93
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  5. 1
      packages/nc-gui/components/smartsheet/grid/index.vue
  6. 6
      packages/nc-gui/components/smartsheet/header/Cell.vue
  7. 14
      packages/nc-gui/components/smartsheet/header/VirtualCell.vue
  8. 1
      packages/nc-gui/components/tabs/Smartsheet.vue
  9. 3
      packages/nc-gui/composables/useExpandedFormStore.ts
  10. 12
      packages/nc-gui/utils/dataUtils.ts
  11. 3
      packages/nocodb/src/services/audits.service.ts

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

@ -126,7 +126,7 @@ const attachments = (record: any): Attachment[] => {
const expandForm = (row: RowType, state?: Record<string, any>) => {
const rowId = extractPkFromRow(row.row, meta.value!.columns!)
if (rowId && !isPublic.value) {
if (rowId) {
router.push({
query: {
...route.query,
@ -374,7 +374,6 @@ watch(
<Suspense>
<LazySmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="route.query.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"

1
packages/nc-gui/components/smartsheet/Map.vue

@ -246,7 +246,6 @@ const count = computed(() => paginationData.value.totalRows)
<Suspense v-if="!isPublic">
<LazySmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="route.query.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"

12
packages/nc-gui/components/smartsheet/expanded-form/Comments.vue

@ -18,8 +18,6 @@ const tab = ref<'comments' | 'audits'>('comments')
const { isUIAllowed } = useRoles()
const { appInfo } = useGlobal()
const hasEditPermission = computed(() => isUIAllowed('commentEdit'))
const editLog = ref<AuditType>()
@ -169,13 +167,13 @@ const processedAudit = (log: string) => {
<span class="truncate font-bold max-w-42">
{{ log.display_name ?? log.user.split('@')[0] ?? 'Shared source' }}
</span>
<div v-if="log.id !== editLog?.id" class="text-xs text-gray-500">
<div v-if="log.id !== editLog?.id" class="text-xs font-medium text-gray-500">
{{ log.created_at !== log.updated_at ? `Edited ${timeAgo(log.updated_at)}` : timeAgo(log.created_at) }}
</div>
</div>
</div>
<NcButton
v-if="log.user === user!.email && !editLog && !appInfo.ee"
v-if="log.user === user!.email && !editLog"
v-e="['c:row-expand:comment:edit']"
type="secondary"
class="!px-2 opacity-0 group-hover:opacity-100 transition-all"
@ -240,14 +238,14 @@ const processedAudit = (log: string) => {
<div class="bg-white rounded-xl border-1 gap-3 border-gray-200">
<div class="flex flex-col p-4 gap-3">
<div class="flex justify-between">
<div class="flex font-bold items-center gap-2">
<div class="flex items-center gap-2">
<GeneralUserIcon size="base" :name="log.display_name ?? log.user" />
<div class="flex flex-col">
<span class="truncate max-w-50">
<span class="truncate font-bold max-w-50">
{{ log.display_name ?? log.user.split('@')[0].slice(0, 2) ?? 'Shared source' }}
</span>
<div v-if="log.id !== editLog?.id" class="text-xs text-gray-500">
<div v-if="log.id !== editLog?.id" class="text-xs font-medium text-gray-500">
{{ timeAgo(log.created_at) }}
</div>
</div>

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

@ -29,15 +29,14 @@ import {
useVModel,
watch,
} from '#imports'
import type { Row } from '#imports'
interface Props {
modelValue?: boolean
row: Row
state?: Record<string, any> | null
meta: TableType
loadRow?: boolean
useMetaFields?: boolean
row?: Row
rowId?: string
view?: ViewType
showNextPrevIcons?: boolean
@ -57,7 +56,9 @@ const { isMobileMode } = useGlobal()
const { t } = useI18n()
const row = ref(props.row)
const rowId = toRef(props, 'rowId')
const row = toRef(props, 'row')
const state = toRef(props, 'state')
@ -108,19 +109,21 @@ const {
loadRow: _loadRow,
primaryKey,
saveRowAndStay,
row: _row,
syncLTARRefs,
save: _save,
loadCommentsAndLogs,
} = useProvideExpandedFormStore(meta, row)
const duplicatingRowInProgress = ref(false)
if (props.loadRow) {
await _loadRow()
await _loadRow(rowId.value)
}
if (props.rowId) {
if (rowId.value) {
try {
await _loadRow(props.rowId)
await _loadRow(rowId.value)
} catch (e: any) {
if (e.response?.status === 404) {
// todo: i18n
@ -149,14 +152,14 @@ const isExpanded = useVModel(props, 'modelValue', emits, {
})
const onClose = () => {
if (row.value?.rowMeta?.new) emits('cancel')
if (_row.value?.rowMeta?.new) emits('cancel')
isExpanded.value = false
}
const onDuplicateRow = () => {
duplicatingRowInProgress.value = true
isUnsavedFormExist.value = true
const oldRow = { ...row.value.row }
const oldRow = { ..._row.value.row }
delete oldRow.ncRecordId
const newRow = Object.assign(
{},
@ -167,7 +170,7 @@ const onDuplicateRow = () => {
},
)
setTimeout(async () => {
row.value = newRow
_row.value = newRow
duplicatingRowInProgress.value = false
message.success(t('msg.success.rowDuplicatedWithoutSavedYet'))
}, 500)
@ -219,17 +222,12 @@ provide(ReloadRowDataHookInj, reloadHook)
if (isKanban.value) {
// adding column titles to changedColumns if they are preset
for (const [k, v] of Object.entries(row.value.row)) {
for (const [k, v] of Object.entries(_row.value.row)) {
if (v) {
changedColumns.value.add(k)
}
}
}
watch(isUnsavedFormExist, () => {
console.log(isUnsavedFormExist.value, 'HEHEH')
})
provide(IsExpandedFormOpenInj, isExpanded)
const cellWrapperEl = ref()
@ -242,7 +240,7 @@ onMounted(() => {
const addNewRow = () => {
setTimeout(async () => {
row.value = {
_row.value = {
row: {},
oldRow: {},
rowMeta: { new: true },
@ -340,22 +338,10 @@ const onConfirmDeleteRowClick = async () => {
showDeleteRowModal.value = false
}
watch(
state,
() => {
if (!state.value?.id) return
setTimeout(() => {
const rowDom = wrapper.value?.querySelector(`.nc-expanded-form-row[col-id="${state.value?.id}"]`)
if (rowDom) {
rowDom.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
}, 650)
},
{
immediate: true,
},
)
watch(rowId, async (nRow) => {
await _loadRow(nRow)
await loadCommentsAndLogs()
})
const showRightSections = computed(() => {
return !isNew.value && commentsDrawer.value && isUIAllowed('commentList')
@ -370,7 +356,6 @@ export default {
<template>
<NcModal
:key="key"
v-model:visible="isExpanded"
:footer="null"
:width="commentsDrawer && isUIAllowed('commentList') ? 'min(80vw,1280px)' : 'min(80vw,1280px)'"
@ -404,13 +389,15 @@ export default {
<MdiChevronDown class="text-md" />
</NcButton>
</div>
<div v-if="displayValue" class="flex items-center truncate font-bold text-gray-800 text-xl">
{{ displayValue }}
</div>
<div class="bg-gray-100 px-2 gap-1 flex my-1 items-center rounded-lg text-gray-800 font-medium">
<TableIcon class="w-6 h-6 text-sm" />
All {{ meta.title }}
<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"
>
<span class="truncate">
{{ displayValue }}
</span>
</div>
<div v-if="row.rowMeta?.new" class="flex items-center truncate font-bold text-gray-800 text-xl">New Record</div>
</div>
<div class="flex gap-2">
<NcDropdown v-if="!isNew">
@ -509,22 +496,26 @@ export default {
:data-testid="`nc-expand-col-${col.title}`"
>
<div class="flex items-start flex-row xs:(flex-col w-full) nc-expanded-cell">
<div class="w-[12rem] xs:(w-full) mt-1.5">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" class="nc-expanded-cell-header" :column="col" />
<div class="w-[12rem] xs:(w-full) mt-1.5 !h-[35px]">
<LazySmartsheetHeaderVirtualCell
v-if="isVirtualCol(col)"
class="nc-expanded-cell-header !text-gray-600"
:column="col"
/>
<LazySmartsheetHeaderCell v-else class="nc-expanded-cell-header" :column="col" />
<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 border-gray-200 px-1 min-h-[35px] flex items-center relative"
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" />
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="_row.row[col.title]" :row="_row" :column="col" />
<LazySmartsheetCell
v-else
v-model="row.row[col.title]"
v-model="_row.row[col.title]"
:column="col"
:edit-enabled="true"
:active="true"
@ -553,22 +544,22 @@ export default {
:data-testid="`nc-expand-col-${col.title}`"
>
<div class="flex flex-row items-start">
<div class="w-[12rem] scale-110 mt-2.5">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
<div class="w-[12rem] scale-110 !h-[35px] mt-2.5">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" class="!text-gray-600" :column="col" />
<LazySmartsheetHeaderCell v-else :column="col" />
<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 border-gray-200 px-1 min-h-[35px] flex items-center relative"
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" />
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="_row.row[col.title]" :row="_row" :column="col" />
<LazySmartsheetCell
v-else
v-model="row.row[col.title]"
v-model="_row.row[col.title]"
:column="col"
:edit-enabled="true"
:active="true"

1
packages/nc-gui/components/smartsheet/grid/index.vue

@ -241,7 +241,6 @@ onMounted(() => {
<SmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="routeQuery.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"

6
packages/nc-gui/components/smartsheet/header/Cell.vue

@ -74,7 +74,11 @@ const openDropDown = () => {
<div
v-if="column"
class="name pl-1"
:class="{ 'cursor-pointer pt-0.25': !isForm && isUIAllowed('fieldEdit') && !hideMenu }"
:class="{
'cursor-pointer pt-0.25': !isForm && isUIAllowed('fieldEdit') && !hideMenu && !isExpandedForm,
'cursor-default': isForm || !isUIAllowed('fieldEdit') || hideMenu,
'!truncate': !isForm,
}"
:data-test-id="column.title"
>
{{ column.title }}

14
packages/nc-gui/components/smartsheet/header/VirtualCell.vue

@ -123,22 +123,14 @@ const closeAddColumnDropdown = () => {
</script>
<template>
<div
class="flex items-center w-full text-xs text-gray-500 font-weight-medium"
:class="{ 'h-full': column }"
@click.right="isDropDownOpen = !isDropDownOpen"
>
<div class="flex items-center w-full text-xs text-gray-500 font-weight-medium" @click.right="isDropDownOpen = !isDropDownOpen">
<LazySmartsheetHeaderVirtualCellIcon v-if="column && !props.hideIcon" />
<a-tooltip placement="bottom">
<template #title>
<template v-if="!isForm && !isExpandedForm" #title>
{{ tooltipMsg }}
</template>
<span
class="name pl-1"
:class="{ 'truncate': !isForm || !isExpandedForm, 'whitespace-pre-line': isForm || isExpandedForm }"
:data-test-id="column.title"
>
<span class="name truncate pl-1" :class="{ truncate: !isForm }" :data-test-id="column.title">
{{ column.title }}
</span>
</a-tooltip>

1
packages/nc-gui/components/tabs/Smartsheet.vue

@ -190,7 +190,6 @@ watch([activeViewTitleOrId, activeTableId], () => {
</div>
<SmartsheetDetails v-else />
</div>
<LazySmartsheetExpandedFormDetached />
</div>
</template>

3
packages/nc-gui/composables/useExpandedFormStore.ts

@ -24,7 +24,7 @@ import {
} from '#imports'
import type { Row } from '#imports'
const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((meta: Ref<TableType>, row: Ref<Row>) => {
const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((meta: Ref<TableType>, _row: Ref<Row>) => {
const { $e, $state, $api } = useNuxtApp()
const { api, isLoading: isCommentsLoading, error: commentsError } = useApi()
@ -44,6 +44,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
const changedColumns = ref(new Set<string>())
const { base } = storeToRefs(useBase())
const row = ref<Row>(_row.value.rowMeta.new ? _row.value : ({ row: {}, oldRow: {}, rowMeta: {} } as Row))
const rowStore = useProvideSmartsheetRowStore(meta, row)

12
packages/nc-gui/utils/dataUtils.ts

@ -4,13 +4,11 @@ import type { Row } from 'lib'
import { isColumnRequiredAndNull } from './columnUtils'
export const extractPkFromRow = (row: Record<string, any>, columns: ColumnType[]) => {
return (
row &&
columns
?.filter((c) => c.pk)
.map((c) => row?.[c.title as string])
.join('___')
)
if (!row || !columns) return null
return columns
.filter((c) => c.pk)
.map((c) => row?.[c.title as string])
.join('___')
}
export const rowPkData = (row: Record<string, any>, columns: ColumnType[]) => {

3
packages/nocodb/src/services/audits.service.ts

@ -93,6 +93,9 @@ export class AuditsService {
);
const log = await Audit.get(param.auditId);
if (log.op_type !== AuditOperationTypes.COMMENT) {
NcError.forbidden('Only comments can be updated');
}
if (log.user !== param.userEmail) {
NcError.unauthorized('Unauthorized access');

Loading…
Cancel
Save