From 32f1ce494ee3867871eb8847e612d4f814492b98 Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Tue, 31 May 2022 08:08:40 -0500 Subject: [PATCH] Dashboard code cleanup (#13996) * Dashboard Cleanup Remove static widgets table, list of available widgets should not be in the database. Remove legacy ajax scripts Cleanup and reorganize controllers * reorganize code to put all dashboard things into it's controller better url scheme while supporting the original * lint clean ups * properly formatted language file * style fixes * update schema --- app/Http/Controllers/DashboardController.php | 271 ++++++++++++++++++ .../Controllers/DashboardWidgetController.php | 93 ++++++ .../Form/CopyDashboardController.php | 82 ------ app/Http/Controllers/OverviewController.php | 109 +------ .../{Form => }/WidgetSettingsController.php | 11 +- app/Models/Dashboard.php | 20 -- app/Models/UserWidget.php | 8 +- app/Models/Widget.php | 35 --- app/Policies/DashboardPolicy.php | 94 ++++++ app/Providers/AuthServiceProvider.php | 1 + ..._widgets_column_to_users_widgets_table.php | 32 +++ .../2022_05_25_084617_migrate_widget_ids.php | 45 +++ ...22_05_25_085715_remove_user_widgets_id.php | 32 +++ .../2022_05_25_090027_drop_widgets_table.php | 33 +++ database/seeders/DatabaseSeeder.php | 1 - database/seeders/DefaultWidgetSeeder.php | 126 -------- includes/html/forms/add-dashboard.inc.php | 53 ---- includes/html/forms/delete-dashboard.inc.php | 56 ---- includes/html/forms/edit-dashboard.inc.php | 48 ---- .../forms/update-dashboard-config.inc.php | 79 ----- misc/db_schema.yaml | 13 +- phpstan-baseline-deprecated.neon | 45 --- phpstan-baseline.neon | 35 --- resources/lang/en/widgets.php | 64 +++++ resources/views/overview/default.blade.php | 87 ++---- routes/web.php | 15 +- 26 files changed, 726 insertions(+), 762 deletions(-) create mode 100644 app/Http/Controllers/DashboardController.php create mode 100644 app/Http/Controllers/DashboardWidgetController.php delete mode 100644 app/Http/Controllers/Form/CopyDashboardController.php rename app/Http/Controllers/{Form => }/WidgetSettingsController.php (84%) delete mode 100644 app/Models/Widget.php create mode 100644 app/Policies/DashboardPolicy.php create mode 100644 database/migrations/2022_05_25_084506_add_widgets_column_to_users_widgets_table.php create mode 100644 database/migrations/2022_05_25_084617_migrate_widget_ids.php create mode 100644 database/migrations/2022_05_25_085715_remove_user_widgets_id.php create mode 100644 database/migrations/2022_05_25_090027_drop_widgets_table.php delete mode 100644 database/seeders/DefaultWidgetSeeder.php delete mode 100644 includes/html/forms/add-dashboard.inc.php delete mode 100644 includes/html/forms/delete-dashboard.inc.php delete mode 100644 includes/html/forms/edit-dashboard.inc.php delete mode 100644 includes/html/forms/update-dashboard-config.inc.php create mode 100644 resources/lang/en/widgets.php diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php new file mode 100644 index 0000000000..9e05cc2ad2 --- /dev/null +++ b/app/Http/Controllers/DashboardController.php @@ -0,0 +1,271 @@ +. + * + * @link https://www.librenms.org + * + * @copyright 2022 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers; + +use App\Models\Dashboard; +use App\Models\User; +use App\Models\UserPref; +use App\Models\UserWidget; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Auth; +use LibreNMS\Config; + +class DashboardController extends Controller +{ + /** @var string[] */ + public static $widgets = [ + 'alerts', + 'alertlog', + 'alertlog-stats', + 'availability-map', + 'component-status', + 'device-summary-horiz', + 'device-summary-vert', + 'device-types', + 'eventlog', + 'globe', + 'generic-graph', + 'graylog', + 'generic-image', + 'notes', + 'server-stats', + 'syslog', + 'top-devices', + 'top-errors', + 'top-interfaces', + 'worldmap', + ]; + + /** @var \Illuminate\Support\Collection<\App\Models\Dashboard> */ + private $dashboards; + + public function __construct() + { + $this->authorizeResource(Dashboard::class, 'dashboard'); + } + + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\View\View + */ + public function index(Request $request) + { + $request->validate([ + 'dashboard' => 'integer', + 'bare' => 'nullable|in:yes', + ]); + + $user = $request->user(); + $dashboards = $this->getAvailableDashboards($user); + + // specific dashboard + if (! empty($request->dashboard) && $dashboards->has($request->dashboard)) { + return $this->show($request, $dashboards->get($request->dashboard)); + } + + // default dashboard + $user_default_dash = (int) UserPref::getPref($user, 'dashboard'); + $global_default = (int) Config::get('webui.default_dashboard_id'); + + // load user default + if ($dashboards->has($user_default_dash)) { + return $this->show($request, $dashboards->get($user_default_dash)); + } + + // load global default + if ($dashboards->has($global_default)) { + return $this->show($request, $dashboards->get($global_default)); + } + + // load users first dashboard + $user_first_dashboard = $dashboards->firstWhere('user_id', $user->user_id); + if ($user_first_dashboard) { + return $this->show($request, $user_first_dashboard); + } + + // create a dashboard for this user + return $this->show($request, Dashboard::create([ + 'dashboard_name' => 'Default', + 'user_id' => $user->user_id, + ])); + } + + /** + * @param \Illuminate\Http\Request $request + * @param \App\Models\Dashboard $dashboard + * @return \Illuminate\Contracts\View\View + */ + public function show(Request $request, Dashboard $dashboard) + { + $request->validate([ + 'bare' => 'nullable|in:yes', + ]); + + $user = Auth::user(); + + // Split dashboards into user owned or shared + $dashboards = $this->getAvailableDashboards($user); + [$user_dashboards, $shared_dashboards] = $dashboards->partition(function ($dashboard) use ($user) { + return $dashboard->user_id == $user->user_id; + }); + + $data = $dashboard->widgets; + + if ($data->isEmpty()) { + $data = [ + [ + 'user_widget_id' => 0, + 'title' => 'Add a widget', + 'widget' => 'placeholder', + 'col' => 1, + 'row' => 1, + 'size_x' => 6, + 'size_y' => 2, + 'refresh' => 60, + ], + ]; + } + + $widgets = array_combine(self::$widgets, array_map(function ($widget) { + return trans("widgets.$widget.title"); + }, self::$widgets)); + + $user_list = $user->can('manage', User::class) + ? User::where('user_id', '!=', $user->user_id) + ->orderBy('username') + ->pluck('username', 'user_id') + : []; + + return view('overview.default', [ + 'bare' => $request->get('bare'), + 'dash_config' => $data, + 'dashboard' => $dashboard, + 'hide_dashboard_editor' => UserPref::getPref($user, 'hide_dashboard_editor'), + 'user_dashboards' => $user_dashboards, + 'shared_dashboards' => $shared_dashboards, + 'widgets' => $widgets, + 'user_list' => $user_list, + ]); + } + + public function store(Request $request): JsonResponse + { + $this->validate($request, [ + 'dashboard_name' => 'string|max:255', + ]); + + $name = trim(strip_tags($request->get('dashboard_name'))); + $dashboard = Dashboard::create([ + 'user_id' => Auth::id(), + 'dashboard_name' => $name, + 'access' => 0, + ]); + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'Dashboard ' . htmlentities($name) . ' created', + 'dashboard_id' => $dashboard->dashboard_id, + ]); + } + + public function update(Request $request, Dashboard $dashboard): JsonResponse + { + $validated = $this->validate($request, [ + 'dashboard_name' => 'string|max:255', + 'access' => 'int|in:0,1,2', + ]); + + $dashboard->fill($validated); + $dashboard->save(); + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'Dashboard ' . htmlentities($dashboard->dashboard_name) . ' updated', + ]); + } + + public function destroy(Dashboard $dashboard): JsonResponse + { + $dashboard->widgets()->delete(); + $dashboard->delete(); + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'Dashboard deleted', + ]); + } + + public function copy(Request $request, Dashboard $dashboard): JsonResponse + { + $this->validate($request, [ + 'target_user_id' => 'required|exists:App\Models\User,user_id', + ]); + + $target_user_id = $request->get('target_user_id'); + + $this->authorize('copy', [$dashboard, $target_user_id]); + + $dashboard_copy = $dashboard->replicate()->fill([ + 'user_id' => $target_user_id, + 'dashboard_name' => $dashboard->dashboard_name . '_' . Auth::user()->username, + ]); + + if ($dashboard_copy->save()) { + // copy widgets + $dashboard->widgets->each(function (UserWidget $widget) use ($dashboard_copy, $target_user_id) { + $dashboard_copy->widgets()->save($widget->replicate()->fill([ + 'user_id' => $target_user_id, + ])); + }); + + return response()->json([ + 'status' => 'ok', + 'message' => 'Dashboard copied', + ]); + } + + return response()->json([ + 'status' => 'error', + 'message' => 'ERROR: Could not copy Dashboard', + ]); + } + + /** + * @param \App\Models\User $user + * @return \Illuminate\Support\Collection<\App\Models\Dashboard> + */ + private function getAvailableDashboards(User $user): Collection + { + if ($this->dashboards === null) { + $this->dashboards = Dashboard::allAvailable($user)->with('user:user_id,username') + ->orderBy('dashboard_name')->get()->keyBy('dashboard_id'); + } + + return $this->dashboards; + } +} diff --git a/app/Http/Controllers/DashboardWidgetController.php b/app/Http/Controllers/DashboardWidgetController.php new file mode 100644 index 0000000000..600611cb5e --- /dev/null +++ b/app/Http/Controllers/DashboardWidgetController.php @@ -0,0 +1,93 @@ +authorize('update', $dashboard); + + $this->validate($request, [ + 'widget_type' => Rule::in(DashboardController::$widgets), + ]); + + $type = $request->get('widget_type'); + $widget = new UserWidget([ + 'user_id' => Auth::id(), + 'widget' => $type, + 'col' => 1, + 'row' => 1, + 'size_x' => 6, + 'size_y' => 3, + 'title' => trans("widgets.$type.title"), + 'refresh' => 60, + 'settings' => '', + ]); + $dashboard->widgets()->save($widget); + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'Widget ' . htmlentities($widget->title) . ' added', + 'extra' => $widget->attributesToArray(), + ]); + } + + public function remove(UserWidget $widget): JsonResponse + { + $this->authorize('update', $widget->dashboard); + + $widget->delete(); + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'Widget ' . htmlentities($widget->title) . ' removed', + ]); + } + + public function clear(Dashboard $dashboard): JsonResponse + { + $this->authorize('update', $dashboard); + + $dashboard->widgets()->delete(); + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'All widgets removed', + ]); + } + + public function update(Dashboard $dashboard, Request $request): JsonResponse + { + $this->authorize('update', $dashboard); + + $validated = $this->getValidationFactory()->make( + json_decode($request->get('data', '[]'), true), [ + '*' => 'array', + '*.id' => 'integer', + '*.col' => 'integer', + '*.row' => 'integer', + '*.size_x' => 'integer', + '*.size_y' => 'integer', + ])->validate(); + + foreach ($validated as $item) { + if ($widget = UserWidget::find($item['id'])) { + $widget->fill($item); + $widget->save(); + } + } + + return new JsonResponse([ + 'status' => 'ok', + 'message' => 'Widgets updated', + ]); + } +} diff --git a/app/Http/Controllers/Form/CopyDashboardController.php b/app/Http/Controllers/Form/CopyDashboardController.php deleted file mode 100644 index bcb2b1fb4d..0000000000 --- a/app/Http/Controllers/Form/CopyDashboardController.php +++ /dev/null @@ -1,82 +0,0 @@ -. - * - * @link https://www.librenms.org - * - * @copyright 2020 Thomas Berberich - * @author Thomas Berberich - */ - -namespace App\Http\Controllers\Form; - -use App\Http\Controllers\Controller; -use App\Models\Dashboard; -use App\Models\UserWidget; -use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; - -class CopyDashboardController extends Controller -{ - public function store(Request $request) - { - $target_user_id = $request->get('target_user_id'); - $dashboard_id = $request->get('dashboard_id'); - - $dashboard = Dashboard::where(['dashboard_id' => $dashboard_id, 'user_id' => Auth::id()])->first(); - - $success = true; - - if ((empty($dashboard)) || (empty($target_user_id))) { - $success = false; - } - - if ($success) { - $dashboard_copy = $dashboard->replicate()->fill([ - 'user_id' => $target_user_id, - 'dashboard_name' => $dashboard['dashboard_name'] .= '_' . Auth::user()->username, - ]); - $success = $dashboard_copy->save(); - } - - if ($success && isset($dashboard_copy)) { - $widgets = UserWidget::where(['dashboard_id' => $dashboard_id, 'user_id' => Auth::id()])->get(); - - foreach ($widgets as $widget) { - $widget_copy = $widget->replicate()->fill([ - 'user_id' => $target_user_id, - 'dashboard_id' => $dashboard_copy->dashboard_id, - ]); - $success &= $widget_copy->save(); - } - } - - if ($success) { - $status = 'ok'; - $message = 'Dashboard copied'; - } else { - $status = 'error'; - $message = 'ERROR: Could not copy Dashboard'; - } - - return response()->json([ - 'status' => $status, - 'message' => $message, - ]); - } -} diff --git a/app/Http/Controllers/OverviewController.php b/app/Http/Controllers/OverviewController.php index bdc4d911e1..28b8554ddc 100644 --- a/app/Http/Controllers/OverviewController.php +++ b/app/Http/Controllers/OverviewController.php @@ -3,27 +3,22 @@ namespace App\Http\Controllers; use App\Models\BgpPeer; -use App\Models\Dashboard; use App\Models\Device; use App\Models\Port; use App\Models\Service; use App\Models\Syslog; -use App\Models\User; -use App\Models\UserPref; -use App\Models\Widget; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use LibreNMS\Config; class OverviewController extends Controller { + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\View\View + */ public function index(Request $request) { - $request->validate([ - 'dashboard' => 'integer', - 'bare' => 'nullable|in:yes', - ]); - $view = Config::get('front_page'); if (view()->exists("overview.custom.$view")) { @@ -32,90 +27,14 @@ class OverviewController extends Controller return $this->{$view}($request); } - return $this->default($request); - } - - public function default(Request $request) - { - $user = Auth::user(); - $dashboards = Dashboard::allAvailable($user)->with('user:user_id,username')->orderBy('dashboard_name')->get()->keyBy('dashboard_id'); - - // Split dashboards into user owned or shared - [$user_dashboards, $shared_dashboards] = $dashboards->partition(function ($dashboard) use ($user) { - return $dashboard->user_id == $user->user_id; - }); - - if (! empty($request->dashboard) && isset($dashboards[$request->dashboard])) { - // specific dashboard - $dashboard = $dashboards[$request->dashboard]; - } else { - $user_default_dash = (int) UserPref::getPref($user, 'dashboard'); - $global_default = (int) Config::get('webui.default_dashboard_id'); - - // load user default - if (isset($dashboards[$user_default_dash])) { - $dashboard = $dashboards[$user_default_dash]; - // load global default - } elseif (isset($dashboards[$global_default])) { - $dashboard = $dashboards[$global_default]; - // load users first dashboard - } elseif (! empty($user_dashboards)) { - $dashboard = $user_dashboards->first(); - } - - // specific dashboard was requested, but doesn't exist - if (isset($dashboard) && ! empty($request->dashboard)) { - flash() - ->using('template.librenms') - ->title('Requested Dashboard Not Found!') - ->addError("Dashboard #$request->dashboard does not exist! Loaded - " . htmlentities($dashboard->dashboard_name) . ' instead.'); - } - } - - if (! isset($dashboard)) { - $dashboard = Dashboard::create([ - 'dashboard_name' => 'Default', - 'user_id' => $user->user_id, - ]); - } - - $data = $dashboard - ->widgets() - ->select(['user_widget_id', 'users_widgets.widget_id', 'title', 'widget', 'col', 'row', 'size_x', 'size_y', 'refresh', 'settings']) - ->join('widgets', 'widgets.widget_id', '=', 'users_widgets.widget_id') - ->get(); - - if ($data->isEmpty()) { - $data[] = ['user_widget_id'=>'0', - 'widget_id'=>1, - 'title'=>'Add a widget', - 'widget'=>'placeholder', - 'col'=>1, - 'row'=>1, - 'size_x'=>6, - 'size_y'=>2, - 'refresh'=>60, - ]; - } - - $bare = $request->bare; - $data = serialize(json_encode($data)); - $dash_config = unserialize($data); - $hide_dashboard_editor = UserPref::getPref($user, 'hide_dashboard_editor'); - $widgets = Widget::select(['widget_id', 'widget_title'])->orderBy('widget_title')->get(); - - $user_list = []; - if ($user->can('manage', User::class)) { - $user_list = User::select(['username', 'user_id']) - ->where('user_id', '!=', $user->user_id) - ->orderBy('username') - ->get(); - } - - return view('overview.default', compact('bare', 'dash_config', 'dashboard', 'hide_dashboard_editor', 'user_dashboards', 'shared_dashboards', 'widgets', 'user_list')); + // default to dashboard + return (new DashboardController())->index($request); } + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\View\View + */ public function simple(Request $request) { //TODO: All below missing D.ignore = '0' check @@ -168,10 +87,10 @@ class OverviewController extends Controller if (Config::get('enable_syslog')) { $syslog = Syslog::hasAccess(Auth::user()) - ->orderBy('timestamp', 'desc') - ->limit(20) - ->with('device') - ->get(); + ->orderBy('timestamp', 'desc') + ->limit(20) + ->with('device') + ->get(); } return view('overview.simple', compact('devices_down', 'ports_down', 'services_down', 'bgp_down', 'devices_uptime', 'syslog')); diff --git a/app/Http/Controllers/Form/WidgetSettingsController.php b/app/Http/Controllers/WidgetSettingsController.php similarity index 84% rename from app/Http/Controllers/Form/WidgetSettingsController.php rename to app/Http/Controllers/WidgetSettingsController.php index 2f665d0497..cd1e97c012 100644 --- a/app/Http/Controllers/Form/WidgetSettingsController.php +++ b/app/Http/Controllers/WidgetSettingsController.php @@ -19,30 +19,29 @@ * * @link https://www.librenms.org * - * @copyright 2018 Tony Murray + * @copyright 2022 Tony Murray * @author Tony Murray */ -namespace App\Http\Controllers\Form; +namespace App\Http\Controllers; -use App\Http\Controllers\Controller; use App\Models\UserWidget; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class WidgetSettingsController extends Controller { - public function update(Request $request, $widget_settings) + public function update(Request $request, UserWidget $widget): JsonResponse { $this->validate($request, [ 'settings' => 'array', 'settings.refresh' => 'int|min:1', ]); - $widget = UserWidget::with('dashboard')->findOrFail($widget_settings); $widget_settings = (array) $request->get('settings', []); unset($widget_settings['_token']); - if (! $widget->dashboard->canWrite($request->user())) { + if (! $request->user()->can('update', $widget->dashboard)) { return response()->json([ 'status' => 'error', 'message' => 'ERROR: You have no write-access to this dashboard', diff --git a/app/Models/Dashboard.php b/app/Models/Dashboard.php index aad0a854e0..72c3ce7666 100644 --- a/app/Models/Dashboard.php +++ b/app/Models/Dashboard.php @@ -13,26 +13,6 @@ class Dashboard extends Model protected $primaryKey = 'dashboard_id'; protected $fillable = ['user_id', 'dashboard_name', 'access']; - // ---- Helper Functions --- - - /** - * @param User $user - * @return bool - */ - public function canRead($user) - { - return $this->user_id == $user->user_id || $this->access > 0; - } - - /** - * @param User $user - * @return bool - */ - public function canWrite($user) - { - return $this->user_id == $user->user_id || $this->access > 1; - } - // ---- Query scopes ---- /** diff --git a/app/Models/UserWidget.php b/app/Models/UserWidget.php index 46e4b318bd..2719168f27 100644 --- a/app/Models/UserWidget.php +++ b/app/Models/UserWidget.php @@ -4,14 +4,13 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\Relations\HasOne; class UserWidget extends Model { public $timestamps = false; protected $table = 'users_widgets'; protected $primaryKey = 'user_widget_id'; - protected $fillable = ['user_id', 'widget_id', 'col', 'row', 'size_x', 'size_y', 'title', 'refresh', 'settings', 'dashboard_id']; + protected $fillable = ['user_id', 'widget', 'col', 'row', 'size_x', 'size_y', 'title', 'refresh', 'settings', 'dashboard_id']; protected $casts = ['settings' => 'array']; // ---- Define Relationships ---- @@ -21,11 +20,6 @@ class UserWidget extends Model return $this->belongsTo(\App\Models\User::class, 'user_id'); } - public function widget(): HasOne - { - return $this->hasOne(\App\Models\Widget::class, 'widget_id'); - } - public function dashboard(): BelongsTo { return $this->belongsTo(\App\Models\Dashboard::class, 'dashboard_id'); diff --git a/app/Models/Widget.php b/app/Models/Widget.php deleted file mode 100644 index a8f6934bb1..0000000000 --- a/app/Models/Widget.php +++ /dev/null @@ -1,35 +0,0 @@ -. - * - * @link https://www.librenms.org - * - * @copyright 2018 Tony Murray - * @author Tony Murray - */ - -namespace App\Models; - -use Illuminate\Database\Eloquent\Model; - -class Widget extends Model -{ - public $timestamps = false; - protected $primaryKey = 'widget_id'; - protected $fillable = ['widget_title', 'widget', 'base_dimensions']; -} diff --git a/app/Policies/DashboardPolicy.php b/app/Policies/DashboardPolicy.php new file mode 100644 index 0000000000..64732c6d18 --- /dev/null +++ b/app/Policies/DashboardPolicy.php @@ -0,0 +1,94 @@ +user_id == $user->user_id || $dashboard->access > 0; + } + + /** + * Determine whether the user can create dashboards. + * + * @param \App\Models\User $user + * @return mixed + */ + public function create(User $user) + { + return true; + } + + /** + * Determine whether the user can update the dashboard. + * + * @param \App\Models\User $user + * @param \App\Models\Dashboard $dashboard + * @return mixed + */ + public function update(User $user, Dashboard $dashboard) + { + return $dashboard->user_id == $user->user_id || $dashboard->access > 1; + } + + /** + * Determine whether the user can delete the dashboard. + * + * @param \App\Models\User $user + * @param \App\Models\Dashboard $dashboard + * @return mixed + */ + public function delete(User $user, Dashboard $dashboard) + { + return $dashboard->user_id == $user->user_id || $user->isAdmin(); + } + + /** + * Determine whether the user can copy the dashboard. + * + * @param \App\Models\User $user + * @param \App\Models\Dashboard $dashboard + * @param int $target_user_id + * @return bool + */ + public function copy(User $user, Dashboard $dashboard, int $target_user_id): bool + { + // user can copy to themselves if they can view, otherwise admins can + return $user->isAdmin() || ($user->user_id == $target_user_id && $this->view($user, $dashboard)); + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index c258ef0698..ef6ef7d124 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -16,6 +16,7 @@ class AuthServiceProvider extends ServiceProvider */ protected $policies = [ \App\Models\User::class => \App\Policies\UserPolicy::class, + \App\Models\Dashboard::class => \App\Policies\DashboardPolicy::class, \App\Models\Device::class => \App\Policies\DevicePolicy::class, \App\Models\DeviceGroup::class => \App\Policies\DeviceGroupPolicy::class, \App\Models\PollerCluster::class => \App\Policies\PollerClusterPolicy::class, diff --git a/database/migrations/2022_05_25_084506_add_widgets_column_to_users_widgets_table.php b/database/migrations/2022_05_25_084506_add_widgets_column_to_users_widgets_table.php new file mode 100644 index 0000000000..7f9c9c73ea --- /dev/null +++ b/database/migrations/2022_05_25_084506_add_widgets_column_to_users_widgets_table.php @@ -0,0 +1,32 @@ +string('widget', 32)->default('')->after('user_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users_widgets', function (Blueprint $table) { + $table->dropColumn('widget'); + }); + } +} diff --git a/database/migrations/2022_05_25_084617_migrate_widget_ids.php b/database/migrations/2022_05_25_084617_migrate_widget_ids.php new file mode 100644 index 0000000000..66e7b092fa --- /dev/null +++ b/database/migrations/2022_05_25_084617_migrate_widget_ids.php @@ -0,0 +1,45 @@ + */ + private $map; + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $this->map = DB::table('widgets')->pluck('widget', 'widget_id'); + + UserWidget::query()->chunk(1000, function (Collection $widgets) { + $widgets->each(function ($widget) { + $widget->widget = $this->map[$widget->widget_id]; + $widget->save(); + }); + }); + + Schema::table('users_widgets', function (Blueprint $table) { + $table->string('widget', 32)->default(null)->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users_widgets', function (Blueprint $table) { + $table->string('widget', 32)->default('')->change(); + }); + } +} diff --git a/database/migrations/2022_05_25_085715_remove_user_widgets_id.php b/database/migrations/2022_05_25_085715_remove_user_widgets_id.php new file mode 100644 index 0000000000..9efd3951e2 --- /dev/null +++ b/database/migrations/2022_05_25_085715_remove_user_widgets_id.php @@ -0,0 +1,32 @@ +dropColumn('widget_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users_widgets', function (Blueprint $table) { + $table->unsignedInteger('widget_id')->after('widget'); + }); + } +} diff --git a/database/migrations/2022_05_25_090027_drop_widgets_table.php b/database/migrations/2022_05_25_090027_drop_widgets_table.php new file mode 100644 index 0000000000..68fba029b5 --- /dev/null +++ b/database/migrations/2022_05_25_090027_drop_widgets_table.php @@ -0,0 +1,33 @@ +increments('widget_id'); + $table->string('widget_title'); + $table->string('widget')->unique(); + $table->string('base_dimensions', 10); + }); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index a4eceec2ad..380fb0827e 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -14,7 +14,6 @@ class DatabaseSeeder extends Seeder public function run() { $this->call(DefaultAlertTemplateSeeder::class); - $this->call(DefaultWidgetSeeder::class); $this->call(DefaultLegacySchemaSeeder::class); $this->call(ConfigSeeder::class); } diff --git a/database/seeders/DefaultWidgetSeeder.php b/database/seeders/DefaultWidgetSeeder.php deleted file mode 100644 index 388705efac..0000000000 --- a/database/seeders/DefaultWidgetSeeder.php +++ /dev/null @@ -1,126 +0,0 @@ - 'Availability map', - 'widget' => 'availability-map', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Device summary horizontal', - 'widget' => 'device-summary-horiz', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Alerts', - 'widget' => 'alerts', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Device summary vertical', - 'widget' => 'device-summary-vert', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Globe map', - 'widget' => 'globe', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Syslog', - 'widget' => 'syslog', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Eventlog', - 'widget' => 'eventlog', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'World map', - 'widget' => 'worldmap', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Graylog', - 'widget' => 'graylog', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Graph', - 'widget' => 'generic-graph', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Top Devices', - 'widget' => 'top-devices', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Top Interfaces', - 'widget' => 'top-interfaces', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Notes', - 'widget' => 'notes', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'External Images', - 'widget' => 'generic-image', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Component Status', - 'widget' => 'component-status', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Alert History Stats', - 'widget' => 'alertlog-stats', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Server Stats', - 'widget' => 'server-stats', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Alert History', - 'widget' => 'alertlog', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Top Errors', - 'widget' => 'top-errors', - 'base_dimensions' => '6,3', - ], - [ - 'widget_title' => 'Device Types', - 'widget' => 'device-types', - 'base_dimensions' => '6,3', - ], - ]; - - $existing = DB::table('widgets')->pluck('widget'); - - DB::table('widgets')->insert(array_filter($widgets, function ($entry) use ($existing) { - return ! $existing->contains($entry['widget']); - })); - } -} diff --git a/includes/html/forms/add-dashboard.inc.php b/includes/html/forms/add-dashboard.inc.php deleted file mode 100644 index d33f07c0f4..0000000000 --- a/includes/html/forms/add-dashboard.inc.php +++ /dev/null @@ -1,53 +0,0 @@ - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ - -/** - * Create Dashboards - * - * @author Daniel Preussker - * @copyright 2015 Daniel Preussker, QuxLabs UG - * @license GPL - */ -header('Content-type: application/json'); - -if (! Auth::check()) { - $response = [ - 'status' => 'error', - 'message' => 'Unauthenticated', - ]; - echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - exit; -} - -$status = 'error'; -$message = 'unknown error'; - -$dashboard_name = trim(strip_tags($_REQUEST['dashboard_name'])); - -if (! empty($dashboard_name) && ($dash_id = dbInsert(['dashboard_name' => $dashboard_name, 'user_id' => Auth::id()], 'dashboards'))) { - $status = 'ok'; - $message = 'Dashboard ' . $dashboard_name . ' created'; -} else { - $status = 'error'; - $message = 'ERROR: Could not create'; -} - -$response = [ - 'status' => $status, - 'message' => $message, - 'dashboard_id' => $dash_id, -]; - -echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/includes/html/forms/delete-dashboard.inc.php b/includes/html/forms/delete-dashboard.inc.php deleted file mode 100644 index 3a8f731354..0000000000 --- a/includes/html/forms/delete-dashboard.inc.php +++ /dev/null @@ -1,56 +0,0 @@ - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ - -/** - * Delete Dashboards - * - * @author Daniel Preussker - * @copyright 2015 Daniel Preussker, QuxLabs UG - * @license GPL - */ -header('Content-type: application/json'); - -if (! Auth::check()) { - $response = [ - 'status' => 'error', - 'message' => 'Unauthenticated', - ]; - echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - exit; -} - -$status = 'error'; -$message = 'unknown error'; - -$dashboard_id = (int) $_REQUEST['dashboard_id']; - -if ($dashboard_id) { - dbDelete('users_widgets', 'user_id = ? && dashboard_id = ?', [Auth::id(), $dashboard_id]); - if (dbDelete('dashboards', 'user_id = ? && dashboard_id = ?', [Auth::id(), $dashboard_id])) { - $status = 'ok'; - $message = 'Dashboard deleted'; - } else { - $message = 'ERROR: Could not delete dashboard ' . $dashboard_id; - } -} else { - $message = 'ERROR: Not enough params'; -} - -$response = [ - 'status' => $status, - 'message' => $message, -]; - -echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/includes/html/forms/edit-dashboard.inc.php b/includes/html/forms/edit-dashboard.inc.php deleted file mode 100644 index fe0b293914..0000000000 --- a/includes/html/forms/edit-dashboard.inc.php +++ /dev/null @@ -1,48 +0,0 @@ - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ - -/** - * Edit Dashboards - * - * @author Daniel Preussker - * @copyright 2015 Daniel Preussker, QuxLabs UG - * @license GPL - */ -header('Content-type: application/json'); - -$status = 'error'; -$message = 'unknown error'; - -$dashboard_id = (int) $_REQUEST['dashboard_id']; -$dashboard_name = \LibreNMS\Util\Clean::html($_REQUEST['dashboard_name'], []); -$access = $_REQUEST['access']; - -if (isset($dashboard_id) && isset($dashboard_name) && isset($access)) { - if (dbUpdate(['dashboard_name'=> $dashboard_name, 'access'=> $access], 'dashboards', '(user_id = ? || access = 2) && dashboard_id = ?', [Auth::id(), $dashboard_id]) >= 0) { - $status = 'ok'; - $message = 'Dashboard ' . $dashboard_name . ' updated'; - } else { - $message = 'ERROR: Could not update dashboard ' . $dashboard_name; - } -} else { - $message = 'ERROR: Not enough params'; -} - -$response = [ - 'status' => $status, - 'message' => $message, -]; - -echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/includes/html/forms/update-dashboard-config.inc.php b/includes/html/forms/update-dashboard-config.inc.php deleted file mode 100644 index d2657aef6d..0000000000 --- a/includes/html/forms/update-dashboard-config.inc.php +++ /dev/null @@ -1,79 +0,0 @@ - 'error', - 'message' => 'Unauthenticated', - ]; - echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - exit; -} - -$status = 'error'; -$message = 'Error updating user dashboard config'; - -$data = json_decode($vars['data'], true); -$sub_type = $vars['sub_type']; -$widget_id = $vars['widget_id']; -$dasboard_id = $vars['dashboard_id']; - -if ($sub_type == 'remove' && is_numeric($widget_id)) { - if (dbFetchCell('select 1 from dashboards where (user_id = ? || access = 2) && dashboard_id = ?', [Auth::id(), $dasboard_id]) == 1) { - if ($widget_id == 0 || dbDelete('users_widgets', '`user_widget_id`=? AND `dashboard_id`=?', [$widget_id, $dasboard_id])) { - $status = 'ok'; - $message = 'Widget ' . $widget_id . ' removed'; - } - } else { - $status = 'error'; - $message = 'ERROR: You don\'t have write access.'; - } -} elseif ($sub_type == 'remove-all') { - if (dbFetchCell('select 1 from dashboards where (user_id = ? || access = 2) && dashboard_id = ?', [Auth::id(), $dasboard_id]) == 1) { - if (dbDelete('users_widgets', '`dashboard_id`=?', [$dasboard_id])) { - $status = 'ok'; - $message = 'All widgets removed'; - } - } else { - $status = 'error'; - $message = 'ERROR: You don\'t have write access.'; - } -} elseif ($sub_type == 'add' && is_numeric($widget_id)) { - if (dbFetchCell('select 1 from dashboards where (user_id = ? || access = 2) && dashboard_id = ?', [Auth::id(), $dasboard_id]) == 1) { - $widget = dbFetchRow('SELECT * FROM `widgets` WHERE `widget_id`=?', [$widget_id]); - if (is_array($widget)) { - [$x,$y] = explode(',', $widget['base_dimensions']); - $item_id = dbInsert(['user_id'=>Auth::id(), 'widget_id'=>$widget_id, 'col'=>1, 'row'=>1, 'refresh'=>60, 'title'=>$widget['widget_title'], 'size_x'=>$x, 'size_y'=>$y, 'settings'=>'', 'dashboard_id'=>$dasboard_id], 'users_widgets'); - if (is_numeric($item_id)) { - $extra = ['user_widget_id'=>$item_id, 'widget_id'=>$item_id, 'title'=>$widget['widget_title'], 'widget'=>$widget['widget'], 'refresh'=>60, 'size_x'=>$x, 'size_y'=>$y]; - $status = 'ok'; - $message = 'Widget ' . $widget['widget_title'] . ' added'; - } - } - } else { - $status = 'error'; - $message = 'ERROR: You don\'t have write access.'; - } -} else { - if (dbFetchCell('select 1 from dashboards where (user_id = ? || access = 2) && dashboard_id = ?', [Auth::id(), $dasboard_id]) == 1) { - $status = 'ok'; - $message = 'Widgets updated'; - foreach ($data as $line) { - if (is_array($line)) { - $update = ['col'=>$line['col'], 'row'=>$line['row'], 'size_x'=>$line['size_x'], 'size_y'=>$line['size_y']]; - dbUpdate($update, 'users_widgets', '`user_widget_id`=? AND `dashboard_id`=?', [$line['id'], $dasboard_id]); - } - } - } else { - $status = 'error'; - $message = 'ERROR: You don\'t have write access.'; - } -} - -$response = [ - 'status' => $status, - 'message' => $message, - 'extra' => $extra, -]; -echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/misc/db_schema.yaml b/misc/db_schema.yaml index dd4d122858..c883ec3663 100644 --- a/misc/db_schema.yaml +++ b/misc/db_schema.yaml @@ -2067,7 +2067,7 @@ users_widgets: Columns: - { Field: user_widget_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment } - { Field: user_id, Type: 'int unsigned', 'Null': false, Extra: '' } - - { Field: widget_id, Type: 'int unsigned', 'Null': false, Extra: '' } + - { Field: widget, Type: varchar(32), 'Null': false, Extra: '' } - { Field: col, Type: tinyint, 'Null': false, Extra: '' } - { Field: row, Type: tinyint, 'Null': false, Extra: '' } - { Field: size_x, Type: tinyint, 'Null': false, Extra: '' } @@ -2078,7 +2078,7 @@ users_widgets: - { Field: dashboard_id, Type: 'int unsigned', 'Null': false, Extra: '' } Indexes: PRIMARY: { Name: PRIMARY, Columns: [user_widget_id], Unique: true, Type: BTREE } - user_id: { Name: user_id, Columns: [user_id, widget_id], Unique: false, Type: BTREE } + user_id: { Name: user_id, Columns: [user_id], Unique: false, Type: BTREE } vlans: Columns: - { Field: vlan_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment } @@ -2131,15 +2131,6 @@ vrf_lite_cisco: vrf_lite_cisco_device_id_context_name_vrf_name_index: { Name: vrf_lite_cisco_device_id_context_name_vrf_name_index, Columns: [device_id, context_name, vrf_name], Unique: false, Type: BTREE } vrf_lite_cisco_device_id_index: { Name: vrf_lite_cisco_device_id_index, Columns: [device_id], Unique: false, Type: BTREE } vrf_lite_cisco_vrf_name_index: { Name: vrf_lite_cisco_vrf_name_index, Columns: [vrf_name], Unique: false, Type: BTREE } -widgets: - Columns: - - { Field: widget_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment } - - { Field: widget_title, Type: varchar(255), 'Null': false, Extra: '' } - - { Field: widget, Type: varchar(255), 'Null': false, Extra: '' } - - { Field: base_dimensions, Type: varchar(10), 'Null': false, Extra: '' } - Indexes: - PRIMARY: { Name: PRIMARY, Columns: [widget_id], Unique: true, Type: BTREE } - widgets_widget_unique: { Name: widgets_widget_unique, Columns: [widget], Unique: true, Type: BTREE } wireless_sensors: Columns: - { Field: sensor_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment } diff --git a/phpstan-baseline-deprecated.neon b/phpstan-baseline-deprecated.neon index 8d6bbb7ef2..4516141bf3 100644 --- a/phpstan-baseline-deprecated.neon +++ b/phpstan-baseline-deprecated.neon @@ -3087,51 +3087,6 @@ parameters: count: 1 path: includes/html/forms/update-alert-rule.inc.php - - - message: - """ - #^Call to deprecated function dbDelete\\(\\)\\: - Please use Eloquent instead; https\\://laravel\\.com/docs/eloquent\\#deleting\\-models$# - """ - count: 2 - path: includes/html/forms/update-dashboard-config.inc.php - - - - message: - """ - #^Call to deprecated function dbFetchCell\\(\\)\\: - Please use Eloquent instead; https\\://laravel\\.com/docs/eloquent$# - """ - count: 4 - path: includes/html/forms/update-dashboard-config.inc.php - - - - message: - """ - #^Call to deprecated function dbFetchRow\\(\\)\\: - Please use Eloquent instead; https\\://laravel\\.com/docs/eloquent$# - """ - count: 1 - path: includes/html/forms/update-dashboard-config.inc.php - - - - message: - """ - #^Call to deprecated function dbInsert\\(\\)\\: - Please use Eloquent instead; https\\://laravel\\.com/docs/eloquent\\#inserting\\-and\\-updating\\-models$# - """ - count: 1 - path: includes/html/forms/update-dashboard-config.inc.php - - - - message: - """ - #^Call to deprecated function dbUpdate\\(\\)\\: - Please use Eloquent instead; https\\://laravel\\.com/docs/eloquent\\#inserting\\-and\\-updating\\-models$# - """ - count: 1 - path: includes/html/forms/update-dashboard-config.inc.php - - message: """ diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 96b9adf4a0..24effc0b4f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7535,21 +7535,6 @@ parameters: count: 1 path: app/Http/Controllers/DeviceGroupController.php - - - message: "#^Method App\\\\Http\\\\Controllers\\\\Form\\\\CopyDashboardController\\:\\:store\\(\\) has no return type specified\\.$#" - count: 1 - path: app/Http/Controllers/Form/CopyDashboardController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\Form\\\\WidgetSettingsController\\:\\:update\\(\\) has no return type specified\\.$#" - count: 1 - path: app/Http/Controllers/Form/WidgetSettingsController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\Form\\\\WidgetSettingsController\\:\\:update\\(\\) has parameter \\$widget_settings with no type specified\\.$#" - count: 1 - path: app/Http/Controllers/Form/WidgetSettingsController.php - - message: "#^Method App\\\\Http\\\\Controllers\\\\Install\\\\ChecksController\\:\\:checkPhpVersion\\(\\) has no return type specified\\.$#" count: 1 @@ -7840,26 +7825,6 @@ parameters: count: 1 path: app/Http/Controllers/Maps/MapController.php - - - message: "#^Method App\\\\Http\\\\Controllers\\\\OverviewController\\:\\:default\\(\\) has no return type specified\\.$#" - count: 1 - path: app/Http/Controllers/OverviewController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\OverviewController\\:\\:index\\(\\) has no return type specified\\.$#" - count: 1 - path: app/Http/Controllers/OverviewController.php - - - - message: "#^Method App\\\\Http\\\\Controllers\\\\OverviewController\\:\\:simple\\(\\) has no return type specified\\.$#" - count: 1 - path: app/Http/Controllers/OverviewController.php - - - - message: "#^Variable \\$user_dashboards in empty\\(\\) always exists and is always falsy\\.$#" - count: 1 - path: app/Http/Controllers/OverviewController.php - - message: "#^Method App\\\\Http\\\\Controllers\\\\PollerController\\:\\:checkTimeSinceLastPoll\\(\\) has no return type specified\\.$#" count: 1 diff --git a/resources/lang/en/widgets.php b/resources/lang/en/widgets.php new file mode 100644 index 0000000000..521b2582d3 --- /dev/null +++ b/resources/lang/en/widgets.php @@ -0,0 +1,64 @@ + [ + 'title' => 'Alerts', + ], + 'alertlog' => [ + 'title' => 'Alert History', + ], + 'alertlog-stats' => [ + 'title' => 'Alert History Stats', + ], + 'availability-map' => [ + 'title' => 'Availability Map', + ], + 'component-status' => [ + 'title' => 'Component Status', + ], + 'device-summary-horiz' => [ + 'title' => 'Device Summary Horizontal', + ], + 'device-summary-vert' => [ + 'title' => 'Device Summary Vertical', + ], + 'device-types' => [ + 'title' => 'Device Types', + ], + 'eventlog' => [ + 'title' => 'Eventlog', + ], + 'generic-graph' => [ + 'title' => 'Graph', + ], + 'generic-image' => [ + 'title' => 'External Images', + ], + 'globe' => [ + 'title' => 'Globe Map', + ], + 'graylog' => [ + 'title' => 'Graylog', + ], + 'notes' => [ + 'title' => 'Notes', + ], + 'server-stats' => [ + 'title' => 'Server Stats', + ], + 'syslog' => [ + 'title' => 'Syslog', + ], + 'top-devices' => [ + 'title' => 'Top Devices', + ], + 'top-errors' => [ + 'title' => 'Top Errors', + ], + 'top-interfaces' => [ + 'title' => 'Top Interfaces', + ], + 'worldmap' => [ + 'title' => 'World Map', + ], +]; diff --git a/resources/views/overview/default.blade.php b/resources/views/overview/default.blade.php index 1076deeb21..70c9714a50 100644 --- a/resources/views/overview/default.blade.php +++ b/resources/views/overview/default.blade.php @@ -23,7 +23,7 @@ @forelse ($user_dashboards as $dash) @if($dash->dashboard_id != $dashboard->dashboard_id)
  • - dashboard_id") }}">{{ $dash->dashboard_name }} + {{ $dash->dashboard_name }}
  • @endif @empty @@ -36,7 +36,7 @@ @foreach ($shared_dashboards as $dash) @if($dash->dashboard_id != $dashboard->dashboard_id)
  • - dashboard_id") }}"> + {{ ($dash->user->username ?? __('Deleted User')) . ':' . $dash->dashboard_name . ($dash->access == 1 ? ' (Read)' : '') }}
  • @endif @@ -99,8 +99,8 @@
    @@ -124,9 +124,9 @@ @@ -175,7 +175,7 @@