mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Plugin Update (#16291)
* Plugin Update Extract interfaces for use in plugin packages # Conflicts: # composer.lock * Fix some issues settings_view -> content_view
This commit is contained in:
@@ -26,11 +26,12 @@
|
|||||||
namespace App\Facades;
|
namespace App\Facades;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Facade;
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
|
||||||
|
|
||||||
class PluginManager extends Facade
|
class PluginManager extends Facade
|
||||||
{
|
{
|
||||||
protected static function getFacadeAccessor()
|
protected static function getFacadeAccessor()
|
||||||
{
|
{
|
||||||
return \App\Plugins\PluginManager::class;
|
return PluginManagerInterface::class;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Plugin;
|
use App\Models\Plugin;
|
||||||
use App\Plugins\PluginManager;
|
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
|
||||||
|
|
||||||
class PluginAdminController extends Controller
|
class PluginAdminController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(PluginManager $manager): \Illuminate\Contracts\View\View
|
public function __invoke(PluginManagerInterface $manager): \Illuminate\Contracts\View\View
|
||||||
{
|
{
|
||||||
// legacy v1 plugins
|
// legacy v1 plugins
|
||||||
\LibreNMS\Plugins::scanNew();
|
\LibreNMS\Plugins::scanNew();
|
||||||
|
@@ -3,13 +3,13 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Plugin;
|
use App\Models\Plugin;
|
||||||
use App\Plugins\Hooks\PageHook;
|
|
||||||
use App\Plugins\PluginManager;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use LibreNMS\Interfaces\Plugins\Hooks\SinglePageHook;
|
||||||
|
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
|
||||||
|
|
||||||
class PluginPageController extends Controller
|
class PluginPageController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(PluginManager $manager, Plugin $plugin): \Illuminate\Contracts\View\View
|
public function __invoke(PluginManagerInterface $manager, Plugin $plugin): \Illuminate\Contracts\View\View
|
||||||
{
|
{
|
||||||
if (! $manager->pluginEnabled($plugin->plugin_name)) {
|
if (! $manager->pluginEnabled($plugin->plugin_name)) {
|
||||||
abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name]));
|
abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name]));
|
||||||
@@ -20,10 +20,10 @@ class PluginPageController extends Controller
|
|||||||
'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]),
|
'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]),
|
||||||
'plugin_name' => $plugin->plugin_name,
|
'plugin_name' => $plugin->plugin_name,
|
||||||
'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'),
|
'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'),
|
||||||
'settings_view' => 'plugins.missing',
|
'content_view' => 'plugins.missing',
|
||||||
'settings' => [],
|
'settings' => [],
|
||||||
],
|
],
|
||||||
(array) $manager->call(PageHook::class, [], $plugin->plugin_name)->first()
|
$manager->call(SinglePageHook::class, [], $plugin->plugin_name)[0] ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
return view('plugins.settings', $data);
|
return view('plugins.settings', $data);
|
||||||
|
@@ -3,14 +3,14 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Plugin;
|
use App\Models\Plugin;
|
||||||
use App\Plugins\Hooks\SettingsHook;
|
|
||||||
use App\Plugins\PluginManager;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use LibreNMS\Interfaces\Plugins\Hooks\SettingsHook;
|
||||||
|
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
|
||||||
use LibreNMS\Util\Notifications;
|
use LibreNMS\Util\Notifications;
|
||||||
|
|
||||||
class PluginSettingsController extends Controller
|
class PluginSettingsController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(PluginManager $manager, Plugin $plugin): \Illuminate\Contracts\View\View
|
public function __invoke(PluginManagerInterface $manager, Plugin $plugin): \Illuminate\Contracts\View\View
|
||||||
{
|
{
|
||||||
if (! $manager->pluginEnabled($plugin->plugin_name)) {
|
if (! $manager->pluginEnabled($plugin->plugin_name)) {
|
||||||
abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name]));
|
abort(404, trans('plugins.errors.disabled', ['plugin' => $plugin->plugin_name]));
|
||||||
@@ -21,10 +21,10 @@ class PluginSettingsController extends Controller
|
|||||||
'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]),
|
'title' => trans('plugins.settings_page', ['plugin' => $plugin->plugin_name]),
|
||||||
'plugin_name' => $plugin->plugin_name,
|
'plugin_name' => $plugin->plugin_name,
|
||||||
'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'),
|
'plugin_id' => Plugin::where('plugin_name', $plugin->plugin_name)->value('plugin_id'),
|
||||||
'settings_view' => 'plugins.missing',
|
'content_view' => 'plugins.missing',
|
||||||
'settings' => [],
|
'settings' => [],
|
||||||
],
|
],
|
||||||
(array) $manager->call(SettingsHook::class, [], $plugin->plugin_name)->first()
|
$manager->call(SettingsHook::class, [], $plugin->plugin_name)[0] ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
return view('plugins.settings', $data);
|
return view('plugins.settings', $data);
|
||||||
|
@@ -41,11 +41,11 @@ use App\Models\User;
|
|||||||
use App\Models\UserPref;
|
use App\Models\UserPref;
|
||||||
use App\Models\Vminfo;
|
use App\Models\Vminfo;
|
||||||
use App\Models\WirelessSensor;
|
use App\Models\WirelessSensor;
|
||||||
use App\Plugins\Hooks\MenuEntryHook;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use LibreNMS\Config;
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\Plugins\Hooks\MenuEntryHook;
|
||||||
use LibreNMS\Plugins;
|
use LibreNMS\Plugins;
|
||||||
use LibreNMS\Util\ObjectCache;
|
use LibreNMS\Util\ObjectCache;
|
||||||
use PluginManager;
|
use PluginManager;
|
||||||
|
@@ -33,7 +33,7 @@ class Page extends PageHook
|
|||||||
{
|
{
|
||||||
// point to the view for your plugin's settings
|
// point to the view for your plugin's settings
|
||||||
// this is the default name so you can create the blade file as in this plugin
|
// this is the default name so you can create the blade file as in this plugin
|
||||||
// by ommitting the variable, or point to another one
|
// by omitting the variable, or point to another one
|
||||||
|
|
||||||
// public string $view = 'resources.views.page';
|
// public string $view = 'resources.views.page';
|
||||||
|
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Plugins;
|
|
||||||
|
|
||||||
interface Hook
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Will be called by the plugin manager to check if the user is authorized. Will be called with Dependency Injection.
|
|
||||||
*/
|
|
||||||
// public function authorize(): bool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will be called by the plugin manager to execute this plugin at the correct time. Will be called with Dependency Injection.
|
|
||||||
*/
|
|
||||||
// public function handle();
|
|
||||||
}
|
|
@@ -30,7 +30,7 @@ use App\Models\User;
|
|||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
abstract class DeviceOverviewHook
|
abstract class DeviceOverviewHook implements \LibreNMS\Interfaces\Plugins\Hooks\DeviceOverviewHook
|
||||||
{
|
{
|
||||||
public string $view = 'resources.views.device-overview';
|
public string $view = 'resources.views.device-overview';
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ use App\Models\User;
|
|||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
abstract class MenuEntryHook
|
abstract class MenuEntryHook implements \LibreNMS\Interfaces\Plugins\Hooks\MenuEntryHook
|
||||||
{
|
{
|
||||||
public string $view = 'resources.views.menu';
|
public string $view = 'resources.views.menu';
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ use App\Models\User;
|
|||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
abstract class PageHook
|
abstract class PageHook implements \LibreNMS\Interfaces\Plugins\Hooks\SinglePageHook
|
||||||
{
|
{
|
||||||
public string $view = 'resources.views.page';
|
public string $view = 'resources.views.page';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ abstract class PageHook
|
|||||||
final public function handle(string $pluginName, array $settings, Application $app): array
|
final public function handle(string $pluginName, array $settings, Application $app): array
|
||||||
{
|
{
|
||||||
return array_merge([
|
return array_merge([
|
||||||
'settings_view' => Str::start($this->view, "$pluginName::"),
|
'content_view' => Str::start($this->view, "$pluginName::"),
|
||||||
], $app->call([$this, 'data'], [
|
], $app->call([$this, 'data'], [
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
]));
|
]));
|
||||||
|
@@ -27,11 +27,10 @@ namespace App\Plugins\Hooks;
|
|||||||
|
|
||||||
use App\Models\Port;
|
use App\Models\Port;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Plugins\Hook;
|
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
abstract class PortTabHook implements Hook
|
abstract class PortTabHook implements \LibreNMS\Interfaces\Plugins\Hooks\PortTabHook
|
||||||
{
|
{
|
||||||
/** @var string */
|
/** @var string */
|
||||||
public $view = 'resources.views.port-tab';
|
public $view = 'resources.views.port-tab';
|
||||||
|
@@ -29,7 +29,7 @@ use App\Models\User;
|
|||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
abstract class SettingsHook
|
abstract class SettingsHook implements \LibreNMS\Interfaces\Plugins\Hooks\SettingsHook
|
||||||
{
|
{
|
||||||
public string $view = 'resources.views.settings';
|
public string $view = 'resources.views.settings';
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ abstract class SettingsHook
|
|||||||
final public function handle(string $pluginName, array $settings, Application $app): array
|
final public function handle(string $pluginName, array $settings, Application $app): array
|
||||||
{
|
{
|
||||||
return array_merge([
|
return array_merge([
|
||||||
'settings_view' => Str::start($this->view, "$pluginName::"),
|
'content_view' => Str::start($this->view, "$pluginName::"),
|
||||||
], $this->data($app->call([$this, 'data'], [
|
], $this->data($app->call([$this, 'data'], [
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
])));
|
])));
|
||||||
|
@@ -30,10 +30,11 @@ use App\Models\Plugin;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
|
||||||
use LibreNMS\Util\Notifications;
|
use LibreNMS\Util\Notifications;
|
||||||
use Log;
|
use Log;
|
||||||
|
|
||||||
class PluginManager
|
class PluginManager implements PluginManagerInterface
|
||||||
{
|
{
|
||||||
/** @var Collection */
|
/** @var Collection */
|
||||||
private $hooks;
|
private $hooks;
|
||||||
@@ -104,9 +105,9 @@ class PluginManager
|
|||||||
* @param string $hookType
|
* @param string $hookType
|
||||||
* @param array $args
|
* @param array $args
|
||||||
* @param string|null $plugin only for this plugin if set
|
* @param string|null $plugin only for this plugin if set
|
||||||
* @return \Illuminate\Support\Collection
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function call(string $hookType, array $args = [], ?string $plugin = null): Collection
|
public function call(string $hookType, array $args = [], ?string $plugin = null): array
|
||||||
{
|
{
|
||||||
return $this->hooksFor($hookType, $args, $plugin)
|
return $this->hooksFor($hookType, $args, $plugin)
|
||||||
->map(function ($hook) use ($args, $hookType) {
|
->map(function ($hook) use ($args, $hookType) {
|
||||||
@@ -127,7 +128,7 @@ class PluginManager
|
|||||||
}
|
}
|
||||||
})->filter(function ($hook) {
|
})->filter(function ($hook) {
|
||||||
return $hook !== 'HOOK FAILED';
|
return $hook !== 'HOOK FAILED';
|
||||||
});
|
})->values()->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -26,28 +26,28 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Exceptions\PluginDoesNotImplementHookException;
|
use App\Exceptions\PluginDoesNotImplementHookException;
|
||||||
use App\Plugins\PluginManager;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use LibreNMS\Interfaces\Plugins\PluginManagerInterface;
|
||||||
|
|
||||||
class PluginProvider extends ServiceProvider
|
class PluginProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
$this->app->singleton(PluginManager::class, function ($app) {
|
$this->app->singleton(PluginManagerInterface::class, function ($app) {
|
||||||
return new PluginManager;
|
return new \App\Plugins\PluginManager;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
$this->loadLocalPlugins($this->app->make(PluginManager::class));
|
$this->loadLocalPlugins($this->app->make(PluginManagerInterface::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load any local plugins these plugins must implement only one hook.
|
* Load any local plugins these plugins must implement only one hook.
|
||||||
*/
|
*/
|
||||||
protected function loadLocalPlugins(PluginManager $manager): void
|
protected function loadLocalPlugins(PluginManagerInterface $manager): void
|
||||||
{
|
{
|
||||||
$plugin_view_location_registered = [];
|
$plugin_view_location_registered = [];
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ class PluginProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
protected function hookType(string $class): string
|
protected function hookType(string $class): string
|
||||||
{
|
{
|
||||||
foreach (class_parents($class) as $parent) {
|
foreach (class_implements($class) as $parent) {
|
||||||
if (Str::startsWith($parent, 'App\Plugins\Hooks\\')) {
|
if (Str::startsWith($parent, 'LibreNMS\Interfaces\Plugins\Hooks\\')) {
|
||||||
return $parent;
|
return $parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
"laravel/ui": "^4.2",
|
"laravel/ui": "^4.2",
|
||||||
"librenms/laravel-vue-i18n-generator": "dev-master",
|
"librenms/laravel-vue-i18n-generator": "dev-master",
|
||||||
|
"librenms/plugin-interfaces": "^1.0",
|
||||||
"mews/purifier": "^3.4",
|
"mews/purifier": "^3.4",
|
||||||
"nunomaduro/laravel-console-summary": "^1.9",
|
"nunomaduro/laravel-console-summary": "^1.9",
|
||||||
"pear/console_color2": "^0.1",
|
"pear/console_color2": "^0.1",
|
||||||
|
37
composer.lock
generated
37
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "277d3c3cae41b8c97cf6e330393f124a",
|
"content-hash": "dabb9a7876ed5d206fc8278729d2d417",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "amenadiel/jpgraph",
|
"name": "amenadiel/jpgraph",
|
||||||
@@ -3180,6 +3180,41 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-07-26T10:48:47+00:00"
|
"time": "2024-07-26T10:48:47+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "librenms/plugin-interfaces",
|
||||||
|
"version": "1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/librenms/plugin-interfaces.git",
|
||||||
|
"reference": "7a196c3e47c5c5eb140f895dde6ceac998cf7b48"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/librenms/plugin-interfaces/zipball/7a196c3e47c5c5eb140f895dde6ceac998cf7b48",
|
||||||
|
"reference": "7a196c3e47c5c5eb140f895dde6ceac998cf7b48",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"LibreNMS\\Interfaces\\Plugins\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"0BSD"
|
||||||
|
],
|
||||||
|
"description": "Interfaces required to create a LibreNMS Plugin",
|
||||||
|
"homepage": "https://www.librenms.org/",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/librenms/plugin-interfaces/issues",
|
||||||
|
"source": "https://github.com/librenms/plugin-interfaces/tree/1.0"
|
||||||
|
},
|
||||||
|
"time": "2024-08-15T15:23:53+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "mews/purifier",
|
"name": "mews/purifier",
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Plugins\Hooks\DeviceOverviewHook;
|
use LibreNMS\Interfaces\Plugins\Hooks\DeviceOverviewHook;
|
||||||
|
|
||||||
$overview = 1;
|
$overview = 1;
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@ require 'includes/html/dev-groups-overview-data.inc.php';
|
|||||||
require 'overview/puppet_agent.inc.php';
|
require 'overview/puppet_agent.inc.php';
|
||||||
|
|
||||||
echo LibreNMS\Plugins::call('device_overview_container', [$device]);
|
echo LibreNMS\Plugins::call('device_overview_container', [$device]);
|
||||||
PluginManager::call(DeviceOverviewHook::class, ['device' => DeviceCache::getPrimary()])->each(function ($view) {
|
foreach (PluginManager::call(DeviceOverviewHook::class, ['device' => DeviceCache::getPrimary()]) as $view) {
|
||||||
echo $view;
|
echo $view;
|
||||||
});
|
}
|
||||||
|
|
||||||
require 'overview/ports.inc.php';
|
require 'overview/ports.inc.php';
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
* @author PipoCanaja <pipocanaja@gmail.com>
|
* @author PipoCanaja <pipocanaja@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use App\Plugins\Hooks\PortTabHook;
|
use LibreNMS\Interfaces\Plugins\Hooks\PortTabHook;
|
||||||
|
|
||||||
$pagetitle[] = 'Plugins';
|
$pagetitle[] = 'Plugins';
|
||||||
$no_refresh = true;
|
$no_refresh = true;
|
||||||
@@ -23,6 +23,6 @@ $no_refresh = true;
|
|||||||
<hr>
|
<hr>
|
||||||
<?php
|
<?php
|
||||||
echo \LibreNMS\Plugins::call('port_container', [$device, $port]);
|
echo \LibreNMS\Plugins::call('port_container', [$device, $port]);
|
||||||
PluginManager::call(PortTabHook::class, ['port' => $portModel])->each(function ($view) {
|
foreach (PluginManager::call(PortTabHook::class, ['port' => $portModel]) as $view) {
|
||||||
echo $view;
|
echo $view;
|
||||||
});
|
};
|
||||||
|
@@ -3,5 +3,5 @@
|
|||||||
@section('title', $title)
|
@section('title', $title)
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
@include($settings_view, $settings)
|
@include($content_view, $settings)
|
||||||
@endsection
|
@endsection
|
||||||
|
Reference in New Issue
Block a user