Merge pull request #993 from Budibase/external-tables
External Data Connectors
This commit is contained in:
commit
77241281b8
|
@ -70,6 +70,7 @@
|
|||
"@sentry/browser": "5.19.1",
|
||||
"@svelteschool/svelte-forms": "^0.7.0",
|
||||
"britecharts": "^2.16.0",
|
||||
"codemirror": "^5.59.0",
|
||||
"d3-selection": "^1.4.1",
|
||||
"deepmerge": "^4.2.2",
|
||||
"fast-sort": "^2.2.0",
|
||||
|
|
|
@ -23,13 +23,20 @@ import { cloneDeep, difference } from "lodash/fp"
|
|||
* @param {fetchBindablePropertiesParameter} param
|
||||
* @returns {Array.<BindableProperty>}
|
||||
*/
|
||||
export default function({ componentInstanceId, screen, components, tables }) {
|
||||
export default function({
|
||||
componentInstanceId,
|
||||
screen,
|
||||
components,
|
||||
tables,
|
||||
queries,
|
||||
}) {
|
||||
const result = walk({
|
||||
// cloning so we are free to mutate props (e.g. by adding _contexts)
|
||||
instance: cloneDeep(screen.props),
|
||||
targetId: componentInstanceId,
|
||||
components,
|
||||
tables,
|
||||
queries,
|
||||
})
|
||||
|
||||
return [
|
||||
|
@ -37,6 +44,9 @@ export default function({ componentInstanceId, screen, components, tables }) {
|
|||
.filter(isInstanceInSharedContext(result))
|
||||
.map(componentInstanceToBindable),
|
||||
...(result.target?._contexts.map(contextToBindables(tables)).flat() ?? []),
|
||||
...(result.target?._contexts
|
||||
.map(context => queriesToBindables(queries, context))
|
||||
.flat() ?? []),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -61,9 +71,36 @@ const componentInstanceToBindable = i => {
|
|||
}
|
||||
}
|
||||
|
||||
const queriesToBindables = (queries, context) => {
|
||||
let queryId = context.table._id
|
||||
|
||||
const query = queries.find(query => query._id === queryId)
|
||||
let schema = query?.schema
|
||||
|
||||
// Avoid crashing whenever no data source has been selected
|
||||
if (!schema) {
|
||||
return []
|
||||
}
|
||||
|
||||
const queryBindings = Object.entries(schema).map(([key, value]) => ({
|
||||
type: "context",
|
||||
fieldSchema: value,
|
||||
instance: context.instance,
|
||||
// how the binding expression persists, and is used in the app at runtime
|
||||
runtimeBinding: `${context.instance._id}.${key}`,
|
||||
// how the binding expressions looks to the user of the builder
|
||||
readableBinding: `${context.instance._instanceName}.${query.name}.${key}`,
|
||||
// table / view info
|
||||
table: context.table,
|
||||
}))
|
||||
|
||||
return queryBindings
|
||||
}
|
||||
|
||||
const contextToBindables = tables => context => {
|
||||
const tableId = context.table?.tableId ?? context.table
|
||||
const table = tables.find(table => table._id === tableId)
|
||||
let tableId = context.table?.tableId ?? context.table
|
||||
|
||||
const table = tables.find(table => table._id === tableId || context.table._id)
|
||||
let schema =
|
||||
context.table?.type === "view"
|
||||
? table?.views?.[context.table.name]?.schema
|
||||
|
@ -152,8 +189,8 @@ const walk = ({ instance, targetId, components, tables, result }) => {
|
|||
|
||||
const currentContexts = [...result.currentContexts]
|
||||
for (let child of instance._children || []) {
|
||||
// attaching _contexts of components, for eas comparison later
|
||||
// these have been deep cloned above, so shouln't modify the
|
||||
// attaching _contexts of components, for easy comparison later
|
||||
// these have been deep cloned above, so shouldn't modify the
|
||||
// original component instances
|
||||
child._contexts = currentContexts
|
||||
walk({ instance: child, targetId, components, tables, result })
|
||||
|
|
|
@ -7,6 +7,9 @@ const INITIAL_BACKEND_UI_STATE = {
|
|||
views: [],
|
||||
users: [],
|
||||
roles: [],
|
||||
datasources: [],
|
||||
queries: [],
|
||||
integrations: {},
|
||||
selectedDatabase: {},
|
||||
selectedTable: {},
|
||||
draftTable: {},
|
||||
|
@ -21,9 +24,19 @@ export const getBackendUiStore = () => {
|
|||
select: async db => {
|
||||
const tablesResponse = await api.get(`/api/tables`)
|
||||
const tables = await tablesResponse.json()
|
||||
const datasourcesResponse = await api.get(`/api/datasources`)
|
||||
const datasources = await datasourcesResponse.json()
|
||||
const queriesResponse = await api.get(`/api/queries`)
|
||||
const queries = await queriesResponse.json()
|
||||
const integrationsResponse = await api.get("/api/integrations")
|
||||
const integrations = await integrationsResponse.json()
|
||||
|
||||
store.update(state => {
|
||||
state.selectedDatabase = db
|
||||
state.tables = tables
|
||||
state.datasources = datasources
|
||||
state.queries = queries
|
||||
state.integrations = integrations
|
||||
return state
|
||||
})
|
||||
},
|
||||
|
@ -45,6 +58,107 @@ export const getBackendUiStore = () => {
|
|||
return state
|
||||
}),
|
||||
},
|
||||
datasources: {
|
||||
fetch: async () => {
|
||||
const response = await api.get(`/api/datasources`)
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
state.datasources = json
|
||||
return state
|
||||
})
|
||||
return json
|
||||
},
|
||||
select: async datasourceId => {
|
||||
store.update(state => {
|
||||
state.selectedDatasourceId = datasourceId
|
||||
state.selectedQueryId = null
|
||||
return state
|
||||
})
|
||||
},
|
||||
save: async datasource => {
|
||||
const response = await api.post("/api/datasources", datasource)
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
const currentIdx = state.datasources.findIndex(
|
||||
ds => ds._id === json._id
|
||||
)
|
||||
|
||||
if (currentIdx >= 0) {
|
||||
state.datasources.splice(currentIdx, 1, json)
|
||||
} else {
|
||||
state.datasources.push(json)
|
||||
}
|
||||
|
||||
state.datasources = state.datasources
|
||||
state.selectedDatasourceId = json._id
|
||||
return state
|
||||
})
|
||||
return json
|
||||
},
|
||||
delete: async datasource => {
|
||||
await api.delete(
|
||||
`/api/datasources/${datasource._id}/${datasource._rev}`
|
||||
)
|
||||
store.update(state => {
|
||||
state.datasources = state.datasources.filter(
|
||||
existing => existing._id !== datasource._id
|
||||
)
|
||||
state.selectedDatasourceId = null
|
||||
return state
|
||||
})
|
||||
},
|
||||
},
|
||||
queries: {
|
||||
fetch: async () => {
|
||||
const response = await api.get(`/api/queries`)
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
state.queries = json
|
||||
return state
|
||||
})
|
||||
return json
|
||||
},
|
||||
save: async (datasourceId, query) => {
|
||||
query.datasourceId = datasourceId
|
||||
const response = await api.post(`/api/queries`, query)
|
||||
const json = await response.json()
|
||||
store.update(state => {
|
||||
const currentIdx = state.queries.findIndex(
|
||||
query => query._id === json._id
|
||||
)
|
||||
|
||||
if (currentIdx >= 0) {
|
||||
state.queries.splice(currentIdx, 1, json)
|
||||
} else {
|
||||
state.queries.push(json)
|
||||
}
|
||||
|
||||
state.queries = state.queries
|
||||
state.selectedQueryId = json._id
|
||||
return state
|
||||
})
|
||||
return json
|
||||
},
|
||||
select: query =>
|
||||
store.update(state => {
|
||||
state.selectedDatasourceId = query.datasourceId
|
||||
state.selectedQueryId = query._id
|
||||
return state
|
||||
}),
|
||||
delete: async query => {
|
||||
await api.delete(`/api/queries/${query._id}/${query._rev}`)
|
||||
store.update(state => {
|
||||
state.queries = state.queries.filter(
|
||||
existing => existing._id !== query._id
|
||||
)
|
||||
if (state.selectedQueryId === query._id) {
|
||||
state.selectedQueryId = null
|
||||
}
|
||||
|
||||
return state
|
||||
})
|
||||
},
|
||||
},
|
||||
tables: {
|
||||
fetch: async () => {
|
||||
const tablesResponse = await api.get(`/api/tables`)
|
||||
|
|
|
@ -42,6 +42,7 @@ const INITIAL_FRONTEND_STATE = {
|
|||
libraries: null,
|
||||
appId: "",
|
||||
routes: {},
|
||||
bottomDrawerVisible: false,
|
||||
}
|
||||
|
||||
export const getFrontendStore = () => {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<script>
|
||||
import { params } from "@sveltech/routify"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import * as api from "./api"
|
||||
import Table from "./Table.svelte"
|
||||
|
||||
export let query = {}
|
||||
export let data = []
|
||||
|
||||
let loading = false
|
||||
let error = false
|
||||
</script>
|
||||
|
||||
{#if error}
|
||||
<div class="errors">{error}</div>
|
||||
{/if}
|
||||
<Table title={''} schema={query.schema} {data} {loading} />
|
||||
|
||||
<style>
|
||||
.errors {
|
||||
color: var(--red);
|
||||
background: var(--red-light);
|
||||
padding: var(--spacing-m);
|
||||
border-radius: var(--border-radius-m);
|
||||
margin-bottom: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -199,7 +199,6 @@
|
|||
align-items: stretch;
|
||||
}
|
||||
.grid-wrapper :global(> *) {
|
||||
height: auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
:global(.grid-wrapper) {
|
||||
|
@ -236,6 +235,7 @@
|
|||
}
|
||||
|
||||
:global(.ag-filter) {
|
||||
background: var(--background);
|
||||
padding: var(--spacing-s);
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
|
|
|
@ -23,5 +23,10 @@ export async function fetchDataForView(view) {
|
|||
const FETCH_ROWS_URL = `/api/views/${view.name}`
|
||||
|
||||
const response = await api.get(FETCH_ROWS_URL)
|
||||
return await response.json()
|
||||
const json = await response.json()
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(json.message)
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { goto } from "@sveltech/routify"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { TableNames } from "constants"
|
||||
import CreateDatasourceModal from "./modals/CreateDatasourceModal.svelte"
|
||||
import EditDatasourcePopover from "./popovers/EditDatasourcePopover.svelte"
|
||||
import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
|
||||
import { Modal, Switcher } from "@budibase/bbui"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
import ICONS from "./icons"
|
||||
|
||||
$: selectedView =
|
||||
$backendUiStore.selectedView && $backendUiStore.selectedView.name
|
||||
|
||||
function selectDatasource(datasource) {
|
||||
backendUiStore.actions.datasources.select(datasource._id)
|
||||
$goto(`./datasource/${datasource._id}`)
|
||||
}
|
||||
|
||||
function onClickQuery(query) {
|
||||
if ($backendUiStore.selectedQueryId === query._id) {
|
||||
return
|
||||
}
|
||||
backendUiStore.actions.queries.select(query)
|
||||
$goto(`./datasource/${query.datasourceId}/${query._id}`)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
backendUiStore.actions.datasources.fetch()
|
||||
backendUiStore.actions.queries.fetch()
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
|
||||
<div class="hierarchy-items-container">
|
||||
{#each $backendUiStore.datasources as datasource, idx}
|
||||
<NavItem
|
||||
border={idx > 0}
|
||||
text={datasource.name}
|
||||
selected={$backendUiStore.selectedDatasourceId === datasource._id}
|
||||
on:click={() => selectDatasource(datasource)}>
|
||||
<div class="datasource-icon" slot="icon">
|
||||
<svelte:component
|
||||
this={ICONS[datasource.source]}
|
||||
height="15"
|
||||
width="15" />
|
||||
</div>
|
||||
<EditDatasourcePopover {datasource} />
|
||||
</NavItem>
|
||||
{#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
|
||||
<NavItem
|
||||
indentLevel={1}
|
||||
icon="ri-eye-line"
|
||||
text={query.name}
|
||||
selected={$backendUiStore.selectedQueryId === query._id}
|
||||
on:click={() => onClickQuery(query)}>
|
||||
<EditQueryPopover {query} />
|
||||
</NavItem>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
|
@ -0,0 +1,55 @@
|
|||
<script>
|
||||
export let icon
|
||||
export let className
|
||||
export let title
|
||||
export let selected
|
||||
export let indented
|
||||
</script>
|
||||
|
||||
<div
|
||||
data-cy="table-nav-item"
|
||||
class:indented
|
||||
class:selected
|
||||
on:click
|
||||
class={className}>
|
||||
<i class={icon} />
|
||||
<span>{title}</span>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.indented {
|
||||
grid-template-columns: 46px 1fr 20px;
|
||||
}
|
||||
.indented i {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
div {
|
||||
padding: var(--spacing-s) var(--spacing-m);
|
||||
border-radius: var(--border-radius-m);
|
||||
display: grid;
|
||||
grid-template-columns: 20px 1fr 20px;
|
||||
align-items: center;
|
||||
transition: 0.3s background-color;
|
||||
color: var(--ink);
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
grid-gap: var(--spacing-s);
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: var(--grey-2);
|
||||
}
|
||||
|
||||
div:hover {
|
||||
background-color: var(--grey-1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
i {
|
||||
color: var(--grey-7);
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import { Input, TextArea, Spacer } from "@budibase/bbui"
|
||||
|
||||
export let integration
|
||||
</script>
|
||||
|
||||
<form>
|
||||
{#each Object.keys(integration) as configKey}
|
||||
<Input
|
||||
thin
|
||||
type={integration[configKey].type}
|
||||
label={configKey}
|
||||
bind:value={integration[configKey]} />
|
||||
<Spacer medium />
|
||||
{/each}
|
||||
</form>
|
|
@ -0,0 +1,97 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import api from "builderStore/api"
|
||||
import { Input, TextArea, Spacer } from "@budibase/bbui"
|
||||
import ICONS from "../icons"
|
||||
|
||||
export let integration = {}
|
||||
|
||||
let schema
|
||||
let integrations = []
|
||||
|
||||
async function fetchIntegrations() {
|
||||
const response = await api.get("/api/integrations")
|
||||
const json = await response.json()
|
||||
|
||||
integrations = json
|
||||
return json
|
||||
}
|
||||
|
||||
function selectIntegration(integrationType) {
|
||||
schema = integrations[integrationType].datasource
|
||||
integration = {
|
||||
type: integrationType,
|
||||
...Object.keys(schema).reduce(
|
||||
(acc, next) => ({ ...acc, [next]: schema[next].default }),
|
||||
{}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fetchIntegrations()
|
||||
})
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<div class="integration-list">
|
||||
{#each Object.keys(integrations) as integrationType}
|
||||
<div
|
||||
class="integration hoverable"
|
||||
class:selected={integration.type === integrationType}
|
||||
on:click={() => selectIntegration(integrationType)}>
|
||||
<svelte:component
|
||||
this={ICONS[integrationType]}
|
||||
height="100"
|
||||
width="100" />
|
||||
<span>{integrationType}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if schema}
|
||||
{#each Object.keys(schema) as configKey}
|
||||
<Input
|
||||
thin
|
||||
type={schema[configKey].type}
|
||||
label={configKey}
|
||||
bind:value={integration[configKey]} />
|
||||
<Spacer medium />
|
||||
{/each}
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
section {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.integration-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: var(--spacing-m);
|
||||
}
|
||||
|
||||
.integration {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 5px;
|
||||
transition: 0.3s all;
|
||||
border-radius: var(--border-radius-s);
|
||||
height: 75px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: var(--font-size-xs);
|
||||
margin-top: var(--spacing-m);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.integration:hover,
|
||||
.selected {
|
||||
background-color: var(--grey-3);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,46 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 256 215"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path
|
||||
d="M114.259 2.701L18.86 42.176C13.555 44.371 13.61 51.906 18.949
|
||||
54.023L114.746 92.012C123.163 95.3503 132.537 95.3503 140.954
|
||||
92.012L236.753 54.022C242.09 51.907 242.146 44.372 236.839 42.176L141.442
|
||||
2.7C132.739 -0.901099 122.962 -0.901099 114.259 2.7"
|
||||
fill="#FFBF00" />
|
||||
<path
|
||||
d="M136.35 112.757V207.659C136.35 212.173 140.9 215.264 145.096
|
||||
213.601L251.844 172.166C253.034 171.694 254.056 170.875 254.775
|
||||
169.816C255.495 168.757 255.879 167.506 255.879 166.225V71.322C255.879
|
||||
66.808 251.328 63.718 247.132 65.381L140.384 106.815C139.194 107.287
|
||||
138.172 108.106 137.453 109.166C136.734 110.225 136.349 111.476 136.349
|
||||
112.757"
|
||||
fill="#26B5F8" />
|
||||
<path
|
||||
d="M111.423 117.654L79.743 132.95L76.526 134.505L9.65 166.548C5.411
|
||||
168.593 0 165.504 0 160.795V71.72C0 70.016 0.874 68.545 2.046
|
||||
67.437C2.52616 66.9592 3.07076 66.5509 3.664 66.224C5.262 65.265 7.542
|
||||
65.009 9.48 65.776L110.89 105.956C116.045 108.001 116.45 115.224 111.423
|
||||
117.653"
|
||||
fill="#ED3049" />
|
||||
<path
|
||||
d="M111.423 117.654L79.743 132.95L2.045 67.438C2.52516 66.9602 3.06976
|
||||
66.5519 3.663 66.225C5.261 65.266 7.541 65.01 9.479 65.777L110.889
|
||||
105.957C116.044 108.002 116.449 115.225 111.422 117.654"
|
||||
fill="black"
|
||||
fill-opacity="0.25" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="256" height="215" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
|
@ -0,0 +1,35 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 175 115"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M142.187 76.6667C142.187 83.9288 138.367 87.4876 131.249
|
||||
87.6136V87.6184H43.7507V87.6136C36.6331 87.4876 32.8132 83.9288 32.8132
|
||||
76.666C32.8132 69.4052 36.6331 65.845 43.7507
|
||||
65.7204V65.7136H131.249V65.7204C138.367 65.845 142.187 69.4052 142.187
|
||||
76.666V76.6667ZM131.249 93.1014V93.0952H43.7507V93.1021C36.6331 93.2267
|
||||
32.8132 96.7869 32.8132 104.05C32.8132 111.312 36.6331 114.869 43.7507
|
||||
114.995V115H131.249V114.993C138.367 114.869 142.187 111.31 142.187
|
||||
104.048C142.187 96.7848 138.367 93.2267 131.249 93.1021V93.1014ZM158.593
|
||||
32.8695V32.8633C151.477 32.9893 147.656 36.5481 147.656
|
||||
43.8109V104.048C147.656 111.31 151.477 114.867 158.593
|
||||
114.993V114.982C169.269 114.606 175 103.929 175 82.1429V54.7619C175 40.2384
|
||||
169.269 33.1214 158.594 32.8688L158.593 32.8695ZM16.4062
|
||||
32.8626V32.8695C5.73193 33.1207 0 40.2377 0 54.7619V82.1429C0 103.929
|
||||
5.73125 114.605 16.4062 114.982V114.993C23.5238 114.869 27.3438 111.31
|
||||
27.3438 104.048V43.8095C27.3438 36.5474 23.5238 32.9886 16.4062
|
||||
32.8626ZM158.594 27.381C158.594 9.22533 149.042 0.328571 131.25
|
||||
0.014375V0H43.75V0.014375C25.9595 0.329256 16.4062 9.22533 16.4062
|
||||
27.3816V27.3905C27.0819 27.5788 32.8132 32.9167 32.8132 43.8102C32.8132
|
||||
54.703 38.5444 60.0403 49.2194 60.2292V60.2381H125.782V60.2299C136.456
|
||||
60.0416 142.187 54.7037 142.187 43.8109C142.187 32.9174 147.918 27.5795
|
||||
158.593 27.3912V27.381H158.594Z"
|
||||
fill="#E42528" />
|
||||
</svg>
|
|
@ -0,0 +1,58 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 256 289"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path
|
||||
d="M165.258 288.501H168.766L226.027 259.867L226.98 258.52V29.964L226.027
|
||||
28.61L168.766 0H165.215L165.258 288.501Z"
|
||||
fill="#5294CF" />
|
||||
<path
|
||||
d="M90.741 288.501H87.184L29.972 259.867L28.811 257.87L28.222
|
||||
31.128L29.972 28.61L87.184 0H90.785L90.741 288.501Z"
|
||||
fill="#1F5B98" />
|
||||
<path d="M87.285 0H168.711V288.501H87.285V0Z" fill="#2D72B8" />
|
||||
<path
|
||||
d="M256 137.769L254.065 137.34L226.437 134.764L226.027 134.968L168.715
|
||||
132.676H87.285L29.972 134.968V91.264L29.912 91.296L29.972 91.168L87.285
|
||||
77.888H168.715L226.027 91.168L247.096 102.367V95.167L256 94.193L255.078
|
||||
92.395L226.886 72.236L226.027 72.515L168.715 54.756H87.285L29.972
|
||||
72.515V28.61L0 63.723V94.389L0.232 94.221L8.904 95.167V102.515L0
|
||||
107.28V137.793L0.232 137.769L8.904 137.897V150.704L1.422 150.816L0
|
||||
150.68V181.205L8.904 185.993V193.426L0.373 194.368L0
|
||||
194.088V224.749L29.972 259.867V215.966L87.285 233.725H168.715L226.196
|
||||
215.914L226.96 216.249L254.781 196.387L256 194.408L247.096
|
||||
193.426V186.142L245.929 185.676L226.886 195.941L226.196 197.381L168.715
|
||||
210.584V210.6H87.285V210.584L29.972 197.325V153.461L87.285
|
||||
155.745V155.801H168.715L226.027 153.461L227.332 154.061L254.111
|
||||
151.755L256 150.832L247.096 150.704V137.897L256 137.769"
|
||||
fill="#1A476F" />
|
||||
<path
|
||||
d="M226.027 215.966V259.867L256 224.749V194.288L226.2 215.914L226.027
|
||||
215.966Z"
|
||||
fill="#2D72B8" />
|
||||
<path
|
||||
d="M226.027 197.421L226.2 197.381L256 181.353V150.704L226.027
|
||||
153.461V197.421"
|
||||
fill="#2D72B8" />
|
||||
<path
|
||||
d="M226.2 91.208L226.027 91.168V134.968L256 137.769V107.135L226.2 91.208Z"
|
||||
fill="#2D72B8" />
|
||||
<path
|
||||
d="M226.2 72.687L256 94.193V63.731L226.027 28.61V72.515L226.2
|
||||
72.575V72.687Z"
|
||||
fill="#2D72B8" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="256" height="289" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
|
@ -0,0 +1,47 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 128 143"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path
|
||||
d="M7.172 40.0865H101.775C112.201 40.0865 121.51 35.3065 127.757
|
||||
27.843C114.727 10.918 94.2765 0 71.265 0C43.089 0 18.738 16.3555 7.172
|
||||
40.0865Z"
|
||||
fill="#F0BF1A" />
|
||||
<path
|
||||
d="M93.7575 51.222H2.8775C0.969102 57.732 0.000154178 64.4811 0 71.265C0
|
||||
78.227 1.0165 84.9485 2.8775 91.3085H93.7575C104.67 91.3085 113.801
|
||||
82.4005 113.801 71.265C113.801 60.13 104.893 51.222 93.7575 51.222"
|
||||
fill="#07A5DE" />
|
||||
<path
|
||||
d="M128 114.378C121.793 107.082 112.559 102.443 102.22
|
||||
102.443H7.173C18.7385 126.175 43.0895 142.53 71.265 142.53C94.418 142.53
|
||||
114.983 131.482 128 114.378Z"
|
||||
fill="#3EBEB0" />
|
||||
<path
|
||||
d="M2.87749 51.222C-0.959651 64.3087 -0.959651 78.2218 2.87749
|
||||
91.3085H62.357C63.916 85.2955 64.8065 78.6145 64.8065 71.265C64.8065
|
||||
63.916 63.916 57.235 62.3565 51.222H2.87849H2.87749Z"
|
||||
fill="#231F20" />
|
||||
<path
|
||||
d="M35.41 9.5765C23.3835 16.703 13.362 27.3925 7.1265
|
||||
40.0865H59.6845C54.3395 27.838 45.877 17.594 35.4095 9.5765"
|
||||
fill="#D7A229" />
|
||||
<path
|
||||
d="M37.637 134.068C47.881 125.828 56.121 114.915 61.2435
|
||||
102.443H7.1265C13.8075 115.806 24.4975 126.941 37.637 134.068Z"
|
||||
fill="#019B8F" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="128" height="143" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
|
@ -0,0 +1,77 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 179 179"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M153.828 30.7656H101.806L90.0594
|
||||
54.2594H24.6125V148.234H165.575V30.7656H153.828ZM153.828
|
||||
54.2594H107.959L114.112 42.5125H153.828V54.2594Z"
|
||||
fill="#458248" />
|
||||
<path
|
||||
d="M149.773 173.406L146.623 172.36C146.623 172.36 147.026 156.412 141.276
|
||||
155.299C137.483 150.903 141.835 -32.4046 155.635 154.673C153.015 156 151.011
|
||||
158.289 150.041 161.061C149.521 165.155 149.431 169.293 149.773
|
||||
173.406V173.406Z"
|
||||
fill="url(#paint0_linear)" />
|
||||
<path
|
||||
d="M151.473 158.007C159.86 151.69 166.283 143.124 169.994 133.302C173.705
|
||||
123.48 174.553 112.807 172.439 102.522C166.285 75.3142 151.68 66.3698
|
||||
150.108 62.9577C148.75 60.8316 147.591 58.5845 146.646 56.2452L147.809
|
||||
132.052C147.809 132.052 145.398 155.215 151.473 158.007Z"
|
||||
fill="url(#paint1_linear)" />
|
||||
<path
|
||||
d="M145.018 159.014C145.018 159.014 119.337 141.522 120.825 110.583C120.964
|
||||
101.255 123.102 92.0662 127.096 83.636C131.091 75.2058 136.847 67.7308
|
||||
143.978 61.7158C144.809 61.0059 145.469 60.1177 145.91 59.1173C146.351
|
||||
58.1169 146.56 57.03 146.523 55.9375C148.123 59.3777 147.86 107.299 148.027
|
||||
112.904C148.682 134.709 146.819 154.897 145.018 159.014V159.014Z"
|
||||
fill="url(#paint2_linear)" />
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear"
|
||||
x1="128.589"
|
||||
y1="115.729"
|
||||
x2="164.805"
|
||||
y2="128.016"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.231" stop-color="#999875" />
|
||||
<stop offset="0.563" stop-color="#9B9977" />
|
||||
<stop offset="0.683" stop-color="#A09F7E" />
|
||||
<stop offset="0.768" stop-color="#A9A889" />
|
||||
<stop offset="0.837" stop-color="#B7B69A" />
|
||||
<stop offset="0.896" stop-color="#C9C7B0" />
|
||||
<stop offset="0.948" stop-color="#DEDDCB" />
|
||||
<stop offset="0.994" stop-color="#F8F6EB" />
|
||||
<stop offset="1" stop-color="#FBF9EF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear"
|
||||
x1="141.872"
|
||||
y1="55.7038"
|
||||
x2="157.883"
|
||||
y2="155.673"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#48A547" />
|
||||
<stop offset="1" stop-color="#3F9143" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear"
|
||||
x1="118.614"
|
||||
y1="113.645"
|
||||
x2="161.577"
|
||||
y2="99.2572"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#41A247" />
|
||||
<stop offset="0.352" stop-color="#4BA74B" />
|
||||
<stop offset="0.956" stop-color="#67B554" />
|
||||
<stop offset="1" stop-color="#69B655" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
|
@ -0,0 +1,149 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 170 175"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M169.341 104.792C168.322 101.71 165.652 99.5637 162.199 99.0487C160.57
|
||||
98.8061 158.706 98.9095 156.499 99.3635C152.653 100.156 149.799 100.457
|
||||
147.717 100.516C155.577 87.268 161.969 72.161 165.648 57.9402C171.598
|
||||
34.9456 168.419 24.4702 164.704 19.7319C154.871 7.19025 140.525 0.452754
|
||||
123.218 0.246599C113.986 0.13391 105.881 1.95351 101.653 3.26203C97.7162
|
||||
2.56866 93.4835 2.18154 89.0422 2.10995C80.7169 1.97738 73.361 3.78902
|
||||
67.0757 7.51241C63.596 6.33779 58.0112 4.68192 51.5619 3.62529C36.3933
|
||||
1.1395 24.1679 3.07643 15.2257 9.38239C4.39748 17.0174 -0.622171 30.283
|
||||
0.306188 48.8104C0.601032 54.6928 3.89744 72.5905 9.08775 89.5642C12.0707
|
||||
99.3205 15.2516 107.422 18.542 113.647C23.2084 122.473 28.2015 127.67
|
||||
33.8068 129.537C36.9485 130.582 42.6568 131.314 48.6606 126.322C49.4216
|
||||
127.242 50.4369 128.156 51.7843 129.005C53.4956 130.083 55.5881 130.963
|
||||
57.6779 131.485C65.209 133.364 72.2633 132.894 78.2817 130.26C78.3189
|
||||
131.328 78.3475 132.349 78.3714 133.231C78.4112 134.661 78.4511 136.063
|
||||
78.5035 137.374C78.8601 146.239 79.4644 153.132 81.2548 157.955C81.353
|
||||
158.221 81.4852 158.625 81.6246 159.054C82.5178 161.784 84.0113 166.353
|
||||
87.811 169.932C91.7456 173.64 96.5049 174.777 100.864 174.777C103.05 174.777
|
||||
105.136 174.49 106.965 174.099C113.486 172.704 120.893 170.579 126.25
|
||||
162.963C131.316 155.765 133.778 144.922 134.224 127.838C134.281 127.354
|
||||
134.335 126.893 134.386 126.453L134.492 125.551L135.685 125.655L135.993
|
||||
125.676C142.635 125.978 150.756 124.572 155.744 122.259C159.685 120.434
|
||||
172.315 113.778 169.341 104.792"
|
||||
fill="black" />
|
||||
<path
|
||||
d="M157.984 106.539C138.235 110.606 136.877 103.931 136.877 103.931C157.729
|
||||
73.046 166.446 33.8413 158.924 24.2462C138.402 -1.92761 102.878 10.451
|
||||
102.285 10.7718L102.094 10.8063C98.1923 9.99759 93.8261 9.51633 88.918
|
||||
9.43613C79.9824 9.29029 73.2036 11.7748 68.0598 15.6685C68.0598 15.6685
|
||||
4.68831 -10.3919 7.63609 48.4439C8.26296 60.9604 25.6083 143.151 46.2965
|
||||
118.326C53.8582 109.248 61.1648 101.572 61.1648 101.572C64.7933 103.979
|
||||
69.1376 105.206 73.6917 104.765L74.0457 104.466C73.9354 105.593 73.9859
|
||||
106.695 74.1871 108C68.8573 113.944 70.4239 114.988 59.7696 117.177C48.9886
|
||||
119.395 55.3218 123.343 59.4569 124.376C64.4699 125.627 76.0671 127.399
|
||||
83.903 116.449L83.5909 117.699C85.6787 119.369 87.1449 128.559 86.8992
|
||||
136.89C86.6535 145.222 86.4895 150.942 88.1344 155.409C89.7806 159.877
|
||||
91.4202 169.93 105.427 166.934C117.129 164.43 123.194 157.943 124.038
|
||||
147.121C124.637 139.427 125.992 140.565 126.077 133.686L127.164
|
||||
130.43C128.417 120.001 127.363 116.636 134.573 118.201L136.326
|
||||
118.355C141.632 118.596 148.578 117.503 152.655 115.611C161.432 111.545
|
||||
166.639 104.755 157.983 106.539H157.984"
|
||||
fill="#336791" />
|
||||
<path
|
||||
d="M71.7692 54.0412C69.9895 53.7939 68.3778 54.0226 67.5623 54.6391C67.1041
|
||||
54.9858 66.962 55.3875 66.9235 55.6639C66.8212 56.3964 67.3352 57.2064
|
||||
67.6513 57.624C68.5452 58.8066 69.8507 59.6193 71.143 59.7983C71.3302
|
||||
59.8248 71.5168 59.8367 71.7021 59.8367C73.857 59.8367 75.8167 58.1616
|
||||
75.9893 56.9254C76.2051 55.3769 73.9533 54.3448 71.7692 54.0418"
|
||||
fill="white" />
|
||||
<path
|
||||
d="M130.727 54.0902C130.557 52.8765 128.394 52.5305 126.341 52.8155C124.29
|
||||
53.1006 122.302 54.0246 122.468 55.241C122.601 56.1869 124.312 57.8017
|
||||
126.337 57.8017C126.509 57.8017 126.681 57.7904 126.855 57.7659C128.207
|
||||
57.579 129.199 56.7219 129.671 56.228C130.388 55.475 130.804 54.6358 130.727
|
||||
54.0902"
|
||||
fill="white" />
|
||||
<path
|
||||
d="M164.556 106.077C163.803 103.804 161.379 103.073 157.352 103.903C145.396
|
||||
106.366 141.114 104.66 139.708 103.627C149.002 89.494 156.647 72.4103
|
||||
160.771 56.4713C162.725 48.9212 163.804 41.9092 163.893 36.1939C163.99
|
||||
29.9211 162.92 25.3114 160.712 22.4955C151.813 11.1437 138.751 5.05449
|
||||
122.939 4.88744C112.069 4.76547 102.885 7.54227 101.105 8.32314C97.3555
|
||||
7.39246 93.2682 6.82106 88.8183 6.74814C80.6583 6.61623 73.6046 8.56642
|
||||
67.7649 12.5417C65.2282 11.5991 58.6725 9.35259 50.6553 8.06329C36.795
|
||||
5.83602 25.7809 7.52371 17.921 13.0819C8.54246 19.7147 4.21277 31.571
|
||||
5.05148 48.3206C5.33371 53.9557 8.55043 71.2913 13.6265 87.8931C20.3083
|
||||
109.744 27.5718 122.114 35.2139 124.659C36.1084 124.957 37.1396 125.165
|
||||
38.2772 125.165C41.0649 125.165 44.4829 123.911 48.0389 119.643C52.3763
|
||||
114.449 56.863 109.381 61.4935 104.446C64.4977 106.055 67.7981 106.954
|
||||
71.1735 107.044C71.1802 107.133 71.1888 107.221 71.1968 107.308C70.6157 108
|
||||
70.0468 108.701 69.4901 109.413C67.1513 112.377 66.6645 112.994 59.1361
|
||||
114.541C56.9945 114.982 51.3068 116.152 51.2231 120.132C51.1328 124.481
|
||||
57.9467 126.307 58.723 126.501C61.4284 127.177 64.0348 127.51 66.5204
|
||||
127.51C72.5654 127.51 77.8852 125.527 82.1365 121.689C82.0057 137.191
|
||||
82.6532 152.467 84.5179 157.121C86.0452 160.931 89.7759 170.243 101.56
|
||||
170.242C103.29 170.242 105.193 170.041 107.287 169.593C119.586 166.961
|
||||
124.927 161.535 126.993 149.572C128.098 143.179 129.996 127.912 130.888
|
||||
119.723C132.771 120.309 135.196 120.578 137.817 120.577C143.283 120.577
|
||||
149.591 119.418 153.547 117.585C157.991 115.525 166.01 110.469 164.556
|
||||
106.077V106.077ZM135.267 50.7401C135.226 53.1576 134.893 55.3524 134.54
|
||||
57.6433C134.159 60.1072 133.766 62.6547 133.667 65.747C133.569 68.7565
|
||||
133.946 71.8853 134.31 74.9113C135.046 81.023 135.801 87.3151 132.878
|
||||
93.5236C132.393 92.665 131.96 91.7775 131.583 90.8661C131.22 89.9872 130.431
|
||||
88.5752 129.339 86.6211C125.089 79.0139 115.138 61.1997 120.232
|
||||
53.9305C121.75 51.7669 125.601 49.5423 135.267 50.7401V50.7401ZM123.55
|
||||
9.7828C137.717 10.095 148.924 15.3855 156.858 25.5063C162.944 33.2693
|
||||
156.243 68.5921 136.843 99.0653C136.648 98.8177 136.452 98.5708 136.255
|
||||
98.3248L136.009 98.0186C141.022 89.7545 140.042 81.5779 139.17
|
||||
74.3286C138.811 71.3536 138.472 68.5437 138.559 65.9041C138.648 63.1068
|
||||
139.018 60.7071 139.377 58.3871C139.817 55.5281 140.265 52.5696 140.142
|
||||
49.0822C140.234 48.7163 140.271 48.2841 140.223 47.7711C139.907 44.4268
|
||||
136.082 34.418 128.286 25.3591C124.022 20.4041 117.803 14.8591 109.311
|
||||
11.1192C112.964 10.3635 117.958 9.65884 123.55 9.7828V9.7828ZM44.2757
|
||||
116.52C40.3577 121.222 37.6523 120.32 36.7625 120.025C30.9652 118.095
|
||||
24.2382 105.863 18.3075 86.4673C13.1756 69.6845 10.1767 52.8083 9.93898
|
||||
48.076C9.18992 33.1095 12.8243 22.6791 20.742 17.0738C33.6274 7.95259
|
||||
54.8123 13.4121 63.325 16.1809C63.2028 16.3016 63.0753 16.4142 62.9544
|
||||
16.5369C48.9852 30.6191 49.3166 54.6789 49.3511 56.1498C49.3498 56.7173
|
||||
49.3976 57.5207 49.4627 58.6257C49.703 62.6726 50.1506 70.2042 48.9553
|
||||
78.7335C47.845 86.6595 50.2927 94.4172 55.6696 100.018C56.2215 100.592
|
||||
56.8015 101.138 57.4075 101.654C55.0142 104.213 49.8126 109.871 44.2757
|
||||
116.52V116.52ZM59.2031 96.6378C54.8695 92.1236 52.9012 85.8448 53.8023
|
||||
79.4096C55.064 70.3998 54.5985 62.5526 54.3482 58.3367C54.313 57.7467
|
||||
54.2818 57.2297 54.2638 56.822C56.3045 55.0157 65.7614 49.9579 72.5056
|
||||
51.5004C75.5829 52.2037 77.4582 54.2958 78.2378 57.8939C82.2727 76.5228
|
||||
78.7717 84.2871 75.9587 90.5267C75.379 91.8121 74.8312 93.0271 74.3637
|
||||
94.2839L74.0011 95.2557C73.0834 97.7123 72.2294 99.9966 71.7001
|
||||
102.166C67.0929 102.152 62.6111 100.188 59.2031 96.6372V96.6378ZM59.9104
|
||||
121.761C58.565 121.426 57.355 120.843 56.6452 120.36C57.2382 120.081 58.2934
|
||||
119.702 60.1235 119.326C68.9801 117.506 70.3481 116.221 73.335
|
||||
112.436C74.0197 111.567 74.796 110.583 75.8711 109.385L75.8724
|
||||
109.384C77.4735 107.594 78.2059 107.897 79.5341 108.448C80.6105 108.892
|
||||
81.6591 110.239 82.0841 111.721C82.2853 112.421 82.5111 113.749 81.772
|
||||
114.783C75.5324 123.504 66.4401 123.392 59.9104 121.761V121.761ZM106.261
|
||||
164.816C95.4264 167.134 91.5901 161.615 89.062 155.307C87.4304 151.234
|
||||
86.6282 132.868 87.1973 112.586C87.2047 112.316 87.1661 112.056 87.0918
|
||||
111.81C87.0252 111.326 86.924 110.847 86.7889 110.377C85.9429 107.426 83.881
|
||||
104.958 81.4074 103.934C80.4246 103.528 78.621 102.782 76.4535
|
||||
103.336C76.9157 101.434 77.7172 99.2873 78.5864 96.9626L78.951
|
||||
95.9849C79.3614 94.8825 79.8767 93.7404 80.4213 92.5313C83.365 86.0033
|
||||
87.3966 77.0617 83.0211 56.8618C81.3821 49.2957 75.9089 45.6008 67.6121
|
||||
46.4592C62.6383 46.973 58.0875 48.9762 55.8177 50.1249C55.3296 50.3715
|
||||
54.8834 50.6102 54.4664 50.8422C55.0999 43.2191 57.4932 28.9725 66.4461
|
||||
19.9587C72.0833 14.2844 79.5905 11.4818 88.7373 11.6329C106.76 11.9272
|
||||
118.317 21.1598 124.84 28.8538C130.46 35.4833 133.504 42.1618 134.718
|
||||
45.7639C125.584 44.8365 119.372 46.6362 116.223 51.1305C109.372 60.9067
|
||||
119.971 79.8809 125.065 89.0001C125.999 90.6712 126.805 92.1157 127.059
|
||||
92.7295C128.718 96.7426 130.865 99.4219 132.433 101.377C132.914 101.977
|
||||
133.38 102.558 133.735 103.066C130.968 103.862 125.999 105.701 126.452
|
||||
114.896C126.087 119.51 123.49 141.11 122.17 148.742C120.428 158.824 116.712
|
||||
162.58 106.261 164.817V164.816ZM151.487 113.154C148.658 114.465 143.924
|
||||
115.448 139.427 115.659C134.459 115.891 131.931 115.104 131.336
|
||||
114.619C131.057 108.889 133.193 108.291 135.454 107.657C135.809 107.557
|
||||
136.156 107.46 136.491 107.343C136.699 107.512 136.926 107.68 137.176
|
||||
107.844C141.168 110.475 148.289 110.758 158.342 108.687L158.453
|
||||
108.665C157.097 109.931 154.776 111.629 151.487 113.154Z"
|
||||
fill="white" />
|
||||
</svg>
|
|
@ -0,0 +1,55 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
viewBox="0 0 128 155"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M10.312 26.843L0 32V122.51L10.312 127.637L10.374 127.562V26.914L10.312
|
||||
26.843Z"
|
||||
fill="#8C3123" />
|
||||
<path
|
||||
d="M65.5 114.5L10.312 127.637V26.843L65.5 39.6935V114.5Z"
|
||||
fill="#E05243" />
|
||||
<path
|
||||
d="M40.589 93.933L63.998 96.913L64.145 96.574L64.2765 58.189L63.998
|
||||
57.889L40.589 60.826V93.933"
|
||||
fill="#8C3123" />
|
||||
<path
|
||||
d="M63.998 114.647L117.683 127.665L117.768 127.53L117.766 26.933L117.681
|
||||
26.843L63.998 39.841V114.647"
|
||||
fill="#8C3123" />
|
||||
<path
|
||||
d="M87.4135 93.933L63.998 96.913V57.889L87.4135 60.826V93.933Z"
|
||||
fill="#E05243" />
|
||||
<path
|
||||
d="M87.4135 44.8155L63.998 49.083L40.589 44.8155L63.9685 38.6875L87.4135
|
||||
44.8155Z"
|
||||
fill="#5E1F18" />
|
||||
<path
|
||||
d="M87.4135 109.901L63.998 105.605L40.589 109.901L63.9695 116.427L87.4135
|
||||
109.901Z"
|
||||
fill="#F2B0A9" />
|
||||
<path
|
||||
d="M40.589 44.8155L63.998 39.0225L64.1875 38.964V0.1565L63.998 0L40.589
|
||||
11.7065V44.8155Z"
|
||||
fill="#8C3123" />
|
||||
<path
|
||||
d="M87.4135 44.8155L63.998 39.0225V0L87.4135 11.7065V44.8155Z"
|
||||
fill="#E05243" />
|
||||
<path
|
||||
d="M63.998 154.714L40.5865 143.012V109.903L63.998 115.694L64.3425
|
||||
116.086L64.249 154.039L63.998 154.714Z"
|
||||
fill="#8C3123" />
|
||||
<path
|
||||
d="M63.998 154.714L87.4115 143.012V109.903L63.998 115.694V154.714"
|
||||
fill="#E05243" />
|
||||
<path
|
||||
d="M117.684 26.843L128 32V122.51L117.684 127.665V26.843Z"
|
||||
fill="#E05243" />
|
||||
</svg>
|
|
@ -0,0 +1,391 @@
|
|||
<script>
|
||||
export let width = "100"
|
||||
export let height = "100"
|
||||
</script>
|
||||
|
||||
<svg
|
||||
{width}
|
||||
{height}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1478.201 1195.111">
|
||||
<g transform="matrix(.569 0 0 .569 199.451 -82.735)">
|
||||
<linearGradient
|
||||
id="a"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-2901.952"
|
||||
y1="923.573"
|
||||
x2="-2061.249"
|
||||
y2="1420.331"
|
||||
gradientTransform="matrix(.1234 0 0 -.1234 1158.33 1550.273)">
|
||||
<stop offset="0" stop-color="#909ca9" />
|
||||
<stop offset="1" stop-color="#ededee" />
|
||||
</linearGradient>
|
||||
<path
|
||||
fill="url(#a)"
|
||||
d="M1410.773 814.195l-286.9 93.683-249.599 110.161-69.829 18.435c-17.784
|
||||
16.916-36.431 34.049-56.599 51.397-22.119 19.082-42.72 36.433-58.553
|
||||
49.008-17.564 13.88-43.587 39.902-56.814 56.38-19.735 24.721-35.348
|
||||
50.96-42.071 71.13-11.928 36.433-6.07 73.297 16.916 107.346 29.492 43.369
|
||||
88.261 87.606 156.785 117.749 34.916 15.4 93.683 35.132 137.92 46.19
|
||||
73.512 18.651 215.771 38.819 294.054 41.857 15.828.65 37.082.65 37.947 0
|
||||
1.737-1.088 13.881-24.289 27.979-53.129 48.142-98.238 82.838-190.402
|
||||
101.703-269.119 11.276-47.706 20.166-111.246 26.019-186.492 1.521-21.036
|
||||
2.169-91.514.868-115.37-1.953-39.033-5.423-70.692-10.84-101.703-.868-4.555-1.088-8.676-.652-8.892.865-.65
|
||||
3.467-1.517 38.815-11.712l-7.153-16.912v-.005h.004zm-65.49 38.386c2.602 0
|
||||
9.539 66.573 11.273 108.646.436 8.89.216 14.745-.216 14.745-1.733
|
||||
0-36.649-20.599-61.583-36.212-21.687-13.663-62.888-40.988-69.393-46.192-2.173-1.517-1.957-1.733
|
||||
15.828-7.807 30.14-10.194 101.706-33.18 104.091-33.18zm-146.161
|
||||
48.143c1.953 0 6.937 2.816 18.865 10.191 44.671 27.974 105.393 61.805
|
||||
131.415 73.083 8.022 3.469 8.887 2.166-9.542 14.746-39.468 26.889-88.697
|
||||
53.344-148.983 80.018-10.624 4.771-19.514 8.456-19.73 8.456-.432 0
|
||||
.865-5.418 2.598-11.925 14.53-54.001 22.772-108.647
|
||||
23.208-152.452.216-21.687.216-21.687 2.169-22.334-.436.217-.22.217 0
|
||||
.217zm-30.142 11.492c1.297 1.299.432 49.877-1.304 63.104-3.903
|
||||
31.662-9.975 61.153-19.947 94.335-2.386 8.018-4.558 14.745-4.987
|
||||
15.177-.872
|
||||
1.083-30.581-27.975-40.339-39.251-16.916-19.518-30.141-39.035-39.9-58.117-4.988-9.759-12.793-28.84-12.144-29.492
|
||||
3.469-2.385 117.753-46.622 118.621-45.756zm-141.826 55.731c.216 0 .432 0
|
||||
.652.216.432.434 1.953 3.905 3.254 7.807 6.937 18.867 22.548 46.624 35.997
|
||||
64.407 14.746 19.518 34.048 40.334 50.091 53.996 5.207 4.337 9.975 8.456
|
||||
10.624 9.108 1.304 1.302 1.737 1.083-33.612 14.53-40.981 15.613-85.656
|
||||
31.226-136.835 47.706a6825.474 6825.474 0 0 0-36.643
|
||||
11.928c-1.955.652-1.303-.434 4.335-9.323 25.371-39.686 63.97-117.536
|
||||
85.657-172.618 3.687-9.542 7.373-19.082 8.025-21.251.868-3.038 1.95-4.121
|
||||
4.768-5.64 1.518-.43 3.038-.866 3.687-.866zm-43.367 17.999c.649.436-10.411
|
||||
23.637-21.254 44.889-21.036 40.985-44.022 81.323-74.815 130.331-5.204
|
||||
8.456-10.19 16.265-10.842 17.132-1.083 1.519-1.519
|
||||
1.083-4.988-5.638-7.373-14.53-13.447-33.181-16.699-50.313-3.254-16.916-2.602-46.406
|
||||
1.086-64.621 2.816-13.444 2.602-13.227 9.107-16.481 27.757-14.095
|
||||
117.537-56.166 118.405-55.299zm374.073 15.182v9.107c0 48.359-5.204
|
||||
114.716-12.797 163.077-1.301 8.456-2.389 15.393-2.602 15.613 0
|
||||
0-6.288-1.733-13.661-3.905-32.527-10.193-67.875-25.156-99.754-42.718-21.038-11.494-51.612-30.363-50.743-31.231.213-.215
|
||||
9.323-4.986 19.947-10.625 42.509-22.118 83.274-45.972 118.622-69.609
|
||||
13.229-8.892 33.176-23.202 37.518-27.107l3.47-2.602zm-537.802 64.185c.867
|
||||
0 .65 1.735-.651 9.542-.868 5.64-1.951 16.049-2.382 23.202-1.739 31.662
|
||||
3.469 55.084 19.082 87.177 4.337 8.892 7.809 16.265 7.589 16.48-1.519
|
||||
1.303-145.074 43.375-190.183 55.734-13.444 3.685-25.152 6.939-26.024
|
||||
7.153-1.515.436-1.733.22-1.083-3.47 4.987-31.875 29.276-73.512
|
||||
63.104-108.644 22.554-23.419 40.554-37.08 71.347-54.648 22.119-12.575
|
||||
56.165-31.439 58.767-32.309.002-.217.218-.217.434-.217zm338.295
|
||||
60.503c.216-.216 5.42 2.605 11.708 6.29 46.408 26.891 111.03 51.83 166.108
|
||||
64.623l4.991 1.086-6.941 3.899c-28.84 16.049-123.606 55.515-220.538
|
||||
91.732-14.098 5.202-27.975 10.409-30.581 11.492-2.602 1.083-4.988
|
||||
1.735-4.988 1.519 0-.22 3.906-7.809 8.89-17.132 27.107-50.744
|
||||
54.433-112.547 68.311-155.485 1.739-4.12 2.82-7.805 3.04-8.024zm-34.48
|
||||
11.278c.22.221-1.517 4.771-3.687 9.975-18.865 45.756-43.59 95.636-75.249
|
||||
151.583-8.022 14.314-14.746 25.808-14.966 25.808-.213
|
||||
0-6.721-3.906-14.527-8.676-45.976-28.192-86.743-62.888-113.414-96.501l-3.905-4.771
|
||||
19.732-5.422c70.696-19.298 130.762-40.116 190.4-65.704 8.459-3.471
|
||||
15.4-6.292 15.616-6.292zm214.253 74.815s.217.217 0 0c.216 4.988-10.844
|
||||
49.661-19.953 81.969-7.589 27.107-14.098 48.361-26.022 85.874-5.204
|
||||
16.485-9.755 30.143-9.975 30.143-.216
|
||||
0-1.517-.216-2.818-.647-64.405-11.714-122.089-27.977-176.303-49.661-15.182-6.074-36.866-15.833-38.167-16.916-.432-.438
|
||||
12.58-6.506 29.06-13.663 98.669-43.154 201.024-92.164 236.153-113.196
|
||||
4.119-2.603 7.373-3.903 8.025-3.903zm-494.646 16.916c.434.432-27.107
|
||||
40.118-65.709 94.114-13.444 18.867-29.057 40.985-34.911 49.225-5.856
|
||||
8.241-14.746 21.253-19.734 29.06l-9.112
|
||||
14.096-9.759-8.24c-11.494-9.544-31.442-29.927-40.333-41.204-18.651-23.201-31.226-47.706-36.214-70.04-2.386-10.411-2.386-15.618-.22-16.265
|
||||
3.252-.867 61.153-14.53 115.37-27.11 30.143-6.937 65.054-15.177
|
||||
77.632-18.213 12.579-3.041 22.774-5.423 22.99-5.423zm27.756 10.626l6.937
|
||||
7.806c31.231 34.914 63.108 60.724 101.708 83.272 6.941 3.906 12.144 7.373
|
||||
11.708 7.594-1.514 1.083-134.016 48.136-195.385 69.389-34.478
|
||||
12.143-62.888 21.901-63.102 21.901-.216
|
||||
0-2.169-1.299-4.341-2.818l-3.901-2.82 6.288-9.106c20.383-29.493
|
||||
45.976-61.803 101.707-129.028l38.381-46.19zm173.053 123.822c.213-.215
|
||||
9.755 3.252 21.464 7.594 28.195 10.624 50.527 17.345 80.456 24.936 36.866
|
||||
9.326 90.211 18.434 121.657 21.035 4.771.432 7.373.868 6.505
|
||||
1.519-1.521.868-33.395 11.494-56.816 18.867-37.302 11.708-151.149
|
||||
45.32-243.962 71.995-17.132 4.987-31.879 9.108-32.746
|
||||
9.323-2.166.436-9.325-1.519-9.325-2.386 0-.431 5.204-7.153 11.494-14.527
|
||||
31.225-37.3 62.238-78.935 88.044-118.403 7.154-10.846 13.229-19.736
|
||||
13.229-19.953zm-38.17 1.087c.216.216-15.179 24.936-42.066 67.439-11.496
|
||||
17.999-24.291 38.383-28.846 45.54-4.337 6.939-10.842 17.784-14.527
|
||||
23.854l-6.29
|
||||
11.061-3.252-.868c-7.809-2.169-62.672-21.471-77.202-27.325-18-7.157-36.649-15.829-50.529-23.202-17.346-9.326-39.03-23.206-37.297-23.637.433-.216
|
||||
30.143-8.243 65.922-17.999 94.984-25.809 147.678-40.77 182.161-51.612
|
||||
6.29-1.952 11.71-3.471 11.926-3.251zm269.985 63.318h.216c.868 2.171-34.26
|
||||
99.755-47.06 130.547-2.815 6.939-3.896 8.677-5.417
|
||||
8.456-3.687-.213-54.646-7.37-85.66-11.925-53.994-8.24-144.641-24.073-167.409-29.275l-5.204-1.083
|
||||
32.307-7.378c69.396-15.613 102.791-24.069 136.619-34.478 42.722-13.011
|
||||
85.011-29.276 127.729-49.225 6.722-3.037 12.361-5.422 13.879-5.639z" />
|
||||
<linearGradient
|
||||
id="b"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-2882.7"
|
||||
y1="10288.81"
|
||||
x2="-2206.249"
|
||||
y2="10288.81"
|
||||
gradientTransform="matrix(.1234 0 0 -.1234 1158.33 1550.273)">
|
||||
<stop offset="0" stop-color="#939fab" />
|
||||
<stop offset="1" stop-color="#dcdee1" />
|
||||
</linearGradient>
|
||||
<path
|
||||
fill="url(#b)"
|
||||
d="M1114.983 145.414c-4.771-.647-81.757 27.11-131.415 47.275-67.01
|
||||
27.327-119.052 53.351-151.148 75.899-11.925 8.461-26.891 23.422-29.273
|
||||
29.276-.867 2.169-1.303 4.771-1.303 7.373l29.06 27.541 69.175 22.119
|
||||
164.594 29.493 188.228 32.312 1.953-16.264c-.649
|
||||
0-1.085-.216-1.73-.216l-24.728-3.905-4.984-8.89c-25.59-45.107-53.781-101.056-70.261-138.789-12.793-29.276-24.938-63.102-31.662-87.391-3.687-14.746-4.119-15.613-6.501-15.829v-.005h-.005zm-3.474
|
||||
11.063h.223c.213.214 1.081 6.29 1.95 13.442 3.683 30.364 10.411 59.635
|
||||
21.035 91.297 8.022 23.855 8.022 22.555-1.301
|
||||
19.734-22.119-6.07-121.221-23.202-193-33.177-11.494-1.519-21.253-3.036-21.253-3.252-.867-.867
|
||||
51.827-28.41 75.031-39.25 29.709-13.665 111.246-47.711
|
||||
117.315-48.794zm-209.047 97.15l8.461 2.816c45.97 15.616 161.551 37.736
|
||||
225.31 42.94 7.154.651 13.229 1.303 13.442 1.303.216.216-5.852
|
||||
3.469-13.661 7.154-30.79 15.397-64.621 34.264-88.042 48.794-6.937
|
||||
4.335-13.229 7.807-14.094 7.807-.868
|
||||
0-5.42-.868-10.191-1.519l-8.674-1.303-21.683-21.253c-38.167-37.08-68.094-65.704-79.588-76.549l-11.28-10.19zm-8.671
|
||||
6.721l30.576 38.168c16.696 21.035 33.611 41.635 37.301 46.187 3.683 4.557
|
||||
6.721 8.245 6.505
|
||||
8.461-.868.65-44.236-7.809-67.226-13.011-23.637-5.423-33.395-8.025-47.924-12.577l-11.928-3.905v-3.038c.216-14.53
|
||||
18.651-36.214 49.877-58.331l2.819-1.954zm259.791 52.046c.869 0 1.95 1.951
|
||||
4.552 7.806 7.373 16.263 30.364 60.07 35.997 68.526 1.74 2.822 4.771
|
||||
3.038-25.802-1.95-73.512-11.93-97.152-15.829-97.152-16.263 0-.216
|
||||
2.169-1.735 4.988-3.254 22.771-12.575 45.756-28.624 66.142-45.756
|
||||
4.988-4.121 9.542-8.024 10.407-8.676.216-.433.652-.649.868-.433z" />
|
||||
<radialGradient
|
||||
id="c"
|
||||
cx="-14217.448"
|
||||
cy="7277.705"
|
||||
r="898.12"
|
||||
gradientTransform="matrix(-.1185 -.0178 -.036 .237 -198.955 -1314.415)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ee352c" />
|
||||
<stop offset="1" stop-color="#a91d22" />
|
||||
</radialGradient>
|
||||
<path
|
||||
fill="url(#c)"
|
||||
d="M804.66 294.828s-4.768 7.593-.215 18.87c2.822 6.937 11.061 15.393
|
||||
20.384 24.069 0 0 96.5 94.114 108.211 107.561 53.344 61.585 76.549 122.305
|
||||
78.718 206.012 1.301 53.78-8.894 101.054-34.264 155.919-45.106
|
||||
98.453-140.307 207.098-287.117 327.67l21.472-7.157c13.878-10.411
|
||||
32.745-21.467 76.982-45.756 102.137-55.952 217.071-107.346 358.028-160.258
|
||||
202.971-76.335 536.715-165.681
|
||||
726.676-194.736l19.737-3.038-3.038-4.771c-17.345-26.891-29.276-43.587-43.59-61.369-41.633-51.612-92.157-93.463-153.964-128.161-85.007-47.489-194.956-84.571-334.173-112.112-26.239-5.207-83.923-15.181-130.763-22.337-99.321-15.393-163.51-26.021-234.203-38.165-25.37-4.339-63.323-10.843-88.478-16.263-13.011-2.822-37.947-8.676-57.464-15.398-15.613-6.075-38.168-12.147-42.939-30.58zm55.952
|
||||
54.216c.214-.214 3.683 1.083 8.24 2.602 8.24 2.816 18.865 6.07 31.446
|
||||
9.542a1599.47 1599.47 0 0 0 28.624 7.589c13.011 3.251 23.852 6.288 24.068
|
||||
6.288 1.521 1.519 23.424 71.558 30.797 98.449 2.815 10.195 4.988 18.867
|
||||
4.771
|
||||
18.867-.223.22-2.605-3.469-5.423-8.456-25.373-44.673-65.491-89.995-111.899-126.428-6.069-4.333-10.624-8.237-10.624-8.453zm106.692
|
||||
29.492c1.085 0 5.856.651 11.708 1.951 36.866 8.24 103.008 20.818 145.293
|
||||
27.975 7.157 1.083 12.797 2.387 12.797 2.818 0 .436-2.605 1.951-5.859
|
||||
3.688-7.153 3.685-35.997 20.815-45.536 27.322-24.073 16.047-45.756
|
||||
33.395-61.371 49.008-6.288 6.29-11.712 11.494-11.712
|
||||
11.494s-1.297-3.685-2.386-8.242c-7.802-30.143-24.069-74.816-38.815-106.258-2.386-4.986-4.339-9.541-4.339-9.973
|
||||
0 .433 0 .217.22.217zm187.795 35.781c1.301.432 3.47 7.806 7.806 24.069
|
||||
8.025 31.446 11.712 66.576 10.411 99.321-.436 9.108-.868 17.564-1.304
|
||||
18.651l-.649
|
||||
2.166-11.276-3.685c-23.204-7.373-60.935-18.435-93.245-27.541-18.436-4.988-33.395-9.542-33.395-9.975
|
||||
0-1.303 26.891-28.192 38.383-38.383 21.898-19.303 81.316-65.275
|
||||
83.269-64.623zm14.963 2.166c.652-.647 89.779 14.746 130.331 22.554 30.145
|
||||
5.854 73.948 14.963 76.549 16.049 1.301.432-3.254 3.034-17.784
|
||||
9.539-57.248 25.808-99.754 49.008-142.036 77.202-11.06 7.373-20.386
|
||||
13.444-20.602 13.444-.216 0-.433-6.287-.433-13.878
|
||||
0-41.201-8.241-82.838-23.424-117.968-1.517-3.47-2.818-6.722-2.601-6.942zm230.516
|
||||
45.542c.652.65-2.169 18.217-4.771 28.624-7.806 32.312-28.84 80.24-54.643
|
||||
125.343-4.558 8.024-8.677 14.53-9.114
|
||||
14.746-.429.216-6.285-3.038-13.009-6.941-25.154-14.746-53.778-28.624-85.007-41.637-8.671-3.685-16.263-6.723-16.48-7.153-1.521-1.303
|
||||
68.308-47.493 105.174-69.612 29.276-17.781 76.982-44.239
|
||||
77.85-43.37zm16.48 2.601c1.953 0 41.421 10.844 62.019 16.916 50.963 15.181
|
||||
109.512 36.648 147.679 53.996l15.828 7.159-11.056 2.6c-93.245
|
||||
21.467-173.049 46.192-250.034 77.418-6.289 2.602-11.928 4.771-12.357
|
||||
4.771-.436 0 1.733-4.987 4.552-11.061 23.204-49.225 38.167-100.62
|
||||
41.85-144.427.221-4.121.867-7.372 1.519-7.372zm-392.938 90.213c.649-.652
|
||||
30.793 6.506 47.057 11.056 24.721 6.942 77.198 24.505 77.198 25.808 0
|
||||
.216-5.853 5.204-12.79 11.278-28.408 23.637-55.734 48.572-88.481
|
||||
80.234-9.759 9.328-17.997 16.917-18.429 16.917-.436
|
||||
0-.649-1.304-.436-3.038 4.987-36.433
|
||||
3.906-83.272-3.034-130.763-.653-6.074-1.302-11.276-1.085-11.492zm633.433.652c.429.431-13.881
|
||||
22.984-22.988 35.777-13.009 18.649-32.098 43.375-75.252 97.588-22.765
|
||||
28.622-48.358 60.936-56.812 71.778-8.678 10.842-15.831 19.948-16.051
|
||||
19.948-.216
|
||||
0-3.031-3.901-6.069-8.671-24.289-36.433-53.349-68.311-87.829-96.935-6.505-5.423-13.658-11.278-16.044-13.013-2.386-1.734-4.339-3.469-4.339-3.685
|
||||
0-.649 36.862-16.483 64.841-27.757 49.01-19.952 115.794-43.805
|
||||
165.892-59.203 26.24-8.239 54.215-16.263 54.651-15.827zm16.696
|
||||
4.334c.865-.215 6.072 2.387 12.361 6.07 52.697 30.143 104.305 68.962
|
||||
145.077 108.864 11.492 11.278 39.9 40.77 39.464 40.986 0
|
||||
0-9.975.867-21.683 1.733-91.296 6.942-208.178 26.239-320.511 53.345-7.589
|
||||
1.733-14.31 3.252-14.746 3.252-.429 0 8.025-8.456 18.653-18.647
|
||||
65.922-63.538 96.067-103.656 131.628-175.22 4.986-10.623 9.325-19.731
|
||||
9.757-20.383-.216 0-.216 0 0 0zm-482.936 49.446c3.038.647 31.229 13.88
|
||||
52.48 24.503 19.517 9.755 48.794 25.372 50.311 26.671.216.216-10.195
|
||||
5.638-22.984 11.928-40.772 20.384-75.684 39.682-112.118 61.802-10.408
|
||||
6.29-19.082 11.497-19.298 11.497-.868 0-.652-.872 5.204-11.497
|
||||
19.518-35.561 35.129-78.065 44.023-119.486.864-3.252 1.733-5.418
|
||||
2.382-5.418zm-28.192 5.202c.652.652-6.721 27.323-11.273 41.853-8.894
|
||||
27.541-23.856 62.02-38.383 88.043-3.474 6.069-8.677 14.961-11.496
|
||||
19.948l-5.42
|
||||
8.674-12.144-11.707c-14.094-13.663-25.59-22.12-40.333-29.712-5.859-3.033-10.411-5.638-10.411-6.069
|
||||
0-1.735 37.082-35.347 65.49-59.635 20.383-17.566 63.321-52.045
|
||||
63.97-51.395zm172.404 70.913l10.627 6.937c24.282 15.833 52.906 36.866
|
||||
74.813 55.298 12.357 10.19 36.21 31.662 40.985 36.866l2.598 2.822-17.561
|
||||
4.986c-99.321 27.538-176.087 52.043-265.649 85.007-9.975 3.685-18.433
|
||||
6.721-19.085 6.721-1.297 0-2.385 1.083 19.954-19.519 57.251-52.691
|
||||
107.992-110.812 145.726-167.411l7.592-11.707zm-45.324
|
||||
11.276c.432.432-29.276 42.284-47.06 65.922-21.251 28.192-58.985
|
||||
75.465-85.007 106.256-10.84 12.797-20.163 23.422-20.599
|
||||
23.64-.652.216-.868-3.036-.868-8.024
|
||||
0-26.242-6.721-54.216-18.433-78.068-4.988-9.975-5.856-12.361-4.768-13.444
|
||||
4.119-3.688 67.223-39.686 107.123-61.153 26.89-14.312 68.956-35.563
|
||||
69.612-35.129zm-274.107 67.225c.652 0 5.64 2.6 11.279 5.638 13.878 7.589
|
||||
26.239 16.046 37.298 25.156.432.432-5.204 4.988-12.577 10.406-20.602
|
||||
14.746-51.828 38.385-70.041 52.915-19.088 15.18-19.734 15.613-17.568
|
||||
12.361 14.314-21.903 21.467-34.264 29.06-50.093 6.721-14.094 13.442-30.793
|
||||
18.213-45.323 1.734-6.289 3.904-11.06 4.336-11.06zm73.083
|
||||
57.248c1.081-.214 2.386 1.735 8.238 10.411 12.361 18.429 21.903 43.154
|
||||
24.292 63.104l.429 4.339-29.705 11.494c-53.133 20.599-102.139
|
||||
40.985-135.322 56.162-9.322 4.339-25.587 12.144-36.211 17.352-10.627
|
||||
5.418-19.301 9.539-19.301 9.323s6.721-5.204 14.961-11.278c64.844-47.055
|
||||
121.007-98.669 163.076-150.279 4.555-5.423 8.677-10.411
|
||||
9.107-10.627l.436-.001zm-33.612 8.242c.868.867-23.853 28.84-40.768
|
||||
45.971-41.853 42.723-83.273 76.12-134.669 108.649-6.505 4.119-12.359
|
||||
7.804-13.011 8.24-1.519.867.432-1.303 22.986-25.808 14.314-15.397
|
||||
25.155-28.408 37.516-44.453 8.24-10.624 9.759-12.143 21.688-20.604
|
||||
31.878-22.987 105.39-72.864 106.258-71.995z" />
|
||||
</g>
|
||||
<path
|
||||
fill="#231F1F"
|
||||
d="M265.747 900.102c-2.276 0-4.553.217-6.809.217-45.975 2.45-76.983
|
||||
22.683-95.113 62.195-15.506 35.735-13.813 82.446.174 118.4 16.265 35.131
|
||||
42.547 53.672 86.416 60.675 9.282 1.52 15.506 6.616 33.483 27.606l22.12
|
||||
25.915h40.118l-26.676-26.892c-14.746-14.745-26.673-27.584-26.673-28.712
|
||||
0-1.127 5.641-3.599 12.469-5.68 22.51-6.812 41.203-24.202 54.279-50.854
|
||||
10.583-21.402 12.102-28.018 13.619-54.646
|
||||
3.969-79.26-37.82-128.813-107.409-128.247l.002.023zm35.173 207.27c-19.517
|
||||
9.453-47.857 11.34-66.356
|
||||
4.553-19.127-7.025-37.646-26.889-45.975-49.377-9.259-24.591-7.937-69.956
|
||||
2.646-90.386 17.023-32.528 39.534-47.49 72.43-47.49 48.792 0 76.549 29.884
|
||||
80.171 86.048 2.863 46.885-12.838 82.058-42.895
|
||||
96.632l-.021.02zm693.025-139.568c-16.828 0-29.709 6.811-38.385 20.231l-6.809
|
||||
10.627v-27.628h-29.123v165.678h29.104v-52.956c0-48.424.604-54.084
|
||||
7.371-67.335 9.326-18.172 25.371-27.234 40.879-22.897l10.408
|
||||
3.036v-28.712h-13.445v-.044zm-171.098-1.519c-5.705 0-11.756.76-17.781
|
||||
2.084-38.971 10.19-60.938 47.489-59.594 85.873 0 32.139 6.244 48.206 21.752
|
||||
65.057 31.77 26.065 60.502 28.146 99.275 14.161 6.615-2.819 13.814-6.072
|
||||
13.814-6.072v-26.065l-13.814 7.156c-31.379 13.661-55.016
|
||||
13.661-73.949-2.43-12.076-12.296-17.391-27.042-19.84-43.868h117.426v-22.339c0-45.539-27.41-74.294-67.313-73.557h.024zm-47.492
|
||||
72.647s4.338-28.407 20.428-39.554c7.744-5.466 16.633-8.11 25.328-8.11 8.719
|
||||
0 17.414 2.818 24.592 8.306 14.748 11.341 17.219 39.143 17.219
|
||||
39.143h-87.566v.215h-.001zm-702.111-29.881c-31.573-19.128-45.582-32.921-43.869-49.185
|
||||
4.9-44.997 60.503-38.773
|
||||
91.295-21.749l.219-30.272s-17.024-7.373-41.421-7.764c-37.429-.564-61.63
|
||||
11.709-72.97 36.691-16.656 36.865-1.908 64.665 51.396 95.677 29.925 17.412
|
||||
43.152 32.528 43.152 49.008 0 34.047-41.05 45.931-83.401
|
||||
24.57-8.716-4.337-16.09-7.959-16.48-7.959-1.519 9.651-.736 32.745-.736
|
||||
32.745s13.012 5.466 32.527 9.236c48.4 9.65 92.445-13.054 96.608-49.919
|
||||
3.622-34.609-8.893-52.761-56.318-81.104l-.002.025zm1178.454-43.155c-5.682
|
||||
0-11.711.78-18 2.103-38.924 10.192-60.85 47.492-59.354 85.876 0 32.095 6.225
|
||||
48.011 21.729 64.838 31.771 26.089 60.504 28.191 99.473 14.184 6.592-2.818
|
||||
13.77-6.026 13.77-6.026v-26.109l-13.791 7.197c-31.443 13.619-55.082
|
||||
13.619-73.947-2.471-12.145-12.274-17.414-26.847-19.865-43.871h117.232v-22.336c0-45.321-27.412-74.099-67.313-73.339l.066-.046zm-47.492
|
||||
72.646s4.381-28.365 20.449-39.729c7.721-5.485 16.611-8.132 25.307-8.132
|
||||
8.674 0 17.414 2.819 24.594 8.327 14.746 11.342 17.219 39.338 17.219
|
||||
39.338h-87.545l-.024.196zm-533.809-29.123c-31.573-19.083-45.54-32.92-43.848-49.185
|
||||
4.9-45.02 60.504-38.773
|
||||
91.296-21.749l.218-30.272s-17.024-7.374-41.421-7.722c-37.429-.563-61.63
|
||||
11.711-72.991 36.692-16.633 36.864-1.692 64.666 51.437 95.677 29.884 17.393
|
||||
43.111 32.312 43.111 48.792 0 34.047-41.029 46.126-83.381
|
||||
24.569-8.674-4.337-16.046-7.916-16.48-7.916-1.519 9.649-.736 32.746-.736
|
||||
32.746s12.858 5.27 32.31 9.237c48.445 9.672 92.51-13.012 96.653-49.877
|
||||
3.6-34.437-8.891-52.587-56.167-80.952v-.04zm752.421-42.005c-16.828 0-29.859
|
||||
6.829-38.383 20.254l-6.811
|
||||
10.582v-27.583h-29.123V1136.3h29.102v-52.954c0-48.403.584-54.085
|
||||
7.375-67.313 9.324-18.15 25.369-27.235 40.875-22.878l10.408
|
||||
3.035v-28.775h-13.443zm-984.021
|
||||
41.05V902.941h-29.361v233.728h123.478v-27.604h-94.116v-100.601zm679.015
|
||||
32.896l-24.201 62.975-23.27-63.322-23.637-70.173h-30.055c19.475 55.212
|
||||
40.658 111.376 62.02 165.829 9.26.216 18.541 0 27.799 0l32.682-82.058
|
||||
33.287-83.75h-28.732s-12.688 33.266-25.914 70.521l.021-.022zM506.455
|
||||
839.251c4.728 0 8.674-1.516 11.927-4.769 3.208-3.211 4.9-6.984 4.9-11.711
|
||||
0-4.728-1.692-8.675-4.9-11.711-3.253-3.035-7.005-4.555-11.711-4.555-4.769
|
||||
0-8.717 1.52-11.927 4.728-3.252 3.211-4.727 7.158-4.727 11.712 0 4.771 1.519
|
||||
8.716 4.727 11.711 3.037 3.034 6.984 4.553 11.711
|
||||
4.553v.042zm-10.408-26.889c2.818-2.818 6.245-4.121 10.625-4.121 4.121 0
|
||||
7.548 1.303 10.411 4.121 2.819 2.819 4.337 6.245 4.337 10.409 0 4.163-1.518
|
||||
7.764-4.337 10.582-2.862 2.817-6.29 4.163-10.411 4.163-4.185
|
||||
0-7.59-1.301-10.408-4.163-2.819-2.818-4.337-6.419-4.337-10.582 0-4.164
|
||||
1.301-7.589 4.12-10.409zm7.003 11.928h1.908c1.346 0 2.668 1.3 3.795
|
||||
3.773l2.279 5.116h3.577l-2.818-5.683c-1.149-2.275-2.276-3.598-3.6-3.969
|
||||
1.67-.39 2.992-.953 3.947-2.082.952-.974 1.3-2.298 1.3-3.795
|
||||
0-1.734-.542-3.034-1.69-3.989-1.302-1.084-3.384-1.669-6.074-1.669h-6.026v21.187h3.035v-8.891l.367.002zm0-9.846h2.647c1.908
|
||||
0 3.253.39 3.99.953.716.564.911 1.303.911 2.646 0 2.45-1.52 3.601-4.337
|
||||
3.601h-3.252v-7.2h.041zm-485.018
|
||||
7.958c0-7.373-.216-12.858-.39-16.09h.174c.758 3.814 1.691 6.657 2.45
|
||||
8.543l28.19 62.975h4.728l28.19-63.538c.761-1.733 1.52-4.337
|
||||
2.452-7.959h.216c-.563 6.29-.758 11.754-.758
|
||||
16.112v55.581h9.648v-82.622h-12.1L54.919 852.87c-.955 2.276-2.278
|
||||
5.683-3.969
|
||||
10.193h-.392c-.563-2.234-1.886-5.639-3.772-9.803l-25.33-58.053H8.598v82.621h9.281v-55.385l.153-.041zm96.045.154h8.329v51.458h-8.329v-51.458zm4.164-18.868c1.736
|
||||
0 3.21-.587 4.337-1.734 1.15-1.129 1.91-2.603 1.91-4.337
|
||||
0-1.692-.565-3.211-1.887-4.337-1.171-1.15-2.668-1.737-4.381-1.737-1.69
|
||||
0-3.208.587-4.338 1.737-1.146 1.126-1.907 2.645-1.907 4.337 0 1.887.586
|
||||
3.208 1.907 4.337 1.304 1.147 2.647 1.734 4.338 1.734h.021zm63.54
|
||||
71.455v-9.066c-4.555 3.405-9.456 5.098-14.53 5.098-6.07
|
||||
0-10.995-2.081-14.595-6.07-3.577-3.947-5.485-9.436-5.485-16.266 0-7.156
|
||||
1.908-12.84 5.854-17.177 3.795-4.163 8.719-6.245 14.748-6.245 4.922 0 9.647
|
||||
1.52 14.009 4.557v-9.65c-3.968-2.082-8.5-3.037-13.619-3.037-9.456 0-16.827
|
||||
3.037-22.335 8.894-5.466 5.854-8.285 13.813-8.285 23.42 0 8.543 2.45 15.722
|
||||
7.548 21.209 5.312 5.637 12.102 8.5 20.428 8.5 6.438-.178 11.707-1.523
|
||||
16.262-4.167zm23.831-27.433c0-6.788 1.518-12.273 4.337-16.049 2.647-3.403
|
||||
5.855-5.116 9.65-5.116 3.21 0 5.486.585 7.155
|
||||
1.908v-9.846c-1.3-.563-3.187-.758-5.637-.758-3.405 0-6.439 1.146-9.107
|
||||
3.253-2.819 2.231-5.074 5.638-6.397
|
||||
9.975h-.216v-12.08h-9.433v58.985h9.454V847.71h.194zm54.279 31.443c8.892 0
|
||||
16.048-2.863 21.36-8.543 5.29-5.641 7.936-13.229 7.936-22.686
|
||||
0-9.647-2.427-17.021-7.372-22.51-4.9-5.483-11.711-8.132-20.603-8.132s-16.048
|
||||
2.647-21.36 7.764c-5.681 5.641-8.674 13.599-8.674 23.813 0 8.891 2.429
|
||||
16.265 7.548 21.751 5.29 5.68 12.295 8.521 21.165
|
||||
8.521v.022zm-13.445-48.055c3.6-3.795 8.329-5.683 14.182-5.683 6.074 0 10.627
|
||||
1.888 14.01 5.683 3.404 3.969 5.097 9.63 5.097 17.197 0 7.198-1.519
|
||||
12.859-4.729 16.654-3.208 3.969-7.936 6.071-14.183 6.071-6.071
|
||||
0-10.777-2.104-14.377-6.071-3.577-3.99-5.291-9.456-5.291-16.654-.368-7.156
|
||||
1.519-13.01 5.291-17.197zm84.141 42.916c3.599-3.208 5.509-7.155 5.509-12.102
|
||||
0-4.337-1.52-7.936-4.338-10.777-2.3-2.275-5.854-4.337-10.994-6.419-4.556-1.906-7.374-3.6-8.893-4.923-1.517-1.517-2.45-3.402-2.45-6.071
|
||||
0-2.45.955-4.337 2.821-5.855 1.908-1.516 4.337-2.253 7.59-2.253 5.096 0
|
||||
9.454 1.343 13.443 4.185v-9.456c-3.816-1.906-7.958-2.817-12.686-2.817-6.071
|
||||
0-11.189 1.671-14.964 4.899-3.969 3.212-5.854 7.375-5.854 12.274 0 4.337 1.3
|
||||
7.938 3.771 10.582 2.082 2.256 5.641 4.556 10.583 6.614 4.729 2.083 7.938
|
||||
3.968 9.65 5.485 1.691 1.52 2.45 3.405 2.45 5.641 0 5.506-3.772 8.349-11.146
|
||||
8.349-5.682 0-10.776-1.866-15.333-5.638v10.189c4.121 2.475 9.066 3.601 14.53
|
||||
3.601 7.005-.368 12.49-2.081 16.264-5.486l.047-.022zm45.019-56.73c-8.893
|
||||
0-16.048 2.647-21.361 7.764-5.638 5.641-8.674 13.599-8.674 23.813 0 8.891
|
||||
2.452 16.265 7.547 21.751 5.313 5.68 12.295 8.521 21.187 8.521 9.107 0
|
||||
16.048-2.861 21.36-8.545 5.313-5.637 7.958-13.227 7.958-22.683
|
||||
0-9.65-2.472-17.022-7.374-22.509-5.115-5.487-11.927-8.133-20.601-8.133l-.042.021zm18.345
|
||||
31.012c0 7.198-1.518 12.859-4.727 16.654-3.21 3.969-7.938 6.071-14.184
|
||||
6.071-6.074 0-10.778-2.104-14.379-6.071-3.577-3.99-5.29-9.456-5.29-16.654
|
||||
0-7.59 1.888-13.444 5.683-17.393 3.576-3.773 8.306-5.682 14.182-5.682 5.854
|
||||
0 10.561 1.907 13.964 5.682 3.037 4.163 4.729 9.824 4.729
|
||||
17.393h.022zm25.547 29.513h9.433v-51.068h13.813v-7.938H428.93v-9.108c0-8.282
|
||||
3.208-12.446 9.845-12.446 2.234 0 4.511.563 6.203
|
||||
1.518v-8.521c-1.692-.759-3.969-.932-6.812-.932-5.095 0-9.258 1.519-12.664
|
||||
4.727-3.969 3.773-6.071 8.674-6.071
|
||||
15.312v9.672h-9.978v7.936h9.978v50.876l.067-.028zm38.75-16.091c0 11.538
|
||||
5.098 17.414 15.506 17.414 3.774 0 6.614-.606 8.891-1.951v-8.11c-1.734
|
||||
1.302-3.795 1.91-6.071 1.91-3.208
|
||||
0-5.464-.762-6.788-2.475-1.345-1.689-2.103-4.554-2.103-8.501v-33.286h14.961v-7.938h-14.961v-17.39c-3.253
|
||||
1.127-6.44 2.082-9.456
|
||||
3.034v14.355h-10.192v7.938h10.192v34.979l.021.021zm1014.88
|
||||
108.73c-3.209-3.034-7.004-4.553-11.709-4.553-4.77 0-8.719 1.519-11.928
|
||||
4.771-3.209 3.188-4.729 7.155-4.729 11.711 0 4.728 1.52 8.675 4.705 11.709
|
||||
3.211 3.036 7.156 4.556 11.928 4.556 4.705 0 8.674-1.52 11.928-4.729
|
||||
3.188-3.253 4.879-7.004
|
||||
4.879-11.709-.174-4.771-1.887-8.719-5.096-11.754l.022-.002zm-1.517
|
||||
22.338c-2.82 2.818-6.246 4.119-10.41 4.119-4.119
|
||||
0-7.545-1.301-10.408-4.119-2.818-2.863-4.338-6.441-4.338-10.627 0-4.121
|
||||
1.301-7.545 4.164-10.408 2.818-2.817 6.225-4.121 10.582-4.121 4.121 0 7.549
|
||||
1.304 10.41 4.121 2.818 2.863 4.336 6.287 4.336 10.408 0 4.382-1.301
|
||||
7.764-4.336 10.627zm-8.502-9.651c1.691-.39 3.037-1.149 3.969-2.081.955-.977
|
||||
1.303-2.301 1.303-3.815
|
||||
0-1.692-.543-3.037-1.691-3.969-1.301-1.085-3.404-1.671-6.07-1.671h-6.029v21.164h3.037v-8.891h1.885c1.303
|
||||
0 2.604 1.3 3.773 3.773l2.254
|
||||
5.096h3.602l-2.818-5.683c-.977-2.472-2.105-3.601-3.252-3.97l.037.047zm-2.082-1.907h-3.252v-7.155h2.668c1.887
|
||||
0 3.209.345 3.969.932.758.563.932 1.301.932 2.646 0 2.45-1.518 3.579-4.336
|
||||
3.579l.019-.002zM933.443
|
||||
816.353h2.646v-21.187h7.002v-2.646h-16.652v2.646h7.006v21.187h-.002zm16.047-15.917c0-2.062
|
||||
0-3.753-.152-4.705.174 1.126.564 1.887.738 2.45l8.133
|
||||
18.172h1.301l8.152-18.347c.219-.563.393-1.301.76-2.275-.174 1.887-.174
|
||||
3.401-.174 4.553v16.048h2.82V792.52h-3.406l-7.371 16.438c-.174.587-.762
|
||||
1.734-1.129
|
||||
3.037h-.217c-.152-.761-.541-1.519-1.084-2.818l-7.373-16.655h-3.816v23.854h2.666v-15.917l.152-.023z" />
|
||||
</svg>
|
|
@ -0,0 +1,19 @@
|
|||
import Postgres from "./Postgres.svelte"
|
||||
import DynamoDB from "./DynamoDB.svelte"
|
||||
import Elasticsearch from "./Elasticsearch.svelte"
|
||||
import MongoDB from "./MongoDB.svelte"
|
||||
import CouchDB from "./CouchDB.svelte"
|
||||
import S3 from "./S3.svelte"
|
||||
import Airtable from "./Airtable.svelte"
|
||||
import SqlServer from "./SQLServer.svelte"
|
||||
|
||||
export default {
|
||||
POSTGRES: Postgres,
|
||||
DYNAMODB: DynamoDB,
|
||||
MONGODB: MongoDB,
|
||||
ELASTICSEARCH: Elasticsearch,
|
||||
COUCHDB: CouchDB,
|
||||
SQL_SERVER: SqlServer,
|
||||
S3: S3,
|
||||
AIRTABLE: Airtable,
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<script>
|
||||
import { goto, params } from "@sveltech/routify"
|
||||
import { backendUiStore, store } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import { Input, Label, ModalContent, Button, Spacer } from "@budibase/bbui"
|
||||
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
|
||||
import analytics from "analytics"
|
||||
|
||||
let modal
|
||||
let error = ""
|
||||
|
||||
let name
|
||||
let source
|
||||
let integration
|
||||
let datasource
|
||||
|
||||
function checkValid(evt) {
|
||||
const datasourceName = evt.target.value
|
||||
if (
|
||||
$backendUiStore.datasources?.some(
|
||||
datasource => datasource.name === datasourceName
|
||||
)
|
||||
) {
|
||||
error = `Datasource with name ${datasourceName} already exists. Please choose another name.`
|
||||
return
|
||||
}
|
||||
error = ""
|
||||
}
|
||||
|
||||
async function saveDatasource() {
|
||||
const { type, ...config } = integration
|
||||
|
||||
// Create datasource
|
||||
const response = await backendUiStore.actions.datasources.save({
|
||||
name,
|
||||
source: type,
|
||||
config,
|
||||
})
|
||||
notifier.success(`Datasource ${name} created successfully.`)
|
||||
analytics.captureEvent("Datasource Created", { name })
|
||||
|
||||
// Navigate to new datasource
|
||||
$goto(`./datasource/${response._id}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
title="Create Datasource"
|
||||
confirmText="Create"
|
||||
onConfirm={saveDatasource}
|
||||
disabled={error || !name}>
|
||||
<Input
|
||||
data-cy="datasource-name-input"
|
||||
thin
|
||||
label="Datasource Name"
|
||||
on:input={checkValid}
|
||||
bind:value={name}
|
||||
{error} />
|
||||
<Label grey extraSmall>Source</Label>
|
||||
<TableIntegrationMenu bind:integration />
|
||||
</ModalContent>
|
|
@ -0,0 +1,61 @@
|
|||
<script>
|
||||
import { goto, params } from "@sveltech/routify"
|
||||
import { backendUiStore, store } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import { Input, Label, ModalContent, Button, Spacer } from "@budibase/bbui"
|
||||
import TableIntegrationMenu from "../TableIntegrationMenu/index.svelte"
|
||||
import analytics from "analytics"
|
||||
|
||||
let modal
|
||||
let error = ""
|
||||
|
||||
let name
|
||||
let source
|
||||
let integration
|
||||
let datasource
|
||||
|
||||
function checkValid(evt) {
|
||||
const datasourceName = evt.target.value
|
||||
if (
|
||||
$backendUiStore.datasources?.some(
|
||||
datasource => datasource.name === datasourceName
|
||||
)
|
||||
) {
|
||||
error = `Datasource with name ${tableName} already exists. Please choose another name.`
|
||||
return
|
||||
}
|
||||
error = ""
|
||||
}
|
||||
|
||||
async function saveDatasource() {
|
||||
const { type, ...config } = integration
|
||||
|
||||
// Create datasource
|
||||
await backendUiStore.actions.datasources.save({
|
||||
name,
|
||||
source: type,
|
||||
config,
|
||||
})
|
||||
notifier.success(`Datasource ${name} created successfully.`)
|
||||
analytics.captureEvent("Datasource Created", { name })
|
||||
|
||||
// Navigate to new datasource
|
||||
$goto(`./datasource/${datasource._id}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
title="Create Datasource"
|
||||
confirmText="Create"
|
||||
onConfirm={saveDatasource}
|
||||
disabled={error || !name}>
|
||||
<Input
|
||||
data-cy="datasource-name-input"
|
||||
thin
|
||||
label="Datasource Name"
|
||||
on:input={checkValid}
|
||||
bind:value={name}
|
||||
{error} />
|
||||
<Label grey extraSmall>Create Integrated Table from External Source</Label>
|
||||
<TableIntegrationMenu bind:integration />
|
||||
</ModalContent>
|
|
@ -0,0 +1,87 @@
|
|||
<script>
|
||||
import { backendUiStore, store, allScreens } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import { DropdownMenu, Button, Input } from "@budibase/bbui"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import IntegrationConfigForm from "../TableIntegrationMenu//IntegrationConfigForm.svelte"
|
||||
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
||||
|
||||
export let datasource
|
||||
|
||||
let anchor
|
||||
let dropdown
|
||||
let confirmDeleteDialog
|
||||
let error = ""
|
||||
let originalName = datasource.name
|
||||
let willBeDeleted
|
||||
|
||||
function hideEditor() {
|
||||
dropdown?.hide()
|
||||
}
|
||||
|
||||
function showModal() {
|
||||
hideEditor()
|
||||
confirmDeleteDialog.show()
|
||||
}
|
||||
|
||||
async function deleteDatasource() {
|
||||
await backendUiStore.actions.datasources.delete(datasource)
|
||||
notifier.success("Datasource deleted")
|
||||
hideEditor()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div on:click|stopPropagation>
|
||||
<div bind:this={anchor} class="icon" on:click={dropdown.show}>
|
||||
<i class="ri-more-line" />
|
||||
</div>
|
||||
<DropdownMenu align="left" {anchor} bind:this={dropdown}>
|
||||
<DropdownContainer>
|
||||
<DropdownItem
|
||||
icon="ri-delete-bin-line"
|
||||
title="Delete"
|
||||
on:click={showModal}
|
||||
data-cy="delete-datasource" />
|
||||
</DropdownContainer>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
bind:this={confirmDeleteDialog}
|
||||
okText="Delete Datasource"
|
||||
onOk={deleteDatasource}
|
||||
title="Confirm Deletion">
|
||||
Are you sure you wish to delete the datasource
|
||||
<i>{datasource.name}?</i>
|
||||
This action cannot be undone.
|
||||
</ConfirmDialog>
|
||||
|
||||
<style>
|
||||
div.icon {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div.icon i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding: var(--spacing-xl);
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-xl);
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,84 @@
|
|||
<script>
|
||||
import { backendUiStore, store, allScreens } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import { DropdownMenu, Button, Input } from "@budibase/bbui"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import IntegrationConfigForm from "../TableIntegrationMenu//IntegrationConfigForm.svelte"
|
||||
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
||||
|
||||
export let query
|
||||
|
||||
let anchor
|
||||
let dropdown
|
||||
let confirmDeleteDialog
|
||||
let error = ""
|
||||
let willBeDeleted
|
||||
|
||||
function hideEditor() {
|
||||
dropdown?.hide()
|
||||
}
|
||||
|
||||
function showModal() {
|
||||
hideEditor()
|
||||
confirmDeleteDialog.show()
|
||||
}
|
||||
|
||||
async function deleteQuery() {
|
||||
await backendUiStore.actions.queries.delete(query)
|
||||
notifier.success("Query deleted")
|
||||
hideEditor()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div on:click|stopPropagation>
|
||||
<div bind:this={anchor} class="icon" on:click={dropdown.show}>
|
||||
<i class="ri-more-line" />
|
||||
</div>
|
||||
<DropdownMenu align="left" {anchor} bind:this={dropdown}>
|
||||
<DropdownContainer>
|
||||
<DropdownItem
|
||||
icon="ri-delete-bin-line"
|
||||
title="Delete"
|
||||
on:click={showModal}
|
||||
data-cy="delete-datasource" />
|
||||
</DropdownContainer>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
bind:this={confirmDeleteDialog}
|
||||
okText="Delete Query"
|
||||
onOk={deleteQuery}
|
||||
title="Confirm Deletion">
|
||||
Are you sure you wish to delete this query? This action cannot be undone.
|
||||
</ConfirmDialog>
|
||||
|
||||
<style>
|
||||
div.icon {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div.icon i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding: var(--spacing-xl);
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-xl);
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -5,7 +5,7 @@
|
|||
import api from "builderStore/api"
|
||||
|
||||
const BYTES_IN_MB = 1000000
|
||||
const FILE_SIZE_LIMIT = BYTES_IN_MB * 1
|
||||
const FILE_SIZE_LIMIT = BYTES_IN_MB * 5
|
||||
|
||||
export let files = []
|
||||
export let dataImport = {
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
import { goto } from "@sveltech/routify"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { TableNames } from "constants"
|
||||
import CreateTableModal from "./modals/CreateTableModal.svelte"
|
||||
import EditTablePopover from "./popovers/EditTablePopover.svelte"
|
||||
import EditViewPopover from "./popovers/EditViewPopover.svelte"
|
||||
import { Modal } from "@budibase/bbui"
|
||||
import { Switcher } from "@budibase/bbui"
|
||||
import NavItem from "components/common/NavItem.svelte"
|
||||
|
||||
let modal
|
||||
$: selectedView =
|
||||
$backendUiStore.selectedView && $backendUiStore.selectedView.name
|
||||
|
||||
|
@ -34,10 +32,6 @@
|
|||
</script>
|
||||
|
||||
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
|
||||
<div class="title">
|
||||
<h1>Tables</h1>
|
||||
<i data-cy="new-table" on:click={modal.show} class="ri-add-circle-fill" />
|
||||
</div>
|
||||
<div class="hierarchy-items-container">
|
||||
{#each $backendUiStore.tables as table, idx}
|
||||
<NavItem
|
||||
|
@ -64,27 +58,3 @@
|
|||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<Modal bind:this={modal}>
|
||||
<CreateTableModal />
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.title h1 {
|
||||
font-size: var(--font-size-m);
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
.title i {
|
||||
font-size: 20px;
|
||||
}
|
||||
.title i:hover {
|
||||
cursor: pointer;
|
||||
color: var(--blue);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
import { goto } from "@sveltech/routify"
|
||||
import { backendUiStore, store } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import { Input, Label, ModalContent, Toggle } from "@budibase/bbui"
|
||||
import {
|
||||
Input,
|
||||
Label,
|
||||
ModalContent,
|
||||
Button,
|
||||
Spacer,
|
||||
Toggle,
|
||||
} from "@budibase/bbui"
|
||||
import TableDataImport from "../TableDataImport.svelte"
|
||||
import analytics from "analytics"
|
||||
import screenTemplates from "builderStore/store/screenTemplates"
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<script>
|
||||
import { slide } from "svelte/transition"
|
||||
import Portal from "svelte-portal"
|
||||
|
||||
export let title
|
||||
export let onClose = () => {}
|
||||
</script>
|
||||
|
||||
<Portal>
|
||||
<section class="drawer" transition:slide>
|
||||
<header>
|
||||
{title}
|
||||
<div class="controls">
|
||||
<slot name="buttons" />
|
||||
<i class="ri-close-fill close" on:click={onClose} />
|
||||
</div>
|
||||
</header>
|
||||
<slot name="body" />
|
||||
</section>
|
||||
</Portal>
|
||||
|
||||
<style>
|
||||
.drawer {
|
||||
height: 50vh;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100vw;
|
||||
background: var(--background);
|
||||
border-top: var(--border-light);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border: var(--border-light);
|
||||
padding: var(--spacing-m);
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-gap: var(--spacing-m);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: var(--font-size-xl);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -29,6 +29,8 @@
|
|||
<i class="ri-arrow-right-s-line" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<slot name="icon" />
|
||||
{#if icon}
|
||||
<div class="icon"><i class={icon} /></div>
|
||||
{/if}
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<script>
|
||||
import CodeMirror from "./codemirror"
|
||||
import { onMount, createEventDispatcher } from "svelte"
|
||||
import { themeStore } from "builderStore"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const THEMES = {
|
||||
DARK: "tomorrow-night-eighties",
|
||||
LIGHT: "default",
|
||||
}
|
||||
|
||||
export let value = ""
|
||||
export let readOnly = false
|
||||
export let lineNumbers = true
|
||||
export let tab = true
|
||||
export let mode
|
||||
|
||||
let width
|
||||
let height
|
||||
|
||||
// We have to expose set and update methods, rather
|
||||
// than making this state-driven through props,
|
||||
// because it's difficult to update an editor
|
||||
// without resetting scroll otherwise
|
||||
export async function set(new_value, new_mode) {
|
||||
if (new_mode !== mode) {
|
||||
await createEditor((mode = new_mode))
|
||||
}
|
||||
|
||||
value = new_value
|
||||
updating_externally = true
|
||||
if (editor) editor.setValue(value)
|
||||
updating_externally = false
|
||||
}
|
||||
|
||||
export function update(new_value) {
|
||||
value = new_value
|
||||
|
||||
if (editor) {
|
||||
const { left, top } = editor.getScrollInfo()
|
||||
editor.setValue((value = new_value))
|
||||
editor.scrollTo(left, top)
|
||||
}
|
||||
}
|
||||
|
||||
export function resize() {
|
||||
editor.refresh()
|
||||
}
|
||||
|
||||
export function focus() {
|
||||
editor.focus()
|
||||
}
|
||||
|
||||
const modes = {
|
||||
js: {
|
||||
name: "javascript",
|
||||
json: false,
|
||||
},
|
||||
json: {
|
||||
name: "javascript",
|
||||
json: true,
|
||||
},
|
||||
sql: {
|
||||
name: "sql",
|
||||
},
|
||||
svelte: {
|
||||
name: "handlebars",
|
||||
base: "text/html",
|
||||
},
|
||||
}
|
||||
|
||||
const refs = {}
|
||||
let editor
|
||||
let updating_externally = false
|
||||
let marker
|
||||
let error_line
|
||||
let destroyed = false
|
||||
|
||||
$: if (editor && width && height) {
|
||||
editor.refresh()
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
createEditor(mode).then(() => {
|
||||
if (editor) editor.setValue(value || "")
|
||||
})
|
||||
|
||||
return () => {
|
||||
destroyed = true
|
||||
if (editor) editor.toTextArea()
|
||||
}
|
||||
})
|
||||
|
||||
let first = true
|
||||
|
||||
async function createEditor(mode) {
|
||||
if (destroyed || !CodeMirror) return
|
||||
|
||||
if (editor) editor.toTextArea()
|
||||
|
||||
const opts = {
|
||||
lineNumbers,
|
||||
lineWrapping: true,
|
||||
indentWithTabs: true,
|
||||
indentUnit: 2,
|
||||
tabSize: 2,
|
||||
value: "",
|
||||
mode: modes[mode] || {
|
||||
name: mode,
|
||||
},
|
||||
readOnly,
|
||||
autoCloseBrackets: true,
|
||||
autoCloseTags: true,
|
||||
theme: $themeStore.darkMode ? THEMES.DARK : THEMES.LIGHT,
|
||||
}
|
||||
|
||||
if (!tab)
|
||||
opts.extraKeys = {
|
||||
Tab: tab,
|
||||
"Shift-Tab": tab,
|
||||
}
|
||||
|
||||
// Creating a text editor is a lot of work, so we yield
|
||||
// the main thread for a moment. This helps reduce jank
|
||||
if (first) await sleep(50)
|
||||
|
||||
if (destroyed) return
|
||||
|
||||
editor = CodeMirror.fromTextArea(refs.editor, opts)
|
||||
|
||||
editor.on("change", instance => {
|
||||
if (!updating_externally) {
|
||||
const value = instance.getValue()
|
||||
dispatch("change", { value })
|
||||
}
|
||||
})
|
||||
|
||||
if (first) await sleep(50)
|
||||
editor.refresh()
|
||||
|
||||
first = false
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(fulfil => setTimeout(fulfil, ms))
|
||||
}
|
||||
</script>
|
||||
|
||||
<textarea tabindex="0" bind:this={refs.editor} readonly {value} />
|
||||
|
||||
<style>
|
||||
textarea {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
:global(.CodeMirror) {
|
||||
height: auto !important;
|
||||
border-radius: var(--border-radius-m);
|
||||
font-family: var(--font-sans) !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,56 @@
|
|||
<script>
|
||||
import {
|
||||
Button,
|
||||
TextArea,
|
||||
Label,
|
||||
Input,
|
||||
Heading,
|
||||
Select,
|
||||
} from "@budibase/bbui"
|
||||
import Editor from "./QueryEditor.svelte"
|
||||
|
||||
export let fields = {}
|
||||
export let schema
|
||||
export let editable
|
||||
|
||||
let draftField = {}
|
||||
|
||||
$: fieldKeys = Object.keys(fields)
|
||||
$: schemaKeys = Object.keys(schema.fields)
|
||||
|
||||
function updateCustomFields({ detail }) {
|
||||
fields.customData = detail.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault>
|
||||
{#each schemaKeys as field}
|
||||
<Label extraSmall grey>{field}</Label>
|
||||
<div class="field">
|
||||
<Input
|
||||
disabled={!editable}
|
||||
type={schema.fields[field]?.type}
|
||||
required={schema.fields[field]?.required}
|
||||
bind:value={fields[field]} />
|
||||
</div>
|
||||
{/each}
|
||||
</form>
|
||||
<Label extraSmall grey>Data</Label>
|
||||
{#if schema.customisable}
|
||||
<Editor
|
||||
label="Query"
|
||||
mode="json"
|
||||
on:change={updateCustomFields}
|
||||
readOnly={!editable}
|
||||
value={fields.customData} />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.field {
|
||||
margin-bottom: var(--spacing-m);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2%;
|
||||
grid-gap: var(--spacing-m);
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,88 @@
|
|||
<script>
|
||||
import { Button, TextArea, Label, Input, Heading } from "@budibase/bbui"
|
||||
import BindableInput from "components/userInterface/BindableInput.svelte"
|
||||
import {
|
||||
readableToRuntimeBinding,
|
||||
runtimeToReadableBinding,
|
||||
} from "builderStore/replaceBindings"
|
||||
|
||||
export let bindable = true
|
||||
export let parameters = []
|
||||
export let bindings = []
|
||||
export let customParams = {}
|
||||
|
||||
function newQueryParameter() {
|
||||
parameters = [...parameters, {}]
|
||||
}
|
||||
|
||||
function deleteQueryParameter(idx) {
|
||||
parameters.splice(idx, 1)
|
||||
parameters = parameters
|
||||
}
|
||||
|
||||
// This is necessary due to the way readable and writable bindings are stored.
|
||||
// The readable binding in the UI gets converted to a UUID value that the client understands
|
||||
// for parsing, then converted back so we can display it the readable form in the UI
|
||||
function onBindingChange(param, valueToParse) {
|
||||
const parsedBindingValue = readableToRuntimeBinding(bindings, valueToParse)
|
||||
customParams[param] = parsedBindingValue
|
||||
}
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<Heading extraSmall black>Parameters</Heading>
|
||||
<div class="parameters" class:bindable>
|
||||
<Label extraSmall grey>Parameter Name</Label>
|
||||
<Label extraSmall grey>Default</Label>
|
||||
{#if bindable}
|
||||
<Label extraSmall grey>Value</Label>
|
||||
{:else}
|
||||
<div />
|
||||
{/if}
|
||||
{#each parameters as parameter, idx}
|
||||
<Input thin disabled={bindable} bind:value={parameter.name} />
|
||||
<Input thin disabled={bindable} bind:value={parameter.default} />
|
||||
{#if bindable}
|
||||
<BindableInput
|
||||
type="string"
|
||||
thin
|
||||
on:change={evt => onBindingChange(parameter.name, evt.detail)}
|
||||
value={runtimeToReadableBinding(bindings, customParams[parameter.name])}
|
||||
{bindings} />
|
||||
{:else}
|
||||
<i
|
||||
class="ri-close-circle-line delete"
|
||||
on:click={() => deleteQueryParameter(idx)} />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{#if !bindable}
|
||||
<Button thin secondary small on:click={newQueryParameter}>
|
||||
Add Parameter
|
||||
</Button>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.parameters.bindable {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.parameters {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 5%;
|
||||
grid-gap: 10px;
|
||||
align-items: center;
|
||||
margin-bottom: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.delete {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.delete:hover {
|
||||
transform: scale(1.1);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,284 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { goto } from "@sveltech/routify"
|
||||
import {
|
||||
Select,
|
||||
Button,
|
||||
Label,
|
||||
Input,
|
||||
TextArea,
|
||||
Heading,
|
||||
Spacer,
|
||||
Switcher,
|
||||
} from "@budibase/bbui"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import api from "builderStore/api"
|
||||
import { FIELDS } from "constants/backend"
|
||||
import IntegrationQueryEditor from "components/integration/index.svelte"
|
||||
import ExternalDataSourceTable from "components/backend/DataTable/ExternalDataSourceTable.svelte"
|
||||
import { backendUiStore } from "builderStore"
|
||||
|
||||
const PREVIEW_HEADINGS = [
|
||||
{
|
||||
title: "JSON",
|
||||
key: "JSON",
|
||||
},
|
||||
{
|
||||
title: "Schema",
|
||||
key: "SCHEMA",
|
||||
},
|
||||
{
|
||||
title: "Preview",
|
||||
key: "PREVIEW",
|
||||
},
|
||||
]
|
||||
|
||||
export let query
|
||||
export let fields = []
|
||||
|
||||
let config
|
||||
let tab = "JSON"
|
||||
let parameters
|
||||
let data = []
|
||||
|
||||
$: datasource = $backendUiStore.datasources.find(
|
||||
ds => ds._id === query.datasourceId
|
||||
)
|
||||
|
||||
$: query.schema = fields.reduce(
|
||||
(acc, next) => ({
|
||||
...acc,
|
||||
[next.name]: {
|
||||
name: next.name,
|
||||
type: "string",
|
||||
},
|
||||
}),
|
||||
{}
|
||||
)
|
||||
|
||||
$: datasourceType = datasource?.source
|
||||
|
||||
$: config = $backendUiStore.integrations[datasourceType]?.query
|
||||
$: docsLink = $backendUiStore.integrations[datasourceType]?.docs
|
||||
|
||||
$: shouldShowQueryConfig = config && query.queryVerb && query.queryType
|
||||
|
||||
function newField() {
|
||||
fields = [...fields, {}]
|
||||
}
|
||||
|
||||
function deleteField(idx) {
|
||||
fields.splice(idx, 1)
|
||||
fields = fields
|
||||
}
|
||||
|
||||
async function previewQuery() {
|
||||
try {
|
||||
const response = await api.post(`/api/queries/preview`, {
|
||||
fields: query.fields,
|
||||
queryVerb: query.queryVerb,
|
||||
parameters: query.parameters.reduce(
|
||||
(acc, next) => ({
|
||||
...acc,
|
||||
[next.name]: next.default,
|
||||
}),
|
||||
{}
|
||||
),
|
||||
datasourceId: datasource._id,
|
||||
})
|
||||
const json = await response.json()
|
||||
|
||||
if (response.status !== 200) throw new Error(json.message)
|
||||
|
||||
data = json || []
|
||||
|
||||
if (data.length === 0) {
|
||||
notifier.info(
|
||||
"Query results empty. Please execute a query with results to create your schema."
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
notifier.success("Query executed successfully.")
|
||||
|
||||
// Assume all the fields are strings and create a basic schema
|
||||
// from the first record returned by the query
|
||||
fields = Object.keys(json[0]).map(field => ({
|
||||
name: field,
|
||||
type: "STRING",
|
||||
}))
|
||||
} catch (err) {
|
||||
notifier.danger(`Query Error: ${err.message}`)
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
async function saveQuery() {
|
||||
try {
|
||||
const { _id } = await backendUiStore.actions.queries.save(
|
||||
query.datasourceId,
|
||||
query
|
||||
)
|
||||
notifier.success(`Query saved successfully.`)
|
||||
$goto(`../../${_id}`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
notifier.danger(`Error creating query. ${err.message}`)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<Heading small>{query.name}</Heading>
|
||||
{#if config}
|
||||
<div class="queryVerbs">
|
||||
{#each Object.keys(config) as queryVerb}
|
||||
<div
|
||||
class="queryVerb"
|
||||
class:selected={queryVerb === query.queryVerb}
|
||||
on:click={() => {
|
||||
query.queryVerb = queryVerb
|
||||
}}>
|
||||
{queryVerb}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if query.queryVerb}
|
||||
<Select thin secondary bind:value={query.queryType}>
|
||||
<option value={''}>Select an option</option>
|
||||
{#each Object.keys(config[query.queryVerb]) as queryType}
|
||||
<option value={queryType}>{queryType}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
{/if}
|
||||
<Spacer medium />
|
||||
<Button primary href={docsLink} target="_blank">
|
||||
<i class="ri-book-2-line" />
|
||||
</Button>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
<Spacer large />
|
||||
|
||||
{#if shouldShowQueryConfig}
|
||||
<section>
|
||||
<div class="config">
|
||||
<Label extraSmall grey>Query Name</Label>
|
||||
<Input thin bind:value={query.name} />
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
<IntegrationQueryEditor
|
||||
{query}
|
||||
schema={config[query.queryVerb][query.queryType]}
|
||||
bind:parameters />
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
<div class="viewer-controls">
|
||||
<Button
|
||||
wide
|
||||
thin
|
||||
blue
|
||||
disabled={data.length === 0}
|
||||
on:click={saveQuery}>
|
||||
Save
|
||||
</Button>
|
||||
<Button wide thin primary on:click={previewQuery}>Run</Button>
|
||||
</div>
|
||||
|
||||
<section class="viewer">
|
||||
{#if data}
|
||||
<Switcher headings={PREVIEW_HEADINGS} bind:value={tab}>
|
||||
{#if tab === 'JSON'}
|
||||
<pre class="preview">{JSON.stringify(data[0], undefined, 2)}</pre>
|
||||
{:else if tab === 'PREVIEW'}
|
||||
<ExternalDataSourceTable {query} {data} />
|
||||
{:else if tab === 'SCHEMA'}
|
||||
{#each fields as field, idx}
|
||||
<div class="field">
|
||||
<Input thin type={'text'} bind:value={field.name} />
|
||||
<Select secondary thin bind:value={field.type}>
|
||||
<option value={''}>Select an option</option>
|
||||
<option value={'STRING'}>Text</option>
|
||||
<option value={'NUMBER'}>Number</option>
|
||||
<option value={'BOOLEAN'}>Boolean</option>
|
||||
<option value={'DATETIME'}>Datetime</option>
|
||||
</Select>
|
||||
<i
|
||||
class="ri-close-circle-line delete"
|
||||
on:click={() => deleteField(idx)} />
|
||||
</div>
|
||||
{/each}
|
||||
<Button thin secondary on:click={newField}>Add Field</Button>
|
||||
{/if}
|
||||
</Switcher>
|
||||
{/if}
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.field {
|
||||
display: grid;
|
||||
grid-gap: 10px;
|
||||
grid-template-columns: 1fr 1fr 50px;
|
||||
margin-bottom: var(--spacing-m);
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: var(--font-size-s);
|
||||
}
|
||||
|
||||
.config {
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
|
||||
.delete {
|
||||
align-self: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 800px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.queryVerbs {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
font-size: var(--font-size-m);
|
||||
align-items: center;
|
||||
margin-left: var(--spacing-l);
|
||||
}
|
||||
|
||||
.queryVerb {
|
||||
text-transform: capitalize;
|
||||
margin-right: var(--spacing-m);
|
||||
color: var(--grey-5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: var(--white);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.viewer-controls {
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-m);
|
||||
grid-auto-flow: column;
|
||||
direction: rtl;
|
||||
grid-template-columns: 10% 10% 1fr;
|
||||
margin-bottom: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,10 @@
|
|||
import CodeMirror from "codemirror"
|
||||
import "codemirror/lib/codemirror.css"
|
||||
import "codemirror/theme/tomorrow-night-eighties.css"
|
||||
import "codemirror/theme/neo.css"
|
||||
import "codemirror/mode/sql/sql"
|
||||
import "codemirror/mode/css/css"
|
||||
import "codemirror/mode/handlebars/handlebars"
|
||||
import "codemirror/mode/javascript/javascript"
|
||||
|
||||
export default CodeMirror
|
|
@ -0,0 +1,52 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { TextArea, Label, Input, Heading, Spacer } from "@budibase/bbui"
|
||||
import Editor from "./QueryEditor.svelte"
|
||||
import ParameterBuilder from "./QueryParameterBuilder.svelte"
|
||||
import FieldsBuilder from "./QueryFieldsBuilder.svelte"
|
||||
|
||||
const QueryTypes = {
|
||||
SQL: "sql",
|
||||
JSON: "json",
|
||||
FIELDS: "fields",
|
||||
}
|
||||
|
||||
export let query
|
||||
export let schema
|
||||
export let editable = true
|
||||
|
||||
function updateQuery({ detail }) {
|
||||
query.fields[schema.type] = detail.value
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if editable}
|
||||
<ParameterBuilder bind:parameters={query.parameters} bindable={false} />
|
||||
<Spacer large />
|
||||
{/if}
|
||||
|
||||
<Heading extraSmall black>Query</Heading>
|
||||
<Spacer medium />
|
||||
|
||||
{#if schema}
|
||||
{#key query._id}
|
||||
{#if schema.type === QueryTypes.SQL}
|
||||
<Editor
|
||||
label="Query"
|
||||
mode="sql"
|
||||
on:change={updateQuery}
|
||||
readOnly={!editable}
|
||||
value={query.fields.sql} />
|
||||
{:else if schema.type === QueryTypes.JSON}
|
||||
<Spacer large />
|
||||
<Editor
|
||||
label="Query"
|
||||
mode="json"
|
||||
on:change={updateQuery}
|
||||
readOnly={!editable}
|
||||
value={query.fields.json} />
|
||||
{:else if schema.type === QueryTypes.FIELDS}
|
||||
<FieldsBuilder bind:fields={query.fields} {schema} {editable} />
|
||||
{/if}
|
||||
{/key}
|
||||
{/if}
|
|
@ -1,9 +1,13 @@
|
|||
<script>
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import GenericBindingPopover from "./GenericBindingPopover.svelte"
|
||||
import { Input, Icon } from "@budibase/bbui"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let bindings = []
|
||||
export let value
|
||||
|
||||
let anchor
|
||||
let popover = undefined
|
||||
let enrichedValue
|
||||
|
@ -14,6 +18,7 @@
|
|||
let { bindings, ...otherProps } = $$props
|
||||
inputProps = otherProps
|
||||
}
|
||||
$: value && dispatch("change", value)
|
||||
</script>
|
||||
|
||||
<div class="container" bind:this={anchor}>
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
<script>
|
||||
import {
|
||||
Button,
|
||||
TextButton,
|
||||
Body,
|
||||
DropdownMenu,
|
||||
ModalContent,
|
||||
} from "@budibase/bbui"
|
||||
import { AddIcon, ArrowDownIcon } from "components/common/Icons/"
|
||||
import actionTypes from "./actions"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { automationStore } from "builderStore"
|
||||
|
||||
const EVENT_TYPE_KEY = "##eventHandlerType"
|
||||
|
||||
export let event
|
||||
|
||||
let addActionButton
|
||||
let addActionDropdown
|
||||
let selectedAction
|
||||
|
||||
$: actions = event || []
|
||||
$: selectedActionComponent =
|
||||
selectedAction &&
|
||||
actionTypes.find(t => t.name === selectedAction[EVENT_TYPE_KEY]).component
|
||||
|
||||
const deleteAction = index => {
|
||||
actions.splice(index, 1)
|
||||
actions = actions
|
||||
}
|
||||
|
||||
const addAction = actionType => () => {
|
||||
const newAction = {
|
||||
parameters: {},
|
||||
[EVENT_TYPE_KEY]: actionType.name,
|
||||
}
|
||||
actions.push(newAction)
|
||||
selectedAction = newAction
|
||||
actions = actions
|
||||
addActionDropdown.hide()
|
||||
}
|
||||
|
||||
const selectAction = action => () => {
|
||||
selectedAction = action
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="actions-container">
|
||||
<div class="actions-list">
|
||||
<div>
|
||||
<div bind:this={addActionButton}>
|
||||
<TextButton text small blue on:click={addActionDropdown.show}>
|
||||
<div style="height: 20px; width: 20px;">
|
||||
<AddIcon />
|
||||
</div>
|
||||
Add Action
|
||||
</TextButton>
|
||||
</div>
|
||||
<DropdownMenu
|
||||
bind:this={addActionDropdown}
|
||||
anchor={addActionButton}
|
||||
align="right">
|
||||
<div class="available-actions-container">
|
||||
{#each actionTypes as actionType}
|
||||
<div class="available-action" on:click={addAction(actionType)}>
|
||||
<span>{actionType.name}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
{#if actions && actions.length > 0}
|
||||
{#each actions as action, index}
|
||||
<div class="action-container">
|
||||
<div class="action-header" on:click={selectAction(action)}>
|
||||
<span class:selected={action === selectedAction}>
|
||||
{index + 1}.
|
||||
{action[EVENT_TYPE_KEY]}
|
||||
</span>
|
||||
</div>
|
||||
<i
|
||||
class="ri-close-fill"
|
||||
style="margin-left: var(--spacing-m);"
|
||||
on:click={() => deleteAction(index)} />
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="action-config">
|
||||
{#if selectedAction}
|
||||
<div class="selected-action-container">
|
||||
<svelte:component
|
||||
this={selectedActionComponent}
|
||||
parameters={selectedAction.parameters} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.action-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-m);
|
||||
}
|
||||
|
||||
.action-header > span {
|
||||
margin-bottom: var(--spacing-m);
|
||||
font-size: var(--font-size-s);
|
||||
}
|
||||
|
||||
.action-header > span:hover,
|
||||
.selected {
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.actions-list {
|
||||
border: var(--border-light);
|
||||
padding: var(--spacing-s);
|
||||
}
|
||||
|
||||
.available-action {
|
||||
padding: var(--spacing-s);
|
||||
font-size: var(--font-size-m);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.available-action:hover {
|
||||
background: var(--grey-2);
|
||||
}
|
||||
|
||||
.actions-container {
|
||||
height: 40vh;
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-m);
|
||||
grid-template-columns: 15% 1fr;
|
||||
grid-auto-flow: column;
|
||||
min-height: 0;
|
||||
padding-top: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.action-container {
|
||||
border: var(--border-light);
|
||||
border-width: 1px 0 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.selected-action-container {
|
||||
padding-bottom: var(--spacing-s);
|
||||
padding-top: var(--spacing-s);
|
||||
}
|
||||
|
||||
a {
|
||||
flex: 1;
|
||||
color: var(--grey-5);
|
||||
font-size: var(--font-size-s);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--blue);
|
||||
}
|
||||
</style>
|
|
@ -1,17 +1,76 @@
|
|||
<script>
|
||||
import { Button, Modal } from "@budibase/bbui"
|
||||
import EventEditorModal from "./EventEditorModal.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { store } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import EventEditor from "./EventEditor.svelte"
|
||||
import BottomDrawer from "components/common/BottomDrawer.svelte"
|
||||
import { automationStore } from "builderStore"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let value
|
||||
export let name
|
||||
|
||||
let modal
|
||||
let drawerVisible
|
||||
|
||||
function showDrawer() {
|
||||
drawerVisible = true
|
||||
}
|
||||
|
||||
const saveEventData = async () => {
|
||||
// any automations that need created from event triggers
|
||||
const automationsToCreate = value.filter(
|
||||
action => action["##eventHandlerType"] === "Trigger Automation"
|
||||
)
|
||||
automationsToCreate.forEach(action => createAutomation(action.parameters))
|
||||
|
||||
dispatch("change", value)
|
||||
notifier.success("Component actions saved.")
|
||||
}
|
||||
|
||||
// called by the parent modal when actions are saved
|
||||
const createAutomation = async parameters => {
|
||||
if (parameters.automationId || !parameters.newAutomationName) return
|
||||
|
||||
await automationStore.actions.create({ name: parameters.newAutomationName })
|
||||
|
||||
const appActionDefinition = $automationStore.blockDefinitions.TRIGGER.APP
|
||||
|
||||
const newBlock = $automationStore.selectedAutomation.constructBlock(
|
||||
"TRIGGER",
|
||||
"APP",
|
||||
appActionDefinition
|
||||
)
|
||||
|
||||
newBlock.inputs = {
|
||||
fields: Object.entries(parameters.fields).reduce(
|
||||
(fields, [key, value]) => {
|
||||
fields[key] = value.type
|
||||
return fields
|
||||
},
|
||||
{}
|
||||
),
|
||||
}
|
||||
|
||||
automationStore.actions.addBlockToAutomation(newBlock)
|
||||
|
||||
await automationStore.actions.save($automationStore.selectedAutomation)
|
||||
|
||||
parameters.automationId = $automationStore.selectedAutomation.automation._id
|
||||
delete parameters.newAutomationName
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button secondary small on:click={modal.show}>Define Actions</Button>
|
||||
<Button secondary small on:click={showDrawer}>Define Actions</Button>
|
||||
|
||||
<Modal bind:this={modal} width="600px">
|
||||
<EventEditorModal event={value} eventType={name} on:change />
|
||||
</Modal>
|
||||
{#if drawerVisible}
|
||||
<BottomDrawer title={'Actions'} onClose={() => (drawerVisible = false)}>
|
||||
<heading slot="buttons">
|
||||
<Button thin blue on:click={saveEventData}>Save</Button>
|
||||
</heading>
|
||||
<div slot="body">
|
||||
<EventEditor event={value} eventType={name} />
|
||||
</div>
|
||||
</BottomDrawer>
|
||||
{/if}
|
||||
|
|
|
@ -11,11 +11,9 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
// just wraps binding in {{ ... }}
|
||||
const toBindingExpression = bindingPath => `{{ ${bindingPath} }}`
|
||||
|
||||
const tableFields = tableId => {
|
||||
const table = $backendUiStore.tables.find(m => m._id === tableId)
|
||||
|
||||
|
@ -63,12 +61,4 @@
|
|||
grid-column-start: 2;
|
||||
grid-column-end: 6;
|
||||
}
|
||||
|
||||
.cannot-use {
|
||||
color: var(--red);
|
||||
font-size: var(--font-size-s);
|
||||
text-align: center;
|
||||
width: 70%;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
$: idFields = bindableProperties.filter(
|
||||
|
@ -42,8 +43,6 @@
|
|||
typeof tableInfo === "string" ? tableInfo : tableInfo.tableId
|
||||
}
|
||||
}
|
||||
|
||||
console.log(parameters)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<script>
|
||||
import { Select, Label, Spacer } from "@budibase/bbui"
|
||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
||||
import ParameterBuilder from "../../../integration/QueryParameterBuilder.svelte"
|
||||
|
||||
export let parameters
|
||||
|
||||
$: datasource = $backendUiStore.datasources.find(
|
||||
ds => ds._id === parameters.datasourceId
|
||||
)
|
||||
// TODO: binding needs to be centralised
|
||||
$: bindableProperties = fetchBindableProperties({
|
||||
componentInstanceId: $store.selectedComponentId,
|
||||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
}).map(property => ({
|
||||
...property,
|
||||
category: property.type === "instance" ? "Component" : "Table",
|
||||
label: property.readableBinding,
|
||||
path: property.readableBinding,
|
||||
}))
|
||||
|
||||
$: query =
|
||||
parameters.queryId &&
|
||||
$backendUiStore.queries.find(query => query._id === parameters.queryId)
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<Label size="m" color="dark">Datasource</Label>
|
||||
<Select thin secondary bind:value={parameters.datasourceId}>
|
||||
<option value="" />
|
||||
{#each $backendUiStore.datasources as datasource}
|
||||
<option value={datasource._id}>{datasource.name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
{#if parameters.datasourceId}
|
||||
<Label size="m" color="dark">Query</Label>
|
||||
<Select thin secondary bind:value={parameters.queryId}>
|
||||
<option value="" />
|
||||
{#each $backendUiStore.queries.filter(query => query.datasourceId === datasource._id) as query}
|
||||
<option value={query._id}>{query.name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
{/if}
|
||||
|
||||
<Spacer medium />
|
||||
|
||||
{#if query?.parameters?.length > 0}
|
||||
<ParameterBuilder
|
||||
bind:customParams={parameters.queryParams}
|
||||
parameters={query.parameters}
|
||||
bindings={bindableProperties} />
|
||||
{#if query.fields.sql}
|
||||
<pre>{query.fields.queryString}</pre>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
padding: var(--spacing-m);
|
||||
}
|
||||
</style>
|
|
@ -44,6 +44,7 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
const addField = () => {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
$: {
|
||||
|
|
|
@ -3,9 +3,16 @@
|
|||
import { automationStore } from "builderStore"
|
||||
import SaveFields from "./SaveFields.svelte"
|
||||
|
||||
const AUTOMATION_STATUS = {
|
||||
NEW: "new",
|
||||
EXISTING: "existing",
|
||||
}
|
||||
|
||||
export let parameters = {}
|
||||
|
||||
let newOrExisting = parameters.automationId ? "existing" : "new"
|
||||
let automationStatus = parameters.automationId
|
||||
? AUTOMATION_STATUS.EXISTING
|
||||
: AUTOMATION_STATUS.NEW
|
||||
|
||||
$: automations = $automationStore.automations
|
||||
.filter(a => a.definition.trigger?.stepId === "APP")
|
||||
|
@ -33,12 +40,12 @@
|
|||
}
|
||||
|
||||
const setNew = () => {
|
||||
newOrExisting = "new"
|
||||
automationStatus = AUTOMATION_STATUS.NEW
|
||||
parameters.automationId = undefined
|
||||
}
|
||||
|
||||
const setExisting = () => {
|
||||
newOrExisting = "existing"
|
||||
automationStatus = AUTOMATION_STATUS.EXISTING
|
||||
parameters.newAutomationName = ""
|
||||
}
|
||||
</script>
|
||||
|
@ -47,8 +54,8 @@
|
|||
<div class="radio-container" on:click={setNew}>
|
||||
<input
|
||||
type="radio"
|
||||
value="new"
|
||||
bind:group={newOrExisting}
|
||||
value={AUTOMATION_STATUS.NEW}
|
||||
bind:group={automationStatus}
|
||||
disabled={!hasAutomations} />
|
||||
|
||||
<Label disabled={!hasAutomations}>Create a new automation</Label>
|
||||
|
@ -57,8 +64,8 @@
|
|||
<div class="radio-container" on:click={setExisting}>
|
||||
<input
|
||||
type="radio"
|
||||
value="existing"
|
||||
bind:group={newOrExisting}
|
||||
value={AUTOMATION_STATUS.EXISTING}
|
||||
bind:group={automationStatus}
|
||||
disabled={!hasAutomations} />
|
||||
|
||||
<Label disabled={!hasAutomations}>Use an existing automation</Label>
|
||||
|
@ -66,7 +73,7 @@
|
|||
|
||||
<Label size="m" color="dark">Automation</Label>
|
||||
|
||||
{#if newOrExisting === 'existing'}
|
||||
{#if automationStatus === AUTOMATION_STATUS.EXISTING}
|
||||
<Select
|
||||
secondary
|
||||
bind:value={parameters.automationId}
|
||||
|
@ -85,7 +92,7 @@
|
|||
|
||||
<SaveFields
|
||||
parameterFields={parameters.fields}
|
||||
schemaFields={newOrExisting === 'existing' && selectedAutomation && selectedAutomation.schema}
|
||||
schemaFields={automationStatus === AUTOMATION_STATUS.EXISTING && selectedAutomation && selectedAutomation.schema}
|
||||
fieldLabel="Field"
|
||||
on:fieldschanged={onFieldsChanged} />
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
let idFields
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import NavigateTo from "./NavigateTo.svelte"
|
||||
import SaveRow from "./SaveRow.svelte"
|
||||
import DeleteRow from "./DeleteRow.svelte"
|
||||
import ExecuteQuery from "./ExecuteQuery.svelte"
|
||||
import TriggerAutomation from "./TriggerAutomation.svelte"
|
||||
|
||||
// defines what actions are available, when adding a new one
|
||||
|
@ -21,6 +22,10 @@ export default [
|
|||
name: "Navigate To",
|
||||
component: NavigateTo,
|
||||
},
|
||||
{
|
||||
name: "Execute Query",
|
||||
component: ExecuteQuery,
|
||||
},
|
||||
{
|
||||
name: "Trigger Automation",
|
||||
component: TriggerAutomation,
|
||||
|
|
|
@ -50,7 +50,9 @@
|
|||
<span class="binding__label">{binding.label}</span>
|
||||
<span class="binding__type">{binding.type}</span>
|
||||
<br />
|
||||
<div class="binding__description">{binding.description}</div>
|
||||
<div class="binding__description">
|
||||
{binding.description || ''}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -120,6 +121,7 @@
|
|||
flex-flow: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
const detailScreens = $allScreens.filter(screen =>
|
||||
|
|
|
@ -9,17 +9,20 @@
|
|||
export let multiselect = false
|
||||
|
||||
const tables = $backendUiStore.tables
|
||||
const queries = $backendUiStore.queries
|
||||
|
||||
let options = []
|
||||
|
||||
$: table = componentInstance.datasource
|
||||
? tables.find(m => m._id === componentInstance.datasource.tableId)
|
||||
: null
|
||||
$: table =
|
||||
componentInstance.datasource?.type === "table"
|
||||
? tables.find(m => m._id === componentInstance.datasource.tableId)
|
||||
: queries.find(query => query._id === componentInstance.datasource._id)
|
||||
|
||||
$: type = componentInstance.datasource.type
|
||||
|
||||
$: if (table) {
|
||||
options =
|
||||
type === "table" || type === "link"
|
||||
type === "table" || type === "link" || type === "query"
|
||||
? Object.keys(table.schema)
|
||||
: Object.keys(table.views[componentInstance.datasource.name].schema)
|
||||
}
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
import { Button, Icon, DropdownMenu, Spacer, Heading } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import BottomDrawer from "components/common/BottomDrawer.svelte"
|
||||
import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
|
||||
import IntegrationQueryEditor from "components/integration/index.svelte"
|
||||
import fetchBindableProperties from "../../builderStore/fetchBindableProperties"
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let anchorRight, dropdownRight
|
||||
let bindingDrawerOpen
|
||||
|
||||
export let value = {}
|
||||
|
||||
function handleSelected(selected) {
|
||||
dispatch("change", selected)
|
||||
dropdownRight.hide()
|
||||
}
|
||||
|
||||
$: tables = $backendUiStore.tables.map(m => ({
|
||||
label: m.name,
|
||||
name: `all_${m._id}`,
|
||||
|
@ -31,13 +31,30 @@
|
|||
return [...acc, ...viewsArr]
|
||||
}, [])
|
||||
|
||||
$: queries = $backendUiStore.queries.map(query => ({
|
||||
label: query.name,
|
||||
name: query.name,
|
||||
...query,
|
||||
schema: query.schema,
|
||||
parameters: query.parameters,
|
||||
type: "query",
|
||||
}))
|
||||
|
||||
$: bindableProperties = fetchBindableProperties({
|
||||
componentInstanceId: $store.selectedComponentId,
|
||||
components: $store.components,
|
||||
screen: $currentAsset,
|
||||
tables: $backendUiStore.tables,
|
||||
queries: $backendUiStore.queries,
|
||||
})
|
||||
|
||||
$: queryBindableProperties = bindableProperties.map(property => ({
|
||||
...property,
|
||||
category: property.type === "instance" ? "Component" : "Table",
|
||||
label: property.readableBinding,
|
||||
path: property.readableBinding,
|
||||
}))
|
||||
|
||||
$: links = bindableProperties
|
||||
.filter(x => x.fieldSchema?.type === "link")
|
||||
.map(property => {
|
||||
|
@ -50,15 +67,68 @@
|
|||
type: "link",
|
||||
}
|
||||
})
|
||||
|
||||
function handleSelected(selected) {
|
||||
dispatch("change", selected)
|
||||
dropdownRight.hide()
|
||||
}
|
||||
|
||||
function openBindingDrawer() {
|
||||
bindingDrawerOpen = true
|
||||
}
|
||||
|
||||
function closeDatabindingDrawer() {
|
||||
bindingDrawerOpen = false
|
||||
}
|
||||
|
||||
function fetchDatasourceSchema(query) {
|
||||
const source = $backendUiStore.datasources.find(
|
||||
ds => ds._id === query.datasourceId
|
||||
).source
|
||||
return $backendUiStore.integrations[source].query[query.queryVerb][
|
||||
query.queryType
|
||||
]
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="dropdownbutton"
|
||||
bind:this={anchorRight}
|
||||
on:click={dropdownRight.show}>
|
||||
<span>{value.label ? value.label : 'Table / View'}</span>
|
||||
<span>{value.label ? value.label : 'Table / View / Query'}</span>
|
||||
<Icon name="arrowdown" />
|
||||
</div>
|
||||
{#if value.type === 'query'}
|
||||
<i class="ri-settings-5-line" on:click={openBindingDrawer} />
|
||||
{#if bindingDrawerOpen}
|
||||
<BottomDrawer title={'Query'} onClose={closeDatabindingDrawer}>
|
||||
<div slot="buttons">
|
||||
<Button
|
||||
blue
|
||||
thin
|
||||
on:click={() => {
|
||||
notifier.success('Query parameters saved.')
|
||||
handleSelected(value)
|
||||
}}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
<div class="drawer-contents" slot="body">
|
||||
<IntegrationQueryEditor
|
||||
query={value}
|
||||
schema={fetchDatasourceSchema(value)}
|
||||
editable={false} />
|
||||
<Spacer large />
|
||||
{#if value.parameters.length > 0}
|
||||
<ParameterBuilder
|
||||
bind:customParams={value.queryParams}
|
||||
parameters={queries.find(query => query._id === value._id).parameters}
|
||||
bindings={queryBindableProperties} />
|
||||
{/if}
|
||||
</div>
|
||||
</BottomDrawer>
|
||||
{/if}
|
||||
{/if}
|
||||
<DropdownMenu bind:this={dropdownRight} anchor={anchorRight}>
|
||||
<div class="dropdown">
|
||||
<div class="title">
|
||||
|
@ -99,6 +169,20 @@
|
|||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<hr />
|
||||
<div class="title">
|
||||
<Heading extraSmall>Queries</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each queries as query}
|
||||
<li
|
||||
class:selected={value === query}
|
||||
on:click={() => handleSelected(query)}>
|
||||
{query.label}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
|
||||
|
@ -163,4 +247,23 @@
|
|||
li:hover {
|
||||
background-color: var(--grey-4);
|
||||
}
|
||||
|
||||
.drawer-contents {
|
||||
padding: var(--spacing-xl);
|
||||
height: 40vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-left: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
transform: scale(1.1);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,11 +1,49 @@
|
|||
<script>
|
||||
import { params } from "@sveltech/routify"
|
||||
import { Switcher, Modal } from "@budibase/bbui"
|
||||
import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte"
|
||||
import DatasourceNavigator from "components/backend/DatasourceNavigator/DatasourceNavigator.svelte"
|
||||
import CreateDatasourceModal from "components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte"
|
||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
title: "Tables",
|
||||
key: "table",
|
||||
},
|
||||
{
|
||||
title: "Data Sources",
|
||||
key: "datasource",
|
||||
},
|
||||
]
|
||||
|
||||
let tab = $params.selectedDatasource ? "datasource" : "table"
|
||||
|
||||
let modal
|
||||
</script>
|
||||
|
||||
<!-- routify:options index=0 -->
|
||||
<div class="root">
|
||||
<div class="nav">
|
||||
<TableNavigator />
|
||||
<Switcher headings={tabs} bind:value={tab}>
|
||||
<div class="title">
|
||||
<i
|
||||
data-cy={`new-${tab}`}
|
||||
class="ri-add-circle-fill"
|
||||
on:click={modal.show} />
|
||||
</div>
|
||||
{#if tab === 'table'}
|
||||
<TableNavigator />
|
||||
<Modal bind:this={modal}>
|
||||
<CreateTableModal />
|
||||
</Modal>
|
||||
{:else if tab === 'datasource'}
|
||||
<DatasourceNavigator />
|
||||
<Modal bind:this={modal}>
|
||||
<CreateDatasourceModal />
|
||||
</Modal>
|
||||
{/if}
|
||||
</Switcher>
|
||||
</div>
|
||||
<div class="content">
|
||||
<slot />
|
||||
|
@ -19,6 +57,7 @@
|
|||
grid-template-columns: 260px minmax(0, 1fr);
|
||||
background: var(--grey-2);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1 1 auto;
|
||||
padding: var(--spacing-l) 40px;
|
||||
|
@ -29,6 +68,7 @@
|
|||
align-items: stretch;
|
||||
gap: var(--spacing-l);
|
||||
}
|
||||
|
||||
.nav {
|
||||
overflow-y: auto;
|
||||
background: var(--background);
|
||||
|
@ -38,5 +78,18 @@
|
|||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
gap: var(--spacing-l);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
top: var(--spacing-l);
|
||||
right: var(--spacing-xl);
|
||||
}
|
||||
|
||||
i:hover {
|
||||
cursor: pointer;
|
||||
color: var(--blue);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import { params } from "@sveltech/routify"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { Switcher } from "@budibase/bbui"
|
||||
import QueryInterface from "components/integration/QueryViewer.svelte"
|
||||
|
||||
let query
|
||||
|
||||
async function fetchQueryConfig() {
|
||||
try {
|
||||
const response = await api.get(`/api/integrations/${datasource.source}`)
|
||||
const json = await response.json()
|
||||
config = json.query
|
||||
} catch (err) {
|
||||
notifier.danger("Error fetching datasource configuration options.")
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
$: selectedQuery = $backendUiStore.queries.find(
|
||||
query => query._id === $backendUiStore.selectedQueryId
|
||||
) || {
|
||||
datasourceId: $params.selectedDatasource,
|
||||
name: "New Query",
|
||||
parameters: [],
|
||||
fields: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<section>
|
||||
{#if $backendUiStore.selectedDatabase._id && selectedQuery}
|
||||
<QueryInterface query={selectedQuery} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
section {
|
||||
background: var(--background);
|
||||
padding: var(--spacing-xl);
|
||||
border-radius: var(--border-radius-m);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
import { params } from "@sveltech/routify"
|
||||
import { backendUiStore } from "builderStore"
|
||||
|
||||
if ($params.selectedDatasourceId) {
|
||||
const datasource = $backendUiStore.datasources.find(
|
||||
m => m._id === $params.selectedDatasource
|
||||
)
|
||||
if (datasource) {
|
||||
backendUiStore.actions.datasources.select(datasource)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot />
|
|
@ -0,0 +1,44 @@
|
|||
<script>
|
||||
import { goto } from "@sveltech/routify"
|
||||
import { Button, Spacer, Icon, TextButton } from "@budibase/bbui"
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { notifier } from "builderStore/store/notifications"
|
||||
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte"
|
||||
|
||||
$: datasource = $backendUiStore.datasources.find(
|
||||
ds => ds._id === $backendUiStore.selectedDatasourceId
|
||||
)
|
||||
|
||||
async function saveDatasource() {
|
||||
// Create datasource
|
||||
await backendUiStore.actions.datasources.save(datasource)
|
||||
notifier.success(`Datasource ${name} saved successfully.`)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if datasource}
|
||||
<TextButton text small on:click={() => $goto('../new')}>
|
||||
<Icon name="filter" />
|
||||
Create Query
|
||||
</TextButton>
|
||||
<section>
|
||||
<h4>{datasource.name}: Configuration</h4>
|
||||
<IntegrationConfigForm integration={datasource.config} />
|
||||
<Spacer medium />
|
||||
<footer>
|
||||
<Button blue wide on:click={saveDatasource}>Save</Button>
|
||||
</footer>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
h4 {
|
||||
margin-top: var(--spacing-xl);
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
section {
|
||||
background: var(--background);
|
||||
border-radius: var(--border-radius-m);
|
||||
padding: var(--spacing-xl);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import { backendUiStore } from "builderStore"
|
||||
import { goto, leftover } from "@sveltech/routify"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
onMount(async () => {
|
||||
// navigate to first datasource in list, if not already selected
|
||||
if (
|
||||
!$leftover &&
|
||||
$backendUiStore.datasources.length > 0 &&
|
||||
!$backendUiStore.selectedDatasourceId
|
||||
) {
|
||||
$goto(`./${$backendUiStore.datasources[0]._id}`)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<slot />
|
|
@ -103,6 +103,15 @@
|
|||
padding: var(--spacing-l) var(--spacing-xl);
|
||||
}
|
||||
|
||||
.binding-drawer-container {
|
||||
height: 50vh;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: var(--background);
|
||||
padding: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.nav-group-header > div:nth-child(1) {
|
||||
padding: 0rem 0.5rem 0rem 0rem;
|
||||
vertical-align: bottom;
|
||||
|
|
|
@ -224,6 +224,8 @@ const testData = () => {
|
|||
},
|
||||
]
|
||||
|
||||
const queries = []
|
||||
|
||||
const components = {
|
||||
"@budibase/standard-components/container": {
|
||||
props: {},
|
||||
|
@ -247,5 +249,5 @@ const testData = () => {
|
|||
},
|
||||
}
|
||||
|
||||
return { screen, tables, components }
|
||||
return { screen, tables, components, queries }
|
||||
}
|
||||
|
|
|
@ -2255,6 +2255,11 @@ code-point-at@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||
|
||||
codemirror@^5.59.0:
|
||||
version "5.59.0"
|
||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.59.0.tgz#6d8132055459aabf21d04cae5cf5c430e5c57bb9"
|
||||
integrity sha512-UGzSkCacY9z0rSpQ3wnTWRN2nvRE6foDXnJltWW8pazInR/R+3gXHrao4IFQMv/bSBvFBxt8/HPpkpKAS54x5Q==
|
||||
|
||||
collection-visit@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { get } from "svelte/store"
|
||||
import { fetchTableData } from "./tables"
|
||||
import { fetchViewData } from "./views"
|
||||
import { fetchRelationshipData } from "./relationships"
|
||||
import { executeQuery } from "./queries"
|
||||
import { enrichRows } from "./rows"
|
||||
import { enrichDataBindings } from "../utils/enrichDataBinding"
|
||||
import { bindingStore } from "../store/binding"
|
||||
|
||||
/**
|
||||
* Fetches all rows for a particular Budibase data source.
|
||||
|
@ -18,6 +22,21 @@ export const fetchDatasource = async (datasource, dataContext) => {
|
|||
rows = await fetchTableData(tableId)
|
||||
} else if (type === "view") {
|
||||
rows = await fetchViewData(datasource)
|
||||
} else if (type === "query") {
|
||||
const bindings = get(bindingStore)
|
||||
|
||||
// Set the default query params
|
||||
let queryParams = datasource.queryParams || {}
|
||||
for (let param of datasource.parameters) {
|
||||
if (!queryParams[param.name]) {
|
||||
queryParams[param.name] = param.default
|
||||
}
|
||||
}
|
||||
const parameters = enrichDataBindings(queryParams, {
|
||||
...bindings,
|
||||
...dataContext,
|
||||
})
|
||||
return await executeQuery({ queryId: datasource._id, parameters })
|
||||
} else if (type === "link") {
|
||||
const row = dataContext[datasource.providerId]
|
||||
rows = await fetchRelationshipData({
|
||||
|
@ -26,7 +45,6 @@ export const fetchDatasource = async (datasource, dataContext) => {
|
|||
fieldName,
|
||||
})
|
||||
}
|
||||
|
||||
// Enrich rows
|
||||
return await enrichRows(rows, tableId)
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@ export * from "./attachments"
|
|||
export * from "./views"
|
||||
export * from "./relationships"
|
||||
export * from "./routes"
|
||||
export * from "./queries"
|
||||
export * from "./app"
|
||||
export * from "./automations"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import API from "./api"
|
||||
|
||||
/**
|
||||
* Executes a query against an external data connector.
|
||||
*/
|
||||
export const executeQuery = async ({ queryId, parameters }) => {
|
||||
const response = await API.post({
|
||||
url: `/api/queries/${queryId}`,
|
||||
body: {
|
||||
parameters,
|
||||
},
|
||||
})
|
||||
return response
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { enrichDataBinding } from "./enrichDataBinding"
|
||||
import { enrichDataBinding, enrichDataBindings } from "./enrichDataBinding"
|
||||
import { routeStore } from "../store"
|
||||
import { saveRow, deleteRow, triggerAutomation } from "../api"
|
||||
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
|
||||
|
||||
const saveRowHandler = async (action, context) => {
|
||||
let draft = context[`${action.parameters.contextPath}_draft`]
|
||||
|
@ -36,10 +36,23 @@ const navigationHandler = action => {
|
|||
routeStore.actions.navigate(action.parameters.url)
|
||||
}
|
||||
|
||||
const queryExecutionHandler = async (action, context) => {
|
||||
const { datasourceId, queryId, queryParams } = action.parameters
|
||||
|
||||
const enrichedQueryParameters = enrichDataBindings(queryParams, context)
|
||||
|
||||
await executeQuery({
|
||||
datasourceId,
|
||||
queryId,
|
||||
parameters: enrichedQueryParameters,
|
||||
})
|
||||
}
|
||||
|
||||
const handlerMap = {
|
||||
["Save Row"]: saveRowHandler,
|
||||
["Delete Row"]: deleteRowHandler,
|
||||
["Navigate To"]: navigationHandler,
|
||||
["Execute Query"]: queryExecutionHandler,
|
||||
["Trigger Automation"]: triggerAutomationHandler,
|
||||
}
|
||||
|
||||
|
|
|
@ -49,10 +49,12 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "^7.10.0",
|
||||
"@budibase/client": "^0.5.3",
|
||||
"@koa/router": "^8.0.0",
|
||||
"@sendgrid/mail": "^7.1.1",
|
||||
"@sentry/node": "^5.19.2",
|
||||
"airtable": "^0.10.1",
|
||||
"aws-sdk": "^2.767.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"chmodr": "^1.2.0",
|
||||
|
@ -78,9 +80,12 @@
|
|||
"koa-session": "^5.12.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"lodash": "^4.17.13",
|
||||
"mongodb": "^3.6.3",
|
||||
"mssql": "^6.2.3",
|
||||
"mustache": "^4.0.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"open": "^7.3.0",
|
||||
"pg": "^8.5.1",
|
||||
"pino-pretty": "^4.0.0",
|
||||
"pouchdb": "^7.2.1",
|
||||
"pouchdb-all-dbs": "^1.0.2",
|
||||
|
|
|
@ -3,7 +3,7 @@ const { exportTemplateFromApp } = require("../src/utilities/templates")
|
|||
const yargs = require("yargs")
|
||||
|
||||
// Script to export a chosen budibase app into a package
|
||||
// Usage: ./scripts/exportAppTemplate.js export --name=Funky --appId=someInstanceId --appId=appId
|
||||
// Usage: ./scripts/exportAppTemplate.js export --name=Funky --appId=appId
|
||||
|
||||
yargs
|
||||
.command(
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
const CouchDB = require("../../db")
|
||||
const bcrypt = require("../../utilities/bcrypt")
|
||||
const {
|
||||
generateDatasourceID,
|
||||
getDatasourceParams,
|
||||
getQueryParams,
|
||||
} = require("../../db/utils")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const database = new CouchDB(ctx.user.appId)
|
||||
const datasources = (
|
||||
await database.allDocs(
|
||||
getDatasourceParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
).rows.map(row => row.doc)
|
||||
ctx.body = datasources
|
||||
}
|
||||
|
||||
exports.save = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = {
|
||||
_id: generateDatasourceID(),
|
||||
type: "datasource",
|
||||
...ctx.request.body,
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await db.post(datasource)
|
||||
datasource._rev = response.rev
|
||||
|
||||
ctx.status = 200
|
||||
ctx.message = "Datasource saved successfully."
|
||||
ctx.body = datasource
|
||||
} catch (err) {
|
||||
ctx.throw(err.status, err)
|
||||
}
|
||||
}
|
||||
|
||||
exports.update = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
const user = ctx.request.body
|
||||
const dbUser = await db.get(ctx.request.body._id)
|
||||
if (user.password) {
|
||||
user.password = await bcrypt.hash(user.password)
|
||||
} else {
|
||||
delete user.password
|
||||
}
|
||||
const newData = { ...dbUser, ...user }
|
||||
|
||||
const response = await db.put(newData)
|
||||
user._rev = response.rev
|
||||
|
||||
ctx.status = 200
|
||||
ctx.message = `User ${ctx.request.body.email} updated successfully.`
|
||||
ctx.body = response
|
||||
}
|
||||
|
||||
exports.destroy = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
// Delete all queries for the datasource
|
||||
const rows = await db.allDocs(getQueryParams(ctx.params.datasourceId, null))
|
||||
await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
|
||||
|
||||
// delete the datasource
|
||||
await db.remove(ctx.params.datasourceId, ctx.params.revId)
|
||||
|
||||
ctx.message = `Datasource deleted.`
|
||||
ctx.status = 200
|
||||
}
|
||||
|
||||
exports.find = async function(ctx) {
|
||||
const database = new CouchDB(ctx.user.appId)
|
||||
const datasource = await database.get(ctx.params.datasourceId)
|
||||
ctx.body = datasource
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
const { definitions } = require("../../integrations")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
// TODO: fetch these from a github repo etc
|
||||
console.log(definitions)
|
||||
ctx.status = 200
|
||||
ctx.body = definitions
|
||||
}
|
||||
|
||||
exports.find = async function(ctx) {
|
||||
ctx.status = 200
|
||||
ctx.body = definitions[ctx.params.type]
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
const handlebars = require("handlebars")
|
||||
const CouchDB = require("../../db")
|
||||
const { generateQueryID, getQueryParams } = require("../../db/utils")
|
||||
const { integrations } = require("../../integrations")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const body = await db.allDocs(
|
||||
getQueryParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
ctx.body = body.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
exports.save = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
const query = ctx.request.body
|
||||
|
||||
if (!query._id) {
|
||||
query._id = generateQueryID(query.datasourceId)
|
||||
}
|
||||
|
||||
const response = await db.put(query)
|
||||
query._rev = response.rev
|
||||
|
||||
ctx.body = query
|
||||
ctx.message = `Query ${query.name} saved successfully.`
|
||||
}
|
||||
|
||||
function enrichQueryFields(fields, parameters) {
|
||||
const enrichedQuery = {}
|
||||
|
||||
// enrich the fields with dynamic parameters
|
||||
for (let key in fields) {
|
||||
const template = handlebars.compile(fields[key])
|
||||
enrichedQuery[key] = template(parameters)
|
||||
}
|
||||
|
||||
if (enrichedQuery.json || enrichedQuery.customData) {
|
||||
enrichedQuery.json = JSON.parse(
|
||||
enrichedQuery.json || enrichedQuery.customData
|
||||
)
|
||||
delete enrichedQuery.customData
|
||||
}
|
||||
|
||||
return enrichedQuery
|
||||
}
|
||||
|
||||
exports.preview = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const datasource = await db.get(ctx.request.body.datasourceId)
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
const { fields, parameters, queryVerb } = ctx.request.body
|
||||
|
||||
const enrichedQuery = enrichQueryFields(fields, parameters)
|
||||
|
||||
ctx.body = await new Integration(datasource.config)[queryVerb](enrichedQuery)
|
||||
}
|
||||
|
||||
exports.execute = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
|
||||
const query = await db.get(ctx.params.queryId)
|
||||
const datasource = await db.get(query.datasourceId)
|
||||
|
||||
const Integration = integrations[datasource.source]
|
||||
|
||||
if (!Integration) {
|
||||
ctx.throw(400, "Integration type does not exist.")
|
||||
return
|
||||
}
|
||||
|
||||
const enrichedQuery = enrichQueryFields(
|
||||
query.fields,
|
||||
ctx.request.body.parameters
|
||||
)
|
||||
|
||||
// call the relevant CRUD method on the integration class
|
||||
const response = await new Integration(datasource.config)[query.queryVerb](
|
||||
enrichedQuery
|
||||
)
|
||||
|
||||
ctx.body = response
|
||||
}
|
||||
|
||||
exports.destroy = async function(ctx) {
|
||||
const db = new CouchDB(ctx.user.appId)
|
||||
await db.remove(ctx.params.queryId, ctx.params.revId)
|
||||
ctx.message = `Query deleted.`
|
||||
ctx.status = 200
|
||||
}
|
|
@ -175,7 +175,7 @@ exports.fetchView = async function(ctx) {
|
|||
const viewName = ctx.params.viewName
|
||||
|
||||
// if this is a table view being looked for just transfer to that
|
||||
if (viewName.indexOf(TABLE_VIEW_BEGINS_WITH) === 0) {
|
||||
if (viewName.startsWith(TABLE_VIEW_BEGINS_WITH)) {
|
||||
ctx.params.tableId = viewName.substring(4)
|
||||
await exports.fetchTableRows(ctx)
|
||||
return
|
||||
|
@ -217,6 +217,7 @@ exports.fetchView = async function(ctx) {
|
|||
|
||||
exports.fetchTableRows = async function(ctx) {
|
||||
const appId = ctx.user.appId
|
||||
|
||||
// special case for users, fetch through the user controller
|
||||
let rows
|
||||
if (ctx.params.tableId === ViewNames.USERS) {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
const Router = require("@koa/router")
|
||||
const datasourceController = require("../controllers/datasource")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const {
|
||||
BUILDER,
|
||||
PermissionLevels,
|
||||
PermissionTypes,
|
||||
} = require("../../utilities/security/permissions")
|
||||
|
||||
const router = Router()
|
||||
|
||||
router
|
||||
.get("/api/datasources", authorized(BUILDER), datasourceController.fetch)
|
||||
.get(
|
||||
"/api/datasources/:id",
|
||||
authorized(PermissionTypes.TABLE, PermissionLevels.READ),
|
||||
datasourceController.find
|
||||
)
|
||||
.post("/api/datasources", authorized(BUILDER), datasourceController.save)
|
||||
.delete(
|
||||
"/api/datasources/:datasourceId/:revId",
|
||||
authorized(BUILDER),
|
||||
datasourceController.destroy
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -16,7 +16,10 @@ const apiKeysRoutes = require("./apikeys")
|
|||
const templatesRoutes = require("./templates")
|
||||
const analyticsRoutes = require("./analytics")
|
||||
const routingRoutes = require("./routing")
|
||||
const integrationRoutes = require("./integration")
|
||||
const permissionRoutes = require("./permission")
|
||||
const datasourceRoutes = require("./datasource")
|
||||
const queryRoutes = require("./query")
|
||||
const hostingRoutes = require("./hosting")
|
||||
|
||||
exports.mainRoutes = [
|
||||
|
@ -34,7 +37,10 @@ exports.mainRoutes = [
|
|||
analyticsRoutes,
|
||||
webhookRoutes,
|
||||
routingRoutes,
|
||||
integrationRoutes,
|
||||
permissionRoutes,
|
||||
datasourceRoutes,
|
||||
queryRoutes,
|
||||
hostingRoutes,
|
||||
// these need to be handled last as they still use /api/:tableId
|
||||
// this could be breaking as koa may recognise other routes as this
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/integration")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("../../utilities/security/permissions")
|
||||
|
||||
const router = Router()
|
||||
|
||||
router
|
||||
.get("/api/integrations", authorized(BUILDER), controller.fetch)
|
||||
.get("/api/integrations/:type", authorized(BUILDER), controller.find)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,74 @@
|
|||
const Router = require("@koa/router")
|
||||
const queryController = require("../controllers/query")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("../../utilities/security/permissions")
|
||||
const Joi = require("joi")
|
||||
const {
|
||||
PermissionLevels,
|
||||
PermissionTypes,
|
||||
} = require("../../utilities/security/permissions")
|
||||
const joiValidator = require("../../middleware/joi-validator")
|
||||
|
||||
const router = Router()
|
||||
|
||||
const QueryVerb = {
|
||||
Create: "create",
|
||||
Read: "read",
|
||||
Update: "update",
|
||||
Delete: "delete",
|
||||
}
|
||||
|
||||
function generateQueryValidation() {
|
||||
// prettier-ignore
|
||||
return joiValidator.body(Joi.object({
|
||||
_id: Joi.string(),
|
||||
_rev: Joi.string(),
|
||||
name: Joi.string().required(),
|
||||
fields: Joi.object().required(),
|
||||
datasourceId: Joi.string().required(),
|
||||
parameters: Joi.array().items(Joi.object({
|
||||
name: Joi.string(),
|
||||
default: Joi.string()
|
||||
})),
|
||||
queryVerb: Joi.string().allow(...Object.values(QueryVerb)).required(),
|
||||
queryType: Joi.string().required(),
|
||||
schema: Joi.object({}).required().unknown(true)
|
||||
}))
|
||||
}
|
||||
|
||||
function generateQueryPreviewValidation() {
|
||||
// prettier-ignore
|
||||
return joiValidator.body(Joi.object({
|
||||
fields: Joi.object().required(),
|
||||
queryVerb: Joi.string().allow(...Object.values(QueryVerb)).required(),
|
||||
datasourceId: Joi.string().required(),
|
||||
parameters: Joi.object({}).required().unknown(true)
|
||||
}))
|
||||
}
|
||||
|
||||
router
|
||||
.get("/api/queries", authorized(BUILDER), queryController.fetch)
|
||||
.post(
|
||||
"/api/queries",
|
||||
authorized(BUILDER),
|
||||
generateQueryValidation(),
|
||||
queryController.save
|
||||
)
|
||||
.post(
|
||||
"/api/queries/preview",
|
||||
authorized(BUILDER),
|
||||
generateQueryPreviewValidation(),
|
||||
queryController.preview
|
||||
)
|
||||
.post(
|
||||
"/api/queries/:queryId",
|
||||
authorized(PermissionTypes.QUERY, PermissionLevels.WRITE),
|
||||
queryController.execute
|
||||
)
|
||||
.delete(
|
||||
"/api/queries/:queryId/:revId",
|
||||
authorized(BUILDER),
|
||||
queryController.destroy
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,149 @@
|
|||
const {
|
||||
supertest,
|
||||
createApplication,
|
||||
defaultHeaders,
|
||||
builderEndpointShouldBlockNormalUsers,
|
||||
getDocument,
|
||||
insertDocument
|
||||
} = require("./couchTestUtils")
|
||||
let { generateDatasourceID, generateQueryID } = require("../../../db/utils")
|
||||
|
||||
const DATASOURCE_ID = generateDatasourceID()
|
||||
const TEST_DATASOURCE = {
|
||||
_id: DATASOURCE_ID,
|
||||
type: "datasource",
|
||||
name: "Test",
|
||||
source: "POSTGRES",
|
||||
config: {},
|
||||
type: "datasource",
|
||||
}
|
||||
|
||||
const TEST_QUERY = {
|
||||
_id: generateQueryID(DATASOURCE_ID),
|
||||
datasourceId: DATASOURCE_ID,
|
||||
name:"New Query",
|
||||
parameters:[],
|
||||
fields:{},
|
||||
schema:{},
|
||||
queryVerb:"read",
|
||||
queryType:"Table",
|
||||
}
|
||||
|
||||
describe("/datasources", () => {
|
||||
let request
|
||||
let server
|
||||
let app
|
||||
let appId
|
||||
let datasource
|
||||
|
||||
beforeAll(async () => {
|
||||
({ request, server } = await supertest())
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
app = await createApplication(request)
|
||||
appId = app.instance._id
|
||||
});
|
||||
|
||||
async function createDatasource() {
|
||||
return await insertDocument(appId, TEST_DATASOURCE)
|
||||
}
|
||||
|
||||
async function createQuery() {
|
||||
return await insertDocument(appId, TEST_QUERY)
|
||||
}
|
||||
|
||||
describe("create", () => {
|
||||
it("should create a new datasource", async () => {
|
||||
const res = await request
|
||||
.post(`/api/datasources`)
|
||||
.send(TEST_DATASOURCE)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(res.res.statusMessage).toEqual("Datasource saved successfully.");
|
||||
expect(res.body.name).toEqual("Test");
|
||||
})
|
||||
});
|
||||
|
||||
describe("fetch", () => {
|
||||
let datasource
|
||||
|
||||
beforeEach(async () => {
|
||||
datasource = await createDatasource()
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete datasource._rev
|
||||
});
|
||||
|
||||
it("returns all the datasources from the server", async () => {
|
||||
const res = await request
|
||||
.get(`/api/datasources`)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
const datasources = res.body;
|
||||
expect(datasources).toEqual([
|
||||
{
|
||||
"_rev": datasources[0]._rev,
|
||||
...TEST_DATASOURCE
|
||||
}
|
||||
]);
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
await builderEndpointShouldBlockNormalUsers({
|
||||
request,
|
||||
method: "GET",
|
||||
url: `/api/datasources`,
|
||||
appId: appId,
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
describe("destroy", () => {
|
||||
let datasource;
|
||||
|
||||
beforeEach(async () => {
|
||||
datasource = await createDatasource()
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete datasource._rev
|
||||
});
|
||||
|
||||
it("deletes queries for the datasource after deletion and returns a success message", async () => {
|
||||
await createQuery(datasource.id)
|
||||
|
||||
await request
|
||||
.delete(`/api/datasources/${datasource.id}/${datasource.rev}`)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect(200)
|
||||
|
||||
const res = await request
|
||||
.get(`/api/datasources`)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(res.body).toEqual([])
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
await builderEndpointShouldBlockNormalUsers({
|
||||
request,
|
||||
method: "DELETE",
|
||||
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
||||
appId: appId,
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
});
|
|
@ -0,0 +1,153 @@
|
|||
const {
|
||||
supertest,
|
||||
createApplication,
|
||||
defaultHeaders,
|
||||
builderEndpointShouldBlockNormalUsers,
|
||||
getDocument,
|
||||
insertDocument
|
||||
} = require("./couchTestUtils")
|
||||
let { generateDatasourceID, generateQueryID } = require("../../../db/utils")
|
||||
|
||||
const DATASOURCE_ID = generateDatasourceID()
|
||||
const TEST_DATASOURCE = {
|
||||
_id: DATASOURCE_ID,
|
||||
type: "datasource",
|
||||
name: "Test",
|
||||
source: "POSTGRES",
|
||||
config: {},
|
||||
type: "datasource",
|
||||
}
|
||||
|
||||
const TEST_QUERY = {
|
||||
_id: generateQueryID(DATASOURCE_ID),
|
||||
datasourceId: DATASOURCE_ID,
|
||||
name:"New Query",
|
||||
parameters:[],
|
||||
fields:{},
|
||||
schema:{},
|
||||
queryVerb:"read",
|
||||
queryType:"Table",
|
||||
}
|
||||
|
||||
describe("/queries", () => {
|
||||
let request
|
||||
let server
|
||||
let app
|
||||
let appId
|
||||
let datasource
|
||||
let query
|
||||
|
||||
beforeAll(async () => {
|
||||
({ request, server } = await supertest())
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.close()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
app = await createApplication(request)
|
||||
appId = app.instance._id
|
||||
});
|
||||
|
||||
async function createDatasource() {
|
||||
return await insertDocument(appId, TEST_DATASOURCE)
|
||||
}
|
||||
|
||||
async function createQuery() {
|
||||
return await insertDocument(appId, TEST_QUERY)
|
||||
}
|
||||
|
||||
describe("create", () => {
|
||||
it("should create a new query", async () => {
|
||||
const res = await request
|
||||
.post(`/api/queries`)
|
||||
.send(TEST_QUERY)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(res.res.statusMessage).toEqual(`Query ${TEST_QUERY.name} saved successfully.`);
|
||||
expect(res.body).toEqual({
|
||||
_rev: res.body._rev,
|
||||
...TEST_QUERY,
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe("fetch", () => {
|
||||
let datasource
|
||||
|
||||
beforeEach(async () => {
|
||||
datasource = await createDatasource()
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete datasource._rev
|
||||
});
|
||||
|
||||
it("returns all the queries from the server", async () => {
|
||||
const query = await createQuery()
|
||||
const res = await request
|
||||
.get(`/api/queries`)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
const queries = res.body;
|
||||
expect(queries).toEqual([
|
||||
{
|
||||
"_rev": query.rev,
|
||||
...TEST_QUERY
|
||||
}
|
||||
]);
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
await builderEndpointShouldBlockNormalUsers({
|
||||
request,
|
||||
method: "GET",
|
||||
url: `/api/datasources`,
|
||||
appId: appId,
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
describe("destroy", () => {
|
||||
let datasource;
|
||||
|
||||
beforeEach(async () => {
|
||||
datasource = await createDatasource()
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete datasource._rev
|
||||
});
|
||||
|
||||
it("deletes a query and returns a success message", async () => {
|
||||
const query = await createQuery()
|
||||
|
||||
await request
|
||||
.delete(`/api/queries/${query.id}/${query.rev}`)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect(200)
|
||||
|
||||
const res = await request
|
||||
.get(`/api/queries`)
|
||||
.set(defaultHeaders(appId))
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(res.body).toEqual([])
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
await builderEndpointShouldBlockNormalUsers({
|
||||
request,
|
||||
method: "DELETE",
|
||||
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
||||
appId: appId,
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
|
@ -15,6 +15,8 @@ const DocumentTypes = {
|
|||
INSTANCE: "inst",
|
||||
LAYOUT: "layout",
|
||||
SCREEN: "screen",
|
||||
DATASOURCE: "datasource",
|
||||
QUERY: "query",
|
||||
}
|
||||
|
||||
const ViewNames = {
|
||||
|
@ -223,3 +225,43 @@ exports.generateWebhookID = () => {
|
|||
exports.getWebhookParams = (webhookId = null, otherProps = {}) => {
|
||||
return getDocParams(DocumentTypes.WEBHOOK, webhookId, otherProps)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new datasource ID.
|
||||
* @returns {string} The new datasource ID which the webhook doc can be stored under.
|
||||
*/
|
||||
exports.generateDatasourceID = () => {
|
||||
return `${DocumentTypes.DATASOURCE}${SEPARATOR}${newid()}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameters for retrieving a datasource, this is a utility function for the getDocParams function.
|
||||
*/
|
||||
exports.getDatasourceParams = (datasourceId = null, otherProps = {}) => {
|
||||
return getDocParams(DocumentTypes.DATASOURCE, datasourceId, otherProps)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new query ID.
|
||||
* @returns {string} The new query ID which the query doc can be stored under.
|
||||
*/
|
||||
exports.generateQueryID = datasourceId => {
|
||||
return `${
|
||||
DocumentTypes.QUERY
|
||||
}${SEPARATOR}${datasourceId}${SEPARATOR}${newid()}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameters for retrieving a query, this is a utility function for the getDocParams function.
|
||||
*/
|
||||
exports.getQueryParams = (datasourceId = null, otherProps = {}) => {
|
||||
if (datasourceId == null) {
|
||||
return getDocParams(DocumentTypes.QUERY, null, otherProps)
|
||||
}
|
||||
|
||||
return getDocParams(
|
||||
DocumentTypes.QUERY,
|
||||
`${datasourceId}${SEPARATOR}`,
|
||||
otherProps
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
exports.QUERY_TYPES = {
|
||||
SQL: "sql",
|
||||
JSON: "json",
|
||||
FIELDS: "fields",
|
||||
}
|
||||
|
||||
exports.FIELD_TYPES = {
|
||||
STRING: "string",
|
||||
NUMBER: "number",
|
||||
PASSWORD: "password",
|
||||
LIST: "list",
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
const Airtable = require("airtable")
|
||||
const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://airtable.com/api",
|
||||
datasource: {
|
||||
apiKey: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
default: "enter api key",
|
||||
required: true,
|
||||
},
|
||||
base: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
default: "mybase",
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
"Airtable Record": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
customisable: true,
|
||||
fields: {
|
||||
table: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
read: {
|
||||
Table: {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
table: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
view: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {
|
||||
Fields: {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
customisable: true,
|
||||
fields: {
|
||||
id: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
"Airtable Ids": {
|
||||
type: FIELD_TYPES.JSON,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class AirtableIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.client = new Airtable(config).base(config.base)
|
||||
}
|
||||
|
||||
async create(query) {
|
||||
const { table, json } = query
|
||||
|
||||
try {
|
||||
const records = await this.client(table).create([
|
||||
{
|
||||
fields: json,
|
||||
},
|
||||
])
|
||||
return records
|
||||
} catch (err) {
|
||||
console.error("Error writing to airtable", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
try {
|
||||
const records = await this.client(query.table)
|
||||
.select({ maxRecords: query.numRecords || 10, view: query.view })
|
||||
.firstPage()
|
||||
return records.map(({ fields }) => fields)
|
||||
} catch (err) {
|
||||
console.error("Error writing to airtable", err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async update(query) {
|
||||
const { table, id, json } = query
|
||||
|
||||
try {
|
||||
const records = await this.client(table).update([
|
||||
{
|
||||
id,
|
||||
fields: json,
|
||||
},
|
||||
])
|
||||
return records
|
||||
} catch (err) {
|
||||
console.error("Error writing to airtable", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async delete(query) {
|
||||
try {
|
||||
const records = await this.client(query.table).destroy(query.ids)
|
||||
return records
|
||||
} catch (err) {
|
||||
console.error("Error writing to airtable", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: AirtableIntegration,
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
const PouchDB = require("pouchdb")
|
||||
const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://docs.couchdb.org/en/stable/",
|
||||
datasource: {
|
||||
url: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
default: "http://localhost:5984",
|
||||
},
|
||||
database: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
"CouchDB DSL": {
|
||||
type: QUERY_TYPES.JSON,
|
||||
},
|
||||
},
|
||||
read: {
|
||||
"CouchDB DSL": {
|
||||
type: QUERY_TYPES.JSON,
|
||||
},
|
||||
},
|
||||
update: {
|
||||
"CouchDB Document": {
|
||||
type: QUERY_TYPES.JSON,
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
"Document ID": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
id: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class CouchDBIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.client = new PouchDB(`${config.url}/${config.database}`)
|
||||
}
|
||||
|
||||
async create(query) {
|
||||
try {
|
||||
const result = await this.client.post(query.json)
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error("Error writing to couchDB", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
try {
|
||||
const result = await this.client.allDocs({
|
||||
include_docs: true,
|
||||
...query.json,
|
||||
})
|
||||
return result.rows.map(row => row.doc)
|
||||
} catch (err) {
|
||||
console.error("Error querying couchDB", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async update(query) {
|
||||
try {
|
||||
const result = await this.client.put(query.json)
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error("Error updating couchDB document", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async delete(query) {
|
||||
try {
|
||||
const result = await this.client.remove(query.id)
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error("Error deleting couchDB document", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: CouchDBIntegration,
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
const AWS = require("aws-sdk")
|
||||
const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://github.com/dabit3/dynamodb-documentclient-cheat-sheet",
|
||||
datasource: {
|
||||
region: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
default: "us-east-1",
|
||||
},
|
||||
accessKeyId: {
|
||||
type: FIELD_TYPES.PASSWORD,
|
||||
required: true,
|
||||
},
|
||||
secretKey: {
|
||||
type: FIELD_TYPES.PASSWORD,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
DynamoConfig: {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
table: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
customisable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
read: {
|
||||
DynamoConfig: {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
table: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
},
|
||||
customisable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {
|
||||
DynamoConfig: {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
table: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
customisable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
"Dynamo Partition Key": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
table: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
key: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class DynamoDBIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.connect()
|
||||
this.client = new AWS.DynamoDB.DocumentClient()
|
||||
}
|
||||
|
||||
async connect() {
|
||||
AWS.config.update(this.config)
|
||||
}
|
||||
|
||||
async create(query) {
|
||||
const response = await this.client.query({
|
||||
TableName: query.table,
|
||||
Item: query.json,
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
const response = await this.client.query({
|
||||
TableName: query.Table,
|
||||
...query.json,
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
async update(query) {
|
||||
const response = await this.client.query({
|
||||
TableName: query.Table,
|
||||
...query.json,
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
async delete(query) {
|
||||
const response = await this.client.query({
|
||||
TableName: query.Table,
|
||||
Key: {
|
||||
id: query.key,
|
||||
},
|
||||
})
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: DynamoDBIntegration,
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
const { Client } = require("@elastic/elasticsearch")
|
||||
const { QUERY_TYPES, FIELD_TYPES } = require("./Integration")
|
||||
|
||||
const SCHEMA = {
|
||||
docs:
|
||||
"https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html",
|
||||
datasource: {
|
||||
url: {
|
||||
type: "string",
|
||||
required: true,
|
||||
default: "http://localhost:9200",
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
"ES Query DSL": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
customisable: true,
|
||||
fields: {
|
||||
index: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
read: {
|
||||
"ES Query DSL": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
customisable: true,
|
||||
fields: {
|
||||
index: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {
|
||||
"ES Query DSL": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
customisable: true,
|
||||
fields: {
|
||||
id: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
"Document ID": {
|
||||
type: QUERY_TYPES.FIELDS,
|
||||
fields: {
|
||||
index: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
id: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class ElasticSearchIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.client = new Client({ node: config.url })
|
||||
}
|
||||
|
||||
async create(query) {
|
||||
const { index, json } = query
|
||||
|
||||
try {
|
||||
const result = await this.client.index({
|
||||
index,
|
||||
body: json,
|
||||
})
|
||||
return result.body
|
||||
} catch (err) {
|
||||
console.error("Error writing to elasticsearch", err)
|
||||
throw err
|
||||
} finally {
|
||||
await this.client.close()
|
||||
}
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
const { index, json } = query
|
||||
try {
|
||||
const result = await this.client.search({
|
||||
index: index,
|
||||
body: json,
|
||||
})
|
||||
return result.body.hits.hits.map(({ _source }) => _source)
|
||||
} catch (err) {
|
||||
console.error("Error querying elasticsearch", err)
|
||||
throw err
|
||||
} finally {
|
||||
await this.client.close()
|
||||
}
|
||||
}
|
||||
|
||||
async update(query) {
|
||||
const { id, index, json } = query
|
||||
try {
|
||||
const result = await this.client.update({
|
||||
id,
|
||||
index,
|
||||
body: json,
|
||||
})
|
||||
return result.body
|
||||
} catch (err) {
|
||||
console.error("Error querying elasticsearch", err)
|
||||
throw err
|
||||
} finally {
|
||||
await this.client.close()
|
||||
}
|
||||
}
|
||||
|
||||
async delete(query) {
|
||||
try {
|
||||
const result = await this.client.delete(query)
|
||||
return result.body
|
||||
} catch (err) {
|
||||
console.error("Error deleting from elasticsearch", err)
|
||||
throw err
|
||||
} finally {
|
||||
await this.client.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: ElasticSearchIntegration,
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
const postgres = require("./postgres")
|
||||
const dynamodb = require("./dynamodb")
|
||||
const mongodb = require("./mongodb")
|
||||
const elasticsearch = require("./elasticsearch")
|
||||
const couchdb = require("./couchdb")
|
||||
// const redis = require("./redis")
|
||||
const sqlServer = require("./microsoftSqlServer")
|
||||
const s3 = require("./s3")
|
||||
const airtable = require("./airtable")
|
||||
|
||||
const DEFINITIONS = {
|
||||
POSTGRES: postgres.schema,
|
||||
DYNAMODB: dynamodb.schema,
|
||||
MONGODB: mongodb.schema,
|
||||
ELASTICSEARCH: elasticsearch.schema,
|
||||
COUCHDB: couchdb.schema,
|
||||
SQL_SERVER: sqlServer.schema,
|
||||
S3: s3.schema,
|
||||
AIRTABLE: airtable.schema,
|
||||
}
|
||||
|
||||
const INTEGRATIONS = {
|
||||
POSTGRES: postgres.integration,
|
||||
DYNAMODB: dynamodb.integration,
|
||||
MONGODB: mongodb.integration,
|
||||
ELASTICSEARCH: elasticsearch.integration,
|
||||
COUCHDB: couchdb.integration,
|
||||
S3: s3.integration,
|
||||
SQL_SERVER: sqlServer.integration,
|
||||
AIRTABLE: airtable.integration,
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
definitions: DEFINITIONS,
|
||||
integrations: INTEGRATIONS,
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
const sqlServer = require("mssql")
|
||||
const { FIELD_TYPES } = require("./Integration")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://github.com/tediousjs/node-mssql",
|
||||
datasource: {
|
||||
user: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
default: "localhost",
|
||||
},
|
||||
password: {
|
||||
type: FIELD_TYPES.PASSWORD,
|
||||
required: true,
|
||||
},
|
||||
server: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
default: "localhost",
|
||||
},
|
||||
database: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
default: "root",
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
SQL: {
|
||||
type: "sql",
|
||||
},
|
||||
},
|
||||
read: {
|
||||
SQL: {
|
||||
type: "sql",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class SqlServerIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.client = sqlServer
|
||||
}
|
||||
|
||||
async connect() {
|
||||
return await this.client.connect(this.config)
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
try {
|
||||
await this.connect()
|
||||
const response = await this.client.query(query.sql)
|
||||
return response.recordset
|
||||
} catch (err) {
|
||||
console.error("Error querying MS SQL Server", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async create(query) {
|
||||
try {
|
||||
await this.connect()
|
||||
const response = await this.client.query(query.sql)
|
||||
return response.recordset
|
||||
} catch (err) {
|
||||
console.error("Error querying MS SQL Server", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: SqlServerIntegration,
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
const { MongoClient } = require("mongodb")
|
||||
const { FIELD_TYPES, QUERY_TYPES } = require("./Integration")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://github.com/mongodb/node-mongodb-native",
|
||||
datasource: {
|
||||
connectionString: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
default: "mongodb://localhost:27017",
|
||||
},
|
||||
db: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
collection: {
|
||||
type: FIELD_TYPES.STRING,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
JSON: {
|
||||
type: QUERY_TYPES.JSON,
|
||||
},
|
||||
},
|
||||
read: {
|
||||
JSON: {
|
||||
type: QUERY_TYPES.JSON,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class MongoIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.client = new MongoClient(config.connectionString)
|
||||
}
|
||||
|
||||
async connect() {
|
||||
return this.client.connect()
|
||||
}
|
||||
|
||||
async create(query) {
|
||||
try {
|
||||
await this.connect()
|
||||
const db = this.client.db(this.config.db)
|
||||
const collection = db.collection(this.config.collection)
|
||||
const result = await collection.insertOne(query.json)
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error("Error writing to mongodb", err)
|
||||
throw err
|
||||
} finally {
|
||||
await this.client.close()
|
||||
}
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
try {
|
||||
await this.connect()
|
||||
const db = this.client.db(this.config.db)
|
||||
const collection = db.collection(this.config.collection)
|
||||
const result = await collection.find(query.json).toArray()
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error("Error querying mongodb", err)
|
||||
throw err
|
||||
} finally {
|
||||
await this.client.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: MongoIntegration,
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
const { Client } = require("pg")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://node-postgres.com",
|
||||
datasource: {
|
||||
host: {
|
||||
type: "string",
|
||||
default: "localhost",
|
||||
required: true,
|
||||
},
|
||||
port: {
|
||||
type: "number",
|
||||
required: true,
|
||||
default: 5432,
|
||||
},
|
||||
database: {
|
||||
type: "string",
|
||||
default: "postgres",
|
||||
required: true,
|
||||
},
|
||||
username: {
|
||||
type: "string",
|
||||
default: "root",
|
||||
required: true,
|
||||
},
|
||||
password: {
|
||||
type: "password",
|
||||
default: "root",
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
create: {
|
||||
SQL: {
|
||||
type: "sql",
|
||||
},
|
||||
},
|
||||
read: {
|
||||
SQL: {
|
||||
type: "sql",
|
||||
},
|
||||
},
|
||||
update: {
|
||||
SQL: {
|
||||
type: "sql",
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
SQL: {
|
||||
type: "sql",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class PostgresIntegration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.client = new Client(config)
|
||||
this.connect()
|
||||
}
|
||||
|
||||
async connect() {
|
||||
return this.client.connect()
|
||||
}
|
||||
|
||||
async create({ sql }) {
|
||||
const response = await this.client.query(sql)
|
||||
return response.rows
|
||||
}
|
||||
|
||||
async read({ sql }) {
|
||||
const response = await this.client.query(sql)
|
||||
return response.rows
|
||||
}
|
||||
|
||||
async update({ sql }) {
|
||||
const response = await this.client.query(sql)
|
||||
return response.rows
|
||||
}
|
||||
|
||||
async delete({ sql }) {
|
||||
const response = await this.client.query(sql)
|
||||
return response.rows
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: PostgresIntegration,
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
const AWS = require("aws-sdk")
|
||||
|
||||
const SCHEMA = {
|
||||
docs: "https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html",
|
||||
datasource: {
|
||||
region: {
|
||||
type: "string",
|
||||
required: true,
|
||||
default: "us-east-1",
|
||||
},
|
||||
accessKeyId: {
|
||||
type: "password",
|
||||
required: true,
|
||||
},
|
||||
secretAccessKey: {
|
||||
type: "password",
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
read: {
|
||||
Bucket: {
|
||||
type: "fields",
|
||||
fields: {
|
||||
bucket: {
|
||||
type: "string",
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
class S3Integration {
|
||||
constructor(config) {
|
||||
this.config = config
|
||||
this.connect()
|
||||
this.client = new AWS.S3()
|
||||
}
|
||||
|
||||
async connect() {
|
||||
AWS.config.update(this.config)
|
||||
}
|
||||
|
||||
async read(query) {
|
||||
const response = await this.client
|
||||
.listObjects({
|
||||
Bucket: query.bucket,
|
||||
})
|
||||
.promise()
|
||||
return response.Contents
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schema: SCHEMA,
|
||||
integration: S3Integration,
|
||||
}
|
|
@ -14,6 +14,7 @@ const PermissionTypes = {
|
|||
WEBHOOK: "webhook",
|
||||
BUILDER: "builder",
|
||||
VIEW: "view",
|
||||
QUERY: "query",
|
||||
}
|
||||
|
||||
function Permission(type, level) {
|
||||
|
@ -57,6 +58,7 @@ exports.BUILTIN_PERMISSIONS = {
|
|||
_id: exports.BUILTIN_PERMISSION_IDS.READ_ONLY,
|
||||
name: "Read only",
|
||||
permissions: [
|
||||
new Permission(PermissionTypes.QUERY, PermissionLevels.READ),
|
||||
new Permission(PermissionTypes.TABLE, PermissionLevels.READ),
|
||||
new Permission(PermissionTypes.VIEW, PermissionLevels.READ),
|
||||
],
|
||||
|
@ -65,6 +67,7 @@ exports.BUILTIN_PERMISSIONS = {
|
|||
_id: exports.BUILTIN_PERMISSION_IDS.WRITE,
|
||||
name: "Read/Write",
|
||||
permissions: [
|
||||
new Permission(PermissionTypes.QUERY, PermissionLevels.WRITE),
|
||||
new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE),
|
||||
new Permission(PermissionTypes.VIEW, PermissionLevels.READ),
|
||||
],
|
||||
|
@ -89,6 +92,7 @@ exports.BUILTIN_PERMISSIONS = {
|
|||
new Permission(PermissionTypes.AUTOMATION, PermissionLevels.ADMIN),
|
||||
new Permission(PermissionTypes.VIEW, PermissionLevels.ADMIN),
|
||||
new Permission(PermissionTypes.WEBHOOK, PermissionLevels.READ),
|
||||
new Permission(PermissionTypes.QUERY, PermissionLevels.ADMIN),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -7,6 +7,34 @@
|
|||
resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.0.3.tgz#bc5b5532ecafd923a61f2fb097e3b108c0106a3f"
|
||||
integrity sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==
|
||||
|
||||
"@azure/ms-rest-azure-env@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-env/-/ms-rest-azure-env-1.1.2.tgz#8505873afd4a1227ec040894a64fdd736b4a101f"
|
||||
integrity sha512-l7z0DPCi2Hp88w12JhDTtx5d0Y3+vhfE7JKJb9O7sEz71Cwp053N8piTtTnnk/tUor9oZHgEKi/p3tQQmLPjvA==
|
||||
|
||||
"@azure/ms-rest-js@^1.8.7":
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-1.9.0.tgz#5eb6516cf20e972a2eb4c589d6b48c3151bc801b"
|
||||
integrity sha512-cB4Z2Mg7eBmet1rfbf0QSO1XbhfknRW7B+mX3IHJq0KGHaGJvCPoVTgdsJdCkazEMK1jtANFNEDDzSQacxyzbA==
|
||||
dependencies:
|
||||
"@types/tunnel" "0.0.0"
|
||||
axios "^0.19.0"
|
||||
form-data "^2.3.2"
|
||||
tough-cookie "^2.4.3"
|
||||
tslib "^1.9.2"
|
||||
tunnel "0.0.6"
|
||||
uuid "^3.2.1"
|
||||
xml2js "^0.4.19"
|
||||
|
||||
"@azure/ms-rest-nodeauth@2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-2.0.2.tgz#037e29540c5625eaec718b8fcc178dd7ad5dfb96"
|
||||
integrity sha512-KmNNICOxt3EwViAJI3iu2VH8t8BQg5J2rSAyO4IUYLF9ZwlyYsP419pdvl4NBUhluAP2cgN7dfD2V6E6NOMZlQ==
|
||||
dependencies:
|
||||
"@azure/ms-rest-azure-env" "^1.1.2"
|
||||
"@azure/ms-rest-js" "^1.8.7"
|
||||
adal-node "^0.1.28"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||
|
@ -226,6 +254,17 @@
|
|||
ajv "^6.12.0"
|
||||
ajv-keywords "^3.4.1"
|
||||
|
||||
"@elastic/elasticsearch@^7.10.0":
|
||||
version "7.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.10.0.tgz#da105a9c1f14146f9f2cab4e7026cb7949121b8d"
|
||||
integrity sha512-vXtMAQf5/DwqeryQgRriMtnFppJNLc/R7/R0D8E+wG5/kGM5i7mg+Hi7TM4NZEuXgtzZ2a/Nf7aR0vLyrxOK/w==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
hpagent "^0.1.1"
|
||||
ms "^2.1.1"
|
||||
pump "^3.0.0"
|
||||
secure-json-parse "^2.1.0"
|
||||
|
||||
"@electron/get@^1.0.1":
|
||||
version "1.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.12.2.tgz#6442066afb99be08cefb9a281e4b4692b33764f3"
|
||||
|
@ -918,16 +957,39 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.8.tgz#fe2012f2355e4ce08bca44aeb3abbb21cf88d33f"
|
||||
integrity sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==
|
||||
|
||||
"@types/node@>=8.0.0 <15":
|
||||
version "14.14.20"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340"
|
||||
integrity sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==
|
||||
|
||||
"@types/node@^12.0.12":
|
||||
version "12.12.67"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.67.tgz#4f86badb292e822e3b13730a1f9713ed2377f789"
|
||||
integrity sha512-R48tgL2izApf+9rYNH+3RBMbRpPeW3N8f0I9HMhggeq4UXwBDqumJ14SDs4ctTMhG11pIOduZ4z3QWGOiMc9Vg==
|
||||
|
||||
"@types/node@^12.12.17":
|
||||
version "12.19.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679"
|
||||
integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==
|
||||
|
||||
"@types/node@^8.0.47":
|
||||
version "8.10.66"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3"
|
||||
integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==
|
||||
|
||||
"@types/normalize-package-data@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
||||
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
||||
|
||||
"@types/readable-stream@^2.3.5":
|
||||
version "2.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-2.3.9.tgz#40a8349e6ace3afd2dd1b6d8e9b02945de4566a9"
|
||||
integrity sha512-sqsgQqFT7HmQz/V5jH1O0fvQQnXAJO46Gg9LRO/JPfjmVmGUlcx831TZZO3Y3HtWhIkzf3kTsNT0Z0kzIhIvZw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
safe-buffer "*"
|
||||
|
||||
"@types/semver@^7.3.1":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
|
||||
|
@ -938,6 +1000,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
|
||||
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
|
||||
|
||||
"@types/tunnel@0.0.0":
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.0.tgz#c2a42943ee63c90652a5557b8c4e56cda77f944e"
|
||||
integrity sha512-FGDp0iBRiBdPjOgjJmn1NH0KDLN+Z8fRmo+9J7XGBhubq1DPrGrbmG4UTlGzrpbCpesMqD0sWkzi27EYkOMHyg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/yargs-parser@*":
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
|
||||
|
@ -967,13 +1036,18 @@ abbrev@1:
|
|||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
abort-controller@3.0.0:
|
||||
abort-controller@3.0.0, abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
abortcontroller-polyfill@^1.4.0:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.1.tgz#27084bac87d78a7224c8ee78135d05df430c2d2f"
|
||||
integrity sha512-yml9NiDEH4M4p0G4AcPkg8AAa4mF3nfYF28VQxaokpO67j9H7gWgmsVWJ/f1Rn+PzsnDYvzJzWIQzCqDKRvWlA==
|
||||
|
||||
abstract-leveldown@^6.2.1:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a"
|
||||
|
@ -1049,6 +1123,21 @@ acorn@^7.1.1:
|
|||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
adal-node@^0.1.28:
|
||||
version "0.1.28"
|
||||
resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.1.28.tgz#468c4bb3ebbd96b1270669f4b9cba4e0065ea485"
|
||||
integrity sha1-RoxLs+u9lrEnBmn0ucuk4AZepIU=
|
||||
dependencies:
|
||||
"@types/node" "^8.0.47"
|
||||
async ">=0.6.0"
|
||||
date-utils "*"
|
||||
jws "3.x.x"
|
||||
request ">= 2.52.0"
|
||||
underscore ">= 1.3.1"
|
||||
uuid "^3.1.0"
|
||||
xmldom ">= 0.1.x"
|
||||
xpath.js "~1.1.0"
|
||||
|
||||
agent-base@6:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4"
|
||||
|
@ -1056,6 +1145,17 @@ agent-base@6:
|
|||
dependencies:
|
||||
debug "4"
|
||||
|
||||
airtable@^0.10.1:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/airtable/-/airtable-0.10.1.tgz#0b311002bb44b39f19bf7c4bd2d47d75c733bf87"
|
||||
integrity sha512-obFW+R3ly2mKtCj0D/xto0ggUvYwdM0RJT3VJ9wvgqoxDkzqg2mNtkuTNfYjF6wWQA0GvoHG9guqzgBBqFjItw==
|
||||
dependencies:
|
||||
"@types/node" ">=8.0.0 <15"
|
||||
abort-controller "^3.0.0"
|
||||
abortcontroller-polyfill "^1.4.0"
|
||||
lodash "^4.17.19"
|
||||
node-fetch "^2.6.1"
|
||||
|
||||
ajv-keywords@^3.4.1:
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
||||
|
@ -1294,6 +1394,11 @@ async@0.9.x:
|
|||
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
|
||||
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
|
||||
|
||||
async@>=0.6.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
||||
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
@ -1346,7 +1451,7 @@ aws4@^1.8.0:
|
|||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
|
||||
integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==
|
||||
|
||||
axios@^0.19.2:
|
||||
axios@^0.19.0, axios@^0.19.2:
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
||||
|
@ -1456,6 +1561,21 @@ bl@^1.0.0:
|
|||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
bl@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5"
|
||||
integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
bl@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.1.tgz#1cbb439299609e419b5a74d7fce2f8b37d8e5c6f"
|
||||
integrity sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==
|
||||
dependencies:
|
||||
readable-stream "^3.0.1"
|
||||
|
||||
bl@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489"
|
||||
|
@ -1551,6 +1671,11 @@ bser@2.1.1:
|
|||
dependencies:
|
||||
node-int64 "^0.4.0"
|
||||
|
||||
bson@^1.1.4:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.5.tgz#2aaae98fcdf6750c0848b0cba1ddec3c73060a34"
|
||||
integrity sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
|
@ -1589,6 +1714,11 @@ buffer-from@1.1.1, buffer-from@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||
|
||||
buffer-writer@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04"
|
||||
integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
|
||||
|
||||
buffer@4.9.2:
|
||||
version "4.9.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
|
||||
|
@ -2091,6 +2221,11 @@ data-urls@^1.0.0:
|
|||
whatwg-mimetype "^2.2.0"
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
date-utils@*:
|
||||
version "1.2.21"
|
||||
resolved "https://registry.yarnpkg.com/date-utils/-/date-utils-1.2.21.tgz#61fb16cdc1274b3c9acaaffe9fc69df8720a2b64"
|
||||
integrity sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=
|
||||
|
||||
dateformat@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||
|
@ -2124,7 +2259,7 @@ debug@^3.1.0, debug@^3.2.6:
|
|||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.3.0:
|
||||
debug@^4, debug@^4.3.0:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
|
||||
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
||||
|
@ -2304,12 +2439,17 @@ delegates@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
denque@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
|
||||
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
|
||||
|
||||
depd@^1.1.2, depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||
|
||||
depd@~2.0.0:
|
||||
depd@^2.0.0, depd@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
@ -3224,7 +3364,7 @@ forever-agent@~0.6.1:
|
|||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@^2.3.1:
|
||||
form-data@^2.3.1, form-data@^2.3.2:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
|
||||
integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
|
||||
|
@ -3629,6 +3769,11 @@ hosted-git-info@^3.0.5:
|
|||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
hpagent@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-0.1.1.tgz#66f67f16e5c7a8b59a068e40c2658c2c749ad5e2"
|
||||
integrity sha512-IxJWQiY0vmEjetHdoE9HZjD4Cx+mYTr25tR7JCxXaiI3QxW0YqYyM11KyZbHufoa/piWhMb2+D3FGpMgmA2cFQ==
|
||||
|
||||
html-encoding-sniffer@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
|
||||
|
@ -3715,6 +3860,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.5:
|
|||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.5.0:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.2.tgz#af6d628dccfb463b7364d97f715e4b74b8c8c2b8"
|
||||
integrity sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01"
|
||||
|
@ -4683,6 +4835,11 @@ js-yaml@^3.13.1, js-yaml@^3.14.0:
|
|||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsbi@^3.1.1:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.1.4.tgz#9654dd02207a66a4911b4e4bb74265bc2cbc9dd0"
|
||||
integrity sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
|
@ -4843,7 +5000,7 @@ jwa@^1.4.1:
|
|||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^3.2.2:
|
||||
jws@3.x.x, jws@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
|
||||
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
|
||||
|
@ -5391,6 +5548,11 @@ memdown@1.4.1:
|
|||
ltgt "~2.2.0"
|
||||
safe-buffer "~5.1.1"
|
||||
|
||||
memory-pager@^1.0.2:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
|
||||
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
|
@ -5496,6 +5658,19 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4:
|
|||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
mongodb@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.3.tgz#eddaed0cc3598474d7a15f0f2a5b04848489fd05"
|
||||
integrity sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==
|
||||
dependencies:
|
||||
bl "^2.2.1"
|
||||
bson "^1.1.4"
|
||||
denque "^1.4.1"
|
||||
require_optional "^1.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
optionalDependencies:
|
||||
saslprep "^1.0.0"
|
||||
|
||||
mri@1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
|
||||
|
@ -5511,6 +5686,15 @@ ms@2.1.2, ms@^2.1.1:
|
|||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
mssql@^6.2.3:
|
||||
version "6.2.3"
|
||||
resolved "https://registry.yarnpkg.com/mssql/-/mssql-6.2.3.tgz#1d15bbe8c3057e32ee6e98596b6c323b097a6cba"
|
||||
integrity sha512-4TW/fA9UgzmVTNgjl65r6ISr6aL5QHnlptEt1A3jIpdzkNbFPIkRbUNz90324HIdE+5pKc3VqikOImcTrhd4og==
|
||||
dependencies:
|
||||
debug "^4"
|
||||
tarn "^1.1.5"
|
||||
tedious "^6.6.2"
|
||||
|
||||
mustache@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.1.tgz#d99beb031701ad433338e7ea65e0489416c854a2"
|
||||
|
@ -5548,6 +5732,11 @@ napi-macros@~2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b"
|
||||
integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==
|
||||
|
||||
native-duplexpair@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/native-duplexpair/-/native-duplexpair-1.0.0.tgz#7899078e64bf3c8a3d732601b3d40ff05db58fa0"
|
||||
integrity sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=
|
||||
|
||||
natural-compare@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
|
@ -5588,7 +5777,7 @@ node-fetch@2.6.0:
|
|||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
|
||||
node-fetch@^2.6.0:
|
||||
node-fetch@^2.6.0, node-fetch@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
@ -5925,6 +6114,11 @@ package-json@^6.3.0:
|
|||
registry-url "^5.0.0"
|
||||
semver "^6.2.0"
|
||||
|
||||
packet-reader@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
|
||||
integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
|
||||
|
||||
pako@^1.0.5:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
|
||||
|
@ -6042,6 +6236,57 @@ performance-now@^2.1.0:
|
|||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
pg-connection-string@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.4.0.tgz#c979922eb47832999a204da5dbe1ebf2341b6a10"
|
||||
integrity sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==
|
||||
|
||||
pg-int8@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
|
||||
integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
|
||||
|
||||
pg-pool@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.2.2.tgz#a560e433443ed4ad946b84d774b3f22452694dff"
|
||||
integrity sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==
|
||||
|
||||
pg-protocol@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.4.0.tgz#43a71a92f6fe3ac559952555aa3335c8cb4908be"
|
||||
integrity sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==
|
||||
|
||||
pg-types@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
|
||||
integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
|
||||
dependencies:
|
||||
pg-int8 "1.0.1"
|
||||
postgres-array "~2.0.0"
|
||||
postgres-bytea "~1.0.0"
|
||||
postgres-date "~1.0.4"
|
||||
postgres-interval "^1.1.0"
|
||||
|
||||
pg@^8.5.1:
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/pg/-/pg-8.5.1.tgz#34dcb15f6db4a29c702bf5031ef2e1e25a06a120"
|
||||
integrity sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==
|
||||
dependencies:
|
||||
buffer-writer "2.0.0"
|
||||
packet-reader "1.0.0"
|
||||
pg-connection-string "^2.4.0"
|
||||
pg-pool "^3.2.2"
|
||||
pg-protocol "^1.4.0"
|
||||
pg-types "^2.1.0"
|
||||
pgpass "1.x"
|
||||
|
||||
pgpass@1.x:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.4.tgz#85eb93a83800b20f8057a2b029bf05abaf94ea9c"
|
||||
integrity sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==
|
||||
dependencies:
|
||||
split2 "^3.1.1"
|
||||
|
||||
phin@^2.9.1:
|
||||
version "2.9.3"
|
||||
resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c"
|
||||
|
@ -6158,6 +6403,28 @@ posix-character-classes@^0.1.0:
|
|||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
||||
|
||||
postgres-array@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
|
||||
integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
|
||||
|
||||
postgres-bytea@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
|
||||
integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=
|
||||
|
||||
postgres-date@~1.0.4:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
|
||||
integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
|
||||
|
||||
postgres-interval@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
|
||||
integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
|
||||
dependencies:
|
||||
xtend "^4.0.0"
|
||||
|
||||
pouch-stream@^0.4.0:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/pouch-stream/-/pouch-stream-0.4.1.tgz#0c6d8475c9307677627991a2f079b301c3b89bdd"
|
||||
|
@ -6543,7 +6810,7 @@ readable-stream@1.1.14, readable-stream@^1.0.27-1:
|
|||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
|
@ -6690,7 +6957,7 @@ request-promise-native@^1.0.5:
|
|||
stealthy-require "^1.1.1"
|
||||
tough-cookie "^2.3.3"
|
||||
|
||||
request@^2.87.0:
|
||||
"request@>= 2.52.0", request@^2.87.0:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
|
@ -6726,6 +6993,14 @@ require-main-filename@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
require_optional@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
|
||||
integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==
|
||||
dependencies:
|
||||
resolve-from "^2.0.0"
|
||||
semver "^5.1.0"
|
||||
|
||||
resolve-cwd@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
|
||||
|
@ -6733,6 +7008,11 @@ resolve-cwd@^2.0.0:
|
|||
dependencies:
|
||||
resolve-from "^3.0.0"
|
||||
|
||||
resolve-from@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
|
||||
integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
|
||||
|
||||
resolve-from@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
|
||||
|
@ -6831,16 +7111,16 @@ rxjs@^6.6.0:
|
|||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
safe-buffer@*, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-regex@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
|
||||
|
@ -6880,6 +7160,13 @@ sanitize-s3-objectkey@^0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e"
|
||||
integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ==
|
||||
|
||||
saslprep@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226"
|
||||
integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==
|
||||
dependencies:
|
||||
sparse-bitfield "^3.0.3"
|
||||
|
||||
sax@1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
|
||||
|
@ -6890,6 +7177,11 @@ sax@>=0.6.0, sax@^1.2.4:
|
|||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
secure-json-parse@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.1.0.tgz#ae76f5624256b5c497af887090a5d9e156c9fb20"
|
||||
integrity sha512-GckO+MS/wT4UogDyoI/H/S1L0MCcKS1XX/vp48wfmU7Nw4woBmb8mIpu4zPBQjKlRT88/bt9xdoV4111jPpNJA==
|
||||
|
||||
seek-bzip@^1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4"
|
||||
|
@ -6909,7 +7201,7 @@ semver-diff@^3.1.1:
|
|||
dependencies:
|
||||
semver "^6.3.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
@ -7144,6 +7436,13 @@ spark-md5@3.0.1:
|
|||
resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d"
|
||||
integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig==
|
||||
|
||||
sparse-bitfield@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
|
||||
integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE=
|
||||
dependencies:
|
||||
memory-pager "^1.0.2"
|
||||
|
||||
spdx-correct@^3.0.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
|
||||
|
@ -7507,6 +7806,28 @@ tar-stream@^2.0.0:
|
|||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
tarn@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/tarn/-/tarn-1.1.5.tgz#7be88622e951738b9fa3fb77477309242cdddc2d"
|
||||
integrity sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==
|
||||
|
||||
tedious@^6.6.2:
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/tedious/-/tedious-6.7.0.tgz#ad02365f16f9e0416b216e13d3f83c53addd42ca"
|
||||
integrity sha512-8qr7+sB0h4SZVQBRWUgHmYuOEflAOl2eihvxk0fVNvpvGJV4V5UC/YmSvebyfgyfwWcPO22/AnSbYVZZqf9wuQ==
|
||||
dependencies:
|
||||
"@azure/ms-rest-nodeauth" "2.0.2"
|
||||
"@types/node" "^12.12.17"
|
||||
"@types/readable-stream" "^2.3.5"
|
||||
bl "^3.0.0"
|
||||
depd "^2.0.0"
|
||||
iconv-lite "^0.5.0"
|
||||
jsbi "^3.1.1"
|
||||
native-duplexpair "^1.0.0"
|
||||
punycode "^2.1.0"
|
||||
readable-stream "^3.4.0"
|
||||
sprintf-js "^1.1.2"
|
||||
|
||||
temp-file@^3.3.7:
|
||||
version "3.3.7"
|
||||
resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.3.7.tgz#686885d635f872748e384e871855958470aeb18a"
|
||||
|
@ -7672,7 +7993,7 @@ touch@^3.1.0:
|
|||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0:
|
||||
tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.4.3, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
|
@ -7710,7 +8031,7 @@ truncate-utf8-bytes@^1.0.0:
|
|||
dependencies:
|
||||
utf8-byte-length "^1.0.1"
|
||||
|
||||
tslib@^1.9.0, tslib@^1.9.3:
|
||||
tslib@^1.9.0, tslib@^1.9.2, tslib@^1.9.3:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
@ -7727,7 +8048,7 @@ tunnel-agent@^0.6.0:
|
|||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tunnel@^0.0.6:
|
||||
tunnel@0.0.6, tunnel@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||
|
@ -7804,6 +8125,11 @@ undefsafe@^2.0.2:
|
|||
dependencies:
|
||||
debug "^2.2.0"
|
||||
|
||||
"underscore@>= 1.3.1":
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.0.tgz#4814940551fc80587cef7840d1ebb0f16453be97"
|
||||
integrity sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==
|
||||
|
||||
union-value@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
|
||||
|
@ -7951,7 +8277,7 @@ uuid@8.1.0:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
|
||||
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
|
||||
|
||||
uuid@^3.3.2:
|
||||
uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
@ -8208,7 +8534,7 @@ xml2js@0.4.19:
|
|||
sax ">=0.6.0"
|
||||
xmlbuilder "~9.0.1"
|
||||
|
||||
xml2js@^0.4.5:
|
||||
xml2js@^0.4.19, xml2js@^0.4.5:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||
|
@ -8226,6 +8552,16 @@ xmlbuilder@~9.0.1:
|
|||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
|
||||
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
|
||||
|
||||
"xmldom@>= 0.1.x":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.4.0.tgz#8771e482a333af44587e30ce026f0998c23f3830"
|
||||
integrity sha512-2E93k08T30Ugs+34HBSTQLVtpi6mCddaY8uO+pMNk1pqSjV5vElzn4mmh6KLxN3hki8rNcHSYzILoh3TEWORvA==
|
||||
|
||||
xpath.js@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1"
|
||||
integrity sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==
|
||||
|
||||
"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
const { styleable, setBindableValue } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
// Keep bindable value up to date
|
||||
let value
|
||||
$: setBindableValue(value, $component.id)
|
||||
|
||||
function onBlur() {
|
||||
setBindableValue(value, $component.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
<input bind:value on:change={onchange} use:styleable={$component.styles} />
|
||||
<input bind:value on:blur={onBlur} use:styleable={$component.styles} />
|
||||
|
|
|
@ -10,9 +10,15 @@
|
|||
|
||||
let rows = []
|
||||
|
||||
$: datasource && fetchData()
|
||||
|
||||
async function fetchData() {
|
||||
rows = await API.fetchDatasource(datasource, $dataContext)
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if (!isEmpty(datasource)) {
|
||||
rows = await API.fetchDatasource(datasource, $dataContext)
|
||||
fetchData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -57,63 +57,68 @@
|
|||
pagination,
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if (!isEmpty(datasource)) {
|
||||
data = await API.fetchDatasource(datasource, $dataContext)
|
||||
let schema
|
||||
async function fetchData() {
|
||||
data = await API.fetchDatasource(datasource, $dataContext)
|
||||
|
||||
// Get schema for datasource
|
||||
// Views with "Calculate" applied provide their own schema.
|
||||
// For everything else, use the tableId property to pull to table schema
|
||||
if (datasource.schema) {
|
||||
schema = datasource.schema
|
||||
} else {
|
||||
schema = (await API.fetchTableDefinition(datasource.tableId)).schema
|
||||
}
|
||||
let schema
|
||||
|
||||
columnDefs = Object.keys(schema).map((key, i) => {
|
||||
return {
|
||||
headerCheckboxSelection: i === 0 && canEdit,
|
||||
checkboxSelection: i === 0 && canEdit,
|
||||
valueSetter: setters.get(schema[key].type),
|
||||
headerName: key,
|
||||
field: key,
|
||||
hide: shouldHideField(key),
|
||||
sortable: true,
|
||||
editable: canEdit && schema[key].type !== "link",
|
||||
cellRenderer: getRenderer(schema[key], canEdit, SDK),
|
||||
autoHeight: true,
|
||||
}
|
||||
})
|
||||
|
||||
if (detailUrl) {
|
||||
columnDefs = [
|
||||
...columnDefs,
|
||||
{
|
||||
headerName: "Detail",
|
||||
field: "_id",
|
||||
minWidth: 100,
|
||||
width: 100,
|
||||
flex: 0,
|
||||
editable: false,
|
||||
sortable: false,
|
||||
cellRenderer: getRenderer(
|
||||
{
|
||||
type: "_id",
|
||||
options: { detailUrl },
|
||||
},
|
||||
false,
|
||||
SDK
|
||||
),
|
||||
autoHeight: true,
|
||||
pinned: "left",
|
||||
filter: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
dataLoaded = true
|
||||
// Get schema for datasource
|
||||
// Views with "Calculate" applied provide their own schema.
|
||||
// For everything else, use the tableId property to pull to table schema
|
||||
if (datasource.schema) {
|
||||
schema = datasource.schema
|
||||
} else {
|
||||
schema = (await API.fetchTableDefinition(datasource.tableId)).schema
|
||||
}
|
||||
|
||||
columnDefs = Object.keys(schema).map((key, i) => {
|
||||
return {
|
||||
headerCheckboxSelection: i === 0 && canEdit,
|
||||
checkboxSelection: i === 0 && canEdit,
|
||||
valueSetter: setters.get(schema[key].type),
|
||||
headerName: key,
|
||||
field: key,
|
||||
hide: shouldHideField(key),
|
||||
sortable: true,
|
||||
editable: canEdit && schema[key].type !== "link",
|
||||
cellRenderer: getRenderer(schema[key], canEdit, SDK),
|
||||
autoHeight: true,
|
||||
}
|
||||
})
|
||||
|
||||
if (detailUrl) {
|
||||
columnDefs = [
|
||||
...columnDefs,
|
||||
{
|
||||
headerName: "Detail",
|
||||
field: "_id",
|
||||
minWidth: 100,
|
||||
width: 100,
|
||||
flex: 0,
|
||||
editable: false,
|
||||
sortable: false,
|
||||
cellRenderer: getRenderer(
|
||||
{
|
||||
type: "_id",
|
||||
options: { detailUrl },
|
||||
},
|
||||
false,
|
||||
SDK
|
||||
),
|
||||
autoHeight: true,
|
||||
pinned: "left",
|
||||
filter: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
dataLoaded = true
|
||||
}
|
||||
|
||||
$: datasource && fetchData()
|
||||
|
||||
onMount(() => {
|
||||
if (!isEmpty(datasource)) fetchData()
|
||||
})
|
||||
|
||||
const shouldHideField = name => {
|
||||
|
|
Loading…
Reference in New Issue