Skip to content

Commit ae39b0f

Browse files
committed
fix: reference widget shows state-specific icons (Incident/UserRequest); align with search logic; include class in ticket rich object; robust detection + safe fallback
1 parent 9638bbb commit ae39b0f

File tree

6 files changed

+63
-25
lines changed

6 files changed

+63
-25
lines changed
43.3 KB
Loading
43.3 KB
Loading
Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

js/integration_itop-reference.mjs

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

lib/Reference/ItopReferenceProvider.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,15 @@ private function getTicketIconUrl(array $ticket): string {
9090
// Determine icon based on ticket state
9191
$iconName = '';
9292

93-
// Check for closed state first
93+
// Check for closed state first (based on close_date)
9494
if (!empty($closeDate)) {
9595
$iconName = strtolower($type) . '-closed.svg';
9696
}
97-
// Check for escalated state (high priority)
98-
elseif (stripos($priority, 'high') !== false || stripos($priority, 'critical') !== false) {
97+
// Check for escalated state (high priority: 1 or 2)
98+
elseif (is_numeric($priority) && (int)$priority <= 2) {
9999
$iconName = strtolower($type) . '-escalated.svg';
100100
}
101-
// Check for deadline state (you may need to adjust this logic based on your needs)
101+
// Check for deadline state (pending/waiting status)
102102
elseif (stripos($status, 'pending') !== false || stripos($status, 'waiting') !== false) {
103103
$iconName = strtolower($type) . '-deadline.svg';
104104
}
@@ -362,7 +362,7 @@ private function getTicketReference(int $ticketId, string $class, string $url):
362362
'class' => $class,
363363
'id' => $ticketId
364364
]);
365-
return $this->buildTicketReference($cachedTicketInfo, $url);
365+
return $this->buildTicketReference($cachedTicketInfo, $url, $class);
366366
}
367367

368368
// Cache miss - fetch data from iTop API
@@ -398,7 +398,7 @@ private function getTicketReference(int $ticketId, string $class, string $url):
398398
// Cache the ticket info for next request
399399
$this->cacheService->setTicketInfo($this->userId, $ticketId, $class, $fields);
400400

401-
return $this->buildTicketReference($fields, $url);
401+
return $this->buildTicketReference($fields, $url, $class);
402402
} catch (\Exception $e) {
403403
$this->logger->error('Error getting iTop ticket reference: ' . $e->getMessage(), ['app' => Application::APP_ID]);
404404
return null;
@@ -619,7 +619,7 @@ private function formatCIDescription(array $ci): string {
619619
* @param string $url Original iTop URL
620620
* @return IReference
621621
*/
622-
private function buildTicketReference(array $fields, string $url): IReference {
622+
private function buildTicketReference(array $fields, string $url, string $class = ''): IReference {
623623
// Get iTop URL for building links
624624
$adminItopUrl = $this->config->getAppValue(Application::APP_ID, 'admin_instance_url', '');
625625
$userItopUrl = $this->config->getUserValue($this->userId, Application::APP_ID, 'url', '');
@@ -636,6 +636,7 @@ private function buildTicketReference(array $fields, string $url): IReference {
636636
$reference->setRichObject(
637637
self::RICH_OBJECT_TYPE,
638638
[
639+
'class' => $class,
639640
'title' => $fields['title'] ?? '',
640641
'ref' => $fields['ref'] ?? '',
641642
'status' => $fields['status'] ?? '',

src/views/ReferenceItopWidget.vue

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,31 +220,51 @@ export default {
220220
return null
221221
},
222222
ticketIcon() {
223-
const objectClass = this.richObject.class || ''
223+
// Determine class robustly: explicit rich object, URL param, or ref prefix
224+
const explicitClass = this.richObject.class || ''
225+
const fromUrl = this.getClassFromUrl(this.richObject.url)
226+
const fromRef = this.getClassFromRef(this.richObject.ref)
227+
const objectClass = explicitClass || fromUrl || fromRef || ''
224228
const status = this.richObject.status?.toLowerCase() || ''
225-
const isClosed = status.includes('resolved') || status.includes('closed')
229+
const closeDate = this.richObject.close_date || ''
230+
const priority = this.richObject.priority || ''
226231
227232
// Use direct path without generateUrl to avoid /index.php/ prefix
228233
const basePath = window.location.origin + '/apps/integration_itop/img/'
229234
230235
if (this.isCI) {
231-
// CI icons
236+
// CI icons only; do not mix with ticket fallbacks
232237
const iconFile = this.richObject.icon || 'ci-default.svg'
233238
return basePath + iconFile
234239
}
235240
236-
// Ticket icons
237-
if (objectClass === 'Incident') {
238-
return basePath + 'incident.svg'
241+
// If we cannot determine ticket class at all, use a generic ticket icon
242+
if (!objectClass) {
243+
return basePath + 'ticket.svg'
239244
}
240-
if (objectClass === 'UserRequest') {
241-
if (isClosed) {
242-
return basePath + 'user-request-closed.svg'
243-
}
244-
return basePath + 'user-request.svg'
245+
246+
// Ticket icons with state-specific logic matching SearchProvider
247+
let iconName = ''
248+
const ticketType = objectClass.toLowerCase()
249+
250+
// Check for closed state first (based on close_date)
251+
if (closeDate) {
252+
iconName = ticketType + '-closed.svg'
253+
} else if (priority && !isNaN(priority) && parseInt(priority) <= 2) {
254+
// Check for escalated state (high priority: 1 or 2)
255+
iconName = ticketType + '-escalated.svg'
256+
} else if (status.includes('pending') || status.includes('waiting')) {
257+
// Check for deadline state (pending/waiting status)
258+
iconName = ticketType + '-deadline.svg'
259+
} else {
260+
// Default icon for the ticket type
261+
iconName = ticketType + '.svg'
245262
}
246-
// Default fallback
247-
return basePath + 'ticket.svg'
263+
264+
// Convert class names to match icon filenames
265+
iconName = iconName.replace('userrequest', 'user-request')
266+
267+
return basePath + iconName
248268
},
249269
statusColor() {
250270
const status = this.richObject.status?.toLowerCase() || ''
@@ -387,6 +407,23 @@ export default {
387407
}
388408
return iconMap[iconName] || ''
389409
},
410+
getClassFromUrl(url) {
411+
try {
412+
if (!url) return ''
413+
const u = new URL(url)
414+
const cls = u.searchParams.get('class')
415+
return cls || ''
416+
} catch (e) {
417+
return ''
418+
}
419+
},
420+
getClassFromRef(ref) {
421+
if (!ref || typeof ref !== 'string') return ''
422+
const r = ref.toUpperCase()
423+
if (r.startsWith('I-')) return 'Incident'
424+
if (r.startsWith('R-')) return 'UserRequest'
425+
return ''
426+
},
390427
},
391428
}
392429
</script>

0 commit comments

Comments
 (0)