PHP-Flasher for toast messages (#13401)

* PHP-Flasher for toast messages
Allows customized template
removes dependency on unmaintained package using dev stability
no solution for javascript toasts yet

Use DI in places it makes sense

allow html in flashes

Use "template.librenms" as a default notification style

merge toast containers
toastr needs to be second because it will find the containr made by flasher, but the inverse is not true

upgrade php-flasher to add custom options and persistent notifications

Add dark theme

* update composer.lock
This commit is contained in:
Tony Murray 2021-10-29 09:13:56 -05:00 committed by GitHub
parent 38773598e0
commit 5900edbf16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 598 additions and 158 deletions

View File

@ -27,11 +27,11 @@ namespace App;
use App\Models\Device;
use App\Models\Notification;
use App\Models\User;
use Cache;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use LibreNMS\Config;
use Toastr;
class Checks
{
@ -47,31 +47,38 @@ class Checks
Cache::put('checks_popup_timeout', true, Config::get('checks_popup_timer', 5) * 60);
/** @var User $user */
$user = Auth::user();
if ($user->isAdmin()) {
$notifications = Notification::isUnread($user)->where('severity', '>', \LibreNMS\Enum\Alert::OK)->get();
foreach ($notifications as $notification) {
Toastr::error("<a href='notifications/'>$notification->body</a>", $notification->title);
flash()
->using('template.librenms')
->title($notification->title)
->addWarning("<a href='notifications/'>$notification->body</a>");
}
$warn_sec = Config::get('rrd.step', 300) * 3;
if (Device::isUp()->where('last_polled', '<=', Carbon::now()->subSeconds($warn_sec))->exists()) {
$warn_min = $warn_sec / 60;
Toastr::warning('<a href="poller/log?filter=unpolled/">It appears as though you have some devices that haven\'t completed polling within the last ' . $warn_min . ' minutes, you may want to check that out :)</a>', 'Devices unpolled');
flash()
->using('template.librenms')
->title('Devices unpolled')
->addWarning('<a href="poller/log?filter=unpolled/">It appears as though you have some devices that haven\'t completed polling within the last ' . $warn_min . ' minutes, you may want to check that out :)</a>');
}
// Directory access checks
$rrd_dir = Config::get('rrd_dir');
if (! is_dir($rrd_dir)) {
Toastr::error("RRD Directory is missing ($rrd_dir). Graphing may fail. <a href=" . url('validate') . '>Validate your install</a>');
flash()->addError("RRD Directory is missing ($rrd_dir). Graphing may fail. <a href=" . url('validate') . '>Validate your install</a>');
}
$temp_dir = Config::get('temp_dir');
if (! is_dir($temp_dir)) {
Toastr::error("Temp Directory is missing ($temp_dir). Graphing may fail. <a href=" . url('validate') . '>Validate your install</a>');
flash()->addError("Temp Directory is missing ($temp_dir). Graphing may fail. <a href=" . url('validate') . '>Validate your install</a>');
} elseif (! is_writable($temp_dir)) {
Toastr::error("Temp Directory is not writable ($temp_dir). Graphing may fail. <a href='" . url('validate') . "'>Validate your install</a>");
flash()->addError("Temp Directory is not writable ($temp_dir). Graphing may fail. <a href='" . url('validate') . "'>Validate your install</a>");
}
}
}

View File

@ -34,7 +34,6 @@ use LibreNMS\Authentication\TwoFactor;
use LibreNMS\Config;
use LibreNMS\Exceptions\AuthenticationException;
use Session;
use Toastr;
class TwoFactorController extends Controller
{
@ -55,7 +54,7 @@ class TwoFactorController extends Controller
UserPref::forgetPref(auth()->user(), 'twofactor');
$request->session()->forget(['twofactor', 'twofactorremove']);
\Toastr::info(__('TwoFactor auth removed.'));
flash()->addInfo(__('TwoFactor auth removed.'));
return redirect('preferences');
}
@ -193,7 +192,7 @@ class TwoFactorController extends Controller
// notify if added
if (Session::has('twofactoradd')) {
Toastr::success(__('TwoFactor auth added.'));
flash()->addSuccess(__('TwoFactor auth added.'));
Session::forget('twofactoradd');
}

View File

@ -4,11 +4,11 @@ namespace App\Http\Controllers;
use App\Models\Device;
use App\Models\DeviceGroup;
use Flasher\Prime\FlasherInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use LibreNMS\Alerting\QueryBuilderFilter;
use LibreNMS\Alerting\QueryBuilderFluentParser;
use Toastr;
class DeviceGroupController extends Controller
{
@ -55,7 +55,7 @@ class DeviceGroupController extends Controller
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(Request $request, FlasherInterface $flasher)
{
$this->validate($request, [
'name' => 'required|string|unique:device_groups',
@ -73,7 +73,7 @@ class DeviceGroupController extends Controller
$deviceGroup->devices()->sync($request->devices);
}
Toastr::success(__('Device Group :name created', ['name' => $deviceGroup->name]));
$flasher->addSuccess(__('Device Group :name created', ['name' => $deviceGroup->name]));
return redirect()->route('device-groups.index');
}
@ -116,7 +116,7 @@ class DeviceGroupController extends Controller
* @param \App\Models\DeviceGroup $deviceGroup
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request, DeviceGroup $deviceGroup)
public function update(Request $request, DeviceGroup $deviceGroup, FlasherInterface $flasher)
{
$this->validate($request, [
'name' => [
@ -149,9 +149,9 @@ class DeviceGroupController extends Controller
if ($deviceGroup->isDirty() || $devices_updated) {
try {
if ($deviceGroup->save() || $devices_updated) {
Toastr::success(__('Device Group :name updated', ['name' => $deviceGroup->name]));
$flasher->addSuccess(__('Device Group :name updated', ['name' => $deviceGroup->name]));
} else {
Toastr::error(__('Failed to save'));
$flasher->addError(__('Failed to save'));
return redirect()->back()->withInput();
}
@ -161,7 +161,7 @@ class DeviceGroupController extends Controller
]);
}
} else {
Toastr::info(__('No changes made'));
$flasher->addInfo(__('No changes made'));
}
return redirect()->route('device-groups.index');

View File

@ -14,7 +14,6 @@ use App\Models\Widget;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use LibreNMS\Config;
use Toastr;
class OverviewController extends Controller
{
@ -66,11 +65,11 @@ class OverviewController extends Controller
// specific dashboard was requested, but doesn't exist
if (isset($dashboard) && ! empty($request->dashboard)) {
Toastr::error(
"Dashboard <code>#$request->dashboard</code> does not exist! Loaded <code>
" . htmlentities($dashboard->dashboard_name) . '</code> instead.',
'Requested Dashboard Not Found!'
);
flash()
->using('template.librenms')
->title('Requested Dashboard Not Found!')
->addError("Dashboard <code>#$request->dashboard</code> does not exist! Loaded <code>
" . htmlentities($dashboard->dashboard_name) . '</code> instead.');
}
}

View File

@ -3,9 +3,9 @@
namespace App\Http\Controllers;
use App\Models\PortGroup;
use Flasher\Prime\FlasherInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Toastr;
class PortGroupController extends Controller
{
@ -39,7 +39,7 @@ class PortGroupController extends Controller
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
public function store(Request $request, FlasherInterface $flasher)
{
$this->validate($request, [
'name' => 'required|string|unique:port_groups',
@ -48,7 +48,7 @@ class PortGroupController extends Controller
$portGroup = PortGroup::make($request->only(['name', 'desc']));
$portGroup->save();
Toastr::success(__('Port Group :name created', ['name' => $portGroup->name]));
$flasher->addSuccess(__('Port Group :name created', ['name' => $portGroup->name]));
return redirect()->route('port-groups.index');
}
@ -73,7 +73,7 @@ class PortGroupController extends Controller
* @param \App\Models\PortGroup $portGroup
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request, PortGroup $portGroup)
public function update(Request $request, PortGroup $portGroup, FlasherInterface $flasher)
{
$this->validate($request, [
'name' => [
@ -90,9 +90,9 @@ class PortGroupController extends Controller
$portGroup->fill($request->only(['name', 'desc']));
if ($portGroup->save()) {
Toastr::success(__('Port Group :name updated', ['name' => $portGroup->name]));
$flasher->addSuccess(__('Port Group :name updated', ['name' => $portGroup->name]));
} else {
Toastr::error(__('Failed to save'));
$flasher->addError(__('Failed to save'));
return redirect()->back()->withInput();
}

View File

@ -4,7 +4,6 @@ namespace App\Http\Controllers;
use App\Models\Service;
use Illuminate\Http\Request;
use Toastr;
class ServiceController extends Controller
{
@ -45,7 +44,7 @@ class ServiceController extends Controller
);
$service->save();
Toastr::success(__('Service :name created', ['name' => $service->service_name]));
flash()->addSuccess(__('Service :name created', ['name' => $service->service_name]));
return redirect()->route('services.templates.index');
}

View File

@ -6,11 +6,11 @@ use App\Models\Device;
use App\Models\DeviceGroup;
use App\Models\Service;
use App\Models\ServiceTemplate;
use Flasher\Prime\FlasherInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use LibreNMS\Alerting\QueryBuilderFilter;
use LibreNMS\Services;
use Toastr;
class ServiceTemplateController extends Controller
{
@ -60,7 +60,7 @@ class ServiceTemplateController extends Controller
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
*/
public function store(Request $request)
public function store(Request $request, FlasherInterface $flasher)
{
$this->validate(
$request, [
@ -105,7 +105,7 @@ class ServiceTemplateController extends Controller
}
$template->groups()->sync($request->groups);
Toastr::success(__('Service Template :name created', ['name' => $template->name]));
$flasher->addSuccess(__('Service Template :name created', ['name' => $template->name]));
return redirect()->route('services.templates.index');
}
@ -146,7 +146,7 @@ class ServiceTemplateController extends Controller
* @param \App\Models\ServiceTemplate $template
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
*/
public function update(Request $request, ServiceTemplate $template)
public function update(Request $request, ServiceTemplate $template, FlasherInterface $flasher)
{
$this->validate(
$request, [
@ -214,9 +214,9 @@ class ServiceTemplateController extends Controller
if ($template->isDirty() || $devices_updated || isset($device_groups_updated)) {
try {
if ($template->save() || $devices_updated || isset($device_groups_updated)) {
Toastr::success(__('Service Template :name updated', ['name' => $template->name]));
$flasher->addSuccess(__('Service Template :name updated', ['name' => $template->name]));
} else {
Toastr::error(__('Failed to save'));
$flasher->addError(__('Failed to save'));
return redirect()->back()->withInput();
}
@ -226,7 +226,7 @@ class ServiceTemplateController extends Controller
]);
}
} else {
Toastr::info(__('No changes made'));
$flasher->addInfo(__('No changes made'));
}
return redirect()->route('services.templates.index');

View File

@ -32,10 +32,10 @@ use App\Models\Dashboard;
use App\Models\User;
use App\Models\UserPref;
use Auth;
use Flasher\Prime\FlasherInterface;
use Illuminate\Support\Str;
use LibreNMS\Authentication\LegacyAuth;
use LibreNMS\Config;
use Toastr;
use URL;
class UserController extends Controller
@ -89,7 +89,7 @@ class UserController extends Controller
* @param StoreUserRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreUserRequest $request)
public function store(StoreUserRequest $request, FlasherInterface $flasher)
{
$user = $request->only(['username', 'realname', 'email', 'descr', 'level', 'can_modify_passwd']);
$user['auth_type'] = LegacyAuth::getType();
@ -102,12 +102,12 @@ class UserController extends Controller
$this->updateDashboard($user, $request->get('dashboard'));
if ($user->save()) {
Toastr::success(__('User :username created', ['username' => $user->username]));
$flasher->addSuccess(__('User :username created', ['username' => $user->username]));
return redirect(route('users.index'));
}
Toastr::error(__('Failed to create user'));
$flasher->addError(__('Failed to create user'));
return redirect()->back();
}
@ -165,7 +165,7 @@ class UserController extends Controller
* @param User $user
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateUserRequest $request, User $user)
public function update(UpdateUserRequest $request, User $user, FlasherInterface $flasher)
{
if ($request->get('new_password') && $user->canSetPassword($request->user())) {
$user->setPassword($request->new_password);
@ -183,16 +183,16 @@ class UserController extends Controller
$user->fill($request->all());
if ($request->has('dashboard') && $this->updateDashboard($user, $request->get('dashboard'))) {
Toastr::success(__('Updated dashboard for :username', ['username' => $user->username]));
$flasher->addSuccess(__('Updated dashboard for :username', ['username' => $user->username]));
}
if ($user->save()) {
Toastr::success(__('User :username updated', ['username' => $user->username]));
$flasher->addSuccess(__('User :username updated', ['username' => $user->username]));
return redirect(route(Str::contains(URL::previous(), 'preferences') ? 'preferences.index' : 'users.index'));
}
Toastr::error(__('Failed to update user :username', ['username' => $user->username]));
$flasher->addError(__('Failed to update user :username', ['username' => $user->username]));
return redirect()->back();
}

View File

@ -7,7 +7,6 @@ use DB;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Request;
use Toastr;
class AuthEventListener
{
@ -34,7 +33,7 @@ class AuthEventListener
DB::table('authlog')->insert(['user' => $user->username ?: '', 'address' => Request::ip(), 'result' => 'Logged In']);
Toastr::info('Welcome ' . ($user->realname ?: $user->username));
flash()->addInfo('Welcome ' . ($user->realname ?: $user->username));
}
/**

View File

@ -35,7 +35,6 @@ use LibreNMS\Util\Debug;
use Log;
use Request;
use Session;
use Toastr;
class LegacyUserProvider implements UserProvider
{
@ -137,7 +136,7 @@ class LegacyUserProvider implements UserProvider
if (Debug::isEnabled()) {
$auth_message .= '<br /> ' . $ae->getFile() . ': ' . $ae->getLine();
}
\Toastr::error($auth_message);
flash()->addError($auth_message);
$username = $username ?? Session::get('username', $credentials['username']);
@ -184,7 +183,7 @@ class LegacyUserProvider implements UserProvider
error_reporting(-1);
} catch (AuthenticationException $ae) {
Toastr::error($ae->getMessage());
flash()->addError($ae->getMessage());
}
if (empty($new_user)) {

View File

@ -40,12 +40,13 @@
"laravel/tinker": "^2.5",
"laravel/ui": "^3.0",
"librenms/laravel-vue-i18n-generator": "^0.1.46",
"mews/purifier": "^3.3",
"nunomaduro/laravel-console-summary": "^1.7",
"oriceon/toastr-5-laravel": "dev-master",
"pear/console_color2": "^0.1",
"pear/console_table": "^1.3",
"pear/net_dns2": "^1.5",
"php-amqplib/php-amqplib": "^3.0",
"php-flasher/flasher-laravel": "^0.9",
"phpmailer/phpmailer": "~6.0",
"predis/predis": "^1.1",
"rmccue/requests": "^1.7",

324
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7d318d5eaf5bfcc28029dfc6acd19ebc",
"content-hash": "c57b725a8b55eda2e119496d6d41522c",
"packages": [
{
"name": "amenadiel/jpgraph",
@ -2630,6 +2630,87 @@
},
"time": "2020-09-25T08:51:26+00:00"
},
{
"name": "mews/purifier",
"version": "3.3.6",
"source": {
"type": "git",
"url": "https://github.com/mewebstudio/Purifier.git",
"reference": "1d033fc32b98036226002c38747d4a45424d5f28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mewebstudio/Purifier/zipball/1d033fc32b98036226002c38747d4a45424d5f28",
"reference": "1d033fc32b98036226002c38747d4a45424d5f28",
"shasum": ""
},
"require": {
"ezyang/htmlpurifier": "4.13.*",
"illuminate/config": "^5.8|^6.0|^7.0|^8.0",
"illuminate/filesystem": "^5.8|^6.0|^7.0|^8.0",
"illuminate/support": "^5.8|^6.0|^7.0|^8.0",
"php": "^7.2|^8.0"
},
"require-dev": {
"graham-campbell/testbench": "^3.2|^5.5.1",
"mockery/mockery": "^1.3.3",
"phpunit/phpunit": "^8.0|^9.0"
},
"suggest": {
"laravel/framework": "To test the Laravel bindings",
"laravel/lumen-framework": "To test the Lumen bindings"
},
"type": "package",
"extra": {
"laravel": {
"providers": [
"Mews\\Purifier\\PurifierServiceProvider"
],
"aliases": {
"Purifier": "Mews\\Purifier\\Facades\\Purifier"
}
}
},
"autoload": {
"psr-4": {
"Mews\\Purifier\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Muharrem ERİN",
"email": "me@mewebstudio.com",
"homepage": "https://github.com/mewebstudio",
"role": "Developer"
}
],
"description": "Laravel 5/6/7 HtmlPurifier Package",
"homepage": "https://github.com/mewebstudio/purifier",
"keywords": [
"Purifier",
"htmlpurifier",
"laravel5 HtmlPurifier",
"laravel5 Purifier",
"laravel5 Security",
"laravel6 HtmlPurifier",
"laravel6 Purifier",
"laravel6 Security",
"security",
"xss"
],
"support": {
"issues": "https://github.com/mewebstudio/Purifier/issues",
"source": "https://github.com/mewebstudio/Purifier/tree/3.3.6"
},
"time": "2021-10-14T15:27:18+00:00"
},
{
"name": "minishlink/web-push",
"version": "v6.0.5",
@ -3066,69 +3147,6 @@
},
"time": "2021-04-09T13:42:10+00:00"
},
{
"name": "oriceon/toastr-5-laravel",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/oriceon/toastr-5-laravel.git",
"reference": "8a03502cc7b151ee0e923fb66a92d91245ccb662"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/oriceon/toastr-5-laravel/zipball/8a03502cc7b151ee0e923fb66a92d91245ccb662",
"reference": "8a03502cc7b151ee0e923fb66a92d91245ccb662",
"shasum": ""
},
"require": {
"illuminate/session": ">=5.0.0",
"illuminate/support": ">=5.0.0",
"php": ">=5.4.0"
},
"default-branch": true,
"type": "library",
"extra": {
"laravel": {
"providers": [
"Kamaln7\\Toastr\\ToastrServiceProvider"
],
"aliases": {
"Toastr": "Kamaln7\\Toastr\\Facades\\Toastr"
}
}
},
"autoload": {
"psr-0": {
"Kamaln7\\Toastr\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kamal Nasser",
"email": "kamal@kamalnasser.net"
},
{
"name": "Valentin Ivascu",
"email": "oriceon@gmail.com"
}
],
"description": "Easy toastr notifications for Laravel 5",
"homepage": "https://github.com/oriceon/toastr-5-laravel",
"keywords": [
"laravel",
"notification",
"php",
"toastr"
],
"support": {
"source": "https://github.com/oriceon/toastr-5-laravel/tree/1.0.0"
},
"time": "2018-04-30T05:58:02+00:00"
},
{
"name": "paragonie/constant_time_encoding",
"version": "v2.4.0",
@ -3489,6 +3507,179 @@
},
"time": "2021-03-16T15:00:23+00:00"
},
{
"name": "php-flasher/flasher",
"version": "v0.9.4",
"source": {
"type": "git",
"url": "https://github.com/php-flasher/flasher.git",
"reference": "2f024db71d13ab0fcbe95d2558acc2952967e548"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-flasher/flasher/zipball/2f024db71d13ab0fcbe95d2558acc2952967e548",
"reference": "2f024db71d13ab0fcbe95d2558acc2952967e548",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Flasher\\Prime\\": ""
},
"files": [
"helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Younes Khoubza",
"email": "younes.khoubza@gmail.com",
"homepage": "https://github.com/yoeunes",
"role": "Developer"
}
],
"description": "A powerful and flexible flash notifications system for PHP",
"homepage": "https://php-flasher.github.io/",
"keywords": [
"Flasher",
"alerts",
"flash",
"laravel",
"lumen",
"messages",
"notifications",
"notify",
"noty",
"notyf",
"php",
"pnotify",
"sweet alert",
"symfony",
"toastr"
],
"support": {
"issues": "https://github.com/php-flasher/flasher/issues",
"source": "https://github.com/php-flasher/flasher/tree/v0.9.4"
},
"funding": [
{
"url": "https://www.paypal.com/paypalme/yoeunes",
"type": "custom"
},
{
"url": "https://ko-fi.com/yoeunes",
"type": "ko_fi"
},
{
"url": "https://opencollective.com/php-flasher",
"type": "open_collective"
},
{
"url": "https://www.patreon.com/yoeunes",
"type": "patreon"
}
],
"time": "2021-10-24T22:18:23+00:00"
},
{
"name": "php-flasher/flasher-laravel",
"version": "v0.9.4",
"source": {
"type": "git",
"url": "https://github.com/php-flasher/flasher-laravel.git",
"reference": "c95372eb2f7ad48be582fb94867ef1217e4413e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-flasher/flasher-laravel/zipball/c95372eb2f7ad48be582fb94867ef1217e4413e6",
"reference": "c95372eb2f7ad48be582fb94867ef1217e4413e6",
"shasum": ""
},
"require": {
"illuminate/support": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0",
"php": ">=5.3",
"php-flasher/flasher": "^0.9"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Flasher\\Laravel\\FlasherServiceProvider"
],
"aliases": {
"Flasher": "Flasher\\Laravel\\Facade\\Flasher"
}
}
},
"autoload": {
"psr-4": {
"Flasher\\Laravel\\": ""
},
"files": [
"helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Younes Khoubza",
"email": "younes.khoubza@gmail.com",
"homepage": "https://github.com/yoeunes",
"role": "Developer"
}
],
"description": "Laravel package integrating PHP Flasher into Laravel applications",
"homepage": "https://php-flasher.github.io/",
"keywords": [
"Flasher",
"alerts",
"bundle",
"flex",
"laravel",
"lumen",
"messages",
"notifications",
"notify",
"php",
"pnotify",
"symfony",
"toastr",
"yoeunes"
],
"support": {
"issues": "https://github.com/php-flasher/flasher-laravel/issues",
"source": "https://github.com/php-flasher/flasher-laravel/tree/v0.9.4"
},
"funding": [
{
"url": "https://www.paypal.com/paypalme/yoeunes",
"type": "custom"
},
{
"url": "https://ko-fi.com/yoeunes",
"type": "ko_fi"
},
{
"url": "https://opencollective.com/php-flasher",
"type": "open_collective"
},
{
"url": "https://www.patreon.com/yoeunes",
"type": "patreon"
}
],
"time": "2021-10-27T19:21:05+00:00"
},
{
"name": "phpmailer/phpmailer",
"version": "v6.5.1",
@ -11601,7 +11792,6 @@
"type": "github"
}
],
"abandoned": true,
"time": "2020-09-28T06:45:17+00:00"
},
{
@ -12315,9 +12505,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"oriceon/toastr-5-laravel": 20
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View File

@ -241,7 +241,6 @@ return [
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Debugbar' => Barryvdh\Debugbar\Facade::class,
'Toastr' => Kamaln7\Toastr\Facades\Toastr::class,
// LibreNMS
'Permissions' => \App\Facades\Permissions::class,

21
config/flasher.php Normal file
View File

@ -0,0 +1,21 @@
<?php
return [
'default' => 'template.librenms',
'root_script' => null,
'template_factory' => [
'templates' => [
'librenms' => [
'view' => 'layouts.flasher-notification',
'options' => [
'timeout' => 12000,
'style' => [
'top' => '55px',
],
],
],
],
],
];

115
config/purifier.php Normal file
View File

@ -0,0 +1,115 @@
<?php
/**
* Ok, glad you are here
* first we get a config instance, and set the settings
* $config = HTMLPurifier_Config::createDefault();
* $config->set('Core.Encoding', $this->config->get('purifier.encoding'));
* $config->set('Cache.SerializerPath', $this->config->get('purifier.cachePath'));
* if ( ! $this->config->get('purifier.finalize')) {
* $config->autoFinalize = false;
* }
* $config->loadArray($this->getConfig());
*
* You must NOT delete the default settings
* anything in settings should be compacted with params that needed to instance HTMLPurifier_Config.
*
* @link http://htmlpurifier.org/live/configdoc/plain.html
*/
return [
'encoding' => 'UTF-8',
'finalize' => true,
'ignoreNonStrings' => false,
'cachePath' => storage_path('app/purifier'),
'cacheFileMode' => 0755,
'settings' => [
'default' => [
'HTML.Doctype' => 'HTML 4.01 Transitional',
'HTML.Allowed' => 'div,b,strong,i,em,u,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src]',
'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align',
'AutoFormat.AutoParagraph' => true,
'AutoFormat.RemoveEmpty' => true,
],
'notification' => [
'HTML.Allowed' => 'a,b,i,ul,ol,li,h1,h2,h3,h4,br,p,pre',
],
'widget' => [
'HTML.Allowed' => 'b,iframe[frameborder|src|width|height],i,ul,ol,li,h1,h2,h3,h4,br,p,pre',
'HTML.Trusted' => true,
'HTML.SafeIframe' => true,
'URI.SafeIframeRegexp' => '%^(https?:)?//%',
],
'test' => [
'Attr.EnableID' => 'true',
],
'youtube' => [
'HTML.SafeIframe' => 'true',
'URI.SafeIframeRegexp' => '%^(http://|https://|//)(www.youtube.com/embed/|player.vimeo.com/video/)%',
],
'custom_definition' => [
'id' => 'html5-definitions',
'rev' => 1,
'debug' => false,
'elements' => [
// http://developers.whatwg.org/sections.html
['section', 'Block', 'Flow', 'Common'],
['nav', 'Block', 'Flow', 'Common'],
['article', 'Block', 'Flow', 'Common'],
['aside', 'Block', 'Flow', 'Common'],
['header', 'Block', 'Flow', 'Common'],
['footer', 'Block', 'Flow', 'Common'],
// Content model actually excludes several tags, not modelled here
['address', 'Block', 'Flow', 'Common'],
['hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common'],
// http://developers.whatwg.org/grouping-content.html
['figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'],
['figcaption', 'Inline', 'Flow', 'Common'],
// http://developers.whatwg.org/the-video-element.html#the-video-element
['video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [
'src' => 'URI',
'type' => 'Text',
'width' => 'Length',
'height' => 'Length',
'poster' => 'URI',
'preload' => 'Enum#auto,metadata,none',
'controls' => 'Bool',
]],
['source', 'Block', 'Flow', 'Common', [
'src' => 'URI',
'type' => 'Text',
]],
// http://developers.whatwg.org/text-level-semantics.html
['s', 'Inline', 'Inline', 'Common'],
['var', 'Inline', 'Inline', 'Common'],
['sub', 'Inline', 'Inline', 'Common'],
['sup', 'Inline', 'Inline', 'Common'],
['mark', 'Inline', 'Inline', 'Common'],
['wbr', 'Inline', 'Empty', 'Core'],
// http://developers.whatwg.org/edits.html
['ins', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
['del', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']],
],
'attributes' => [
['iframe', 'allowfullscreen', 'Bool'],
['table', 'height', 'Text'],
['td', 'border', 'Text'],
['th', 'border', 'Text'],
['tr', 'width', 'Text'],
['tr', 'height', 'Text'],
['tr', 'border', 'Text'],
],
],
'custom_attributes' => [
['a', 'target', 'Enum#_blank,_self,_target,_top'],
],
'custom_elements' => [
['u', 'Inline', 'Inline', 'Common'],
],
],
];

File diff suppressed because one or more lines are too long

View File

@ -2271,10 +2271,6 @@ label {
width: auto !important;
}
.toast-top-right {
top: 34px;
}
.tooltip {
display: block !important;
z-index: 10000;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><circle cx="16" cy="16" r="15" fill="#fff"/><path d="M16 0A16 16 0 0 0 0 16a16 16 0 0 0 16 16 16 16 0 0 0 16-16A16 16 0 0 0 16 0zm-6 9a1 1 0 0 1 .707.293L16 14.586l5.293-5.293a1 1 0 0 1 1.414 0 1 1 0 0 1 0 1.414L17.414 16l5.293 5.293a1 1 0 0 1 0 1.414 1 1 0 0 1-1.414 0L16 17.414l-5.293 5.293a1 1 0 0 1-1.414 0 1 1 0 0 1 0-1.414L14.586 16l-5.293-5.293a1 1 0 0 1 0-1.414A1 1 0 0 1 10 9z" fill="#dc2626"/></svg>

After

Width:  |  Height:  |  Size: 470 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><circle cx="16" cy="16" r="15" fill="#fff"/><path d="M16 0A16 16 0 0 0 0 16a16 16 0 0 0 16 16 16 16 0 0 0 16-16A16 16 0 0 0 16 0zm0 6c5.511 0 10 4.489 10 10s-4.489 10-10 10S6 21.511 6 16 10.489 6 16 6zm0 2c-4.43 0-8 3.57-8 8s3.57 8 8 8 8-3.57 8-8-3.57-8-8-8zm0 3a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1 1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zm0 8h.01a1 1 0 0 1 1 1 1 1 0 0 1-1 1H16a1 1 0 0 1-1-1 1 1 0 0 1 1-1z" fill="#2563eb" /></svg>

After

Width:  |  Height:  |  Size: 478 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><circle cx="16" cy="16" r="15" fill="#fff"/><path d="M16 0A16 16 0 0 0 0 16a16 16 0 0 0 16 16 16 16 0 0 0 16-16A16 16 0 0 0 16 0zm7 10a1 1 0 0 1 .707.293 1 1 0 0 1 0 1.414l-10 10a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 0-1.414 1 1 0 0 1 1.414 0L13 19.586l9.293-9.293A1 1 0 0 1 23 10z" fill="#059669" /></svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><circle cx="16" cy="16" r="15" fill="#fff"/><path d="M16 0A16 16 0 0 0 0 16a16 16 0 0 0 16 16 16 16 0 0 0 16-16A16 16 0 0 0 16 0zm0 6.156c1.016 0 2.032.49 2.598 1.469l6.927 12c1.131 1.958-.336 4.5-2.597 4.5H9.072c-2.261 0-3.728-2.542-2.597-4.5l6.927-12c.566-.979 1.582-1.469 2.598-1.469zm0 1.938c-.33 0-.66.177-.865.531l-6.93 12c-.409.708.049 1.5.867 1.5h13.856c.818 0 1.276-.792.867-1.5l-6.93-12c-.204-.354-.534-.531-.865-.531zm0 4.031a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1 1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1zm0 6h.01a1 1 0 0 1 1 1 1 1 0 0 1-1 1H16a1 1 0 0 1-1-1 1 1 0 0 1 1-1z" fill="#d97706"/></svg>

After

Width:  |  Height:  |  Size: 651 B

File diff suppressed because one or more lines are too long

View File

@ -27,3 +27,20 @@ $.ajaxSetup({
headers:
{ 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }
});
// toastr style to match php toasts
toastr.options = {
toastClass: 'tw-relative tw-pl-20 tw-py-4 tw-pr-2 tw-bg-white dark:tw-bg-dark-gray-300 tw-opacity-80 hover:tw-opacity-100 tw-rounded-md tw-shadow-lg hover:tw-shadow-xl tw-border-l-8 tw-mt-2 tw-cursor-pointer',
titleClass: 'tw-text-xl tw-leading-7 tw-font-semibold tw-capitalize',
messageClass: 'tw-mt-1 tw-text-base tw-leading-5 tw-text-gray-500 dark:tw-text-white',
iconClasses: {
error: 'flasher-error tw-text-red-600 tw-border-red-600',
info: 'flasher-info tw-text-blue-600 tw-border-blue-600',
success: 'flasher-success tw-text-green-600 tw-border-green-600',
warning: 'flasher-warning tw-text-yellow-600 tw-border-yellow-600'
},
timeOut: 12000,
progressBar: true,
progressClass: 'toast-progress tw-h-1 tw-bg-current tw-absolute tw-bottom-0 tw-left-0',
containerId: 'flasher-container-top-right'
};

1
html/js/flasher.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
*/
/*!
* vue-i18n v8.25.0
* vue-i18n v8.26.5
* (c) 2021 kazuya kawaguchi
* Released under the MIT License.
*/

View File

@ -1,11 +1,11 @@
{
"/js/app.js": "/js/app.js?id=f86bb54abe9f728932a7",
"/js/app.js": "/js/app.js?id=f9dd05e6d476f489c33c",
"/js/manifest.js": "/js/manifest.js?id=8d61162bb0caf92f60ff",
"/css/vendor.css": "/css/vendor.css?id=8d7b2ecb46047fe813e4",
"/css/app.css": "/css/app.css?id=54a173acc7d587a9afa4",
"/js/vendor.js": "/js/vendor.js?id=294cef17a3cf43045d61",
"/css/app.css": "/css/app.css?id=6a1f0821482cfcaa93b1",
"/js/vendor.js": "/js/vendor.js?id=b90d598798a7357bce8f",
"/js/lang/de.js": "/js/lang/de.js?id=1aedfce25e3daad3046a",
"/js/lang/en.js": "/js/lang/en.js?id=9524c5b5c41772bbb465",
"/js/lang/en.js": "/js/lang/en.js?id=5d3b737deb1cc7818f2a",
"/js/lang/fr.js": "/js/lang/fr.js?id=a20c4c78eb5f9f4a374b",
"/js/lang/it.js": "/js/lang/it.js?id=4e3b200da489000822dd",
"/js/lang/ru.js": "/js/lang/ru.js?id=f6b7c078755312a0907c",

View File

@ -13,9 +13,9 @@ if ($request->has('oauthtransport')) {
if (class_exists($class)) {
$transport = app($class);
if ($transport->handleOauth($request)) {
Toastr::success("$transport_name added successfully.");
flash()->addSuccess("$transport_name added successfully.");
} else {
Toastr::error("$transport_name was not added. Check the log for details.");
flash()->addError("$transport_name was not added. Check the log for details.");
}
}
}

View File

@ -41,9 +41,9 @@ if ($_POST['editing']) {
if ($device_model->isDirty()) {
if ($device_model->save()) {
Toastr::success(__('Device record updated'));
flash()->addSuccess(__('Device record updated'));
} else {
Toastr::error(__('Device record update error'));
flash()->addError(__('Device record update error'));
}
}
@ -51,7 +51,7 @@ if ($_POST['editing']) {
if (Auth::user()->hasGlobalAdmin()) {
$result = renamehost($device['device_id'], $_POST['hostname'], 'webui');
if ($result == '') {
Toastr::success("Hostname updated from {$device['hostname']} to {$_POST['hostname']}");
flash()->addSuccess("Hostname updated from {$device['hostname']} to {$_POST['hostname']}");
echo '
<script>
var loc = window.location;
@ -59,10 +59,10 @@ if ($_POST['editing']) {
</script>
';
} else {
Toastr::error($result . '. Does your web server have permission to modify the rrd files?');
flash()->addError($result . '. Does your web server have permission to modify the rrd files?');
}
} else {
Toastr::error('Only administrative users may update the device hostname');
flash()->addError('Only administrative users may update the device hostname');
}
}

View File

@ -180,38 +180,35 @@ $max_repeaters = get_dev_attrib($device, 'snmp_max_repeaters');
echo '<h3> SNMP Settings </h3>';
// use Toastr to print normal (success) messages, similar to Device Settings
// use PHP Flasher to print normal (success) messages, similar to Device Settings
if (isset($update_message)) {
$toastr_options = [];
if (is_array($update_message)) {
foreach ($update_message as $message) {
Toastr::success($message, null, $toastr_options);
flash()->addSuccess($message);
}
}
if (is_string($update_message)) {
Toastr::success($update_message, null, $toastr_options);
flash()->addSuccess($update_message);
}
unset($message, $toastr_options, $update_message);
unset($message, $update_message);
}
// use Toastr:error to call attention to the problem; don't let it time out
// use flash()->addError to call attention to the problem; don't let it time out
if (isset($update_failed_message)) {
$toastr_options = [];
$toastr_options['closeButton'] = true;
$toastr_options['extendedTimeOut'] = 0;
$toastr_options['timeOut'] = 0;
if (is_array($update_failed_message)) {
foreach ($update_failed_message as $error) {
Toastr::error($error, null, $toastr_options);
flash()
->option('timeout', 30000)
->addError($error);
}
}
if (is_string($update_failed_message)) {
Toastr::error($update_failed_message, null, $toastr_options);
flash()
->option('timeout', 30000)
->addError($update_failed_message);
}
unset($error, $update_failed_message);

View File

@ -1,3 +1,5 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import 'flasher.css';

58
resources/css/flasher.css Normal file
View File

@ -0,0 +1,58 @@
/*
* flasher.css
*
* -Description-
*
* 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 <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2021 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
#flasher-container-top-right {
position: fixed;
z-index: 999999;
top: 55px;
right: 12px;
}
#flasher-container-top-right a {
font-weight: bold;
}
#flasher-container-top-right > div {
width: 304px;
min-height: 50px;
background-position: 10px center;
background-repeat: no-repeat;
}
.flasher-error {
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzIgMzIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTUiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNMTYgMEExNiAxNiAwIDAgMCAwIDE2YTE2IDE2IDAgMCAwIDE2IDE2IDE2IDE2IDAgMCAwIDE2LTE2QTE2IDE2IDAgMCAwIDE2IDB6bS02IDlhMSAxIDAgMCAxIC43MDcuMjkzTDE2IDE0LjU4Nmw1LjI5My01LjI5M2ExIDEgMCAwIDEgMS40MTQgMCAxIDEgMCAwIDEgMCAxLjQxNEwxNy40MTQgMTZsNS4yOTMgNS4yOTNhMSAxIDAgMCAxIDAgMS40MTQgMSAxIDAgMCAxLTEuNDE0IDBMMTYgMTcuNDE0bC01LjI5MyA1LjI5M2ExIDEgMCAwIDEtMS40MTQgMCAxIDEgMCAwIDEgMC0xLjQxNEwxNC41ODYgMTZsLTUuMjkzLTUuMjkzYTEgMSAwIDAgMSAwLTEuNDE0QTEgMSAwIDAgMSAxMCA5eiIgZmlsbD0iI2RjMjYyNiIvPjwvc3ZnPg==");
background-size: 32px;
}
.flasher-info {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTUiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNMTYgMEExNiAxNiAwIDAgMCAwIDE2YTE2IDE2IDAgMCAwIDE2IDE2IDE2IDE2IDAgMCAwIDE2LTE2QTE2IDE2IDAgMCAwIDE2IDB6bTAgNmM1LjUxMSAwIDEwIDQuNDg5IDEwIDEwcy00LjQ4OSAxMC0xMCAxMFM2IDIxLjUxMSA2IDE2IDEwLjQ4OSA2IDE2IDZ6bTAgMmMtNC40MyAwLTggMy41Ny04IDhzMy41NyA4IDggOCA4LTMuNTcgOC04LTMuNTctOC04LTh6bTAgM2ExIDEgMCAwIDEgMSAxdjRhMSAxIDAgMCAxLTEgMSAxIDEgMCAwIDEtMS0xdi00YTEgMSAwIDAgMSAxLTF6bTAgOGguMDFhMSAxIDAgMCAxIDEgMSAxIDEgMCAwIDEtMSAxSDE2YTEgMSAwIDAgMS0xLTEgMSAxIDAgMCAxIDEtMXoiIGZpbGw9IiMyNTYzZWIiIC8+PC9zdmc+");
background-size: 32px;
}
.flasher-success {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTUiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNMTYgMEExNiAxNiAwIDAgMCAwIDE2YTE2IDE2IDAgMCAwIDE2IDE2IDE2IDE2IDAgMCAwIDE2LTE2QTE2IDE2IDAgMCAwIDE2IDB6bTcgMTBhMSAxIDAgMCAxIC43MDcuMjkzIDEgMSAwIDAgMSAwIDEuNDE0bC0xMCAxMGExIDEgMCAwIDEtMS40MTQgMGwtNC00YTEgMSAwIDAgMSAwLTEuNDE0IDEgMSAwIDAgMSAxLjQxNCAwTDEzIDE5LjU4Nmw5LjI5My05LjI5M0ExIDEgMCAwIDEgMjMgMTB6IiBmaWxsPSIjMDU5NjY5IiAvPjwvc3ZnPg==");
background-size: 32px;
}
.flasher-warning {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTUiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNMTYgMEExNiAxNiAwIDAgMCAwIDE2YTE2IDE2IDAgMCAwIDE2IDE2IDE2IDE2IDAgMCAwIDE2LTE2QTE2IDE2IDAgMCAwIDE2IDB6bTAgNi4xNTZjMS4wMTYgMCAyLjAzMi40OSAyLjU5OCAxLjQ2OWw2LjkyNyAxMmMxLjEzMSAxLjk1OC0uMzM2IDQuNS0yLjU5NyA0LjVIOS4wNzJjLTIuMjYxIDAtMy43MjgtMi41NDItMi41OTctNC41bDYuOTI3LTEyYy41NjYtLjk3OSAxLjU4Mi0xLjQ2OSAyLjU5OC0xLjQ2OXptMCAxLjkzOGMtLjMzIDAtLjY2LjE3Ny0uODY1LjUzMWwtNi45MyAxMmMtLjQwOS43MDguMDQ5IDEuNS44NjcgMS41aDEzLjg1NmMuODE4IDAgMS4yNzYtLjc5Mi44NjctMS41bC02LjkzLTEyYy0uMjA0LS4zNTQtLjUzNC0uNTMxLS44NjUtLjUzMXptMCA0LjAzMWExIDEgMCAwIDEgMSAxdjJhMSAxIDAgMCAxLTEgMSAxIDEgMCAwIDEtMS0xdi0yYTEgMSAwIDAgMSAxLTF6bTAgNmguMDFhMSAxIDAgMCAxIDEgMSAxIDEgMCAwIDEtMSAxSDE2YTEgMSAwIDAgMS0xLTEgMSAxIDAgMCAxIDEtMXoiIGZpbGw9IiNkOTc3MDYiLz48L3N2Zz4=");
background-size: 32px;
}

View File

@ -0,0 +1,37 @@
<?php
$title = $envelope->getTitle();
switch ($envelope->getType()) {
case 'success':
$color = 'tw-text-green-600';
$class = 'flasher-success';
break;
case 'error':
$color = 'tw-text-red-600';
$class = 'flasher-error';
break;
case 'warning':
$color = 'tw-text-yellow-600';
$class = 'flasher-warning';
break;
case 'info':
default:
$color = 'tw-text-blue-600';
$class = 'flasher-info';
break;
}
?>
<div class="{{ $class }} {{ $color }} tw-border-current tw-flex tw-flex-col tw-justify-between tw-bg-white dark:tw-bg-dark-gray-300 tw-opacity-80 hover:tw-opacity-100 tw-rounded-md tw-shadow-lg hover:tw-shadow-xl tw-border-l-8 tw-mt-2 tw-cursor-pointer">
<div class="tw-pl-20 tw-py-4 tw-pr-2 tw-overflow-hidden">
@if($title)
<div class="tw-text-xl tw-leading-7 tw-font-semibold tw-capitalize">
{{ $title }}
</div>
@endif
<div class="tw-mt-1 tw-text-base tw-leading-5 tw-text-gray-500 dark:tw-text-white">
{!! clean(stripslashes($envelope->getMessage()), 'notifications') !!}
</div>
</div>
<div class="tw-h-1 tw-flex tw-mr-1">
<span class="flasher-progress tw-bg-current"></span>
</div>
</div>

View File

@ -75,10 +75,11 @@
});
var ajax_url = "{{ url('/ajax') }}";
</script>
<script src="{{ asset('js/librenms.js?ver=09072021') }}"></script>
<script src="{{ asset('js/librenms.js?ver=10272021') }}"></script>
<script type="text/javascript" src="{{ asset('js/overlib_mini.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/flasher.min.js?ver=0.6.1') }}"></script>
<script type="text/javascript" src="{{ asset('js/toastr.min.js?ver=05072021') }}"></script>
<script type="text/javascript" src="{{ asset('js/boot.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/boot.js?ver=10272021') }}"></script>
<script>
// Apply color scheme
if ('{{ LibreNMS\Config::get('applied_site_style') }}' === 'dark') {
@ -109,7 +110,7 @@
@yield('scripts')
{!! Toastr::render() !!}
@flasher_render
@stack('scripts')
</body>