1
0
Fork 0
mirror of synced 2024-07-04 14:01:27 +12:00

Add progress indicator to bulk pasting

This commit is contained in:
Andrew Kingston 2024-06-23 19:12:03 +01:00
parent 37c0417848
commit a84a56ae1b
No known key found for this signature in database
4 changed files with 46 additions and 29 deletions

View file

@ -1,33 +1,22 @@
<script> <script>
import "@spectrum-css/progressbar/dist/index-vars.css" import "@spectrum-css/progressbar/dist/index-vars.css"
import { tweened } from "svelte/motion"
import { cubicOut } from "svelte/easing"
export let value = false export let value = false
export let easing = cubicOut
export let duration = 1000 export let duration = 1000
export let width = false export let width = false
export let sideLabel = false export let sideLabel = false
export let hidePercentage = true export let hidePercentage = true
export let color // red, green, default = blue export let color // red, green, default = blue
export let size = "M" export let size = "M"
const progress = tweened(0, {
duration: duration,
easing: easing,
})
$: if (value || value === 0) $progress = value
</script> </script>
<div <div
class:spectrum-ProgressBar--indeterminate={!value && value !== 0} class:spectrum-ProgressBar--indeterminate={!value && value !== 0}
class:spectrum-ProgressBar--sideLabel={sideLabel} class:spectrum-ProgressBar--sideLabel={sideLabel}
class="spectrum-ProgressBar spectrum-ProgressBar--size{size}" class="spectrum-ProgressBar spectrum-ProgressBar--size{size}"
value={$progress} {value}
role="progressbar" role="progressbar"
aria-valuenow={$progress} aria-valuenow={value}
aria-valuemin="0" aria-valuemin="0"
aria-valuemax="100" aria-valuemax="100"
style={width ? `width: ${width};` : ""} style={width ? `width: ${width};` : ""}
@ -43,7 +32,7 @@
<div <div
class="spectrum-FieldLabel spectrum-ProgressBar-percentage spectrum-FieldLabel--size{size}" class="spectrum-FieldLabel spectrum-ProgressBar-percentage spectrum-FieldLabel--size{size}"
> >
{Math.round($progress)}% {Math.round(value)}%
</div> </div>
{/if} {/if}
<div class="spectrum-ProgressBar-track"> <div class="spectrum-ProgressBar-track">
@ -51,7 +40,7 @@
class="spectrum-ProgressBar-fill" class="spectrum-ProgressBar-fill"
class:color-green={color === "green"} class:color-green={color === "green"}
class:color-red={color === "red"} class:color-red={color === "red"}
style={value || value === 0 ? `width: ${$progress}%` : ""} style="width: {value}%; --duration: {duration}ms;"
/> />
</div> </div>
<div class="spectrum-ProgressBar-label" hidden="" /> <div class="spectrum-ProgressBar-label" hidden="" />
@ -64,4 +53,7 @@
.color-red { .color-red {
background: #dd2019; background: #dd2019;
} }
.spectrum-ProgressBar-fill {
transition: width var(--duration) ease-out;
}
</style> </style>

View file

@ -1,20 +1,25 @@
<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 { sleep } from "../../../utils/utils"
const { clipboard, subscribe, copyAllowed, pasteAllowed, selectedCellCount } = const { clipboard, subscribe, copyAllowed, pasteAllowed, selectedCellCount } =
getContext("grid") getContext("grid")
const duration = 260
let modal let modal
let progressPercentage = 0
let pasting = false
const copy = () => { const handleCopyRequest = () => {
if (!$copyAllowed) { if (!$copyAllowed) {
return return
} }
clipboard.actions.copy() clipboard.actions.copy()
} }
const paste = async () => { const handlePasteRequest = async () => {
progressPercentage = 0
if (!$pasteAllowed) { if (!$pasteAllowed) {
return return
} }
@ -28,8 +33,17 @@
} }
} }
onMount(() => subscribe("copy", copy)) const performBulkPaste = async () => {
onMount(() => subscribe("paste", paste)) pasting = true
await clipboard.actions.paste(progress => {
progressPercentage = progress * 100
})
await sleep(duration)
pasting = false
}
onMount(() => subscribe("copy", handleCopyRequest))
onMount(() => subscribe("paste", handlePasteRequest))
</script> </script>
<Modal bind:this={modal}> <Modal bind:this={modal}>
@ -37,9 +51,17 @@
title="Confirm bulk paste" title="Confirm bulk paste"
confirmText="Continue" confirmText="Continue"
cancelText="Cancel" cancelText="Cancel"
onConfirm={clipboard.actions.paste} 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}
<ProgressBar
size="L"
value={progressPercentage}
{duration}
width="100%"
/>
{/if}
</ModalContent> </ModalContent>
</Modal> </Modal>

