Added presets

This commit is contained in:
2025-11-15 14:50:20 +01:00
parent c8cb61f766
commit fb272ee63c
6 changed files with 151 additions and 3 deletions

View File

@@ -36,6 +36,14 @@ public class SettingsController : Controller
return View(adminSettingsModel);
}
[Authorize]
[HttpGet("Presets")]
public async Task<Dictionary<string, Preset>> PresetsAsync()
{
AdminSettingsModel adminSettingsModel = await _ldap.GetAdminSettingsModelAsync();
return adminSettingsModel.Presets;
}
[Authorize(Roles = "CanManageSettings")]
[HttpPut("Admin")]
public async Task<AdminUpdateResponseModel> UpdateAdminAsync([FromBody]AdminUpdateRequestModel adminSettingsRequestModel)

View File

@@ -43,7 +43,13 @@
<data name="Error loading locations" xml:space="preserve">
<value>Fehler beim Laden der Orte</value>
</data>
<data name="Error loading presets" xml:space="preserve">
<value>Fehler beim Laden der Vorlagen</value>
</data>
<data name="Select user" xml:space="preserve">
<value>Benutzer auswählen</value>
</data>
<data name="Select preset" xml:space="preserve">
<value>Vorlage auswählen</value>
</data>
</root>

View File

