Browse Source

enhanced modals

master
Martin McKeaveney 7 years ago
parent
commit
9756574e6f
  1. 77
      packages/builder/src/builderStore/store/backend.js
  2. 4
      packages/builder/src/builderStore/store/index.js
  3. 1
      packages/builder/src/common/Modal.svelte
  4. 35
      packages/builder/src/database/ActionsHeader.svelte
  5. 30
      packages/builder/src/database/DatabaseRoot.svelte
  6. 20
      packages/builder/src/database/ModelDataTable/ModelDataTable.svelte
  7. 9
      packages/builder/src/database/ModelDataTable/api.js
  8. 16
      packages/builder/src/database/ModelDataTable/modals/CreateDatabase.svelte
  9. 7
      packages/builder/src/database/ModelDataTable/modals/CreateEditModel.svelte
  10. 8
      packages/builder/src/database/ModelDataTable/modals/CreateEditRecord.svelte
  11. 4
      packages/builder/src/database/ModelDataTable/modals/CreateEditView.svelte
  12. 27
      packages/builder/src/database/ModelDataTable/modals/CreateUser.svelte
  13. 12
      packages/builder/src/database/ModelDataTable/modals/DeleteRecord.svelte
  14. 2
      packages/builder/src/database/ModelView.svelte
  15. 30
      packages/builder/src/nav/HierarchyRow.svelte

77
packages/builder/src/builderStore/store/backend.js

@ -45,6 +45,11 @@ export const getBackendUiStore = () => {
modals: {
show: modal => store.update(state => ({ ...state, visibleModal: modal })),
hide: () => store.update(state => ({ ...state, visibleModal: null }))
},
nodes: {
select: () => {},
update: () => {},
delete: () => {},
}
}
@ -52,10 +57,13 @@ export const getBackendUiStore = () => {
};
// Store Actions
export const createShadowHierarchy = hierarchy => {
const hi = constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
console.log(hi)
return hi
export const createShadowHierarchy = hierarchy => constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
export const createDatabaseForApp = store => appInstance => {
store.update(state => {
state.appInstances.push(appInstance)
return state
})
}
export const saveBackend = async state => {
@ -98,12 +106,12 @@ export const selectExistingNode = store => nodeId => {
export const newIndex = (store, useRoot) => () => {
store.update(state => {
const shadowHierarchy = createShadowHierarchy(state.hierarchy)
state.currentNodeIsNew = true
state.errors = []
const shadowHierarchy = createShadowHierarchy(state.hierarchy)
const parent = useRoot
? shadowHierarchy
: getNode(shadowHierarchy, state.currentNode.nodeId)
? state.hierarchy
: getNode(state.hierarchy, state.currentNode.nodeId)
state.currentNode = templateApi(shadowHierarchy).getNewIndexTemplate(parent)
return state
@ -114,7 +122,7 @@ export const saveCurrentNode = store => () => {
store.update(state => {
const errors = validate.node(state.currentNode)
state.errors = errors
if (errorstate.length > 0) {
if (errors.length > 0) {
return state
}
@ -126,9 +134,10 @@ export const saveCurrentNode = store => () => {
if (existingNode) {
// remove existing
index = existingNode.parent().children.indexOf(existingNode)
existingNode.parent().children = pipe(existingNode.parent().children, [
filter(c => c.nodeId !== existingNode.nodeId),
])
existingNode.parent().children = existingNode.parent().children.filter(c => c.nodeId !== existingNode.nodeId);
// existingNode.parent().children = pipe(existingNode.parent().children, [
// filter(c => c.nodeId !== existingNode.nodeId),
// ])
}
// should add node into existing hierarchy
@ -141,7 +150,7 @@ export const saveCurrentNode = store => () => {
return currentIndex >= index ? currentIndex + 1 : currentIndex
}
parentNode.children = pipe(parentNode.children, [sortBy(newIndexOfChild)])
parentNode.children = sortBy(newIndexOfChild, parentNode.children)
if (!existingNode && state.currentNode.type === "record") {
const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
@ -162,18 +171,28 @@ export const saveCurrentNode = store => () => {
export const deleteCurrentNode = store => () => {
store.update(state => {
const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId)
state.currentNode = hierarchyFunctionstate.isRoot(nodeToDelete.parent())
? find(n => n != state.currentNode)(state.hierarchy.children)
state.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
? find(n => n !== state.currentNode)(state.hierarchy.children)
: nodeToDelete.parent()
if (hierarchyFunctionstate.isRecord(nodeToDelete)) {
nodeToDelete.parent().children = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().children)
} else {
nodeToDelete.parent().indexes = filter(
c => c.nodeId !== nodeToDelete.nodeId
)(nodeToDelete.parent().indexes)
}
const recordOrIndexKey = hierarchyFunctions.isRecord(nodeToDelete) ? "children" : "indexes";
// remove the selected record or index
nodeToDelete.parent()[recordOrIndexKey] = remove(
nodeToDelete.parent()[recordOrIndexKey],
node => node.nodeId === nodeToDelete.nodeId
)
// if (hierarchyFunctions.isRecord(nodeToDelete)) {
// nodeToDelete.parent().children = filter(
// c => c.nodeId !== nodeToDelete.nodeId
// )(nodeToDelete.parent().children)
// } else {
// nodeToDelete.parent().indexes = remove(
// nodeToDelete.parent().indexes,
// node => node.nodeId === nodeToDelete.nodeId
// )
// }
state.errors = []
saveBackend(state)
return state
@ -202,25 +221,23 @@ export const deleteField = databaseStore => field => {
}
const incrementAccessLevelsVersion = state =>
(state.accessLevelstate.version = (state.accessLevelstate.version || 0) + 1)
(state.accessLevels.version = (state.accessLevels.version || 0) + 1)
export const saveLevel = store => (newLevel, isNew, oldLevel = null) => {
store.update(state => {
const levels = state.accessLevelstate.levels
const levels = state.accessLevels.levels
const existingLevel = isNew
? null
: find(a => a.name === oldLevel.name)(levels)
if (existingLevel) {
state.accessLevelstate.levels = pipe(levels, [
map(a => (a === existingLevel ? newLevel : a)),
])
state.accessLevels.levels = levels.map(level => level === existingLevel ? newLevel : level)
} else {
state.accessLevelstate.levelstate.push(newLevel)
state.accessLevels.levels.push(newLevel)
}
incrementAccessLevelsVersion(s)
incrementAccessLevelsVersion(state)
saveBackend(state)
return state

4
packages/builder/src/builderStore/store/index.js

@ -1,7 +1,6 @@
import {
filter,
cloneDeep,
// sortBy,
map,
last,
concat,
@ -12,9 +11,7 @@ import {
import {
pipe,
getNode,
// validate,
constructHierarchy,
// templateApi,
} from "../../common/core"
import * as backendStoreActions from "./backend";
import { writable } from "svelte/store"
@ -78,6 +75,7 @@ export const getStore = () => {
store.deleteField = backendStoreActions.deleteField(store)
store.saveLevel = backendStoreActions.saveLevel(store)
store.deleteLevel = backendStoreActions.deleteLevel(store)
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store)
store.importAppDefinition = importAppDefinition(store)
store.saveAction = saveAction(store)

1
packages/builder/src/common/Modal.svelte

@ -24,6 +24,7 @@
}
}
}
</script>
<div bind:this={ukModal} uk-modal {id}>

35
packages/builder/src/database/ActionsHeader.svelte

@ -19,39 +19,32 @@
</script>
<div class="root">
<ButtonGroup>
<ActionButton color="secondary" grouped on:click={store.saveCurrentNode}>
Save
</ActionButton>
<div class="button-container">
{#if !$store.currentNodeIsNew}
<ActionButton alert grouped on:click={openConfirmDelete}>
<ActionButton alert on:click={deleteCurrentNode}>
Delete
</ActionButton>
{/if}
</ButtonGroup>
<ActionButton color="secondary" on:click={store.saveCurrentNode}>
Save
</ActionButton>
</div>
{#if $store.errors && $store.errors.length > 0}
<ErrorsBox errors={$store.errors} />
{/if}
<Modal onClosed={() => (confirmDelete = false)} bind:isOpen={confirmDelete}>
<span>Are you sure you want to delete {$store.currentNode.name}?</span>
<div class="uk-modal-footer uk-text-right">
<ButtonGroup>
<ActionButton alert on:click={deleteCurrentNode}>Yes</ActionButton>
<ActionButton primary on:click={() => (confirmDelete = false)}>
No
</ActionButton>
</ButtonGroup>
</div>
</Modal>
</div>
<style>
.root {
padding: 1.5rem;
display: flex;
background: #fafafa;
width: 100%;
align-items: right;
border-top: 1px solid #ccc;
}
.button-container {
padding: 20px;
}
</style>

30
packages/builder/src/database/DatabaseRoot.svelte

@ -12,34 +12,46 @@
CreateEditRecordModal,
CreateEditModelModal,
CreateEditViewModal,
CreateDatabaseModal
CreateDatabaseModal,
DeleteRecordModal
} from "./ModelDataTable/modals"
let selectedRecord
function selectRecord(record) {
selectedRecord = record
backendUiStore.actions.modals.show("RECORD")
}
function onClosed() {
// backendUiStore.actions.modals.hide()
backendUiStore.actions.modals.hide()
}
$: recordOpen = $backendUiStore.visibleModal === "RECORD"
$: modelOpen = $backendUiStore.visibleModal === "MODEL"
$: viewOpen = $backendUiStore.visibleModal === "VIEW"
$: databaseOpen = $backendUiStore.visibleModal === "DATABASE"
$: deleteRecordOpen = $backendUiStore.visibleModal === "DELETE_RECORD"
// $: recordOpen = $store.currentNode && $store.currentNode.type === 'record'
// $: viewOpen = $store.currentNode && $store.currentNode.type === 'index'
</script>
({ console.log($backendUiStore.visibleModal) })
<CreateEditRecordModal modalOpen={recordOpen} record={selectedRecord} {onClosed} />
<CreateEditModelModal modalOpen={modelOpen} {onClosed} />
<CreateEditViewModal modalOpen={viewOpen} {onClosed} />
<CreateDatabaseModal modalOpen={databaseOpen} {onClosed} />
<Modal isOpen={!!$backendUiStore.visibleModal} {onClosed}>
{#if recordOpen}
<CreateEditRecordModal record={selectedRecord} {onClosed} />
{/if}
{#if modelOpen}
<CreateEditModelModal {onClosed} />
{/if}
{#if viewOpen}
<CreateEditViewModal {onClosed} />
{/if}
{#if databaseOpen}
<CreateDatabaseModal {onClosed} />
{/if}
{#if deleteRecordOpen}
<DeleteRecordModal record={selectedRecord} />
{/if}
</Modal>
<div class="root">

20
packages/builder/src/database/ModelDataTable/ModelDataTable.svelte

@ -38,15 +38,12 @@
}
onMount(async () => {
await fetchRecordsForView(views[0].name, currentAppInfo)
if (views.length > 0) {
await fetchRecordsForView(views[0].name, currentAppInfo)
}
})
</script>
<DeleteRecordModal
modalOpen={deleteRecordModal}
record={selectedRecord}
/>
<section>
<div class="table-controls">
<h4 class="budibase__title--3">Shoe database</h4>
@ -79,13 +76,16 @@
<div>View</div>
</li>
<li
on:click={() => selectRecord(row)}>
on:click={() => {
selectRecord(row)
backendUiStore.actions.modals.show("RECORD")
}}>
<div>Edit</div>
</li>
<li>
<div
on:click={() => {
selectedRecord = row
selectRecord(row)
backendUiStore.actions.modals.show("DELETE_RECORD")
}}>
Delete
@ -112,7 +112,8 @@
table {
border: 1px solid #ccc;
background: #fff;
border-radius: 2px;
border-radius: 3px;
border-collapse: separate;
}
thead {
@ -128,6 +129,7 @@
tbody tr {
border-bottom: 1px solid #ccc;
transition: 0.3s background-color;
color: var(--darkslate);
}
tbody tr:hover {

9
packages/builder/src/database/ModelDataTable/api.js

@ -1,5 +1,12 @@
import api from "../../builderStore/api";
import { getNewRecord } from "../../common/core"
import { getNewRecord, getNewInstance } from "../../common/core"
export async function createDatabase(appname, instanceName) {
const CREATE_DATABASE_URL = `/_builder/instance/_master/0/api/record`
const database = getNewInstance(appname, instanceName);
const response = await api.post(CREATE_DATABASE_URL, database);
return await response.json()
}
export async function deleteRecord(record, { appname, instanceId }) {
const DELETE_RECORDS_URL = `/_builder/instance/${appname}/${instanceId}/api/record${record.key}`

16
packages/builder/src/database/ModelDataTable/modals/CreateDatabase.svelte

@ -1,17 +1,23 @@
<script>
import Modal from "../../../common/Modal.svelte"
import { store } from "../../../builderStore"
import ActionButton from "../../../common/ActionButton.svelte"
import * as api from "../api"
export let modalOpen = false
let databaseName
const onClosed = () => (modalOpen = false)
async function createDatabase() {
const response = await api.createDatabase($store.appname, databaseName)
store.createDatabaseForApp(response)
onClosed()
}
</script>
<Modal {onClosed} isOpen={modalOpen}>
<section>
CREATE A NEW DATABASE FROM HERE
<input type="text" bind:value={databaseName} />
<div class="actions">
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton disabled={false}>Save</ActionButton>
<ActionButton disabled={!databaseName} on:click={createDatabase}>Save</ActionButton>
</div>
</Modal>
</section>

7
packages/builder/src/database/ModelDataTable/modals/CreateEditModel.svelte

@ -5,12 +5,9 @@
import ModelView from "../../ModelView.svelte"
import ActionsHeader from "../../ActionsHeader.svelte"
import * as api from "../api"
export let modalOpen = false
export let onClosed
</script>
<Modal {onClosed} isOpen={modalOpen}>
<section>
<h4 class="budibase__title--4">
<i class="ri-list-settings-line" />
Create / Edit Model
@ -19,4 +16,4 @@
<ModelView />
<ActionsHeader />
</div>
</Modal>
</section>

8
packages/builder/src/database/ModelDataTable/modals/CreateEditRecord.svelte

@ -7,7 +7,6 @@
import { getNewRecord } from "../../../common/core"
import * as api from "../api"
export let modalOpen = false
export let record
export let onClosed
@ -22,10 +21,9 @@
$: modelFields = selectedModel
? selectedModel.fields.map(({ name }) => name)
: []
</script>
<Modal {onClosed} isOpen={modalOpen}>
<div>
<h4 class="budibase__title--4">Create / Edit Record</h4>
<div class="actions">
<form class="uk-form-stacked">
@ -80,10 +78,10 @@
</ActionButton>
</div>
</div>
</Modal>
</div>
<style>
.actions {
position: absolute;
/* position: absolute; */
}
</style>

4
packages/builder/src/database/ModelDataTable/modals/CreateEditView.svelte

@ -12,7 +12,7 @@
</script>
<Modal {onClosed} isOpen={modalOpen}>
<section>
<IndexView />
<ActionsHeader />
@ -22,4 +22,4 @@
Save
</ActionButton>
</div> -->
</Modal>
</section>

27
packages/builder/src/database/ModelDataTable/modals/CreateUser.svelte

@ -0,0 +1,27 @@
<script>
import Modal from "../../../common/Modal.svelte"
import { store } from "../../../builderStore"
import ActionButton from "../../../common/ActionButton.svelte"
import * as api from "../api"
export let modalOpen = false
let userName
const onClosed = () => (modalOpen = false)
async function createUser() {
const response = await api.createUser($store.appname, userName)
store.createUserForInstance(response)
onClosed()
}
</script>
<Modal {onClosed} isOpen={modalOpen}>
CREATE A NEW user FROM HERE
<input type="text" bind:value={userName} />
<div class="actions">
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
<ActionButton disabled={!userName} on:click={createUser}>Save</ActionButton>
</div>
</Modal>

12
packages/builder/src/database/ModelDataTable/modals/DeleteRecord.svelte

@ -15,22 +15,22 @@
function onClosed() {
backendUiStore.actions.modals.hide()
}
</script>
<Modal {onClosed} isOpen={modalOpen}>
<section>
<h4 class="budibase__title--4">Delete Record</h4>
Are you sure you want to delete this record? All of your data will be permanently removed. This action cannot be undone.
Are you sure you want to delete this record? All of your data will be
permanently removed. This action cannot be undone.
<div class="modal-actions">
<ActionButton on:click={onClosed}>Cancel</ActionButton>
<ActionButton
alert
on:click={async () => {
on:click={async () => {
await api.deleteRecord(record, currentAppInfo)
backendUiStore.actions.records.delete(record)
onClosed();
onClosed()
}}>
Delete
</ActionButton>
</div>
</Modal>
</section>

2
packages/builder/src/database/ModelView.svelte

@ -110,7 +110,7 @@
<div class="uk-form-controls">
<Select
value={parentRecord}
on:change={e => (parentRecord = e.target.value)}>
on:change={e => store.newChildRecord()}>
{#each models as model}
<option value={model}>{model.name}</option>
{/each}

30
packages/builder/src/nav/HierarchyRow.svelte

@ -3,11 +3,15 @@
import { store, backendUiStore } from "../builderStore"
import { cloneDeep } from "lodash/fp"
import getIcon from "../common/icon"
export let level = 0
export let node
export let type
let navActive = ""
let expanded = false
$: hasChildren = (node.children || node.indexes) && (node.children.length || node.indexes.length)
const ICON_MAP = {
index: "ri-eye-line",
@ -34,18 +38,26 @@
class:capitalized={type === 'record'}
style="padding-left: {20 + level * 20}px"
class:selected={navActive}>
{#if hasChildren}
<i
class={`ri-arrow-${expanded ? "down" : "right"}-s-line`}
on:click={() => expanded = !expanded}
/>
{/if}
<i class={ICON_MAP[type]} />
<span style="margin-left: 1rem">{node.name}</span>
</div>
{#if node.children}
{#each node.children as child}
<svelte:self node={child} level={level + 1} type="record" />
{/each}
{/if}
{#if node.indexes}
{#each node.indexes as index}
<svelte:self node={index} level={level + 1} type="index" />
{/each}
{#if expanded}
{#if node.children}
{#each node.children as child}
<svelte:self node={child} level={level + 1} type="record" />
{/each}
{/if}
{#if node.indexes}
{#each node.indexes as index}
<svelte:self node={index} level={level + 1} type="index" />
{/each}
{/if}
{/if}
</div>

Loading…
Cancel
Save