View file

@ -123,7 +123,7 @@ export const createActions = context => {
} }
// Pastes the previously copied value(s) into the selected cell(s) // Pastes the previously copied value(s) into the selected cell(s)
const paste = async () => { const paste = async progressCallback => {
if (!get(pasteAllowed)) { if (!get(pasteAllowed)) {
return return
} }
@ -151,7 +151,7 @@ export const createActions = context => {
} }
// Paste the new value // Paste the new value
await pasteIntoSelectedCells(newValue) await pasteIntoSelectedCells(newValue, progressCallback)
} else { } else {
// Multi to single - expand to paste all values // Multi to single - expand to paste all values
// Get indices of focused cell // Get indices of focused cell
@ -184,14 +184,14 @@ export const createActions = context => {
} else { } else {
// Select the new cells to paste into, then paste // Select the new cells to paste into, then paste
selectedCells.actions.selectRange($focusedCellId, targetCellId) selectedCells.actions.selectRange($focusedCellId, targetCellId)
await pasteIntoSelectedCells(value) await pasteIntoSelectedCells(value, progressCallback)
} }
} }
} else { } else {
if (multiCellPaste) { if (multiCellPaste) {
// Single to multi - duplicate value to all selected cells // Single to multi - duplicate value to all selected cells
const newValue = get(selectedCells).map(row => row.map(() => value)) const newValue = get(selectedCells).map(row => row.map(() => value))
await pasteIntoSelectedCells(newValue) await pasteIntoSelectedCells(newValue, progressCallback)
} else { } else {
// Single to single - just update the cell's value // Single to single - just update the cell's value
get(focusedCellAPI).setValue(value) get(focusedCellAPI).setValue(value)
@ -200,7 +200,7 @@ export const createActions = context => {
} }
// Paste the specified value into the currently selected cells // Paste the specified value into the currently selected cells
const pasteIntoSelectedCells = async value => { const pasteIntoSelectedCells = async (value, progressCallback) => {
const $selectedCells = get(selectedCells) const $selectedCells = get(selectedCells)
// Find the extent at which we can paste // Find the extent at which we can paste
@ -219,7 +219,7 @@ export const createActions = context => {
changeMap[rowId][field] = value[rowIdx][colIdx] changeMap[rowId][field] = value[rowIdx][colIdx]
} }
} }
await rows.actions.bulkUpdate(changeMap) await rows.actions.bulkUpdate(changeMap, progressCallback)
} }
return { return {

View file

@ -524,7 +524,7 @@ export const createActions = context => {
} }
} }
const bulkUpdate = async changeMap => { const bulkUpdate = async (changeMap, progressCallback) => {
const rowIds = Object.keys(changeMap || {}) const rowIds = Object.keys(changeMap || {})
if (!rowIds.length) { if (!rowIds.length) {
return return
@ -533,8 +533,10 @@ export const createActions = context => {
// Update rows // Update rows
let updated = [] let updated = []
let failed = 0 let failed = 0
for (let rowId of rowIds) { for (let i = 0; i < rowIds.length; i++) {
const rowId = rowIds[i]
if (!Object.keys(changeMap[rowId] || {}).length) { if (!Object.keys(changeMap[rowId] || {}).length) {
progressCallback?.((i + 1) / rowIds.length)
continue continue
} }
try { try {
@ -554,6 +556,7 @@ export const createActions = context => {
failed++ failed++
console.error("Failed to update row", error) console.error("Failed to update row", error)
} }
progressCallback?.((i + 1) / rowIds.length)
} }
// Update state // Update state