Tidy up import data modal and change to be a detail popover

This commit is contained in:
Andrew Kingston 2024-10-25 16:24:40 +01:00
parent c110cb628d
commit dae550c21e
No known key found for this signature in database
3 changed files with 145 additions and 142 deletions

View File

@ -1,17 +1,91 @@
<script>
import { ActionButton, Modal } from "@budibase/bbui"
import ImportModal from "../modals/ImportModal.svelte"
import {
ActionButton,
Label,
Button,
Body,
Layout,
notifications,
} from "@budibase/bbui"
import DetailPopover from "components/common/DetailPopover.svelte"
import TableDataImport from "components/backend/TableNavigator/TableDataImport.svelte"
import { createEventDispatcher } from "svelte"
import { API } from "api"
export let tableId
export let tableType
export let disabled
let modal
const dispatch = createEventDispatcher()
let popover
let rows = []
let allValid = false
let displayColumn = null
let identifierFields = []
let loading = false
const openPopover = () => {
rows = []
allValid = false
displayColumn = null
identifierFields = []
loading = false
popover.show()
}
const importData = async () => {
try {
loading = true
await API.importTableData({
tableId,
rows,
identifierFields,
})
notifications.success("Rows successfully imported")
popover.hide()
} catch (error) {
console.error(error)
notifications.error("Unable to import data")
} finally {
loading = false
}
// Always refresh rows just to be sure
dispatch("importrows")
}
</script>
<ActionButton icon="DataUpload" quiet on:click={modal.show} {disabled}>
Import
</ActionButton>
<Modal bind:this={modal}>
<ImportModal {tableId} {tableType} on:importrows />
</Modal>
<DetailPopover title="Import data" bind:this={popover}>
<svelte:fragment slot="anchor" let:open>
<ActionButton
icon="DataUpload"
quiet
on:click={openPopover}
{disabled}
selected={open}
>
Import
</ActionButton>
</svelte:fragment>
<Body size="S">
Import rows to an existing table from a CSV or JSON file. Only columns from
the file which exist in the table will be imported.
</Body>
<Layout gap="XS" noPadding>
<Label grey extraSmall>CSV or JSON file to import</Label>
<TableDataImport
{tableId}
{tableType}
bind:rows
bind:allValid
bind:displayColumn
bind:identifierFields
/>
</Layout>
<div>
<Button cta disabled={loading || !allValid} on:click={importData}>
Import
</Button>
</div>
</DetailPopover>

View File

@ -1,61 +0,0 @@
<script>
import {
ModalContent,
Label,
notifications,
Body,
Layout,
} from "@budibase/bbui"
import TableDataImport from "../../TableNavigator/ExistingTableDataImport.svelte"
import { API } from "api"
import { createEventDispatcher } from "svelte"
const dispatch = createEventDispatcher()
export let tableId
export let tableType
let rows = []
let allValid = false
let displayColumn = null
let identifierFields = []
async function importData() {
try {
await API.importTableData({
tableId,
rows,
identifierFields,
})
notifications.success("Rows successfully imported")
} catch (error) {
notifications.error("Unable to import data")
}
// Always refresh rows just to be sure
dispatch("importrows")
}
</script>
<ModalContent
title="Import Data"
confirmText="Import"
onConfirm={importData}
disabled={!allValid}
>
<Body size="S">
Import rows to an existing table from a CSV or JSON file. Only columns from
the file which exist in the table will be imported.
</Body>
<Layout gap="XS" noPadding>
<Label grey extraSmall>CSV or JSON file to import</Label>
<TableDataImport
{tableId}
{tableType}
bind:rows
bind:allValid
bind:displayColumn
bind:identifierFields
/>
</Layout>
</ModalContent>

View File

