This commit is contained in:
2023-10-02 23:10:49 +03:00
commit c6cb488379
255 changed files with 18731 additions and 0 deletions
@@ -0,0 +1,83 @@
<script>
import {getContext} from "svelte";
const channel = getContext("channel");
export let selected;
export let schema;
export let filter;
function deleteRecords(e) {
e.preventDefault();
axios
.post(channel.lucentUrl + "/records/delete", {
ids: selected.map((s) => s.id),
})
.then((response) => {
window.location.reload();
})
.catch((error) => {
console.log(error);
});
}
function changeStatus(e, status) {
axios
.post(channel.lucentUrl + "/records/status/" + status, {
schemaName: schema.name,
records: selected
})
.then((response) => {
window.location.reload();
})
.catch((error) => {
console.log(error);
});
}
</script>
<div class="d-flex align-items-center mb-3">
<span class="me-2">{selected.length} records selected</span>
<div class="btn-group " role="group" aria-label="Basic example">
<button
on:click|preventDefault={(e) => changeStatus(e, "published")}
type="button"
class="btn btn-sm btn-outline-primary">Publish
</button
>
<button
on:click|preventDefault={(e) => changeStatus(e, "draft")}
type="button"
class="btn btn-sm btn-outline-primary">Make Draft
</button
>
{#if filter["_sys.status_in"] === "trashed"}
<button
on:click|preventDefault={(e) => changeStatus(e, "published")}
type="button"
class="btn btn-sm btn-outline-primary">Publish
</button
>
{#if schema.hasDrafts}
<button
on:click|preventDefault={(e) => changeStatus(e, "draft")}
type="button"
class="btn btn-sm btn-outline-primary">Make Draft
</button
>
{/if}
<button
on:click|preventDefault={deleteRecords}
type="button"
class="btn btn-sm btn-outline-primary">Delete forever
</button
>
{:else}
<button
type="button"
on:click|preventDefault={(e) => changeStatus(e, "trashed")}
class="btn btn-sm btn-outline-primary">Move to trash
</button
>
{/if}
</div>
</div>
+152
View File
@@ -0,0 +1,152 @@
<script>
import Tools from "./tools/Tools.svelte";
import Pagination from "./pagination/Pagination.svelte";
import ActionsOnSelected from "./ActionsOnSelected.svelte";
import Preview from "../files/Preview.svelte";
import Table from "./Table.svelte";
import {getContext} from "svelte";
const channel = getContext("channel");
export let title;
export let schema;
export let users;
export let records;
export let graph;
export let visibleFields;
export let systemFields;
export let sort;
export let operators;
export let filter;
export let limit;
export let skip;
export let total;
export let inModal;
export let modalUrl;
export let selected = [];
function selectRecord(e, record) {
let recordExists = selected.find((r) => r.id === record.id);
if (recordExists) {
selected = selected.filter((r) => r.id !== record.id);
} else {
selected = [...selected, record];
}
}
function refresh(e) {
const newUrl = e.detail;
axios
.get(newUrl)
.then((response) => {
records = response.data.records;
sort = response.data.sort;
operators = response.data.operators;
filter = response.data.filter;
skip = response.data.skip;
limit = response.data.limit;
total = response.data.total;
modalUrl = response.data.modalUrl;
})
.catch((error) => {
console.log(error);
});
}
</script>
<div class="wrapper-large transparent ">
<!-- <Manager managerRecords={recordHistory} {schemas} /> -->
<div class="lx-card mb-4 {inModal ? 'mt-0' : 'mt-5'}">
<h3 class="header-normal mb-5 ">
{schema.label}
</h3>
{#if selected.length > 0 && !inModal}
<ActionsOnSelected {schema} {selected} {inModal} {filter}/>
{:else}
<Tools
bind:schema
bind:records
{systemFields}
{sort}
{operators}
{filter}
{inModal}
{modalUrl}
on:refresh={refresh}
/>
{/if}
{#if schema.type === "collection"}
<Table
{records}
{graph}
{schema}
{sort}
{systemFields}
{inModal}
{users}
bind:selected
/>
{:else}
<div class="row" style="max-width:1000px">
{#each records as record (record.id)}
<div class="col-6 col-md-4">
<div
class="file-wrapper rounded p-2 mb-4 bg-light"
class:selected={selected.includes(record)}
>
<div class="form-check">
<input
on:change={(e) => selectRecord(e, record)}
class="form-check-input "
type="checkbox"
checked={selected.find(
(r) => r.id === record.id
)}
value={record}
/>
</div>
<div class="d-flex justify-content-center">
<Preview {record} size="medium"/>
</div>
<a
href="{channel.lucentUrl}/records/{record.id}"
title={record._file.path}
class="d-block text-center overflow-hidden text-nowrap my-2 "
style="
text-overflow: ellipsis;
font-size: 13px;
color: #333;
">{record._file.path}</a
>
<span
class="lx-small-text text-muted d-block text-center"
>{record._file.mime}</span
>
</div>
</div>
{/each}
</div>
{/if}
</div>
<Pagination
{limit}
{skip}
{total}
on:refresh={refresh}
{inModal}
{modalUrl}
/>
</div>
<style>
.form-check {
display: inline-block;
margin-bottom: 0;
}
</style>
+58
View File
@@ -0,0 +1,58 @@
<script>
import RenderField from "./RenderField.svelte";
import Avatar from "../account/Avatar.svelte";
import Status from "../records/Status.svelte";
import {usernameById} from "../account/users";
import {friendlyDate} from "../../helpers";
export let schema;
export let users;
export let graph;
export let record;
export let sort;
export let visibleColumns;
</script>
{#each visibleColumns as field, index}
<td
class="field-ui-{field.info.name}"
class:is-sort={"-" + field.name == sort || field.name == sort}
>
<RenderField {record} {schema} {graph} {field}/>
</td>
{/each}
{#if schema.visible.includes("_sys.status")}
<td
class="text-center"
class:is-sort={"-_sys.status" == sort || "_sys.status" == sort}
>
<Status status={record._sys.status}/>
</td>
{/if}
{#if schema.visible.includes("_sys.createdBy")}
<td
class="text-center"
class:is-sort={"-_sys.createdBy" == sort || "_sys.createdBy" == sort}
>
<Avatar name={usernameById(users, record._sys.createdBy)} side={24}/>
</td>
{/if}
{#if schema.visible.includes("_sys.updatedBy")}
<td
class="text-center"
class:is-sort={"-_sys.updatedBy" == sort || "_sys.updatedBy" == sort}
>
<Avatar name={usernameById(users, record._sys.updatedBy)} side={24}/>
</td>
{/if}
{#if schema.visible.includes("_sys.createdAt")}
<td class:is-sort={"-_sys.createdAt" == sort || "_sys.createdAt" == sort}>
{friendlyDate(record._sys.createdAt)}
</td>
{/if}
{#if schema.visible.includes("_sys.updatedAt")}
<td class:is-sort={"-_sys.updatedAt" == sort || "_sys.updatedAt" == sort}>
{friendlyDate(record._sys.updatedAt)}
</td>
{/if}
@@ -0,0 +1,43 @@
<script>
import Checkbox from "./elements/Checkbox.svelte";
import Color from "./elements/Color.svelte";
import Reference from "./elements/Reference.svelte";
import Number from "./elements/Number.svelte";
import Text from "./elements/Text.svelte";
import Url from "./elements/Url.svelte";
import Date from "./elements/Date.svelte";
import File from "./elements/File.svelte";
import Uuid from "./elements/UUID.svelte";
import Rich from "./elements/Rich.svelte";
const renderElements = {
text: Text,
rich: Rich,
textarea: Text,
color: Color,
checkbox: Checkbox,
reference: Reference,
number: Number,
url: Url,
date: Date,
datetime: Date,
uuid: Uuid,
file: File,
};
export let field;
export let schema;
export let record;
export let graph;
</script>
<svelte:component
this={renderElements[field.info.name]}
value={record.data[field.name]}
{record}
{graph}
{schema}
{field}
/>
+141
View File
@@ -0,0 +1,141 @@
<script>
import RecordRow from "./RecordRow.svelte";
import {previewTitle} from "../records/Preview";
import {usernameById} from "../account/users";
import {getContext} from "svelte";
import Avatar from "../account/Avatar.svelte";
const channel = getContext("channel");
export let schema;
export let users;
export let records;
export let graph;
export let systemFields;
export let sort;
export let inModal;
export let selected = [];
function toggleAll(e) {
// e.preventDefault();
if (selected.length === records.length) {
selected = [];
} else {
selected = records;
}
e.currentTarget.checked = selected.length > 0;
}
function selectRecord(e, record) {
let recordExists = selected.find((r) => r.id == record.id);
if (recordExists) {
selected = selected.filter((r) => r.id !== record.id);
} else {
selected = [...selected, record];
}
}
$: visibleColumns = schema.fields.filter(c => schema.visible.includes(c.name))
</script>
<div class="lx-table rounded">
<table class="">
<thead class="table-light">
<tr>
<th>
<input
on:change|preventDefault={toggleAll}
indeterminate={selected.length > 0 &&
selected.length < records.length}
checked={selected.length == records.length}
class="form-check-input"
type="checkbox"
/>
</th>
{#each visibleColumns as field}
<th
class="field-ui-{field.ui}"
class:is-sort={"-" + field.name == sort ||
field.name == sort}
scope="col"
title={field.help}
data-bs-toggle="tooltip"
data-bs-placement="top">{field.label}</th
>
{/each}
{#each systemFields.filter(c => schema.visible.includes(c.name)) as sysField}
<th>{sysField.label}</th>
{/each}
</tr>
</thead>
<tbody>
{#each records as record (record.id)}
<tr>
<td class="title-td">
<div
class="title-td-contents d-inline-flex justify-content-between w-100 align-items-center"
>
<div class="d-flex align-items-center ">
<div class="form-check">
<input
on:change={(e) =>
selectRecord(e, record)}
class="form-check-input "
type="checkbox"
checked={selected.find(
(r) => r.id === record.id
)}
value={record}
/>
</div>
<a
class="me-2 text-decoration-none text-dark fs-6"
href="{channel.lucentUrl}/records/{record.id}"
target={inModal ? "_blank" : "_self"}
>
{previewTitle(channel.schemas, record, graph)}
</a>
</div>
<div>
<Avatar
name={usernameById(
users,
record._sys.updatedBy
)}
side={24}
/>
</div>
</div>
</td>
<RecordRow
{record}
{graph}
{schema}
{visibleColumns}
{sort}
{systemFields}
{inModal}
{users}
/>
</tr>
{/each}
</tbody>
</table>
</div>
<style>
/* .title-td:hover {
overflow: visible;
}
.title-td:hover .title-td-contents a {
z-index: 1;
box-shadow: inset 0em 0em 0em 10em rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 100%;
} */
</style>
@@ -0,0 +1,5 @@
<script>
export let value;
</script>
{value}
@@ -0,0 +1,20 @@
<script>
export let value;
</script>
{#if value}
<div class="d-inline-flex">
<span class="color border border-2" style="background:{value}" />
{value}
</div>
{/if}
<style>
.color {
width: 18px;
height: 18px;
display: inline-block;
position: relative;
top: 3px;
}
</style>
@@ -0,0 +1,5 @@
<script>
export let value;
</script>
{value}
@@ -0,0 +1,27 @@
<script>
import Preview from "../../files/Preview.svelte";
export let record;
export let field;
export let graph;
let filePreviews = graph.edges?.filter((ed) => ed.field === field.name && ed.source === record.id)
.map((ed) => graph.records.find((r) => r.id === ed.target));
// if (edges[0]) {
// firstRecord = record._children.find((r) => r.data.id === edges[0].to);
// }
console.log(filePreviews)
</script>
<!-- {#if firstRecord}
<Preview record={firstRecord} size="tiny" />
{/if} -->
<div class="d-flex me-1">
{#each filePreviews as file}
<div class="me-1">
<Preview record={file} size="tiny"/>
</div>
{/each}
</div>
@@ -0,0 +1,6 @@
<script>
export let value;
// let display = new Intl.NumberFormat().format(value);
</script>
{value}
@@ -0,0 +1,35 @@
<script>
import PreviewCardSmall from "../../records/PreviewCardSmall.svelte";
export let record;
export let field;
export let schemas;
export let graph;
$: recordEdges =
graph.edges
?.filter((ed) => ed.field === field.name && ed.source === record.id)
.map((edge) => {
return graph.records.find((r) => r.id === edge.target);
})
.filter((record) => (!record ? false : true)) ?? [];
</script>
<div class="references">
{#each recordEdges as recordEdge}
<span class="mr-3">
<PreviewCardSmall {schemas} {graph} record={recordEdge}/>
</span>
{/each}
</div>
<style>
div.references {
/* max-width: 148px; */
max-height: 48px;
/* text-overflow: ellipsis; */
overflow-x: hidden;
overflow-y: hidden;
}
</style>
@@ -0,0 +1,17 @@
<script>
export let value;
</script>
<div>
{value}
</div>
<style>
div {
/* max-width: 128px; */
max-height: 24px;
text-overflow: ellipsis;
/* white-space: nowrap; */
overflow: hidden;
}
</style>
@@ -0,0 +1,17 @@
<script>
export let value;
</script>
<div title={value} data-bs-toggle="tooltip" data-bs-placement="top">
{value}
</div>
<style>
div {
/* max-width: 128px; */
max-height: 24px;
text-overflow: ellipsis;
/* white-space: nowrap; */
overflow: hidden;
}
</style>
@@ -0,0 +1,11 @@
<script>
export let value;
export let field;
</script>
<span
class="badge rounded-pill bg-primary bg-opacity-75"
style="max-width:64px; overflow:hidden; white-space: nowrap; text-overflow: ellipsis;"
title={value}
data-bs-toggle="tooltip"
>{value}</span
>
@@ -0,0 +1,5 @@
<script>
export let value;
</script>
<a href={value} target="_blank">{value}</a>
@@ -0,0 +1,40 @@
<script>
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
export let pages;
export let limit;
export let currentPage;
export let inModal;
export let modalUrl;
function url(page) {
const url = new URL(modalUrl ?? window.location.href);
let skip = page * limit - limit;
url.searchParams.set("skip", skip);
return url;
}
function goto(e, pagenum) {
e.preventDefault();
const url = new URL(modalUrl ?? window.location.href);
let skip = pagenum * limit - limit;
url.searchParams.set("skip", skip);
if (inModal) {
dispatch("refresh", url);
} else {
window.location = url;
}
}
</script>
{#each pages as i}
<li class="page-item">
{#if currentPage == i}
<span class="page-link active">{i}</span>
{:else}
<a class="page-link" on:click={(e) => goto(e, i)} href={url(i)}
>{i}</a
>
{/if}
</li>
{/each}
@@ -0,0 +1,82 @@
<script>
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
import { range } from "lodash";
import NavItem from "./NavItem.svelte";
export let inModal;
export let modalUrl;
export let limit;
export let skip;
export let total;
$: totalPages = Math.ceil(total / limit);
$: currentPage = Math.ceil((skip - 1) / limit) + 1;
$: pageRange = range(currentPage - 3, currentPage + 4).filter((i) => {
return i > 0 && i <= totalPages;
});
function last(e) {
e.preventDefault();
goto(totalPages);
}
function first(e) {
e.preventDefault();
goto(1);
}
function page(e, page) {
e.preventDefault();
goto(page);
}
function goto(page) {
const url = new URL(modalUrl ?? window.location.href);
let skip = page * limit - limit;
url.searchParams.set("skip", skip);
if (inModal) {
dispatch("refresh", url);
} else {
window.location = url;
}
}
</script>
<nav>
<ul class="pagination justify-content-center">
{#if totalPages > 1}
<li class="page-item disabled" class:disabled={currentPage === 1}>
<a on:click={first} href="/" class="page-link"> First </a>
</li>
<NavItem
pages={pageRange}
{currentPage}
{limit}
{inModal}
{modalUrl}
on:refresh
/>
<li class="page-item">
<a
on:click={last}
class="page-link"
href="/"
class:disabled={currentPage === totalPages}>Last</a
>
</li>
{/if}
</ul>
</nav>
<p class="text-muted text-center">
Showing
<span class="font-medium">{+skip + 1}</span>
to
<span class="font-medium"
>{+skip + limit > total ? total : +skip + limit}</span
>
of
<span class="font-medium">{total}</span>
total
</p>
@@ -0,0 +1,60 @@
<script>
import {createEventDispatcher} from "svelte";
const dispatch = createEventDispatcher();
export let schema;
export let operators;
export let key;
export let value;
export let inModal;
export let modalUrl;
export let systemFields;
let filterSplit = key.split("_");
let operator = filterSplit[filterSplit.length - 1] ?? "eq";
let fieldName = key.replace("_" + operator, "");
let filterField = schema.fields.find((f) => f.name === fieldName);
let filterLabel = filterField?.label ?? fieldName;
function removeFilter(e, k) {
e.preventDefault();
let filterKey = `filter[${k}]`;
const url = new URL(modalUrl ?? window.location.href);
url.searchParams.set("skip", "0");
url.searchParams.delete(filterKey);
if (inModal) {
dispatch("refresh", url);
} else {
window.location = url;
}
}
</script>
<span
class="applied-filter d-inline-block border border-primary rounded lx-small-text me-1 px-2 py-1"
style="line-height:22px ;"
>
<div class="d-flex align-items-center justify-content-center">
{filterLabel}
{operators.find((o) => o.name === operator)?.symbol ?? ""}
{value}
<button
on:click={(e) => removeFilter(e, key)}
type="button"
class="btn-close btn-close ms-1"
aria-label="Close"
/>
</div>
</span>
<style>
.applied-filter {
background-color: #fff;
}
.applied-filter:hover {
opacity: .8;
background-color: #eee;
}
</style>
@@ -0,0 +1,131 @@
<script>
import Icon from "../../common/Icon.svelte";
import {createEventDispatcher} from "svelte";
const dispatch = createEventDispatcher();
export let schema;
export let systemFields = [];
export let operators;
export let inModal;
export let modalUrl;
let search = "";
let systemFieldsFiltered = systemFields;
if (schema.type == "collection") {
systemFieldsFiltered = systemFields.filter((f) => f.files === false);
}
let filterableFields = [...schema.fields, ...systemFieldsFiltered].filter(
(f) => !["file", "json", "tab"].includes(f.ui)
);
let selectedField;
let selectedInput = "";
$: operatorsFiltered = operators.filter(
(o) => o.uis.includes(selectedField?.ui) || o.uis[0] == "*"
);
$: selectedOperator = operatorsFiltered[0];
function addFilter(e) {
e.preventDefault();
let filterPrefix = "";
if (schema.fields.find(f => f.name === selectedField.name)) {
filterPrefix = "data.";
}
let filterKey = `filter[${filterPrefix + selectedField.name}_${selectedOperator.name}]`;
const url = new URL(modalUrl ?? window.location.href);
url.searchParams.set("skip", "0");
url.searchParams.set(filterKey, selectedInput);
if (inModal) {
dispatch("refresh", url);
} else {
window.location = url;
}
}
function submitSearch(e) {
e.preventDefault();
let filterKeyValue = search.split("=")[0] ?? "";
if (!filterKeyValue) {
return;
}
let filterKey = `filter[${filterKeyValue}]`;
let filterValue = search.split("=")[1] ?? "";
if (!filterValue) {
return;
}
const url = new URL(modalUrl ?? window.location.href);
url.searchParams.set("skip", "0");
url.searchParams.set(filterKey, filterValue);
if (inModal) {
dispatch("refresh", url);
} else {
window.location = url;
}
}
</script>
<div class="mx-2 d-flex align-items-center">
<div class="btn-group">
<button
class="btn btn-sm btn-outline-primary dropdown-toggle d-flex align-items-center"
type="button"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
<Icon icon="filter"/>
<span class="ms-1">Filter</span>
</button>
<div class="dropdown-menu" style="width:300px;">
<div class="px-3 py-1 d-flex align-items-center">
<select bind:value={selectedField} class="form-select">
{#each filterableFields as field}
<option value={field}>{field.label}</option>
{/each}
</select>
</div>
<div class="px-3 py-1 d-flex align-items-center">
<select class="form-select" bind:value={selectedOperator}>
{#each operatorsFiltered as operator}
<option value={operator}>{operator.label}</option>
{/each}
</select>
</div>
<div class="px-3 py-1 d-flex align-items-center">
<input
type="text"
class="form-control"
bind:value={selectedInput}
/>
</div>
<div class="px-3 py-1 d-flex align-items-center">
<button
on:click={addFilter}
class="btn btn-outline-primary"
type="button"
>
Add filter
</button>
</div>
<hr/>
<div><h6 class="dropdown-header">Advanced filters</h6></div>
<form on:submit={submitSearch}>
<div class="px-3 py-1 d-flex align-items-center">
<input
bind:value={search}
type="search"
class="form-control"
placeholder="Advanced filters"
required
/>
</div>
</form>
</div>
</div>
</div>
@@ -0,0 +1,133 @@
<script>
import Icon from "../../common/Icon.svelte";
import {createEventDispatcher} from "svelte";
const dispatch = createEventDispatcher();
export let schema;
export let sort;
export let inModal;
export let modalUrl;
export let systemFields = [];
$: activeField = [...schema.fields, ...systemFields].find(
(f) => f.name === sort || "-" + f.name === sort || "data." + f.name === sort || "-data." + f.name === sort
);
$: sortableFields = schema.fields.filter(
(f) => !["reference", "file", "json", "id", "tab"].includes(f.ui)
);
$: systemFieldsFiltered = systemFields;
$: if (schema.type === "collection") {
systemFieldsFiltered = systemFields.filter((f) => f.files === false);
}
function sortField(fieldSort) {
const url = new URL(modalUrl ?? window.location.href);
url.searchParams.set("sort", fieldSort);
if (inModal) {
dispatch("refresh", url);
} else {
window.location = url;
}
}
function sortAsc(e, field) {
e.preventDefault();
let prefix = systemFields.includes(el => el.name === field.name) ? "" : "data.";
return sortField(prefix + field.name);
}
function sortDesc(e, field) {
e.preventDefault();
let prefix = systemFields.includes(el => el.name === field.name) ? "" : "data.";
return sortField("-" + prefix + field.name);
}
</script>
<div class=" ">
<button
class="btn btn-sm btn-outline-primary dropdown-toggle d-flex align-items-center"
type="button"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
{#if sort.startsWith("-")}
<Icon icon="arrow-down-wide-short"/>
{:else}
<Icon icon="arrow-up-short-wide"/>
{/if}
<span class="ms-1">{activeField.label}</span>
</button>
<div class="dropdown-menu" style="width:auto;max-width:800px;">
<div class="row">
{#each sortableFields as field}
<div class="col-4 px-3 py-1 d-flex align-items-center">
<div class="btn-group w-100">
<button
on:click={(e) => sortAsc(e, field)}
title="Sort Ascending"
class="btn btn-sm {field.name == sort
? 'btn-primary'
: 'btn-outline-primary'} "
>
<Icon icon="arrow-up-short-wide"/>
</button>
<button
on:click={(e) => sortDesc(e, field)}
title="Sort Descending"
class="btn btn-sm {'-' + field.name == sort
? 'btn-primary'
: 'btn-outline-primary'} "
>
<Icon icon="arrow-down-wide-short"/>
</button>
<button
title="Sort Ascending"
on:click={(e) => sortAsc(e, field)}
class="btn btn-sm btn-outline-primary w-100 text-nowrap"
style="overflow: hidden;"
>
{field.label}
</button>
</div>
</div>
{/each}
</div>
<h6 class="dropdown-header px-0">System</h6>
<div class="row">
{#each systemFieldsFiltered as field}
<div class="col-4 px-3 py-1 d-flex align-items-center">
<div class="btn-group w-100">
<button
on:click={(e) => sortAsc(e, field)}
title="Sort Ascending"
class="btn btn-sm {field.name == sort
? 'btn-primary'
: 'btn-outline-primary'} "
>
<Icon icon="arrow-up-short-wide"/>
</button>
<button
on:click={(e) => sortDesc(e, field)}
title="Sort Descending"
class="btn btn-sm {'-' + field.name == sort
? 'btn-primary'
: 'btn-outline-primary'} "
>
<Icon icon="arrow-down-wide-short"/>
</button>
<button
title="Sort Ascending"
on:click={(e) => sortAsc(e, field)}
class="btn btn-sm btn-outline-primary w-100 text-nowrap"
style="overflow: hidden;"
>
{field.label}
</button>
</div>
</div>
{/each}
</div>
</div>
</div>
+115
View File
@@ -0,0 +1,115 @@
<script>
import FilterFields from "./FilterFields.svelte";
import Uploader from "../../files/Uploader.svelte";
import Icon from "../../common/Icon.svelte";
import SortFields from "./SortFields.svelte";
import AppliedFilter from "./AppliedFilter.svelte";
import {getContext} from "svelte";
const channel = getContext("channel");
export let sort;
export let schema;
export let operators;
export let filter;
export let inModal;
export let modalUrl;
export let records;
export let systemFields = [];
export let visibleFields = [];
let url = new URL(window.location.href);
let csvUrl = url.pathname + "/csv?" + url.searchParams.toString();
function uploadComplete(e) {
records = e.detail;
}
</script>
<div class="mb-3 d-flex align-items-center justify-content-between">
<div class=" d-flex">
<SortFields
{schema}
{sort}
{systemFields}
{inModal}
{modalUrl}
on:refresh
/>
<FilterFields
bind:schema
{systemFields}
{operators}
{filter}
{inModal}
{modalUrl}
on:refresh
/>
{#if Object.entries(filter).length > 0}
{#each Object.entries(filter) as [k, v]}
<AppliedFilter
{schema}
{operators}
key={k}
value={v}
{inModal}
{modalUrl}
{systemFields}
on:refresh
/>
{/each}
{/if}
</div>
<div class="d-flex align-items-center ">
{#if schema.type === "collection"}
{#if !inModal}
<a
href="{channel.lucentUrl}/records/new?schema={schema.name}"
class="btn btn-sm btn-primary"
>
New Record
</a>
{/if}
{:else }
<div class="d-inline-block ms-1">
<Uploader {schema} on:uploadComplete={uploadComplete}/>
</div>
{/if}
{#if !inModal}
<div class="dropdown d-inline-block">
<button
class="btn btn-link btn-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<Icon icon="ellipsis-vertical"/>
</button>
<ul class="dropdown-menu">
<li>
<a
class="dropdown-item"
href={csvUrl}
>Export to CSV</a
>
</li>
<li>
<a
class="dropdown-item"
href="{channel.lucentUrl}/content/{schema.name}?filter[_sys.status_in]=trashed"
>View trashed records</a
>
</li>
</ul>
</div>
{/if}
</div>
</div>