Add initial work on new S3 upload component and button action

This commit is contained in:
Andrew Kingston 2022-01-11 14:01:21 +00:00
parent 4ccf3f9687
commit 8772dc342d
13 changed files with 231 additions and 1 deletions

View File

@ -44,7 +44,8 @@
"relationshipfield",
"daterangepicker",
"multifieldselect",
"jsonfield"
"jsonfield",
"s3upload"
]
},
{

View File

@ -0,0 +1,33 @@
<script>
import { Select, Label } from "@budibase/bbui"
import { currentAsset } from "builderStore"
import { findAllMatchingComponents } from "builderStore/componentUtils"
export let parameters
$: components = findAllMatchingComponents($currentAsset.props, component =>
component._component.endsWith("s3upload")
)
</script>
<div class="root">
<Label small>S3 Upload Component</Label>
<Select
bind:value={parameters.componentId}
options={components}
getOptionLabel={x => x._instanceName}
getOptionValue={x => x._id}
/>
</div>
<style>
.root {
display: grid;
column-gap: var(--spacing-l);
row-gap: var(--spacing-s);
grid-template-columns: 120px 1fr;
align-items: center;
max-width: 400px;
margin: 0 auto;
}
</style>

View File

@ -11,3 +11,4 @@ export { default as ChangeFormStep } from "./ChangeFormStep.svelte"
export { default as UpdateState } from "./UpdateState.svelte"
export { default as RefreshDataProvider } from "./RefreshDataProvider.svelte"
export { default as DuplicateRow } from "./DuplicateRow.svelte"
export { default as S3Upload } from "./S3Upload.svelte"

View File

@ -70,6 +70,10 @@
"name": "Update State",
"component": "UpdateState",
"dependsOnFeature": "state"
},
{
"name": "Upload File to S3",
"component": "S3Upload"
}
]
}

View File

@ -0,0 +1,15 @@
<script>
import { Select } from "@budibase/bbui"
import { datasources } from "stores/backend"
export let value = null
$: dataSources = $datasources.list
.filter(ds => ds.source === "S3")
.map(ds => ({
label: ds.name,
value: ds._id,
}))
</script>
<Select options={dataSources} {value} on:change />

View File

@ -1,5 +1,6 @@
import { Checkbox, Select, Stepper } from "@budibase/bbui"
import DataSourceSelect from "./DataSourceSelect.svelte"
import S3DataSourceSelect from "./S3DataSourceSelect.svelte"
import DataProviderSelect from "./DataProviderSelect.svelte"
import ButtonActionEditor from "./ButtonActionEditor/ButtonActionEditor.svelte"
import TableSelect from "./TableSelect.svelte"
@ -21,6 +22,7 @@ const componentMap = {
text: DrawerBindableCombobox,
select: Select,
dataSource: DataSourceSelect,
"dataSource/s3": S3DataSourceSelect,
dataProvider: DataProviderSelect,
boolean: Checkbox,
number: Stepper,

View File

@ -3315,5 +3315,44 @@
"suffix": "repeater"
}
]
},
"s3upload": {
"name": "S3 File Upload",
"icon": "UploadToCloud",
"styles": ["size"],
"editable": true,
"settings": [
{
"type": "field/attachment",
"label": "Field",
"key": "field"
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "dataSource/s3",
"label": "S3 Datasource",
"key": "datasource"
},
{
"type": "text",
"label": "Bucket",
"key": "bucket"
},
{
"type": "boolean",
"label": "Disabled",
"key": "disabled",
"defaultValue": false
},
{
"type": "validation/attachment",
"label": "Validation",
"key": "validation"
}
]
}
}

View File

@ -0,0 +1,79 @@
<script>
import Field from "./Field.svelte"
import { CoreDropzone } from "@budibase/bbui"
import { getContext, onMount, onDestroy } from "svelte"
export let dataSource
export let bucket
export let field
export let label
export let disabled = false
export let validation
let fieldState
let fieldApi
const { API, notificationStore, uploadStore } = getContext("sdk")
const component = getContext("component")
const formContext = getContext("form")
// 5GB cap per item sent via S3 REST API
const MaxFileSize = 1000000000 * 5
let file
const handleFileTooLarge = () => {
notificationStore.actions.warning(
"Files cannot exceed 5GB. Please try again with a smaller file."
)
}
const processFiles = async fileList => {
// let data = new FormData()
// for (let i = 0; i < fileList.length; i++) {
// data.append("file", fileList[i])
// }
// return await API.uploadAttachment(data, formContext?.dataSource?.tableId)
file = fileList[0]
console.log("processing", fileList)
return []
}
const upload = async () => {
console.log("UPLOADING!!!")
}
onMount(() => {
uploadStore.actions.registerFileUpload($component.id, upload)
})
onDestroy(() => {
uploadStore.actions.unregisterFileUpload($component.id)
})
</script>
<Field
{label}
{field}
{disabled}
{validation}
type="s3upload"
bind:fieldState
bind:fieldApi
defaultValue={[]}
>
{#if fieldState}
<CoreDropzone
value={fieldState.value}
disabled={fieldState.disabled}
error={fieldState.error}
on:change={e => {
fieldApi.setValue(e.detail)
}}
{processFiles}
{handleFileTooLarge}
maximum={1}
fileSizeLimit={MaxFileSize}
/>
{/if}
</Field>

View File

@ -12,3 +12,4 @@ export { default as relationshipfield } from "./RelationshipField.svelte"
export { default as passwordfield } from "./PasswordField.svelte"
export { default as formstep } from "./FormStep.svelte"
export { default as jsonfield } from "./JSONField.svelte"
export { default as s3upload } from "./S3Upload.svelte"

View File

@ -5,6 +5,7 @@ import {
routeStore,
screenStore,
builderStore,
uploadStore,
} from "stores"
import { styleable } from "utils/styleable"
import { linkable } from "utils/linkable"
@ -19,6 +20,7 @@ export default {
routeStore,
screenStore,
builderStore,
uploadStore,
styleable,
linkable,
getAction,

View File

@ -9,6 +9,7 @@ export { confirmationStore } from "./confirmation"
export { peekStore } from "./peek"
export { stateStore } from "./state"
export { themeStore } from "./theme"
export { uploadStore } from "./uploads.js"
// Context stores are layered and duplicated, so it is not a singleton
export { createContextStore } from "./context"

View File

@ -0,0 +1,42 @@
import { writable, get } from "svelte/store"
export const createUploadStore = () => {
const store = writable([])
// Registers a new file upload component
const registerFileUpload = (componentId, callback) => {
if (!componentId || !callback) {
return
}
store.update(state => {
state.push({
componentId,
callback,
})
return state
})
}
// Unregisters a file upload component
const unregisterFileUpload = componentId => {
store.update(state => state.filter(c => c.componentId !== componentId))
}
// Processes a file upload for a given component ID
const processFileUpload = async componentId => {
if (!componentId) {
return
}
const component = get(store).find(c => c.componentId === componentId)
await component?.callback()
}
return {
subscribe: store.subscribe,
actions: { registerFileUpload, unregisterFileUpload, processFileUpload },
}
}
export const uploadStore = createUploadStore()

View File

@ -5,6 +5,7 @@ import {
confirmationStore,
authStore,
stateStore,
uploadStore,
} from "stores"
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "api"
import { ActionTypes } from "constants"
@ -157,6 +158,14 @@ const updateStateHandler = action => {
}
}
const s3UploadHandler = async action => {
const { componentId } = action.parameters
if (!componentId) {
return
}
await uploadStore.actions.processFileUpload(componentId)
}
const handlerMap = {
["Save Row"]: saveRowHandler,
["Duplicate Row"]: duplicateRowHandler,
@ -171,6 +180,7 @@ const handlerMap = {
["Close Screen Modal"]: closeScreenModalHandler,
["Change Form Step"]: changeFormStepHandler,
["Update State"]: updateStateHandler,
["Upload File to S3"]: s3UploadHandler,
}
const confirmTextMap = {