Add progress indicator to bulk pasting
This commit is contained in:
parent
37c0417848
commit
a84a56ae1b
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue