Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5.0/asset inline edit #377

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions etc/RT_Config.pm.in
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,15 @@ Grouping" are created by the L</%CustomFieldGroupings> setting.
'Links' => 'hide',
'People' => 'link',
},
'RT::Asset' => {
'_default' => 'click',

'Grouping Name' => 'link',
'Another Grouping' => 'click',
'Dates' => 'hide',
'Links' => 'hide',
'People' => 'link',
},
);

=back
Expand Down
46 changes: 45 additions & 1 deletion share/html/Asset/Display.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<& /Elements/ListActions, actions => \@results &>

<span class="catalog <% CSSClass($asset->CatalogObj->Name) %>">
<& Elements/ShowSummary, AssetObj => $asset &>
<& Elements/ShowSummary, AssetObj => $asset, InlineEdit => $InlineEdit &>

% $m->callback(CallbackName => 'AfterShowSummary', ARGSRef => \%ARGS, Asset => $asset);

Expand All @@ -68,9 +68,53 @@

<%args>
$id => undef
$InlineEdit => RT->Config->Get( 'InlineEdit', $session{CurrentUser} )
</%args>
<%init>
my @results;
my $asset = LoadAsset($id);

# fill ACL cache
$asset->CurrentUser->PrincipalObj->HasRights( Object => $asset );

my $SkipProcessing;

$m->callback( CallbackName => 'BeforeProcessArguments',
AssetObj => $asset,
ActionsRef => \@results, ARGSRef => \%ARGS,
SkipProcessing => \$SkipProcessing );

my ($status, @msg) = $m->comp(
'/Elements/ValidateCustomFields',
Object => $asset,
CustomFields => $asset->CustomFields,
ARGSRef => \%ARGS,
);
unless ($status) {
push @results, @msg;
$SkipProcessing = 1;
}

if ( !$SkipProcessing ) {

push @results, ProcessAssetRoleMembers( $asset => %ARGS );
push @results, ProcessRecordLinks( RecordObj => $asset, ARGSRef => \%ARGS );
push @results, ProcessObjectCustomFieldUpdates( Object => $asset, ARGSRef => \%ARGS );

push @results, UpdateRecordObject(
Object => $asset,
AttributesRef => [ $asset->WritableAttributes ],
ARGSRef => \%ARGS,
);

}

$m->callback(CallbackName => 'BeforeDisplay', ARGSRef => \%ARGS, Asset => $asset, Results => \@results);

MaybeRedirectForResults(
Actions => \@results,
Path => '/Asset/Display.html',
Anchor => $ARGS{'Anchor'},
Arguments => { id => $asset->Id },
);
</%init>
93 changes: 93 additions & 0 deletions share/html/Asset/Elements/EditPeopleInline
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
%# BEGIN BPS TAGGED BLOCK {{{
%#
%# COPYRIGHT:
%#
%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
%# <[email protected]>
%#
%# (Except where explicitly superseded by other copyright notices)
%#
%#
%# LICENSE:
%#
%# This work is made available to you under the terms of Version 2 of
%# the GNU General Public License. A copy of that license should have
%# been provided with this software, but in any event can be snarfed
%# from www.gnu.org.
%#
%# This work is distributed in the hope that it will be useful, but
%# WITHOUT ANY WARRANTY; without even the implied warranty of
%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%# General Public License for more details.
%#
%# You should have received a copy of the GNU General Public License
%# along with this program; if not, write to the Free Software
%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
%# 02110-1301 or visit their web page on the internet at
%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
%#
%#
%# CONTRIBUTION SUBMISSION POLICY:
%#
%# (The following paragraph is not intended to limit the rights granted
%# to you to modify and distribute this software under the terms of
%# the GNU General Public License and is only of importance to you if
%# you choose to contribute your changes and enhancements to the
%# community by submitting them to Best Practical Solutions, LLC.)
%#
%# By intentionally submitting any modifications, corrections or
%# derivatives to this work, or any other work intended for use with
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
%# you are the copyright holder for those contributions and you grant
%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
%# royalty-free, perpetual, license to use, copy, create derivative
%# works based on those contributions, and sublicense and distribute
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}

% for my $role ($AssetObj->Roles( ACLOnly => 0 )) {
<div class="role-<% CSSClass($role) %> role">
<h5 class="mt-2"><% $AssetObj->LabelForRole($role) %></h5>
<& EditRoleMembers, Object => $AssetObj, Role => $role &>
</div>
% }

