Add progress indicators to all other bulk operations and select more modified cells
This commit is contained in:
parent
a84a56ae1b
commit
7a3eabc529
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue