Merge branch 'master' of github.com:Budibase/budibase into feature/self-hosting
This commit is contained in:
commit
4c8ee99905
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "0.3.8",
|
"version": "0.4.2",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -115,7 +115,7 @@ Cypress.Commands.add("createUser", (email, password, role) => {
|
||||||
// Create User
|
// Create User
|
||||||
cy.contains("Users").click()
|
cy.contains("Users").click()
|
||||||
|
|
||||||
cy.contains("Create New Row").click()
|
cy.contains("Create New User").click()
|
||||||
|
|
||||||
cy.get(".modal").within(() => {
|
cy.get(".modal").within(() => {
|
||||||
cy.get("input")
|
cy.get("input")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/builder",
|
"name": "@budibase/builder",
|
||||||
"version": "0.3.8",
|
"version": "0.4.2",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -63,8 +63,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^1.52.2",
|
"@budibase/bbui": "^1.52.4",
|
||||||
"@budibase/client": "^0.3.8",
|
"@budibase/client": "^0.4.2",
|
||||||
"@budibase/colorpicker": "^1.0.1",
|
"@budibase/colorpicker": "^1.0.1",
|
||||||
"@budibase/svelte-ag-grid": "^0.0.16",
|
"@budibase/svelte-ag-grid": "^0.0.16",
|
||||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||||
|
|
|
@ -39,10 +39,10 @@ function identify(id) {
|
||||||
|
|
||||||
async function identifyByApiKey(apiKey) {
|
async function identifyByApiKey(apiKey) {
|
||||||
if (!analyticsEnabled) return true
|
if (!analyticsEnabled) return true
|
||||||
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://03gaine137.execute-api.eu-west-1.amazonaws.com/prod/account/id?api_key=${apiKey.trim()}`
|
`https://03gaine137.execute-api.eu-west-1.amazonaws.com/prod/account/id?api_key=${apiKey.trim()}`
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const id = await response.json()
|
const id = await response.json()
|
||||||
|
|
||||||
|
@ -52,6 +52,9 @@ async function identifyByApiKey(apiKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function captureException(err) {
|
function captureException(err) {
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { getAutomationStore } from "./store/automation"
|
||||||
import { getHostingStore } from "./store/hosting"
|
import { getHostingStore } from "./store/hosting"
|
||||||
|
|
||||||
import { getThemeStore } from "./store/theme"
|
import { getThemeStore } from "./store/theme"
|
||||||
import { derived } from "svelte/store"
|
import { derived, writable } from "svelte/store"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import { LAYOUT_NAMES } from "../constants"
|
import { FrontendTypes, LAYOUT_NAMES } from "../constants"
|
||||||
import { makePropsSafe } from "components/userInterface/assetParsing/createProps"
|
import { makePropsSafe } from "components/userInterface/assetParsing/createProps"
|
||||||
|
|
||||||
export const store = getFrontendStore()
|
export const store = getFrontendStore()
|
||||||
|
@ -16,18 +16,12 @@ export const themeStore = getThemeStore()
|
||||||
export const hostingStore = getHostingStore()
|
export const hostingStore = getHostingStore()
|
||||||
|
|
||||||
export const currentAsset = derived(store, $store => {
|
export const currentAsset = derived(store, $store => {
|
||||||
const layout = $store.layouts
|
const type = $store.currentFrontEndType
|
||||||
? $store.layouts.find(layout => layout._id === $store.currentAssetId)
|
if (type === FrontendTypes.SCREEN) {
|
||||||
: null
|
return $store.screens.find(screen => screen._id === $store.selectedScreenId)
|
||||||
|
} else if (type === FrontendTypes.LAYOUT) {
|
||||||
if (layout) return layout
|
return $store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
||||||
|
}
|
||||||
const screen = $store.screens
|
|
||||||
? $store.screens.find(screen => screen._id === $store.currentAssetId)
|
|
||||||
: null
|
|
||||||
|
|
||||||
if (screen) return screen
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -62,8 +56,14 @@ export const selectedComponent = derived(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const currentAssetName = derived(store, () => {
|
export const currentAssetId = derived(store, $store => {
|
||||||
return currentAsset.name
|
return $store.currentFrontEndType === FrontendTypes.SCREEN
|
||||||
|
? $store.selectedScreenId
|
||||||
|
: $store.selectedLayoutId
|
||||||
|
})
|
||||||
|
|
||||||
|
export const currentAssetName = derived(currentAsset, $currentAsset => {
|
||||||
|
return $currentAsset?.name
|
||||||
})
|
})
|
||||||
|
|
||||||
// leave this as before for consistency
|
// leave this as before for consistency
|
||||||
|
@ -77,6 +77,8 @@ export const mainLayout = derived(store, $store => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const selectedAccessRole = writable("BASIC")
|
||||||
|
|
||||||
export const initialise = async () => {
|
export const initialise = async () => {
|
||||||
try {
|
try {
|
||||||
await analytics.activate()
|
await analytics.activate()
|
||||||
|
|
|
@ -6,6 +6,7 @@ const INITIAL_BACKEND_UI_STATE = {
|
||||||
tables: [],
|
tables: [],
|
||||||
views: [],
|
views: [],
|
||||||
users: [],
|
users: [],
|
||||||
|
roles: [],
|
||||||
selectedDatabase: {},
|
selectedDatabase: {},
|
||||||
selectedTable: {},
|
selectedTable: {},
|
||||||
draftTable: {},
|
draftTable: {},
|
||||||
|
@ -177,6 +178,26 @@ export const getBackendUiStore = () => {
|
||||||
return state
|
return state
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
roles: {
|
||||||
|
fetch: async () => {
|
||||||
|
const response = await api.get("/api/roles")
|
||||||
|
const roles = await response.json()
|
||||||
|
store.update(state => {
|
||||||
|
state.roles = roles
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
},
|
||||||
|
delete: async role => {
|
||||||
|
const response = await api.delete(`/api/roles/${role._id}/${role._rev}`)
|
||||||
|
await store.actions.roles.fetch()
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
save: async role => {
|
||||||
|
const response = await api.post("/api/roles", role)
|
||||||
|
await store.actions.roles.fetch()
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return store
|
return store
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { cloneDeep } from "lodash/fp"
|
||||||
import {
|
import {
|
||||||
createProps,
|
createProps,
|
||||||
getBuiltin,
|
getBuiltin,
|
||||||
makePropsSafe,
|
|
||||||
} from "components/userInterface/assetParsing/createProps"
|
} from "components/userInterface/assetParsing/createProps"
|
||||||
import {
|
import {
|
||||||
allScreens,
|
allScreens,
|
||||||
|
@ -12,6 +11,7 @@ import {
|
||||||
currentAsset,
|
currentAsset,
|
||||||
mainLayout,
|
mainLayout,
|
||||||
selectedComponent,
|
selectedComponent,
|
||||||
|
selectedAccessRole,
|
||||||
} from "builderStore"
|
} from "builderStore"
|
||||||
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
|
@ -33,7 +33,8 @@ const INITIAL_FRONTEND_STATE = {
|
||||||
screens: [],
|
screens: [],
|
||||||
components: [],
|
components: [],
|
||||||
currentFrontEndType: "none",
|
currentFrontEndType: "none",
|
||||||
currentAssetId: "",
|
selectedScreenId: "",
|
||||||
|
selectedLayoutId: "",
|
||||||
selectedComponentId: "",
|
selectedComponentId: "",
|
||||||
errors: [],
|
errors: [],
|
||||||
hasAppPackage: false,
|
hasAppPackage: false,
|
||||||
|
@ -85,25 +86,31 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
screens: {
|
screens: {
|
||||||
select: async screenId => {
|
select: screenId => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const screen = get(allScreens).find(screen => screen._id === screenId)
|
let screens = get(allScreens)
|
||||||
|
let screen =
|
||||||
|
screens.find(screen => screen._id === screenId) || screens[0]
|
||||||
if (!screen) return state
|
if (!screen) return state
|
||||||
|
|
||||||
|
// Update role to the screen's role setting so that it will always
|
||||||
|
// be visible
|
||||||
|
selectedAccessRole.set(screen.routing.roleId)
|
||||||
|
|
||||||
state.currentFrontEndType = FrontendTypes.SCREEN
|
state.currentFrontEndType = FrontendTypes.SCREEN
|
||||||
state.currentAssetId = screenId
|
state.selectedScreenId = screen._id
|
||||||
state.currentView = "detail"
|
state.currentView = "detail"
|
||||||
state.selectedComponentId = screen.props?._id
|
state.selectedComponentId = screen.props?._id
|
||||||
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
create: async screen => {
|
create: async screen => {
|
||||||
screen = await store.actions.screens.save(screen)
|
screen = await store.actions.screens.save(screen)
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.currentAssetId = screen._id
|
state.selectedScreenId = screen._id
|
||||||
state.selectedComponentId = screen.props._id
|
state.selectedComponentId = screen.props._id
|
||||||
state.currentFrontEndType = FrontendTypes.SCREEN
|
state.currentFrontEndType = FrontendTypes.SCREEN
|
||||||
|
selectedAccessRole.set(screen.routing.roleId)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
return screen
|
return screen
|
||||||
|
@ -112,6 +119,7 @@ export const getFrontendStore = () => {
|
||||||
const creatingNewScreen = screen._id === undefined
|
const creatingNewScreen = screen._id === undefined
|
||||||
const response = await api.post(`/api/screens`, screen)
|
const response = await api.post(`/api/screens`, screen)
|
||||||
screen = await response.json()
|
screen = await response.json()
|
||||||
|
await store.actions.routing.fetch()
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const foundScreen = state.screens.findIndex(
|
const foundScreen = state.screens.findIndex(
|
||||||
|
@ -121,17 +129,13 @@ export const getFrontendStore = () => {
|
||||||
state.screens.splice(foundScreen, 1)
|
state.screens.splice(foundScreen, 1)
|
||||||
}
|
}
|
||||||
state.screens.push(screen)
|
state.screens.push(screen)
|
||||||
|
|
||||||
if (creatingNewScreen) {
|
|
||||||
const safeProps = makePropsSafe(
|
|
||||||
state.components[screen.props._component],
|
|
||||||
screen.props
|
|
||||||
)
|
|
||||||
state.selectedComponentId = safeProps._id
|
|
||||||
screen.props = safeProps
|
|
||||||
}
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (creatingNewScreen) {
|
||||||
|
store.actions.screens.select(screen._id)
|
||||||
|
}
|
||||||
|
|
||||||
return screen
|
return screen
|
||||||
},
|
},
|
||||||
delete: async screens => {
|
delete: async screens => {
|
||||||
|
@ -148,8 +152,8 @@ export const getFrontendStore = () => {
|
||||||
`/api/screens/${screenToDelete._id}/${screenToDelete._rev}`
|
`/api/screens/${screenToDelete._id}/${screenToDelete._rev}`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (screenToDelete._id === state.currentAssetId) {
|
if (screenToDelete._id === state.selectedScreenId) {
|
||||||
state.currentAssetId = ""
|
state.selectedScreenId = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
@ -172,39 +176,42 @@ export const getFrontendStore = () => {
|
||||||
layouts: {
|
layouts: {
|
||||||
select: layoutId => {
|
select: layoutId => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const layout = store.actions.layouts.find(layoutId)
|
const layout =
|
||||||
|
store.actions.layouts.find(layoutId) || get(store).layouts[0]
|
||||||
|
if (!layout) return
|
||||||
state.currentFrontEndType = FrontendTypes.LAYOUT
|
state.currentFrontEndType = FrontendTypes.LAYOUT
|
||||||
state.currentView = "detail"
|
state.currentView = "detail"
|
||||||
|
state.selectedLayoutId = layout._id
|
||||||
state.currentAssetId = layout._id
|
|
||||||
state.selectedComponentId = layout.props?._id
|
state.selectedComponentId = layout.props?._id
|
||||||
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
save: async layout => {
|
save: async layout => {
|
||||||
const layoutToSave = cloneDeep(layout)
|
const layoutToSave = cloneDeep(layout)
|
||||||
|
const creatingNewLayout = layoutToSave._id === undefined
|
||||||
const response = await api.post(`/api/layouts`, layoutToSave)
|
const response = await api.post(`/api/layouts`, layoutToSave)
|
||||||
|
const savedLayout = await response.json()
|
||||||
const json = await response.json()
|
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const layoutIdx = state.layouts.findIndex(
|
const layoutIdx = state.layouts.findIndex(
|
||||||
stateLayout => stateLayout._id === json._id
|
stateLayout => stateLayout._id === savedLayout._id
|
||||||
)
|
)
|
||||||
|
|
||||||
if (layoutIdx >= 0) {
|
if (layoutIdx >= 0) {
|
||||||
// update existing layout
|
// update existing layout
|
||||||
state.layouts.splice(layoutIdx, 1, json)
|
state.layouts.splice(layoutIdx, 1, savedLayout)
|
||||||
} else {
|
} else {
|
||||||
// save new layout
|
// save new layout
|
||||||
state.layouts.push(json)
|
state.layouts.push(savedLayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.currentAssetId = json._id
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Select layout if creating a new one
|
||||||
|
if (creatingNewLayout) {
|
||||||
|
store.actions.layouts.select(savedLayout._id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return savedLayout
|
||||||
},
|
},
|
||||||
find: layoutId => {
|
find: layoutId => {
|
||||||
if (!layoutId) {
|
if (!layoutId) {
|
||||||
|
@ -217,16 +224,17 @@ export const getFrontendStore = () => {
|
||||||
const response = await api.delete(
|
const response = await api.delete(
|
||||||
`/api/layouts/${layoutToDelete._id}/${layoutToDelete._rev}`
|
`/api/layouts/${layoutToDelete._id}/${layoutToDelete._rev}`
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
throw new Error(json.message)
|
throw new Error(json.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.layouts = state.layouts.filter(
|
state.layouts = state.layouts.filter(
|
||||||
layout => layout._id !== layoutToDelete._id
|
layout => layout._id !== layoutToDelete._id
|
||||||
)
|
)
|
||||||
|
if (layoutToDelete._id === state.selectedLayoutId) {
|
||||||
|
state.selectedLayoutId = get(mainLayout)._id
|
||||||
|
}
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -455,7 +463,6 @@ export const getFrontendStore = () => {
|
||||||
|
|
||||||
// Save layout
|
// Save layout
|
||||||
nav._children = [...nav._children, newLink]
|
nav._children = [...nav._children, newLink]
|
||||||
state.currentAssetId = layout._id
|
|
||||||
promises.push(store.actions.layouts.save(layout))
|
promises.push(store.actions.layouts.save(layout))
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
<CreateColumnButton />
|
<CreateColumnButton />
|
||||||
{#if schema && Object.keys(schema).length > 0}
|
{#if schema && Object.keys(schema).length > 0}
|
||||||
<CreateRowButton
|
<CreateRowButton
|
||||||
|
title={isUsersTable ? 'Create New User' : 'Create New Row'}
|
||||||
modalContentComponent={isUsersTable ? CreateEditUser : CreateEditRow} />
|
modalContentComponent={isUsersTable ? CreateEditUser : CreateEditRow} />
|
||||||
<CreateViewButton />
|
<CreateViewButton />
|
||||||
<ExportButton view={tableView} />
|
<ExportButton view={tableView} />
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
if (!allowEditing) {
|
if (!allowEditing) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return !(isUsersTable && ["email", "roleId"].indexOf(key) !== -1)
|
return !(isUsersTable && ["email", "roleId"].includes(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.entries(schema || {}).forEach(([key, value]) => {
|
Object.entries(schema || {}).forEach(([key, value]) => {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import CreateEditRow from "../modals/CreateEditRow.svelte"
|
import CreateEditRow from "../modals/CreateEditRow.svelte"
|
||||||
|
|
||||||
export let modalContentComponent = CreateEditRow
|
export let modalContentComponent = CreateEditRow
|
||||||
|
export let title = "Create New Row"
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
</script>
|
</script>
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
<div>
|
<div>
|
||||||
<Button text small on:click={modal.show}>
|
<Button text small on:click={modal.show}>
|
||||||
<Icon name="addrow" />
|
<Icon name="addrow" />
|
||||||
Create New Row
|
{title}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
|
|
|
@ -1,42 +1,10 @@
|
||||||
<!-- Module scoped cache of saved role options -->
|
|
||||||
<script context="module">
|
|
||||||
import builderApi from "builderStore/api"
|
|
||||||
|
|
||||||
let cachedRoles
|
|
||||||
|
|
||||||
async function getRoles(force = false) {
|
|
||||||
if (cachedRoles && !force) {
|
|
||||||
return await cachedRoles
|
|
||||||
}
|
|
||||||
cachedRoles = new Promise(resolve => {
|
|
||||||
builderApi
|
|
||||||
.get("/api/roles")
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(resolve)
|
|
||||||
})
|
|
||||||
return await cachedRoles
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
export let roleId
|
export let roleId
|
||||||
|
|
||||||
let roleName
|
$: role = $backendUiStore.roles.find(role => role._id === roleId)
|
||||||
$: getRole()
|
$: roleName = role?.name ?? "Unknown role"
|
||||||
|
|
||||||
async function getRole() {
|
|
||||||
// Try to find a matching role
|
|
||||||
let roles = await getRoles()
|
|
||||||
let role = roles.find(role => role._id === roleId)
|
|
||||||
|
|
||||||
// If we didn't find a matching role, try updating the cached results
|
|
||||||
if (!role) {
|
|
||||||
let roles = await getRoles(true)
|
|
||||||
let role = roles.find(role => role._id === roleId)
|
|
||||||
}
|
|
||||||
role = roles.find(role => role._id === roleId)
|
|
||||||
roleName = role?.name ?? "Unknown role"
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>{roleName}</div>
|
<div>{roleName}</div>
|
||||||
|
|
|
@ -45,3 +45,9 @@
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import RowFieldControl from "../RowFieldControl.svelte"
|
import RowFieldControl from "../RowFieldControl.svelte"
|
||||||
import * as backendApi from "../api"
|
import * as backendApi from "../api"
|
||||||
import builderApi from "builderStore/api"
|
|
||||||
import { ModalContent, Select } from "@budibase/bbui"
|
import { ModalContent, Select } from "@budibase/bbui"
|
||||||
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
||||||
|
|
||||||
export let row = {}
|
export let row = {}
|
||||||
|
|
||||||
let errors = []
|
let errors = []
|
||||||
let roles = []
|
|
||||||
let rolesLoaded = false
|
|
||||||
|
|
||||||
$: creating = row?._id == null
|
$: creating = row?._id == null
|
||||||
$: table = row.tableId
|
$: table = row.tableId
|
||||||
|
@ -56,14 +52,6 @@
|
||||||
notifier.success("User saved successfully.")
|
notifier.success("User saved successfully.")
|
||||||
backendUiStore.actions.rows.save(rowResponse)
|
backendUiStore.actions.rows.save(rowResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchRoles = async () => {
|
|
||||||
const rolesResponse = await builderApi.get("/api/roles")
|
|
||||||
roles = await rolesResponse.json()
|
|
||||||
rolesLoaded = true
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(fetchRoles)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ModalContent
|
<ModalContent
|
||||||
|
@ -80,7 +68,6 @@
|
||||||
bind:value={row.password} />
|
bind:value={row.password} />
|
||||||
<!-- Defer rendering this select until roles load, otherwise the initial
|
<!-- Defer rendering this select until roles load, otherwise the initial
|
||||||
selection is always undefined -->
|
selection is always undefined -->
|
||||||
{#if rolesLoaded}
|
|
||||||
<Select
|
<Select
|
||||||
thin
|
thin
|
||||||
secondary
|
secondary
|
||||||
|
@ -88,11 +75,10 @@
|
||||||
data-cy="roleId-select"
|
data-cy="roleId-select"
|
||||||
bind:value={row.roleId}>
|
bind:value={row.roleId}>
|
||||||
<option value="">Choose an option</option>
|
<option value="">Choose an option</option>
|
||||||
{#each roles as role}
|
{#each $backendUiStore.roles as role}
|
||||||
<option value={role._id}>{role.name}</option>
|
<option value={role._id}>{role.name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</Select>
|
||||||
{/if}
|
|
||||||
{#each customSchemaKeys as [key, meta]}
|
{#each customSchemaKeys as [key, meta]}
|
||||||
<RowFieldControl {meta} bind:value={row[key]} {creating} />
|
<RowFieldControl {meta} bind:value={row[key]} {creating} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -4,27 +4,26 @@
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
let roles = []
|
|
||||||
let permissions = []
|
let permissions = []
|
||||||
let selectedRole = {}
|
let selectedRole = {}
|
||||||
let errors = []
|
let errors = []
|
||||||
$: selectedRoleId = selectedRole._id
|
$: selectedRoleId = selectedRole._id
|
||||||
$: otherRoles = roles.filter(role => role._id !== selectedRoleId)
|
$: otherRoles = $backendUiStore.roles.filter(
|
||||||
|
role => role._id !== selectedRoleId
|
||||||
|
)
|
||||||
$: isCreating = selectedRoleId == null || selectedRoleId === ""
|
$: isCreating = selectedRoleId == null || selectedRoleId === ""
|
||||||
|
|
||||||
// Loads available roles and permissions from the server
|
const fetchPermissions = async () => {
|
||||||
const fetchRoles = async () => {
|
|
||||||
const rolesResponse = await api.get("/api/roles")
|
|
||||||
roles = await rolesResponse.json()
|
|
||||||
const permissionsResponse = await api.get("/api/permissions")
|
const permissionsResponse = await api.get("/api/permissions")
|
||||||
permissions = await permissionsResponse.json()
|
permissions = await permissionsResponse.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes the seleced role
|
// Changes the selected role
|
||||||
const changeRole = event => {
|
const changeRole = event => {
|
||||||
const id = event?.target?.value
|
const id = event?.target?.value
|
||||||
const role = roles.find(role => role._id === id)
|
const role = $backendUiStore.roles.find(role => role._id === id)
|
||||||
if (role) {
|
if (role) {
|
||||||
selectedRole = {
|
selectedRole = {
|
||||||
...role,
|
...role,
|
||||||
|
@ -61,7 +60,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save/create the role
|
// Save/create the role
|
||||||
const response = await api.post("/api/roles", selectedRole)
|
const response = await backendUiStore.actions.roles.save(selectedRole)
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
notifier.success("Role saved successfully.")
|
notifier.success("Role saved successfully.")
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,11 +71,8 @@
|
||||||
|
|
||||||
// Deletes the selected role
|
// Deletes the selected role
|
||||||
const deleteRole = async () => {
|
const deleteRole = async () => {
|
||||||
const response = await api.delete(
|
const response = await backendUiStore.actions.roles.delete(selectedRole)
|
||||||
`/api/roles/${selectedRole._id}/${selectedRole._rev}`
|
|
||||||
)
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
await fetchRoles()
|
|
||||||
changeRole()
|
changeRole()
|
||||||
notifier.success("Role deleted successfully.")
|
notifier.success("Role deleted successfully.")
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,7 +80,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(fetchRoles)
|
onMount(fetchPermissions)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ModalContent
|
<ModalContent
|
||||||
|
@ -101,7 +97,7 @@
|
||||||
value={selectedRoleId}
|
value={selectedRoleId}
|
||||||
on:change={changeRole}>
|
on:change={changeRole}>
|
||||||
<option value="">Create new role</option>
|
<option value="">Create new role</option>
|
||||||
{#each roles as role}
|
{#each $backendUiStore.roles as role}
|
||||||
<option value={role._id}>{role.name}</option>
|
<option value={role._id}>{role.name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
files = fileArray
|
files = fileArray
|
||||||
validateCSV()
|
validateCSV()
|
||||||
})
|
})
|
||||||
reader.readAsBinaryString(fileArray[0])
|
reader.readAsText(fileArray[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
async function omitColumn(columnName) {
|
async function omitColumn(columnName) {
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
}
|
}
|
||||||
.nav-item:hover,
|
.nav-item:hover,
|
||||||
.nav-item.selected {
|
.nav-item.selected {
|
||||||
border-radius: var(--border-radius-m);
|
border-radius: var(--border-radius-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
|
|
||||||
async function updateApplication(data) {
|
async function updateApplication(data) {
|
||||||
const response = await api.put(`/api/${$store.appId}`, data)
|
const response = await api.put(`/api/applications/${$store.appId}`, data)
|
||||||
const app = await response.json()
|
const app = await response.json()
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state = {
|
state = {
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
.component-container iframe {
|
.component-container iframe {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAssetId } from "builderStore"
|
||||||
import { getComponentDefinition } from "builderStore/storeUtils"
|
import { getComponentDefinition } from "builderStore/storeUtils"
|
||||||
import { DropEffect, DropPosition } from "./dragDropStore"
|
import { DropEffect, DropPosition } from "./dragDropStore"
|
||||||
import ComponentDropdownMenu from "../ComponentDropdownMenu.svelte"
|
import ComponentDropdownMenu from "../ComponentDropdownMenu.svelte"
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
const path = store.actions.components.findRoute(component)
|
const path = store.actions.components.findRoute(component)
|
||||||
|
|
||||||
// Go to correct URL
|
// Go to correct URL
|
||||||
$goto(`./${$store.currentAssetId}/${path}`)
|
$goto(`./${$currentAssetId}/${path}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragstart = component => e => {
|
const dragstart = component => e => {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script>
|
<script>
|
||||||
import { writable } from "svelte/store"
|
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, selectedComponent, currentAsset } from "builderStore"
|
import { store, selectedComponent, currentAsset } from "builderStore"
|
||||||
import instantiateStore from "./dragDropStore"
|
import instantiateStore from "./dragDropStore"
|
||||||
|
@ -20,6 +19,7 @@
|
||||||
export let route
|
export let route
|
||||||
export let path
|
export let path
|
||||||
export let indent
|
export let indent
|
||||||
|
export let border
|
||||||
|
|
||||||
$: selectedScreen = $currentAsset
|
$: selectedScreen = $currentAsset
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
icon="ri-folder-line"
|
icon="ri-folder-line"
|
||||||
text={path}
|
text={path}
|
||||||
opened={true}
|
opened={true}
|
||||||
|
{border}
|
||||||
withArrow={route.subpaths} />
|
withArrow={route.subpaths} />
|
||||||
|
|
||||||
{#each Object.entries(route.subpaths) as [url, subpath]}
|
{#each Object.entries(route.subpaths) as [url, subpath]}
|
||||||
|
@ -41,8 +42,8 @@
|
||||||
<NavItem
|
<NavItem
|
||||||
icon="ri-artboard-2-line"
|
icon="ri-artboard-2-line"
|
||||||
indentLevel={indent || 1}
|
indentLevel={indent || 1}
|
||||||
selected={$store.currentAssetId === screenId}
|
selected={$store.selectedScreenId === screenId}
|
||||||
opened={$store.currentAssetId === screenId}
|
opened={$store.selectedScreenId === screenId}
|
||||||
text={ROUTE_NAME_MAP[url]?.[role] || url}
|
text={ROUTE_NAME_MAP[url]?.[role] || url}
|
||||||
withArrow={route.subpaths}
|
withArrow={route.subpaths}
|
||||||
on:click={() => changeScreen(screenId)}>
|
on:click={() => changeScreen(screenId)}>
|
||||||
|
|
|
@ -1,12 +1,76 @@
|
||||||
<script>
|
<script>
|
||||||
import { store } from "builderStore"
|
import { store, selectedAccessRole } from "builderStore"
|
||||||
import PathTree from "./PathTree.svelte"
|
import PathTree from "./PathTree.svelte"
|
||||||
|
|
||||||
$: paths = Object.keys($store.routes || {}).sort()
|
let routes = {}
|
||||||
|
$: paths = Object.keys(routes || {}).sort()
|
||||||
|
|
||||||
|
$: {
|
||||||
|
const allRoutes = $store.routes
|
||||||
|
const sortedPaths = Object.keys(allRoutes || {}).sort()
|
||||||
|
const selectedRoleId = $selectedAccessRole
|
||||||
|
const selectedScreenId = $store.selectedScreenId
|
||||||
|
|
||||||
|
let found = false
|
||||||
|
let firstValidScreenId
|
||||||
|
let filteredRoutes = {}
|
||||||
|
let screenRoleId
|
||||||
|
|
||||||
|
// Filter all routes down to only those which match the current role
|
||||||
|
sortedPaths.forEach(path => {
|
||||||
|
const config = allRoutes[path]
|
||||||
|
Object.entries(config.subpaths).forEach(([subpath, pathConfig]) => {
|
||||||
|
Object.entries(pathConfig.screens).forEach(([roleId, screenId]) => {
|
||||||
|
if (screenId === selectedScreenId) {
|
||||||
|
screenRoleId = roleId
|
||||||
|
found = roleId === selectedRoleId
|
||||||
|
}
|
||||||
|
if (roleId === selectedRoleId) {
|
||||||
|
if (!firstValidScreenId) {
|
||||||
|
firstValidScreenId = screenId
|
||||||
|
}
|
||||||
|
if (!filteredRoutes[path]) {
|
||||||
|
filteredRoutes[path] = { subpaths: {} }
|
||||||
|
}
|
||||||
|
filteredRoutes[path].subpaths[subpath] = {
|
||||||
|
screens: {
|
||||||
|
[selectedRoleId]: screenId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
routes = filteredRoutes
|
||||||
|
|
||||||
|
// Select the correct role for the current screen ID
|
||||||
|
if (!found && screenRoleId) {
|
||||||
|
selectedAccessRole.set(screenRoleId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the selected screen isn't in this filtered list, select the first one
|
||||||
|
else if (!found && firstValidScreenId) {
|
||||||
|
store.actions.screens.select(firstValidScreenId)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
{#each paths as path}
|
{#each paths as path, idx}
|
||||||
<PathTree {path} route={$store.routes[path]} />
|
<PathTree border={idx > 0} {path} route={routes[path]} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
{#if !paths.length}
|
||||||
|
<div class="empty">
|
||||||
|
There aren't any screens configured with this access role.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.empty {
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
color: var(--grey-5);
|
||||||
|
padding-top: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto, url } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, currentAssetName, selectedComponent } from "builderStore"
|
import {
|
||||||
|
store,
|
||||||
|
currentAssetName,
|
||||||
|
selectedComponent,
|
||||||
|
currentAssetId,
|
||||||
|
} from "builderStore"
|
||||||
import components from "./temporaryPanelStructure.js"
|
import components from "./temporaryPanelStructure.js"
|
||||||
import { DropdownMenu } from "@budibase/bbui"
|
import { DropdownMenu } from "@budibase/bbui"
|
||||||
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
import { DropdownContainer, DropdownItem } from "components/common/Dropdowns"
|
||||||
|
@ -27,7 +32,7 @@
|
||||||
const onComponentChosen = component => {
|
const onComponentChosen = component => {
|
||||||
store.actions.components.create(component._component, component.presetProps)
|
store.actions.components.create(component._component, component.presetProps)
|
||||||
const path = store.actions.components.findRoute($selectedComponent)
|
const path = store.actions.components.findRoute($selectedComponent)
|
||||||
$goto(`./${$store.currentAssetId}/${path}`)
|
$goto(`./${$currentAssetId}/${path}`)
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { goto, params, url } from "@sveltech/routify"
|
import { goto, params, url } from "@sveltech/routify"
|
||||||
import { store, currentAsset, selectedComponent } from "builderStore"
|
import {
|
||||||
|
store,
|
||||||
|
allScreens,
|
||||||
|
currentAsset,
|
||||||
|
backendUiStore,
|
||||||
|
selectedAccessRole,
|
||||||
|
} from "builderStore"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import ComponentNavigationTree from "components/userInterface/ComponentNavigationTree/index.svelte"
|
import ComponentNavigationTree from "components/userInterface/ComponentNavigationTree/index.svelte"
|
||||||
import Layout from "components/userInterface/Layout.svelte"
|
import Layout from "components/userInterface/Layout.svelte"
|
||||||
import NewScreenModal from "components/userInterface/NewScreenModal.svelte"
|
import NewScreenModal from "components/userInterface/NewScreenModal.svelte"
|
||||||
import NewLayoutModal from "components/userInterface/NewLayoutModal.svelte"
|
import NewLayoutModal from "components/userInterface/NewLayoutModal.svelte"
|
||||||
import { Modal, Switcher } from "@budibase/bbui"
|
import { Modal, Switcher, Select } from "@budibase/bbui"
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
|
@ -24,11 +30,38 @@
|
||||||
let routes = {}
|
let routes = {}
|
||||||
let tab = $params.assetType
|
let tab = $params.assetType
|
||||||
|
|
||||||
function navigate({ detail }) {
|
const navigate = ({ detail }) => {
|
||||||
if (!detail) return
|
if (!detail) {
|
||||||
|
return
|
||||||
|
}
|
||||||
$goto(`../${detail.heading.key}`)
|
$goto(`../${detail.heading.key}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateAccessRole = event => {
|
||||||
|
const role = event.target.value
|
||||||
|
|
||||||
|
// Select a valid screen with this new role - otherwise we'll not be
|
||||||
|
// able to change role at all because ComponentNavigationTree will kick us
|
||||||
|
// back the current role again because the same screen ID is still selected
|
||||||
|
const firstValidScreenId = $allScreens.find(
|
||||||
|
screen => screen.routing.roleId === role
|
||||||
|
)?._id
|
||||||
|
if (firstValidScreenId) {
|
||||||
|
store.actions.screens.select(firstValidScreenId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise clear the selected screen ID so that the first new valid screen
|
||||||
|
// can be selected by ComponentNavigationTree
|
||||||
|
else {
|
||||||
|
store.update(state => {
|
||||||
|
state.selectedScreenId = null
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedAccessRole.set(role)
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
store.actions.routing.fetch()
|
store.actions.routing.fetch()
|
||||||
})
|
})
|
||||||
|
@ -41,11 +74,21 @@
|
||||||
on:click={modal.show}
|
on:click={modal.show}
|
||||||
data-cy="new-screen"
|
data-cy="new-screen"
|
||||||
class="ri-add-circle-fill" />
|
class="ri-add-circle-fill" />
|
||||||
{#if $currentAsset}
|
<div class="role-select">
|
||||||
|
<Select
|
||||||
|
extraThin
|
||||||
|
secondary
|
||||||
|
on:change={updateAccessRole}
|
||||||
|
value={$selectedAccessRole}
|
||||||
|
label="Filter by Access">
|
||||||
|
{#each $backendUiStore.roles as role}
|
||||||
|
<option value={role._id}>{role.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
<div class="nav-items-container">
|
<div class="nav-items-container">
|
||||||
<ComponentNavigationTree />
|
<ComponentNavigationTree />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<NewScreenModal />
|
<NewScreenModal />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -54,8 +97,8 @@
|
||||||
on:click={modal.show}
|
on:click={modal.show}
|
||||||
data-cy="new-layout"
|
data-cy="new-layout"
|
||||||
class="ri-add-circle-fill" />
|
class="ri-add-circle-fill" />
|
||||||
{#each $store.layouts as layout (layout._id)}
|
{#each $store.layouts as layout, idx (layout._id)}
|
||||||
<Layout {layout} />
|
<Layout {layout} border={idx > 0} />
|
||||||
{/each}
|
{/each}
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<NewLayoutModal />
|
<NewLayoutModal />
|
||||||
|
@ -82,4 +125,8 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.role-select {
|
||||||
|
margin-bottom: var(--spacing-m);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
export let layout
|
export let layout
|
||||||
|
export let border
|
||||||
|
|
||||||
let confirmDeleteDialog
|
let confirmDeleteDialog
|
||||||
let componentToDelete = ""
|
let componentToDelete = ""
|
||||||
|
@ -23,17 +24,17 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<NavItem
|
<NavItem
|
||||||
border={false}
|
{border}
|
||||||
icon="ri-layout-3-line"
|
icon="ri-layout-3-line"
|
||||||
text={layout.name}
|
text={layout.name}
|
||||||
withArrow
|
withArrow
|
||||||
selected={$store.currentAssetId === layout._id}
|
selected={$store.selectedLayoutId === layout._id}
|
||||||
opened={$store.currentAssetId === layout._id}
|
opened={$store.selectedLayoutId === layout._id}
|
||||||
on:click={selectLayout}>
|
on:click={selectLayout}>
|
||||||
<LayoutDropdownMenu {layout} />
|
<LayoutDropdownMenu {layout} />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
|
|
||||||
{#if $store.currentAssetId === layout._id && layout.props?._children}
|
{#if $store.selectedLayoutId === layout._id && layout.props?._children}
|
||||||
<ComponentTree
|
<ComponentTree
|
||||||
components={layout.props._children}
|
components={layout.props._children}
|
||||||
currentComponent={$selectedComponent}
|
currentComponent={$selectedComponent}
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import api from "builderStore/api"
|
|
||||||
import { notifier } from "builderStore/store/notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import { store, backendUiStore, allScreens } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { Input, ModalContent } from "@budibase/bbui"
|
import { Input, ModalContent } from "@budibase/bbui"
|
||||||
import analytics from "analytics"
|
|
||||||
|
|
||||||
const CONTAINER = "@budibase/standard-components/container"
|
|
||||||
|
|
||||||
let name = ""
|
let name = ""
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
try {
|
try {
|
||||||
await store.actions.layouts.save({ name })
|
const layout = await store.actions.layouts.save({ name })
|
||||||
$goto(`./${$store.currentAssetId}`)
|
$goto(`./${layout._id}`)
|
||||||
notifier.success(`Layout ${name} created successfully`)
|
notifier.success(`Layout ${name} created successfully`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifier.danger(`Error creating layout ${name}.`)
|
notifier.danger(`Error creating layout ${name}.`)
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, backendUiStore, allScreens } from "builderStore"
|
import { store, backendUiStore, allScreens } from "builderStore"
|
||||||
import {
|
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
|
||||||
Input,
|
|
||||||
Button,
|
|
||||||
Spacer,
|
|
||||||
Select,
|
|
||||||
ModalContent,
|
|
||||||
Toggle,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import getTemplates from "builderStore/store/screenTemplates"
|
import getTemplates from "builderStore/store/screenTemplates"
|
||||||
import { some } from "lodash/fp"
|
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
const CONTAINER = "@budibase/standard-components/container"
|
const CONTAINER = "@budibase/standard-components/container"
|
||||||
|
|
||||||
|
@ -21,15 +15,13 @@
|
||||||
let templateIndex
|
let templateIndex
|
||||||
let draftScreen
|
let draftScreen
|
||||||
let createLink = true
|
let createLink = true
|
||||||
|
let roleId = "BASIC"
|
||||||
|
|
||||||
$: templates = getTemplates($store, $backendUiStore.tables)
|
$: templates = getTemplates($store, $backendUiStore.tables)
|
||||||
|
|
||||||
$: route = !route && $allScreens.length === 0 ? "*" : route
|
$: route = !route && $allScreens.length === 0 ? "*" : route
|
||||||
|
|
||||||
$: baseComponents = Object.values($store.components)
|
$: baseComponents = Object.values($store.components)
|
||||||
.filter(componentDefinition => componentDefinition.baseComponent)
|
.filter(componentDefinition => componentDefinition.baseComponent)
|
||||||
.map(c => c._component)
|
.map(c => c._component)
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (templates && templateIndex === undefined) {
|
if (templates && templateIndex === undefined) {
|
||||||
templateIndex = 0
|
templateIndex = 0
|
||||||
|
@ -56,10 +48,10 @@
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
if (!route) {
|
if (!route) {
|
||||||
routeError = "Url is required"
|
routeError = "URL is required"
|
||||||
} else {
|
} else {
|
||||||
if (routeNameExists(route)) {
|
if (routeExists(route, roleId)) {
|
||||||
routeError = "This url is already taken"
|
routeError = "This URL is already taken for this access role"
|
||||||
} else {
|
} else {
|
||||||
routeError = ""
|
routeError = ""
|
||||||
}
|
}
|
||||||
|
@ -69,8 +61,7 @@
|
||||||
|
|
||||||
draftScreen.props._instanceName = name
|
draftScreen.props._instanceName = name
|
||||||
draftScreen.props._component = baseComponent
|
draftScreen.props._component = baseComponent
|
||||||
// TODO: need to fix this up correctly
|
draftScreen.routing = { route, roleId }
|
||||||
draftScreen.routing = { route, roleId: "ADMIN" }
|
|
||||||
|
|
||||||
const createdScreen = await store.actions.screens.create(draftScreen)
|
const createdScreen = await store.actions.screens.create(draftScreen)
|
||||||
if (createLink) {
|
if (createLink) {
|
||||||
|
@ -85,12 +76,14 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$goto(`./screen/${createdScreen._id}`)
|
$goto(`./${createdScreen._id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const routeNameExists = route => {
|
const routeExists = (route, roleId) => {
|
||||||
return $allScreens.some(
|
return $allScreens.some(
|
||||||
screen => screen.routing.route.toLowerCase() === route.toLowerCase()
|
screen =>
|
||||||
|
screen.routing.route.toLowerCase() === route.toLowerCase() &&
|
||||||
|
screen.routing.roleId === roleId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,14 +106,16 @@
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<Input label="Name" bind:value={name} />
|
<Input label="Name" bind:value={name} />
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
label="Url"
|
label="Url"
|
||||||
error={routeError}
|
error={routeError}
|
||||||
bind:value={route}
|
bind:value={route}
|
||||||
on:change={routeChanged} />
|
on:change={routeChanged} />
|
||||||
|
<Select label="Access" bind:value={roleId} secondary>
|
||||||
|
{#each $backendUiStore.roles as role}
|
||||||
|
<option value={role._id}>{role.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
<Toggle text="Create link in navigation bar" bind:checked={createLink} />
|
<Toggle text="Create link in navigation bar" bind:checked={createLink} />
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script>
|
||||||
|
import { Select } from "@budibase/bbui"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
|
||||||
|
let roles = []
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Select bind:value extraThin secondary on:change>
|
||||||
|
<option value="">Choose an option</option>
|
||||||
|
{#each $backendUiStore.roles as role}
|
||||||
|
<option value={role._id}>{role.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
|
@ -4,6 +4,7 @@
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import PropertyControl from "./PropertyControl.svelte"
|
import PropertyControl from "./PropertyControl.svelte"
|
||||||
import LayoutSelect from "./LayoutSelect.svelte"
|
import LayoutSelect from "./LayoutSelect.svelte"
|
||||||
|
import RoleSelect from "./RoleSelect.svelte"
|
||||||
import Input from "./PropertyPanelControls/Input.svelte"
|
import Input from "./PropertyPanelControls/Input.svelte"
|
||||||
import { excludeProps } from "./propertyCategories.js"
|
import { excludeProps } from "./propertyCategories.js"
|
||||||
import { store, allScreens, currentAsset } from "builderStore"
|
import { store, allScreens, currentAsset } from "builderStore"
|
||||||
|
@ -36,8 +37,8 @@
|
||||||
const screenDefinition = [
|
const screenDefinition = [
|
||||||
{ key: "description", label: "Description", control: Input },
|
{ key: "description", label: "Description", control: Input },
|
||||||
{ key: "routing.route", label: "Route", control: Input },
|
{ key: "routing.route", label: "Route", control: Input },
|
||||||
|
{ key: "routing.roleId", label: "Access", control: RoleSelect },
|
||||||
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
||||||
{ key: "routing.roleId", label: "Role", control: Input },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const layoutDefinition = [{ key: "title", label: "Title", control: Input }]
|
const layoutDefinition = [{ key: "title", label: "Title", control: Input }]
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
backendUiStore.actions.reset()
|
backendUiStore.actions.reset()
|
||||||
await store.actions.initialise(pkg)
|
await store.actions.initialise(pkg)
|
||||||
await automationStore.actions.fetch()
|
await automationStore.actions.fetch()
|
||||||
|
await backendUiStore.actions.roles.fetch()
|
||||||
return pkg
|
return pkg
|
||||||
} else {
|
} else {
|
||||||
throw new Error(pkg)
|
throw new Error(pkg)
|
||||||
|
@ -217,5 +218,6 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: var(--spacing-m);
|
bottom: var(--spacing-m);
|
||||||
left: var(--spacing-m);
|
left: var(--spacing-m);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -26,11 +26,12 @@
|
||||||
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
|
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
|
||||||
if ($leftover) {
|
if ($leftover) {
|
||||||
// Get the correct screen children.
|
// Get the correct screen children.
|
||||||
const assetChildren = assetList.find(
|
const assetChildren =
|
||||||
|
assetList.find(
|
||||||
asset =>
|
asset =>
|
||||||
asset._id === $params.asset ||
|
asset._id === $params.asset ||
|
||||||
asset._id === decodeURIComponent($params.asset)
|
asset._id === decodeURIComponent($params.asset)
|
||||||
).props._children
|
)?.props._children ?? []
|
||||||
findComponent(componentIds, assetChildren)
|
findComponent(componentIds, assetChildren)
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import CurrentItemPreview from "components/userInterface/AppPreview"
|
import CurrentItemPreview from "components/userInterface/AppPreview"
|
||||||
import ComponentPropertiesPanel from "components/userInterface/ComponentPropertiesPanel.svelte"
|
import ComponentPropertiesPanel from "components/userInterface/ComponentPropertiesPanel.svelte"
|
||||||
import ComponentSelectionList from "components/userInterface/ComponentSelectionList.svelte"
|
import ComponentSelectionList from "components/userInterface/ComponentSelectionList.svelte"
|
||||||
import { last } from "lodash/fp"
|
|
||||||
import FrontendNavigatePane from "components/userInterface/FrontendNavigatePane.svelte"
|
import FrontendNavigatePane from "components/userInterface/FrontendNavigatePane.svelte"
|
||||||
|
|
||||||
$: instance = $store.appInstance
|
$: instance = $store.appInstance
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="preview-pane">
|
<div class="preview-pane">
|
||||||
{#if $store.currentAssetId && $store.currentAssetId.length > 0}
|
{#if $currentAsset}
|
||||||
<ComponentSelectionList />
|
<ComponentSelectionList />
|
||||||
<div class="preview-content">
|
<div class="preview-content">
|
||||||
<CurrentItemPreview />
|
<CurrentItemPreview />
|
||||||
|
|
|
@ -5,12 +5,32 @@
|
||||||
|
|
||||||
// Go to first layout
|
// Go to first layout
|
||||||
if ($params.assetType === FrontendTypes.LAYOUT) {
|
if ($params.assetType === FrontendTypes.LAYOUT) {
|
||||||
$goto(`../${$store.layouts[0]?._id}`)
|
// Try to use previously selected layout first
|
||||||
|
let id
|
||||||
|
if (
|
||||||
|
$store.selectedLayoutId &&
|
||||||
|
$store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
||||||
|
) {
|
||||||
|
id = $store.selectedLayoutId
|
||||||
|
} else {
|
||||||
|
id = $store.layouts[0]?._id
|
||||||
|
}
|
||||||
|
$goto(`../${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go to first screen
|
// Go to first screen
|
||||||
if ($params.assetType === FrontendTypes.SCREEN) {
|
if ($params.assetType === FrontendTypes.SCREEN) {
|
||||||
$goto(`../${$allScreens[0]?._id}`)
|
// Try to use previously selected layout first
|
||||||
|
let id
|
||||||
|
if (
|
||||||
|
$store.selectedScreenId &&
|
||||||
|
$allScreens.find(screen => screen._id === $store.selectedScreenId)
|
||||||
|
) {
|
||||||
|
id = $store.selectedScreenId
|
||||||
|
} else {
|
||||||
|
id = $allScreens[0]?._id
|
||||||
|
}
|
||||||
|
$goto(`../${id}`)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -842,10 +842,10 @@
|
||||||
lodash "^4.17.19"
|
lodash "^4.17.19"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@budibase/bbui@^1.52.2":
|
"@budibase/bbui@^1.52.4":
|
||||||
version "1.52.2"
|
version "1.52.4"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.52.2.tgz#a0774880fb755eb81c762bc355550af7f4562b09"
|
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.52.4.tgz#ae3c17e1f49f14e65831703958bcddc6e64afd24"
|
||||||
integrity sha512-PxiN5xvr+Z/RpypMDYh3lNhCUnejH1moMoWW7PiuCiho5VXGauR+M8T49p5eTKoFSqRMC7BUdFJJ9ye/cnQxNA==
|
integrity sha512-/wiv5dSyvXLgy2/zGEslnCsjwE8qqng1D8k5ScSOPEyMab8tzzd1XxfZAN9rp84zIMgAXeH6s5a4j4riR+jVkg==
|
||||||
dependencies:
|
dependencies:
|
||||||
markdown-it "^12.0.2"
|
markdown-it "^12.0.2"
|
||||||
quill "^1.3.7"
|
quill "^1.3.7"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/client",
|
"name": "@budibase/client",
|
||||||
"version": "0.3.8",
|
"version": "0.4.2",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"main": "dist/budibase-client.js",
|
"main": "dist/budibase-client.js",
|
||||||
"module": "dist/budibase-client.js",
|
"module": "dist/budibase-client.js",
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
"svelte-spa-router": "^3.0.5"
|
"svelte-spa-router": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@budibase/standard-components": "^0.3.8",
|
"@budibase/standard-components": "^0.4.2",
|
||||||
"@rollup/plugin-commonjs": "^16.0.0",
|
"@rollup/plugin-commonjs": "^16.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^10.0.0",
|
"@rollup/plugin-node-resolve": "^10.0.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
|
@ -23,8 +23,8 @@
|
||||||
"rollup": "^2.33.2",
|
"rollup": "^2.33.2",
|
||||||
"rollup-plugin-node-builtins": "^2.1.2",
|
"rollup-plugin-node-builtins": "^2.1.2",
|
||||||
"rollup-plugin-node-globals": "^1.4.0",
|
"rollup-plugin-node-globals": "^1.4.0",
|
||||||
"rollup-plugin-svelte": "^6.1.1",
|
|
||||||
"rollup-plugin-node-resolve": "^5.2.0",
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
|
"rollup-plugin-svelte": "^6.1.1",
|
||||||
"rollup-plugin-terser": "^4.0.4",
|
"rollup-plugin-terser": "^4.0.4",
|
||||||
"svelte": "^3.30.0",
|
"svelte": "^3.30.0",
|
||||||
"svelte-jester": "^1.0.6"
|
"svelte-jester": "^1.0.6"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import { setContext, onMount } from "svelte"
|
import { setContext, onMount } from "svelte"
|
||||||
import Component from "./Component.svelte"
|
import Component from "./Component.svelte"
|
||||||
import SDK from "../sdk"
|
import SDK from "../sdk"
|
||||||
import { createDataStore, routeStore, screenStore } from "../store"
|
import { createDataStore, initialise, screenStore } from "../store"
|
||||||
|
|
||||||
// Provide contexts
|
// Provide contexts
|
||||||
setContext("sdk", SDK)
|
setContext("sdk", SDK)
|
||||||
|
@ -14,13 +14,11 @@
|
||||||
|
|
||||||
// Load app config
|
// Load app config
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await routeStore.actions.fetchRoutes()
|
await initialise()
|
||||||
await screenStore.actions.fetchScreens()
|
|
||||||
loaded = true
|
loaded = true
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loaded && $screenStore.activeLayout}
|
{#if loaded && $screenStore.activeLayout}
|
||||||
<!-- // TODO: need to get the active screen as well -->
|
|
||||||
<Component definition={$screenStore.activeLayout.props} />
|
<Component definition={$screenStore.activeLayout.props} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -7,7 +7,15 @@
|
||||||
const { styleable } = getContext("sdk")
|
const { styleable } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
|
||||||
$: routerConfig = getRouterConfig($routeStore.routes)
|
// Only wrap this as an array to take advantage of svelte keying,
|
||||||
|
// to ensure the svelte-spa-router is fully remounted when route config
|
||||||
|
// changes
|
||||||
|
$: configs = [
|
||||||
|
{
|
||||||
|
routes: getRouterConfig($routeStore.routes),
|
||||||
|
id: $routeStore.routeSessionId,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const getRouterConfig = routes => {
|
const getRouterConfig = routes => {
|
||||||
let config = {}
|
let config = {}
|
||||||
|
@ -25,11 +33,11 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if routerConfig}
|
{#each configs as config (config.id)}
|
||||||
<div use:styleable={$component.styles}>
|
<div use:styleable={$component.styles}>
|
||||||
<Router on:routeLoading={onRouteLoading} routes={routerConfig} />
|
<Router on:routeLoading={onRouteLoading} routes={config.routes} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/each}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
|
|
|
@ -1,18 +1,29 @@
|
||||||
import * as API from "../api"
|
import * as API from "../api"
|
||||||
import { getAppId } from "../utils/getAppId"
|
import { getAppId } from "../utils/getAppId"
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
|
import { initialise } from "./initialise"
|
||||||
|
import { routeStore } from "./routes"
|
||||||
|
|
||||||
const createAuthStore = () => {
|
const createAuthStore = () => {
|
||||||
const store = writable("")
|
const store = writable("")
|
||||||
|
|
||||||
|
const goToDefaultRoute = () => {
|
||||||
|
// Setting the active route forces an update of the active screen ID,
|
||||||
|
// even if we're on the same URL
|
||||||
|
routeStore.actions.setActiveRoute("/")
|
||||||
|
|
||||||
|
// Navigating updates the URL to reflect this route
|
||||||
|
routeStore.actions.navigate("/")
|
||||||
|
}
|
||||||
const logIn = async ({ email, password }) => {
|
const logIn = async ({ email, password }) => {
|
||||||
const user = await API.logIn({ email, password })
|
const user = await API.logIn({ email, password })
|
||||||
if (!user.error) {
|
if (!user.error) {
|
||||||
store.set(user.token)
|
store.set(user.token)
|
||||||
location.reload()
|
await initialise()
|
||||||
|
goToDefaultRoute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const logOut = () => {
|
const logOut = async () => {
|
||||||
store.set("")
|
store.set("")
|
||||||
const appId = getAppId()
|
const appId = getAppId()
|
||||||
if (appId) {
|
if (appId) {
|
||||||
|
@ -20,7 +31,8 @@ const createAuthStore = () => {
|
||||||
window.document.cookie = `budibase:${appId}:${environment}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`
|
window.document.cookie = `budibase:${appId}:${environment}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
location.reload()
|
await initialise()
|
||||||
|
goToDefaultRoute()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -6,3 +6,6 @@ export { bindingStore } from "./binding"
|
||||||
|
|
||||||
// Data stores are layered and duplicated, so it is not a singleton
|
// Data stores are layered and duplicated, so it is not a singleton
|
||||||
export { createDataStore, dataStore } from "./data"
|
export { createDataStore, dataStore } from "./data"
|
||||||
|
|
||||||
|
// Initialises an app by loading screens and routes
|
||||||
|
export { initialise } from "./initialise"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { routeStore } from "./routes"
|
||||||
|
import { screenStore } from "./screens"
|
||||||
|
|
||||||
|
export async function initialise() {
|
||||||
|
await routeStore.actions.fetchRoutes()
|
||||||
|
await screenStore.actions.fetchScreens()
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ const createRouteStore = () => {
|
||||||
routes: [],
|
routes: [],
|
||||||
routeParams: {},
|
routeParams: {},
|
||||||
activeRoute: null,
|
activeRoute: null,
|
||||||
|
routeSessionId: Math.random(),
|
||||||
}
|
}
|
||||||
const store = writable(initialState)
|
const store = writable(initialState)
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ const createRouteStore = () => {
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.routes = routes
|
state.routes = routes
|
||||||
|
state.routeSessionId = Math.random()
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@budibase/server",
|
"name": "@budibase/server",
|
||||||
"email": "hi@budibase.com",
|
"email": "hi@budibase.com",
|
||||||
"version": "0.3.8",
|
"version": "0.4.2",
|
||||||
"description": "Budibase Web Server",
|
"description": "Budibase Web Server",
|
||||||
"main": "src/electron.js",
|
"main": "src/electron.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -21,7 +21,6 @@
|
||||||
"maintainer": "Budibase",
|
"maintainer": "Budibase",
|
||||||
"icon": "./build/icons/",
|
"icon": "./build/icons/",
|
||||||
"target": [
|
"target": [
|
||||||
"AppImage",
|
|
||||||
"deb"
|
"deb"
|
||||||
],
|
],
|
||||||
"category": "Development"
|
"category": "Development"
|
||||||
|
@ -49,7 +48,7 @@
|
||||||
"author": "Budibase",
|
"author": "Budibase",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/client": "^0.3.8",
|
"@budibase/client": "^0.4.2",
|
||||||
"@koa/router": "^8.0.0",
|
"@koa/router": "^8.0.0",
|
||||||
"@sendgrid/mail": "^7.1.1",
|
"@sendgrid/mail": "^7.1.1",
|
||||||
"@sentry/node": "^5.19.2",
|
"@sentry/node": "^5.19.2",
|
||||||
|
|
|
@ -5,7 +5,7 @@ Array [
|
||||||
Object {
|
Object {
|
||||||
"Address": "5 Sesame Street",
|
"Address": "5 Sesame Street",
|
||||||
"Age": 4324,
|
"Age": 4324,
|
||||||
"Name": "Bert",
|
"Name": "Bertå",
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"Address": "1 World Trade Center",
|
"Address": "1 World Trade Center",
|
||||||
|
|
|
@ -89,7 +89,7 @@ describe("CSV Parser", () => {
|
||||||
})
|
})
|
||||||
).toEqual([
|
).toEqual([
|
||||||
{
|
{
|
||||||
Name: "Bert",
|
Name: "Bertå",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Ernie",
|
Name: "Ernie",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"Name","Age","Address"
|
"Name","Age","Address"
|
||||||
"Bert","4324","5 Sesame Street"
|
"Bertå","4324","5 Sesame Street"
|
||||||
"Ernie","34","1 World Trade Center"
|
"Ernie","34","1 World Trade Center"
|
||||||
"Big Bird","23423","44 Second Avenue"
|
"Big Bird","23423","44 Second Avenue"
|
|
|
@ -29,11 +29,11 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"svelte"
|
"svelte"
|
||||||
],
|
],
|
||||||
"version": "0.3.8",
|
"version": "0.4.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
|
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^1.52.1",
|
"@budibase/bbui": "^1.52.4",
|
||||||
"@budibase/svelte-ag-grid": "^0.0.16",
|
"@budibase/svelte-ag-grid": "^0.0.16",
|
||||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||||
"apexcharts": "^3.22.1",
|
"apexcharts": "^3.22.1",
|
||||||
|
@ -41,8 +41,8 @@
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"markdown-it": "^12.0.2",
|
"markdown-it": "^12.0.2",
|
||||||
"quill": "^1.3.7",
|
"quill": "^1.3.7",
|
||||||
"turndown": "^7.0.0",
|
|
||||||
"svelte-apexcharts": "^1.0.2",
|
"svelte-apexcharts": "^1.0.2",
|
||||||
"svelte-flatpickr": "^3.1.0"
|
"svelte-flatpickr": "^3.1.0",
|
||||||
|
"turndown": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
$: target = openInNewTab ? "_blank" : "_self"
|
$: target = openInNewTab ? "_blank" : "_self"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a href={url} use:linkable {target} use:styleable={$component.styles}>
|
<a href={url || '/'} use:linkable {target} use:styleable={$component.styles}>
|
||||||
{text}
|
{text}
|
||||||
<slot />
|
<slot />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
export let logoUrl
|
export let logoUrl
|
||||||
|
|
||||||
const logOut = () => {
|
const logOut = async () => {
|
||||||
authStore.actions.logOut()
|
await authStore.actions.logOut()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
{#if options}
|
{#if options}
|
||||||
<div use:chart={options} use:styleable={$component.styles} />
|
<div use:chart={options} use:styleable={$component.styles} />
|
||||||
{:else if options === false}
|
{:else if options === false}
|
||||||
<div use:styleable={$component.styles}>Invalid chart options</div>
|
<div use:styleable={$component.styles}>
|
||||||
|
Use the settings panel to build your chart -->
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -39,10 +39,10 @@
|
||||||
lodash "^4.17.19"
|
lodash "^4.17.19"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@budibase/bbui@^1.52.1":
|
"@budibase/bbui@^1.52.4":
|
||||||
version "1.52.1"
|
version "1.52.4"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.52.1.tgz#7f1612616205debeac0c65242b4856cce07e4cd0"
|
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.52.4.tgz#ae3c17e1f49f14e65831703958bcddc6e64afd24"
|
||||||
integrity sha512-950HXR4Z8b0TgJH3Dt7gLgeHlgtBVMTtG+KkFTtID/zeiXohf60wr2cyAuttCZ3yb4rFRHC+SDXo2NOsKdenKw==
|
integrity sha512-/wiv5dSyvXLgy2/zGEslnCsjwE8qqng1D8k5ScSOPEyMab8tzzd1XxfZAN9rp84zIMgAXeH6s5a4j4riR+jVkg==
|
||||||
dependencies:
|
dependencies:
|
||||||
markdown-it "^12.0.2"
|
markdown-it "^12.0.2"
|
||||||
quill "^1.3.7"
|
quill "^1.3.7"
|
||||||
|
|
Loading…
Reference in New Issue