@ -1,5 +1,5 @@
<script>
import { Select, Icon } from "@budibase/bbui"
import { Select, Icon, Layout } from "@budibase/bbui"
import { FIELDS } from "constants/backend"
import { utils } from "@budibase/shared-core"
import { canBeDisplayColumn } from "@budibase/frontend-core"
@ -184,70 +184,71 @@
}
</script>
<div class="dropzone">
<input
bind:this={fileInput}
disabled={loading}
id="file-upload"
accept="text/csv,application/json"
type="file"
on:change={handleFile}
/>
<label for="file-upload" class:uploaded={rawRows.length > 0}>
{#if error}
Error: {error}
{:else if fileName}
{fileName}
{:else}
Upload
{/if}
</label>
</div>
{#if rawRows.length > 0 && !error}
<div class="schema-fields">
{#each Object.entries(schema) as [name, column]}
<div class="field">
<span>{column.name}</span>
<Select
bind:value={selectedColumnTypes[column.name]}
on:change={e => handleChange(name, e)}
options={Object.values(typeOptions)}
placeholder={null}
getOptionLabel={option => option.label}
getOptionValue={option => option.value}
/>
<span
class={validation[column.name]
? "fieldStatusSuccess"
: "fieldStatusFailure"}
>
{#if validation[column.name]}
Success
{:else}
Failure
{#if errors[column.name]}
<Icon name="Help" tooltip={errors[column.name]} />
{/if}
{/if}
</span>
<Icon
size="S"
name="Close"
hoverable
on:click={() => deleteColumn(column.name)}
/>
</div>
{/each}
<Layout noPadding gap="S">
<div class="dropzone">
<input
bind:this={fileInput}
disabled={loading}
id="file-upload"
accept="text/csv,application/json"
type="file"
on:change={handleFile}
/>
<label for="file-upload" class:uploaded={rawRows.length > 0}>
{#if error}
Error: {error}
{:else if fileName}
{fileName}
{:else}
Upload
{/if}
</label>
</div>
<div class="display-column">
{#if rawRows.length > 0 && !error}
<div>
{#each Object.entries(schema) as [name, column]}
<div class="field">
<span>{column.name}</span>
<Select
bind:value={selectedColumnTypes[column.name]}
on:change={e => handleChange(name, e)}
options={Object.values(typeOptions)}
placeholder={null}
getOptionLabel={option => option.label}
getOptionValue={option => option.value}
/>
<span
class={validation[column.name]
? "fieldStatusSuccess"
: "fieldStatusFailure"}
>
{#if validation[column.name]}
Success
{:else}
Failure
{#if errors[column.name]}
<Icon name="Help" tooltip={errors[column.name]} />
{/if}
{/if}
</span>
<Icon
size="S"
name="Close"
hoverable
on:click={() => deleteColumn(column.name)}
/>
</div>
{/each}
</div>
<Select
label="Display Column"
bind:value={displayColumn}
options={displayColumnOptions}
sort
/>
</div>
{/if}
{/if}
</Layout>
<style>
.dropzone {
@ -269,7 +270,6 @@
box-sizing: border-box;
overflow: hidden;
border-radius: var(--border-radius-s);
color: var(--ink);
padding: var(--spacing-m) var(--spacing-l);
transition: all 0.2s ease 0s;
display: inline-flex;
@ -283,20 +283,14 @@
align-items: center;
justify-content: center;
width: 100%;
background-color: var(--grey-2);
font-size: var(--font-size-xs);
background-color: var(--spectrum-global-color-gray-300);
font-size: var(--font-size-s);
line-height: normal;
border: var(--border-transparent);
}
.uploaded {
color: var(--blue);
color: var(--spectrum-global-color-blue-600);
}
.schema-fields {
margin-top: var(--spacing-xl);
}
.field {
display: grid;
grid-template-columns: 2fr 2fr 1fr auto;
@ -322,8 +316,4 @@
.fieldStatusFailure :global(.spectrum-Icon) {
width: 12px;
}
.display-column {
margin-top: var(--spacing-xl);
}
</style>