forked from tsai/budibase
11 changed files with 230 additions and 106 deletions
@ -0,0 +1,72 @@ |
|||
<script> |
|||
import { Search, Layout, Select } from "@budibase/bbui" |
|||
import NavigationPanel from "components/design/NavigationPanel/NavigationPanel.svelte" |
|||
import { roles } from "stores/backend" |
|||
import { store } from "builderStore" |
|||
import NavItem from "components/common/NavItem.svelte" |
|||
import ScreenDropdownMenu from "./ScreenDropdownMenu.svelte" |
|||
import { RoleColours } from "constants" |
|||
import ScreenWizard from "./ScreenWizard.svelte" |
|||
let searchString |
|||
let accessRole = "all" |
|||
let showNewScreenModal |
|||
|
|||
$: filteredScreens = getFilteredScreens( |
|||
$store.screens, |
|||
searchString, |
|||
accessRole |
|||
) |
|||
|
|||
const getFilteredScreens = (screens, search, role) => { |
|||
return screens |
|||
.filter(screen => { |
|||
const searchMatch = !search || screen.routing.route.includes(search) |
|||
const roleMatch = |
|||
!role || role === "all" || screen.routing.roleId === role |
|||
return searchMatch && roleMatch |
|||
}) |
|||
.slice() |
|||
.sort((a, b) => { |
|||
return a.routing.route < b.routing.route ? -1 : 1 |
|||
}) |
|||
} |
|||
|
|||
const getRoleColor = roleId => { |
|||
return RoleColours[roleId] || "#ffa500" |
|||
} |
|||
</script> |
|||
|
|||
<NavigationPanel |
|||
title="Screens" |
|||
showAddButton |
|||
onClickAddButton={showNewScreenModal} |
|||
> |
|||
<Layout paddingX="L" paddingY="XL" gap="S"> |
|||
<Search |
|||
placeholder="Enter a route to search" |
|||
value={searchString} |
|||
on:change={e => (searchString = e.detail)} |
|||
/> |
|||
<Select |
|||
bind:value={accessRole} |
|||
placeholder={null} |
|||
getOptionLabel={role => role.name} |
|||
getOptionValue={role => role._id} |
|||
options={[{ name: "All screens", _id: "all" }, ...$roles]} |
|||
/> |
|||
</Layout> |
|||
{#each filteredScreens as screen (screen._id)} |
|||
<NavItem |
|||
icon={screen.routing.homeScreen ? "Home" : "WebPage"} |
|||
indentLevel={0} |
|||
selected={$store.selectedScreenId === screen._id} |
|||
text={screen.routing.route} |
|||
on:click={() => ($store.selectedScreenId = screen._id)} |
|||
color={getRoleColor(screen.routing.roleId)} |
|||
> |
|||
<ScreenDropdownMenu screenId={screen._id} /> |
|||
</NavItem> |
|||
{/each} |
|||
</NavigationPanel> |
|||
|
|||
<ScreenWizard bind:showModal={showNewScreenModal} /> |
|||
@ -0,0 +1,146 @@ |
|||
<script> |
|||
import { selectedScreen } from "builderStore" |
|||
import SettingsPanel from "components/design/SettingsPanel/SettingsPanel.svelte" |
|||
import { get } from "svelte/store" |
|||
import { get as deepGet, setWith } from "lodash" |
|||
import { |
|||
Input, |
|||
Layout, |
|||
Button, |
|||
Toggle, |
|||
Checkbox, |
|||
notifications, |
|||
} from "@budibase/bbui" |
|||
import PropertyControl from "components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte" |
|||
import RoleSelect from "components/design/PropertiesPanel/PropertyControls/RoleSelect.svelte" |
|||
import { currentAsset, store, selectedAccessRole } from "builderStore" |
|||
import { FrontendTypes } from "constants" |
|||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl" |
|||
|
|||
let errors = {} |
|||
|
|||
const routeTaken = url => { |
|||
const roleId = get(selectedAccessRole) || "BASIC" |
|||
return get(store).screens.some( |
|||
screen => |
|||
screen.routing.route.toLowerCase() === url.toLowerCase() && |
|||
screen.routing.roleId === roleId |
|||
) |
|||
} |
|||
|
|||
const roleTaken = roleId => { |
|||
const url = get(currentAsset)?.routing.route |
|||
return get(store).screens.some( |
|||
screen => |
|||
screen.routing.route.toLowerCase() === url.toLowerCase() && |
|||
screen.routing.roleId === roleId |
|||
) |
|||
} |
|||
|
|||
const setAssetProps = (name, value, parser, validate) => { |
|||
if (parser) { |
|||
value = parser(value) |
|||
} |
|||
if (validate) { |
|||
const error = validate(value) |
|||
errors = { |
|||
...errors, |
|||
[name]: error, |
|||
} |
|||
if (error) { |
|||
return |
|||
} |
|||
} else { |
|||
errors = { |
|||
...errors, |
|||
[name]: null, |
|||
} |
|||
} |
|||
|
|||
const selectedAsset = get(currentAsset) |
|||
store.update(state => { |
|||
if ( |
|||
name === "_instanceName" && |
|||
state.currentFrontEndType === FrontendTypes.SCREEN |
|||
) { |
|||
selectedAsset.props._instanceName = value |
|||
} else { |
|||
setWith(selectedAsset, name.split("."), value, Object) |
|||
} |
|||
return state |
|||
}) |
|||
|
|||
try { |
|||
store.actions.preview.saveSelected() |
|||
} catch (error) { |
|||
notifications.error("Error saving settings") |
|||
} |
|||
} |
|||
|
|||
const screenSettings = [ |
|||
{ |
|||
key: "routing.homeScreen", |
|||
control: Checkbox, |
|||
props: { |
|||
text: "Set as home screen", |
|||
}, |
|||
}, |
|||
{ |
|||
key: "routing.route", |
|||
label: "Route", |
|||
control: Input, |
|||
parser: val => { |
|||
if (!val.startsWith("/")) { |
|||
val = "/" + val |
|||
} |
|||
return sanitizeUrl(val) |
|||
}, |
|||
validate: val => { |
|||
const exisingValue = get(currentAsset)?.routing.route |
|||
if (val !== exisingValue && routeTaken(val)) { |
|||
return "That URL is already in use for this role" |
|||
} |
|||
return null |
|||
}, |
|||
}, |
|||
{ |
|||
key: "routing.roleId", |
|||
label: "Access", |
|||
control: RoleSelect, |
|||
validate: val => { |
|||
const exisingValue = get(currentAsset)?.routing.roleId |
|||
if (val !== exisingValue && roleTaken(val)) { |
|||
return "That role is already in use for this URL" |
|||
} |
|||
return null |
|||
}, |
|||
}, |
|||
{ |
|||
key: "showNavigation", |
|||
label: "Navigation", |
|||
control: Toggle, |
|||
props: { |
|||
text: "Show navigation", |
|||
}, |
|||
}, |
|||
] |
|||
</script> |
|||
|
|||
<SettingsPanel |
|||
title={$selectedScreen?.routing.route} |
|||
icon={$selectedScreen.routing.route === "/" ? "Home" : "WebPage"} |
|||
> |
|||
<Layout gap="S" paddingX="L" paddingY="XL"> |
|||
{#each screenSettings as def (def.key)} |
|||
<PropertyControl |
|||
control={def.control} |
|||
label={def.label} |
|||
key={def.key} |
|||
value={deepGet($currentAsset, def.key)} |
|||
onChange={val => setAssetProps(def.key, val, def.parser, def.validate)} |
|||
props={{ ...def.props, error: errors[def.key] }} |
|||
/> |
|||
{/each} |
|||
<Button cta>View components</Button> |
|||
</Layout> |
|||
</SettingsPanel> |
|||
Loading…
Reference in new issue