revisions complete
This commit is contained in:
@@ -221,7 +221,7 @@
|
|||||||
{:else if activeContentTab === "_graph"}
|
{:else if activeContentTab === "_graph"}
|
||||||
<Graph {graph} {record}/>
|
<Graph {graph} {record}/>
|
||||||
{:else if activeContentTab === "_info"}
|
{:else if activeContentTab === "_info"}
|
||||||
<Info bind:record {users} {schema}/>
|
<Info {record} {graph} {users} {schema}/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,23 +2,26 @@
|
|||||||
import {friendlyDate} from "../../helpers";
|
import {friendlyDate} from "../../helpers";
|
||||||
import Avatar from "../account/Avatar.svelte";
|
import Avatar from "../account/Avatar.svelte";
|
||||||
import {usernameById} from "../account/users";
|
import {usernameById} from "../account/users";
|
||||||
import {isEqual} from "lodash";
|
import {isEqual, sortBy} from "lodash";
|
||||||
import Status from "./Status.svelte";
|
|
||||||
import Icon from "../common/Icon.svelte";
|
import Icon from "../common/Icon.svelte";
|
||||||
import RevisionCell from "./revisions/RevisionCell.svelte";
|
import RevisionCell from "./revisions/RevisionCell.svelte";
|
||||||
|
import {getContext} from "svelte";
|
||||||
|
import RevisionEdgeRow from "./revisions/RevisionEdgeRow.svelte";
|
||||||
|
|
||||||
|
const channel = getContext("channel");
|
||||||
export let record;
|
export let record;
|
||||||
|
export let graph;
|
||||||
export let users;
|
export let users;
|
||||||
export let schema;
|
export let schema;
|
||||||
|
let revisionSection;
|
||||||
let rollbackError = "";
|
let rollbackError = "";
|
||||||
$: revisions = [];
|
$: revisions = [];
|
||||||
$: fieldsWithDiff = [];
|
$: fieldsWithDiff = [];
|
||||||
$: selectedRevision = null;
|
$: selectedRevision = null;
|
||||||
$: recordEdges = {};
|
$: edgeFieldsDiff = {};
|
||||||
$: selectedRevisionEdges = {};
|
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.get(`/records/${record.id}/revisions`)
|
.get(`${channel.lucentUrl}/records/${record.id}/revisions`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
revisions = response.data;
|
revisions = response.data;
|
||||||
})
|
})
|
||||||
@@ -26,19 +29,30 @@
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getEdgesByField(edges) {
|
function getEdgesByField(fieldsWithDiff, revision) {
|
||||||
return schema.fields
|
|
||||||
.filter((f) => ["file", "reference"].includes(f.ui))
|
|
||||||
.reduce((c, f) => {
|
|
||||||
let fieldEdges = edges
|
|
||||||
.filter((e) => e.field === f.name)
|
|
||||||
.map((e) =>
|
|
||||||
record._children.find((child) => child.id === e.to)
|
|
||||||
);
|
|
||||||
|
|
||||||
c[f.name] = fieldEdges;
|
edgeFieldsDiff = graph.edges.filter((e) => e.depth === 1).reduce((c, e) => {
|
||||||
|
if (!c[e.field]) {
|
||||||
|
c[e.field] = {
|
||||||
|
record: [],
|
||||||
|
revision: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c[e.field]["record"].push(e)
|
||||||
return c;
|
return c;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
|
||||||
|
edgeFieldsDiff = revision._edges.reduce((c, e) => {
|
||||||
|
if (!c[e.field]) {
|
||||||
|
c[e.field] = {
|
||||||
|
record: [],
|
||||||
|
revision: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c[e.field]["revision"].push(e)
|
||||||
|
return c;
|
||||||
|
}, edgeFieldsDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compare(e, revision) {
|
function compare(e, revision) {
|
||||||
@@ -48,6 +62,8 @@
|
|||||||
fieldsWithDiff = schema.fields.filter((f) => {
|
fieldsWithDiff = schema.fields.filter((f) => {
|
||||||
return !isEqual(selectedRevision.data[f.name], record.data[f.name]);
|
return !isEqual(selectedRevision.data[f.name], record.data[f.name]);
|
||||||
});
|
});
|
||||||
|
getEdgesByField(fieldsWithDiff, revision)
|
||||||
|
revisionSection.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
|
||||||
function rollback(e) {
|
function rollback(e) {
|
||||||
@@ -55,7 +71,7 @@
|
|||||||
rollbackError = "";
|
rollbackError = "";
|
||||||
axios
|
axios
|
||||||
.post(
|
.post(
|
||||||
`/records/${record.id}/rollback/${selectedRevision._sys.version}`
|
`${channel.lucentUrl}/records/${record.id}/rollback/${selectedRevision._sys.version}`
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@@ -101,16 +117,14 @@
|
|||||||
>Rules for this schema
|
>Rules for this schema
|
||||||
</span>
|
</span>
|
||||||
<small>
|
<small>
|
||||||
Revisions are retained for {schema.revisionRetentionDays} days
|
Each record maintains the last {schema.revisions}
|
||||||
<br/>
|
|
||||||
Each record maintains the last {schema.revisionRetentionNumber}
|
|
||||||
versions
|
versions
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="lx-card mt-4">
|
<div class="lx-card mt-4">
|
||||||
{#if schema.revisionRetentionDays > 0}
|
{#if schema.revisions > 0}
|
||||||
<div class="header-small mb-3">Revisions</div>
|
<div class="header-small mb-3">Revisions</div>
|
||||||
{#each revisions as revision}
|
{#each revisions as revision}
|
||||||
{#if revision._sys.version != record._sys.version}
|
{#if revision._sys.version != record._sys.version}
|
||||||
@@ -119,9 +133,7 @@
|
|||||||
class:active={revision._sys.version ===
|
class:active={revision._sys.version ===
|
||||||
selectedRevision?._sys.version}
|
selectedRevision?._sys.version}
|
||||||
>
|
>
|
||||||
<div class="col-2">
|
|
||||||
<Status status={revision.status}/>
|
|
||||||
</div>
|
|
||||||
<div class="col-2">version {revision._sys.version}</div>
|
<div class="col-2">version {revision._sys.version}</div>
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<Avatar
|
<Avatar
|
||||||
@@ -150,6 +162,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<div bind:this={revisionSection}>
|
||||||
{#if selectedRevision}
|
{#if selectedRevision}
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
{#if fieldsWithDiff.length > 0}
|
{#if fieldsWithDiff.length > 0}
|
||||||
@@ -181,7 +194,6 @@
|
|||||||
>
|
>
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<RevisionCell
|
<RevisionCell
|
||||||
edges={recordEdges}
|
|
||||||
{field}
|
{field}
|
||||||
side={record.data[field.name]}
|
side={record.data[field.name]}
|
||||||
colorClass="text-danger"
|
colorClass="text-danger"
|
||||||
@@ -201,7 +213,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<RevisionCell
|
<RevisionCell
|
||||||
edges={selectedRevisionEdges}
|
edges={selectedRevision._edges}
|
||||||
{field}
|
{field}
|
||||||
side={selectedRevision.data[field.name]}
|
side={selectedRevision.data[field.name]}
|
||||||
colorClass="text-success"
|
colorClass="text-success"
|
||||||
@@ -216,8 +228,40 @@
|
|||||||
<span>Nothing will change</span>
|
<span>Nothing will change</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<p class="text-center fw-bold mb-3 mt-5">
|
||||||
|
Record References
|
||||||
|
</p>
|
||||||
|
{#each Object.entries(edgeFieldsDiff) as [field, edges]}
|
||||||
|
<div
|
||||||
|
class="lx-card row p-4 mb-4 w-100"
|
||||||
|
style="overflow:hidden"
|
||||||
|
>
|
||||||
|
<div class="col-4">
|
||||||
|
{field}:
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-8">
|
||||||
|
<p class="mb-2 text-danger">Record</p>
|
||||||
|
{#each edges.record as edge}
|
||||||
|
<RevisionEdgeRow {edge} />
|
||||||
|
{:else}
|
||||||
|
<p>No references</p>
|
||||||
|
{/each}
|
||||||
|
<p class="mt-4 mb-2 text-success">Revision</p>
|
||||||
|
{#each edges.revision as edge}
|
||||||
|
<RevisionEdgeRow {edge} />
|
||||||
|
{:else}
|
||||||
|
<p>No references</p>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.label {
|
.label {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
export let colorClass;
|
export let colorClass;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if ["reference", "file"].includes(field.ui)}
|
{#if ["reference", "file"].includes(field.info.name)}
|
||||||
<div class="{colorClass} field-content">
|
<div class="{colorClass} field-content">
|
||||||
<div class="d-flex align-items-center text-center flex-wrap">
|
<div class="d-flex align-items-center text-center flex-wrap">
|
||||||
{#each edges[field.name] as edgeRecord}
|
{#each edges[field.name] as edgeRecord}
|
||||||
@@ -31,11 +31,11 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if field.ui === "json"}
|
{:else if ["json", "block"].includes(field.info.name)}
|
||||||
<div class="{colorClass} field-content" style="white-space: break-spaces;">
|
<div class="{colorClass} field-content" style="white-space: break-spaces;">
|
||||||
{JSON.stringify(side, null, 2) ?? ""}
|
{JSON.stringify(side, null, 2) ?? ""}
|
||||||
</div>
|
</div>
|
||||||
{:else if field.ui === "rich"}
|
{:else if field.info.name === "rich"}
|
||||||
<div class="{colorClass} field-content">{@html side ?? ""}</div>
|
<div class="{colorClass} field-content">{@html side ?? ""}</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="{colorClass} field-content">{JSON.stringify(side) ?? ""}</div>
|
<div class="{colorClass} field-content">{JSON.stringify(side) ?? ""}</div>
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
import Preview from "../../files/Preview.svelte";
|
||||||
|
import PreviewCardSmall from "../PreviewCardSmall.svelte";
|
||||||
|
import {getContext} from "svelte";
|
||||||
|
|
||||||
|
const channel = getContext("channel")
|
||||||
|
export let edge;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span class="me-3">Rank: {edge.rank}</span>
|
||||||
|
<span>id: </span> <a href="{channel.lucentUrl}/records/{edge.target}" target="_blank">{edge.target}</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -341,20 +341,19 @@ class RecordController extends Controller
|
|||||||
}
|
}
|
||||||
return ok();
|
return ok();
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// public function rollback(Request $request)
|
public function rollback(Request $request)
|
||||||
// {
|
{
|
||||||
// try {
|
try {
|
||||||
// $this->recordService->rollback(
|
$this->recordService->rollback(
|
||||||
// userId: AuthService::currentUserId($request),
|
recordId: $request->route("rid"),
|
||||||
// recordId: $request->route("rid"),
|
version: (int)$request->route("version")
|
||||||
// version: (int)$request->route("version")
|
);
|
||||||
// );
|
} catch (ValidatorException $th) {
|
||||||
// } catch (ValidatorException $th) {
|
return fail($th->getFirstValidatorError());
|
||||||
// return fail($th->getFirstValidatorError());
|
} catch (LucentException|Throwable $th) {
|
||||||
// } catch (LucentException|Throwable $th) {
|
return fail($th);
|
||||||
// return fail($th);
|
}
|
||||||
// }
|
return ok();
|
||||||
// return ok();
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,38 +4,22 @@ namespace Lucent\Http\Controller;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Account\Auth;
|
|
||||||
use Lucent\Channel\ChannelContext;
|
|
||||||
use Lucent\Record\RecordRepo;
|
use Lucent\Record\RecordRepo;
|
||||||
use Lucent\Revision\RevisionRepo;
|
use Lucent\Revision\RevisionRepo;
|
||||||
use Lucent\Schema\SchemaRepo;
|
use Lucent\Revision\RevisionService;
|
||||||
use function Lucent\Response\fail;
|
use function Lucent\Response\fail;
|
||||||
use function Lucent\Response\ok;
|
use function Lucent\Response\ok;
|
||||||
|
|
||||||
class RevisionController extends Controller
|
class RevisionController extends Controller
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
public RevisionService $revisionService
|
||||||
|
){}
|
||||||
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
|
$revisions = $this->revisionService->getByRecordId($request->route("rid"));
|
||||||
$revisions = RevisionRepo::getByRecordId($request->route("rid"));
|
return ok($revisions->toArray());
|
||||||
return ok($revisions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rollback(Request $request)
|
|
||||||
{
|
|
||||||
$schemas = SchemaRepo::all();
|
|
||||||
$revision = RevisionRepo::getByRecordIdAndVersion($request->route("rid"), (int)$request->route("version"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
RecordRepo::replaceMany($schemas, [$revision->toDB()], Auth::currentUserId());
|
|
||||||
} catch (\Lucent\Schema\Validator\ValidatorException $th) {
|
|
||||||
return fail($th->getFirstValidatorError());
|
|
||||||
} catch (\Lucent\LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ 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;
|
||||||
use Lucent\Http\Controller\RecordController;
|
use Lucent\Http\Controller\RecordController;
|
||||||
use Lucent\Revision\RevisionController;
|
use Lucent\Http\Controller\RevisionController;
|
||||||
|
|
||||||
|
|
||||||
Route::group([
|
Route::group([
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ class RecordRepo
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
|
|
||||||
DB::table("records")
|
DB::table("records")->whereIn("id", $ids)->delete();
|
||||||
->whereIn("id", $ids)->delete();
|
|
||||||
DB::table("edges")->whereIn("source", $ids)->delete();
|
DB::table("edges")->whereIn("source", $ids)->delete();
|
||||||
DB::table("edges")->whereIn("target", $ids)->delete();
|
DB::table("edges")->whereIn("target", $ids)->delete();
|
||||||
DB::table("revisions")->whereIn("recordId", $ids)->delete();
|
DB::table("revisions")->whereIn("recordId", $ids)->delete();
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ readonly class RecordService
|
|||||||
|
|
||||||
RecordRepo::create($record);
|
RecordRepo::create($record);
|
||||||
EdgeRepo::update($record->id, $uniqueEdgesCollection);
|
EdgeRepo::update($record->id, $uniqueEdgesCollection);
|
||||||
$this->revisionService->create($record);
|
$this->revisionService->create($record,$uniqueEdgesCollection);
|
||||||
return $record->id;
|
return $record->id;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ readonly class RecordService
|
|||||||
}
|
}
|
||||||
$formattedData = $this->inputFormatter->fill($record->schema, new RecordData($data));
|
$formattedData = $this->inputFormatter->fill($record->schema, new RecordData($data));
|
||||||
|
|
||||||
$uniqueEdgesCollection = null;
|
$uniqueEdgesCollection = new EdgeCollection();
|
||||||
if ($updateEdges) {
|
if ($updateEdges) {
|
||||||
$uniqueEdges = collect($edges)
|
$uniqueEdges = collect($edges)
|
||||||
->map(function ($edge, $index) {
|
->map(function ($edge, $index) {
|
||||||
@@ -161,7 +161,7 @@ readonly class RecordService
|
|||||||
EdgeRepo::update($newRecord->id, $uniqueEdgesCollection);
|
EdgeRepo::update($newRecord->id, $uniqueEdgesCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->revisionService->create($newRecord);
|
$this->revisionService->create($newRecord,$uniqueEdgesCollection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +240,8 @@ readonly class RecordService
|
|||||||
$this->update(
|
$this->update(
|
||||||
id: $revision->recordId,
|
id: $revision->recordId,
|
||||||
data: $revision->data->toArray(),
|
data: $revision->data->toArray(),
|
||||||
|
edges: toArray($revision->_edges),
|
||||||
|
updateEdges: true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
namespace Lucent\Revision;
|
namespace Lucent\Revision;
|
||||||
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Lucent\Edge\Edge;
|
||||||
|
use Lucent\Edge\EdgeCollection;
|
||||||
|
use Lucent\Primitive\Collection;
|
||||||
use Lucent\Record\File;
|
use Lucent\Record\File;
|
||||||
use Lucent\Record\Record;
|
use Lucent\Record\Record;
|
||||||
use Lucent\Record\RecordData;
|
use Lucent\Record\RecordData;
|
||||||
@@ -18,46 +21,15 @@ readonly class Revision
|
|||||||
public string $schema,
|
public string $schema,
|
||||||
public System $_sys,
|
public System $_sys,
|
||||||
public RecordData $data,
|
public RecordData $data,
|
||||||
|
public EdgeCollection $_edges,
|
||||||
public ?File $_file = null,
|
public ?File $_file = null,
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromDB(stdClass $data): Revision
|
|
||||||
{
|
|
||||||
|
|
||||||
$file = json_decode($data->_file, true);
|
public static function fromRecord(Record $record, EdgeCollection $edges): Revision
|
||||||
if (!empty($file)) {
|
|
||||||
|
|
||||||
$file = new File(...$file);
|
|
||||||
} else {
|
|
||||||
$file = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Revision(
|
|
||||||
id: $data->id,
|
|
||||||
recordId: $data->recordId,
|
|
||||||
schema: $data->schema,
|
|
||||||
_sys: System::fromArray(json_decode($data->_sys, true)),
|
|
||||||
data: new RecordData(json_decode($data->data, true)),
|
|
||||||
_file: $file,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toDB(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"id" => $this->id,
|
|
||||||
"recordId" => $this->recordId,
|
|
||||||
"schema" => $this->schema,
|
|
||||||
"_sys" => json_encode($this->_sys),
|
|
||||||
"_file" => json_encode($this->_file),
|
|
||||||
"data" => json_encode($this->data),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function fromRecord(Record $record): Revision
|
|
||||||
{
|
{
|
||||||
return new Revision(
|
return new Revision(
|
||||||
id: (string)Str::uuid(),
|
id: (string)Str::uuid(),
|
||||||
@@ -65,7 +37,8 @@ readonly class Revision
|
|||||||
schema: $record->schema,
|
schema: $record->schema,
|
||||||
_sys: $record->_sys,
|
_sys: $record->_sys,
|
||||||
data: $record->data,
|
data: $record->data,
|
||||||
_file: $record->_file,
|
_edges: $edges,
|
||||||
|
_file: $record->_file
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Revision;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use function Lucent\Response\ok;
|
|
||||||
|
|
||||||
class RevisionController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
private readonly RevisionRepo $revisionRepo,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index(Request $request): Response
|
|
||||||
{
|
|
||||||
$revisions = $this->revisionRepo->getByRecordId($request->route("rid"));
|
|
||||||
return ok($revisions->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,14 @@
|
|||||||
namespace Lucent\Revision;
|
namespace Lucent\Revision;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Lucent\Edge\Edge;
|
||||||
|
use Lucent\Edge\EdgeCollection;
|
||||||
use Lucent\Primitive\Collection;
|
use Lucent\Primitive\Collection;
|
||||||
|
use Lucent\Record\File;
|
||||||
|
use Lucent\Record\RecordData;
|
||||||
|
use Lucent\Record\System;
|
||||||
use PhpOption\Option;
|
use PhpOption\Option;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class RevisionRepo
|
class RevisionRepo
|
||||||
{
|
{
|
||||||
@@ -13,7 +19,7 @@ class RevisionRepo
|
|||||||
|
|
||||||
public function create(Revision $revision): string
|
public function create(Revision $revision): string
|
||||||
{
|
{
|
||||||
$revisionDB = $revision->toDB();
|
$revisionDB = $this->toDB($revision);
|
||||||
DB::table($this->table)->insert($revisionDB);
|
DB::table($this->table)->insert($revisionDB);
|
||||||
return $revision->id;
|
return $revision->id;
|
||||||
}
|
}
|
||||||
@@ -27,13 +33,28 @@ class RevisionRepo
|
|||||||
$revisions = DB::table($this->table)
|
$revisions = DB::table($this->table)
|
||||||
->where("recordId", $rid)
|
->where("recordId", $rid)
|
||||||
->get()
|
->get()
|
||||||
->map([Revision::class, 'fromDB'])
|
->map([$this, 'fromDB'])
|
||||||
->sortByDesc("_sys.version")
|
->sortByDesc("_sys.version")
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
return new Collection($revisions);
|
return new Collection($revisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function cleanupRecord(string $rid, int $numKeep): void
|
||||||
|
{
|
||||||
|
$revisionIds = DB::table($this->table)
|
||||||
|
->where("recordId", $rid)
|
||||||
|
->orderBy("_sys->version", "desc")
|
||||||
|
->limit(100)
|
||||||
|
->skip($numKeep)
|
||||||
|
->get()
|
||||||
|
->pluck("id");
|
||||||
|
|
||||||
|
DB::table($this->table)
|
||||||
|
->whereIn("id", $revisionIds)
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Option<Revision>
|
* @return Option<Revision>
|
||||||
@@ -49,6 +70,42 @@ class RevisionRepo
|
|||||||
return none();
|
return none();
|
||||||
}
|
}
|
||||||
|
|
||||||
return some(Revision::fromDB($res));
|
return some($this->fromDB($res));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDB(Revision $revision): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"id" => $revision->id,
|
||||||
|
"recordId" => $revision->recordId,
|
||||||
|
"schema" => $revision->schema,
|
||||||
|
"_sys" => json_encode($revision->_sys),
|
||||||
|
"_file" => json_encode($revision->_file),
|
||||||
|
"data" => json_encode($revision->data),
|
||||||
|
"_edges" => $revision->_edges->toJson(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromDB(stdClass $data): Revision
|
||||||
|
{
|
||||||
|
$file = json_decode($data->_file, true);
|
||||||
|
if (!empty($file)) {
|
||||||
|
|
||||||
|
$file = new File(...$file);
|
||||||
|
} else {
|
||||||
|
$file = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$edges = array_map(fn($e) => Edge::fromArray($e), json_decode($data->_edges ?? "[]", true));
|
||||||
|
|
||||||
|
return new Revision(
|
||||||
|
id: $data->id,
|
||||||
|
recordId: $data->recordId,
|
||||||
|
schema: $data->schema,
|
||||||
|
_sys: System::fromArray(json_decode($data->_sys, true)),
|
||||||
|
data: new RecordData(json_decode($data->data, true)),
|
||||||
|
_edges: new EdgeCollection(...$edges),
|
||||||
|
_file: $file
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
namespace Lucent\Revision;
|
namespace Lucent\Revision;
|
||||||
|
|
||||||
|
use Lucent\Channel\ChannelService;
|
||||||
|
use Lucent\Edge\Edge;
|
||||||
|
use Lucent\Edge\EdgeCollection;
|
||||||
|
use Lucent\Primitive\Collection;
|
||||||
use Lucent\Record\Record;
|
use Lucent\Record\Record;
|
||||||
use PhpOption\Option;
|
use PhpOption\Option;
|
||||||
|
|
||||||
@@ -9,11 +13,21 @@ readonly class RevisionService
|
|||||||
{
|
{
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
private ChannelService $channelService,
|
||||||
private RevisionRepo $revisionRepo,
|
private RevisionRepo $revisionRepo,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<Revision>
|
||||||
|
*/
|
||||||
|
public function getByRecordId(string $recordId): Collection
|
||||||
|
{
|
||||||
|
|
||||||
|
return $this->revisionRepo->getByRecordId($recordId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Option<Revision>
|
* @return Option<Revision>
|
||||||
*/
|
*/
|
||||||
@@ -23,10 +37,16 @@ readonly class RevisionService
|
|||||||
return $this->revisionRepo->getByRecordIdAndVersion($recordId, $version);
|
return $this->revisionRepo->getByRecordIdAndVersion($recordId, $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(Record $record): string
|
|
||||||
|
public function create(Record $record, EdgeCollection $edges): void
|
||||||
{
|
{
|
||||||
$revision = Revision::fromRecord($record);
|
$schema = $this->channelService->getSchema($record->schema)->get();
|
||||||
return $this->revisionRepo->create($revision);
|
if($schema->revisions <= 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$revision = Revision::fromRecord($record, $edges);
|
||||||
|
$this->revisionRepo->create($revision);
|
||||||
|
$this->revisionRepo->cleanupRecord($record->id,$schema->revisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ class CollectionSchema implements Schema
|
|||||||
/**
|
/**
|
||||||
* @param Collection<FieldInterface> $fields
|
* @param Collection<FieldInterface> $fields
|
||||||
* @param array<string> $visible
|
* @param array<string> $visible
|
||||||
* @param array<string> $fields
|
|
||||||
*/
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $name,
|
public string $name,
|
||||||
@@ -22,6 +21,7 @@ class CollectionSchema implements Schema
|
|||||||
public bool $isEntry = false,
|
public bool $isEntry = false,
|
||||||
public string $color = "",
|
public string $color = "",
|
||||||
public string $titleTemplate = "",
|
public string $titleTemplate = "",
|
||||||
|
public int $revisions = 0,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class FilesSchema implements Schema
|
|||||||
public bool $isEntry = false,
|
public bool $isEntry = false,
|
||||||
public string $color = "",
|
public string $color = "",
|
||||||
public string $titleTemplate = "",
|
public string $titleTemplate = "",
|
||||||
|
public int $revisions = 0,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class SchemaService
|
|||||||
isEntry: $schemaArr["isEntry"] ?? false,
|
isEntry: $schemaArr["isEntry"] ?? false,
|
||||||
color: $schemaArr["color"] ?? "",
|
color: $schemaArr["color"] ?? "",
|
||||||
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
||||||
|
revisions: $schemaArr["revisions"] ?? 0,
|
||||||
),
|
),
|
||||||
"files" => new FilesSchema(
|
"files" => new FilesSchema(
|
||||||
name: $schemaArr["name"],
|
name: $schemaArr["name"],
|
||||||
@@ -35,6 +36,7 @@ class SchemaService
|
|||||||
isEntry: $schemaArr["isEntry"] ?? false,
|
isEntry: $schemaArr["isEntry"] ?? false,
|
||||||
color: $schemaArr["color"] ?? "",
|
color: $schemaArr["color"] ?? "",
|
||||||
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
||||||
|
revisions: $schemaArr["revisions"] ?? 0,
|
||||||
),
|
),
|
||||||
"block" => new BlockSchema(
|
"block" => new BlockSchema(
|
||||||
name: $schemaArr["name"],
|
name: $schemaArr["name"],
|
||||||
|
|||||||
Reference in New Issue
Block a user