Browse Source

Merge pull request #6922 from nocodb/nc-fix/grid-context-menu-shared-view

Added copy/cell selection in share view grid
pull/6930/head
Raju Udava 10 months ago committed by GitHub
parent
commit
2576e7df1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      packages/nc-gui/components/cell/DatePicker.vue
  2. 10
      packages/nc-gui/components/cell/DateTimePicker.vue
  3. 8
      packages/nc-gui/components/cell/TimePicker.vue
  4. 8
      packages/nc-gui/components/cell/YearPicker.vue
  5. 65
      packages/nc-gui/components/smartsheet/grid/Table.vue
  6. 2
      packages/nc-gui/composables/useMultiSelect/index.ts
  7. 8
      tests/playwright/pages/Dashboard/common/Cell/index.ts

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

@ -185,6 +185,14 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
}
})
const isOpen = computed(() => {
if (readOnly.value) return false
return ((readOnly.value || (localState.value && isPk)) && !active.value && !editable.value) || isLockedMode.value
? false
: open.value
})
// use the default date picker open sync only to close the picker
const updateOpen = (next: boolean) => {
if (open.value && !next) {
@ -222,7 +230,7 @@ const clickHandler = () => {
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-date ${open ? 'active' : ''}`"
:open="((readOnly || (localState && isPk)) && !active && !editable) || isLockedMode ? false : open"
:open="isOpen"
@click="clickHandler"
@update:open="updateOpen"
>

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

@ -123,6 +123,14 @@ const localState = computed({
const open = ref(false)
const isOpen = computed(() => {
if (readOnly.value) return false
return readOnly.value || (localState.value && isPk) || isLockedMode.value
? false
: open.value && (active.value || editable.value)
})
const randomClass = `picker_${Math.floor(Math.random() * 99999)}`
watch(
open,
@ -270,7 +278,7 @@ const isColDisabled = computed(() => {
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-datetime ${open ? 'active' : ''}`"
:open="readOnly || (localState && isPk) || isLockedMode ? false : open && (active || editable)"
:open="isOpen"
@click="clickHandler"
@ok="open = !open"
>

8
packages/nc-gui/components/cell/TimePicker.vue

@ -101,6 +101,12 @@ const placeholder = computed(() => {
}
})
const isOpen = computed(() => {
if (readOnly.value) return false
return (readOnly.value || (localState.value && isPk)) && !active.value && !editable.value ? false : open.value
})
useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
switch (e.key) {
case 'Enter':
@ -129,7 +135,7 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
:placeholder="placeholder"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:open="(readOnly || (localState && isPk)) && !active && !editable ? false : open"
:open="isOpen"
:popup-class-name="`${randomClass} nc-picker-time ${open ? 'active' : ''}`"
@click="open = (active || editable) && !open"
@ok="open = !open"

8
packages/nc-gui/components/cell/YearPicker.vue

@ -88,6 +88,12 @@ const placeholder = computed(() => {
}
})
const isOpen = computed(() => {
if (readOnly.value) return false
return (readOnly.value || (localState.value && isPk)) && !active.value && !editable.value ? false : open.value
})
useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
switch (e.key) {
case 'Enter':
@ -114,7 +120,7 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
:placeholder="placeholder"
:allow-clear="(!readOnly && !localState && !isPk) || isEditColumn"
:input-read-only="true"
:open="(readOnly || (localState && isPk)) && !active && !editable ? false : open"
:open="isOpen"
:dropdown-class-name="`${randomClass} nc-picker-year ${open ? 'active' : ''}`"
@click="open = (active || editable) && !open"
@change="open = (active || editable) && !open"

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

@ -181,7 +181,7 @@ const gridRect = useElementBounding(gridWrapper)
// #Permissions
const { isUIAllowed } = useRoles()
const hasEditPermission = computed(() => isUIAllowed('dataEdit'))
const hasEditPermission = computed(() => isUIAllowed('dataEdit') && !isLocked.value)
const isAddingColumnAllowed = computed(() => !readOnly.value && !isLocked.value && isUIAllowed('fieldAdd') && !isSqlView.value)
const { onDrag, onDragStart, draggedCol, dragColPlaceholderDomRef, toBeDroppedColId } = useColumnDrag({
@ -223,9 +223,7 @@ const _contextMenu = ref(false)
const contextMenu = computed({
get: () => _contextMenu.value,
set: (val) => {
if (hasEditPermission.value) {
_contextMenu.value = val
}
_contextMenu.value = val
},
})
const contextMenuClosing = ref(false)
@ -1549,14 +1547,12 @@ onKeyStroke('ArrowDown', onDown)
<SmartsheetTableDataCell
v-for="(columnObj, colIndex) of fields"
:key="columnObj.id"
class="cell relative nc-grid-cell"
class="cell relative nc-grid-cell cursor-pointer"
:class="{
'cursor-pointer': hasEditPermission,
'active': hasEditPermission && isCellSelected(rowIndex, colIndex),
'active': isCellSelected(rowIndex, colIndex),
'active-cell':
hasEditPermission &&
((activeCell.row === rowIndex && activeCell.col === colIndex) ||
(selectedRange._start?.row === rowIndex && selectedRange._start?.col === colIndex)),
(activeCell.row === rowIndex && activeCell.col === colIndex) ||
(selectedRange._start?.row === rowIndex && selectedRange._start?.col === colIndex),
'last-cell':
rowIndex === (isNaN(selectedRange.end.row) ? activeCell.row : selectedRange.end.row) &&
colIndex === (isNaN(selectedRange.end.col) ? activeCell.col : selectedRange.end.col),
@ -1594,7 +1590,7 @@ onKeyStroke('ArrowDown', onDown)
:column="columnObj"
:active="activeCell.col === colIndex && activeCell.row === rowIndex"
:row="row"
:read-only="readOnly"
:read-only="!hasEditPermission"
@navigate="onNavigate"
@save="updateOrSaveRow?.(row, '', state)"
/>
@ -1608,7 +1604,7 @@ onKeyStroke('ArrowDown', onDown)
"
:row-index="rowIndex"
:active="activeCell.col === colIndex && activeCell.row === rowIndex"
:read-only="readOnly"
:read-only="!hasEditPermission"
@update:edit-enabled="editEnabled = $event"
@save="updateOrSaveRow?.(row, columnObj.title, state)"
@navigate="onNavigate"
@ -1658,7 +1654,7 @@ onKeyStroke('ArrowDown', onDown)
/>
</div>
<template v-if="!isLocked && hasEditPermission" #overlay>
<template #overlay>
<NcMenu class="!rounded !py-0" @click="contextMenu = false">
<NcMenuItem
v-if="isEeUI && !contextMenuClosing && !contextMenuTarget && data.some((r) => r.rowMeta.selected)"
@ -1709,6 +1705,7 @@ onKeyStroke('ArrowDown', onDown)
<NcMenuItem
v-if="
contextMenuTarget &&
hasEditPermission &&
selectedRange.isSingleCell() &&
(isLinksOrLTAR(fields[contextMenuTarget.col]) || !isVirtualCol(fields[contextMenuTarget.col]))
"
@ -1722,7 +1719,7 @@ onKeyStroke('ArrowDown', onDown)
<!-- Clear cell -->
<NcMenuItem
v-else-if="contextMenuTarget"
v-else-if="contextMenuTarget && hasEditPermission"
v-e="['a:row:clear-range']"
class="nc-base-menu-item"
@click="clearSelectedRangeOfCells()"
@ -1731,7 +1728,9 @@ onKeyStroke('ArrowDown', onDown)
{{ $t('general.clear') }}
</NcMenuItem>
<template v-if="contextMenuTarget && selectedRange.isSingleCell() && isUIAllowed('commentEdit') && !isMobileMode">
<template
v-if="contextMenuTarget && !isLocked && selectedRange.isSingleCell() && isUIAllowed('commentEdit') && !isMobileMode"
>
<NcDivider />
<NcMenuItem v-e="['a:row:comment']" class="nc-base-menu-item" @click="commentRow(contextMenuTarget.row)">
<MdiMessageOutline class="h-4 w-4" />
@ -1739,28 +1738,30 @@ onKeyStroke('ArrowDown', onDown)
{{ $t('general.comment') }}
</NcMenuItem>
</template>
<NcDivider v-if="!(!contextMenuClosing && !contextMenuTarget && data.some((r) => r.rowMeta.selected))" />
<NcMenuItem
v-if="contextMenuTarget && (selectedRange.isSingleCell() || selectedRange.isSingleRow())"
v-e="['a:row:delete']"
class="nc-base-menu-item !text-red-600 !hover:bg-red-50"
@click="confirmDeleteRow(contextMenuTarget.row)"
>
<GeneralIcon icon="delete" />
<!-- Delete Row -->
{{ $t('activity.deleteRow') }}
</NcMenuItem>
<div v-else-if="contextMenuTarget && deleteRangeOfRows">
<template v-if="hasEditPermission">
<NcDivider v-if="!(!contextMenuClosing && !contextMenuTarget && data.some((r) => r.rowMeta.selected))" />
<NcMenuItem
v-if="contextMenuTarget && (selectedRange.isSingleCell() || selectedRange.isSingleRow())"
v-e="['a:row:delete']"
class="nc-base-menu-item !text-red-600 !hover:bg-red-50"
@click="deleteSelectedRangeOfRows"
@click="confirmDeleteRow(contextMenuTarget.row)"
>
<GeneralIcon icon="delete" class="text-gray-500 text-red-600" />
<!-- Delete Rows -->
{{ $t('activity.deleteRows') }}
<GeneralIcon icon="delete" />
<!-- Delete Row -->
{{ $t('activity.deleteRow') }}
</NcMenuItem>
</div>
<div v-else-if="contextMenuTarget && deleteRangeOfRows">
<NcMenuItem
v-e="['a:row:delete']"
class="nc-base-menu-item !text-red-600 !hover:bg-red-50"
@click="deleteSelectedRangeOfRows"
>
<GeneralIcon icon="delete" class="text-gray-500 text-red-600" />
<!-- Delete Rows -->
{{ $t('activity.deleteRows') }}
</NcMenuItem>
</div>
</template>
</NcMenu>
</template>
</NcDropdown>

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

@ -116,6 +116,8 @@ export function useMultiSelect(
if (typeof textToCopy === 'object') {
textToCopy = JSON.stringify(textToCopy)
} else {
textToCopy = textToCopy.toString()
}
if (columnObj.uidt === UITypes.Formula) {

8
tests/playwright/pages/Dashboard/common/Cell/index.ts

@ -381,25 +381,25 @@ export class CellPageObject extends BasePage {
async verifyRoleAccess(param: { role: string }) {
const role = param.role.toLowerCase();
const count = role === 'creator' || role === 'editor' || role === 'owner' ? 1 : 0;
const isEditAccess = role === 'creator' || role === 'editor' || role === 'owner';
// normal text cell
const cell = this.get({ index: 0, columnHeader: 'Country' });
// editable cell
await cell.dblclick();
await expect(cell.locator(`input`)).toHaveCount(count);
await expect(cell.locator(`input`)).toHaveCount(isEditAccess ? 1 : 0);
// press escape to close the input
await cell.press('Escape');
await cell.press('Escape');
await cell.click({ button: 'right', clickCount: 1 });
await expect(this.rootPage.locator(`.nc-dropdown-grid-context-menu:visible`)).toHaveCount(count);
await expect(this.rootPage.locator(`.nc-dropdown-grid-context-menu:visible`)).toHaveCount(1);
// virtual cell
const vCell = this.get({ index: 0, columnHeader: 'Cities' });
await vCell.hover();
// in-cell add
await expect(vCell.locator('.nc-action-icon.nc-plus:visible')).toHaveCount(count);
await expect(vCell.locator('.nc-action-icon.nc-plus:visible')).toHaveCount(isEditAccess ? 1 : 0);
// virtual cell link text
const linkText = await getTextExcludeIconText(vCell);

Loading…
Cancel
Save