First major part of the REST query resdesign.
This commit is contained in:
parent
f520d9f843
commit
a85213f280
|
@ -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}
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
|
@ -19,6 +19,7 @@
|
|||
)
|
||||
|
||||
export function addEntry() {
|
||||
console.log(fields)
|
||||
fields = [...fields, {}]
|
||||
changed()
|
||||
}
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<script>
|
||||
</script>
|
||||
|
||||
<slot />
|
|
@ -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>
|
Loading…
Reference in New Issue