Rework ticket detail page: Details panel with click-to-change properties and status menu, plain-language reply types with who-sees-it line, slimmer header with billing in the menu, clearer modal titles and labels; fix billable wiped on edit by non-sales agents, email reply offered with no mail provider, timer JS error on resolved tickets, unshown due date

This commit is contained in:
johnnyq
2026-10-10 12:50:59 -04:00
parent 3e36185198
commit ae28b9fc34
23 changed files with 1115 additions and 656 deletions

View File

@@ -1,54 +1,81 @@
/* Ticket detail page */
/*
* Header property fields.
* Page layout.
*
* These used to be a run of inline label/value pairs separated only by a right
* margin, which read as one crunched line and collided outright when it wrapped.
* A fixed minimum width and a shared gutter give the row a rhythm, so each
* value reads as its own field and a wrapped row keeps its spacing.
* Desktop: two columns that both start at the top - the header and the
* conversation on the left, the sidebar (Details, Contact, Tasks, Linked,
* History) on the right, so the ticket's properties sit beside its title
* instead of in a strip that wrapped onto a second row.
*
* Phone: one column. Left alone, the whole sidebar would land under the
* conversation and put status and priority at the bottom of a long page. The
* sidebar wrapper steps aside (display: contents) so its cards become items of
* the column, and `order` lifts Details up between the header and the
* conversation while the other sidebar cards stay below it.
*/
.ticket-fields {
.ticket-layout {
display: flex;
flex-wrap: wrap;
margin: 0 -0.85rem;
flex-direction: column;
}
.ticket-field {
flex: 0 0 auto;
min-width: 150px;
max-width: 100%;
padding: 0 0.85rem;
margin-top: 0.85rem;
.ticket-layout-header {
order: 0;
}
.ticket-field-label {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: #8a94a0;
margin-bottom: 0.2rem;
white-space: nowrap;
.ticket-layout-main {
order: 2;
min-width: 0;
}
.ticket-field-value {
font-size: 0.95rem;
line-height: 1.4;
.ticket-layout-side {
display: contents;
}
/*
* Task progress. A slim track sitting beside the count rather than a chart
* with text floating on top of it. The count is real text, so the flex cell
* can size itself - the old bar's only children were a percentage-width div
* and an absolutely-positioned label, neither of which contributes intrinsic
* width, so the Tasks cell was pinned at min-width whatever it contained.
*/
.ticket-task-progress {
flex: 0 0 56px;
height: 6px;
.ticket-layout-side > * {
order: 3;
}
.ticket-layout-side > .ticket-details {
order: 1;
}
@media (min-width: 992px) {
.ticket-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) 300px;
/* The second row soaks up the height, so the header row is only as tall as the header */
grid-template-rows: auto 1fr;
grid-template-areas:
"header side"
"main side";
column-gap: 1rem;
align-items: start;
}
.ticket-layout-header {
grid-area: header;
}
.ticket-layout-main {
grid-area: main;
}
.ticket-layout-side {
display: block;
grid-area: side;
min-width: 0;
}
}
@media (min-width: 1400px) {
.ticket-layout {
grid-template-columns: minmax(0, 1fr) 340px;
}
}
/* Header */
/* The subject is the page's real heading, so let it breathe */
.ticket-subject {
font-weight: 600;
@@ -63,16 +90,197 @@
.ticket-meta {
font-size: 0.85rem;
color: #6c757d;
color: var(--bs-secondary-color);
word-break: break-word;
}
@media (max-width: 575px) {
.ticket-field {
min-width: 45%;
/*
* Details panel - one property per row, label on the left, value on the right.
*
* A value that can be changed is a full-width button: it highlights on hover and
* shows a small pencil, which is how the page says "click to change" without a
* column of blue links. Values that can't be changed get the same box with no
* hover, so every row lines up whether it is editable or not.
*/
.ticket-prop {
display: grid;
grid-template-columns: 6.25rem minmax(0, 1fr);
align-items: center;
min-height: 2.4rem;
}
.ticket-prop + .ticket-prop {
border-top: 1px solid var(--bs-border-color-translucent);
}
.ticket-prop dt {
margin: 0;
padding-left: 0.5rem;
font-size: 0.8rem;
font-weight: 500;
color: var(--bs-secondary-color);
}
.ticket-prop dd {
margin: 0;
min-width: 0;
}
.ticket-prop-edit,
.ticket-prop-static {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
width: 100%;
min-width: 0;
padding: 0.3rem 0.5rem;
border: 0;
border-radius: var(--bs-border-radius);
background: transparent;
color: var(--bs-body-color);
font: inherit;
text-align: left;
text-decoration: none;
}
.ticket-prop-edit:hover,
.ticket-prop-edit:focus-visible,
.ticket-prop-edit[aria-expanded="true"] {
background-color: var(--bs-tertiary-bg);
color: var(--bs-body-color);
}
.ticket-prop-edit-icon {
flex: 0 0 auto;
font-size: 0.7rem;
color: var(--bs-secondary-color);
opacity: 0;
transition: opacity 0.15s;
}
.ticket-prop-edit:hover .ticket-prop-edit-icon,
.ticket-prop-edit:focus-visible .ticket-prop-edit-icon,
.ticket-prop-edit[aria-expanded="true"] .ticket-prop-edit-icon {
opacity: 1;
}
/* Touch screens have no hover, so the pencil stays faintly visible there */
@media (hover: none) {
.ticket-prop-edit-icon {
opacity: 0.6;
}
}
/* A second line under a value - the SLA plan name, Onsite/Remote */
.ticket-prop-sub {
display: block;
font-size: 0.8rem;
color: var(--bs-secondary-color);
}
.ticket-prop .badge {
font-size: 0.78rem;
font-weight: 600;
/* Badges never wrap by default, and an SLA countdown can be wider than a narrow column */
white-space: normal;
text-align: left;
}
/* Small uppercase headings inside the Linked and History cards */
.ticket-link-heading {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--bs-secondary-color);
}
/* Tasks - the progress count lives in the card heading, the one place it is shown */
.ticket-task-count {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-size: 0.8rem;
font-weight: 400;
color: var(--bs-secondary-color);
vertical-align: middle;
}
.ticket-task-progress {
width: 48px;
height: 5px;
}
.ticket-task-table td {
vertical-align: top;
padding-top: 0.45rem;
padding-bottom: 0.45rem;
}
.ticket-task-check {
width: 1.75rem;
}
.ticket-task-table .drag-handle {
cursor: grab;
opacity: 0.4;
}
.ticket-task-table tr:hover .drag-handle {
opacity: 1;
}
/* History - label/value pairs in two columns */
.ticket-history-facts {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
column-gap: 0.75rem;
row-gap: 0.4rem;
font-size: 0.875rem;
}
.ticket-history-facts dt {
font-weight: 500;
color: var(--bs-secondary-color);
}
.ticket-history-facts dd {
margin: 0;
}
/* Conversation - the coloured edge says who wrote it and who can see it */
.ticket-reply.border-start {
border-left-width: 4px !important;
}
/*
* Dark mode: Bootstrap's "dark" is the page colour there, so the ticket reference,
* the Internal badge and an internal note's edge would all vanish into the card.
* Lift them to a mid grey that still reads as the dark/neutral one.
*/
[data-bs-theme="dark"] .ticket-ref,
[data-bs-theme="dark"] .ticket-badge-internal {
background-color: #495057 !important;
color: #fff !important;
}
[data-bs-theme="dark"] .ticket-reply.border-dark {
border-left-color: #6c757d !important;
}
/* The "who will see this" line under the reply type buttons */
.ticket-reply-audience {
padding: 0.5rem 0.75rem;
border-radius: var(--bs-border-radius);
background-color: var(--bs-tertiary-bg);
color: var(--bs-secondary-color);
}
.ticket-reply-audience strong {
color: var(--bs-body-color);
}
/*
* Bootstrap cancels hover on any .btn following a .btn-check (twbs #31149 / PR #37026):
* a checked outline toggle and an unchecked one looked identical while hovered, so you
@@ -87,3 +295,14 @@
#replyTypePicker .btn-check:not(:checked) + .btn:hover {
background-color: var(--bs-secondary-bg);
}
/* Paper gets one column, conversation first */
@media print {
.ticket-layout {
display: block;
}
.ticket-layout-side {
display: block;
}
}

View File

@@ -16,7 +16,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-eye me-2"></i>Adding a ticket Watcher</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-eye me-2"></i>Add watcher</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -24,12 +24,14 @@ ob_start();
<input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
<div class="modal-body">
<p class="text-muted small">Watchers get a copy of every emailed reply on this ticket.</p>
<div class="mb-3">
<label>Watcher Email</label>
<label>Email</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
<select class="form-select select2" data-tags="true" name="watcher_email">
<option value="">- Select a contact or enter an email(s) -</option>
<option value="">- Pick a contact or type an email address -</option>
<?php
$sql_client_contacts_select = mysqli_query($mysqli, "SELECT contact_id, contact_name, contact_email FROM contacts WHERE contact_client_id = $client_id AND contact_email <> '' ORDER BY contact_name ASC");
@@ -47,12 +49,12 @@ ob_start();
</div>
</div>
<?php if (!empty($config_smtp_host)) { ?>
<?php if (!empty($config_smtp_provider)) { ?>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="watcher_notify" value="1" id="checkNotifyWatcher">
<label class="form-check-label" for="checkNotifyWatcher">
Send email notification
Email them a link to this ticket now
</label>
</div>
</div>
@@ -61,7 +63,7 @@ ob_start();
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_watcher" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Add</button>
<button type="submit" name="add_ticket_watcher" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Add watcher</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Cancel</button>
</div>

View File

@@ -31,7 +31,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class='fa fa-fw fa-user-check me-2'></i>Assigning Ticket: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
<h5 class="modal-title"><i class='fa fa-fw fa-user-check me-2'></i>Assign ticket <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
@@ -42,7 +42,7 @@ ob_start();
<div class="modal-body">
<div class="mb-3">
<label>Assign to</label>
<label>Technician</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-user-check"></i></span>
<select class="form-select select2" name="assigned_to">

View File

@@ -22,7 +22,7 @@ ob_start();
<div class="modal-header bg-dark">
<h5 class="modal-title">
<i class="fa fa-fw fa-money-bill me-2"></i>Editing Billable Status: <strong><?= "$ticket_prefix$ticket_number" ?></strong>
<i class="fa fa-fw fa-money-bill me-2"></i>Billing <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small>
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
@@ -31,14 +31,15 @@ ob_start();
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
<div class="mb-3">
<label>Billable?</label>
<label>This ticket is</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-money-bill"></i></span>
<select class="form-select" name="billable_status">
<option <?php if ($ticket_billable == 1) { echo "selected"; } ?> value="1">Yes</option>
<option <?php if ($ticket_billable == 0) { echo "selected"; } ?> value="0">No</option>
<option <?php if ($ticket_billable == 1) { echo "selected"; } ?> value="1">Billable</option>
<option <?php if ($ticket_billable == 0) { echo "selected"; } ?> value="0">Not billable</option>
</select>
</div>
<small class="text-muted">Billable tickets show in the Unbilled Tickets report until they are invoiced.</small>
</div>
</div>

View File

@@ -23,8 +23,7 @@ ob_start();
<div class="modal-header bg-dark">
<h5 class="modal-title">
<i class="fa fa-fw fa-people-carry me-2"></i>
Change <?= "$ticket_prefix$ticket_number" ?> to another client
<i class="fa fa-fw fa-people-carry me-2"></i>Move to another client <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small>
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
@@ -34,8 +33,14 @@ ob_start();
<input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
<div class="modal-body">
<!-- change_client_ticket turns every reply internal - the agent should know before, not after -->
<div class="alert alert-info small">
Every reply already on this ticket becomes an internal note, so the new client never sees the old conversation.
</div>
<div class="mb-3">
<label>New Client <strong class="text-danger">*</strong></label>
<label>Client <strong class="text-danger">*</strong></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-users"></i></span>
<select class="form-select select2" name="new_client_id" id="client_select" required>
@@ -54,7 +59,7 @@ ob_start();
</div>
<div class="mb-3">
<label>New Contact</label>
<label>Contact</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
<select class="form-select select2" name="new_contact_id" id="contact_select">
@@ -66,7 +71,7 @@ ob_start();
<div class="modal-footer">
<button type="submit" name="change_client_ticket" class="btn btn-primary text-bold">
<i class="fa fa-check me-2"></i>Change
<i class="fa fa-check me-2"></i>Move ticket
</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal">
<i class="fa fa-times me-2"></i>Cancel

View File

@@ -26,7 +26,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-user me-2"></i>Changing contact: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-user me-2"></i>Change contact <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -39,7 +39,7 @@ ob_start();
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
<select class="form-select select2" name="contact">
<option value="">No One</option>
<option value="">No contact</option>
<?php
$sql_client_contacts_select = mysqli_query($mysqli, "SELECT contact_id, contact_name, contact_title, contact_primary, contact_technical FROM contacts WHERE contact_client_id = $client_id AND contact_archived_at IS NULL ORDER BY contact_primary DESC, contact_technical DESC, contact_name ASC");
while ($row = mysqli_fetch_assoc($sql_client_contacts_select)) {
@@ -76,12 +76,12 @@ ob_start();
</div>
</div>
<?php if (!empty($config_smtp_host)) { ?>
<?php if (!empty($config_smtp_provider)) { ?>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="contact_notify" value="1" id="checkNotifyContact" <?php if ($config_ticket_client_general_notifications) { echo "checked"; } ?>>
<label class="form-check-label" for="checkNotifyContact">
Send email notification
Email the new contact a link to this ticket
</label>
</div>
</div>

View File

@@ -51,7 +51,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring me-2"></i>Ticket: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring me-2"></i>Edit ticket <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -66,10 +66,10 @@ ob_start();
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="pill" href="#pills-contacts"><i class="fa fa-fw fa-users me-2"></i>Contact</a>
<a class="nav-link" data-bs-toggle="pill" href="#pills-contacts"><i class="fa fa-fw fa-user me-2"></i>Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" data-bs-toggle="pill" href="#pills-assignment"><i class="fa fa-fw fa-desktop me-2"></i>Assignment</a>
<a class="nav-link" data-bs-toggle="pill" href="#pills-assignment"><i class="fa fa-fw fa-link me-2"></i>Related</a>
</li>
</ul>
@@ -138,11 +138,11 @@ ob_start();
<div class="row">
<div class="col">
<div class="mb-3">
<label>Assign to</label>
<label>Assigned to</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-user-check"></i></span>
<select class="form-select select2" name="assigned_to">
<option value="0">Not Assigned</option>
<option value="0">Unassigned</option>
<?php
$sql = mysqli_query(
@@ -165,7 +165,7 @@ ob_start();
</div>
<div class="col">
<div class="mb-3">
<label>Due</label>
<label>Due date</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-calendar-check"></i></span>
<input type="datetime-local" class="form-control" name="due" value="<?= $ticket_due_at ?>">
@@ -178,9 +178,12 @@ ob_start();
<div class="mb-3">
<div class="form-check form-switch">
<input type="checkbox" class="form-check-input" name="billable" <?php if ($ticket_billable == 1) { echo "checked"; } ?> value="1" id="billableSwitch<?= $ticket_id ?>">
<label class="form-check-label" for="billableSwitch<?= $ticket_id ?>">Mark Billable</label>
<label class="form-check-label" for="billableSwitch<?= $ticket_id ?>">Billable</label>
</div>
</div>
<?php } else { ?>
<!-- No switch for this user, so carry the current value through untouched -->
<input type="hidden" name="billable" value="<?= $ticket_billable ?>">
<?php } ?>
</div>
@@ -194,7 +197,7 @@ ob_start();
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
<select class="form-select select2" name="contact_id">
<option value="0">No One</option>
<option value="0">No contact</option>
<?php
$sql_client_contacts_select = mysqli_query($mysqli, "SELECT contact_id, contact_name, contact_title, contact_primary, contact_technical FROM contacts WHERE contact_client_id = $client_id AND contact_archived_at IS NULL ORDER BY contact_primary DESC, contact_technical DESC, contact_name ASC");
while ($row = mysqli_fetch_assoc($sql_client_contacts_select)) {
@@ -226,12 +229,12 @@ ob_start();
</div>
</div>
<?php if (!empty($config_smtp_host)) { ?>
<?php if (!empty($config_smtp_provider)) { ?>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="contact_notify" value="1" id="checkNotifyContact">
<label class="form-check-label" for="checkNotifyContact">
Send email notification
Email the contact a link to this ticket
</label>
</div>
</div>
@@ -242,7 +245,7 @@ ob_start();
<div class="tab-pane fade" id="pills-assignment">
<div class="mb-3">
<label>Asset</label>
<label>Primary asset</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-desktop"></i></span>
<select class="form-select select2" name="asset_id">
@@ -255,7 +258,7 @@ ob_start();
$asset_name_select = escapeHtml($row['asset_name']);
$asset_contact_name_select = escapeHtml($row['contact_name']);
?>
<option <?php if ($asset_id == $asset_id_select) { echo "selected"; } ?> value="<?= $asset_id_select ?>"><?= "$asset_name_select - $asset_contact_name_select" ?></option>
<option <?php if ($asset_id == $asset_id_select) { echo "selected"; } ?> value="<?= $asset_id_select ?>"><?= $asset_contact_name_select ? "$asset_name_select ($asset_contact_name_select)" : $asset_name_select ?></option>
<?php
}
@@ -265,10 +268,10 @@ ob_start();
</div>
<div class="mb-3">
<label>Additional Assets</label>
<label>Other assets</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-desktop"></i></span>
<select class="form-select select2" name="additional_assets[]" data-placeholder="- Select Additional Assets -" multiple>
<select class="form-select select2" name="additional_assets[]" data-placeholder="- Any other assets involved -" multiple>
<option value=""></option>
<?php
@@ -280,7 +283,7 @@ ob_start();
?>
<option value="<?= $asset_id_select ?>"
<?php if (in_array($asset_id_select, $additional_assets_array)) { echo "selected"; } ?>
><?= "$asset_name_select - $asset_contact_name_select" ?></option>
><?= $asset_contact_name_select ? "$asset_name_select ($asset_contact_name_select)" : $asset_name_select ?></option>
<?php } ?>
</select>
@@ -340,10 +343,10 @@ ob_start();
<div class="col">
<div class="mb-3">
<label>Vendor Ticket Number</label>
<label>Vendor's ticket number</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
<input type="text" class="form-control" name="vendor_ticket_number" placeholder="Vendor ticket number" maxlength="255" value="<?= $ticket_vendor_ticket_number ?>">
<input type="text" class="form-control" name="vendor_ticket_number" placeholder="Their reference for this issue" maxlength="255" value="<?= $ticket_vendor_ticket_number ?>">
</div>
</div>

View File

@@ -32,7 +32,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-desktop me-2"></i>Editing ticket Asset: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-desktop me-2"></i>Assets <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -41,11 +41,11 @@ ob_start();
<div class="modal-body">
<div class="mb-3">
<label>Asset</label>
<label>Primary asset</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-desktop"></i></span>
<select class="form-select select2" name="asset">
<option value="0">- None -</option>
<option value="0">No asset</option>
<?php
$sql_assets = mysqli_query($mysqli, "SELECT asset_id, asset_name, contact_name FROM assets LEFT JOIN contacts ON contact_id = asset_contact_id WHERE asset_client_id = $client_id AND asset_archived_at IS NULL ORDER BY asset_name ASC");
@@ -54,7 +54,7 @@ ob_start();
$asset_name_select = escapeHtml($row['asset_name']);
$asset_contact_name_select = escapeHtml($row['contact_name']);
?>
<option <?php if ($asset_id == $asset_id_select) { echo "selected"; } ?> value="<?= $asset_id_select ?>"><?= "$asset_name_select - $asset_contact_name_select" ?></option>
<option <?php if ($asset_id == $asset_id_select) { echo "selected"; } ?> value="<?= $asset_id_select ?>"><?= $asset_contact_name_select ? "$asset_name_select ($asset_contact_name_select)" : $asset_name_select ?></option>
<?php
}
@@ -64,10 +64,10 @@ ob_start();
</div>
<div class="mb-3">
<label>Additional Assets</label>
<label>Other assets</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-desktop"></i></span>
<select class="form-select select2" name="additional_assets[]" data-placeholder="- Select Additional Assets -" multiple>
<select class="form-select select2" name="additional_assets[]" data-placeholder="- Any other assets involved -" multiple>
<option value=""></option>
<?php
@@ -79,7 +79,7 @@ ob_start();
?>
<option value="<?= $asset_id_select ?>"
<?php if (in_array($asset_id_select, $additional_assets_array)) { echo "selected"; } ?>
><?= "$asset_name_select - $asset_contact_name_select" ?></option>
><?= $asset_contact_name_select ? "$asset_name_select ($asset_contact_name_select)" : $asset_name_select ?></option>
<?php } ?>
</select>

View File

@@ -27,7 +27,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-project-diagram me-2"></i>Project: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
<h5 class="modal-title"><i class="fas fa-fw fa-project-diagram me-2"></i>Project <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -40,7 +40,7 @@ ob_start();
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
<select class="form-select select2" name="project">
<option value="0">- None -</option>
<option value="0">No project</option>
<?php
while ($row = mysqli_fetch_assoc($sql_projects)) {
$project_id = intval($row['project_id']);

View File

@@ -31,7 +31,7 @@ ob_start();
<div class="modal-header bg-dark">
<h5 class="modal-title">
<i class="fa fa-fw fa-calendar-check me-2"></i>Scheduling Ticket: <strong><?= "$ticket_prefix$ticket_number" ?></strong>
<i class="fa fa-fw fa-calendar-check me-2"></i>Schedule <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small>
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
@@ -41,7 +41,7 @@ ob_start();
<input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
<div class="mb-3">
<label>Date / Time</label>
<label>Date and time</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-calendar-day"></i></span>
<input type="datetime-local" class="form-control" name="scheduled_date_time" placeholder="Scheduled Date & Time" min="<?= date('Y-m-d\TH:i') ?>" <?php if ($ticket_scheduled_for) { echo "value='$ticket_scheduled_for'"; } ?>>
@@ -49,12 +49,12 @@ ob_start();
</div>
<div class="mb-3">
<label>Onsite?</label>
<label>Visit</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-map-marker-alt"></i></span>
<select class="form-select" name="onsite" required>
<option value="0" <?php if ($ticket_onsite == 0) echo "selected"; ?>>No</option>
<option value="1" <?php if ($ticket_onsite == 1) echo "selected"; ?>>Yes</option>
<option value="0" <?php if ($ticket_onsite == 0) echo "selected"; ?>>Remote</option>
<option value="1" <?php if ($ticket_onsite == 1) echo "selected"; ?>>Onsite</option>
</select>
</div>
</div>
@@ -62,8 +62,8 @@ ob_start();
<div class="modal-footer">
<?php if ($ticket_scheduled_for) { ?>
<a href="post.php?cancel_ticket_schedule=<?= $ticket_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>" class="btn btn-danger text-bold confirm-link" data-confirm-text="A cancellation email goes to the assigned agent, and to the contact and watchers if client notifications are on." data-confirm-button="Cancel scheduled time">
<i class="fa fa-trash me-2"></i>Cancel Scheduled Time
<a href="post.php?cancel_ticket_schedule=<?= $ticket_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>" class="btn btn-outline-danger confirm-link me-auto" data-confirm-title="Remove from the schedule?" data-confirm-text="A cancellation email goes to the assigned agent, and to the contact and watchers if client notifications are on." data-confirm-button="Remove from schedule">
<i class="fa fa-calendar-times me-2"></i>Remove from schedule
</a>
<?php } ?>
<button type="submit" name="edit_ticket_schedule" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Save</button>

View File

@@ -6,12 +6,13 @@ enforceUserPermission('module_support', 2);
$ticket_id = intval($_GET['ticket_id']);
$sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_number, ticket_prefix, ticket_vendor_id FROM tickets WHERE ticket_id = $ticket_id LIMIT 1");
$sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_number, ticket_prefix, ticket_vendor_id, ticket_vendor_ticket_number FROM tickets WHERE ticket_id = $ticket_id LIMIT 1");
$row = mysqli_fetch_assoc($sql);
$ticket_prefix = escapeHtml($row['ticket_prefix']);
$ticket_number = intval($row['ticket_number']);
$vendor_id = intval($row['ticket_vendor_id']);
$vendor_ticket_number = escapeHtml($row['ticket_vendor_ticket_number']);
$client_id = intval($row['ticket_client_id']);
if ($client_id) {
@@ -23,7 +24,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-building me-2"></i>Editing Vendor: <strong><?= "$ticket_prefix$ticket_number" ?></strong></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-building me-2"></i>Vendor <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -36,7 +37,7 @@ ob_start();
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-building"></i></span>
<select class="form-select select2" name="vendor">
<option value="0">- None -</option>
<option value="0">No vendor</option>
<?php
$sql_vendors = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE vendor_client_id = $client_id AND vendor_archived_at IS NULL ORDER BY vendor_name ASC");
@@ -53,6 +54,14 @@ ob_start();
</div>
</div>
<div class="mb-3">
<label>Vendor's ticket number</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-hashtag"></i></span>
<input type="text" class="form-control" name="vendor_ticket_number" placeholder="Their reference for this issue" maxlength="255" value="<?= $vendor_ticket_number ?>">
</div>
</div>
</div>
<div class="modal-footer">

View File

@@ -94,7 +94,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-invoice-dollar me-2"></i>Invoice ticket</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-file-invoice-dollar me-2"></i>Invoice this ticket</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">

View File

@@ -36,7 +36,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-clone me-2"></i>Merge & Close <?= "$ticket_prefix$ticket_number" ?> into another ticket</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-clone me-2"></i>Merge into another ticket <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -44,16 +44,16 @@ ob_start();
<input type="hidden" id="current_ticket_id" name="ticket_id" value="<?= $ticket_id ?>">
<div class="modal-body">
<div class="alert alert-dark">
The current ticket <strong><?= "$ticket_prefix$ticket_number" ?></strong> will be closed once merging is complete.
<div class="alert alert-info small">
<strong><?= "$ticket_prefix$ticket_number" ?></strong> is closed, and its subject and description are added to the ticket you pick as an internal note.
</div>
<div class="mb-3">
<label>Ticket number to merge this ticket into <strong class="text-danger">*</strong></label>
<label>Merge into <strong class="text-danger">*</strong></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
<select class="form-select select2" name="merge_into_ticket_id" required>
<option value=''>- Select a Ticket -</option>
<option value=''>- Pick the ticket to keep -</option>
<?php
while ($row = mysqli_fetch_assoc($sql_merge)) {
$ticket_id_merge = intval($row['ticket_id']);
@@ -64,7 +64,7 @@ ob_start();
$ticket_subject_merge = escapeHtml($row['ticket_subject']);
?>
<option value="<?= $ticket_id_merge ?>">
<?= "$ticket_prefix_merge$ticket_number_merge ($ticket_status_name_merge) $client_name_merge - $ticket_subject_merge" ?>
<?= "$ticket_prefix_merge$ticket_number_merge ($ticket_status_name_merge) $client_name_merge - $ticket_subject_merge" ?>
</option>
<?php } ?>
</select>
@@ -72,10 +72,10 @@ ob_start();
</div>
<div class="mb-3">
<label>Reason for merge <strong class="text-danger">*</strong></label>
<label>Reason <strong class="text-danger">*</strong></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-sticky-note"></i></span>
<input type="text" class="form-control" name="merge_comment" placeholder="Comments" required>
<input type="text" class="form-control" name="merge_comment" placeholder="Noted on both tickets" required>
</div>
</div>
@@ -83,14 +83,14 @@ ob_start();
<div class="form-check">
<input class="form-check-input" type="checkbox" id="checkMoveReplies" name="merge_move_replies" value="1">
<label class="form-check-label" for="checkMoveReplies">
Move notes & replies to the new parent ticket
Also move this ticket's replies onto it
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="merge_ticket" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Merge</button>
<button type="submit" name="merge_ticket" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Merge and close</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Cancel</button>
</div>
</form>

View File

@@ -28,7 +28,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-thermometer-half me-2"></i>Editing priority: <strong><?= "$ticket_prefix$ticket_number" ?></strong></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-thermometer-half me-2"></i>Change priority <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">

View File

@@ -73,7 +73,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-comment-dollar me-2"></i>Quote ticket</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-comment-dollar me-2"></i>Create quote from ticket</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>

View File

@@ -2,6 +2,8 @@
require_once '../../../includes/modal_header.php';
enforceUserPermission('module_support', 2);
$ticket_reply_id = intval($_GET['id']);
$sql = mysqli_query($mysqli, "SELECT ticket_client_id, ticket_reply, ticket_reply_time_worked, ticket_reply_type FROM ticket_replies
@@ -27,7 +29,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-edit me-2"></i>Editing Ticket Reply</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-edit me-2"></i>Edit reply</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -39,10 +41,11 @@ ob_start();
<div class="mb-3">
<div class="btn-group w-100" role="group">
<input class="btn-check" id="ticket_reply_type_opt0" type="radio" name="ticket_reply_type" value="Internal" <?php if ($ticket_reply_type == 'Internal') { echo "checked"; } ?>>
<label class="btn btn-outline-secondary" for="ticket_reply_type_opt0">Internal Note</label>
<label class="btn btn-outline-secondary" for="ticket_reply_type_opt0"><i class="fas fa-fw fa-lock me-1"></i>Internal note</label>
<input class="btn-check" id="ticket_reply_type_opt1" type="radio" name="ticket_reply_type" value="Public" <?php if ($ticket_reply_type == 'Public') { echo "checked"; } ?>>
<label class="btn btn-outline-secondary" for="ticket_reply_type_opt1">Public Comment</label>
<label class="btn btn-outline-secondary" for="ticket_reply_type_opt1"><i class="fas fa-fw fa-eye me-1"></i>Public</label>
</div>
<small class="text-muted">Public replies show in the client portal. Saving here never sends an email.</small>
</div>
<div class="mb-3">
@@ -50,7 +53,7 @@ ob_start();
</div>
<?php if (!empty($ticket_reply_time_worked)) { ?>
<div class="col-3">
<div class="col-6 col-md-3">
<div class="mb-3">
<label>Time worked</label>
<input class="form-control" name="time" type="text" placeholder="HH:MM:SS" pattern="([01]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9])" value="<?= $ticket_reply_time_worked_formatted ?>" required>

View File

@@ -25,7 +25,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-edit me-2"></i>Redacting Ticket Reply</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-user-secret me-2"></i>Redact reply</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -34,13 +34,19 @@ ob_start();
<div class="modal-body">
<!-- The editor blocks typing and only has a REDACT button - nothing on screen said so -->
<p class="small text-muted mb-2">
Select the text to hide, such as a password, then press <strong>REDACT</strong>. Typing is switched off here.
Saving replaces the original text for good.
</p>
<div class="mb-3">
<textarea class="form-control tinymceRedact" name="ticket_reply"><?= $ticket_reply ?></textarea>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="redact_ticket_reply" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Save</button>
<button type="submit" name="redact_ticket_reply" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Save redaction</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Cancel</button>
</div>
</form>

View File

@@ -28,7 +28,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-stopwatch me-2"></i>Editing SLA: <strong><?= "$ticket_prefix$ticket_number" ?></strong></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-stopwatch me-2"></i>Change SLA plan <small class="ms-1 opacity-75"><?= "$ticket_prefix$ticket_number" ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -38,17 +38,17 @@ ob_start();
<div class="modal-body">
<div class="mb-3">
<label>SLA</label>
<label>SLA plan</label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-stopwatch"></i></span>
<select class="form-select select2" name="sla_id" required>
<option value="0" <?php if ($ticket_sla_id == 0) { echo "selected"; } ?>>None</option>
<option value="0" <?php if ($ticket_sla_id == 0) { echo "selected"; } ?>>No SLA</option>
<?php while ($sla_row = mysqli_fetch_assoc($sql_slas)) { ?>
<option value="<?= intval($sla_row['sla_id']) ?>" <?php if ($ticket_sla_id == intval($sla_row['sla_id'])) { echo "selected"; } ?>><?= escapeHtml($sla_row['sla_name']) ?></option>
<?php } ?>
</select>
</div>
<small class="text-muted">Response and resolution targets are recalculated from the ticket's creation time.</small>
<small class="text-muted">The response and resolution deadlines are worked out again from when the ticket was opened.</small>
</div>
</div>

View File

@@ -9,7 +9,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title" id="summaryModalTitle">Ticket Summary</h5>
<h5 class="modal-title" id="summaryModalTitle"><i class="fas fa-fw fa-magic me-2"></i>AI summary</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">

View File

@@ -25,7 +25,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-shield-alt me-2"></i>New approver for task <?=$task_name?></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-shield-alt me-2"></i>Require approval <small class="ms-1 opacity-75"><?= $task_name ?></small></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -35,13 +35,13 @@ ob_start();
<div class="modal-body">
<div class="mb-3">
<label>Approval scope <strong class="text-danger">*</strong></label>
<label>Approval comes from <strong class="text-danger">*</strong></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-layer-group"></i></span>
<select class="form-select" name="approval_scope" id="approval_scope" required>
<option value="">Select scope...</option>
<option value="internal">Internal</option>
<option value="client">Client</option>
<option value="">- Pick one -</option>
<option value="internal">Our team</option>
<option value="client">The client</option>
</select>
</div>
</div>
@@ -59,7 +59,7 @@ ob_start();
<div class="mb-3 d-none" id="specific_user_wrapper">
<label>Select specific internal approver <strong class="text-danger">*</strong></label>
<label>Technician <strong class="text-danger">*</strong></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-user-circle"></i></span>
<select class="form-select select2" name="approval_required_user_id" id="specific_user_select">
@@ -72,7 +72,7 @@ ob_start();
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_task_approver" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Save</button>
<button type="submit" name="add_ticket_task_approver" class="btn btn-primary text-bold"><i class="fa fa-check me-2"></i>Require approval</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Cancel</button>
</div>
@@ -118,8 +118,8 @@ ob_start();
if (scope === 'internal') {
setOptions(typeSelect, [
['', 'Select...'],
['any', 'Any internal reviewer'],
['specific', 'Specific agent']
['any', 'Any other technician'],
['specific', 'A specific technician']
]);
}

View File

@@ -34,7 +34,7 @@ ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-tasks me-2"></i>Editing task</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-tasks me-2"></i>Edit task</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" autocomplete="off">
@@ -44,33 +44,32 @@ ob_start();
<div class="modal-body">
<div class="mb-3">
<label>Name <strong class="text-danger">*</strong></label>
<label>Task <strong class="text-danger">*</strong></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
<input type="text" class="form-control" name="name" placeholder="Name the task" maxlength="255" value="<?= $task_name ?>" required autofocus>
<input type="text" class="form-control" name="name" placeholder="What needs doing" maxlength="255" value="<?= $task_name ?>" required autofocus>
</div>
</div>
<div class="mb-3">
<label>Estimated Completion Time <span class="text-secondary">(Minutes)</span></label>
<label>Time estimate <span class="text-secondary">(minutes)</span></label>
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
<input type="number" class="form-control" name="completion_estimate" placeholder="Estimated time to complete task in mins" value="<?= $task_completion_estimate ?>">
<input type="number" class="form-control" name="completion_estimate" placeholder="e.g. 30" value="<?= $task_completion_estimate ?>">
</div>
</div>
<?php if (mysqli_num_rows($sql_task_approvals) > 0) { ?>
<hr>
<div class="mb-3">
<b>Task Approvals</b>
<b>Approvals</b>
<table class="table table-sm table-bordered" style="margin-top:10px;">
<thead>
<tr>
<th>Scope</th>
<th>Type</th>
<th>Who can approve</th>
<th>Status</th>
<th>Action</th>
<th></th>
</tr>
</thead>
<tbody>
@@ -82,17 +81,29 @@ ob_start();
$approval_status = escapeHtml($row['approval_status']);
$approval_created_by = intval($row['approval_created_by']);
$approval_approved_by = escapeHtml($row['approval_approved_by']);
// In words - the raw scope/type pair ("Internal", "Any") meant nothing on screen
if ($approval_scope == 'internal' && $approval_type == 'specific') {
$approval_who = $approval_user_name ?: 'A specific technician';
} elseif ($approval_scope == 'internal') {
$approval_who = 'Any other technician';
} elseif ($approval_type == 'technical') {
$approval_who = "The client's technical contacts";
} elseif ($approval_type == 'billing') {
$approval_who = "The client's billing contacts";
} else {
$approval_who = 'The ticket contact';
}
?>
<tr>
<td><?= ucfirst($approval_scope) ?></td>
<td><?= ucfirst($approval_type) ?> <?php if (!empty($approval_user_name)) { echo " - $approval_user_name"; } ?></td>
<td><?= $approval_who ?></td>
<td><?= ucfirst($approval_status) ?></td>
<td>
<?php if ($approval_status !== 'approved') { ?>
<a class="text-danger"
onclick="return confirm('Delete this approval request?');"
href="post.php?delete_ticket_task_approver=<?= $approval_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-trash-alt"></i>Delete
<i class="fas fa-fw fa-times"></i>Remove
</a>
<!-- confirm-link won't work -->
<?php } ?>

View File

@@ -815,6 +815,13 @@ if (isset($_POST['edit_ticket_vendor'])) {
mysqli_query($mysqli, "UPDATE tickets SET ticket_vendor_id = $vendor_id WHERE ticket_id = $ticket_id");
// The vendor modal now carries the vendor's own ticket number too. Only touched when the
// field was posted, so anything else that submits this action cannot blank it by omission
if (isset($_POST['vendor_ticket_number'])) {
$vendor_ticket_number = escapeSql($_POST['vendor_ticket_number']);
mysqli_query($mysqli, "UPDATE tickets SET ticket_vendor_ticket_number = '$vendor_ticket_number' WHERE ticket_id = $ticket_id");
}
// Get ticket / vendor details for logging
$sql = mysqli_query($mysqli, "SELECT vendor_name, ticket_prefix, ticket_number, ticket_status_name, ticket_client_id FROM vendors
LEFT JOIN tickets ON ticket_vendor_id = $vendor_id

File diff suppressed because it is too large Load Diff