WIP uploading files

This commit is contained in:
2026-04-29 19:40:37 +03:00
parent e058ceadee
commit bd01e5c32c
15 changed files with 506 additions and 362 deletions
+49 -66
View File
@@ -4,7 +4,7 @@
import Icon from "../../common/Icon.svelte";
import SortFields from "./SortFields.svelte";
import AppliedFilter from "./AppliedFilter.svelte";
import {createEventDispatcher, getContext} from "svelte";
import { createEventDispatcher, getContext } from "svelte";
import Dropdown from "../../common/Dropdown.svelte";
import AppliedFilterNotLinked from "./AppliedFilterNotLinked.svelte";
@@ -41,7 +41,6 @@
} else {
window.location = url;
}
}
function uploadComplete(e) {
@@ -51,110 +50,94 @@
<div class="toolbar">
<div class="toolbar-filters">
<SortFields
{schema}
{sortParam}
{sortField}
{systemFields}
{inModal}
{modalUrl}
on:refresh
{schema}
{sortParam}
{sortField}
{systemFields}
{inModal}
{modalUrl}
on:refresh
/>
<FilterFields
bind:schema
{systemFields}
{operators}
{filter}
{inModal}
{modalUrl}
on:refresh
bind:schema
{systemFields}
{operators}
{filter}
{inModal}
{modalUrl}
on:refresh
/>
<form method="GET" on:submit={search}>
<input type="search" name="filter[search_regex]" placeholder="Search"
class="search" required>
<input
type="search"
name="filter[search_regex]"
placeholder="Search"
class="search"
required
/>
</form>
</div>
<div style="display:flex;align-items: center;gap:4px">
{#if schema.type === "collection"}
{#if !inModal && isWritable}
<a
href="{channel.lucentUrl}/records/new?schema={schema.name}"
class="button"
>
New Record
</a>
{/if}
{:else }
<div>
<Uploader {schema} on:uploadComplete={uploadComplete}/>
</div>
{#if !inModal && isWritable}
<a
href="{channel.lucentUrl}/records/new?schema={schema.name}"
class="button"
>
New Record
</a>
{/if}
{#if !inModal}
<Dropdown orientation="right">
<div slot="button">
<Icon icon="ellipsis-vertical"/>
<Icon icon="ellipsis-vertical" />
</div>
{#if filter["status_in"] === "trashed"}
{#if isWritable}
<a
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}/emptyTrash"
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}/emptyTrash"
>
Empty trash
</a>
{/if}
{:else}
<a class="dropdown-item" href={csvUrl}>Export to CSV</a>
<a
class="dropdown-item"
href={csvUrl}
>Export to CSV</a
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}?filter[status_in]=trashed"
>View trashed records</a
>
<a
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}?filter[status_in]=trashed"
>View trashed records</a
>
<a
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}?notlinked=*"
>View unlinked records</a
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}?notlinked=*"
>View unlinked records</a
>
{/if}
</Dropdown>
{/if}
</div>
</div>
<div class="applied-filters">
<AppliedFilterNotLinked
{inModal}
{modalUrl}
on:refresh
<AppliedFilterNotLinked {inModal} {modalUrl} on:refresh
></AppliedFilterNotLinked>
{#if Object.entries(filter).length > 0}
{#each Object.entries(filter) as [k, v]}
<AppliedFilter
{schema}
{operators}
key={k}
value={v}
{inModal}
{modalUrl}
{graph}
on:refresh
{schema}
{operators}
key={k}
value={v}
{inModal}
{modalUrl}
{graph}
on:refresh
/>
{/each}
{/if}
</div>
+97
View File
@@ -0,0 +1,97 @@
<script>
import { createEventDispatcher, getContext } from "svelte";
import Icon from "../common/Icon.svelte";
import Index from "../content/Index.svelte";
import axios from "axios";
let dialogEl;
const dispatch = createEventDispatcher();
const channel = getContext("channel");
$: data = {};
let selectedRecords = [];
// onMount(() => {
// load();
// });
export function close(e) {
if (e) {
e.preventDefault();
}
dialogEl.close();
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",
schema: data.schema.name,
});
}
function replace(e) {
e.preventDefault();
dispatch("insert", {
records: selectedRecords,
action: "replace",
});
}
export function open(schema) {
dialogEl.showModal();
load(schema);
}
</script>
<dialog bind:this={dialogEl}>
{#if data.schema}
<div class="dialog-header">
<button
type="button"
class="button"
on:click={insert}
disabled={selectedRecords.length === 0}
>
Insert
</button>
<button
type="button"
class="button"
on:click={replace}
disabled={selectedRecords.length === 0}
>
Replace
</button>
{#if selectedRecords.length > 0}
<span class="">
{selectedRecords.length} records selected
</span>
{/if}
<button
on:click|preventDefault={close}
type="button"
class="button close"
aria-label="Close"
>
<Icon icon="close"></Icon>
</button>
</div>
<div class="dialog-body">
<Index {...data} bind:selected={selectedRecords}></Index>
</div>
{/if}
</dialog>
+25 -21
View File
@@ -1,10 +1,10 @@
<script>
import {createEventDispatcher, getContext} from "svelte";
import { createEventDispatcher, getContext } from "svelte";
const dispatch = createEventDispatcher();
const channel = getContext("channel");
export let schema;
export let recordId;
let mimeTypes = "";
let files = [];
let isLoading = false;
@@ -17,39 +17,43 @@
files = e.target.files ? [...e.target.files] : [];
let formData = new FormData();
formData.append("schema", schema.name);
formData.append("recordId", recordId);
Array.from(files).forEach(function (file) {
formData.append("files[]", file);
});
dispatch("beforeUpload", files);
axios
.post(channel.lucentUrl + "/files/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((response) => {
if (response.data.error) {
dispatch("uploadError", response.data.error);
fetch(channel.lucentUrl + "/files/upload", {
method: "POST",
body: formData,
headers: {
"X-CSRF-TOKEN": document.querySelector(
'meta[name="csrf-token"]',
).content,
},
})
.then((response) => response.json())
.then((data) => {
if (data.error) {
dispatch("uploadError", data.error);
} else {
dispatch("uploadComplete", response.data);
dispatch("uploadComplete", data);
}
isLoading = false;
})
.catch((error) => {
isLoading = false;
console.log(error.response.data);
console.log(error);
});
}
</script>
<fieldset class="upload-button" disabled={isLoading}>
<label class="button primary btn-spinner ">
<span
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
<fieldset class="upload-button" disabled={isLoading}>
<label class="button primary btn-spinner">
<span
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
Upload file
<input
+44 -45
View File
@@ -1,31 +1,24 @@
<script>
import {sortByField} from "../../edges/sortEdges";
import { sortByField } from "../../edges/sortEdges";
import Sortable from "../../libs/Sortable.svelte";
import PreviewFile from "../previews/PreviewFile.svelte";
import Dropdown from "../../common/Dropdown.svelte";
import Dialog from "../../dialog/Dialog.svelte";
import {insertEdges} from "./reference.js";
import {getContext} from "svelte";
import { insertEdges } from "./reference.js";
import { getContext } from "svelte";
import FileDialog from "../../dialog/FileDialog.svelte";
import Uploader from "../../files/Uploader.svelte";
const channel = getContext("channel");
export let field;
export let record;
export let graph
export let graph;
let browseModal;
$: 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 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)
(edge) => !(edge.target === e.detail && edge.field === field.name),
);
}
@@ -35,50 +28,56 @@
}
async function reorder(e) {
graph.edges = await sortByField(e.detail.source, e.detail.target, graph.edges, field.name, references);
graph.edges = await sortByField(
e.detail.source,
e.detail.target,
graph.edges,
field.name,
references,
);
}
function insert(e) {
e.preventDefault();
browseModal.close();
graph = insertEdges(graph, record, e.detail.records, field.name, e.detail.action);
graph = insertEdges(
graph,
record,
e.detail.records,
field.name,
e.detail.action,
);
}
function uploadComplete(e) {
records = e.detail;
}
</script>
<div class="mb-0">
{#if field.collections.length === 1}
<button
class="button"
on:click={(e) => openBrowseModal(e, collections[0].name)}
>
Browse
</button>
{:else}
<Dropdown>
<div slot="button">
Browse
</div>
{#each collections as collection}
<!-- {`${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
>
{/each}
</Dropdown>
{/if}
<!-- <button
class="button"
on:click={(e) => openFileModal(e, collections[0].name)}
>
Browse
</button> -->
<div>
<Uploader recordId={record.id} on:uploadComplete={uploadComplete} />
</div>
</div>
{#if references.length > 0}
<!-- {#if references.length > 0}
<Sortable sortableClass="mt-3" on:update={reorder}>
{#each references as reference (reference.id)}
<!--This div helps the sorting thing-->
<div>
<PreviewFile record={reference} hasDelete={true} on:remove={removeReference}></PreviewFile>
<!-- <div>
<PreviewFile
record={reference}
hasDelete={true}
on:remove={removeReference}
></PreviewFile>
</div>
{/each}
</Sortable>
{/if}
<Dialog bind:this={browseModal} on:insert={insert}></Dialog>
{/if} -->
<!-- <FileDialog bind:this={browseModal} on:insert={insert}></FileDialog> -->