First major part of the REST query resdesign.

This commit is contained in:
mike12345567 2021-12-01 17:55:57 +00:00
parent f520d9f843
commit a85213f280
10 changed files with 313 additions and 4 deletions

View File

@ -0,0 +1,59 @@
<script>
import { createEventDispatcher } from "svelte"
let dispatch = createEventDispatcher()
export let type = "info"
export let icon = "Info"
export let size = "S"
export let extraButtonText
export let extraButtonAction
let show = true
function clear() {
show = false
dispatch("change")
}
</script>
{#if show}
<div class="spectrum-Toast spectrum-Toast--{type}">
<svg
class="spectrum-Icon spectrum-Icon--size{size} spectrum-Toast-typeIcon"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-icon-18-{icon}" />
</svg>
<div class="spectrum-Toast-body">
<div class="spectrum-Toast-content">
<slot />
</div>
{#if extraButtonText && extraButtonAction}
<button
class="spectrum-Button spectrum-Button--sizeM spectrum-Button--overBackground spectrum-Button--quiet"
on:click={extraButtonAction}
>
<span class="spectrum-Button-label">{extraButtonText}</span>
</button>
{/if}
</div>
<div class="spectrum-Toast-buttons">
<button
class="spectrum-ClearButton spectrum-ClearButton--overBackground spectrum-ClearButton--size{size}"
on:click={clear}
>
<div class="spectrum-ClearButton-fill">
<svg
class="spectrum-ClearButton-icon spectrum-Icon spectrum-UIIcon-Cross100"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-css-icon-Cross100" />
</svg>
</div>
</button>
</div>
</div>
{/if}

View File

@ -5,7 +5,7 @@
export let icon = ""
const dispatch = createEventDispatcher()
const selected = getContext("tab")
let selected = getContext("tab")
let tab
let tabInfo
@ -16,8 +16,8 @@
// We just need to get this off the main thread to fix this, by using
// a 0ms timeout.
setTimeout(() => {
tabInfo = tab.getBoundingClientRect()
if ($selected.title === title) {
tabInfo = tab?.getBoundingClientRect()
if (tabInfo && $selected.title === title) {
$selected.info = tabInfo
}
}, 0)

View File

@ -59,6 +59,7 @@ export { default as Badge } from "./Badge/Badge.svelte"
export { default as StatusLight } from "./StatusLight/StatusLight.svelte"
export { default as ColorPicker } from "./ColorPicker/ColorPicker.svelte"
export { default as InlineAlert } from "./InlineAlert/InlineAlert.svelte"
export { default as Banner } from "./Banner/Banner.svelte"
// Typography
export { default as Body } from "./Typography/Body.svelte"

View File

@ -0,0 +1,63 @@
<script>
import { Heading, Icon, Input, Label, Body } from "@budibase/bbui"
import { createEventDispatcher } from "svelte"
let dispatch = createEventDispatcher()
export let defaultValue = ""
export let value
export let type = "label"
export let size = "M"
let editing = false
function setEditing(state) {
editing = state
if (editing) {
dispatch("change")
}
}
</script>
<div class="parent">
{#if !editing}
{#if type === "heading"}
<Heading {size}>{value || defaultValue}</Heading>
{:else if type === "body"}
<Body {size}>{value || defaultValue}</Body>
{:else}
<Label {size}>{value || defaultValue}</Label>
{/if}
<div class="hide">
<Icon name="Edit" hoverable size="S" on:click={() => setEditing(true)} />
</div>
{:else}
<div class="input">
<Input placeholder={defaultValue} bind:value on:change />
</div>
<Icon
name="SaveFloppy"
hoverable
size="S"
on:click={() => setEditing(false)}
/>
{/if}
</div>
<style>
.parent {
display: flex;
align-items: center;
gap: var(--spacing-m);
}
.hide {
display: none;
margin-top: 5px;
}
.parent:hover .hide {
display: block;
}
.input {
flex: 1;
}
</style>

View File

@ -19,6 +19,7 @@
)
export function addEntry() {
console.log(fields)
fields = [...fields, {}]
changed()
}

View File

@ -1,6 +1,8 @@
<script>
import { params } from "@roxi/routify"
import { queries } from "stores/backend"
import { queries, datasources } from "stores/backend"
import { IntegrationTypes } from "constants"
import { goto } from "@roxi/routify"
if ($params.query) {
const query = $queries.list.find(q => q._id === $params.query)
@ -8,6 +10,12 @@
queries.select(query)
}
}
const datasource = $datasources.list.find(
ds => ds._id === $datasources.selected
)
if (datasource.source === IntegrationTypes.REST) {
$goto("../rest")
}
</script>
<slot />

View File

@ -0,0 +1,173 @@
<script>
import { params } from "@roxi/routify"
import { datasources, integrations, queries } from "stores/backend"
import {
Layout,
Input,
Select,
Tabs,
Tab,
Banner,
Divider,
Button,
Heading,
} from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import EditableLabel from "components/common/inputs/EditableLabel.svelte"
import CodeMirrorEditor from "components/common/CodeMirrorEditor.svelte"
import { capitalise } from "helpers"
import { onMount } from "svelte"
let query
let breakQs = {}
$: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
$: datasourceType = datasource?.source
$: integrationInfo = $integrations[datasourceType]
$: queryConfig = integrationInfo?.query
function getSelectedQuery() {
return (
$queries.list.find(q => q._id === $queries.selected) || {
datasourceId: $params.selectedDatasource,
parameters: [],
fields: {},
queryVerb: "read",
}
)
}
function breakQueryString(qs) {
if (!qs) {
return {}
}
const params = qs.split("&")
let paramObj = {}
for (let param of params) {
const [key, value] = param.split("=")
paramObj[key] = value
}
}
// function buildQueryString(obj) {
// let str = ""
// for (let [key, value] of Object.entries(obj)) {
// if (str !== "") {
// str += "&"
// }
// str += `${key}=${value}`
// }
// return str
// }
function checkQueryName(queryToCheck, url = null) {
if (queryToCheck && (!queryToCheck.name || queryToCheck.flags.urlName)) {
queryToCheck.flags.urlName = true
queryToCheck.name = url || queryToCheck.fields.path
}
}
function learnMoreBanner() {}
function saveQuery() {}
onMount(() => {
query = getSelectedQuery()
breakQs = breakQueryString(query?.fields.queryString)
if (query && !query.transformer) {
query.transformer = "return data"
}
if (query && !query.flags) {
query.flags = {
urlName: false,
bannerCleared: false,
}
}
})
</script>
{#if query}
<div class="inner">
<div class="top">
<Layout gap="S">
<EditableLabel
type="heading"
bind:value={query.name}
defaultValue="Untitled"
on:change={() => (query.flags.urlName = false)}
/>
<div class="url-block">
<div class="verb">
<Select
bind:value={query.queryVerb}
on:change={() => {}}
options={Object.keys(queryConfig)}
getOptionLabel={verb =>
queryConfig[verb]?.displayName || capitalise(verb)}
/>
</div>
<div class="url">
<Input
bind:value={query.fields.path}
on:change={({ detail }) => checkQueryName(query, detail)}
/>
</div>
<Button cta disabled={!query.fields.path} on:click={saveQuery}
>Send</Button
>
</div>
<Tabs selected="Params">
<Tab title="Params">
<KeyValueBuilder bind:object={breakQs} name="param" />
</Tab>
<Tab title="Headers" />
<Tab title="Body" />
<Tab title="Transformer">
<Layout noPadding>
{#if !query.flags.bannerCleared}
<Banner
extraButtonText="Learn more"
extraButtonAction={learnMoreBanner}
on:change={() => (query.flags.bannerCleared = true)}
>
Add a JavaScript function to transform the query result.
</Banner>
{/if}
<CodeMirrorEditor
height={200}
value={query.transformer}
resize="vertical"
on:change={e => (query.transformer = e.detail)}
/>
</Layout>
</Tab>
</Tabs>
</Layout>
</div>
<Layout paddingY="L">
<Divider size="S" />
<Heading size="M">Response</Heading>
</Layout>
</div>
{/if}
<style>
.inner {
width: 840px;
margin: 0 auto;
height: 100%;
}
.url-block {
display: flex;
gap: var(--spacing-s);
}
.verb {
flex: 1;
}
.url {
flex: 4;
}
.top {
min-height: 50%;
}
</style>