1
0
Fork 0
mirror of synced 2024-06-29 19:41:03 +12:00

Merge branch 'develop' of github.com:Budibase/budibase into fix/date-filtering

This commit is contained in:
Andrew Kingston 2022-03-15 11:44:04 +00:00
commit bf29fa43b4
66 changed files with 10766 additions and 3317 deletions

View file

@ -42,7 +42,7 @@ jobs:
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build:docker:proxy:prod
docker tag budibase/proxy:$release_tag budibase/proxy:$PROD_TAG
docker tag proxy-service budibase/proxy:$PROD_TAG
docker push budibase/proxy:$PROD_TAG
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}

View file

@ -34,7 +34,7 @@ jobs:
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build:docker:proxy:preprod
docker tag budibase/proxy:$release_tag budibase/proxy:$PREPROD_TAG
docker tag proxy-service budibase/proxy:$PREPROD_TAG
docker push budibase/proxy:$PREPROD_TAG
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}

View file

@ -48,7 +48,7 @@ jobs:
yarn build
popd
- name: Build OpenAPI sepc
- name: Build OpenAPI spec
run: |
pushd packages/server
yarn
@ -63,6 +63,7 @@ jobs:
run: |
git config user.name "Budibase Helm Bot"
git config user.email "<>"
git reset --hard
git pull
helm package charts/budibase
git checkout gh-pages

1
.gitignore vendored
View file

@ -98,3 +98,4 @@ hosting/proxy/.generated-nginx.prod.conf
bin/
hosting/.generated*
packages/builder/cypress.env.json
stats.html

View file

@ -5,6 +5,7 @@ packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
packages/server/builder
packages/server/coverage
packages/server/client
packages/server/src/definitions/openapi.ts
packages/builder/.routify
packages/builder/cypress/support/queryLevelTransformerFunction.js
packages/builder/cypress/support/queryLevelTransformerFunctionWithData.js

View file

