budibase/packages/builder/src/database/RecordView.svelte

300 lines
7.0 KiB
Svelte

<script>
import Textbox from "../common/Textbox.svelte";
import Button from "../common/Button.svelte";
import getIcon from "../common/icon";
import FieldView from "./FieldView.svelte";
import Modal from "../common/Modal.svelte";
import {map, join, filter, some,
find, keys, isDate} from "lodash/fp";
import { store } from "../builderStore";
import {common, hierarchy as h} from "../../../core/src";
import {templateApi, pipe, validate} from "../common/core";
let record;
let getIndexAllowedRecords;
let editingField = false;
let fieldToEdit;
let isNewField = false;
let newField;
let editField;
let deleteField;
let onFinishedFieldEdit;
let editIndex;
store.subscribe($store => {
record = $store.currentNode;
const flattened = h.getFlattenedHierarchy($store.hierarchy);
getIndexAllowedRecords = index =>
pipe(index.allowedRecordNodeIds, [
filter(id => some(n => n.nodeId === id)(flattened)),
map(id => find(n => n.nodeId === id)
(flattened).name),
join(", ")
]);
newField = () => {
isNewField = true;
fieldToEdit = templateApi($store.hierarchy).getNewField("string");
editingField = true;
}
onFinishedFieldEdit = (field) => {
if(field) {
store.saveField(field);
}
editingField = false;
}
editField = (field) => {
isNewField = false;
fieldToEdit = field;
editingField = true;
}
deleteField = (field) => {
store.deleteField(field);
}
editIndex = index => {
store.selectExistingNode(index.nodeId);
}
})
let getTypeOptionsValueText = value => {
if(value === Number.MAX_SAFE_INTEGER
|| value === Number.MIN_SAFE_INTEGER
|| new Date(value).getTime() === new Date(8640000000000000).getTime()
|| new Date(value).getTime() === new Date(-8640000000000000).getTime()) return "(any)";
if(value === null) return "(not set)";
return value;
}
let getTypeOptions = typeOptions =>
pipe(typeOptions, [
keys,
map(k => `<span style="color:var(--slate)">${k}: </span>${getTypeOptionsValueText(typeOptions[k])}`),
join("<br>")
]);
const nameChanged = ev => {
const pluralName = n => `${n}s`;
if(record.collectionName === "") {
record.collectionName = pluralName(ev.target.value);
}
}
</script>
<div class="root">
<form class="uk-form-horizontal">
<h3 class="settings-title">
Settings
</h3>
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged}/>
{#if !record.isSingle}
<Textbox label="Collection Name:" bind:text={record.collectionName} />
<Textbox label="Shard Factor:" bind:text={record.allidsShardFactor} />
{/if}
<div class="recordkey">{record.nodeKey()}</div>
</form>
<h3 class="title">
Fields <span class="add-field-button" on:click={newField}>{@html getIcon("plus")}</span>
</h3>
{#if record.fields.length > 0}
<table class="fields-table uk-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Options</th>
<th></th>
</tr>
</thead>
<tbody>
{#each record.fields as field}
<tr>
<td >
<div class="field-label">{field.label}</div>
<div style="font-size: 0.8em; color: var(--slate)">{field.name}</div>
</td>
<td >{field.type}</td>
<td >{@html getTypeOptions(field.typeOptions)}</td>
<td>
<span class="edit-button" on:click={() => editField(field)}>{@html getIcon("edit")}</span>
<span class="edit-button" on:click={() => deleteField(field)}>{@html getIcon("trash")}</span>
</td>
</tr>
{/each}
</tbody>
</table>
{:else}
(no fields added)
{/if}
{#if editingField}
<Modal bind:isOpen={editingField} onClosed={() => onFinishedFieldEdit(false) }>
<FieldView field={fieldToEdit}
onFinished={onFinishedFieldEdit}
allFields={record.fields}
store={$store}/>
</Modal>
{/if}
<h3 class="title">
Indexes
</h3>
{#each record.indexes as index}
<div class="index-container">
<div class="index-name">
{index.name}
<span style="margin-left: 7px" on:click={() => editIndex(index)}>{@html getIcon("edit")}</span>
</div>
<div class="index-field-row">
<span class="index-label">records indexed: </span>
<span>{getIndexAllowedRecords(index)}</span>
<span class="index-label" style="margin-left: 15px">type:</span>
<span>{index.indexType}</span>
</div>
<div class="index-field-row">
<span class="index-label">map:</span>
<code class="index-mapfilter">{index.map}</code>
</div>
{#if index.filter}
<div class="index-field-row">
<span class="index-label">filter:</span>
<code class="index-mapfilter">{index.filter}</code>
</div>
{/if}
</div>
{:else}
<div class="no-indexes">
No indexes added.
</div>
{/each}
</div>
<style>
.root {
height: 100%;
padding: 2rem;
}
.settings-title {
font-weight: 700;
}
.title {
margin: 3rem 0rem 0rem 0rem;
font-weight: 700;
}
.recordkey {
font-size: 14px;
font-weight: 600;
color: var(--primary100);
}
.fields-table {
margin: 1rem 1rem 0rem 0rem;
border-collapse:collapse;
}
.add-field-button {
cursor:pointer;
}
.edit-button {
cursor:pointer;
color: var(--secondary25);
}
.edit-button:hover {
cursor:pointer;
color: var(--secondary75);
}
th {
text-align: left;
}
td {
padding: 1rem 5rem 1rem 0rem;
margin:0;
font-size: 14px;
font-weight: 500;
}
.field-label {
font-size: 14px;
font-weight: 500;
}
thead > tr {
border-width: 0px 0px 1px 0px;
border-style: solid;
border-color: var(--secondary75);
margin-bottom: 20px;
}
tbody > tr {
border-width: 0px 0px 1px 0px;
border-style: solid;
border-color: var(--primary10);
}
tbody > tr:hover {
background-color: var(--primary10);
}
tbody > tr:hover .edit-button {
color: var(--secondary75);
}
.index-container {
border-style: solid;
border-width: 0 0 1px 0;
border-color: var(--secondary25);
padding: 10px;
margin-bottom: 5px;
}
.index-label {
color: var(--slate);
}
.index-name {
font-weight: bold;
color: var(--primary100);
}
.index-container code {
margin: 0;
display: inline;
background-color: var(--primary10);
color: var(--secondary100);
padding:3px;
}
.index-field-row {
margin: 1rem 0rem 0rem 0rem;
}
.no-indexes {
margin: 1rem 0rem 0rem 0rem;
font-family: var(--fontnormal);
font-size: 14px;
}
</style>