Merge branch 'develop' of github.com:Budibase/budibase into merge/master-develop-29-06-23
This commit is contained in:
commit
488e7b9502
|
@ -71,6 +71,7 @@
|
|||
timeOnly,
|
||||
enableTime,
|
||||
time24hr,
|
||||
disabled,
|
||||
}
|
||||
|
||||
const handleChange = event => {
|
||||
|
|
|
@ -155,6 +155,7 @@ export const getFrontendStore = () => {
|
|||
...INITIAL_FRONTEND_STATE.features,
|
||||
...application.features,
|
||||
},
|
||||
icon: application.icon || {},
|
||||
initialised: true,
|
||||
}))
|
||||
screenHistoryStore.reset()
|
||||
|
@ -235,6 +236,7 @@ export const getFrontendStore = () => {
|
|||
legalDirectChildren = []
|
||||
) => {
|
||||
const type = component._component
|
||||
|
||||
if (illegalChildren.includes(type)) {
|
||||
return type
|
||||
}
|
||||
|
@ -248,10 +250,13 @@ export const getFrontendStore = () => {
|
|||
return
|
||||
}
|
||||
|
||||
if (type === "@budibase/standard-components/sidepanel") {
|
||||
illegalChildren = []
|
||||
}
|
||||
|
||||
const definition = store.actions.components.getDefinition(
|
||||
component._component
|
||||
)
|
||||
|
||||
// Reset whitelist for direct children
|
||||
legalDirectChildren = []
|
||||
if (definition?.legalDirectChildren?.length) {
|
||||
|
|
|
@ -275,7 +275,7 @@
|
|||
}
|
||||
}}
|
||||
>
|
||||
{selectedApp ? `${selectedApp?.url}` : ""}
|
||||
{$store.url}
|
||||
{#if isPublished}
|
||||
<Icon size="S" name="LinkOut" />
|
||||
{:else}
|
||||
|
@ -344,7 +344,12 @@
|
|||
|
||||
<Modal bind:this={updateAppModal} padding={false} width="600px">
|
||||
<UpdateAppModal
|
||||
app={selectedApp}
|
||||
app={{
|
||||
name: $store.name,
|
||||
url: $store.url,
|
||||
icon: $store.icon,
|
||||
appId: $store.appId,
|
||||
}}
|
||||
onUpdateComplete={async () => {
|
||||
await initialiseApp()
|
||||
}}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
export let app
|
||||
export let onUpdateComplete
|
||||
|
||||
$: appIdParts = app.appId ? app.appId?.split("_") : []
|
||||
$: appId = appIdParts.slice(-1)[0]
|
||||
|
||||
const values = writable({
|
||||
name: app.name,
|
||||
url: app.url,
|
||||
|
@ -35,8 +38,20 @@
|
|||
|
||||
const setupValidation = async () => {
|
||||
const applications = svelteGet(apps)
|
||||
appValidation.name(validation, { apps: applications, currentApp: app })
|
||||
appValidation.url(validation, { apps: applications, currentApp: app })
|
||||
appValidation.name(validation, {
|
||||
apps: applications,
|
||||
currentApp: {
|
||||
...app,
|
||||
appId,
|
||||
},
|
||||
})
|
||||
appValidation.url(validation, {
|
||||
apps: applications,
|
||||
currentApp: {
|
||||
...app,
|
||||
appId,
|
||||
},
|
||||
})
|
||||
// init validation
|
||||
const { url } = $values
|
||||
validation.check({
|
||||
|
@ -47,7 +62,7 @@
|
|||
|
||||
async function updateApp() {
|
||||
try {
|
||||
await apps.update(app.instance._id, {
|
||||
await apps.update(app.appId, {
|
||||
name: $values.name?.trim(),
|
||||
url: $values.url?.trim(),
|
||||
icon: {
|
||||
|
|
|
@ -52,7 +52,13 @@ export const url = (validation, { apps, currentApp } = { apps: [] }) => {
|
|||
}
|
||||
return !apps
|
||||
.map(app => app.url)
|
||||
.some(appUrl => appUrl?.toLowerCase() === value.toLowerCase())
|
||||
.some(appUrl => {
|
||||
const url =
|
||||
appUrl?.[0] === "/"
|
||||
? appUrl.substring(1, appUrl.length)
|
||||
: appUrl
|
||||
return url?.toLowerCase() === value.toLowerCase()
|
||||
})
|
||||
}
|
||||
)
|
||||
.test("valid-url", "Not a valid URL", value => {
|
||||
|
|
|
@ -52,6 +52,9 @@
|
|||
// Build up list of illegal children from ancestors
|
||||
let illegalChildren = definition.illegalChildren || []
|
||||
path.forEach(ancestor => {
|
||||
if (ancestor._component === `@budibase/standard-components/sidepanel`) {
|
||||
illegalChildren = []
|
||||
}
|
||||
const def = store.actions.components.getDefinition(ancestor._component)
|
||||
const blacklist = def?.illegalChildren?.map(x => {
|
||||
return `@budibase/standard-components/${x}`
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
notifications.success("Copied")
|
||||
}}
|
||||
>
|
||||
Copy Code
|
||||
Copy code
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
|
|
|
@ -19,11 +19,10 @@
|
|||
|
||||
$: filteredApps = $apps.filter(app => app.devId == $store.appId)
|
||||
$: app = filteredApps.length ? filteredApps[0] : {}
|
||||
$: appUrl = `${window.origin}/app${app?.url}`
|
||||
$: appDeployed = app?.status === AppStatus.DEPLOYED
|
||||
|
||||
const initialiseApp = async () => {
|
||||
const applicationPkg = await API.fetchAppPackage(app.devId)
|
||||
const applicationPkg = await API.fetchAppPackage($store.appId)
|
||||
await store.actions.initialise(applicationPkg)
|
||||
}
|
||||
</script>
|
||||
|
@ -37,7 +36,7 @@
|
|||
|
||||
<Layout noPadding gap="XXS">
|
||||
<Label size="L">Name</Label>
|
||||
<Body>{app?.name}</Body>
|
||||
<Body>{$store?.name}</Body>
|
||||
</Layout>
|
||||
|
||||
<Layout noPadding gap="XS">
|
||||
|
@ -45,15 +44,15 @@
|
|||
<div class="icon">
|
||||
<Icon
|
||||
size="L"
|
||||
name={app?.icon?.name || "Apps"}
|
||||
color={app?.icon?.color}
|
||||
name={$store?.icon?.name || "Apps"}
|
||||
color={$store?.icon?.color}
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<Layout noPadding gap="XXS">
|
||||
<Label size="L">URL</Label>
|
||||
<Body>{appUrl}</Body>
|
||||
<Body>{$store.url}</Body>
|
||||
</Layout>
|
||||
|
||||
<div>
|
||||
|
@ -75,7 +74,12 @@
|
|||
|
||||
<Modal bind:this={updatingModal} padding={false} width="600px">
|
||||
<UpdateAppModal
|
||||
{app}
|
||||
app={{
|
||||
name: $store.name,
|
||||
url: $store.url,
|
||||
icon: $store.icon,
|
||||
appId: $store.appId,
|
||||
}}
|
||||
onUpdateComplete={async () => {
|
||||
await initialiseApp()
|
||||
}}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import { writable, derived } from "svelte/store"
|
||||
import { apps } from "./apps"
|
||||
|
||||
const createOverviewStore = () => {
|
||||
const store = writable({
|
||||
selectedAppId: null,
|
||||
})
|
||||
const derivedStore = derived([store, apps], ([$store, $apps]) => {
|
||||
return {
|
||||
...$store,
|
||||
selectedApp: $apps?.find(app => app.devId === $store.selectedAppId),
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
update: store.update,
|
||||
subscribe: derivedStore.subscribe,
|
||||
}
|
||||
}
|
||||
|
||||
export const overview = createOverviewStore()
|
|
@ -16,7 +16,7 @@
|
|||
export let columns = null
|
||||
|
||||
const component = getContext("component")
|
||||
const { styleable, API, builderStore } = getContext("sdk")
|
||||
const { styleable, API, builderStore, notificationStore } = getContext("sdk")
|
||||
|
||||
$: columnWhitelist = columns?.map(col => col.name)
|
||||
$: schemaOverrides = getSchemaOverrides(columns)
|
||||
|
@ -52,6 +52,8 @@
|
|||
showControls={false}
|
||||
allowExpandRows={false}
|
||||
allowSchemaChanges={false}
|
||||
notifySuccess={notificationStore.actions.success}
|
||||
notifyError={notificationStore.actions.error}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { getContext } from "svelte"
|
||||
import { Dropzone, notifications } from "@budibase/bbui"
|
||||
import { Dropzone } from "@budibase/bbui"
|
||||
|
||||
export let value
|
||||
export let focused = false
|
||||
|
@ -11,7 +11,7 @@
|
|||
export let invertX = false
|
||||
export let invertY = false
|
||||
|
||||
const { API } = getContext("grid")
|
||||
const { API, notifications } = getContext("grid")
|
||||
const imageExtensions = ["png", "tiff", "gif", "raw", "jpg", "jpeg"]
|
||||
|
||||
let isOpen = false
|
||||
|
@ -40,7 +40,7 @@
|
|||
}
|
||||
|
||||
const handleFileTooLarge = fileSizeLimit => {
|
||||
notifications.error(
|
||||
$notifications.error(
|
||||
`Files cannot exceed ${
|
||||
fileSizeLimit / 1000000
|
||||
}MB. Please try again with smaller files.`
|
||||
|
@ -55,7 +55,7 @@
|
|||
try {
|
||||
return await API.uploadBuilderAttachment(data)
|
||||
} catch (error) {
|
||||
notifications.error("Failed to upload attachment")
|
||||
$notifications.error("Failed to upload attachment")
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script>
|
||||
import { Modal, ModalContent, notifications } from "@budibase/bbui"
|
||||
import { Modal, ModalContent } from "@budibase/bbui"
|
||||
import { getContext, onMount } from "svelte"
|
||||
|
||||
const { selectedRows, rows, subscribe } = getContext("grid")
|
||||
const { selectedRows, rows, subscribe, notifications } = getContext("grid")
|
||||
|
||||
let modal
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
|||
const performDeletion = async () => {
|
||||
const count = rowsToDelete.length
|
||||
await rows.actions.deleteRows(rowsToDelete)
|
||||
notifications.success(`Deleted ${count} row${count === 1 ? "" : "s"}`)
|
||||
$notifications.success(`Deleted ${count} row${count === 1 ? "" : "s"}`)
|
||||
}
|
||||
|
||||
onMount(() => subscribe("request-bulk-delete", () => modal?.show()))
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
export let initialSortColumn = null
|
||||
export let initialSortOrder = null
|
||||
export let initialRowHeight = null
|
||||
export let notifySuccess = null
|
||||
export let notifyError = null
|
||||
|
||||
// Unique identifier for DOM nodes inside this instance
|
||||
const rand = Math.random()
|
||||
|
@ -89,6 +91,8 @@
|
|||
initialSortColumn,
|
||||
initialSortOrder,
|
||||
initialRowHeight,
|
||||
notifySuccess,
|
||||
notifyError,
|
||||
})
|
||||
|
||||
// Set context for children to consume
|
||||
|
|
|
@ -78,6 +78,11 @@
|
|||
}
|
||||
|
||||
const startAdding = async () => {
|
||||
// Attempt to submit if already adding a row
|
||||
if (visible && !isAdding) {
|
||||
await addRow()
|
||||
return
|
||||
}
|
||||
if (visible || !firstColumn) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<script>
|
||||
import {
|
||||
clickOutside,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Helpers,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { clickOutside, Menu, MenuItem, Helpers } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
import { NewRowID } from "../lib/constants"
|
||||
|
||||
|
@ -22,6 +16,7 @@
|
|||
dispatch,
|
||||
focusedCellAPI,
|
||||
focusedRowId,
|
||||
notifications,
|
||||
} = getContext("grid")
|
||||
|
||||
$: style = makeStyle($menu)
|
||||
|
@ -34,7 +29,7 @@
|
|||
const deleteRow = () => {
|
||||
rows.actions.deleteRows([$focusedRow])
|
||||
menu.actions.close()
|
||||
notifications.success("Deleted 1 row")
|
||||
$notifications.success("Deleted 1 row")
|
||||
}
|
||||
|
||||
const duplicate = async () => {
|
||||
|
@ -48,7 +43,7 @@
|
|||
|
||||
const copyToClipboard = async value => {
|
||||
await Helpers.copyToClipboard(value)
|
||||
notifications.success("Copied to clipboard")
|
||||
$notifications.success("Copied to clipboard")
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -35,10 +35,20 @@ export const createStores = () => {
|
|||
[]
|
||||
)
|
||||
|
||||
// Checks if we have a certain column by name
|
||||
const hasColumn = column => {
|
||||
const $columns = get(columns)
|
||||
const $sticky = get(stickyColumn)
|
||||
return $columns.some(col => col.name === column) || $sticky?.name === column
|
||||
}
|
||||
|
||||
return {
|
||||
columns: {
|
||||
...columns,
|
||||
subscribe: enrichedColumns.subscribe,
|
||||
actions: {
|
||||
hasColumn,
|
||||
},
|
||||
},
|
||||
stickyColumn,
|
||||
visibleColumns,
|
||||
|
@ -121,6 +131,7 @@ export const deriveStores = context => {
|
|||
columns: {
|
||||
...columns,
|
||||
actions: {
|
||||
...columns.actions,
|
||||
saveChanges,
|
||||
saveTable,
|
||||
changePrimaryDisplay,
|
||||
|
|
|
@ -13,6 +13,8 @@ export const createStores = context => {
|
|||
const initialRowHeight = getProp("initialRowHeight")
|
||||
const schemaOverrides = getProp("schemaOverrides")
|
||||
const columnWhitelist = getProp("columnWhitelist")
|
||||
const notifySuccess = getProp("notifySuccess")
|
||||
const notifyError = getProp("notifyError")
|
||||
|
||||
return {
|
||||
config,
|
||||
|
@ -23,5 +25,7 @@ export const createStores = context => {
|
|||
initialRowHeight,
|
||||
schemaOverrides,
|
||||
columnWhitelist,
|
||||
notifySuccess,
|
||||
notifyError,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ import * as Clipboard from "./clipboard"
|
|||
import * as Config from "./config"
|
||||
import * as Sort from "./sort"
|
||||
import * as Filter from "./filter"
|
||||
import * as Notifications from "./notifications"
|
||||
|
||||
const DependencyOrderedStores = [
|
||||
Config,
|
||||
Notifications,
|
||||
Sort,
|
||||
Filter,
|
||||
Bounds,
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { notifications as BBUINotifications } from "@budibase/bbui"
|
||||
import { derived } from "svelte/store"
|
||||
|
||||
export const createStores = context => {
|
||||
const { notifySuccess, notifyError } = context
|
||||
|
||||
// Normally we would not derive a store in "createStores" as it should be
|
||||
// dependency free, but in this case it's safe as we only depend on grid props
|
||||
// which are guaranteed to be first in the dependency chain
|
||||
const notifications = derived(
|
||||
[notifySuccess, notifyError],
|
||||
([$notifySuccess, $notifyError]) => {
|
||||
return {
|
||||
success: $notifySuccess || BBUINotifications.success,
|
||||
error: $notifyError || BBUINotifications.error,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
notifications,
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import { writable, derived, get } from "svelte/store"
|
||||
import { fetchData } from "../../../fetch/fetchData"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
import { NewRowID, RowPageSize } from "../lib/constants"
|
||||
import { tick } from "svelte"
|
||||
|
||||
|
@ -71,6 +70,7 @@ export const deriveStores = context => {
|
|||
previousFocusedRowId,
|
||||
hasNextPage,
|
||||
error,
|
||||
notifications,
|
||||
} = context
|
||||
const instanceLoaded = writable(false)
|
||||
const fetch = writable(null)
|
||||
|
@ -203,10 +203,23 @@ export const deriveStores = context => {
|
|||
// state, storing error messages against relevant cells
|
||||
const handleValidationError = (rowId, error) => {
|
||||
if (error?.json?.validationErrors) {
|
||||
// Normal validation error
|
||||
// Normal validation errors
|
||||
const keys = Object.keys(error.json.validationErrors)
|
||||
const $columns = get(columns)
|
||||
|
||||
// Filter out missing columns from columns that we have
|
||||
let erroredColumns = []
|
||||
let missingColumns = []
|
||||
for (let column of keys) {
|
||||
if (columns.actions.hasColumn(column)) {
|
||||
erroredColumns.push(column)
|
||||
} else {
|
||||
missingColumns.push(column)
|
||||
}
|
||||
}
|
||||
|
||||
// Process errors for columns that we have
|
||||
for (let column of erroredColumns) {
|
||||
validation.actions.setError(
|
||||
`${rowId}-${column}`,
|
||||
`${column} ${error.json.validationErrors[column]}`
|
||||
|
@ -221,8 +234,16 @@ export const deriveStores = context => {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Notify about missing columns
|
||||
for (let column of missingColumns) {
|
||||
get(notifications).error(`${column} is required but is missing`)
|
||||
}
|
||||
|
||||
// Focus the first cell with an error
|
||||
focusedCellId.set(`${rowId}-${keys[0]}`)
|
||||
if (erroredColumns.length) {
|
||||
focusedCellId.set(`${rowId}-${erroredColumns[0]}`)
|
||||
}
|
||||
} else {
|
||||
// Some other error - just update the current cell
|
||||
validation.actions.setError(get(focusedCellId), error?.message || "Error")
|
||||
|
@ -250,7 +271,7 @@ export const deriveStores = context => {
|
|||
}
|
||||
|
||||
// Refresh row to ensure data is in the correct format
|
||||
notifications.success("Row created successfully")
|
||||
get(notifications).success("Row created successfully")
|
||||
return newRow
|
||||
} catch (error) {
|
||||
if (bubble) {
|
||||
|
|
Loading…
Reference in New Issue