diff --git a/Netdisco/lib/App/Netdisco/Util/Web.pm b/Netdisco/lib/App/Netdisco/Util/Web.pm index b02aa861..d5ee3085 100644 --- a/Netdisco/lib/App/Netdisco/Util/Web.pm +++ b/Netdisco/lib/App/Netdisco/Util/Web.pm @@ -116,4 +116,43 @@ sub sort_port { return $val; } +=head2 sort_modules( $modules ) + +Sort devices modules into tree hierarchy based upon position and parent - +input arg is module list. + +=cut + +sub sort_modules { + my $input = shift; + + my %modules; + + foreach my $module (@$input) { + $modules{$module->index}{module} = $module; + if ($module->parent) { + # Next wrong: some things have weird pos' + # index | description | type | parent | class | pos + #-------+----------------------------------------+---------------------+--------+---------+----- + # 1 | Cisco Aironet 1200 Series Access Point | cevChassisAIRAP1210 | 0 | chassis | -1 + # 3 | PowerPC405GP Ethernet | cevPortFEIP | 1 | port | -1 + # 2 | 802.11G Radio | cevPortUnknown | 1 | port | 0 + $module->pos = 0 if ($module->pos < 0); + + # this is wrong. a given parent can + # have multiple items at a single pos value. + # (HP may have gotten this wrong, but that's + # reality...) + if ($module->pos) { + ${$modules{$module->parent}{children}{$module->class}}[$module->pos] = $module->index; + } else { + push(@{$modules{$module->parent}{children}{$module->class}}, $module->index); + } + } else { + push(@{$modules{root}}, $module->index); + } + } + return \%modules; +} + 1; diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Modules.pm b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Modules.pm index 79f07046..df1bf61f 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Modules.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin/Device/Modules.pm @@ -2,14 +2,29 @@ package App::Netdisco::Web::Plugin::Device::Modules; use Dancer ':syntax'; use Dancer::Plugin::Ajax; +use Dancer::Plugin::DBIC; use Dancer::Plugin::Auth::Extensible; +use App::Netdisco::Util::Web (); # for sort_module use App::Netdisco::Web::Plugin; register_device_tab({ tag => 'modules', label => 'Modules' }); -ajax '/ajax/content/device/:thing' => require_login sub { - return "

Hello, this is where the ". param('thing') ." content goes.

"; +ajax '/ajax/content/device/modules' => require_login sub { + my $q = param('q'); + + my $device = schema('netdisco')->resultset('Device') + ->search_for_device($q) or send_error('Bad device', 400); + my @set = $device->modules->search({}, {order_by => { -asc => [qw/parent pos index/] }}); + + # sort modules (empty set would be a 'no records' msg) + my $results = &App::Netdisco::Util::Web::sort_modules( \@set ); + return unless scalar %$results; + + content_type('text/html'); + template 'ajax/device/modules.tt', { + nodes => $results, + }, { layout => undef }; }; true; diff --git a/Netdisco/share/config.yml b/Netdisco/share/config.yml index 7a632188..8d2fec9b 100644 --- a/Netdisco/share/config.yml +++ b/Netdisco/share/config.yml @@ -45,7 +45,7 @@ web_plugins: - Search::Port - Device::Details - Device::Ports - # - Device::Modules + - Device::Modules - Device::Neighbors - Device::Addresses web_plugins_extra: [] diff --git a/Netdisco/share/public/css/bootstrap-tree.css b/Netdisco/share/public/css/bootstrap-tree.css new file mode 100644 index 00000000..f8c49fe7 --- /dev/null +++ b/Netdisco/share/public/css/bootstrap-tree.css @@ -0,0 +1,63 @@ +/* style for collapsable tree */ + +.tree { + min-height:20px; + padding:19px; + margin-bottom:20px; + background-color:#fbfbfb; + border:1px solid #999; + -webkit-border-radius:4px; + -moz-border-radius:4px; + border-radius:4px; + -webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05) +} +.tree li { + list-style-type:none; + margin:0; + padding:10px 5px 0 5px; + position:relative +} +.tree li::before, .tree li::after { + content:''; + left:-20px; + position:absolute; + right:auto +} +.tree li::before { + border-left:1px solid #999; + bottom:50px; + height:100%; + top:0; + width:1px +} +.tree li::after { + border-top:1px solid #999; + height:20px; + top:25px; + width:25px +} +.tree li span { + -moz-border-radius:5px; + -webkit-border-radius:5px; + border:1px solid #999; + border-radius:5px; + display:inline-block; + padding:3px 8px; + text-decoration:none +} +.tree li.parent_li>span { + cursor:pointer +} +.tree>ul>li::before, .tree>ul>li::after { + border:0 +} +.tree li:last-child::before { + height:30px +} +.tree li.parent_li>span:hover, .tree li.parent_li>span:hover+ul li span { + background:#eee; + border:1px solid #94a0b4; + color:#000 +} \ No newline at end of file diff --git a/Netdisco/share/views/ajax/device/modules.tt b/Netdisco/share/views/ajax/device/modules.tt new file mode 100644 index 00000000..2dd098ba --- /dev/null +++ b/Netdisco/share/views/ajax/device/modules.tt @@ -0,0 +1,60 @@ +[% BLOCK recurse -%] +[% INCLUDE print_line item=item %] + [% IF nodes.$item.children.defined -%] + + [% END -%] + +[%- END -%] +[% BLOCK print_line -%] +
  • +[% IF nodes.$item.children.defined -%] +  +[%- ELSE -%] +  +[%- END -%] + [% nodes.$item.module.description -%] +[%- IF nodes.$item.module.name -%] + ([% nodes.$item.module.name %]) +[%- END -%] +[%- IF nodes.$item.module.fw_ver -%] + fw: [% nodes.$item.module.fw_ver %] +[%- END -%] +[%- IF nodes.$item.module.hw_ver -%] + hw: [% nodes.$item.module.fw_ver %] +[%- END -%] +[%- IF nodes.$item.module.sw_ver -%] + sw: [% nodes.$item.module.sw_ver %] +[%- END -%] +[%- IF nodes.$item.module.serial -%] + [serial: [% nodes.$item.module.serial %]] +[%- END -%] +[%- IF nodes.$item.module.type -%] + / [% nodes.$item.module.type %] +[%- END -%] +[%- IF nodes.$item.module.model -%] + / [% nodes.$item.module.model %] +[%- END -%] +[%- IF nodes.$item.module.fru -%] + [FRU] +[%- END -%] + +[%- END -%] +
    +
      +[% FOREACH module IN nodes.root %] + [% INCLUDE recurse item=module %] +[%- END -%] +
    +
    + + diff --git a/Netdisco/share/views/js/bootstrap-tree.js b/Netdisco/share/views/js/bootstrap-tree.js new file mode 100644 index 00000000..e9ac53ba --- /dev/null +++ b/Netdisco/share/views/js/bootstrap-tree.js @@ -0,0 +1,15 @@ +$(document).ready(function() { +$('.tree > ul').attr('role', 'tree').find('ul').attr('role', 'group'); +$('.tree').find('li:has(ul)').addClass('parent_li').attr('role', 'treeitem').find(' > span').attr('title', 'Collapse this branch').on('click', function (e) { + var children = $(this).parent('li.parent_li').find(' > ul > li'); + if (children.is(':visible')) { + children.hide('fast'); + $(this).attr('title', 'Expand this branch').find(' > i').addClass('icon-plus-sign').removeClass('icon-minus-sign'); + } + else { + children.show('fast'); + $(this).attr('title', 'Collapse this branch').find(' > i').addClass('icon-minus-sign').removeClass('icon-plus-sign'); + } + e.stopPropagation(); + }); +}); \ No newline at end of file diff --git a/Netdisco/share/views/layouts/main.tt b/Netdisco/share/views/layouts/main.tt index ff68c56a..2c7d8d4c 100644 --- a/Netdisco/share/views/layouts/main.tt +++ b/Netdisco/share/views/layouts/main.tt @@ -43,6 +43,7 @@ + [% FOREACH add_css IN settings._additional_css %]