can delete screens

This commit is contained in:
Michael Shanks 2020-07-21 15:01:32 +01:00
parent 09fda4b703
commit 3b4c68163d
6 changed files with 163 additions and 37 deletions

View File

@ -53,7 +53,6 @@ export const getStore = () => {
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store) store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store)
store.saveScreen = saveScreen(store) store.saveScreen = saveScreen(store)
store.deleteScreen = deleteScreen(store)
store.setCurrentScreen = setCurrentScreen(store) store.setCurrentScreen = setCurrentScreen(store)
store.setCurrentPage = setCurrentPage(store) store.setCurrentPage = setCurrentPage(store)
store.createScreen = createScreen(store) store.createScreen = createScreen(store)
@ -162,6 +161,7 @@ const createScreen = store => (screenName, route, layoutComponentName) => {
props: createProps(rootComponent).props, props: createProps(rootComponent).props,
} }
newScreen.route = route newScreen.route = route
newScreen.name = newScreen.props._id
newScreen.props._instanceName = screenName || "" newScreen.props._instanceName = screenName || ""
state.currentPreviewItem = newScreen state.currentPreviewItem = newScreen
state.currentComponentInfo = newScreen.props state.currentComponentInfo = newScreen.props
@ -191,24 +191,6 @@ const setCurrentScreen = store => screenName => {
}) })
} }
const deleteScreen = store => name => {
store.update(s => {
const components = s.components.filter(c => c.name !== name)
const screens = s.screens.filter(c => c.name !== name)
s.components = components
s.screens = screens
if (s.currentPreviewItem.name === name) {
s.currentPreviewItem = null
s.currentFrontEndType = ""
}
api.delete(`/_builder/api/${s.appId}/screen/${name}`)
return s
})
}
const savePage = store => async page => { const savePage = store => async page => {
store.update(state => { store.update(state => {
if (state.currentFrontEndType !== "page" || !state.currentPageName) { if (state.currentFrontEndType !== "page" || !state.currentPageName) {

View File

@ -6,6 +6,7 @@
import { pipe } from "components/common/core" import { pipe } from "components/common/core"
import { store } from "builderStore" import { store } from "builderStore"
import { ArrowDownIcon, ShapeIcon } from "components/common/Icons/" import { ArrowDownIcon, ShapeIcon } from "components/common/Icons/"
import ScreenDropdownMenu from "./ScreenDropdownMenu.svelte"
export let screens = [] export let screens = []
@ -15,12 +16,15 @@
const joinPath = join("/") const joinPath = join("/")
const normalizedName = name => const normalizedName = name =>
pipe(name, [ pipe(
trimCharsStart("./"), name,
trimCharsStart("~/"), [
trimCharsStart("../"), trimCharsStart("./"),
trimChars(" "), trimCharsStart("~/"),
]) trimCharsStart("../"),
trimChars(" "),
]
)
const changeScreen = screen => { const changeScreen = screen => {
store.setCurrentScreen(screen.props._instanceName) store.setCurrentScreen(screen.props._instanceName)
@ -31,7 +35,7 @@
<div class="root"> <div class="root">
{#each screens as screen} {#each screens as screen}
<div <div
class="budibase__nav-item component" class="budibase__nav-item screen-header-row"
class:selected={$store.currentComponentInfo._id === screen.props._id} class:selected={$store.currentComponentInfo._id === screen.props._id}
on:click|stopPropagation={() => changeScreen(screen)}> on:click|stopPropagation={() => changeScreen(screen)}>
@ -46,6 +50,10 @@
<i class="ri-artboard-2-fill icon" /> <i class="ri-artboard-2-fill icon" />
<span class="title">{screen.props._instanceName}</span> <span class="title">{screen.props._instanceName}</span>
<div class="dropdown-menu">
<ScreenDropdownMenu {screen} />
</div>
</div> </div>
{#if $store.currentPreviewItem.props._instanceName && $store.currentPreviewItem.props._instanceName === screen.props._instanceName && screen.props._children} {#if $store.currentPreviewItem.props._instanceName && $store.currentPreviewItem.props._instanceName === screen.props._instanceName && screen.props._children}
@ -63,10 +71,16 @@
color: var(--ink); color: var(--ink);
} }
.screen-header-row {
display: flex;
flex-direction: row;
}
.title { .title {
margin-left: 14px; margin-left: 14px;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
flex: 1;
} }
.icon { .icon {
@ -89,4 +103,20 @@
.rotate :global(svg) { .rotate :global(svg) {
transform: rotate(-90deg); transform: rotate(-90deg);
} }
.dropdown-menu {
display: none;
height: 24px;
width: 24px;
color: var(--ink);
padding: 0px 5px;
border-style: none;
background: rgba(0, 0, 0, 0);
cursor: pointer;
position: relative;
}
.budibase__nav-item:hover .dropdown-menu {
display: block;
}
</style> </style>

View File

@ -19,7 +19,11 @@
const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1) const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1)
const get_name = s => (!s ? "" : last(s.split("/"))) const get_name = s => (!s ? "" : last(s.split("/")))
const get_capitalised_name = name => pipe(name, [get_name, capitalise]) const get_capitalised_name = name =>
pipe(
name,
[get_name, capitalise]
)
const isScreenslot = name => name === "##builtin/screenslot" const isScreenslot = name => name === "##builtin/screenslot"
const selectComponent = component => { const selectComponent = component => {

View File

@ -0,0 +1,115 @@
<script>
import { MoreIcon } from "components/common/Icons"
import { store } from "builderStore"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import UIkit from "uikit"
import api from "builderStore/api"
export let screen
let confirmDeleteDialog
let dropdownEl
$: dropdown = UIkit.dropdown(dropdownEl, {
mode: "click",
offset: 0,
pos: "bottom-right",
"delay-hide": 0,
animation: false,
})
$: dropdown && UIkit.util.on(dropdown, "shown", () => (hidden = false))
const hideDropdown = () => {
dropdown.hide()
}
const deleteScreen = () => {
store.update(s => {
const screens = s.screens.filter(c => c.name !== screen.name)
s.screens = screens
if (s.currentPreviewItem.name === screen.name) {
s.currentPreviewItem = s.pages[s.currentPageName]
s.currentFrontEndType = "page"
}
api.delete(
`/_builder/api/pages/${s.currentPageName}/screens/${screen.name}`
)
return s
})
}
</script>
<div class="root boundary" on:click|stopPropagation={() => {}}>
<button>
<MoreIcon />
</button>
<ul class="menu" bind:this={dropdownEl} on:click={hideDropdown}>
<li class="item" on:click={() => confirmDeleteDialog.show()}>
<i class="icon ri-delete-bin-2-line" />
Delete
</li>
</ul>
</div>
<ConfirmDialog
bind:this={confirmDeleteDialog}
title="Confirm Delete"
body={`Are you sure you wish to delete the screen '${screen.props._instanceName}' ?`}
okText="Delete Screen"
onOk={deleteScreen} />
<style>
.root {
overflow: hidden;
z-index: 9;
}
.root button {
border-style: none;
border-radius: 2px;
padding: 5px;
background: transparent;
cursor: pointer;
color: var(--ink);
outline: none;
}
.menu {
z-index: 100000;
overflow: visible;
padding: 12px 0px;
border-radius: 5px;
}
.menu li {
border-style: none;
background-color: transparent;
list-style-type: none;
padding: 4px 16px;
margin: 0;
width: 100%;
box-sizing: border-box;
}
.item {
display: flex;
align-items: center;
font-size: 14px;
}
.icon {
margin-right: 8px;
}
.menu li:not(.disabled) {
cursor: pointer;
color: var(--grey-7);
}
.menu li:not(.disabled):hover {
color: var(--ink);
background-color: var(--grey-1);
}
</style>

View File

@ -69,19 +69,14 @@ router.patch(
) )
router.delete( router.delete(
"/_builder/api/:appname/pages/:pagename/screen/*", "/_builder/api/pages/:pagename/screens/:id",
authorized(BUILDER), authorized(BUILDER),
async ctx => { async ctx => {
const name = ctx.request.path.replace(
`/_builder/api/${ctx.params.appname}/pages/${ctx.params.pagename}/screen/`,
""
)
await deleteScreen( await deleteScreen(
ctx.config, ctx.config,
ctx.params.appname, ctx.user.appId,
ctx.params.pagename, ctx.params.pagename,
decodeURI(name) ctx.params.id
) )
ctx.response.status = StatusCodes.OK ctx.response.status = StatusCodes.OK

View File

@ -75,8 +75,8 @@ module.exports.renameScreen = async (
await rename(oldComponentPath, newComponentPath) await rename(oldComponentPath, newComponentPath)
} }
module.exports.deleteScreen = async (config, appname, pagename, name) => { module.exports.deleteScreen = async (config, appId, pagename, name) => {
const appPath = appPackageFolder(config, appname) const appPath = appPackageFolder(config, appId)
const componentFile = screenPath(appPath, pagename, name) const componentFile = screenPath(appPath, pagename, name)
await unlink(componentFile) await unlink(componentFile)