223 lines
7.0 KiB
Svelte
223 lines
7.0 KiB
Svelte
<script>
|
|
import { get, post } from "../../../modules/remote";
|
|
import { uploadFile } from "../../../modules/upload";
|
|
import { getApp } from "../../../app";
|
|
import FieldLabel from "./FieldLabel.svelte";
|
|
import FieldError from "./FieldError.svelte";
|
|
import Sortable from "../../../common/Sortable.svelte";
|
|
let {
|
|
channel,
|
|
record,
|
|
schemaField,
|
|
dataField,
|
|
locale,
|
|
validationError,
|
|
edgeRecordPreviews,
|
|
filesPreviews,
|
|
} = $props();
|
|
let originalValue = dataField?.value ?? schemaField.props.default;
|
|
let newValue = $state(originalValue);
|
|
let valuesChanged = $derived(newValue !== originalValue);
|
|
let errorMessage = $state("");
|
|
|
|
let filesInProgress = $state([]);
|
|
let uploadInProgress = $derived(filesInProgress.length > 0);
|
|
// let validationErrorState = $state(validationError);
|
|
const app = getApp();
|
|
|
|
let suggestionsLoaded = $state(false);
|
|
let suggestions = $state([]);
|
|
let selectedFilesIds = $state([]);
|
|
let dialog = $state();
|
|
|
|
function handleModalOpen(e) {
|
|
// Add logic to handle adding a record
|
|
dialog.showModal();
|
|
if (suggestionsLoaded) {
|
|
return;
|
|
}
|
|
get(app.url("records/files"), { recordId: record.id }, (data, err) => {
|
|
suggestionsLoaded = true;
|
|
suggestions = data;
|
|
});
|
|
}
|
|
|
|
function handleModalClose(e) {
|
|
dialog.close();
|
|
}
|
|
|
|
function handleInsertSelected() {
|
|
suggestionsLoaded = false;
|
|
post(
|
|
app.url("records/files"),
|
|
{
|
|
toIds: selectedFilesIds,
|
|
from: record.id,
|
|
fieldId: schemaField.id,
|
|
locale: locale,
|
|
},
|
|
(data, err) => {
|
|
suggestionsLoaded = true;
|
|
dialog.close();
|
|
edgeRecordPreviews = data.edgeRecordPreviews;
|
|
validationError = data.validationError;
|
|
},
|
|
);
|
|
}
|
|
|
|
function handleSortUpdate(updatedEdges) {
|
|
// let updatedFieldIds = updatedFields.map((f) => f.id);
|
|
// fields = fields.filter((f) => !updatedFieldIds.includes(f.id));
|
|
// fields = [...fields, ...updatedFields];
|
|
post(
|
|
app.url("records/sort-edges"),
|
|
{
|
|
ids: updatedEdges.map((e) => e.edge.id),
|
|
},
|
|
(data, err) => {
|
|
edgeRecordPreviews = updatedEdges;
|
|
},
|
|
);
|
|
}
|
|
|
|
function handleRemoveEdge(edgeId) {
|
|
post(
|
|
app.url("edges/delete"),
|
|
{
|
|
id: edgeId,
|
|
from: record.id,
|
|
fieldId: schemaField.id,
|
|
locale: locale,
|
|
},
|
|
(data, err) => {
|
|
edgeRecordPreviews = edgeRecordPreviews.filter(
|
|
(e) => e.edge.id !== edgeId,
|
|
);
|
|
validationError = data.validationError;
|
|
},
|
|
);
|
|
}
|
|
|
|
function handleFilesUpload(e) {
|
|
let files = e.target.files ? [...e.target.files] : [];
|
|
|
|
let filesUploaded = files.map((file) => {
|
|
let fileInProgress = {
|
|
pct: 0,
|
|
hasFailed: false,
|
|
name: file.name,
|
|
};
|
|
filesInProgress.push(fileInProgress);
|
|
|
|
const progress = ({ pct, isComplete }) => {
|
|
filesInProgress.find((f) => f.name === file.name).pct = pct;
|
|
if (isComplete) {
|
|
filesInProgress = filesInProgress.filter(
|
|
(f) => f.name !== file.name,
|
|
);
|
|
}
|
|
};
|
|
const error = (errorMessage) => {
|
|
filesInProgress.find((f) => f.name === file.name).hasFailed =
|
|
true;
|
|
};
|
|
|
|
uploadFile(
|
|
file,
|
|
record.id,
|
|
schemaField.id,
|
|
locale,
|
|
progress,
|
|
error,
|
|
);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<div style="min-width: 400px;">
|
|
<label>
|
|
<FieldLabel {locale} {channel} {schemaField}></FieldLabel>
|
|
</label>
|
|
<FieldError {schemaField} {validationError}></FieldError>
|
|
<button onclick={handleModalOpen}>Choose files</button>
|
|
|
|
<dialog bind:this={dialog}>
|
|
<article>
|
|
<header>
|
|
<button onclick={handleModalClose} aria-label="Close" rel="prev"
|
|
></button>
|
|
<p>
|
|
<strong>Records</strong>
|
|
</p>
|
|
</header>
|
|
{#if suggestionsLoaded}
|
|
<form>
|
|
<button onclick={handleInsertSelected}>
|
|
Insert selected
|
|
</button>
|
|
|
|
<input
|
|
oninput={handleFilesUpload}
|
|
type="file"
|
|
multiple
|
|
disabled={uploadInProgress}
|
|
/>
|
|
{#each filesInProgress as fileInProgress}
|
|
<div>
|
|
<span>{fileInProgress.name}</span>
|
|
<progress value={fileInProgress.pct} max="100" />
|
|
{#if fileInProgress.hasFailed}
|
|
<span>Error</span>
|
|
{/if}
|
|
</div>
|
|
{/each}
|
|
|
|
<table>
|
|
<tbody>
|
|
{#each suggestions as suggestion}
|
|
<tr>
|
|
<td>
|
|
<input
|
|
type="checkbox"
|
|
value={suggestion.id}
|
|
bind:group={selectedFilesIds}
|
|
/>
|
|
</td>
|
|
<td>
|
|
<a href="#">{suggestion.name}</a>
|
|
</td>
|
|
<td> </td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
</form>
|
|
{:else}
|
|
<progress />
|
|
{/if}
|
|
</article>
|
|
</dialog>
|
|
<div>
|
|
{#if filesPreviews.length == 0}
|
|
No files exist
|
|
{:else}
|
|
<Sortable
|
|
onUpdate={handleSortUpdate}
|
|
items={filesPreviews}
|
|
itemKey="recordFile.id"
|
|
>
|
|
{#snippet itemView(filesPreview)}
|
|
<div>
|
|
<a href="#">{filesPreview.file.name}</a>
|
|
<button
|
|
onclick={(e) =>
|
|
handleRemoveEdge(filesPreview.recordFile.id)}
|
|
>remove</button
|
|
>
|
|
</div>
|
|
{/snippet}
|
|
</Sortable>
|
|
{/if}
|
|
</div>
|
|
</div>
|