- a new feature, "Peering Overview" under the "Tools" menu that shows a consolidated table of peering rules, peering groups and peering hosts with a quick links to the related edit dialogs - added a group selection for "peering rule edit" dialogs that enables a possibility to move a peering rule into another peering group - changed the "back" uri in the "peering host" and "peering rule" dialogs to return back to the previous uri instead of forcing it to /peering, that is needed to call those dialogs from /peeringoverview and then get back to the original uri upon completion - dynamic columns support - separate outbound and inbound peering rules respresentation - export to "CSV", also with the "Search" filter support - add dynamic column join detection excluding excessive joins if no related columns are selected Change-Id: I71b4c62c4583989baacfc166f08e965c4464e4b2changes/86/12586/16
parent
8f98cd1d73
commit
fc9593175f
@ -0,0 +1,212 @@
|
||||
package NGCP::Panel::Controller::PeeringOverview;
|
||||
use NGCP::Panel::Utils::Generic qw(:all);
|
||||
use Sipwise::Base;
|
||||
|
||||
use parent 'Catalyst::Controller';
|
||||
|
||||
use NGCP::Panel::Form::PeeringOverview::Columns;
|
||||
use NGCP::Panel::Utils::Navigation;
|
||||
|
||||
sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) {
|
||||
my ($self, $c) = @_;
|
||||
$c->log->debug(__PACKAGE__ . '::auto');
|
||||
NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub list :Chained('/') :PathPart('peeringoverview') :CaptureArgs(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
|
||||
my $stored = $c->session->{created_objects}{peeringoverview} //= {};
|
||||
$stored->{rule_direction} //= "outbound";
|
||||
|
||||
my @default = (
|
||||
{ name => "callee_prefix", search => 1, title => $c->loc("Callee Prefix") },
|
||||
{ name => "enabled", search => 1, title => $c->loc("State") },
|
||||
{ name => "description", search => 1, title => $c->loc("Description") },
|
||||
{ name => "group.name", search => 1, title => $c->loc("Peer Group") },
|
||||
{ name => "group.voip_peer_hosts.name", search => 1, title => $c->loc("Peer Name") },
|
||||
{ name => "group.voip_peer_hosts.host", search => 1, title => $c->loc("Peer Host") },
|
||||
{ name => "group.voip_peer_hosts.ip", search => 1, title => $c->loc("Peer IP") },
|
||||
{ name => "group.voip_peer_hosts.enabled", search => 1, title => $c->loc("Peer State") },
|
||||
{ name => "group.priority", search => 1, title => $c->loc("Priority") },
|
||||
{ name => "group.voip_peer_hosts.weight", search => 1, title => $c->loc("Weight") },
|
||||
);
|
||||
|
||||
if (defined $stored->{cols}) {
|
||||
foreach my $col (@{$stored->{cols}}) {
|
||||
unless ($col->{name} || $col->{title}) {
|
||||
delete $stored->{$col};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@{$stored->{cols}} = @default;
|
||||
}
|
||||
|
||||
$c->stash->{po_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
|
||||
{ name => "id", search => 1, title => $c->loc("#") },
|
||||
@{$stored->{cols}}
|
||||
]);
|
||||
|
||||
$c->stash->{template} = 'peeringoverview/list.tt';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub root :Chained('list') :PathPart('') :Args(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
}
|
||||
|
||||
sub ajax :Chained('list') :PathPart('ajax') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $stored = $c->session->{created_objects}{peeringoverview} //= {};
|
||||
$stored->{search} = $c->req->params->{sSearch} // '';
|
||||
|
||||
my $rules_table = "voip_peer_rules";
|
||||
if ($stored->{rule_direction} eq "inbound") {
|
||||
$rules_table = "voip_peer_inbound_rules";
|
||||
}
|
||||
|
||||
my $join = { 'join' => 'group' };
|
||||
if (grep { /voip_peer_hosts/ } map { $_->{name} } @{$stored->{cols}}) {
|
||||
$join = {
|
||||
'join' => { 'group' => 'voip_peer_hosts' },
|
||||
'+select' => [ 'voip_peer_hosts.id' ],
|
||||
'+as' => [ 'peer_id' ],
|
||||
};
|
||||
}
|
||||
|
||||
$c->stash->{po_rs} = $c->model('DB')->resultset($rules_table)->search(
|
||||
{}, $join
|
||||
);
|
||||
|
||||
NGCP::Panel::Utils::Datatables::process($c, @{$c->stash}{qw(po_rs po_dt_columns)}, sub {
|
||||
my $item = shift;
|
||||
my %cols = $item->get_inflated_columns;
|
||||
return ( peer_group_id => $cols{group_id},
|
||||
peer_host_id => $cols{peer_id} );
|
||||
},);
|
||||
|
||||
$c->detach( $c->view("JSON") );
|
||||
}
|
||||
|
||||
|
||||
sub edit :Chained('list') :PathPart('edit') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $form = NGCP::Panel::Form::PeeringOverview::Columns->new(ctx => $c);
|
||||
my $params = $c->session->{created_objects}{peeringoverview}{states} // {};
|
||||
my $posted = ($c->req->method eq 'POST');
|
||||
my $data = $c->req->params;
|
||||
|
||||
$form->process(
|
||||
posted => $posted,
|
||||
params => $c->request->params,
|
||||
item => $params,
|
||||
);
|
||||
|
||||
unless ($posted && $form->validated) {
|
||||
$c->stash(
|
||||
template => 'peeringoverview/edit.tt',
|
||||
form => $form,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
my $stored = { rule_direction => $data->{rule_direction} // "undef", cols => [] };
|
||||
foreach my $field ($form->fields) {
|
||||
my $prefix = ($stored->{rule_direction} eq "outbound" ? "out" : "in");
|
||||
if ($field->name =~ /^${prefix}_(.+)$/ && $data->{$field->name}) {
|
||||
push @{$stored->{cols}}, {
|
||||
name => $field->{element_attr}->{field},
|
||||
title => $c->loc($field->label),
|
||||
search => 1,
|
||||
};
|
||||
}
|
||||
$stored->{states}{$field->name} = $data->{$field->name} // 0;
|
||||
}
|
||||
$c->session->{created_objects}{peeringoverview} = $stored;
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for);
|
||||
}
|
||||
|
||||
sub csv :Chained('list') :PathPart('csv') :Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
my $stored = $c->session->{created_objects}{peeringoverview} //= {};
|
||||
|
||||
my $csv = Text::CSV_XS->new({ allow_whitespace => 1, binary => 1, keep_meta_info => 1 });
|
||||
my @hdr_cols = map { $_->{title} } @{$stored->{cols}};
|
||||
$csv->column_names(@hdr_cols);
|
||||
my $io = IO::String->new();
|
||||
|
||||
my $rules_table = "voip_peer_rules";
|
||||
if ($stored->{rule_direction} eq "inbound") {
|
||||
$rules_table = "voip_peer_inbound_rules";
|
||||
}
|
||||
|
||||
my @sel_cols = map { scalar split(/\./, $_->{name}) == 3
|
||||
? join('.', (split(/\./, $_->{name}))[1,2])
|
||||
: $_->{name}
|
||||
} @{$stored->{cols}};
|
||||
my @as_cols = map { (my $t = $_) =~ s/\./_/g; $t } @sel_cols;
|
||||
|
||||
my $filter = {};
|
||||
if ($stored->{search}) {
|
||||
foreach my $col (@sel_cols) {
|
||||
my $rel_col = ($col =~ /\./ ? $col : 'me.'.$col);
|
||||
push @{$filter->{'-or'}},
|
||||
{ $rel_col => { like => '%'.$stored->{search}.'%' } }
|
||||
}
|
||||
}
|
||||
|
||||
my $join = {
|
||||
'join' => 'group',
|
||||
'select' => [ @sel_cols ],
|
||||
'as' => [ @as_cols ],
|
||||
};
|
||||
if (grep { /voip_peer_hosts/ } map { $_->{name} } @{$stored->{cols}}) {
|
||||
$join = {
|
||||
'join' => { 'group' => 'voip_peer_hosts' },
|
||||
'select' => [ @sel_cols ],
|
||||
'as' => [ @as_cols ],
|
||||
};
|
||||
}
|
||||
|
||||
my $res = $c->model('DB')->resultset($rules_table)->search(
|
||||
$filter, $join
|
||||
);
|
||||
|
||||
$csv->print($io, [ @hdr_cols ]);
|
||||
print $io "\n";
|
||||
foreach my $row ($res->all) {
|
||||
my %data = $row->get_inflated_columns;
|
||||
$csv->print($io, [ @data{@as_cols} ]);
|
||||
print $io "\n";
|
||||
}
|
||||
|
||||
my $date_str = POSIX::strftime('%Y-%m-%d_%H_%M_%S', localtime(time));
|
||||
|
||||
$c->response->header ('Content-Disposition' => 'attachment; filename="peering_overview_'. $date_str .'.csv"');
|
||||
$c->response->content_type('text/csv');
|
||||
$c->response->body(${$io->string_ref});
|
||||
}
|
||||
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Kirill Solomko <ksolomko@sipwise.com>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
This library is free software. You can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,18 @@
|
||||
package NGCP::Panel::Field::PeeringGroupSelect;
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler::Field::Compound';
|
||||
|
||||
has_field 'id' => (
|
||||
type => '+NGCP::Panel::Field::DataTable',
|
||||
label => 'Peering Group',
|
||||
do_label => 0,
|
||||
do_wrapper => 0,
|
||||
required => 1,
|
||||
template => 'helpers/datatables_field.tt',
|
||||
ajax_src => '/peering/ajax',
|
||||
table_titles => ['#', 'Name', 'Priority', 'Description'],
|
||||
table_fields => ['id', 'name', 'priority', 'description'],
|
||||
);
|
||||
|
||||
no Moose;
|
||||
1;
|
@ -0,0 +1,336 @@
|
||||
package NGCP::Panel::Form::PeeringOverview::Columns;
|
||||
|
||||
use HTML::FormHandler::Moose;
|
||||
extends 'HTML::FormHandler';
|
||||
|
||||
use HTML::FormHandler::Widget::Block::Bootstrap;
|
||||
|
||||
has '+widget_wrapper' => ( default => 'Bootstrap' );
|
||||
has_field 'submitid' => ( type => 'Hidden' );
|
||||
sub build_render_list {[qw/submitid fields actions/]}
|
||||
sub build_form_element_class { [qw/form-horizontal/] }
|
||||
|
||||
has_field 'rule_direction' => (
|
||||
type => 'Select',
|
||||
label => 'Direction',
|
||||
widget => 'RadioGroup',
|
||||
options => [ { checked => 1, label => 'Outbound', value => 'outbound' },
|
||||
{ label => 'Inbound', value => 'inbound'} ],
|
||||
required => 1,
|
||||
element_attr => {
|
||||
rel => ['tooltip'],
|
||||
title => ['Peering rules direction (outbound or inbound).'],
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_callee_prefix' => (
|
||||
type => 'Boolean',
|
||||
label => 'Prefix',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'callee_prefix',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_callee_pattern' => (
|
||||
type => 'Boolean',
|
||||
label => 'Callee Pattern',
|
||||
default => 0,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'callee_pattern',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_caller_pattern' => (
|
||||
type => 'Boolean',
|
||||
label => 'Caller Pattern',
|
||||
default => 0,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'caller_pattern',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_enabled' => (
|
||||
type => 'Boolean',
|
||||
label => 'State',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'enabled',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_description' => (
|
||||
type => 'Boolean',
|
||||
label => 'Description',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'description',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_group_name' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Group',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.name',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_name' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Name',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.name',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_host' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Host',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.host',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_ip' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer IP',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.ip',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_port' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Port',
|
||||
default => 0,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.port',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_transport' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Proto',
|
||||
default => 0,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.transport',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_state' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer State',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.enabled',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_group_priority' => (
|
||||
type => 'Boolean',
|
||||
label => 'Priority',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.priority',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'out_peer_weight' => (
|
||||
type => 'Boolean',
|
||||
label => 'Weight',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'outbound',
|
||||
field => 'group.voip_peer_hosts.weight',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_field' => (
|
||||
type => 'Boolean',
|
||||
label => 'Field',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'field',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_pattern' => (
|
||||
type => 'Boolean',
|
||||
label => 'Pattern',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'pattern',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_reject_code' => (
|
||||
type => 'Boolean',
|
||||
label => 'Reject Code',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'reject_code',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_reject_reason' => (
|
||||
type => 'Boolean',
|
||||
label => 'Reject Reason',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'reject_reason',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_priority' => (
|
||||
type => 'Boolean',
|
||||
label => 'Rule Priority',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'priority',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_enabled' => (
|
||||
type => 'Boolean',
|
||||
label => 'State',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'enabled',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_group_name' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Group',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.name',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_name' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Name',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.name',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_host' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Host',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.host',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_ip' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer IP',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.ip',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_port' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Port',
|
||||
default => 0,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.port',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_transport' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer Proto',
|
||||
default => 0,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.transport',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_state' => (
|
||||
type => 'Boolean',
|
||||
label => 'Peer State',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.enabled',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_group_priority' => (
|
||||
type => 'Boolean',
|
||||
label => 'Priority',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.priority',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'in_peer_weight' => (
|
||||
type => 'Boolean',
|
||||
label => 'Weight',
|
||||
default => 1,
|
||||
element_attr => {
|
||||
type => 'inbound',
|
||||
field => 'group.voip_peer_hosts.weight',
|
||||
},
|
||||
);
|
||||
|
||||
has_field 'save' => (
|
||||
type => 'Submit',
|
||||
value => 'Save',
|
||||
element_class => [qw/btn btn-primary/],
|
||||
label => '',
|
||||
);
|
||||
|
||||
has_block 'fields' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-body/],
|
||||
);
|
||||
|
||||
has_block 'actions' => (
|
||||
tag => 'div',
|
||||
class => [qw/modal-footer/],
|
||||
render_list => [qw/save/],
|
||||
);
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,98 @@
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
if ($('input[name=rule_direction]:checked').attr("value") == "outbound") {
|
||||
$("#control-inbound").hide();
|
||||
$("#control-outbound").show();
|
||||
} else {
|
||||
$("#control-inbound").show();
|
||||
$("#control-outbound").hide();
|
||||
}
|
||||
|
||||
$('input[name$="rule_direction"]').click(function() {
|
||||
if ($(this).attr("value") == "outbound") {
|
||||
$("#control-outbound").show();
|
||||
$("#control-inbound").hide();
|
||||
$('div"#control-direction" input[type=checkbox]').prop('checked', false);
|
||||
}
|
||||
if ($(this).attr("value") == "inbound") {
|
||||
$("#control-outbound").hide();
|
||||
$("#control-inbound").show();
|
||||
$('div"#control-direction" input[type=checkbox]').prop('checked', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
[% site_config.title = c.loc('Peering Overview Columns');
|
||||
|
||||
helper.identifier = 'call_routing_verify';
|
||||
helper.close_target = close_target;
|
||||
|
||||
PROCESS "helpers/modal.tt";
|
||||
|
||||
modal_header(m.create_flag=0,
|
||||
m.name = c.loc("Peering Overview Columns"));
|
||||
|
||||
helper.form = translate_form(form);
|
||||
-%]
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
[% helper.form.render_start %]
|
||||
<div class="form_messages">
|
||||
</div>
|
||||
<div>
|
||||
<div class="controls">
|
||||
<input type="hidden" name="submitid" id="submitid" value="" /></div>
|
||||
</div>
|
||||
|
||||
[% helper.form.field('rule_direction').render %]
|
||||
<div id="control-rule-direction">
|
||||
<div id="control-outbound">
|
||||
<table width="100%" border="0">
|
||||
[% tmpcol = 0 -%]
|
||||
[% FOREACH field IN helper.form.fields -%]
|
||||
[% IF field.element_attr.type == 'outbound' -%]
|
||||
[% IF tmpcol mod 2 == 0 -%]
|
||||
<tr><td>[% field.render -%]</td>
|
||||
[% ELSE -%]
|
||||
<td>[% field.render -%]</td></tr>
|
||||
[% END -%]
|
||||
[% tmpcol = tmpcol + 1 -%]
|
||||
[% END -%]
|
||||
[% END -%]
|
||||
</table>
|
||||
</div>
|
||||
<div id="control-inbound">
|
||||
<table width="100%" border="0">
|
||||
[% tmpcol = 0 -%]
|
||||
[% FOREACH field IN helper.form.fields -%]
|
||||
[% IF field.element_attr.type == 'inbound' -%]
|
||||
[% IF tmpcol mod 2 == 0 -%]
|
||||
<tr><td>[% field.render -%]</td>
|
||||
[% ELSE -%]
|
||||
<td>[% field.render -%]</td></tr>
|
||||
[% END -%]
|
||||
[% tmpcol = tmpcol + 1 -%]
|
||||
[% END -%]
|
||||
[% END -%]
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[% helper.form.field('save').render %]
|
||||
|
||||
[% helper.form.render_end %]
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
[%
|
||||
modal_footer();
|
||||
modal_script(m.close_target = helper.close_target);
|
||||
-%]
|
||||
|
||||
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
@ -0,0 +1,29 @@
|
||||
[% site_config.title = c.loc('Peering Overview') -%]
|
||||
[%
|
||||
helper.name = c.loc('Peering Overview');
|
||||
helper.identifier = 'PeeringOverview';
|
||||
helper.data = po;
|
||||
helper.messages = messages;
|
||||
helper.dt_columns = po_dt_columns;
|
||||
helper.length_change = 1;
|
||||
|
||||
helper.close_target = close_target;
|
||||
helper.create_flag = create_flag;
|
||||
helper.edit_flag = edit_flag;
|
||||
helper.form_object = form;
|
||||
helper.ajax_uri = c.uri_for_action('/peeringoverview/ajax');
|
||||
|
||||
helper.dt_buttons = [
|
||||
{ name = c.loc('Rule'), uri = "/peering/'+full.peer_group_id+'/rules/'+full.id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' },
|
||||
{ name = c.loc('Group'), uri = "/peering/'+full.peer_group_id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' },
|
||||
{ name = c.loc('Host'), uri = "/peering/'+full.peer_group_id+'/servers/'+full.peer_host_id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' },
|
||||
{ name = c.loc('Delete'), uri = "/peering/'+full.peer_group_id+'/rules/'+full.id+'/delete", class = 'btn-small btn-secondary', icon = 'icon-remove' },
|
||||
];
|
||||
helper.top_buttons = [
|
||||
{ name = c.loc('Columns'), uri = c.uri_for_action('/peeringoverview/edit'), icon = 'icon-edit' },
|
||||
{ name = c.loc('Download as CSV'), uri = c.uri_for_action('/peeringoverview/csv'), icon = 'icon-star' },
|
||||
];
|
||||
|
||||
PROCESS 'helpers/datatables.tt';
|
||||
-%]
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
Loading…
Reference in new issue