Add progress indicators to all other bulk operations and select more modified cells

This commit is contained in:
Andrew Kingston 2024-06-23 20:55:00 +01:00
parent a84a56ae1b
commit 7a3eabc529
No known key found for this signature in database
5 changed files with 87 additions and 33 deletions

View File

@ -1,7 +1,8 @@
<script> <script>
import { Modal, ModalContent } from "@budibase/bbui" import { Modal, ModalContent, ProgressBar } from "@budibase/bbui"
import { getContext, onMount } from "svelte" import { getContext, onMount } from "svelte"
import { parseCellID } from "../lib/utils" import { parseCellID } from "../lib/utils"
import { sleep } from "../../../utils/utils"
const { const {
selectedRows, selectedRows,
@ -13,15 +14,20 @@
selectedRowCount, selectedRowCount,
selectedCells, selectedCells,
} = getContext("grid") } = getContext("grid")
const duration = 260
let rowsModal let rowsModal
let cellsModal let cellsModal
let processing = false
let progressPercentage = 0
$: rowsToDelete = Object.entries($selectedRows) $: rowsToDelete = Object.entries($selectedRows)
.map(entry => $rows.find(x => x._id === entry[0])) .map(entry => $rows.find(x => x._id === entry[0]))
.filter(x => x != null) .filter(x => x != null)
const handleBulkDeleteRequest = () => { const handleBulkDeleteRequest = () => {
progressPercentage = 0
menu.actions.close()
if ($selectedRowCount) { if ($selectedRowCount) {
rowsModal?.show() rowsModal?.show()
} else if ($selectedCellCount) { } else if ($selectedCellCount) {
@ -30,15 +36,18 @@
} }
const bulkDeleteRows = async () => { const bulkDeleteRows = async () => {
processing = true
const count = rowsToDelete.length const count = rowsToDelete.length
await rows.actions.deleteRows(rowsToDelete) await rows.actions.deleteRows(rowsToDelete, progress => {
progressPercentage = progress * 100
})
await sleep(duration)
$notifications.success(`Deleted ${count} row${count === 1 ? "" : "s"}`) $notifications.success(`Deleted ${count} row${count === 1 ? "" : "s"}`)
processing = false
// Ensure menu is closed, as we may have triggered this from there
menu.actions.close()
} }
const bulkDeleteCells = async () => { const bulkDeleteCells = async () => {
processing = true
let changeMap = {} let changeMap = {}
for (let row of $selectedCells) { for (let row of $selectedCells) {
for (let cellId of row) { for (let cellId of row) {
@ -49,10 +58,11 @@
changeMap[rowId][field] = null changeMap[rowId][field] = null
} }
} }
await rows.actions.bulkUpdate(changeMap) await rows.actions.bulkUpdate(changeMap, progress => {
progressPercentage = progress * 100
// Ensure menu is closed, as we may have triggered this from there })
menu.actions.close() await sleep(duration)
processing = false
} }
onMount(() => subscribe("request-bulk-delete", handleBulkDeleteRequest)) onMount(() => subscribe("request-bulk-delete", handleBulkDeleteRequest))
@ -68,6 +78,14 @@
> >
Are you sure you want to delete {$selectedRowCount} Are you sure you want to delete {$selectedRowCount}
row{$selectedRowCount === 1 ? "" : "s"}? row{$selectedRowCount === 1 ? "" : "s"}?
{#if processing}
<ProgressBar
size="L"
value={progressPercentage}
{duration}
width="100%"
/>
{/if}
</ModalContent> </ModalContent>
</Modal> </Modal>
@ -81,5 +99,13 @@
> >
Are you sure you want to delete {$selectedCellCount} Are you sure you want to delete {$selectedCellCount}
cell{$selectedCellCount === 1 ? "" : "s"}? cell{$selectedCellCount === 1 ? "" : "s"}?
{#if processing}
<ProgressBar
size="L"
value={progressPercentage}
{duration}
width="100%"
/>
{/if}
</ModalContent> </ModalContent>
</Modal> </Modal>

View File

@ -1,30 +1,51 @@
<script> <script>
import { Modal, ModalContent } from "@budibase/bbui" import { Modal, ModalContent, ProgressBar } from "@budibase/bbui"
import { getContext, onMount } from "svelte" import { getContext, onMount } from "svelte"
import { getCellID } from "../lib/utils" import { getCellID } from "../lib/utils"
import { sleep } from "../../../utils/utils"
const { const {
selectedRows, selectedRows,
rows, rows,
subscribe, subscribe,
focusedCellId,
stickyColumn,
columns,
selectedRowCount, selectedRowCount,
allVisibleColumns,
selectedCells,
} = getContext("grid") } = getContext("grid")
const duration = 260
let modal let modal
let progressPercentage = 0
let processing = false
// Deletion callback when confirmed // Deletion callback when confirmed
const performDuplication = async () => { const performDuplication = async () => {
progressPercentage = 0
processing = true
// duplicate rows
const rowsToDuplicate = Object.keys($selectedRows).map(id => { const rowsToDuplicate = Object.keys($selectedRows).map(id => {
return rows.actions.getRow(id) return rows.actions.getRow(id)
}) })
const newRows = await rows.actions.bulkDuplicate(rowsToDuplicate) const newRows = await rows.actions.bulkDuplicate(
if (newRows[0]) { rowsToDuplicate,
const column = $stickyColumn?.name || $columns[0].name progress => {
$focusedCellId = getCellID(newRows[0]._id, column) progressPercentage = progress * 100
} }
)
// Select new cells to highlight them
if (newRows.length) {
const firstRow = newRows[0]
const lastRow = newRows[newRows.length - 1]
const firstCol = $allVisibleColumns[0]
const lastCol = $allVisibleColumns[$allVisibleColumns.length - 1]
const startCellId = getCellID(firstRow._id, firstCol.name)
const endCellId = getCellID(lastRow._id, lastCol.name)
selectedCells.actions.selectRange(startCellId, endCellId)
}
await sleep(duration)
processing = false
} }
onMount(() => subscribe("request-bulk-duplicate", () => modal?.show())) onMount(() => subscribe("request-bulk-duplicate", () => modal?.show()))
@ -40,9 +61,13 @@
> >
Are you sure you want to duplicate {$selectedRowCount} Are you sure you want to duplicate {$selectedRowCount}
row{$selectedRowCount === 1 ? "" : "s"}? row{$selectedRowCount === 1 ? "" : "s"}?
{#if $selectedRowCount >= 10} {#if processing}
<br /><br /> <ProgressBar
This may take a few seconds. size="L"
value={progressPercentage}
{duration}
width="100%"
/>
{/if} {/if}
</ModalContent> </ModalContent>
</Modal> </Modal>

View File

@ -9,7 +9,7 @@
let modal let modal
let progressPercentage = 0 let progressPercentage = 0
let pasting = false let processing = false
const handleCopyRequest = () => { const handleCopyRequest = () => {
if (!$copyAllowed) { if (!$copyAllowed) {
@ -34,12 +34,12 @@
} }
const performBulkPaste = async () => { const performBulkPaste = async () => {
pasting = true processing = true
await clipboard.actions.paste(progress => { await clipboard.actions.paste(progress => {
progressPercentage = progress * 100 progressPercentage = progress * 100
}) })
await sleep(duration) await sleep(duration)
pasting = false processing = false
} }
onMount(() => subscribe("copy", handleCopyRequest)) onMount(() => subscribe("copy", handleCopyRequest))
@ -48,14 +48,14 @@
<Modal bind:this={modal}> <Modal bind:this={modal}>
<ModalContent <ModalContent
title="Confirm bulk paste" title="Confirm paste"
confirmText="Continue" confirmText="Continue"
cancelText="Cancel" cancelText="Cancel"
onConfirm={performBulkPaste} onConfirm={performBulkPaste}
size="M" size="M"
> >
Are you sure you want to paste? This will update multiple values. Are you sure you want to paste? This will update multiple values.
{#if pasting} {#if processing}
<ProgressBar <ProgressBar
size="L" size="L"
value={progressPercentage} value={progressPercentage}

View File

@ -9,9 +9,6 @@
focusedRow, focusedRow,
menu, menu,
rows, rows,
columns,
focusedCellId,
stickyColumn,
config, config,
dispatch, dispatch,
focusedRowId, focusedRowId,
@ -21,6 +18,8 @@
copyAllowed, copyAllowed,
pasteAllowed, pasteAllowed,
selectedCellCount, selectedCellCount,
allVisibleColumns,
selectedCells,
} = getContext("grid") } = getContext("grid")
let anchor let anchor
@ -42,8 +41,11 @@
menu.actions.close() menu.actions.close()
const newRow = await rows.actions.duplicateRow($focusedRow) const newRow = await rows.actions.duplicateRow($focusedRow)
if (newRow) { if (newRow) {
const column = $stickyColumn?.name || $columns[0].name const firstCol = $allVisibleColumns[0]
$focusedCellId = getCellID(newRow._id, column) const lastCol = $allVisibleColumns[$allVisibleColumns.length - 1]
const startCellId = getCellID(newRow._id, firstCol.name)
const endCellId = getCellID(newRow._id, lastCol.name)
selectedCells.actions.selectRange(startCellId, endCellId)
} }
} }

View File

@ -320,7 +320,7 @@ export const createActions = context => {
} }
// Duplicates multiple rows, inserting them after the last source row // Duplicates multiple rows, inserting them after the last source row
const bulkDuplicate = async rowsToDupe => { const bulkDuplicate = async (rowsToDupe, progressCallback) => {
// Find index of last row // Find index of last row
const $rowLookupMap = get(rowLookupMap) const $rowLookupMap = get(rowLookupMap)
const index = Math.max(...rowsToDupe.map(row => $rowLookupMap[row._id])) const index = Math.max(...rowsToDupe.map(row => $rowLookupMap[row._id]))
@ -336,15 +336,16 @@ export const createActions = context => {
// Create rows // Create rows
let saved = [] let saved = []
let failed = 0 let failed = 0
for (let clone of clones) { for (let i = 0; i < clones.length; i++) {
try { try {
saved.push(await datasource.actions.addRow(clone)) saved.push(await datasource.actions.addRow(clones[i]))
rowCacheMap[saved._id] = true rowCacheMap[saved._id] = true
await sleep(50) // Small sleep to ensure we avoid rate limiting await sleep(50) // Small sleep to ensure we avoid rate limiting
} catch (error) { } catch (error) {
failed++ failed++
console.error("Duplicating row failed", error) console.error("Duplicating row failed", error)
} }
progressCallback?.((i + 1) / clones.length)
} }
// Add to state // Add to state