Merge pull request #10584 from Budibase/feature/db-query-save-prompt
Database query save prompt
This commit is contained in:
commit
8784773f49
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
export let query = {}
|
export let query = {}
|
||||||
export let data = []
|
export let data = []
|
||||||
|
export let editRows = false
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
let error = false
|
let error = false
|
||||||
|
@ -12,7 +13,14 @@
|
||||||
{#if error}
|
{#if error}
|
||||||
<div class="errors">{error}</div>
|
<div class="errors">{error}</div>
|
||||||
{/if}
|
{/if}
|
||||||
<Table schema={query.schema} {data} {loading} {type} rowCount={5} />
|
<Table
|
||||||
|
schema={query.schema}
|
||||||
|
{data}
|
||||||
|
{loading}
|
||||||
|
{type}
|
||||||
|
rowCount={5}
|
||||||
|
allowEditing={editRows}
|
||||||
|
/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.errors {
|
.errors {
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
export let rowCount
|
export let rowCount
|
||||||
export let disableSorting = false
|
export let disableSorting = false
|
||||||
export let customPlaceholder = false
|
export let customPlaceholder = false
|
||||||
export let allowClickRows
|
|
||||||
export let allowEditing = true
|
export let allowEditing = true
|
||||||
|
export let allowClickRows
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
|
|
||||||
|
export let disabled = false
|
||||||
|
|
||||||
let revertModal
|
let revertModal
|
||||||
let appName
|
let appName
|
||||||
|
|
||||||
|
@ -34,6 +36,7 @@
|
||||||
size="M"
|
size="M"
|
||||||
tooltip="Revert changes"
|
tooltip="Revert changes"
|
||||||
on:click={revertModal.show}
|
on:click={revertModal.show}
|
||||||
|
{disabled}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal bind:this={revertModal}>
|
<Modal bind:this={revertModal}>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@roxi/routify"
|
import { goto, beforeUrlChange } from "@roxi/routify"
|
||||||
import {
|
import {
|
||||||
Icon,
|
Icon,
|
||||||
Select,
|
Select,
|
||||||
|
@ -12,6 +12,8 @@
|
||||||
Heading,
|
Heading,
|
||||||
Tabs,
|
Tabs,
|
||||||
Tab,
|
Tab,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { notifications, Divider } from "@budibase/bbui"
|
import { notifications, Divider } from "@budibase/bbui"
|
||||||
import ExtraQueryConfig from "./ExtraQueryConfig.svelte"
|
import ExtraQueryConfig from "./ExtraQueryConfig.svelte"
|
||||||
|
@ -29,6 +31,12 @@
|
||||||
|
|
||||||
export let query
|
export let query
|
||||||
|
|
||||||
|
const resumeNavigation = () => {
|
||||||
|
if (typeof navigateTo == "string") {
|
||||||
|
$goto(typeof navigateTo == "string" ? `${navigateTo}` : navigateTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const transformerDocs = "https://docs.budibase.com/docs/transformers"
|
const transformerDocs = "https://docs.budibase.com/docs/transformers"
|
||||||
|
|
||||||
let fields = query?.schema ? schemaToFields(query.schema) : []
|
let fields = query?.schema ? schemaToFields(query.schema) : []
|
||||||
|
@ -36,6 +44,31 @@
|
||||||
let data = []
|
let data = []
|
||||||
let saveId
|
let saveId
|
||||||
let currentTab = "JSON"
|
let currentTab = "JSON"
|
||||||
|
let saveModal
|
||||||
|
let override = false
|
||||||
|
let navigateTo = null
|
||||||
|
|
||||||
|
// seed the transformer
|
||||||
|
if (query && !query.transformer) {
|
||||||
|
query.transformer = "return data"
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialise a new empty schema
|
||||||
|
if (query && !query.schema) {
|
||||||
|
query.schema = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let queryStr = JSON.stringify(query)
|
||||||
|
|
||||||
|
$beforeUrlChange(event => {
|
||||||
|
const updated = JSON.stringify(query)
|
||||||
|
|
||||||
|
if (updated !== queryStr && !override) {
|
||||||
|
navigateTo = event.type == "pushstate" ? event.url : null
|
||||||
|
saveModal.show()
|
||||||
|
return false
|
||||||
|
} else return true
|
||||||
|
})
|
||||||
|
|
||||||
$: datasource = $datasources.list.find(ds => ds._id === query.datasourceId)
|
$: datasource = $datasources.list.find(ds => ds._id === query.datasourceId)
|
||||||
$: query.schema = fieldsToSchema(fields)
|
$: query.schema = fieldsToSchema(fields)
|
||||||
|
@ -60,11 +93,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// seed the transformer
|
|
||||||
if (query && !query.transformer) {
|
|
||||||
query.transformer = "return data"
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetDependentFields() {
|
function resetDependentFields() {
|
||||||
if (query.fields.extra) {
|
if (query.fields.extra) {
|
||||||
query.fields.extra = {}
|
query.fields.extra = {}
|
||||||
|
@ -101,22 +129,48 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return the query.
|
||||||
async function saveQuery() {
|
async function saveQuery() {
|
||||||
try {
|
try {
|
||||||
const { _id } = await queries.save(query.datasourceId, query)
|
const response = await queries.save(query.datasourceId, query)
|
||||||
saveId = _id
|
saveId = response._id
|
||||||
notifications.success(`Query saved successfully`)
|
|
||||||
|
|
||||||
// Go to the correct URL if we just created a new query
|
if (response?._rev) {
|
||||||
if (!query._rev) {
|
queryStr = JSON.stringify(query)
|
||||||
$goto(`../../${_id}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error saving query")
|
notifications.error("Error saving query")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
bind:this={saveModal}
|
||||||
|
on:hide={() => {
|
||||||
|
navigateTo = null
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ModalContent
|
||||||
|
title="You have unsaved changes"
|
||||||
|
confirmText="Save and Continue"
|
||||||
|
cancelText="Discard Changes"
|
||||||
|
size="L"
|
||||||
|
onConfirm={async () => {
|
||||||
|
await saveQuery()
|
||||||
|
override = true
|
||||||
|
resumeNavigation()
|
||||||
|
}}
|
||||||
|
onCancel={async () => {
|
||||||
|
override = true
|
||||||
|
resumeNavigation()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body>Leaving this section will mean losing and changes to your query</Body>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<Layout gap="S" noPadding>
|
<Layout gap="S" noPadding>
|
||||||
<Heading size="M">Query {integrationInfo?.friendlyName}</Heading>
|
<Heading size="M">Query {integrationInfo?.friendlyName}</Heading>
|
||||||
|
@ -125,7 +179,13 @@
|
||||||
<div class="config">
|
<div class="config">
|
||||||
<div class="config-field">
|
<div class="config-field">
|
||||||
<Label>Query Name</Label>
|
<Label>Query Name</Label>
|
||||||
<Input bind:value={query.name} />
|
<Input
|
||||||
|
value={query.name}
|
||||||
|
on:input={e => {
|
||||||
|
let newValue = e.target.value || ""
|
||||||
|
query.name = newValue.trim()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#if queryConfig}
|
{#if queryConfig}
|
||||||
<div class="config-field">
|
<div class="config-field">
|
||||||
|
@ -149,18 +209,20 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#key query.parameters}
|
{#key query.parameters}
|
||||||
<BindingBuilder
|
<div class="binding-wrap">
|
||||||
queryBindings={query.parameters}
|
<BindingBuilder
|
||||||
bindable={false}
|
queryBindings={query.parameters}
|
||||||
on:change={e => {
|
bindable={false}
|
||||||
query.parameters = e.detail.map(binding => {
|
on:change={e => {
|
||||||
return {
|
query.parameters = e.detail.map(binding => {
|
||||||
name: binding.name,
|
return {
|
||||||
default: binding.value,
|
name: binding.name,
|
||||||
}
|
default: binding.value,
|
||||||
})
|
}
|
||||||
}}
|
})
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -203,7 +265,18 @@
|
||||||
<div class="viewer-controls">
|
<div class="viewer-controls">
|
||||||
<Heading size="S">Results</Heading>
|
<Heading size="S">Results</Heading>
|
||||||
<ButtonGroup gap="XS">
|
<ButtonGroup gap="XS">
|
||||||
<Button cta disabled={queryInvalid} on:click={saveQuery}>
|
<Button
|
||||||
|
cta
|
||||||
|
disabled={queryInvalid}
|
||||||
|
on:click={async () => {
|
||||||
|
await saveQuery()
|
||||||
|
notifications.success(`Query saved successfully`)
|
||||||
|
// Go to the correct URL if we just created a new query
|
||||||
|
if (!query._rev) {
|
||||||
|
$goto(`../../${query._id}`)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
Save Query
|
Save Query
|
||||||
</Button>
|
</Button>
|
||||||
<Button secondary on:click={previewQuery}>Run Query</Button>
|
<Button secondary on:click={previewQuery}>Run Query</Button>
|
||||||
|
@ -274,4 +347,9 @@
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.binding-wrap :global(div.container) {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
import QueryViewer from "components/integration/QueryViewer.svelte"
|
import QueryViewer from "components/integration/QueryViewer.svelte"
|
||||||
import RestQueryViewer from "components/integration/RestQueryViewer.svelte"
|
import RestQueryViewer from "components/integration/RestQueryViewer.svelte"
|
||||||
import { IntegrationTypes } from "constants/backend"
|
import { IntegrationTypes } from "constants/backend"
|
||||||
|
import { cloneDeep } from "lodash/fp"
|
||||||
|
|
||||||
$: query = $queries.selected
|
$: query = $queries.selected
|
||||||
|
$: editableQuery = cloneDeep(query)
|
||||||
$: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
|
$: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
|
||||||
$: isRestQuery = datasource?.source === IntegrationTypes.REST
|
$: isRestQuery = datasource?.source === IntegrationTypes.REST
|
||||||
</script>
|
</script>
|
||||||
|
@ -13,6 +15,6 @@
|
||||||
{#if isRestQuery}
|
{#if isRestQuery}
|
||||||
<RestQueryViewer queryId={$queries.selectedQueryId} />
|
<RestQueryViewer queryId={$queries.selectedQueryId} />
|
||||||
{:else}
|
{:else}
|
||||||
<QueryViewer {query} />
|
<QueryViewer query={editableQuery} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
Loading…
Reference in New Issue