Tidy up import data modal and change to be a detail popover
This commit is contained in:
parent
c110cb628d
commit
dae550c21e
|
@ -1,17 +1,91 @@
|
||||||
<script>
|
<script>
|
||||||
import { ActionButton, Modal } from "@budibase/bbui"
|
import {
|
||||||
import ImportModal from "../modals/ImportModal.svelte"
|
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 tableId
|
||||||
export let tableType
|
export let tableType
|
||||||
export let disabled
|
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>
|
</script>
|
||||||
|
|
||||||
<ActionButton icon="DataUpload" quiet on:click={modal.show} {disabled}>
|
<DetailPopover title="Import data" bind:this={popover}>
|
||||||
Import
|
<svelte:fragment slot="anchor" let:open>
|
||||||
</ActionButton>
|
<ActionButton
|
||||||
<Modal bind:this={modal}>
|
icon="DataUpload"
|
||||||
<ImportModal {tableId} {tableType} on:importrows />
|
quiet
|
||||||
</Modal>
|
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>
|
||||||
|
|
|
@ -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>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select, Icon } from "@budibase/bbui"
|
import { Select, Icon, Layout } from "@budibase/bbui"
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
import { utils } from "@budibase/shared-core"
|
import { utils } from "@budibase/shared-core"
|
||||||
import { canBeDisplayColumn } from "@budibase/frontend-core"
|
import { canBeDisplayColumn } from "@budibase/frontend-core"
|
||||||
|
@ -184,70 +184,71 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="dropzone">
|
<Layout noPadding gap="S">
|
||||||
<input
|
<div class="dropzone">
|
||||||
bind:this={fileInput}
|
<input
|
||||||
disabled={loading}
|
bind:this={fileInput}
|
||||||
id="file-upload"
|
disabled={loading}
|
||||||
accept="text/csv,application/json"
|
id="file-upload"
|
||||||
type="file"
|
accept="text/csv,application/json"
|
||||||
on:change={handleFile}
|
type="file"
|
||||||
/>
|
on:change={handleFile}
|
||||||
<label for="file-upload" class:uploaded={rawRows.length > 0}>
|
/>
|
||||||
{#if error}
|
<label for="file-upload" class:uploaded={rawRows.length > 0}>
|
||||||
Error: {error}
|
{#if error}
|
||||||
{:else if fileName}
|
Error: {error}
|
||||||
{fileName}
|
{:else if fileName}
|
||||||
{:else}
|
{fileName}
|
||||||
Upload
|
{:else}
|
||||||
{/if}
|
Upload
|
||||||
</label>
|
{/if}
|
||||||
</div>
|
</label>
|
||||||
{#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}
|
|
||||||
</div>
|
</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
|
<Select
|
||||||
label="Display Column"
|
label="Display Column"
|
||||||
bind:value={displayColumn}
|
bind:value={displayColumn}
|
||||||
options={displayColumnOptions}
|
options={displayColumnOptions}
|
||||||
sort
|
sort
|
||||||
/>
|
/>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.dropzone {
|
.dropzone {
|
||||||
|
@ -269,7 +270,6 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--border-radius-s);
|
border-radius: var(--border-radius-s);
|
||||||
color: var(--ink);
|
|
||||||
padding: var(--spacing-m) var(--spacing-l);
|
padding: var(--spacing-m) var(--spacing-l);
|
||||||
transition: all 0.2s ease 0s;
|
transition: all 0.2s ease 0s;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
@ -283,20 +283,14 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--grey-2);
|
background-color: var(--spectrum-global-color-gray-300);
|
||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-s);
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
border: var(--border-transparent);
|
border: var(--border-transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.uploaded {
|
.uploaded {
|
||||||
color: var(--blue);
|
color: var(--spectrum-global-color-blue-600);
|
||||||
}
|
}
|
||||||
|
|
||||||
.schema-fields {
|
|
||||||
margin-top: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 2fr 1fr auto;
|
grid-template-columns: 2fr 2fr 1fr auto;
|
||||||
|
@ -322,8 +316,4 @@
|
||||||
.fieldStatusFailure :global(.spectrum-Icon) {
|
.fieldStatusFailure :global(.spectrum-Icon) {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-column {
|
|
||||||
margin-top: var(--spacing-xl);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue