Merge master.
This commit is contained in:
commit
23ea494590
|
@ -32,7 +32,7 @@
|
|||
if (!attribute || value == null) {
|
||||
return ""
|
||||
}
|
||||
if (isNaN(value)) {
|
||||
if (typeof value === "number" && isNaN(value)) {
|
||||
return `${attribute}:${value};`
|
||||
}
|
||||
return `${attribute}:${value}px;`
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import "@spectrum-css/inlinealert/dist/index-vars.css"
|
||||
import Button from "../Button/Button.svelte"
|
||||
import Icon from "../Icon/Icon.svelte"
|
||||
|
||||
export let type = "info"
|
||||
export let header = ""
|
||||
|
@ -8,6 +9,8 @@
|
|||
export let onConfirm = undefined
|
||||
export let buttonText = ""
|
||||
export let cta = false
|
||||
export let link = ""
|
||||
export let linkText = ""
|
||||
|
||||
$: icon = selectIcon(type)
|
||||
// if newlines used, convert them to different elements
|
||||
|
@ -49,6 +52,19 @@
|
|||
>
|
||||
</div>
|
||||
{/if}
|
||||
{#if link && linkText}
|
||||
<div id="docs-link">
|
||||
<a
|
||||
href={link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="docs-link"
|
||||
>
|
||||
{linkText}
|
||||
<Icon name="LinkOut" size="XS" />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@ -64,4 +80,21 @@
|
|||
margin: 0;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#docs-link {
|
||||
padding-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
#docs-link > * {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
export let title
|
||||
export let icon = ""
|
||||
export let id
|
||||
export let id = undefined
|
||||
export let href = "#"
|
||||
export let link = false
|
||||
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
<script>
|
||||
import { goto } from "@roxi/routify"
|
||||
import {
|
||||
keepOpen,
|
||||
ModalContent,
|
||||
notifications,
|
||||
Body,
|
||||
Layout,
|
||||
Tabs,
|
||||
Tab,
|
||||
Heading,
|
||||
TextArea,
|
||||
Dropzone,
|
||||
} from "@budibase/bbui"
|
||||
import { datasources, queries } from "@/stores/builder"
|
||||
import { writable } from "svelte/store"
|
||||
|
||||
export let navigateDatasource = false
|
||||
export let datasourceId
|
||||
export let createDatasource = false
|
||||
export let onCancel
|
||||
|
||||
const data = writable({
|
||||
url: "",
|
||||
raw: "",
|
||||
file: undefined,
|
||||
})
|
||||
|
||||
let lastTouched = "url"
|
||||
|
||||
const getData = async () => {
|
||||
let dataString
|
||||
|
||||
// parse the file into memory and send as string
|
||||
if (lastTouched === "file") {
|
||||
dataString = await $data.file.text()
|
||||
} else if (lastTouched === "url") {
|
||||
const response = await fetch($data.url)
|
||||
dataString = await response.text()
|
||||
} else if (lastTouched === "raw") {
|
||||
dataString = $data.raw
|
||||
}
|
||||
|
||||
return dataString
|
||||
}
|
||||
|
||||
async function importQueries() {
|
||||
try {
|
||||
const dataString = await getData()
|
||||
|
||||
if (!datasourceId && !createDatasource) {
|
||||
throw new Error("No datasource id")
|
||||
}
|
||||
|
||||
const body = {
|
||||
data: dataString,
|
||||
datasourceId,
|
||||
}
|
||||
|
||||
const importResult = await queries.import(body)
|
||||
if (!datasourceId) {
|
||||
datasourceId = importResult.datasourceId
|
||||
}
|
||||
|
||||
// reload
|
||||
await datasources.fetch()
|
||||
await queries.fetch()
|
||||
|
||||
if (navigateDatasource) {
|
||||
$goto(`./datasource/${datasourceId}`)
|
||||
}
|
||||
|
||||
notifications.success(`Imported successfully.`)
|
||||
} catch (error) {
|
||||
notifications.error("Error importing queries")
|
||||
return keepOpen
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
onConfirm={() => importQueries()}
|
||||
{onCancel}
|
||||
confirmText={"Import"}
|
||||
cancelText="Back"
|
||||
size="L"
|
||||
>
|
||||
<Layout noPadding>
|
||||
<Heading size="S">Import</Heading>
|
||||
<Body size="XS"
|
||||
>Import your rest collection using one of the options below</Body
|
||||
>
|
||||
<Tabs selected="File">
|
||||
<!-- Commenting until nginx csp issue resolved -->
|
||||
<!-- <Tab title="Link">
|
||||
<Input
|
||||
bind:value={$data.url}
|
||||
on:change={() => (lastTouched = "url")}
|
||||
label="Enter a URL"
|
||||
placeholder="e.g. https://petstore.swagger.io/v2/swagger.json"
|
||||
/>
|
||||
</Tab> -->
|
||||
<Tab title="File">
|
||||
<Dropzone
|
||||
gallery={false}
|
||||
value={$data.file ? [$data.file] : []}
|
||||
on:change={e => {
|
||||
$data.file = e.detail?.[0]
|
||||
lastTouched = "file"
|
||||
}}
|
||||
fileTags={[
|
||||
"OpenAPI 3.0",
|
||||
"OpenAPI 2.0",
|
||||
"Swagger 2.0",
|
||||
"cURL",
|
||||
"YAML",
|
||||
"JSON",
|
||||
]}
|
||||
maximum={1}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab title="Raw Text">
|
||||
<TextArea
|
||||
bind:value={$data.raw}
|
||||
on:change={() => (lastTouched = "raw")}
|
||||
label={"Paste raw text"}
|
||||
placeholder={'e.g. curl --location --request GET "https://example.com"'}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Layout>
|
||||
</ModalContent>
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
const validateDescription = description => {
|
||||
if (!description?.length) {
|
||||
return "Please enter a name"
|
||||
return "Please enter a description"
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -334,16 +334,15 @@
|
|||
EditorView.inputHandler.of((view, from, to, insert) => {
|
||||
if (jsBindingWrapping && insert === "$") {
|
||||
let { text } = view.state.doc.lineAt(from)
|
||||
|
||||
const left = from ? text.substring(0, from) : ""
|
||||
const right = to ? text.substring(to) : ""
|
||||
const wrap = !left.includes('$("') || !right.includes('")')
|
||||
const wrap =
|
||||
(!left.includes('$("') || !right.includes('")')) &&
|
||||
!(left.includes("`") && right.includes("`"))
|
||||
const anchor = from + (wrap ? 3 : 1)
|
||||
const tr = view.state.update(
|
||||
{
|
||||
changes: [{ from, insert: wrap ? '$("")' : "$" }],
|
||||
selection: {
|
||||
anchor: from + (wrap ? 3 : 1),
|
||||
},
|
||||
},
|
||||
{
|
||||
scrollIntoView: true,
|
||||
|
@ -351,6 +350,19 @@
|
|||
}
|
||||
)
|
||||
view.dispatch(tr)
|
||||
// the selection needs to fired after the dispatch - this seems
|
||||
// to fix an issue with the cursor not moving when the editor is
|
||||
// first loaded, the first usage of the editor is not ready
|
||||
// for the anchor to move as well as perform a change
|
||||
setTimeout(() => {
|
||||
view.dispatch(
|
||||
view.state.update({
|
||||
selection: {
|
||||
anchor,
|
||||
},
|
||||
})
|
||||
)
|
||||
}, 1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -519,6 +531,7 @@
|
|||
.code-editor {
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
cursor: text;
|
||||
}
|
||||
.code-editor :global(.cm-editor) {
|
||||
height: 100%;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { Label, Select, Body } from "@budibase/bbui"
|
||||
import { findAllMatchingComponents } from "@/helpers/components"
|
||||
import { selectedScreen } from "@/stores/builder"
|
||||
import { InlineAlert } from "@budibase/bbui"
|
||||
|
||||
export let parameters
|
||||
|
||||
|
@ -27,6 +28,12 @@
|
|||
<Label small>Table</Label>
|
||||
<Select bind:value={parameters.componentId} options={componentOptions} />
|
||||
</div>
|
||||
<InlineAlert
|
||||
header="Legacy action"
|
||||
message="This action is only compatible with the (deprecated) Table Block. Please see the documentation for further info."
|
||||
link="https://docs.budibase.com/docs/data-actions#clear-row-selection"
|
||||
linkText="Budibase Documentation"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<script>
|
||||
import { Label, Checkbox } from "@budibase/bbui"
|
||||
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
||||
|
||||
export let parameters
|
||||
export let bindings = []
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<Label>Text to copy</Label>
|
||||
<DrawerBindableInput
|
||||
title="Text to copy"
|
||||
{bindings}
|
||||
value={parameters.textToCopy}
|
||||
on:change={e => (parameters.textToCopy = e.detail)}
|
||||
/>
|
||||
<Label />
|
||||
<Checkbox text="Show notification" bind:value={parameters.showNotification} />
|
||||
{#if parameters.showNotification}
|
||||
<Label>Notification message</Label>
|
||||
<DrawerBindableInput
|
||||
title="Notification message"
|
||||
{bindings}
|
||||
value={parameters.notificationMessage}
|
||||
placeholder="Copied to clipboard"
|
||||
on:change={e => (parameters.notificationMessage = e.detail)}
|
||||
/>
|
||||
{/if}
|
||||
</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>
|
|
@ -26,3 +26,4 @@ export { default as CloseModal } from "./CloseModal.svelte"
|
|||
export { default as ClearRowSelection } from "./ClearRowSelection.svelte"
|
||||
export { default as DownloadFile } from "./DownloadFile.svelte"
|
||||
export { default as RowAction } from "./RowAction.svelte"
|
||||
export { default as CopyToClipboard } from "./CopyToClipboard.svelte"
|
||||
|
|
|
@ -183,6 +183,17 @@
|
|||
"name": "Row Action",
|
||||
"type": "data",
|
||||
"component": "RowAction"
|
||||
},
|
||||
{
|
||||
"name": "Copy To Clipboard",
|
||||
"type": "data",
|
||||
"component": "CopyToClipboard",
|
||||
"context": [
|
||||
{
|
||||
"label": "Copied text",
|
||||
"value": "copied"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { goto } from "@roxi/routify"
|
||||
import {
|
||||
keepOpen,
|
||||
|
@ -14,13 +14,14 @@
|
|||
} from "@budibase/bbui"
|
||||
import { datasources, queries } from "@/stores/builder"
|
||||
import { writable } from "svelte/store"
|
||||
import type { Datasource } from "@budibase/types"
|
||||
|
||||
export let navigateDatasource = false
|
||||
export let datasourceId
|
||||
export let datasourceId: string | undefined = undefined
|
||||
export let createDatasource = false
|
||||
export let onCancel
|
||||
export let onCancel: (() => void) | undefined = undefined
|
||||
|
||||
const data = writable({
|
||||
const data = writable<{ url: string; raw: string; file?: any }>({
|
||||
url: "",
|
||||
raw: "",
|
||||
file: undefined,
|
||||
|
@ -28,12 +29,14 @@
|
|||
|
||||
let lastTouched = "url"
|
||||
|
||||
const getData = async () => {
|
||||
$: datasource = $datasources.selected as Datasource
|
||||
|
||||
const getData = async (): Promise<string> => {
|
||||
let dataString
|
||||
|
||||
// parse the file into memory and send as string
|
||||
if (lastTouched === "file") {
|
||||
dataString = await $data.file.text()
|
||||
dataString = await $data.file?.text()
|
||||
} else if (lastTouched === "url") {
|
||||
const response = await fetch($data.url)
|
||||
dataString = await response.text()
|
||||
|
@ -55,9 +58,9 @@
|
|||
const body = {
|
||||
data: dataString,
|
||||
datasourceId,
|
||||
datasource,
|
||||
}
|
||||
|
||||
const importResult = await queries.import(body)
|
||||
const importResult = await queries.importQueries(body)
|
||||
if (!datasourceId) {
|
||||
datasourceId = importResult.datasourceId
|
||||
}
|
||||
|
@ -71,8 +74,8 @@
|
|||
}
|
||||
|
||||
notifications.success("Imported successfully")
|
||||
} catch (error) {
|
||||
notifications.error("Error importing queries")
|
||||
} catch (error: any) {
|
||||
notifications.error(`Error importing queries - ${error.message}`)
|
||||
|
||||
return keepOpen
|
||||
}
|
||||
|
|
|
@ -421,6 +421,28 @@ const showNotificationHandler = action => {
|
|||
|
||||
const promptUserHandler = () => {}
|
||||
|
||||
const copyToClipboardHandler = async action => {
|
||||
const { textToCopy, showNotification, notificationMessage } =
|
||||
action.parameters
|
||||
|
||||
if (!textToCopy) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(textToCopy)
|
||||
if (showNotification) {
|
||||
const message = notificationMessage || "Copied to clipboard"
|
||||
notificationStore.actions.success(message, true, 3000)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to copy text: ", err)
|
||||
notificationStore.actions.error("Failed to copy to clipboard")
|
||||
}
|
||||
|
||||
return { copied: textToCopy }
|
||||
}
|
||||
|
||||
const openSidePanelHandler = action => {
|
||||
const { id } = action.parameters
|
||||
if (id) {
|
||||
|
@ -514,6 +536,7 @@ const handlerMap = {
|
|||
["Close Modal"]: closeModalHandler,
|
||||
["Download File"]: downloadFileHandler,
|
||||
["Row Action"]: rowActionHandler,
|
||||
["Copy To Clipboard"]: copyToClipboardHandler,
|
||||
}
|
||||
|
||||
const confirmTextMap = {
|
||||
|
|
|
@ -168,6 +168,7 @@ class S3Integration implements IntegrationBase {
|
|||
secretAccessKey: config.secretAccessKey,
|
||||
},
|
||||
region: config.region,
|
||||
endpoint: config.endpoint,
|
||||
}
|
||||
if (config.endpoint) {
|
||||
this.config.forcePathStyle = true
|
||||
|
|
|
@ -11,7 +11,7 @@ export interface SaveQueryRequest extends Query {}
|
|||
export interface SaveQueryResponse extends Query {}
|
||||
|
||||
export interface ImportRestQueryRequest {
|
||||
datasourceId: string
|
||||
datasourceId?: string
|
||||
data: string
|
||||
datasource: Datasource
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue