Merge remote-tracking branch 'origin/master' into feature/buttongroup-component
This commit is contained in:
commit
e7fcd08fc6
|
@ -1,72 +0,0 @@
|
||||||
name: Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
|
||||||
REGISTRY_URL: registry.hub.docker.com
|
|
||||||
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: "build"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [18.x]
|
|
||||||
steps:
|
|
||||||
- name: "Checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
cache: "yarn"
|
|
||||||
- name: Setup QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Setup Docker Buildx
|
|
||||||
id: buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Run Yarn
|
|
||||||
run: yarn
|
|
||||||
- name: Run Yarn Build
|
|
||||||
run: yarn build --scope @budibase/server --scope @budibase/worker
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_API_KEY }}
|
|
||||||
- name: Get the latest release version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
release_version=$(cat lerna.json | jq -r '.version')
|
|
||||||
echo $release_version
|
|
||||||
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
|
|
||||||
- name: Tag and release Budibase service docker image
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
pull: true
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
build-args: BUDIBASE_VERSION=0.0.0+test
|
|
||||||
tags: budibase/budibase-test:test
|
|
||||||
file: ./hosting/single/Dockerfile.v2
|
|
||||||
cache-from: type=registry,ref=budibase/budibase-test:test
|
|
||||||
cache-to: type=inline
|
|
||||||
- name: Tag and release Budibase Azure App Service docker image
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
platforms: linux/amd64
|
|
||||||
build-args: |
|
|
||||||
TARGETBUILD=aas
|
|
||||||
BUDIBASE_VERSION=0.0.0+test
|
|
||||||
tags: budibase/budibase-test:aas
|
|
||||||
file: ./hosting/single/Dockerfile.v2
|
|
|
@ -33,7 +33,6 @@
|
||||||
"build:sdk": "lerna run --stream build:sdk",
|
"build:sdk": "lerna run --stream build:sdk",
|
||||||
"deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular",
|
"deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular",
|
||||||
"release": "lerna publish from-package --yes --force-publish --no-git-tag-version --no-push --no-git-reset",
|
"release": "lerna publish from-package --yes --force-publish --no-git-tag-version --no-push --no-git-reset",
|
||||||
"release:develop": "yarn release --dist-tag develop",
|
|
||||||
"restore": "yarn run clean && yarn && yarn run build",
|
"restore": "yarn run clean && yarn && yarn run build",
|
||||||
"nuke": "yarn run nuke:packages && yarn run nuke:docker",
|
"nuke": "yarn run nuke:packages && yarn run nuke:docker",
|
||||||
"nuke:packages": "yarn run restore",
|
"nuke:packages": "yarn run restore",
|
||||||
|
|
|
@ -2,14 +2,14 @@ import sanitizeUrl from "./utils/sanitizeUrl"
|
||||||
import { Screen } from "./utils/Screen"
|
import { Screen } from "./utils/Screen"
|
||||||
import { Component } from "./utils/Component"
|
import { Component } from "./utils/Component"
|
||||||
|
|
||||||
export default function (datasources) {
|
export default function (datasources, mode = "table") {
|
||||||
if (!Array.isArray(datasources)) {
|
if (!Array.isArray(datasources)) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return datasources.map(datasource => {
|
return datasources.map(datasource => {
|
||||||
return {
|
return {
|
||||||
name: `${datasource.label} - List`,
|
name: `${datasource.label} - List`,
|
||||||
create: () => createScreen(datasource),
|
create: () => createScreen(datasource, mode),
|
||||||
id: ROW_LIST_TEMPLATE,
|
id: ROW_LIST_TEMPLATE,
|
||||||
resourceId: datasource.resourceId,
|
resourceId: datasource.resourceId,
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,24 @@ const generateTableBlock = datasource => {
|
||||||
return tableBlock
|
return tableBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
const createScreen = datasource => {
|
const generateGridBlock = datasource => {
|
||||||
|
const gridBlock = new Component("@budibase/standard-components/gridblock")
|
||||||
|
gridBlock
|
||||||
|
.customProps({
|
||||||
|
table: datasource,
|
||||||
|
})
|
||||||
|
.instanceName(`${datasource.label} - Grid block`)
|
||||||
|
return gridBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
const createScreen = (datasource, mode) => {
|
||||||
return new Screen()
|
return new Screen()
|
||||||
.route(rowListUrl(datasource))
|
.route(rowListUrl(datasource))
|
||||||
.instanceName(`${datasource.label} - List`)
|
.instanceName(`${datasource.label} - List`)
|
||||||
.addChild(generateTableBlock(datasource))
|
.addChild(
|
||||||
|
mode === "table"
|
||||||
|
? generateTableBlock(datasource)
|
||||||
|
: generateGridBlock(datasource)
|
||||||
|
)
|
||||||
.json()
|
.json()
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,8 +196,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const validateQuery = async () => {
|
||||||
|
const forbiddenBindings = /{{\s?user(\.(\w|\$)*\s?|\s?)}}/g
|
||||||
|
const bindingError = new Error(
|
||||||
|
"'user' is a protected binding and cannot be used"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (forbiddenBindings.test(url)) {
|
||||||
|
throw bindingError
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forbiddenBindings.test(query.fields.requestBody ?? "")) {
|
||||||
|
throw bindingError
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.values(requestBindings).forEach(bindingValue => {
|
||||||
|
if (forbiddenBindings.test(bindingValue)) {
|
||||||
|
throw bindingError
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.values(query.fields.headers).forEach(headerValue => {
|
||||||
|
if (forbiddenBindings.test(headerValue)) {
|
||||||
|
throw bindingError
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function runQuery() {
|
async function runQuery() {
|
||||||
try {
|
try {
|
||||||
|
await validateQuery()
|
||||||
response = await queries.preview(buildQuery())
|
response = await queries.preview(buildQuery())
|
||||||
if (response.rows.length === 0) {
|
if (response.rows.length === 0) {
|
||||||
notifications.info("Request did not return any data")
|
notifications.info("Request did not return any data")
|
||||||
|
|
|
@ -91,7 +91,12 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if section == "styles"}
|
{#if section == "styles"}
|
||||||
<DesignSection {componentInstance} {componentDefinition} {bindings} />
|
<DesignSection
|
||||||
|
{componentInstance}
|
||||||
|
{componentBindings}
|
||||||
|
{componentDefinition}
|
||||||
|
{bindings}
|
||||||
|
/>
|
||||||
<CustomStylesSection
|
<CustomStylesSection
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
{componentDefinition}
|
{componentDefinition}
|
||||||
|
|
|
@ -16,18 +16,32 @@
|
||||||
export let isScreen = false
|
export let isScreen = false
|
||||||
export let onUpdateSetting
|
export let onUpdateSetting
|
||||||
export let showSectionTitle = true
|
export let showSectionTitle = true
|
||||||
|
export let tag
|
||||||
|
|
||||||
$: sections = getSections(componentInstance, componentDefinition, isScreen)
|
$: sections = getSections(
|
||||||
|
componentInstance,
|
||||||
|
componentDefinition,
|
||||||
|
isScreen,
|
||||||
|
tag
|
||||||
|
)
|
||||||
|
|
||||||
const getSections = (instance, definition, isScreen) => {
|
const getSections = (instance, definition, isScreen, tag) => {
|
||||||
const settings = definition?.settings ?? []
|
const settings = definition?.settings ?? []
|
||||||
const generalSettings = settings.filter(setting => !setting.section)
|
const generalSettings = settings.filter(
|
||||||
const customSections = settings.filter(setting => setting.section)
|
setting => !setting.section && setting.tag === tag
|
||||||
|
)
|
||||||
|
const customSections = settings.filter(
|
||||||
|
setting => setting.section && setting.tag === tag
|
||||||
|
)
|
||||||
let sections = [
|
let sections = [
|
||||||
{
|
...(generalSettings?.length
|
||||||
name: "General",
|
? [
|
||||||
settings: generalSettings,
|
{
|
||||||
},
|
name: "General",
|
||||||
|
settings: generalSettings,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
...(customSections || []),
|
...(customSections || []),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -132,7 +146,7 @@
|
||||||
<div class="section-info">
|
<div class="section-info">
|
||||||
<InfoDisplay body={section.info} />
|
<InfoDisplay body={section.info} />
|
||||||
</div>
|
</div>
|
||||||
{:else if idx === 0 && section.name === "General" && componentDefinition.info}
|
{:else if idx === 0 && section.name === "General" && componentDefinition?.info && !tag}
|
||||||
<InfoDisplay
|
<InfoDisplay
|
||||||
title={componentDefinition.name}
|
title={componentDefinition.name}
|
||||||
body={componentDefinition.info}
|
body={componentDefinition.info}
|
||||||
|
@ -181,7 +195,7 @@
|
||||||
</DetailSummary>
|
</DetailSummary>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{#if componentDefinition?.block}
|
{#if componentDefinition?.block && !tag}
|
||||||
<DetailSummary name="Eject" collapsible={false}>
|
<DetailSummary name="Eject" collapsible={false}>
|
||||||
<EjectBlockButton />
|
<EjectBlockButton />
|
||||||
</DetailSummary>
|
</DetailSummary>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import StyleSection from "./StyleSection.svelte"
|
import StyleSection from "./StyleSection.svelte"
|
||||||
import * as ComponentStyles from "./componentStyles"
|
import * as ComponentStyles from "./componentStyles"
|
||||||
|
import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
|
||||||
|
|
||||||
export let componentDefinition
|
export let componentDefinition
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
export let bindings
|
export let bindings
|
||||||
|
export let componentBindings
|
||||||
|
|
||||||
const getStyles = def => {
|
const getStyles = def => {
|
||||||
if (!def?.styles?.length) {
|
if (!def?.styles?.length) {
|
||||||
|
@ -22,6 +24,19 @@
|
||||||
$: styles = getStyles(componentDefinition)
|
$: styles = getStyles(componentDefinition)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Load any general settings or sections tagged as "style"
|
||||||
|
-->
|
||||||
|
<ComponentSettingsSection
|
||||||
|
{componentInstance}
|
||||||
|
{componentDefinition}
|
||||||
|
isScreen={false}
|
||||||
|
showInstanceName={false}
|
||||||
|
{bindings}
|
||||||
|
{componentBindings}
|
||||||
|
tag="style"
|
||||||
|
/>
|
||||||
|
|
||||||
{#if styles?.length > 0}
|
{#if styles?.length > 0}
|
||||||
{#each styles as style}
|
{#each styles as style}
|
||||||
<StyleSection
|
<StyleSection
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
import { capitalise } from "helpers"
|
import { capitalise } from "helpers"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
|
||||||
|
let mode
|
||||||
let pendingScreen
|
let pendingScreen
|
||||||
|
|
||||||
// Modal refs
|
// Modal refs
|
||||||
|
@ -100,14 +101,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for NewScreenModal
|
// Handler for NewScreenModal
|
||||||
export const show = mode => {
|
export const show = newMode => {
|
||||||
|
mode = newMode
|
||||||
selectedTemplates = null
|
selectedTemplates = null
|
||||||
blankScreenUrl = null
|
blankScreenUrl = null
|
||||||
screenMode = mode
|
screenMode = mode
|
||||||
pendingScreen = null
|
pendingScreen = null
|
||||||
screenAccessRole = Roles.BASIC
|
screenAccessRole = Roles.BASIC
|
||||||
|
|
||||||
if (mode === "table") {
|
if (mode === "table" || mode === "grid") {
|
||||||
datasourceModal.show()
|
datasourceModal.show()
|
||||||
} else if (mode === "blank") {
|
} else if (mode === "blank") {
|
||||||
let templates = getTemplates($tables.list)
|
let templates = getTemplates($tables.list)
|
||||||
|
@ -123,6 +125,7 @@
|
||||||
|
|
||||||
// Handler for DatasourceModal confirmation, move to screen access select
|
// Handler for DatasourceModal confirmation, move to screen access select
|
||||||
const confirmScreenDatasources = async ({ templates }) => {
|
const confirmScreenDatasources = async ({ templates }) => {
|
||||||
|
console.log(templates)
|
||||||
selectedTemplates = templates
|
selectedTemplates = templates
|
||||||
screenAccessRoleModal.show()
|
screenAccessRoleModal.show()
|
||||||
}
|
}
|
||||||
|
@ -177,6 +180,7 @@
|
||||||
|
|
||||||
<Modal bind:this={datasourceModal} autoFocus={false}>
|
<Modal bind:this={datasourceModal} autoFocus={false}>
|
||||||
<DatasourceModal
|
<DatasourceModal
|
||||||
|
{mode}
|
||||||
onConfirm={confirmScreenDatasources}
|
onConfirm={confirmScreenDatasources}
|
||||||
initialScreens={!selectedTemplates ? [] : [...selectedTemplates]}
|
initialScreens={!selectedTemplates ? [] : [...selectedTemplates]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import rowListScreen from "builderStore/store/screenTemplates/rowListScreen"
|
import rowListScreen from "builderStore/store/screenTemplates/rowListScreen"
|
||||||
import DatasourceTemplateRow from "./DatasourceTemplateRow.svelte"
|
import DatasourceTemplateRow from "./DatasourceTemplateRow.svelte"
|
||||||
|
|
||||||
|
export let mode
|
||||||
export let onCancel
|
export let onCancel
|
||||||
export let onConfirm
|
export let onConfirm
|
||||||
export let initialScreens = []
|
export let initialScreens = []
|
||||||
|
@ -24,7 +25,10 @@
|
||||||
screen => screen.resourceId !== resourceId
|
screen => screen.resourceId !== resourceId
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
selectedScreens = [...selectedScreens, rowListScreen([datasource])[0]]
|
selectedScreens = [
|
||||||
|
...selectedScreens,
|
||||||
|
rowListScreen([datasource], mode)[0],
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -3,6 +3,7 @@
|
||||||
import CreationPage from "components/common/CreationPage.svelte"
|
import CreationPage from "components/common/CreationPage.svelte"
|
||||||
import blankImage from "./blank.png"
|
import blankImage from "./blank.png"
|
||||||
import tableImage from "./table.png"
|
import tableImage from "./table.png"
|
||||||
|
import gridImage from "./grid.png"
|
||||||
import CreateScreenModal from "./CreateScreenModal.svelte"
|
import CreateScreenModal from "./CreateScreenModal.svelte"
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
|
|
||||||
|
@ -43,6 +44,16 @@
|
||||||
<Body size="XS">View, edit and delete rows on a table</Body>
|
<Body size="XS">View, edit and delete rows on a table</Body>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card" on:click={() => createScreenModal.show("grid")}>
|
||||||
|
<div class="image">
|
||||||
|
<img alt="" src={gridImage} />
|
||||||
|
</div>
|
||||||
|
<div class="text">
|
||||||
|
<Body size="S">Grid</Body>
|
||||||
|
<Body size="XS">View and manipulate rows on a grid</Body>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CreationPage>
|
</CreationPage>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5570,38 +5570,6 @@
|
||||||
"section": true,
|
"section": true,
|
||||||
"name": "Fields",
|
"name": "Fields",
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
|
||||||
"type": "select",
|
|
||||||
"label": "Align labels",
|
|
||||||
"key": "labelPosition",
|
|
||||||
"defaultValue": "left",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"label": "Left",
|
|
||||||
"value": "left"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Above",
|
|
||||||
"value": "above"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "select",
|
|
||||||
"label": "Size",
|
|
||||||
"key": "size",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"label": "Medium",
|
|
||||||
"value": "spectrum--medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Large",
|
|
||||||
"value": "spectrum--large"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"defaultValue": "spectrum--medium"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "fieldConfiguration",
|
"type": "fieldConfiguration",
|
||||||
"key": "fields",
|
"key": "fields",
|
||||||
|
@ -5621,6 +5589,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "style",
|
||||||
|
"type": "select",
|
||||||
|
"label": "Align labels",
|
||||||
|
"key": "labelPosition",
|
||||||
|
"defaultValue": "left",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"label": "Left",
|
||||||
|
"value": "left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Above",
|
||||||
|
"value": "above"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "style",
|
||||||
|
"type": "select",
|
||||||
|
"label": "Size",
|
||||||
|
"key": "size",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"label": "Medium",
|
||||||
|
"value": "spectrum--medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Large",
|
||||||
|
"value": "spectrum--large"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"defaultValue": "spectrum--medium"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"context": [
|
"context": [
|
||||||
|
|
|
@ -44,7 +44,7 @@ RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
||||||
WORKDIR /string-templates
|
WORKDIR /string-templates
|
||||||
COPY packages/string-templates/package.json package.json
|
COPY packages/string-templates/package.json package.json
|
||||||
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true
|
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000
|
||||||
COPY packages/string-templates .
|
COPY packages/string-templates .
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.
|
||||||
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
||||||
RUN ./scripts/removeWorkspaceDependencies.sh package.json
|
RUN ./scripts/removeWorkspaceDependencies.sh package.json
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true \
|
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000 \
|
||||||
# Remove unneeded data from file system to reduce image size
|
# Remove unneeded data from file system to reduce image size
|
||||||
&& yarn cache clean && apt-get remove -y --purge --auto-remove g++ make python jq \
|
&& yarn cache clean && apt-get remove -y --purge --auto-remove g++ make python jq \
|
||||||
&& rm -rf /tmp/* /root/.node-gyp /usr/local/lib/node_modules/npm/node_modules/node-gyp
|
&& rm -rf /tmp/* /root/.node-gyp /usr/local/lib/node_modules/npm/node_modules/node-gyp
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { context, db as dbCore, events, roles } from "@budibase/backend-core"
|
import {
|
||||||
|
context,
|
||||||
|
db as dbCore,
|
||||||
|
events,
|
||||||
|
roles,
|
||||||
|
Header,
|
||||||
|
} from "@budibase/backend-core"
|
||||||
import { getUserMetadataParams, InternalTables } from "../../db/utils"
|
import { getUserMetadataParams, InternalTables } from "../../db/utils"
|
||||||
import { Database, Role, UserCtx, UserRoles } from "@budibase/types"
|
import { Database, Role, UserCtx, UserRoles } from "@budibase/types"
|
||||||
import { sdk as sharedSdk } from "@budibase/shared-core"
|
import { sdk as sharedSdk } from "@budibase/shared-core"
|
||||||
|
@ -143,4 +149,20 @@ export async function accessible(ctx: UserCtx) {
|
||||||
} else {
|
} else {
|
||||||
ctx.body = await roles.getUserRoleIdHierarchy(roleId!)
|
ctx.body = await roles.getUserRoleIdHierarchy(roleId!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a custom role is provided in the header, filter out higher level roles
|
||||||
|
const roleHeader = ctx.header?.[Header.PREVIEW_ROLE] as string
|
||||||
|
if (roleHeader && !Object.keys(roles.BUILTIN_ROLE_IDS).includes(roleHeader)) {
|
||||||
|
const inherits = (await roles.getRole(roleHeader))?.inherits
|
||||||
|
const orderedRoles = ctx.body.reverse()
|
||||||
|
let filteredRoles = [roleHeader]
|
||||||
|
for (let role of orderedRoles) {
|
||||||
|
filteredRoles = [role, ...filteredRoles]
|
||||||
|
if (role === inherits) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filteredRoles.pop()
|
||||||
|
ctx.body = [roleHeader, ...filteredRoles]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,5 +158,25 @@ describe("/roles", () => {
|
||||||
expect(res.body.length).toBe(1)
|
expect(res.body.length).toBe(1)
|
||||||
expect(res.body[0]).toBe("PUBLIC")
|
expect(res.body[0]).toBe("PUBLIC")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should not fetch higher level accessible roles when a custom role header is provided", async () => {
|
||||||
|
await createRole({
|
||||||
|
name: `CUSTOM_ROLE`,
|
||||||
|
inherits: roles.BUILTIN_ROLE_IDS.BASIC,
|
||||||
|
permissionId: permissions.BuiltinPermissionID.READ_ONLY,
|
||||||
|
version: "name",
|
||||||
|
})
|
||||||
|
const res = await request
|
||||||
|
.get("/api/roles/accessible")
|
||||||
|
.set({
|
||||||
|
...config.defaultHeaders(),
|
||||||
|
"x-budibase-role": "CUSTOM_ROLE"
|
||||||
|
})
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.length).toBe(3)
|
||||||
|
expect(res.body[0]).toBe("CUSTOM_ROLE")
|
||||||
|
expect(res.body[1]).toBe("BASIC")
|
||||||
|
expect(res.body[2]).toBe("PUBLIC")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const setup = require("./utilities")
|
const setup = require("./utilities")
|
||||||
const { basicScreen } = setup.structures
|
const { basicScreen, powerScreen } = setup.structures
|
||||||
const { checkBuilderEndpoint, runInProd } = require("./utilities/TestFunctions")
|
const { checkBuilderEndpoint, runInProd } = require("./utilities/TestFunctions")
|
||||||
const { roles } = require("@budibase/backend-core")
|
const { roles } = require("@budibase/backend-core")
|
||||||
const { BUILTIN_ROLE_IDS } = roles
|
const { BUILTIN_ROLE_IDS } = roles
|
||||||
|
@ -12,19 +12,14 @@ const route = "/test"
|
||||||
describe("/routing", () => {
|
describe("/routing", () => {
|
||||||
let request = setup.getRequest()
|
let request = setup.getRequest()
|
||||||
let config = setup.getConfig()
|
let config = setup.getConfig()
|
||||||
let screen, screen2
|
let basic, power
|
||||||
|
|
||||||
afterAll(setup.afterAll)
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
screen = basicScreen()
|
basic = await config.createScreen(basicScreen(route))
|
||||||
screen.routing.route = route
|
power = await config.createScreen(powerScreen(route))
|
||||||
screen = await config.createScreen(screen)
|
|
||||||
screen2 = basicScreen()
|
|
||||||
screen2.routing.roleId = BUILTIN_ROLE_IDS.POWER
|
|
||||||
screen2.routing.route = route
|
|
||||||
screen2 = await config.createScreen(screen2)
|
|
||||||
await config.publish()
|
await config.publish()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -61,8 +56,8 @@ describe("/routing", () => {
|
||||||
expect(res.body.routes[route]).toEqual({
|
expect(res.body.routes[route]).toEqual({
|
||||||
subpaths: {
|
subpaths: {
|
||||||
[route]: {
|
[route]: {
|
||||||
screenId: screen._id,
|
screenId: basic._id,
|
||||||
roleId: screen.routing.roleId
|
roleId: basic.routing.roleId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -80,8 +75,8 @@ describe("/routing", () => {
|
||||||
expect(res.body.routes[route]).toEqual({
|
expect(res.body.routes[route]).toEqual({
|
||||||
subpaths: {
|
subpaths: {
|
||||||
[route]: {
|
[route]: {
|
||||||
screenId: screen2._id,
|
screenId: power._id,
|
||||||
roleId: screen2.routing.roleId
|
roleId: power.routing.roleId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -101,8 +96,8 @@ describe("/routing", () => {
|
||||||
expect(res.body.routes).toBeDefined()
|
expect(res.body.routes).toBeDefined()
|
||||||
expect(res.body.routes[route].subpaths[route]).toBeDefined()
|
expect(res.body.routes[route].subpaths[route]).toBeDefined()
|
||||||
const subpath = res.body.routes[route].subpaths[route]
|
const subpath = res.body.routes[route].subpaths[route]
|
||||||
expect(subpath.screens[screen2.routing.roleId]).toEqual(screen2._id)
|
expect(subpath.screens[power.routing.roleId]).toEqual(power._id)
|
||||||
expect(subpath.screens[screen.routing.roleId]).toEqual(screen._id)
|
expect(subpath.screens[basic.routing.roleId]).toEqual(basic._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("make sure it is a builder only endpoint", async () => {
|
it("make sure it is a builder only endpoint", async () => {
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import { roles } from "@budibase/backend-core"
|
import { roles } from "@budibase/backend-core"
|
||||||
import { BASE_LAYOUT_PROP_IDS } from "./layouts"
|
import { BASE_LAYOUT_PROP_IDS } from "./layouts"
|
||||||
|
|
||||||
export function createHomeScreen() {
|
export function createHomeScreen(
|
||||||
|
config: {
|
||||||
|
roleId: string
|
||||||
|
route: string
|
||||||
|
} = {
|
||||||
|
roleId: roles.BUILTIN_ROLE_IDS.BASIC,
|
||||||
|
route: "/",
|
||||||
|
}
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
description: "",
|
description: "",
|
||||||
url: "",
|
url: "",
|
||||||
|
@ -40,8 +48,8 @@ export function createHomeScreen() {
|
||||||
gap: "M",
|
gap: "M",
|
||||||
},
|
},
|
||||||
routing: {
|
routing: {
|
||||||
route: "/",
|
route: config.route,
|
||||||
roleId: roles.BUILTIN_ROLE_IDS.BASIC,
|
roleId: config.roleId,
|
||||||
},
|
},
|
||||||
name: "home-screen",
|
name: "home-screen",
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
SourceName,
|
SourceName,
|
||||||
Table,
|
Table,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
const { BUILTIN_ROLE_IDS } = roles
|
||||||
|
|
||||||
export function basicTable(): Table {
|
export function basicTable(): Table {
|
||||||
return {
|
return {
|
||||||
|
@ -322,8 +323,22 @@ export function basicUser(role: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function basicScreen() {
|
export function basicScreen(route: string = "/") {
|
||||||
return createHomeScreen()
|
return createHomeScreen({
|
||||||
|
roleId: BUILTIN_ROLE_IDS.BASIC,
|
||||||
|
route,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function powerScreen(route: string = "/") {
|
||||||
|
return createHomeScreen({
|
||||||
|
roleId: BUILTIN_ROLE_IDS.POWER,
|
||||||
|
route,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function customScreen(config: { roleId: string; route: string }) {
|
||||||
|
return createHomeScreen(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function basicLayout() {
|
export function basicLayout() {
|
||||||
|
|
|
@ -19,7 +19,7 @@ RUN chmod +x ./scripts/removeWorkspaceDependencies.sh
|
||||||
WORKDIR /string-templates
|
WORKDIR /string-templates
|
||||||
COPY packages/string-templates/package.json package.json
|
COPY packages/string-templates/package.json package.json
|
||||||
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true
|
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000
|
||||||
COPY packages/string-templates .
|
COPY packages/string-templates .
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ RUN cd ../string-templates && yarn link && cd - && yarn link @budibase/string-te
|
||||||
|
|
||||||
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
RUN ../scripts/removeWorkspaceDependencies.sh package.json
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true
|
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production=true --network-timeout 1000000
|
||||||
# Remove unneeded data from file system to reduce image size
|
# Remove unneeded data from file system to reduce image size
|
||||||
RUN apk del .gyp \
|
RUN apk del .gyp \
|
||||||
&& yarn cache clean
|
&& yarn cache clean
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
version=$1
|
||||||
|
echo "Setting version $version"
|
||||||
|
yarn lerna exec "yarn version --no-git-tag-version --new-version=$version"
|
||||||
|
echo "Updating dependencies"
|
||||||
|
node scripts/syncLocalDependencies.js $version
|
||||||
|
echo "Syncing yarn workspace"
|
||||||
|
yarn
|
Loading…
Reference in New Issue