Compare commits
1 Commits
master
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
| b19a84b6ba |
@@ -0,0 +1,5 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", onReady);
|
||||||
|
|
||||||
|
function onReady(){
|
||||||
|
console.log("ready yo")
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>@yield('title') - {{ config("lucent.name") }}</title>
|
<title>@yield('title') - {{ config("lucent.name") }}</title>
|
||||||
@include("lucent::includes.assets")
|
@include("lucent::includes.assets")
|
||||||
|
@stack("scripts")
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
@extends("lucent::layouts.channel")
|
||||||
|
@pushonce("scripts")
|
||||||
|
<script type="module" src="/vendor/lucent/public/js/editor.js"></script>
|
||||||
|
@endpushonce
|
||||||
|
@section("title")
|
||||||
|
Edit Record
|
||||||
|
@endsection
|
||||||
|
@section("content")
|
||||||
|
|
||||||
|
<script type="application/json" id="edit-data">{!! json_encode($record)!!}</script>
|
||||||
|
|
||||||
|
@foreach($schema->groups as $group)
|
||||||
|
<div>{{$group}}</div>
|
||||||
|
@foreach($schema->fields as $field)
|
||||||
|
@php
|
||||||
|
$fieldId = "field-".$field->data->name."-".$record->id;
|
||||||
|
@endphp
|
||||||
|
<div class="editor-field">
|
||||||
|
@include("lucent::new.edit.field-header" ,["id" => $fieldId])
|
||||||
|
{!! $field->renderForm($record, $fieldId) !!}
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="field-header">
|
||||||
|
<div class="labels">
|
||||||
|
<div class="label-and-help">
|
||||||
|
<label for={{$id}}>{{$field->data->label}}</label>
|
||||||
|
@if($field->data->help)
|
||||||
|
<small class="help-text light-text">{{$field->data->help}}</small>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<span tabindex="-1"><code class="field-id">{{$field->data->name}}</code></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@pushonce("scripts")
|
||||||
|
<script>
|
||||||
|
console.log("cool");
|
||||||
|
</script>
|
||||||
|
@endpushonce
|
||||||
|
|
||||||
|
|
||||||
|
yo
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@pushonce("scripts")
|
||||||
|
<script>
|
||||||
|
console.log("cool");
|
||||||
|
</script>
|
||||||
|
@endpushonce
|
||||||
|
|
||||||
|
|
||||||
|
yo
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@pushonce("scripts")
|
||||||
|
<script>
|
||||||
|
console.log("cool");
|
||||||
|
</script>
|
||||||
|
@endpushonce
|
||||||
|
|
||||||
|
|
||||||
|
yo
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@pushonce("scripts")
|
||||||
|
<script>
|
||||||
|
console.log("cool");
|
||||||
|
</script>
|
||||||
|
@endpushonce
|
||||||
|
|
||||||
|
|
||||||
|
yo
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
@pushonce("scripts")
|
||||||
|
<script>
|
||||||
|
console.log("cool");
|
||||||
|
</script>
|
||||||
|
@endpushonce
|
||||||
|
|
||||||
|
|
||||||
|
<input
|
||||||
|
id="{{$fieldId}}"
|
||||||
|
name="{{$data->name}}"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
autocomplete="off"
|
||||||
|
value="{{$record->data[$data->name]}}"
|
||||||
|
/>
|
||||||
@@ -3,41 +3,45 @@
|
|||||||
namespace Lucent\Channel;
|
namespace Lucent\Channel;
|
||||||
|
|
||||||
|
|
||||||
use DirectoryIterator;
|
use Illuminate\Foundation\Application;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Intervention\Image\Drivers\Imagick\Encoders\WebpEncoder;
|
|
||||||
use Lucent\Channel\Data\UserCommand;
|
use Lucent\Channel\Data\UserCommand;
|
||||||
|
use Lucent\Field\Field;
|
||||||
|
use Lucent\LucentException;
|
||||||
use Lucent\Primitive\Collection;
|
use Lucent\Primitive\Collection;
|
||||||
|
use Lucent\Schema\CollectionSchema;
|
||||||
|
use Lucent\Schema\FieldInterface;
|
||||||
|
use Lucent\Schema\FilesSchema;
|
||||||
use Lucent\Schema\Schema;
|
use Lucent\Schema\Schema;
|
||||||
use Lucent\Schema\SchemaService;
|
use Lucent\Schema\SingletonSchema;
|
||||||
use PhpOption\Option;
|
use PhpOption\Option;
|
||||||
|
|
||||||
final class ChannelService
|
final class ChannelService
|
||||||
{
|
{
|
||||||
public Channel $channel;
|
public Channel $channel;
|
||||||
|
/**
|
||||||
|
* @var class-string[]
|
||||||
|
*/
|
||||||
|
public array $fields = [];
|
||||||
|
|
||||||
private function __construct(
|
public function __construct(public Application $app)
|
||||||
public SchemaService $schemaService,
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromConfig(): ChannelService
|
public function load(): void
|
||||||
{
|
{
|
||||||
$schemasArray = [];
|
$schemasArray = [];
|
||||||
if (file_exists(schemas_path())) {
|
if (file_exists(schemas_path())) {
|
||||||
$schemasJson = file_get_contents(schemas_path());
|
$schemasJson = file_get_contents(schemas_path());
|
||||||
$schemasArray = json_decode($schemasJson, true);
|
$schemasArray = json_decode($schemasJson, true);
|
||||||
}
|
}
|
||||||
$schemaService = new SchemaService();
|
|
||||||
$schemasCollection = (new Collection($schemasArray["schemas"] ?? []))->map([$schemaService, 'fromArray']);
|
$schemasCollection = (new Collection($schemasArray["schemas"] ?? []))->map($this->makeSchemafromArray(...));
|
||||||
|
|
||||||
$userCommands = [];
|
$userCommands = [];
|
||||||
foreach (config("lucent.commands") ?? [] as $signature => $desc) {
|
foreach (config("lucent.commands") ?? [] as $signature => $desc) {
|
||||||
$userCommands[] = new UserCommand($desc, $signature);
|
$userCommands[] = new UserCommand($desc, $signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
$channel = new Channel(
|
$channel = new Channel(
|
||||||
name: config("lucent.name") ?? "",
|
name: config("lucent.name") ?? "",
|
||||||
url: rtrim(config("lucent.url") ?? "", "/"),
|
url: rtrim(config("lucent.url") ?? "", "/"),
|
||||||
@@ -48,9 +52,7 @@ final class ChannelService
|
|||||||
roles: $schemasArray["roles"] ?? []
|
roles: $schemasArray["roles"] ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
$channelService = new ChannelService($schemaService);
|
$this->channel = $channel;
|
||||||
$channelService->channel = $channel;
|
|
||||||
return $channelService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,4 +92,81 @@ final class ChannelService
|
|||||||
return $schemasAllRead->merge($schemasCanWrite)->unique()->values()->toArray();
|
return $schemasAllRead->merge($schemasCanWrite)->unique()->values()->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param class-string[] $fields
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function registerFields(array $fields): void
|
||||||
|
{
|
||||||
|
$this->fields = array_merge($this->fields, $fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function makeSchemafromArray(array $schemaArr): Schema
|
||||||
|
{
|
||||||
|
|
||||||
|
return match ($schemaArr["type"]) {
|
||||||
|
"collection" => new CollectionSchema(
|
||||||
|
name: $schemaArr["name"],
|
||||||
|
label: $schemaArr["label"],
|
||||||
|
visible: $schemaArr["visible"] ?? [],
|
||||||
|
groups: $schemaArr["groups"] ?? [],
|
||||||
|
fields: (new Collection($schemaArr["fields"]))->map($this->mapFields(...)),
|
||||||
|
folder: $schemaArr["folder"] ?? "",
|
||||||
|
color: $schemaArr["color"] ?? "",
|
||||||
|
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
|
||||||
|
cardTitle: $schemaArr["titleTemplate"] ?? $schemaArr["cardTitle"] ?? null,
|
||||||
|
cardImage: $schemaArr["cardImage"] ?? null,
|
||||||
|
revisions: $schemaArr["revisions"] ?? 0,
|
||||||
|
read: $schemaArr["read"] ?? [],
|
||||||
|
write: $schemaArr["write"] ?? [],
|
||||||
|
),
|
||||||
|
"singleton" => new SingletonSchema(
|
||||||
|
name: $schemaArr["name"],
|
||||||
|
label: $schemaArr["label"],
|
||||||
|
groups: $schemaArr["groups"] ?? [],
|
||||||
|
fields: (new Collection($schemaArr["fields"]))->map($this->mapFields(...)),
|
||||||
|
folder: $schemaArr["folder"] ?? "",
|
||||||
|
color: $schemaArr["color"] ?? "",
|
||||||
|
cardTitle: $schemaArr["titleTemplate"] ?? $schemaArr["cardTitle"] ?? null,
|
||||||
|
cardImage: $schemaArr["cardImage"] ?? null,
|
||||||
|
revisions: $schemaArr["revisions"] ?? 0,
|
||||||
|
read: $schemaArr["read"] ?? [],
|
||||||
|
write: $schemaArr["write"] ?? [],
|
||||||
|
),
|
||||||
|
"files" => new FilesSchema(
|
||||||
|
name: $schemaArr["name"],
|
||||||
|
label: $schemaArr["label"],
|
||||||
|
fields: (new Collection($schemaArr["fields"]))->map($this->mapFields(...)),
|
||||||
|
disk: $schemaArr["disk"] ?? "lucent",
|
||||||
|
path: $schemaArr["path"] ?? $schemaArr["name"],
|
||||||
|
groups: $schemaArr["groups"] ?? [],
|
||||||
|
folder: $schemaArr["folder"] ?? "",
|
||||||
|
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
|
||||||
|
color: $schemaArr["color"] ?? "",
|
||||||
|
cardTitle: $schemaArr["titleTemplate"] ?? $schemaArr["cardTitle"] ?? null,
|
||||||
|
cardImage: $schemaArr["cardImage"] ?? null,
|
||||||
|
revisions: $schemaArr["revisions"] ?? 0,
|
||||||
|
read: $schemaArr["read"] ?? [],
|
||||||
|
write: $schemaArr["write"] ?? [],
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mapFields(array $field): Field
|
||||||
|
{
|
||||||
|
$uiClass = collect($this->fields)
|
||||||
|
->filter(fn($className) => str_ends_with(strtolower($className), strtolower($field["ui"])))
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (empty($uiClass)) {
|
||||||
|
throw new LucentException("Field UI " . $field["ui"] . " not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$ui = $this->app->make($uiClass);
|
||||||
|
$ui->setData($field);
|
||||||
|
return $ui;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field;
|
||||||
|
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
|
||||||
|
abstract class Field
|
||||||
|
{
|
||||||
|
abstract public function format(RecordData $input, RecordData $output): RecordData;
|
||||||
|
// abstract public function renderForm(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field;
|
||||||
|
|
||||||
|
abstract class FieldData
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field;
|
||||||
|
use Lucent\Schema\FieldType;
|
||||||
|
|
||||||
|
class FieldInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $label,
|
||||||
|
public FieldType $type,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\File;
|
||||||
|
|
||||||
|
use Lucent\Field\FieldData;
|
||||||
|
|
||||||
|
class Data extends FieldData
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $label,
|
||||||
|
public string $mime = "",
|
||||||
|
public string $help = "",
|
||||||
|
public ?int $min = null,
|
||||||
|
public ?int $max = null,
|
||||||
|
public array $collections = [],
|
||||||
|
public string $group = "",
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromArray(array $data): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
name: data_get($data, 'name'),
|
||||||
|
label: data_get($data, 'label'),
|
||||||
|
mime: data_get($data, 'mime',""),
|
||||||
|
help: data_get($data, 'help', ""),
|
||||||
|
min: data_get($data, 'min'),
|
||||||
|
max: data_get($data, 'max'),
|
||||||
|
collections: data_get($data, 'collections',[]),
|
||||||
|
group: data_get($data, 'group', ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\File;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
|
use Lucent\Field\FieldInfo;
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
use Lucent\Schema\FieldType;
|
||||||
|
use Lucent\Schema\Nullable;
|
||||||
|
|
||||||
|
class File extends Field
|
||||||
|
{
|
||||||
|
public FieldInfo $info;
|
||||||
|
public Data $data;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->info = new FieldInfo("file", "File", FieldType::FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData(array $data): void
|
||||||
|
{
|
||||||
|
$this->data = Data::fromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function format(RecordData $input, RecordData $output): RecordData
|
||||||
|
{
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderForm(): string
|
||||||
|
{
|
||||||
|
return view('lucent::new.edit.fields.file', ["info" => $this->info, "data" => $this->data])->render();;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Reference;
|
||||||
|
|
||||||
|
use Lucent\Field\FieldData;
|
||||||
|
|
||||||
|
class Data extends FieldData
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $label,
|
||||||
|
public string $mime = "",
|
||||||
|
public string $help = "",
|
||||||
|
public ?int $min = null,
|
||||||
|
public ?int $max = null,
|
||||||
|
public array $collections = [],
|
||||||
|
public string $searchField = "",
|
||||||
|
public string $layout = "",
|
||||||
|
public string $group = "",
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromArray(array $data): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
name: data_get($data, 'name'),
|
||||||
|
label: data_get($data, 'label'),
|
||||||
|
mime: data_get($data, 'mime',""),
|
||||||
|
help: data_get($data, 'help', ""),
|
||||||
|
min: data_get($data, 'min'),
|
||||||
|
max: data_get($data, 'max'),
|
||||||
|
collections: data_get($data, 'collections',[]),
|
||||||
|
searchField: data_get($data, 'searchField',""),
|
||||||
|
group: data_get($data, 'group', ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Reference;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
|
use Lucent\Field\FieldInfo;
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
use Lucent\Schema\FieldType;
|
||||||
|
|
||||||
|
class Reference extends Field
|
||||||
|
{
|
||||||
|
public FieldInfo $info;
|
||||||
|
public Data $data;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->info = new FieldInfo("reference", "Reference", FieldType::REFERENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData(array $data): void
|
||||||
|
{
|
||||||
|
$this->data = Data::fromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function format(RecordData $input, RecordData $output): RecordData
|
||||||
|
{
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderForm(): string
|
||||||
|
{
|
||||||
|
return view('lucent::new.edit.fields.reference', ["info" => $this->info, "data" => $this->data])->render();;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Rich;
|
||||||
|
|
||||||
|
use Lucent\Field\FieldData;
|
||||||
|
|
||||||
|
class Data extends FieldData
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $label,
|
||||||
|
public bool $required = false,
|
||||||
|
public bool $nullable = false,
|
||||||
|
public string $default = "",
|
||||||
|
public string $help = "",
|
||||||
|
public array $collections = [],
|
||||||
|
public ?int $min = null,
|
||||||
|
public ?int $max = null,
|
||||||
|
public bool $readonly = false,
|
||||||
|
public string $group = "",
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromArray(array $data): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
name: data_get($data, 'name'),
|
||||||
|
label: data_get($data, 'label'),
|
||||||
|
required: data_get($data, 'required', false),
|
||||||
|
nullable: data_get($data, 'nullable', false),
|
||||||
|
default: data_get($data, 'default', ""),
|
||||||
|
help: data_get($data, 'help', ""),
|
||||||
|
min: data_get($data, 'min'),
|
||||||
|
max: data_get($data, 'max'),
|
||||||
|
readonly: data_get($data, 'readonly', false),
|
||||||
|
group: data_get($data, 'group', ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Rich;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
|
use Lucent\Field\FieldInfo;
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
use Lucent\Schema\FieldType;
|
||||||
|
use Lucent\Schema\Nullable;
|
||||||
|
|
||||||
|
class Rich extends Field
|
||||||
|
{
|
||||||
|
public FieldInfo $info;
|
||||||
|
public Data $data;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->info = new FieldInfo("rich", "Rich Editor", FieldType::STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData(array $data): void
|
||||||
|
{
|
||||||
|
$this->data = Data::fromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function format(RecordData $input, RecordData $output): RecordData
|
||||||
|
{
|
||||||
|
$value = $input[$this->data->name] ?? null;
|
||||||
|
$output[$this->data->name] = (new Nullable($this->data->nullable, $value, ""))->value();
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderForm(): string
|
||||||
|
{
|
||||||
|
return view('lucent::new.edit.fields.rich', ["info" => $this->info, "data" => $this->data])->render();;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Slug;
|
||||||
|
|
||||||
|
use Lucent\Field\FieldData;
|
||||||
|
|
||||||
|
class Data extends FieldData
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $label,
|
||||||
|
public bool $required = false,
|
||||||
|
public bool $nullable = false,
|
||||||
|
public ?int $min = null,
|
||||||
|
public ?int $max = null,
|
||||||
|
public string $default = "",
|
||||||
|
public string $help = "",
|
||||||
|
public bool $readonly = false,
|
||||||
|
public string $source = "",
|
||||||
|
public string $group = "",
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromArray(array $data): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
name: data_get($data, 'name'),
|
||||||
|
label: data_get($data, 'label'),
|
||||||
|
required: data_get($data, 'required', false),
|
||||||
|
nullable: data_get($data, 'nullable', false),
|
||||||
|
min: data_get($data, 'min'),
|
||||||
|
max: data_get($data, 'max'),
|
||||||
|
default: data_get($data, 'default', ""),
|
||||||
|
help: data_get($data, 'help', ""),
|
||||||
|
readonly: data_get($data, 'readonly', false),
|
||||||
|
source: data_get($data, 'source',""),
|
||||||
|
group: data_get($data, 'group', ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Slug;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Lucent\Field\Field;
|
||||||
|
use Lucent\Field\FieldInfo;
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
use Lucent\Schema\FieldType;
|
||||||
|
use Lucent\Schema\Nullable;
|
||||||
|
|
||||||
|
class Slug extends Field
|
||||||
|
{
|
||||||
|
public FieldInfo $info;
|
||||||
|
public Data $data;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->info = new FieldInfo("slug", "Slug", FieldType::STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData(array $data): void
|
||||||
|
{
|
||||||
|
$this->data = Data::fromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function format(RecordData $input, RecordData $output): RecordData
|
||||||
|
{
|
||||||
|
$value = !empty($input[$this->data->name]) ? (string)$input[$this->data->name] : null;
|
||||||
|
if(empty($value)){
|
||||||
|
$value = Str::slug($input[$this->data->source]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$output[$this->data->name] = (new Nullable($this->data->nullable, $value, ""))->value();
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderForm(): string
|
||||||
|
{
|
||||||
|
return view('lucent::new.edit.fields.slug', ["info" => $this->info, "data" => $this->data])->render();;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Text;
|
||||||
|
|
||||||
|
use Lucent\Field\FieldData;
|
||||||
|
|
||||||
|
class Data extends FieldData
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public string $label,
|
||||||
|
public bool $required = false,
|
||||||
|
public bool $nullable = false,
|
||||||
|
public ?int $min = null,
|
||||||
|
public ?int $max = null,
|
||||||
|
public string $help = "",
|
||||||
|
public string $default = "",
|
||||||
|
public bool $readonly = false,
|
||||||
|
public ?array $selectOptions = null,
|
||||||
|
public string $group = "",
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromArray(array $data): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
name: data_get($data, 'name'),
|
||||||
|
label: data_get($data, 'label'),
|
||||||
|
required: data_get($data, 'required', false),
|
||||||
|
nullable: data_get($data, 'nullable', false),
|
||||||
|
min: data_get($data, 'min'),
|
||||||
|
max: data_get($data, 'max'),
|
||||||
|
help: data_get($data, 'help', ""),
|
||||||
|
default: data_get($data, 'default', ""),
|
||||||
|
readonly: data_get($data, 'readonly', false),
|
||||||
|
selectOptions: data_get($data, 'selectOptions'),
|
||||||
|
group: data_get($data, 'group', ""),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Field\Text;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
|
use Lucent\Field\FieldInfo;
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
use Lucent\Schema\FieldType;
|
||||||
|
use Lucent\Schema\Nullable;
|
||||||
|
|
||||||
|
class Text extends Field
|
||||||
|
{
|
||||||
|
public FieldInfo $info;
|
||||||
|
public Data $data;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->info = new FieldInfo("text", "Text", FieldType::STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData(array $data): void
|
||||||
|
{
|
||||||
|
$this->data = Data::fromArray($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function format(RecordData $input, RecordData $output): RecordData
|
||||||
|
{
|
||||||
|
$value = !empty($input[$this->data->name]) ? (string)$input[$this->data->name] : null;
|
||||||
|
$output[$this->data->name] = (new Nullable($this->data->nullable, $value, ""))->value();
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderForm($record, string $fieldId): string
|
||||||
|
{
|
||||||
|
return view('lucent::new.edit.fields.text', ["info" => $this->info, "data" => $this->data , "record" => $record, "fieldId" => $fieldId])->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -233,6 +233,49 @@ class RecordController extends Controller
|
|||||||
|
|
||||||
$record = $graph->records->first();
|
$record = $graph->records->first();
|
||||||
|
|
||||||
|
if (!in_array($record->schema, $this->accountService->currentReadableSchemas())) {
|
||||||
|
return $this->svelte->render(
|
||||||
|
layout: "channel",
|
||||||
|
view: "recordNotFound",
|
||||||
|
title: "Schema Not Found",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$schema = $this->channelService->getSchema($record->schema)->get();
|
||||||
|
|
||||||
|
return view("lucent::new.edit.edit",[
|
||||||
|
"schema" => $schema,
|
||||||
|
"graph" => $graph,
|
||||||
|
"record" => $record,
|
||||||
|
"users" => $this->accountService->all(),
|
||||||
|
"isWritable" => in_array($record->schema, $this->accountService->currentWritableSchemas())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function _edit(Request $request)
|
||||||
|
{
|
||||||
|
$rid = $request->route("rid");
|
||||||
|
|
||||||
|
$graph = $this->query
|
||||||
|
->filter(["id" => $rid])
|
||||||
|
->limit(1)
|
||||||
|
->skip(0)
|
||||||
|
->childrenDepth(2)
|
||||||
|
->childrenLimit(200)
|
||||||
|
->parentsDepth(1)
|
||||||
|
->parentsLimit(200)
|
||||||
|
->run();
|
||||||
|
|
||||||
|
if ($graph->records->isEmpty()) {
|
||||||
|
return $this->svelte->render(
|
||||||
|
layout: "channel",
|
||||||
|
view: "recordNotFound",
|
||||||
|
title: "Record Not Found",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$record = $graph->records->first();
|
||||||
|
|
||||||
|
|
||||||
if (!in_array($record->schema, $this->accountService->currentReadableSchemas())) {
|
if (!in_array($record->schema, $this->accountService->currentReadableSchemas())) {
|
||||||
return $this->svelte->render(
|
return $this->svelte->render(
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ use Lucent\Commands\RemoveOrphanRecords;
|
|||||||
use Lucent\Commands\Setup;
|
use Lucent\Commands\Setup;
|
||||||
use Lucent\Commands\SetupDatabase;
|
use Lucent\Commands\SetupDatabase;
|
||||||
use Lucent\Commands\UpgradeFiles122;
|
use Lucent\Commands\UpgradeFiles122;
|
||||||
|
use Lucent\Field\File\File;
|
||||||
|
use Lucent\Field\Reference\Reference;
|
||||||
|
use Lucent\Field\Rich\Rich;
|
||||||
|
use Lucent\Field\Slug\Slug;
|
||||||
|
use Lucent\Field\Text\Text;
|
||||||
use Lucent\File\FileService;
|
use Lucent\File\FileService;
|
||||||
use Lucent\Hook\HookService;
|
use Lucent\Hook\HookService;
|
||||||
use Lucent\Query\DatabaseGraph\DatabaseGraph;
|
use Lucent\Query\DatabaseGraph\DatabaseGraph;
|
||||||
@@ -29,7 +34,6 @@ use Lucent\Query\DatabaseGraph\PgsqlDatabaseGraph;
|
|||||||
use Lucent\Query\DatabaseGraph\SqliteDatabaseGraph;
|
use Lucent\Query\DatabaseGraph\SqliteDatabaseGraph;
|
||||||
use Lucent\Record\Event\RecordCreated;
|
use Lucent\Record\Event\RecordCreated;
|
||||||
use Lucent\Record\Event\RecordUpdated;
|
use Lucent\Record\Event\RecordUpdated;
|
||||||
use Lucent\Record\Record;
|
|
||||||
use Lucent\Revision\Listener\CreateRevision;
|
use Lucent\Revision\Listener\CreateRevision;
|
||||||
|
|
||||||
class LucentServiceProvider extends ServiceProvider
|
class LucentServiceProvider extends ServiceProvider
|
||||||
@@ -40,9 +44,10 @@ class LucentServiceProvider extends ServiceProvider
|
|||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
$this->app->singleton(ChannelService::class, function (Application $application) {
|
$this->app->singleton(ChannelService::class, function (Application $application) {
|
||||||
return ChannelService::fromConfig();
|
return new ChannelService($application);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$this->app->singleton(HookService::class, function (Application $application) {
|
$this->app->singleton(HookService::class, function (Application $application) {
|
||||||
return new HookService;
|
return new HookService;
|
||||||
});
|
});
|
||||||
@@ -69,7 +74,7 @@ class LucentServiceProvider extends ServiceProvider
|
|||||||
/**
|
/**
|
||||||
* Bootstrap any package services.
|
* Bootstrap any package services.
|
||||||
*/
|
*/
|
||||||
public function boot(Router $router): void
|
public function boot(Router $router, ChannelService $channelService): void
|
||||||
{
|
{
|
||||||
|
|
||||||
$manifestPath = public_path('vendor/lucent/dist/manifest.json');
|
$manifestPath = public_path('vendor/lucent/dist/manifest.json');
|
||||||
@@ -102,6 +107,16 @@ class LucentServiceProvider extends ServiceProvider
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$channelService->registerFields([
|
||||||
|
Text::class,
|
||||||
|
Slug::class,
|
||||||
|
Rich::class,
|
||||||
|
File::class,
|
||||||
|
Reference::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$channelService->load();
|
||||||
|
|
||||||
View::share('manifest', $manifest);
|
View::share('manifest', $manifest);
|
||||||
View::share('file', app()->make(FileService::class));
|
View::share('file', app()->make(FileService::class));
|
||||||
Blade::anonymousComponentPath(__DIR__ . '../front/views/components', "lucent");
|
Blade::anonymousComponentPath(__DIR__ . '../front/views/components', "lucent");
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace Lucent\Record;
|
namespace Lucent\Record;
|
||||||
|
|
||||||
use Lucent\Channel\ChannelService;
|
use Lucent\Channel\ChannelService;
|
||||||
|
use Lucent\Field\Field;
|
||||||
use Lucent\Schema\FieldInterface;
|
use Lucent\Schema\FieldInterface;
|
||||||
|
|
||||||
class InputFormatter
|
class InputFormatter
|
||||||
@@ -16,12 +17,8 @@ class InputFormatter
|
|||||||
|
|
||||||
public function fill(string $schemaName, RecordData $input): RecordData
|
public function fill(string $schemaName, RecordData $input): RecordData
|
||||||
{
|
{
|
||||||
|
|
||||||
$schema = $this->channelService->getSchema($schemaName)->get();
|
$schema = $this->channelService->getSchema($schemaName)->get();
|
||||||
|
return $schema->fields->reduce(fn(RecordData $carry, Field $field) => $field->format($input, $carry), new RecordData([]));
|
||||||
$data = $schema->fields->reduce(fn(array $carry, FieldInterface $field) => $field->format($input->toArray(), $carry), []);
|
|
||||||
|
|
||||||
return new RecordData($data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use Lucent\ArrayContainer;
|
|||||||
class RecordData extends ArrayContainer
|
class RecordData extends ArrayContainer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public function merge(RecordData $data): RecordData
|
public function merge(RecordData $data): RecordData
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Schema;
|
namespace Lucent\Schema;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
use Lucent\Primitive\Collection;
|
use Lucent\Primitive\Collection;
|
||||||
|
|
||||||
class CollectionSchema implements Schema
|
class CollectionSchema implements Schema
|
||||||
@@ -9,7 +10,7 @@ class CollectionSchema implements Schema
|
|||||||
public Type $type = Type::COLLECTION;
|
public Type $type = Type::COLLECTION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection<FieldInterface> $fields
|
* @param Collection<Field> $fields
|
||||||
* @param array<string> $visible
|
* @param array<string> $visible
|
||||||
*/
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Lucent\Schema;
|
namespace Lucent\Field;
|
||||||
|
|
||||||
|
|
||||||
class FieldInfo
|
class FieldInfo
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $name,
|
public string $name,
|
||||||
public string $label,
|
public string $label,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Schema;
|
namespace Lucent\Schema;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
use Lucent\Primitive\Collection;
|
use Lucent\Primitive\Collection;
|
||||||
|
|
||||||
class FilesSchema implements Schema
|
class FilesSchema implements Schema
|
||||||
@@ -10,7 +11,7 @@ class FilesSchema implements Schema
|
|||||||
public Type $type = Type::FILES;
|
public Type $type = Type::FILES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection<FieldInterface> $fields
|
* @param Collection<Field> $fields
|
||||||
* @param array<string> $groups
|
* @param array<string> $groups
|
||||||
*/
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
|
|||||||
@@ -13,86 +13,6 @@ class SchemaService
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fromArray(array $schemaArr): Schema
|
|
||||||
{
|
|
||||||
|
|
||||||
return match ($schemaArr["type"]) {
|
|
||||||
"collection" => new CollectionSchema(
|
|
||||||
name: $schemaArr["name"],
|
|
||||||
label: $schemaArr["label"],
|
|
||||||
visible: $schemaArr["visible"] ?? [],
|
|
||||||
groups: $schemaArr["groups"] ?? [],
|
|
||||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
|
||||||
folder: $schemaArr["folder"] ?? "",
|
|
||||||
color: $schemaArr["color"] ?? "",
|
|
||||||
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
|
|
||||||
cardTitle: $schemaArr["titleTemplate"] ?? $schemaArr["cardTitle"] ?? null,
|
|
||||||
cardImage: $schemaArr["cardImage"] ?? null,
|
|
||||||
revisions: $schemaArr["revisions"] ?? 0,
|
|
||||||
read: $schemaArr["read"] ?? [],
|
|
||||||
write: $schemaArr["write"] ?? [],
|
|
||||||
),
|
|
||||||
"singleton" => new SingletonSchema(
|
|
||||||
name: $schemaArr["name"],
|
|
||||||
label: $schemaArr["label"],
|
|
||||||
groups: $schemaArr["groups"] ?? [],
|
|
||||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
|
||||||
folder: $schemaArr["folder"] ?? "",
|
|
||||||
color: $schemaArr["color"] ?? "",
|
|
||||||
cardTitle: $schemaArr["titleTemplate"] ?? $schemaArr["cardTitle"] ?? null,
|
|
||||||
cardImage: $schemaArr["cardImage"] ?? null,
|
|
||||||
revisions: $schemaArr["revisions"] ?? 0,
|
|
||||||
read: $schemaArr["read"] ?? [],
|
|
||||||
write: $schemaArr["write"] ?? [],
|
|
||||||
),
|
|
||||||
"files" => new FilesSchema(
|
|
||||||
name: $schemaArr["name"],
|
|
||||||
label: $schemaArr["label"],
|
|
||||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
|
||||||
disk: $schemaArr["disk"] ?? "lucent",
|
|
||||||
path: $schemaArr["path"] ?? $schemaArr["name"],
|
|
||||||
groups: $schemaArr["groups"] ?? [],
|
|
||||||
folder: $schemaArr["folder"] ?? "",
|
|
||||||
sortBy: $schemaArr["sortBy"] ?? "-_sys.updatedAt",
|
|
||||||
color: $schemaArr["color"] ?? "",
|
|
||||||
cardTitle: $schemaArr["titleTemplate"] ?? $schemaArr["cardTitle"] ?? null,
|
|
||||||
cardImage: $schemaArr["cardImage"] ?? null,
|
|
||||||
revisions: $schemaArr["revisions"] ?? 0,
|
|
||||||
read: $schemaArr["read"] ?? [],
|
|
||||||
write: $schemaArr["write"] ?? [],
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mapFields(array $field): FieldInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
$schemaFields = [
|
|
||||||
\Lucent\Schema\Ui\Checkbox::class,
|
|
||||||
\Lucent\Schema\Ui\Color::class,
|
|
||||||
\Lucent\Schema\Ui\Date::class,
|
|
||||||
\Lucent\Schema\Ui\Datetime::class,
|
|
||||||
\Lucent\Schema\Ui\File::class,
|
|
||||||
\Lucent\Schema\Ui\Json::class,
|
|
||||||
\Lucent\Schema\Ui\Markdown::class,
|
|
||||||
\Lucent\Schema\Ui\Number::class,
|
|
||||||
\Lucent\Schema\Ui\Reference::class,
|
|
||||||
\Lucent\Schema\Ui\Rich::class,
|
|
||||||
\Lucent\Schema\Ui\Slug::class,
|
|
||||||
\Lucent\Schema\Ui\Text::class,
|
|
||||||
\Lucent\Schema\Ui\Textarea::class,
|
|
||||||
];
|
|
||||||
$ui = collect($schemaFields)->filter(function ($className) use ($field) {
|
|
||||||
return str_ends_with(strtolower($className), "\\" . strtolower($field["ui"]));
|
|
||||||
})->first();
|
|
||||||
|
|
||||||
if (empty($ui)) {
|
|
||||||
throw new LucentException("Field UI " . $field["ui"] . " not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($field["ui"]);
|
|
||||||
return new $ui(...$field);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Schema;
|
namespace Lucent\Schema;
|
||||||
|
|
||||||
|
use Lucent\Field\Field;
|
||||||
use Lucent\Primitive\Collection;
|
use Lucent\Primitive\Collection;
|
||||||
|
|
||||||
class SingletonSchema implements Schema
|
class SingletonSchema implements Schema
|
||||||
@@ -9,7 +10,7 @@ class SingletonSchema implements Schema
|
|||||||
public Type $type = Type::COLLECTION;
|
public Type $type = Type::COLLECTION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection<FieldInterface> $fields
|
* @param Collection<Field> $fields
|
||||||
*/
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $name,
|
public string $name,
|
||||||
|
|||||||
Reference in New Issue
Block a user