Browse Source

Merge pull request #7376 from nocodb/nc-fix/multifield-editor-issues

Multifield editor bug fixes ( Sync EE to OSS )
pull/7394/head
Raju Udava 10 months ago committed by GitHub
parent
commit
977cceb271
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui/components/smartsheet/VirtualCell.vue
  2. 147
      packages/nc-gui/components/smartsheet/details/Fields.vue
  3. 2
      packages/nc-gui/components/smartsheet/grid/GroupByLabel.vue
  4. 2
      packages/nc-gui/components/tabs/Smartsheet.vue
  5. 3
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  6. 2
      packages/nc-gui/components/virtual-cell/components/ListItems.vue
  7. 10
      packages/nc-gui/composables/useLTARStore.ts
  8. 26
      packages/nocodb/src/services/columns.service.ts

2
packages/nc-gui/components/smartsheet/VirtualCell.vue

@ -20,11 +20,11 @@ import {
isLink, isLink,
isLookup, isLookup,
isMm, isMm,
isPrimary,
isQrCode, isQrCode,
isRollup, isRollup,
provide, provide,
toRef, toRef,
isPrimary,
} from '#imports' } from '#imports'
import type { Row } from '#imports' import type { Row } from '#imports'

147
packages/nc-gui/components/smartsheet/details/Fields.vue

