web-mojo 2.1.824 → 2.1.867
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 +317 -39
- 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/{ChatView-DsdSe1A5.js → ChatView-8wuIN1zH.js} +327 -53
- package/dist/chunks/ChatView-8wuIN1zH.js.map +1 -0
- package/dist/chunks/ChatView-BtoAS3jU.js +2 -0
- package/dist/chunks/ChatView-BtoAS3jU.js.map +1 -0
- package/dist/chunks/{ContextMenu-C7wfFMyp.js → ContextMenu-Bem9gIL6.js} +2 -2
- package/dist/chunks/{ContextMenu-C7wfFMyp.js.map → ContextMenu-Bem9gIL6.js.map} +1 -1
- package/dist/chunks/{ContextMenu-6zcMDDiv.js → ContextMenu-DPxZgf69.js} +3 -2
- package/dist/chunks/{ContextMenu-6zcMDDiv.js.map → ContextMenu-DPxZgf69.js.map} +1 -1
- package/dist/chunks/{DataView-BDxfTYf0.js → DataView-C9O8uelM.js} +2 -2
- package/dist/chunks/{DataView-BDxfTYf0.js.map → DataView-C9O8uelM.js.map} +1 -1
- package/dist/chunks/{DataView-BJCAbOpx.js → DataView-DhbOr4Wm.js} +2 -2
- package/dist/chunks/{DataView-BJCAbOpx.js.map → DataView-DhbOr4Wm.js.map} +1 -1
- package/dist/chunks/{Dialog-CCnOsBBK.js → Dialog-CQA_WzmY.js} +5 -5
- package/dist/chunks/{Dialog-CCnOsBBK.js.map → Dialog-CQA_WzmY.js.map} +1 -1
- package/dist/chunks/{Dialog-B8_iNgDO.js → Dialog-gO9ln-ej.js} +2 -2
- package/dist/chunks/{Dialog-B8_iNgDO.js.map → Dialog-gO9ln-ej.js.map} +1 -1
- package/dist/chunks/{FormView-CHyzkf7A.js → FormView-DbPm-jDU.js} +4 -4
- package/dist/chunks/FormView-DbPm-jDU.js.map +1 -0
- package/dist/chunks/FormView-DkxYCmes.js +3 -0
- package/dist/chunks/FormView-DkxYCmes.js.map +1 -0
- package/dist/chunks/{MetricsMiniChartWidget-Co_cyqd4.js → MetricsMiniChartWidget-C41dYV1K.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-Co_cyqd4.js.map → MetricsMiniChartWidget-C41dYV1K.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-DkroX-HM.js → MetricsMiniChartWidget-Dz2d0GG2.js} +3 -3
- package/dist/chunks/{MetricsMiniChartWidget-DkroX-HM.js.map → MetricsMiniChartWidget-Dz2d0GG2.js.map} +1 -1
- package/dist/chunks/{PDFViewer-DLYyetM9.js → PDFViewer-BJT0-zQL.js} +3 -3
- package/dist/chunks/{PDFViewer-DLYyetM9.js.map → PDFViewer-BJT0-zQL.js.map} +1 -1
- package/dist/chunks/{PDFViewer-CFbFrBdS.js → PDFViewer-DvTxpaXI.js} +2 -2
- package/dist/chunks/{PDFViewer-CFbFrBdS.js.map → PDFViewer-DvTxpaXI.js.map} +1 -1
- package/dist/chunks/{Page-kuadj0PG.js → Page-CeYPFh_j.js} +2 -2
- package/dist/chunks/{Page-kuadj0PG.js.map → Page-CeYPFh_j.js.map} +1 -1
- package/dist/chunks/{Page-C1nY4u_3.js → Page-xjtBxzqE.js} +2 -2
- package/dist/chunks/{Page-C1nY4u_3.js.map → Page-xjtBxzqE.js.map} +1 -1
- package/dist/chunks/{TopNav-B40XDQjS.js → TopNav-CcS_qMvn.js} +2 -2
- package/dist/chunks/{TopNav-B40XDQjS.js.map → TopNav-CcS_qMvn.js.map} +1 -1
- package/dist/chunks/{TopNav-CkJNTimo.js → TopNav-baMWNGG2.js} +5 -5
- package/dist/chunks/{TopNav-CkJNTimo.js.map → TopNav-baMWNGG2.js.map} +1 -1
- package/dist/chunks/{WebApp-DT6XLijH.js → WebApp-DLAySO90.js} +13 -13
- package/dist/chunks/{WebApp-DT6XLijH.js.map → WebApp-DLAySO90.js.map} +1 -1
- package/dist/chunks/{WebApp-D0vBp8ks.js → WebApp-DkJV3BmZ.js} +2 -2
- package/dist/chunks/{WebApp-D0vBp8ks.js.map → WebApp-DkJV3BmZ.js.map} +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +5 -5
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +58 -52
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +4 -4
- package/package.json +1 -1
- package/dist/chunks/ChatView-Dm-1ojKc.js +0 -2
- package/dist/chunks/ChatView-Dm-1ojKc.js.map +0 -1
- package/dist/chunks/ChatView-DsdSe1A5.js.map +0 -1
- package/dist/chunks/FormView-CHyzkf7A.js.map +0 -1
- package/dist/chunks/FormView-NYVaTwDE.js +0 -3
- package/dist/chunks/FormView-NYVaTwDE.js.map +0 -1
package/dist/admin.es.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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, c as MetricsMiniChartWidget, P as PieChart } from "./chunks/MetricsMiniChartWidget-
|
|
6
|
-
import { b as TablePage, k as EmailDomainForms, j as EmailDomainList, E as EmailDomain, n as MailboxForms, m as MailboxList, l as Mailbox, r as EmailTemplate, d as TabView, t as EmailTemplateForms, s as EmailTemplateList, I as IncidentEvent, B as IncidentEventForms, A as IncidentEventList, w as FileManagerForms, v as FileManagerList, x as File, T as TableView, z as FileForms, y as FileList,
|
|
7
|
-
import DataView from "./chunks/DataView-
|
|
8
|
-
import { b as ContextMenu, C as Collection, a as Group, G as GroupList, c as GroupForms, g as UserDevice, j as UserDeviceLocationList, h as UserDeviceList, U as User, f as UserDataView, e as UserForms, d as UserList } from "./chunks/ContextMenu-
|
|
9
|
-
import { L as LightboxGallery, P as PDFViewer } from "./chunks/PDFViewer-
|
|
10
|
-
import { a as applyFileDropMixin, F as FormView } from "./chunks/FormView-
|
|
1
|
+
import { P as Page } from "./chunks/Page-CeYPFh_j.js";
|
|
2
|
+
import { V as View, h as MOJOUtils } from "./chunks/WebApp-DLAySO90.js";
|
|
3
|
+
import { B, b, a, c, e, f, W } from "./chunks/WebApp-DLAySO90.js";
|
|
4
|
+
import Dialog$1 from "./chunks/Dialog-CQA_WzmY.js";
|
|
5
|
+
import { M as MetricsChart, c as MetricsMiniChartWidget, P as PieChart } from "./chunks/MetricsMiniChartWidget-Dz2d0GG2.js";
|
|
6
|
+
import { b as TablePage, k as EmailDomainForms, j as EmailDomainList, E as EmailDomain, n as MailboxForms, m as MailboxList, l as Mailbox, r as EmailTemplate, d as TabView, t as EmailTemplateForms, s as EmailTemplateList, I as IncidentEvent, B as IncidentEventForms, A as IncidentEventList, w as FileManagerForms, v as FileManagerList, x as File, T as TableView, z as FileForms, y as FileList, av as GeoLocatedIP, aw as GeoLocatedIPList, ag as MemberList, af as LogList, ay as TicketList, G as IncidentList, _ as IncidentStats, R as IncidentHistoryList, Q as IncidentHistory, D as Incident, C as ChatView, H as IncidentForms, a3 as Job, a9 as JobEventList, a7 as JobLogList, a5 as JobForms, a4 as JobList, ac as JobRunnerList, aa as JobsEngineStats, ad as JobRunnerForms, ab as JobRunner, ae as Log, M as Member, ah as MemberForms, ai as MetricsPermission, ak as MetricsForms, aj as MetricsPermissionList, at as PushConfigForms, aq as PushConfigList, as as PushDeliveryList, am as PushDeviceList, au as PushTemplateForms, ao as PushTemplateList, U as RuleSet, a0 as MatchByOptions, $ as BundleByOptions, Y as RuleList, V as RuleSetList, i as S3BucketForms, h as S3BucketList, o as SentMessage, p as SentMessageList, aA as TicketNoteList, az as TicketNote, ax as Ticket, aB as TicketForms, aC as TicketCategories } from "./chunks/ChatView-8wuIN1zH.js";
|
|
7
|
+
import DataView from "./chunks/DataView-DhbOr4Wm.js";
|
|
8
|
+
import { b as ContextMenu, C as Collection, a as Group, G as GroupList, c as GroupForms, g as UserDevice, j as UserDeviceLocationList, h as UserDeviceList, U as User, f as UserDataView, e as UserForms, d as UserList } from "./chunks/ContextMenu-DPxZgf69.js";
|
|
9
|
+
import { L as LightboxGallery, P as PDFViewer } from "./chunks/PDFViewer-BJT0-zQL.js";
|
|
10
|
+
import { a as applyFileDropMixin, F as FormView } from "./chunks/FormView-DbPm-jDU.js";
|
|
11
11
|
class AdminHeaderView extends View {
|
|
12
12
|
constructor(options = {}) {
|
|
13
13
|
super({
|
|
@@ -798,6 +798,10 @@ class EmailTemplateTablePage extends TablePage {
|
|
|
798
798
|
size: "xl",
|
|
799
799
|
scrollable: true
|
|
800
800
|
},
|
|
801
|
+
formDialogConfig: {
|
|
802
|
+
// Dialog options for forms
|
|
803
|
+
size: "xl"
|
|
804
|
+
},
|
|
801
805
|
// Table columns
|
|
802
806
|
columns: [
|
|
803
807
|
{ key: "id", label: "ID", width: "70px", sortable: true, class: "text-muted" },
|
|
@@ -827,6 +831,129 @@ class EmailTemplateTablePage extends TablePage {
|
|
|
827
831
|
});
|
|
828
832
|
}
|
|
829
833
|
}
|
|
834
|
+
class StackTraceView extends View {
|
|
835
|
+
constructor(options = {}) {
|
|
836
|
+
super({
|
|
837
|
+
className: "stack-trace-view",
|
|
838
|
+
...options
|
|
839
|
+
});
|
|
840
|
+
this.stackTrace = options.stackTrace || "";
|
|
841
|
+
this.template = `
|
|
842
|
+
<div class="stack-trace-container p-3">
|
|
843
|
+
<style>
|
|
844
|
+
.stack-trace-line {
|
|
845
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace;
|
|
846
|
+
font-size: 13px;
|
|
847
|
+
line-height: 1.6;
|
|
848
|
+
padding: 4px 8px;
|
|
849
|
+
margin: 0;
|
|
850
|
+
border-left: 3px solid transparent;
|
|
851
|
+
}
|
|
852
|
+
.stack-trace-line:hover {
|
|
853
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
854
|
+
}
|
|
855
|
+
.stack-trace-error {
|
|
856
|
+
color: #dc3545;
|
|
857
|
+
font-weight: 600;
|
|
858
|
+
border-left-color: #dc3545;
|
|
859
|
+
background-color: rgba(220, 53, 69, 0.05);
|
|
860
|
+
}
|
|
861
|
+
.stack-trace-file {
|
|
862
|
+
color: #0d6efd;
|
|
863
|
+
font-weight: 500;
|
|
864
|
+
border-left-color: #0d6efd;
|
|
865
|
+
}
|
|
866
|
+
.stack-trace-function {
|
|
867
|
+
color: #6610f2;
|
|
868
|
+
font-weight: 500;
|
|
869
|
+
}
|
|
870
|
+
.stack-trace-location {
|
|
871
|
+
color: #6c757d;
|
|
872
|
+
font-size: 12px;
|
|
873
|
+
}
|
|
874
|
+
.stack-trace-line-number {
|
|
875
|
+
color: #fd7e14;
|
|
876
|
+
font-weight: 600;
|
|
877
|
+
}
|
|
878
|
+
.stack-trace-context {
|
|
879
|
+
color: #495057;
|
|
880
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
881
|
+
}
|
|
882
|
+
.stack-trace-container {
|
|
883
|
+
background-color: #f8f9fa;
|
|
884
|
+
border: 1px solid #dee2e6;
|
|
885
|
+
border-radius: 0.375rem;
|
|
886
|
+
max-height: 600px;
|
|
887
|
+
overflow-y: auto;
|
|
888
|
+
}
|
|
889
|
+
</style>
|
|
890
|
+
<div class="stack-trace-content">
|
|
891
|
+
{{{formattedStackTrace}}}
|
|
892
|
+
</div>
|
|
893
|
+
</div>
|
|
894
|
+
`;
|
|
895
|
+
}
|
|
896
|
+
async onBeforeRender() {
|
|
897
|
+
this.formattedStackTrace = this.formatStackTrace(this.stackTrace);
|
|
898
|
+
}
|
|
899
|
+
formatStackTrace(stackTrace) {
|
|
900
|
+
if (!stackTrace) {
|
|
901
|
+
return '<div class="text-muted p-3">No stack trace available</div>';
|
|
902
|
+
}
|
|
903
|
+
const traceStr = typeof stackTrace === "string" ? stackTrace : JSON.stringify(stackTrace, null, 2);
|
|
904
|
+
const lines = traceStr.split("\n");
|
|
905
|
+
let html = "";
|
|
906
|
+
lines.forEach((line, index) => {
|
|
907
|
+
if (!line.trim()) {
|
|
908
|
+
html += '<div class="stack-trace-line"> </div>';
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
if (index === 0 && (line.includes("Error:") || line.includes("Exception:"))) {
|
|
912
|
+
html += `<div class="stack-trace-line stack-trace-error">${this.escapeHtml(line)}</div>`;
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const filePattern = /(.+?)\s*\(([^:]+):(\d+):(\d+)\)/;
|
|
916
|
+
const simpleFilePattern = /^\s*at\s+([^:]+):(\d+):(\d+)/;
|
|
917
|
+
let match = line.match(filePattern);
|
|
918
|
+
if (match) {
|
|
919
|
+
const [, funcName, filePath, lineNum, colNum] = match;
|
|
920
|
+
html += `<div class="stack-trace-line stack-trace-file">
|
|
921
|
+
<span class="stack-trace-function">${this.escapeHtml(funcName.trim())}</span>
|
|
922
|
+
<span class="stack-trace-location"> (${this.escapeHtml(filePath)}:<span class="stack-trace-line-number">${lineNum}</span>:${colNum})</span>
|
|
923
|
+
</div>`;
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
match = line.match(simpleFilePattern);
|
|
927
|
+
if (match) {
|
|
928
|
+
const [, filePath, lineNum, colNum] = match;
|
|
929
|
+
html += `<div class="stack-trace-line stack-trace-file">
|
|
930
|
+
<span class="stack-trace-location">at ${this.escapeHtml(filePath)}:<span class="stack-trace-line-number">${lineNum}</span>:${colNum}</span>
|
|
931
|
+
</div>`;
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
const pythonPattern = /File\s+"([^"]+)",\s+line\s+(\d+),\s+in\s+(.+)/;
|
|
935
|
+
match = line.match(pythonPattern);
|
|
936
|
+
if (match) {
|
|
937
|
+
const [, filePath, lineNum, funcName] = match;
|
|
938
|
+
html += `<div class="stack-trace-line stack-trace-file">
|
|
939
|
+
<span class="stack-trace-location">File "${this.escapeHtml(filePath)}", line <span class="stack-trace-line-number">${lineNum}</span>, in </span>
|
|
940
|
+
<span class="stack-trace-function">${this.escapeHtml(funcName)}</span>
|
|
941
|
+
</div>`;
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (line.trim().startsWith("at ")) {
|
|
945
|
+
html += `<div class="stack-trace-line stack-trace-file">${this.escapeHtml(line)}</div>`;
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
html += `<div class="stack-trace-line stack-trace-context">${this.escapeHtml(line)}</div>`;
|
|
949
|
+
});
|
|
950
|
+
return html;
|
|
951
|
+
}
|
|
952
|
+
updateStackTrace(newStackTrace) {
|
|
953
|
+
this.stackTrace = newStackTrace;
|
|
954
|
+
this.render();
|
|
955
|
+
}
|
|
956
|
+
}
|
|
830
957
|
class EventView extends View {
|
|
831
958
|
constructor(options = {}) {
|
|
832
959
|
super({
|
|
@@ -882,20 +1009,20 @@ class EventView extends View {
|
|
|
882
1009
|
{ name: "details", label: "Details", columns: 12 }
|
|
883
1010
|
]
|
|
884
1011
|
});
|
|
885
|
-
this.metadataView = new View({
|
|
886
|
-
model: this.model,
|
|
887
|
-
template: `<pre class="bg-light p-3 border rounded"><code>{{{model.metadata|json}}}</code></pre>`
|
|
888
|
-
});
|
|
889
1012
|
const tabs = { "Overview": this.overviewView };
|
|
890
|
-
|
|
891
|
-
|
|
1013
|
+
const metadata = this.model.get("metadata") || {};
|
|
1014
|
+
if (metadata.stack_trace) {
|
|
1015
|
+
this.stackTraceView = new StackTraceView({
|
|
1016
|
+
stackTrace: metadata.stack_trace
|
|
1017
|
+
});
|
|
1018
|
+
tabs["Stack Trace"] = this.stackTraceView;
|
|
892
1019
|
}
|
|
893
|
-
if (
|
|
894
|
-
this.
|
|
1020
|
+
if (Object.keys(metadata).length > 0) {
|
|
1021
|
+
this.metadataView = new View({
|
|
895
1022
|
model: this.model,
|
|
896
|
-
template: `<pre class="bg-
|
|
1023
|
+
template: `<pre class="bg-light p-3 border rounded"><code>{{{model.metadata|json}}}</code></pre>`
|
|
897
1024
|
});
|
|
898
|
-
tabs["
|
|
1025
|
+
tabs["Metadata"] = this.metadataView;
|
|
899
1026
|
}
|
|
900
1027
|
this.tabView = new TabView({
|
|
901
1028
|
containerId: "event-tabs",
|
|
@@ -1463,7 +1590,7 @@ class FileTablePage extends TablePage {
|
|
|
1463
1590
|
*/
|
|
1464
1591
|
async onActionAdd(event, element) {
|
|
1465
1592
|
event.preventDefault();
|
|
1466
|
-
const Dialog2 = (await import("./chunks/Dialog-
|
|
1593
|
+
const Dialog2 = (await import("./chunks/Dialog-CQA_WzmY.js")).default;
|
|
1467
1594
|
const formData = await Dialog2.showForm({
|
|
1468
1595
|
title: "Upload File",
|
|
1469
1596
|
size: "md",
|
|
@@ -1916,6 +2043,10 @@ class GroupTablePage extends TablePage {
|
|
|
1916
2043
|
viewDialogOptions: {
|
|
1917
2044
|
header: false
|
|
1918
2045
|
},
|
|
2046
|
+
defaultQuery: {
|
|
2047
|
+
sort: "-id",
|
|
2048
|
+
is_active: 1
|
|
2049
|
+
},
|
|
1919
2050
|
// Column definitions
|
|
1920
2051
|
columns: [
|
|
1921
2052
|
{
|
|
@@ -1925,6 +2056,11 @@ class GroupTablePage extends TablePage {
|
|
|
1925
2056
|
sortable: true,
|
|
1926
2057
|
class: "text-muted"
|
|
1927
2058
|
},
|
|
2059
|
+
{
|
|
2060
|
+
key: "is_active|yesnoicon",
|
|
2061
|
+
label: "Enabled",
|
|
2062
|
+
visibility: "lg"
|
|
2063
|
+
},
|
|
1928
2064
|
{
|
|
1929
2065
|
label: "Avatar",
|
|
1930
2066
|
key: 'avatar|avatar("sm", "rounded")',
|
|
@@ -2352,13 +2488,39 @@ class IncidentView extends View {
|
|
|
2352
2488
|
{ name: "details", label: "Details", columns: 12, format: "pre" }
|
|
2353
2489
|
]
|
|
2354
2490
|
});
|
|
2491
|
+
const eventsCollection = new IncidentEventList({
|
|
2492
|
+
params: { incident: this.model.get("id") }
|
|
2493
|
+
});
|
|
2494
|
+
this.eventsView = new TableView({
|
|
2495
|
+
collection: eventsCollection,
|
|
2496
|
+
hideActivePillNames: ["incident"],
|
|
2497
|
+
columns: [
|
|
2498
|
+
{ key: "id", label: "ID", width: "70px", sortable: true },
|
|
2499
|
+
{ key: "created", label: "Date", formatter: "datetime", sortable: true, width: "180px" },
|
|
2500
|
+
{ key: "category", label: "Category", formatter: "badge", sortable: true },
|
|
2501
|
+
{ key: "title", label: "Title", sortable: true },
|
|
2502
|
+
{ key: "level", label: "Level", sortable: true, width: "80px" }
|
|
2503
|
+
],
|
|
2504
|
+
showAdd: false,
|
|
2505
|
+
actions: ["view"],
|
|
2506
|
+
paginated: true,
|
|
2507
|
+
size: 10
|
|
2508
|
+
});
|
|
2355
2509
|
const adapter = new IncidentHistoryAdapter(this.model.get("id"));
|
|
2356
2510
|
this.historyView = new ChatView({ adapter });
|
|
2357
2511
|
const tabs = {
|
|
2358
2512
|
"Overview": this.overviewView,
|
|
2513
|
+
"Events": this.eventsView,
|
|
2359
2514
|
"History & Comments": this.historyView
|
|
2360
2515
|
};
|
|
2361
|
-
|
|
2516
|
+
const metadata = this.model.get("metadata") || {};
|
|
2517
|
+
if (metadata.stack_trace) {
|
|
2518
|
+
this.stackTraceView = new StackTraceView({
|
|
2519
|
+
stackTrace: metadata.stack_trace
|
|
2520
|
+
});
|
|
2521
|
+
tabs["Stack Trace"] = this.stackTraceView;
|
|
2522
|
+
}
|
|
2523
|
+
if (Object.keys(metadata).length > 0) {
|
|
2362
2524
|
this.metadataView = new View({
|
|
2363
2525
|
model: this.model,
|
|
2364
2526
|
template: `<pre class="bg-light p-3 border rounded"><code>{{{model.metadata|json}}}</code></pre>`
|
|
@@ -2493,8 +2655,8 @@ class IncidentTablePage extends TablePage {
|
|
|
2493
2655
|
{ label: "Open", icon: "bi bi-folder2-open", action: "open" },
|
|
2494
2656
|
{ label: "Resolve", icon: "bi bi-check-circle", action: "resolve" },
|
|
2495
2657
|
{ label: "Pause", icon: "bi bi-pause-circle", action: "pause" },
|
|
2496
|
-
{ label: "Ignore", icon: "bi bi-x-circle", action: "
|
|
2497
|
-
{ label: "
|
|
2658
|
+
{ label: "Ignore", icon: "bi bi-x-circle", action: "ignore" },
|
|
2659
|
+
{ label: "Merge", icon: "bi bi-merge", action: "merge" }
|
|
2498
2660
|
],
|
|
2499
2661
|
// Table display options
|
|
2500
2662
|
tableOptions: {
|
|
@@ -2541,6 +2703,29 @@ class IncidentTablePage extends TablePage {
|
|
|
2541
2703
|
await Promise.all(selected.map((item) => item.model.save({ status: "ignored" })));
|
|
2542
2704
|
this.tableView.collection.fetch();
|
|
2543
2705
|
}
|
|
2706
|
+
async onActionBatchMerge(_event, _element) {
|
|
2707
|
+
const selected = this.tableView.getSelectedItems();
|
|
2708
|
+
if (!selected.length) return;
|
|
2709
|
+
const app = this.getApp();
|
|
2710
|
+
const result = await app.showForm({
|
|
2711
|
+
title: `Merge ${selected.length} incidents`,
|
|
2712
|
+
fields: [
|
|
2713
|
+
{
|
|
2714
|
+
name: "merge",
|
|
2715
|
+
type: "select",
|
|
2716
|
+
label: "Select Parent Incident",
|
|
2717
|
+
options: selected.map((item) => ({ value: item.model.id, label: item.model.id })),
|
|
2718
|
+
required: true
|
|
2719
|
+
}
|
|
2720
|
+
]
|
|
2721
|
+
});
|
|
2722
|
+
if (!result) return;
|
|
2723
|
+
const parentModel = selected.find((item) => item.model.id == result.merge)?.model;
|
|
2724
|
+
if (!parentModel) return;
|
|
2725
|
+
const mergeIds = selected.map((item) => item.model.id).filter((id) => id != result.merge);
|
|
2726
|
+
await parentModel.save({ merge: mergeIds });
|
|
2727
|
+
this.tableView.collection.fetch();
|
|
2728
|
+
}
|
|
2544
2729
|
}
|
|
2545
2730
|
class JobStatsView extends View {
|
|
2546
2731
|
constructor(options = {}) {
|
|
@@ -5000,20 +5185,36 @@ class RuleSetView extends View {
|
|
|
5000
5185
|
`;
|
|
5001
5186
|
}
|
|
5002
5187
|
async onInit() {
|
|
5188
|
+
const matchByValue = this.model.get("match_by");
|
|
5189
|
+
const matchByOption = MatchByOptions.find((opt) => opt.value === matchByValue);
|
|
5190
|
+
const matchByLabel = matchByOption ? matchByOption.label : String(matchByValue);
|
|
5191
|
+
const bundleByValue = this.model.get("bundle_by");
|
|
5192
|
+
const bundleByOption = BundleByOptions.find((opt) => opt.value === bundleByValue);
|
|
5193
|
+
const bundleByLabel = bundleByOption ? bundleByOption.label : String(bundleByValue);
|
|
5003
5194
|
this.configView = new DataView({
|
|
5004
5195
|
model: this.model,
|
|
5005
5196
|
className: "p-3",
|
|
5006
5197
|
columns: 2,
|
|
5007
5198
|
fields: [
|
|
5008
|
-
{ name: "id", label: "RuleSet ID" },
|
|
5009
|
-
{ name: "
|
|
5010
|
-
{ name: "
|
|
5011
|
-
{ name: "
|
|
5012
|
-
{ name: "
|
|
5013
|
-
{
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5199
|
+
{ name: "id", label: "RuleSet ID", cols: 6 },
|
|
5200
|
+
{ name: "priority", label: "Priority", cols: 6 },
|
|
5201
|
+
{ name: "name", label: "Name", cols: 12 },
|
|
5202
|
+
{ name: "category", label: "Category", formatter: "badge", cols: 6 },
|
|
5203
|
+
{ name: "is_active", label: "Status", formatter: "boolean", cols: 6 },
|
|
5204
|
+
{
|
|
5205
|
+
name: "match_by",
|
|
5206
|
+
label: "Match Logic",
|
|
5207
|
+
template: matchByLabel,
|
|
5208
|
+
cols: 12
|
|
5209
|
+
},
|
|
5210
|
+
{
|
|
5211
|
+
name: "bundle_by",
|
|
5212
|
+
label: "Bundle By",
|
|
5213
|
+
template: bundleByLabel,
|
|
5214
|
+
cols: 12
|
|
5215
|
+
},
|
|
5216
|
+
{ name: "bundle_minutes", label: "Bundle Minutes", cols: 6 },
|
|
5217
|
+
{ name: "handler", label: "Handler", cols: 12 }
|
|
5017
5218
|
]
|
|
5018
5219
|
});
|
|
5019
5220
|
const rulesCollection = new RuleList({
|
|
@@ -5025,12 +5226,23 @@ class RuleSetView extends View {
|
|
|
5025
5226
|
{ key: "id", label: "ID", width: "70px" },
|
|
5026
5227
|
{ key: "name", label: "Name" },
|
|
5027
5228
|
{ key: "field_name", label: "Field" },
|
|
5028
|
-
{ key: "comparator", label: "Comparator" },
|
|
5229
|
+
{ key: "comparator", label: "Comparator", width: "120px" },
|
|
5029
5230
|
{ key: "value", label: "Value" },
|
|
5030
|
-
{ key: "value_type", label: "Type" }
|
|
5231
|
+
{ key: "value_type", label: "Type", width: "100px" }
|
|
5031
5232
|
],
|
|
5032
5233
|
showAdd: true,
|
|
5033
|
-
|
|
5234
|
+
clickAction: "edit",
|
|
5235
|
+
actions: ["edit", "delete"],
|
|
5236
|
+
contextMenu: [
|
|
5237
|
+
{ label: "Edit Rule", action: "edit", icon: "bi-pencil" },
|
|
5238
|
+
{ label: "Duplicate Rule", action: "duplicate", icon: "bi-files" },
|
|
5239
|
+
{ divider: true },
|
|
5240
|
+
{ label: "Delete Rule", action: "delete", icon: "bi-trash", danger: true }
|
|
5241
|
+
],
|
|
5242
|
+
// Pass the parent ID so new rules get associated with this ruleset
|
|
5243
|
+
defaultData: {
|
|
5244
|
+
parent: this.model.get("id")
|
|
5245
|
+
}
|
|
5034
5246
|
});
|
|
5035
5247
|
this.tabView = new TabView({
|
|
5036
5248
|
containerId: "ruleset-tabs",
|
|
@@ -5056,6 +5268,73 @@ class RuleSetView extends View {
|
|
|
5056
5268
|
});
|
|
5057
5269
|
this.addChild(contextMenu);
|
|
5058
5270
|
}
|
|
5271
|
+
/**
|
|
5272
|
+
* Action handler: Edit RuleSet
|
|
5273
|
+
*/
|
|
5274
|
+
async onActionEditRuleset() {
|
|
5275
|
+
const resp = await Dialog$1.showModelForm({
|
|
5276
|
+
title: `Edit RuleSet - ${this.model.get("name")}`,
|
|
5277
|
+
model: this.model,
|
|
5278
|
+
formConfig: RuleSet.EDIT_FORM
|
|
5279
|
+
});
|
|
5280
|
+
if (resp) {
|
|
5281
|
+
await this.render();
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
/**
|
|
5285
|
+
* Action handler: Disable/Enable RuleSet
|
|
5286
|
+
*/
|
|
5287
|
+
async onActionDisableRuleset() {
|
|
5288
|
+
const isActive = this.model.get("is_active");
|
|
5289
|
+
const newStatus = !isActive;
|
|
5290
|
+
try {
|
|
5291
|
+
this.model.set("is_active", newStatus);
|
|
5292
|
+
await this.model.save();
|
|
5293
|
+
await this.render();
|
|
5294
|
+
Dialog$1.showToast({
|
|
5295
|
+
message: `RuleSet ${newStatus ? "enabled" : "disabled"} successfully`,
|
|
5296
|
+
type: "success"
|
|
5297
|
+
});
|
|
5298
|
+
} catch (error) {
|
|
5299
|
+
Dialog$1.showToast({
|
|
5300
|
+
message: `Failed to update RuleSet: ${error.message}`,
|
|
5301
|
+
type: "error"
|
|
5302
|
+
});
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
/**
|
|
5306
|
+
* Action handler: Delete RuleSet
|
|
5307
|
+
*/
|
|
5308
|
+
async onActionDeleteRuleset() {
|
|
5309
|
+
const confirmed = await Dialog$1.confirm({
|
|
5310
|
+
title: "Delete RuleSet",
|
|
5311
|
+
message: `Are you sure you want to delete the ruleset "${this.model.get("name")}"? This action cannot be undone.`,
|
|
5312
|
+
confirmText: "Delete",
|
|
5313
|
+
confirmClass: "btn-danger"
|
|
5314
|
+
});
|
|
5315
|
+
if (confirmed) {
|
|
5316
|
+
try {
|
|
5317
|
+
await this.model.destroy();
|
|
5318
|
+
Dialog$1.showToast({
|
|
5319
|
+
message: "RuleSet deleted successfully",
|
|
5320
|
+
type: "success"
|
|
5321
|
+
});
|
|
5322
|
+
const dialog = this.element?.closest(".modal");
|
|
5323
|
+
if (dialog) {
|
|
5324
|
+
const bsModal = bootstrap.Modal.getInstance(dialog);
|
|
5325
|
+
if (bsModal) {
|
|
5326
|
+
bsModal.hide();
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5329
|
+
this.emit("ruleset:deleted", { model: this.model });
|
|
5330
|
+
} catch (error) {
|
|
5331
|
+
Dialog$1.showToast({
|
|
5332
|
+
message: `Failed to delete RuleSet: ${error.message}`,
|
|
5333
|
+
type: "error"
|
|
5334
|
+
});
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5059
5338
|
}
|
|
5060
5339
|
RuleSetView.VIEW_CLASS = RuleSetView;
|
|
5061
5340
|
class RuleSetTablePage extends TablePage {
|
|
@@ -5066,7 +5345,7 @@ class RuleSetTablePage extends TablePage {
|
|
|
5066
5345
|
pageName: "Rule Engine",
|
|
5067
5346
|
router: "admin/rulesets",
|
|
5068
5347
|
Collection: RuleSetList,
|
|
5069
|
-
|
|
5348
|
+
itemView: RuleSetView,
|
|
5070
5349
|
viewDialogOptions: {
|
|
5071
5350
|
header: false,
|
|
5072
5351
|
size: "xl"
|
|
@@ -5076,8 +5355,7 @@ class RuleSetTablePage extends TablePage {
|
|
|
5076
5355
|
{ key: "name", label: "Name", sortable: true },
|
|
5077
5356
|
{ key: "category", label: "Category", sortable: true, formatter: "badge" },
|
|
5078
5357
|
{ key: "priority", label: "Priority", sortable: true },
|
|
5079
|
-
{ key: "match_by", label: "Match Logic", formatter: (v) => v === 0 ? "ALL" : "ANY" }
|
|
5080
|
-
{ key: "is_active", label: "Status", formatter: "boolean|badge('Active:success,Inactive:secondary')" }
|
|
5358
|
+
{ key: "match_by", label: "Match Logic", formatter: (v) => v === 0 ? "ALL" : "ANY" }
|
|
5081
5359
|
],
|
|
5082
5360
|
selectable: true,
|
|
5083
5361
|
searchable: true,
|