schemas and fields
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDistanceToNow, parseJSON } from "date-fns";
|
import { formatDistanceToNow, parseJSON } from "date-fns";
|
||||||
import Avatar from "../../svelte/account/Avatar.svelte";
|
import Avatar from "../../common/Avatar.svelte";
|
||||||
import { previewTitle } from "../../svelte/records/Preview";
|
import { previewTitle } from "../../svelte/records/Preview";
|
||||||
import Preview from "../../svelte/files/Preview.svelte";
|
import Preview from "../../svelte/files/Preview.svelte";
|
||||||
import { usernameById } from "../../svelte/account/users";
|
import { usernameById } from "../../svelte/account/users";
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<script>
|
||||||
|
import ChannelLayout from "../../layouts/ChannelLayout.svelte";
|
||||||
|
import { post } from "../../modules/remote";
|
||||||
|
let { channel, user, data } = $props();
|
||||||
|
let newSchemaName = $state("");
|
||||||
|
let newSchemaAlias = $state("");
|
||||||
|
|
||||||
|
function handleSchemaCreate(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
post(
|
||||||
|
channel.lucentUrl + "/schemas",
|
||||||
|
{
|
||||||
|
name: newSchemaName,
|
||||||
|
alias: newSchemaAlias,
|
||||||
|
},
|
||||||
|
(data, err) => {
|
||||||
|
if (err.isEmpty()) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ChannelLayout {body} {channel} {user}></ChannelLayout>
|
||||||
|
{#snippet body()}
|
||||||
|
<h3 class="header-small mb-4 mt-5">Schemas</h3>
|
||||||
|
|
||||||
|
<details style="max-width: 400px;">
|
||||||
|
<summary>Create Schema</summary>
|
||||||
|
<form onsubmit={handleSchemaCreate}>
|
||||||
|
<fieldset>
|
||||||
|
<label>
|
||||||
|
Name
|
||||||
|
<input
|
||||||
|
bind:value={newSchemaName}
|
||||||
|
placeholder="Schema name"
|
||||||
|
minlength="2"
|
||||||
|
maxlength="30"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Alias
|
||||||
|
<input
|
||||||
|
bind:value={newSchemaAlias}
|
||||||
|
placeholder="Schema alias"
|
||||||
|
minlength="2"
|
||||||
|
maxlength="30"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<button type="submit">Create</button>
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
<div style="display: flex;gap:20px">
|
||||||
|
{#each data.schemas as schema}
|
||||||
|
<article style="min-width: 300px;">
|
||||||
|
<header>{schema.name}</header>
|
||||||
|
<details>
|
||||||
|
<summary>Fields</summary>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Title</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Add field</summary>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href={`/fields/create?schema=${schema.id}&type=text`}
|
||||||
|
>Text</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href={`/fields/create?schema=${schema.id}&type=text`}
|
||||||
|
>File</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href={`/fields/create?schema=${schema.id}&type=text`}
|
||||||
|
>Rich</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<footer>
|
||||||
|
<small> Id: {schema.id}</small><br />
|
||||||
|
<small> Alias: {schema.alias}</small><br />
|
||||||
|
<small> Revisions: {schema.revisions}</small><br />
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<div class="top-nav">
|
<div class="top-nav">
|
||||||
<a class="top-nav-item" href="{channel.lucentUrl}/members">Members</a>
|
<a class="top-nav-item" href="{channel.lucentUrl}/members">Members</a>
|
||||||
|
<a class="top-nav-item" href="{channel.lucentUrl}/schemas">Schemas</a>
|
||||||
|
|
||||||
<!-- {#if channel.commands.length > 0}
|
<!-- {#if channel.commands.length > 0}
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import RecordNotFound from "./svelte/records/NotFound.svelte";
|
|||||||
import RecordEdit from "./svelte/records/Edit.svelte";
|
import RecordEdit from "./svelte/records/Edit.svelte";
|
||||||
import ContentIndex from "./svelte/content/Index.svelte";
|
import ContentIndex from "./svelte/content/Index.svelte";
|
||||||
import HomeEntry from "./entry/HomeEntry/HomeEntry.svelte";
|
import HomeEntry from "./entry/HomeEntry/HomeEntry.svelte";
|
||||||
|
import SchemaEntry from "./entry/SchemaEntry/SchemaEntry.svelte";
|
||||||
import BuildReport from "./svelte/build/Report.svelte";
|
import BuildReport from "./svelte/build/Report.svelte";
|
||||||
|
|
||||||
const entryComponents = {
|
const entryComponents = {
|
||||||
@@ -27,6 +28,7 @@ const entryComponents = {
|
|||||||
verify: Verify,
|
verify: Verify,
|
||||||
profile: Profile,
|
profile: Profile,
|
||||||
setup: SetupIndex,
|
setup: SetupIndex,
|
||||||
|
schemas: SchemaEntry,
|
||||||
};
|
};
|
||||||
|
|
||||||
let loadedComponents = [];
|
let loadedComponents = [];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import ErrorAlert from "../common/ErrorAlert.svelte";
|
import ErrorAlert from "../common/ErrorAlert.svelte";
|
||||||
import SpinnerButton from "../common/SpinnerButton.svelte";
|
import SpinnerButton from "../common/SpinnerButton.svelte";
|
||||||
import Avatar from "./Avatar.svelte";
|
import Avatar from "./../../common/Avatar.svelte";
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
import SuccessAlert from "../common/SuccessAlert.svelte";
|
import SuccessAlert from "../common/SuccessAlert.svelte";
|
||||||
|
|
||||||
@@ -47,7 +47,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="wrapper-tiny">
|
<div class="wrapper-tiny">
|
||||||
<ErrorAlert message={errorMessage} />
|
<ErrorAlert message={errorMessage} />
|
||||||
<SuccessAlert bind:this={successAlert} />
|
<SuccessAlert bind:this={successAlert} />
|
||||||
@@ -81,7 +80,9 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<a class="list-group-item list-group-item-action" href="{ channel.lucentUrl }/logout">Logout from this
|
<a
|
||||||
device</a>
|
class="list-group-item list-group-item-action"
|
||||||
|
href="{channel.lucentUrl}/logout">Logout from this device</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import RenderField from "./RenderField.svelte";
|
import RenderField from "./RenderField.svelte";
|
||||||
import Avatar from "../account/Avatar.svelte";
|
import Avatar from "../../common/Avatar.svelte";
|
||||||
import Status from "../records/Status.svelte";
|
import Status from "../records/Status.svelte";
|
||||||
import { usernameById } from "../account/users";
|
import { usernameById } from "../account/users";
|
||||||
import { friendlyDate } from "../../helpers";
|
import { friendlyDate } from "../../helpers";
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
export let sortParam;
|
export let sortParam;
|
||||||
export let sortField;
|
export let sortField;
|
||||||
export let visibleColumns;
|
export let visibleColumns;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each visibleColumns as field, index}
|
{#each visibleColumns as field, index}
|
||||||
@@ -34,7 +33,8 @@
|
|||||||
{#if schema.visible?.includes("_sys.createdBy")}
|
{#if schema.visible?.includes("_sys.createdBy")}
|
||||||
<td
|
<td
|
||||||
class="text-center"
|
class="text-center"
|
||||||
class:is-sort={"-_sys.createdBy" == sortParam || "_sys.createdBy" == sortParam}
|
class:is-sort={"-_sys.createdBy" == sortParam ||
|
||||||
|
"_sys.createdBy" == sortParam}
|
||||||
>
|
>
|
||||||
<Avatar name={usernameById(users, record._sys.createdBy)} side={24} />
|
<Avatar name={usernameById(users, record._sys.createdBy)} side={24} />
|
||||||
</td>
|
</td>
|
||||||
@@ -42,18 +42,25 @@
|
|||||||
{#if schema.visible?.includes("_sys.updatedBy")}
|
{#if schema.visible?.includes("_sys.updatedBy")}
|
||||||
<td
|
<td
|
||||||
class="text-center"
|
class="text-center"
|
||||||
class:is-sort={"-_sys.updatedBy" == sortParam || "_sys.updatedBy" == sortParam}
|
class:is-sort={"-_sys.updatedBy" == sortParam ||
|
||||||
|
"_sys.updatedBy" == sortParam}
|
||||||
>
|
>
|
||||||
<Avatar name={usernameById(users, record._sys.updatedBy)} side={24} />
|
<Avatar name={usernameById(users, record._sys.updatedBy)} side={24} />
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
{#if schema.visible?.includes("_sys.createdAt")}
|
{#if schema.visible?.includes("_sys.createdAt")}
|
||||||
<td class:is-sort={"-_sys.createdAt" == sortParam || "_sys.createdAt" == sortParam}>
|
<td
|
||||||
|
class:is-sort={"-_sys.createdAt" == sortParam ||
|
||||||
|
"_sys.createdAt" == sortParam}
|
||||||
|
>
|
||||||
{friendlyDate(record._sys.createdAt)}
|
{friendlyDate(record._sys.createdAt)}
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
{#if schema.visible?.includes("_sys.updatedAt")}
|
{#if schema.visible?.includes("_sys.updatedAt")}
|
||||||
<td class:is-sort={"-_sys.updatedAt" == sortParam || "_sys.updatedAt" == sortParam}>
|
<td
|
||||||
|
class:is-sort={"-_sys.updatedAt" == sortParam ||
|
||||||
|
"_sys.updatedAt" == sortParam}
|
||||||
|
>
|
||||||
{friendlyDate(record._sys.updatedAt)}
|
{friendlyDate(record._sys.updatedAt)}
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { previewTitle } from "../records/Preview";
|
import { previewTitle } from "../records/Preview";
|
||||||
import { usernameById } from "../account/users";
|
import { usernameById } from "../account/users";
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
import Avatar from "../account/Avatar.svelte";
|
import Avatar from "../../common/Avatar.svelte";
|
||||||
import { selectRecord, toggleAll } from "./functions/recordSelect.js";
|
import { selectRecord, toggleAll } from "./functions/recordSelect.js";
|
||||||
import Checkbox from "../common/Checkbox.svelte";
|
import Checkbox from "../common/Checkbox.svelte";
|
||||||
import Preview from "../files/Preview.svelte";
|
import Preview from "../files/Preview.svelte";
|
||||||
@@ -23,14 +23,16 @@
|
|||||||
export let selected = [];
|
export let selected = [];
|
||||||
|
|
||||||
function eventToggleAll(e) {
|
function eventToggleAll(e) {
|
||||||
selected = toggleAll(e, records, selected)
|
selected = toggleAll(e, records, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
function select(record) {
|
function select(record) {
|
||||||
selected = selectRecord(record, selected)
|
selected = selectRecord(record, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: visibleColumns = schema.fields.filter(c => schema.visible?.includes(c.name) ?? [])
|
$: visibleColumns = schema.fields.filter(
|
||||||
|
(c) => schema.visible?.includes(c.name) ?? [],
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="table mt-5">
|
<div class="table mt-5">
|
||||||
@@ -42,10 +44,10 @@
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
value=""
|
value=""
|
||||||
on:change={eventToggleAll}
|
on:change={eventToggleAll}
|
||||||
indeterminate={selected.length > 0 && selected.length < records.length}
|
indeterminate={selected.length > 0 &&
|
||||||
|
selected.length < records.length}
|
||||||
checked={selected.length === records.length}
|
checked={selected.length === records.length}
|
||||||
>
|
></Checkbox>
|
||||||
</Checkbox>
|
|
||||||
</th>
|
</th>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -54,12 +56,13 @@
|
|||||||
class="field-ui-{field.info.name ?? field.ui}"
|
class="field-ui-{field.info.name ?? field.ui}"
|
||||||
class:is-sort={field.name === sortField.name}
|
class:is-sort={field.name === sortField.name}
|
||||||
scope="col"
|
scope="col"
|
||||||
title={field.help}
|
title={field.help}>{field.label}</th
|
||||||
>{field.label}</th
|
|
||||||
>
|
>
|
||||||
{/each}
|
{/each}
|
||||||
{#each systemFields.filter(c => schema.visible?.includes(c.name)) as sysField}
|
{#each systemFields.filter( (c) => schema.visible?.includes(c.name), ) as sysField}
|
||||||
<th class:is-sort={sysField.name === sortField.name}>{sysField.label}</th>
|
<th class:is-sort={sysField.name === sortField.name}
|
||||||
|
>{sysField.label}</th
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -68,45 +71,64 @@
|
|||||||
{#each records as record (record.id)}
|
{#each records as record (record.id)}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title-td">
|
<td class="title-td">
|
||||||
<div
|
<div class="title-td-contents">
|
||||||
class="title-td-contents"
|
|
||||||
>
|
|
||||||
{#if isWritable}
|
{#if isWritable}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
on:change={() => select(record)}
|
on:change={() => select(record)}
|
||||||
checked={selected.find((r) => r.id === record.id)}
|
checked={selected.find(
|
||||||
|
(r) => r.id === record.id,
|
||||||
|
)}
|
||||||
value={record}
|
value={record}
|
||||||
>
|
></Checkbox>
|
||||||
</Checkbox>
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if record._file?.path}
|
{#if record._file?.path}
|
||||||
<div class="file-table-row">
|
<div class="file-table-row">
|
||||||
<Preview record={record} size={record._file?.width > 0 ? "medium" : "small"}/>
|
<Preview
|
||||||
|
{record}
|
||||||
|
size={record._file?.width > 0
|
||||||
|
? "medium"
|
||||||
|
: "small"}
|
||||||
|
/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{#if record.status === "draft"}
|
{#if record.status === "draft"}
|
||||||
<span style="text-transform: uppercase;font-size:10px">{record.status}</span>
|
<span
|
||||||
|
style="text-transform: uppercase;font-size:10px"
|
||||||
|
>{record.status}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<a
|
<a
|
||||||
href="{channel.lucentUrl}/records/{record.id}"
|
href="{channel.lucentUrl}/records/{record.id}"
|
||||||
target={inModal ? "_blank" : "_self"}
|
target={inModal
|
||||||
|
? "_blank"
|
||||||
|
: "_self"}
|
||||||
>
|
>
|
||||||
{previewTitle(channel.schemas, record, graph)}
|
{previewTitle(
|
||||||
|
channel.schemas,
|
||||||
|
record,
|
||||||
|
graph,
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
<span>{(record._file.size / 1024).toFixed(1)}kB</span>
|
<span
|
||||||
|
>{(
|
||||||
|
record._file.size / 1024
|
||||||
|
).toFixed(1)}kB</span
|
||||||
|
>
|
||||||
|
|
||||||
{#if record._file.width > 0}
|
{#if record._file.width > 0}
|
||||||
<span>{record._file.width + "x" + record._file.height}</span>
|
<span
|
||||||
|
>{record._file.width +
|
||||||
|
"x" +
|
||||||
|
record._file.height}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<a
|
<a
|
||||||
href="{fileurl(channel,record)}"
|
href={fileurl(channel, record)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Download
|
Download
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<a
|
<a
|
||||||
@@ -114,13 +136,18 @@
|
|||||||
target={inModal ? "_blank" : "_self"}
|
target={inModal ? "_blank" : "_self"}
|
||||||
>
|
>
|
||||||
{#if record.status === "draft"}
|
{#if record.status === "draft"}
|
||||||
<span style="text-transform: uppercase;font-size:10px">{record.status}</span>
|
<span
|
||||||
|
style="text-transform: uppercase;font-size:10px"
|
||||||
|
>{record.status}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{previewTitle(channel.schemas, record, graph)}
|
{previewTitle(
|
||||||
|
channel.schemas,
|
||||||
|
record,
|
||||||
|
graph,
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<RecordRow
|
<RecordRow
|
||||||
@@ -134,10 +161,7 @@
|
|||||||
/>
|
/>
|
||||||
<td>
|
<td>
|
||||||
<Avatar
|
<Avatar
|
||||||
name={usernameById(
|
name={usernameById(users, record._sys.updatedBy)}
|
||||||
users,
|
|
||||||
record._sys.updatedBy
|
|
||||||
)}
|
|
||||||
side={24}
|
side={24}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
@@ -146,4 +170,3 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import Avatar from "../account/Avatar.svelte";
|
import Avatar from "../../common/Avatar.svelte";
|
||||||
import { fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import Dropdown from "../common/Dropdown.svelte";
|
import Dropdown from "../common/Dropdown.svelte";
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
export let member;
|
export let member;
|
||||||
export let roles;
|
export let roles;
|
||||||
|
|
||||||
|
|
||||||
function removeFrom(e, aRole) {
|
function removeFrom(e, aRole) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let newRoles = member.roles.filter((r) => r !== aRole);
|
let newRoles = member.roles.filter((r) => r !== aRole);
|
||||||
@@ -22,23 +21,22 @@
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
let newRoles = [...member.roles, aRole];
|
let newRoles = [...member.roles, aRole];
|
||||||
console.log(member.roles)
|
console.log(member.roles);
|
||||||
console.log(aRole)
|
console.log(aRole);
|
||||||
console.log(newRoles)
|
console.log(newRoles);
|
||||||
dispatch("update", {
|
dispatch("update", {
|
||||||
user: member.id,
|
user: member.id,
|
||||||
roles: newRoles,
|
roles: newRoles,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div transition:fly={{ duration: 200 }} class="member-item">
|
||||||
<div
|
<div
|
||||||
transition:fly={{ duration: 200 }}
|
class="member-name status-{member.roles.includes('removed')
|
||||||
class="member-item"
|
? 'removed'
|
||||||
|
: 'active'}"
|
||||||
>
|
>
|
||||||
<div class="member-name status-{member.roles.includes('removed') ? 'removed' : 'active'}">
|
|
||||||
<Avatar name={member.name ?? ""} side={32} />
|
<Avatar name={member.name ?? ""} side={32} />
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@@ -50,9 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Dropdown orientation="right">
|
<Dropdown orientation="right">
|
||||||
<div slot="button">
|
<div slot="button">Roles</div>
|
||||||
Roles
|
|
||||||
</div>
|
|
||||||
<h6 class="dropdown-header">Remove role</h6>
|
<h6 class="dropdown-header">Remove role</h6>
|
||||||
{#each roles as role}
|
{#each roles as role}
|
||||||
{#if member.roles.includes(role)}
|
{#if member.roles.includes(role)}
|
||||||
@@ -65,7 +61,6 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
|
||||||
<h6 class="dropdown-header">Add role</h6>
|
<h6 class="dropdown-header">Add role</h6>
|
||||||
{#each roles as role}
|
{#each roles as role}
|
||||||
{#if !member.roles.includes(role)}
|
{#if !member.roles.includes(role)}
|
||||||
@@ -77,14 +72,11 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.status-removed {
|
.status-removed {
|
||||||
opacity: .5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { friendlyDate } from "../../helpers";
|
import { friendlyDate } from "../../helpers";
|
||||||
import Avatar from "../account/Avatar.svelte";
|
import Avatar from "../../common/Avatar.svelte";
|
||||||
import { usernameById } from "../account/users";
|
import { usernameById } from "../account/users";
|
||||||
import Icon from "../common/Icon.svelte";
|
import Icon from "../common/Icon.svelte";
|
||||||
import RevisionCell from "./revisions/RevisionCell.svelte";
|
import RevisionCell from "./revisions/RevisionCell.svelte";
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ namespace Lucent\Commands;
|
|||||||
|
|
||||||
use DirectoryIterator;
|
use DirectoryIterator;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Lucent\Schema\Schema;
|
use Lucent\Core\Schema\SchemaModule;
|
||||||
use Lucent\Schema\SchemaService;
|
use Lucent\Schema\SchemaService;
|
||||||
use Lucent\Schema\Type;
|
|
||||||
use Yosymfony\Toml\Toml;
|
use Yosymfony\Toml\Toml;
|
||||||
|
|
||||||
class CompileSchemas extends Command
|
class CompileSchemas extends Command
|
||||||
@@ -32,8 +31,20 @@ class CompileSchemas extends Command
|
|||||||
$schemas[] = $schemaData;
|
$schemas[] = $schemaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
$schemas = collect($schemas)->sortBy("label")->values();
|
$schemas = collect($schemas)
|
||||||
|
->sortBy("label")
|
||||||
|
->values()
|
||||||
|
->map(function ($schemaData) {
|
||||||
|
$fields = [];
|
||||||
|
foreach ($schemaData["fields"] as $fieldId => $fieldData) {
|
||||||
|
$fieldData["id"] = $fieldId;
|
||||||
|
$fields[] = $fieldData;
|
||||||
|
}
|
||||||
|
$schemaData["fields"] = $fields;
|
||||||
|
return $schemaData;
|
||||||
|
})
|
||||||
|
->map(SchemaModule::fromArray(...));
|
||||||
|
dd($schemas);
|
||||||
if (!file_exists(storage_path("lucent"))) {
|
if (!file_exists(storage_path("lucent"))) {
|
||||||
mkdir(storage_path("lucent"));
|
mkdir(storage_path("lucent"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php namespace Lucent\Core\Repository;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Lucent\Core\Schema\Data\Schema;
|
||||||
|
use Lucent\Core\Schema\SchemaModule;
|
||||||
|
|
||||||
|
class SchemaRepo
|
||||||
|
{
|
||||||
|
const TABLE_NAME = "schemas";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @@return Schema[]
|
||||||
|
*/
|
||||||
|
public static function all(): array
|
||||||
|
{
|
||||||
|
return DB::table(self::TABLE_NAME)
|
||||||
|
->orderBy("name")
|
||||||
|
->get()
|
||||||
|
->map(SchemaModule::fromDb(...))
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function insert(Schema $schema): void
|
||||||
|
{
|
||||||
|
DB::table(self::TABLE_NAME)->insert(SchemaModule::toDb($schema));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,8 @@ class Field
|
|||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $id,
|
public string $id,
|
||||||
public string $label,
|
public string $alias,
|
||||||
|
public string $name,
|
||||||
public string $type,
|
public string $type,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ class Schema
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $id
|
* @param string $id
|
||||||
* @param string $label
|
* @param string $alias
|
||||||
|
* @param string $name
|
||||||
|
* @param int $revisions
|
||||||
* @param Field[] $fields
|
* @param Field[] $fields
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $id,
|
public string $id,
|
||||||
public string $label,
|
public string $alias,
|
||||||
|
public string $name,
|
||||||
|
public int $revisions,
|
||||||
public array $fields,
|
public array $fields,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php namespace Lucent\Core\Schema;
|
||||||
|
|
||||||
|
use Lucent\Core\Schema\Data\Field;
|
||||||
|
|
||||||
|
class FieldModule
|
||||||
|
{
|
||||||
|
public static function fromArray(array $data): Field
|
||||||
|
{
|
||||||
|
return new Field(
|
||||||
|
id: $data["id"],
|
||||||
|
alias: $data["alias"],
|
||||||
|
name: $data["name"],
|
||||||
|
type: $data["type"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toDb(Field $field): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"id" => $field->id,
|
||||||
|
"alias" => $field->alias,
|
||||||
|
"name" => $field->name,
|
||||||
|
"type" => $field->type,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,39 @@
|
|||||||
<?php namespace Lucent\Core\Schema;
|
<?php namespace Lucent\Core\Schema;
|
||||||
|
|
||||||
|
use Lucent\Core\Schema\Data\Schema;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class SchemaModule
|
class SchemaModule
|
||||||
{
|
{
|
||||||
public function __construct()
|
public static function fromArray(array $data): Schema
|
||||||
{
|
{
|
||||||
// Constructor logic here
|
return new Schema(
|
||||||
|
id: $data["id"],
|
||||||
|
alias: $data["alias"],
|
||||||
|
name: $data["label"],
|
||||||
|
revisions: $data["revisions"],
|
||||||
|
fields: array_map(FieldModule::fromArray(...), $data["fields"]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromDb(stdClass $data): Schema
|
||||||
|
{
|
||||||
|
return new Schema(
|
||||||
|
id: data_get($data, "id"),
|
||||||
|
alias: data_get($data, "alias"),
|
||||||
|
name: data_get($data, "name"),
|
||||||
|
revisions: data_get($data, "revisions"),
|
||||||
|
fields: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toDb(Schema $schema): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"id" => $schema->id,
|
||||||
|
"alias" => $schema->alias,
|
||||||
|
"name" => $schema->name,
|
||||||
|
"revisions" => $schema->revisions,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Lucent\Account\AccountService;
|
||||||
|
use Lucent\Account\AuthService;
|
||||||
|
use Lucent\Core\Repository\SchemaRepo;
|
||||||
|
use Lucent\Core\Schema\Data\Schema;
|
||||||
|
use Lucent\Id\Id;
|
||||||
|
use Lucent\Svelte\Svelte;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class SchemaController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly AuthService $authService,
|
||||||
|
private readonly AccountService $accountService,
|
||||||
|
private readonly Svelte $svelte,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function home()
|
||||||
|
{
|
||||||
|
$schemas = SchemaRepo::all();
|
||||||
|
|
||||||
|
return $this->svelte->render(
|
||||||
|
view: "schemas",
|
||||||
|
title: "Schemas",
|
||||||
|
data: [
|
||||||
|
"schemas" => $schemas,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postCreate(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
"name" => "required|string|max:30|min:2|",
|
||||||
|
"alias" => "required|alpha_dash:ascii|max:30|min:2|",
|
||||||
|
]);
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json(["errors" => $validator->errors()], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$schema = new Schema(
|
||||||
|
id: Id::new(),
|
||||||
|
alias: $request->input("alias"),
|
||||||
|
name: $request->input("name"),
|
||||||
|
revisions: 0,
|
||||||
|
fields: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
SchemaRepo::insert($schema);
|
||||||
|
|
||||||
|
return response()->json(
|
||||||
|
["message" => "Schema created successfully"],
|
||||||
|
201,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+105
-62
@@ -10,91 +10,134 @@ use Lucent\Http\Controller\HomeController;
|
|||||||
use Lucent\Http\Controller\MemberController;
|
use Lucent\Http\Controller\MemberController;
|
||||||
use Lucent\Http\Controller\RecordController;
|
use Lucent\Http\Controller\RecordController;
|
||||||
use Lucent\Http\Controller\RevisionController;
|
use Lucent\Http\Controller\RevisionController;
|
||||||
|
use Lucent\Http\Controller\SchemaController;
|
||||||
use Lucent\Http\Controller\SetupController;
|
use Lucent\Http\Controller\SetupController;
|
||||||
|
|
||||||
|
Route::get("/lucent/setup", [SetupController::class, "setup"]);
|
||||||
|
Route::get("/lfs-{disk}/{any}", [FileController::class, "fromDisk"])->where(
|
||||||
|
"any",
|
||||||
|
".*",
|
||||||
|
);
|
||||||
|
|
||||||
Route::get('/lucent/setup', [SetupController::class, 'setup']);
|
Route::group(
|
||||||
Route::get('/lfs-{disk}/{any}', [FileController::class, 'fromDisk'])->where('any', '.*');
|
[
|
||||||
|
"middleware" => ["web"],
|
||||||
|
"prefix" => "lucent",
|
||||||
Route::group([
|
],
|
||||||
'middleware' => ['web'],
|
function () {
|
||||||
'prefix' => "lucent"
|
Route::middleware(["lucent.guest"])->group(function () {
|
||||||
], function () {
|
Route::get("/", [AuthController::class, "login"]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Route::middleware(['lucent.guest'])->group(function () {
|
|
||||||
Route::get('/', [AuthController::class, 'login']);
|
|
||||||
|
|
||||||
Route::get('/register', [AuthController::class, 'register']);
|
|
||||||
Route::post('/register', [AuthController::class, 'postRegister']);
|
|
||||||
Route::get('/login', [AuthController::class, 'login']);
|
|
||||||
Route::post('/login', [AuthController::class, 'postLogin']);
|
|
||||||
Route::get('/verify', [AuthController::class, 'verify']);
|
|
||||||
Route::post('/verify', [AuthController::class, 'postVerify']);
|
|
||||||
|
|
||||||
|
Route::get("/register", [AuthController::class, "register"]);
|
||||||
|
Route::post("/register", [AuthController::class, "postRegister"]);
|
||||||
|
Route::get("/login", [AuthController::class, "login"]);
|
||||||
|
Route::post("/login", [AuthController::class, "postLogin"]);
|
||||||
|
Route::get("/verify", [AuthController::class, "verify"]);
|
||||||
|
Route::post("/verify", [AuthController::class, "postVerify"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware('lucent.auth')->group(function () {
|
Route::middleware("lucent.auth")->group(function () {
|
||||||
Route::get('/logout', [AuthController::class, 'logout']);
|
Route::get("/logout", [AuthController::class, "logout"]);
|
||||||
Route::get('/profile', [AccountController::class, 'profile']);
|
Route::get("/profile", [AccountController::class, "profile"]);
|
||||||
Route::post('/account/update-name', [AccountController::class, 'updateName']);
|
Route::post("/account/update-name", [
|
||||||
Route::post('/account/update-email', [AccountController::class, 'updateEmail']);
|
AccountController::class,
|
||||||
Route::get('/command-report/{signature}', [BuildController::class, 'report']);
|
"updateName",
|
||||||
Route::get('/command-report-source/{signature}', [BuildController::class, 'reportSource']);
|
]);
|
||||||
Route::post('/command/{signature}', [BuildController::class, 'build']);
|
Route::post("/account/update-email", [
|
||||||
|
AccountController::class,
|
||||||
|
"updateEmail",
|
||||||
|
]);
|
||||||
|
Route::get("/command-report/{signature}", [
|
||||||
|
BuildController::class,
|
||||||
|
"report",
|
||||||
|
]);
|
||||||
|
Route::get("/command-report-source/{signature}", [
|
||||||
|
BuildController::class,
|
||||||
|
"reportSource",
|
||||||
|
]);
|
||||||
|
Route::post("/command/{signature}", [
|
||||||
|
BuildController::class,
|
||||||
|
"build",
|
||||||
|
]);
|
||||||
|
Route::get("/schemas", [SchemaController::class, "home"]);
|
||||||
|
Route::post("/schemas", [SchemaController::class, "postCreate"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
Route::get('/members/', [MemberController::class, 'index']);
|
Route::get("/members/", [MemberController::class, "index"]);
|
||||||
Route::post('/members/invite', [MemberController::class, 'invite']);
|
Route::post("/members/invite", [MemberController::class, "invite"]);
|
||||||
Route::post('/members/update', [MemberController::class, 'update']);
|
Route::post("/members/update", [MemberController::class, "update"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::middleware(["lucent.auth"])
|
||||||
Route::middleware(["lucent.auth"])->prefix("/records")->group(function () {
|
->prefix("/records")
|
||||||
|
->group(function () {
|
||||||
Route::get('/new', [RecordController::class, 'new']);
|
Route::get("/new", [RecordController::class, "new"]);
|
||||||
Route::get('/newInline', [RecordController::class, 'newInline']);
|
Route::get("/newInline", [
|
||||||
Route::get('/suggestions', [RecordController::class, 'suggestions']);
|
RecordController::class,
|
||||||
Route::get('/{rid}', [RecordController::class, 'edit']);
|
"newInline",
|
||||||
Route::post('/clone/{rid}', [RecordController::class, 'clone']);
|
]);
|
||||||
|
Route::get("/suggestions", [
|
||||||
|
RecordController::class,
|
||||||
|
"suggestions",
|
||||||
|
]);
|
||||||
|
Route::get("/{rid}", [RecordController::class, "edit"]);
|
||||||
|
Route::post("/clone/{rid}", [RecordController::class, "clone"]);
|
||||||
// Route::get('/editInline/{rid}', [RecordController::class, 'editInline']);
|
// Route::get('/editInline/{rid}', [RecordController::class, 'editInline']);
|
||||||
Route::get('/{rid}/parents', [RecordController::class, 'parents']);
|
Route::get("/{rid}/parents", [
|
||||||
Route::post('/', [RecordController::class, 'save']);
|
RecordController::class,
|
||||||
Route::post('/status/{status}', [RecordController::class, 'status']);
|
"parents",
|
||||||
Route::post('/delete', [RecordController::class, 'delete']);
|
]);
|
||||||
Route::post('/{rid}/rollback/{version}', [RecordController::class, 'rollback']);
|
Route::post("/", [RecordController::class, "save"]);
|
||||||
|
Route::post("/status/{status}", [
|
||||||
|
RecordController::class,
|
||||||
|
"status",
|
||||||
|
]);
|
||||||
|
Route::post("/delete", [RecordController::class, "delete"]);
|
||||||
|
Route::post("/{rid}/rollback/{version}", [
|
||||||
|
RecordController::class,
|
||||||
|
"rollback",
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/edges")->group(function () {
|
Route::middleware(["lucent.auth"])
|
||||||
Route::post('/insert-many', [EdgeController::class, 'insertMany']);
|
->prefix("/edges")
|
||||||
|
->group(function () {
|
||||||
|
Route::post("/insert-many", [
|
||||||
|
EdgeController::class,
|
||||||
|
"insertMany",
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
Route::get('/records/{rid}/revisions', [RevisionController::class, 'index']);
|
Route::get("/records/{rid}/revisions", [
|
||||||
|
RevisionController::class,
|
||||||
|
"index",
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
Route::get('/', [HomeController::class, 'home']);
|
Route::get("/", [HomeController::class, "home"]);
|
||||||
Route::get('/home/records', [HomeController::class, 'records']);
|
Route::get("/home/records", [HomeController::class, "records"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/content")->group(function () {
|
Route::middleware(["lucent.auth"])
|
||||||
Route::get('/{schemaName}', [RecordController::class, 'index']);
|
->prefix("/content")
|
||||||
Route::get('/{schemaName}/csv', [RecordController::class, 'exportCSV']);
|
->group(function () {
|
||||||
Route::get('/{schemaName}/emptyTrash', [RecordController::class, 'emptyTrash']);
|
Route::get("/{schemaName}", [RecordController::class, "index"]);
|
||||||
|
Route::get("/{schemaName}/csv", [
|
||||||
|
RecordController::class,
|
||||||
|
"exportCSV",
|
||||||
|
]);
|
||||||
|
Route::get("/{schemaName}/emptyTrash", [
|
||||||
|
RecordController::class,
|
||||||
|
"emptyTrash",
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
Route::post('/files/upload', [FileController::class, 'upload']);
|
Route::post("/files/upload", [FileController::class, "upload"]);
|
||||||
Route::get('/files/download', [FileController::class, 'download']);
|
Route::get("/files/download", [FileController::class, "download"]);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user