App::Netdisco's plugin subsystem allows developers to write and test web user interface (UI) components without needing to patch the main Netdisco application.
It also allows the end-user more control over the UI components displayed in their browser.

A plugin is simply a Perl module which is loaded.
Therefore it can do anything you like,
but most usefully for the App::Netdisco web application the module will install a Dancer route handler subroutine,
and link this to a web user interface (UI) component.

Explaining how to write Dancer route handlers is beyond the scope of this document,
but by examining the source to the plugins in App::Netdisco you'll probably get enough of an idea to begin on your own.

App::Netdisco plugins should load the App::Netdisco::Web::Plugin module.
This exports a set of helper subroutines to register the new UI components.
Here's the boilerplate code for our example plugin module:

This causes an item to appear in the Navigation Bar with a visible text of "My New Feature" which when clicked sends the user to the /mynewfeature page. Note that this won't work for any target link - the path must be an App::Netdisco Dancer route handler. Please bug the App::Netdisco devs if you want arbitrary links supported.

These components appear as tabs in the interface when the user reaches the Search page or Device details page. Note that Tab plugins usually live in the App::Netdisco::Web::Plugin::Device or App::Netdisco::Web::Plugin::Search namespace.

To register a handler for display as a Search page Tab, use the following code:

This causes a tab to appear with the label "My New Feature". So how does App::Netdisco know what the link should be? Well, as the App::Netdisco::Developing documentation says, tab content is retrieved by an AJAX call back to the web server. This uses a predictable URL path format:

Report components contain pre-canned searches which the user community have found to be useful. Before you go further, it might be the case that you can generate the report without any Perl or HTML: see the Reports Configuration for details.

Otherwise, the typical implementation is very similar to one of the Search and Device page Tabs, so please read that documentation above, first.

Report plugins usually live in the App::Netdisco::Web::Plugin::Report namespace. To register a handler for display as a Report, you need to pick the category of the report. Here are the pre-defined categories:

You will note that like Device and Search page Tabs, there's no path specified in the registration. The reports engine will make an AJAX request to the following URL:

/ajax/content/report/<report tag>

Therefore you should implement in your plugin a route handler for this path. The handler must return the HTML content for the report. It can also process any query parameters which might customize the report search.

An additional feature allows you to create Reports which do not appear in the Navbar menu. This is useful if the page is only linked directly from another (for example Port Log). To enable this feature add the hidden key:

Most pages in Netdisco are a table with data. It's possible to have the application add a link to download a CSV version of the same data. To do this, include the following option in your call to register_search_tab, register_device_tab, or register_report:

provides_csv => 1

The other thing you need to do is adjust your Dancer route handler to return either HTML or CSV data. Here's the typical way to do it:

This causes an item to appear in the Admin menu with a visible text of "My New Feature" which when clicked sends the user to the /admin/mynewfeature page. Note that this won't work for any target link - the path must be an App::Netdisco Dancer route handler. Please bug the App::Netdisco devs if you want arbitrary links supported.

An additional feature allows you to create Admin Tasks which do not appear in the Navbar menu. This is useful if the page is only linked directly from another. To enable this feature add the hidden key:

You can also add columns to the Device Ports page. The canonical example of this is to add hyperlinks (or embedded images) of traffic graphs for each port, however the plugin is a regular Template::Toolkit template so can be any HTML output.

The column plugin has a name (used internally to locate files on disk), label (the heading for the column in the table or CSV output), position in the table (three options: left, mid, right), and finally a flag for whether the column is displayed by default.

App::Netdisco searches for one Template::Toolkit file in the regular template include paths (see also register_template_path, below). The template must be called "device_port_column.tt" on disk and live in the directory:

You can add items to the Device Details tab as well. A good example of this is to add a link to the RANCID backup of the device in a WebSVN app somewhere. Like Device Port Columns plugins, the plugin is a regular Template::Toolkit snippet so can be any HTML output.

The details plugin has a name (used internally to locate files on disk) and label (the heading for the row in the table).

App::Netdisco searches for one Template::Toolkit file in the regular template include paths (see also register_template_path, below). The template must be called "device_details.tt" on disk and live in the directory:

A simple mechanism exists for loading additional Javascript and CSS documents. This is done in the <head> section of the web page.

Within a Template include path (see register_template_path, above) create a directory called "plugin" and within that another directory named after your plugin (e.g. "mynewfeature"). The Javascript and/or CSS files must then be named "mynewfeature.js" and "mynewfeature.css" respectively. For example:

As mentioned in App::Netdisco::Web::Plugin, official Netdisco plugins live in the App::Netdisco::Web::Plugin:: namespace. You can use this namespace and submit the product to the Netdisco developer team for consideration for inclusion in the official distribution.

Alternatively you can release the plugin to CPAN under your own account. In that case we request that you instead use the App::NetdiscoX::Web::Plugin:: namespace (note the "X"). Users can load such modules by using the abbreviated form "X::MyPluginName" which is then expanded to the full package.

You can support new configuration items which the user should add to their ~/environments/deployment.yml file. Please use a single Hash-Ref option named "plugin_mypluginname" (if your plugin's called mypluginname). For example: