Skip to content

Commit 3eb81db

Browse files
authored
Support displaying child workflows (#25)
1 parent 4d63997 commit 3eb81db

File tree

9 files changed

+219
-51
lines changed

9 files changed

+219
-51
lines changed

app/Dto/ChartDataPoint.php

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Waterline\Dto;
5+
6+
use JsonSerializable;
7+
8+
class ChartDataPoint implements JsonSerializable
9+
{
10+
public function __construct(
11+
private string $x,
12+
private float | int $yMin,
13+
private float | int $yMax,
14+
private string $type,
15+
) {}
16+
17+
public function jsonSerialize(): mixed
18+
{
19+
return [
20+
'x' => $this->x,
21+
'y' => [$this->yMin, $this->yMax],
22+
'type' => $this->type,
23+
];
24+
}
25+
}

app/Http/Controllers/WorkflowsController.php

+3-31
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Waterline\Http\Controllers;
44

55
use SplFileObject;
6+
use Waterline\Http\Resources\StoredWorkflowResource;
7+
use Waterline\Transformer\WorkflowToChartDataTransformer;
68
use Workflow\Models\StoredWorkflow;
79
use Workflow\Serializers\Y;
810

@@ -34,36 +36,6 @@ public function running() {
3436
public function show($id) {
3537
$flow = config('workflows.stored_workflow_model', StoredWorkflow::class)::with(['exceptions', 'logs'])->find($id);
3638

37-
$flow->arguments = serialize(Y::unserialize($flow->arguments));
38-
39-
$flow->logs = $flow->logs->map(function ($log) {
40-
$log->result = serialize(Y::unserialize($log->result));
41-
return $log;
42-
});
43-
44-
$flow->exceptions = $flow->exceptions->map(function ($exception) {
45-
$exception->code ??= null;
46-
$unserialized = Y::unserialize($exception->exception);
47-
if (is_array($unserialized)
48-
&& array_key_exists('class', $unserialized)
49-
&& is_subclass_of($unserialized['class'], \Throwable::class)
50-
&& file_exists($unserialized['file'])
51-
) {
52-
$file = new SplFileObject($unserialized['file']);
53-
$file->seek($unserialized['line'] - 4);
54-
for ($line = 0; $line < 7; ++$line) {
55-
$exception->code .= $file->current();
56-
$file->next();
57-
if ($file->eof()) break;
58-
}
59-
$exception->code = rtrim($exception->code);
60-
$exception->exception = serialize($unserialized);
61-
}
62-
return $exception;
63-
});
64-
65-
$flow->output = $flow->output === null ? serialize(null) : serialize(Y::unserialize($flow->output));
66-
67-
return $flow;
39+
return StoredWorkflowResource::make($flow);
6840
}
6941
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Waterline\Http\Resources;
5+
6+
use Illuminate\Http\Request;
7+
use Illuminate\Http\Resources\Json\JsonResource;
8+
use SplFileObject;
9+
use Waterline\Transformer\WorkflowToChartDataTransformer;
10+
use Workflow\Models\StoredWorkflow;
11+
use Workflow\Models\StoredWorkflowException;
12+
use Workflow\Serializers\Y;
13+
14+
/**
15+
* @mixin StoredWorkflowException
16+
*/
17+
class StoredWorkflowExceptionResource extends JsonResource
18+
{
19+
public static $wrap = null;
20+
21+
public function toArray(Request $request)
22+
{
23+
$code = null;
24+
$exception = $this->exception;
25+
26+
$unserialized = Y::unserialize($exception);
27+
if (is_array($unserialized)
28+
&& array_key_exists('class', $unserialized)
29+
&& is_subclass_of($unserialized['class'], \Throwable::class)
30+
&& file_exists($unserialized['file'])
31+
) {
32+
$file = new SplFileObject($unserialized['file']);
33+
$file->seek($unserialized['line'] - 4);
34+
for ($line = 0; $line < 7; ++$line) {
35+
$exception->code .= $file->current();
36+
$file->next();
37+
if ($file->eof()) break;
38+
}
39+
$code = rtrim($exception->code);
40+
$exception = serialize($unserialized);
41+
}
42+
43+
return [
44+
"code" => $code,
45+
"exception" => $exception,
46+
"class" => $this->class,
47+
"created_at" => $this->created_at,
48+
];
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Waterline\Http\Resources;
5+
6+
use Illuminate\Http\Request;
7+
use Illuminate\Http\Resources\Json\JsonResource;
8+
use Waterline\Transformer\WorkflowToChartDataTransformer;
9+
use Workflow\Models\StoredWorkflow;
10+
use Workflow\Models\StoredWorkflowLog;
11+
use Workflow\Serializers\Y;
12+
13+
/**
14+
* @mixin StoredWorkflowLog
15+
*/
16+
class StoredWorkflowLogResource extends JsonResource
17+
{
18+
public static $wrap = null;
19+
20+
public function toArray(Request $request)
21+
{
22+
return [
23+
"id" => $this->id,
24+
"index" => $this->index,
25+
"now" => $this->now,
26+
"class" => $this->class,
27+
"result" => serialize(Y::unserialize($this->result)),
28+
"created_at" => $this->created_at,
29+
];
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Waterline\Http\Resources;
5+
6+
use Illuminate\Http\Request;
7+
use Illuminate\Http\Resources\Json\JsonResource;
8+
use Waterline\Transformer\WorkflowToChartDataTransformer;
9+
use Workflow\Models\StoredWorkflow;
10+
use Workflow\Serializers\Y;
11+
12+
/**
13+
* @mixin StoredWorkflow
14+
*/
15+
class StoredWorkflowResource extends JsonResource
16+
{
17+
public static $wrap = null;
18+
19+
public function toArray(Request $request)
20+
{
21+
return [
22+
"id" => $this->id,
23+
"class" => $this->class,
24+
"arguments" => serialize(Y::unserialize($this->arguments)),
25+
"output" => $this->output === null ? serialize(null) : serialize(Y::unserialize($this->output)),
26+
"status" => $this->status,
27+
"created_at" => $this->created_at,
28+
"updated_at" => $this->updated_at,
29+
"logs" => StoredWorkflowLogResource::collection($this->logs),
30+
"exceptions" => StoredWorkflowExceptionResource::collection($this->exceptions),
31+
"chartData" => app(WorkflowToChartDataTransformer::class)->transform($this->resource),
32+
];
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Waterline\Transformer;
5+
6+
use Carbon\CarbonInterface;
7+
use DateTimeInterface;
8+
use Illuminate\Support\Arr;
9+
use Waterline\Dto\ChartDataPoint;
10+
use Workflow\Models\StoredWorkflow;
11+
use Workflow\Models\StoredWorkflowLog;
12+
use Workflow\Workflow;
13+
14+
class WorkflowToChartDataTransformer
15+
{
16+
/**
17+
* @return ChartDataPoint[]
18+
*/
19+
public function transform(StoredWorkflow $storedWorkflow) : array {
20+
$data = $this->transformWorkflow($storedWorkflow);
21+
22+
foreach ($storedWorkflow->children as $childWorkflow) {
23+
$data = array_merge(
24+
$data,
25+
$this->transform($childWorkflow),
26+
);
27+
}
28+
29+
return $data;
30+
}
31+
32+
/**
33+
* @return ChartDataPoint[]
34+
*/
35+
private function transformWorkflow(StoredWorkflow $storedWorkflow) : array {
36+
$data = [
37+
app(ChartDataPoint::class, [
38+
'x' => $storedWorkflow->class,
39+
'yMin' => (float) $storedWorkflow->created_at->isoFormat('XSSS'),
40+
'yMax' => (float) $storedWorkflow->updated_at->isoFormat('XSSS'),
41+
'type' => 'Workflow'
42+
])
43+
];
44+
45+
$prevLogCreated = $storedWorkflow->created_at;
46+
foreach ($storedWorkflow->logs as $log) {
47+
if (is_subclass_of($log->class, Workflow::class)) {
48+
continue;
49+
}
50+
51+
$data[] = $this->transformLog($log, $prevLogCreated);
52+
$prevLogCreated = $log->created_at;
53+
}
54+
55+
return $data;
56+
}
57+
58+
/**
59+
* @return ChartDataPoint
60+
*/
61+
private function transformLog(StoredWorkflowLog $storedWorkflowLog, CarbonInterface $prevLogCreated) : ChartDataPoint {
62+
63+
return app(ChartDataPoint::class, [
64+
'x' => $storedWorkflowLog->class,
65+
'yMin' => (float) $prevLogCreated->isoFormat('XSSS'),
66+
'yMax' => (float) $storedWorkflowLog->created_at->isoFormat('XSSS'),
67+
'type' => 'Activity',
68+
]);
69+
}
70+
}

public/app.js

+2-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/mix-manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"/app.js": "/app.js?id=ad4fe9437176e22cd21076e124a481f3",
2+
"/app.js": "/app.js?id=d8462d5df178a947e8a71869b5ea1018",
33
"/app-dark.css": "/app-dark.css?id=3e8dddb1d146175eb19d916f9cd87bfa",
44
"/app.css": "/app.css?id=12fca36d651455c3d460d9c4abf772c5",
55
"/img/favicon.png": "/img/favicon.png?id=7c006241b093796d6abfa3049df93a59",

resources/js/screens/flows/flow.vue

+3-12
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export default {
233233
let data = w.globals.initialSeries[seriesIndex].data[dataPointIndex]
234234
235235
return '<div style="padding: 1em">' +
236-
'<b>Activity</b>: ' + data.x.split('_')[0] + '<br />' +
236+
'<b>'+data.type+'</b>: ' + data.x.split('_')[0] + '<br />' +
237237
'<b>Time</b>: ' + (data.y[1] - data.y[0]) + 'ms </div>'
238238
}
239239
if (seriesIndex === 1) {
@@ -298,16 +298,7 @@ export default {
298298
this.$http.get(Waterline.basePath + '/api/flows/' + id)
299299
.then(response => {
300300
this.flow = response.data;
301-
this.series[0].data = this.flow.logs.map((activity, index, activities) => {
302-
return {
303-
x: activity.class,
304-
y: [
305-
index === 0 ? moment(this.flow.created_at).valueOf() : moment(activities[index - 1].created_at).valueOf(),
306-
moment(activity.created_at).valueOf(),
307-
],
308-
}
309-
})
310-
301+
this.series[0].data = response.data.chartData;
311302
this.series[1].data = this.flow.exceptions.map((exception) => {
312303
this.$nextTick(() => {
313304
this.$nextTick(() => {
@@ -331,7 +322,7 @@ export default {
331322
],
332323
fillColor: '#721c24',
333324
}
334-
})
325+
});
335326
336327
this.ready = true;
337328
});

0 commit comments

Comments
 (0)