Update routify structure to prevent remounting full page when changing URL params and update nav item wrapping
This commit is contained in:
parent
300f1e8ab1
commit
1e59576a30
|
@ -39,6 +39,7 @@
|
||||||
class:spectrum-StatusLight--negative={negative}
|
class:spectrum-StatusLight--negative={negative}
|
||||||
class:spectrum-StatusLight--disabled={disabled}
|
class:spectrum-StatusLight--disabled={disabled}
|
||||||
class:spectrum-StatusLight--active={active}
|
class:spectrum-StatusLight--active={active}
|
||||||
|
class:withText={!!$$slots.default}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,6 +50,10 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
--spectrum-statuslight-info-text-gap: 4px;
|
||||||
|
}
|
||||||
|
.spectrum-StatusLight.withText::before {
|
||||||
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
.custom::before {
|
.custom::before {
|
||||||
background: var(--color) !important;
|
background: var(--color) !important;
|
||||||
|
|
|
@ -9,10 +9,13 @@ export const store = getFrontendStore()
|
||||||
export const automationStore = getAutomationStore()
|
export const automationStore = getAutomationStore()
|
||||||
export const themeStore = getThemeStore()
|
export const themeStore = getThemeStore()
|
||||||
|
|
||||||
|
export const selectedScreen = derived(store, $store => {
|
||||||
|
return $store.screens.find(screen => screen._id === $store.selectedScreenId)
|
||||||
|
})
|
||||||
|
|
||||||
export const currentAsset = derived(store, $store => {
|
export const currentAsset = derived(store, $store => {
|
||||||
const type = $store.currentFrontEndType
|
const type = $store.currentFrontEndType
|
||||||
if (type === FrontendTypes.SCREEN) {
|
if (type === FrontendTypes.SCREEN) {
|
||||||
return $store.screens.find(screen => screen._id === $store.selectedScreenId)
|
|
||||||
} else if (type === FrontendTypes.LAYOUT) {
|
} else if (type === FrontendTypes.LAYOUT) {
|
||||||
return $store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
return $store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
||||||
}
|
}
|
||||||
|
@ -39,21 +42,10 @@ export const selectedComponentPath = derived(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const currentAssetId = derived(store, $store => {
|
|
||||||
return $store.currentFrontEndType === FrontendTypes.SCREEN
|
|
||||||
? $store.selectedScreenId
|
|
||||||
: $store.selectedLayoutId
|
|
||||||
})
|
|
||||||
|
|
||||||
export const currentAssetName = derived(currentAsset, $currentAsset => {
|
export const currentAssetName = derived(currentAsset, $currentAsset => {
|
||||||
return $currentAsset?.name
|
return $currentAsset?.name
|
||||||
})
|
})
|
||||||
|
|
||||||
// leave this as before for consistency
|
|
||||||
export const allScreens = derived(store, $store => {
|
|
||||||
return $store.screens
|
|
||||||
})
|
|
||||||
|
|
||||||
export const mainLayout = derived(store, $store => {
|
export const mainLayout = derived(store, $store => {
|
||||||
return $store.layouts?.find(
|
return $store.layouts?.find(
|
||||||
layout => layout._id === LAYOUT_NAMES.MASTER.PRIVATE
|
layout => layout._id === LAYOUT_NAMES.MASTER.PRIVATE
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { get, writable } from "svelte/store"
|
import { get, writable } from "svelte/store"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import {
|
import {
|
||||||
allScreens,
|
|
||||||
currentAsset,
|
currentAsset,
|
||||||
mainLayout,
|
mainLayout,
|
||||||
selectedComponent,
|
selectedComponent,
|
||||||
|
@ -148,7 +147,7 @@ export const getFrontendStore = () => {
|
||||||
screens: {
|
screens: {
|
||||||
select: screenId => {
|
select: screenId => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
let screens = get(allScreens)
|
let screens = state.screens
|
||||||
let screen =
|
let screen =
|
||||||
screens.find(screen => screen._id === screenId) || screens[0]
|
screens.find(screen => screen._id === screenId) || screens[0]
|
||||||
if (!screen) return state
|
if (!screen) return state
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import { allScreens, store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { tables, datasources } from "stores/backend"
|
import { tables, datasources } from "stores/backend"
|
||||||
import {
|
import {
|
||||||
ActionMenu,
|
ActionMenu,
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
$: allowDeletion = !external || table?.created
|
$: allowDeletion = !external || table?.created
|
||||||
|
|
||||||
function showDeleteModal() {
|
function showDeleteModal() {
|
||||||
templateScreens = $allScreens.filter(
|
templateScreens = $store.screens.filter(
|
||||||
screen => screen.autoTableId === table._id
|
screen => screen.autoTableId === table._id
|
||||||
)
|
)
|
||||||
willBeDeleted = ["All table data"].concat(
|
willBeDeleted = ["All table data"].concat(
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
class:border
|
class:border
|
||||||
class:selected
|
class:selected
|
||||||
|
class:withActions
|
||||||
style={`padding-left: ${14 + indentLevel * 14}px`}
|
style={`padding-left: ${14 + indentLevel * 14}px`}
|
||||||
{draggable}
|
{draggable}
|
||||||
on:dragend
|
on:dragend
|
||||||
|
@ -80,7 +81,9 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if color}
|
{#if color}
|
||||||
|
<div class="light">
|
||||||
<StatusLight size="L" {color} />
|
<StatusLight size="L" {color} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,7 +94,7 @@
|
||||||
color: var(--grey-7);
|
color: var(--grey-7);
|
||||||
transition: background-color
|
transition: background-color
|
||||||
var(--spectrum-global-animation-duration-100, 130ms) ease-in-out;
|
var(--spectrum-global-animation-duration-100, 130ms) ease-in-out;
|
||||||
padding: 0 var(--spacing-m) 0 var(--spacing-l);
|
padding: 0 var(--spacing-l) 0;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -111,9 +114,8 @@
|
||||||
background-color: var(--grey-3);
|
background-color: var(--grey-3);
|
||||||
}
|
}
|
||||||
.nav-item:hover .actions {
|
.nav-item:hover .actions {
|
||||||
visibility: visible;
|
display: grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item-content {
|
.nav-item-content {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -122,6 +124,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-xs);
|
gap: var(--spacing-xs);
|
||||||
width: max-content;
|
width: max-content;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
@ -157,19 +160,23 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
visibility: hidden;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: grid;
|
display: none;
|
||||||
margin-left: var(--spacing-s);
|
|
||||||
place-items: center;
|
place-items: center;
|
||||||
}
|
}
|
||||||
|
.actions,
|
||||||
|
.light :global(.spectrum-StatusLight) {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-left: var(--spacing-s);
|
||||||
|
}
|
||||||
.iconText {
|
.iconText {
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
font-size: var(--spectrum-global-dimension-font-size-50);
|
font-size: var(--spectrum-global-dimension-font-size-50);
|
||||||
flex: 0 0 34px;
|
flex: 0 0 34px;
|
||||||
}
|
}
|
||||||
|
.nav-item.withActions:hover .light {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { onMount, onDestroy } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import { store, currentAsset, allScreens } from "builderStore"
|
import { store, selectedScreen, currentAsset } from "builderStore"
|
||||||
import iframeTemplate from "./iframeTemplate"
|
import iframeTemplate from "./iframeTemplate"
|
||||||
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
// Extract data to pass to the iframe
|
// Extract data to pass to the iframe
|
||||||
$: {
|
$: {
|
||||||
screen = $allScreens.find(x => x._id === $store.selectedScreenId)
|
screen = $selectedScreen
|
||||||
layout = $store.layouts.find(layout => layout._id === screen?.layoutId)
|
layout = $store.layouts.find(layout => layout._id === screen?.layoutId)
|
||||||
}
|
}
|
||||||
$: selectedComponentId = $store.selectedComponentId ?? ""
|
$: selectedComponentId = $store.selectedComponentId ?? ""
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount, setContext } from "svelte"
|
import { onMount, setContext } from "svelte"
|
||||||
import { goto, params } from "@roxi/routify"
|
import { goto, params } from "@roxi/routify"
|
||||||
import {
|
import { store, selectedAccessRole, screenSearchString } from "builderStore"
|
||||||
store,
|
|
||||||
allScreens,
|
|
||||||
selectedAccessRole,
|
|
||||||
screenSearchString,
|
|
||||||
} from "builderStore"
|
|
||||||
import { roles } from "stores/backend"
|
import { roles } from "stores/backend"
|
||||||
import ComponentNavigationTree from "components/design/NavigationPanel/ComponentNavigationTree/index.svelte"
|
import ComponentNavigationTree from "components/design/NavigationPanel/ComponentNavigationTree/index.svelte"
|
||||||
import Layout from "components/design/NavigationPanel/Layout.svelte"
|
import Layout from "components/design/NavigationPanel/Layout.svelte"
|
||||||
|
@ -99,7 +94,7 @@
|
||||||
// Select a valid screen with this new role - otherwise we'll not be
|
// Select a valid screen with this new role - otherwise we'll not be
|
||||||
// able to change role at all because ComponentNavigationTree will kick us
|
// able to change role at all because ComponentNavigationTree will kick us
|
||||||
// back the current role again because the same screen ID is still selected
|
// back the current role again because the same screen ID is still selected
|
||||||
const firstValidScreenId = $allScreens.find(
|
const firstValidScreenId = $store.screens.find(
|
||||||
screen => screen.routing.roleId === role
|
screen => screen.routing.roleId === role
|
||||||
)?._id
|
)?._id
|
||||||
if (firstValidScreenId) {
|
if (firstValidScreenId) {
|
||||||
|
|
|
@ -31,11 +31,12 @@
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
|
height: 55px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: var(--spacing-m) var(--spacing-l);
|
padding: 0 var(--spacing-l);
|
||||||
border-bottom: var(--border-light);
|
border-bottom: var(--border-light);
|
||||||
gap: var(--spacing-l);
|
gap: var(--spacing-l);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { currentAsset, store } from "builderStore"
|
import { currentAsset, store } from "builderStore"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||||
import { allScreens, selectedAccessRole } from "builderStore"
|
import { store, selectedAccessRole } from "builderStore"
|
||||||
|
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
export let bindings
|
export let bindings
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
const routeTaken = url => {
|
const routeTaken = url => {
|
||||||
const roleId = get(selectedAccessRole) || "BASIC"
|
const roleId = get(selectedAccessRole) || "BASIC"
|
||||||
return get(allScreens).some(
|
return get(store).screens.some(
|
||||||
screen =>
|
screen =>
|
||||||
screen.routing.route.toLowerCase() === url.toLowerCase() &&
|
screen.routing.route.toLowerCase() === url.toLowerCase() &&
|
||||||
screen.routing.roleId === roleId
|
screen.routing.roleId === roleId
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
const roleTaken = roleId => {
|
const roleTaken = roleId => {
|
||||||
const url = get(currentAsset)?.routing.route
|
const url = get(currentAsset)?.routing.route
|
||||||
return get(allScreens).some(
|
return get(store).screens.some(
|
||||||
screen =>
|
screen =>
|
||||||
screen.routing.route.toLowerCase() === url.toLowerCase() &&
|
screen.routing.route.toLowerCase() === url.toLowerCase() &&
|
||||||
screen.routing.roleId === roleId
|
screen.routing.roleId === roleId
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import { Icon, Heading } from "@budibase/bbui"
|
||||||
|
|
||||||
|
export let title
|
||||||
|
export let icon
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="settings-panel">
|
||||||
|
{#if title}
|
||||||
|
<div class="header">
|
||||||
|
{#if icon}
|
||||||
|
<Icon name={icon} />
|
||||||
|
{/if}
|
||||||
|
<div class="title">
|
||||||
|
<Heading size="XS">{title || ""}</Heading>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.settings-panel {
|
||||||
|
width: 260px;
|
||||||
|
background: var(--background);
|
||||||
|
border-left: var(--border-light);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
height: 55px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 var(--spacing-l);
|
||||||
|
border-bottom: var(--border-light);
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.header :global(*) {
|
||||||
|
color: var(--spectrum-global-color-gray-700);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
.title :global(h1) {
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: 600;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,7 +2,7 @@ import { get } from "svelte/store"
|
||||||
import { isChangingPage } from "@roxi/routify"
|
import { isChangingPage } from "@roxi/routify"
|
||||||
|
|
||||||
export const syncURLToState = options => {
|
export const syncURLToState = options => {
|
||||||
const { keys, params, store, goto, redirect } = options || {}
|
const { keys, params, store, goto, redirect, baseUrl = "." } = options || {}
|
||||||
if (
|
if (
|
||||||
!keys?.length ||
|
!keys?.length ||
|
||||||
!params?.subscribe ||
|
!params?.subscribe ||
|
||||||
|
@ -22,13 +22,15 @@ export const syncURLToState = options => {
|
||||||
let cachedGoto = get(goto)
|
let cachedGoto = get(goto)
|
||||||
let cachedRedirect = get(redirect)
|
let cachedRedirect = get(redirect)
|
||||||
let hydrated = false
|
let hydrated = false
|
||||||
|
let debug = false
|
||||||
|
const log = (...params) => debug && console.log(...params)
|
||||||
|
|
||||||
// Navigate to a certain URL
|
// Navigate to a certain URL
|
||||||
const gotoUrl = url => {
|
const gotoUrl = url => {
|
||||||
if (get(isChangingPage) && hydrated) {
|
if (get(isChangingPage) && hydrated) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log("Navigating to", url)
|
log("Navigating to", url)
|
||||||
cachedGoto(url)
|
cachedGoto(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +39,7 @@ export const syncURLToState = options => {
|
||||||
if (get(isChangingPage) && hydrated) {
|
if (get(isChangingPage) && hydrated) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log("Redirecting to", url)
|
log("Redirecting to", url)
|
||||||
cachedRedirect(url)
|
cachedRedirect(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +52,7 @@ export const syncURLToState = options => {
|
||||||
const urlValue = params?.[key.url]
|
const urlValue = params?.[key.url]
|
||||||
const stateValue = state?.[key.state]
|
const stateValue = state?.[key.state]
|
||||||
if (urlValue && urlValue !== stateValue) {
|
if (urlValue && urlValue !== stateValue) {
|
||||||
console.log(
|
log(
|
||||||
`state.${key.state} (${stateValue}) <= url.${key.url} (${urlValue})`
|
`state.${key.state} (${stateValue}) <= url.${key.url} (${urlValue})`
|
||||||
)
|
)
|
||||||
stateUpdates.push(state => {
|
stateUpdates.push(state => {
|
||||||
|
@ -58,7 +60,7 @@ export const syncURLToState = options => {
|
||||||
})
|
})
|
||||||
if (key.validate && key.fallbackUrl) {
|
if (key.validate && key.fallbackUrl) {
|
||||||
if (!key.validate(urlValue)) {
|
if (!key.validate(urlValue)) {
|
||||||
console.log("Invalid URL param!")
|
log("Invalid URL param!")
|
||||||
redirectUrl(key.fallbackUrl)
|
redirectUrl(key.fallbackUrl)
|
||||||
hydrated = true
|
hydrated = true
|
||||||
return
|
return
|
||||||
|
@ -77,7 +79,7 @@ export const syncURLToState = options => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the required state updates
|
// Apply the required state updates
|
||||||
console.log("Performing", stateUpdates.length, "state updates")
|
log("Performing", stateUpdates.length, "state updates")
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
for (let update of stateUpdates) {
|
for (let update of stateUpdates) {
|
||||||
update(state)
|
update(state)
|
||||||
|
@ -89,7 +91,7 @@ export const syncURLToState = options => {
|
||||||
// Updates the URL with new state values
|
// Updates the URL with new state values
|
||||||
const mapStateToUrl = state => {
|
const mapStateToUrl = state => {
|
||||||
// Determine new URL while checking for changes
|
// Determine new URL while checking for changes
|
||||||
let url = ".."
|
let url = baseUrl
|
||||||
let needsUpdate = false
|
let needsUpdate = false
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
const urlValue = cachedParams?.[key.url]
|
const urlValue = cachedParams?.[key.url]
|
||||||
|
@ -97,12 +99,12 @@ export const syncURLToState = options => {
|
||||||
url += `/${stateValue}`
|
url += `/${stateValue}`
|
||||||
if (stateValue !== urlValue) {
|
if (stateValue !== urlValue) {
|
||||||
needsUpdate = true
|
needsUpdate = true
|
||||||
console.log(
|
log(
|
||||||
`url.${key.url} (${urlValue}) <= state.${key.state} (${stateValue})`
|
`url.${key.url} (${urlValue}) <= state.${key.state} (${stateValue})`
|
||||||
)
|
)
|
||||||
if (key.validate && key.fallbackUrl) {
|
if (key.validate && key.fallbackUrl) {
|
||||||
if (!key.validate(stateValue)) {
|
if (!key.validate(stateValue)) {
|
||||||
console.log("Invalid state param!")
|
log("Invalid state param!")
|
||||||
redirectUrl(key.fallbackUrl)
|
redirectUrl(key.fallbackUrl)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<script>
|
|
||||||
import { redirect } from "@roxi/routify"
|
|
||||||
|
|
||||||
$redirect(`./screens`)
|
|
||||||
</script>
|
|
|
@ -1 +0,0 @@
|
||||||
<slot />
|
|
|
@ -1,30 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { IconSideNav, IconSideNavItem } from "@budibase/bbui"
|
import { IconSideNav, IconSideNavItem } from "@budibase/bbui"
|
||||||
import { params, goto, redirect, isActive } from "@roxi/routify"
|
import { goto, isActive } from "@roxi/routify"
|
||||||
import { store, allScreens } from "builderStore"
|
|
||||||
import { syncURLToState } from "helpers/urlStateSync"
|
|
||||||
import { onDestroy } from "svelte"
|
|
||||||
|
|
||||||
// Keep URL and state in sync for selected screen ID
|
|
||||||
const unsync = syncURLToState({
|
|
||||||
keys: [
|
|
||||||
{
|
|
||||||
url: "screenId",
|
|
||||||
state: "selectedScreenId",
|
|
||||||
validate: screenId => $allScreens.some(x => x._id === screenId),
|
|
||||||
fallbackUrl: "../",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
store,
|
|
||||||
params,
|
|
||||||
goto,
|
|
||||||
redirect,
|
|
||||||
})
|
|
||||||
|
|
||||||
onDestroy(unsync)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- routify:options index=1 -->
|
|
||||||
<div class="design">
|
<div class="design">
|
||||||
<div class="icon-nav">
|
<div class="icon-nav">
|
||||||
<IconSideNav>
|
<IconSideNav>
|
|
@ -1,19 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { allScreens } from "builderStore"
|
|
||||||
import { onMount } from "svelte"
|
|
||||||
import { redirect } from "@roxi/routify"
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
let loaded = false
|
$redirect(`./screens`)
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if ($allScreens?.length) {
|
|
||||||
$redirect(`./${$allScreens[0]._id}`)
|
|
||||||
} else {
|
|
||||||
loaded = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loaded}
|
|
||||||
You need to create a screen!
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -2,18 +2,26 @@
|
||||||
import { Search, Layout, Select } from "@budibase/bbui"
|
import { Search, Layout, Select } from "@budibase/bbui"
|
||||||
import NavigationPanel from "components/design/NavigationPanel/NavigationPanel.svelte"
|
import NavigationPanel from "components/design/NavigationPanel/NavigationPanel.svelte"
|
||||||
import { roles } from "stores/backend"
|
import { roles } from "stores/backend"
|
||||||
import { store, allScreens } from "builderStore"
|
import { store, selectedScreen } from "builderStore"
|
||||||
import NavItem from "components/common/NavItem.svelte"
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
import ScreenDropdownMenu from "./_components/ScreenDropdownMenu.svelte"
|
import ScreenDropdownMenu from "./_components/ScreenDropdownMenu.svelte"
|
||||||
import AppPanel from "components/design/AppPanel/AppPanel.svelte"
|
|
||||||
import { RoleColours } from "constants"
|
import { RoleColours } from "constants"
|
||||||
import ScreenWizard from "./_components/ScreenWizard.svelte"
|
import ScreenWizard from "./_components/ScreenWizard.svelte"
|
||||||
|
import { onDestroy } from "svelte"
|
||||||
|
import { syncURLToState } from "helpers/urlStateSync"
|
||||||
|
import { goto, params, redirect } from "@roxi/routify"
|
||||||
|
import AppPanel from "components/design/AppPanel/AppPanel.svelte"
|
||||||
|
import SettingsPanel from "components/design/SettingsPanel/SettingsPanel.svelte"
|
||||||
|
|
||||||
let searchString
|
let searchString
|
||||||
let accessRole = "all"
|
let accessRole = "all"
|
||||||
let showNewScreenModal
|
let showNewScreenModal
|
||||||
|
|
||||||
$: filteredScreens = getFilteredScreens($allScreens, searchString, accessRole)
|
$: filteredScreens = getFilteredScreens(
|
||||||
|
$store.screens,
|
||||||
|
searchString,
|
||||||
|
accessRole
|
||||||
|
)
|
||||||
|
|
||||||
const getFilteredScreens = (screens, search, role) => {
|
const getFilteredScreens = (screens, search, role) => {
|
||||||
return screens
|
return screens
|
||||||
|
@ -32,6 +40,24 @@
|
||||||
const getRoleColor = roleId => {
|
const getRoleColor = roleId => {
|
||||||
return RoleColours[roleId] || "pink"
|
return RoleColours[roleId] || "pink"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep URL and state in sync for selected screen ID
|
||||||
|
const stopSyncing = syncURLToState({
|
||||||
|
keys: [
|
||||||
|
{
|
||||||
|
url: "screenId",
|
||||||
|
state: "selectedScreenId",
|
||||||
|
validate: screenId => $store.screens.some(x => x._id === screenId),
|
||||||
|
fallbackUrl: "../",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
store,
|
||||||
|
params,
|
||||||
|
goto,
|
||||||
|
redirect,
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(stopSyncing)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<NavigationPanel
|
<NavigationPanel
|
||||||
|
@ -64,17 +90,14 @@
|
||||||
>
|
>
|
||||||
<ScreenDropdownMenu screenId={screen._id} />
|
<ScreenDropdownMenu screenId={screen._id} />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<!--{#if selectedScreen?._id === screen.id}-->
|
|
||||||
<!-- <ComponentTree-->
|
|
||||||
<!-- level={1}-->
|
|
||||||
<!-- components={selectedScreen.props._children}-->
|
|
||||||
<!-- currentComponent={$selectedComponent}-->
|
|
||||||
<!-- {dragDropStore}-->
|
|
||||||
<!-- />-->
|
|
||||||
<!--{/if}-->
|
|
||||||
{/each}
|
{/each}
|
||||||
</NavigationPanel>
|
</NavigationPanel>
|
||||||
|
|
||||||
<ScreenWizard bind:showModal={showNewScreenModal} />
|
|
||||||
|
|
||||||
<AppPanel />
|
<AppPanel />
|
||||||
|
|
||||||
|
<SettingsPanel
|
||||||
|
title={$selectedScreen?.routing.route}
|
||||||
|
icon={$selectedScreen.routing.route === "/" ? "Home" : "WebPage"}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ScreenWizard bind:showModal={showNewScreenModal} />
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { ModalContent, Input } from "@budibase/bbui"
|
import { ModalContent, Input } from "@budibase/bbui"
|
||||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||||
import { selectedAccessRole, allScreens } from "builderStore"
|
import { store, selectedAccessRole } from "builderStore"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
|
|
||||||
export let onConfirm
|
export let onConfirm
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
const routeExists = url => {
|
const routeExists = url => {
|
||||||
const roleId = get(selectedAccessRole) || "BASIC"
|
const roleId = get(selectedAccessRole) || "BASIC"
|
||||||
return get(allScreens).some(
|
return get(store).screens.some(
|
||||||
screen =>
|
screen =>
|
||||||
screen.routing.route.toLowerCase() === url.toLowerCase() &&
|
screen.routing.route.toLowerCase() === url.toLowerCase() &&
|
||||||
screen.routing.roleId === roleId
|
screen.routing.roleId === roleId
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import { store, allScreens } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import {
|
import {
|
||||||
ActionMenu,
|
ActionMenu,
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
let confirmDeleteDialog
|
let confirmDeleteDialog
|
||||||
let screenDetailsModal
|
let screenDetailsModal
|
||||||
|
|
||||||
$: screen = $allScreens.find(screen => screen._id === screenId)
|
$: screen = $store.screens.find(screen => screen._id === screenId)
|
||||||
|
|
||||||
const duplicateScreen = () => {
|
const duplicateScreen = () => {
|
||||||
screenDetailsModal.show()
|
screenDetailsModal.show()
|
|
@ -1,10 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { store, currentAsset, selectedComponent } from "builderStore"
|
||||||
store,
|
|
||||||
currentAsset,
|
|
||||||
selectedComponent,
|
|
||||||
allScreens,
|
|
||||||
} from "builderStore"
|
|
||||||
import { Detail, Layout, Button, Icon } from "@budibase/bbui"
|
import { Detail, Layout, Button, Icon } from "@budibase/bbui"
|
||||||
|
|
||||||
import CurrentItemPreview from "components/design/AppPreview"
|
import CurrentItemPreview from "components/design/AppPreview"
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script>
|
||||||
|
import { store } from "builderStore"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
|
let loaded = false
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if ($store.screens?.length) {
|
||||||
|
$redirect(`./${$store.screens[0]._id}`)
|
||||||
|
} else {
|
||||||
|
loaded = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loaded}
|
||||||
|
You need to create a screen!
|
||||||
|
{/if}
|
Loading…
Reference in New Issue