Merge branch 'master' into feature/binding-interface

This commit is contained in:
Michael Shanks 2020-08-07 10:43:07 +01:00
commit ae734970a6
52 changed files with 834 additions and 528 deletions

View File

@ -33,3 +33,4 @@ jobs:
env: env:
CI: true CI: true
name: Budibase CI name: Budibase CI
- run: yarn test:e2e:ci

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.12", "version": "0.1.13",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -26,7 +26,8 @@
"lint": "eslint packages", "lint": "eslint packages",
"lint:fix": "eslint --fix packages", "lint:fix": "eslint --fix packages",
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"", "format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\"",
"test:e2e": "lerna run cy:test" "test:e2e": "lerna run cy:test",
"test:e2e:ci": "lerna run cy:ci"
}, },
"dependencies": { "dependencies": {
"@material/icon-button": "4.0.0", "@material/icon-button": "4.0.0",

View File

@ -1,4 +1,5 @@
{ {
"baseUrl": "http://localhost:4001/_builder/", "baseUrl": "http://localhost:4001/_builder/",
"video": false "video": true,
"projectId": "bmbemn"
} }

View File

@ -0,0 +1,3 @@
{
"budibase": "CB373643-3FC4-4902-9E31-449C0ED066B6"
}

View File

@ -1,6 +1,7 @@
context('Create an Application', () => { context('Create an Application', () => {
beforeEach(() => { beforeEach(() => {
cy.server()
cy.visit('localhost:4001/_builder') cy.visit('localhost:4001/_builder')
}) })

View File

@ -1,6 +1,7 @@
context('Create Components', () => { xcontext('Create Components', () => {
before(() => { before(() => {
cy.server()
cy.visit('localhost:4001/_builder') cy.visit('localhost:4001/_builder')
// https://on.cypress.io/type // https://on.cypress.io/type
cy.createApp('Model App', 'Model App Description') cy.createApp('Model App', 'Model App Description')
@ -22,8 +23,8 @@ context('Create Components', () => {
}) })
it('change the font size of the headline', () => { it('change the font size of the headline', () => {
cy.contains('Typography').click() cy.contains('Typography').click()
cy.get('input[name="font-size"]') cy.get('[data-cy=font-size-prop-control]').click()
.type('60px') cy.contains("60px").click()
cy.contains('Design').click() cy.contains('Design').click()
getIframeBody().contains('An Amazing headline!').should('have.css', 'font-size', '60px') getIframeBody().contains('An Amazing headline!').should('have.css', 'font-size', '60px')

View File

@ -1,4 +1,4 @@
context('Create a Model', () => { xcontext('Create a Model', () => {
before(() => { before(() => {
cy.visit('localhost:4001/_builder') cy.visit('localhost:4001/_builder')

View File

@ -1,6 +1,7 @@
context('Create a User', () => { context('Create a User', () => {
before(() => { before(() => {
cy.server()
cy.visit('localhost:4001/_builder') cy.visit('localhost:4001/_builder')
// https://on.cypress.io/type // https://on.cypress.io/type
cy.createApp('User App', 'This app is used to test user creation') cy.createApp('User App', 'This app is used to test user creation')
@ -8,12 +9,9 @@ context('Create a User', () => {
// https://on.cypress.io/interacting-with-elements // https://on.cypress.io/interacting-with-elements
it('should create a user', () => { it('should create a user', () => {
// Close Model modal that shows up after creating an app
cy.get('.close').click()
cy.createUser('bbuser', 'test', 'ADMIN') cy.createUser('bbuser', 'test', 'ADMIN')
// Check to make sure user was created! // Check to make sure user was created!
cy.contains('bbuser').should('have.text', 'bbuser') cy.get("input[disabled]").should('have.value', 'bbuser')
}) })
}) })

View File

@ -1,6 +1,7 @@
context('Create a workflow', () => { xcontext('Create a workflow', () => {
before(() => { before(() => {
cy.server()
cy.visit('localhost:4001/_builder') cy.visit('localhost:4001/_builder')
cy.createApp('Workflow Test App', 'This app is used to test that workflows do in fact work!') cy.createApp('Workflow Test App', 'This app is used to test that workflows do in fact work!')
@ -9,11 +10,9 @@ context('Create a workflow', () => {
// https://on.cypress.io/interacting-with-elements // https://on.cypress.io/interacting-with-elements
it('should create a workflow', () => { it('should create a workflow', () => {
cy.createModel('dog', 'name', 'age') cy.createModel('dog', 'name', 'age')
cy.createUser('bbuser', 'test', 'ADMIN')
cy.contains('workflow').click() cy.contains('workflow').click()
cy.get('.new-workflow-button').click() cy.contains('Create New Workflow').click()
cy.get('input').type('Add Record') cy.get('input').type('Add Record')
cy.contains('Save').click() cy.contains('Save').click()
@ -28,14 +27,13 @@ context('Create a workflow', () => {
cy.get(':nth-child(3) > .budibase__input').type('11') cy.get(':nth-child(3) > .budibase__input').type('11')
// Save // Save
cy.get('[data-cy=save-workflow-setup]').click() cy.contains('Save Workflow').click()
cy.get('.workflow-button').click()
// Activate Workflow // Activate Workflow
cy.get('[data-cy=activate-workflow]').click() cy.get('[data-cy=activate-workflow]').click()
}) })
it('should add record when a new record is added', () => { xit('should add record when a new record is added', () => {
cy.contains('backend').click() cy.contains('backend').click()
cy.addRecord('bob', '15') cy.addRecord('bob', '15')

View File

@ -1,13 +1,14 @@
context('Screen Tests', () => { context('Screen Tests', () => {
before(() => { before(() => {
cy.server()
cy.visit('localhost:4001/_builder') cy.visit('localhost:4001/_builder')
cy.createApp('Conor Cy App', 'Model App Description') cy.createApp('Conor Cy App', 'Model App Description')
cy.navigateToFrontend() cy.navigateToFrontend()
}) })
it('Should successful create a screen', () => { it('Should successful create a screen', () => {
cy.createScreen("test Screen") cy.createScreen("test Screen", "/test")
}) })
it('Should rename a screen', () => { it('Should rename a screen', () => {

View File

@ -19,4 +19,5 @@
module.exports = (on, config) => { module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits // `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config // `config` is the resolved Cypress config
require("cypress-terminal-report/src/installLogsPrinter")(on)
} }

View File

@ -1,17 +1,23 @@
// What this script does: // What this script does:
// 1. Removes the old test folder if it exists (.budibase-cypress) // 1. Removes the old test folder if it exists (.budibase)
// 2. Initialises using `.budibase-cypress` // 2. Initialises using `.budibase`
// 3. Runs the server using said folder // 3. Runs the server using said folder
const rimraf = require("rimraf") const rimraf = require("rimraf")
const { join } = require("path") const { join } = require("path")
const homedir = join(require("os").homedir(), ".budibase-cypress")
const init = require("../../cli/src/commands/init/initHandler")
const run = require("../../cli/src/commands/run/runHandler") const run = require("../../cli/src/commands/run/runHandler")
const initialiseBudibase = require("../../server/src/utilities/initialiseBudibase")
const homedir = join(require("os").homedir(), ".budibase")
rimraf.sync(homedir) rimraf.sync(homedir)
init({ dir: homedir, clientId: "cypress-test" }).then(() => { process.env.BUDIBASE_API_KEY = "6BE826CB-6B30-4AEC-8777-2E90464633DE"
process.env.NODE_ENV = "cypress"
initialiseBudibase({ dir: homedir, clientId: "cypress-test" })
.then(() => {
delete require.cache[require.resolve("../../server/src/environment")] delete require.cache[require.resolve("../../server/src/environment")]
run({ dir: homedir }) run({ dir: homedir })
}) })
.catch(e => console.error(e))

View File

@ -24,69 +24,81 @@
// -- This will overwrite an existing command -- // -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
Cypress.Commands.add("createApp", (name, description) => { Cypress.Commands.add("createApp", name => {
cy.get(".banner-button") cy.contains("Create New Web App").click()
.click()
.get('input[name="name"]') cy.get("body")
.then($body => {
if ($body.find("input[name=apiKey]").length) {
// input was found, do something else here
cy.get("input[name=apiKey]")
.type(name)
.should("have.value", name)
cy.contains("Next").click()
}
})
.then(() => {
cy.get("input[name=applicationName]")
.type(name) .type(name)
.should("have.value", name) .should("have.value", name)
cy.get('textarea[name="description"]') cy.contains("Next").click()
.type(description)
.should("have.value", description)
cy.contains("Save").click() cy.get("input[name=username]")
})
Cypress.Commands.add("createModel", (modelName, firstField, secondField) => {
// Enter model name
cy.get("[data-cy=Name]")
.click() .click()
.type(modelName) .type("test")
cy.get("input[name=password]")
.click()
.type("test")
cy.contains("Submit").click()
cy.contains("Create New Table", {
timeout: 10000,
}).should("be.visible")
})
})
Cypress.Commands.add("createModel", modelName => {
// Enter model name
cy.contains("Create New Table").click()
cy.get("[data-cy=table-name-input]").type(modelName)
// Add 'name' field // Add 'name' field
cy.get("[data-cy=add-new-model-field]").click() cy.contains("Add").click()
cy.get("[data-cy=Name]") cy.contains("Plain Text").click()
.click()
.type(firstField)
cy.contains("Save").click()
// Add 'age' field // Add 'age' field
cy.get("[data-cy=add-new-model-field]").click() cy.contains("Add").click()
cy.contains("Number").click()
cy.get("[data-cy=Name]")
.click()
.type(secondField)
cy.get("select").select("number")
cy.contains("Save").click() cy.contains("Save").click()
cy.contains(secondField).should("exist")
// Save model cy.contains(modelName).click()
cy.contains("Save").click()
}) })
Cypress.Commands.add("addRecord", (firstField, secondField) => { Cypress.Commands.add("addRecord", (firstField, secondField) => {
cy.contains("Create new record").click() cy.contains("Create New Record").click()
cy.get("[data-cy=name-input]") cy.get("[data-cy='Plain Text-input']").type(firstField)
.click() cy.get("[data-cy=Number-input]").type(secondField)
.type(firstField)
cy.get("[data-cy=age-input]")
.click()
.type(secondField)
// Save // Save
cy.contains("Save").click() cy.contains("Save").click()
}) })
Cypress.Commands.add("createUser", (username, password, level) => { Cypress.Commands.add("createUser", (username, password) => {
// Create User // Create User
cy.get(".nav-group-header > .ri-add-line").click() cy.get(".toprightnav > .settings").click()
cy.contains("Users").click()
cy.get("[data-cy=username]").type(username) cy.get("[name=Name]")
cy.get("[data-cy=password]").type(password) .first()
cy.get("[data-cy=accessLevel]").select(level) .type(username)
cy.get("[name=Password]")
.first()
.type(password)
// Save // Save
cy.contains("Save").click() cy.get(".create-button").click()
}) })
Cypress.Commands.add("addHeadlineComponent", text => { Cypress.Commands.add("addHeadlineComponent", text => {
@ -95,7 +107,8 @@ Cypress.Commands.add("addHeadlineComponent", text => {
cy.get("[data-cy=Text]").click() cy.get("[data-cy=Text]").click()
cy.get("[data-cy=Headline]").click() cy.get("[data-cy=Headline]").click()
cy.get(".tabs > :nth-child(2)").click() cy.get(".tabs > :nth-child(2)").click()
cy.get('input[type="text"]').type(text) cy.contains("Settings").click()
cy.get('input[name="text"]').type(text)
cy.contains("Design").click() cy.contains("Design").click()
}) })
Cypress.Commands.add("addButtonComponent", () => { Cypress.Commands.add("addButtonComponent", () => {
@ -105,9 +118,7 @@ Cypress.Commands.add("addButtonComponent", () => {
}) })
Cypress.Commands.add("navigateToFrontend", () => { Cypress.Commands.add("navigateToFrontend", () => {
cy.get(".close", { timeout: 10000 }).click()
cy.contains("frontend").click() cy.contains("frontend").click()
cy.get(".close", { timeout: 10000 }).click()
}) })
Cypress.Commands.add("createScreen", (screenName, route) => { Cypress.Commands.add("createScreen", (screenName, route) => {

View File

@ -19,3 +19,4 @@ import "./commands"
// Alternatively you can use CommonJS syntax: // Alternatively you can use CommonJS syntax:
// require('./commands') // require('./commands')
require("cypress-terminal-report/src/installLogsCollector")()

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "0.1.11", "version": "0.1.13",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -13,7 +13,9 @@
"cy:setup": "node ./cypress/setup.js", "cy:setup": "node ./cypress/setup.js",
"cy:run": "cypress run", "cy:run": "cypress run",
"cy:open": "cypress open", "cy:open": "cypress open",
"cy:test": "start-server-and-test cy:setup http://localhost:4001/_builder cy:run" "cy:run:ci": "cypress run --browser electron --record --key f308590b-6070-41af-b970-794a3823d451",
"cy:test": "start-server-and-test cy:setup http://localhost:4001/_builder cy:run",
"cy:ci": "start-server-and-test cy:setup http://localhost:4001/_builder cy:run:ci"
}, },
"jest": { "jest": {
"globals": { "globals": {
@ -55,11 +57,12 @@
] ]
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "^1.16.0", "@budibase/bbui": "^1.18.0",
"@budibase/client": "^0.1.1", "@budibase/client": "^0.1.1",
"@budibase/colorpicker": "^1.0.1", "@budibase/colorpicker": "^1.0.1",
"@nx-js/compiler-util": "^2.0.0", "@nx-js/compiler-util": "^2.0.0",
"@sentry/browser": "5.19.1", "@sentry/browser": "5.19.1",
"@svelteschool/svelte-forms": "^0.7.0",
"codemirror": "^5.51.0", "codemirror": "^5.51.0",
"date-fns": "^1.29.0", "date-fns": "^1.29.0",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
@ -74,7 +77,8 @@
"string_decoder": "^1.2.0", "string_decoder": "^1.2.0",
"svelte-portal": "^0.1.0", "svelte-portal": "^0.1.0",
"svelte-simple-modal": "^0.4.2", "svelte-simple-modal": "^0.4.2",
"uikit": "^3.1.7" "uikit": "^3.1.7",
"yup": "^0.29.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.5.5", "@babel/core": "^7.5.5",
@ -89,6 +93,7 @@
"babel-jest": "^26.2.2", "babel-jest": "^26.2.2",
"browser-sync": "^2.26.7", "browser-sync": "^2.26.7",
"cypress": "^4.8.0", "cypress": "^4.8.0",
"cypress-terminal-report": "^1.4.1",
"eslint-plugin-cypress": "^2.11.1", "eslint-plugin-cypress": "^2.11.1",
"http-proxy-middleware": "^0.19.1", "http-proxy-middleware": "^0.19.1",
"jest": "^26.2.2", "jest": "^26.2.2",

View File

@ -3,6 +3,7 @@ import posthog from "posthog-js"
function activate() { function activate() {
Sentry.init({ dsn: process.env.SENTRY_DSN }) Sentry.init({ dsn: process.env.SENTRY_DSN })
if (!process.env.POSTHOG_TOKEN) return
posthog.init(process.env.POSTHOG_TOKEN, { posthog.init(process.env.POSTHOG_TOKEN, {
api_host: process.env.POSTHOG_URL, api_host: process.env.POSTHOG_URL,
}) })
@ -13,7 +14,7 @@ function captureException(err) {
} }
function captureEvent(event) { function captureEvent(event) {
if (process.env.NODE_ENV !== "production") return if (!process.env.POSTHOG_TOKEN) return
posthog.capture(event) posthog.capture(event)
} }

View File

@ -99,6 +99,7 @@
<div class="titled-input"> <div class="titled-input">
<header>Name</header> <header>Name</header>
<input <input
data-cy="table-name-input"
type="text" type="text"
class="budibase__input" class="budibase__input"
bind:value={$backendUiStore.draftModel.name} /> bind:value={$backendUiStore.draftModel.name} />

View File

@ -24,7 +24,7 @@
} }
</script> </script>
<span class="topnavitemright" on:click={showSettingsModal}> <span class="topnavitemright settings" on:click={showSettingsModal}>
<SettingsIcon /> <SettingsIcon />
</span> </span>

View File

@ -1,14 +1,10 @@
<script> <script>
import Button from "components/common/Button.svelte" import Button from "components/common/Button.svelte"
export let name, export let name, _id
description = `A minimalist CRM which removes the noise and allows you to focus
on your business.`,
_id
</script> </script>
<div class="apps-card"> <div class="apps-card">
<h3 class="app-title">{name}</h3> <h3 class="app-title">{name}</h3>
<p class="app-desc">{description}</p>
<div class="card-footer"> <div class="card-footer">
<a href={`/_builder/${_id}`} class="app-button">Open {name}</a> <a href={`/_builder/${_id}`} class="app-button">Open {name}</a>
</div> </div>

View File

@ -1,5 +1,13 @@
<script> <script>
import { writable } from "svelte/store"
import { store, workflowStore, backendUiStore } from "builderStore"
import { string, object } from "yup"
import api, { get } from "builderStore/api"
import Form from "@svelteschool/svelte-forms"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import { API, Info, User } from "./Steps"
import Indicator from "./Indicator.svelte"
import { Input, TextArea, Button } from "@budibase/bbui" import { Input, TextArea, Button } from "@budibase/bbui"
import { goto } from "@sveltech/routify" import { goto } from "@sveltech/routify"
import { AppsIcon, InfoIcon, CloseIcon } from "components/common/Icons/" import { AppsIcon, InfoIcon, CloseIcon } from "components/common/Icons/"
@ -9,49 +17,158 @@
import analytics from "../../analytics" import analytics from "../../analytics"
const { open, close } = getContext("simple-modal") const { open, close } = getContext("simple-modal")
//Move this to context="module" once svelte-forms is updated so that it can bind to stores correctly
const createAppStore = writable({ currentStep: 0, values: {} })
let name = "" export let hasKey
let description = ""
let loading = false
let error = {}
const createNewApp = async () => { let submitting = false
if ((name.length > 100 || name.length < 1) && description.length < 1) { let errors = {}
error = { let validationErrors = {}
name: true, let validationSchemas = [
description: true, {
apiKey: string().required("Please enter your API key."),
},
{
applicationName: string().required("Your application must have a name."),
},
{
username: string().required("Your application needs a first user."),
password: string().required(
"Please enter a password for your first user."
),
accessLevelId: string().required(
"You need to select an access level for your user."
),
},
]
let steps = [
{
component: API,
errors,
},
{
component: Info,
errors,
},
{
component: User,
errors,
},
]
if (hasKey) {
validationSchemas.shift()
validationSchemas = validationSchemas
steps.shift()
steps = steps
} }
} else if (description.length < 1) {
error = { // Handles form navigation
name: false, const back = () => {
description: true, if ($createAppStore.currentStep > 0) {
$createAppStore.currentStep -= 1
} }
} else if (name.length > 100 || name.length < 1) {
error = {
name: true,
} }
} else { const next = () => {
error = {} $createAppStore.currentStep += 1
const data = { name, description } }
loading = true
// $: errors = validationSchemas.validate(values);
$: getErrors(
$createAppStore.values,
validationSchemas[$createAppStore.currentStep]
)
async function getErrors(values, schema) {
try { try {
const response = await post("/api/applications", data) validationErrors = {}
await object(schema).validate(values, { abortEarly: false })
} catch (error) {
validationErrors = extractErrors(error)
}
}
const res = await response.json() const checkValidity = async (values, currentStep) => {
const validity = await object()
.shape(validationSchemas[currentStep])
.isValid(values)
currentStepIsValid = validity
// Check full form on last step
if (currentStep === steps.length - 1) {
// Make one big schema from all the small ones
const fullSchema = Object.assign({}, ...validationSchemas)
// Check full form schema
const formIsValid = await object()
.shape(fullSchema)
.isValid(values)
fullFormIsValid = formIsValid
}
}
async function signUp() {
submitting = true
try {
// Add API key if there is none.
if (!hasKey) {
await updateKey(["budibase", $createAppStore.values.apiKey])
}
// Create App
const appResp = await post("/api/applications", {
name: $createAppStore.values.applicationName,
})
const appJson = await appResp.json()
analytics.captureEvent("web_app_created", { analytics.captureEvent("web_app_created", {
name, name,
description, appId: appJson._id,
appId: res._id,
}) })
$goto(`./${res._id}`)
// Select Correct Application/DB in prep for creating user
const applicationPkg = await get(`/api/${appJson._id}/appPackage`)
const pkg = await applicationPkg.json()
if (applicationPkg.ok) {
backendUiStore.actions.reset()
await store.setPackage(pkg)
workflowStore.actions.fetch()
} else {
throw new Error(pkg)
}
// Create user
const user = {
name: $createAppStore.values.username,
username: $createAppStore.values.username,
password: $createAppStore.values.password,
accessLevelId: $createAppStore.values.accessLevelId,
}
const userResp = await api.post(`/api/users`, user)
const json = await userResp.json()
$goto(`./${appJson._id}`)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }
} }
async function updateKey([key, value]) {
const response = await api.put(`/api/keys/${key}`, { value })
const res = await response.json()
return res
} }
let value function extractErrors({ inner }) {
return inner.reduce((acc, err) => {
return { ...acc, [err.path]: err.message }
}, {})
}
let currentStepIsValid = false
let fullFormIsValid = false
$: checkValidity($createAppStore.values, $createAppStore.currentStep)
let onChange = () => {} let onChange = () => {}
function _onCancel() { function _onCancel() {
@ -64,45 +181,55 @@
</script> </script>
<div class="container"> <div class="container">
<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="body">
<div class="heading"> <div class="heading">
<span class="icon"> <h3 class="header">Get Started with Budibase</h3>
<AppsIcon />
</span>
<h3 class="header">Create new web app</h3>
</div> </div>
<Input <div class="step">
name="name" <Form bind:values={$createAppStore.values}>
label="Name" {#each steps as step, i (i)}
placeholder="Enter application name" <div class:hidden={$createAppStore.currentStep !== i}>
on:change={e => (name = e.target.value)} <svelte:component
on:input={e => (name = e.target.value)} /> this={step.component}
{#if error.name} {validationErrors}
<span class="error">You need to enter a name for your application.</span> options={step.options}
{/if} name={step.name} />
<TextArea </div>
bind:value={description} {/each}
name="description" </Form>
label="Description"
placeholder="Describe your application" />
{#if error.description}
<span class="error">
Please enter a short description of your application
</span>
{/if}
</div> </div>
<div class="footer"> <div class="footer">
<a href="./#" class="info"> {#if $createAppStore.currentStep > 0}
<InfoIcon /> <Button secondary on:click={back}>Back</Button>
How to get started {/if}
</a> {#if $createAppStore.currentStep < steps.length - 1}
<Button secondary thin on:click={_onCancel}>Cancel</Button> <Button secondary on:click={next} disabled={!currentStepIsValid}>
<Button primary thin on:click={_onOkay}>Save</Button> Next
</Button>
{/if}
{#if $createAppStore.currentStep === steps.length - 1}
<Button
secondary
on:click={signUp}
disabled={!fullFormIsValid || submitting}>
{submitting ? 'Loading...' : 'Submit'}
</Button>
{/if}
</div>
</div> </div>
<div class="close-button" on:click={_onCancel}> <div class="close-button" on:click={_onCancel}>
<CloseIcon /> <CloseIcon />
</div> </div>
{#if loading} <img src="/_builder/assets/bb-logo.svg" alt="budibase icon" />
{#if submitting}
<div in:fade class="spinner-container"> <div in:fade class="spinner-container">
<Spinner /> <Spinner />
<span class="spinner-text">Creating your app...</span> <span class="spinner-text">Creating your app...</span>
@ -112,9 +239,19 @@
<style> <style>
.container { .container {
min-height: 600px;
display: grid;
grid-template-columns: 80px 1fr;
position: relative; position: relative;
} }
.sidebar {
display: grid;
border-bottom-left-radius: 0.5rem;
border-top-left-radius: 0.5rem;
grid-gap: 30px;
align-content: center;
background: #f5f5f5;
}
.close-button { .close-button {
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
@ -135,43 +272,18 @@
margin: 0; margin: 0;
font-size: 24px; font-size: 24px;
font-weight: 600; font-weight: 600;
font-family: inter;
}
.icon {
display: grid;
border-radius: 3px;
align-content: center;
justify-content: center;
margin-right: 12px;
height: 20px;
width: 20px;
padding: 10px;
background-color: var(--blue-light);
}
.info {
color: var(--blue);
text-decoration-color: var(--blue);
}
.info :global(svg) {
fill: var(--blue);
margin-right: 8px;
width: 24px;
height: 24px;
} }
.body { .body {
padding: 40px 40px 80px 40px; padding: 40px 60px 60px 60px;
display: grid; display: grid;
grid-gap: 20px; align-items: center;
grid-template-rows: auto 1fr auto;
} }
.footer { .footer {
display: grid; display: grid;
grid-gap: 20px; grid-gap: 15px;
align-items: center; grid-template-columns: auto auto;
grid-template-columns: 1fr auto auto; justify-content: end;
padding: 30px 40px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 50px;
background-color: var(--grey-1);
} }
.spinner-container { .spinner-container {
background: white; background: white;
@ -189,9 +301,14 @@
.spinner-text { .spinner-text {
font-size: 2em; font-size: 2em;
} }
.error {
color: var(--red); .hidden {
font-weight: bold; display: none;
font-size: 0.8em; }
img {
position: absolute;
top: 20px;
left: 20px;
height: 40px;
} }
</style> </style>

View File

@ -0,0 +1,80 @@
<script>
export let step, done, active
</script>
<div class="container" class:active class:done>
<div class="circle" class:active class:done>
{#if done}
<svg
width="12"
height="10"
viewBox="0 0 12 10"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.1212 0.319527C10.327 0.115582 10.6047 0.000803464 10.8944
4.20219e-06C11.1841 -0.00079506 11.4624 0.11245 11.6693
0.315256C11.8762 0.518062 11.9949 0.794134 11.9998 1.08379C12.0048
1.37344 11.8955 1.65339 11.6957 1.86313L5.82705 9.19893C5.72619
9.30757 5.60445 9.39475 5.46913 9.45527C5.3338 9.51578 5.18766 9.54839
5.03944 9.55113C4.89123 9.55388 4.74398 9.52671 4.60651
9.47124C4.46903 9.41578 4.34416 9.33316 4.23934 9.22833L0.350925
5.33845C0.242598 5.23751 0.155712 5.11578 0.0954499 4.98054C0.0351876
4.84529 0.00278364 4.69929 0.00017159 4.55124C-0.00244046 4.4032
0.024793 4.25615 0.0802466 4.11886C0.1357 3.98157 0.218238 3.85685
0.322937 3.75215C0.427636 3.64746 0.55235 3.56492 0.68964
3.50946C0.82693 3.45401 0.973983 3.42678 1.12203 3.42939C1.27007 3.432
1.41607 3.46441 1.55132 3.52467C1.68657 3.58493 1.80829 3.67182
1.90923 3.78014L4.98762 6.85706L10.0933 0.35187C10.1024 0.340482
10.1122 0.329679 10.1227 0.319527H10.1212Z"
fill="white" />
</svg>
{:else}{step}{/if}
</div>
</div>
<style>
.container::before {
content: "";
position: absolute;
top: -30px;
width: 1px;
height: 30px;
background: #bdbdbd;
}
.container:first-child::before {
display: none;
}
.container {
position: relative;
height: 45px;
display: grid;
place-items: center;
}
.container.active {
box-shadow: inset 3px 0 0 0 #4285f4;
}
.circle.active {
background: #4285f4;
color: white;
border: none;
}
.circle.done {
background: #bdbdbd;
color: white;
border: none;
}
.circle {
color: #bdbdbd;
font-size: 14px;
display: grid;
place-items: center;
width: 30px;
height: 30px;
border-radius: 50%;
border: 1px solid #bdbdbd;
box-sizing: border-box;
}
</style>

View File

@ -0,0 +1,25 @@
<script>
import { Input } from "@budibase/bbui"
export let validationErrors
let blurred = { api: false }
</script>
<h2>Setup your API Key</h2>
<div class="container">
<Input
on:input={() => (blurred.api = true)}
label="API Key"
name="apiKey"
placeholder="Enter your API Key"
type="password"
error={blurred.api && validationErrors.apiKey} />
<a target="_blank" href="https://portal.budi.live/">Get API Key</a>
</div>
<style>
.container {
display: grid;
grid-gap: 40px;
}
</style>

View File

@ -0,0 +1,24 @@
<script>
import { Input } from "@budibase/bbui"
export let validationErrors
let blurred = { appName: false }
</script>
<h2>Create your first web app</h2>
<div class="container">
<Input
on:input={() => (blurred.appName = true)}
label="Web app name"
name="applicationName"
placeholder="Enter name of your web application"
type="name"
error={blurred.appName && validationErrors.applicationName} />
</div>
<style>
.container {
display: grid;
grid-gap: 40px;
}
</style>

View File

@ -0,0 +1,35 @@
<script>
import { Input, Select } from "@budibase/bbui"
export let validationErrors
let blurred = { username: false, password: false }
</script>
<h2>Create new user</h2>
<div class="container">
<Input
on:input={() => (blurred.username = true)}
label="Username"
name="username"
placeholder="Username"
type="name"
error={blurred.username && validationErrors.username} />
<Input
on:input={() => (blurred.password = true)}
label="Password"
name="password"
placeholder="Password"
type="pasword"
error={blurred.password && validationErrors.password} />
<Select name="accessLevelId">
<option value="ADMIN">Admin</option>
<option value="POWER_USER">Power User</option>
</Select>
</div>
<style>
.container {
display: grid;
grid-gap: 40px;
}
</style>

View File

@ -0,0 +1,3 @@
export { default as API } from "./API.svelte"
export { default as Info } from "./Info.svelte"
export { default as User } from "./User.svelte"

View File

@ -14,14 +14,6 @@
const getProperties = name => panelDefinition[name] const getProperties = name => panelDefinition[name]
onMount(() => {
// if(propGroup) {
// propGroup.addEventListener("scroll", function(e){
// console.log("I SCROLLED", e.target.scrollTop)
// })
// }
})
function onChange(category) { function onChange(category) {
selectedCategory = category selectedCategory = category
} }

View File

@ -32,7 +32,7 @@
<div class="property-control"> <div class="property-control">
<div class="label">{label}</div> <div class="label">{label}</div>
<div class="control"> <div data-cy={`${key}-prop-control`} class="control">
<svelte:component <svelte:component
this={control} this={control}
{...handlevalueKey(value)} {...handlevalueKey(value)}

View File

@ -246,6 +246,66 @@ export default {
name: "Blocks", name: "Blocks",
isCategory: true, isCategory: true,
children: [ children: [
{
name: "List",
_component: "@budibase/standard-components/list",
description: "Renders all children once per record, of a given table",
icon: "ri-file-list-line",
properties: {
design: { ...all },
settings: [{ label: "Table", key: "model", control: ModelSelect }],
},
children: [],
},
{
_component: "@budibase/standard-components/stackedlist",
name: "Stacked List",
description:
"A basic card component that can contain content and actions.",
icon: "ri-archive-drawer-line",
children: [],
properties: {
design: { ...all },
settings: [
{
label: "Image",
key: "imageUrl",
control: Input,
placeholder: "{{{context.Image}}}",
},
{
label: "Heading",
key: "heading",
control: Input,
placeholder: "{{context.Heading}}",
},
{
label: "Text 1",
key: "text1",
control: Input,
placeholder: "{{context.Text 1}}",
},
{
label: "Text 2",
key: "text2",
control: Input,
placeholder: "{{context.Text 2}}",
},
{
label: "Text 3",
key: "text3",
control: Input,
placeholder: "{{context.Text 3}}",
},
{
label: "destinationUrl",
key: "destinationUrl",
control: Input,
placeholder: "/table/_id",
},
],
},
},
{ {
_component: "@budibase/materialdesign-components/BasicCard", _component: "@budibase/materialdesign-components/BasicCard",
name: "Card", name: "Card",
@ -407,17 +467,6 @@ export default {
// }, // },
// children: [], // children: [],
// }, // },
{
name: "List",
_component: "@budibase/standard-components/list",
description: "Renders all children once per record, of a given table",
icon: "ri-file-list-line",
properties: {
design: { ...all },
settings: [{ label: "Table", key: "model", control: ModelSelect }],
},
children: [],
},
{ {
name: "Record Detail", name: "Record Detail",
_component: "@budibase/standard-components/recorddetail", _component: "@budibase/standard-components/recorddetail",

View File

@ -1,6 +1,7 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { store } from "builderStore" import { store } from "builderStore"
import api from "builderStore/api"
import AppList from "components/start/AppList.svelte" import AppList from "components/start/AppList.svelte"
import { onMount } from "svelte" import { onMount } from "svelte"
import ActionButton from "components/common/ActionButton.svelte" import ActionButton from "components/common/ActionButton.svelte"
@ -23,6 +24,24 @@
} }
} }
let hasKey
async function fetchKeys() {
const response = await api.get(`/api/keys/`)
const res = await response.json()
return res.budibase
}
async function checkIfKeysAndApps() {
const key = await fetchKeys()
const apps = await getApps()
if (key) {
hasKey = true
} else {
showCreateAppModal()
}
}
// Handle create app modal // Handle create app modal
const { open } = getContext("simple-modal") const { open } = getContext("simple-modal")
@ -30,8 +49,7 @@
open( open(
CreateAppModal, CreateAppModal,
{ {
message: "What is your name?", hasKey,
hasForm: true,
}, },
{ {
closeButton: false, closeButton: false,
@ -42,6 +60,8 @@
} }
) )
} }
checkIfKeysAndApps()
</script> </script>
<div class="header"> <div class="header">

View File

@ -1,6 +1,6 @@
{ {
"name": "budibase", "name": "budibase",
"version": "0.1.12", "version": "0.1.13",
"description": "Budibase CLI", "description": "Budibase CLI",
"repository": "https://github.com/Budibase/Budibase", "repository": "https://github.com/Budibase/Budibase",
"homepage": "https://www.budibase.com", "homepage": "https://www.budibase.com",
@ -17,7 +17,7 @@
"author": "Budibase", "author": "Budibase",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@budibase/server": "^0.1.12", "@budibase/server": "^0.1.13",
"@inquirer/password": "^0.0.6-alpha.0", "@inquirer/password": "^0.0.6-alpha.0",
"chalk": "^2.4.2", "chalk": "^2.4.2",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
@ -29,5 +29,5 @@
"uuid": "^7.0.3", "uuid": "^7.0.3",
"yargs": "^14.2.0" "yargs": "^14.2.0"
}, },
"gitHead": "eff4fa93ca1db11b97b5fdedc0c488413e277eb8" "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691"
} }

View File

@ -8,8 +8,6 @@ module.exports = async ({ dir }) => {
// dont make this a variable or top level require // dont make this a variable or top level require
// it will cause environment module to be loaded prematurely // it will cause environment module to be loaded prematurely
return require("@budibase/server/src/app")().then(server => { const server = require("@budibase/server/src/app")
server.on("close", () => console.log("Server Closed")) server.on("close", () => console.log("Server Closed"))
console.log(`Budibase running on ${JSON.stringify(server.address())}`)
})
} }

View File

@ -13,7 +13,7 @@
}, },
"devDependencies": { "devDependencies": {
"@budibase/client": "^0.1.1", "@budibase/client": "^0.1.1",
"@budibase/standard-components": "^0.1.10", "@budibase/standard-components": "^0.1.13",
"@material/button": "^4.0.0", "@material/button": "^4.0.0",
"@material/checkbox": "^4.0.0", "@material/checkbox": "^4.0.0",
"@material/data-table": "4.0.0", "@material/data-table": "4.0.0",
@ -50,9 +50,9 @@
"keywords": [ "keywords": [
"svelte" "svelte"
], ],
"version": "0.1.10", "version": "0.1.13",
"license": "MIT", "license": "MIT",
"gitHead": "eff4fa93ca1db11b97b5fdedc0c488413e277eb8", "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
"dependencies": { "dependencies": {
"@material/card": "4.0.0" "@material/card": "4.0.0"
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"version": "0.1.12", "version": "0.1.13",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/electron.js", "main": "src/electron.js",
"repository": { "repository": {
@ -97,5 +97,5 @@
"./scripts/jestSetup.js" "./scripts/jestSetup.js"
] ]
}, },
"gitHead": "eff4fa93ca1db11b97b5fdedc0c488413e277eb8" "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691"
} }

View File

@ -69,7 +69,6 @@ exports.create = async function(ctx) {
"@budibase/materialdesign-components", "@budibase/materialdesign-components",
], ],
name: ctx.request.body.name, name: ctx.request.body.name,
description: ctx.request.body.description,
} }
const { rev } = await db.put(newApplication) const { rev } = await db.put(newApplication)
@ -208,7 +207,7 @@ const getClientId = ctx => {
env.CLIENT_ID env.CLIENT_ID
if (!clientId) { if (!clientId) {
ctx.throw(400, "ClientId not suplied") ctx.throw(400, "ClientId not supplied")
} }
return clientId return clientId
} }

View File

@ -68,7 +68,9 @@ exports.save = async function(ctx) {
ctx.eventEmitter && ctx.eventEmitter &&
ctx.eventEmitter.emit(`record:save`, { ctx.eventEmitter.emit(`record:save`, {
args: {
record, record,
},
instanceId: ctx.user.instanceId, instanceId: ctx.user.instanceId,
}) })
ctx.body = record ctx.body = record

View File

@ -1,17 +1,17 @@
const recordController = require("../../record") const recordController = require("../../record")
module.exports = async function saveRecord({ args, instanceId }) { module.exports = async function saveRecord({ args, context }) {
const { model, ...record } = args.record const { model, ...record } = args.record
const ctx = { const ctx = {
params: { params: {
instanceId, instanceId: context.instanceId,
modelId: model._id, modelId: model._id,
}, },
request: { request: {
body: record, body: record,
}, },
user: { instanceId }, user: { instanceId: context.instanceId },
} }
await recordController.save(ctx) await recordController.save(ctx)

View File

@ -44,7 +44,9 @@ router
useAppRootPath: true, useAppRootPath: true,
} }
ctx.isDev = ctx.isDev =
process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "jest" process.env.NODE_ENV !== "production" &&
process.env.NODE_ENV !== "jest" &&
process.env.NODE_ENV !== "cypress"
await next() await next()
}) })
.use(authenticated) .use(authenticated)

View File

@ -18,7 +18,7 @@ async function executeRelevantWorkflows(event, eventType) {
workflowOrchestrator.strategy = serverStrategy workflowOrchestrator.strategy = serverStrategy
for (let workflow of workflows) { for (let workflow of workflows) {
workflowOrchestrator.execute(workflow) workflowOrchestrator.execute(workflow, event)
} }
} }

View File

@ -12,9 +12,9 @@ exports.Orchestrator = class Orchestrator {
this._strategy = strategy() this._strategy = strategy()
} }
async execute(workflow) { async execute(workflow, context) {
if (workflow.live) { if (workflow.live) {
this._strategy.run(workflow.definition) this._strategy.run(workflow.definition, context)
} }
} }
} }
@ -35,12 +35,15 @@ exports.serverStrategy = () => ({
return mappedArgs return mappedArgs
}, },
run: async function(workflow) { run: async function(workflow, context) {
for (let block of workflow.steps) { for (let block of workflow.steps) {
if (block.type === "CLIENT") continue if (block.type === "CLIENT") continue
const action = require(`../api/controllers/workflow/actions/${block.actionId}`) const action = require(`../api/controllers/workflow/actions/${block.actionId}`)
const response = await action({ args: this.bindContextArgs(block.args) }) const response = await action({
args: this.bindContextArgs(block.args),
context,
})
this.context = { this.context = {
...this.context, ...this.context,

View File

@ -5,6 +5,8 @@ const fetch = require("node-fetch")
const tar = require("tar-fs") const tar = require("tar-fs")
const zlib = require("zlib") const zlib = require("zlib")
const { promisify } = require("util") const { promisify } = require("util")
const packageJson = require("../../package.json")
const streamPipeline = promisify(stream.pipeline) const streamPipeline = promisify(stream.pipeline)
exports.appPackageFolder = (config, appname) => exports.appPackageFolder = (config, appname) =>
@ -16,8 +18,7 @@ exports.downloadExtractComponentLibraries = async appFolder => {
// Need to download tarballs directly from NPM as our users may not have node on their machine // Need to download tarballs directly from NPM as our users may not have node on their machine
for (let lib of LIBRARIES) { for (let lib of LIBRARIES) {
// download tarball // download tarball
// TODO: make sure the latest version is always downloaded const registryUrl = `https://registry.npmjs.org/@budibase/${lib}/-/${lib}-${packageJson.version}.tgz`
const registryUrl = `https://registry.npmjs.org/@budibase/${lib}/-/${lib}-0.1.2.tgz`
const response = await fetch(registryUrl) const response = await fetch(registryUrl)
if (!response.ok) if (!response.ok)
throw new Error(`unexpected response ${response.statusText}`) throw new Error(`unexpected response ${response.statusText}`)

View File

@ -172,21 +172,6 @@
lodash "^4.17.13" lodash "^4.17.13"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@budibase/client@^0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.1.1.tgz#6df65bef641d956dea6d648e5dcd7e95622a24fc"
integrity sha512-z5CYj/4wahV9Kg7GwYi1knRZdm60uspkjOX7b3GXy85Zam1+m4ObSQ1aT6857WCXgl2+CQ3hIb2QGqSZfOTFuA==
dependencies:
"@nx-js/compiler-util" "^2.0.0"
bcryptjs "^2.4.3"
deep-equal "^2.0.1"
lodash "^4.17.15"
lunr "^2.3.5"
mustache "^4.0.1"
regexparam "^1.3.0"
shortid "^2.2.8"
svelte "^3.9.2"
"@cnakazawa/watch@^1.0.3": "@cnakazawa/watch@^1.0.3":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
@ -369,11 +354,6 @@
path-to-regexp "1.x" path-to-regexp "1.x"
urijs "^1.19.2" urijs "^1.19.2"
"@nx-js/compiler-util@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@nx-js/compiler-util/-/compiler-util-2.0.0.tgz#c74c12165fa2f017a292bb79af007e8fce0af297"
integrity sha512-AxSQbwj9zqt8DYPZ6LwZdytqnwfiOEdcFdq4l8sdjkZmU2clTht7RDLCI8xvkp7KqgcNaOGlTeCM55TULWruyQ==
"@sendgrid/client@^7.1.1": "@sendgrid/client@^7.1.1":
version "7.1.1" version "7.1.1"
resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.1.1.tgz#09a25e58ac7e5321d66807e7110ff0fb61bb534f" resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.1.1.tgz#09a25e58ac7e5321d66807e7110ff0fb61bb534f"
@ -842,11 +822,6 @@ array-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
array-filter@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
array-unique@^0.3.2: array-unique@^0.3.2:
version "0.3.2" version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
@ -906,13 +881,6 @@ atomic-sleep@^1.0.0:
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==
available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==
dependencies:
array-filter "^1.0.0"
aws-sdk@^2.706.0: aws-sdk@^2.706.0:
version "2.706.0" version "2.706.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz#09f65e9a91ecac5a635daf934082abae30eca953" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz#09f65e9a91ecac5a635daf934082abae30eca953"
@ -1584,26 +1552,6 @@ decompress-response@^3.3.0:
dependencies: dependencies:
mimic-response "^1.0.0" mimic-response "^1.0.0"
deep-equal@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.3.tgz#cad1c15277ad78a5c01c49c2dee0f54de8a6a7b0"
integrity sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==
dependencies:
es-abstract "^1.17.5"
es-get-iterator "^1.1.0"
is-arguments "^1.0.4"
is-date-object "^1.0.2"
is-regex "^1.0.5"
isarray "^2.0.5"
object-is "^1.1.2"
object-keys "^1.1.1"
object.assign "^4.1.0"
regexp.prototype.flags "^1.3.0"
side-channel "^1.0.2"
which-boxed-primitive "^1.0.1"
which-collection "^1.0.1"
which-typed-array "^1.1.2"
deep-equal@~1.0.1: deep-equal@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@ -1932,36 +1880,6 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5:
string.prototype.trimleft "^2.1.1" string.prototype.trimleft "^2.1.1"
string.prototype.trimright "^2.1.1" string.prototype.trimright "^2.1.1"
es-abstract@^1.17.4:
version "1.17.6"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.2.0"
is-regex "^1.1.0"
object-inspect "^1.7.0"
object-keys "^1.1.1"
object.assign "^4.1.0"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
es-get-iterator@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8"
integrity sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==
dependencies:
es-abstract "^1.17.4"
has-symbols "^1.0.1"
is-arguments "^1.0.4"
is-map "^2.0.1"
is-set "^2.0.1"
is-string "^1.0.5"
isarray "^2.0.5"
es-to-primitive@^1.2.1: es-to-primitive@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@ -2856,32 +2774,17 @@ is-accessor-descriptor@^1.0.0:
dependencies: dependencies:
kind-of "^6.0.0" kind-of "^6.0.0"
is-arguments@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
is-arrayish@^0.2.1: is-arrayish@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
is-bigint@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4"
integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==
is-binary-path@~2.1.0: is-binary-path@~2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
dependencies: dependencies:
binary-extensions "^2.0.0" binary-extensions "^2.0.0"
is-boolean-object@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e"
integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==
is-buffer@^1.1.5: is-buffer@^1.1.5:
version "1.1.6" version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -2891,11 +2794,6 @@ is-callable@^1.1.4, is-callable@^1.1.5:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==
is-callable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
is-ci@^2.0.0: is-ci@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
@ -2918,7 +2816,7 @@ is-data-descriptor@^1.0.0:
dependencies: dependencies:
kind-of "^6.0.0" kind-of "^6.0.0"
is-date-object@^1.0.1, is-date-object@^1.0.2: is-date-object@^1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
@ -2981,21 +2879,11 @@ is-installed-globally@^0.3.1:
global-dirs "^2.0.1" global-dirs "^2.0.1"
is-path-inside "^3.0.1" is-path-inside "^3.0.1"
is-map@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1"
integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==
is-npm@^4.0.0: is-npm@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==
is-number-object@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197"
integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==
is-number@^3.0.0: is-number@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
@ -3026,28 +2914,11 @@ is-regex@^1.0.5:
dependencies: dependencies:
has "^1.0.3" has "^1.0.3"
is-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
dependencies:
has-symbols "^1.0.1"
is-set@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.1.tgz#d1604afdab1724986d30091575f54945da7e5f43"
integrity sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==
is-stream@^1.1.0: is-stream@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
is-string@^1.0.4, is-string@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
is-symbol@^1.0.2: is-symbol@^1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@ -3062,31 +2933,11 @@ is-type-of@^1.0.0:
is-class-hotfix "~0.0.6" is-class-hotfix "~0.0.6"
isstream "~0.1.2" isstream "~0.1.2"
is-typed-array@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d"
integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==
dependencies:
available-typed-arrays "^1.0.0"
es-abstract "^1.17.4"
foreach "^2.0.5"
has-symbols "^1.0.1"
is-typedarray@^1.0.0, is-typedarray@~1.0.0: is-typedarray@^1.0.0, is-typedarray@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
is-weakmap@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
is-weakset@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83"
integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==
is-windows@^1.0.2: is-windows@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@ -3108,11 +2959,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isarray@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isbinaryfile@^4.0.6: isbinaryfile@^4.0.6:
version "4.0.6" version "4.0.6"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b"
@ -4009,14 +3855,10 @@ lodash.sortby@^4.7.0:
version "4.7.0" version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
lodash@^4.17.10: lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
version "4.17.19" version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
loose-envify@^1.0.0: loose-envify@^1.0.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -4058,11 +3900,6 @@ ltgt@~2.1.3:
version "2.1.3" version "2.1.3"
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34"
lunr@^2.3.5:
version "2.3.8"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
integrity sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==
make-dir@^2.1.0: make-dir@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
@ -4227,11 +4064,6 @@ nan@^2.12.1:
version "2.14.0" version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
nanoid@^2.1.0:
version "2.1.11"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
nanomatch@^1.2.9: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -4381,14 +4213,6 @@ object-inspect@^1.7.0:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
object-is@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.1.1: object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@ -5038,19 +4862,6 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2" extend-shallow "^3.0.2"
safe-regex "^1.1.0" safe-regex "^1.1.0"
regexp.prototype.flags@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.0-next.1"
regexparam@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f"
integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==
regexpp@^2.0.1: regexpp@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
@ -5344,21 +5155,6 @@ shellwords@^0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
shortid@^2.2.8:
version "2.2.15"
resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.15.tgz#2b902eaa93a69b11120373cd42a1f1fe4437c122"
integrity sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==
dependencies:
nanoid "^2.1.0"
side-channel@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==
dependencies:
es-abstract "^1.17.0-next.1"
object-inspect "^1.7.0"
signal-exit@^3.0.0, signal-exit@^3.0.2: signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@ -5575,7 +5371,7 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
is-fullwidth-code-point "^3.0.0" is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
string.prototype.trimend@^1.0.0, string.prototype.trimend@^1.0.1: string.prototype.trimend@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
dependencies: dependencies:
@ -5598,7 +5394,7 @@ string.prototype.trimright@^2.1.1:
es-abstract "^1.17.5" es-abstract "^1.17.5"
string.prototype.trimend "^1.0.0" string.prototype.trimend "^1.0.0"
string.prototype.trimstart@^1.0.0, string.prototype.trimstart@^1.0.1: string.prototype.trimstart@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
dependencies: dependencies:
@ -5717,11 +5513,6 @@ supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" has-flag "^4.0.0"
svelte@^3.9.2:
version "3.24.0"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.24.0.tgz#6565a42c9705796fa66c6abb4fedc09f4323a4a8"
integrity sha512-VFXom6EP2DK83kxy4ZlBbaZklSbZIrpNH3oNXlPYHJUuW4q1OuAr3ZoYbfIVTVYPDgrI7Yq0gQcOhDlAtO4qfw==
symbol-tree@^3.2.2: symbol-tree@^3.2.2:
version "3.2.4" version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
@ -6156,44 +5947,11 @@ whatwg-url@^7.0.0:
tr46 "^1.0.1" tr46 "^1.0.1"
webidl-conversions "^4.0.2" webidl-conversions "^4.0.2"
which-boxed-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1"
integrity sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==
dependencies:
is-bigint "^1.0.0"
is-boolean-object "^1.0.0"
is-number-object "^1.0.3"
is-string "^1.0.4"
is-symbol "^1.0.2"
which-collection@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"
integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==
dependencies:
is-map "^2.0.1"
is-set "^2.0.1"
is-weakmap "^2.0.1"
is-weakset "^2.0.1"
which-module@^2.0.0: which-module@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
which-typed-array@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2"
integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==
dependencies:
available-typed-arrays "^1.0.2"
es-abstract "^1.17.5"
foreach "^2.0.5"
function-bind "^1.1.1"
has-symbols "^1.0.1"
is-typed-array "^1.1.3"
which@^1.2.9, which@^1.3.0: which@^1.2.9, which@^1.3.0:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"

View File

@ -249,6 +249,18 @@
"model": "models" "model": "models"
} }
}, },
"stackedlist": {
"name": "Stacked List",
"description": "A stacked list component for displaying information",
"props": {
"imageUrl": "string",
"heading": "string",
"text1": "string",
"text2": "string",
"text3": "string",
"destinationUrl": "string"
}
},
"recorddetail": { "recorddetail": {
"description": "Loads a record, using an ID in the url", "description": "Loads a record, using an ID in the url",
"data": true, "data": true,

View File

@ -33,11 +33,12 @@
"keywords": [ "keywords": [
"svelte" "svelte"
], ],
"version": "0.1.10", "version": "0.1.13",
"license": "MIT", "license": "MIT",
"gitHead": "eff4fa93ca1db11b97b5fdedc0c488413e277eb8", "gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691",
"dependencies": { "dependencies": {
"@beyonk/svelte-googlemaps": "^2.2.0", "@beyonk/svelte-googlemaps": "^2.2.0",
"fast-sort": "^2.2.0",
"fusioncharts": "^3.15.1-sr.1", "fusioncharts": "^3.15.1-sr.1",
"svelte-fusioncharts": "^1.0.0" "svelte-fusioncharts": "^1.0.0"
} }

View File

@ -32,11 +32,35 @@
$: Object.values(inputElements).length && setForm(record) $: Object.values(inputElements).length && setForm(record)
const createBlankRecord = () => {
if (!schema) return
const newrecord = {
modelId: model,
}
for (let fieldName in schema) {
const field = schema[fieldName]
// defaulting to first one, as a blank value will fail validation
if (
field.type === "string" &&
field.constraints &&
field.constraints.inclusion &&
field.constraints.inclusion.length > 0
) {
newrecord[fieldName] = field.constraints.inclusion[0]
} else if (field.type === "number") newrecord[fieldName] = null
else if (field.type === "boolean") newrecord[fieldName] = false
else if (field.type === "link") newrecord[fieldName] = []
else newrecord[fieldName] = ""
}
return newrecord
}
async function fetchModel() { async function fetchModel() {
const FETCH_MODEL_URL = `/api/models/${model}` const FETCH_MODEL_URL = `/api/models/${model}`
const response = await _bb.api.get(FETCH_MODEL_URL) const response = await _bb.api.get(FETCH_MODEL_URL)
modelDef = await response.json() modelDef = await response.json()
schema = modelDef.schema schema = modelDef.schema
record = createBlankRecord()
} }
async function save() { async function save() {
@ -81,9 +105,7 @@
el.checked = false el.checked = false
} }
} }
record = { record = createBlankRecord()
modelId: model,
}
} }
const setForm = rec => { const setForm = rec => {
@ -123,7 +145,7 @@
isNew = !recordId || recordId === "new" isNew = !recordId || recordId === "new"
if (isNew) { if (isNew) {
record = { modelId: model } record = createBlankRecord()
} else { } else {
const GET_RECORD_URL = `/api/${model}/records/${recordId}` const GET_RECORD_URL = `/api/${model}/records/${recordId}`
_bb.api _bb.api

View File

@ -32,11 +32,35 @@
$: Object.values(inputElements).length && setForm(record) $: Object.values(inputElements).length && setForm(record)
const createBlankRecord = () => {
if (!schema) return
const newrecord = {
modelId: model,
}
for (let fieldName in schema) {
const field = schema[fieldName]
// defaulting to first one, as a blank value will fail validation
if (
field.type === "string" &&
field.constraints &&
field.constraints.inclusion &&
field.constraints.inclusion.length > 0
) {
newrecord[fieldName] = field.constraints.inclusion[0]
} else if (field.type === "number") newrecord[fieldName] = null
else if (field.type === "boolean") newrecord[fieldName] = false
else if (field.type === "link") newrecord[fieldName] = []
else newrecord[fieldName] = ""
}
return newrecord
}
async function fetchModel() { async function fetchModel() {
const FETCH_MODEL_URL = `/api/models/${model}` const FETCH_MODEL_URL = `/api/models/${model}`
const response = await _bb.api.get(FETCH_MODEL_URL) const response = await _bb.api.get(FETCH_MODEL_URL)
modelDef = await response.json() modelDef = await response.json()
schema = modelDef.schema schema = modelDef.schema
record = createBlankRecord()
} }
async function save() { async function save() {
@ -81,9 +105,7 @@
el.checked = false el.checked = false
} }
} }
record = { record = createBlankRecord()
modelId: model,
}
} }
const setForm = rec => { const setForm = rec => {
@ -123,7 +145,7 @@
isNew = !recordId || recordId === "new" isNew = !recordId || recordId === "new"
if (isNew) { if (isNew) {
record = { modelId: model } record = createBlankRecord()
} else { } else {
const GET_RECORD_URL = `/api/${model}/records/${recordId}` const GET_RECORD_URL = `/api/${model}/records/${recordId}`
_bb.api _bb.api

View File

@ -1,31 +0,0 @@
<script>
import { GoogleMap } from "@beyonk/svelte-googlemaps"
// export let _bb
// export let onLoad
// export let _instanceId
// export let model
// let mapComponent
// let headers = []
// let store = _bb.store
// $: data = $store[model._id] || []
// async function fetchData() {
// const FETCH_RECORDS_URL = `/api/${_instanceId}/all_${model._id}/records`
// const response = await _bb.api.get(FETCH_RECORDS_URL)
// if (response.status === 200) {
// const json = await response.json()
// store.update(state => {
// state[model._id] = json
// return state
// });
// } else {
// throw new Error("Failed to fetch records.", response)
// }
// }
</script>
<GoogleMap apiKey={'AIzaSyCPJ_eiSIbhRMmKBiVYXgh4HFHmbC4ZL5U'} />

View File

@ -1,6 +1,9 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { cssVars, createClasses } from "./cssVars" import { cssVars, createClasses } from "./cssVars"
import ArrowUp from "./icons/ArrowUp.svelte"
import ArrowDown from "./icons/ArrowDown.svelte"
import fsort from "fast-sort"
export let _bb export let _bb
export let onLoad export let onLoad
@ -12,6 +15,8 @@
let headers = [] let headers = []
let store = _bb.store let store = _bb.store
let sort = {}
let sorted = []
$: cssVariables = { $: cssVariables = {
backgroundColor, backgroundColor,
@ -20,6 +25,10 @@
borderColor, borderColor,
} }
$: data = $store[model] || []
$: sorted = sort.direction ? fsort(data)[sort.direction](sort.column) : data
$: if (model) fetchData()
const shouldDisplayField = name => { const shouldDisplayField = name => {
if (name.startsWith("_")) return false if (name.startsWith("_")) return false
// always 'record' // always 'record'
@ -48,8 +57,20 @@
} }
} }
$: data = $store[model] || [] function sortColumn(column) {
$: if (model) fetchData() if (column === sort.column) {
sort = {
direction: sort.direction === "asc" ? "desc" : null,
column: sort.direction === "asc" ? sort.column : null,
}
return
}
sort = {
column,
direction: "asc",
}
}
onMount(async () => { onMount(async () => {
await fetchData() await fetchData()
@ -60,12 +81,21 @@
<thead> <thead>
<tr> <tr>
{#each headers as header} {#each headers as header}
<th>{header}</th> <th on:click={() => sortColumn(header)}>
<span>
{header}
{#if sort.column === header}
<svelte:component
this={sort.direction === 'asc' ? ArrowDown : ArrowUp}
style="height: 1em;" />
{/if}
</span>
</th>
{/each} {/each}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each data as row} {#each sorted as row (row._id)}
<tr> <tr>
{#each headers as header} {#each headers as header}
{#if row[header]} {#if row[header]}
@ -95,6 +125,12 @@
color: var(--color); color: var(--color);
font-weight: bold; font-weight: bold;
text-transform: capitalize; text-transform: capitalize;
cursor: pointer;
}
th span {
display: flex;
align-items: center;
} }
td, td,

View File

@ -0,0 +1,89 @@
<script>
export let imageUrl = ""
export let heading = ""
export let text1 = ""
export let text2 = ""
export let text3 = ""
export let destinationUrl = ""
$: showImage = !!imageUrl
</script>
<div class="container">
<a href={destinationUrl}>
<div class="content">
{#if showImage}
<div class="image-block">
<img class="image" src={imageUrl} alt="" />
</div>
{/if}
<h2 class="heading">{heading}</h2>
<h4 class="text">{text1}</h4>
<h4 class="text">{text2}</h4>
<h4 class="text3">{text3}</h4>
</div>
</a>
</div>
<style>
a {
text-decoration: none;
color: inherit;
}
.container {
padding: 20px;
}
.content {
display: grid;
grid-template-columns: 120px 300px 1fr 1fr 1fr;
align-items: center;
gap: 20px;
min-height: 80px;
}
@media (max-width: 800px) {
.content {
display: grid;
grid-template-columns: 1fr;
gap: 20px;
}
}
.image-block {
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
}
.image {
padding: 2px;
max-width: 80px;
max-height: 80px;
margin-right: 20px;
}
.heading {
font-size: 24px;
margin: 0;
min-width: 200px;
}
.text {
font-size: 16px;
font-weight: 400;
}
.text3 {
text-align: end;
font-size: 16px;
font-weight: 400;
}
@media (max-width: 800px) {
.text3 {
text-align: start;
}
}
</style>

View File

@ -0,0 +1,10 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="18"
height="18">
<path fill="none" d="M0 0h24v24H0z" />
<path
d="M13 16.172l5.364-5.364 1.414 1.414L12 20l-7.778-7.778 1.414-1.414L11
16.172V4h2v12.172z" />
</svg>

After

Width:  |  Height:  |  Size: 251 B

View File

@ -0,0 +1,10 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="18"
height="18">
<path fill="none" d="M0 0h24v24H0z" />
<path
d="M13 7.828V20h-2V7.828l-5.364 5.364-1.414-1.414L12 4l7.778 7.778-1.414
1.414L13 7.828z" />
</svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@ -21,6 +21,6 @@ export { default as datachart } from "./DataChart.svelte"
export { default as datalist } from "./DataList.svelte" export { default as datalist } from "./DataList.svelte"
export { default as list } from "./List.svelte" export { default as list } from "./List.svelte"
export { default as datasearch } from "./DataSearch.svelte" export { default as datasearch } from "./DataSearch.svelte"
export { default as datamap } from "./DataMap.svelte"
export { default as embed } from "./Embed.svelte" export { default as embed } from "./Embed.svelte"
export { default as stackedlist } from "./StackedList.svelte"
export { default as recorddetail } from "./RecordDetail.svelte" export { default as recorddetail } from "./RecordDetail.svelte"