<div class="add-user">
<h5 class="mt-2"><&|/l&>Add a person</&></h5>
<div class="form-row">
<div class="col-3">
<& SelectRoleType, Object => $AssetObj, Name => "AddUserRoleMember-Role" &>
</div>
<div class="col-9">
<input type="text" name="AddUserRoleMember"
data-autocomplete="Users"
data-autocomplete-return="Name"
placeholder="<% loc("Find a user...") %>"
class="form-control"
>
</div>
</div>
</div>

<div class="add-group">
<h5 class="mt-2"><&|/l&>Add a group</&></h5>
<div class="form-row">
<div class="col-3">
<& SelectRoleType, Object => $AssetObj, Name => "AddGroupRoleMember-Role" &>
</div>
<div class="col-9">
<input type="text" name="AddGroupRoleMember"
data-autocomplete="Groups"
data-autocomplete-return="Name"
placeholder="<% loc("Find a group...") %>"
class="form-control"
>
</div>
</div>
</div>

<& /Elements/EditCustomFields, Object => $AssetObj, Grouping => 'People', InTable => 1 &>
<%ARGS>
$AssetObj => undef
</%ARGS>
4 changes: 2 additions & 2 deletions share/html/Asset/Elements/EditRoleMembers
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ $Recursively => 0
</%args>
<%init>
my $Group = $Object->RoleGroup($Role);
my $field_name = "RemoveRoleMember-" . $Group->Name;
my $field_name = "RemoveRoleMember-" . $Role;
</%init>
<ul class="role-members list-group list-group-compact">
% my $Users = $Group->UserMembersObj( Recursively => $Recursively );
% if ($Object->Role($Role)->{Single}) {
% my $user = $Users->First || RT->Nobody;
<li class="list-group-item">
<input class="form-control selectpicker" type="text" value="<% $user->Name %>" name="SetRoleMember-<% $Group->Name %>" id="SetRoleMember-<% $Group->Name %>" data-autocomplete="Users" data-autocomplete-return="Name" />
<input class="form-control" type="text" value="<% $user->Name %>" name="SetRoleMember-<% $Role %>" id="SetRoleMember-<% $Role %>" data-autocomplete="Users" data-autocomplete-return="Name" />
</li>
% } else {
% while ( my $user = $Users->Next ) {
Expand Down
61 changes: 55 additions & 6 deletions share/html/Asset/Elements/ShowSummary
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
%# END BPS TAGGED BLOCK }}}
<%args>
$AssetObj
$InlineEdit => 0
</%args>
<%init>
my @sections = (
Expand All @@ -56,9 +57,6 @@ my @sections = (
"Links", #loc
);

my $can_edit = $session{CurrentUser}->Privileged
&& $AssetObj->CurrentUserHasRight("ModifyAsset");

my %link;
for my $section (@sections) {
my $page = $section eq 'Basics' ? "Modify.html" : "Modify$section.html";
Expand All @@ -67,20 +65,71 @@ for my $section (@sections) {
. "/Asset/$page?id="
. $AssetObj->id;
}

my $can_modify = $AssetObj->CurrentUserHasRight('ModifyAsset');
my $can_modify_cf = $AssetObj->CurrentUserHasRight('ModifyCustomField');

$m->callback( CallbackName => 'ModifyRights', %ARGS, AssetObj => $AssetObj, ARGSRef => \%ARGS,
CanModify => \$can_modify, CanModifyCF => \$can_modify_cf );

my $edit_label = $m->interp->apply_escapes( loc("Edit"), 'h' );
my $cancel_label = $m->interp->apply_escapes( loc("Cancel"), 'h' );

my %inline_edit_behavior;
if (RT->Config->Get('InlineEditPanelBehavior')) {
%inline_edit_behavior = %{ RT->Config->Get('InlineEditPanelBehavior')->{'RT::Asset'} || {} };
}

my $modify_inline
= '<a class="inline-edit-toggle edit" href="%s">'
. qq{<span class="fas fa-pencil-alt icon-bordered fa-2x" alt="$edit_label" data-toggle="tooltip" data-placement="top" data-original-title="$edit_label"></span>}
. '</a>'
. '<a class="inline-edit-toggle cancel hidden" href="#">'
. qq{<span class="fas fa-times icon-bordered fa-2x" alt="$cancel_label" data-toggle="tooltip" data-placement="top" data-original-title="$cancel_label"></span>}
. '</a>';
</%init>
<div class="asset-metadata">
<div class="form-row">
% for my $section (@sections) {
% my $modify_url = sprintf( $modify_inline, $m->interp->apply_escapes( $link{$section}, 'h' ) );
% my $modify_behavior = $InlineEdit ? ($inline_edit_behavior{$section} || $inline_edit_behavior{_default} || 'link') : 'hide';

<div class="col-4">
<&| /Widgets/TitleBox, title => loc($section), title_href => $can_edit ? $link{$section} : "", title_class => "inverse", class => "asset-\L$section" &>
<& "Show$section", AssetObj => $AssetObj &>
<&| /Widgets/TitleBox, title => loc($section), title_href => ($can_modify || $can_modify_cf) ? $link{$section} : "", title_class => "inverse",
(($can_modify || $can_modify_cf) && $modify_behavior =~ /^(link|click)$/ ? (titleright_raw => $modify_url) : ()),
class => (join " ", "asset-\L$section", ($modify_behavior eq 'always' ? 'editing' : ())),
data => { 'inline-edit-behavior' => $modify_behavior }
&>
% unless ($modify_behavior eq 'always') {
<div class="inline-edit-display">
<& "Show$section", AssetObj => $AssetObj &>
</div>
% }
% if ($modify_behavior ne 'hide') {
<form class="inline-edit" action="<%RT->Config->Get('WebPath')%>/Asset/Display.html" method="post" enctype="multipart/form-data">
<input type="hidden" class="hidden" name="id" value="<% $AssetObj->id %>" />
% if ( $section eq 'Links' ) {
<& /Elements/EditLinks, Object => $AssetObj &>
<& /Elements/EditCustomFields, Object => $AssetObj, Grouping => $section, InTable => 1 &>
% } elsif ( $section eq 'People' ) {
<& /Asset/Elements/EditPeopleInline, AssetObj => $AssetObj &>
% } else {
<& "/Asset/Elements/Edit$section", AssetObj => $AssetObj &>
% }
<div class="form-row">
<div class="col-12 text-right">
<input type="submit" class="button btn btn-primary" value="<&|/l&>Save</&>" />
</div>
</div>
</form>
% }
</&>
</div>
% }

<& /Elements/ShowCustomFieldCustomGroupings,
Object => $AssetObj,
title_href => $can_edit ? RT->Config->Get("WebPath") . "/Asset/ModifyCFs.html" : "",
title_href => ($can_modify || $can_modify_cf) ? RT->Config->Get("WebPath") . "/Asset/ModifyCFs.html" : "",
TitleBoxARGS => { title_class => "inverse" },
GroupingClass => 'col-4'
&>
Expand Down
1 change: 1 addition & 0 deletions share/html/Asset/Search/Bulk.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
Collection => $assets,
AllowSorting => 1,
DisplayFormat => $DisplayFormat,
InlineEdit => 0,
&>
% if (not $assets->Count) {
<em><&|/l&>No assets matching search criteria found.</&></em>
Expand Down
13 changes: 10 additions & 3 deletions share/html/Elements/CollectionAsTable/Row
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,15 @@ foreach my $column (@Format) {

my %attrs;
my @possible_attrs = qw(style align);
if ($InlineEdit && $record->isa('RT::Ticket') && $record->CurrentUserHasRight('ModifyTicket')) {
push(@possible_attrs, 'edit');
if (
$InlineEdit
&& ( $record->isa('RT::Ticket') && $record->CurrentUserHasRight('ModifyTicket')
|| $record->isa('RT::Asset') && $record->CurrentUserHasRight('ModifyAsset') )
)
{
push( @possible_attrs, 'edit' );
}

foreach my $attr (@possible_attrs) {
if ( defined $column->{ $attr } ) {
$attrs{ $attr } = $column->{ $attr };
Expand Down Expand Up @@ -171,7 +177,8 @@ foreach my $column (@Format) {
$m->out('>');

if ( $attrs{edit} ) {
$m->out( '<form method="POST" action="' . RT->Config->Get('WebPath') . '/Helpers/TicketUpdate?id=' . $record->id . '" class="editor" autocomplete="off">' );
my $helper_name = $record->isa('RT::Ticket') ? 'TicketUpdate' : 'AssetUpdate';
$m->out( '<form method="POST" action="' . RT->Config->Get('WebPath') . "/Helpers/$helper_name?id=" . $record->id . '" class="editor" autocomplete="off">' );
$m->out( $attrs{edit} );
$m->out( '<span class="cancel text-danger far fa-times-circle" data-toggle="tooltip" data-placement="left" data-original-title="' . loc('Cancel') . '"></span>' );
$m->out( '<span class="submit text-success far fa-check-circle" data-toggle="tooltip" data-placement="right" data-original-title="' . loc('Save') . '"></span>' );
Expand Down
3 changes: 2 additions & 1 deletion share/html/Elements/CollectionList
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ foreach my $col (@Format) {

$Class ||= $Collection->ColumnMapClassName;

$InlineEdit = 0 unless $Collection->isa('RT::Tickets');
$InlineEdit = 0
unless $session{CurrentUser}->Privileged && ( $Collection->isa('RT::Tickets') || $Collection->isa('RT::Assets') );

$m->out('<div class="table-responsive">');
$m->out('<table cellspacing="0"');
Expand Down
26 changes: 25 additions & 1 deletion share/html/Elements/ColumnMap
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,20 @@ $WCOLUMN_MAP = $COLUMN_MAP = {
my $role = $self->{load}->(@_);
return unless $role->Id;
if ($role->SingleValue) {
return \($m->scomp("/Elements/SingleUserRoleInput", role => $role, Ticket => $_[0]));
if ( $_[0]->isa('RT::Ticket') ) {
return \($m->scomp("/Elements/SingleUserRoleInput", role => $role, Ticket => $_[0]));
}
elsif ( $_[0]->isa('RT::Asset') ) {
my $group = $_[0]->RoleGroup( $role->GroupType);
my $user = $group->UserMembersObj()->First || RT->Nobody;
my $user_name = $m->interp->apply_escapes( $user->Name, 'h' );
my $group_type = $role->GroupType;
return \qq{<input class="form-control" type="text" value="$user_name" name="SetRoleMember-$group_type" data-autocomplete="Users" data-autocomplete-return="Name" />};
}
else {
RT->Logger->warning( "Invalid object for custom roles: " . ref $_[0] );
return undef;
}
}
else {
return undef;
Expand Down Expand Up @@ -447,6 +460,17 @@ if ($RecordClass->DOES("RT::Record::Role::Roles")) {
}
},
value => sub { return $role_value->($role, @_, @_ == 2 ? '' : () ) },
edit => sub {
if ($attrs->{Single} && $RecordClass eq 'RT::Asset' ) {
my $group = $_[0]->RoleGroup($role);
my $user = $group->UserMembersObj()->First || RT->Nobody;
my $user_name = $m->interp->apply_escapes( $user->Name, 'h' );
return \qq{<input class="form-control" type="text" value="$user_name" name="SetRoleMember-$role" data-autocomplete="Users" data-autocomplete-return="Name" />};
}
else {
return undef;
}
},
};

$ROLE_MAP->{$RecordClass}{$role . "s"} = $ROLE_MAP->{$RecordClass}{$role}
Expand Down
6 changes: 5 additions & 1 deletion share/html/Elements/RT__Asset/ColumnMap
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,25 @@ my $COLUMN_MAP = {
attribute => 'Name',
title => 'Name',
value => sub { $_[0]->Name },
edit => sub { return \('<input name="Name" class="form-control" value="'.$m->interp->apply_escapes( $_[0]->Name, 'h' ).'" />') },
},
Description => {
attribute => 'Description',
title => 'Description',
value => sub { $_[0]->Description },
edit => sub { return \('<input name="Description" class="form-control" value="'.$m->interp->apply_escapes( $_[0]->Description, 'h' ).'" />') },
},
Catalog => {
attribute => 'Catalog',
title => 'Catalog', # loc
value => sub { $_[0]->CatalogObj->Name },
edit => sub { return \($m->scomp('/Asset/Elements/SelectCatalog', Default => $_[0]->Catalog, Name => 'Catalog', ShowNullOption => 0)) },
},
Status => {
title => 'Status',
attribute => 'Status',
value => sub { loc($_[0]->Status) }
value => sub { loc($_[0]->Status) },
edit => sub { return \($m->scomp("/Asset/Elements/SelectStatus", AssetObj => $_[0], Name => 'Status' ) ) },
},
ActiveTickets => {
title => 'Active tickets', # loc
Expand Down
Loading