Fix table imports

This commit is contained in:
Andrew Kingston 2024-10-29 12:09:01 +00:00
parent 5bda7daf2f
commit b8f27b9bf7
No known key found for this signature in database
4 changed files with 129 additions and 158 deletions

View File

@ -1,14 +1,7 @@
<script> <script>
import { import { ActionButton, Button, Body, notifications } from "@budibase/bbui"
ActionButton,
Label,
Button,
Body,
Layout,
notifications,
} from "@budibase/bbui"
import DetailPopover from "components/common/DetailPopover.svelte" import DetailPopover from "components/common/DetailPopover.svelte"
import TableDataImport from "components/backend/TableNavigator/TableDataImport.svelte" import ExistingTableDataImport from "components/backend/TableNavigator/ExistingTableDataImport.svelte"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { API } from "api" import { API } from "api"
@ -72,17 +65,14 @@
Import rows to an existing table from a CSV or JSON file. Only columns from 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. the file which exist in the table will be imported.
</Body> </Body>
<Layout gap="XS" noPadding> <ExistingTableDataImport
<Label grey extraSmall>CSV or JSON file to import</Label> {tableId}
<TableDataImport {tableType}
{tableId} bind:rows
{tableType} bind:allValid
bind:rows bind:displayColumn
bind:allValid bind:identifierFields
bind:displayColumn />
bind:identifierFields
/>
</Layout>
<div> <div>
<Button cta disabled={loading || !allValid} on:click={importData}> <Button cta disabled={loading || !allValid} on:click={importData}>
Import Import

View File

