Skip to content

Commit aba9294

Browse files
Julien NahumJulien Nahum
authored andcommitted
Added custom code widgets
1 parent 07d8360 commit aba9294

File tree

19 files changed

+373470
-32
lines changed

19 files changed

+373470
-32
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ Model statistics dashboard for your Laravel Application
1111

1212
This Laravel packages gives you a statistic dashboard for you Laravel application. Think of it as a light version of
1313
[Grafana](https://grafana.com/), but built-in your Laravel application, and much easier to get started with.
14-
No code knowledge is required to use Laravel Model Stats, users can do everything from the web interface.
14+
No code knowledge is required to use Laravel Model Stats, users can do everything from the web interface. It also
15+
optionally supports custom-code widgets, allowing you to define your widget data with
16+
code, just like you would do with tinker.
1517

1618
---
1719

@@ -31,7 +33,7 @@ php artisan migrate
3133
```
3234

3335

34-
## Available Widgets
36+
## Available No-Code Widgets
3537

3638
Different type of widgets (daily count, daily average, etc.) are available. When creating a widget,
3739
you choose a Model, an aggregation type and the column(s) for the graph. You can then resize and move the widgets around on your dashboard.
@@ -45,6 +47,27 @@ The aggregation types currently available:
4547

4648
For each widget type, date can be any column: `created_at`,`updated_at`,`custom_date`.
4749

50+
## Custom Code Widgets
51+
52+
You can also use custom code widgets, allowing you to define your widget data with
53+
code, just like you would do with tinker.
54+
55+
Your code must define a `$result` variable containing the data to return to the choosen chart. You can use the `$dateFrom` and `$dateTo` variable.
56+
57+
Example custom code for a bar chart:
58+
59+
```php
60+
$result = [
61+
'a' => 10,
62+
'b' => 20
63+
];
64+
```
65+
66+
Note that for safety reasons, your code won't be allowed to perform any write operations on the database.
67+
You can only use the code to query data and transform it in-memory.
68+
Even if disabling write operations makes things sage, **remote code execution is always a
69+
very risky operation**. Be sure that your dashboard authorization is properly configured. You may want to disable custom code widgets by setting the `MODEL_STATS_CUSTOM_CODE` env variable to `false`.
70+
4871
## Dashboard Authorization
4972

5073
The ModelStats dashboard may be accessed at the `/stats` route. By default, you will only be able to access this
@@ -95,7 +118,8 @@ Please review [our security policy](../../security/policy) on how to report secu
95118

96119
## Inspiration
97120
- [Grafana](https://grafana.com/): for the dashboard/widget aspect
98-
- [Laravel Telescope](https://github.com/laravel/telescope): for many things in the package structure (front-end, authorization...)
121+
- [Laravel/Telescope](https://github.com/laravel/telescope): for many things in the package structure (front-end, authorization...)
122+
- [Spatie/Laravel-Web-Tinker](https://github.com/spatie/laravel-web-tinker): for their web tinker implementation, which is used for custom code widgets
99123

100124
## License
101125

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
"require": {
1919
"php": "^8.0",
2020
"spatie/laravel-package-tools": "^1.4.3",
21-
"illuminate/contracts": "^8.37"
21+
"illuminate/contracts": "^8.37",
22+
"illuminate/support": "^5.8|^6.0|^7.0|^8.0",
23+
"laravel/tinker": "^1.0|^2.0"
2224
},
2325
"require-dev": {
2426
"brianium/paratest": "^6.2",

config/model-stats.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
*/
1818

1919
'enabled' => env('MODEL_STATS_ENABLED', true),
20+
'allow_custom_code' => env('MODEL_STATS_CUSTOM_CODE', true),
2021

2122
/*
2223
|--------------------------------------------------------------------------
2324
| Route Middleware
2425
|--------------------------------------------------------------------------
2526
|
26-
| These middleware will be assigned to every Telescope route, giving you
27+
| These middleware will be assigned to every ModelStats route, giving you
2728
| the chance to add your own middleware to this list or change any of
2829
| the existing middleware. Or, you can simply stick with this list.
2930
|

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
},
3030
"dependencies": {
3131
"chart.js": "^2.9.4",
32+
"codemirror": "^5.63.1",
3233
"vue-chartjs": "^3.5.1",
3334
"vue-grid-layout": "^2.3.12"
3435
}

public/app.css

Lines changed: 255353 additions & 2 deletions
Large diffs are not rendered by default.

public/app.js

Lines changed: 117354 additions & 2 deletions
Large diffs are not rendered by default.

public/mix-manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"/app.js": "/app.js?id=a15abf91bccabf4ac23f",
3-
"/app.css": "/app.css?id=1b1e2e3e366c06d4c19a"
2+
"/app.js": "/app.js?id=1d359e4a46e6fb75ddb1",
3+
"/app.css": "/app.css?id=19e0f7b7376df74f5ecb"
44
}

resources/js/components/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default {
3333
},
3434
3535
data: () => ({
36-
frontEndVersion: 5,
36+
frontEndVersion: 6,
3737
alert: {
3838
type: null,
3939
autoClose: 0,
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<template>
2+
<div class="custom-code">
3+
<label v-if="label" class="text-gray-700 dark:text-gray-300 uppercase font-bold text-xs">
4+
{{ label }} - <button @click="executeCode" class="bg-blue-500 text-white text-xs p-1 rounded hover:bg-blue-400 pointer">Run Code</button>
5+
</label>
6+
<section class="border shadow-sm mt-1 relative">
7+
<textarea ref="codeEditor" class="z-0"/>
8+
<div class="pl-8 border-t bg-blue-100 bg-opacity-70 text-blue-900 absolute inset-x-0 bottom-0 text-sm backdrop-filter backdrop-blur-sm z-20">
9+
Make sure to put your resulting data in a variable named <span class="font-semibold">$result</span>.<br>You can use the variables <span class="font-semibold">$dateFrom</span> and <span class="font-semibold">$dateTo</span> anywhere in your code.
10+
</div>
11+
</section>
12+
<div v-if="error" class="text-sm text-red-500 -bottom-3"
13+
v-html="error"></div>
14+
</div>
15+
16+
</template>
17+
18+
<script>
19+
import 'codemirror/mode/php/php';
20+
import CodeMirror from 'codemirror';
21+
import axios from 'axios';
22+
23+
export default {
24+
data: () => ({
25+
value: '',
26+
codeEditor: null,
27+
error: null,
28+
}),
29+
props: ['path', 'label'],
30+
mounted() {
31+
const config = {
32+
autofocus: true,
33+
extraKeys: {
34+
'Cmd-Enter': () => {
35+
this.executeCode();
36+
},
37+
'Ctrl-Enter': () => {
38+
this.executeCode();
39+
},
40+
},
41+
indentWithTabs: true,
42+
lineNumbers: true,
43+
lineWrapping: true,
44+
mode: 'text/x-php',
45+
tabSize: 4,
46+
};
47+
this.codeEditor = CodeMirror.fromTextArea(this.$refs.codeEditor, config);
48+
this.codeEditor.on('change', editor => {
49+
localStorage.setItem('tinker-tool', editor.getValue());
50+
});
51+
let value = localStorage.getItem('tinker-tool');
52+
if (typeof value === 'string') {
53+
this.codeEditor.setValue(value);
54+
this.codeEditor.execCommand('goDocEnd');
55+
}
56+
},
57+
methods: {
58+
executeCode() {
59+
this.error = null
60+
let code = this.codeEditor.getValue().trim();
61+
if (code === '') {
62+
this.error = 'You must type some code to execute.'
63+
return;
64+
}
65+
this.$emit('execute', code);
66+
},
67+
},
68+
};
69+
</script>
70+
71+
<style src="codemirror/lib/codemirror.css"/>
72+
<style src="codemirror/theme/idea.css"/>

0 commit comments

Comments
 (0)