diff --git a/lerna.json b/lerna.json index c893e4b402..afcb33918b 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.4.6", + "version": "3.4.9", "npmClient": "yarn", "concurrency": 20, "command": { diff --git a/package.json b/package.json index c0b295728e..1475abadf9 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "eslint-plugin-jest": "28.9.0", "eslint-plugin-local-rules": "3.0.2", "eslint-plugin-svelte": "2.46.1", + "svelte-preprocess": "^6.0.3", "husky": "^8.0.3", "kill-port": "^1.6.1", "lerna": "7.4.2", diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index bdbab63767..064cc630d8 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -424,7 +424,7 @@ export async function retrieveDirectory(bucketName: string, path: string) { stream.pipe(writeStream) writePromises.push( new Promise((resolve, reject) => { - stream.on("finish", resolve) + writeStream.on("finish", resolve) stream.on("error", reject) writeStream.on("error", reject) }) diff --git a/packages/backend-core/src/utils/utils.ts b/packages/backend-core/src/utils/utils.ts index 30cf55b149..7f2e25b6d4 100644 --- a/packages/backend-core/src/utils/utils.ts +++ b/packages/backend-core/src/utils/utils.ts @@ -247,3 +247,7 @@ export function hasCircularStructure(json: any) { } return false } + +export function urlHasProtocol(url: string): boolean { + return !!url.match(/^.+:\/\/.+$/) +} diff --git a/packages/bbui/src/Typography/Body.svelte b/packages/bbui/src/Typography/Body.svelte index 2123eeee95..06664c9033 100644 --- a/packages/bbui/src/Typography/Body.svelte +++ b/packages/bbui/src/Typography/Body.svelte @@ -1,11 +1,11 @@ -

{ +const buildHelperInfoNode = (helper: Helper) => { const ele = document.createElement("div") ele.classList.add("info-bubble") @@ -65,7 +54,7 @@ const toSpectrumIcon = (name: string) => { ` } -export const buildSectionHeader = ( +const buildSectionHeader = ( type: string, sectionName: string, icon: string, @@ -84,30 +73,27 @@ export const buildSectionHeader = ( } } -export const helpersToCompletion = ( +const helpersToCompletion = ( helpers: Record, mode: { name: "javascript" | "handlebars" } -) => { - const { type, name: sectionName, icon } = SECTIONS.HB_HELPER - const helperSection = buildSectionHeader(type, sectionName, icon, 99) +): BindingCompletionOption[] => { + const helperSection = buildSectionHeader("helper", "Helpers", "Code", 99) return Object.keys(helpers).flatMap(helperName => { - let helper = helpers[helperName] + const helper = helpers[helperName] return { label: helperName, - info: (completion: BindingCompletion) => { - return buildHelperInfoNode(completion, helper) - }, + info: () => buildHelperInfoNode(helper), type: "helper", section: helperSection, detail: "Function", apply: ( - view: any, - completion: BindingCompletion, + view: EditorView, + _completion: BindingCompletionOption, from: number, to: number ) => { - insertBinding(view, from, to, helperName, mode) + insertBinding(view, from, to, helperName, mode, AutocompleteType.HELPER) }, } }) @@ -115,7 +101,7 @@ export const helpersToCompletion = ( export const getHelperCompletions = (mode: { name: "javascript" | "handlebars" -}) => { +}): BindingCompletionOption[] => { // TODO: manifest needs to be properly typed const manifest: any = getManifest() return Object.keys(manifest).flatMap(key => { @@ -123,49 +109,33 @@ export const getHelperCompletions = (mode: { }) } -export const snippetAutoComplete = (snippets: Snippet[]) => { - return function myCompletions(context: CompletionContext) { - if (!snippets?.length) { - return null - } - const word = context.matchBefore(/\w*/) - if (!word || (word.from == word.to && !context.explicit)) { - return null - } - return { - from: word.from, - options: snippets.map(snippet => ({ - label: `snippets.${snippet.name}`, - type: "text", - simple: true, - apply: ( - view: any, - completion: BindingCompletion, - from: number, - to: number - ) => { - insertSnippet(view, from, to, completion.label) - }, - })), - } - } +export const snippetAutoComplete = (snippets: Snippet[]): BindingCompletion => { + return setAutocomplete( + snippets.map(snippet => ({ + section: buildSectionHeader("snippets", "Snippets", "Code", 100), + label: `snippets.${snippet.name}`, + displayLabel: snippet.name, + })) + ) } -const bindingFilter = (options: BindingCompletion[], query: string) => { +const bindingFilter = (options: BindingCompletionOption[], query: string) => { return options.filter(completion => { - const section_parsed = completion.section.name.toLowerCase() + const section_parsed = completion.section?.toString().toLowerCase() const label_parsed = completion.label.toLowerCase() const query_parsed = query.toLowerCase() return ( - section_parsed.includes(query_parsed) || + section_parsed?.includes(query_parsed) || label_parsed.includes(query_parsed) ) }) } -export const hbAutocomplete = (baseCompletions: BindingCompletion[]) => { - async function coreCompletion(context: CompletionContext) { +export const hbAutocomplete = ( + baseCompletions: BindingCompletionOption[] +): BindingCompletion => { + function coreCompletion(context: CompletionContext) { let bindingStart = context.matchBefore(EditorModes.Handlebars.match) let options = baseCompletions || [] @@ -191,9 +161,15 @@ export const hbAutocomplete = (baseCompletions: BindingCompletion[]) => { return coreCompletion } -export const jsAutocomplete = (baseCompletions: BindingCompletion[]) => { - async function coreCompletion(context: CompletionContext) { - let jsBinding = context.matchBefore(/\$\("[\s\w]*/) +function wrappedAutocompleteMatch(context: CompletionContext) { + return context.matchBefore(/\$\("[\s\w]*/) +} + +export const jsAutocomplete = ( + baseCompletions: BindingCompletionOption[] +): BindingCompletion => { + function coreCompletion(context: CompletionContext) { + let jsBinding = wrappedAutocompleteMatch(context) let options = baseCompletions || [] if (jsBinding) { @@ -217,10 +193,42 @@ export const jsAutocomplete = (baseCompletions: BindingCompletion[]) => { return coreCompletion } -export const buildBindingInfoNode = ( - completion: BindingCompletion, - binding: any -) => { +export const jsHelperAutocomplete = ( + baseCompletions: BindingCompletionOption[] +): BindingCompletion => { + return setAutocomplete( + baseCompletions.map(helper => ({ + ...helper, + displayLabel: helper.label, + label: `helpers.${helper.label}()`, + })) + ) +} + +function setAutocomplete( + options: BindingCompletionOption[] +): BindingCompletion { + return function (context: CompletionContext) { + if (wrappedAutocompleteMatch(context)) { + return null + } + + const word = context.matchBefore(/\b\w*(\.\w*)?/) + if (!word || (word.from == word.to && !context.explicit)) { + return null + } + + return { + from: word.from, + options, + } + } +} + +const buildBindingInfoNode = (binding: { + valueHTML: string + value: string | null +}) => { if (!binding.valueHTML || binding.value == null) { return null } @@ -278,18 +286,28 @@ export function jsInsert( return parsedInsert } +const enum AutocompleteType { + BINDING, + HELPER, + TEXT, +} + // Autocomplete apply behaviour -export const insertBinding = ( - view: any, +const insertBinding = ( + view: EditorView, from: number, to: number, text: string, - mode: { name: "javascript" | "handlebars" } + mode: { name: "javascript" | "handlebars" }, + type: AutocompleteType ) => { let parsedInsert if (mode.name == "javascript") { - parsedInsert = jsInsert(view.state.doc?.toString(), from, to, text) + parsedInsert = jsInsert(view.state.doc?.toString(), from, to, text, { + helper: type === AutocompleteType.HELPER, + disableWrapping: type === AutocompleteType.TEXT, + }) } else if (mode.name == "handlebars") { parsedInsert = hbInsert(view.state.doc?.toString(), from, to, text) } else { @@ -319,30 +337,11 @@ export const insertBinding = ( }) } -export const insertSnippet = ( - view: any, - from: number, - to: number, - text: string -) => { - let cursorPos = from + text.length - view.dispatch({ - changes: { - from, - to, - insert: text, - }, - selection: { - anchor: cursorPos, - }, - }) -} - // TODO: typing in this function isn't great export const bindingsToCompletions = ( bindings: any, mode: { name: "javascript" | "handlebars" } -) => { +): BindingCompletionOption[] => { const bindingByCategory = groupBy(bindings, "category") const categoryMeta = bindings?.reduce((acc: any, ele: any) => { acc[ele.category] = acc[ele.category] || {} @@ -356,46 +355,54 @@ export const bindingsToCompletions = ( return acc }, {}) - const completions = Object.keys(bindingByCategory).reduce( - (comps: any, catKey: string) => { - const { icon, rank } = categoryMeta[catKey] || {} + const completions = Object.keys(bindingByCategory).reduce< + BindingCompletionOption[] + >((comps, catKey) => { + const { icon, rank } = categoryMeta[catKey] || {} - const bindingSectionHeader = buildSectionHeader( - // @ts-ignore something wrong with this - logically this should be dictionary - bindingByCategory.type, - catKey, - icon || "", - typeof rank == "number" ? rank : 1 - ) + const bindingSectionHeader = buildSectionHeader( + // @ts-ignore something wrong with this - logically this should be dictionary + bindingByCategory.type, + catKey, + icon || "", + typeof rank == "number" ? rank : 1 + ) - return [ - ...comps, - ...bindingByCategory[catKey].reduce((acc, binding) => { + comps.push( + ...bindingByCategory[catKey].reduce( + (acc, binding) => { let displayType = binding.fieldSchema?.type || binding.display?.type acc.push({ label: binding.display?.name || binding.readableBinding || "NO NAME", - info: (completion: BindingCompletion) => { - return buildBindingInfoNode(completion, binding) - }, + info: () => buildBindingInfoNode(binding), type: "binding", detail: displayType, section: bindingSectionHeader, apply: ( - view: any, - completion: BindingCompletion, + view: EditorView, + _completion: BindingCompletionOption, from: number, to: number ) => { - insertBinding(view, from, to, binding.readableBinding, mode) + insertBinding( + view, + from, + to, + binding.readableBinding, + mode, + AutocompleteType.BINDING + ) }, }) return acc - }, []), - ] - }, - [] - ) + }, + [] + ) + ) + + return comps + }, []) return completions } diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index ffb477012c..4bd37bf72c 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -23,6 +23,7 @@ snippetAutoComplete, EditorModes, bindingsToCompletions, + jsHelperAutocomplete, } from "../CodeEditor" import BindingSidePanel from "./BindingSidePanel.svelte" import EvaluationSidePanel from "./EvaluationSidePanel.svelte" @@ -34,7 +35,6 @@ import { BindingMode, SidePanel } from "@budibase/types" import type { EnrichedBinding, - BindingCompletion, Snippet, Helper, CaretPositionFn, @@ -42,7 +42,7 @@ JSONValue, } from "@budibase/types" import type { Log } from "@budibase/string-templates" - import type { CompletionContext } from "@codemirror/autocomplete" + import type { BindingCompletion, BindingCompletionOption } from "@/types" const dispatch = createEventDispatcher() @@ -91,7 +91,10 @@ $: bindingCompletions = bindingsToCompletions(enrichedBindings, editorMode) $: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos) $: hbsCompletions = getHBSCompletions(bindingCompletions) - $: jsCompletions = getJSCompletions(bindingCompletions, snippets, useSnippets) + $: jsCompletions = getJSCompletions(bindingCompletions, snippets, { + useHelpers: allowHelpers, + useSnippets, + }) $: { // Ensure a valid side panel option is always selected if (sidePanel && !sidePanelOptions.includes(sidePanel)) { @@ -99,7 +102,7 @@ } } - const getHBSCompletions = (bindingCompletions: BindingCompletion[]) => { + const getHBSCompletions = (bindingCompletions: BindingCompletionOption[]) => { return [ hbAutocomplete([ ...bindingCompletions, @@ -109,17 +112,23 @@ } const getJSCompletions = ( - bindingCompletions: BindingCompletion[], + bindingCompletions: BindingCompletionOption[], snippets: Snippet[] | null, - useSnippets?: boolean + config: { + useHelpers: boolean + useSnippets: boolean + } ) => { - const completions: ((_: CompletionContext) => any)[] = [ - jsAutocomplete([ - ...bindingCompletions, - ...getHelperCompletions(EditorModes.JS), - ]), - ] - if (useSnippets && snippets) { + const completions: BindingCompletion[] = [] + if (bindingCompletions.length) { + completions.push(jsAutocomplete([...bindingCompletions])) + } + if (config.useHelpers) { + completions.push( + jsHelperAutocomplete([...getHelperCompletions(EditorModes.JS)]) + ) + } + if (config.useSnippets && snippets) { completions.push(snippetAutoComplete(snippets)) } return completions @@ -381,7 +390,7 @@ autofocus={autofocusEditor} placeholder={placeholder || "Add bindings by typing $ or use the menu on the right"} - jsBindingWrapping + jsBindingWrapping={bindingCompletions.length > 0} /> {/key} {/if} diff --git a/packages/builder/src/components/common/bindings/SnippetDrawer.svelte b/packages/builder/src/components/common/bindings/SnippetDrawer.svelte index f10c44f81f..4862217b13 100644 --- a/packages/builder/src/components/common/bindings/SnippetDrawer.svelte +++ b/packages/builder/src/components/common/bindings/SnippetDrawer.svelte @@ -118,6 +118,7 @@ allowHBS={false} allowJS allowSnippets={false} + allowHelpers={false} showTabBar={false} placeholder="return function(input) ❴ ... ❵" value={code} diff --git a/packages/builder/src/components/design/settings/controls/URLVariableTestInput.svelte b/packages/builder/src/components/design/settings/controls/URLVariableTestInput.svelte new file mode 100644 index 0000000000..a75d7e625d --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/URLVariableTestInput.svelte @@ -0,0 +1,126 @@ + + +{#if hasUrlParams} +

+
+ +
+
+
+ +
+
+ +
+
+
+{/if} + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte index 3a6e7a702c..31479bc820 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte @@ -15,6 +15,7 @@ import ButtonActionEditor from "@/components/design/settings/controls/ButtonActionEditor/ButtonActionEditor.svelte" import { getBindableProperties } from "@/dataBinding" import BarButtonList from "@/components/design/settings/controls/BarButtonList.svelte" + import URLVariableTestInput from "@/components/design/settings/controls/URLVariableTestInput.svelte" $: bindings = getBindableProperties($selectedScreen, null) $: screenSettings = getScreenSettings($selectedScreen) @@ -93,6 +94,13 @@ ], }, }, + { + key: "urlTest", + control: URLVariableTestInput, + props: { + baseRoute: screen.routing?.route, + }, + }, ] return settings diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte index aa0b26f6b7..d13d72b89f 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte @@ -13,6 +13,11 @@ import { fly } from "svelte/transition" import { findComponentPath } from "@/helpers/components" + // Smallest possible 1x1 transparent GIF + const ghost = new Image(1, 1) + ghost.src = + "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" + let searchString let searchRef let selectedIndex @@ -217,7 +222,8 @@ } }) - const onDragStart = component => { + const onDragStart = (e, component) => { + e.dataTransfer.setDragImage(ghost, 0, 0) previewStore.startDrag(component) } @@ -250,13 +256,12 @@ {#each category.children as component}
onDragStart(component.component)} + on:dragstart={e => onDragStart(e, component.component)} on:dragend={onDragEnd} class="component" class:selected={selectedIndex === orderMap[component.component]} on:click={() => addComponent(component.component)} - on:mouseover={() => (selectedIndex = null)} - on:focus + on:mouseenter={() => (selectedIndex = null)} > {component.name} @@ -308,7 +313,6 @@ } .component:hover { background: var(--spectrum-global-color-gray-300); - cursor: pointer; } .component :global(.spectrum-Body) { line-height: 1.2 !important; diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index ba600c8eef..59548ada01 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -189,8 +189,8 @@ } else if (type === "reload-plugin") { await componentStore.refreshDefinitions() } else if (type === "drop-new-component") { - const { component, parent, index } = data - await componentStore.create(component, null, parent, index) + const { component, parent, index, props } = data + await componentStore.create(component, props, parent, index) } else if (type === "add-parent-component") { const { componentId, parentType } = data await componentStore.addParent(componentId, parentType) diff --git a/packages/builder/src/stores/builder/app.ts b/packages/builder/src/stores/builder/app.ts index 3c8ed4afc1..abebb5d9f1 100644 --- a/packages/builder/src/stores/builder/app.ts +++ b/packages/builder/src/stores/builder/app.ts @@ -39,7 +39,7 @@ interface AppMetaState { appInstance: { _id: string } | null initialised: boolean hasAppPackage: boolean - usedPlugins: Plugin[] | null + usedPlugins: Plugin[] automations: AutomationSettings routes: { [key: string]: any } version?: string @@ -76,7 +76,7 @@ export const INITIAL_APP_META_STATE: AppMetaState = { appInstance: null, initialised: false, hasAppPackage: false, - usedPlugins: null, + usedPlugins: [], automations: {}, routes: {}, } @@ -109,7 +109,7 @@ export class AppMetaStore extends BudiStore { appInstance: app.instance, revertableVersion: app.revertableVersion, upgradableVersion: app.upgradableVersion, - usedPlugins: app.usedPlugins || null, + usedPlugins: app.usedPlugins || [], icon: app.icon, features: { ...INITIAL_APP_META_STATE.features, diff --git a/packages/builder/src/stores/builder/components.ts b/packages/builder/src/stores/builder/components.ts index b1198ca7b4..38fa9a6a41 100644 --- a/packages/builder/src/stores/builder/components.ts +++ b/packages/builder/src/stores/builder/components.ts @@ -11,6 +11,7 @@ import { findComponentParent, findAllMatchingComponents, makeComponentUnique, + findComponentType, } from "@/helpers/components" import { getComponentFieldOptions } from "@/helpers/formFields" import { selectedScreen } from "./screens" @@ -139,10 +140,6 @@ export class ComponentStore extends BudiStore { /** * Retrieve the component definition object - * @param {string} componentType - * @example - * '@budibase/standard-components/container' - * @returns {object} */ getDefinition(componentType: string) { if (!componentType) { @@ -151,10 +148,6 @@ export class ComponentStore extends BudiStore { return get(this.store).components[componentType] } - /** - * - * @returns {object} - */ getDefaultDatasource() { // Ignore users table const validTables = get(tables).list.filter(x => x._id !== "ta_users") @@ -188,8 +181,6 @@ export class ComponentStore extends BudiStore { /** * Takes an enriched component instance and applies any required migration * logic - * @param {object} enrichedComponent - * @returns {object} migrated Component */ migrateSettings(enrichedComponent: Component) { const componentPrefix = "@budibase/standard-components" @@ -230,22 +221,15 @@ export class ComponentStore extends BudiStore { for (let setting of filterableTypes || []) { const isLegacy = Array.isArray(enrichedComponent[setting.key]) if (isLegacy) { - const processedSetting = utils.processSearchFilters( + enrichedComponent[setting.key] = utils.processSearchFilters( enrichedComponent[setting.key] ) - enrichedComponent[setting.key] = processedSetting migrated = true } } return migrated } - /** - * - * @param {object} component - * @param {object} opts - * @returns - */ enrichEmptySettings( component: Component, opts: { screen?: Screen; parent?: Component; useDefaultValues?: boolean } @@ -280,14 +264,25 @@ export class ComponentStore extends BudiStore { type: "table", } } else if (setting.type === "dataProvider") { - // Pick closest data provider where required + let providerId + + // Pick closest parent data provider if one exists const path = findComponentPath(screen.props, treeId) const providers = path.filter((component: Component) => component._component?.endsWith("/dataprovider") ) - if (providers.length) { - const id = providers[providers.length - 1]?._id - component[setting.key] = `{{ literal ${safe(id)} }}` + providerId = providers[providers.length - 1]?._id + + // If none in our direct path, select the first one the screen + if (!providerId) { + providerId = findComponentType( + screen.props, + "@budibase/standard-components/dataprovider" + )?._id + } + + if (providerId) { + component[setting.key] = `{{ literal ${safe(providerId)} }}` } } else if (setting.type.startsWith("field/")) { // Autofill form field names @@ -427,17 +422,10 @@ export class ComponentStore extends BudiStore { } } - /** - * - * @param {string} componentName - * @param {object} presetProps - * @param {object} parent - * @returns - */ createInstance( componentType: string, - presetProps: any, - parent: any + presetProps?: Record, + parent?: Component ): Component | null { const screen = get(selectedScreen) if (!screen) { @@ -463,7 +451,7 @@ export class ComponentStore extends BudiStore { _id: Helpers.uuid(), _component: definition.component, _styles: { - normal: {}, + normal: { ...presetProps?._styles?.normal }, hover: {}, active: {}, }, @@ -512,19 +500,11 @@ export class ComponentStore extends BudiStore { } } - /** - * - * @param {string} componentName - * @param {object} presetProps - * @param {object} parent - * @param {number} index - * @returns - */ async create( componentType: string, - presetProps: any, - parent: Component, - index: number + presetProps?: Record, + parent?: Component, + index?: number ) { const state = get(this.store) const componentInstance = this.createInstance( @@ -611,13 +591,6 @@ export class ComponentStore extends BudiStore { return componentInstance } - /** - * - * @param {function} patchFn - * @param {string} componentId - * @param {string} screenId - * @returns - */ async patch( patchFn: (component: Component, screen: Screen) => any, componentId?: string, @@ -652,11 +625,6 @@ export class ComponentStore extends BudiStore { await screenStore.patch(patchScreen, screenId) } - /** - * - * @param {object} component - * @returns - */ async delete(component: Component) { if (!component) { return @@ -737,13 +705,6 @@ export class ComponentStore extends BudiStore { }) } - /** - * - * @param {object} targetComponent - * @param {string} mode - * @param {object} targetScreen - * @returns - */ async paste( targetComponent: Component, mode: string, @@ -1101,6 +1062,7 @@ export class ComponentStore extends BudiStore { async updateStyles(styles: Record, id: string) { const patchFn = (component: Component) => { + delete component._placeholder component._styles.normal = { ...component._styles.normal, ...styles, @@ -1231,7 +1193,7 @@ export class ComponentStore extends BudiStore { } // Create new parent instance - const newParentDefinition = this.createInstance(parentType, null, parent) + const newParentDefinition = this.createInstance(parentType) if (!newParentDefinition) { return } @@ -1267,10 +1229,6 @@ export class ComponentStore extends BudiStore { /** * Check if the components settings have been cached - * @param {string} componentType - * @example - * '@budibase/standard-components/container' - * @returns {boolean} */ isCached(componentType: string) { const settings = get(this.store).settingsCache @@ -1279,11 +1237,6 @@ export class ComponentStore extends BudiStore { /** * Cache component settings - * @param {string} componentType - * @param {object} definition - * @example - * '@budibase/standard-components/container' - * @returns {array} the settings */ cacheSettings(componentType: string, definition: ComponentDefinition | null) { let settings: ComponentSetting[] = [] @@ -1313,12 +1266,7 @@ export class ComponentStore extends BudiStore { /** * Retrieve an array of the component settings. * These settings are cached because they cannot change at run time. - * * Searches a component's definition for a setting matching a certain predicate. - * @param {string} componentType - * @example - * '@budibase/standard-components/container' - * @returns {Array} */ getComponentSettings(componentType: string) { if (!componentType) { diff --git a/packages/builder/src/stores/builder/navigation.ts b/packages/builder/src/stores/builder/navigation.ts index 1574efee2a..1ef019a11c 100644 --- a/packages/builder/src/stores/builder/navigation.ts +++ b/packages/builder/src/stores/builder/navigation.ts @@ -4,15 +4,13 @@ import { appStore } from "@/stores/builder" import { BudiStore } from "../BudiStore" import { AppNavigation, AppNavigationLink, UIObject } from "@budibase/types" -interface BuilderNavigationStore extends AppNavigation {} - export const INITIAL_NAVIGATION_STATE = { navigation: "Top", links: [], textAlign: "Left", } -export class NavigationStore extends BudiStore { +export class NavigationStore extends BudiStore { constructor() { super(INITIAL_NAVIGATION_STATE) } diff --git a/packages/builder/src/stores/builder/preview.ts b/packages/builder/src/stores/builder/preview.ts index 87b2b9355e..0fef91d6b9 100644 --- a/packages/builder/src/stores/builder/preview.ts +++ b/packages/builder/src/stores/builder/preview.ts @@ -1,9 +1,8 @@ import { get } from "svelte/store" import { BudiStore } from "../BudiStore" +import { PreviewDevice, ComponentContext } from "@budibase/types" -type PreviewDevice = "desktop" | "tablet" | "mobile" type PreviewEventHandler = (name: string, payload?: any) => void -type ComponentContext = Record interface PreviewState { previewDevice: PreviewDevice @@ -54,7 +53,7 @@ export class PreviewStore extends BudiStore { })) } - startDrag(component: any) { + async startDrag(component: string) { this.sendEvent("dragging-new-component", { dragging: true, component, @@ -86,6 +85,10 @@ export class PreviewStore extends BudiStore { this.sendEvent("builder-state", data) } + setUrlTestData(data: Record) { + this.sendEvent("builder-url-test-data", data) + } + requestComponentContext() { this.sendEvent("request-context") } diff --git a/packages/builder/src/types/bindings.ts b/packages/builder/src/types/bindings.ts new file mode 100644 index 0000000000..00571f1d8b --- /dev/null +++ b/packages/builder/src/types/bindings.ts @@ -0,0 +1,8 @@ +import { CompletionContext, Completion } from "@codemirror/autocomplete" + +export type BindingCompletion = (context: CompletionContext) => { + from: number + options: Completion[] +} | null + +export type BindingCompletionOption = Completion diff --git a/packages/builder/src/types/index.ts b/packages/builder/src/types/index.ts new file mode 100644 index 0000000000..f280d975b4 --- /dev/null +++ b/packages/builder/src/types/index.ts @@ -0,0 +1 @@ +export * from "./bindings" diff --git a/packages/client/manifest.json b/packages/client/manifest.json index c240e17176..a2d29d3020 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -1455,7 +1455,8 @@ "type": "icon", "label": "Icon", "key": "icon", - "required": true + "required": true, + "defaultValue": "ri-star-fill" }, { "type": "select", diff --git a/packages/client/package.json b/packages/client/package.json index 2ae049f6d0..72be403698 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -5,7 +5,7 @@ "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", "type": "module", - "svelte": "src/index.js", + "svelte": "src/index.ts", "exports": { ".": { "import": "./dist/budibase-client.js", diff --git a/packages/client/src/api/api.ts b/packages/client/src/api/api.ts index b944f7bd7c..564f401164 100644 --- a/packages/client/src/api/api.ts +++ b/packages/client/src/api/api.ts @@ -1,10 +1,6 @@ import { createAPIClient } from "@budibase/frontend-core" import { authStore } from "../stores/auth" -import { - notificationStore, - devToolsEnabled, - devToolsStore, -} from "../stores/index" +import { notificationStore, devToolsEnabled, devToolsStore } from "../stores" import { get } from "svelte/store" export const API = createAPIClient({ diff --git a/packages/client/src/components/Block.svelte b/packages/client/src/components/Block.svelte index 48c11f152a..5f39f7eef1 100644 --- a/packages/client/src/components/Block.svelte +++ b/packages/client/src/components/Block.svelte @@ -1,7 +1,7 @@ diff --git a/packages/client/src/components/context/RowSelectionProvider.svelte b/packages/client/src/components/context/RowSelectionProvider.svelte index 2c87a5fa00..da731e6f05 100644 --- a/packages/client/src/components/context/RowSelectionProvider.svelte +++ b/packages/client/src/components/context/RowSelectionProvider.svelte @@ -1,6 +1,6 @@ diff --git a/packages/client/src/components/context/SnippetsProvider.svelte b/packages/client/src/components/context/SnippetsProvider.svelte index 53fa1e8b7f..104147ecf7 100644 --- a/packages/client/src/components/context/SnippetsProvider.svelte +++ b/packages/client/src/components/context/SnippetsProvider.svelte @@ -1,6 +1,6 @@ diff --git a/packages/client/src/components/context/StateBindingsProvider.svelte b/packages/client/src/components/context/StateBindingsProvider.svelte index a1166594a8..4ef99228c1 100644 --- a/packages/client/src/components/context/StateBindingsProvider.svelte +++ b/packages/client/src/components/context/StateBindingsProvider.svelte @@ -1,6 +1,6 @@ diff --git a/packages/client/src/components/context/TestUrlBindingsProvider.svelte b/packages/client/src/components/context/TestUrlBindingsProvider.svelte new file mode 100644 index 0000000000..15894ee032 --- /dev/null +++ b/packages/client/src/components/context/TestUrlBindingsProvider.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/client/src/components/context/UserBindingsProvider.svelte b/packages/client/src/components/context/UserBindingsProvider.svelte index 98769cf76a..02293e2f50 100644 --- a/packages/client/src/components/context/UserBindingsProvider.svelte +++ b/packages/client/src/components/context/UserBindingsProvider.svelte @@ -1,7 +1,7 @@ diff --git a/packages/client/src/components/devtools/DevToolsComponentContextTab.svelte b/packages/client/src/components/devtools/DevToolsComponentContextTab.svelte index 3b4c426851..02032aa0a5 100644 --- a/packages/client/src/components/devtools/DevToolsComponentContextTab.svelte +++ b/packages/client/src/components/devtools/DevToolsComponentContextTab.svelte @@ -1,6 +1,6 @@ diff --git a/packages/client/src/components/overlay/ConfirmationDisplay.svelte b/packages/client/src/components/overlay/ConfirmationDisplay.svelte index b96af502df..823c1c1ab2 100644 --- a/packages/client/src/components/overlay/ConfirmationDisplay.svelte +++ b/packages/client/src/components/overlay/ConfirmationDisplay.svelte @@ -1,5 +1,5 @@ diff --git a/packages/client/src/components/overlay/NotificationDisplay.svelte b/packages/client/src/components/overlay/NotificationDisplay.svelte index 46b3a2a6a1..28f4b33433 100644 --- a/packages/client/src/components/overlay/NotificationDisplay.svelte +++ b/packages/client/src/components/overlay/NotificationDisplay.svelte @@ -1,5 +1,5 @@ diff --git a/packages/client/src/components/overlay/PeekScreenDisplay.svelte b/packages/client/src/components/overlay/PeekScreenDisplay.svelte index 6e0fa81b43..17a92797d5 100644 --- a/packages/client/src/components/overlay/PeekScreenDisplay.svelte +++ b/packages/client/src/components/overlay/PeekScreenDisplay.svelte @@ -5,7 +5,7 @@ notificationStore, routeStore, stateStore, - } from "stores" + } from "@/stores" import { Modal, ModalContent, ActionButton } from "@budibase/bbui" import { onDestroy } from "svelte" diff --git a/packages/client/src/components/preview/DNDHandler.svelte b/packages/client/src/components/preview/DNDHandler.svelte index bdd538748b..15177a90c4 100644 --- a/packages/client/src/components/preview/DNDHandler.svelte +++ b/packages/client/src/components/preview/DNDHandler.svelte @@ -1,19 +1,22 @@ - - - - -{#if $dndIsDragging} - -{/if} diff --git a/packages/client/src/components/preview/DNDPlaceholderOverlay.svelte b/packages/client/src/components/preview/DNDPlaceholderOverlay.svelte deleted file mode 100644 index 61cecc885b..0000000000 --- a/packages/client/src/components/preview/DNDPlaceholderOverlay.svelte +++ /dev/null @@ -1,51 +0,0 @@ - - -{#if left != null && top != null && width && height} -
-{/if} - - diff --git a/packages/client/src/components/preview/DNDSelectionIndicators.svelte b/packages/client/src/components/preview/DNDSelectionIndicators.svelte new file mode 100644 index 0000000000..cd7eb8302d --- /dev/null +++ b/packages/client/src/components/preview/DNDSelectionIndicators.svelte @@ -0,0 +1,40 @@ + + +{#if $dndIsDragging} + {#if !$isGridScreen && $dndParent} + + {/if} + + {#if !waitingForGrid} + + {/if} +{/if} diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index f173dfd960..e5297e9208 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -1,15 +1,50 @@ - diff --git a/packages/client/src/components/preview/GridStylesButton.svelte b/packages/client/src/components/preview/GridStylesButton.svelte index 430a0659ec..059971b0da 100644 --- a/packages/client/src/components/preview/GridStylesButton.svelte +++ b/packages/client/src/components/preview/GridStylesButton.svelte @@ -1,6 +1,6 @@ - +{#if !$dndIsDragging && componentId} + +{/if}} diff --git a/packages/client/src/components/preview/Indicator.svelte b/packages/client/src/components/preview/Indicator.svelte index dce7945b29..800bc0423b 100644 --- a/packages/client/src/components/preview/Indicator.svelte +++ b/packages/client/src/components/preview/Indicator.svelte @@ -1,19 +1,21 @@ - - +{#if !$dndIsDragging && $builderStore.selectedComponentId} + +{/if} diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index 9dae1dcb22..32d2e8e62e 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -4,9 +4,9 @@ import GridStylesButton from "./GridStylesButton.svelte" import SettingsColorPicker from "./SettingsColorPicker.svelte" import SettingsPicker from "./SettingsPicker.svelte" - import { builderStore, componentStore, dndIsDragging } from "stores" + import { builderStore, componentStore, dndIsDragging } from "@/stores" import { Utils, shouldDisplaySetting } from "@budibase/frontend-core" - import { getGridVar, GridParams, Devices } from "utils/grid" + import { getGridVar, GridParams, Devices } from "@/utils/grid" const context = getContext("context") const verticalOffset = 36 diff --git a/packages/client/src/components/preview/SettingsButton.svelte b/packages/client/src/components/preview/SettingsButton.svelte index 16a4fe23d0..01e5964917 100644 --- a/packages/client/src/components/preview/SettingsButton.svelte +++ b/packages/client/src/components/preview/SettingsButton.svelte @@ -1,6 +1,6 @@ @@ -28,27 +14,27 @@ /> - - + + - - + + - + - - - - + + + + - {title} - {#if favicon !== ""} - + {props.title} + {#if props.favicon !== ""} + {:else} {/if} @@ -105,11 +91,15 @@ - {#if showSkeletonLoader} - + {#if props.showSkeletonLoader} + {/if}
- {#if clientLibPath} + {#if props.clientLibPath}

There was an error loading your app

The Budibase client library could not be loaded. Try republishing your @@ -120,24 +110,24 @@

{/if}

- - {#if appMigrating} - {/if} - - {#if usedPlugins?.length} - {#each usedPlugins as plugin} + {#if props.usedPlugins?.length} + {#each props.usedPlugins as plugin} {/each} {/if} -