diff --git a/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pm b/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pm new file mode 100644 index 00000000..bb15f950 --- /dev/null +++ b/Netdisco/lib/App/Netdisco/Manual/WritingPlugins.pm @@ -0,0 +1,187 @@ +=head1 NAME + +App::Netdisco::Manual::WritingPlugins - Documentation on Plugins for Developers + +=head1 Introduction + +L'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 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 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 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 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 or +C 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 documentation says, tab content is retrieved by +an AJAX call back to the web server. This uses a predictable URL path format: + + /ajax/content// + +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 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 +path. We recommend use of the L module to package and ship +templates along with your plugin, as shown. + +Each path added using C is searched I 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 + +A base url which links to the Node tab of the Search page, together with the +correct default search options set. + +=item C + +A base url which links to the Device tab of the Search page, together with the +correct default search options set. + +=item C + +A base url which links to the Ports tab of the Device page, together with +the correct default column view options set. + +=item C + +Used for linking to static content within App::Netdisco safely if the base of +the app is relocated, for example: + + + +=item C + +Simply the Dancer C method. Allows you to do things like this in the +template safely if the base of the app is relocated: + + + +=item C + +Available in the Device tabs, use this if you need to refer back to the +current page with some additional parameters, for example: + + + +=back + +=cut + diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin.pm b/Netdisco/lib/App/Netdisco/Web/Plugin.pm index 860680af..49c7e6a6 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin.pm @@ -113,12 +113,12 @@ App::Netdisco::Web::Plugin - Plugin subsystem for App::Netdisco Web UI component =head1 Introduction -L'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'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 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 is significant. Unsurprisingly, the @@ -190,174 +191,5 @@ C setting, use the C setting instead in your Environment configuration. Any Navigation Bar items or Page Tabs are added after those in C. -=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 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 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 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 or -C 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 documentation says, tab content is retrieved by -an AJAX call back to the web server. This uses a predictable URL path format: - - /ajax/content// - -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 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 -path. We recommend use of the L 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 - -A base url which links to the Node tab of the Search page, together with the -correct default search options set. - -=item C - -A base url which links to the Device tab of the Search page, together with the -correct default search options set. - -=item C - -A base url which links to the Ports tab of the Device page, together with -the correct default column view options set. - -=item C - -Used for linking to static content within App::Netdisco safely if the base of -the app is relocated, for example: - - - -=item C - -Simply the Dancer C method. Allows you to do things like this in the -template safely if the base of the app is relocated: - - - -=item C - -Available in the Device tabs, use this if you need to refer back to the -current page with some additional parameters, for example: - - - -=back - =cut