@ -11,7 +11,7 @@
The low code platform you'll enjoy using
</h3>
<p align="center">
Budibase is an open source low-code platform, and the easiest way to build internal tools that improve productivity.
Budibase is an open source low-code platform, and the easiest way to build internal apps that improve productivity.
</p>
<h3 align="center">
@ -40,9 +40,11 @@
</p>
<h3 align="center">
<a href="https://docs.budibase.com/getting-started">Get started</a>
<a href="https://account.budibase.app/register">Get started - we host (Budibase Cloud)</a>
<span> · </span>
<a href="https://docs.budibase.com">Docs</a>
<a href="https://docs.budibase.com/docs/hosting-methods">Get started - you host (Docker, K8s, DO)</a>
<span> · </span>
<a href="https://docs.budibase.com/docs">Docs</a>
<span> · </span>
<a href="https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas">Feature request</a>
<span> · </span>
@ -104,12 +106,12 @@ Budibase is made to scale. With Budibase, you can self-host on your own infrastr
## 🏁 Get started
<a href="https://docs.budibase.com/self-hosting/self-host"><img src="https://res.cloudinary.com/daog6scxm/image/upload/v1634808888/logo/deploy_npl9za.png" /></a>
<a href="https://docs.budibase.com/docs/hosting-methods"><img src="https://res.cloudinary.com/daog6scxm/image/upload/v1634808888/logo/deploy_npl9za.png" /></a>
Deploy Budibase self-hosted in your existing infrastructure, using Docker, Kubernetes, and Digital Ocean.
Or use Budibase Cloud if you don't need to self-host, and would like to get started quickly.
### [Get started with self-hosting Budibase](https://docs.budibase.com/self-hosting/self-host)
### [Get started with self-hosting Budibase](https://docs.budibase.com/docs/hosting-methods)
### [Get started with Budibase Cloud](https://budibase.com)
@ -118,7 +120,7 @@ Or use Budibase Cloud if you don't need to self-host, and would like to get star
## 🎓 Learning Budibase
The Budibase documentation [lives here](https://docs.budibase.com).
The Budibase documentation [lives here](https://docs.budibase.com/docs).
<br />

View file

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

38
examples/nextjs-api-sales/.gitignore vendored Normal file
View file

@ -0,0 +1,38 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel
# typescript
*.tsbuildinfo

View file

@ -0,0 +1,41 @@
# Budibase API + Next.js example
This is an example of how Budibase can be used as a backend for a Postgres database for a Next.js sales app. You will
need to follow the walk-through that has been published in the Budibase docs to set up your Budibase app for this example.
## Pre-requisites
To use this example you will need:
1. [Docker](https://www.docker.com/)
2. [Docker Compose](https://docs.docker.com/compose/)
3. [Node.js](https://nodejs.org/en/)
4. A self-hosted Budibase installation
## Getting Started
The first step is to set up the database - you can do this by going to the `db/` directory and running the command:
```bash
docker-compose up
```
The next step is to follow the example walk-through and set up a Budibase app as it describes. Once you've done
this you can configure the settings in `next.config.js`, specifically the `apiKey`, `host` and `appName`.
Finally, you can start the dev server with the following command:
```bash
npm run dev
# or
yarn dev
```
## Accessing the app
Open [http://localhost:3001](http://localhost:3001) with your browser to see the sales app.
Look in the API routes (`pages/api/sales.ts` and `pages/api/salespeople.ts`) to see how this is integrated with Budibase.
There is also a utility file where some core functions and types have been defined, in `utilities/index.ts`.
## Attribution
This example was set up using [Next.js](https://nextjs.org/) and bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

View file

@ -0,0 +1,42 @@
import Link from "next/link"
import Image from "next/image"
import { ReactNotifications } from "react-notifications-component"
function layout(props: any) {
return (
<>
<nav className="navbar" role="navigation" aria-label="main navigation">
<div id="navbar" className="navbar-menu">
<div className="logo">
<Image alt="logo" src="/bb-emblem.svg" width="50" height="50" />
</div>
<div className="navbar-start">
<Link href="/">
<a className="navbar-item">
List
</a>
</Link>
<Link href="/save">
<a className="navbar-item">
New sale
</a>
</Link>
</div>
<div className="navbar-end">
<div className="navbar-item">
<div className="buttons">
<a className="button is-primary" href="https://budibase.readme.io/reference">
<strong>API Documentation</strong>
</a>
</div>
</div>
</div>
</div>
</nav>
<ReactNotifications />
{props.children}
</>
)
}
export default layout

View file

@ -0,0 +1,28 @@
import { Store } from "react-notifications-component"
const notifications = {
error: (error: string, title: string) => {
Store.addNotification({
container: "top-right",
type: "danger",
message: error,
title: title,
dismiss: {
duration: 10000,
},
})
},
success: (message: string, title: string) => {
Store.addNotification({
container: "top-right",
type: "success",
message: message,
title: title,
dismiss: {
duration: 3000,
},
})
},
}
export default notifications

View file

@ -0,0 +1,17 @@
version: "3.8"
services:
db:
container_name: postgres
image: postgres
restart: always
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
POSTGRES_DB: postgres
ports:
- "5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data/
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
pg_data:

View file

@ -0,0 +1,21 @@
CREATE TABLE IF NOT EXISTS sales_people (
person_id SERIAL PRIMARY KEY,
name varchar(200) NOT NULL
);
CREATE TABLE IF NOT EXISTS sales (
sale_id SERIAL PRIMARY KEY,
sale_name varchar(200) NOT NULL,
sold_by INT,
CONSTRAINT sold_by_fk
FOREIGN KEY(sold_by)
REFERENCES sales_people(person_id)
);
INSERT INTO sales_people (name)
select 'Salesperson ' || id
FROM GENERATE_SERIES(1, 50) as id;
INSERT INTO sales (sale_name, sold_by)
select 'Sale ' || id, floor(random() * 50 + 1)::int
FROM GENERATE_SERIES(1, 200) as id;

View file

@ -0,0 +1,7 @@
import { components } from "./openapi"
export type App = components["schemas"]["applicationOutput"]["data"]
export type Table = components["schemas"]["tableOutput"]["data"]
export type TableSearch = components["schemas"]["tableSearch"]
export type AppSearch = components["schemas"]["applicationSearch"]
export type RowSearch = components["schemas"]["searchOutput"]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View file

@ -0,0 +1,16 @@
const { join } = require("path")
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
sassOptions: {
includePaths: [join(__dirname, "styles")],
},
serverRuntimeConfig: {
apiKey:
"bf4d86af933b5ac0af0fdbe4bf7d89ff-f929752a1eeaafb00f4b5e3325097d51a44fe4b39f22ed857923409cc75414b379323a25ebfb4916",
appName: "sales",
host: "http://localhost:10000",
},
}
module.exports = nextConfig

View file

@ -0,0 +1,27 @@
{
"name": "nextjs-api-sales",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"bulma": "^0.9.3",
"next": "12.1.0",
"node-fetch": "^3.2.2",
"node-sass": "^7.0.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-notifications-component": "^3.4.1"
},
"devDependencies": {
"@types/node": "17.0.21",
"@types/react": "17.0.39",
"eslint": "8.10.0",
"eslint-config-next": "12.1.0",
"typescript": "4.6.2"
}
}

View file

@ -0,0 +1,17 @@
import "../styles/global.sass"
import type { AppProps } from "next/app"
import Head from "next/head"
import Layout from "../components/layout"
function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Head>
<title>BB NextJS Sales Example</title>
</Head>
<Component {...pageProps} />
</Layout>
)
}
export default MyApp

View file

@ -0,0 +1,46 @@
import { getApp, findTable, makeCall } from "../../utilities"
async function getSales(req: any) {
const { page } = req.query
const { _id: appId } = await getApp()
const table = await findTable(appId, "sales")
return await makeCall("post", `tables/${table._id}/rows/search`, {
appId,
body: {
limit: 10,
sort: {
type: "string",
order: "descending",
column: "sale_id",
},
paginate: true,
bookmark: parseInt(page),
},
})
}
async function saveSale(req: any) {
const { _id: appId } = await getApp()
const table = await findTable(appId, "sales")
return await makeCall("post", `tables/${table._id}/rows`, {
body: req.body,
appId,
})
}
export default async function handler(req: any, res: any) {
let response: any = {}
try {
if (req.method === "POST") {
response = await saveSale(req)
} else if (req.method === "GET") {
response = await getSales(req)
} else {
res.status(404)
return
}
res.status(200).json(response)
} catch (err: any) {
res.status(400).send(err)
}
}

View file

@ -0,0 +1,31 @@
import { getApp, findTable, makeCall } from "../../utilities"
async function getSalespeople() {
const { _id: appId } = await getApp()
const table = await findTable(appId, "sales_people")
return await makeCall("post", `tables/${table._id}/rows/search`, {
appId,
body: {
sort: {
type: "string",
order: "ascending",
column: "person_id",
},
},
})
}
export default async function handler(req: any, res: any) {
let response: any = {}
try {
if (req.method === "GET") {
response = await getSalespeople()
} else {
res.status(404)
return
}
res.status(200).json(response)
} catch (err: any) {
res.status(400).send(err)
}
}

View file

@ -0,0 +1,83 @@
import type { NextPage } from "next"
import styles from "../styles/home.module.css"
import { useState, useEffect, useCallback } from "react"
import Notifications from "../components/notifications"
const Home: NextPage = () => {
const [sales, setSales] = useState([])
const [currentPage, setCurrentPage] = useState(1)
const [loaded, setLoaded] = useState(false)
const getSales = useCallback(async (page: Number = 1) => {
let url = "/api/sales"
if (page) {
url += `?page=${page}`
}
const response = await fetch(url)
if (!response.ok) {
const error = await response.text()
Notifications.error(error, "Failed to get sales")
return
}
const sales = await response.json()
// @ts-ignore
setCurrentPage(page)
return setSales(sales.data)
}, [])
const goToNextPage = useCallback(async () => {
await getSales(currentPage + 1)
}, [currentPage, getSales])
const goToPrevPage = useCallback(async () => {
if (currentPage > 1) {
await getSales(currentPage - 1)
}
}, [currentPage, getSales])
useEffect(() => {
getSales().then(() => {
setLoaded(true)
}).catch(() => {
setSales([])
})
}, [])
if (!loaded) {
return null
}
return (
<div className={styles.container}>
<div className={styles.tableSection}>
<h1 className="subtitle">Sales</h1>
<div className={styles.table}>
<table className="table">
<thead>
<tr>
<th>Sale ID</th>
<th>name</th>
<th>Sold by</th>
</tr>
</thead>
<tbody>
{sales.map((sale: any) =>
<tr key={sale.sale_id}>
<th>{sale.sale_id}</th>
<th>{sale.sale_name}</th>
<th>{sale.sales_person?.map((person: any) => person.primaryDisplay)[0]}</th>
</tr>
)}
</tbody>
</table>
<div className={styles.buttons}>
<button className="button" onClick={goToPrevPage}>Prev Page</button>
<button className="button" onClick={goToNextPage}>Next Page</button>
</div>
</div>
</div>
</div>
)
}
export default Home

View file

@ -0,0 +1,81 @@
import type { NextPage } from "next"
import { useCallback, useEffect, useState } from "react"
import styles from "../styles/save.module.css"
import Notifications from "../components/notifications"
const Save: NextPage = () => {
const [salespeople, setSalespeople] = useState([])
const [loaded, setLoaded] = useState(false)
const saveSale = useCallback(async (event: any) => {
event.preventDefault()
const sale = {
sale_name: event.target.name.value,
sales_person: [event.target.soldBy.value],
}
const response = await fetch("/api/sales", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(sale),
})
if (!response.ok) {
const error = await response.text()
Notifications.error(error, "Failed to save sale")
return
}
Notifications.success("Sale saved successfully!", "Sale saved")
}, [])
const getSalespeople = useCallback(async () => {
const response: any = await fetch("/api/salespeople")
if (!response.ok) {
throw new Error(await response.text())
}
const json = await response.json()
setSalespeople(json.data)
}, [])
useEffect(() => {
getSalespeople().then(() => {
setLoaded(true)
}).catch(() => {
setSalespeople([])
})
}, [])
if (!loaded) {
return null
}
return (
<div className={styles.container}>
<div className={styles.formSection}>
<h1 className="subtitle">New sale</h1>
<form onSubmit={saveSale}>
<div className="field">
<label className="label">Name</label>
<div className="control">
<input id="name" className="input" type="text" placeholder="Text input" />
</div>
</div>
<div className="field">
<label className="label">Sold by</label>
<div className="control">
<div className="select">
<select id="soldBy">
{salespeople.map((person: any) => <option key={person._id} value={person._id}>{person.name}</option>)}
</select>
</div>
</div>
</div>
<div className="control">
<button className="button is-link">Submit</button>
</div>
</form>
</div>
</div>
)
}
export default Save

View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<style type="text/css">
.st0{fill:#393C44;}
.st1{fill:#FFFFFF;}
.st2{fill:#4285F4;}
</style>
<rect x="-152.17" y="-24.17" class="st0" width="96.17" height="96.17"/>
<path class="st1" d="M-83.19,48h-41.79c-1.76,0-3.19-1.43-3.19-3.19V3.02c0-1.76,1.43-3.19,3.19-3.19h41.79
c1.76,0,3.19,1.43,3.19,3.19v41.79C-80,46.57-81.43,48-83.19,48z"/>
<g>
<g>
<path class="st0" d="M-99.62,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35h-4.89V12.57H-99.62z
M-93.46,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
C-93.55,28.92-93.46,28.52-93.46,28.11z"/>
</g>
<g>
<path class="st0" d="M-114.76,12.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58
c0.86,0.39,1.59,0.91,2.19,1.57c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89
c-0.35,0.9-0.84,1.68-1.47,2.35c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V35
h-4.89V12.57H-114.76z M-108.6,28.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
C-108.68,28.92-108.6,28.52-108.6,28.11z"/>
</g>
</g>
<path class="st2" d="M44.81,159H3.02c-1.76,0-3.19-1.43-3.19-3.19v-41.79c0-1.76,1.43-3.19,3.19-3.19h41.79
c1.76,0,3.19,1.43,3.19,3.19v41.79C48,157.57,46.57,159,44.81,159z"/>
<g>
<g>
<path class="st1" d="M28.38,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146h-4.89v-22.43H28.38z
M34.54,139.11c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69
c-0.38-0.17-0.79-0.26-1.24-0.26c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01
c-0.17,0.39-0.26,0.8-0.26,1.23c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68
c0.39,0.17,0.8,0.26,1.23,0.26c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1
C34.45,139.92,34.54,139.52,34.54,139.11z"/>
</g>
<g>
<path class="st1" d="M13.24,123.57v9.94c1.15-1.21,2.59-1.81,4.32-1.81c1.03,0,1.97,0.19,2.82,0.58c0.86,0.39,1.59,0.91,2.19,1.57
c0.6,0.66,1.08,1.43,1.42,2.32c0.34,0.89,0.51,1.84,0.51,2.85c0,1.03-0.18,1.99-0.53,2.89c-0.35,0.9-0.84,1.68-1.47,2.35
c-0.63,0.67-1.37,1.19-2.23,1.58c-0.86,0.39-1.78,0.58-2.77,0.58c-1.8,0-3.22-0.66-4.27-1.97V146H8.35v-22.43H13.24z M19.4,139.11
c0-0.43-0.08-0.84-0.24-1.23c-0.16-0.39-0.39-0.72-0.68-1.01c-0.29-0.29-0.62-0.52-1-0.69c-0.38-0.17-0.79-0.26-1.24-0.26
c-0.43,0-0.84,0.08-1.22,0.24c-0.38,0.16-0.71,0.39-0.99,0.68c-0.28,0.29-0.5,0.63-0.68,1.01c-0.17,0.39-0.26,0.8-0.26,1.23
c0,0.43,0.08,0.84,0.24,1.22c0.16,0.38,0.39,0.71,0.68,0.99c0.29,0.28,0.63,0.5,1.01,0.68c0.39,0.17,0.8,0.26,1.23,0.26
c0.43,0,0.84-0.08,1.22-0.24c0.38-0.16,0.71-0.39,0.99-0.68c0.28-0.29,0.5-0.62,0.68-1C19.32,139.92,19.4,139.52,19.4,139.11z"/>
</g>
</g>
<g>
<path class="st0" d="M44,48H4c-2.21,0-4-1.79-4-4V4c0-2.21,1.79-4,4-4h40c2.21,0,4,1.79,4,4v40C48,46.21,46.21,48,44,48z"/>
<g>
<path class="st1" d="M28.48,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47
c-0.64,0.7-1.4,1.25-2.28,1.66C34.8,35.8,33.86,36,32.84,36c-1.84,0-3.3-0.69-4.37-2.07v1.62h-5V12H28.48z M34.78,28.31
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C34.69,29.16,34.78,28.75,34.78,28.31z"
/>
</g>
<g>
<path class="st1" d="M13,12v10.44c1.18-1.27,2.65-1.9,4.42-1.9c1.05,0,2.01,0.2,2.89,0.61c0.87,0.41,1.62,0.96,2.24,1.65
c0.62,0.69,1.1,1.5,1.45,2.44c0.35,0.94,0.52,1.93,0.52,2.99c0,1.08-0.18,2.09-0.54,3.04c-0.36,0.95-0.86,1.77-1.51,2.47
c-0.64,0.7-1.4,1.25-2.28,1.66C19.32,35.8,18.38,36,17.37,36c-1.84,0-3.3-0.69-4.37-2.07v1.62H8V12H13z M19.3,28.31
c0-0.45-0.08-0.88-0.25-1.29c-0.17-0.41-0.4-0.76-0.69-1.06c-0.3-0.3-0.64-0.54-1.02-0.72c-0.39-0.18-0.81-0.27-1.27-0.27
c-0.44,0-0.86,0.09-1.24,0.26c-0.39,0.17-0.72,0.41-1.01,0.71c-0.29,0.3-0.52,0.66-0.69,1.06c-0.18,0.41-0.26,0.84-0.26,1.29
s0.08,0.88,0.25,1.28c0.17,0.4,0.4,0.74,0.69,1.04c0.29,0.29,0.64,0.53,1.04,0.71c0.4,0.18,0.82,0.27,1.26,0.27
c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C19.21,29.16,19.3,28.75,19.3,28.31z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,26 @@
@charset "utf-8"
@import url('https://fonts.googleapis.com/css?family=Roboto:400,700')
$family-sans-serif: "Roboto", sans-serif
#__next
display: flex
flex-direction: column
justify-content: flex-start
align-items: stretch
height: 100vh
--bg-color: #f5f5f5
.logo
padding: 0.75rem
@import "../node_modules/bulma/bulma.sass"
@import "../node_modules/react-notifications-component/dist/theme.css"
// applied after bulma styles are enabled
html
overflow-y: auto
.navbar
background-color: var(--bg-color)
color: white

View file

@ -0,0 +1,30 @@
.container {
width: 100vw;
display: flex;
flex-direction: column;
padding: 5rem 2rem 0;
align-items: center;
flex: 1 1 auto;
}
.buttons {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.tableSection {
padding: 2rem;
background: var(--bg-color);
width: 800px;
border-radius: 10px;
}
.table table {
width: 100%;
}
.tableSection h1 {
text-align: center;
color: black;
}

View file

@ -0,0 +1,20 @@
.container {
width: 100vw;
display: flex;
flex-direction: column;
padding: 5rem 2rem 0;
align-items: center;
flex: 1 1 auto;
}
.formSection {
padding: 2rem;
background: var(--bg-color);
width: 400px;
border-radius: 10px;
}
.formSection h1 {
text-align: center;
color: black;
}

View file

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View file

@ -0,0 +1,82 @@
import { App, AppSearch, Table, TableSearch } from "../definitions"
import getConfig from "next/config"
const { serverRuntimeConfig } = getConfig()
const apiKey = serverRuntimeConfig["apiKey"]
const appName = serverRuntimeConfig["appName"]
const host = serverRuntimeConfig["host"]
let APP: App | null = null
let TABLES: { [key: string]: Table } = {}
export async function makeCall(
method: string,
url: string,
opts?: { body?: any; appId?: string }
): Promise<any> {
const fetchOpts: any = {
method,
headers: {
"x-budibase-api-key": apiKey,
},
}
if (opts?.appId) {
fetchOpts.headers["x-budibase-app-id"] = opts.appId
}
if (opts?.body) {
fetchOpts.body =
typeof opts.body !== "string" ? JSON.stringify(opts.body) : opts.body
fetchOpts.headers["Content-Type"] = "application/json"
}
const finalUrl = `${host}/api/public/v1/${url}`
const response = await fetch(finalUrl, fetchOpts)
if (response.ok) {
return response.json()
} else {
const error = await response.text()
console.error("Budibase server error - ", error)
throw new Error(error)
}
}
export async function getApp(): Promise<App> {
if (APP) {
return APP
}
const apps: AppSearch = await makeCall("post", "applications/search", {
body: {
name: appName,
},
})
const app = apps.data.find((app: App) => app.name === appName)
if (!app) {
throw new Error(
"Could not find app, please make sure app name in config is correct."
)
}
APP = app
return app
}
export async function findTable(
appId: string,
tableName: string
): Promise<Table> {
if (TABLES[tableName]) {
return TABLES[tableName]
}
const tables: TableSearch = await makeCall("post", "tables/search", {
body: {
name: tableName,
},
appId,
})
const table = tables.data.find((table: Table) => table.name === tableName)
if (!table) {
throw new Error(
"Could not find table, please make sure your app is configured with the Postgres datasource correctly."
)
}
TABLES[tableName] = table
return table
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
{
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"npmClient": "yarn",
"packages": [
"packages/*"

View file

@ -39,7 +39,7 @@
"lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\"",
"lint": "yarn run lint:eslint && yarn run lint:prettier",
"lint:fix:eslint": "eslint --fix packages",
"lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\"",
"lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\"",
"lint:fix:ts": "lerna run lint:fix",
"lint:fix": "yarn run lint:fix:ts && yarn run lint:fix:prettier && yarn run lint:fix:eslint",
"test:e2e": "lerna run cy:test --stream",

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/backend-core",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"description": "Budibase backend core libraries used in server and worker",
"main": "src/index.js",
"author": "Budibase",

View file

@ -5,7 +5,7 @@ const { getSession, updateSessionTTL } = require("../security/sessions")
const { buildMatcherRegex, matches } = require("./matchers")
const env = require("../environment")
const { SEPARATOR, ViewNames, queryGlobalView } = require("../../db")
const { getGlobalDB } = require("../tenancy")
const { getGlobalDB, doInTenant } = require("../tenancy")
const { decrypt } = require("../security/encryption")
function finalise(
@ -25,20 +25,25 @@ async function checkApiKey(apiKey, populateUser) {
}
const decrypted = decrypt(apiKey)
const tenantId = decrypted.split(SEPARATOR)[0]
const db = getGlobalDB(tenantId)
// api key is encrypted in the database
const userId = await queryGlobalView(
ViewNames.BY_API_KEY,
{
key: apiKey,
},
db
)
if (userId) {
return { valid: true, user: await getUser(userId, tenantId, populateUser) }
} else {
throw "Invalid API key"
}
return doInTenant(tenantId, async () => {
const db = getGlobalDB()
// api key is encrypted in the database
const userId = await queryGlobalView(
ViewNames.BY_API_KEY,
{
key: apiKey,
},
db
)
if (userId) {
return {
valid: true,
user: await getUser(userId, tenantId, populateUser),
}
} else {
throw "Invalid API key"
}
})
}
/**

View file

@ -22,12 +22,25 @@ exports.Databases = {
exports.SEPARATOR = SEPARATOR
exports.getRedisOptions = (clustered = false) => {
const [host, port, ...rest] = REDIS_URL.split(":")
let password = REDIS_PASSWORD
let url = REDIS_URL.split("//")
// get rid of the protocol
url = url.length > 1 ? url[1] : url[0]
// check for a password etc
url = url.split("@")
if (url.length > 1) {
// get the password
password = url[0].split(":")[1]
url = url[1]
} else {
url = url[0]
}
const [host, port] = url.split(":")
let redisProtocolUrl
// fully qualified redis URL
if (rest.length && /rediss?/.test(host)) {
if (/rediss?:\/\//.test(REDIS_URL)) {
redisProtocolUrl = REDIS_URL
}
@ -37,13 +50,13 @@ exports.getRedisOptions = (clustered = false) => {
if (clustered) {
opts.redisOptions = {}
opts.redisOptions.tls = {}
opts.redisOptions.password = REDIS_PASSWORD
opts.redisOptions.password = password
opts.slotsRefreshTimeout = SLOT_REFRESH_MS
opts.dnsLookup = (address, callback) => callback(null, address)
} else {
opts.host = host
opts.port = port
opts.password = REDIS_PASSWORD
opts.password = password
}
return { opts, host, port, redisProtocolUrl }
}

View file

@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",
@ -38,7 +38,7 @@
],
"dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
"@budibase/string-templates": "^1.0.81-alpha.7",
"@budibase/string-templates": "^1.0.89-alpha.0",
"@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2",

File diff suppressed because it is too large Load diff

View file

@ -36,10 +36,12 @@ filterTests(["smoke", "all"], () => {
// createRestQuery confirms query creation
cy.createRestQuery("GET", restUrl, "/breweries")
// Confirm status code response within REST datasource
cy.get(".spectrum-FieldLabel")
.contains("Status")
.children()
cy.wait(1000)
cy.get(".stats").within(() => {
cy.get(".spectrum-FieldLabel")
.eq(0)
.should("contain", 200)
})
})
})
})

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"license": "GPL-3.0",
"private": true,
"scripts": {
@ -65,10 +65,10 @@
}
},
"dependencies": {
"@budibase/bbui": "^1.0.81-alpha.7",
"@budibase/client": "^1.0.81-alpha.7",
"@budibase/frontend-core": "^1.0.81-alpha.7",
"@budibase/string-templates": "^1.0.81-alpha.7",
"@budibase/bbui": "^1.0.89-alpha.0",
"@budibase/client": "^1.0.89-alpha.0",
"@budibase/frontend-core": "^1.0.89-alpha.0",
"@budibase/string-templates": "^1.0.89-alpha.0",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/client",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
"@budibase/bbui": "^1.0.81-alpha.7",
"@budibase/frontend-core": "^1.0.81-alpha.7",
"@budibase/string-templates": "^1.0.81-alpha.7",
"@budibase/bbui": "^1.0.89-alpha.0",
"@budibase/frontend-core": "^1.0.89-alpha.0",
"@budibase/string-templates": "^1.0.89-alpha.0",
"@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3",

File diff suppressed because one or more lines are too long

View file

@ -28,13 +28,13 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@budibase/bbui@^1.0.80-alpha.6", "@budibase/bbui@^1.0.81":
version "1.0.81"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.0.81.tgz#54365af09bf7fdca4fe84639cec13cb993314e7d"
integrity sha512-cYggJ6vDria98edMxOoo4yBAe7EAS1rAy0lSlt89TGTFuK6YNnvXOkE44lyyw/xznYD9WlOLlFX9Sq7lC1yK6w==
"@budibase/bbui@^1.0.85":
version "1.0.85"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.0.85.tgz#b4f4415f2acfe3f2891413545c5338a250522576"
integrity sha512-gxRu48r39b/FLaDIaU89xuPnIjr76b9HoKqx7vgNWyiwaNh6IyyA0LtHRTLj7r2/sLjDCTjYXTVBqDkcmbANpw==
dependencies:
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
"@budibase/string-templates" "^1.0.81"
"@budibase/string-templates" "^1.0.85"
"@spectrum-css/actionbutton" "^1.0.1"
"@spectrum-css/actiongroup" "^1.0.1"
"@spectrum-css/avatar" "^3.0.2"
@ -80,12 +80,12 @@
svelte-flatpickr "^3.2.3"
svelte-portal "^1.0.0"
"@budibase/frontend-core@^1.0.80-alpha.6":
version "1.0.81"
resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.81.tgz#e2c95c4fbeead2bab132b076db54f8bd011718b1"
integrity sha512-fGYCTnKs74jOistXy9hvqz32mfX8govm9O8tOhMxR721kL/R5kQEMoMolecRI+Nb7ywuOFdm+2CiVelfDIBjbA==
"@budibase/frontend-core@^1.0.85":
version "1.0.85"
resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.85.tgz#f44d97016edc54d4bd6a10a6066f9d0f8d5b5a45"
integrity sha512-dTHnmWrr87wuulxLsyR7g2hlSOxKtMuDAOXsDZe8drGCiD7gdbSgcYPckJ9dC4XxRJ/rKZN0AZ1tZdRoH7Tx6g==
dependencies:
"@budibase/bbui" "^1.0.81"
"@budibase/bbui" "^1.0.85"
lodash "^4.17.21"
svelte "^3.46.2"
@ -114,10 +114,10 @@
to-gfm-code-block "^0.1.1"
year "^0.2.1"
"@budibase/string-templates@^1.0.80-alpha.6", "@budibase/string-templates@^1.0.81":
version "1.0.81"
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.81.tgz#c88f1efd647e55bd0c0a51d080b27d0f38962286"
integrity sha512-G909aR/IZVH74mmofbXF9F6FwtLfDdkduucQE6nxQCTHSBz2ZTNzbNbrjEn2mxDhNLpnmDeYs4LbHF7GkKSpgA==
"@budibase/string-templates@^1.0.85":
version "1.0.85"
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.85.tgz#1119ddb28bb3a512a894d4f20b9982cc65911cc7"
integrity sha512-buU5+rMRXFTQZlG9M3e+uPuaJ57OXE3pSPt/H0mo/8l7Bs5O1Xs9p8O6k2YvTkvQueJeqfwbL9QbztxPmCK9xQ==
dependencies:
"@budibase/handlebars-helpers" "^0.11.8"
dayjs "^1.10.4"
@ -291,9 +291,9 @@
integrity sha512-wjZr7NAcqHK6fxNIGKTYEVtAOJugJTbcz4d8K7DZuUDgBVwLJJHJBi4uJ4KrIRYliMWOvqWTZzCJLmmTfx4cyw==
"@spectrum-css/picker@^1.0.1":
version "1.1.14"
resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.1.14.tgz#91ac4302fedc0e42ea6ef1e69f8f6a1d902877e5"
integrity sha512-/sb47P1PiuJ8CtiZRJ7rOZeDiAqB2SzfJXfmiMxcaCZpKzV92c4F1xG4mlvIM+ymwSoJgD+UevHt6MiELoAbkw==
version "1.2.0"
resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.2.0.tgz#5e986d3b725b2f6820949fb92f6ea6262e11dda7"
integrity sha512-NQEZUV7pnT5CliHq08g8dO6KpWgipycpa+vBw+Cqw93h8IjIHWCUU+gUo87EV+h/Z1fI1l/sWguBpwzb/nGEAg==
"@spectrum-css/popover@^3.0.1":
version "3.0.11"
@ -301,9 +301,9 @@
integrity sha512-bzyNQJVw6Mn1EBelTaRlXCdd0ZfykNX9O6SHx3a+jXPYu8VBrRpHm0gsfWzPAz1etd1vj1CxwG/teQt4qvyZ/Q==
"@spectrum-css/progressbar@^1.0.2":
version "1.0.20"
resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.20.tgz#5d66a72a2961bbd4a14be3e256c9c17a7932e5e6"
integrity sha512-+hLr06LLjIX3ROxn419O6QlGJJTh1aXYdvwOTB0iOfZifHkyWNoWC85UYQOiXpcTDo+OEKJbIbvdQ/5W/utCzw==
version "1.0.21"
resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.21.tgz#892a0f3655e0e0f97734362b1e5763a6c3214dcc"
integrity sha512-CC7QrVfFT/IwDSBkTooe8aORVG+SuXC2kxkCbRHz789W4ST/ntM5qv62Axvb9AhR0HTGdEVMJByFt6wsdB5ZpQ==
"@spectrum-css/progresscircle@^1.0.2":
version "1.0.16"
@ -346,9 +346,9 @@
integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg==
"@spectrum-css/tabs@^3.0.1":
version "3.2.6"
resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.6.tgz#e15fc5ac742f4b53df37cd2476f2a347d8385754"
integrity sha512-ert7szHDDCD4Hf7D2ozRECt3X+ARZoL6U5B9vJoPghes2YX8lhJI2aIJ82Fg39jj7Y+qaJA1lyPIwS/RqE8grQ==
version "3.2.7"
resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.7.tgz#f68a6e2a7ffb93520eb7831fe4e391d58a63d23d"
integrity sha512-HsdUL5ytBdhjFbA6CnAnU24Fifs4qWVH0MIdKL5hqsVQOauVgul8VqqaTGIhhfvmRBl5G9GRVrpg0I30qD3iDA==
"@spectrum-css/tag@^3.1.4":
version "3.3.5"
@ -2672,9 +2672,9 @@ typo-js@*:
integrity sha512-bTGLjbD3WqZDR3CgEFkyi9Q/SS2oM29ipXrWfDb4M74ea69QwKAECVceYpaBu0GfdnASMg9Qfl67ttB23nePHg==
uglify-js@^3.1.4:
version "3.15.2"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.2.tgz#1ed2c976f448063b1f87adb68c741be79959f951"
integrity sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==
version "3.15.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471"
integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg==
union-value@^1.0.0:
version "1.0.1"

View file

@ -1,12 +1,12 @@
{
"name": "@budibase/frontend-core",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase",
"license": "MPL-2.0",
"svelte": "src/index.js",
"dependencies": {
"@budibase/bbui": "^1.0.81-alpha.7",
"@budibase/bbui": "^1.0.89-alpha.0",
"lodash": "^4.17.21",
"svelte": "^3.46.2"
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@ -71,9 +71,9 @@
"license": "GPL-3.0",
"dependencies": {
"@apidevtools/swagger-parser": "^10.0.3",
"@budibase/backend-core": "^1.0.81-alpha.7",
"@budibase/client": "^1.0.81-alpha.7",
"@budibase/string-templates": "^1.0.81-alpha.7",
"@budibase/backend-core": "^1.0.89-alpha.0",
"@budibase/client": "^1.0.89-alpha.0",
"@budibase/string-templates": "^1.0.89-alpha.0",
"@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0",

View file

@ -437,8 +437,7 @@
}
},
"required": [
"name",
"url"
"name"
]
},
"applicationOutput": {
@ -1803,11 +1802,6 @@
"tags": [
"applications"
],
"parameters": [
{
"$ref": "#/components/parameters/appId"
}
],
"requestBody": {
"required": true,
"content": {

View file

@ -309,7 +309,6 @@ components:
type: string
required:
- name
- url
applicationOutput:
type: object
properties:
@ -1346,8 +1345,6 @@ paths:
applications.
tags:
- applications
parameters:
- $ref: "#/components/parameters/appId"
requestBody:
required: true
content:

View file

@ -27,7 +27,7 @@ const base = {
},
}
const applicationSchema = object(base, { required: ["name", "url"] })
const applicationSchema = object(base, { required: ["name"] })
const applicationOutputSchema = object(
{

View file

@ -121,8 +121,6 @@ read.push(new Endpoint("get", "/applications/:appId", controller.read))
* description: Based on application properties (currently only name) search for applications.
* tags:
* - applications
* parameters:
* - $ref: '#/components/parameters/appId'
* requestBody:
* required: true
* content:

View file

@ -31,16 +31,24 @@ function getApiLimitPerSecond(): number {
if (!env.isTest()) {
const REDIS_OPTS = getRedisOptions()
RateLimit.defaultOptions({
store: new Stores.Redis({
// @ts-ignore
let options
if (REDIS_OPTS.redisProtocolUrl) {
// fully qualified redis URL
options = {
url: REDIS_OPTS.redisProtocolUrl,
}
} else {
options = {
socket: {
host: REDIS_OPTS.host,
port: REDIS_OPTS.port,
},
password: REDIS_OPTS.opts.password,
database: 1,
}),
}
}
RateLimit.defaultOptions({
store: new Stores.Redis(options),
})
}
// rate limiting, allows for 2 requests per second

File diff suppressed because it is too large Load diff

View file

@ -8,5 +8,6 @@ export interface DatasourcePlus extends IntegrationBase {
// if the datasource supports the use of bindings directly (to protect against SQL injection)
// this returns the format of the identifier
getBindingIdentifier(): string
getStringConcat(parts: string[]): string
buildSchema(datasourceId: string, entities: Record<string, Table>): any
}

View file

@ -115,6 +115,10 @@ module GoogleSheetsModule {
return ""
}
getStringConcat(parts: string[]) {
return ""
}
/**
* Pull the spreadsheet ID out from a valid google sheets URL
* @param spreadsheetId - the URL or standard spreadsheetId of the google sheet

View file

@ -126,7 +126,11 @@ module MSSQLModule {
}
getBindingIdentifier(): string {
return `(@p${this.index++})`
return `@p${this.index++}`
}
getStringConcat(parts: string[]): string {
return `concat(${parts.join(", ")})`
}
async connect() {

View file

@ -99,6 +99,10 @@ module MySQLModule {
return "?"
}
getStringConcat(parts: string[]): string {
return `concat(${parts.join(", ")})`
}
async connect() {
this.client = await mysql.createConnection(this.config)
}

View file

@ -179,6 +179,10 @@ module OracleModule {
return `:${this.index++}`
}
getStringConcat(parts: string[]): string {
return parts.join(" || ")
}
/**
* Map the flat tabular columns and constraints data into a nested object
*/

View file

@ -148,6 +148,10 @@ module PostgresModule {
return `$${this.index++}`
}
getStringConcat(parts: string[]): string {
return parts.join(" || ")
}
async internalQuery(query: SqlQuery) {
const client = this.client
this.index = 1

View file

@ -37,7 +37,20 @@ class QueryRunner {
for (let binding of bindings) {
let variable = integration.getBindingIdentifier()
variables.push(binding)
sql = sql.replace(binding, variable)
// check if the variable was used as part of a string concat e.g. 'Hello {{binding}}'
const charConstRegex = new RegExp(`'[^']*${binding}[^']*'`)
const charConstMatch = sql.match(charConstRegex)
if (charConstMatch) {
let [part1, part2] = charConstMatch[0].split(binding)
part1 = `'${part1.substring(1)}'`
part2 = `'${part2.substring(0, part2.length - 1)}'`
sql = sql.replace(
charConstMatch[0],
integration.getStringConcat([part1, variable, part2])
)
} else {
sql = sql.replace(binding, variable)
}
}
// replicate the knex structure
fields.sql = sql

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",

View file

@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
"version": "1.0.81-alpha.7",
"version": "1.0.89-alpha.0",
"description": "Budibase background service",
"main": "src/index.ts",
"repository": {
@ -34,8 +34,8 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
"@budibase/backend-core": "^1.0.81-alpha.7",
"@budibase/string-templates": "^1.0.81-alpha.7",
"@budibase/backend-core": "^1.0.89-alpha.0",
"@budibase/string-templates": "^1.0.89-alpha.0",
"@koa/router": "^8.0.0",
"@sentry/node": "^6.0.0",
"@techpass/passport-openidconnect": "^0.3.0",

View file

@ -85,7 +85,12 @@ exports.setInitInfo = ctx => {
}
exports.getInitInfo = ctx => {
ctx.body = getCookie(ctx, Cookies.Init) || {}
try {
ctx.body = getCookie(ctx, Cookies.Init) || {}
} catch (err) {
clearCookie(ctx, Cookies.Init)
ctx.body = {}
}
}
/**

File diff suppressed because it is too large Load diff