field create

This commit is contained in:
2026-01-08 13:10:18 +02:00
parent 4d2497d96f
commit ebccac210a
15 changed files with 318 additions and 18 deletions
+17
View File
@@ -0,0 +1,17 @@
let app;
let channel;
export function createApp(channelData) {
channel = channelData;
app = {
url: (path) => {
return channel.lucentUrl + "/" + path;
},
};
return app;
}
export function getApp() {
return app;
}
@@ -0,0 +1,66 @@
<script>
import ChannelLayout from "../../layouts/ChannelLayout.svelte";
import { post } from "../../modules/remote";
import { getApp } from "../../app";
let { channel, user, data } = $props();
let name = $state("");
let alias = $state("");
const app = getApp();
function handleSchemaCreate(e) {
e.preventDefault();
console.log(data);
post(
app.url("fields"),
{
schemaId: data.schema.id,
name: name,
alias: alias,
fieldType: data.type,
},
(data, err) => {
if (err.isEmpty()) {
Turbo.visit(app.url("fields/edit/" + data.field.id));
} else {
console.log(err);
}
},
);
}
</script>
<ChannelLayout {body} {channel} {user}></ChannelLayout>
{#snippet body()}
<h3 class="header-small mb-4 mt-5">Create a <em>{data.type}</em> field</h3>
<form onsubmit={handleSchemaCreate}>
<fieldset>
<label>
Name
<input
bind:value={name}
placeholder="ex. Description"
minlength="2"
maxlength="30"
required
/>
</label>
<label>
Alias
<input
bind:value={alias}
placeholder="ex. description"
minlength="2"
maxlength="30"
required
aria-describedby="alias-helper"
/>
<small id="alias-helper">
Developers will use this to reference the field
</small>
</label>
</fieldset>
<button type="submit">Create</button>
</form>
{/snippet}
@@ -1,9 +1,11 @@
<script>
import ChannelLayout from "../../layouts/ChannelLayout.svelte";
import { post } from "../../modules/remote";
import { getApp } from "../../app";
let { channel, user, data } = $props();
let newSchemaName = $state("");
let newSchemaAlias = $state("");
const app = getApp();
function handleSchemaCreate(e) {
e.preventDefault();
@@ -15,7 +17,7 @@
},
(data, err) => {
if (err.isEmpty()) {
window.location.reload();
Turbo.visit(window.location.href);
}
},
);
@@ -79,8 +81,9 @@
<ul>
<li>
<a
href={`/fields/create?schema=${schema.id}&type=text`}
>Text</a
href={app.url(
`fields/create?schema=${schema.id}&type=text`,
)}>Text</a
>
</li>
+9 -6
View File
@@ -1,7 +1,6 @@
import { axiosInstance } from "./bootstrap";
import { mount, setContext, unmount } from "svelte";
import * as Turbo from "@hotwired/turbo";
// import "../sass/app.scss";
import { mount, unmount } from "svelte";
import "../css/app.css";
import Register from "./svelte/account/Register.svelte";
import Login from "./svelte/account/Login.svelte";
@@ -14,7 +13,9 @@ import RecordEdit from "./svelte/records/Edit.svelte";
import ContentIndex from "./svelte/content/Index.svelte";
import HomeEntry from "./entry/HomeEntry/HomeEntry.svelte";
import SchemaEntry from "./entry/SchemaEntry/SchemaEntry.svelte";
import FieldCreateEntry from "./entry/FieldCreateEntry/FieldCreateEntry.svelte";
import BuildReport from "./svelte/build/Report.svelte";
import { createApp } from "./app";
const entryComponents = {
members: Members,
@@ -29,11 +30,14 @@ const entryComponents = {
profile: Profile,
setup: SetupIndex,
schemas: SchemaEntry,
fieldCreate: FieldCreateEntry,
};
Turbo.start();
let loadedComponents = [];
let loadSvelte = function () {
Turbo.cache.clear();
loadedComponents.map((comp) => unmount(comp));
loadedComponents = [];
@@ -53,7 +57,7 @@ let loadSvelte = function () {
return [];
}
// props.axios = axiosInstance;
createApp(props.channel);
const compOptions = {
target: element,
props: props,
@@ -62,5 +66,4 @@ let loadSvelte = function () {
};
Array.from(elements).map(loadElement);
};
document.addEventListener("DOMContentLoaded", loadSvelte);
document.addEventListener("turbo:load", loadSvelte);
+12
View File
@@ -4,6 +4,9 @@
"requires": true,
"packages": {
"": {
"dependencies": {
"@hotwired/turbo": "^8.0.20"
},
"devDependencies": {
"@codemirror/commands": "^6.6.0",
"@codemirror/lang-json": "^6.0.1",
@@ -622,6 +625,15 @@
"node": ">=18"
}
},
"node_modules/@hotwired/turbo": {
"version": "8.0.20",
"resolved": "https://registry.npmjs.org/@hotwired/turbo/-/turbo-8.0.20.tgz",
"integrity": "sha512-IilkH/+h92BRLeY/rMMR3MUh1gshIfdra/qZzp/Bl5FmiALD/6sQZK/ecxSbumeyOYiWr/JRI+Au1YQmkJGnoA==",
"license": "MIT",
"engines": {
"node": ">= 18"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+3
View File
@@ -26,5 +26,8 @@
"tinymce": "^6.8.4",
"trix": "^2.1.5",
"vite": "^7.3.1"
},
"dependencies": {
"@hotwired/turbo": "^8.0.20"
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php namespace Lucent\Core\Repository;
use Illuminate\Support\Facades\DB;
use Lucent\Core\Schema\Data\Field;
use Lucent\Core\Schema\FieldModule;
use Lucent\Core\Schema\SchemaModule;
class FieldRepo
{
const TABLE_NAME = "fields";
/**
* @@return Field[]
*/
public static function all(): array
{
return DB::table(self::TABLE_NAME)
->orderBy("name")
->get()
->map(SchemaModule::fromDb(...))
->toArray();
}
public static function insert(Field $field): void
{
DB::table(self::TABLE_NAME)->insert(FieldModule::toDb($field));
}
}
+4
View File
@@ -1,5 +1,7 @@
<?php namespace Lucent\Core\Schema\Data;
use Lucent\Core\Schema\Data\FieldProp\IFieldProp;
class Field
{
public function __construct(
@@ -7,5 +9,7 @@ class Field
public string $alias,
public string $name,
public string $type,
public string $schemaId,
public IFieldProp $props,
) {}
}
@@ -0,0 +1,37 @@
<?php namespace Lucent\Core\Schema\Data\FieldProp;
class FieldProp
{
public static function fromType(string $type): IFieldProp
{
return match ($type) {
"text" => new TextFieldProp(
required: false,
readonly: false,
hidden: false,
min: 0,
max: 0,
help: "",
default: "",
),
default => new InvalidFieldProp(),
};
}
public static function fromDb(string $propsJson): IFieldProp
{
$props = json_decode($propsJson, true);
return match ($props["type"]) {
"text" => new TextFieldProp(
required: $props["required"] ?? false,
readonly: $props["readonly"] ?? false,
hidden: $props["hidden"] ?? false,
min: $props["min"] ?? 0,
max: $props["max"] ?? 0,
help: $props["help"] ?? "",
default: $props["default"] ?? "",
),
default => new InvalidFieldProp(),
};
}
}
@@ -0,0 +1,3 @@
<?php namespace Lucent\Core\Schema\Data\FieldProp;
interface IFieldProp {}
@@ -0,0 +1,6 @@
<?php namespace Lucent\Core\Schema\Data\FieldProp;
class InvalidFieldProp implements IFieldProp
{
public function __construct() {}
}
@@ -0,0 +1,14 @@
<?php namespace Lucent\Core\Schema\Data\FieldProp;
class TextFieldProp implements IFieldProp
{
public function __construct(
public bool $required,
public bool $readonly,
public bool $hidden,
public string $default,
public int $min,
public int $max,
public string $help,
) {}
}
+25 -9
View File
@@ -1,18 +1,20 @@
<?php namespace Lucent\Core\Schema;
use Lucent\Core\Schema\Data\Field;
use Lucent\Core\Schema\Data\FieldProp\FieldProp;
use stdClass;
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 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
{
@@ -21,6 +23,20 @@ class FieldModule
"alias" => $field->alias,
"name" => $field->name,
"type" => $field->type,
"props" => json_encode($field->props),
"schema_id" => $field->schemaId,
];
}
public static function fromDb(stdClass $data): Field
{
return new Field(
id: data_get($data, "id"),
alias: data_get($data, "alias"),
name: data_get($data, "name"),
type: data_get($data, "type"),
schemaId: data_get($data, "schema_id"),
props: FieldProp::fromDb(data_get($data, "props")),
);
}
}
+85
View File
@@ -0,0 +1,85 @@
<?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\FieldRepo;
use Lucent\Core\Repository\SchemaRepo;
use Lucent\Core\Schema\Data\Field;
use Lucent\Core\Schema\Data\FieldProp\FieldProp;
use Lucent\Core\Schema\Data\Schema;
use Lucent\Id\Id;
use Lucent\Svelte\Svelte;
use Illuminate\Support\Facades\Validator;
class FieldController extends Controller
{
public function __construct(private readonly Svelte $svelte) {}
public function create(Request $request)
{
$schemaId = $request->input("schema");
$fieldType = $request->input("type");
$schemas = SchemaRepo::all();
$schema = collect($schemas)->firstWhere("id", $schemaId);
if (empty($schema)) {
return response()->json(["error" => "Schema not found"], 404);
}
if (empty($fieldType)) {
return response()->json(["error" => "Field type not found"], 404);
}
// $fieldProps = FieldProp::fromType($fieldType);
return $this->svelte->render(
view: "fieldCreate",
title: "Create Field",
data: [
"schemas" => $schemas,
"schema" => $schema,
// "fieldProps" => $fieldProps,
"type" => $fieldType,
],
);
}
public function postCreate(Request $request)
{
$schemaId = $request->input("schemaId");
$name = $request->input("name");
$alias = $request->input("alias");
$fieldType = $request->input("fieldType");
$validator = Validator::make($request->all(), [
"name" => "required|string|max:30|min:2",
"alias" => "required|alpha_dash:ascii|max:30|min:2",
"schemaId" => "required",
"fieldType" => "required",
]);
if ($validator->fails()) {
return response()->json(["errors" => $validator->errors()], 422);
}
$schemas = SchemaRepo::all();
$schema = collect($schemas)->firstWhere("id", $schemaId);
$fieldProps = FieldProp::fromType($fieldType);
$field = new Field(
id: Id::new(),
schemaId: $schemaId,
name: $name,
alias: $alias,
type: $fieldType,
props: $fieldProps,
);
FieldRepo::insert($field);
return response()->json(["field" => $field], 201);
}
}
+3
View File
@@ -5,6 +5,7 @@ use Lucent\Http\Controller\AccountController;
use Lucent\Http\Controller\AuthController;
use Lucent\Http\Controller\BuildController;
use Lucent\Http\Controller\EdgeController;
use Lucent\Http\Controller\FieldController;
use Lucent\Http\Controller\FileController;
use Lucent\Http\Controller\HomeController;
use Lucent\Http\Controller\MemberController;
@@ -61,6 +62,8 @@ Route::group(
]);
Route::get("/schemas", [SchemaController::class, "home"]);
Route::post("/schemas", [SchemaController::class, "postCreate"]);
Route::get("/fields/create", [FieldController::class, "create"]);
Route::post("/fields", [FieldController::class, "postCreate"]);
});
Route::middleware(["lucent.auth"])->group(function () {