split Plugin docs into user and developer pages
This commit is contained in:
187
Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pm
Normal file
187
Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pm
Normal file
@@ -0,0 +1,187 @@
|
||||
=head1 NAME
|
||||
|
||||
App::Netdisco::Manual::WritingPlugins - Documentation on Plugins for Developers
|
||||
|
||||
=head1 Introduction
|
||||
|
||||
L<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.
|
||||
|
||||
See L<App::Netdisco::Web::Plugin> for more general information about plugins.
|
||||
|
||||
=head1 Developing Plugins
|
||||
|
||||
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 L<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 L<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:
|
||||
|
||||
package App::Netdisco::Web::Plugin::MyNewFeature
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use App::Netdisco::Web::Plugin;
|
||||
|
||||
# plugin registration code goes here, ** see below **
|
||||
|
||||
# your Dancer route handler, for example:
|
||||
get '/mynewfeature' => sub {
|
||||
# ...lorem ipsum...
|
||||
};
|
||||
|
||||
true;
|
||||
|
||||
=head2 Navigation Bar items
|
||||
|
||||
These components appear in the black navigation bar at the top of each page,
|
||||
as individual items (i.e. not in a menu). The canonical example of this is the
|
||||
Inventory link.
|
||||
|
||||
To register an item for display in the navigation bar, use the following code:
|
||||
|
||||
register_navbar_item({
|
||||
id => 'newfeature',
|
||||
path => '/mynewfeature',
|
||||
label => 'My New Feature',
|
||||
});
|
||||
|
||||
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 C</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.
|
||||
|
||||
=head2 Search and Device page Tabs
|
||||
|
||||
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 C<App::Netdisco::Web::Plugin::Device> or
|
||||
C<App::Netdisco::Web::Plugin::Search> namespace.
|
||||
|
||||
To register a handler for display as a Search page Tab, use the following
|
||||
code:
|
||||
|
||||
register_search_tab({id => 'newfeature', label => 'My New Feature'});
|
||||
|
||||
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
|
||||
L<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:
|
||||
|
||||
/ajax/content/<search or device>/<feature ID>
|
||||
|
||||
For example:
|
||||
|
||||
/ajax/content/search/newfeature
|
||||
|
||||
Therefore your plugin module should look like the following:
|
||||
|
||||
package App::Netdisco::Web::Plugin::Search::MyNewFeature
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use App::Netdisco::Web::Plugin;
|
||||
|
||||
register_search_tab({id => 'newfeature', label => 'My New Feature'});
|
||||
|
||||
ajax '/ajax/content/search/newfeature' => sub {
|
||||
# ...lorem ipsum...
|
||||
|
||||
content_type('text/html');
|
||||
# return some HTML content here, probably using a template
|
||||
};
|
||||
|
||||
true;
|
||||
|
||||
If this all sounds a bit daunting, take a look at the
|
||||
L<App::Netdisco::Web::Plugin::Search::Port> module which is fairly
|
||||
straightforward.
|
||||
|
||||
To register a handler for display as a Device page Tab, the only difference is
|
||||
the name of the registration helper sub:
|
||||
|
||||
register_device_tab({id => 'newfeature', label => 'My New Feature'});
|
||||
|
||||
=head2 Templates
|
||||
|
||||
All of Netdisco's web page templates are stashed away in its distribution,
|
||||
probably installed in your system's or user's Perl directory. It's not
|
||||
recommended that you mess about with those files.
|
||||
|
||||
So in order to replace a template with your own version, or to reference a
|
||||
template file of your own in your plugin, you need a new path:
|
||||
|
||||
package App::Netdisco::Web::Plugin::Search::MyNewFeature
|
||||
|
||||
use File::ShareDir 'dist_dir';
|
||||
register_template_path(
|
||||
dist_dir( 'App-Netdisco-Web-Plugin-Search-MyNewFeature' ));
|
||||
|
||||
The registered path will be searched before the built-in C<App::Netdisco>
|
||||
path. We recommend use of the L<File::ShareDir> module to package and ship
|
||||
templates along with your plugin, as shown.
|
||||
|
||||
Each path added using C<register_template_path> is searched I<before> any
|
||||
existing paths in the template config.
|
||||
|
||||
=head3 Template Variables
|
||||
|
||||
Some useful variables are made available in your templates automatically by
|
||||
App::Netdisco:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<search_node>
|
||||
|
||||
A base url which links to the Node tab of the Search page, together with the
|
||||
correct default search options set.
|
||||
|
||||
=item C<search_device>
|
||||
|
||||
A base url which links to the Device tab of the Search page, together with the
|
||||
correct default search options set.
|
||||
|
||||
=item C<device_ports>
|
||||
|
||||
A base url which links to the Ports tab of the Device page, together with
|
||||
the correct default column view options set.
|
||||
|
||||
=item C<uri_base>
|
||||
|
||||
Used for linking to static content within App::Netdisco safely if the base of
|
||||
the app is relocated, for example:
|
||||
|
||||
<link rel="stylesheet" href="[% uri_base %]/css/toastr.css"/>
|
||||
|
||||
=item C<uri_for>
|
||||
|
||||
Simply the Dancer C<uri_for> method. Allows you to do things like this in the
|
||||
template safely if the base of the app is relocated:
|
||||
|
||||
<a href="[% uri_for('/search') %]" ...>
|
||||
|
||||
=item C<self_options>
|
||||
|
||||
Available in the Device tabs, use this if you need to refer back to the
|
||||
current page with some additional parameters, for example:
|
||||
|
||||
<a href="[% uri_for('/device', self_options) %]&foo=bar" ...>
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
@@ -113,12 +113,12 @@ App::Netdisco::Web::Plugin - Plugin subsystem for App::Netdisco Web UI component
|
||||
|
||||
=head1 Introduction
|
||||
|
||||
L<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.
|
||||
L<App::Netdisco>'s plugin subsystem allows the user more control of Netdisco
|
||||
UI components displayed in the web browser. Plugins can be distributed
|
||||
independently from Netdisco and are a better alternative to source code
|
||||
patches.
|
||||
|
||||
So far, the following UI compoents are implemented as plugins:
|
||||
The following UI components are implemented as plugins:
|
||||
|
||||
=over 4
|
||||
|
||||
@@ -130,12 +130,14 @@ Navigation Bar items (e.g. Inventory link)
|
||||
|
||||
Tabs for Search and Device pages
|
||||
|
||||
=item *
|
||||
|
||||
Reports (pre-canned searches)
|
||||
|
||||
=back
|
||||
|
||||
In the future there will be other components supported, such as Reports.
|
||||
|
||||
This document explains first how to configure which plugins are loaded (useful
|
||||
for the end-user) and then also how to write and install your own plugins.
|
||||
This document explains how to configure which plugins are loaded. See
|
||||
L<App::Netdisco::Manual::WritingPlugins> if you want to develop new plugins.
|
||||
|
||||
=head1 Application Configuration
|
||||
|
||||
@@ -146,6 +148,7 @@ be loaded. For example:
|
||||
|
||||
web_plugins:
|
||||
- Inventory
|
||||
- Report::DuplexMismatch
|
||||
- Search::Device
|
||||
- Search::Node
|
||||
- Search::Port
|
||||
@@ -169,9 +172,7 @@ namespaces:
|
||||
web_plugins:
|
||||
- Inventory
|
||||
- Search::Device
|
||||
- Search::Node
|
||||
- Device::Details
|
||||
- Device::Ports
|
||||
- +My::Other::Netdisco::Web::Component
|
||||
|
||||
The order of the entries in C<web_plugins> is significant. Unsurprisingly, the
|
||||
@@ -190,174 +191,5 @@ C<web_plugins> setting, use the C<extra_web_plugins> setting instead in your
|
||||
Environment configuration. Any Navigation Bar items or Page Tabs are added
|
||||
after those in C<web_plugins>.
|
||||
|
||||
=head1 Developing Plugins
|
||||
|
||||
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 L<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 L<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:
|
||||
|
||||
package App::Netdisco::Web::Plugin::MyNewFeature
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use App::Netdisco::Web::Plugin;
|
||||
|
||||
# plugin registration code goes here, ** see below **
|
||||
|
||||
# your Dancer route handler, for example:
|
||||
get '/mynewfeature' => sub {
|
||||
# ...lorem ipsum...
|
||||
};
|
||||
|
||||
true;
|
||||
|
||||
=head2 Navigation Bar items
|
||||
|
||||
These components appear in the black navigation bar at the top of each page,
|
||||
as individual items (i.e. not in a menu). The canonical example of this is the
|
||||
Inventory link.
|
||||
|
||||
To register an item for display in the navigation bar, use the following code:
|
||||
|
||||
register_navbar_item({
|
||||
id => 'newfeature',
|
||||
path => '/mynewfeature',
|
||||
label => 'My New Feature',
|
||||
});
|
||||
|
||||
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 C</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.
|
||||
|
||||
=head2 Search and Device page Tabs
|
||||
|
||||
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 C<App::Netdisco::Web::Plugin::Device> or
|
||||
C<App::Netdisco::Web::Plugin::Search> namespace.
|
||||
|
||||
To register a handler for display as a Search page Tab, use the following
|
||||
code:
|
||||
|
||||
register_search_tab({id => 'newfeature', label => 'My New Feature'});
|
||||
|
||||
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
|
||||
L<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:
|
||||
|
||||
/ajax/content/<search or device>/<feature ID>
|
||||
|
||||
For example:
|
||||
|
||||
/ajax/content/search/newfeature
|
||||
|
||||
Therefore your plugin module should look like the following:
|
||||
|
||||
package App::Netdisco::Web::Plugin::Search::MyNewFeature
|
||||
|
||||
use Dancer ':syntax';
|
||||
use Dancer::Plugin::Ajax;
|
||||
use Dancer::Plugin::DBIC;
|
||||
|
||||
use App::Netdisco::Web::Plugin;
|
||||
|
||||
register_search_tab({id => 'newfeature', label => 'My New Feature'});
|
||||
|
||||
ajax '/ajax/content/search/newfeature' => sub {
|
||||
# ...lorem ipsum...
|
||||
|
||||
content_type('text/html');
|
||||
# return some HTML content here, probably using a template
|
||||
};
|
||||
|
||||
true;
|
||||
|
||||
If this all sounds a bit daunting, take a look at the
|
||||
L<App::Netdisco::Web::Plugin::Search::Port> module which is fairly
|
||||
straightforward.
|
||||
|
||||
To register a handler for display as a Device page Tab, the only difference is
|
||||
the name of the registration helper sub:
|
||||
|
||||
register_device_tab({id => 'newfeature', label => 'My New Feature'});
|
||||
|
||||
=head2 Templates
|
||||
|
||||
All of Netdisco's web page templates are stashed away in its distribution,
|
||||
probably installed in your system's or user's Perl directory. It's not
|
||||
recommended that you mess about with those files.
|
||||
|
||||
So in order to replace a template with your own version, or to reference a
|
||||
template file of your own in your plugin, you need a new path:
|
||||
|
||||
package App::Netdisco::Web::Plugin::Search::MyNewFeature
|
||||
|
||||
use File::ShareDir 'dist_dir';
|
||||
register_template_path(
|
||||
dist_dir( 'App-Netdisco-Web-Plugin-Search-MyNewFeature' ));
|
||||
|
||||
The registered path will be searched before the built-in C<App::Netdisco>
|
||||
path. We recommend use of the L<File::ShareDir> module to package and ship
|
||||
templates along with your plugin, as shown.
|
||||
|
||||
=head3 Template Variables
|
||||
|
||||
Some useful variables are made available in your templates automatically by
|
||||
App::Netdisco:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<search_node>
|
||||
|
||||
A base url which links to the Node tab of the Search page, together with the
|
||||
correct default search options set.
|
||||
|
||||
=item C<search_device>
|
||||
|
||||
A base url which links to the Device tab of the Search page, together with the
|
||||
correct default search options set.
|
||||
|
||||
=item C<device_ports>
|
||||
|
||||
A base url which links to the Ports tab of the Device page, together with
|
||||
the correct default column view options set.
|
||||
|
||||
=item C<uri_base>
|
||||
|
||||
Used for linking to static content within App::Netdisco safely if the base of
|
||||
the app is relocated, for example:
|
||||
|
||||
<link rel="stylesheet" href="[% uri_base %]/css/toastr.css"/>
|
||||
|
||||
=item C<uri_for>
|
||||
|
||||
Simply the Dancer C<uri_for> method. Allows you to do things like this in the
|
||||
template safely if the base of the app is relocated:
|
||||
|
||||
<a href="[% uri_for('/search') %]" ...>
|
||||
|
||||
=item C<self_options>
|
||||
|
||||
Available in the Device tabs, use this if you need to refer back to the
|
||||
current page with some additional parameters, for example:
|
||||
|
||||
<a href="[% uri_for('/device', self_options) %]&foo=bar" ...>
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
Reference in New Issue
Block a user