Merge pull request #748 from Budibase/autolinks

Autolinks
This commit is contained in:
Andrew Kingston 2020-10-18 20:48:17 +01:00 committed by GitHub
commit 7c870dcfbf
6 changed files with 146 additions and 20 deletions

View File

@ -155,9 +155,13 @@ Cypress.Commands.add("navigateToFrontend", () => {
Cypress.Commands.add("createScreen", (screenName, route) => { Cypress.Commands.add("createScreen", (screenName, route) => {
cy.contains("Create New Screen").click() cy.contains("Create New Screen").click()
cy.get(".modal").within(() => { cy.get(".modal").within(() => {
cy.get("input:first").type(screenName) cy.get("input")
.eq(0)
.type(screenName)
if (route) { if (route) {
cy.get("input:last").type(route) cy.get("input")
.eq(1)
.type(route)
} }
cy.contains("Create Screen").click() cy.contains("Create Screen").click()
}) })

View File

@ -27,7 +27,9 @@ import {
regenerateCssForScreen, regenerateCssForScreen,
generateNewIdsForComponent, generateNewIdsForComponent,
getComponentDefinition, getComponentDefinition,
findChildComponentType,
} from "../storeUtils" } from "../storeUtils"
export const getStore = () => { export const getStore = () => {
const initial = { const initial = {
apps: [], apps: [],
@ -56,6 +58,7 @@ export const getStore = () => {
store.setCurrentScreen = setCurrentScreen(store) store.setCurrentScreen = setCurrentScreen(store)
store.deleteScreens = deleteScreens(store) store.deleteScreens = deleteScreens(store)
store.setCurrentPage = setCurrentPage(store) store.setCurrentPage = setCurrentPage(store)
store.createLink = createLink(store)
store.createScreen = createScreen(store) store.createScreen = createScreen(store)
store.addStylesheet = addStylesheet(store) store.addStylesheet = addStylesheet(store)
store.removeStylesheet = removeStylesheet(store) store.removeStylesheet = removeStylesheet(store)
@ -190,6 +193,58 @@ const createScreen = store => async screen => {
await savePromise await savePromise
} }
const createLink = store => async (url, title) => {
let savePromise
store.update(state => {
// Try to extract a nav component from the master screen
const nav = findChildComponentType(
state.pages.main,
"@budibase/standard-components/Navigation"
)
if (nav) {
let newLink
// Clone an existing link if one exists
if (nav._children && nav._children.length) {
// Clone existing link style
newLink = cloneDeep(nav._children[0])
// Manipulate IDs to ensure uniqueness
generateNewIdsForComponent(newLink, state, false)
// Set our new props
newLink._instanceName = `${title} Link`
newLink.url = url
newLink.text = title
} else {
// Otherwise create vanilla new link
const component = getComponentDefinition(
state,
"@budibase/standard-components/link"
)
const instanceId = get(backendUiStore).selectedDatabase._id
newLink = createProps(component, {
url,
text: title,
_instanceName: `${title} Link`,
_instanceId: instanceId,
}).props
}
// Save page and regenerate all CSS because otherwise weird things happen
nav._children = [...nav._children, newLink]
setCurrentPage("main")
regenerateCssForScreen(state.pages.main)
for (let screen of state.pages.main._screens) {
regenerateCssForScreen(screen)
}
savePromise = _savePage(state)
}
return state
})
await savePromise
}
const setCurrentScreen = store => screenName => { const setCurrentScreen = store => screenName => {
store.update(s => { store.update(s => {
const screen = getExactComponent(s.screens, screenName, true) const screen = getExactComponent(s.screens, screenName, true)

View File

@ -84,7 +84,9 @@ export const regenerateCssForScreen = screen => {
} }
export const regenerateCssForCurrentScreen = state => { export const regenerateCssForCurrentScreen = state => {
if (state.currentPreviewItem) {
regenerateCssForScreen(state.currentPreviewItem) regenerateCssForScreen(state.currentPreviewItem)
}
return state return state
} }
@ -96,3 +98,33 @@ export const generateNewIdsForComponent = (c, state, changeName = true) =>
export const getComponentDefinition = (state, name) => export const getComponentDefinition = (state, name) =>
name.startsWith("##") ? getBuiltin(name) : state.components[name] name.startsWith("##") ? getBuiltin(name) : state.components[name]
export const findChildComponentType = (node, typeToFind) => {
// Stop recursion if invalid props
if (!node || !typeToFind) {
return null
}
// Stop recursion if this element matches
if (node._component === typeToFind) {
return node
}
// Otherwise check if any children match
// Stop recursion if no valid children to process
const children = node._children || (node.props && node.props._children)
if (!children || !children.length) {
return null
}
// Recurse and check each child component
for (let child of children) {
const childResult = findChildComponentType(child, typeToFind)
if (childResult) {
return childResult
}
}
// If we reach here then no children were valid
return null
}

View File

@ -38,21 +38,21 @@
} }
async function saveTable() { async function saveTable() {
// Create table
const table = await backendUiStore.actions.tables.save({ const table = await backendUiStore.actions.tables.save({
name, name,
schema: dataImport.schema || {}, schema: dataImport.schema || {},
dataImport, dataImport,
}) })
notifier.success(`Table ${name} created successfully.`) notifier.success(`Table ${name} created successfully.`)
$goto(`./table/${table._id}`)
analytics.captureEvent("Table Created", { name }) analytics.captureEvent("Table Created", { name })
// Create auto screens
const screens = screenTemplates($store, [table]) const screens = screenTemplates($store, [table])
.filter(template => defaultScreens.includes(template.id)) .filter(template => defaultScreens.includes(template.id))
.map(template => template.create()) .map(template => template.create())
for (let screen of screens) { for (let screen of screens) {
// record the table that created this screen so we can link it later // Record the table that created this screen so we can link it later
screen.autoTableId = table._id screen.autoTableId = table._id
try { try {
await store.createScreen(screen) await store.createScreen(screen)
@ -65,6 +65,15 @@
// we should remove this after this has been released // we should remove this after this has been released
} }
} }
// Create autolink to newly created list page
const listPage = screens.find(screen =>
screen.props._instanceName.endsWith("List")
)
await store.createLink(listPage.route, table.name)
// Navigate to new table
$goto(`./table/${table._id}`)
} }
</script> </script>

View File

@ -1,7 +1,14 @@
<script> <script>
import { goto } from "@sveltech/routify" import { goto } from "@sveltech/routify"
import { store, backendUiStore } from "builderStore" import { store, backendUiStore } from "builderStore"
import { Input, Button, Spacer, Select, ModalContent } from "@budibase/bbui" import {
Input,
Button,
Spacer,
Select,
ModalContent,
Toggle,
} from "@budibase/bbui"
import getTemplates from "builderStore/store/screenTemplates" import getTemplates from "builderStore/store/screenTemplates"
import { some } from "lodash/fp" import { some } from "lodash/fp"
import analytics from "analytics" import analytics from "analytics"
@ -13,6 +20,7 @@
let baseComponent = CONTAINER let baseComponent = CONTAINER
let templateIndex let templateIndex
let draftScreen let draftScreen
let createLink = true
$: templates = getTemplates($store, $backendUiStore.tables) $: templates = getTemplates($store, $backendUiStore.tables)
@ -46,7 +54,7 @@
} }
} }
const save = () => { const save = async () => {
if (!route) { if (!route) {
routeError = "Url is required" routeError = "Url is required"
} else { } else {
@ -63,7 +71,10 @@
draftScreen.props._component = baseComponent draftScreen.props._component = baseComponent
draftScreen.route = route draftScreen.route = route
store.createScreen(draftScreen) await store.createScreen(draftScreen)
if (createLink) {
await store.createLink(route, name)
}
if (templateIndex !== undefined) { if (templateIndex !== undefined) {
const template = templates[templateIndex] const template = templates[templateIndex]
@ -108,4 +119,6 @@
error={routeError} error={routeError}
bind:value={route} bind:value={route}
on:change={routeChanged} /> on:change={routeChanged} />
<Toggle text="Create link in navigation bar" bind:checked={createLink} />
</ModalContent> </ModalContent>

View File

@ -1,6 +1,6 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { params, leftover } from "@sveltech/routify" import { params, leftover, goto } from "@sveltech/routify"
import { store } from "builderStore" import { store } from "builderStore"
// Get any leftover params not caught by Routifys params store. // Get any leftover params not caught by Routifys params store.
@ -8,7 +8,19 @@
// It's a screen, set it to that screen // It's a screen, set it to that screen
if ($params.screen !== "page-layout") { if ($params.screen !== "page-layout") {
store.setCurrentScreen(decodeURI($params.screen)) const currentScreenName = decodeURI($params.screen)
const validScreen =
$store.screens.findIndex(
screen => screen.props._instanceName === currentScreenName
) !== -1
if (!validScreen) {
// Go to main layout if URL set to invalid screen
store.setCurrentPage("main")
$goto("../../main")
} else {
// Otherwise proceed to set screen
store.setCurrentScreen(currentScreenName)
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it. // There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
if ($leftover) { if ($leftover) {
@ -20,6 +32,7 @@
).props._children ).props._children
findComponent(componentIds, screenChildren) findComponent(componentIds, screenChildren)
} }
}
} else { } else {
// It's a page, so set the screentype to page. // It's a page, so set the screentype to page.
store.setScreenType("page") store.setScreenType("page")