web-mojo 2.1.827 → 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 +303 -38
- 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-DJK49g8O.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-K8sVV2Sf.js → ContextMenu-Bem9gIL6.js} +2 -2
- package/dist/chunks/{ContextMenu-K8sVV2Sf.js.map → ContextMenu-Bem9gIL6.js.map} +1 -1
- package/dist/chunks/{ContextMenu-CRwv6-gc.js → ContextMenu-DPxZgf69.js} +3 -2
- package/dist/chunks/{ContextMenu-CRwv6-gc.js.map → ContextMenu-DPxZgf69.js.map} +1 -1
- package/dist/chunks/{DataView-DoKRJHii.js → DataView-C9O8uelM.js} +2 -2
- package/dist/chunks/{DataView-DoKRJHii.js.map → DataView-C9O8uelM.js.map} +1 -1
- package/dist/chunks/{DataView-3iqbZ_4y.js → DataView-DhbOr4Wm.js} +2 -2
- package/dist/chunks/{DataView-3iqbZ_4y.js.map → DataView-DhbOr4Wm.js.map} +1 -1
- package/dist/chunks/{Dialog-Bup1WdQn.js → Dialog-CQA_WzmY.js} +5 -5
- package/dist/chunks/{Dialog-Bup1WdQn.js.map → Dialog-CQA_WzmY.js.map} +1 -1
- package/dist/chunks/{Dialog-CEEzQOVl.js → Dialog-gO9ln-ej.js} +2 -2
- package/dist/chunks/{Dialog-CEEzQOVl.js.map → Dialog-gO9ln-ej.js.map} +1 -1
- package/dist/chunks/{FormView-C4Po3Q3z.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-CxTnMgp6.js → MetricsMiniChartWidget-C41dYV1K.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-CxTnMgp6.js.map → MetricsMiniChartWidget-C41dYV1K.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-CK6K9Kh6.js → MetricsMiniChartWidget-Dz2d0GG2.js} +3 -3
- package/dist/chunks/{MetricsMiniChartWidget-CK6K9Kh6.js.map → MetricsMiniChartWidget-Dz2d0GG2.js.map} +1 -1
- package/dist/chunks/{PDFViewer-DgXB4rR9.js → PDFViewer-BJT0-zQL.js} +3 -3
- package/dist/chunks/{PDFViewer-DgXB4rR9.js.map → PDFViewer-BJT0-zQL.js.map} +1 -1
- package/dist/chunks/{PDFViewer-BvBw9BNk.js → PDFViewer-DvTxpaXI.js} +2 -2
- package/dist/chunks/{PDFViewer-BvBw9BNk.js.map → PDFViewer-DvTxpaXI.js.map} +1 -1
- package/dist/chunks/{Page-DaptCfWp.js → Page-CeYPFh_j.js} +2 -2
- package/dist/chunks/{Page-DaptCfWp.js.map → Page-CeYPFh_j.js.map} +1 -1
- package/dist/chunks/{Page-BJxsE5Os.js → Page-xjtBxzqE.js} +2 -2
- package/dist/chunks/{Page-BJxsE5Os.js.map → Page-xjtBxzqE.js.map} +1 -1
- package/dist/chunks/{TopNav-BkpUjJB2.js → TopNav-CcS_qMvn.js} +2 -2
- package/dist/chunks/{TopNav-BkpUjJB2.js.map → TopNav-CcS_qMvn.js.map} +1 -1
- package/dist/chunks/{TopNav-BjJojcF7.js → TopNav-baMWNGG2.js} +5 -5
- package/dist/chunks/{TopNav-BjJojcF7.js.map → TopNav-baMWNGG2.js.map} +1 -1
- package/dist/chunks/{WebApp-Cd21W4Hv.js → WebApp-DLAySO90.js} +13 -13
- package/dist/chunks/{WebApp-Cd21W4Hv.js.map → WebApp-DLAySO90.js.map} +1 -1
- package/dist/chunks/{WebApp-9L0mkLAO.js → WebApp-DkJV3BmZ.js} +2 -2
- package/dist/chunks/{WebApp-9L0mkLAO.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-CM0ATZID.js +0 -2
- package/dist/chunks/ChatView-CM0ATZID.js.map +0 -1
- package/dist/chunks/ChatView-DJK49g8O.js.map +0 -1
- package/dist/chunks/FormView-BEIw_LH9.js +0 -3
- package/dist/chunks/FormView-BEIw_LH9.js.map +0 -1
- package/dist/chunks/FormView-C4Po3Q3z.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({
|
|
@@ -831,6 +831,129 @@ class EmailTemplateTablePage extends TablePage {
|
|
|
831
831
|
});
|
|
832
832
|
}
|
|
833
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
|
+
}
|
|
834
957
|
class EventView extends View {
|
|
835
958
|
constructor(options = {}) {
|
|
836
959
|
super({
|
|
@@ -886,20 +1009,20 @@ class EventView extends View {
|
|
|
886
1009
|
{ name: "details", label: "Details", columns: 12 }
|
|
887
1010
|
]
|
|
888
1011
|
});
|
|
889
|
-
this.metadataView = new View({
|
|
890
|
-
model: this.model,
|
|
891
|
-
template: `<pre class="bg-light p-3 border rounded"><code>{{{model.metadata|json}}}</code></pre>`
|
|
892
|
-
});
|
|
893
1012
|
const tabs = { "Overview": this.overviewView };
|
|
894
|
-
|
|
895
|
-
|
|
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;
|
|
896
1019
|
}
|
|
897
|
-
if (
|
|
898
|
-
this.
|
|
1020
|
+
if (Object.keys(metadata).length > 0) {
|
|
1021
|
+
this.metadataView = new View({
|
|
899
1022
|
model: this.model,
|
|
900
|
-
template: `<pre class="bg-
|
|
1023
|
+
template: `<pre class="bg-light p-3 border rounded"><code>{{{model.metadata|json}}}</code></pre>`
|
|
901
1024
|
});
|
|
902
|
-
tabs["
|
|
1025
|
+
tabs["Metadata"] = this.metadataView;
|
|
903
1026
|
}
|
|
904
1027
|
this.tabView = new TabView({
|
|
905
1028
|
containerId: "event-tabs",
|
|
@@ -1467,7 +1590,7 @@ class FileTablePage extends TablePage {
|
|
|
1467
1590
|
*/
|
|
1468
1591
|
async onActionAdd(event, element) {
|
|
1469
1592
|
event.preventDefault();
|
|
1470
|
-
const Dialog2 = (await import("./chunks/Dialog-
|
|
1593
|
+
const Dialog2 = (await import("./chunks/Dialog-CQA_WzmY.js")).default;
|
|
1471
1594
|
const formData = await Dialog2.showForm({
|
|
1472
1595
|
title: "Upload File",
|
|
1473
1596
|
size: "md",
|
|
@@ -2365,13 +2488,39 @@ class IncidentView extends View {
|
|
|
2365
2488
|
{ name: "details", label: "Details", columns: 12, format: "pre" }
|
|
2366
2489
|
]
|
|
2367
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
|
+
});
|
|
2368
2509
|
const adapter = new IncidentHistoryAdapter(this.model.get("id"));
|
|
2369
2510
|
this.historyView = new ChatView({ adapter });
|
|
2370
2511
|
const tabs = {
|
|
2371
2512
|
"Overview": this.overviewView,
|
|
2513
|
+
"Events": this.eventsView,
|
|
2372
2514
|
"History & Comments": this.historyView
|
|
2373
2515
|
};
|
|
2374
|
-
|
|
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) {
|
|
2375
2524
|
this.metadataView = new View({
|
|
2376
2525
|
model: this.model,
|
|
2377
2526
|
template: `<pre class="bg-light p-3 border rounded"><code>{{{model.metadata|json}}}</code></pre>`
|
|
@@ -2507,7 +2656,7 @@ class IncidentTablePage extends TablePage {
|
|
|
2507
2656
|
{ label: "Resolve", icon: "bi bi-check-circle", action: "resolve" },
|
|
2508
2657
|
{ label: "Pause", icon: "bi bi-pause-circle", action: "pause" },
|
|
2509
2658
|
{ label: "Ignore", icon: "bi bi-x-circle", action: "ignore" },
|
|
2510
|
-
{ label: "
|
|
2659
|
+
{ label: "Merge", icon: "bi bi-merge", action: "merge" }
|
|
2511
2660
|
],
|
|
2512
2661
|
// Table display options
|
|
2513
2662
|
tableOptions: {
|
|
@@ -2554,6 +2703,29 @@ class IncidentTablePage extends TablePage {
|
|
|
2554
2703
|
await Promise.all(selected.map((item) => item.model.save({ status: "ignored" })));
|
|
2555
2704
|
this.tableView.collection.fetch();
|
|
2556
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
|
+
}
|
|
2557
2729
|
}
|
|
2558
2730
|
class JobStatsView extends View {
|
|
2559
2731
|
constructor(options = {}) {
|
|
@@ -5013,20 +5185,36 @@ class RuleSetView extends View {
|
|
|
5013
5185
|
`;
|
|
5014
5186
|
}
|
|
5015
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);
|
|
5016
5194
|
this.configView = new DataView({
|
|
5017
5195
|
model: this.model,
|
|
5018
5196
|
className: "p-3",
|
|
5019
5197
|
columns: 2,
|
|
5020
5198
|
fields: [
|
|
5021
|
-
{ name: "id", label: "RuleSet ID" },
|
|
5022
|
-
{ name: "
|
|
5023
|
-
{ name: "
|
|
5024
|
-
{ name: "
|
|
5025
|
-
{ name: "
|
|
5026
|
-
{
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
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 }
|
|
5030
5218
|
]
|
|
5031
5219
|
});
|
|
5032
5220
|
const rulesCollection = new RuleList({
|
|
@@ -5038,12 +5226,23 @@ class RuleSetView extends View {
|
|
|
5038
5226
|
{ key: "id", label: "ID", width: "70px" },
|
|
5039
5227
|
{ key: "name", label: "Name" },
|
|
5040
5228
|
{ key: "field_name", label: "Field" },
|
|
5041
|
-
{ key: "comparator", label: "Comparator" },
|
|
5229
|
+
{ key: "comparator", label: "Comparator", width: "120px" },
|
|
5042
5230
|
{ key: "value", label: "Value" },
|
|
5043
|
-
{ key: "value_type", label: "Type" }
|
|
5231
|
+
{ key: "value_type", label: "Type", width: "100px" }
|
|
5044
5232
|
],
|
|
5045
5233
|
showAdd: true,
|
|
5046
|
-
|
|
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
|
+
}
|
|
5047
5246
|
});
|
|
5048
5247
|
this.tabView = new TabView({
|
|
5049
5248
|
containerId: "ruleset-tabs",
|
|
@@ -5069,6 +5268,73 @@ class RuleSetView extends View {
|
|
|
5069
5268
|
});
|
|
5070
5269
|
this.addChild(contextMenu);
|
|
5071
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
|
+
}
|
|
5072
5338
|
}
|
|
5073
5339
|
RuleSetView.VIEW_CLASS = RuleSetView;
|
|
5074
5340
|
class RuleSetTablePage extends TablePage {
|
|
@@ -5079,7 +5345,7 @@ class RuleSetTablePage extends TablePage {
|
|
|
5079
5345
|
pageName: "Rule Engine",
|
|
5080
5346
|
router: "admin/rulesets",
|
|
5081
5347
|
Collection: RuleSetList,
|
|
5082
|
-
|
|
5348
|
+
itemView: RuleSetView,
|
|
5083
5349
|
viewDialogOptions: {
|
|
5084
5350
|
header: false,
|
|
5085
5351
|
size: "xl"
|
|
@@ -5089,8 +5355,7 @@ class RuleSetTablePage extends TablePage {
|
|
|
5089
5355
|
{ key: "name", label: "Name", sortable: true },
|
|
5090
5356
|
{ key: "category", label: "Category", sortable: true, formatter: "badge" },
|
|
5091
5357
|
{ key: "priority", label: "Priority", sortable: true },
|
|
5092
|
-
{ key: "match_by", label: "Match Logic", formatter: (v) => v === 0 ? "ALL" : "ANY" }
|
|
5093
|
-
{ 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" }
|
|
5094
5359
|
],
|
|
5095
5360
|
selectable: true,
|
|
5096
5361
|
searchable: true,
|