@ -4,7 +4,7 @@
BBReferenceFieldSubType, BBReferenceFieldSubType,
SourceName, SourceName,
} from "@budibase/types" } from "@budibase/types"
import { Select, Toggle, Multiselect } from "@budibase/bbui" import { Select, Toggle, Multiselect, Label, Layout } from "@budibase/bbui"
import { DB_TYPE_INTERNAL } from "constants/backend" import { DB_TYPE_INTERNAL } from "constants/backend"
import { API } from "api" import { API } from "api"
import { parseFile } from "./utils" import { parseFile } from "./utils"
@ -140,84 +140,91 @@
} }
</script> </script>
<div class="dropzone"> <Layout gap="S" noPadding>
<input <Layout noPadding gap="XS">
disabled={!schema || loading} <Label grey extraSmall>CSV or JSON file to import</Label>
id="file-upload" <div class="dropzone">
accept="text/csv,application/json" <input
type="file" disabled={!schema || loading}
on:change={handleFile} id="file-upload"
/> accept="text/csv,application/json"
<label for="file-upload" class:uploaded={rows.length > 0}> type="file"
{#if loading} on:change={handleFile}
loading...
{:else if error}
error: {error}
{:else if fileName}
{fileName}
{:else}
Upload
{/if}
</label>
</div>
{#if fileName && Object.keys(validation).length === 0}
<p>No valid fields, try another file</p>
{:else if rows.length > 0 && !error}
<div class="schema-fields">
{#each Object.keys(validation) as name}
<div class="field">
<span>{name}</span>
<Select
value={`${schema[name]?.type}${schema[name]?.subtype || ""}`}
options={typeOptions}
placeholder={null}
getOptionLabel={option => option.label}
getOptionValue={option => option.value}
disabled
/>
<span
class={loading || validation[name]
? "fieldStatusSuccess"
: "fieldStatusFailure"}
>
{validation[name] ? "Success" : "Failure"}
</span>
</div>
{/each}
</div>
<br />
<!-- SQL Server doesn't yet support overwriting rows by existing keys -->
{#if datasource?.source !== SourceName.SQL_SERVER}
<Toggle
bind:value={updateExistingRows}
on:change={() => (identifierFields = [])}
thin
text="Update existing rows"
/>
{/if}
{#if updateExistingRows}
{#if tableType === DB_TYPE_INTERNAL}
<Multiselect
label="Identifier field(s)"
options={Object.keys(validation)}
bind:value={identifierFields}
/> />
{:else} <label for="file-upload" class:uploaded={rows.length > 0}>
<p>Rows will be updated based on the table's primary key.</p> {#if loading}
loading...
{:else if error}
error: {error}
{:else if fileName}
{fileName}
{:else}
Upload
{/if}
</label>
</div>
</Layout>
{#if fileName && Object.keys(validation).length === 0}
<div>No valid fields - please try another file.</div>
{:else if fileName && rows.length > 0 && !error}
<div>
{#each Object.keys(validation) as name}
<div class="field">
<span>{name}</span>
<Select
value={`${schema[name]?.type}${schema[name]?.subtype || ""}`}
options={typeOptions}
placeholder={null}
getOptionLabel={option => option.label}
getOptionValue={option => option.value}
disabled
/>
<span
class={loading || validation[name]
? "fieldStatusSuccess"
: "fieldStatusFailure"}
>
{validation[name] ? "Success" : "Failure"}
</span>
</div>
{/each}
</div>
<!-- SQL Server doesn't yet support overwriting rows by existing keys -->
{#if datasource?.source !== SourceName.SQL_SERVER}
<Toggle
bind:value={updateExistingRows}
on:change={() => (identifierFields = [])}
thin
text="Update existing rows"
/>
{/if}
{#if updateExistingRows}
{#if tableType === DB_TYPE_INTERNAL}
<Multiselect
label="Identifier field(s)"
options={Object.keys(validation)}
bind:value={identifierFields}
/>
{:else}
<div>Rows will be updated based on the table's primary key.</div>
{/if}
{/if}
{#if invalidColumns.length > 0}
<Layout noPadding gap="XS">
<div>
The following columns are present in the data you wish to import, but
do not match the schema of this table and will be ignored:
</div>
<div>
{#each invalidColumns as column}
- {column}<br />
{/each}
</div>
</Layout>
{/if} {/if}
{/if} {/if}
{#if invalidColumns.length > 0} </Layout>
<p class="spectrum-FieldLabel spectrum-FieldLabel--sizeM">
The following columns are present in the data you wish to import, but do
not match the schema of this table and will be ignored.
</p>
<ul class="ignoredList">
{#each invalidColumns as column}
<li>{column}</li>
{/each}
</ul>
{/if}
{/if}
<style> <style>
.dropzone { .dropzone {
@ -228,11 +235,9 @@
border-radius: 10px; border-radius: 10px;
transition: all 0.3s; transition: all 0.3s;
} }
input { input {
display: none; display: none;
} }
label { label {
font-family: var(--font-sans); font-family: var(--font-sans);
cursor: pointer; cursor: pointer;
@ -240,7 +245,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;
@ -254,20 +258,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;
@ -276,23 +274,14 @@
grid-gap: var(--spacing-m); grid-gap: var(--spacing-m);
font-size: var(--spectrum-global-dimension-font-size-75); font-size: var(--spectrum-global-dimension-font-size-75);
} }
.fieldStatusSuccess { .fieldStatusSuccess {
color: var(--green); color: var(--green);
justify-self: center; justify-self: center;
font-weight: 600; font-weight: 600;
} }
.fieldStatusFailure { .fieldStatusFailure {
color: var(--red); color: var(--red);
justify-self: center; justify-self: center;
font-weight: 600; font-weight: 600;
} }
.ignoredList {
margin: 0;
padding: 0;
list-style: none;
font-size: var(--spectrum-global-dimension-font-size-75);
}
</style> </style>

View File

@ -1,5 +1,5 @@
<script> <script>
import { Select, Icon, Layout } from "@budibase/bbui" import { Select, Icon, Layout, Label } 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"
@ -185,25 +185,30 @@
</script> </script>
<Layout noPadding gap="S"> <Layout noPadding gap="S">
<div class="dropzone"> <Layout gap="XS" noPadding>
<input <Label grey extraSmall>
bind:this={fileInput} Create a Table from a CSV or JSON file (Optional)
disabled={loading} </Label>
id="file-upload" <div class="dropzone">
accept="text/csv,application/json" <input
type="file" bind:this={fileInput}
on:change={handleFile} disabled={loading}
/> id="file-upload"
<label for="file-upload" class:uploaded={rawRows.length > 0}> accept="text/csv,application/json"
{#if error} type="file"
Error: {error} on:change={handleFile}
{:else if fileName} />
{fileName} <label for="file-upload" class:uploaded={rawRows.length > 0}>
{:else} {#if error}
Upload Error: {error}
{/if} {:else if fileName}
</label> {fileName}
</div> {:else}
Upload
{/if}
</label>
</div>
</Layout>
{#if rawRows.length > 0 && !error} {#if rawRows.length > 0 && !error}
<div> <div>

View File

@ -1,13 +1,7 @@
<script> <script>
import { goto, url } from "@roxi/routify" import { goto, url } from "@roxi/routify"
import { tables, datasources } from "stores/builder" import { tables, datasources } from "stores/builder"
import { import { notifications, Input, ModalContent } from "@budibase/bbui"
notifications,
Input,
Label,
ModalContent,
Layout,
} from "@budibase/bbui"
import TableDataImport from "../TableDataImport.svelte" import TableDataImport from "../TableDataImport.svelte"
import { import {
BUDIBASE_INTERNAL_DB_ID, BUDIBASE_INTERNAL_DB_ID,
@ -101,18 +95,11 @@
bind:value={name} bind:value={name}
{error} {error}
/> />
<div> <TableDataImport
<Layout gap="XS" noPadding> {promptUpload}
<Label grey extraSmall bind:rows
>Create a Table from a CSV or JSON file (Optional)</Label bind:schema
> bind:allValid
<TableDataImport bind:displayColumn
{promptUpload} />
bind:rows
bind:schema
bind:allValid
bind:displayColumn
/>
</Layout>
</div>
</ModalContent> </ModalContent>