├── .gitignore ├── LICENSE.md ├── composer.json ├── dist ├── css │ └── card.css ├── js │ └── card.js └── mix-manifest.json ├── img ├── after.gif ├── custom-trend.png └── metrics-before.gif ├── package.json ├── readme.md ├── resources ├── js │ ├── card.js │ └── components │ │ ├── CustomPartitionMetric.vue │ │ ├── CustomTrendMetric.vue │ │ └── CustomValueMetric.vue └── sass │ └── card.scss ├── routes └── api.php ├── src ├── CardServiceProvider.php ├── CustomPartition.php ├── CustomTrend.php └── CustomValue.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | package-lock.json 5 | composer.phar 6 | composer.lock 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Square1 LTD hello@square1.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "square1/nova-metrics", 3 | "description": "Add support for resource-filters on your laravel nova metrics", 4 | "keywords": [ 5 | "laravel", 6 | "nova", 7 | "metrics", 8 | "filters" 9 | ], 10 | "license": "MIT", 11 | "require": { 12 | "php": ">=7.1.0" 13 | }, 14 | "autoload": { 15 | "psr-4": { 16 | "Square1\\NovaMetrics\\": "src/" 17 | } 18 | }, 19 | "extra": { 20 | "laravel": { 21 | "providers": [ 22 | "Square1\\NovaMetrics\\CardServiceProvider" 23 | ] 24 | } 25 | }, 26 | "config": { 27 | "sort-packages": true 28 | }, 29 | "minimum-stability": "dev", 30 | "prefer-stable": true 31 | } 32 | -------------------------------------------------------------------------------- /dist/css/card.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square1-io/nova-metrics/f006fe8f79db058fb49ee57fc79f2e8346933b36/dist/css/card.css -------------------------------------------------------------------------------- /dist/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/js/card.js": "/js/card.js", 3 | "/css/card.css": "/css/card.css" 4 | } -------------------------------------------------------------------------------- /img/after.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square1-io/nova-metrics/f006fe8f79db058fb49ee57fc79f2e8346933b36/img/after.gif -------------------------------------------------------------------------------- /img/custom-trend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square1-io/nova-metrics/f006fe8f79db058fb49ee57fc79f2e8346933b36/img/custom-trend.png -------------------------------------------------------------------------------- /img/metrics-before.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/square1-io/nova-metrics/f006fe8f79db058fb49ee57fc79f2e8346933b36/img/metrics-before.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "cross-env": "^5.0.0", 14 | "laravel-mix": "^1.0" 15 | }, 16 | "dependencies": { 17 | "vue": "^2.5.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Custom Nova Metrics Components 2 | 3 | This package will allow you to access your resource-filters on any Laravel Nova Metric class, and will update these cards dynamically every time you select a new filter on your resources-list. 4 | 5 | --- 6 | 7 | Charts are a great way to display graphic information on your dashboard, and with Laravel Nova you can create beautiful **Metrics Cards** really fast. 8 | 9 | You can use these charts on your resource views as well. 10 | 11 | ![Custom Trend](./img/custom-trend.png "CustomTrend") 12 | 13 | Usually when you add those metrics to any resource, you'd expect the chart to be a representation of the data you are seeing in the list down below. Currently on Nova this is not possible - when you change a filter selection, the resources-list is updated, but the corresponding charts are not. 14 | 15 | ![Custom Trend](./img/metrics-before.gif "Nova Filters") 16 | 17 | This happens because the requests to populate the list are independent from the request used to get the metrics-data. This means that updating the filters breaks the connection with the charts, leaving them outdated. 18 | 19 | This package restores that connection, ensuring that the charts and data on-screen remain in sync. 20 | 21 | ![Custom Trend](./img/after.gif "Nova Filters") 22 | 23 | ## Install 24 | 25 | Install via composer 26 | 27 | ```bash 28 | composer require square1/nova-metrics 29 | ``` 30 | 31 | ## Usage 32 | 33 | You can create new metrics using the default nova commands: 34 | 35 | ```bash 36 | php artisan nova:partition NewPartition 37 | php artisan nova:trend NewTrend 38 | php artisan nova:value NewValue 39 | ``` 40 | 41 | Then you only need to update your recently created metric class. Extend from one of the following classes to have access to your resource filters: 42 | 43 | ```php 44 | use Square1\NovaMetrics\CustomTrend; 45 | use Square1\NovaMetrics\CustomValue; 46 | use Square1\NovaMetrics\CustomPartition; 47 | ``` 48 | 49 | For example: 50 | 51 | ```php 52 | filters 65 | } 66 | } 67 | ``` 68 | 69 | Let's say you have a `CategoryFilter::class` : 70 | 71 | ```php 72 | where('category', $value); 88 | } 89 | 90 | public function options(Request $request) 91 | { 92 | return [ 93 | 'css' => 'css', 94 | 'javascript' => 'javascript', 95 | 'laravel' =>'laravel', 96 | 'php' => 'php', 97 | ]; 98 | } 99 | } 100 | ``` 101 | 102 | This is how you can apply this filter to your `NewTrend::class` : 103 | 104 | ```php 105 | class NewTrend extends CustomTrend 106 | { 107 | public function calculate(NovaRequest $request) 108 | { 109 | $model = Post::make(); 110 | 111 | if (!empty($filters)) { 112 | if ($request->has('filters')) { 113 | // Get the decoded list of filters 114 | $filters = json_decode(base64_decode($request->filters)); 115 | 116 | foreach ($filters as $filter) { 117 | if (empty($filter->value)) { 118 | continue; 119 | } 120 | // Create a new instance of the filter and apply the query to your model 121 | $model = (new $filter->class)->apply($request, $model, $filter->value); 122 | } 123 | } 124 | } 125 | 126 | return $this->averageByDays($request, $model, 'pageviews'); 127 | } 128 | } 129 | ``` 130 | 131 | --- 132 | 133 | ## Known Issues 134 | 135 | If you'd like to contribute on this package, this is a good place to start 🙂 136 | 137 | - Wait until the first `resources-loaded` event is fired to load the cards. 138 | - Decode the `$request->filters` in the request object. 139 | 140 | ## Credits 141 | 142 | - [Jeff Ochoa](https://github.com/jeffochoa) 143 | - [All Contributors](../../contributors) 144 | 145 | ## License 146 | 147 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 148 | -------------------------------------------------------------------------------- /resources/js/card.js: -------------------------------------------------------------------------------- 1 | Nova.booting((Vue, router, store) => { 2 | Vue.component('CustomTrendMetric', require('./components/CustomTrendMetric')) 3 | Vue.component('CustomValueMetric', require('./components/CustomValueMetric')) 4 | Vue.component('CustomPartitionMetric', require('./components/CustomPartitionMetric')) 5 | }) 6 | -------------------------------------------------------------------------------- /resources/js/components/CustomPartitionMetric.vue: -------------------------------------------------------------------------------- 1 | 44 | -------------------------------------------------------------------------------- /resources/js/components/CustomTrendMetric.vue: -------------------------------------------------------------------------------- 1 | 44 | -------------------------------------------------------------------------------- /resources/js/components/CustomValueMetric.vue: -------------------------------------------------------------------------------- 1 | 41 | -------------------------------------------------------------------------------- /resources/sass/card.scss: -------------------------------------------------------------------------------- 1 | // Nova Card CSS 2 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | app->booted(function () { 20 | $this->routes(); 21 | }); 22 | 23 | Nova::serving(function (ServingNova $event) { 24 | Nova::script('CustomTrend', __DIR__.'/../dist/js/card.js'); 25 | Nova::style('CustomTrend', __DIR__.'/../dist/css/card.css'); 26 | 27 | Nova::script('CustomValue', __DIR__.'/../dist/js/card.js'); 28 | Nova::style('CustomValue', __DIR__.'/../dist/css/card.css'); 29 | 30 | Nova::script('CustomPartition', __DIR__.'/../dist/js/card.js'); 31 | Nova::style('CustomPartition', __DIR__.'/../dist/css/card.css'); 32 | }); 33 | } 34 | 35 | /** 36 | * Register the card's routes. 37 | * 38 | * @return void 39 | */ 40 | protected function routes() 41 | { 42 | if ($this->app->routesAreCached()) { 43 | return; 44 | } 45 | 46 | Route::middleware(['nova']) 47 | ->prefix('nova-vendor/CustomTrend') 48 | ->group(__DIR__.'/../routes/api.php'); 49 | 50 | Route::middleware(['nova']) 51 | ->prefix('nova-vendor/CustomValue') 52 | ->group(__DIR__.'/../routes/api.php'); 53 | 54 | Route::middleware(['nova']) 55 | ->prefix('nova-vendor/CustomPartition') 56 | ->group(__DIR__.'/../routes/api.php'); 57 | } 58 | 59 | /** 60 | * Register any application services. 61 | * 62 | * @return void 63 | */ 64 | public function register() 65 | { 66 | // 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/CustomPartition.php: -------------------------------------------------------------------------------- 1 |