further changes to support persisting values when component changes
This commit is contained in:
parent
deeb1fc29f
commit
af0c722af1
|
@ -1,37 +1,71 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { Input, Icon, Body, AbsTooltip } from "@budibase/bbui"
|
import {
|
||||||
import { previewStore } from "@/stores/builder"
|
Input,
|
||||||
|
Icon,
|
||||||
|
Body,
|
||||||
|
AbsTooltip,
|
||||||
|
TooltipPosition,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import { previewStore, selectedScreen } from "@/stores/builder"
|
||||||
|
import { ComponentContext } from "@budibase/types"
|
||||||
|
|
||||||
export let baseRoute = ""
|
export let baseRoute = ""
|
||||||
export let testValue = ""
|
|
||||||
|
|
||||||
$: routeParams = baseRoute.match(/:[a-zA-Z]+/g) || []
|
let testValue: string | undefined
|
||||||
$: placeholder = (() => {
|
|
||||||
// Helper function to extract the route parameters
|
$: placeholder = getPlaceholder(baseRoute)
|
||||||
// e.g /employees/:id/:name becomes /employees/1/John for the placeholder
|
$: baseInput = createBaseInput(baseRoute)
|
||||||
if (!routeParams.length) return "Add test values"
|
$: updateTestValueFromContext($previewStore.selectedComponentContext)
|
||||||
const segments = baseRoute.split("/").slice(2)
|
$: if ($selectedScreen) {
|
||||||
let paramCount = 1
|
testValue = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPlaceholder = (route: string) => {
|
||||||
|
const trimmed = route.replace(/\/$/, "")
|
||||||
|
if (trimmed.startsWith("/:")) {
|
||||||
|
return "1"
|
||||||
|
}
|
||||||
|
const segments = trimmed.split("/").slice(2)
|
||||||
|
let count = 1
|
||||||
return segments
|
return segments
|
||||||
.map(segment => {
|
.map(segment => (segment.startsWith(":") ? count++ : segment))
|
||||||
if (segment.startsWith(":")) {
|
|
||||||
return paramCount++
|
|
||||||
}
|
|
||||||
return segment
|
|
||||||
})
|
|
||||||
.join("/")
|
.join("/")
|
||||||
})()
|
}
|
||||||
|
|
||||||
$: {
|
// This function is needed to repopulate the test value from componentContext
|
||||||
if ($previewStore.selectedComponentContext?.url?.testValue !== undefined) {
|
// when a user navigates to another component and then back again
|
||||||
testValue = $previewStore.selectedComponentContext.url.testValue
|
const updateTestValueFromContext = (context: ComponentContext | null) => {
|
||||||
|
if (context?.url && !testValue) {
|
||||||
|
const { wild, ...urlParams } = context.url
|
||||||
|
const queryParams = context.query
|
||||||
|
if (Object.values(urlParams).some(v => Boolean(v))) {
|
||||||
|
let value = baseRoute
|
||||||
|
.split("/")
|
||||||
|
.slice(2)
|
||||||
|
.map(segment =>
|
||||||
|
segment.startsWith(":")
|
||||||
|
? urlParams[segment.slice(1)] || ""
|
||||||
|
: segment
|
||||||
|
)
|
||||||
|
.join("/")
|
||||||
|
const qs = new URLSearchParams(queryParams).toString()
|
||||||
|
if (qs) {
|
||||||
|
value += `?${qs}`
|
||||||
|
}
|
||||||
|
testValue = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onVariableChange = e => {
|
const createBaseInput = (baseRoute: string) => {
|
||||||
|
return baseRoute === "/" || baseRoute.split("/")[1]?.startsWith(":")
|
||||||
|
? "/"
|
||||||
|
: `/${baseRoute.split("/")[1]}/`
|
||||||
|
}
|
||||||
|
|
||||||
|
const onVariableChange = (e: CustomEvent) => {
|
||||||
previewStore.updateUrl({ route: baseRoute, testValue: e.detail })
|
previewStore.updateUrl({ route: baseRoute, testValue: e.detail })
|
||||||
previewStore.requestComponentContext()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
@ -43,8 +77,8 @@
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<Body size="XS">URL Variable Testing</Body>
|
<Body size="XS">URL Variable Testing</Body>
|
||||||
<AbsTooltip
|
<AbsTooltip
|
||||||
text="Test how your screen behaves with different URL parameters. Enter values in the format shown in the placeholder."
|
text="Test how your screen behaves with different URL parameters. Enter values in the format shown in the placeholder below."
|
||||||
position={"bottom"}
|
position={TooltipPosition.Top}
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
|
@ -54,7 +88,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="url-test-container">
|
<div class="url-test-container">
|
||||||
<div class="base-input">
|
<div class="base-input">
|
||||||
<Input disabled={true} value={`/${baseRoute.split("/")[1]}/`} />
|
<Input disabled={true} value={baseInput} />
|
||||||
</div>
|
</div>
|
||||||
<div class="variable-input">
|
<div class="variable-input">
|
||||||
<Input
|
<Input
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
$: bindings = getBindableProperties($selectedScreen, null)
|
$: bindings = getBindableProperties($selectedScreen, null)
|
||||||
$: screenSettings = getScreenSettings($selectedScreen)
|
$: screenSettings = getScreenSettings($selectedScreen)
|
||||||
let urlTestValue = ""
|
|
||||||
|
|
||||||
let errors = {}
|
let errors = {}
|
||||||
|
|
||||||
|
@ -100,7 +99,6 @@
|
||||||
control: URLVariableTestInput,
|
control: URLVariableTestInput,
|
||||||
props: {
|
props: {
|
||||||
baseRoute: screen.routing?.route,
|
baseRoute: screen.routing?.route,
|
||||||
testValue: urlTestValue,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { BudiStore } from "../BudiStore"
|
import { BudiStore } from "../BudiStore"
|
||||||
|
import { PreviewDevice, ComponentContext } from "@budibase/types"
|
||||||
|
|
||||||
type PreviewDevice = "desktop" | "tablet" | "mobile"
|
|
||||||
type PreviewEventHandler = (name: string, payload?: any) => void
|
type PreviewEventHandler = (name: string, payload?: any) => void
|
||||||
type ComponentContext = Record<string, any>
|
|
||||||
|
|
||||||
interface PreviewState {
|
interface PreviewState {
|
||||||
previewDevice: PreviewDevice
|
previewDevice: PreviewDevice
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
componentStore,
|
componentStore,
|
||||||
navigationStore,
|
navigationStore,
|
||||||
selectedComponent,
|
selectedComponent,
|
||||||
|
previewStore,
|
||||||
} from "@/stores/builder"
|
} from "@/stores/builder"
|
||||||
import { createHistoryStore, HistoryStore } from "@/stores/builder/history"
|
import { createHistoryStore, HistoryStore } from "@/stores/builder/history"
|
||||||
import { API } from "@/api"
|
import { API } from "@/api"
|
||||||
|
@ -110,6 +111,9 @@ export class ScreenStore extends BudiStore<ScreenState> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When we select a screen, we want to clear the url binding test value
|
||||||
|
previewStore.updateUrl({ route: screen.routing.route, testValue: "" })
|
||||||
|
|
||||||
// Select new screen
|
// Select new screen
|
||||||
this.update(state => {
|
this.update(state => {
|
||||||
state.selectedScreenId = screen._id
|
state.selectedScreenId = screen._id
|
||||||
|
|
|
@ -120,15 +120,36 @@ const createRouteStore = () => {
|
||||||
return `${base}#${relativeURL}`
|
return `${base}#${relativeURL}`
|
||||||
}
|
}
|
||||||
const setTestUrlParams = (route: string, testValue: string) => {
|
const setTestUrlParams = (route: string, testValue: string) => {
|
||||||
const routeSegments = route.split("/").slice(2)
|
if (route === "/") {
|
||||||
const testSegments = testValue.split("/")
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const [pathPart, queryPart] = testValue.split("?")
|
||||||
|
const routeSegments = route.split("/").filter(Boolean)
|
||||||
|
|
||||||
|
// If first segment is a parameter (e.g. /:foo), include it in processing
|
||||||
|
const startIndex = routeSegments[0]?.startsWith(":") ? 0 : 1
|
||||||
|
const segments = routeSegments.slice(startIndex)
|
||||||
|
const testSegments = pathPart.split("/")
|
||||||
|
|
||||||
const params: Record<string, string> = {}
|
const params: Record<string, string> = {}
|
||||||
routeSegments.forEach((segment, index) => {
|
segments.forEach((segment, index) => {
|
||||||
if (segment.startsWith(":") && index < testSegments.length) {
|
if (segment.startsWith(":") && index < testSegments.length) {
|
||||||
params[segment.slice(1)] = testSegments[index]
|
params[segment.slice(1)] = testSegments[index]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const queryParams: Record<string, string> = {}
|
||||||
|
if (queryPart) {
|
||||||
|
queryPart.split("&").forEach(param => {
|
||||||
|
const [key, value] = param.split("=")
|
||||||
|
if (key && value) {
|
||||||
|
queryParams[key] = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setQueryParams({ ...queryParams })
|
||||||
store.update(state => ({ ...state, testUrlParams: params }))
|
store.update(state => ({ ...state, testUrlParams: params }))
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export type PreviewDevice = "desktop" | "tablet" | "mobile"
|
export type PreviewDevice = "desktop" | "tablet" | "mobile"
|
||||||
|
export type ComponentContext = Record<string, any>
|
||||||
|
|
Loading…
Reference in New Issue