@ -100,6 +100,7 @@ const fields = computed<TableExplorerColumn[]>({
const x = ((meta.value?.columns as ColumnType[]) ?? []) const x = ((meta.value?.columns as ColumnType[]) ?? [])
.filter((field) => !field.fk_column_id && !isSystemColumn(field)) .filter((field) => !field.fk_column_id && !isSystemColumn(field))
.concat(newFields.value) .concat(newFields.value)
.map((field) => updateDefaultColumnValues(field))
.sort((a, b) => { .sort((a, b) => {
return getFieldOrder(a) - getFieldOrder(b) return getFieldOrder(a) - getFieldOrder(b)
}) })
@ -268,8 +269,30 @@ const duplicateField = async (field: TableExplorerColumn) => {
const onFieldUpdate = (state: TableExplorerColumn) => { const onFieldUpdate = (state: TableExplorerColumn) => {
const col = fields.value.find((col) => compareCols(col, state)) const col = fields.value.find((col) => compareCols(col, state))
if (!col) return if (!col) return
const diffs = diff(col, state) const diffs = diff(col, state)
if (Object.keys(diffs).length === 0 || (Object.keys(diffs).length === 1 && 'altered' in diffs)) {
// hack to prevent update status `Updated Field` when clicking on field first time
let isUpdated = true
if (
[UITypes.SingleSelect, UITypes.MultiSelect].includes(col.uidt) &&
Object.keys(diffs).length === 1 &&
diffs?.colOptions?.options &&
(diffs?.colOptions?.options?.length === 0 ||
(diffs?.colOptions?.options[0]?.index !== undefined && Object.keys(diffs?.colOptions?.options[0] || {}).length === 1))
) {
isUpdated = false
}
if (!isUpdated) {
let field = fields.value.find((field) => compareCols(field, state))
if (field) {
field = state
}
}
if (Object.keys(diffs).length === 0 || (Object.keys(diffs).length === 1 && 'altered' in diffs) || !isUpdated) {
ops.value = ops.value.filter((op) => op.op === 'add' || !compareCols(op.column, state)) ops.value = ops.value.filter((op) => op.op === 'add' || !compareCols(op.column, state))
} else { } else {
const field = ops.value.find((op) => compareCols(op.column, state)) const field = ops.value.find((op) => compareCols(op.column, state))
@ -291,7 +314,7 @@ const onFieldUpdate = (state: TableExplorerColumn) => {
return return
} }
if (field && !moveField) { if (field || (field && moveField)) {
field.column = state field.column = state
} else { } else {
ops.value.push({ ops.value.push({
@ -376,6 +399,19 @@ const onMove = (_event: { moved: { newIndex: number; oldIndex: number } }) => {
return return
} }
const mop = moveOps.value.find((op) => compareCols(op.column, fields.value[_event.moved.oldIndex]))
if (mop) {
mop.index = _event.moved.newIndex
mop.order = order
} else {
moveOps.value.push({
op: 'move',
column: fields.value[_event.moved.oldIndex],
index: _event.moved.newIndex,
order,
})
}
if (op) { if (op) {
onFieldUpdate({ onFieldUpdate({
...op.column, ...op.column,
@ -393,19 +429,6 @@ const onMove = (_event: { moved: { newIndex: number; oldIndex: number } }) => {
}, },
}) })
} }
const mop = moveOps.value.find((op) => compareCols(op.column, fields.value[_event.moved.oldIndex]))
if (mop) {
mop.index = _event.moved.newIndex
mop.order = order
} else {
moveOps.value.push({
op: 'move',
column: fields.value[_event.moved.oldIndex],
index: _event.moved.newIndex,
order,
})
}
} }
const isColumnValid = (column: TableExplorerColumn) => { const isColumnValid = (column: TableExplorerColumn) => {
@ -438,6 +461,52 @@ const isColumnValid = (column: TableExplorerColumn) => {
return true return true
} }
function updateDefaultColumnValues(column: TableExplorerColumn) {
if (column.uidt === UITypes.QrCode && column.colOptions?.fk_qr_value_column_id) {
if (!column?.fk_qr_value_column_id) {
column.fk_qr_value_column_id = column.colOptions.fk_qr_value_column_id
}
}
if (column.uidt === UITypes.Barcode && column.colOptions?.fk_barcode_value_column_id) {
if (!column?.fk_barcode_value_column_id) {
column.fk_barcode_value_column_id = column.colOptions.fk_barcode_value_column_id
}
}
if (column.uidt === UITypes.Lookup && column?.colOptions?.fk_lookup_column_id && column?.colOptions?.fk_relation_column_id) {
if (!column?.fk_lookup_column_id) {
column.fk_lookup_column_id = column.colOptions.fk_lookup_column_id
}
if (!column?.fk_relation_column_id) {
column.fk_relation_column_id = column.colOptions.fk_relation_column_id
}
}
if (
column.uidt === UITypes.Rollup &&
column?.colOptions?.fk_relation_column_id &&
column?.colOptions?.fk_rollup_column_id &&
column?.colOptions?.rollup_function
) {
if (!column?.fk_relation_column_id) {
column.fk_relation_column_id = column.colOptions.fk_relation_column_id
}
if (!column?.fk_rollup_column_id) {
column.fk_rollup_column_id = column.colOptions.fk_rollup_column_id
}
if (!column?.rollup_function) {
column.rollup_function = column.colOptions.rollup_function
}
}
if (column.uidt === UITypes.Formula && column.colOptions?.formula_raw && !column?.formula_raw) {
column.formula_raw = column.colOptions?.formula_raw
}
return column
}
const recoverField = (state: TableExplorerColumn) => { const recoverField = (state: TableExplorerColumn) => {
const field = ops.value.find((op) => compareCols(op.column, state)) const field = ops.value.find((op) => compareCols(op.column, state))
if (field) { if (field) {
@ -512,10 +581,13 @@ const saveChanges = async () => {
view_id: view.value?.id as string, view_id: view.value?.id as string,
} }
} }
}
for (const f of fields.value) { if (op && op.op === 'update') {
console.log(f.title, getFieldOrder(f)) op.column.column_order = {
order: mop.order,
view_id: view.value?.id as string,
}
}
} }
for (const op of ops.value) { for (const op of ops.value) {
@ -545,7 +617,10 @@ const saveChanges = async () => {
await loadViewColumns() await loadViewColumns()
if (res) { if (res) {
ops.value = (res.failedOps as op[]) || [] ops.value =
res.failedOps && res.failedOps?.length
? (res.failedOps as (op & { error: unknown })[]).map(({ error: _, ...rest }) => rest)
: []
newFields.value = newFields.value.filter((col) => { newFields.value = newFields.value.filter((col) => {
if (res.failedOps) { if (res.failedOps) {
const op = res.failedOps.find((fop) => { const op = res.failedOps.find((fop) => {
@ -631,8 +706,14 @@ onKeyDown('ArrowUp', () => {
onKeyDown('Delete', () => { onKeyDown('Delete', () => {
if (isLocked.value) return if (isLocked.value) return
if (document.activeElement?.tagName === 'INPUT') return if (
if (document.activeElement?.tagName === 'TEXTAREA') return document.activeElement?.tagName === 'INPUT' ||
document.activeElement?.tagName === 'TEXTAREA' ||
// A rich text editor is a div with the contenteditable attribute set to true.
document.activeElement?.getAttribute('contenteditable')
) {
return
}
const isDeletedField = fieldStatus(activeField.value) === 'delete' const isDeletedField = fieldStatus(activeField.value) === 'delete'
if (!isDeletedField && activeField.value) { if (!isDeletedField && activeField.value) {
@ -643,8 +724,14 @@ onKeyDown('Delete', () => {
onKeyDown('Backspace', () => { onKeyDown('Backspace', () => {
if (isLocked.value) return if (isLocked.value) return
if (document.activeElement?.tagName === 'INPUT') return if (
if (document.activeElement?.tagName === 'TEXTAREA') return document.activeElement?.tagName === 'INPUT' ||
document.activeElement?.tagName === 'TEXTAREA' ||
// A rich text editor is a div with the contenteditable attribute set to true.
document.activeElement?.getAttribute('contenteditable')
) {
return
}
const isDeletedField = fieldStatus(activeField.value) === 'delete' const isDeletedField = fieldStatus(activeField.value) === 'delete'
if (!isDeletedField && activeField.value) { if (!isDeletedField && activeField.value) {
@ -705,6 +792,16 @@ const onFieldOptionUpdate = () => {
isFieldIdCopied.value = false isFieldIdCopied.value = false
}, 200) }, 200)
} }
watch(
fields,
() => {
if (activeField.value) {
activeField.value = fields.value.find((field) => field.id === activeField.value.id) || activeField.value
}
},
{ deep: true },
)
</script> </script>
<template> <template>
@ -771,7 +868,7 @@ const onFieldOptionUpdate = () => {
</div> </div>
<div class="flex flex-row rounded-lg border-1 overflow-clip border-gray-200"> <div class="flex flex-row rounded-lg border-1 overflow-clip border-gray-200">
<div ref="fieldsListWrapperDomRef" class="nc-scrollbar-md !overflow-auto flex-1 flex-grow-1 nc-fields-height"> <div ref="fieldsListWrapperDomRef" class="nc-scrollbar-md !overflow-auto flex-1 flex-grow-1 nc-fields-height">
<Draggable v-model="fields" :disabled="isLocked" item-key="id" @change="onMove($event)"> <Draggable :model-value="fields" :disabled="isLocked" item-key="id" @change="onMove($event)">
<template #item="{ element: field }"> <template #item="{ element: field }">
<div <div
v-if="field.title.toLowerCase().includes(searchQuery.toLowerCase()) && !field.pv" v-if="field.title.toLowerCase().includes(searchQuery.toLowerCase()) && !field.pv"
@ -1080,7 +1177,7 @@ const onFieldOptionUpdate = () => {
</template> </template>
</Draggable> </Draggable>
</div> </div>
<Transition v-if="!changingField" name="slide-fade"> <Transition name="slide-fade">
<div v-if="!changingField" class="border-gray-200 border-l-1 nc-scrollbar-md nc-fields-height !overflow-y-auto"> <div v-if="!changingField" class="border-gray-200 border-l-1 nc-scrollbar-md nc-fields-height !overflow-y-auto">
<SmartsheetColumnEditOrAddProvider <SmartsheetColumnEditOrAddProvider
v-if="activeField" v-if="activeField"

2
packages/nc-gui/components/smartsheet/grid/GroupByLabel.vue

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ColumnType } from 'nocodb-sdk' import type { ColumnType } from 'nocodb-sdk'
import { isVirtualCol } from 'nocodb-sdk' import { isVirtualCol } from 'nocodb-sdk'
import { ReadonlyInj, IsGroupByLabelInj } from '#imports' import { IsGroupByLabelInj, ReadonlyInj } from '#imports'
defineProps<{ defineProps<{
column: ColumnType column: ColumnType

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

@ -87,7 +87,7 @@ const onDrop = async (event: DragEvent) => {
event.preventDefault() event.preventDefault()
try { try {
// Access the dropped data // Access the dropped data
const data = JSON.parse(event.dataTransfer!.getData('text/json')) const data = JSON.parse(event.dataTransfer!.getData('text/json') || '{}')
// Do something with the received data // Do something with the received data
// if dragged item is not from the same source, return // if dragged item is not from the same source, return

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

@ -55,10 +55,9 @@ const {
isChildrenListLinked, isChildrenListLinked,
isChildrenLoading, isChildrenLoading,
relatedTableMeta, relatedTableMeta,
row,
link, link,
meta, meta,
headerDisplayValue headerDisplayValue,
} = useLTARStoreOrThrow() } = useLTARStoreOrThrow()
const { isNew, state, removeLTARRef, addLTARRef } = useSmartsheetRowStoreOrThrow() const { isNew, state, removeLTARRef, addLTARRef } = useSmartsheetRowStoreOrThrow()

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

@ -49,7 +49,7 @@ const {
meta, meta,
unlink, unlink,
row, row,
headerDisplayValue headerDisplayValue,
} = useLTARStoreOrThrow() } = useLTARStoreOrThrow()
const { addLTARRef, isNew, removeLTARRef, state: rowState } = useSmartsheetRowStoreOrThrow() const { addLTARRef, isNew, removeLTARRef, state: rowState } = useSmartsheetRowStoreOrThrow()

10
packages/nc-gui/composables/useLTARStore.ts

@ -1,13 +1,13 @@
import { import {
UITypes,
type ColumnType, type ColumnType,
type LinkToAnotherRecordType, type LinkToAnotherRecordType,
type PaginatedType, type PaginatedType,
type RequestParams, type RequestParams,
type TableType, type TableType,
UITypes,
dateFormats, dateFormats,
timeFormats,
parseStringDateTime, parseStringDateTime,
timeFormats,
} from 'nocodb-sdk' } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import { import {
@ -19,6 +19,7 @@ import {
extractSdkResponseErrorMsg, extractSdkResponseErrorMsg,
inject, inject,
message, message,
parseProp,
reactive, reactive,
ref, ref,
storeToRefs, storeToRefs,
@ -30,7 +31,6 @@ import {
useRouter, useRouter,
useSharedView, useSharedView,
watch, watch,
parseProp,
} from '#imports' } from '#imports'
import type { Row } from '#imports' import type { Row } from '#imports'
@ -145,7 +145,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
type: '', type: '',
format: '', format: '',
} }
let currentColumn = relatedTableMeta.value?.columns?.find((c) => c.pv) || relatedTableMeta?.value?.columns?.[0] const currentColumn = relatedTableMeta.value?.columns?.find((c) => c.pv) || relatedTableMeta?.value?.columns?.[0]
if (currentColumn) { if (currentColumn) {
if (currentColumn?.uidt === UITypes.DateTime) { if (currentColumn?.uidt === UITypes.DateTime) {
@ -545,7 +545,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
isChildrenExcludedLoading, isChildrenExcludedLoading,
deleteRelatedRow, deleteRelatedRow,
getRelatedTableRowId, getRelatedTableRowId,
headerDisplayValue headerDisplayValue,
} }
}, },
'ltar-store', 'ltar-store',

26
packages/nocodb/src/services/columns.service.ts

@ -52,6 +52,7 @@ import {
KanbanView, KanbanView,
Model, Model,
Source, Source,
View,
} from '~/models'; } from '~/models';
import Noco from '~/Noco'; import Noco from '~/Noco';
import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2';
@ -195,7 +196,8 @@ export class ColumnsService {
formula?: string; formula?: string;
formula_raw?: string; formula_raw?: string;
parsed_tree?: any; parsed_tree?: any;
}; } & Partial<Pick<ColumnReqType, 'column_order'>>;
if ( if (
isCreatedOrLastModifiedTimeCol(column) || isCreatedOrLastModifiedTimeCol(column) ||
[ [
@ -274,7 +276,29 @@ export class ColumnsService {
meta: colBody.meta, meta: colBody.meta,
}); });
} }
// handle reorder column for Links and LinkToAnotherRecord
if (
[UITypes.Links, UITypes.LinkToAnotherRecord].includes(
column.uidt,
) &&
colBody?.column_order &&
colBody.column_order?.order &&
colBody.column_order?.view_id
) {
const viewColumn = (
await View.getColumns(colBody.column_order.view_id)
).find((col) => col.fk_column_id === column.id);
await View.updateColumn(
colBody.column_order.view_id,
viewColumn.id,
{
order: colBody.column_order.order,
},
);
}
} }
await this.updateRollupOrLookup(colBody, column); await this.updateRollupOrLookup(colBody, column);
} else { } else {
NcError.notImplemented( NcError.notImplemented(

Loading…
Cancel
Save