refactor edit and edges

This commit is contained in:
2024-03-25 21:26:21 +02:00
parent e74e1e7956
commit 02224eb580
83 changed files with 3569 additions and 818 deletions
@@ -1,114 +0,0 @@
<script>
import {createEventDispatcher, getContext} from "svelte";
import Index from "../../content/Index.svelte";
const dispatch = createEventDispatcher();
const channel = getContext("channel");
$: data = {};
let isOpen = false;
let selectedRecords = [];
// onMount(() => {
// load();
// });
export function open(schema) {
isOpen = true;
load(schema);
}
export function close() {
isOpen = false;
selectedRecords = [];
}
function load(schema) {
axios
.get(channel.lucentUrl + "/content/" + schema)
.then((response) => {
data = response.data;
})
.catch((error) => console.log(error));
}
function insert(e) {
e.preventDefault();
dispatch("insert", {
records: selectedRecords,
action: "insert",
});
}
function replace(e) {
e.preventDefault();
dispatch("insert", {
records: selectedRecords,
action: "replace",
});
}
</script>
{#if data.schema}
<div
class="modal fade show"
tabindex="-1"
class:d-block={isOpen}
aria-modal="true"
role="dialog"
style="background: rgba(100,100,100,.6);"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div class="d-flex align-items-center">
<button
type="button"
class="btn btn-primary me-1"
on:click={insert}
disabled={selectedRecords.length === 0}
>
Insert
</button>
<button
type="button"
class="btn btn-outline-primary me-3"
on:click={replace}
disabled={selectedRecords.length === 0}
>
Replace
</button>
{#if selectedRecords.length > 0}
<span class="">
{selectedRecords.length} records selected
</span>
{/if}
</div>
<button
on:click|preventDefault={(e) => (isOpen = false)}
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
/>
</div>
<div class="modal-body">
<Index {...data} bind:selected={selectedRecords}/>
</div>
</div>
</div>
</div>
{/if}
<style>
.modal-dialog {
width: auto;
max-width: 100%;
}
.modal-content {
margin: 40px auto;
width: auto;
height: 100%;
}
</style>
@@ -1,56 +0,0 @@
<script>
import { getErrorMessage } from "./errorMessage";
export let id;
export let field;
export let value;
export let isCreateMode;
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
</script>
<div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
class:is-invalid={errorMessage}
bind:group={value}
id="{id}-1"
value={true}
disabled={field.readonly && !isCreateMode}
/>
<label class="form-check-label" for="{id}-1">Yes</label>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
id="{id}-2"
class:is-invalid={errorMessage}
bind:group={value}
value={false}
disabled={field.readonly && !isCreateMode}
/>
<label class="form-check-label" for="{id}-2">No</label>
</div>
{#if field.nullable}
<div class="form-check form-check-inline">
<input
class="form-check-input"
class:is-invalid={errorMessage}
id="{id}-3"
type="radio"
bind:group={value}
value={null}
disabled={field.readonly && !isCreateMode}
/>
<label class="form-check-label" for="{id}-3">Don't Know</label>
</div>
{/if}
</div>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
@@ -1,37 +0,0 @@
<script>
import { getErrorMessage } from "./errorMessage";
export let field;
export let value;
export let isCreateMode;
export let validationErrors;
export let id;
$: errorMessage = getErrorMessage(validationErrors, field.name);
</script>
<div class="mb-0">
<div class="input-group ">
<div style="width:64px;">
<input
type="color"
{id}
class="form-control form-control-color"
disabled={field.readonly && !isCreateMode}
bind:value
/>
</div>
<input
type="text"
class:is-invalid={errorMessage}
{id}
class="form-control"
bind:value
readonly={field.readonly && !isCreateMode}
/>
</div>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,70 +0,0 @@
<script>
import {getContext} from "svelte";
import {debounce} from "lodash";
import {previewTitle} from "../Preview";
const channel = getContext("channel");
export let field;
export let value;
export let search;
$: options = [];
export const update = debounce((e) => {
axios
.get("/records/suggestions", {
params: {
schema: field.optionsFrom,
field: field.optionsField,
value: search,
ui: field.ui,
},
})
.then((response) => {
options = response.data;
})
.catch((error) => {
console.log(error);
});
}, 500);
function select(e, option) {
e.preventDefault();
value = option.data[field.optionsField];
search = "";
}
</script>
{#if field.optionsFrom}
{#each options as option (option.id)}
<div
on:click={(e) => select(e, option)}
on:keypress={(e) => select(e, option)}
>
<span class="dropdown-item">
{previewTitle(channel.schemas, option)}
<small class="text-muted "
>{option.data[field.optionsField]}</small
>
</span>
</div>
{:else}
{#if search && field.optionsSuggest}
<div
on:click={(e) => {
value = search;
search = "";
}}
on:keypress={(e) => {
value = search;
search = "";
}}
>
<span class="dropdown-item">
Add "{search}"
</span>
</div>
{:else}
No results
{/if}
{/each}
{/if}
@@ -1,112 +0,0 @@
<script>
import Datalist from "./Datalist.svelte";
import {onMount} from "svelte";
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.css";
import "flatpickr/dist/themes/light.css";
import {getErrorMessage} from "./errorMessage";
import Icon from "../../common/Icon.svelte";
export let field;
export let value;
export let id;
export let isCreateMode;
export let validationErrors;
$: search = "";
$: listMode = field.optionsFrom && !(field.readonly && !isCreateMode);
$: errorMessage = getErrorMessage(validationErrors, field.name);
let list;
let pickerInput;
let pickerInstance;
let flatpickrOptions = {
enableTime: false,
allowInput: true,
dateFormat: "Y-m-d",
};
if (field.min) {
flatpickrOptions.minDate = field.min;
}
if (field.max) {
flatpickrOptions.maxDate = field.max;
}
onMount(() => {
if (!field.readonly || isCreateMode) {
if (listMode) {
flatpickrOptions.clickOpens = false;
}
pickerInstance = flatpickr(pickerInput, flatpickrOptions);
}
});
</script>
<div class="mb-0">
{#if listMode}
<div class="dropdown d-flex">
<input
type="search"
{id}
on:keyup={list.update}
on:focus={list.update}
class="form-control dropdown-toggle"
class:is-invalid={errorMessage}
bind:value={search}
bind:this={pickerInput}
placeholder="Search for options"
data-bs-toggle="dropdown"
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
<button
class="btn btn-light ms-1"
on:click|preventDefault={(e) => pickerInstance.open()}
>
<Icon icon="calendar"/>
</button>
<ul class="dropdown-menu w-100">
{#if field.optionsFrom}
<Datalist
{field}
bind:this={list}
bind:value
bind:search
/>
{/if}
</ul>
</div>
{#if value}
<span class="badge rounded-pill bg-light text-dark fs-6 mt-3">
<div class="d-flex align-items-center ">
{value}
<button
on:click|preventDefault={(e) => (value = "")}
type="button"
class="btn-close btn-sm ms-1"
style="font-size:10px"
aria-label="Close"
/>
</div>
</span>
{/if}
{:else}
<input
type="text"
{id}
class="form-control"
class:is-invalid={errorMessage}
bind:value
bind:this={pickerInput}
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
{/if}
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,121 +0,0 @@
<script>
import Datalist from "./Datalist.svelte";
import {onMount} from "svelte";
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.css";
import "flatpickr/dist/themes/light.css";
import {getErrorMessage} from "./errorMessage";
import Icon from "../../common/Icon.svelte";
export let field;
export let value;
export let isCreateMode;
export let validationErrors;
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
$: search = "";
$: listMode = field.optionsFrom && !(field.readonly && !isCreateMode);
$: errorMessage = getErrorMessage(validationErrors, field.name);
export let id;
let list;
let pickerInput;
let pickerInstance;
let flatpickrOptions = {
enableTime: false,
allowInput: true,
altInput: true,
altFormat: "Y-m-d H:i:S",
dateFormat: "Z",
enableTime: true,
time_24hr: true,
enableSeconds: true,
};
if (field.min) {
flatpickrOptions.minDate = field.min;
}
if (field.max) {
flatpickrOptions.maxDate = field.max;
}
onMount(() => {
if (!field.readonly || isCreateMode) {
if (listMode) {
flatpickrOptions.clickOpens = false;
}
pickerInstance = flatpickr(pickerInput, flatpickrOptions);
}
});
</script>
<div class="mb-0">
{#if listMode}
<div class="dropdown d-flex">
<input
type="search"
{id}
on:keyup={list.update}
on:focus={list.update}
class="form-control dropdown-toggle"
class:is-invalid={errorMessage}
bind:value={search}
bind:this={pickerInput}
placeholder="Search for options"
data-bs-toggle="dropdown"
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
<button
class="btn btn-light ms-1"
on:click|preventDefault={(e) => pickerInstance.open()}
>
<Icon icon="calendar"/>
</button>
<ul class="dropdown-menu w-100">
{#if field.optionsFrom}
<Datalist
{field}
bind:this={list}
bind:value
bind:search
/>
{/if}
</ul>
</div>
{#if value}
<span class="badge rounded-pill bg-light text-dark fs-6 mt-3">
<div class="d-flex align-items-center ">
{value}
<button
on:click|preventDefault={(e) => (value = "")}
type="button"
class="btn-close btn-sm ms-1"
style="font-size:10px"
aria-label="Close"
/>
</div>
</span>
{/if}
{:else}
<input
type="text"
{id}
class="form-control"
class:is-invalid={errorMessage}
bind:value
bind:this={pickerInput}
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
{/if}
<small class=" text-primary opacity-50"
>Dates are displayed according to your timezone: {timezone}</small
>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,22 +0,0 @@
<script>
export let field;
export let id;
</script>
<div class="mb-1">
<div class="d-flex justify-content-between">
<div>
<label for={id} class="form-label"
>{field.label}</label
>
{#if field.help}
<small class=" text-primary opacity-50">{field.help}</small>
{/if}
</div>
<span
tabindex="-1"
class="text-decoration-none"
><code class="text-primary opacity-50">{field.name}</code>
</span>
</div>
</div>
@@ -1,122 +0,0 @@
<script>
import {getContext} from "svelte";
import {uniqBy} from "lodash";
import {sortByField} from "../../edges/sortEdges";
import PreviewCard from "../PreviewCard.svelte";
import Sortable from "../../libs/Sortable.svelte";
import BrowseModal from "./BrowseModal.svelte";
import Preview from "../../newPreview/Preview.svelte";
const channel = getContext("channel");
export let field;
export let record;
export let graph
let browseModal;
$: currentReferences = graph._children[field.name] ?? [];
let collections = channel.schemas.filter((aschema) =>
field.collections.includes(aschema.name)
);
function removeReference(e) {
e.preventDefault();
// graph.edges = graph.edges.filter(
// (edge) => !(edge.target === e.detail && edge.field === field.name)
// );
}
function openBrowseModal(e, schema) {
e.preventDefault();
browseModal.open(schema);
}
async function reorder(e) {
// graph.edges = await sortByField(e.detail.source, e.detail.target, graph.edges, field.name);
}
function insert(e) {
e.preventDefault();
browseModal.close();
const recordsToInsert = e.detail.records;
console.log({recordsToInsert})
const action = e.detail.action;
let newEdges = recordsToInsert.map((r) => {
return {
target: r.id,
source: record.id,
sourceSchema: record.schema,
targetSchema: r.schema,
field: field.name,
rank: ""
};
});
let replacedEdges = graph.edges ?? [];
if (action === "replace") {
replacedEdges = replacedEdges.filter((e) => e.field !== field.name);
}
// graph.records = uniqBy([...graph.records, ...recordsToInsert], (r) => r.id);
// graph.edges = uniqBy([...replacedEdges, ...newEdges], (e) => e.target + e.field);
}
</script>
<div class="mb-0">
{#if field.collections.length === 1}
<button
class="btn btn-outline-primary"
on:click={(e) => openBrowseModal(e, collections[0].name)}
>
Browse
</button>
{:else}
<div class="dropdown d-inline-block">
<button
class="btn btn-outline-primary btn-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
Browse
</button>
<ul class="dropdown-menu">
{#each collections as collection}
<li>
<!-- {`${channelurl}/content/${collection.name}?parent=${record.id}&parentfield=${field.name}`} -->
<a
class="dropdown-item"
on:click={(e) =>
openBrowseModal(e, collection.name)}
href="/">{collection.label}</a
>
</li>
{/each}
</ul>
</div>
{/if}
</div>
{#if currentReferences.length > 0}
<Sortable sortableClass="row row-cols-3 mt-3" on:update={reorder}>
{#each currentReferences as reference (reference.record.id)}
<div class="col mb-3">
<PreviewCard
classes="h-100"
record={reference.record}
hasDelete={true}
on:remove={removeReference}
/>
<!-- <Preview-->
<!-- classes="h-100"-->
<!-- record={reference.record}-->
<!-- edge={reference.edge}-->
<!-- hasDelete={true}-->
<!-- {field}-->
<!-- on:remove={removeReference}-->
<!-- />-->
</div>
{/each}
</Sortable>
{/if}
<BrowseModal bind:this={browseModal} on:insert={insert}/>
@@ -1,24 +0,0 @@
<script>
import Codemirror from "../../libs/Codemirror.svelte";
import { getErrorMessage } from "./errorMessage";
export let value;
export let field;
export let isCreateMode;
// export let id;
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
</script>
<div class="mb-3">
<Codemirror bind:value editable={!field.readonly || isCreateMode} />
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,24 +0,0 @@
<script>
import Codemirror from "../../libs/CodemirrorMarkdown.svelte";
import { getErrorMessage } from "./errorMessage";
export let value;
export let field;
export let isCreateMode;
// export let id;
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
</script>
<div class="mb-3">
<Codemirror bind:value editable={!field.readonly || isCreateMode} />
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,92 +0,0 @@
<script>
import Datalist from "./Datalist.svelte";
import {getErrorMessage} from "./errorMessage";
export let field;
export let value;
export let schemas;
export let validationErrors;
export let isCreateMode;
export let id;
$: search = "";
$: errorMessage = getErrorMessage(validationErrors, field.name);
let list;
function fixDecimals(e) {
const number = e.currentTarget.value;
const formattedNumber = formatNumber(number);
value = isNaN(formattedNumber) ? null : formattedNumber;
}
function formatNumber(number) {
return parseFloat(number).toFixed(field.decimals);
}
$: listMode = field.optionsFrom && !(field.readonly && !isCreateMode);
</script>
<div class="mb-0">
{#if listMode}
<div class="dropdown">
<input
type="number"
{id}
on:keyup={list.update}
on:focus={list.update}
bind:value={search}
placeholder="Search for options"
class="form-control dropdown-toggle"
class:is-invalid={errorMessage}
data-bs-toggle="dropdown"
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
<ul class="dropdown-menu w-100">
{#if field.optionsFrom}
<Datalist
{field}
bind:this={list}
{schemas}
bind:value
bind:search
/>
{/if}
</ul>
</div>
{#if value}
<span class="badge rounded-pill bg-light text-dark fs-6 mt-3">
<div class="d-flex align-items-center ">
{value}
<button
on:click|preventDefault={(e) => (value = "")}
type="button"
class="btn-close btn-sm ms-1"
style="font-size:10px"
aria-label="Close"
/>
</div>
</span>
{/if}
{:else}
<input
type="number"
{id}
class="form-control"
class:is-invalid={errorMessage}
on:change={fixDecimals}
bind:value
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
{/if}
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,8 +1,8 @@
<script>
import {getContext} from "svelte";
import {insertEdges} from "./reference";
import {insertEdges} from "../form/references/reference.js";
import PreviewCard from "../PreviewCard.svelte";
import {getErrorMessage} from "./errorMessage";
import {getErrorMessage} from "../form/errorMessage.js";
import {sortByField} from "../../edges/sortEdges";
import ReferenceInlineButtons from "./ReferenceInlineButtons.svelte";
import Sortable from "../../libs/Sortable.svelte";
@@ -2,7 +2,7 @@
import {getContext} from "svelte";
import {uniqBy} from "lodash";
import PreviewCardInline from "../PreviewCardInline.svelte";
import {getErrorMessage} from "./errorMessage";
import {getErrorMessage} from "../form/errorMessage.js";
import {sortByField} from "../../edges/sortEdges";
import ReferenceInlineButtons from "./ReferenceInlineButtons.svelte";
import {flip} from "svelte/animate";
@@ -2,7 +2,7 @@
import {createEventDispatcher, getContext} from "svelte";
import Icon from "../../common/Icon.svelte";
import InlineEdit from "../InlineEdit.svelte";
import BrowseModal from "./BrowseModal.svelte";
import BrowseModal from "../form/references/BrowseModal.svelte";
const dispatch = createEventDispatcher();
// export let field;
@@ -1,13 +1,13 @@
<script>
import {getContext} from "svelte";
import {previewTitle} from "../Preview";
import {getErrorMessage} from "./errorMessage";
import {getErrorMessage} from "../form/errorMessage.js";
import {sortByField} from "../../edges/sortEdges";
import ReferenceInlineButtons from "./ReferenceInlineButtons.svelte";
import Sortable from "../../libs/Sortable.svelte";
import RenderField from "../../content/RenderField.svelte";
import Icon from "../../common/Icon.svelte";
import {insertEdges} from "./reference.js";
import {insertEdges} from "../form/references/reference.js";
const channel = getContext("channel");
export let field;
@@ -1,161 +0,0 @@
<script>
import {getContext} from "svelte";
import {uniqBy, debounce} from "lodash";
import {previewTitle} from "../Preview";
import {getErrorMessage} from "./errorMessage";
import {sortByField} from "../../edges/sortEdges";
import ReferenceInlineButtons from "./ReferenceInlineButtons.svelte";
import Sortable from "../../libs/Sortable.svelte";
import RenderField from "../../content/RenderField.svelte";
import Icon from "../../common/Icon.svelte";
import Datalist from "./Datalist.svelte";
import {insertEdges} from "./reference.js";
const channel = getContext("channel");
export let field;
export let id;
export let record;
export let graph;
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
$: references = graph.edges
.filter((edge) => edge.field === field.name)
.map((edge) => {
return graph.records.find((increc) => increc.id == edge.target && record.id == edge.source);
}).filter((rec) => (rec?.id ? true : false)) ?? [];
let search = ""
$: searchOptions = []
function removeReference(e, recordId) {
e.preventDefault();
graph.edges = graph.edges.filter(
(edge) => !(edge.target === recordId && edge.field === field.name)
);
}
function saveNew(e, newValue) {
e.preventDefault();
axios
.post(channel.lucentUrl + "/records", {
isCreateMode: true,
record: {
schema: field.collections[0],
status: "published",
data: {
[field.searchField]: newValue
}
},
})
.then((response) => {
searchOptions = [];
insert(e,response.data.records[0]);
console.log(response)
})
.catch((error) => {
searchOptions = [];
console.log(error);
});
}
function insert(e, insertRecord) {
e.preventDefault();
graph = insertEdges(graph,record,[insertRecord],field.name,e.detail.action);
}
const updateResults = debounce((e) => {
axios
.get(channel.lucentUrl + "/records/suggestions", {
params: {
schema: field.collections[0],
field: field.searchField,
value: search,
ui: "text",
},
})
.then((response) => {
searchOptions = response.data;
})
.catch((error) => {
searchOptions = [];
console.log(error);
});
}, 500);
</script>
{#if errorMessage}
<div class="invalid-feedback d-block mb-3">
{errorMessage}
</div>
{/if}
<input
type="search"
{id}
on:keyup={updateResults}
class="form-control dropdown-toggle"
class:is-invalid={errorMessage}
bind:value={search}
placeholder={"Search for "+field.label}
data-bs-toggle="dropdown"
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
<div class="dropdown-menu w-100">
{#if searchOptions}
{#each searchOptions as option (option.id)}
<div
on:click={(e) => insert(e, option)}
on:keypress={(e) => insert(e, option)}
>
<span class="dropdown-item">
{previewTitle(channel.schemas, option)}
</span>
</div>
{:else}
Start typing...
{/each}
{/if}
{#if search }
<div
on:click={(e) => saveNew(e,search)}
on:keypress={(e) => saveNew(e,search)}
>
<span class="dropdown-item">
Add "{search}"
</span>
</div>
{/if}
</div>
{#if references.length > 0}
<div class="d-flex">
{#each references as record (record.id)}
<span class="badge rounded-pill bg-light text-dark fs-6 mt-3">
<div class="d-flex align-items-center ">
{previewTitle(channel.schemas, record)}
<button
on:click|preventDefault={(e) => removeReference(e, record.id)}
type="button"
class="btn-close btn-sm ms-1"
style="font-size:10px"
aria-label="Close"
/>
</div>
</span>
{/each}
</div>
{/if}
@@ -1,24 +0,0 @@
<script>
import Tinymce from "../../libs/Tinymce.svelte";
import {getErrorMessage} from "./errorMessage";
export let value;
export let field;
export let isCreateMode;
export let schema;
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
let additionalConfig = {
readonly: field.readonly && !isCreateMode,
};
</script>
<div class="mb-0">
<Tinymce bind:value {additionalConfig} {schema}/>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,39 +0,0 @@
<script>
export let field;
export let value;
export let search;
function select(e, option) {
e.preventDefault();
value = option;
search = "";
}
</script>
{#if field.selectOptions}
{#if Array.isArray(field.selectOptions)}
{#each field.selectOptions as suggestion (suggestion)}
<div
on:click={(e) => select(e, suggestion)}
on:keypress={(e) => select(e, suggestion)}
>
<span class="dropdown-item">
{suggestion}
</span>
</div>
{/each}
{:else}
{#each Object.entries(field.selectOptions) as [k, v] (k)}
<div
on:click={(e) => select(e, k)}
on:keypress={(e) => select(e, k)}
>
<span class="dropdown-item">
{v}
</span>
</div>
{/each}
{/if}
{/if}
@@ -1,30 +0,0 @@
<script>
import { getErrorMessage } from "./errorMessage";
export let field;
export let value;
export let isCreateMode;
export let validationErrors;
let thisEl;
$: errorMessage = getErrorMessage(validationErrors, field.name);
export let id;
</script>
<div class="mb-0">
<input
type="text"
{id}
class="form-control"
class:is-invalid={errorMessage}
bind:value
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,122 +0,0 @@
<script>
import Datalist from "./Datalist.svelte";
import Selectlist from "./Selectlist.svelte";
import {getErrorMessage} from "./errorMessage";
export let field;
export let value;
export let isCreateMode;
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
$: search = "";
export let id;
let list;
$: listMode = field.optionsFrom && !(field.readonly && !isCreateMode);
</script>
<div class="mb-0">
{#if listMode}
<div class="dropdown">
<input
type="search"
{id}
on:keyup={list.update}
on:focus={list.update}
class="form-control dropdown-toggle"
class:is-invalid={errorMessage}
bind:value={search}
placeholder="Search for options"
data-bs-toggle="dropdown"
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
<div class="dropdown-menu w-100">
{#if field.optionsFrom}
<Datalist
{field}
bind:this={list}
bind:value
bind:search
/>
{/if}
</div>
</div>
{#if value}
<span class="badge rounded-pill bg-light text-dark fs-6 mt-3">
<div class="d-flex align-items-center ">
{value}
<button
on:click|preventDefault={(e) => (value = "")}
type="button"
class="btn-close btn-sm ms-1"
style="font-size:10px"
aria-label="Close"
/>
</div>
</span>
{/if}
{:else if field.selectOptions}
<div class="dropdown">
<input
type="search"
{id}
class="form-control dropdown-toggle"
class:is-invalid={errorMessage}
bind:value={search}
placeholder="Search for options"
data-bs-toggle="dropdown"
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
<div class="dropdown-menu w-100">
<Selectlist
{field}
bind:value
bind:search
/>
</div>
</div>
{#if value}
<span class="badge rounded-pill bg-light text-dark fs-6 mt-3">
<div class="d-flex align-items-center ">
{#if Array.isArray(field.selectOptions)}
{value}
{:else}
{field.selectOptions[value]}
{/if}
<button
on:click|preventDefault={(e) => (value = "")}
type="button"
class="btn-close btn-sm ms-1"
style="font-size:10px"
aria-label="Close"
/>
</div>
</span>
{/if}
{:else}
<input
type="text"
{id}
class="form-control"
class:is-invalid={errorMessage}
bind:value
autocomplete="off"
readonly={field.readonly && !isCreateMode}
/>
{/if}
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,53 +0,0 @@
<script>
import { onMount } from "svelte";
import { getErrorMessage } from "./errorMessage";
export let field;
export let value;
export let isCreateMode;
export let validationErrors;
let thisEl;
$: errorMessage = getErrorMessage(validationErrors, field.name);
export let id;
function resize(e) {
let el;
if (e.target) {
el = e.target;
} else {
el = e;
}
el.style.overflow = "hidden";
el.style.height = "1px";
el.style.height = +el.scrollHeight + "px";
}
onMount(() => {
resize(thisEl);
});
</script>
<div class="mb-0">
<textarea
bind:value
bind:this={thisEl}
{id}
class="form-control"
on:input={resize}
on:focus={resize}
rows="2"
class:is-invalid={errorMessage}
readonly={field.readonly && !isCreateMode}
/>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
<style>
textarea {
resize: none;
}
</style>
@@ -1,49 +0,0 @@
<script>
import { v4 as uuidv4 } from "uuid";
import { getContext } from "svelte";
import Icon from "../../common/Icon.svelte";
import { getErrorMessage } from "./errorMessage";
const channelurl = getContext("channelurl");
export let validationErrors;
$: errorMessage = getErrorMessage(validationErrors, field.name);
export let field;
export let value;
export let id;
export let isCreateMode;
let readonly = field.readonly && !isCreateMode;
function generateId(e) {
e.preventDefault();
value = uuidv4();
}
</script>
<div class="mb-0">
<div class="d-flex justify-content-between">
<input
type="text"
{id}
class="form-control"
class:is-invalid={errorMessage}
bind:value
autocomplete="off"
{readonly}
/>
{#if !readonly}
<button
class="btn btn-primary ms-2"
title="Generate a new UUIDv4"
on:click={generateId}
>
<Icon icon="dice" />
</button>
{/if}
</div>
{#if errorMessage}
<div class="invalid-feedback d-block">
{errorMessage}
</div>
{/if}
</div>
@@ -1,30 +0,0 @@
<script>
import { uniqueId } from "lodash";
import { getContext } from "svelte";
const channelurl = getContext("channelurl");
export let field;
export let value;
export let schema;
let id = uniqueId();
</script>
<div class="mb-0">
<div class="d-flex justify-content-between">
<label for={id} class="form-label">{field.label}</label>
<a
class="text-decoration-none"
href="{channelurl}/schemas/{schema.name}/fields/edit/{field.name}"
><code class="text-primary opacity-50">{field.name}</code></a
>
</div>
<input
type="url"
{id}
class="form-control"
bind:value
placeholder="https://www.example.com"
/>
{#if field.help}
<small class=" text-primary opacity-50">{field.help}</small>
{/if}
</div>
@@ -1,3 +0,0 @@
export function getErrorMessage(validationErrors, fieldName) {
return validationErrors?.find((e) => e.fieldName === fieldName)?.message;
}
@@ -1,24 +0,0 @@
import {uniqBy} from "lodash";
export function insertEdges(graph, sourceRecord, targetRecords, fieldName, action = "") {
let newEdges = targetRecords.map((r) => {
return {
target: r.id,
source: sourceRecord.id,
sourceSchema: sourceRecord.schema,
targetSchema: r.schema,
field: fieldName,
depth: 1,
rank: ""
};
});
let replacedEdges = graph.edges;
if (action === "replace") {
replacedEdges = replacedEdges.filter((edge) => edge.field !== field.name);
}
graph.records = uniqBy([...graph.records, ...targetRecords], (r) => r.id);
graph.edges = uniqBy([...replacedEdges, ...newEdges], (edge) => edge.source + edge.target + edge.field + edge.depth);
return graph;
}