Merge remote-tracking branch 'origin/master' into feature/automation-sidebar
This commit is contained in:
commit
3610eaf158
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let focus = false
|
let isFocused = false
|
||||||
let textarea: HTMLTextAreaElement
|
let textarea: HTMLTextAreaElement
|
||||||
let scrollable = false
|
let scrollable = false
|
||||||
|
|
||||||
|
@ -27,8 +27,16 @@
|
||||||
$: minHeightString = getStyleString("min-height", minHeight)
|
$: minHeightString = getStyleString("min-height", minHeight)
|
||||||
$: dispatch("scrollable", scrollable)
|
$: dispatch("scrollable", scrollable)
|
||||||
|
|
||||||
|
export function focus() {
|
||||||
|
textarea.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function contents() {
|
||||||
|
return textarea.value
|
||||||
|
}
|
||||||
|
|
||||||
const onBlur = () => {
|
const onBlur = () => {
|
||||||
focus = false
|
isFocused = false
|
||||||
updateValue()
|
updateValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +73,7 @@
|
||||||
style={`${heightString}${minHeightString}`}
|
style={`${heightString}${minHeightString}`}
|
||||||
class="spectrum-Textfield spectrum-Textfield--multiline"
|
class="spectrum-Textfield spectrum-Textfield--multiline"
|
||||||
class:is-disabled={disabled}
|
class:is-disabled={disabled}
|
||||||
class:is-focused={focus}
|
class:is-focused={isFocused}
|
||||||
>
|
>
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -77,7 +85,7 @@
|
||||||
{readonly}
|
{readonly}
|
||||||
{id}
|
{id}
|
||||||
on:input={onChange}
|
on:input={onChange}
|
||||||
on:focus={() => (focus = true)}
|
on:focus={() => (isFocused = true)}
|
||||||
on:blur={onBlur}
|
on:blur={onBlur}
|
||||||
on:blur
|
on:blur
|
||||||
on:keypress
|
on:keypress
|
||||||
|
|
|
@ -1059,6 +1059,7 @@
|
||||||
inputData[key] = e.detail
|
inputData[key] = e.detail
|
||||||
}}
|
}}
|
||||||
completions={stepCompletions}
|
completions={stepCompletions}
|
||||||
|
{bindings}
|
||||||
mode={codeMode}
|
mode={codeMode}
|
||||||
autocompleteEnabled={codeMode !== EditorModes.JS}
|
autocompleteEnabled={codeMode !== EditorModes.JS}
|
||||||
bind:getCaretPosition
|
bind:getCaretPosition
|
||||||
|
|
|
@ -152,6 +152,7 @@
|
||||||
<div class="field-wrap json-field">
|
<div class="field-wrap json-field">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
value={readableValue}
|
value={readableValue}
|
||||||
|
{bindings}
|
||||||
on:blur={e => {
|
on:blur={e => {
|
||||||
onChange({
|
onChange({
|
||||||
row: {
|
row: {
|
||||||
|
|
|
@ -59,7 +59,11 @@
|
||||||
import { javascript } from "@codemirror/lang-javascript"
|
import { javascript } from "@codemirror/lang-javascript"
|
||||||
import { EditorModes } from "./"
|
import { EditorModes } from "./"
|
||||||
import { themeStore } from "@/stores/portal"
|
import { themeStore } from "@/stores/portal"
|
||||||
import { FeatureFlag, type EditorMode } from "@budibase/types"
|
import {
|
||||||
|
type EnrichedBinding,
|
||||||
|
FeatureFlag,
|
||||||
|
type EditorMode,
|
||||||
|
} from "@budibase/types"
|
||||||
import { tooltips } from "@codemirror/view"
|
import { tooltips } from "@codemirror/view"
|
||||||
import type { BindingCompletion, CodeValidator } from "@/types"
|
import type { BindingCompletion, CodeValidator } from "@/types"
|
||||||
import { validateHbsTemplate } from "./validator/hbs"
|
import { validateHbsTemplate } from "./validator/hbs"
|
||||||
|
@ -80,6 +84,7 @@
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
export let readonlyLineNumbers = false
|
export let readonlyLineNumbers = false
|
||||||
export let dropdown = DropdownPosition.Relative
|
export let dropdown = DropdownPosition.Relative
|
||||||
|
export let bindings: EnrichedBinding[] = []
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
@ -100,7 +105,8 @@
|
||||||
let promptInput: TextArea
|
let promptInput: TextArea
|
||||||
$: aiGenEnabled =
|
$: aiGenEnabled =
|
||||||
featureFlag.isEnabled(FeatureFlag.AI_JS_GENERATION) &&
|
featureFlag.isEnabled(FeatureFlag.AI_JS_GENERATION) &&
|
||||||
mode.name === "javascript"
|
mode.name === "javascript" &&
|
||||||
|
!readonly
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (autofocus && isEditorInitialised) {
|
if (autofocus && isEditorInitialised) {
|
||||||
|
@ -165,15 +171,24 @@
|
||||||
popoverWidth = 30
|
popoverWidth = 30
|
||||||
let code = ""
|
let code = ""
|
||||||
try {
|
try {
|
||||||
const resp = await API.generateJs({ prompt })
|
const resp = await API.generateJs({ prompt, bindings })
|
||||||
code = resp.code
|
code = resp.code
|
||||||
|
|
||||||
|
if (code === "") {
|
||||||
|
throw new Error(
|
||||||
|
"we didn't understand your prompt, please phrase your request in another way"
|
||||||
|
)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
notifications.error("Unable to generate code, please try again later.")
|
if (e instanceof Error) {
|
||||||
|
notifications.error(`Unable to generate code: ${e.message}`)
|
||||||
|
} else {
|
||||||
|
notifications.error("Unable to generate code, please try again later.")
|
||||||
|
}
|
||||||
code = previousContents
|
code = previousContents
|
||||||
popoverWidth = 300
|
|
||||||
promptLoading = false
|
promptLoading = false
|
||||||
popover.hide()
|
resetPopover()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
value = code
|
value = code
|
||||||
|
@ -189,6 +204,8 @@
|
||||||
suggestedCode = null
|
suggestedCode = null
|
||||||
previousContents = null
|
previousContents = null
|
||||||
resetPopover()
|
resetPopover()
|
||||||
|
dispatch("change", editor.state.doc.toString())
|
||||||
|
dispatch("blur", editor.state.doc.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
const rejectSuggestion = () => {
|
const rejectSuggestion = () => {
|
||||||
|
@ -513,13 +530,18 @@
|
||||||
bind:this={popover}
|
bind:this={popover}
|
||||||
minWidth={popoverWidth}
|
minWidth={popoverWidth}
|
||||||
anchor={popoverAnchor}
|
anchor={popoverAnchor}
|
||||||
|
on:close={() => {
|
||||||
|
if (suggestedCode) {
|
||||||
|
acceptSuggestion()
|
||||||
|
}
|
||||||
|
}}
|
||||||
align="left-outside"
|
align="left-outside"
|
||||||
>
|
>
|
||||||
{#if promptLoading}
|
{#if promptLoading}
|
||||||
<div class="prompt-spinner">
|
<div class="prompt-spinner">
|
||||||
<Spinner size="20" color="white" />
|
<Spinner size="20" color="white" />
|
||||||
</div>
|
</div>
|
||||||
{:else if suggestedCode}
|
{:else if suggestedCode !== null}
|
||||||
<Button on:click={acceptSuggestion}>Accept</Button>
|
<Button on:click={acceptSuggestion}>Accept</Button>
|
||||||
<Button on:click={rejectSuggestion}>Reject</Button>
|
<Button on:click={rejectSuggestion}>Reject</Button>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
@ -359,6 +359,7 @@
|
||||||
bind:getCaretPosition
|
bind:getCaretPosition
|
||||||
bind:insertAtPos
|
bind:insertAtPos
|
||||||
{completions}
|
{completions}
|
||||||
|
{bindings}
|
||||||
{validations}
|
{validations}
|
||||||
autofocus={autofocusEditor}
|
autofocus={autofocusEditor}
|
||||||
placeholder={placeholder ||
|
placeholder={placeholder ||
|
||||||
|
@ -372,6 +373,7 @@
|
||||||
value={jsValue ? decodeJSBinding(jsValue) : ""}
|
value={jsValue ? decodeJSBinding(jsValue) : ""}
|
||||||
on:change={onChangeJSValue}
|
on:change={onChangeJSValue}
|
||||||
{completions}
|
{completions}
|
||||||
|
{bindings}
|
||||||
{validations}
|
{validations}
|
||||||
mode={EditorModes.JS}
|
mode={EditorModes.JS}
|
||||||
bind:getCaretPosition
|
bind:getCaretPosition
|
||||||
|
|
|
@ -147,6 +147,7 @@
|
||||||
on:change={onChangeJSValue}
|
on:change={onChangeJSValue}
|
||||||
on:blur
|
on:blur
|
||||||
completions={jsCompletions}
|
completions={jsCompletions}
|
||||||
|
{bindings}
|
||||||
mode={EditorModes.JS}
|
mode={EditorModes.JS}
|
||||||
bind:getCaretPosition
|
bind:getCaretPosition
|
||||||
bind:insertAtPos
|
bind:insertAtPos
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
export let type = "label"
|
export let type = "label"
|
||||||
export let size = "M"
|
export let size = "M"
|
||||||
|
|
||||||
|
export const disableEditingState = () => setEditing(false)
|
||||||
|
|
||||||
let editing = false
|
let editing = false
|
||||||
|
|
||||||
function setEditing(state) {
|
function setEditing(state) {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
import { lowercase } from "@/helpers"
|
import { lowercase } from "@/helpers"
|
||||||
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let defaults = undefined
|
export let defaults = undefined
|
||||||
export let object = defaults || {}
|
export let object = defaults || {}
|
||||||
|
@ -46,10 +46,17 @@
|
||||||
}))
|
}))
|
||||||
let fieldActivity = buildFieldActivity(activity)
|
let fieldActivity = buildFieldActivity(activity)
|
||||||
|
|
||||||
$: object = fields.reduce(
|
$: fullObject = fields.reduce((acc, next) => {
|
||||||
(acc, next) => ({ ...acc, [next.name]: next.value }),
|
acc[next.name] = next.value
|
||||||
{}
|
return acc
|
||||||
)
|
}, {})
|
||||||
|
|
||||||
|
$: object = Object.entries(fullObject).reduce((acc, [key, next]) => {
|
||||||
|
if (key) {
|
||||||
|
acc[key] = next
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
function buildFieldActivity(obj) {
|
function buildFieldActivity(obj) {
|
||||||
if (!obj || typeof obj !== "object") {
|
if (!obj || typeof obj !== "object") {
|
||||||
|
@ -77,16 +84,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function changed() {
|
function changed() {
|
||||||
|
// Required for reactivity
|
||||||
fields = fields
|
fields = fields
|
||||||
const newActivity = {}
|
const newActivity = {}
|
||||||
|
const trimmedFields = []
|
||||||
for (let idx = 0; idx < fields.length; idx++) {
|
for (let idx = 0; idx < fields.length; idx++) {
|
||||||
const fieldName = fields[idx].name
|
const fieldName = fields[idx].name
|
||||||
if (fieldName) {
|
if (fieldName) {
|
||||||
newActivity[fieldName] = fieldActivity[idx]
|
newActivity[fieldName] = fieldActivity[idx]
|
||||||
|
trimmedFields.push(fields[idx])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activity = newActivity
|
activity = newActivity
|
||||||
dispatch("change", fields)
|
dispatch("change", trimmedFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isJsonArray(value) {
|
function isJsonArray(value) {
|
||||||
|
@ -101,7 +111,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Builds Objects with Key Value Pairs. Useful for building things like Request Headers. -->
|
<!-- Builds Objects with Key Value Pairs. Useful for building things like Request Headers. -->
|
||||||
{#if Object.keys(object || {}).length > 0}
|
{#if Object.keys(fullObject || {}).length > 0}
|
||||||
{#if headings}
|
{#if headings}
|
||||||
<div class="container" class:container-active={toggle}>
|
<div class="container" class:container-active={toggle}>
|
||||||
<Label {tooltip}>{keyHeading || keyPlaceholder}</Label>
|
<Label {tooltip}>{keyHeading || keyPlaceholder}</Label>
|
||||||
|
|
|
@ -56,12 +56,13 @@
|
||||||
let query, datasource
|
let query, datasource
|
||||||
let breakQs = {},
|
let breakQs = {},
|
||||||
requestBindings = {}
|
requestBindings = {}
|
||||||
let saveId, url
|
let saveId
|
||||||
let response, schema, enabledHeaders
|
let response, schema, enabledHeaders
|
||||||
let authConfigId
|
|
||||||
let dynamicVariables, addVariableModal, varBinding, globalDynamicBindings
|
let dynamicVariables, addVariableModal, varBinding, globalDynamicBindings
|
||||||
let restBindings = getRestBindings()
|
let restBindings = getRestBindings()
|
||||||
let nestedSchemaFields = {}
|
let nestedSchemaFields = {}
|
||||||
|
let saving
|
||||||
|
let queryNameLabel
|
||||||
|
|
||||||
$: staticVariables = datasource?.config?.staticVariables || {}
|
$: staticVariables = datasource?.config?.staticVariables || {}
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@
|
||||||
$: datasourceType = datasource?.source
|
$: datasourceType = datasource?.source
|
||||||
$: integrationInfo = $integrations[datasourceType]
|
$: integrationInfo = $integrations[datasourceType]
|
||||||
$: queryConfig = integrationInfo?.query
|
$: queryConfig = integrationInfo?.query
|
||||||
$: url = buildUrl(url, breakQs)
|
$: url = buildUrl(query?.fields?.path, breakQs)
|
||||||
$: checkQueryName(url)
|
$: checkQueryName(url)
|
||||||
$: responseSuccess = response?.info?.code >= 200 && response?.info?.code < 400
|
$: responseSuccess = response?.info?.code >= 200 && response?.info?.code < 400
|
||||||
$: isGet = query?.queryVerb === "read"
|
$: isGet = query?.queryVerb === "read"
|
||||||
|
@ -103,6 +104,10 @@
|
||||||
|
|
||||||
$: runtimeUrlQueries = readableToRuntimeMap(mergedBindings, breakQs)
|
$: runtimeUrlQueries = readableToRuntimeMap(mergedBindings, breakQs)
|
||||||
|
|
||||||
|
$: originalQuery = originalQuery ?? cloneDeep(query)
|
||||||
|
$: builtQuery = buildQuery(query, runtimeUrlQueries, requestBindings)
|
||||||
|
$: isModified = JSON.stringify(originalQuery) !== JSON.stringify(builtQuery)
|
||||||
|
|
||||||
function getSelectedQuery() {
|
function getSelectedQuery() {
|
||||||
return cloneDeep(
|
return cloneDeep(
|
||||||
$queries.list.find(q => q._id === queryId) || {
|
$queries.list.find(q => q._id === queryId) || {
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
?.trim() || inputUrl
|
?.trim() || inputUrl
|
||||||
|
|
||||||
function checkQueryName(inputUrl = null) {
|
function checkQueryName(inputUrl = null) {
|
||||||
if (query && (!query.name || query.flags.urlName)) {
|
if (query && (!query.name || query.flags?.urlName)) {
|
||||||
|
query.flags ??= {}
|
||||||
query.flags.urlName = true
|
query.flags.urlName = true
|
||||||
query.name = cleanUrl(inputUrl)
|
query.name = cleanUrl(inputUrl)
|
||||||
}
|
}
|
||||||
|
@ -147,9 +153,12 @@
|
||||||
return qs.length === 0 ? newUrl : `${newUrl}?${qs}`
|
return qs.length === 0 ? newUrl : `${newUrl}?${qs}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildQuery() {
|
function buildQuery(fromQuery, urlQueries, requestBindings) {
|
||||||
const newQuery = cloneDeep(query)
|
if (!fromQuery) {
|
||||||
const queryString = restUtils.buildQueryString(runtimeUrlQueries)
|
return
|
||||||
|
}
|
||||||
|
const newQuery = cloneDeep(fromQuery)
|
||||||
|
const queryString = restUtils.buildQueryString(urlQueries)
|
||||||
|
|
||||||
newQuery.parameters = restUtils.keyValueToQueryParameters(requestBindings)
|
newQuery.parameters = restUtils.keyValueToQueryParameters(requestBindings)
|
||||||
newQuery.fields.requestBody =
|
newQuery.fields.requestBody =
|
||||||
|
@ -157,9 +166,8 @@
|
||||||
? readableToRuntimeMap(mergedBindings, newQuery.fields.requestBody)
|
? readableToRuntimeMap(mergedBindings, newQuery.fields.requestBody)
|
||||||
: readableToRuntimeBinding(mergedBindings, newQuery.fields.requestBody)
|
: readableToRuntimeBinding(mergedBindings, newQuery.fields.requestBody)
|
||||||
|
|
||||||
newQuery.fields.path = url.split("?")[0]
|
newQuery.fields.path = url?.split("?")[0]
|
||||||
newQuery.fields.queryString = queryString
|
newQuery.fields.queryString = queryString
|
||||||
newQuery.fields.authConfigId = authConfigId
|
|
||||||
newQuery.fields.disabledHeaders = restUtils.flipHeaderState(enabledHeaders)
|
newQuery.fields.disabledHeaders = restUtils.flipHeaderState(enabledHeaders)
|
||||||
newQuery.schema = schema || {}
|
newQuery.schema = schema || {}
|
||||||
newQuery.nestedSchemaFields = nestedSchemaFields || {}
|
newQuery.nestedSchemaFields = nestedSchemaFields || {}
|
||||||
|
@ -168,13 +176,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveQuery() {
|
async function saveQuery() {
|
||||||
const toSave = buildQuery()
|
const toSave = builtQuery
|
||||||
|
saving = true
|
||||||
try {
|
try {
|
||||||
const isNew = !query._rev
|
const isNew = !query._rev
|
||||||
const { _id } = await queries.save(toSave.datasourceId, toSave)
|
const { _id } = await queries.save(toSave.datasourceId, toSave)
|
||||||
saveId = _id
|
saveId = _id
|
||||||
query = getSelectedQuery()
|
|
||||||
notifications.success(`Request saved successfully`)
|
|
||||||
if (dynamicVariables) {
|
if (dynamicVariables) {
|
||||||
datasource.config.dynamicVariables = rebuildVariables(saveId)
|
datasource.config.dynamicVariables = rebuildVariables(saveId)
|
||||||
datasource = await datasources.save({
|
datasource = await datasources.save({
|
||||||
|
@ -182,6 +189,13 @@
|
||||||
datasource,
|
datasource,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifications.success(`Request saved successfully`)
|
||||||
|
if (isNew) {
|
||||||
|
$goto(`../../${_id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = getSelectedQuery()
|
||||||
prettifyQueryRequestBody(
|
prettifyQueryRequestBody(
|
||||||
query,
|
query,
|
||||||
requestBindings,
|
requestBindings,
|
||||||
|
@ -189,11 +203,15 @@
|
||||||
staticVariables,
|
staticVariables,
|
||||||
restBindings
|
restBindings
|
||||||
)
|
)
|
||||||
if (isNew) {
|
|
||||||
$goto(`../../${_id}`)
|
// Force rebuilding original query
|
||||||
}
|
originalQuery = null
|
||||||
|
|
||||||
|
queryNameLabel.disableEditingState()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.error(`Error saving query`)
|
notifications.error(`Error saving query`)
|
||||||
|
} finally {
|
||||||
|
saving = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +245,7 @@
|
||||||
async function runQuery() {
|
async function runQuery() {
|
||||||
try {
|
try {
|
||||||
await validateQuery()
|
await validateQuery()
|
||||||
response = await queries.preview(buildQuery())
|
response = await queries.preview(builtQuery)
|
||||||
if (response.rows.length === 0) {
|
if (response.rows.length === 0) {
|
||||||
notifications.info("Request did not return any data")
|
notifications.info("Request did not return any data")
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,22 +267,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAuthConfigId = () => {
|
|
||||||
let id = query.fields.authConfigId
|
|
||||||
if (id) {
|
|
||||||
// find the matching config on the datasource
|
|
||||||
const matchedConfig = datasource?.config?.authConfigs?.filter(
|
|
||||||
c => c._id === id
|
|
||||||
)[0]
|
|
||||||
// clear the id if the config is not found (deleted)
|
|
||||||
// i.e. just show 'None' in the dropdown
|
|
||||||
if (!matchedConfig) {
|
|
||||||
id = undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildAuthConfigs = datasource => {
|
const buildAuthConfigs = datasource => {
|
||||||
if (datasource?.config?.authConfigs) {
|
if (datasource?.config?.authConfigs) {
|
||||||
return datasource.config.authConfigs.map(c => ({
|
return datasource.config.authConfigs.map(c => ({
|
||||||
|
@ -375,13 +377,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramsChanged = evt => {
|
|
||||||
breakQs = {}
|
|
||||||
for (let param of evt.detail) {
|
|
||||||
breakQs[param.name] = param.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlChanged = evt => {
|
const urlChanged = evt => {
|
||||||
breakQs = {}
|
breakQs = {}
|
||||||
const qs = evt.target.value.split("?")[1]
|
const qs = evt.target.value.split("?")[1]
|
||||||
|
@ -426,9 +421,7 @@
|
||||||
) {
|
) {
|
||||||
query.fields.path = `${datasource.config.url}/${path ? path : ""}`
|
query.fields.path = `${datasource.config.url}/${path ? path : ""}`
|
||||||
}
|
}
|
||||||
url = buildUrl(query.fields.path, breakQs)
|
|
||||||
requestBindings = restUtils.queryParametersToKeyValue(query.parameters)
|
requestBindings = restUtils.queryParametersToKeyValue(query.parameters)
|
||||||
authConfigId = getAuthConfigId()
|
|
||||||
if (!query.fields.disabledHeaders) {
|
if (!query.fields.disabledHeaders) {
|
||||||
query.fields.disabledHeaders = {}
|
query.fields.disabledHeaders = {}
|
||||||
}
|
}
|
||||||
|
@ -497,6 +490,7 @@
|
||||||
<Layout gap="S">
|
<Layout gap="S">
|
||||||
<div class="top-bar">
|
<div class="top-bar">
|
||||||
<EditableLabel
|
<EditableLabel
|
||||||
|
bind:this={queryNameLabel}
|
||||||
type="heading"
|
type="heading"
|
||||||
bind:value={query.name}
|
bind:value={query.name}
|
||||||
defaultValue="Untitled"
|
defaultValue="Untitled"
|
||||||
|
@ -504,7 +498,9 @@
|
||||||
on:save={saveQuery}
|
on:save={saveQuery}
|
||||||
/>
|
/>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<ConnectedQueryScreens sourceId={query._id} />
|
{#if query._id}
|
||||||
|
<ConnectedQueryScreens sourceId={query._id} />
|
||||||
|
{/if}
|
||||||
<div class="access">
|
<div class="access">
|
||||||
<Label>Access</Label>
|
<Label>Access</Label>
|
||||||
<AccessLevelSelect {query} {saveId} />
|
<AccessLevelSelect {query} {saveId} />
|
||||||
|
@ -524,13 +520,13 @@
|
||||||
<div class="url">
|
<div class="url">
|
||||||
<Input
|
<Input
|
||||||
on:blur={urlChanged}
|
on:blur={urlChanged}
|
||||||
bind:value={url}
|
bind:value={query.fields.path}
|
||||||
placeholder="http://www.api.com/endpoint"
|
placeholder="http://www.api.com/endpoint"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button primary disabled={!url} on:click={runQuery}>Send</Button>
|
<Button primary disabled={!url} on:click={runQuery}>Send</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={!query.name}
|
disabled={!query.name || !isModified || saving}
|
||||||
cta
|
cta
|
||||||
on:click={saveQuery}
|
on:click={saveQuery}
|
||||||
tooltip={!hasSchema
|
tooltip={!hasSchema
|
||||||
|
@ -556,15 +552,12 @@
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Params">
|
<Tab title="Params">
|
||||||
{#key breakQs}
|
<KeyValueBuilder
|
||||||
<KeyValueBuilder
|
bind:object={breakQs}
|
||||||
on:change={paramsChanged}
|
name="param"
|
||||||
object={breakQs}
|
headings
|
||||||
name="param"
|
bindings={mergedBindings}
|
||||||
headings
|
/>
|
||||||
bindings={mergedBindings}
|
|
||||||
/>
|
|
||||||
{/key}
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Headers">
|
<Tab title="Headers">
|
||||||
<KeyValueBuilder
|
<KeyValueBuilder
|
||||||
|
@ -651,7 +644,7 @@
|
||||||
label="Auth"
|
label="Auth"
|
||||||
labelPosition="left"
|
labelPosition="left"
|
||||||
placeholder="None"
|
placeholder="None"
|
||||||
bind:value={authConfigId}
|
bind:value={query.fields.authConfigId}
|
||||||
options={authConfigs}
|
options={authConfigs}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
<script>
|
<script>
|
||||||
import RestAuthenticationBuilder from "./RestAuthenticationBuilder.svelte"
|
import RestAuthenticationBuilder from "./RestAuthenticationBuilder.svelte"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import SaveDatasourceButton from "../SaveDatasourceButton.svelte"
|
|
||||||
import Panel from "../Panel.svelte"
|
import Panel from "../Panel.svelte"
|
||||||
import Tooltip from "../Tooltip.svelte"
|
import Tooltip from "../Tooltip.svelte"
|
||||||
|
import { integrations } from "@/stores/builder"
|
||||||
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
export let datasource
|
export let datasource
|
||||||
$: updatedDatasource = cloneDeep(datasource)
|
$: updatedDatasource = cloneDeep(datasource)
|
||||||
|
|
||||||
const updateAuthConfigs = newAuthConfigs => {
|
const updateAuthConfigs = async newAuthConfigs => {
|
||||||
updatedDatasource.config.authConfigs = newAuthConfigs
|
updatedDatasource.config.authConfigs = newAuthConfigs
|
||||||
|
|
||||||
|
try {
|
||||||
|
await integrations.saveDatasource(updatedDatasource)
|
||||||
|
notifications.success(
|
||||||
|
`Datasource ${updatedDatasource.name} updated successfully`
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error(`Error saving datasource: ${error.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Panel>
|
<Panel>
|
||||||
<SaveDatasourceButton slot="controls" {datasource} {updatedDatasource} />
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
slot="tooltip"
|
slot="tooltip"
|
||||||
title="REST Authentication"
|
title="REST Authentication"
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { get } from "svelte/store"
|
|
||||||
import { isEqual } from "lodash"
|
import { isEqual } from "lodash"
|
||||||
import { integrationForDatasource } from "@/stores/selectors"
|
import { integrations } from "@/stores/builder"
|
||||||
import { integrations, datasources } from "@/stores/builder"
|
|
||||||
import { notifications, Button } from "@budibase/bbui"
|
import { notifications, Button } from "@budibase/bbui"
|
||||||
|
|
||||||
export let datasource
|
export let datasource
|
||||||
|
@ -12,11 +10,7 @@
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
try {
|
try {
|
||||||
const integration = integrationForDatasource(
|
await integrations.saveDatasource(updatedDatasource)
|
||||||
get(integrations),
|
|
||||||
updatedDatasource
|
|
||||||
)
|
|
||||||
await datasources.save({ datasource: updatedDatasource, integration })
|
|
||||||
notifications.success(
|
notifications.success(
|
||||||
`Datasource ${updatedDatasource.name} updated successfully`
|
`Datasource ${updatedDatasource.name} updated successfully`
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { writable, type Writable } from "svelte/store"
|
import { get, writable, type Writable } from "svelte/store"
|
||||||
import { API } from "@/api"
|
import { API } from "@/api"
|
||||||
import { Integration } from "@budibase/types"
|
import { Datasource, Integration } from "@budibase/types"
|
||||||
|
import { integrationForDatasource } from "@/stores/selectors"
|
||||||
|
import { datasources } from "./datasources"
|
||||||
|
|
||||||
type IntegrationsState = Record<string, Integration>
|
type IntegrationsState = Record<string, Integration>
|
||||||
|
|
||||||
|
@ -25,9 +27,15 @@ const createIntegrationsStore = () => {
|
||||||
store.set(integrations)
|
store.set(integrations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saveDatasource = async (datasource: Datasource) => {
|
||||||
|
const integration = integrationForDatasource(get(store), datasource)
|
||||||
|
await datasources.save({ datasource, integration })
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...store,
|
...store,
|
||||||
init,
|
init,
|
||||||
|
saveDatasource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit bb1ed6fa96ebed30e30659e47b0712567601f3c0
|
Subproject commit f709bb6a07483785c32ebb6f186709450d735ec3
|
|
@ -1,6 +1,10 @@
|
||||||
|
import { EnrichedBinding } from "../../ui"
|
||||||
|
|
||||||
export interface GenerateJsRequest {
|
export interface GenerateJsRequest {
|
||||||
prompt: string
|
prompt: string
|
||||||
|
bindings?: EnrichedBinding[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenerateJsResponse {
|
export interface GenerateJsResponse {
|
||||||
code: string
|
code: string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue