enhanced modals
This commit is contained in:
parent
a8fec53ff3
commit
9756574e6f
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div bind:this={ukModal} uk-modal {id}>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}`
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
</script>
|
||||
|
||||
<Modal {onClosed} isOpen={modalOpen}>
|
||||
<section>
|
||||
<IndexView />
|
||||
<ActionsHeader />
|
||||
|
||||
|
@ -22,4 +22,4 @@
|
|||
Save
|
||||
</ActionButton>
|
||||
</div> -->
|
||||
</Modal>
|
||||
</section>
|
||||
|
|
|
@ -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>
|
|
@ -15,12 +15,12 @@
|
|||
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
|
||||
|
@ -28,9 +28,9 @@
|
|||
on:click={async () => {
|
||||
await api.deleteRecord(record, currentAppInfo)
|
||||
backendUiStore.actions.records.delete(record)
|
||||
onClosed();
|
||||
onClosed()
|
||||
}}>
|
||||
Delete
|
||||
</ActionButton>
|
||||
</div>
|
||||
</Modal>
|
||||
</section>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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…
Reference in New Issue