Files
Disco/Disco.Web/Areas/Config/Views/DeviceModel/_DeviceComponentsTable.cshtml
T
2025-07-31 16:18:32 +10:00

318 lines
14 KiB
Plaintext

@model Disco.Web.Areas.Config.Models.DeviceModel.ComponentsModel
@{
Authorization.Require(Claims.Config.DeviceModel.Show);
var canConfig = Authorization.Has(Claims.Config.DeviceModel.ConfigureComponents);
Html.BundleDeferred("~/ClientScripts/Modules/Disco-jQueryExtensions");
}
@if (canConfig)
{
<table id="deviceComponents" data-devicemodelid="@(Model.DeviceModelId.HasValue ? Model.DeviceModelId.Value.ToString() : string.Empty)" data-addurl="@Url.Action(MVC.API.DeviceModel.ComponentAdd(null, null, null))" data-updateurl="@Url.Action(MVC.API.DeviceModel.ComponentUpdate())" data-removeurl="@Url.Action(MVC.API.DeviceModel.ComponentRemove())" data-geturl="@Url.Action(MVC.API.DeviceModel.Component())" data-updatejobsubtypesurl="@Url.Action(MVC.API.DeviceModel.ComponentUpdateJobSubTypes())">
<tr>
<th>
Description
</th>
<th>
Cost
</th>
<th>
Job Types
</th>
<th class="actions">
&nbsp;
</th>
</tr>
@foreach (var item in Model.DeviceComponents)
{
<tr data-devicecomponentid="@item.Id">
<td>
<input type="text" class="description" value="@item.Description" />
</td>
<td>
<input type="text" class="cost" value="@item.Cost.ToString("C")" />
</td>
<td>
<span class="fa-stack edit">
<i class="fa fa-list-alt fa-stack-2x"></i>
<i class="fa fa-asterisk fa-stack-1x@(item.JobSubTypes.Count == 0 ? " hidden" : string.Empty)"></i>
</span>
</td>
<td>
<i class="fa fa-times-circle remove"></i>
</td>
</tr>
}
<tr>
<td colspan="4">
<a href="#" id="addDeviceComponent">Add Component</a>
</td>
</tr>
</table>
<script type="text/javascript">
$(function () {
const $deviceComponents = $('#deviceComponents');
$('#addDeviceComponent').click(function () {
const dc = $('<tr><td><input type="text" class="description" /></td><td><input type="text" class="cost" /></td><td><span class="fa-stack edit"><i class="fa fa-list-alt fa-stack-2x"></i><i class="fa fa-asterisk fa-stack-1x hidden"></i></span></td><td><i class="fa fa-times-circle remove"></i></td></tr>');
dc.insertBefore($deviceComponents.find('tr').last());
dc.find('input.description').focus();
return false;
});
$deviceComponents.on('change', 'input', function () { updateComponent(this); });
$deviceComponents.on('focus', 'input', function () { $(this).select(); });
$deviceComponents.on('click', '.remove', removeComponent);
$deviceComponents.on('click', '.edit', function () { editComponentJobTypes(this); });
async function removeComponentConfirmed(id, row) {
const body = new FormData();
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
body.append('id', id);
try {
const response = await fetch($deviceComponents.attr('data-removeurl'), {
method: 'POST',
body: body
});
if (response.ok) {
row.remove();
} else {
alert('Unable to remove component: ' + response.statusText);
}
} catch (e) {
alert('Unable to remove component: ' + e);
}
}
function removeComponent() {
const componentRow = $(this).closest('tr');
const id = componentRow.attr('data-devicecomponentid');
if (id) {
const dialog = $("#dialogConfirmRemove");
const buttons = dialog.dialog("option", "buttons");
buttons['Remove'] = function () { removeComponentConfirmed(id, componentRow); $(this).dialog("close"); };
dialog.dialog("option", "buttons", buttons);
dialog.dialog('open');
} else {
// New - Remove
componentRow.remove();
}
}
async function updateComponent(input) {
const componentRow = $(input).closest('tr');
componentRow.find('input').attr('disabled', true).addClass('updating');
const id = componentRow.attr('data-devicecomponentid');
if (id) {
// Update
const body = new FormData();
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
body.append('id', id);
body.append('description', componentRow.find('input.description').val());
body.append('cost', componentRow.find('input.cost').val());
try {
const response = await fetch($deviceComponents.attr('data-updateurl'), {
method: 'POST',
body: body
});
if (response.ok) {
const result = await response.json();
componentRow.find('input').attr('disabled', false).removeClass('updating');
componentRow.find('input.description').val(result.Description);
componentRow.find('input.cost').val(result.Cost);
} else {
alert('Unable to update component: ' + response.statusText);
}
} catch (e) {
alert('Unable to update component: ' + e);
}
} else {
// Add
const modelId = componentRow.closest('table').attr('data-devicemodelid');
const body = new FormData();
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
body.append('id', modelId);
body.append('description', componentRow.find('input.description').val());
body.append('cost', componentRow.find('input.cost').val());
try {
const response = await fetch($deviceComponents.attr('data-addurl'), {
method: 'POST',
body: body
});
if (response.ok) {
const result = await response.json();
componentRow.find('input').attr('disabled', false).removeClass('updating');
componentRow.attr('data-devicecomponentid', result.Id);
componentRow.find('input.description').val(result.Description);
componentRow.find('input.cost').val(result.Cost);
} else {
alert('Unable to add component: ' + response.statusText);
}
} catch (e) {
alert('Unable to add component: ' + e);
}
}
}
async function editComponentJobTypes(input) {
const edit$this = $(input);
const componentRow = edit$this.closest('tr');
const id = componentRow.attr('data-devicecomponentid');
if (id) {
try {
const body = new FormData();
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
body.append('id', id);
const getResponse = await fetch($deviceComponents.attr('data-geturl'), {
method: 'POST',
body: body
})
componentRow.find('input').attr('disabled', false).removeClass('updating');
if (getResponse.ok) {
const component = await getResponse.json();
$dialogUpdateJobTypes = $('#dialogUpdateJobTypes');
$dialogUpdateJobTypes.find('input:checked').each(function () { $(this).prop('checked', false) });
for (var i = 0; i < component.JobSubTypes.length; i++) {
var sjt = component.JobSubTypes[i];
$dialogUpdateJobTypes.find('#SubTypes_' + sjt).prop('checked', true);
}
$('#CheckboxBulkSelect_dialogUpdateJobTypes').checkboxBulkSelect('update');
const buttons = $dialogUpdateJobTypes.dialog("option", "buttons");
buttons['Save'] = function () {
async function saveAsync() {
const body = new FormData();
let jobSubTypeCount = 0;
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
body.append('id', id);
$dialogUpdateJobTypes.find('input:checked').each(function () { body.append('jobSubTypes', $(this).val()); jobSubTypeCount++; });
try {
const updateResponse = await fetch($deviceComponents.attr('data-updatejobsubtypesurl'), {
method: 'POST',
body: body
})
if (updateResponse.ok) {
if (jobSubTypeCount > 0) {
edit$this.find('.fa-asterisk').removeClass('hidden');
} else {
edit$this.find('.fa-asterisk').addClass('hidden');
}
$dialogUpdateJobTypes.dialog("close");
} else {
alert('Unable to update component sub types: ' + updateResponse.statusText);
}
} catch (e) {
alert('Unable to update component sub types: ' + e);
}
}
saveAsync();
};
$dialogUpdateJobTypes.dialog("option", "buttons", buttons);
$dialogUpdateJobTypes.dialog('open');
} else {
alert('Unable to load component: ' + getResponse.statusText);
}
} catch (e) {
alert('Unable to load component: ' + e);
}
}
}
$("#dialogConfirmRemove").dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false,
buttons: {
"Remove": function () {
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
$('#dialogUpdateJobTypes').dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 550,
buttons: {
"Save": function () {
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
$('#CheckboxBulkSelect_dialogUpdateJobTypes').checkboxBulkSelect({ parentSelector: 'div' });
});
</script>
<div id="dialogUpdateJobTypes" title="Update Job Types">
<div>
<h2>Hardware Non-Warranty Job Types</h2>
@CommonHelpers.CheckBoxList("SubTypes", Model.JobSubTypes.ToSelectListItems(), 2)
<br />
<span id="CheckboxBulkSelect_dialogUpdateJobTypes" class="checkboxBulkSelectContainer"></span>
</div>
</div>
<div id="dialogConfirmRemove" title="Delete this Component?">
<p>
<i class="fa fa-exclamation-triangle fa-lg warning"></i>
This item will be permanently deleted and cannot be recovered. Are you sure?
</p>
</div>
}
else
{
<table id="deviceComponents" data-devicemodelid="@(Model.DeviceModelId.HasValue ? Model.DeviceModelId.Value.ToString() : string.Empty)">
<tr>
<th>
Description
</th>
<th>
Cost
</th>
<th>
Job Types
</th>
</tr>
@foreach (var item in Model.DeviceComponents)
{
<tr data-devicecomponentid="@item.Id">
<td>
@item.Description
</td>
<td>
@item.Cost.ToString("C")
</td>
<td>
@if (item.JobSubTypes.Count > 0)
{
<ul>
@foreach (var jst in item.JobSubTypes)
{
<li>@jst.Description</li>
}
</ul>
}
else
{
<span class="smallMessage">&lt;None Specified&gt;</span>
}
</td>
</tr>
}
</table>
}