web-mojo 2.1.219 → 2.1.265
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +261 -59
- package/dist/admin.es.js.map +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.cjs.js.map +1 -1
- package/dist/auth.es.js +3 -3
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +2 -2
- package/dist/chunks/{ContextMenu-DjS0WgXA.js → ContextMenu-BqYO9pWG.js} +2 -2
- package/dist/chunks/{ContextMenu-DjS0WgXA.js.map → ContextMenu-BqYO9pWG.js.map} +1 -1
- package/dist/chunks/{ContextMenu-BGstYX-N.js → ContextMenu-CsMXWcoQ.js} +2 -2
- package/dist/chunks/{ContextMenu-BGstYX-N.js.map → ContextMenu-CsMXWcoQ.js.map} +1 -1
- package/dist/chunks/{DataView-Dmobu7T8.js → DataView-Cy9OMdVA.js} +2 -2
- package/dist/chunks/{DataView-Dmobu7T8.js.map → DataView-Cy9OMdVA.js.map} +1 -1
- package/dist/chunks/{DataView-LCk00Xma.js → DataView-Di2F5dQR.js} +2 -2
- package/dist/chunks/{DataView-LCk00Xma.js.map → DataView-Di2F5dQR.js.map} +1 -1
- package/dist/chunks/Dialog-BIOrX51Q.js +2 -0
- package/dist/chunks/Dialog-BIOrX51Q.js.map +1 -0
- package/dist/chunks/{Dialog-Bu9EGh-z.js → Dialog-ia-mdhjA.js} +41 -34
- package/dist/chunks/Dialog-ia-mdhjA.js.map +1 -0
- package/dist/chunks/{FilePreviewView-C-VswdQl.js → FilePreviewView-BsV1ur-F.js} +9 -6
- package/dist/chunks/FilePreviewView-BsV1ur-F.js.map +1 -0
- package/dist/chunks/FilePreviewView-C550ZqA1.js +2 -0
- package/dist/chunks/FilePreviewView-C550ZqA1.js.map +1 -0
- package/dist/chunks/{FormView-DWV5Lhc3.js → FormView-BxKY1Pua.js} +2 -2
- package/dist/chunks/{FormView-DWV5Lhc3.js.map → FormView-BxKY1Pua.js.map} +1 -1
- package/dist/chunks/{FormView-DhZi_-D_.js → FormView-Ieig2Ikt.js} +2 -2
- package/dist/chunks/{FormView-DhZi_-D_.js.map → FormView-Ieig2Ikt.js.map} +1 -1
- package/dist/chunks/{MetricsChart-CHQmuqGa.js → MetricsChart-BDhDGz4E.js} +2 -2
- package/dist/chunks/{MetricsChart-CHQmuqGa.js.map → MetricsChart-BDhDGz4E.js.map} +1 -1
- package/dist/chunks/{MetricsChart-BOSgjGoW.js → MetricsChart-Ch8QKUkf.js} +14 -8
- package/dist/chunks/{MetricsChart-BOSgjGoW.js.map → MetricsChart-Ch8QKUkf.js.map} +1 -1
- package/dist/chunks/{PDFViewer-C7_03lr6.js → PDFViewer-CzjtNiNr.js} +3 -3
- package/dist/chunks/{PDFViewer-C7_03lr6.js.map → PDFViewer-CzjtNiNr.js.map} +1 -1
- package/dist/chunks/{PDFViewer-CTQ_WArl.js → PDFViewer-DANtnv28.js} +2 -2
- package/dist/chunks/{PDFViewer-CTQ_WArl.js.map → PDFViewer-DANtnv28.js.map} +1 -1
- package/dist/chunks/{Page-7mRcLFeD.js → Page-BXT4XGsW.js} +2 -2
- package/dist/chunks/{Page-7mRcLFeD.js.map → Page-BXT4XGsW.js.map} +1 -1
- package/dist/chunks/{Page-CG1u27-d.js → Page-D-s2pJ4R.js} +2 -2
- package/dist/chunks/{Page-CG1u27-d.js.map → Page-D-s2pJ4R.js.map} +1 -1
- package/dist/chunks/{TopNav-CF1Ic6Ty.js → TopNav-E_ZvzFaL.js} +2 -2
- package/dist/chunks/{TopNav-CF1Ic6Ty.js.map → TopNav-E_ZvzFaL.js.map} +1 -1
- package/dist/chunks/{TopNav-CprY7p9c.js → TopNav-WEv4D1Jr.js} +2 -2
- package/dist/chunks/{TopNav-CprY7p9c.js.map → TopNav-WEv4D1Jr.js.map} +1 -1
- package/dist/chunks/{User-CgSxo-iW.js → User-BH8gosuT.js} +4 -2
- package/dist/chunks/{User-CgSxo-iW.js.map → User-BH8gosuT.js.map} +1 -1
- package/dist/chunks/{User-DPWffTVQ.js → User-CHIu2dzX.js} +2 -2
- package/dist/chunks/User-CHIu2dzX.js.map +1 -0
- package/dist/chunks/WebApp-AQ6Px5yi.js +2 -0
- package/dist/chunks/WebApp-AQ6Px5yi.js.map +1 -0
- package/dist/chunks/{WebApp-DDt4Ihy7.js → WebApp-Dr-gVl9H.js} +23 -12
- package/dist/chunks/WebApp-Dr-gVl9H.js.map +1 -0
- package/dist/css/web-mojo.css +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +6 -6
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +11 -11
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +4 -4
- package/dist/table.css +1 -8
- package/package.json +1 -1
- package/dist/chunks/Dialog-Bu9EGh-z.js.map +0 -1
- package/dist/chunks/Dialog-CxJjXDJ-.js +0 -2
- package/dist/chunks/Dialog-CxJjXDJ-.js.map +0 -1
- package/dist/chunks/FilePreviewView-C-VswdQl.js.map +0 -1
- package/dist/chunks/FilePreviewView-CxT-vXFS.js +0 -2
- package/dist/chunks/FilePreviewView-CxT-vXFS.js.map +0 -1
- package/dist/chunks/User-DPWffTVQ.js.map +0 -1
- package/dist/chunks/WebApp-D35UJNMm.js +0 -2
- package/dist/chunks/WebApp-D35UJNMm.js.map +0 -1
- package/dist/chunks/WebApp-DDt4Ihy7.js.map +0 -1
package/dist/admin.es.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { P as Page } from "./chunks/Page-
|
|
2
|
-
import { V as View, h as MOJOUtils } from "./chunks/WebApp-
|
|
3
|
-
import { B, b, a, c, e, f, W } from "./chunks/WebApp-
|
|
4
|
-
import Dialog$1 from "./chunks/Dialog-
|
|
5
|
-
import { M as MetricsChart, P as PieChart } from "./chunks/MetricsChart-
|
|
6
|
-
import { b as TablePage, i as EmailDomainForms, h as EmailDomainList, E as EmailDomain, l as MailboxForms, k as MailboxList, j as Mailbox, p as EmailTemplate, d as TabView, r as EmailTemplateForms, q as EmailTemplateList, I as IncidentEvent, z as IncidentEventForms, y as IncidentEventList, u as FileManagerForms, t as FileManagerList, v as File, T as TableView, x as FileForms, w as FileList, am as GeoLocatedIP, an as GeoLocatedIPList, a7 as MemberList, a6 as LogList, ap as TicketList, B as IncidentList, V as IncidentStats, N as IncidentHistoryList, K as IncidentHistory, F as FilePreviewView, A as Incident, C as IncidentForms, W as Job, a0 as JobEventList, _ as JobLogList, Y as JobForms, X as JobList, a3 as JobRunnerList, a1 as JobsEngineStats, a4 as JobRunnerForms, a2 as JobRunner, a5 as Log, M as Member, a8 as MemberForms, a9 as MetricsPermission, ab as MetricsForms, aa as MetricsPermissionList, ak as PushConfigForms, ah as PushConfigList, aj as PushDeliveryList, ad as PushDeviceList, al as PushTemplateForms, af as PushTemplateList, R as RuleSet, U as RuleList, O as RuleSetList, g as S3BucketForms, f as S3BucketList, m as SentMessage, n as SentMessageList, ar as TicketNoteList, aq as TicketNote, ao as Ticket, as as TicketForms } from "./chunks/FilePreviewView-
|
|
7
|
-
import DataView from "./chunks/DataView-
|
|
8
|
-
import { C as ContextMenu } from "./chunks/ContextMenu-
|
|
9
|
-
import { C as Collection, a as Group, G as GroupList, b as GroupForms, f as UserDevice, i as UserDeviceLocationList, g as UserDeviceList, U as User, e as UserDataView, d as UserForms, c as UserList } from "./chunks/User-
|
|
10
|
-
import { L as LightboxGallery, P as PDFViewer } from "./chunks/PDFViewer-
|
|
11
|
-
import { a as applyFileDropMixin } from "./chunks/FormView-
|
|
1
|
+
import { P as Page } from "./chunks/Page-BXT4XGsW.js";
|
|
2
|
+
import { V as View, h as MOJOUtils } from "./chunks/WebApp-Dr-gVl9H.js";
|
|
3
|
+
import { B, b, a, c, e, f, W } from "./chunks/WebApp-Dr-gVl9H.js";
|
|
4
|
+
import Dialog$1 from "./chunks/Dialog-ia-mdhjA.js";
|
|
5
|
+
import { M as MetricsChart, P as PieChart } from "./chunks/MetricsChart-Ch8QKUkf.js";
|
|
6
|
+
import { b as TablePage, i as EmailDomainForms, h as EmailDomainList, E as EmailDomain, l as MailboxForms, k as MailboxList, j as Mailbox, p as EmailTemplate, d as TabView, r as EmailTemplateForms, q as EmailTemplateList, I as IncidentEvent, z as IncidentEventForms, y as IncidentEventList, u as FileManagerForms, t as FileManagerList, v as File, T as TableView, x as FileForms, w as FileList, am as GeoLocatedIP, an as GeoLocatedIPList, a7 as MemberList, a6 as LogList, ap as TicketList, B as IncidentList, V as IncidentStats, N as IncidentHistoryList, K as IncidentHistory, F as FilePreviewView, A as Incident, C as IncidentForms, W as Job, a0 as JobEventList, _ as JobLogList, Y as JobForms, X as JobList, a3 as JobRunnerList, a1 as JobsEngineStats, a4 as JobRunnerForms, a2 as JobRunner, a5 as Log, M as Member, a8 as MemberForms, a9 as MetricsPermission, ab as MetricsForms, aa as MetricsPermissionList, ak as PushConfigForms, ah as PushConfigList, aj as PushDeliveryList, ad as PushDeviceList, al as PushTemplateForms, af as PushTemplateList, R as RuleSet, U as RuleList, O as RuleSetList, g as S3BucketForms, f as S3BucketList, m as SentMessage, n as SentMessageList, ar as TicketNoteList, aq as TicketNote, ao as Ticket, as as TicketForms } from "./chunks/FilePreviewView-BsV1ur-F.js";
|
|
7
|
+
import DataView from "./chunks/DataView-Cy9OMdVA.js";
|
|
8
|
+
import { C as ContextMenu } from "./chunks/ContextMenu-BqYO9pWG.js";
|
|
9
|
+
import { C as Collection, a as Group, G as GroupList, b as GroupForms, f as UserDevice, i as UserDeviceLocationList, g as UserDeviceList, U as User, e as UserDataView, d as UserForms, c as UserList } from "./chunks/User-BH8gosuT.js";
|
|
10
|
+
import { L as LightboxGallery, P as PDFViewer } from "./chunks/PDFViewer-CzjtNiNr.js";
|
|
11
|
+
import { a as applyFileDropMixin } from "./chunks/FormView-Ieig2Ikt.js";
|
|
12
12
|
class AdminHeaderView extends View {
|
|
13
13
|
constructor(options = {}) {
|
|
14
14
|
super({
|
|
@@ -2169,6 +2169,7 @@ class ChatInputView extends View {
|
|
|
2169
2169
|
...options
|
|
2170
2170
|
});
|
|
2171
2171
|
this.uploads = [];
|
|
2172
|
+
this.buttonText = options.buttonText || "Send";
|
|
2172
2173
|
}
|
|
2173
2174
|
getTemplate() {
|
|
2174
2175
|
return `
|
|
@@ -2176,7 +2177,7 @@ class ChatInputView extends View {
|
|
|
2176
2177
|
<textarea class="form-control" placeholder="Type a message..." rows="3"></textarea>
|
|
2177
2178
|
<div class="d-flex justify-content-between align-items-center mt-2">
|
|
2178
2179
|
<small class="text-muted">Drag & drop files to attach.</small>
|
|
2179
|
-
<button class="btn btn-primary" data-action="send-message"
|
|
2180
|
+
<button class="btn btn-primary" data-action="send-message">${this.buttonText}</button>
|
|
2180
2181
|
</div>
|
|
2181
2182
|
<div class="uploads-container mt-2"></div>
|
|
2182
2183
|
</div>
|
|
@@ -2218,6 +2219,7 @@ class ChatView extends View {
|
|
|
2218
2219
|
});
|
|
2219
2220
|
this.adapter = options.adapter;
|
|
2220
2221
|
this.items = [];
|
|
2222
|
+
this.inputButtonText = options.inputButtonText || "Send";
|
|
2221
2223
|
}
|
|
2222
2224
|
getTemplate() {
|
|
2223
2225
|
return `
|
|
@@ -2236,14 +2238,16 @@ class ChatView extends View {
|
|
|
2236
2238
|
messageView.render(true, historyContainer);
|
|
2237
2239
|
});
|
|
2238
2240
|
const inputContainer = this.element.querySelector(".chat-input-container");
|
|
2239
|
-
this.inputView
|
|
2240
|
-
|
|
2241
|
+
if (!this.inputView) {
|
|
2242
|
+
this.inputView = new ChatInputView({ buttonText: this.inputButtonText });
|
|
2243
|
+
this.addChild(this.inputView);
|
|
2244
|
+
this.inputView.on("note:submit", async (data) => {
|
|
2245
|
+
await this.adapter.addNote(data);
|
|
2246
|
+
this.items = await this.adapter.fetch();
|
|
2247
|
+
this.render();
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2241
2250
|
this.inputView.render(true, inputContainer);
|
|
2242
|
-
this.inputView.on("note:submit", async (data) => {
|
|
2243
|
-
await this.adapter.addNote(data);
|
|
2244
|
-
this.items = await this.adapter.fetch();
|
|
2245
|
-
this.render();
|
|
2246
|
-
});
|
|
2247
2251
|
}
|
|
2248
2252
|
}
|
|
2249
2253
|
class IncidentView extends View {
|
|
@@ -2472,7 +2476,7 @@ class JobStatsView extends View {
|
|
|
2472
2476
|
<div class="job-stats-header mb-4">
|
|
2473
2477
|
<div class="row">
|
|
2474
2478
|
<div class="col-xl-2 col-lg-4 col-md-6 col-12 mb-3">
|
|
2475
|
-
<div class="card h-100 border-0 shadow
|
|
2479
|
+
<div class="card h-100 border-0 shadow">
|
|
2476
2480
|
<div class="card-body">
|
|
2477
2481
|
<div class="d-flex justify-content-between align-items-start">
|
|
2478
2482
|
<div>
|
|
@@ -2491,7 +2495,7 @@ class JobStatsView extends View {
|
|
|
2491
2495
|
</div>
|
|
2492
2496
|
|
|
2493
2497
|
<div class="col-xl-2 col-lg-4 col-md-6 col-12 mb-3">
|
|
2494
|
-
<div class="card h-100 border-0 shadow
|
|
2498
|
+
<div class="card h-100 border-0 shadow">
|
|
2495
2499
|
<div class="card-body">
|
|
2496
2500
|
<div class="d-flex justify-content-between align-items-start">
|
|
2497
2501
|
<div>
|
|
@@ -2510,7 +2514,7 @@ class JobStatsView extends View {
|
|
|
2510
2514
|
</div>
|
|
2511
2515
|
|
|
2512
2516
|
<div class="col-xl-2 col-lg-4 col-md-6 col-12 mb-3">
|
|
2513
|
-
<div class="card h-100 border-0 shadow
|
|
2517
|
+
<div class="card h-100 border-0 shadow">
|
|
2514
2518
|
<div class="card-body">
|
|
2515
2519
|
<div class="d-flex justify-content-between align-items-start">
|
|
2516
2520
|
<div>
|
|
@@ -2529,7 +2533,7 @@ class JobStatsView extends View {
|
|
|
2529
2533
|
</div>
|
|
2530
2534
|
|
|
2531
2535
|
<div class="col-xl-3 col-lg-6 col-md-6 col-12 mb-3">
|
|
2532
|
-
<div class="card h-100 border-0 shadow
|
|
2536
|
+
<div class="card h-100 border-0 shadow">
|
|
2533
2537
|
<div class="card-body">
|
|
2534
2538
|
<div class="d-flex justify-content-between align-items-start">
|
|
2535
2539
|
<div>
|
|
@@ -2548,7 +2552,7 @@ class JobStatsView extends View {
|
|
|
2548
2552
|
</div>
|
|
2549
2553
|
|
|
2550
2554
|
<div class="col-xl-3 col-lg-6 col-md-6 col-12 mb-3">
|
|
2551
|
-
<div class="card h-100 border-0 shadow
|
|
2555
|
+
<div class="card h-100 border-0 shadow">
|
|
2552
2556
|
<div class="card-body">
|
|
2553
2557
|
<div class="d-flex justify-content-between align-items-start">
|
|
2554
2558
|
<div>
|
|
@@ -2592,7 +2596,7 @@ class JobHealthView extends View {
|
|
|
2592
2596
|
};
|
|
2593
2597
|
this.template = `
|
|
2594
2598
|
<div class="job-health-header mb-4">
|
|
2595
|
-
<div class="card border-0 shadow
|
|
2599
|
+
<div class="card border-0 shadow">
|
|
2596
2600
|
<div class="card-body">
|
|
2597
2601
|
<div class="row align-items-center">
|
|
2598
2602
|
<div class="col-md-6">
|
|
@@ -3082,7 +3086,6 @@ class JobsTable extends TableView {
|
|
|
3082
3086
|
super({
|
|
3083
3087
|
Collection: JobList,
|
|
3084
3088
|
collectionParams: {
|
|
3085
|
-
start: 0,
|
|
3086
3089
|
size: 15,
|
|
3087
3090
|
sort: "-created"
|
|
3088
3091
|
},
|
|
@@ -3581,10 +3584,17 @@ class JobsAdminPage extends Page {
|
|
|
3581
3584
|
<div data-container="job-stats"></div>
|
|
3582
3585
|
|
|
3583
3586
|
<!-- Job Health -->
|
|
3584
|
-
<div
|
|
3587
|
+
<div class="row">
|
|
3588
|
+
<div class="col-12">
|
|
3589
|
+
<div data-container="job-health"></div>
|
|
3590
|
+
</div>
|
|
3591
|
+
<div class="col-12">
|
|
3592
|
+
<div class="mb-3" data-container="job-metrics"></div>
|
|
3593
|
+
</div>
|
|
3594
|
+
</div>
|
|
3585
3595
|
|
|
3586
3596
|
<!-- Job Tables -->
|
|
3587
|
-
<div class="card border shadow
|
|
3597
|
+
<div class="card border shadow">
|
|
3588
3598
|
<div class="card-header">
|
|
3589
3599
|
<h5 class="card-title mb-0">
|
|
3590
3600
|
<i class="bi bi-list-task me-2"></i>Job Management
|
|
@@ -3619,6 +3629,25 @@ class JobsAdminPage extends Page {
|
|
|
3619
3629
|
activeTab: "Jobs"
|
|
3620
3630
|
});
|
|
3621
3631
|
this.addChild(this.jobTablesView);
|
|
3632
|
+
this.jobMetricsChart = new MetricsChart({
|
|
3633
|
+
title: `<i class="bi bi-graph-up me-2"></i> Job Metrics`,
|
|
3634
|
+
endpoint: "/api/metrics/fetch",
|
|
3635
|
+
height: 100,
|
|
3636
|
+
granularity: "hours",
|
|
3637
|
+
category: "jobs_channels",
|
|
3638
|
+
account: "global",
|
|
3639
|
+
chartType: "bar",
|
|
3640
|
+
showDateRange: false,
|
|
3641
|
+
yAxis: {
|
|
3642
|
+
label: "Count",
|
|
3643
|
+
beginAtZero: true
|
|
3644
|
+
},
|
|
3645
|
+
tooltip: {
|
|
3646
|
+
y: "number"
|
|
3647
|
+
},
|
|
3648
|
+
containerId: "job-metrics"
|
|
3649
|
+
});
|
|
3650
|
+
this.addChild(this.jobMetricsChart);
|
|
3622
3651
|
await this.jobStats.fetch();
|
|
3623
3652
|
}
|
|
3624
3653
|
// Auto-refresh management
|
|
@@ -6887,8 +6916,8 @@ class TicketNoteAdapter {
|
|
|
6887
6916
|
type: "user_comment",
|
|
6888
6917
|
// Ticket notes are always user comments
|
|
6889
6918
|
author: {
|
|
6890
|
-
name: note.get("
|
|
6891
|
-
avatarUrl: note.get("
|
|
6919
|
+
name: note.get("user.display_name") || "System",
|
|
6920
|
+
avatarUrl: note.get("user.avatar.url")
|
|
6892
6921
|
},
|
|
6893
6922
|
timestamp: note.get("created"),
|
|
6894
6923
|
content: note.get("note"),
|
|
@@ -6896,12 +6925,12 @@ class TicketNoteAdapter {
|
|
|
6896
6925
|
};
|
|
6897
6926
|
}
|
|
6898
6927
|
async addNote(data) {
|
|
6899
|
-
const note = new TicketNote(
|
|
6900
|
-
|
|
6928
|
+
const note = new TicketNote();
|
|
6929
|
+
const resp = await note.save({
|
|
6930
|
+
parent: this.ticketId,
|
|
6901
6931
|
note: data.text,
|
|
6902
6932
|
media: data.files && data.files.length > 0 ? data.files[0].id : null
|
|
6903
6933
|
});
|
|
6904
|
-
const resp = await note.save();
|
|
6905
6934
|
if (resp.success) {
|
|
6906
6935
|
await this.collection.fetch();
|
|
6907
6936
|
}
|
|
@@ -6916,31 +6945,79 @@ class TicketView extends View {
|
|
|
6916
6945
|
});
|
|
6917
6946
|
this.model = options.model || new Ticket(options.data || {});
|
|
6918
6947
|
this.template = `
|
|
6919
|
-
<div class="ticket-view-container
|
|
6920
|
-
<!-- Header -->
|
|
6921
|
-
<div class="d-flex justify-content-between align-items-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
<
|
|
6925
|
-
|
|
6948
|
+
<div class="ticket-view-container">
|
|
6949
|
+
<!-- Ticket Header -->
|
|
6950
|
+
<div class="d-flex justify-content-between align-items-start mb-4">
|
|
6951
|
+
<!-- Left Side: Primary Identity -->
|
|
6952
|
+
<div class="d-flex align-items-center gap-3">
|
|
6953
|
+
<div class="avatar-placeholder rounded-circle bg-light d-flex align-items-center justify-content-center" style="width: 80px; height: 80px;">
|
|
6954
|
+
<i class="bi bi-ticket-perforated text-secondary" style="font-size: 40px;"></i>
|
|
6955
|
+
</div>
|
|
6956
|
+
<div>
|
|
6957
|
+
<h3 class="mb-1">{{model.title|truncate(50)|default('Untitled Ticket')}}</h3>
|
|
6958
|
+
<div class="text-muted small">
|
|
6959
|
+
<span>Ticket #{{model.id}}</span>
|
|
6960
|
+
<span class="mx-2">|</span>
|
|
6961
|
+
<span>Priority: {{model.priority|capitalize}}</span>
|
|
6962
|
+
{{#model.assignee}}
|
|
6963
|
+
<span class="mx-2">|</span>
|
|
6964
|
+
<span>Assigned to: {{model.assignee.display_name}}</span>
|
|
6965
|
+
{{/model.assignee}}
|
|
6966
|
+
</div>
|
|
6967
|
+
{{#model.incident}}
|
|
6968
|
+
<div class="text-muted small mt-1">
|
|
6969
|
+
<i class="bi bi-exclamation-triangle"></i> Related to incident: {{model.incident}}
|
|
6970
|
+
</div>
|
|
6971
|
+
{{/model.incident}}
|
|
6972
|
+
</div>
|
|
6926
6973
|
</div>
|
|
6927
|
-
<div data-container="ticket-context-menu"></div>
|
|
6928
|
-
</div>
|
|
6929
6974
|
|
|
6930
|
-
|
|
6931
|
-
<div class="
|
|
6932
|
-
<
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6975
|
+
<!-- Right Side: Status & Actions -->
|
|
6976
|
+
<div class="d-flex align-items-start gap-4">
|
|
6977
|
+
<div class="text-end">
|
|
6978
|
+
<div class="d-flex align-items-center gap-2">
|
|
6979
|
+
<span class="badge {{model.status|badgeClass}}">{{model.status|capitalize}}</span>
|
|
6980
|
+
</div>
|
|
6981
|
+
{{#model.created}}
|
|
6982
|
+
<div class="text-muted small mt-1">Created {{model.created|relative}}</div>
|
|
6983
|
+
{{/model.created}}
|
|
6984
|
+
{{#model.modified}}
|
|
6985
|
+
<div class="text-muted small">Updated {{model.modified|relative}}</div>
|
|
6986
|
+
{{/model.modified}}
|
|
6987
|
+
</div>
|
|
6988
|
+
<div data-container="ticket-context-menu"></div>
|
|
6938
6989
|
</div>
|
|
6939
6990
|
</div>
|
|
6991
|
+
|
|
6992
|
+
<!-- Content Area -->
|
|
6940
6993
|
<div class="row">
|
|
6941
|
-
<div class="col-
|
|
6942
|
-
|
|
6943
|
-
<div
|
|
6994
|
+
<div class="col-lg-8">
|
|
6995
|
+
<!-- Description Section -->
|
|
6996
|
+
<div class="mb-4">
|
|
6997
|
+
<h5 class="border-bottom pb-2 mb-3">Description</h5>
|
|
6998
|
+
<div class="border rounded p-3 bg-light">
|
|
6999
|
+
{{#model.description}}
|
|
7000
|
+
{{{model.description}}}
|
|
7001
|
+
{{/model.description}}
|
|
7002
|
+
{{^model.description}}
|
|
7003
|
+
<em class="text-muted">No description provided</em>
|
|
7004
|
+
{{/model.description}}
|
|
7005
|
+
</div>
|
|
7006
|
+
</div>
|
|
7007
|
+
|
|
7008
|
+
<!-- Activity & Notes Section -->
|
|
7009
|
+
<div>
|
|
7010
|
+
<h5 class="border-bottom pb-2 mb-3">Activity & Notes</h5>
|
|
7011
|
+
<div data-container="chat-view"></div>
|
|
7012
|
+
</div>
|
|
7013
|
+
</div>
|
|
7014
|
+
|
|
7015
|
+
<div class="col-lg-4">
|
|
7016
|
+
<!-- Details Sidebar -->
|
|
7017
|
+
<div class="border rounded p-3 bg-light">
|
|
7018
|
+
<h5 class="mb-3">Ticket Details</h5>
|
|
7019
|
+
<div data-container="details-view"></div>
|
|
7020
|
+
</div>
|
|
6944
7021
|
</div>
|
|
6945
7022
|
</div>
|
|
6946
7023
|
</div>
|
|
@@ -6961,29 +7038,153 @@ class TicketView extends View {
|
|
|
6961
7038
|
const adapter = new TicketNoteAdapter(this.model.get("id"));
|
|
6962
7039
|
this.chatView = new ChatView({
|
|
6963
7040
|
containerId: "chat-view",
|
|
6964
|
-
adapter
|
|
7041
|
+
adapter,
|
|
7042
|
+
inputButtonText: "Add Note"
|
|
6965
7043
|
});
|
|
6966
7044
|
this.addChild(this.chatView);
|
|
6967
|
-
const
|
|
7045
|
+
const ticketMenu = new ContextMenu({
|
|
6968
7046
|
containerId: "ticket-context-menu",
|
|
7047
|
+
className: "context-menu-view header-menu-absolute",
|
|
6969
7048
|
context: this.model,
|
|
6970
7049
|
config: {
|
|
6971
7050
|
icon: "bi-three-dots-vertical",
|
|
6972
7051
|
items: [
|
|
7052
|
+
{ label: "Edit Ticket", action: "edit-ticket", icon: "bi-pencil" },
|
|
6973
7053
|
{ label: "Change Status", action: "change-status", icon: "bi-tag" },
|
|
6974
7054
|
{ label: "Set Priority", action: "set-priority", icon: "bi-flag" },
|
|
6975
|
-
{ label: "Assign User", action: "assign-user", icon: "bi-person" }
|
|
7055
|
+
{ label: "Assign User", action: "assign-user", icon: "bi-person" },
|
|
7056
|
+
{ type: "divider" },
|
|
7057
|
+
{ label: "Close Ticket", action: "close-ticket", icon: "bi-x-circle" }
|
|
6976
7058
|
]
|
|
6977
7059
|
}
|
|
6978
7060
|
});
|
|
6979
|
-
this.addChild(
|
|
7061
|
+
this.addChild(ticketMenu);
|
|
7062
|
+
}
|
|
7063
|
+
// Context Menu Action Handlers
|
|
7064
|
+
async onActionEditTicket() {
|
|
7065
|
+
const resp = await Dialog$1.showModelForm({
|
|
7066
|
+
title: `Edit Ticket #${this.model.get("id")} - ${this.model.get("title")}`,
|
|
7067
|
+
model: this.model,
|
|
7068
|
+
size: "lg",
|
|
7069
|
+
fields: [
|
|
7070
|
+
{ name: "title", label: "Title", type: "text", required: true },
|
|
7071
|
+
{ name: "description", label: "Description", type: "textarea", rows: 4 },
|
|
7072
|
+
{
|
|
7073
|
+
name: "status",
|
|
7074
|
+
label: "Status",
|
|
7075
|
+
type: "select",
|
|
7076
|
+
options: ["open", "in_progress", "pending", "resolved", "closed"]
|
|
7077
|
+
},
|
|
7078
|
+
{
|
|
7079
|
+
name: "priority",
|
|
7080
|
+
label: "Priority",
|
|
7081
|
+
type: "select",
|
|
7082
|
+
options: ["low", "normal", "high", "urgent"]
|
|
7083
|
+
},
|
|
7084
|
+
{ name: "assignee_id", label: "Assignee", type: "user_select" }
|
|
7085
|
+
]
|
|
7086
|
+
});
|
|
7087
|
+
if (resp) {
|
|
7088
|
+
this.render();
|
|
7089
|
+
}
|
|
7090
|
+
}
|
|
7091
|
+
async onActionChangeStatus() {
|
|
7092
|
+
const statuses = ["new", "open", "in_progress", "pending", "resolved", "closed", "ignored"];
|
|
7093
|
+
const currentStatus = this.model.get("status");
|
|
7094
|
+
const result = await Dialog$1.showForm({
|
|
7095
|
+
title: "Change Ticket Status",
|
|
7096
|
+
size: "sm",
|
|
7097
|
+
fields: [
|
|
7098
|
+
{
|
|
7099
|
+
name: "status",
|
|
7100
|
+
label: "New Status",
|
|
7101
|
+
type: "select",
|
|
7102
|
+
options: statuses.map((s) => ({ value: s, label: s.replace("_", " ").toUpperCase() })),
|
|
7103
|
+
value: currentStatus,
|
|
7104
|
+
required: true
|
|
7105
|
+
}
|
|
7106
|
+
]
|
|
7107
|
+
});
|
|
7108
|
+
if (result) {
|
|
7109
|
+
try {
|
|
7110
|
+
await this.model.save({ status: result.status });
|
|
7111
|
+
this.render();
|
|
7112
|
+
} catch (error) {
|
|
7113
|
+
Dialog$1.alert({
|
|
7114
|
+
type: "error",
|
|
7115
|
+
title: "Error",
|
|
7116
|
+
message: "Failed to update ticket status: " + error.message
|
|
7117
|
+
});
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
}
|
|
7121
|
+
async onActionSetPriority() {
|
|
7122
|
+
const priorities = ["low", "normal", "high", "urgent"];
|
|
7123
|
+
const currentPriority = this.model.get("priority");
|
|
7124
|
+
const result = await Dialog$1.showForm({
|
|
7125
|
+
title: "Set Ticket Priority",
|
|
7126
|
+
size: "sm",
|
|
7127
|
+
fields: [
|
|
7128
|
+
{
|
|
7129
|
+
name: "priority",
|
|
7130
|
+
label: "Priority Level",
|
|
7131
|
+
type: "select",
|
|
7132
|
+
options: priorities.map((p) => ({ value: p, label: p.toUpperCase() })),
|
|
7133
|
+
value: currentPriority,
|
|
7134
|
+
required: true
|
|
7135
|
+
}
|
|
7136
|
+
]
|
|
7137
|
+
});
|
|
7138
|
+
if (result) {
|
|
7139
|
+
try {
|
|
7140
|
+
await this.model.save({ priority: result.priority });
|
|
7141
|
+
this.render();
|
|
7142
|
+
} catch (error) {
|
|
7143
|
+
Dialog$1.alert({
|
|
7144
|
+
type: "error",
|
|
7145
|
+
title: "Error",
|
|
7146
|
+
message: "Failed to update ticket priority: " + error.message
|
|
7147
|
+
});
|
|
7148
|
+
}
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
async onActionAssignUser() {
|
|
7152
|
+
console.log("TODO: Implement assign user dialog with user selector");
|
|
7153
|
+
Dialog$1.alert({
|
|
7154
|
+
title: "Coming Soon",
|
|
7155
|
+
message: "User assignment feature will be implemented soon."
|
|
7156
|
+
});
|
|
7157
|
+
}
|
|
7158
|
+
async onActionCloseTicket() {
|
|
7159
|
+
const confirmed = await Dialog$1.confirm({
|
|
7160
|
+
title: "Close Ticket",
|
|
7161
|
+
message: `Are you sure you want to close ticket #${this.model.get("id")}?`,
|
|
7162
|
+
confirmText: "Close Ticket",
|
|
7163
|
+
confirmClass: "btn-warning"
|
|
7164
|
+
});
|
|
7165
|
+
if (confirmed) {
|
|
7166
|
+
try {
|
|
7167
|
+
await this.model.save({ status: "closed" });
|
|
7168
|
+
this.render();
|
|
7169
|
+
Dialog$1.alert({
|
|
7170
|
+
type: "success",
|
|
7171
|
+
title: "Success",
|
|
7172
|
+
message: "Ticket has been closed successfully."
|
|
7173
|
+
});
|
|
7174
|
+
} catch (error) {
|
|
7175
|
+
Dialog$1.alert({
|
|
7176
|
+
type: "error",
|
|
7177
|
+
title: "Error",
|
|
7178
|
+
message: "Failed to close ticket: " + error.message
|
|
7179
|
+
});
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
6980
7182
|
}
|
|
6981
7183
|
}
|
|
6982
7184
|
Ticket.VIEW_CLASS = TicketView;
|
|
6983
7185
|
class TicketTablePage extends TablePage {
|
|
6984
7186
|
constructor(options = {}) {
|
|
6985
7187
|
super({
|
|
6986
|
-
...options,
|
|
6987
7188
|
name: "admin_tickets",
|
|
6988
7189
|
pageName: "Tickets",
|
|
6989
7190
|
router: "admin/tickets",
|
|
@@ -7037,7 +7238,8 @@ class TicketTablePage extends TablePage {
|
|
|
7037
7238
|
bordered: false,
|
|
7038
7239
|
hover: true,
|
|
7039
7240
|
responsive: false
|
|
7040
|
-
}
|
|
7241
|
+
},
|
|
7242
|
+
...options
|
|
7041
7243
|
});
|
|
7042
7244
|
}
|
|
7043
7245
|
}
|