Files
Disco/Disco.Web/Areas/Config/Views/DeviceFlag/Show.cshtml
T
2025-09-19 12:18:45 +10:00

983 lines
50 KiB
Plaintext

@model Disco.Web.Areas.Config.Models.DeviceFlag.ShowModel
@using Disco.Services.Interop.ActiveDirectory;
@using Disco.Services.Devices.DeviceFlags;
@using Disco.Web.Areas.Config.Models.Shared;
@{
Authorization.Require(Claims.Config.DeviceFlag.Show);
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Device Flags", MVC.Config.DeviceFlag.Index(null), Model.DeviceFlag.ToString());
var canConfig = Authorization.Has(Claims.Config.DeviceFlag.Configure);
var canDelete = Authorization.Has(Claims.Config.DeviceFlag.Delete);
var canBulkAssignment = Authorization.HasAll(Claims.Device.Actions.AddFlags, Claims.Device.Actions.RemoveFlags, Claims.Device.ShowFlagAssignments);
var canShowDevices = Model.CurrentAssignmentCount > 0 && Authorization.HasAll(Claims.Device.Search, Claims.Device.ShowFlagAssignments);
var canExportCurrent = Model.CurrentAssignmentCount > 0 && Authorization.Has(Claims.Config.DeviceFlag.Export);
var canExportAll = Model.TotalAssignmentCount > 0 && Authorization.Has(Claims.Config.DeviceFlag.Export);
var hideAdvanced =
Model.Permission.IsDefault() &&
Model.DeviceFlag.DevicesLinkedGroup == null &&
Model.DeviceFlag.DeviceUsersLinkedGroup == null &&
Model.DeviceFlag.OnAssignmentExpression == null &&
Model.DeviceFlag.OnUnassignmentExpression == null;
Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers");
}
<div id="Config_DeviceFlags_Show" class="form@(hideAdvanced ? " Config_HideAdvanced" : null)" style="width: 550px">
<table>
<tr>
<th style="width: 150px">
Id:
</th>
<td>
@Html.DisplayFor(model => model.DeviceFlag.Id)
</td>
</tr>
<tr>
<th>
Name:
</th>
<td>
@if (canConfig)
{
@Html.EditorFor(model => model.DeviceFlag.Name)
@AjaxHelpers.AjaxSave()
@AjaxHelpers.AjaxLoader()
<script type="text/javascript">
$(function () {
document.DiscoFunctions.PropertyChangeHelper(
$('#DeviceFlag_Name'),
'Invalid Name',
'@(Url.Action(MVC.API.DeviceFlag.UpdateName(Model.DeviceFlag.Id)))',
'FlagName'
);
});
</script>
}
else
{
@Model.DeviceFlag.Name
}
</td>
</tr>
<tr>
<th>
Description:
</th>
<td>
@if (canConfig)
{@Html.EditorFor(model => model.DeviceFlag.Description)
@AjaxHelpers.AjaxSave()
@AjaxHelpers.AjaxLoader()
<script type="text/javascript">
$(function () {
document.DiscoFunctions.PropertyChangeHelper(
$('#DeviceFlag_Description'),
'Invalid Description',
'@(Url.Action(MVC.API.DeviceFlag.UpdateDescription(Model.DeviceFlag.Id)))',
'Description'
);
});
</script>
}
else
{
<pre>
@if (string.IsNullOrEmpty(Model.DeviceFlag.Description))
{
<text>&lt;None&gt;</text>
}
else
{
@Model.DeviceFlag.Description.ToHtmlComment()
}
</pre>
}
</td>
</tr>
<tr>
<th>
Statistics:
</th>
<td>
<div><strong>@Model.CurrentAssignmentCount device@(Model.CurrentAssignmentCount != 1 ? "s" : null) currently assigned</strong></div>
<div>@Model.TotalAssignmentCount total device historical assignment@(Model.TotalAssignmentCount != 1 ? "s" : null)</div>
</td>
</tr>
<tr>
<th>
Icon:
</th>
<td>
<i id="Config_DeviceFlags_Icon" data-icon="@(Model.DeviceFlag.Icon)" data-colour="@(Model.DeviceFlag.IconColour)" class="fa fa-@(Model.DeviceFlag.Icon) fa-4x d-@(Model.DeviceFlag.IconColour)"></i>
@if (canConfig)
{
<div>
<a id="Config_DeviceFlags_Icon_Update" href="#" class="button small">Update</a>
<div id="Config_DeviceFlags_Icon_Update_Dialog" class="dialog" title="Device Flag Icon">
@using (Html.BeginForm(MVC.API.DeviceFlag.UpdateIconAndColour(id: Model.DeviceFlag.Id, redirect: true)))
{
@Html.AntiForgeryToken()
<input type="hidden" name="icon" />
<input type="hidden" name="iconColour" />
}
<div>
<div class="colours">
@foreach (var colour in Model.ThemeColours)
{
<i data-colour="@(colour.Key)" class="fa fa-square d-@(colour.Key)" title="@colour.Value"></i>
}
</div>
<div class="icons">
@foreach (var icon in Model.Icons)
{
<i data-icon="@(icon.Key)" class="fa fa-@(icon.Key)" title="@icon.Value"></i>
}
</div>
</div>
</div>
<script>
(function () {
var dialog, icon, colours, icons;
function showDialog() {
if (!dialog) {
dialog = $('#Config_DeviceFlags_Icon_Update_Dialog').dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 1000,
buttons: {
"Save": save,
Cancel: cancel
}
});
colours = dialog.find('.colours');
icons = dialog.find('.icons');
colours.on('click', 'i', selectColour);
icons.on('click', 'i', selectIcon);
}
colours.find('i[data-colour="' + icon.attr('data-colour') + '"]').each(selectColour);
icons.find('i[data-icon="' + icon.attr('data-icon') + '"]').each(selectIcon);
dialog.dialog('open');
return false;
}
function selectColour() {
var $this = $(this),
colourCode = $this.attr('data-colour'),
previousColourCode = icons.attr('data-colour');
colours.find('i').removeClass('selected fa-check-square').addClass('fa-square');
$this.removeClass('fa-square').addClass('fa-check-square selected');
if (previousColourCode)
icons.removeClass('d-' + previousColourCode);
icons.attr('data-colour', colourCode)
icons.addClass('d-' + colourCode);
}
function selectIcon() {
var $this = $(this),
iconCode = $this.attr('data-icon');
icons.find('i').removeClass('selected');
$this.addClass('selected');
}
function save() {
dialog.dialog("option", "buttons", null);
const $form = dialog.find('form');
$form.find('input[name="icon"]').val(icons.find('i.selected').attr('data-icon'));
$form.find('input[name="iconColour"]').val(colours.find('i.selected').attr('data-colour'));
$form.trigger('submit');
}
function cancel() {
$(this).dialog("close");
}
$(function () {
icon = $('#Config_DeviceFlags_Icon');
$('#Config_DeviceFlags_Icon_Update').click(showDialog);
});
}());
</script>
</div>
}
</td>
</tr>
<tr>
<th>
Scheduled Unassignment:
</th>
<td>
@if (canConfig)
{
<input id="DeviceFlag_DefaultRemoveDays" type="number" min="1" max="@int.MaxValue" value="@Model.DeviceFlag.DefaultRemoveDays" />
@AjaxHelpers.AjaxSave()
@AjaxHelpers.AjaxLoader()
@:days
<script type="text/javascript">
$(function () {
document.DiscoFunctions.PropertyChangeHelper(
$('#DeviceFlag_DefaultRemoveDays'),
'Invalid Value',
'@(Url.Action(MVC.API.DeviceFlag.UpdateDefaultRemoveDays(Model.DeviceFlag.Id)))',
'defaultRemoveDays'
);
});
</script>
}
else
{
if (Model.DeviceFlag.DefaultRemoveDays.HasValue)
{
<span><strong>@Model.DeviceFlag.DefaultRemoveDays</strong> days</span>
}
else
{
<span><em>Not Enabled</em></span>
}
}
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i>
Optionally specify the number of days a flag is removed from a device.
If one (1), the flag will be removed that night (midnight).<br />
If the user has permission, the date can be adjusted when assigning the flag.
Changing this value does not affect existing assignments.
</p>
</div>
</td>
</tr>
@if (hideAdvanced)
{
<tr>
<td colspan="2" style="text-align: right;">
<button id="Config_HideAdvanced_Show" class="button small">Show Advanced Options</button>
<script>
$(function () {
$('#Config_HideAdvanced_Show').click(function () {
var $this = $(this);
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
$this.closest('tr').remove();
});
});
</script>
</td>
</tr>
}
<tr class="Config_HideAdvanced_Item">
<th>
Assignment Permission<br />
Override:
</th>
<td>
@if (!Model.Permission.IsDefault())
{
var permission = Model.Permission;
<div>
@if (permission.Inherit)
{
<span><i class="fa fa-check-square-o"></i> Inheriting from Authorization Roles</span>
}
else
{
<span><i class="fa fa-square-o"></i> Authorization Roles are Ignored</span>
}
</div>
if (!permission.HasSubjects())
{
<span class="smallMessage">There are no users/groups associated with this permission override</span>
}
else
{
if (permission.IsSimple())
{
<table class="tableData">
<thead>
<tr>
<th>Users/Groups/Roles</th>
</tr>
</thead>
<tbody>
@foreach (var subjectId in permission.CanShowSubjectIds)
{
<tr>
<td>
@{
int roleId;
if (subjectId.StartsWith("[") && int.TryParse(subjectId.Trim('[', ']'), out roleId))
{
<span>@Disco.Services.Users.UserService.GetAuthorizationRoleName(roleId) @subjectId</span>
}
else
{
<span>@subjectId</span>
}
}
</td>
</tr>
}
</tbody>
</table>
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i> All users/groups/roles can view, assign, edit assignments, and remove assignments for this flag.
</p>
</div>
}
else
{
var subjects = permission.AllSubjects();
<table class="tableData">
<thead>
<tr>
<th>Users/Groups/Roles</th>
<th>View</th>
<th>Assign</th>
<th>Edit</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
@foreach (var subjectId in subjects.OrderBy(s => s))
{
<tr>
<td>
<i class="fa"></i> @{
int roleId;
if (subjectId.StartsWith("[") && int.TryParse(subjectId.Trim('[', ']'), out roleId))
{
<span>@Disco.Services.Users.UserService.GetAuthorizationRoleName(roleId) @subjectId</span>
}
else
{
<span>@subjectId</span>
}
}
</td>
<td>
@if (permission.CanShowSubjectIds.Contains(subjectId))
{
<i class="fa fa-fw fa-check"></i>
}
</td>
<td>
@if (permission.CanAssignSubjectIds.Contains(subjectId))
{
<i class="fa fa-fw fa-check"></i>
}
</td>
<td>
@if (permission.CanEditSubjectIds.Contains(subjectId))
{
<i class="fa fa-fw fa-check"></i>
}
</td>
<td>
@if (permission.CanRemoveSubjectIds.Contains(subjectId))
{
<i class="fa fa-fw fa-check"></i>
}
</td>
</tr>
}
</tbody>
</table>
}
}
}
@if (canConfig)
{
var permission = Model.Permission;
<button id="Config_Flag_Permission_Edit" class="button small">@(permission.IsDefault() ? "Override" : "Edit") Permission</button>
<div id="Config_Flag_Permissions" class="dialog" title="Flag Assignment Permission Override">
@using (Html.BeginForm(MVC.API.DeviceFlag.Permission(Model.DeviceFlag.Id)))
{
@Html.AntiForgeryToken()
<input type="hidden" name="IsOverride" value="true" />
<div id="Config_Flag_Permissions_Inherit_Container">
<label>
<input id="Config_Flag_Permissions_Inherit" type="checkbox" name="Inherit" value="true" @(permission.Inherit ? "checked" : null) /> Inherit Authorization from Authorization Roles
</label>
</div>
<div class="tableDataContainer">
<table class="tableData">
<thead>
<tr>
<th>User/Group/Role</th>
<th>View</th>
<th>Assign</th>
<th>Edit</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
@{
var subjects = permission.AllSubjects();
foreach (var subjectId in subjects.OrderBy(s => s))
{
<tr data-subjectid="@subjectId">
<td><i class="fa type"></i> <span>@subjectId</span><i class="fa fa-times-circle remove"></i></td>
<td>
<input type="checkbox" name="CanShow" value="@subjectId" @(permission.CanShowSubjectIds.Contains(subjectId) ? " checked" : null) />
</td>
<td>
<input type="checkbox" name="CanAssign" value="@subjectId" @(permission.CanAssignSubjectIds.Contains(subjectId) ? " checked" : null) />
</td>
<td>
<input type="checkbox" name="CanEdit" value="@subjectId" @(permission.CanEditSubjectIds.Contains(subjectId) ? " checked" : null) />
</td>
<td>
<input type="checkbox" name="CanRemove" value="@subjectId" @(permission.CanRemoveSubjectIds.Contains(subjectId) ? " checked" : null) />
</td>
</tr>
}
}
</tbody>
</table>
</div>
<div>
<input type="text" id="Config_Flag_Permissions_Subject_Input" placeholder="Search Users/Groups/Roles" data-autocompleteurl="@(Url.Action(MVC.API.System.SearchSubjects(null, includeAuthorizationRoles: true)))" />
<button type="button" id="Config_Flag_Permissions_Subject_Add" class="button small" data-subjecturl="@Url.Action(MVC.API.System.Subject(null, includeAuthorizationRoles: true))">Add</button>
</div>
}
</div>
<script>
$(function () {
let $dialog = null;
let originalSubjects = null;
let originalInherit = null;
$('#Config_Flag_Permission_Edit').on('click', async function () {
if (!$dialog) {
$dialog = $('#Config_Flag_Permissions');
const $tbody = $dialog.find('tbody');
const $inherit = $dialog.find('#Config_Flag_Permissions_Inherit');
const $input = $dialog.find('#Config_Flag_Permissions_Subject_Input');
const $add = $dialog.find('#Config_Flag_Permissions_Subject_Add');
$dialog.dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 550,
height: 420,
buttons: {
Cancel: function () {
$(this).dialog('close');
$tbody.html(originalSubjects);
$inherit.prop('checked', originalInherit);
},
'Remove Override': function () {
const $this = $(this);
$(this).dialog('option', 'buttons', null);
$this.find('input[name="IsOverride"]').val('false');
$this.find('form').trigger('submit');
},
'Save Changes': function () {
$(this).dialog('option', 'buttons', null);
$(this).find('form').trigger('submit');
}
}
});
$tbody.on('click', 'i.remove', function () {
$(this).closest('tr').remove();
});
$input
.autocomplete({
source: $input.attr('data-autocompleteurl'),
minLength: 2,
focus: function (e, ui) {
$input.val(ui.item.Id);
return false;
},
select: function (e, ui) {
$input.val(ui.item.Id).blur();
$add.trigger('click');
$input.val('');
return false;
}
}).data('ui-autocomplete')._renderItem = function (ul, item) {
return $("<li></li>")
.data('item.autocomplete', item)
.append('<a><strong>' + item.Name + '</strong><br>' + item.Id + ' (' + item.Type + ')</a>')
.appendTo(ul);
};
$add.on('click', async function () {
const value = $input.val();
if (!value) {
$input.focus();
return;
}
const existing = $tbody.find('tr').filter(function () {
return $(this).attr('data-subjectid') === value;
});
if (existing.length !== 0) {
$input.val('');
$input.focus();
return;
}
const body = new FormData();
body.append('id', value);
const response = await fetch($add.attr('data-subjecturl'), {
body: body,
method: 'POST'
});
if (!response.ok) {
alert('Unable to lookup User/Group/Role: ' + response.statusText);
$input.focus();
return;
}
const subject = await response.json();
if (!subject) {
alert('Invalid User/Group/Role');
$input.focus();
return;
}
const $record = $('<tr><td><i class="fa type"></i> <span></span><i class="fa fa-times-circle remove"></i></td><td><input type="checkbox" name="CanShow" checked /></td><td><input type="checkbox" name="CanAssign" checked /></td><td><input type="checkbox" name="CanEdit" checked /></td><td><input type="checkbox" name="CanRemove" checked /></td></tr>');
$record.attr('data-subjectid', subject.Id);
$record.find('span').text(subject.Name + ' ' + subject.Id);
$record.find('i.type').addClass(subject.Type === 'role' ? 'fa-lock' : subject.IsGroup ? 'fa-users' : 'fa-user');
$record.find('input').val(subject.Id);
$tbody.append($record);
$input.val('');
$input.focus();
});
const $records = $tbody.find('tr');
for (var i = 0; i < $records.length; i++) {
const $record = $($records[i]);
const body = new FormData();
body.append('id', $record.attr('data-subjectid'));
const response = await fetch($add.attr('data-subjecturl'), {
body: body,
method: 'POST'
});
if (response.ok) {
const subject = await response.json();
if (subject) {
$record.find('span').text(subject.Name + ' ' + subject.Id);
$record.find('i.type').addClass(subject.Type === 'role' ? 'fa-lock' : subject.IsGroup ? 'fa-users' : 'fa-user');
continue;
}
}
$record.remove();
}
originalInherit = $inherit.prop('checked');
originalSubjects = $tbody.html();
$dialog.dialog('open');
} else {
$dialog.dialog('open');
}
});
});
</script>
}
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i> Flag actions are normally authorized globally by
@if (Authorization.Has(Claims.DiscoAdminAccount))
{
<span><a href="@Url.Action(MVC.Config.AuthorizationRole.Index(null))">Authorization Roles</a>.</span>
}
else
{
<span>Authorization Roles.</span>
}
Overriding individual flag permissions allows for targeted authorization.
</p>
</div>
</td>
</tr>
<tr class="Config_HideAdvanced_Item">
<th>
On Assignment<br />Expression:
</th>
<td>
@if (canConfig)
{
@Html.EditorFor(model => model.DeviceFlag.OnAssignmentExpression)
@AjaxHelpers.AjaxRemove()
@AjaxHelpers.AjaxSave()
@AjaxHelpers.AjaxLoader()
<script type="text/javascript">
$(function () {
var field = $('#DeviceFlag_OnAssignmentExpression');
var fieldRemove = field.next('.ajaxRemove');
var fieldOriginalWidth, fieldOriginalHeight;
document.DiscoFunctions.PropertyChangeHelper(
field,
'None',
'@Url.Action(MVC.API.DeviceFlag.UpdateOnAssignmentExpression(Model.DeviceFlag.Id))',
'OnAssignmentExpression'
);
field.focus(function () {
fieldOriginalWidth = field.width();
fieldOriginalHeight = field.height();
field.css('overflow', 'visible').animate({ width: field.parent().width() - 42, height: 75 }, 200);
}).blur(function () {
field.css('overflow', 'hidden').animate({ width: fieldOriginalWidth, height: fieldOriginalHeight }, 200);
}).change(function () {
if (!!field.val()) {
fieldRemove.show();
} else {
fieldRemove.hide();
}
}).attr('placeholder', 'None').attr('spellcheck', 'false');
fieldRemove.click(function () {
field.val('').change();
});
if (!!field.val()) {
fieldRemove.show();
} else {
fieldRemove.hide();
}
});
</script>
}
else
{
if (string.IsNullOrWhiteSpace(Model.DeviceFlag.OnAssignmentExpression))
{
<span class="smallMessage">&lt;None Specified&gt;</span>
}
else
{
<div class="code">
@Model.DeviceFlag.OnAssignmentExpression
</div>
}
}
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i>This expression will be evaluated whenever the flag is assigned to a device. The output of the expression will be shown with the flag assignment.
</p>
</div>
</td>
</tr>
<tr class="Config_HideAdvanced_Item">
<th>
On Unassignment<br />Expression:
</th>
<td>
@if (canConfig)
{
@Html.EditorFor(model => model.DeviceFlag.OnUnassignmentExpression)
@AjaxHelpers.AjaxRemove()
@AjaxHelpers.AjaxSave()
@AjaxHelpers.AjaxLoader()
<script type="text/javascript">
$(function () {
var field = $('#DeviceFlag_OnUnassignmentExpression');
var fieldRemove = field.next('.ajaxRemove');
var fieldOriginalWidth, fieldOriginalHeight;
document.DiscoFunctions.PropertyChangeHelper(
field,
'None',
'@Url.Action(MVC.API.DeviceFlag.UpdateOnUnassignmentExpression(Model.DeviceFlag.Id))',
'OnUnassignmentExpression'
);
field.focus(function () {
fieldOriginalWidth = field.width();
fieldOriginalHeight = field.height();
field.css('overflow', 'visible').animate({ width: field.parent().width() - 42, height: 75 }, 200);
}).blur(function () {
field.css('overflow', 'hidden').animate({ width: fieldOriginalWidth, height: fieldOriginalHeight }, 200);
}).change(function () {
if (!!field.val()) {
fieldRemove.show();
} else {
fieldRemove.hide();
}
}).attr('placeholder', 'None').attr('spellcheck', 'false');
fieldRemove.click(function () {
field.val('').change();
});
if (!!field.val()) {
fieldRemove.show();
} else {
fieldRemove.hide();
}
});
</script>
}
else
{
if (string.IsNullOrWhiteSpace(Model.DeviceFlag.OnUnassignmentExpression))
{
<span class="smallMessage">&lt;None Specified&gt;</span>
}
else
{
<div class="code">
@Model.DeviceFlag.OnUnassignmentExpression
</div>
}
}
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i>This expression will be evaluated whenever the flag is removed from a device. The output of the expression will be shown with the flag assignment.
</p>
</div>
</td>
</tr>
<tr class="Config_HideAdvanced_Item">
<th>
Linked Groups:
</th>
<td>
<div>
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
{
CanConfigure = canConfig,
CategoryDescription = DeviceFlagDevicesManagedGroup.GetCategoryDescription(Model.DeviceFlag),
Description = DeviceFlagDevicesManagedGroup.GetDescription(Model.DeviceFlag),
ManagedGroup = Model.DevicesLinkedGroup,
IncludeFilterBeginDate = true,
UpdateUrl = Url.Action(MVC.API.DeviceFlag.UpdateDevicesLinkedGroup(Model.DeviceFlag.Id, redirect: true))
})
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
{
CanConfigure = canConfig,
CategoryDescription = DeviceFlagDeviceAssignedUsersManagedGroup.GetCategoryDescription(Model.DeviceFlag),
Description = DeviceFlagDeviceAssignedUsersManagedGroup.GetDescription(Model.DeviceFlag),
ManagedGroup = Model.AssignedUserLinkedGroup,
IncludeFilterBeginDate = true,
UpdateUrl = Url.Action(MVC.API.DeviceFlag.UpdateAssignedUserLinkedGroup(Model.DeviceFlag.Id, redirect: true))
})
@if (canConfig)
{
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared)
}
</div>
</td>
</tr>
</table>
</div>
@if (canBulkAssignment || canDelete || canShowDevices || canExportCurrent || canExportAll)
{
<div class="actionBar">
@if (canExportCurrent)
{
@Html.ActionLinkButton("Export Current Assignments", MVC.Config.DeviceFlag.Export(null, Model.DeviceFlag.Id, true), "Config_DeviceFlags_Actions_ExportCurrent_Button")
}
@if (canExportAll)
{
@Html.ActionLinkButton("Export All Assignments", MVC.Config.DeviceFlag.Export(null, Model.DeviceFlag.Id, false), "Config_DeviceFlags_Actions_ExportAll_Button")
}
@if (canBulkAssignment)
{
<a href="#" id="Config_DeviceFlags_BulkAssign_Button" class="button">Bulk Assign Devices</a>
<div id="Config_DeviceFlags_BulkAssign_ModeDialog" class="dialog" title="Bulk Assign Device Mode">
<p>
Select the mode used to assign devices:
</p>
<div>
<div class="add">
<h5><i class="fa fa-plus fa-fw"></i>Add</h5>
<p>
Specified devices will have this flag <strong>added</strong>. Devices who already have this flag will be skipped.
</p>
</div>
<div class="override">
<h5><i class="fa fa-repeat fa-fw"></i>Override</h5>
<p>
Specified devices will have this flag <strong>added</strong>. Specified devices which already have this flag will be skipped.
Devices who already have this flag but are not specified will have the flag <strong>removed</strong>.
</p>
</div>
</div>
</div>
<div id="Config_DeviceFlags_BulkAssign_AssignDialog" class="dialog" title="Bulk Assign Devices" data-assignedurl="@Url.Action(MVC.API.DeviceFlag.AssignedDevices(Model.DeviceFlag.Id))">
<div class="brief">
<div>
Enter multiple <strong>Device Serial Numbers</strong> separated by <code>&lt;new line&gt;</code>, commas (<code>,</code>) or semicolons (<code>;</code>).
</div>
</div>
<div class="loading">
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Loading current assignments...</h4>
</div>
<form action="#" method="post" data-overrideaction="@(Url.Action(MVC.API.DeviceFlag.BulkAssignDevices(Model.DeviceFlag.Id, true)))" data-addaction="@(Url.Action(MVC.API.DeviceFlag.BulkAssignDevices(Model.DeviceFlag.Id, false)))">
@Html.AntiForgeryToken()
<textarea id="Config_DeviceFlags_BulkAssign_AssignDialog_DeviceSerialNumbers" name="DeviceSerialNumbers"></textarea>
<h4>Comments:</h4>
<textarea id="Config_DeviceFlags_BulkAssign_AssignDialog_Comments" name="Comments"></textarea>
</form>
</div>
<script>
$(function () {
var modeDialog, assignDialog, assignDeviceSerialNumbers;
function showModeDialog() {
if (!modeDialog) {
modeDialog = $('#Config_DeviceFlags_BulkAssign_ModeDialog').dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 400,
buttons: {
Cancel: function () {
$(this).dialog('close');
}
}
});
modeDialog.find('.add').click(function () {
modeDialog.dialog('close');
showAssignDialog('Add');
});
modeDialog.find('.override').click(function () {
modeDialog.dialog('close');
showAssignDialog('Override');
});
}
modeDialog.dialog('open');
}
function showAssignDialog(mode) {
if (!assignDialog) {
assignDialog = $('#Config_DeviceFlags_BulkAssign_AssignDialog').dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 460
});
assignDeviceSerialNumbers = $('#Config_DeviceFlags_BulkAssign_AssignDialog_DeviceSerialNumbers');
}
assignDialog.removeClass('loading');
var buttons = {};
buttons[mode + " Device Flags"] = function () {
$(this).find('form').submit();
$(this).dialog("disable");
}
buttons['Cancel'] = function () {
$(this).dialog('close');
}
assignDialog.dialog('option', 'buttons', buttons);
assignDialog.dialog('option', 'title', 'Bulk Assign Devices: ' + mode);
const $form = assignDeviceSerialNumbers.closest('form');
if (mode == "Override") {
$form.attr('action', $form.attr('data-overrideaction'));
assignDialog.addClass('loading');
const body = new FormData();
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
fetch(assignDialog.attr('data-assignedurl'), {
method: 'POST',
body: body
}).then(r => {
assignDialog.removeClass('loading');
if (!r.ok) {
alert('Unable to load current assignments:\n' + r.statusText);
assignDialog.dialog('close');
} else {
r.json().then(j => {
if (!j) {
assignDeviceSerialNumbers.val('');
} else {
assignDeviceSerialNumbers.val(j.join('\n'));
}
})
}
});
}
else // Assume Add
{
$form.attr('action', $form.attr('data-addaction'));
}
assignDialog.dialog('open');
}
$('#Config_DeviceFlags_BulkAssign_Button').click(function () {
showModeDialog();
return false;
});
});
</script>
}
@if (canDelete)
{
<button id="Config_DeviceFlags_Actions_Delete_Button" type="button" class="button">Delete</button>
<div id="Config_DeviceFlags_Actions_Delete_Dialog" class="dialog" title="Delete this Device Flag?">
@using (Html.BeginForm(MVC.API.DeviceFlag.Delete(Model.DeviceFlag.Id, true)))
{
@Html.AntiForgeryToken()
}
<p>
<i class="fa fa-exclamation-triangle fa-lg warning"></i>
This item will be permanently deleted and cannot be recovered.<br />
<br />
@if (Model.CurrentAssignmentCount > 0)
{
<strong>@Model.CurrentAssignmentCount device@(Model.CurrentAssignmentCount != 1 ? "s are" : " is") currently assigned</strong>
<br />
<br />
}
Are you sure?
</p>
</div>
<script type="text/javascript">
$(function () {
let buttonDialog = null;
$('#Config_DeviceFlags_Actions_Delete_Button').on('click', function () {
const $button = $(this);
if (!buttonDialog) {
buttonDialog = $('#Config_DeviceFlags_Actions_Delete_Dialog').dialog({
resizable: false,
modal: true,
autoOpen: false,
buttons: {
"Delete": function () {
$(this)
.dialog("option", "buttons", null)
.find('form').trigger('submit');
},
Cancel: function () {
$(this).dialog("close");
}
}
});
}
buttonDialog.dialog('open');
});
});
</script>
}
@if (canShowDevices)
{
@Html.ActionLinkButton(string.Format("Show {0} device{1}", Model.CurrentAssignmentCount, (Model.CurrentAssignmentCount == 1 ? null : "s")), MVC.Search.Query(Model.DeviceFlag.Id.ToString(), "DeviceFlag"), "Config_DeviceFlags_Actions_ShowDevices_Button")
}
</div>
}