Fix cypress texts and update use of modal

This commit is contained in:
Andrew Kingston 2020-10-05 11:13:09 +01:00
parent 82476e2ae9
commit 70b70252ec
28 changed files with 378 additions and 386 deletions

View File

@ -15,8 +15,12 @@ context("Create a automation", () => {
cy.contains("automate").click() cy.contains("automate").click()
cy.contains("Create New Automation").click() cy.contains("Create New Automation").click()
cy.get("input").type("Add Record") cy.get(".modal").within(() => {
cy.contains("Save").click() cy.get("input").type("Add Record")
cy.get(".buttons")
.contains("Create")
.click()
})
// Add trigger // Add trigger
cy.get("[data-cy=add-automation-component]").click() cy.get("[data-cy=add-automation-component]").click()
@ -28,7 +32,7 @@ context("Create a automation", () => {
}) })
// Create action // Create action
cy.get("[data-cy=SAVE_RECORD]").click() cy.get("[data-cy=CREATE_RECORD]").click()
cy.get("[data-cy=automation-block-setup]").within(() => { cy.get("[data-cy=automation-block-setup]").within(() => {
cy.get("select") cy.get("select")
.first() .first()

View File

@ -12,7 +12,7 @@ context("Create a Table", () => {
}) })
it("adds a new column to the table", () => { it("adds a new column to the table", () => {
cy.addColumn("dog", "name", "Plain Text") cy.addColumn("dog", "name", "Text")
cy.contains("name").should("be.visible") cy.contains("name").should("be.visible")
}) })
@ -24,16 +24,18 @@ context("Create a Table", () => {
it("updates a column on the table", () => { it("updates a column on the table", () => {
cy.contains("name").click() cy.contains("name").click()
cy.get("[data-cy='edit-column-header']").click() cy.get("[data-cy='edit-column-header']").click()
cy.get("[placeholder=Name]").type("updated") cy.get(".actions input")
cy.get("select").select("Plain Text") .first()
.type("updated")
cy.get("select").select("Text")
cy.contains("Save Column").click() cy.contains("Save Column").click()
cy.contains("nameupdated").should("have.text", "nameupdated ") cy.contains("nameupdated").should("have.text", "nameupdated")
}) })
it("edits a record", () => { it("edits a record", () => {
cy.get("tbody .ri-more-line").click() cy.get("tbody .ri-more-line").click()
cy.get("[data-cy=edit-row]").click() cy.get("[data-cy=edit-row]").click()
cy.get(".actions input").type("Updated") cy.get(".modal input").type("Updated")
cy.contains("Save").click() cy.contains("Save").click()
cy.contains("RoverUpdated").should("have.text", "RoverUpdated") cy.contains("RoverUpdated").should("have.text", "RoverUpdated")
}) })
@ -48,6 +50,7 @@ context("Create a Table", () => {
it("deletes a column", () => { it("deletes a column", () => {
cy.contains("name").click() cy.contains("name").click()
cy.get("[data-cy='delete-column-header']").click() cy.get("[data-cy='delete-column-header']").click()
cy.contains("Delete Column").click()
cy.contains("nameupdated").should("not.exist") cy.contains("nameupdated").should("not.exist")
}) })

View File

@ -3,7 +3,7 @@ context("Create a View", () => {
cy.visit("localhost:4001/_builder") cy.visit("localhost:4001/_builder")
cy.createApp("View App", "View App Description") cy.createApp("View App", "View App Description")
cy.createTable("data") cy.createTable("data")
cy.addColumn("data", "group", "Plain Text") cy.addColumn("data", "group", "Text")
cy.addColumn("data", "age", "Number") cy.addColumn("data", "age", "Number")
cy.addColumn("data", "rating", "Number") cy.addColumn("data", "rating", "Number")
@ -18,10 +18,12 @@ context("Create a View", () => {
it("creates a view", () => { it("creates a view", () => {
cy.contains("Create New View").click() cy.contains("Create New View").click()
cy.get("[placeholder='View Name']").type("Test View") cy.get(".menu-container").within(() => {
cy.contains("Save View").click() cy.get("input").type("Test View")
cy.contains("Save View").click()
})
cy.get(".title").contains("Test View") cy.get(".title").contains("Test View")
cy.get("thead th").should($headers => { cy.get("thead th div").should($headers => {
expect($headers).to.have.length(3) expect($headers).to.have.length(3)
const headers = $headers.map((i, header) => Cypress.$(header).text()) const headers = $headers.map((i, header) => Cypress.$(header).text())
expect(headers.get()).to.deep.eq(["group", "age", "rating"]) expect(headers.get()).to.deep.eq(["group", "age", "rating"])
@ -39,7 +41,7 @@ context("Create a View", () => {
.find("select") .find("select")
.eq(1) .eq(1)
.select("More Than") .select("More Than")
cy.get("input[placeholder='age']").type(18) cy.get("input").type(18)
cy.contains("Save").click() cy.contains("Save").click()
cy.get("tbody tr").should($values => { cy.get("tbody tr").should($values => {
expect($values).to.have.length(5) expect($values).to.have.length(5)
@ -57,7 +59,7 @@ context("Create a View", () => {
.eq(1) .eq(1)
.select("age") .select("age")
cy.contains("Save").click() cy.contains("Save").click()
cy.get("thead th").should($headers => { cy.get("thead th div").should($headers => {
expect($headers).to.have.length(7) expect($headers).to.have.length(7)
const headers = $headers.map((i, header) => Cypress.$(header).text()) const headers = $headers.map((i, header) => Cypress.$(header).text())
expect(headers.get()).to.deep.eq([ expect(headers.get()).to.deep.eq([
@ -113,8 +115,10 @@ context("Create a View", () => {
.find(".ri-more-line") .find(".ri-more-line")
.click() .click()
cy.contains("Edit").click() cy.contains("Edit").click()
cy.get("[placeholder='View Name']").type(" Updated") cy.get(".menu-container").within(() => {
cy.contains("Save").click() cy.get("input").type(" Updated")
cy.contains("Save").click()
})
cy.contains("Test View Updated").should("be.visible") cy.contains("Test View Updated").should("be.visible")
}) })

View File

@ -59,14 +59,16 @@ Cypress.Commands.add("createApp", name => {
Cypress.Commands.add("createTestTableWithData", () => { Cypress.Commands.add("createTestTableWithData", () => {
cy.createTable("dog") cy.createTable("dog")
cy.addColumn("dog", "name", "Plain Text") cy.addColumn("dog", "name", "Text")
cy.addColumn("dog", "age", "Number") cy.addColumn("dog", "age", "Number")
}) })
Cypress.Commands.add("createTable", tableName => { Cypress.Commands.add("createTable", tableName => {
// Enter model name // Enter model name
cy.contains("Create New Table").click() cy.contains("Create New Table").click()
cy.get("[placeholder='Table Name']").type(tableName) cy.get(".menu-container")
.get("input")
.type(tableName)
cy.contains("Save").click() cy.contains("Save").click()
cy.contains(tableName).should("be.visible") cy.contains(tableName).should("be.visible")
@ -77,25 +79,31 @@ Cypress.Commands.add("addColumn", (tableName, columnName, type) => {
cy.contains(tableName).click() cy.contains(tableName).click()
cy.contains("Create New Column").click() cy.contains("Create New Column").click()
cy.get("[placeholder=Name]").type(columnName) // Configure column
cy.get("select").select(type) cy.get(".menu-container").within(() => {
cy.get("input")
cy.contains("Save Column") .first()
.type(columnName)
cy.contains("Save").click() cy.get("select").select(type)
cy.contains("Save").click()
})
}) })
Cypress.Commands.add("addRecord", values => { Cypress.Commands.add("addRecord", values => {
cy.contains("Create New Row").click() cy.contains("Create New Row").click()
for (let i = 0; i < values.length; i++) { cy.get(".modal").within(() => {
cy.get(".actions input") for (let i = 0; i < values.length; i++) {
.eq(i) cy.get("input")
.type(values[i]) .eq(i)
} .type(values[i])
}
// Save // Save
cy.contains("Save").click() cy.get(".buttons")
.contains("Create")
.click()
})
}) })
Cypress.Commands.add("createUser", (username, password, accessLevel) => { Cypress.Commands.add("createUser", (username, password, accessLevel) => {
@ -114,7 +122,9 @@ Cypress.Commands.add("createUser", (username, password, accessLevel) => {
.select(accessLevel) .select(accessLevel)
// Save // Save
cy.get(".create-button > button").click() cy.get(".inputs")
.contains("Create")
.click()
}) })
Cypress.Commands.add("addHeadlineComponent", text => { Cypress.Commands.add("addHeadlineComponent", text => {

View File

@ -5,7 +5,7 @@
import { Button } from "@budibase/bbui" import { Button } from "@budibase/bbui"
import { Modal } from "components/common/Modal" import { Modal } from "components/common/Modal"
let modal let modalVisible = false
$: selectedAutomationId = $automationStore.selectedAutomation?.automation?._id $: selectedAutomationId = $automationStore.selectedAutomation?.automation?._id
@ -15,7 +15,7 @@
</script> </script>
<section> <section>
<Button primary wide on:click={() => modal.show()}> <Button primary wide on:click={() => (modalVisible = true)}>
Create New Automation Create New Automation
</Button> </Button>
<ul> <ul>
@ -30,9 +30,9 @@
{/each} {/each}
</ul> </ul>
</section> </section>
<Modal bind:this={modal}> {#if modalVisible}
<CreateAutomationModal /> <CreateAutomationModal bind:visible={modalVisible} />
</Modal> {/if}
<style> <style>
section { section {

View File

@ -3,7 +3,9 @@
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import { Input } from "@budibase/bbui" import { Input } from "@budibase/bbui"
import analytics from "analytics" import analytics from "analytics"
import { ModalTitle, ModalFooter } from "components/common/Modal" import { Modal } from "components/common/Modal"
export let visible
let name let name
@ -27,19 +29,22 @@
} }
</script> </script>
<ModalTitle>Create Automation</ModalTitle> <Modal
<Input bind:value={name} label="Name" /> bind:visible
<ModalFooter title="Create Automation"
confirmText="Create" confirmText="Create"
onConfirm={createAutomation} onConfirm={createAutomation}
disabled={!valid}> disabled={!valid}>
<a <Input bind:value={name} label="Name" />
target="_blank" <slot name="footer">
href="https://docs.budibase.com/automate/introduction-to-automate"> <a
<i class="ri-information-line" /> target="_blank"
<span>Learn about automations</span> href="https://docs.budibase.com/automate/introduction-to-automate">
</a> <i class="ri-information-line" />
</ModalFooter> <span>Learn about automations</span>
</a>
</slot>
</Modal>
<style> <style>
a { a {

View File

@ -3,15 +3,15 @@
import CreateEditRecordModal from "../modals/CreateEditRecordModal.svelte" import CreateEditRecordModal from "../modals/CreateEditRecordModal.svelte"
import { Modal } from "components/common/Modal" import { Modal } from "components/common/Modal"
let modal let modalVisible
</script> </script>
<div> <div>
<Button text small on:click={modal.show}> <Button text small on:click={() => (modalVisible = true)}>
<Icon name="addrow" /> <Icon name="addrow" />
Create New Row Create New Row
</Button> </Button>
</div> </div>
<Modal bind:this={modal}> {#if modalVisible}
<CreateEditRecordModal /> <CreateEditRecordModal bind:visible={modalVisible} />
</Modal> {/if}

View File

@ -4,11 +4,11 @@
import LinkedRecordSelector from "components/common/LinkedRecordSelector.svelte" import LinkedRecordSelector from "components/common/LinkedRecordSelector.svelte"
import RecordFieldControl from "../RecordFieldControl.svelte" import RecordFieldControl from "../RecordFieldControl.svelte"
import * as api from "../api" import * as api from "../api"
import { ModalTitle, ModalFooter } from "components/common/Modal" import { Modal } from "components/common/Modal"
import ErrorsBox from "components/common/ErrorsBox.svelte" import ErrorsBox from "components/common/ErrorsBox.svelte"
export let record = {} export let record = {}
export let visible = false export let visible
let modal let modal
let errors = [] let errors = []
@ -36,15 +36,19 @@
} }
</script> </script>
<ModalTitle>{creating ? 'Create Row' : 'Edit Row'}</ModalTitle> <Modal
<ErrorsBox {errors} /> bind:visible
{#each modelSchema as [key, meta]} title={creating ? 'Create Row' : 'Edit Row'}
<div> confirmText={creating ? 'Create Row' : 'Save Row'}
{#if meta.type === 'link'} onConfirm={saveRecord}>
<LinkedRecordSelector bind:linkedRecords={record[key]} schema={meta} /> <ErrorsBox {errors} />
{:else} {#each modelSchema as [key, meta]}
<RecordFieldControl {meta} bind:value={record[key]} /> <div>
{/if} {#if meta.type === 'link'}
</div> <LinkedRecordSelector bind:linkedRecords={record[key]} schema={meta} />
{/each} {:else}
<ModalFooter confirmText={creating ? 'Add' : 'Save'} onConfirm={saveRecord} /> <RecordFieldControl {meta} bind:value={record[key]} />
{/if}
</div>
{/each}
</Modal>

View File

@ -12,11 +12,11 @@
let anchor let anchor
let dropdown let dropdown
let confirmDeleteDialog let confirmDeleteDialog
let modal let editModalVisible
function showModal() { function showModal() {
dropdown.hide() dropdown.hide()
modal.show() editModalVisible = true
} }
function showDelete() { function showDelete() {
@ -52,9 +52,9 @@
okText="Delete Row" okText="Delete Row"
onOk={deleteRow} onOk={deleteRow}
title="Confirm Delete" /> title="Confirm Delete" />
<Modal bind:this={modal}> {#if editModalVisible}
<CreateEditRecordModal record={row} /> <CreateEditRecordModal bind:visible={editModalVisible} record={row} />
</Modal> {/if}
<style> <style>
.ri-more-line:hover { .ri-more-line:hover {

View File

@ -2,9 +2,9 @@
import { goto } from "@sveltech/routify" import { goto } from "@sveltech/routify"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import ListItem from "./ListItem.svelte" import ListItem from "./ListItem.svelte"
import CreateTablePopover from "./CreateTable.svelte" import CreateTablePopover from "./popovers/CreateTablePopover.svelte"
import EditTablePopover from "./EditTable.svelte" import EditTablePopover from "./popovers/EditTablePopover.svelte"
import EditViewPopover from "./EditView.svelte" import EditViewPopover from "./popovers/EditViewPopover.svelte"
import { Heading } from "@budibase/bbui" import { Heading } from "@budibase/bbui"
import { Spacer } from "@budibase/bbui" import { Spacer } from "@budibase/bbui"

View File

@ -2,11 +2,9 @@
import { goto } from "@sveltech/routify" import { goto } from "@sveltech/routify"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import { notifier } from "builderStore/store/notifications" import { notifier } from "builderStore/store/notifications"
import { DropdownMenu, Button, Icon, Input, Select } from "@budibase/bbui" import { Popover, Button, Icon, Input, Select } from "@budibase/bbui"
import analytics from "analytics" import analytics from "analytics"
export let table
let anchor let anchor
let dropdown let dropdown
let name let name
@ -32,7 +30,7 @@
<div bind:this={anchor}> <div bind:this={anchor}>
<Button primary wide on:click={dropdown.show}>Create New Table</Button> <Button primary wide on:click={dropdown.show}>Create New Table</Button>
</div> </div>
<DropdownMenu bind:this={dropdown} {anchor} align="left"> <Popover bind:this={dropdown} {anchor} align="left">
<div class="actions"> <div class="actions">
<h5>Create Table</h5> <h5>Create Table</h5>
<Input <Input
@ -45,11 +43,10 @@
<Button primary on:click={saveTable}>Save</Button> <Button primary on:click={saveTable}>Save</Button>
</footer> </footer>
</div> </div>
</DropdownMenu> </Popover>
<style> <style>
.actions { .actions {
padding: var(--spacing-xl);
display: grid; display: grid;
grid-gap: var(--spacing-xl); grid-gap: var(--spacing-xl);
min-width: 400px; min-width: 400px;

View File

@ -1,5 +1,5 @@
<script> <script>
import { Modal, ModalTitle, ModalFooter } from "components/common/Modal" import { Modal } from "components/common/Modal"
export let title = "" export let title = ""
export let body = "" export let body = ""
@ -8,20 +8,26 @@
export let onOk = () => {} export let onOk = () => {}
export let onCancel = () => {} export let onCancel = () => {}
let modal let visible = false
export const show = () => { export const show = () => {
modal.show() visible = true
} }
export const hide = () => { export const hide = () => {
modal.hide() visible = false
} }
</script> </script>
<Modal id={title} bind:this={modal} on:hide={onCancel}> <Modal
<ModalTitle>{title}</ModalTitle> id={title}
bind:visible
on:hide={onCancel}
{title}
confirmText={okText}
{cancelText}
onConfirm={onOk}
red>
<div class="body">{body}</div> <div class="body">{body}</div>
<ModalFooter confirmText={okText} {cancelText} onConfirm={onOk} red />
</Modal> </Modal>
<style> <style>

View File

@ -12,15 +12,23 @@
import { createEventDispatcher, setContext } from "svelte" import { createEventDispatcher, setContext } from "svelte"
import { fade, fly } from "svelte/transition" import { fade, fly } from "svelte/transition"
import Portal from "svelte-portal" import Portal from "svelte-portal"
import { Button } from "@budibase/bbui"
import { ContextKey } from "./context" import { ContextKey } from "./context"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
export let wide = false export let wide = false
export let padded = true export let padded = true
export let title = undefined
export let cancelText = "Cancel"
export let confirmText = "Confirm"
export let showCancelButton = true
export let showConfirmButton = true
export let onConfirm = () => {}
export let visible = false
let visible let loading = false
export function show() { function show() {
if (visible) { if (visible) {
return return
} }
@ -28,7 +36,7 @@
dispatch("show") dispatch("show")
} }
export function hide() { function hide() {
if (!visible) { if (!visible) {
return return
} }
@ -36,6 +44,14 @@
dispatch("hide") dispatch("hide")
} }
async function confirm() {
loading = true
if (!onConfirm || (await onConfirm()) !== false) {
hide()
}
loading = false
}
setContext(ContextKey, { show, hide }) setContext(ContextKey, { show, hide })
</script> </script>
@ -50,8 +66,37 @@
on:click|self={hide} on:click|self={hide}
transition:fly={{ y: 50 }}> transition:fly={{ y: 50 }}>
<div class="content-wrapper" on:click|self={hide}> <div class="content-wrapper" on:click|self={hide}>
<div class="content" class:wide class:padded> <div class="modal" class:wide class:padded>
{#if title}
<header>
<h5>{title}</h5>
<div class="header-content">
<slot name="header" />
</div>
</header>
{/if}
<slot /> <slot />
{#if showCancelButton || showConfirmButton}
<footer>
<div class="footer-content">
<slot name="footer" />
</div>
<div class="buttons">
{#if showCancelButton}
<Button secondary on:click={hide}>{cancelText}</Button>
{/if}
{#if showConfirmButton}
<Button
primary
{...$$restProps}
disabled={$$restProps.disabled || loading}
on:click={confirm}>
{confirmText}
</Button>
{/if}
</div>
</footer>
{/if}
<i class="ri-close-line" on:click={hide} /> <i class="ri-close-line" on:click={hide} />
</div> </div>
</div> </div>
@ -61,10 +106,6 @@
{/if} {/if}
<style> <style>
.portal-wrapper {
display: none;
}
.overlay { .overlay {
position: fixed; position: fixed;
left: 0; left: 0;
@ -98,7 +139,7 @@
width: 0; width: 0;
} }
.content { .modal {
background-color: white; background-color: white;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -111,13 +152,32 @@
border-radius: var(--border-radius-m); border-radius: var(--border-radius-m);
gap: var(--spacing-xl); gap: var(--spacing-xl);
} }
.content.wide { .modal.wide {
flex: 0 0 600px; flex: 0 0 600px;
} }
.content.padded { .modal.padded {
padding: var(--spacing-xl); padding: var(--spacing-xl);
} }
header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-right: 40px;
}
header h5 {
margin: 0;
font-weight: 500;
}
.header-content {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
i { i {
position: absolute; position: absolute;
top: var(--spacing-xl); top: var(--spacing-xl);
@ -129,4 +189,27 @@
color: var(--grey-6); color: var(--grey-6);
cursor: pointer; cursor: pointer;
} }
footer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: var(--spacing-m);
}
.footer-content {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.buttons {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: var(--spacing-m);
}
</style> </style>

View File

@ -1,63 +0,0 @@
<script>
import { getContext } from "svelte"
import { Button } from "@budibase/bbui"
import { ContextKey } from "./context"
export let cancelText = "Cancel"
export let confirmText = "Confirm"
export let showCancelButton = true
export let showConfirmButton = true
export let onConfirm
const modalContext = getContext(ContextKey)
let loading = false
function hide() {
modalContext.hide()
}
async function confirm() {
loading = true
if (!onConfirm || (await onConfirm()) !== false) {
hide()
}
loading = false
}
</script>
<footer>
<div class="content">
<slot />
</div>
<div class="buttons">
{#if showCancelButton}
<Button secondary on:click={hide}>{cancelText}</Button>
{/if}
{#if showConfirmButton}
<Button
primary
{...$$restProps}
disabled={$$props.disabled || loading}
on:click={confirm}>
{confirmText}
</Button>
{/if}
</div>
</footer>
<style>
footer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: var(--spacing-m);
}
.buttons {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: var(--spacing-m);
}
</style>

View File

@ -1,10 +0,0 @@
<h5>
<slot />
</h5>
<style>
h5 {
margin: 0;
font-weight: 500;
}
</style>

View File

@ -1,5 +1,3 @@
export { default as Modal } from "./Modal.svelte" export { default as Modal } from "./Modal.svelte"
export { default as ModalContainer } from "./ModalContainer.svelte" export { default as ModalContainer } from "./ModalContainer.svelte"
export { default as ModalTitle } from "./ModalTitle.svelte"
export { default as ModalFooter } from "./ModalFooter.svelte"
export { ContextKey } from "./context" export { ContextKey } from "./context"

View File

@ -3,15 +3,15 @@
import { SettingsIcon } from "components/common/Icons/" import { SettingsIcon } from "components/common/Icons/"
import { Modal } from "components/common/Modal" import { Modal } from "components/common/Modal"
let modal let modalVisible
</script> </script>
<span class="topnavitemright settings" on:click={modal.show}> <span class="topnavitemright settings" on:click={() => (modalVisible = true)}>
<SettingsIcon /> <SettingsIcon />
</span> </span>
<Modal bind:this={modal} wide> {#if modalVisible}
<SettingsModal /> <SettingsModal bind:visible={modalVisible} />
</Modal> {/if}
<style> <style>
span:first-letter { span:first-letter {

View File

@ -1,7 +1,7 @@
<script> <script>
import { General, Users, DangerZone, APIKeys } from "./tabs" import { General, Users, DangerZone, APIKeys } from "./tabs"
import { Switcher } from "@budibase/bbui" import { Switcher } from "@budibase/bbui"
import { ModalTitle } from "components/common/Modal" import { Modal } from "components/common/Modal"
const tabs = [ const tabs = [
{ {
@ -26,25 +26,27 @@
}, },
] ]
export let visible
let value = "GENERAL" let value = "GENERAL"
$: selectedTab = tabs.find(tab => tab.key === value).component $: selectedTab = tabs.find(tab => tab.key === value).component
function hide() {}
</script> </script>
<div class="container"> <Modal
<ModalTitle>Settings</ModalTitle> title="Settings"
<Switcher headings={tabs} bind:value> wide
<svelte:component this={selectedTab} /> bind:visible
</Switcher> showConfirmButton={false}
</div> showCancelButton={false}>
<div class="container">
<Switcher headings={tabs} bind:value>
<svelte:component this={selectedTab} />
</Switcher>
</div>
</Modal>
<style> <style>
.container {
display: grid;
grid-gap: var(--spacing-xl);
}
.container :global(section > header) { .container :global(section > header) {
/* Fix margin defined in BBUI as L rather than XL */ /* Fix margin defined in BBUI as L rather than XL */
margin-bottom: var(--spacing-xl); margin-bottom: var(--spacing-xl);

View File

@ -2,7 +2,6 @@
import { params, goto } from "@sveltech/routify" import { params, goto } from "@sveltech/routify"
import { Input, TextArea, Button, Body } from "@budibase/bbui" import { Input, TextArea, Button, Body } from "@budibase/bbui"
import { del } from "builderStore/api" import { del } from "builderStore/api"
import { ModalFooter } from "components/common/Modal"
let value = "" let value = ""
let loading = false let loading = false
@ -29,12 +28,15 @@
thin thin
disabled={loading} disabled={loading}
placeholder="" /> placeholder="" />
<ModalFooter <div class="buttons">
disabled={value !== 'DELETE' || loading} <Button
red primary
showCancelButton={false} disabled={value !== 'DELETE' || loading}
confirmText="Delete Entire App" red
onConfirm={deleteApp} /> on:click={deleteApp}>
Delete Entire App
</Button>
</div>
</div> </div>
<style> <style>
@ -46,4 +48,11 @@
line-height: 1.2; line-height: 1.2;
margin: 0; margin: 0;
} }
.buttons {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
</style> </style>

View File

@ -1,6 +1,6 @@
<script> <script>
import { writable } from "svelte/store" import { writable } from "svelte/store"
import { Modal } from "components/common/Modal"
import { store, automationStore, backendUiStore } from "builderStore" import { store, automationStore, backendUiStore } from "builderStore"
import { string, object } from "yup" import { string, object } from "yup"
import api, { get } from "builderStore/api" import api, { get } from "builderStore/api"
@ -18,6 +18,7 @@
//Move this to context="module" once svelte-forms is updated so that it can bind to stores correctly //Move this to context="module" once svelte-forms is updated so that it can bind to stores correctly
const createAppStore = writable({ currentStep: 0, values: {} }) const createAppStore = writable({ currentStep: 0, values: {} })
export let visible
export let hasKey export let hasKey
let isApiKeyValid let isApiKeyValid
@ -197,60 +198,67 @@
} }
</script> </script>
<div class="container"> <Modal
<div class="sidebar"> bind:visible
{#each steps as { active, done }, i} wide
<Indicator padded={false}
active={$createAppStore.currentStep === i} showCancelButton={false}
done={i < $createAppStore.currentStep} showConfirmButton={false}>
step={i + 1} /> <div class="container">
{/each} <div class="sidebar">
{#each steps as { active, done }, i}
<Indicator
active={$createAppStore.currentStep === i}
done={i < $createAppStore.currentStep}
step={i + 1} />
{/each}
</div>
<div class="body">
<div class="heading">
<h3 class="header">Get Started with Budibase</h3>
</div>
<div class="step">
<Form bind:values={$createAppStore.values}>
{#each steps as step, i (i)}
<div class:hidden={$createAppStore.currentStep !== i}>
<svelte:component
this={step.component}
{validationErrors}
options={step.options}
name={step.name} />
</div>
{/each}
</Form>
</div>
<div class="footer">
{#if $createAppStore.currentStep > 0}
<Button medium secondary on:click={back}>Back</Button>
{/if}
{#if $createAppStore.currentStep < steps.length - 1}
<Button medium blue on:click={next} disabled={!currentStepIsValid}>
Next
</Button>
{/if}
{#if $createAppStore.currentStep === steps.length - 1}
<Button
medium
blue
on:click={signUp}
disabled={!fullFormIsValid || submitting}>
{submitting ? 'Loading...' : 'Submit'}
</Button>
{/if}
</div>
</div>
<img src="/_builder/assets/bb-logo.svg" alt="budibase icon" />
{#if submitting}
<div in:fade class="spinner-container">
<Spinner />
<span class="spinner-text">Creating your app...</span>
</div>
{/if}
</div> </div>
<div class="body"> </Modal>
<div class="heading">
<h3 class="header">Get Started with Budibase</h3>
</div>
<div class="step">
<Form bind:values={$createAppStore.values}>
{#each steps as step, i (i)}
<div class:hidden={$createAppStore.currentStep !== i}>
<svelte:component
this={step.component}
{validationErrors}
options={step.options}
name={step.name} />
</div>
{/each}
</Form>
</div>
<div class="footer">
{#if $createAppStore.currentStep > 0}
<Button medium secondary on:click={back}>Back</Button>
{/if}
{#if $createAppStore.currentStep < steps.length - 1}
<Button medium blue on:click={next} disabled={!currentStepIsValid}>
Next
</Button>
{/if}
{#if $createAppStore.currentStep === steps.length - 1}
<Button
medium
blue
on:click={signUp}
disabled={!fullFormIsValid || submitting}>
{submitting ? 'Loading...' : 'Submit'}
</Button>
{/if}
</div>
</div>
<img src="/_builder/assets/bb-logo.svg" alt="budibase icon" />
{#if submitting}
<div in:fade class="spinner-container">
<Spinner />
<span class="spinner-text">Creating your app...</span>
</div>
{/if}
</div>
<style> <style>
.container { .container {

View File

@ -12,10 +12,12 @@
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers" import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers"
import actionTypes from "./actions" import actionTypes from "./actions"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { Modal } from "components/common/Modal"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
export let event export let event
export let visible
let addActionButton let addActionButton
let addActionDropdown let addActionDropdown
@ -29,12 +31,6 @@
actionTypes.find(t => t.name === selectedAction[EVENT_TYPE_MEMBER_NAME]) actionTypes.find(t => t.name === selectedAction[EVENT_TYPE_MEMBER_NAME])
.component .component
const closeModal = () => {
dispatch("close")
draftEventHandler = { parameters: [] }
actions = []
}
const updateEventHandler = (updatedHandler, index) => { const updateEventHandler = (updatedHandler, index) => {
actions[index] = updatedHandler actions[index] = updatedHandler
} }
@ -61,20 +57,22 @@
const saveEventData = () => { const saveEventData = () => {
dispatch("change", actions) dispatch("change", actions)
closeModal()
} }
</script> </script>
<div class="root"> <Modal
bind:visible
<div class="header"> title="Actions"
<Heading small dark>Actions</Heading> wide
confirmText="Save"
onConfirm={saveEventData}>
<div slot="header">
<div bind:this={addActionButton}> <div bind:this={addActionButton}>
<TextButton text small blue on:click={addActionDropdown.show}> <TextButton text small blue on:click={addActionDropdown.show}>
Add Action
<div style="height: 20px; width: 20px;"> <div style="height: 20px; width: 20px;">
<AddIcon /> <AddIcon />
</div> </div>
Add Action
</TextButton> </TextButton>
</div> </div>
<DropdownMenu <DropdownMenu
@ -120,30 +118,12 @@
{/if} {/if}
</div> </div>
<div class="footer"> <div slot="footer">
<a href="https://docs.budibase.com">Learn more about Actions</a> <a href="https://docs.budibase.com">Learn more about Actions</a>
<Button secondary on:click={closeModal}>Cancel</Button>
<Button primary on:click={saveEventData}>Save</Button>
</div> </div>
</div> </Modal>
<style> <style>
.root {
max-height: 50vh;
width: 700px;
display: flex;
flex-direction: column;
}
.header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: var(--spacing-xl);
padding-bottom: 0;
}
.action-header { .action-header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -200,22 +180,13 @@
flex-direction: row; flex-direction: row;
} }
.footer { a {
display: flex;
flex-direction: row;
gap: var(--spacing-s);
padding: var(--spacing-xl);
padding-top: var(--spacing-m);
}
.footer > a {
flex: 1; flex: 1;
color: var(--grey-5); color: var(--grey-5);
font-size: var(--font-size-s); font-size: var(--font-size-s);
text-decoration: none; text-decoration: none;
} }
a:hover {
.footer > a:hover {
color: var(--blue); color: var(--blue);
} }

View File

@ -7,19 +7,17 @@
export let value export let value
export let name export let name
let eventsModal let modalVisible = false
</script> </script>
<Button secondary small on:click={eventsModal.show}>Define Actions</Button> <Button secondary small on:click={() => (modalVisible = true)}>
Define Actions
</Button>
<Modal bind:this={eventsModal} maxWidth="100vw" hideCloseButton padding="0"> {#if modalVisible}
<EventEditorModal <EventEditorModal
bind:visible={modalVisible}
event={value} event={value}
eventType={name} eventType={name}
on:change on:change />
on:close={eventsModal.hide} /> {/if}
</Modal>
<style>
</style>

View File

@ -7,17 +7,15 @@
import { Button } from "@budibase/bbui" import { Button } from "@budibase/bbui"
import { Spacer } from "@budibase/bbui" import { Spacer } from "@budibase/bbui"
const newScreen = () => { let modalVisible = false
newScreenPicker.show()
}
let newScreenPicker
</script> </script>
<PagesList /> <PagesList />
<Spacer medium /> <Spacer medium />
<Button primary wide on:click={newScreen}>Create New Screen</Button> <Button primary wide on:click={() => (modalVisible = true)}>
Create New Screen
</Button>
<Spacer medium /> <Spacer medium />
<PageLayout layout={$store.pages[$store.currentPageName]} /> <PageLayout layout={$store.pages[$store.currentPageName]} />
@ -25,7 +23,9 @@
<ComponentsHierarchy screens={$store.screens} /> <ComponentsHierarchy screens={$store.screens} />
</div> </div>
<NewScreen bind:this={newScreenPicker} /> {#if modalVisible}
<NewScreen bind:visible={modalVisible} />
{/if}
<style> <style>
.newscreen { .newscreen {

View File

@ -3,14 +3,12 @@
import { pipe } from "components/common/core" import { pipe } from "components/common/core"
import { isRootComponent } from "./pagesParsing/searchComponents" import { isRootComponent } from "./pagesParsing/searchComponents"
import { splitName } from "./pagesParsing/splitRootComponentName.js" import { splitName } from "./pagesParsing/splitRootComponentName.js"
import { Input, Select, Modal, Button, Spacer } from "@budibase/bbui" import { Input, Select, Button, Spacer } from "@budibase/bbui"
import { Modal } from "components/common/Modal"
import { find, filter, some, map, includes } from "lodash/fp" import { find, filter, some, map, includes } from "lodash/fp"
import { assign } from "lodash" import { assign } from "lodash"
export const show = () => { export let visible
dialog.show()
}
let dialog let dialog
let layoutComponents let layoutComponents
@ -41,17 +39,12 @@
routeError = "" routeError = ""
} }
} }
if (routeError) {
if (routeError) return false return false
}
store.createScreen(name, route, layoutComponent._component) store.createScreen(name, route, layoutComponent._component)
name = "" name = ""
route = "" route = ""
dialog.hide()
}
const cancel = () => {
dialog.hide()
} }
const routeNameExists = route => { const routeNameExists = route => {
@ -67,51 +60,20 @@
} }
</script> </script>
<Modal bind:this={dialog} minWidth="500px"> <Modal
<h2>New Screen</h2> bind:visible
<Spacer extraLarge /> title="New Screen"
confirmText="Create Screen"
<div data-cy="new-screen-dialog"> onConfirm={save}>
<div class="bb-margin-xl"> <Input label="Name" bind:value={name} />
<Input label="Name" bind:value={name} /> <Input
</div> label="Url"
error={routeError}
<div class="bb-margin-xl"> bind:value={route}
<Input on:change={routeChanged} />
label="Url" <Select label="Layout Component" bind:value={layoutComponent} secondary>
error={routeError} {#each layoutComponents as { _component, name }}
bind:value={route} <option value={_component}>{name}</option>
on:change={routeChanged} /> {/each}
</div> </Select>
<div class="bb-margin-xl">
<label>Layout Component</label>
<Select bind:value={layoutComponent} secondary>
{#each layoutComponents as { _component, name }}
<option value={_component}>{name}</option>
{/each}
</Select>
</div>
</div>
<Spacer extraLarge />
<div data-cy="create-screen-footer" class="modal-footer">
<Button secondary medium on:click={cancel}>Cancel</Button>
<Button blue medium on:click={save}>Create Screen</Button>
</div>
</Modal> </Modal>
<style>
h2 {
font-size: var(--font-size-xl);
margin: 0;
font-family: var(--font-sans);
font-weight: 600;
}
.modal-footer {
display: flex;
justify-content: space-between;
}
</style>

View File

@ -15,12 +15,9 @@
let newScreenPicker let newScreenPicker
let confirmDeleteDialog let confirmDeleteDialog
let componentToDelete = "" let componentToDelete = ""
const newScreen = () => {
newScreenPicker.show()
}
let settingsView let settingsView
let modalVisible = false
const settings = () => { const settings = () => {
settingsView.show() settingsView.show()
} }
@ -52,7 +49,7 @@
Screens Screens
</span> </span>
<div> <div>
<button on:click={newScreen}> <button on:click={() => (modalVisible = true)}>
<AddIcon /> <AddIcon />
</button> </button>
</div> </div>
@ -76,7 +73,9 @@
</div> </div>
<NewScreen bind:this={newScreenPicker} /> {#if modalVisible}
<NewScreen bind:visible={modalVisible} />
{/if}
<SettingsView bind:this={settingsView} /> <SettingsView bind:this={settingsView} />
<style> <style>

View File

@ -13,7 +13,7 @@
let promise = getApps() let promise = getApps()
let hasKey let hasKey
let modal let modalVisible = false
async function getApps() { async function getApps() {
const res = await get("/api/applications") const res = await get("/api/applications")
@ -40,7 +40,7 @@
} }
if (!keys.budibase) { if (!keys.budibase) {
modal.show() modalVisible = true
} }
} }
@ -49,7 +49,9 @@
<div class="header"> <div class="header">
<Heading medium black>Welcome to the Budibase Beta</Heading> <Heading medium black>Welcome to the Budibase Beta</Heading>
<Button primary black on:click={modal.show}>Create New Web App</Button> <Button primary black on:click={() => (modalVisible = true)}>
Create New Web App
</Button>
</div> </div>
<div class="banner"> <div class="banner">
@ -59,9 +61,9 @@
</div> </div>
</div> </div>
<Modal bind:this={modal} wide padded={false}> {#if modalVisible}
<CreateAppModal {hasKey} /> <CreateAppModal bind:visible={modalVisible} {hasKey} />
</Modal> {/if}
{#await promise} {#await promise}
<div class="spinner-container"> <div class="spinner-container">