@@ -192,6 +192,18 @@
<hr class="my-3" />
<h4 class="fw-bold">@T["Preset"]</h4>
<div class="col-md-8">
<select class="form-select" name="Preset" aria-label="@T["Preset"]" id="createPresetSelect">
<option value="">@T["Select preset"]</option>
</select>
</div>
<div class="col-md-4">
<button type="button" id="createPresetApply" class="btn btn-sm btn-warning">@T["Apply preset"]</button>
</div>
<hr class="my-3" />
<!-- Description Section -->
<h4 class="fw-bold">@T["Description"]</h4>
<div class="col-md-6">
@@ -254,7 +266,7 @@
</div>
<script>
<script defer>
document.addEventListener('DOMContentLoaded', () => {
// Open modal if URL contains parameter: CreateModal=true
const urlParams = new URLSearchParams(window.location.search);
@@ -803,11 +815,77 @@ document.addEventListener('DOMContentLoaded', () => {
createModal.addEventListener('show.bs.modal', async () => {
const selectLocations = createModal.querySelector('#createLocationSelect');
await loadLocationsIntoSelect(selectLocations);
const selectPresets = createModal.querySelector('#createPresetSelect');
await loadPresetsIntoSelect(selectPresets);
const selectUsers = createModal.querySelector('#createUsersSelect');
await loadUsersIntoSelect(selectUsers);
});
});
document.addEventListener('DOMContentLoaded', () => {
const presetApplyButton = document.getElementById('createPresetApply');
presetApplyButton.addEventListener('click', async () => {
const response = await fetch('/Settings/Presets');
const responseJson = await response.json();
const presetSelect = document.getElementById('createPresetSelect');
const presetSelectValue = presetSelect.value;
if (responseJson[presetSelectValue]) {
const attributesContainer = document.getElementById('attributesContainer');
var attributes = responseJson[presetSelectValue].attribute;
for (var attributeKey in attributes) {
var attributeValue = attributes[attributeKey];
if (attributeKey == "Type" || attributeKey == "@T["Type"]") {
document.getElementById("createType").setAttribute("value", attributeValue);
} else if (attributeKey == "Make" || attributeKey == "@T["Make"]") {
document.getElementById("createMake").setAttribute("value", attributeValue);
} else if (attributeKey == "Model" || attributeKey == "@T["Model"]") {
document.getElementById("createModel").setAttribute("value", attributeValue);
} else if (attributeKey == "Purchase Date" || attributeKey == "@T["Purchase Date"]") {
document.getElementById("createPurchaseDate").setAttribute("value", attributeValue);
} else if (attributeKey == "Purchase Value" || attributeKey == "@T["Purchase Value"]") {
document.getElementById("createPurchaseValue").setAttribute("value", attributeValue);
} else if (attributeKey == "Purchased At" || attributeKey == "@T["Purchased At"]") {
document.getElementById("createPurchaseAt").setAttribute("value", attributeValue);
} else if (attributeKey == "Purchased By" || attributeKey == "@T["Purchased By"]") {
document.getElementById("createPurchaseBy").setAttribute("value", attributeValue);
} else if (attributeKey == "Location" || attributeKey == "@T["Location"]") {
document.getElementById("createLocationSelect-ts-control").value = attributeValue;
document.getElementById("createLocationSelect").value = attributeValue;
} else if (attributeKey == "User" || attributeKey == "@T["User"]") {
document.getElementById("createUsersSelect-ts-control").value = attributeValue;
document.getElementById("createUsersSelect").value = attributeValue;
} else if (attributeKey == "Name" || attributeKey == "@T["Name"]") {
document.getElementById("createName").value = attributeValue;
} else if (attributeKey == "Serial Number" || attributeKey == "@T["Serial Number"]") {
document.getElementById("createSerialNumber").value = attributeValue;
} else {
var nameInputs = attributesContainer.querySelectorAll("input[data-attr-name]");
var anyEquals = false;
var anyEqualsElement = null;
nameInputs.forEach(element => {
if (element.value == attributeKey) {
anyEquals = true;
anyEqualsElement = element.nextElementSibling;
return;
}
});
if (anyEquals) {
anyEqualsElement.value = attributeValue;
} else {
const row = document.createElement('div');
row.className = 'd-flex gap-2 align-items-center attribute-row';
row.innerHTML = `
<input type="text" class="form-control" placeholder="@T["Attribute name"]" data-attr-name value="${attributeKey}" />
<input type="text" class="form-control" placeholder="@T["Attribute value"]" data-attr-value value="${attributeValue}" />
<button type="button" class="btn btn-danger btn-sm btn-remove-attribute">@T["Remove"]</button>
`;
attributesContainer.appendChild(row);
}
}
}
}
});
});
</script>
<!-- TomSelect dropdowns -->
<script>
@@ -859,6 +937,28 @@ document.addEventListener('DOMContentLoaded', () => {
initUsersSelect(createUsersSelect);
initUsersSelect(updateUsersSelect);
const createPresetsSelect = document.getElementById('createPresetsSelect');
async function initPresetsSelect(selectElement) {
if (!selectElement) return;
await loadPresetsIntoSelect(selectElement);
new TomSelect(selectElement, {
plugins: ['clear_button'],
create: false,
sortField: { field: 'text', direction: 'asc' },
placeholder: '@T["Select user"]',
maxOptions: 500, // avoid performance hit if there are many
render: {
no_results: function(data, escape) {
return `<div class="no-results">@T["No presets found"]</div>`;
}
}
});
}
initPresetsSelect(createPresetsSelect);
});
</script>

View File

@@ -101,7 +101,7 @@
<button type="submit" class="btn btn-warning float-end mt-3">@T["Apply settings and update presets"]</button>
</form>
<script>
<script defer>
document.addEventListener('DOMContentLoaded', () => {
const updateForm = document.getElementById('updateSettings');
updateForm.addEventListener('submit', async e => {

View File

@@ -25,7 +25,9 @@
selectLocation: '@T["Select location"]',
errorLoadingLocations: '@T["Error loading locations"]',
selectUser: '@T["Select user"]',
errorLoadingUsers: '@T["Error loading users"]'
selectPreset: '@T["Select preset"]',
errorLoadingUsers: '@T["Error loading users"]',
errorLoadingPresets: '@T["Error loading presets"]'
};
</script>
</head>

View File

@@ -270,3 +270,35 @@ function unflatten(obj) {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function loadPresetsIntoSelect(selectElement, selectedValue = null) {
try {
const response = await fetch('/Settings/Presets');
const responseJson = await response.json();
var presets = [];
for (var key in responseJson) {
presets.push(key);
}
console.log(presets);
const ts = selectElement.tomselect;
if (!ts) {
selectElement.innerHTML = `<option value="">${appTranslations.selectPreset}</option>`;
presets.forEach(u => {
const opt = document.createElement('option');
opt.value = u;
opt.textContent = u;
selectElement.appendChild(opt);
});
return;
}
ts.clearOptions();
ts.addOption(presets.map(u => ({ value: u, text: u })));
ts.refreshOptions(false);
if (selectedValue) ts.setValue(selectedValue);
} catch (err) {
console.error('Error loading presets:', err);
showToast(appTranslations.errorLoadingPresets, 'danger');
}
}