Merge pull request #367 from Budibase/backend-ui-update
Backend ui update
This commit is contained in:
commit
6cdd933d09
|
@ -50,7 +50,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@beyonk/svelte-notifications": "^2.0.3",
|
|
||||||
"@budibase/bbui": "^1.10.1",
|
"@budibase/bbui": "^1.10.1",
|
||||||
"@budibase/client": "^0.0.32",
|
"@budibase/client": "^0.0.32",
|
||||||
"@nx-js/compiler-util": "^2.0.0",
|
"@nx-js/compiler-util": "^2.0.0",
|
||||||
|
@ -101,4 +100,4 @@
|
||||||
"svelte": "3.23.x"
|
"svelte": "3.23.x"
|
||||||
},
|
},
|
||||||
"gitHead": "115189f72a850bfb52b65ec61d932531bf327072"
|
"gitHead": "115189f72a850bfb52b65ec61d932531bf327072"
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,10 @@ export default {
|
||||||
find: "builderStore",
|
find: "builderStore",
|
||||||
replacement: path.resolve(projectRootDir, "src/builderStore"),
|
replacement: path.resolve(projectRootDir, "src/builderStore"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
find: "constants",
|
||||||
|
replacement: path.resolve(projectRootDir, "src/constants"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
customResolver,
|
customResolver,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -4,30 +4,10 @@
|
||||||
import { Router, basepath } from "@sveltech/routify"
|
import { Router, basepath } from "@sveltech/routify"
|
||||||
import { routes } from "../routify/routes"
|
import { routes } from "../routify/routes"
|
||||||
import { store, initialise } from "builderStore"
|
import { store, initialise } from "builderStore"
|
||||||
import AppNotification, {
|
import NotificationDisplay from "components/common/Notification/NotificationDisplay.svelte"
|
||||||
showAppNotification,
|
|
||||||
} from "components/common/AppNotification.svelte"
|
|
||||||
import { NotificationDisplay } from "@beyonk/svelte-notifications"
|
|
||||||
|
|
||||||
function showErrorBanner() {
|
|
||||||
showAppNotification({
|
|
||||||
status: "danger",
|
|
||||||
message:
|
|
||||||
"Whoops! Looks like we're having trouble. Please refresh the page.",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
window.addEventListener("error", showErrorBanner)
|
|
||||||
window.addEventListener("unhandledrejection", showErrorBanner)
|
|
||||||
})
|
|
||||||
|
|
||||||
$basepath = "/_builder"
|
$basepath = "/_builder"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AppNotification />
|
|
||||||
|
|
||||||
<!-- svelte-notifications -->
|
|
||||||
<NotificationDisplay />
|
<NotificationDisplay />
|
||||||
|
|
||||||
<Router {routes} />
|
<Router {routes} />
|
||||||
|
|
|
@ -84,7 +84,6 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-left: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.uk-text-right {
|
.uk-text-right {
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
|
import { cloneDeep } from "lodash/fp"
|
||||||
|
import { uuid } from "builderStore/uuid"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
import { getContext } from "svelte"
|
|
||||||
|
|
||||||
/** TODO: DEMO SOLUTION
|
|
||||||
* this section should not be here, it is a quick fix for a demo
|
|
||||||
* when we reorg the backend UI, this should disappear
|
|
||||||
* **/
|
|
||||||
import { CreateEditModelModal } from "components/database/ModelDataTable/modals"
|
|
||||||
/** DEMO SOLUTION END **/
|
|
||||||
|
|
||||||
export const getBackendUiStore = () => {
|
export const getBackendUiStore = () => {
|
||||||
const INITIAL_BACKEND_UI_STATE = {
|
const INITIAL_BACKEND_UI_STATE = {
|
||||||
breadcrumbs: [],
|
|
||||||
models: [],
|
models: [],
|
||||||
views: [],
|
views: [],
|
||||||
users: [],
|
users: [],
|
||||||
selectedDatabase: {},
|
selectedDatabase: {},
|
||||||
selectedModel: {},
|
selectedModel: {},
|
||||||
|
draftModel: {},
|
||||||
|
tabs: {
|
||||||
|
SETUP_PANEL: "SETUP",
|
||||||
|
NAVIGATION_PANEL: "NAVIGATE",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = writable(INITIAL_BACKEND_UI_STATE)
|
const store = writable(INITIAL_BACKEND_UI_STATE)
|
||||||
|
@ -31,26 +29,12 @@ export const getBackendUiStore = () => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.selectedDatabase = db
|
state.selectedDatabase = db
|
||||||
if (models && models.length > 0) {
|
if (models && models.length > 0) {
|
||||||
state.selectedModel = models[0]
|
store.actions.models.select(models[0])
|
||||||
state.selectedView = `all_${models[0]._id}`
|
|
||||||
}
|
}
|
||||||
state.breadcrumbs = [db.name]
|
|
||||||
state.models = models
|
state.models = models
|
||||||
state.views = views
|
state.views = views
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
/** TODO: DEMO SOLUTION**/
|
|
||||||
if (!models || models.length === 0) {
|
|
||||||
const { open, close } = getContext("simple-modal")
|
|
||||||
open(
|
|
||||||
CreateEditModelModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/** DEMO SOLUTION END **/
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
records: {
|
records: {
|
||||||
|
@ -59,11 +43,6 @@ export const getBackendUiStore = () => {
|
||||||
state.selectedView = state.selectedView
|
state.selectedView = state.selectedView
|
||||||
return state
|
return state
|
||||||
}),
|
}),
|
||||||
view: record =>
|
|
||||||
store.update(state => {
|
|
||||||
state.breadcrumbs = [state.selectedDatabase.name, record._id]
|
|
||||||
return state
|
|
||||||
}),
|
|
||||||
select: record =>
|
select: record =>
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.selectedRecord = record
|
state.selectedRecord = record
|
||||||
|
@ -71,14 +50,48 @@ export const getBackendUiStore = () => {
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
models: {
|
models: {
|
||||||
create: model =>
|
fetch: async () => {
|
||||||
|
const modelsResponse = await api.get(`/api/models`)
|
||||||
|
const models = await modelsResponse.json()
|
||||||
|
store.update(state => {
|
||||||
|
state.models = models
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
},
|
||||||
|
select: model =>
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.models.push(model)
|
|
||||||
state.models = state.models
|
|
||||||
state.selectedModel = model
|
state.selectedModel = model
|
||||||
|
state.draftModel = cloneDeep(model)
|
||||||
|
state.selectedField = ""
|
||||||
state.selectedView = `all_${model._id}`
|
state.selectedView = `all_${model._id}`
|
||||||
|
state.tabs.SETUP_PANEL = "SETUP"
|
||||||
return state
|
return state
|
||||||
}),
|
}),
|
||||||
|
save: async ({ model }) => {
|
||||||
|
const updatedModel = cloneDeep(model)
|
||||||
|
|
||||||
|
const SAVE_MODEL_URL = `/api/models`
|
||||||
|
await api.post(SAVE_MODEL_URL, updatedModel)
|
||||||
|
await store.actions.models.fetch()
|
||||||
|
},
|
||||||
|
addField: field => {
|
||||||
|
store.update(state => {
|
||||||
|
if (!state.draftModel.schema) {
|
||||||
|
state.draftModel.schema = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = uuid()
|
||||||
|
|
||||||
|
state.draftModel.schema = {
|
||||||
|
...state.draftModel.schema,
|
||||||
|
[id]: field,
|
||||||
|
}
|
||||||
|
state.selectedField = id
|
||||||
|
state.tabs.NAVIGATION_PANEL = "NAVIGATE"
|
||||||
|
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
views: {
|
views: {
|
||||||
select: view =>
|
select: view =>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
import { generate } from "shortid"
|
||||||
|
|
||||||
|
export const notificationStore = writable({
|
||||||
|
notifications: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
export function send(message, type = "default") {
|
||||||
|
notificationStore.update(state => {
|
||||||
|
state.notifications = [
|
||||||
|
...state.notifications,
|
||||||
|
{ id: generate(), type, message },
|
||||||
|
]
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifier = {
|
||||||
|
danger: msg => send(msg, "danger"),
|
||||||
|
warning: msg => send(msg, "warning"),
|
||||||
|
info: msg => send(msg, "info"),
|
||||||
|
success: msg => send(msg, "success"),
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
<script context="module">
|
|
||||||
import UIKit from "uikit"
|
|
||||||
|
|
||||||
export function showAppNotification({ message, status }) {
|
|
||||||
UIKit.notification({
|
|
||||||
message: `
|
|
||||||
<div class="message-container">
|
|
||||||
<div class="information-icon">🤯</div>
|
|
||||||
<span class="notification-message">
|
|
||||||
${message}
|
|
||||||
</span>
|
|
||||||
<button class="hoverable refresh-page-button" onclick="window.location.reload()">Refresh Page</button>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
status,
|
|
||||||
timeout: 100000,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:global(.information-icon) {
|
|
||||||
font-size: 24px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.uk-nofi) {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 40px 1fr auto;
|
|
||||||
grid-gap: 5px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.message-container) {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.uk-notification) {
|
|
||||||
width: 50% !important;
|
|
||||||
left: 0 !important;
|
|
||||||
right: 0 !important;
|
|
||||||
margin-right: auto !important;
|
|
||||||
margin-left: auto !important;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.uk-notification-message) {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.uk-notification-message:hover .uk-notification-close) {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.uk-notification-message-danger) {
|
|
||||||
background: var(--grey-9) !important;
|
|
||||||
color: #fff !important;
|
|
||||||
font-size: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.refresh-page-button) {
|
|
||||||
font-size: 14px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: none;
|
|
||||||
padding: 8px 16px;
|
|
||||||
color: var(--ink);
|
|
||||||
background: #ffffff;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.refresh-page-button):hover {
|
|
||||||
background: var(--grey-1);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<script>
|
||||||
|
export let title
|
||||||
|
export let icon
|
||||||
|
|
||||||
|
export let primary
|
||||||
|
export let secondary
|
||||||
|
export let tertiary
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div on:click class:primary class:secondary class:tertiary>
|
||||||
|
<i class={icon} />
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
height: 80px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: 0.3s transform;
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
background: var(--ink);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
background: var(--blue-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tertiary {
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -3,8 +3,8 @@
|
||||||
export let label = ""
|
export let label = ""
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<input class="uk-checkbox" type="checkbox" bind:checked on:change />
|
|
||||||
{label}
|
{label}
|
||||||
|
<input class="uk-checkbox" type="checkbox" bind:checked on:change />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
input {
|
input {
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
export let modelId
|
||||||
|
export let linkName
|
||||||
|
export let linked = []
|
||||||
|
|
||||||
|
let records = []
|
||||||
|
let model = {}
|
||||||
|
|
||||||
|
let linkedRecords = new Set(linked)
|
||||||
|
|
||||||
|
$: linked = [...linkedRecords]
|
||||||
|
$: FIELDS_TO_HIDE = [$backendUiStore.selectedModel._id]
|
||||||
|
$: schema = $backendUiStore.selectedModel.schema
|
||||||
|
|
||||||
|
async function fetchRecords() {
|
||||||
|
const FETCH_RECORDS_URL = `/api/${modelId}/records`
|
||||||
|
const response = await api.get(FETCH_RECORDS_URL)
|
||||||
|
const modelResponse = await api.get(`/api/models/${modelId}`)
|
||||||
|
|
||||||
|
model = await modelResponse.json()
|
||||||
|
records = await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkRecord(id) {
|
||||||
|
if (linkedRecords.has(id)) {
|
||||||
|
linkedRecords.delete(id)
|
||||||
|
} else {
|
||||||
|
linkedRecords.add(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedRecords = linkedRecords
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
fetchRecords()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<h3>{linkName}</h3>
|
||||||
|
</header>
|
||||||
|
{#each records as record}
|
||||||
|
<div class="linked-record" on:click={() => linkRecord(record._id)}>
|
||||||
|
<div class="fields" class:selected={linkedRecords.has(record._id)}>
|
||||||
|
{#each Object.keys(model.schema).filter(key => !FIELDS_TO_HIDE.includes(key)) as key}
|
||||||
|
<div class="field">
|
||||||
|
<span>{model.schema[key].name}</span>
|
||||||
|
<p>{record[key]}</p>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.fields.selected {
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields {
|
||||||
|
padding: 15px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
grid-gap: 20px;
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--grey);
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: 0.5s all;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field span {
|
||||||
|
color: var(--ink-lighter);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field p {
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-word;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script>
|
||||||
|
import { notificationStore } from "builderStore/store/notifications"
|
||||||
|
import { onMount, onDestroy } from "svelte"
|
||||||
|
import { fade } from "svelte/transition"
|
||||||
|
|
||||||
|
export let themes = {
|
||||||
|
danger: "#E26D69",
|
||||||
|
success: "#84C991",
|
||||||
|
warning: "#f0ad4e",
|
||||||
|
info: "#5bc0de",
|
||||||
|
default: "#aaaaaa",
|
||||||
|
}
|
||||||
|
|
||||||
|
export let timeout = 3000
|
||||||
|
|
||||||
|
$: if ($notificationStore.notifications.length) {
|
||||||
|
setTimeout(() => {
|
||||||
|
notificationStore.update(state => {
|
||||||
|
state.notifications.shift()
|
||||||
|
state.notifications = state.notifications
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}, timeout)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class="notifications">
|
||||||
|
{#each $notificationStore.notifications as notification (notification.id)}
|
||||||
|
<li
|
||||||
|
class="toast"
|
||||||
|
style="background: {themes[notification.type]};"
|
||||||
|
transition:fade>
|
||||||
|
<div class="content">{notification.message}</div>
|
||||||
|
{#if notification.icon}
|
||||||
|
<i class={notification.icon} />
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.notifications {
|
||||||
|
width: 40vw;
|
||||||
|
list-style: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
padding: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toast {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 10px;
|
||||||
|
display: block;
|
||||||
|
color: var(--white);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -13,13 +13,25 @@
|
||||||
let numberText = value === null || value === undefined ? "" : value.toString()
|
let numberText = value === null || value === undefined ? "" : value.toString()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="uk-margin">
|
<div class="numberbox">
|
||||||
<label class="uk-form-label">{label}</label>
|
<label>{label}</label>
|
||||||
<div class="uk-form-controls">
|
<input
|
||||||
<input
|
class="budibase__input"
|
||||||
class="budibase__input"
|
type="number"
|
||||||
type="number"
|
{value}
|
||||||
{value}
|
on:change={inputChanged} />
|
||||||
on:change={inputChanged} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.numberbox {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
textarea {
|
textarea {
|
||||||
width: 300px;
|
width: 100%;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { fade } from "svelte/transition"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
export let ids = []
|
||||||
|
export let field
|
||||||
|
|
||||||
|
let records = []
|
||||||
|
let open = false
|
||||||
|
let model
|
||||||
|
|
||||||
|
$: FIELDS_TO_HIDE = [$backendUiStore.selectedModel._id, field.modelId]
|
||||||
|
|
||||||
|
async function fetchRecords() {
|
||||||
|
const response = await api.post("/api/records/search", {
|
||||||
|
keys: ids,
|
||||||
|
})
|
||||||
|
const modelResponse = await api.get(`/api/models/${field.modelId}`)
|
||||||
|
records = await response.json()
|
||||||
|
model = await modelResponse.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
$: ids && fetchRecords()
|
||||||
|
|
||||||
|
function toggleOpen() {
|
||||||
|
open = !open
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
fetchRecords()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<a on:click={toggleOpen}>{records.length}</a>
|
||||||
|
{#if open}
|
||||||
|
<div class="popover" transition:fade>
|
||||||
|
<header>
|
||||||
|
<h3>{field.name}</h3>
|
||||||
|
<i class="ri-close-circle-fill" on:click={toggleOpen} />
|
||||||
|
</header>
|
||||||
|
{#each records as record}
|
||||||
|
<div class="linked-record">
|
||||||
|
<div class="fields">
|
||||||
|
{#each Object.keys(model.schema).filter(key => !FIELDS_TO_HIDE.includes(key)) as key}
|
||||||
|
<div class="field">
|
||||||
|
<span>{model.schema[key].name}</span>
|
||||||
|
<p>{record[key]}</p>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
display: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 24px;
|
||||||
|
color: var(--ink-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
i:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover {
|
||||||
|
width: 500px;
|
||||||
|
position: absolute;
|
||||||
|
right: 15%;
|
||||||
|
padding: 20px;
|
||||||
|
background: var(--light-grey);
|
||||||
|
border: 1px solid var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields {
|
||||||
|
padding: 15px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
grid-gap: 20px;
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--grey);
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field span {
|
||||||
|
color: var(--ink-lighter);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field p {
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-word;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,20 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount, getContext } from "svelte"
|
import { onMount, getContext } from "svelte"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import {
|
import { Button } from "@budibase/bbui"
|
||||||
tap,
|
|
||||||
get,
|
|
||||||
find,
|
|
||||||
last,
|
|
||||||
compose,
|
|
||||||
flatten,
|
|
||||||
map,
|
|
||||||
remove,
|
|
||||||
keys,
|
|
||||||
takeRight,
|
|
||||||
} from "lodash/fp"
|
|
||||||
import Select from "components/common/Select.svelte"
|
import Select from "components/common/Select.svelte"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
import LinkedRecord from "./LinkedRecord.svelte"
|
||||||
import TablePagination from "./TablePagination.svelte"
|
import TablePagination from "./TablePagination.svelte"
|
||||||
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
|
||||||
import * as api from "./api"
|
import * as api from "./api"
|
||||||
|
@ -52,23 +42,39 @@
|
||||||
let headers = []
|
let headers = []
|
||||||
let views = []
|
let views = []
|
||||||
let currentPage = 0
|
let currentPage = 0
|
||||||
|
let search
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($backendUiStore.selectedView) {
|
if ($backendUiStore.selectedView) {
|
||||||
api.fetchDataForView($backendUiStore.selectedView).then(records => {
|
api.fetchDataForView($backendUiStore.selectedView).then(records => {
|
||||||
data = records || []
|
data = records || []
|
||||||
headers = Object.keys($backendUiStore.selectedModel.schema).filter(
|
|
||||||
key => !INTERNAL_HEADERS.includes(key)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: paginatedData = data.slice(
|
$: paginatedData = data
|
||||||
currentPage * ITEMS_PER_PAGE,
|
? data.slice(
|
||||||
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
currentPage * ITEMS_PER_PAGE,
|
||||||
|
currentPage * ITEMS_PER_PAGE + ITEMS_PER_PAGE
|
||||||
|
)
|
||||||
|
: []
|
||||||
|
|
||||||
|
$: headers = Object.keys($backendUiStore.selectedModel.schema).filter(
|
||||||
|
id => !INTERNAL_HEADERS.includes(id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
$: schema = $backendUiStore.selectedModel.schema
|
||||||
|
|
||||||
|
const createNewRecord = () => {
|
||||||
|
open(
|
||||||
|
CreateEditRecordModal,
|
||||||
|
{
|
||||||
|
onClosed: close,
|
||||||
|
},
|
||||||
|
{ styleContent: { padding: "0" } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (views.length) {
|
if (views.length) {
|
||||||
backendUiStore.actions.views.select(views[0])
|
backendUiStore.actions.views.select(views[0])
|
||||||
|
@ -79,13 +85,19 @@
|
||||||
<section>
|
<section>
|
||||||
<div class="table-controls">
|
<div class="table-controls">
|
||||||
<h2 class="title">{$backendUiStore.selectedModel.name}</h2>
|
<h2 class="title">{$backendUiStore.selectedModel.name}</h2>
|
||||||
|
<Button primary on:click={createNewRecord}>
|
||||||
|
<span class="button-inner">
|
||||||
|
<i class="ri-add-circle-fill" />
|
||||||
|
Create New Record
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<table class="uk-table">
|
<table class="uk-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Edit</th>
|
<th>Edit</th>
|
||||||
{#each headers as header}
|
{#each headers as header}
|
||||||
<th>{header}</th>
|
<th>{$backendUiStore.selectedModel.schema[header].name}</th>
|
||||||
{/each}
|
{/each}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -119,7 +131,11 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{#each headers as header}
|
{#each headers as header}
|
||||||
<td>{row[header]}</td>
|
<td>
|
||||||
|
{#if schema[header].type === 'link'}
|
||||||
|
<LinkedRecord field={schema[header]} ids={row[header]} />
|
||||||
|
{:else}{row[header]}{/if}
|
||||||
|
</td>
|
||||||
{/each}
|
{/each}
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -186,4 +202,14 @@
|
||||||
.no-data {
|
.no-data {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-inner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-inner i {
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -15,7 +15,7 @@ export async function createDatabase(appname, instanceName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteRecord(record) {
|
export async function deleteRecord(record) {
|
||||||
const DELETE_RECORDS_URL = `/api/${record._modelId}/records/${record._id}/${record._rev}`
|
const DELETE_RECORDS_URL = `/api/${record.modelId}/records/${record._id}/${record._rev}`
|
||||||
const response = await api.delete(DELETE_RECORDS_URL)
|
const response = await api.delete(DELETE_RECORDS_URL)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
<script>
|
|
||||||
import Dropdown from "components/common/Dropdown.svelte"
|
|
||||||
import Textbox from "components/common/Textbox.svelte"
|
|
||||||
import Button from "components/common/Button.svelte"
|
|
||||||
import ButtonGroup from "components/common/ButtonGroup.svelte"
|
|
||||||
import NumberBox from "components/common/NumberBox.svelte"
|
|
||||||
import ValuesList from "components/common/ValuesList.svelte"
|
|
||||||
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
|
||||||
import Checkbox from "components/common/Checkbox.svelte"
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
|
||||||
import DatePicker from "components/common/DatePicker.svelte"
|
|
||||||
import { keys, cloneDeep } from "lodash/fp"
|
|
||||||
|
|
||||||
const FIELD_TYPES = ["string", "number", "boolean"]
|
|
||||||
|
|
||||||
export let field = {
|
|
||||||
type: "string",
|
|
||||||
constraints: { type: "string", presence: false },
|
|
||||||
}
|
|
||||||
export let schema
|
|
||||||
export let goBack
|
|
||||||
|
|
||||||
let errors = []
|
|
||||||
let draftField = cloneDeep(field)
|
|
||||||
|
|
||||||
let type = field.type
|
|
||||||
let constraints = field.constraints
|
|
||||||
let required =
|
|
||||||
field.constraints.presence && !field.constraints.presence.allowEmpty
|
|
||||||
|
|
||||||
const save = () => {
|
|
||||||
constraints.presence = required ? { allowEmpty: false } : false
|
|
||||||
draftField.constraints = constraints
|
|
||||||
draftField.type = type
|
|
||||||
schema[field.name] = draftField
|
|
||||||
goBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
$: constraints =
|
|
||||||
type === "string"
|
|
||||||
? { type: "string", length: {}, presence: false }
|
|
||||||
: type === "number"
|
|
||||||
? { type: "number", presence: false, numericality: {} }
|
|
||||||
: type === "boolean"
|
|
||||||
? { type: "boolean", presence: false }
|
|
||||||
: type === "datetime"
|
|
||||||
? { type: "date", datetime: {}, presence: false }
|
|
||||||
: type.startsWith("array")
|
|
||||||
? { type: "array", presence: false }
|
|
||||||
: { type: "string", presence: false }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="root">
|
|
||||||
|
|
||||||
<ErrorsBox {errors} />
|
|
||||||
|
|
||||||
<form on:submit|preventDefault class="uk-form-stacked">
|
|
||||||
<Textbox label="Name" bind:text={field.name} />
|
|
||||||
<Dropdown label="Type" bind:selected={type} options={FIELD_TYPES} />
|
|
||||||
|
|
||||||
<Checkbox label="Required" bind:checked={required} />
|
|
||||||
|
|
||||||
{#if type === 'string'}
|
|
||||||
<NumberBox label="Max Length" bind:value={constraints.length.maximum} />
|
|
||||||
<ValuesList label="Categories" bind:values={constraints.inclusion} />
|
|
||||||
{:else if type === 'datetime'}
|
|
||||||
<DatePicker
|
|
||||||
label="Min Value"
|
|
||||||
bind:value={constraints.datetime.earliest} />
|
|
||||||
<DatePicker label="Max Value" bind:value={constraints.datetime.latest} />
|
|
||||||
{:else if type === 'number'}
|
|
||||||
<NumberBox
|
|
||||||
label="Min Value"
|
|
||||||
bind:value={constraints.numericality.greaterThanOrEqualTo} />
|
|
||||||
<NumberBox
|
|
||||||
label="Max Value"
|
|
||||||
bind:value={constraints.numericality.lessThanOrEqualTo} />
|
|
||||||
{/if}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<footer>
|
|
||||||
<div class="button">
|
|
||||||
<ActionButton secondary on:click={goBack}>Cancel</ActionButton>
|
|
||||||
</div>
|
|
||||||
<ActionButton primary on:click={save}>Save</ActionButton>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
margin: 40px;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
padding: 20px 40px;
|
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background: var(--grey-1);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,8 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import { compose, map, get, flatten } from "lodash/fp"
|
import { compose, map, get, flatten } from "lodash/fp"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import { Button } from "@budibase/bbui"
|
||||||
|
import LinkedRecordSelector from "components/common/LinkedRecordSelector.svelte"
|
||||||
import Select from "components/common/Select.svelte"
|
import Select from "components/common/Select.svelte"
|
||||||
import RecordFieldControl from "./RecordFieldControl.svelte"
|
import RecordFieldControl from "./RecordFieldControl.svelte"
|
||||||
import * as api from "../api"
|
import * as api from "../api"
|
||||||
|
@ -59,35 +61,75 @@
|
||||||
backendUiStore.update(state => {
|
backendUiStore.update(state => {
|
||||||
state.selectedView = state.selectedView
|
state.selectedView = state.selectedView
|
||||||
onClosed()
|
onClosed()
|
||||||
|
notifier.success("Record created successfully.")
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<h4 class="budibase__title--4">Create / Edit Record</h4>
|
<header>
|
||||||
|
<i class="ri-file-user-fill" />
|
||||||
|
<h4 class="budibase__title--4">Create / Edit Record</h4>
|
||||||
|
</header>
|
||||||
<ErrorsBox {errors} />
|
<ErrorsBox {errors} />
|
||||||
<form on:submit|preventDefault class="uk-form-stacked">
|
<form on:submit|preventDefault class="uk-form-stacked">
|
||||||
{#each modelSchema as [key, meta]}
|
{#each modelSchema as [key, meta]}
|
||||||
<div class="uk-margin">
|
<div class="uk-margin">
|
||||||
<RecordFieldControl
|
{#if meta.type === 'link'}
|
||||||
type={determineInputType(meta)}
|
<LinkedRecordSelector
|
||||||
options={determineOptions(meta)}
|
bind:linked={record[key]}
|
||||||
label={key}
|
linkName={meta.name}
|
||||||
bind:value={record[key]} />
|
modelId={meta.modelId} />
|
||||||
|
{:else}
|
||||||
|
<RecordFieldControl
|
||||||
|
type={determineInputType(meta)}
|
||||||
|
options={determineOptions(meta)}
|
||||||
|
label={meta.name}
|
||||||
|
bind:value={record[key]} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
<Button secondary on:click={onClosed}>Cancel</Button>
|
||||||
<ActionButton on:click={saveRecord}>Save</ActionButton>
|
<Button attention on:click={saveRecord}>Save</Button>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
header {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 20px;
|
||||||
|
grid-template-columns: 40px 1fr;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--blue-light);
|
||||||
|
color: var(--ink);
|
||||||
|
font-size: 20px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--ink);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: var(--grey-1);
|
background: var(--grey-1);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import * as api from "../api"
|
import * as api from "../api"
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
alert
|
alert
|
||||||
on:click={async () => {
|
on:click={async () => {
|
||||||
await api.deleteRecord(record)
|
await api.deleteRecord(record)
|
||||||
|
notifier.danger('Record deleted')
|
||||||
backendUiStore.actions.records.delete(record)
|
backendUiStore.actions.records.delete(record)
|
||||||
onClosed()
|
onClosed()
|
||||||
}}>
|
}}>
|
||||||
|
|
|
@ -51,3 +51,16 @@
|
||||||
on:input={handleInput}
|
on:input={handleInput}
|
||||||
on:change={handleInput} />
|
on:change={handleInput} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
color: var(--dark-grey);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
export { default as DeleteRecordModal } from "./DeleteRecord.svelte"
|
export { default as DeleteRecordModal } from "./DeleteRecord.svelte"
|
||||||
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"
|
export { default as CreateEditRecordModal } from "./CreateEditRecord.svelte"
|
||||||
export { default as CreateEditModelModal } from "./CreateEditModel/CreateEditModel.svelte"
|
|
||||||
export { default as CreateEditViewModal } from "./CreateEditView.svelte"
|
export { default as CreateEditViewModal } from "./CreateEditView.svelte"
|
||||||
export { default as CreateDatabaseModal } from "./CreateDatabase.svelte"
|
export { default as CreateDatabaseModal } from "./CreateDatabase.svelte"
|
||||||
export { default as CreateUserModal } from "./CreateUser.svelte"
|
export { default as CreateUserModal } from "./CreateUser.svelte"
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
<script>
|
|
||||||
import { getContext } from "svelte"
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
|
||||||
import HierarchyRow from "./HierarchyRow.svelte"
|
|
||||||
import DatabasesList from "./DatabasesList.svelte"
|
|
||||||
import UsersList from "./UsersList.svelte"
|
|
||||||
import NavItem from "./NavItem.svelte"
|
|
||||||
import getIcon from "components/common/icon"
|
|
||||||
import {
|
|
||||||
CreateDatabaseModal,
|
|
||||||
CreateUserModal,
|
|
||||||
} from "components/database/ModelDataTable/modals"
|
|
||||||
const { open, close } = getContext("simple-modal")
|
|
||||||
|
|
||||||
const openDatabaseCreator = () => {
|
|
||||||
open(
|
|
||||||
CreateDatabaseModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const openUserCreator = () => {
|
|
||||||
open(
|
|
||||||
CreateUserModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="items-root">
|
|
||||||
<div class="hierarchy" />
|
|
||||||
{#if $backendUiStore.selectedDatabase._id}
|
|
||||||
<div class="hierarchy">
|
|
||||||
<div class="components-list-container">
|
|
||||||
<div class="nav-group-header">
|
|
||||||
<div class="hierarchy-title">Users</div>
|
|
||||||
<i class="ri-add-line hoverable" on:click={openUserCreator} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hierarchy-items-container">
|
|
||||||
<UsersList />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.items-root {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-height: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: var(--white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20px 20px 10px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hierarchy-title {
|
|
||||||
align-items: center;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hierarchy {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hierarchy-items-container {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -3,10 +3,8 @@
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import getIcon from "../common/icon"
|
import getIcon from "../common/icon"
|
||||||
import {
|
import { CreateEditViewModal } from "components/database/ModelDataTable/modals"
|
||||||
CreateEditModelModal,
|
import api from "builderStore/api"
|
||||||
CreateEditViewModal,
|
|
||||||
} from "components/database/ModelDataTable/modals"
|
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
@ -30,14 +28,6 @@
|
||||||
class:selected={$backendUiStore.selectedView === `all_${node._id}`}>
|
class:selected={$backendUiStore.selectedView === `all_${node._id}`}>
|
||||||
<i class={ICON_MAP[type]} />
|
<i class={ICON_MAP[type]} />
|
||||||
<span style="margin-left: 1rem">{node.name}</span>
|
<span style="margin-left: 1rem">{node.name}</span>
|
||||||
<!-- <i
|
|
||||||
class="ri-edit-line hoverable"
|
|
||||||
on:click={editModel}
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
class="ri-delete-bin-7-line hoverable"
|
|
||||||
on:click={deleteModel}
|
|
||||||
/> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
<script>
|
||||||
|
import * as blockDefinitions from "constants/backend"
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import Block from "components/common/Block.svelte"
|
||||||
|
|
||||||
|
const HEADINGS = [
|
||||||
|
{
|
||||||
|
title: "Fields",
|
||||||
|
key: "FIELDS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Blocks",
|
||||||
|
key: "BLOCKS",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let selectedTab = "FIELDS"
|
||||||
|
|
||||||
|
function addField(blockDefinition) {
|
||||||
|
backendUiStore.actions.models.addField(blockDefinition)
|
||||||
|
backendUiStore.actions.models.fetch()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
{#each HEADINGS as tab}
|
||||||
|
<span
|
||||||
|
class:selected={selectedTab === tab.key}
|
||||||
|
on:click={() => (selectedTab = tab.key)}>
|
||||||
|
{tab.title}
|
||||||
|
</span>
|
||||||
|
{/each}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="block-grid">
|
||||||
|
{#each Object.values(blockDefinitions[selectedTab]) as blockDefinition}
|
||||||
|
<Block
|
||||||
|
on:click={() => addField(blockDefinition)}
|
||||||
|
title={blockDefinition.name}
|
||||||
|
icon={blockDefinition.icon} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 20px;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: var(--ink-lighter);
|
||||||
|
font-size: 14px;
|
||||||
|
background: var(--light-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
span:hover {
|
||||||
|
background: var(--blue-light);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background: var(--blue-light);
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-grid {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,112 @@
|
||||||
|
<script>
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import { uuid } from "builderStore/uuid"
|
||||||
|
import { fade } from "svelte/transition"
|
||||||
|
import { FIELDS, BLOCKS, MODELS } from "constants/backend"
|
||||||
|
import Block from "components/common/Block.svelte"
|
||||||
|
|
||||||
|
function addNewField(field) {
|
||||||
|
backendUiStore.actions.models.addField(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createModel(model) {
|
||||||
|
const { schema, ...rest } = $backendUiStore.selectedModel
|
||||||
|
|
||||||
|
const newModel = { ...model, schema: {} }
|
||||||
|
|
||||||
|
// TODO: could be better
|
||||||
|
for (let key in model.schema) {
|
||||||
|
newModel.schema[uuid()] = model.schema[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
backendUiStore.actions.models.save({
|
||||||
|
model: {
|
||||||
|
...newModel,
|
||||||
|
...rest,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section transition:fade>
|
||||||
|
<header>
|
||||||
|
<h2>Create New Model</h2>
|
||||||
|
<p>Before you can view your model, you need to set it up.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="block-row">
|
||||||
|
<span class="block-row-title">Fields</span>
|
||||||
|
<p>Blocks are pre-made fields and help you build your model quicker.</p>
|
||||||
|
<div class="blocks">
|
||||||
|
{#each Object.values(FIELDS) as field}
|
||||||
|
<Block
|
||||||
|
primary
|
||||||
|
title={field.name}
|
||||||
|
icon={field.icon}
|
||||||
|
on:click={() => addNewField(field)} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="block-row">
|
||||||
|
<span class="block-row-title">Blocks</span>
|
||||||
|
<p>Blocks are pre-made fields and help you build your model quicker.</p>
|
||||||
|
<div class="blocks">
|
||||||
|
{#each Object.values(BLOCKS) as field}
|
||||||
|
<Block
|
||||||
|
secondary
|
||||||
|
title={field.name}
|
||||||
|
icon={field.icon}
|
||||||
|
on:click={() => addNewField(field)} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="block-row">
|
||||||
|
<span class="block-row-title">Models</span>
|
||||||
|
<p>Blocks are pre-made fields and help you build your model quicker.</p>
|
||||||
|
<div class="blocks">
|
||||||
|
{#each Object.values(MODELS) as model}
|
||||||
|
<Block
|
||||||
|
tertiary
|
||||||
|
title={model.name}
|
||||||
|
icon={model.icon}
|
||||||
|
on:click={() => createModel(model)} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-row-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-row {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-row .blocks {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
grid-auto-columns: 110px;
|
||||||
|
grid-gap: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<script>
|
||||||
|
export let icon
|
||||||
|
export let className
|
||||||
|
export let title
|
||||||
|
export let selected
|
||||||
|
export let indented
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class:selected on:click class={className}>
|
||||||
|
<i class:indented class={icon} />
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.indented {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
padding: 0 10px 0 10px;
|
||||||
|
width: 90%;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
transition: 0.3s background-color;
|
||||||
|
color: var(--ink);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: var(--blue-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
div:hover {
|
||||||
|
background-color: var(--blue-light);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: var(--dark-grey);
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,107 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { slide } from "svelte/transition"
|
||||||
|
import { Switcher } from "@budibase/bbui"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import BlockNavigator from "./BlockNavigator.svelte"
|
||||||
|
import ListItem from "./ListItem.svelte"
|
||||||
|
import { Button } from "@budibase/bbui"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
let HEADINGS = [
|
||||||
|
{
|
||||||
|
title: "Navigate",
|
||||||
|
key: "NAVIGATE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Add",
|
||||||
|
key: "ADD",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
$: selectedTab = $backendUiStore.tabs.NAVIGATION_PANEL
|
||||||
|
|
||||||
|
function selectModel(model, fieldId) {
|
||||||
|
backendUiStore.actions.models.select(model)
|
||||||
|
|
||||||
|
if (fieldId) {
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.selectedField = fieldId
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupForNewModel() {
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.selectedModel = {}
|
||||||
|
state.draftModel = { schema: {} }
|
||||||
|
state.tabs.SETUP_PANEL = "SETUP"
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="items-root">
|
||||||
|
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
|
||||||
|
<div class="hierarchy">
|
||||||
|
<div class="components-list-container">
|
||||||
|
<Switcher
|
||||||
|
headings={HEADINGS}
|
||||||
|
bind:value={$backendUiStore.tabs.NAVIGATION_PANEL}>
|
||||||
|
{#if selectedTab === 'NAVIGATE'}
|
||||||
|
<Button secondary wide on:click={setupForNewModel}>
|
||||||
|
Create New Model
|
||||||
|
</Button>
|
||||||
|
<div class="hierarchy-items-container">
|
||||||
|
{#each $backendUiStore.models as model}
|
||||||
|
<ListItem
|
||||||
|
selected={!$backendUiStore.selectedField && model._id === $backendUiStore.selectedModel._id}
|
||||||
|
title={model.name}
|
||||||
|
icon="ri-table-fill"
|
||||||
|
on:click={() => selectModel(model)} />
|
||||||
|
{#if model._id === $backendUiStore.selectedModel._id}
|
||||||
|
<div in:slide>
|
||||||
|
{#each Object.keys(model.schema) as fieldId}
|
||||||
|
<ListItem
|
||||||
|
selected={model._id === $backendUiStore.selectedModel._id && fieldId === $backendUiStore.selectedField}
|
||||||
|
indented
|
||||||
|
icon="ri-layout-column-fill"
|
||||||
|
title={model.schema[fieldId].name}
|
||||||
|
on:click={() => selectModel(model, fieldId)} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{:else if selectedTab === 'ADD'}
|
||||||
|
<BlockNavigator />
|
||||||
|
{/if}
|
||||||
|
</Switcher>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.items-root {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--white);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hierarchy {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hierarchy-items-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,124 @@
|
||||||
|
<script>
|
||||||
|
import { backendUiStore } from "builderStore"
|
||||||
|
import { Button } from "@budibase/bbui"
|
||||||
|
import Dropdown from "components/common/Dropdown.svelte"
|
||||||
|
import Textbox from "components/common/Textbox.svelte"
|
||||||
|
import ButtonGroup from "components/common/ButtonGroup.svelte"
|
||||||
|
import NumberBox from "components/common/NumberBox.svelte"
|
||||||
|
import ValuesList from "components/common/ValuesList.svelte"
|
||||||
|
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
||||||
|
import Checkbox from "components/common/Checkbox.svelte"
|
||||||
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
import DatePicker from "components/common/DatePicker.svelte"
|
||||||
|
import { keys, cloneDeep } from "lodash/fp"
|
||||||
|
|
||||||
|
const FIELD_TYPES = ["string", "number", "boolean", "link"]
|
||||||
|
|
||||||
|
let field = {}
|
||||||
|
|
||||||
|
$: field =
|
||||||
|
$backendUiStore.draftModel.schema[$backendUiStore.selectedField] || {}
|
||||||
|
$: required =
|
||||||
|
field.constraints &&
|
||||||
|
field.constraints.presence &&
|
||||||
|
!constraints.presence.allowEmpty
|
||||||
|
|
||||||
|
function attachModelIdToSchema(evt) {
|
||||||
|
const { draftModel } = $backendUiStore
|
||||||
|
if ($backendUiStore.selectedField !== evt.target.value) {
|
||||||
|
delete draftModel.schema[$backendUiStore.selectedField]
|
||||||
|
draftModel.schema[evt.target.value] = field
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.selectedField = evt.target.value
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<div class="field-box">
|
||||||
|
<header>Name</header>
|
||||||
|
<input class="budibase__input" type="text" bind:value={field.name} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<div class="field-box">
|
||||||
|
<header>Type</header>
|
||||||
|
<span>{field.type}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<div class="field">
|
||||||
|
<label>Required</label>
|
||||||
|
<input type="checkbox" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if field.type === 'string'}
|
||||||
|
<NumberBox
|
||||||
|
label="Max Length"
|
||||||
|
bind:value={field.constraints.length.maximum} />
|
||||||
|
<ValuesList label="Categories" bind:values={field.constraints.inclusion} />
|
||||||
|
{:else if field.type === 'datetime'}
|
||||||
|
<DatePicker
|
||||||
|
label="Min Value"
|
||||||
|
bind:value={field.constraints.datetime.earliest} />
|
||||||
|
<DatePicker
|
||||||
|
label="Max Value"
|
||||||
|
bind:value={field.constraints.datetime.latest} />
|
||||||
|
{:else if field.type === 'number'}
|
||||||
|
<NumberBox
|
||||||
|
label="Min Value"
|
||||||
|
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
|
||||||
|
<NumberBox
|
||||||
|
label="Max Value"
|
||||||
|
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
|
||||||
|
{:else if field.type === 'link'}
|
||||||
|
<div class="field">
|
||||||
|
<label>Link</label>
|
||||||
|
<select
|
||||||
|
class="budibase__input"
|
||||||
|
bind:value={field.modelId}
|
||||||
|
on:change={attachModelIdToSchema}>
|
||||||
|
<option value={''} />
|
||||||
|
{#each $backendUiStore.models as model}
|
||||||
|
{#if model._id !== $backendUiStore.draftModel._id}
|
||||||
|
<option value={model._id}>{model.name}</option>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.info {
|
||||||
|
background: var(--light-grey);
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-box header {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-box span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,128 @@
|
||||||
|
<script>
|
||||||
|
import { getContext, onMount } from "svelte"
|
||||||
|
import { Button, Switcher } from "@budibase/bbui"
|
||||||
|
import { notifier } from "builderStore/store/notifications"
|
||||||
|
import { store, backendUiStore } from "builderStore"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
import ModelFieldEditor from "./ModelFieldEditor.svelte"
|
||||||
|
|
||||||
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
const ITEMS = [
|
||||||
|
{
|
||||||
|
title: "Setup",
|
||||||
|
key: "SETUP",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Delete",
|
||||||
|
key: "DELETE",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let edited = false
|
||||||
|
|
||||||
|
$: selectedTab = $backendUiStore.tabs.SETUP_PANEL
|
||||||
|
|
||||||
|
$: edited =
|
||||||
|
$backendUiStore.selectedField ||
|
||||||
|
($backendUiStore.draftModel &&
|
||||||
|
$backendUiStore.draftModel.name !== $backendUiStore.selectedModel.name)
|
||||||
|
|
||||||
|
async function deleteModel() {
|
||||||
|
const model = $backendUiStore.selectedModel
|
||||||
|
const field = $backendUiStore.selectedField
|
||||||
|
|
||||||
|
if (field) {
|
||||||
|
const name = model.schema[field].name
|
||||||
|
delete model.schema[field]
|
||||||
|
backendUiStore.actions.models.save({ model })
|
||||||
|
notifier.danger(`Field ${name} deleted.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const DELETE_MODEL_URL = `/api/models/${model._id}/${model._rev}`
|
||||||
|
const response = await api.delete(DELETE_MODEL_URL)
|
||||||
|
backendUiStore.update(state => {
|
||||||
|
state.selectedView = null
|
||||||
|
state.selectedModel = {}
|
||||||
|
state.draftModel = {}
|
||||||
|
state.models = state.models.filter(({ _id }) => _id !== model._id)
|
||||||
|
notifier.danger(`${model.name} deleted successfully.`)
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveModel() {
|
||||||
|
await backendUiStore.actions.models.save({
|
||||||
|
model: $backendUiStore.draftModel,
|
||||||
|
})
|
||||||
|
notifier.success(
|
||||||
|
"Success! Your changes have been saved. Please continue on with your greatness."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="items-root">
|
||||||
|
<Switcher headings={ITEMS} bind:value={$backendUiStore.tabs.SETUP_PANEL}>
|
||||||
|
{#if selectedTab === 'SETUP'}
|
||||||
|
{#if $backendUiStore.selectedField}
|
||||||
|
<ModelFieldEditor />
|
||||||
|
{:else if $backendUiStore.draftModel.schema}
|
||||||
|
<div class="titled-input">
|
||||||
|
<header>Name</header>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="budibase__input"
|
||||||
|
bind:value={$backendUiStore.draftModel.name} />
|
||||||
|
</div>
|
||||||
|
<div class="titled-input">
|
||||||
|
<header>Import Data</header>
|
||||||
|
<Button wide secondary>Import CSV</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<footer>
|
||||||
|
<Button disabled={!edited} attention={edited} wide on:click={saveModel}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</footer>
|
||||||
|
{:else if selectedTab === 'DELETE'}
|
||||||
|
<div class="titled-input">
|
||||||
|
<header>Danger Zone</header>
|
||||||
|
<Button error wide on:click={deleteModel}>Delete</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Switcher>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-root {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.titled-input {
|
||||||
|
padding: 12px;
|
||||||
|
background: var(--light-grey);
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titled-input header {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as ModelSetupNav } from "./ModelSetupNav.svelte"
|
|
@ -1,143 +0,0 @@
|
||||||
<script>
|
|
||||||
import { getContext, onMount } from "svelte"
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
|
||||||
import HierarchyRow from "./HierarchyRow.svelte"
|
|
||||||
import NavItem from "./NavItem.svelte"
|
|
||||||
import getIcon from "components/common/icon"
|
|
||||||
import api from "builderStore/api"
|
|
||||||
import {
|
|
||||||
CreateEditModelModal,
|
|
||||||
CreateEditViewModal,
|
|
||||||
} from "components/database/ModelDataTable/modals"
|
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
|
||||||
|
|
||||||
function editModel() {
|
|
||||||
open(
|
|
||||||
CreateEditModelModal,
|
|
||||||
{
|
|
||||||
model: node,
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function newModel() {
|
|
||||||
open(
|
|
||||||
CreateEditModelModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function newView() {
|
|
||||||
open(
|
|
||||||
CreateEditViewModal,
|
|
||||||
{
|
|
||||||
onClosed: close,
|
|
||||||
},
|
|
||||||
{ styleContent: { padding: "0" } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectModel(model) {
|
|
||||||
backendUiStore.update(state => {
|
|
||||||
state.selectedModel = model
|
|
||||||
state.selectedView = `all_${model._id}`
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function deleteModel(modelToDelete) {
|
|
||||||
const DELETE_MODEL_URL = `/api/models/${node._id}/${node._rev}`
|
|
||||||
const response = await api.delete(DELETE_MODEL_URL)
|
|
||||||
backendUiStore.update(state => {
|
|
||||||
state.models = state.models.filter(
|
|
||||||
model => model._id !== modelToDelete._id
|
|
||||||
)
|
|
||||||
state.selectedView = {}
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectView(view) {
|
|
||||||
backendUiStore.update(state => {
|
|
||||||
state.selectedView = view.name
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="items-root">
|
|
||||||
<div class="hierarchy">
|
|
||||||
<div class="components-list-container">
|
|
||||||
<div class="nav-group-header">
|
|
||||||
<div class="hierarchy-title">Models</div>
|
|
||||||
<div class="uk-inline">
|
|
||||||
<i class="ri-add-line hoverable" on:click={newModel} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hierarchy-items-container">
|
|
||||||
{#each $backendUiStore.models as model}
|
|
||||||
<HierarchyRow onSelect={selectModel} node={model} type="model" />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hierarchy">
|
|
||||||
<div class="components-list-container">
|
|
||||||
<div class="nav-group-header">
|
|
||||||
<div class="hierarchy-title">Views</div>
|
|
||||||
<div class="uk-inline">
|
|
||||||
<i class="ri-add-line hoverable" on:click={newView} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hierarchy-items-container">
|
|
||||||
{#each $backendUiStore.views as view}
|
|
||||||
<HierarchyRow onSelect={selectView} node={view} type="view" />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.items-root {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-height: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: var(--white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20px 20px 10px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hierarchy-title {
|
|
||||||
align-items: center;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hierarchy {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hierarchy-items-container {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -9,13 +9,8 @@
|
||||||
export let margin = ""
|
export let margin = ""
|
||||||
|
|
||||||
$: style = buildStyle({ backgroundSize, borderRadius, height, width, margin })
|
$: style = buildStyle({ backgroundSize, borderRadius, height, width, margin })
|
||||||
|
|
||||||
$: style = buildStyle({ backgroundSize, borderRadius, height, width })
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div {style}>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
<div in:fade {style}>
|
<div in:fade {style}>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, backendUiStore, workflowStore } from "builderStore"
|
import { store, backendUiStore, workflowStore } from "builderStore"
|
||||||
import { notifier } from "@beyonk/svelte-notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
|
||||||
export let onClosed
|
export let onClosed
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
header i {
|
header i {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
background: var(--secondary);
|
background: var(--blue-light);
|
||||||
color: var(--grey-4);
|
color: var(--grey-4);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { fade } from "svelte/transition"
|
import { fade } from "svelte/transition"
|
||||||
import { onMount, getContext } from "svelte"
|
import { onMount, getContext } from "svelte"
|
||||||
import { backendUiStore, workflowStore } from "builderStore"
|
import { backendUiStore, workflowStore } from "builderStore"
|
||||||
import { notifier } from "@beyonk/svelte-notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import WorkflowBlockSetup from "./WorkflowBlockSetup.svelte"
|
import WorkflowBlockSetup from "./WorkflowBlockSetup.svelte"
|
||||||
import DeleteWorkflowModal from "./DeleteWorkflowModal.svelte"
|
import DeleteWorkflowModal from "./DeleteWorkflowModal.svelte"
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { workflowStore, backendUiStore } from "builderStore"
|
import { workflowStore, backendUiStore } from "builderStore"
|
||||||
import { notifier } from "@beyonk/svelte-notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import Flowchart from "./flowchart/FlowChart.svelte"
|
import Flowchart from "./flowchart/FlowChart.svelte"
|
||||||
|
|
||||||
let selectedWorkflow
|
let selectedWorkflow
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.LOGIC {
|
.LOGIC {
|
||||||
background-color: var(--secondary);
|
background-color: var(--blue-light);
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, backendUiStore, workflowStore } from "builderStore"
|
import { store, backendUiStore, workflowStore } from "builderStore"
|
||||||
import { notifier } from "@beyonk/svelte-notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
|
||||||
export let onClosed
|
export let onClosed
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
header i {
|
header i {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
background: var(--secondary);
|
background: var(--blue-light);
|
||||||
color: var(--grey-4);
|
color: var(--grey-4);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import Modal from "svelte-simple-modal"
|
import Modal from "svelte-simple-modal"
|
||||||
import { notifier } from "@beyonk/svelte-notifications"
|
import { notifier } from "builderStore/store/notifications"
|
||||||
import { onMount, getContext } from "svelte"
|
import { onMount, getContext } from "svelte"
|
||||||
import { backendUiStore, workflowStore } from "builderStore"
|
import { backendUiStore, workflowStore } from "builderStore"
|
||||||
import CreateWorkflowModal from "./CreateWorkflowModal.svelte"
|
import CreateWorkflowModal from "./CreateWorkflowModal.svelte"
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
export const FIELDS = {
|
||||||
|
PLAIN_TEXT: {
|
||||||
|
name: "Plain Text",
|
||||||
|
icon: "ri-text",
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NUMBER: {
|
||||||
|
name: "Number",
|
||||||
|
icon: "ri-number-1",
|
||||||
|
type: "number",
|
||||||
|
constraints: {
|
||||||
|
type: "number",
|
||||||
|
presence: false,
|
||||||
|
numericality: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BOOLEAN: {
|
||||||
|
name: "True/False",
|
||||||
|
icon: "ri-toggle-line",
|
||||||
|
type: "boolean",
|
||||||
|
constraints: {
|
||||||
|
type: "boolean",
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// OPTIONS: {
|
||||||
|
// name: "Options",
|
||||||
|
// icon: "ri-list-check-2",
|
||||||
|
// type: "options",
|
||||||
|
// constraints: {
|
||||||
|
// type: "string",
|
||||||
|
// presence: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
DATETIME: {
|
||||||
|
name: "Date/Time",
|
||||||
|
icon: "ri-calendar-event-fill",
|
||||||
|
type: "datetime",
|
||||||
|
constraints: {
|
||||||
|
type: "date",
|
||||||
|
datetime: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// IMAGE: {
|
||||||
|
// name: "File",
|
||||||
|
// icon: "ri-image-line",
|
||||||
|
// type: "file",
|
||||||
|
// constraints: {
|
||||||
|
// type: "string",
|
||||||
|
// presence: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// FILE: {
|
||||||
|
// name: "Image",
|
||||||
|
// icon: "ri-file-line",
|
||||||
|
// type: "file",
|
||||||
|
// constraints: {
|
||||||
|
// type: "string",
|
||||||
|
// presence: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
DATA_LINK: {
|
||||||
|
name: "Data Links",
|
||||||
|
icon: "ri-link",
|
||||||
|
type: "link",
|
||||||
|
modelId: null,
|
||||||
|
constraints: {
|
||||||
|
type: "array",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BLOCKS = {
|
||||||
|
NAME: {
|
||||||
|
name: "Name",
|
||||||
|
icon: "ri-text",
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
length: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PHONE_NUMBER: {
|
||||||
|
name: "Phone Number",
|
||||||
|
icon: "ri-number-1",
|
||||||
|
type: "number",
|
||||||
|
constraints: {
|
||||||
|
type: "number",
|
||||||
|
presence: false,
|
||||||
|
numericality: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ACTIVE: {
|
||||||
|
name: "Active",
|
||||||
|
icon: "ri-toggle-line",
|
||||||
|
type: "boolean",
|
||||||
|
constraints: {
|
||||||
|
type: "boolean",
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// PRIORITY: {
|
||||||
|
// name: "Options",
|
||||||
|
// icon: "ri-list-check-2",
|
||||||
|
// type: "options",
|
||||||
|
// constraints: {
|
||||||
|
// type: "string",
|
||||||
|
// presence: false,
|
||||||
|
// inclusion: ["low", "medium", "high"],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
END_DATE: {
|
||||||
|
name: "End Date",
|
||||||
|
icon: "ri-calendar-event-fill",
|
||||||
|
type: "datetime",
|
||||||
|
constraints: {
|
||||||
|
type: "date",
|
||||||
|
datetime: {},
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// AVATAR: {
|
||||||
|
// name: "Avatar",
|
||||||
|
// icon: "ri-image-line",
|
||||||
|
// type: "image",
|
||||||
|
// constraints: {
|
||||||
|
// type: "string",
|
||||||
|
// presence: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// PDF: {
|
||||||
|
// name: "PDF",
|
||||||
|
// icon: "ri-file-line",
|
||||||
|
// type: "file",
|
||||||
|
// constraints: {
|
||||||
|
// type: "string",
|
||||||
|
// presence: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MODELS = {
|
||||||
|
CONTACTS: {
|
||||||
|
icon: "ri-contacts-book-line",
|
||||||
|
name: "Contacts",
|
||||||
|
schema: {
|
||||||
|
Name: BLOCKS.NAME,
|
||||||
|
"Phone Number": BLOCKS.PHONE_NUMBER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RECIPES: {
|
||||||
|
icon: "ri-link",
|
||||||
|
name: "Recipes",
|
||||||
|
schema: {
|
||||||
|
Name: BLOCKS.NAME,
|
||||||
|
Cuisine: {
|
||||||
|
...FIELDS.PLAIN_TEXT,
|
||||||
|
name: "Cuisine",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SPORTS_TEAM: {
|
||||||
|
icon: "ri-basketball-line",
|
||||||
|
name: "Sports Team",
|
||||||
|
schema: {
|
||||||
|
Name: BLOCKS.NAME,
|
||||||
|
Championships: {
|
||||||
|
...FIELDS.NUMBER,
|
||||||
|
name: "Championships",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,647 +0,0 @@
|
||||||
body, html {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
overflow: hidden;
|
|
||||||
background-repeat: repeat;
|
|
||||||
background-size: 30px 30px;
|
|
||||||
background-color: var(--grey-1);
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
#navigation {
|
|
||||||
height: 71px;
|
|
||||||
background-color: #FFF;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
width: 100%;
|
|
||||||
display: table;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
z-index: 9
|
|
||||||
}
|
|
||||||
#back {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 100px;
|
|
||||||
background-color: #F1F4FC;
|
|
||||||
text-align: center;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-top: 12px;
|
|
||||||
margin-right: 10px
|
|
||||||
}
|
|
||||||
#back img {
|
|
||||||
margin-top: 13px;
|
|
||||||
}
|
|
||||||
#names {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
#title {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #393C44;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
#subtitle {
|
|
||||||
font-family: Roboto;
|
|
||||||
color: #808292;
|
|
||||||
font-size: 14px;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
#leftside {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
#centerswitch {
|
|
||||||
position: absolute;
|
|
||||||
width: 222px;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -111px;
|
|
||||||
top: 15px;
|
|
||||||
}
|
|
||||||
#leftswitch {
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
background-color: var(--grey-1);
|
|
||||||
width: 111px;
|
|
||||||
height: 39px;
|
|
||||||
line-height: 39px;
|
|
||||||
border-radius: 5px 0px 0px 5px;
|
|
||||||
font-family: Roboto;
|
|
||||||
color: #393C44;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#rightswitch {
|
|
||||||
font-family: Roboto;
|
|
||||||
color: #808292;
|
|
||||||
border-radius: 0px 5px 5px 0px;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
height: 39px;
|
|
||||||
width: 102px;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 39px;
|
|
||||||
text-align: center;
|
|
||||||
margin-left: -5px;
|
|
||||||
}
|
|
||||||
#discard {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #A6A6B3;
|
|
||||||
width: 95px;
|
|
||||||
height: 38px;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 38px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
transition: all .2s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
#discard:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .7;
|
|
||||||
}
|
|
||||||
#publish {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #FFF;
|
|
||||||
background-color: #217CE8;
|
|
||||||
border-radius: 5px;
|
|
||||||
width: 143px;
|
|
||||||
height: 38px;
|
|
||||||
margin-left: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 38px;
|
|
||||||
margin-right: 20px;
|
|
||||||
transition: all .2s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
#publish:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .7;
|
|
||||||
}
|
|
||||||
#buttonsright {
|
|
||||||
float: right;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
#leftcard {
|
|
||||||
width: 363px;
|
|
||||||
background-color: #FFF;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-top: 85px;
|
|
||||||
padding-left: 20px;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
#search input {
|
|
||||||
width: 318px;
|
|
||||||
height: 40px;
|
|
||||||
background-color: #FFF;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
box-sizing: border-box;
|
|
||||||
box-shadow: 0px 2px 8px rgba(34,34,87,0.05);
|
|
||||||
border-radius: 5px;
|
|
||||||
text-indent: 35px;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
::-webkit-input-placeholder { /* Edge */
|
|
||||||
color: #C9C9D5;
|
|
||||||
}
|
|
||||||
|
|
||||||
:-ms-input-placeholder { /* Internet Explorer 10-11 */
|
|
||||||
color: #C9C9D5
|
|
||||||
}
|
|
||||||
|
|
||||||
::placeholder {
|
|
||||||
color: #C9C9D5;
|
|
||||||
}
|
|
||||||
#search img {
|
|
||||||
position: absolute;
|
|
||||||
margin-top: 10px;
|
|
||||||
width: 18px;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
#header {
|
|
||||||
font-size: 20px;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #393C44;
|
|
||||||
}
|
|
||||||
#subnav {
|
|
||||||
border-bottom: 1px solid #E8E8EF;
|
|
||||||
width: calc(100% + 20px);
|
|
||||||
margin-left: -20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.navdisabled {
|
|
||||||
transition: all .3s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
.navdisabled:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
.navactive {
|
|
||||||
color: #393C44!important;
|
|
||||||
}
|
|
||||||
#triggers {
|
|
||||||
margin-left: 20px;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
color: #808292;
|
|
||||||
width: calc(88% / 3);
|
|
||||||
height: 48px;
|
|
||||||
line-height: 48px;
|
|
||||||
display: inline-block;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.navactive:after {
|
|
||||||
display: block;
|
|
||||||
content: "";
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
background-color: #217CE8;
|
|
||||||
margin-top: -4px;
|
|
||||||
}
|
|
||||||
#actions {
|
|
||||||
display: inline-block;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #808292;
|
|
||||||
font-size: 14px;
|
|
||||||
height: 48px;
|
|
||||||
line-height: 48px;
|
|
||||||
width: calc(88% / 3);
|
|
||||||
text-align: center;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
#loggers {
|
|
||||||
width: calc(88% / 3);
|
|
||||||
display: inline-block;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #808292;
|
|
||||||
font-size: 14px;
|
|
||||||
height: 48px;
|
|
||||||
line-height: 48px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#footer {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
padding-left: 20px;
|
|
||||||
line-height: 40px;
|
|
||||||
bottom: 0;
|
|
||||||
width: 362px;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
height: 67px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: #FFF;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
#footer a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #393C44;
|
|
||||||
transition: all .2s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
#footer a:hover {
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
#footer span {
|
|
||||||
color: #808292;
|
|
||||||
}
|
|
||||||
#footer p {
|
|
||||||
display: inline-block;
|
|
||||||
color: #808292;
|
|
||||||
}
|
|
||||||
#footer img {
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
.blockelem:first-child {
|
|
||||||
margin-top: 20px
|
|
||||||
}
|
|
||||||
.blockelem {
|
|
||||||
padding-top: 10px;
|
|
||||||
width: 318px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
transition-property: box-shadow, height;
|
|
||||||
transition-duration: .2s;
|
|
||||||
transition-timing-function: cubic-bezier(.05,.03,.35,1);
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: 0px 0px 30px rgba(22, 33, 74, 0);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.blockelem:hover {
|
|
||||||
box-shadow: 0px 4px 30px rgba(22, 33, 74, 0.08);
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: #FFF;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.grabme, .blockico {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grabme {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-bottom: -14px;
|
|
||||||
width: 15px;
|
|
||||||
}
|
|
||||||
#blocklist {
|
|
||||||
height: calc(100% - 220px);
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
#proplist {
|
|
||||||
height: calc(100% - 305px);
|
|
||||||
overflow: auto;
|
|
||||||
margin-top: -30px;
|
|
||||||
padding-top: 30px;
|
|
||||||
}
|
|
||||||
.blockin {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
.blockico {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
background-color: #F1F4FC;
|
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blockico i {
|
|
||||||
font-size: 24px;
|
|
||||||
color: var(--grey-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blockico span {
|
|
||||||
height: 100%;
|
|
||||||
width: 0px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.blockico img {
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.blocktext {
|
|
||||||
display: inline-block;
|
|
||||||
width: 220px;
|
|
||||||
vertical-align: top;
|
|
||||||
margin-left: 12px
|
|
||||||
}
|
|
||||||
.blocktitle {
|
|
||||||
margin: 0px!important;
|
|
||||||
padding: 0px!important;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #393C44;
|
|
||||||
}
|
|
||||||
.blockdesc {
|
|
||||||
margin-top: 5px;
|
|
||||||
font-family: Roboto;
|
|
||||||
color: #808292;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 21px;
|
|
||||||
}
|
|
||||||
.blockdisabled {
|
|
||||||
background-color: #F0F2F9;
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
#closecard {
|
|
||||||
position: absolute;
|
|
||||||
margin-left: 340px;
|
|
||||||
background-color: #FFF;
|
|
||||||
border-radius: 0px 5px 5px 0px;
|
|
||||||
border-bottom: 1px solid #E8E8EF;
|
|
||||||
border-right: 1px solid #E8E8EF;
|
|
||||||
border-top: 1px solid #E8E8EF;
|
|
||||||
width: 53px;
|
|
||||||
height: 53px;
|
|
||||||
text-align: center;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
#closecard img {
|
|
||||||
margin-top: 15px
|
|
||||||
}
|
|
||||||
#canvas {
|
|
||||||
border: 1px solid green;
|
|
||||||
position: absolute;
|
|
||||||
width: calc(100% - 361px);
|
|
||||||
height: calc(100% - 71px);
|
|
||||||
top: 71px;
|
|
||||||
left: 361px;
|
|
||||||
z-index: 0;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
#propwrap {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 311px;
|
|
||||||
height: 100%;
|
|
||||||
padding-left: 20px;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: -2;
|
|
||||||
}
|
|
||||||
#properties {
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 311px;
|
|
||||||
background-color: #FFF;
|
|
||||||
right: -150px;
|
|
||||||
opacity: 0;
|
|
||||||
z-index: 2;
|
|
||||||
top: 0px;
|
|
||||||
box-shadow: -4px 0px 40px rgba(26, 26, 73, 0);
|
|
||||||
padding-left: 20px;
|
|
||||||
transition: all .25s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
.itson {
|
|
||||||
z-index: 2!important;
|
|
||||||
}
|
|
||||||
.expanded {
|
|
||||||
right: 0!important;
|
|
||||||
opacity: 1!important;
|
|
||||||
box-shadow: -4px 0px 40px rgba(26, 26, 73, 0.05);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
#header2 {
|
|
||||||
font-size: 20px;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #393C44;
|
|
||||||
margin-top: 101px;
|
|
||||||
}
|
|
||||||
#close {
|
|
||||||
margin-top: 100px;
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
z-index: 9999;
|
|
||||||
transition: all .25s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
#close:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .7;
|
|
||||||
}
|
|
||||||
#propswitch {
|
|
||||||
border-bottom: 1px solid #E8E8EF;
|
|
||||||
width: 331px;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: -20px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
#dataprop {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
color: #393C44;
|
|
||||||
width: calc(88% / 3);
|
|
||||||
height: 48px;
|
|
||||||
line-height: 48px;
|
|
||||||
display: inline-block;
|
|
||||||
float: left;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
#dataprop:after {
|
|
||||||
display: block;
|
|
||||||
content: "";
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
background-color: #217CE8;
|
|
||||||
margin-top: -4px;
|
|
||||||
}
|
|
||||||
#alertprop {
|
|
||||||
display: inline-block;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #808292;
|
|
||||||
font-size: 14px;
|
|
||||||
height: 48px;
|
|
||||||
line-height: 48px;
|
|
||||||
width: calc(88% / 3);
|
|
||||||
text-align: center;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
#logsprop {
|
|
||||||
width: calc(88% / 3);
|
|
||||||
display: inline-block;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #808292;
|
|
||||||
font-size: 14px;
|
|
||||||
height: 48px;
|
|
||||||
line-height: 48px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.inputlabel {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #253134;
|
|
||||||
}
|
|
||||||
.dropme {
|
|
||||||
background-color: #FFF;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
box-shadow: 0px 2px 8px rgba(34, 34, 87, 0.05);
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #253134;
|
|
||||||
text-indent: 20px;
|
|
||||||
height: 40px;
|
|
||||||
line-height: 40px;
|
|
||||||
width: 287px;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
.dropme img {
|
|
||||||
margin-top: 17px;
|
|
||||||
float: right;
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
.checkus {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.checkus img {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.checkus p {
|
|
||||||
display: inline-block;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 14px;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
#divisionthing {
|
|
||||||
height: 1px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #E8E8EF;
|
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
|
||||||
bottom: 80;
|
|
||||||
}
|
|
||||||
#removeblock {
|
|
||||||
border-radius: 5px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 20px;
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
width: 287px;
|
|
||||||
height: 38px;
|
|
||||||
line-height: 38px;
|
|
||||||
color: #253134;
|
|
||||||
border: 1px solid #E8E8EF;
|
|
||||||
transition: all .3s cubic-bezier(.05,.03,.35,1);
|
|
||||||
}
|
|
||||||
#removeblock:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
.noselect {
|
|
||||||
-webkit-touch-callout: none; /* iOS Safari */
|
|
||||||
-webkit-user-select: none; /* Safari */
|
|
||||||
-khtml-user-select: none; /* Konqueror HTML */
|
|
||||||
-moz-user-select: none; /* Old versions of Firefox */
|
|
||||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
|
||||||
user-select: none; /* Non-prefixed version, currently
|
|
||||||
supported by Chrome, Opera and Firefox */
|
|
||||||
}
|
|
||||||
.blockyname {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #253134;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.blockyleft img {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.blockyright {
|
|
||||||
display: inline-block;
|
|
||||||
float: right;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: 20px;
|
|
||||||
margin-top: 10px;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #FFF;
|
|
||||||
transition: all .3s cubic-bezier(.05,.03,.35,1);
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
.blockyright:hover {
|
|
||||||
background-color: #F1F4FC;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.blockyright img {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
.blockyleft {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
.blockydiv {
|
|
||||||
width: 100%;
|
|
||||||
height: 1px;
|
|
||||||
background-color: #E9E9EF;
|
|
||||||
}
|
|
||||||
.blockyinfo {
|
|
||||||
font-family: Roboto;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #808292;
|
|
||||||
margin-top: 15px;
|
|
||||||
text-indent: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.blockyinfo span {
|
|
||||||
color: #253134;
|
|
||||||
font-weight: 500;
|
|
||||||
display: inline-block;
|
|
||||||
border-bottom: 1px solid #D3DCEA;
|
|
||||||
line-height: 20px;
|
|
||||||
text-indent: 0px;
|
|
||||||
}
|
|
||||||
.block {
|
|
||||||
background-color: #FFF;
|
|
||||||
margin-top: 0px!important;
|
|
||||||
box-shadow: 0px 4px 30px rgba(22, 33, 74, 0.05);
|
|
||||||
}
|
|
||||||
.selectedblock {
|
|
||||||
border: 2px solid #217CE8;
|
|
||||||
box-shadow: 0px 4px 30px rgba(22, 33, 74, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 832px) {
|
|
||||||
#centerswitch {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 560px) {
|
|
||||||
#names {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,7 +38,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
display: grid;
|
|
||||||
font-family: inter;
|
font-family: inter;
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -3,19 +3,19 @@
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import * as api from "components/database/ModelDataTable/api"
|
import * as api from "components/database/ModelDataTable/api"
|
||||||
|
|
||||||
import BackendNav from "components/nav/BackendNav.svelte"
|
import ModelNavigator from "components/nav/ModelNavigator/ModelNavigator.svelte"
|
||||||
import SchemaManagementDrawer from "components/nav/SchemaManagementDrawer.svelte"
|
import { ModelSetupNav } from "components/nav/ModelSetupNav"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<BackendNav />
|
<ModelNavigator />
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<SchemaManagementDrawer />
|
<ModelSetupNav />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<slot />
|
|
@ -1,5 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
|
import { Button } from "@budibase/bbui"
|
||||||
|
import EmptyModel from "components/nav/ModelNavigator/EmptyModel.svelte"
|
||||||
import ModelDataTable from "components/database/ModelDataTable"
|
import ModelDataTable from "components/database/ModelDataTable"
|
||||||
import { store, backendUiStore } from "builderStore"
|
import { store, backendUiStore } from "builderStore"
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
import ActionButton from "components/common/ActionButton.svelte"
|
||||||
|
@ -8,6 +10,8 @@
|
||||||
|
|
||||||
const { open, close } = getContext("simple-modal")
|
const { open, close } = getContext("simple-modal")
|
||||||
|
|
||||||
|
$: selectedModel = $backendUiStore.selectedModel
|
||||||
|
|
||||||
const createNewRecord = () => {
|
const createNewRecord = () => {
|
||||||
open(
|
open(
|
||||||
CreateEditRecordModal,
|
CreateEditRecordModal,
|
||||||
|
@ -17,38 +21,19 @@
|
||||||
{ styleContent: { padding: "0" } }
|
{ styleContent: { padding: "0" } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export let selectedDatabase
|
|
||||||
|
|
||||||
let selectedRecord
|
|
||||||
|
|
||||||
async function selectRecord(record) {
|
|
||||||
selectedRecord = await api.loadRecord(record.key, {
|
|
||||||
appname: $store.appname,
|
|
||||||
instanceId: selectedDatabase,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
$: breadcrumbs = $backendUiStore.breadcrumbs.join(" / ")
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="database-actions">
|
{#if selectedModel.schema && Object.keys(selectedModel.schema).length === 0}
|
||||||
<div class="budibase__label--big">{breadcrumbs}</div>
|
<EmptyModel />
|
||||||
{#if $backendUiStore.selectedModel._id}
|
{:else if $backendUiStore.selectedDatabase._id && selectedModel.name}
|
||||||
<ActionButton primary on:click={createNewRecord}>
|
<ModelDataTable />
|
||||||
Create new record
|
|
||||||
</ActionButton>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{#if $backendUiStore.selectedDatabase._id && $backendUiStore.selectedModel.name}
|
|
||||||
<ModelDataTable {selectRecord} />
|
|
||||||
{:else}
|
{:else}
|
||||||
<i style="color: var(--grey-4)">create your first model to start building</i>
|
<i style="color: var(--grey-4)">create your first model to start building</i>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.database-actions {
|
i {
|
||||||
display: flex;
|
font-size: 20px;
|
||||||
justify-content: space-between;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
"@sendgrid/mail": "^7.1.1",
|
"@sendgrid/mail": "^7.1.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"electron": "^9.0.4",
|
||||||
"electron-is-dev": "^1.2.0",
|
"electron-is-dev": "^1.2.0",
|
||||||
"electron-unhandled": "^3.0.2",
|
"electron-unhandled": "^3.0.2",
|
||||||
"electron-updater": "^4.3.1",
|
"electron-updater": "^4.3.1",
|
||||||
|
@ -74,7 +75,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/test-sequencer": "^24.8.0",
|
"@jest/test-sequencer": "^24.8.0",
|
||||||
"electron": "^8.2.5",
|
|
||||||
"electron-builder": "^22.6.0",
|
"electron-builder": "^22.6.0",
|
||||||
"electron-builder-notarize": "^1.1.2",
|
"electron-builder-notarize": "^1.1.2",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
|
|
|
@ -45,7 +45,7 @@ exports.create = async function(ctx) {
|
||||||
}
|
}
|
||||||
const appId = newid()
|
const appId = newid()
|
||||||
// insert an appId -> clientId lookup
|
// insert an appId -> clientId lookup
|
||||||
const masterDb = new CouchDB("clientAppLookup")
|
const masterDb = new CouchDB("client_app_lookup")
|
||||||
|
|
||||||
await masterDb.put({
|
await masterDb.put({
|
||||||
_id: appId,
|
_id: appId,
|
||||||
|
@ -132,7 +132,7 @@ const createEmptyAppPackage = async (ctx, app) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const lookupClientId = async appId => {
|
const lookupClientId = async appId => {
|
||||||
const masterDb = new CouchDB("clientAppLookup")
|
const masterDb = new CouchDB("client_app_lookup")
|
||||||
const { clientId } = await masterDb.get(appId)
|
const { clientId } = await masterDb.get(appId)
|
||||||
return clientId
|
return clientId
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ exports.authenticate = async ctx => {
|
||||||
if (!username) ctx.throw(400, "Username Required.")
|
if (!username) ctx.throw(400, "Username Required.")
|
||||||
if (!password) ctx.throw(400, "Password Required")
|
if (!password) ctx.throw(400, "Password Required")
|
||||||
|
|
||||||
const masterDb = new CouchDB("clientAppLookup")
|
const masterDb = new CouchDB("client_app_lookup")
|
||||||
|
|
||||||
const { clientId } = await masterDb.get(ctx.user.appId)
|
const { clientId } = await masterDb.get(ctx.user.appId)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ const {
|
||||||
} = require("../../utilities/budibaseDir")
|
} = require("../../utilities/budibaseDir")
|
||||||
|
|
||||||
exports.fetchAppComponentDefinitions = async function(ctx) {
|
exports.fetchAppComponentDefinitions = async function(ctx) {
|
||||||
const masterDb = new CouchDB("clientAppLookup")
|
const masterDb = new CouchDB("client_app_lookup")
|
||||||
const { clientId } = await masterDb.get(ctx.params.appId)
|
const { clientId } = await masterDb.get(ctx.params.appId)
|
||||||
const db = new CouchDB(ClientDb.name(clientId))
|
const db = new CouchDB(ClientDb.name(clientId))
|
||||||
const app = await db.get(ctx.params.appId)
|
const app = await db.get(ctx.params.appId)
|
||||||
|
|
|
@ -8,7 +8,7 @@ exports.create = async function(ctx) {
|
||||||
const appShortId = appId.substring(0, 7)
|
const appShortId = appId.substring(0, 7)
|
||||||
const instanceId = `inst_${appShortId}_${newid()}`
|
const instanceId = `inst_${appShortId}_${newid()}`
|
||||||
|
|
||||||
const masterDb = new CouchDB("clientAppLookup")
|
const masterDb = new CouchDB("client_app_lookup")
|
||||||
const { clientId } = await masterDb.get(appId)
|
const { clientId } = await masterDb.get(appId)
|
||||||
|
|
||||||
const db = new CouchDB(instanceId)
|
const db = new CouchDB(instanceId)
|
||||||
|
|
|
@ -16,16 +16,16 @@ exports.find = async function(ctx) {
|
||||||
ctx.body = model
|
ctx.body = model
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.create = async function(ctx) {
|
exports.save = async function(ctx) {
|
||||||
const db = new CouchDB(ctx.user.instanceId)
|
const db = new CouchDB(ctx.user.instanceId)
|
||||||
const newModel = {
|
const modelToSave = {
|
||||||
type: "model",
|
type: "model",
|
||||||
...ctx.request.body,
|
|
||||||
_id: newid(),
|
_id: newid(),
|
||||||
|
...ctx.request.body,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await db.post(newModel)
|
const result = await db.post(modelToSave)
|
||||||
newModel._rev = result.rev
|
modelToSave._rev = result.rev
|
||||||
|
|
||||||
const { schema } = ctx.request.body
|
const { schema } = ctx.request.body
|
||||||
for (let key in schema) {
|
for (let key in schema) {
|
||||||
|
@ -33,9 +33,10 @@ exports.create = async function(ctx) {
|
||||||
if (schema[key].type === "link") {
|
if (schema[key].type === "link") {
|
||||||
// create the link field in the other model
|
// create the link field in the other model
|
||||||
const linkedModel = await db.get(schema[key].modelId)
|
const linkedModel = await db.get(schema[key].modelId)
|
||||||
linkedModel.schema[newModel.name] = {
|
linkedModel.schema[modelToSave._id] = {
|
||||||
|
name: modelToSave.name,
|
||||||
type: "link",
|
type: "link",
|
||||||
modelId: newModel._id,
|
modelId: modelToSave._id,
|
||||||
constraints: {
|
constraints: {
|
||||||
type: "array",
|
type: "array",
|
||||||
},
|
},
|
||||||
|
@ -47,9 +48,9 @@ exports.create = async function(ctx) {
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
designDoc.views = {
|
designDoc.views = {
|
||||||
...designDoc.views,
|
...designDoc.views,
|
||||||
[`all_${newModel._id}`]: {
|
[`all_${modelToSave._id}`]: {
|
||||||
map: `function(doc) {
|
map: `function(doc) {
|
||||||
if (doc.modelId === "${newModel._id}") {
|
if (doc.modelId === "${modelToSave._id}") {
|
||||||
emit(doc[doc.key], doc._id);
|
emit(doc[doc.key], doc._id);
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
|
@ -58,12 +59,10 @@ exports.create = async function(ctx) {
|
||||||
await db.put(designDoc)
|
await db.put(designDoc)
|
||||||
|
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.message = `Model ${ctx.request.body.name} created successfully.`
|
ctx.message = `Model ${ctx.request.body.name} saved successfully.`
|
||||||
ctx.body = newModel
|
ctx.body = modelToSave
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.update = async function() {}
|
|
||||||
|
|
||||||
exports.destroy = async function(ctx) {
|
exports.destroy = async function(ctx) {
|
||||||
const db = new CouchDB(ctx.user.instanceId)
|
const db = new CouchDB(ctx.user.instanceId)
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,29 @@ exports.save = async function(ctx) {
|
||||||
const response = await db.post(record)
|
const response = await db.post(record)
|
||||||
record._rev = response.rev
|
record._rev = response.rev
|
||||||
|
|
||||||
|
// create links in other tables
|
||||||
|
for (let key in record) {
|
||||||
|
if (model.schema[key] && model.schema[key].type === "link") {
|
||||||
|
const linked = await db.allDocs({
|
||||||
|
include_docs: true,
|
||||||
|
keys: record[key],
|
||||||
|
})
|
||||||
|
|
||||||
|
// add this record to the linked records in attached models
|
||||||
|
const linkedDocs = linked.rows.map(row => {
|
||||||
|
const doc = row.doc
|
||||||
|
return {
|
||||||
|
...doc,
|
||||||
|
[model._id]: doc[model._id]
|
||||||
|
? [...doc[model._id], record._id]
|
||||||
|
: [record._id],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await db.bulkDocs(linkedDocs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.eventEmitter &&
|
ctx.eventEmitter &&
|
||||||
ctx.eventEmitter.emit(`record:save`, {
|
ctx.eventEmitter.emit(`record:save`, {
|
||||||
record,
|
record,
|
||||||
|
@ -82,7 +105,7 @@ exports.find = async function(ctx) {
|
||||||
const db = new CouchDB(ctx.user.instanceId)
|
const db = new CouchDB(ctx.user.instanceId)
|
||||||
const record = await db.get(ctx.params.recordId)
|
const record = await db.get(ctx.params.recordId)
|
||||||
if (record.modelId !== ctx.params.modelId) {
|
if (record.modelId !== ctx.params.modelId) {
|
||||||
ctx.throw(400, "Supplied modelId doe not match the record's modelId")
|
ctx.throw(400, "Supplied modelId does not match the records modelId")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.body = record
|
ctx.body = record
|
||||||
|
|
|
@ -41,7 +41,7 @@ exports.create = async function(ctx) {
|
||||||
|
|
||||||
const response = await database.post(user)
|
const response = await database.post(user)
|
||||||
|
|
||||||
const masterDb = new CouchDB("clientAppLookup")
|
const masterDb = new CouchDB("client_app_lookup")
|
||||||
const { clientId } = await masterDb.get(appId)
|
const { clientId } = await masterDb.get(appId)
|
||||||
|
|
||||||
// the clientDB needs to store a map of users against the app
|
// the clientDB needs to store a map of users against the app
|
||||||
|
|
|
@ -12,8 +12,7 @@ router
|
||||||
authorized(READ_MODEL, ctx => ctx.params.id),
|
authorized(READ_MODEL, ctx => ctx.params.id),
|
||||||
modelController.find
|
modelController.find
|
||||||
)
|
)
|
||||||
.post("/api/models", authorized(BUILDER), modelController.create)
|
.post("/api/models", authorized(BUILDER), modelController.save)
|
||||||
// .patch("/api/:instanceId/models", controller.update)
|
|
||||||
.delete(
|
.delete(
|
||||||
"/api/models/:modelId/:revId",
|
"/api/models/:modelId/:revId",
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
|
|
|
@ -45,7 +45,7 @@ describe("/models", () => {
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.end(async (err, res) => {
|
.end(async (err, res) => {
|
||||||
expect(res.res.statusMessage).toEqual("Model TestModel created successfully.");
|
expect(res.res.statusMessage).toEqual("Model TestModel saved successfully.");
|
||||||
expect(res.body.name).toEqual("TestModel");
|
expect(res.body.name).toEqual("TestModel");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -112,7 +112,7 @@ describe("/models", () => {
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
delete testModel._rev
|
delete testModel._rev
|
||||||
})
|
});
|
||||||
|
|
||||||
it("returns a success response when a model is deleted.", async done => {
|
it("returns a success response when a model is deleted.", async done => {
|
||||||
request
|
request
|
||||||
|
|
|
@ -194,6 +194,20 @@
|
||||||
lodash "^4.17.13"
|
lodash "^4.17.13"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@budibase/client@^0.0.32":
|
||||||
|
version "0.0.32"
|
||||||
|
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.0.32.tgz#76d9f147563a0bf939eae7f32ce75b2a527ba496"
|
||||||
|
integrity sha512-jmCCLn0CUoQbL6h623S5IqK6+GYLqX3WzUTZInSb1SCBOM3pI0eLP5HwTR6s7r42SfD0v9jTWRdyTnHiElNj8A==
|
||||||
|
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"
|
||||||
|
regexparam "^1.3.0"
|
||||||
|
shortid "^2.2.8"
|
||||||
|
svelte "^3.9.2"
|
||||||
|
|
||||||
"@budibase/core@^0.0.32":
|
"@budibase/core@^0.0.32":
|
||||||
version "0.0.32"
|
version "0.0.32"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/core/-/core-0.0.32.tgz#c5d9ab869c5e9596a1ac337aaf041e795b1cc7fa"
|
resolved "https://registry.yarnpkg.com/@budibase/core/-/core-0.0.32.tgz#c5d9ab869c5e9596a1ac337aaf041e795b1cc7fa"
|
||||||
|
@ -849,6 +863,11 @@ 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"
|
||||||
|
@ -921,6 +940,13 @@ 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-sign2@~0.7.0:
|
aws-sign2@~0.7.0:
|
||||||
version "0.7.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||||
|
@ -1643,6 +1669,26 @@ 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"
|
||||||
|
@ -1924,10 +1970,10 @@ electron-updater@^4.3.1:
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
semver "^7.1.3"
|
semver "^7.1.3"
|
||||||
|
|
||||||
electron@^8.2.5:
|
electron@^9.0.4:
|
||||||
version "8.2.5"
|
version "9.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-8.2.5.tgz#ae3cb23d5517b2189fd35298e487198d65d1a291"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-9.0.4.tgz#5aa72c1576c82c19f6e087311ffe1d7b74358d25"
|
||||||
integrity sha512-LxSCUwmlfJtRwthd3ofpYaZ+1C2hQSW8Ep1DD9K3VbnDItO+kb3t1z35daJgAab78j54aOwo9gMxJtvU0Ftj6w==
|
integrity sha512-QzkeZNAiNB7KxcdoQKSoaiVT/GQdB4Vt0/ZZOuU8tIKABAsni2I7ztiAbUzxcsnQsqEBSfChuPuDQ5A4VbbzPg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^1.0.1"
|
"@electron/get" "^1.0.1"
|
||||||
"@types/node" "^12.0.12"
|
"@types/node" "^12.0.12"
|
||||||
|
@ -2018,6 +2064,36 @@ 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"
|
||||||
|
@ -3010,11 +3086,21 @@ 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"
|
||||||
|
@ -3022,6 +3108,11 @@ is-binary-path@~2.1.0:
|
||||||
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"
|
||||||
|
@ -3032,6 +3123,11 @@ 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"
|
||||||
|
@ -3058,7 +3154,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.1, is-date-object@^1.0.2:
|
||||||
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"
|
||||||
integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
|
integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
|
||||||
|
@ -3133,11 +3229,21 @@ 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"
|
||||||
|
@ -3174,11 +3280,28 @@ 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"
|
||||||
|
@ -3195,11 +3318,31 @@ 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"
|
||||||
|
@ -3225,6 +3368,11 @@ 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"
|
||||||
|
@ -4637,6 +4785,14 @@ 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"
|
||||||
|
@ -5358,6 +5514,19 @@ 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"
|
||||||
|
@ -5686,6 +5855,14 @@ shortid@^2.2.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^2.1.0"
|
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"
|
||||||
|
@ -5938,7 +6115,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.0, string.prototype.trimend@^1.0.1:
|
||||||
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"
|
||||||
integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
|
integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
|
||||||
|
@ -5964,7 +6141,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.0, string.prototype.trimstart@^1.0.1:
|
||||||
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"
|
||||||
integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
|
integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
|
||||||
|
@ -6094,6 +6271,11 @@ supports-color@^7.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
|
svelte@^3.9.2:
|
||||||
|
version "3.23.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.23.2.tgz#f3e500384261a2e77b29681ee744c3c790fbcdc3"
|
||||||
|
integrity sha512-hE8GeTM83YVR4GY6/6PeDEcGct4JS5aCi+IYbCAa76oaPSfuF7L85DQYULQxlTK/KPWzw3L1GRGmC3oPG/PQoA==
|
||||||
|
|
||||||
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"
|
||||||
|
@ -6579,11 +6761,44 @@ 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"
|
||||||
|
|
Loading…
Reference in New Issue