mirror of
https://github.com/itflow-org/itflow
synced 2026-08-08 16:47:16 +00:00
Feature: Add Dynamic Task editing in add ticket and add recurring ticket, recurring tickets now have their own task table as well
This commit is contained in:
148
agent/js/ticket_tasks_modal.js
Normal file
148
agent/js/ticket_tasks_modal.js
Normal file
@@ -0,0 +1,148 @@
|
||||
// Editable task rows for the ticket and recurring ticket add/edit modals, and the
|
||||
// ticket template picker that pre-fills them.
|
||||
//
|
||||
// Rows submit as parallel tasks[] and task_estimates[] arrays, aligned by their
|
||||
// order in the form, so removing a row removes both of its inputs together.
|
||||
//
|
||||
// Wrapped in an IIFE because a modal can be opened, closed and opened again in one
|
||||
// page load, which re-runs this file - top-level const/let would throw on the
|
||||
// second run. Delegated handlers are namespaced and unbound first for the same
|
||||
// reason, otherwise "Add Task" would add one row per time the modal was opened.
|
||||
|
||||
(function () {
|
||||
|
||||
// Builds one task row. Values are assigned as properties rather than built into
|
||||
// markup, so a task name containing quotes or angle brackets needs no escaping.
|
||||
function buildTaskRow(taskName, taskEstimate) {
|
||||
|
||||
const row = document.createElement("div");
|
||||
row.className = "form-row mb-2 ticket-task-row";
|
||||
|
||||
const nameColumn = document.createElement("div");
|
||||
nameColumn.className = "col-7";
|
||||
|
||||
const nameInput = document.createElement("input");
|
||||
nameInput.type = "text";
|
||||
nameInput.className = "form-control";
|
||||
nameInput.name = "tasks[]";
|
||||
nameInput.placeholder = "Task name";
|
||||
nameInput.maxLength = 255;
|
||||
nameInput.value = taskName || '';
|
||||
nameColumn.appendChild(nameInput);
|
||||
|
||||
const estimateColumn = document.createElement("div");
|
||||
estimateColumn.className = "col-3";
|
||||
|
||||
const estimateInput = document.createElement("input");
|
||||
estimateInput.type = "number";
|
||||
estimateInput.className = "form-control";
|
||||
estimateInput.name = "task_estimates[]";
|
||||
estimateInput.placeholder = "Mins";
|
||||
estimateInput.min = 0;
|
||||
estimateInput.value = taskEstimate || '';
|
||||
estimateColumn.appendChild(estimateInput);
|
||||
|
||||
const removeColumn = document.createElement("div");
|
||||
removeColumn.className = "col-2";
|
||||
|
||||
const removeButton = document.createElement("button");
|
||||
removeButton.type = "button";
|
||||
removeButton.className = "btn btn-secondary btn-block ticket-task-remove";
|
||||
removeButton.title = "Remove task";
|
||||
removeButton.innerHTML = '<i class="fa fa-fw fa-trash"></i>';
|
||||
removeColumn.appendChild(removeButton);
|
||||
|
||||
row.appendChild(nameColumn);
|
||||
row.appendChild(estimateColumn);
|
||||
row.appendChild(removeColumn);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
function addTaskRow(taskName, taskEstimate) {
|
||||
|
||||
const container = document.getElementById("ticketTasksContainer");
|
||||
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.appendChild(buildTaskRow(taskName, taskEstimate));
|
||||
}
|
||||
|
||||
// Replaces the whole list - used when a template is picked
|
||||
function setTaskRows(tasks) {
|
||||
|
||||
const container = document.getElementById("ticketTasksContainer");
|
||||
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '';
|
||||
|
||||
(tasks || []).forEach(task => {
|
||||
addTaskRow(task.name, task.estimate);
|
||||
});
|
||||
}
|
||||
|
||||
// jQuery parses a data-tasks attribute holding JSON into an array on its own,
|
||||
// but hand it a string and it stays a string - so handle both
|
||||
function readTemplateTasks($option) {
|
||||
|
||||
const tasks = $option.data('tasks');
|
||||
|
||||
if (!tasks) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (typeof tasks === 'string') {
|
||||
try {
|
||||
return JSON.parse(tasks);
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
$(document).off('click.ticketTasks').on('click.ticketTasks', '#ticketTaskAdd', function () {
|
||||
addTaskRow('', '');
|
||||
});
|
||||
|
||||
$(document).off('click.ticketTaskRemove').on('click.ticketTaskRemove', '.ticket-task-remove', function () {
|
||||
$(this).closest('.ticket-task-row').remove();
|
||||
});
|
||||
|
||||
// Ticket template picker - fills in the subject, details and task rows
|
||||
$(document).off('change.ticketTemplate').on('change.ticketTemplate', '#ticket_template_select', function () {
|
||||
|
||||
const $option = $(this).find(':selected');
|
||||
|
||||
// Selecting "- No Template -" only unlinks the template - it must not wipe
|
||||
// whatever the user has already written or added
|
||||
if (!parseInt($option.val(), 10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const templateSubject = $option.data('subject') || '';
|
||||
const templateDetails = $option.data('details') || '';
|
||||
|
||||
$('#subjectInput').val(templateSubject);
|
||||
|
||||
if (window.tinymce) {
|
||||
const editor = tinymce.get('detailsInput');
|
||||
if (editor) {
|
||||
editor.setContent(templateDetails);
|
||||
} else {
|
||||
$('#detailsInput').val(templateDetails);
|
||||
}
|
||||
} else {
|
||||
$('#detailsInput').val(templateDetails);
|
||||
}
|
||||
|
||||
setTaskRows(readTemplateTasks($option));
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -1,4 +1,4 @@
|
||||
// Used to populate dynamic content in recurring_ticket_add_modal and ticket_add_modal_v2 based on selected client
|
||||
// Used to populate dynamic content in the ticket and recurring ticket add modals based on selected client
|
||||
|
||||
// Not every modal that loads this script has every dropdown, and a modal opened
|
||||
// from a contact page has no client selector at all - the client arrives as a
|
||||
@@ -8,362 +8,370 @@
|
||||
// Client selected listener
|
||||
// We seem to have to use jQuery to listen for events, as the client input is a select2 component?
|
||||
|
||||
const clientSelectDropdown = document.getElementById("changeClientSelect"); // Define client selector
|
||||
// Wrapped in an IIFE because a modal can be opened, closed and opened again in one
|
||||
// page load, which re-runs this file - a top-level const would throw on the second
|
||||
// run and take the whole script with it.
|
||||
|
||||
if (clientSelectDropdown) {
|
||||
(function () {
|
||||
|
||||
// If the client selector is disabled, we must be on a client-specific page instead. Trigger the lists to update.
|
||||
if (clientSelectDropdown.disabled) {
|
||||
const clientSelectDropdown = document.getElementById("changeClientSelect"); // Define client selector
|
||||
|
||||
let client_id = $(clientSelectDropdown).find(':selected').val();
|
||||
if (clientSelectDropdown) {
|
||||
|
||||
// If the client selector is disabled, we must be on a client-specific page instead. Trigger the lists to update.
|
||||
if (clientSelectDropdown.disabled) {
|
||||
|
||||
let client_id = $(clientSelectDropdown).find(':selected').val();
|
||||
|
||||
populateLists(client_id);
|
||||
}
|
||||
|
||||
// Listener for client selection. Populate select lists when a client is selected
|
||||
$(clientSelectDropdown).on('select2:select', function (e) {
|
||||
let client_id = $(this).find(':selected').val();
|
||||
|
||||
// Update the dependent dropdown lists
|
||||
populateLists(client_id);
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
// No client selector - the modal was opened from a contact page, where the
|
||||
// client is fixed and arrives as a hidden field instead
|
||||
const clientIdHiddenField = document.getElementById("clientIdHidden");
|
||||
|
||||
if (clientIdHiddenField && clientIdHiddenField.value) {
|
||||
populateLists(clientIdHiddenField.value);
|
||||
}
|
||||
|
||||
populateLists(client_id);
|
||||
}
|
||||
|
||||
// Listener for client selection. Populate select lists when a client is selected
|
||||
$(clientSelectDropdown).on('select2:select', function (e) {
|
||||
let client_id = $(this).find(':selected').val();
|
||||
// Populates dropdowns with dynamic content based on the client ID
|
||||
// Called when the client select dropdown is used or if the client select is disabled
|
||||
function populateLists(client_id) {
|
||||
|
||||
// Update the dependent dropdown lists
|
||||
populateLists(client_id);
|
||||
populateContactsDropdown(client_id);
|
||||
|
||||
});
|
||||
populateAssetsDropdowns(client_id);
|
||||
|
||||
} else {
|
||||
populateLocationsDropdown(client_id);
|
||||
|
||||
// No client selector - the modal was opened from a contact page, where the
|
||||
// client is fixed and arrives as a hidden field instead
|
||||
const clientIdHiddenField = document.getElementById("clientIdHidden");
|
||||
populateVendorsDropdown(client_id);
|
||||
|
||||
if (clientIdHiddenField && clientIdHiddenField.value) {
|
||||
populateLists(clientIdHiddenField.value);
|
||||
populateProjectsDropdown(client_id);
|
||||
}
|
||||
|
||||
}
|
||||
// Empties a dropdown and adds its placeholder, returning the element - or null if
|
||||
// this modal doesn't have it. Pass null as the label for a multi-select, which has
|
||||
// no placeholder option of its own.
|
||||
function resetDropdown(id, placeholderLabel, placeholderValue) {
|
||||
|
||||
// Populates dropdowns with dynamic content based on the client ID
|
||||
// Called when the client select dropdown is used or if the client select is disabled
|
||||
function populateLists(client_id) {
|
||||
const dropdown = document.getElementById(id);
|
||||
|
||||
populateContactsDropdown(client_id);
|
||||
if (!dropdown) {
|
||||
return null;
|
||||
}
|
||||
|
||||
populateAssetsDropdowns(client_id);
|
||||
// innerHTML rather than removing options one by one, which leaves empty optgroups behind
|
||||
dropdown.innerHTML = '';
|
||||
|
||||
populateLocationsDropdown(client_id);
|
||||
// A multi-select keeps showing its old selections until select2 is told the value changed
|
||||
$(dropdown).val(null).trigger('change.select2');
|
||||
|
||||
populateVendorsDropdown(client_id);
|
||||
if (placeholderLabel !== null) {
|
||||
dropdown[dropdown.length] = new Option(placeholderLabel, placeholderValue);
|
||||
}
|
||||
|
||||
populateProjectsDropdown(client_id);
|
||||
}
|
||||
|
||||
// Empties a dropdown and adds its placeholder, returning the element - or null if
|
||||
// this modal doesn't have it. Pass null as the label for a multi-select, which has
|
||||
// no placeholder option of its own.
|
||||
function resetDropdown(id, placeholderLabel, placeholderValue) {
|
||||
|
||||
const dropdown = document.getElementById(id);
|
||||
|
||||
if (!dropdown) {
|
||||
return null;
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
// innerHTML rather than removing options one by one, which leaves empty optgroups behind
|
||||
dropdown.innerHTML = '';
|
||||
|
||||
// A multi-select keeps showing its old selections until select2 is told the value changed
|
||||
$(dropdown).val(null).trigger('change.select2');
|
||||
|
||||
if (placeholderLabel !== null) {
|
||||
dropdown[dropdown.length] = new Option(placeholderLabel, placeholderValue);
|
||||
}
|
||||
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
// Redraws a select2 component after its options have been replaced
|
||||
function refreshDropdown(dropdown) {
|
||||
if (dropdown) {
|
||||
$(dropdown).trigger('change.select2');
|
||||
}
|
||||
}
|
||||
|
||||
// Re-applies the value the modal was opened with (e.g. ticket_add.php?project_id=4),
|
||||
// which can only be selected once the options it refers to exist
|
||||
function applyPreselection(dropdown) {
|
||||
|
||||
if (!hasPreselection(dropdown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dropdown.value = dropdown.dataset.selected;
|
||||
}
|
||||
|
||||
// True when the modal was opened with a specific value for this dropdown.
|
||||
// '0' is the "none selected" value every one of these dropdowns uses, and is
|
||||
// truthy as a string - so it has to be excluded explicitly.
|
||||
function hasPreselection(dropdown) {
|
||||
return Boolean(dropdown && dropdown.dataset.selected && dropdown.dataset.selected !== '0');
|
||||
}
|
||||
|
||||
// Adds an optgroup to a dropdown and returns it, so options can be appended into it
|
||||
function appendOptionGroup(dropdown, label) {
|
||||
|
||||
if (!dropdown) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const group = document.createElement("optgroup");
|
||||
group.label = label;
|
||||
dropdown.appendChild(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
// Adds an option to an optgroup
|
||||
function appendGroupedOption(group, label, value) {
|
||||
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
group.appendChild(new Option(label, value));
|
||||
}
|
||||
|
||||
// Builds the asset label as "Name - Make Model - (Contact)", matching how assets read elsewhere
|
||||
function buildAssetLabel(asset) {
|
||||
|
||||
let label = asset.asset_name;
|
||||
|
||||
if (asset.asset_make) {
|
||||
label = label + " - " + asset.asset_make;
|
||||
|
||||
if (asset.asset_model) {
|
||||
label = label + " " + asset.asset_model;
|
||||
// Redraws a select2 component after its options have been replaced
|
||||
function refreshDropdown(dropdown) {
|
||||
if (dropdown) {
|
||||
$(dropdown).trigger('change.select2');
|
||||
}
|
||||
}
|
||||
|
||||
if (asset.contact_name) {
|
||||
label = label + " - (" + asset.contact_name + ")";
|
||||
// Re-applies the value the modal was opened with (e.g. ticket_add.php?project_id=4),
|
||||
// which can only be selected once the options it refers to exist
|
||||
function applyPreselection(dropdown) {
|
||||
|
||||
if (!hasPreselection(dropdown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dropdown.value = dropdown.dataset.selected;
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
// Populate client contacts - one request feeds both the contact picker and the
|
||||
// watchers list, as both are built from the same set of people
|
||||
function populateContactsDropdown(client_id) {
|
||||
|
||||
if (!document.getElementById("contactSelect") && !document.getElementById("watchersSelect")) {
|
||||
return;
|
||||
// True when the modal was opened with a specific value for this dropdown.
|
||||
// '0' is the "none selected" value every one of these dropdowns uses, and is
|
||||
// truthy as a string - so it has to be excluded explicitly.
|
||||
function hasPreselection(dropdown) {
|
||||
return Boolean(dropdown && dropdown.dataset.selected && dropdown.dataset.selected !== '0');
|
||||
}
|
||||
|
||||
// Send a GET request to ajax.php as ajax.php?get_client_contacts=true&client_id=NUM
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_contacts: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
// Adds an optgroup to a dropdown and returns it, so options can be appended into it
|
||||
function appendOptionGroup(dropdown, label) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
if (!dropdown) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Access the data for contacts (multiple)
|
||||
const contacts = response.contacts || [];
|
||||
const group = document.createElement("optgroup");
|
||||
group.label = label;
|
||||
dropdown.appendChild(group);
|
||||
|
||||
// Contacts dropdown
|
||||
const contactSelectDropdown = resetDropdown("contactSelect", '- No One -', '0');
|
||||
return group;
|
||||
}
|
||||
|
||||
// Watchers is a tags field - any address can be typed in, these are just the handy ones
|
||||
const watchersDropdown = resetDropdown("watchersSelect", null, null);
|
||||
// Adds an option to an optgroup
|
||||
function appendGroupedOption(group, label, value) {
|
||||
|
||||
// Populate dropdown
|
||||
contacts.forEach(contact => {
|
||||
var appendText = "";
|
||||
if (contact.contact_title) {
|
||||
appendText = " - " + contact.contact_title;
|
||||
}
|
||||
if (contact.contact_primary == "1") {
|
||||
appendText = appendText + " (Primary)";
|
||||
} else if (contact.contact_technical == "1") {
|
||||
appendText = appendText + " (Technical)";
|
||||
}
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contactSelectDropdown) {
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option(contact.contact_name + appendText, contact.contact_id);
|
||||
}
|
||||
group.appendChild(new Option(label, value));
|
||||
}
|
||||
|
||||
if (watchersDropdown && contact.contact_email) {
|
||||
watchersDropdown[watchersDropdown.length] = new Option(contact.contact_email, contact.contact_email);
|
||||
}
|
||||
});
|
||||
// Builds the asset label as "Name - Make Model - (Contact)", matching how assets read elsewhere
|
||||
function buildAssetLabel(asset) {
|
||||
|
||||
// Default to the client's primary contact unless the modal was opened for a
|
||||
// specific one. Contacts arrive primary-first.
|
||||
if (contactSelectDropdown && !hasPreselection(contactSelectDropdown)) {
|
||||
const primaryContact = contacts.find(contact => contact.contact_primary == "1");
|
||||
let label = asset.asset_name;
|
||||
|
||||
if (primaryContact) {
|
||||
contactSelectDropdown.value = primaryContact.contact_id;
|
||||
}
|
||||
if (asset.asset_make) {
|
||||
label = label + " - " + asset.asset_make;
|
||||
|
||||
if (asset.asset_model) {
|
||||
label = label + " " + asset.asset_model;
|
||||
}
|
||||
|
||||
applyPreselection(contactSelectDropdown);
|
||||
|
||||
refreshDropdown(contactSelectDropdown);
|
||||
refreshDropdown(watchersDropdown);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client assets - feeds both the single asset picker and the additional assets
|
||||
// multi-select from one request, as both need the same list
|
||||
function populateAssetsDropdowns(client_id) {
|
||||
if (asset.contact_name) {
|
||||
label = label + " - (" + asset.contact_name + ")";
|
||||
}
|
||||
|
||||
if (!document.getElementById("assetSelect") && !document.getElementById("additionalAssetsSelect")) {
|
||||
return;
|
||||
return label;
|
||||
}
|
||||
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_assets: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
// Populate client contacts - one request feeds both the contact picker and the
|
||||
// watchers list, as both are built from the same set of people
|
||||
function populateContactsDropdown(client_id) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
if (!document.getElementById("contactSelect") && !document.getElementById("watchersSelect")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Access the data for assets (multiple)
|
||||
const assets = response.assets || [];
|
||||
// Send a GET request to ajax.php as ajax.php?get_client_contacts=true&client_id=NUM
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_contacts: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
const assetSelectDropdown = resetDropdown("assetSelect", '- None -', '0');
|
||||
const additionalAssetsDropdown = resetDropdown("additionalAssetsSelect", null, null);
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Assets arrive ordered by type, so a change of type starts a new group
|
||||
let currentType = null;
|
||||
let assetGroup = null;
|
||||
let additionalAssetGroup = null;
|
||||
// Access the data for contacts (multiple)
|
||||
const contacts = response.contacts || [];
|
||||
|
||||
assets.forEach(asset => {
|
||||
const assetType = asset.asset_type || 'Uncategorized';
|
||||
// Contacts dropdown
|
||||
const contactSelectDropdown = resetDropdown("contactSelect", '- No One -', '0');
|
||||
|
||||
if (assetType !== currentType) {
|
||||
currentType = assetType;
|
||||
assetGroup = appendOptionGroup(assetSelectDropdown, assetType);
|
||||
additionalAssetGroup = appendOptionGroup(additionalAssetsDropdown, assetType);
|
||||
// Watchers is a tags field - any address can be typed in, these are just the handy ones
|
||||
const watchersDropdown = resetDropdown("watchersSelect", null, null);
|
||||
|
||||
// Populate dropdown
|
||||
contacts.forEach(contact => {
|
||||
var appendText = "";
|
||||
if (contact.contact_title) {
|
||||
appendText = " - " + contact.contact_title;
|
||||
}
|
||||
if (contact.contact_primary == "1") {
|
||||
appendText = appendText + " (Primary)";
|
||||
} else if (contact.contact_technical == "1") {
|
||||
appendText = appendText + " (Technical)";
|
||||
}
|
||||
|
||||
if (contactSelectDropdown) {
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option(contact.contact_name + appendText, contact.contact_id);
|
||||
}
|
||||
|
||||
if (watchersDropdown && contact.contact_email) {
|
||||
watchersDropdown[watchersDropdown.length] = new Option(contact.contact_email, contact.contact_email);
|
||||
}
|
||||
});
|
||||
|
||||
// Default to the client's primary contact unless the modal was opened for a
|
||||
// specific one. Contacts arrive primary-first.
|
||||
if (contactSelectDropdown && !hasPreselection(contactSelectDropdown)) {
|
||||
const primaryContact = contacts.find(contact => contact.contact_primary == "1");
|
||||
|
||||
if (primaryContact) {
|
||||
contactSelectDropdown.value = primaryContact.contact_id;
|
||||
}
|
||||
}
|
||||
|
||||
const assetLabel = buildAssetLabel(asset);
|
||||
applyPreselection(contactSelectDropdown);
|
||||
|
||||
appendGroupedOption(assetGroup, assetLabel, asset.asset_id);
|
||||
appendGroupedOption(additionalAssetGroup, assetLabel, asset.asset_id);
|
||||
});
|
||||
refreshDropdown(contactSelectDropdown);
|
||||
refreshDropdown(watchersDropdown);
|
||||
|
||||
applyPreselection(assetSelectDropdown);
|
||||
|
||||
refreshDropdown(assetSelectDropdown);
|
||||
refreshDropdown(additionalAssetsDropdown);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client locations
|
||||
function populateLocationsDropdown(client_id) {
|
||||
|
||||
if (!document.getElementById("locationSelect")) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_locations: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for locations (multiple)
|
||||
const locations = response.locations || [];
|
||||
|
||||
// Locations dropdown
|
||||
const locationSelectDropdown = resetDropdown("locationSelect", '- Location -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
locations.forEach(location => {
|
||||
locationSelectDropdown[locationSelectDropdown.length] = new Option(location.location_name, location.location_id);
|
||||
});
|
||||
|
||||
applyPreselection(locationSelectDropdown);
|
||||
|
||||
refreshDropdown(locationSelectDropdown);
|
||||
// Populate client assets - feeds both the single asset picker and the additional assets
|
||||
// multi-select from one request, as both need the same list
|
||||
function populateAssetsDropdowns(client_id) {
|
||||
|
||||
if (!document.getElementById("assetSelect") && !document.getElementById("additionalAssetsSelect")) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client vendors
|
||||
function populateVendorsDropdown(client_id) {
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_assets: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
if (!document.getElementById("vendorSelect")) {
|
||||
return;
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for assets (multiple)
|
||||
const assets = response.assets || [];
|
||||
|
||||
const assetSelectDropdown = resetDropdown("assetSelect", '- None -', '0');
|
||||
const additionalAssetsDropdown = resetDropdown("additionalAssetsSelect", null, null);
|
||||
|
||||
// Assets arrive ordered by type, so a change of type starts a new group
|
||||
let currentType = null;
|
||||
let assetGroup = null;
|
||||
let additionalAssetGroup = null;
|
||||
|
||||
assets.forEach(asset => {
|
||||
const assetType = asset.asset_type || 'Uncategorized';
|
||||
|
||||
if (assetType !== currentType) {
|
||||
currentType = assetType;
|
||||
assetGroup = appendOptionGroup(assetSelectDropdown, assetType);
|
||||
additionalAssetGroup = appendOptionGroup(additionalAssetsDropdown, assetType);
|
||||
}
|
||||
|
||||
const assetLabel = buildAssetLabel(asset);
|
||||
|
||||
appendGroupedOption(assetGroup, assetLabel, asset.asset_id);
|
||||
appendGroupedOption(additionalAssetGroup, assetLabel, asset.asset_id);
|
||||
});
|
||||
|
||||
applyPreselection(assetSelectDropdown);
|
||||
|
||||
refreshDropdown(assetSelectDropdown);
|
||||
refreshDropdown(additionalAssetsDropdown);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_vendors: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for vendors (multiple)
|
||||
const vendors = response.vendors || [];
|
||||
|
||||
// Vendors dropdown
|
||||
const vendorSelectDropdown = resetDropdown("vendorSelect", '- Vendor -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
vendors.forEach(vendor => {
|
||||
vendorSelectDropdown[vendorSelectDropdown.length] = new Option(vendor.vendor_name, vendor.vendor_id);
|
||||
});
|
||||
|
||||
applyPreselection(vendorSelectDropdown);
|
||||
|
||||
refreshDropdown(vendorSelectDropdown);
|
||||
// Populate client locations
|
||||
function populateLocationsDropdown(client_id) {
|
||||
|
||||
if (!document.getElementById("locationSelect")) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client projects
|
||||
function populateProjectsDropdown(client_id) {
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_locations: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
if (!document.getElementById("projectSelect")) {
|
||||
return;
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for locations (multiple)
|
||||
const locations = response.locations || [];
|
||||
|
||||
// Locations dropdown
|
||||
const locationSelectDropdown = resetDropdown("locationSelect", '- Location -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
locations.forEach(location => {
|
||||
locationSelectDropdown[locationSelectDropdown.length] = new Option(location.location_name, location.location_id);
|
||||
});
|
||||
|
||||
applyPreselection(locationSelectDropdown);
|
||||
|
||||
refreshDropdown(locationSelectDropdown);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_projects: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for projects (multiple)
|
||||
const projects = response.projects || [];
|
||||
|
||||
// Projects dropdown
|
||||
const projectSelectDropdown = resetDropdown("projectSelect", '- Select Project -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
projects.forEach(project => {
|
||||
projectSelectDropdown[projectSelectDropdown.length] = new Option(project.project_name, project.project_id);
|
||||
});
|
||||
|
||||
applyPreselection(projectSelectDropdown);
|
||||
|
||||
refreshDropdown(projectSelectDropdown);
|
||||
// Populate client vendors
|
||||
function populateVendorsDropdown(client_id) {
|
||||
|
||||
if (!document.getElementById("vendorSelect")) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_vendors: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for vendors (multiple)
|
||||
const vendors = response.vendors || [];
|
||||
|
||||
// Vendors dropdown
|
||||
const vendorSelectDropdown = resetDropdown("vendorSelect", '- Vendor -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
vendors.forEach(vendor => {
|
||||
vendorSelectDropdown[vendorSelectDropdown.length] = new Option(vendor.vendor_name, vendor.vendor_id);
|
||||
});
|
||||
|
||||
applyPreselection(vendorSelectDropdown);
|
||||
|
||||
refreshDropdown(vendorSelectDropdown);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client projects
|
||||
function populateProjectsDropdown(client_id) {
|
||||
|
||||
if (!document.getElementById("projectSelect")) {
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_projects: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for projects (multiple)
|
||||
const projects = response.projects || [];
|
||||
|
||||
// Projects dropdown
|
||||
const projectSelectDropdown = resetDropdown("projectSelect", '- Select Project -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
projects.forEach(project => {
|
||||
projectSelectDropdown[projectSelectDropdown.length] = new Option(project.project_name, project.project_id);
|
||||
});
|
||||
|
||||
applyPreselection(projectSelectDropdown);
|
||||
|
||||
refreshDropdown(projectSelectDropdown);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user