Browse Source

Merge pull request #5918 from nocodb/fix/various-multi-select

fix: various fixes for UI
test/shared-form-select-field
mertmit 1 year ago committed by GitHub
parent
commit
05ea19157b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      packages/nc-gui/components/cell/MultiSelect.vue
  2. 1
      packages/nc-gui/components/cell/SingleSelect.vue
  3. 11
      packages/nc-gui/components/smartsheet/Grid.vue
  4. 70
      packages/nc-gui/composables/useMultiSelect/index.ts

10
packages/nc-gui/components/cell/MultiSelect.vue

@ -316,10 +316,10 @@ const handleClose = (e: MouseEvent) => {
useEventListener(document, 'click', handleClose, true) useEventListener(document, 'click', handleClose, true)
const selectedOpts = computed(() => { const selectedOpts = computed(() => {
return options.value.reduce<(SelectOptionType & { index: number })[]>((selectedOptions, option) => { return vModel.value.reduce<SelectOptionType[]>((selectedOptions, option) => {
const index = vModel.value.indexOf(option.value!) const selectedOption = options.value.find((o) => o.value === option)
if (index !== -1) { if (selectedOption) {
selectedOptions.push({ ...option, index }) selectedOptions.push(selectedOption)
} }
return selectedOptions return selectedOptions
}, []) }, [])
@ -340,7 +340,7 @@ const selectedOpts = computed(() => {
}" }"
> >
<template v-for="selectedOpt of selectedOpts" :key="selectedOpt.value"> <template v-for="selectedOpt of selectedOpts" :key="selectedOpt.value">
<a-tag class="rounded-tag" :color="selectedOpt.color" :style="{ order: selectedOpt.index }"> <a-tag class="rounded-tag" :color="selectedOpt.color">
<span <span
:style="{ :style="{
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' }) 'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })

1
packages/nc-gui/components/cell/SingleSelect.vue

@ -8,7 +8,6 @@ import {
ActiveCellInj, ActiveCellInj,
CellClickHookInj, CellClickHookInj,
ColumnInj, ColumnInj,
EditModeInj,
IsFormInj, IsFormInj,
IsKanbanInj, IsKanbanInj,
ReadonlyInj, ReadonlyInj,

11
packages/nc-gui/components/smartsheet/Grid.vue

@ -97,6 +97,7 @@ const contextMenu = computed({
} }
}, },
}) })
const contextMenuClosing = ref(false)
const routeQuery = $computed(() => route.query as Record<string, string>) const routeQuery = $computed(() => route.query as Record<string, string>)
const contextMenuTarget = ref<{ row: number; col: number } | null>(null) const contextMenuTarget = ref<{ row: number; col: number } | null>(null)
@ -209,6 +210,7 @@ const {
data, data,
$$(editEnabled), $$(editEnabled),
isPkAvail, isPkAvail,
contextMenu,
clearCell, clearCell,
clearSelectedRangeOfCells, clearSelectedRangeOfCells,
makeEditable, makeEditable,
@ -479,7 +481,10 @@ defineExpose({
// reset context menu target on hide // reset context menu target on hide
watch(contextMenu, () => { watch(contextMenu, () => {
if (!contextMenu.value) { if (!contextMenu.value) {
contextMenuClosing.value = true
contextMenuTarget.value = null contextMenuTarget.value = null
} else {
contextMenuClosing.value = false
} }
}) })
@ -1041,7 +1046,7 @@ function addEmptyRow(row?: number) {
:data-col="columnObj.id" :data-col="columnObj.id"
:data-title="columnObj.title" :data-title="columnObj.title"
@mousedown="handleMouseDown($event, rowIndex, colIndex)" @mousedown="handleMouseDown($event, rowIndex, colIndex)"
@mouseover="handleMouseOver(rowIndex, colIndex)" @mouseover="handleMouseOver($event, rowIndex, colIndex)"
@click="handleCellClick($event, rowIndex, colIndex)" @click="handleCellClick($event, rowIndex, colIndex)"
@dblclick="makeEditable(row, columnObj)" @dblclick="makeEditable(row, columnObj)"
@contextmenu="showContextMenu($event, { row: rowIndex, col: colIndex })" @contextmenu="showContextMenu($event, { row: rowIndex, col: colIndex })"
@ -1115,7 +1120,7 @@ function addEmptyRow(row?: number) {
</div> </div>
</a-menu-item> </a-menu-item>
<a-menu-item v-if="data.some((r) => r.rowMeta.selected)" @click="deleteSelectedRows"> <a-menu-item v-if="!contextMenuClosing && data.some((r) => r.rowMeta.selected)" @click="deleteSelectedRows">
<div v-e="['a:row:delete-bulk']" class="nc-project-menu-item"> <div v-e="['a:row:delete-bulk']" class="nc-project-menu-item">
<!-- Delete Selected Rows --> <!-- Delete Selected Rows -->
{{ $t('activity.deleteSelectedRow') }} {{ $t('activity.deleteSelectedRow') }}
@ -1136,7 +1141,7 @@ function addEmptyRow(row?: number) {
</a-menu-item> </a-menu-item>
<!-- Clear cell --> <!-- Clear cell -->
<a-menu-item v-else @click="clearSelectedRangeOfCells()"> <a-menu-item v-else-if="contextMenuTarget" @click="clearSelectedRangeOfCells()">
<div v-e="['a:row:clear-range']" class="nc-project-menu-item">Clear Cells</div> <div v-e="['a:row:clear-range']" class="nc-project-menu-item">Clear Cells</div>
</a-menu-item> </a-menu-item>

70
packages/nc-gui/composables/useMultiSelect/index.ts

@ -1,4 +1,5 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import type { Ref } from 'vue'
import type { MaybeRef } from '@vueuse/core' import type { MaybeRef } from '@vueuse/core'
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { RelationTypes, UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
@ -39,6 +40,7 @@ export function useMultiSelect(
data: MaybeRef<Row[]>, data: MaybeRef<Row[]>,
_editEnabled: MaybeRef<boolean>, _editEnabled: MaybeRef<boolean>,
isPkAvail: MaybeRef<boolean | undefined>, isPkAvail: MaybeRef<boolean | undefined>,
contextMenu: Ref<boolean>,
clearCell: Function, clearCell: Function,
clearSelectedRangeOfCells: Function, clearSelectedRangeOfCells: Function,
makeEditable: Function, makeEditable: Function,
@ -81,6 +83,9 @@ export function useMultiSelect(
return return
} }
// disable edit mode if active cell is changed
editEnabled.value = false
activeCell.row = row activeCell.row = row
activeCell.col = col activeCell.col = col
} }
@ -207,13 +212,6 @@ export function useMultiSelect(
} }
} }
function handleMouseOver(row: number, col: number) {
if (!isMouseDown) {
return
}
selectedRange.endRange({ row, col })
}
function isCellSelected(row: number, col: number) { function isCellSelected(row: number, col: number) {
if (activeCell.col === col && activeCell.row === row) { if (activeCell.col === col && activeCell.row === row) {
return true return true
@ -231,6 +229,19 @@ export function useMultiSelect(
) )
} }
function handleMouseOver(event: MouseEvent, row: number, col: number) {
if (!isMouseDown) {
return
}
// extend the selection and scroll to the cell
selectedRange.endRange({ row, col })
scrollToCell?.(row, col)
// avoid selecting text
event.preventDefault()
}
function handleMouseDown(event: MouseEvent, row: number, col: number) { function handleMouseDown(event: MouseEvent, row: number, col: number) {
// if there was a right click on selected range, don't restart the selection // if there was a right click on selected range, don't restart the selection
if ( if (
@ -240,11 +251,26 @@ export function useMultiSelect(
return return
} }
isMouseDown = true // if edit is enabled, don't start the selection (some cells shrink after edit mode, which causes the selection to expand if flag is set)
if (!editEnabled.value) isMouseDown = true
// if shift key is pressed, don't restart the selection contextMenu.value = false
if (event.shiftKey) return
// avoid text selection
event.preventDefault()
// if shift key is pressed, extend the selection
if (event.shiftKey) {
// if shift key is pressed, don't restart the selection (unless there is no active cell)
if (activeCell.col === null || activeCell.row === null) {
selectedRange.startRange({ row, col })
}
selectedRange.endRange({ row, col })
return
}
// start a new selection
selectedRange.startRange({ row, col }) selectedRange.startRange({ row, col })
if (activeCell.row !== row || activeCell.col !== col) { if (activeCell.row !== row || activeCell.col !== col) {
@ -255,42 +281,26 @@ export function useMultiSelect(
} }
const handleCellClick = (event: MouseEvent, row: number, col: number) => { const handleCellClick = (event: MouseEvent, row: number, col: number) => {
isMouseDown = true // if shift key is pressed, don't change the active cell (unless there is no active cell)
// if shift key is pressed, prevent selecting text
if (event.shiftKey && !unref(editEnabled)) {
event.preventDefault()
}
// if shift key is pressed, don't restart the selection (unless there is no active cell)
if (!event.shiftKey || activeCell.col === null || activeCell.row === null) { if (!event.shiftKey || activeCell.col === null || activeCell.row === null) {
selectedRange.startRange({ row, col })
makeActive(row, col) makeActive(row, col)
} }
selectedRange.endRange({ row, col })
scrollToCell?.(row, col) scrollToCell?.(row, col)
isMouseDown = false
} }
const handleMouseUp = (event: MouseEvent) => { const handleMouseUp = (_event: MouseEvent) => {
if (isMouseDown) { if (isMouseDown) {
isMouseDown = false isMouseDown = false
// timeout is needed, because we want to set cell as active AFTER all the child's click handler's called // timeout is needed, because we want to set cell as active AFTER all the child's click handler's called
// this is needed e.g. for date field edit, where two clicks had to be done - one to select cell, and another one to open date dropdown // this is needed e.g. for date field edit, where two clicks had to be done - one to select cell, and another one to open date dropdown
setTimeout(() => { setTimeout(() => {
// if shift key is pressed, don't change the active cell
if (event.shiftKey) return
if (selectedRange._start) { if (selectedRange._start) {
if (activeCell.row !== selectedRange._start.row || activeCell.col !== selectedRange._start.col) {
makeActive(selectedRange._start.row, selectedRange._start.col) makeActive(selectedRange._start.row, selectedRange._start.col)
} }
}, 0)
// if the editEnabled is false, prevent selecting text on mouseUp
if (!unref(editEnabled)) {
event.preventDefault()
} }
}, 0)
} }
} }

Loading…
Cancel
Save