field create
This commit is contained in:
@@ -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>
|
<script>
|
||||||
import ChannelLayout from "../../layouts/ChannelLayout.svelte";
|
import ChannelLayout from "../../layouts/ChannelLayout.svelte";
|
||||||
import { post } from "../../modules/remote";
|
import { post } from "../../modules/remote";
|
||||||
|
import { getApp } from "../../app";
|
||||||
let { channel, user, data } = $props();
|
let { channel, user, data } = $props();
|
||||||
let newSchemaName = $state("");
|
let newSchemaName = $state("");
|
||||||
let newSchemaAlias = $state("");
|
let newSchemaAlias = $state("");
|
||||||
|
const app = getApp();
|
||||||
|
|
||||||
function handleSchemaCreate(e) {
|
function handleSchemaCreate(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -15,7 +17,7 @@
|
|||||||
},
|
},
|
||||||
(data, err) => {
|
(data, err) => {
|
||||||
if (err.isEmpty()) {
|
if (err.isEmpty()) {
|
||||||
window.location.reload();
|
Turbo.visit(window.location.href);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -79,8 +81,9 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href={`/fields/create?schema=${schema.id}&type=text`}
|
href={app.url(
|
||||||
>Text</a
|
`fields/create?schema=${schema.id}&type=text`,
|
||||||
|
)}>Text</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -1,7 +1,6 @@
|
|||||||
import { axiosInstance } from "./bootstrap";
|
import * as Turbo from "@hotwired/turbo";
|
||||||
import { mount, setContext, unmount } from "svelte";
|
|
||||||
|
|
||||||
// import "../sass/app.scss";
|
// import "../sass/app.scss";
|
||||||
|
import { mount, unmount } from "svelte";
|
||||||
import "../css/app.css";
|
import "../css/app.css";
|
||||||
import Register from "./svelte/account/Register.svelte";
|
import Register from "./svelte/account/Register.svelte";
|
||||||
import Login from "./svelte/account/Login.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 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 SchemaEntry from "./entry/SchemaEntry/SchemaEntry.svelte";
|
||||||
|
import FieldCreateEntry from "./entry/FieldCreateEntry/FieldCreateEntry.svelte";
|
||||||
import BuildReport from "./svelte/build/Report.svelte";
|
import BuildReport from "./svelte/build/Report.svelte";
|
||||||
|
import { createApp } from "./app";
|
||||||
|
|
||||||
const entryComponents = {
|
const entryComponents = {
|
||||||
members: Members,
|
members: Members,
|
||||||
@@ -29,11 +30,14 @@ const entryComponents = {
|
|||||||
profile: Profile,
|
profile: Profile,
|
||||||
setup: SetupIndex,
|
setup: SetupIndex,
|
||||||
schemas: SchemaEntry,
|
schemas: SchemaEntry,
|
||||||
|
fieldCreate: FieldCreateEntry,
|
||||||
};
|
};
|
||||||
|
Turbo.start();
|
||||||
|
|
||||||
let loadedComponents = [];
|
let loadedComponents = [];
|
||||||
|
|
||||||
let loadSvelte = function () {
|
let loadSvelte = function () {
|
||||||
|
Turbo.cache.clear();
|
||||||
loadedComponents.map((comp) => unmount(comp));
|
loadedComponents.map((comp) => unmount(comp));
|
||||||
loadedComponents = [];
|
loadedComponents = [];
|
||||||
|
|
||||||
@@ -53,7 +57,7 @@ let loadSvelte = function () {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
// props.axios = axiosInstance;
|
// props.axios = axiosInstance;
|
||||||
|
createApp(props.channel);
|
||||||
const compOptions = {
|
const compOptions = {
|
||||||
target: element,
|
target: element,
|
||||||
props: props,
|
props: props,
|
||||||
@@ -62,5 +66,4 @@ let loadSvelte = function () {
|
|||||||
};
|
};
|
||||||
Array.from(elements).map(loadElement);
|
Array.from(elements).map(loadElement);
|
||||||
};
|
};
|
||||||
|
document.addEventListener("turbo:load", loadSvelte);
|
||||||
document.addEventListener("DOMContentLoaded", loadSvelte);
|
|
||||||
|
|||||||
Generated
+12
@@ -4,6 +4,9 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"@hotwired/turbo": "^8.0.20"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@codemirror/commands": "^6.6.0",
|
"@codemirror/commands": "^6.6.0",
|
||||||
"@codemirror/lang-json": "^6.0.1",
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
@@ -622,6 +625,15 @@
|
|||||||
"node": ">=18"
|
"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": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
|
|||||||
@@ -26,5 +26,8 @@
|
|||||||
"tinymce": "^6.8.4",
|
"tinymce": "^6.8.4",
|
||||||
"trix": "^2.1.5",
|
"trix": "^2.1.5",
|
||||||
"vite": "^7.3.1"
|
"vite": "^7.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@hotwired/turbo": "^8.0.20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php namespace Lucent\Core\Schema\Data;
|
<?php namespace Lucent\Core\Schema\Data;
|
||||||
|
|
||||||
|
use Lucent\Core\Schema\Data\FieldProp\IFieldProp;
|
||||||
|
|
||||||
class Field
|
class Field
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -7,5 +9,7 @@ class Field
|
|||||||
public string $alias,
|
public string $alias,
|
||||||
public string $name,
|
public string $name,
|
||||||
public string $type,
|
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,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
<?php namespace Lucent\Core\Schema;
|
<?php namespace Lucent\Core\Schema;
|
||||||
|
|
||||||
use Lucent\Core\Schema\Data\Field;
|
use Lucent\Core\Schema\Data\Field;
|
||||||
|
use Lucent\Core\Schema\Data\FieldProp\FieldProp;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class FieldModule
|
class FieldModule
|
||||||
{
|
{
|
||||||
public static function fromArray(array $data): Field
|
// public static function fromArray(array $data): Field
|
||||||
{
|
// {
|
||||||
return new Field(
|
// return new Field(
|
||||||
id: $data["id"],
|
// id: $data["id"],
|
||||||
alias: $data["alias"],
|
// alias: $data["alias"],
|
||||||
name: $data["name"],
|
// name: $data["name"],
|
||||||
type: $data["type"],
|
// type: $data["type"],
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static function toDb(Field $field): array
|
public static function toDb(Field $field): array
|
||||||
{
|
{
|
||||||
@@ -21,6 +23,20 @@ class FieldModule
|
|||||||
"alias" => $field->alias,
|
"alias" => $field->alias,
|
||||||
"name" => $field->name,
|
"name" => $field->name,
|
||||||
"type" => $field->type,
|
"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")),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use Lucent\Http\Controller\AccountController;
|
|||||||
use Lucent\Http\Controller\AuthController;
|
use Lucent\Http\Controller\AuthController;
|
||||||
use Lucent\Http\Controller\BuildController;
|
use Lucent\Http\Controller\BuildController;
|
||||||
use Lucent\Http\Controller\EdgeController;
|
use Lucent\Http\Controller\EdgeController;
|
||||||
|
use Lucent\Http\Controller\FieldController;
|
||||||
use Lucent\Http\Controller\FileController;
|
use Lucent\Http\Controller\FileController;
|
||||||
use Lucent\Http\Controller\HomeController;
|
use Lucent\Http\Controller\HomeController;
|
||||||
use Lucent\Http\Controller\MemberController;
|
use Lucent\Http\Controller\MemberController;
|
||||||
@@ -61,6 +62,8 @@ Route::group(
|
|||||||
]);
|
]);
|
||||||
Route::get("/schemas", [SchemaController::class, "home"]);
|
Route::get("/schemas", [SchemaController::class, "home"]);
|
||||||
Route::post("/schemas", [SchemaController::class, "postCreate"]);
|
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 () {
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user