Merge branch 'master' into budi-7105-builder-option-for-read-only-form-fields
This commit is contained in:
commit
9161fee687
|
@ -11,10 +11,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: peter-evans/repository-dispatch@v2
|
||||
env:
|
||||
PAYLOAD_VERSION: ${{ github.sha }}
|
||||
REF_NAME: ${{ github.ref_name}}
|
||||
with:
|
||||
repository: budibase/budibase-deploys
|
||||
event-type: budicloud-qa-deploy
|
||||
token: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
client-payload: |-
|
||||
{
|
||||
"PAYLOAD_VERSION": "${{ github.sha }}",
|
||||
"REF_NAME": "${{ github.ref_name}}"
|
||||
}
|
||||
|
|
|
@ -165,17 +165,14 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Get the current budibase release version
|
||||
id: version
|
||||
run: |
|
||||
release_version=$(cat lerna.json | jq -r '.version')
|
||||
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
|
||||
|
||||
- uses: passeidireto/trigger-external-workflow-action@main
|
||||
env:
|
||||
PAYLOAD_VERSION: ${{ env.RELEASE_VERSION }}
|
||||
REF_NAME: ${{ github.ref_name}}
|
||||
- uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
repository: budibase/budibase-deploys
|
||||
event: budicloud-qa-deploy
|
||||
github_pat: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
client-payload: |-
|
||||
{
|
||||
"PAYLOAD_VERSION": "${{ github.ref_name }}",
|
||||
"REF_NAME": "${{ github.ref_name}}"
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ jobs:
|
|||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: BUDIBASE_VERSION=$BUDIBASE_VERSION
|
||||
build-args: BUDIBASE_VERSION=${{ env.BUDIBASE_VERSION }}
|
||||
tags: budibase/budibase,budibase/budibase:${{ env.RELEASE_VERSION }}
|
||||
file: ./hosting/single/Dockerfile.v2
|
||||
env:
|
||||
|
@ -79,7 +79,7 @@ jobs:
|
|||
platforms: linux/amd64
|
||||
build-args: |
|
||||
TARGETBUILD=aas
|
||||
BUDIBASE_VERSION=$BUDIBASE_VERSION
|
||||
BUDIBASE_VERSION=${{ env.BUDIBASE_VERSION }}
|
||||
tags: budibase/budibase-aas,budibase/budibase-aas:${{ env.RELEASE_VERSION }}
|
||||
file: ./hosting/single/Dockerfile.v2
|
||||
env:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.12.4",
|
||||
"version": "2.12.6",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"scripts": {
|
||||
"preinstall": "node scripts/syncProPackage.js",
|
||||
"setup": "git config submodule.recurse true && git submodule update && node ./hosting/scripts/setup.js && yarn && yarn build && yarn dev",
|
||||
"build": "lerna run build --stream",
|
||||
"build": "NODE_OPTIONS=--max-old-space-size=1500 lerna run build --stream",
|
||||
"build:dev": "lerna run --stream prebuild && yarn nx run-many --target=build --output-style=dynamic --watch --preserveWatchOutput",
|
||||
"check:types": "lerna run check:types",
|
||||
"build:sdk": "lerna run --stream build:sdk",
|
||||
|
|
|
@ -30,6 +30,7 @@ export * as timers from "./timers"
|
|||
export { default as env } from "./environment"
|
||||
export * as blacklist from "./blacklist"
|
||||
export * as docUpdates from "./docUpdates"
|
||||
export * from "./utils/Duration"
|
||||
export { SearchParams } from "./db"
|
||||
// Add context to tenancy for backwards compatibility
|
||||
// only do this for external usages to prevent internal
|
||||
|
|
|
@ -36,7 +36,7 @@ class InMemoryQueue {
|
|||
* @param opts This is not used by the in memory queue as there is no real use
|
||||
* case when in memory, but is the same API as Bull
|
||||
*/
|
||||
constructor(name: string, opts = null) {
|
||||
constructor(name: string, opts?: any) {
|
||||
this._name = name
|
||||
this._opts = opts
|
||||
this._messages = []
|
||||
|
|
|
@ -2,11 +2,18 @@ import env from "../environment"
|
|||
import { getRedisOptions } from "../redis/utils"
|
||||
import { JobQueue } from "./constants"
|
||||
import InMemoryQueue from "./inMemoryQueue"
|
||||
import BullQueue from "bull"
|
||||
import BullQueue, { QueueOptions } from "bull"
|
||||
import { addListeners, StalledFn } from "./listeners"
|
||||
import { Duration } from "../utils"
|
||||
import * as timers from "../timers"
|
||||
import * as Redis from "ioredis"
|
||||
|
||||
const CLEANUP_PERIOD_MS = 60 * 1000
|
||||
// the queue lock is held for 5 minutes
|
||||
const QUEUE_LOCK_MS = Duration.fromMinutes(5).toMs()
|
||||
// queue lock is refreshed every 30 seconds
|
||||
const QUEUE_LOCK_RENEW_INTERNAL_MS = Duration.fromSeconds(30).toMs()
|
||||
// cleanup the queue every 60 seconds
|
||||
const CLEANUP_PERIOD_MS = Duration.fromSeconds(60).toMs()
|
||||
let QUEUES: BullQueue.Queue[] | InMemoryQueue[] = []
|
||||
let cleanupInterval: NodeJS.Timeout
|
||||
|
||||
|
@ -21,7 +28,14 @@ export function createQueue<T>(
|
|||
opts: { removeStalledCb?: StalledFn } = {}
|
||||
): BullQueue.Queue<T> {
|
||||
const { opts: redisOpts, redisProtocolUrl } = getRedisOptions()
|
||||
const queueConfig: any = redisProtocolUrl || { redis: redisOpts }
|
||||
const queueConfig: QueueOptions = {
|
||||
redis: redisProtocolUrl! || (redisOpts as Redis.RedisOptions),
|
||||
settings: {
|
||||
maxStalledCount: 0,
|
||||
lockDuration: QUEUE_LOCK_MS,
|
||||
lockRenewTime: QUEUE_LOCK_RENEW_INTERNAL_MS,
|
||||
},
|
||||
}
|
||||
let queue: any
|
||||
if (!env.isTest()) {
|
||||
queue = new BullQueue(jobQueue, queueConfig)
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
export enum DurationType {
|
||||
MILLISECONDS = "milliseconds",
|
||||
SECONDS = "seconds",
|
||||
MINUTES = "minutes",
|
||||
HOURS = "hours",
|
||||
DAYS = "days",
|
||||
}
|
||||
|
||||
const conversion: Record<DurationType, number> = {
|
||||
milliseconds: 1,
|
||||
seconds: 1000,
|
||||
minutes: 60 * 1000,
|
||||
hours: 60 * 60 * 1000,
|
||||
days: 24 * 60 * 60 * 1000,
|
||||
}
|
||||
|
||||
export class Duration {
|
||||
static convert(from: DurationType, to: DurationType, duration: number) {
|
||||
const milliseconds = duration * conversion[from]
|
||||
return milliseconds / conversion[to]
|
||||
}
|
||||
|
||||
static from(from: DurationType, duration: number) {
|
||||
return {
|
||||
to: (to: DurationType) => {
|
||||
return Duration.convert(from, to, duration)
|
||||
},
|
||||
toMs: () => {
|
||||
return Duration.convert(from, DurationType.MILLISECONDS, duration)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
static fromSeconds(duration: number) {
|
||||
return Duration.from(DurationType.SECONDS, duration)
|
||||
}
|
||||
|
||||
static fromMinutes(duration: number) {
|
||||
return Duration.from(DurationType.MINUTES, duration)
|
||||
}
|
||||
|
||||
static fromHours(duration: number) {
|
||||
return Duration.from(DurationType.HOURS, duration)
|
||||
}
|
||||
|
||||
static fromDays(duration: number) {
|
||||
return Duration.from(DurationType.DAYS, duration)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./hashing"
|
||||
export * from "./utils"
|
||||
export * from "./stringUtils"
|
||||
export * from "./Duration"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Duration, DurationType } from "../Duration"
|
||||
|
||||
describe("duration", () => {
|
||||
it("should convert minutes to milliseconds", () => {
|
||||
expect(Duration.fromMinutes(5).toMs()).toBe(300000)
|
||||
})
|
||||
|
||||
it("should convert seconds to milliseconds", () => {
|
||||
expect(Duration.fromSeconds(30).toMs()).toBe(30000)
|
||||
})
|
||||
|
||||
it("should convert days to milliseconds", () => {
|
||||
expect(Duration.fromDays(1).toMs()).toBe(86400000)
|
||||
})
|
||||
|
||||
it("should convert minutes to days", () => {
|
||||
expect(Duration.fromMinutes(1440).to(DurationType.DAYS)).toBe(1)
|
||||
})
|
||||
})
|
|
@ -1,5 +1,5 @@
|
|||
import { Checkbox, Select, RadioGroup, Stepper, Input } from "@budibase/bbui"
|
||||
import DataSourceSelect from "./controls/DataSourceSelect.svelte"
|
||||
import DataSourceSelect from "./controls/DataSourceSelect/DataSourceSelect.svelte"
|
||||
import S3DataSourceSelect from "./controls/S3DataSourceSelect.svelte"
|
||||
import DataProviderSelect from "./controls/DataProviderSelect.svelte"
|
||||
import ButtonActionEditor from "./controls/ButtonActionEditor/ButtonActionEditor.svelte"
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<script>
|
||||
import { Divider, Heading } from "@budibase/bbui"
|
||||
|
||||
export let dividerState
|
||||
export let heading
|
||||
export let dataSet
|
||||
export let value
|
||||
export let onSelect
|
||||
</script>
|
||||
|
||||
{#if dividerState}
|
||||
<Divider />
|
||||
{/if}
|
||||
{#if heading}
|
||||
<div class="title">
|
||||
<Heading size="XS">{heading}</Heading>
|
||||
</div>
|
||||
{/if}
|
||||
<ul class="spectrum-Menu" role="listbox">
|
||||
{#each dataSet as data}
|
||||
<li
|
||||
class="spectrum-Menu-item"
|
||||
class:is-selected={value?.label === data.label &&
|
||||
value?.type === data.type}
|
||||
role="option"
|
||||
aria-selected="true"
|
||||
tabindex="0"
|
||||
on:click={() => onSelect(data)}
|
||||
>
|
||||
<span class="spectrum-Menu-itemLabel">
|
||||
{data.label}
|
||||
</span>
|
||||
<svg
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon"
|
||||
focusable="false"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" />
|
||||
</svg>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.title {
|
||||
padding: 0 var(--spacing-m) var(--spacing-s) var(--spacing-m);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 0px;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -7,10 +7,8 @@
|
|||
import {
|
||||
Button,
|
||||
Popover,
|
||||
Divider,
|
||||
Select,
|
||||
Layout,
|
||||
Heading,
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
Icon,
|
||||
|
@ -32,6 +30,7 @@
|
|||
import IntegrationQueryEditor from "components/integration/index.svelte"
|
||||
import { makePropSafe as safe } from "@budibase/string-templates"
|
||||
import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte"
|
||||
import DataSourceCategory from "components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte"
|
||||
import { API } from "api"
|
||||
|
||||
export let value = {}
|
||||
|
@ -279,102 +278,81 @@
|
|||
</div>
|
||||
<Popover bind:this={dropdownRight} anchor={anchorRight}>
|
||||
<div class="dropdown">
|
||||
<div class="title">
|
||||
<Heading size="XS">Tables</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each tables as table}
|
||||
<li on:click={() => handleSelected(table)}>{table.label}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
heading="Tables"
|
||||
dataSet={tables}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{#if views?.length}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">Views</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each views as view}
|
||||
<li on:click={() => handleSelected(view)}>{view.label}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="Views"
|
||||
dataSet={views}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
{#if queries?.length}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">Queries</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each queries as query}
|
||||
<li
|
||||
class:selected={value === query}
|
||||
on:click={() => handleSelected(query)}
|
||||
>
|
||||
{query.label}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="Queries"
|
||||
dataSet={queries}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
{#if links?.length}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">Relationships</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each links as link}
|
||||
<li on:click={() => handleSelected(link)}>{link.label}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="Links"
|
||||
dataSet={links}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
{#if fields?.length}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">Fields</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each fields as field}
|
||||
<li on:click={() => handleSelected(field)}>{field.label}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="Fields"
|
||||
dataSet={fields}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
{#if jsonArrays?.length}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">JSON Arrays</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each jsonArrays as field}
|
||||
<li on:click={() => handleSelected(field)}>{field.label}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="JSON Arrays"
|
||||
dataSet={jsonArrays}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
{#if showDataProviders && dataProviders?.length}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">Data Providers</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
{#each dataProviders as provider}
|
||||
<li
|
||||
class:selected={value === provider}
|
||||
on:click={() => handleSelected(provider)}
|
||||
>
|
||||
{provider.label}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="Data Providers"
|
||||
dataSet={dataProviders}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
<DataSourceCategory
|
||||
dividerState={true}
|
||||
heading="Other"
|
||||
dataSet={[custom]}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{#if otherSources?.length}
|
||||
<DataSourceCategory
|
||||
dividerState={false}
|
||||
dataSet={otherSources}
|
||||
{value}
|
||||
onSelect={handleSelected}
|
||||
/>
|
||||
{/if}
|
||||
<Divider />
|
||||
<div class="title">
|
||||
<Heading size="XS">Other</Heading>
|
||||
</div>
|
||||
<ul>
|
||||
<li on:click={() => handleSelected(custom)}>{custom.label}</li>
|
||||
{#if otherSources?.length}
|
||||
{#each otherSources as source}
|
||||
<li on:click={() => handleSelected(source)}>{source.label}</li>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
|
@ -398,31 +376,6 @@
|
|||
.dropdown {
|
||||
padding: var(--spacing-m) 0;
|
||||
z-index: 99999999;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.title {
|
||||
padding: 0 var(--spacing-m) var(--spacing-s) var(--spacing-m);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
margin: 0px;
|
||||
padding: var(--spacing-s) var(--spacing-m);
|
||||
font-size: var(--font-size-m);
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: var(--spectrum-global-color-blue-600);
|
||||
}
|
||||
|
||||
li:hover {
|
||||
background-color: var(--spectrum-global-color-gray-200);
|
||||
}
|
||||
|
||||
.icon {
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import DataSourceSelect from "./DataSourceSelect.svelte"
|
||||
import DataSourceSelect from "./DataSourceSelect/DataSourceSelect.svelte"
|
||||
|
||||
const otherSources = [{ name: "Custom", label: "Custom" }]
|
||||
</script>
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
## Description
|
||||
|
||||
_Describe the problem or feature in addition to a link to the relevant github issues._
|
||||
|
||||
Addresses:
|
||||
Addresses:
|
||||
|
||||
- `<Enter the Link to the issue(s) this PR addresses>`
|
||||
- ...more if required
|
||||
|
||||
## App Export
|
||||
|
||||
- If possible, attach an app export file along with your request template to make QA testing easier, with minimal setup.
|
||||
|
||||
## Screenshots
|
||||
|
||||
_If a UI facing feature, a short video of the happy path, and some screenshots of the new functionality._
|
||||
|
||||
## Documentation
|
||||
- [ ] I have reviewed the budibase documentatation to verify if this feature requires any changes. If changes or new docs are required I have written them.
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue