web-mojo 2.5.8 → 2.5.10
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/CHANGELOG.md +7 -0
- package/dist/admin-models.es.js +1 -1
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +1 -1
- package/dist/admin.es.js.map +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.es.js +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +1 -1
- package/dist/chunks/{ChatView-C27ckVwL.js → ChatView-CPaBPG5C.js} +2 -2
- package/dist/chunks/{ChatView-C27ckVwL.js.map → ChatView-CPaBPG5C.js.map} +1 -1
- package/dist/chunks/{ContextMenu-xdLpFeau.js → ContextMenu-Dch7L988.js} +2 -2
- package/dist/chunks/{ContextMenu-xdLpFeau.js.map → ContextMenu-Dch7L988.js.map} +1 -1
- package/dist/chunks/{DataView-DBQUt_vV.js → DataView-DhhTCP0d.js} +2 -2
- package/dist/chunks/{DataView-DBQUt_vV.js.map → DataView-DhhTCP0d.js.map} +1 -1
- package/dist/chunks/{FormView-DaZFbDWr.js → FormView-C6XZFZ6s.js} +2 -2
- package/dist/chunks/{FormView-DaZFbDWr.js.map → FormView-C6XZFZ6s.js.map} +1 -1
- package/dist/chunks/{ListView-C-jiqALE.js → ListView-McEedPG8.js} +2 -2
- package/dist/chunks/{ListView-C-jiqALE.js.map → ListView-McEedPG8.js.map} +1 -1
- package/dist/chunks/{MetricsCountryMapView-5r0SeCQw.js → MetricsCountryMapView-B9hNrGIG.js} +2 -2
- package/dist/chunks/{MetricsCountryMapView-5r0SeCQw.js.map → MetricsCountryMapView-B9hNrGIG.js.map} +1 -1
- package/dist/chunks/{Modal-Dgtnpj85.js → Modal-DfAzkbgB.js} +3 -3
- package/dist/chunks/{Modal-Dgtnpj85.js.map → Modal-DfAzkbgB.js.map} +1 -1
- package/dist/chunks/{Passkeys-B4bndv5b.js → Passkeys-C7YPKCKQ.js} +2 -2
- package/dist/chunks/{Passkeys-B4bndv5b.js.map → Passkeys-C7YPKCKQ.js.map} +1 -1
- package/dist/chunks/{TokenManager-DR5zQikX.js → TokenManager-CIGfr9LQ.js} +2 -2
- package/dist/chunks/{TokenManager-DR5zQikX.js.map → TokenManager-CIGfr9LQ.js.map} +1 -1
- package/dist/chunks/{User-DNifTiFu.js → User-DgB81g6W.js} +2 -2
- package/dist/chunks/{User-DNifTiFu.js.map → User-DgB81g6W.js.map} +1 -1
- package/dist/chunks/{UserProfileView-DugtA_qG.js → UserProfileView-Cn4x_As0.js} +2 -2
- package/dist/chunks/{UserProfileView-DugtA_qG.js.map → UserProfileView-Cn4x_As0.js.map} +1 -1
- package/dist/chunks/{WebApp-CNhEZYYG.js → WebApp-BLO494WW.js} +2 -2
- package/dist/chunks/{WebApp-CNhEZYYG.js.map → WebApp-BLO494WW.js.map} +1 -1
- package/dist/chunks/{admin-models-CdOCWMEj.js → admin-models-C8VPjEPG.js} +2 -2
- package/dist/chunks/{admin-models-CdOCWMEj.js.map → admin-models-C8VPjEPG.js.map} +1 -1
- package/dist/chunks/{exportChart-QDe89jLV.js → exportChart-9xYMybEK.js} +2 -2
- package/dist/chunks/{exportChart-QDe89jLV.js.map → exportChart-9xYMybEK.js.map} +1 -1
- package/dist/chunks/{index-D-gO-M9M.js → index-D09iCOVq.js} +2 -2
- package/dist/chunks/{index-D-gO-M9M.js.map → index-D09iCOVq.js.map} +1 -1
- package/dist/chunks/version-Bs_8ymHO.js +2 -0
- package/dist/chunks/version-Bs_8ymHO.js.map +1 -0
- package/dist/chunks/version-DlzdKqY9.js +2 -0
- package/dist/chunks/version-DlzdKqY9.js.map +1 -0
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +1 -1
- package/dist/map.es.js +1 -1
- package/dist/timeline.es.js +1 -1
- package/dist/user-profile.es.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/version-CBPFfIng.js +0 -2
- package/dist/chunks/version-CBPFfIng.js.map +0 -1
- package/dist/chunks/version-D8Oyq5Pb.js +0 -2
- package/dist/chunks/version-D8Oyq5Pb.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-models-CdOCWMEj.js","sources":["../../src/extensions/admin/models/LoginEvent.js","../../src/extensions/admin/models/Incident.js","../../src/extensions/admin/messaging/push/PushDeviceView.js","../../src/extensions/admin/models/Push.js","../../src/extensions/admin/models/Tickets.js","../../src/extensions/admin/models/Assistant.js","../../src/extensions/admin/models/Job.js","../../src/extensions/admin/models/Email.js","../../src/extensions/admin/models/PublicMessage.js","../../src/extensions/admin/models/Phonehub.js","../../src/extensions/admin/models/JobRunner.js","../../src/extensions/admin/models/Bouncer.js","../../src/extensions/admin/models/IPSet.js","../../src/extensions/admin/models/AWS.js","../../src/extensions/admin/models/ScheduledTask.js"],"sourcesContent":["/**\n * LoginEvent - Model for login event records with geolocation data\n * Used for login location maps and anomaly detection in admin portals.\n *\n * API: GET /api/account/logins\n * Permissions: manage_users + security + users\n */\n\nimport Model from '@core/Model.js';\nimport Collection from '@core/Collection.js';\n\nclass LoginEvent extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/account/logins',\n });\n }\n}\n\nclass LoginEventList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: LoginEvent,\n endpoint: '/api/account/logins',\n ...options,\n });\n }\n}\n\nexport { LoginEvent, LoginEventList };\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * IncidentEvent\n * ========================= */\n class IncidentStats extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/stats',\n requiresId: false\n });\n }\n }\n\n\nclass IncidentEvent extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event',\n });\n }\n}\n\nclass IncidentEventList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentEvent,\n endpoint: '/api/incident/event',\n size: 10,\n ...options,\n });\n }\n}\n\nconst IncidentEventForms = {\n edit: {\n title: 'Edit Incident Event',\n fields: [\n {\n name: 'category',\n type: 'select',\n label: 'Category',\n placeholder: 'Select category',\n options: () => Incident.COMPONENTS,\n editable: true,\n force_top: true,\n cols: 6,\n },\n {\n name: 'incident',\n type: 'text',\n label: 'Incident',\n placeholder: 'Enter Incident ID',\n cols: 6,\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Description',\n placeholder: 'Enter Description',\n cols: 12,\n },\n {\n name: 'details',\n type: 'textarea',\n label: 'Details',\n placeholder: 'Enter Details',\n cols: 12,\n },\n {\n name: 'component',\n type: 'text',\n label: 'Component',\n placeholder: 'Enter Component',\n cols: 8,\n },\n {\n name: 'component_id',\n type: 'text',\n label: 'Component ID',\n placeholder: 'Enter Component ID',\n cols: 4,\n },\n ],\n },\n};\n\n/* =========================\n * Incident\n * ========================= */\nclass Incident extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/incident',\n });\n }\n}\n\nclass IncidentList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Incident,\n endpoint: '/api/incident/incident',\n size: 10,\n ...options,\n });\n }\n}\n\nconst IncidentForms = {\n create: {\n title: 'Create Incident',\n fields: [\n {\n type: 'tabset',\n name: 'settingsTabs',\n tabs: [\n {\n label: 'General',\n fields: [\n {\n name: 'title',\n type: 'text',\n label: 'Title',\n required: true,\n columns: 12\n },\n {\n name: 'details',\n type: 'textarea',\n label: 'Details',\n required: true,\n columns: 12\n },\n\n ]\n },\n {\n label: 'Advanced',\n fields: [\n {\n name: 'priority',\n type: 'select',\n label: 'Priority',\n options: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],\n value: 5,\n columns: 6\n },\n {\n name: 'status',\n type: 'select',\n label: 'Status',\n value: 'open',\n options: ['open', 'investigating', 'resolved', 'closed', \"paused\", \"ignored\"],\n columns: 6\n },\n {\n name: 'category',\n type: 'text',\n label: 'Category',\n value: 'manual',\n columns: 6\n },\n ]\n },\n {\n label: 'Metadata',\n fields: [\n {\n name: 'metadata',\n type: 'json',\n label: 'Metadata',\n value: { \"example\": \"hello world\" },\n rows: 15,\n columns: 12\n }\n ]\n }\n ]\n },\n\n ]\n },\n edit: {\n title: 'Edit Incident',\n fields: [\n {\n name: 'category',\n type: 'text',\n label: 'Category',\n cols: 6,\n },\n {\n name: 'status',\n type: 'select',\n label: 'Status',\n placeholder: 'Select Status',\n options: ['open', 'investigating', 'resolved', 'closed', 'paused', 'ignored'],\n cols: 3,\n },\n {\n name: 'priority',\n type: 'text',\n label: 'Priority',\n },\n {\n name: 'details',\n type: 'textarea',\n label: 'Description',\n placeholder: 'Enter Name',\n cols: 12,\n },\n {\n name: 'model_name',\n type: 'text',\n label: 'Model',\n placeholder: 'Enter Model',\n cols: 8,\n },\n {\n name: 'model_id',\n type: 'text',\n label: 'Model ID',\n placeholder: 'Enter Model ID',\n cols: 4,\n },\n ],\n },\n};\n\n/* =========================\n * RuleSet / Rule\n * ========================= */\nclass IncidentRuleSet extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset',\n });\n }\n}\n\nclass IncidentRuleSetList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentRuleSet,\n endpoint: '/api/incident/event/ruleset',\n size: 10,\n ...options,\n });\n }\n}\n\nclass IncidentRule extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset/rule',\n });\n }\n}\n\nclass IncidentRuleList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentRule,\n endpoint: '/api/incident/event/ruleset/rule',\n size: 10,\n ...options,\n });\n }\n}\n\n/* =========================\n * IncidentHistory\n * ========================= */\nclass IncidentHistory extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/incident/history',\n });\n }\n}\n\nclass IncidentHistoryList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentHistory,\n endpoint: '/api/incident/incident/history',\n size: 10,\n ...options,\n });\n }\n}\n\n/**\n * RelatedIncidentsList - Incidents related by source / rule / group / host / category / status.\n *\n * Backs IncidentView's \"Related Incidents\" section. Pass any subset of:\n * - `sourceIp` → `?source_ip=<ip>`\n * - `ruleSet` → `?rule_set=<id>`\n * - `group` → `?group=<id>`\n * - `hostname` → `?hostname=<host>`\n * - `category` → `?category=<value>`\n * - `status` → `?status=<value>`\n *\n * Note: Incident has no `user` FK — only `group`. Don't pass `user`;\n * use `group` to scope to a user's primary group.\n *\n * @example\n * const related = new RelatedIncidentsList({\n * sourceIp: incident.get('source_ip'),\n * ruleSet: incident.get('rule_set'),\n * status: 'new'\n * });\n * await related.fetch();\n */\nclass RelatedIncidentsList extends IncidentList {\n constructor(options = {}) {\n const {\n sourceIp,\n ruleSet,\n group,\n hostname,\n category,\n status,\n params = {},\n ...rest\n } = options;\n\n const filterParams = {\n ordering: '-modified',\n ...(sourceIp != null ? { source_ip: sourceIp } : {}),\n ...(ruleSet != null ? { rule_set: ruleSet } : {}),\n ...(group != null ? { group: group } : {}),\n ...(hostname != null ? { hostname: hostname } : {}),\n ...(category != null ? { category: category } : {}),\n ...(status != null ? { status: status } : {}),\n ...params\n };\n\n super({\n params: filterParams,\n ...rest,\n });\n }\n}\n\n\n// Wire form statics so admin TablePages can drop inline form configuration.\nIncident.ADD_FORM = IncidentForms.create;\nIncident.EDIT_FORM = IncidentForms.edit;\nIncidentEvent.EDIT_FORM = IncidentEventForms.edit;\n\nexport {\n IncidentEvent,\n IncidentEventList,\n IncidentEventForms,\n Incident,\n IncidentList,\n IncidentForms,\n IncidentRuleSet,\n IncidentRuleSetList,\n IncidentRule,\n IncidentRuleList,\n IncidentHistory,\n IncidentHistoryList,\n RelatedIncidentsList\n};\n\n/* =========================\n * RuleSet\n * ========================= */\n\n// Bundle By Options\nconst BundleByOptions = [\n { value: 0, label: 'No Bundling' },\n { value: 1, label: 'By Hostname' },\n { value: 2, label: 'By Model Name' },\n { value: 3, label: 'By Model Name + ID' },\n { value: 4, label: 'By Source IP' },\n { value: 5, label: 'By Hostname + Model Name' },\n { value: 6, label: 'By Hostname + Model Name + ID' },\n { value: 7, label: 'By Source IP + Model Name' },\n { value: 8, label: 'By Source IP + Model Name + ID' },\n { value: 9, label: 'By Source IP + Hostname' }\n];\n\n// Match By Options\nconst MatchByOptions = [\n { value: 0, label: 'ALL (must match all rules)' },\n { value: 1, label: 'ANY (match any rule)' }\n];\n\n// Comparator Options\nconst ComparatorOptions = [\n { value: '==', label: 'Equal (==)' },\n { value: 'eq', label: 'Equal (eq)' },\n { value: '>', label: 'Greater Than (>)' },\n { value: '>=', label: 'Greater Than or Equal (>=)' },\n { value: '<', label: 'Less Than (<)' },\n { value: '<=', label: 'Less Than or Equal (<=)' },\n { value: 'contains', label: 'Contains' },\n { value: 'regex', label: 'Regular Expression' }\n];\n\n// Value Type Options\nconst ValueTypeOptions = [\n { value: 'str', label: 'String' },\n { value: 'int', label: 'Integer' },\n { value: 'float', label: 'Float' },\n { value: 'bool', label: 'Boolean' }\n];\n\n// Common Event Fields for ComboInput\nconst CommonEventFields = [\n { value: 'level', label: 'Level', description: 'Event level (error, warning, info, debug)', meta: { type: 'str' } },\n { value: 'source_ip', label: 'Source IP Address', description: 'IP address of the event source', meta: { type: 'str' } },\n { value: 'rule_id', label: 'Rule ID', description: 'Numeric rule identifier', meta: { type: 'int' } },\n { value: 'hostname', label: 'Hostname', description: 'Hostname where event occurred', meta: { type: 'str' } },\n { value: 'component', label: 'Component', description: 'System component name', meta: { type: 'str' } },\n { value: 'component_id', label: 'Component ID', description: 'Component identifier', meta: { type: 'str' } },\n { value: 'category', label: 'Category', description: 'Event category (ossec, auth, api_error, etc.)', meta: { type: 'str' } },\n { value: 'description', label: 'Description', description: 'Event description text', meta: { type: 'str' } },\n { value: 'details', label: 'Details', description: 'Additional event details', meta: { type: 'str' } },\n { value: 'alert_id', label: 'Alert ID', description: 'Numeric alert identifier', meta: { type: 'int' } },\n { value: 'severity', label: 'Severity', description: 'Numeric severity level', meta: { type: 'int' } },\n { value: 'user', label: 'User', description: 'Username associated with event', meta: { type: 'str' } },\n { value: 'action', label: 'Action', description: 'Action that triggered the event', meta: { type: 'str' } },\n { value: 'status', label: 'Status', description: 'Status value or code', meta: { type: 'str' } },\n { value: 'status_code', label: 'Status Code', description: 'Numeric status code (e.g., HTTP status)', meta: { type: 'int' } },\n { value: 'message', label: 'Message', description: 'Event message text', meta: { type: 'str' } },\n { value: 'path', label: 'Path', description: 'File path or URL path', meta: { type: 'str' } },\n { value: 'title', label: 'Title', description: 'OSSEC Title', meta: { type: 'str' } },\n { value: 'country_code', label: 'Country Code', description: 'Country code associated with event', meta: { type: 'str' } },\n { value: 'region', label: 'Region', description: 'Region associated with event', meta: { type: 'str' } },\n { value: 'city', label: 'City', description: 'City associated with event', meta: { type: 'str' } },\n { value: 'http_user_agent', label: 'HTTP User Agent', description: 'User agent string associated with event', meta: { type: 'str' } },\n { value: 'request_path', label: 'Request Path', description: 'Request path associated with event', meta: { type: 'str' } },\n { value: 'method', label: 'Method', description: 'HTTP method or function name', meta: { type: 'str' } }\n];\n\nconst CommonCategoryOptions = [\n // Scopes\n 'global', 'account', 'ossec', 'api', 'realtime',\n // Auth & Login\n 'auth', 'login:unknown', 'invalid_password',\n 'sms:login_unknown', 'totp:login_unknown',\n 'reset:unknown', 'magic:unknown', 'token:unknown',\n // Permissions\n 'api_denied', 'unauthenticated',\n 'view_permission_denied', 'edit_permission_denied',\n 'group_member_permission_denied', 'user_permission_denied',\n // Security\n 'security_alert',\n // MFA\n 'totp:confirm_failed', 'totp:login_failed', 'totp:recovery_used',\n 'sms:otp_failed',\n // Email & SMS\n 'email:no_mailbox', 'email:send_failed', 'sms:send_failed',\n // Account Changes\n 'email_change:bad_password', 'email_change:requested',\n 'account:deactivate_requested',\n 'phone_verify:invalid', 'email_verify:invalid',\n // OAuth\n 'oauth:unlink_guard_error',\n // Errors\n 'rest_error', 'mojo_rest_error', 'rest_value_error'\n];\n\n// Keep backward compat alias\nconst CommonScopeOptions = CommonCategoryOptions;\n\nclass RuleSet extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset',\n });\n }\n}\n\nclass RuleSetList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: RuleSet,\n endpoint: '/api/incident/event/ruleset',\n ...options,\n });\n }\n}\n\nconst BundleMinutesOptions = [\n { value: 0, label: \"Disabled — each event gets its own incident\" },\n { value: 5, label: \"5 minutes\" },\n { value: 10, label: \"10 minutes\" },\n { value: 15, label: \"15 minutes\" },\n { value: 30, label: \"30 minutes\" },\n { value: 60, label: \"1 hour\" },\n { value: 120, label: \"2 hours\" },\n { value: 360, label: \"6 hours\" },\n { value: 720, label: \"12 hours\" },\n { value: 1440, label: \"1 day\" },\n { value: null, label: \"No limit — bundle forever\" }\n];\n\nconst RuleSetForms = {\n create: {\n title: 'Create RuleSet',\n size: 'lg',\n fields: [\n {\n type: 'tabset',\n name: 'rulesetTabs',\n tabs: [\n {\n label: 'General',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'e.g., Brute Force Detection',\n columns: 6\n },\n {\n name: 'match_by',\n type: 'select',\n label: 'Match Logic',\n value: 0,\n options: MatchByOptions,\n tooltip: 'ALL = every condition must match. ANY = at least one',\n columns: 6\n },\n {\n name: 'category',\n type: 'combo',\n label: 'Scope / Category',\n required: true,\n options: CommonCategoryOptions,\n allowCustom: true,\n placeholder: 'Type or select...',\n tooltip: 'Scope or event category to match. Use * as a catch-all',\n columns: 6\n },\n {\n name: 'priority',\n type: 'number',\n label: 'Evaluation Priority',\n value: 10,\n required: true,\n tooltip: 'Lower number = evaluated first',\n columns: 6\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n value: true,\n tooltip: 'Inactive rules are skipped during event processing',\n columns: 6\n },\n {\n name: 'metadata.delete_on_resolution',\n type: 'switch',\n label: 'Delete on Resolution',\n value: false,\n tooltip: 'Incidents are permanently deleted when resolved or closed (CASCADE)',\n columns: 6\n }\n ]\n },\n {\n label: 'Bundling',\n fields: [\n {\n name: 'bundle_by',\n type: 'select',\n label: 'Bundle By',\n value: 4,\n options: BundleByOptions,\n tooltip: 'How to group related events into one incident',\n columns: 6\n },\n {\n name: 'bundle_minutes',\n type: 'select',\n label: 'Bundle Window',\n value: 30,\n options: BundleMinutesOptions,\n tooltip: 'Events outside this window create a new incident',\n columns: 6\n },\n {\n name: 'bundle_by_rule_set',\n type: 'switch',\n label: 'Bundle by RuleSet',\n value: true,\n tooltip: 'Group events matched by this rule into the same incident',\n columns: 6\n }\n ]\n },\n {\n label: 'Thresholds',\n fields: [\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-info-circle me-1\"></i>\n <strong>How thresholds work:</strong> Events accumulate in \"pending\" status.\n Once trigger count is reached, the handler fires and the incident becomes \"new\".\n Leave empty to fire immediately on the first event.\n </div>`\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mb-1\"><span class=\"badge bg-secondary me-1\">1</span> Count — events before fire</div>`\n },\n {\n name: 'trigger_count',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire immediately on first event',\n tooltip: 'Number of events before the handler fires',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">2</span> Within window — count only events in this many minutes</div>`\n },\n {\n name: 'trigger_window',\n type: 'number',\n label: '',\n placeholder: 'Empty = count all events regardless of age',\n tooltip: 'Only count events within this many minutes',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">3</span> Re-trigger — re-fire handler every N additional events</div>`\n },\n {\n name: 'retrigger_every',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire once only',\n tooltip: 'Re-fire handler every N additional events after initial trigger',\n columns: 12\n }\n ]\n },\n {\n label: 'Handler',\n fields: [\n {\n name: 'handler',\n type: 'text',\n label: 'Handler Chain',\n placeholder: 'e.g., block://?ttl=3600,ticket://?priority=8',\n tooltip: 'Chain multiple handlers with commas',\n columns: 12\n },\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-light border small mb-0\">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>`\n }\n ]\n },\n {\n label: 'Agent',\n fields: [\n {\n type: 'html', columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-stars me-1\"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>`\n },\n {\n name: 'metadata.agent_prompt',\n type: 'textarea',\n label: 'Agent Prompt',\n rows: 12,\n columns: 12,\n placeholder: 'You are a security analyst triaging…',\n tooltip: 'Free-form prompt the LLM handler receives alongside the structured incident summary'\n }\n ]\n }\n ]\n }\n ]\n },\n edit: {\n title: 'Edit RuleSet',\n size: 'lg',\n fields: [\n {\n type: 'tabset',\n name: 'rulesetTabs',\n tabs: [\n {\n label: 'General',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'e.g., Brute Force Detection',\n columns: 6\n },\n {\n name: 'match_by',\n type: 'select',\n label: 'Match Logic',\n options: MatchByOptions,\n tooltip: 'ALL = every condition must match. ANY = at least one',\n columns: 6\n },\n {\n name: 'category',\n type: 'combo',\n label: 'Scope / Category',\n options: CommonCategoryOptions,\n allowCustom: true,\n required: true,\n placeholder: 'Type or select...',\n tooltip: 'Scope or event category to match. Use * as a catch-all',\n columns: 6\n },\n {\n name: 'priority',\n type: 'number',\n label: 'Evaluation Priority',\n required: true,\n tooltip: 'Lower number = evaluated first',\n columns: 6\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n tooltip: 'Inactive rules are skipped during event processing',\n columns: 6\n },\n {\n name: 'metadata.delete_on_resolution',\n type: 'switch',\n label: 'Delete on Resolution',\n tooltip: 'Incidents are permanently deleted when resolved or closed (CASCADE)',\n columns: 6\n }\n ]\n },\n {\n label: 'Bundling',\n fields: [\n {\n name: 'bundle_by',\n type: 'select',\n label: 'Bundle By',\n options: BundleByOptions,\n tooltip: 'How to group related events into one incident',\n columns: 6\n },\n {\n name: 'bundle_minutes',\n type: 'select',\n label: 'Bundle Window',\n options: BundleMinutesOptions,\n tooltip: 'Events outside this window create a new incident',\n columns: 6\n },\n {\n name: 'bundle_by_rule_set',\n type: 'switch',\n label: 'Bundle by RuleSet',\n tooltip: 'Group events matched by this rule into the same incident',\n columns: 6\n }\n ]\n },\n {\n label: 'Thresholds',\n fields: [\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-info-circle me-1\"></i>\n <strong>How thresholds work:</strong> Events accumulate in \"pending\" status.\n Once trigger count is reached, the handler fires and the incident becomes \"new\".\n Leave empty to fire immediately on the first event.\n </div>`\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mb-1\"><span class=\"badge bg-secondary me-1\">1</span> Count — events before fire</div>`\n },\n {\n name: 'trigger_count',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire immediately on first event',\n tooltip: 'Number of events before the handler fires',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">2</span> Within window — count only events in this many minutes</div>`\n },\n {\n name: 'trigger_window',\n type: 'number',\n label: '',\n placeholder: 'Empty = count all events regardless of age',\n tooltip: 'Only count events within this window toward the trigger count',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">3</span> Re-trigger — re-fire handler every N additional events</div>`\n },\n {\n name: 'retrigger_every',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire once only',\n tooltip: 'Re-fire handler every N additional events after initial trigger',\n columns: 12\n }\n ]\n },\n {\n label: 'Handler',\n fields: [\n {\n name: 'handler',\n type: 'text',\n label: 'Handler Chain',\n placeholder: 'e.g., block://?ttl=3600,ticket://?priority=8',\n tooltip: 'Chain multiple handlers with commas',\n columns: 12\n },\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-light border small mb-0\">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>`\n }\n ]\n },\n {\n label: 'Agent',\n fields: [\n {\n type: 'html', columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-stars me-1\"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>`\n },\n {\n name: 'metadata.agent_prompt',\n type: 'textarea',\n label: 'Agent Prompt',\n rows: 12,\n columns: 12,\n placeholder: 'You are a security analyst triaging…',\n tooltip: 'Free-form prompt the LLM handler receives alongside the structured incident summary'\n }\n ]\n }\n ]\n }\n ]\n }\n};\n\n/* =========================\n * Rule\n * ========================= */\nclass Rule extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset/rule',\n });\n }\n}\n\nclass RuleList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Rule,\n endpoint: '/api/incident/event/ruleset/rule',\n ...options,\n });\n }\n}\n\nconst RuleForms = {\n create: {\n title: 'Create Rule',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'Enter rule name',\n cols: 12\n },\n {\n name: 'field_name',\n type: 'combo',\n label: 'Field Name',\n required: true,\n placeholder: 'Select or enter field name...',\n options: CommonEventFields,\n allowCustom: true,\n showDescription: true,\n help: 'Select a common field or type a custom field name',\n cols: 8\n },\n {\n name: 'index',\n type: 'select',\n label: 'Index',\n required: true,\n start: 0,\n end: 14,\n step: 1,\n cols: 4\n },\n {\n name: 'comparator',\n type: 'select',\n label: 'Comparator',\n required: true,\n options: ComparatorOptions,\n cols: 6\n },\n {\n name: 'value_type',\n type: 'select',\n label: 'Value Type',\n required: true,\n options: ValueTypeOptions,\n value: 'str',\n cols: 6\n },\n {\n name: 'value',\n type: 'textarea',\n label: 'Value',\n required: true,\n placeholder: 'Enter comparison value',\n cols: 12\n }\n ]\n },\n edit: {\n title: 'Edit Rule',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'Enter rule name',\n cols: 12\n },\n {\n name: 'field_name',\n type: 'combo',\n label: 'Field Name',\n required: true,\n placeholder: 'Select or enter field name...',\n options: CommonEventFields,\n allowCustom: true,\n showDescription: true,\n help: 'Select a common field or type a custom field name',\n cols: 12\n },\n {\n name: 'comparator',\n type: 'select',\n label: 'Comparator',\n required: true,\n options: ComparatorOptions,\n cols: 6\n },\n {\n name: 'value_type',\n type: 'select',\n label: 'Value Type',\n required: true,\n options: ValueTypeOptions,\n cols: 6\n },\n {\n name: 'value',\n type: 'text',\n label: 'Value',\n required: true,\n placeholder: 'Enter comparison value',\n cols: 12\n }\n ]\n }\n};\n\n// Attach forms to models\nRuleSet.EDIT_FORM = RuleSetForms.edit;\nRuleSet.ADD_FORM = RuleSetForms.create;\nRuleSet.CREATE_FORM = RuleSetForms.create; // Alias for compatibility\nRuleSet.BundleByOptions = BundleByOptions;\nRuleSet.MatchByOptions = MatchByOptions;\n\nRule.EDIT_FORM = RuleForms.edit;\nRule.ADD_FORM = RuleForms.create;\nRule.CREATE_FORM = RuleForms.create; // Alias for compatibility\nRule.ComparatorOptions = ComparatorOptions;\nRule.ValueTypeOptions = ValueTypeOptions;\n\nexport {\n RuleSet,\n RuleSetList,\n RuleSetForms,\n Rule,\n RuleList,\n RuleForms,\n IncidentStats,\n BundleByOptions,\n BundleMinutesOptions,\n MatchByOptions,\n ComparatorOptions,\n ValueTypeOptions,\n CommonEventFields,\n CommonCategoryOptions,\n CommonScopeOptions\n};\n","import View from '@core/View.js';\nimport DataView from '@core/views/data/DataView.js';\n\nclass PushDeviceView extends View {\n constructor(options = {}) {\n super({\n className: 'push-device-view',\n ...options\n });\n this.model = options.model;\n }\n\n getTemplate() {\n return `\n <div class=\"p-3\">\n <h3>{{model.device_name}}</h3>\n <p class=\"text-muted\">{{model.user.display_name}}</p>\n <div data-container=\"data-view\"></div>\n </div>\n `;\n }\n\n onInit() {\n this.dataView = new DataView({\n containerId: 'data-view',\n model: this.model,\n fields: [\n { name: 'platform', label: 'Platform', format: 'badge' },\n { name: 'push_enabled', label: 'Push Enabled', format: 'boolean' },\n { name: 'app_version', label: 'App Version' },\n { name: 'os_version', label: 'OS Version' },\n { name: 'last_seen', label: 'Last Seen', format: 'datetime' },\n { name: 'push_preferences', label: 'Preferences', format: 'json' },\n ]\n });\n this.addChild(this.dataView);\n }\n}\n\nexport default PushDeviceView;\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport { GroupList } from '@core/models/Group.js';\nimport PushDeviceView from '@ext/admin/messaging/push/PushDeviceView.js';\n\n// =========================\n// PushDevice\n// =========================\nclass PushDevice extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push' });\n }\n}\n\nclass PushDeviceList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushDevice, endpoint: '/api/account/devices/push', ...options });\n }\n}\n\n// =========================\n// PushTemplate\n// =========================\nclass PushTemplate extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push/templates' });\n }\n}\n\nclass PushTemplateList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushTemplate, endpoint: '/api/account/devices/push/templates', ...options });\n }\n}\n\n// =========================\n// PushConfig\n// =========================\nclass PushConfig extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push/config' });\n }\n}\n\nclass PushConfigList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushConfig, endpoint: '/api/account/devices/push/config', ...options });\n }\n}\n\n// =========================\n// PushDelivery\n// =========================\nclass PushDelivery extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push/deliveries' });\n }\n}\n\nclass PushDeliveryList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushDelivery, endpoint: '/api/account/devices/push/deliveries', ...options });\n }\n}\n\n// =========================\n// Forms\n// =========================\nconst PushConfigForms = {\n create: {\n title: 'Create Push Configuration',\n fields: [\n { name: 'name', label: 'Name', required: true },\n { type: 'collection', name: 'group', label: 'Group (optional)', Collection: GroupList, labelField: 'name', valueField: 'id' },\n { name: 'fcm_service_account', label: 'Service Account', type: \"textarea\", rows: 10},\n ]\n },\n edit: {\n title: 'Edit Push Configuration',\n fields: [\n { name: 'name', label: 'Name', required: true },\n { type: 'collection', name: 'group', label: 'Group (optional)', Collection: GroupList, labelField: 'name', valueField: 'id' },\n { name: 'fcm_service_account', label: 'Service Account', type: \"textarea\", rows: 10},\n { name: 'is_active', label: 'Is Active', type: 'switch', value: true },\n ]\n }\n};\n\nconst PushTemplateForms = {\n edit: {\n title: 'Edit Push Template',\n fields: [\n { name: 'name', label: 'Name', required: true },\n { name: 'category', label: 'Category', required: true },\n { \n type: 'collection', \n name: 'group', \n label: 'Group (optional)', \n Collection: GroupList, \n labelField: 'name', \n valueField: 'id',\n defaultParams: { is_active: true } // Example: filter to active groups only\n },\n { name: 'title_template', label: 'Title Template', required: true },\n { name: 'body_template', label: 'Body Template', type: 'textarea', required: true },\n { name: 'action_url', label: 'Action URL' },\n { name: 'priority', label: 'Priority', type: 'select', options: ['high', 'normal'] },\n { name: 'variables', label: 'Variables', type: 'json', help: 'JSON format' },\n { name: 'is_active', label: 'Is Active', type: 'switch' },\n ]\n }\n};\n\nPushConfigForms.create = PushConfigForms.edit;\nPushTemplateForms.create = PushTemplateForms.edit;\n\n// Wire form + view-class statics so admin TablePages can drop inline config.\nPushConfig.ADD_FORM = PushConfigForms.create;\nPushConfig.EDIT_FORM = PushConfigForms.edit;\nPushTemplate.ADD_FORM = PushTemplateForms.create;\nPushTemplate.EDIT_FORM = PushTemplateForms.edit;\nPushDevice.VIEW_CLASS = PushDeviceView;\n\n\nexport {\n PushDevice, PushDeviceList,\n PushTemplate, PushTemplateList,\n PushConfig, PushConfigList,\n PushDelivery, PushDeliveryList,\n PushConfigForms, PushTemplateForms\n};\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport { UserList } from '@core/models/User.js';\nimport { IncidentList } from './Incident.js';\n\n/* =========================\n * Ticket\n * ========================= */\nclass Ticket extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/ticket',\n });\n }\n}\n\nclass TicketList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Ticket,\n endpoint: '/api/incident/ticket',\n ...options,\n });\n }\n}\n\n\nconst TicketCategories = {\n 'ticket': 'Ticket',\n 'bug': 'Bug',\n 'feature': 'Feature Request',\n 'incident': 'Incident',\n 'security': 'Security Incident',\n 'fulfillment': 'Fulfillment',\n 'new_user': 'New User',\n 'new_group': 'New Group',\n 'qa': 'Quality Assurance'\n};\n\n// Convert TicketCategories to select options\nconst TicketCategoriesOptions = Object.entries(TicketCategories).map(([key, label]) => ({\n value: key,\n label: label\n}));\n\n\nconst TicketForms = {\n create: {\n title: 'Create Ticket',\n fields: [\n {\n name: 'title', type: 'text',\n label: 'Title', required: true, cols: 12\n },\n { name: 'description', type: 'textarea', label: 'Description', required: false, cols: 12 },\n {\n name: \"category\", type: \"select\", label: \"Category\",\n options: TicketCategoriesOptions, cols: 12, value: 'ticket' },\n {\n name: 'priority', type: 'number',\n label: 'Priority', value: 5, cols: 6\n },\n {\n name: 'status', type: 'select', label: \"Status\",\n options: [\"new\", \"open\", \"paused\", \"resolved\", \"qa\", \"ignored\"],\n cols: 6, value: 'new'\n },\n {\n type: 'collection', name: 'assignee',\n label: 'Assignee', Collection: UserList,\n labelField: 'display_name',\n valueField: 'id',\n cols: 12\n },\n {\n type: 'collection', name: 'incident',\n label: 'Incident', Collection: IncidentList,\n labelField: 'title',\n valueField: 'id',\n cols: 12\n },\n ]\n },\n edit: {\n title: 'Edit Ticket',\n fields: [\n // Description has its own dedicated edit dialog (with markdown helpers).\n { name: 'title', type: 'text', label: 'Title', required: true, cols: 12 },\n { name: \"category\", type: \"select\", label: \"Category\", options: TicketCategoriesOptions, cols: 12 },\n { name: 'priority', type: 'number', label: 'Priority', cols: 6 },\n { name: 'status', type: 'select', label: 'Status', options: [\"new\", \"open\", \"paused\", \"resolved\", \"qa\", \"ignored\"], cols: 6 },\n { type: 'collection', name: 'assignee', label: 'Assignee', Collection: UserList, labelField: 'display_name', valueField: 'id', cols: 12 },\n { type: 'collection', name: 'incident', label: 'Incident', Collection: IncidentList, labelField: 'title', valueField: 'id', cols: 12 },\n { name: 'enable_llm', type: 'checkbox', label: 'Enable AI agent', cols: 12 },\n ]\n }\n};\n\n/* =========================\n * TicketNote\n * ========================= */\nclass TicketNote extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/ticket/note',\n });\n }\n}\n\nclass TicketNoteList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: TicketNote,\n endpoint: '/api/incident/ticket/note',\n ...options,\n });\n }\n}\n\n// Wire form statics so TicketTablePage can drop inline form configuration.\nTicket.ADD_FORM = TicketForms.create;\nTicket.EDIT_FORM = TicketForms.edit;\n\nexport { Ticket, TicketList, TicketNote, TicketNoteList, TicketForms, TicketCategories };\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * AssistantConversation\n * ========================= */\nclass AssistantConversation extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/assistant/conversation',\n });\n }\n}\n\nclass AssistantConversationList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: AssistantConversation,\n endpoint: '/api/assistant/conversation',\n size: 50,\n ...options,\n });\n }\n}\n\n/* =========================\n * AssistantSkill\n * ========================= */\nclass AssistantSkill extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/assistant/skill',\n });\n }\n}\n\nclass AssistantSkillList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: AssistantSkill,\n endpoint: '/api/assistant/skill',\n size: 50,\n ...options,\n });\n }\n}\n\nexport {\n AssistantConversation,\n AssistantConversationList,\n AssistantSkill,\n AssistantSkillList\n};\n\nexport default AssistantConversation;\n","/**\n * Job Model - Async Job Engine management\n * Supports object-oriented POST_SAVE_ACTIONS pattern from Jobs API\n */\n\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport rest from '@core/Rest.js';\n\nclass Job extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/job'\n });\n }\n\n // Object-oriented actions using POST_SAVE_ACTIONS pattern\n async cancel() {\n const response = await this.save({ cancel_request: true });\n if (response.success && response.data.status) {\n // Update local status if successful\n this.set('cancel_requested', true);\n }\n return response;\n }\n\n async retry(delay = null) {\n const data = delay ?\n { retry_request: { retry: true, delay } } :\n { retry_request: true };\n\n const response = await this.save(data);\n if (response.success && response.data.status && response.data.new_job_id) {\n // Return new job ID if created\n return {\n ...response,\n newJobId: response.data.new_job_id,\n originalJobId: response.data.original_job_id\n };\n }\n return response;\n }\n\n async getDetailedStatus() {\n const response = await this.save({ get_status: true });\n if (response.success && response.data.status) {\n // Update local data with detailed status\n this.set(response.data.data);\n }\n return response;\n }\n\n async cloneJob(newPayload = {}) {\n const publishData = {\n publish_job: {\n payload: newPayload,\n ...newPayload\n }\n };\n\n const response = await this.save(publishData);\n if (response.success && response.data.status && response.data.job_id) {\n return {\n ...response,\n newJobId: response.data.job_id,\n templateJobId: response.data.template_job_id\n };\n }\n return response;\n }\n\n // Status helper methods\n isActive() {\n const status = this.get('status');\n return ['pending', 'running'].includes(status);\n }\n\n /**\n * A pending job with a future `run_at` is \"scheduled\" — it isn't\n * actively waiting in the queue, it'll be enqueued when run_at hits.\n * Treat it as a distinct UI state.\n */\n isScheduled() {\n if (this.get('status') !== 'pending') return false;\n const runAt = this.get('run_at');\n if (!runAt) return false;\n const ms = (typeof runAt === 'number' && runAt < 1e11) ? runAt * 1000 : new Date(runAt).getTime();\n return Number.isFinite(ms) && ms > Date.now();\n }\n\n isTerminal() {\n const status = this.get('status');\n return ['completed', 'failed', 'canceled', 'expired'].includes(status);\n }\n\n canRetry() {\n const status = this.get('status');\n return ['failed', 'canceled', 'expired'].includes(status) && this.get('is_retriable') !== false;\n }\n\n canCancel() {\n const status = this.get('status');\n return ['pending', 'running'].includes(status) && !this.get('cancel_requested');\n }\n\n // Get status badge class for UI\n getStatusBadgeClass() {\n const status = this.get('status');\n const classes = {\n 'pending': 'bg-primary',\n 'running': 'bg-success',\n 'completed': 'bg-info',\n 'failed': 'bg-danger',\n 'canceled': 'bg-secondary',\n 'expired': 'bg-warning'\n };\n return classes[status] || 'bg-secondary';\n }\n\n // Get status icon\n getStatusIcon() {\n const status = this.get('status');\n const icons = {\n 'pending': 'bi-hourglass',\n 'running': 'bi-arrow-repeat',\n 'completed': 'bi-check-circle',\n 'failed': 'bi-x-octagon',\n 'canceled': 'bi-x-circle',\n 'expired': 'bi-clock'\n };\n return icons[status] || 'bi-question-circle';\n }\n\n // Get recent events for timeline\n getEvents() {\n return this.get('recent_events') || [];\n }\n\n // Get formatted duration\n getFormattedDuration() {\n const duration = this.get('duration_ms');\n if (!duration || duration === 0) return 'N/A';\n\n if (duration < 1000) return `${duration}ms`;\n if (duration < 60000) return `${(duration / 1000).toFixed(1)}s`;\n if (duration < 3600000) return `${(duration / 60000).toFixed(1)}m`;\n return `${(duration / 3600000).toFixed(1)}h`;\n }\n\n // Get queue position if available\n getQueuePosition() {\n return this.get('queue_position');\n }\n\n // Check if job has expired\n hasExpired() {\n const expiresAt = this.get('expires_at');\n if (!expiresAt) return false;\n return new Date(expiresAt) < new Date();\n }\n\n // Get runner information\n getRunnerId() {\n return this.get('runner_id');\n }\n\n // Get payload data\n getPayload() {\n return this.get('payload') || {};\n }\n\n // Get metadata\n getMetadata() {\n return this.get('metadata') || {};\n }\n}\n\nclass JobList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Job,\n endpoint: '/api/jobs/job',\n ...options\n });\n }\n\n // Filter by status\n async fetchByStatus(status, params = {}) {\n return this.fetch({ status, ...params });\n }\n\n // Filter by channel\n async fetchByChannel(channel, params = {}) {\n return this.fetch({ channel, ...params });\n }\n\n // Get pending jobs\n async fetchPending(params = {}) {\n return this.fetchByStatus('pending', params);\n }\n\n // Get running jobs\n async fetchRunning(params = {}) {\n return this.fetchByStatus('running', params);\n }\n\n // Get completed jobs\n async fetchCompleted(params = {}) {\n return this.fetchByStatus('completed', params);\n }\n\n // Get failed jobs\n async fetchFailed(params = {}) {\n return this.fetchByStatus('failed', params);\n }\n\n // Get scheduled jobs (those with run_at)\n async fetchScheduled(params = {}) {\n return this.fetch({\n scheduled: true, // This may need to be adjusted based on actual API\n ...params\n });\n }\n}\n\n// Form configurations for job management\nconst JobForms = {\n publish: {\n title: 'Publish New Job',\n fields: [\n {\n name: 'func',\n type: 'text',\n label: 'Function',\n required: true,\n placeholder: 'myapp.jobs.send_email',\n help: 'Module path to job function'\n },\n {\n name: 'channel',\n type: 'text',\n label: 'Channel',\n value: 'default',\n help: 'Queue channel (default: \"default\")'\n },\n {\n name: 'payload',\n type: 'textarea',\n label: 'Payload (JSON)',\n required: true,\n rows: 8,\n placeholder: '{\\n \"key\": \"value\"\\n}',\n help: 'JSON data passed to the job function'\n },\n {\n name: 'delay',\n type: 'number',\n label: 'Delay (seconds)',\n min: 0,\n help: 'Delay execution by specified seconds'\n },\n {\n name: 'run_at',\n type: 'datetime-local',\n label: 'Run At',\n help: 'Schedule for specific date/time'\n },\n {\n name: 'max_retries',\n type: 'number',\n label: 'Max Retries',\n value: 3,\n min: 0,\n max: 10\n },\n {\n name: 'expires_in',\n type: 'number',\n label: 'Expires In (seconds)',\n value: 900,\n min: 60,\n help: 'Job will expire if not completed in this time'\n },\n {\n name: 'broadcast',\n type: 'switch',\n label: 'Broadcast to All Workers',\n help: 'Execute on all available workers'\n }\n ]\n },\n\n retry: {\n title: 'Retry Job',\n fields: [\n {\n name: 'delay',\n type: 'number',\n label: 'Delay (seconds)',\n value: 0,\n min: 0,\n help: 'Delay before retry (0 = immediate)'\n }\n ]\n },\n\n clone: {\n title: 'Clone Job',\n fields: [\n {\n name: 'channel',\n type: 'text',\n label: 'Channel',\n help: 'Override channel for cloned job'\n },\n {\n name: 'payload',\n type: 'textarea',\n label: 'Modified Payload (JSON)',\n rows: 8,\n help: 'Modified payload for cloned job'\n },\n {\n name: 'delay',\n type: 'number',\n label: 'Delay (seconds)',\n min: 0\n }\n ]\n }\n};\n\n// Static method to publish new job directly\nJob.publish = async function(jobData) {\n return await rest.POST('/api/jobs/publish', jobData);\n};\n\n// Static method to get system stats\nJob.getStats = async function() {\n const response = await rest.GET('/api/jobs/stats');\n return response.success ? response.data : null;\n};\n\n// Static method to get system health\nJob.getHealth = async function(channel = null) {\n const endpoint = channel ? `/api/jobs/health/${channel}` : '/api/jobs/health';\n const response = rest.GET(endpoint);\n return response.success ? response.data : null;\n};\n\n// Static method to run test job\nJob.test = async function() {\n return await rest.POST('/api/jobs/test', {});\n};\n\n// Static method to run test jobs\nJob.tests = async function() {\n return await rest.POST('/api/jobs/tests', {});\n};\n\nJob.clearStuck = async function(channel = null) {\n const payload = channel ? { channel } : {};\n return await rest.POST('/api/jobs/control/clear-stuck', payload);\n};\n\nJob.clearChannel = async function(channel) {\n return await rest.POST('/api/jobs/control/clear-queue', { channel, confirm:\"yes\" });\n};\n\nJob.cleanConsumers = async function() {\n return await rest.POST('/api/jobs/control/cleanup-consumers');\n};\n\nJob.purgeJobs = async function(days_old) {\n return await rest.POST('/api/jobs/control/purge', { days_old });\n};\n\n\nclass JobLog extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/logs'\n });\n }\n}\n\nclass JobLogList extends Collection {\n constructor(options = {}) {\n super({\n endpoint: '/api/jobs/logs',\n model: JobLog,\n ...options\n });\n }\n}\n\n\nclass JobEvent extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/event'\n });\n }\n}\n\nclass JobEventList extends Collection {\n constructor(options = {}) {\n super({\n endpoint: '/api/jobs/event',\n model: JobEvent,\n ...options\n });\n }\n}\n\nclass JobsEngineStats extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/stats',\n requiresId: false\n });\n }\n}\n\n/**\n * SimilarJobsList - Recent runs of the same `func`.\n *\n * Backs JobDetailsView's \"Similar Jobs\" section. Consumers pass the\n * function name (or a Job model from which to read `func`) and an\n * optional row limit; the collection's `params` apply on every fetch.\n *\n * @example\n * const sj = new SimilarJobsList({ func: model.get('func') });\n * await sj.fetch();\n * // → GET /api/jobs/job?func=<name>&ordering=-created\n */\nclass SimilarJobsList extends JobList {\n constructor(options = {}) {\n const { func, params = {}, ...rest } = options;\n super({\n params: {\n ordering: '-created',\n ...(func ? { func } : {}),\n ...params\n },\n ...rest\n });\n }\n}\n\n/**\n * ActiveJobsList - Jobs currently running on a runner.\n *\n * Backs RunnerDetailsView's \"Active Jobs\" section. Pass the runner id\n * via `runnerId` (preferred) or as a custom param.\n *\n * @example\n * const aj = new ActiveJobsList({ runnerId: runner.get('runner_id') });\n * await aj.fetch();\n * // → GET /api/jobs/job?runner_id=<id>&status=running\n */\nclass ActiveJobsList extends JobList {\n constructor(options = {}) {\n const { runnerId, params = {}, ...rest } = options;\n super({\n params: {\n status: 'running',\n ...(runnerId != null ? { runner_id: runnerId } : {}),\n ...params\n },\n ...rest\n });\n }\n}\n\nexport {\n Job, JobList, JobForms,\n JobLog, JobLogList, JobEvent,\n JobEventList, JobsEngineStats,\n SimilarJobsList, ActiveJobsList };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport rest from '@core/Rest.js';\n\n\n/**\n * EmailDomain - SES/SNS/S3-backed email domain model\n * Maps to REST endpoints under /api/aws/email/domain\n *\n * Key operations:\n * - Create/Update/Delete domains\n * - Onboard: DNS records + SNS + optional receiving\n * - Audit: Drift report (verification/DKIM, topics, receipt rules)\n * - Reconcile: Safe, idempotent fixes (no DNS writes)\n *\n * Notes:\n * - Management endpoints require \"manage_aws\" permission server-side.\n * - Error handling follows the MOJO Rest response contract.\n */\nclass EmailDomain extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/domain',\n ...options\n });\n }\n\n /**\n * Onboard the domain (DNS/SNS/receiving orchestration).\n * POST /api/aws/email/domain/<id>/onboard\n *\n * @param {object} data\n * receiving_enabled?: boolean\n * s3_inbound_bucket?: string\n * s3_inbound_prefix?: string\n * ensure_mail_from?: boolean\n * mail_from_subdomain?: string\n * dns_mode?: \"manual\" | \"godaddy\"\n * godaddy_key?: string\n * godaddy_secret?: string\n * endpoints?: { bounce, complaint, delivery, inbound }\n * @param {object} options - Optional { params?: object }\n * @returns {Promise<object>} REST response\n */\n async onboard(data = {}, options = {}) {\n if (!this.id) {\n await this.showError('Cannot onboard domain without ID');\n return {\n success: false,\n status: 400,\n error: 'Missing domain id'\n };\n }\n\n try {\n const url = `${this.buildUrl(this.id)}/onboard`;\n const response = await this.rest.POST(url, data, options.params);\n\n // No guaranteed shape to merge; response contains DNS records, topics, notes, etc.\n // If backend returns updated domain fields, you can call this.set(response.data.data).\n return response;\n } catch (err) {\n return {\n success: false,\n status: err?.status || 500,\n error: err?.message || 'Failed to onboard domain'\n };\n }\n }\n\n /**\n * Audit domain configuration for drift.\n * GET or POST /api/aws/email/domain/<id>/audit\n *\n * @param {object} options\n * method?: 'GET'|'POST' (default 'GET')\n * data?: object (when method is POST)\n * params?: object (query params for GET)\n * @returns {Promise<object>} REST response\n */\n async audit(options = {}) {\n if (!this.id) {\n await this.showError('Cannot audit domain without ID');\n return {\n success: false,\n status: 400,\n error: 'Missing domain id'\n };\n }\n\n const method = (options.method || 'GET').toUpperCase();\n const url = `${this.buildUrl(this.id)}/audit`;\n\n try {\n if (method === 'POST') {\n return await this.rest.POST(url, options.data || {}, options.params);\n }\n return await this.rest.GET(url, options.params);\n } catch (err) {\n return {\n success: false,\n status: err?.status || 500,\n error: err?.message || 'Failed to audit domain'\n };\n }\n }\n\n /**\n * Reconcile domain configuration (safe fixes; no DNS writes).\n * POST /api/aws/email/domain/<id>/reconcile\n *\n * @param {object} data - Optional payload (usually none required)\n * @param {object} options - Optional { params?: object }\n * @returns {Promise<object>} REST response\n */\n async reconcile(data = {}, options = {}) {\n if (!this.id) {\n await this.showError('Cannot reconcile domain without ID');\n return {\n success: false,\n status: 400,\n error: 'Missing domain id'\n };\n }\n\n try {\n const url = `${this.buildUrl(this.id)}/reconcile`;\n return await this.rest.POST(url, data, options.params);\n } catch (err) {\n return {\n success: false,\n status: err?.status || 500,\n error: err?.message || 'Failed to reconcile domain'\n };\n }\n }\n\n /**\n * Convenience: Onboard by id without creating a separate instance.\n * @param {string|number} id\n * @param {object} data\n * @param {object} options\n */\n static async onboardById(id, data = {}, options = {}) {\n const model = new EmailDomain({ id }, options);\n return await model.onboard(data, options);\n }\n\n /**\n * Convenience: Audit by id without creating a separate instance.\n * @param {string|number} id\n * @param {object} options - see audit()\n */\n static async auditById(id, options = {}) {\n const model = new EmailDomain({ id }, options);\n return await model.audit(options);\n }\n\n /**\n * Convenience: Reconcile by id without creating a separate instance.\n * @param {string|number} id\n * @param {object} data\n * @param {object} options\n */\n static async reconcileById(id, data = {}, options = {}) {\n const model = new EmailDomain({ id }, options);\n return await model.reconcile(data, options);\n }\n}\n\n/**\n * EmailDomainList - Collection of EmailDomain\n * Supports standard MOJO list/search/sort/pagination patterns\n */\nclass EmailDomainList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: EmailDomain,\n endpoint: '/api/aws/email/domain',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for EmailDomain (for TablePage/Dialog integration)\n * NOTE: Conditional requirements (e.g., s3_inbound_bucket when receiving_enabled)\n * should be validated server-side; help text guides the admin.\n */\nconst EmailDomainForms = {\n create: {\n title: 'Add Email Domain',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Domain Name',\n placeholder: 'example.com',\n required: true,\n columns: 12,\n help: 'Enter the root domain to verify with SES (no protocol).'\n },\n {\n name: 'region',\n type: 'text',\n label: 'AWS Region (optional)',\n placeholder: 'us-east-1',\n columns: 12,\n help: 'Optional. Defaults to project AWS_REGION if omitted.'\n },\n {\n name: 'aws_key',\n type: 'text',\n label: 'AWS Key (optional)',\n placeholder: 'enter your AWS Key with SES permissions',\n columns: 12,\n help: 'Optional, AWS Key with SES permissions'\n },\n {\n name: 'aws_secret',\n type: 'text',\n label: 'AWS Secret (optional)',\n placeholder: 'enter your AWS Secret with SES permissions',\n columns: 12,\n help: 'Optional, AWS Secret with SES permissions'\n },\n {\n name: 'receiving_enabled',\n type: 'switch',\n label: 'Enable Inbound Receiving',\n columns: 12,\n help: 'Catch-all SES receipt rule to S3 + SNS; routing is done in-app.'\n }\n ]\n },\n\n edit: {\n title: 'Edit Email Domain',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Domain Name',\n placeholder: 'example.com',\n required: true,\n columns: 12,\n readonly: true,\n help: 'Domain name cannot be changed after creation.'\n },\n {\n name: 'region',\n type: 'text',\n label: 'AWS Region',\n placeholder: 'us-east-1',\n columns: 12\n },\n {\n name: 'receiving_enabled',\n type: 'switch',\n label: 'Enable Inbound Receiving',\n columns: 12\n },\n {\n name: 's3_inbound_bucket',\n type: 'text',\n label: 'Inbound S3 Bucket',\n placeholder: 'my-inbound-bucket',\n columns: 12\n },\n {\n name: 's3_inbound_prefix',\n type: 'text',\n label: 'Inbound S3 Prefix',\n placeholder: 'inbound/example.com/',\n columns: 12\n },\n {\n name: 'dns_mode',\n type: 'select',\n label: 'DNS Mode',\n options: [\n { value: 'manual', text: 'Manual (show records)' },\n { value: 'godaddy', text: 'GoDaddy (apply via API)' }\n ],\n columns: 12\n }\n ],\n },\n\n credentials: {\n fields: [\n {\n name: 'region',\n type: 'select',\n label: 'AWS Region (optional)',\n placeholder: 'us-east-1',\n options: [\n { value: 'us-east-1', text: 'US East (N. Virginia)' },\n { value: 'us-east-2', text: 'US East (Ohio)' },\n { value: 'us-west-1', text: 'US West (N. California)' },\n { value: 'us-west-2', text: 'US West (Oregon)' },\n { value: 'ca-central-1', text: 'Canada (Central)' },\n { value: 'eu-west-1', text: 'Europe (Ireland)' },\n { value: 'eu-west-2', text: 'Europe (London)' },\n { value: 'eu-west-3', text: 'Europe (Paris)' },\n { value: 'eu-central-1', text: 'Europe (Frankfurt)' },\n { value: 'eu-north-1', text: 'Europe (Stockholm)' },\n { value: 'eu-south-1', text: 'Europe (Milan)' },\n { value: 'ap-southeast-2', text: 'Asia Pacific (Sydney)' }\n ],\n columns: 12,\n help: 'Optional. Defaults to project AWS_REGION if omitted.'\n },\n {\n name: 'aws_key',\n type: 'text',\n label: 'AWS Key (optional)',\n placeholder: 'enter your AWS Key with SES permissions',\n columns: 12,\n help: 'Optional, AWS Key with SES permissions'\n },\n {\n name: 'aws_secret',\n type: 'text',\n label: 'AWS Secret (optional)',\n placeholder: 'enter your AWS Secret with SES permissions',\n columns: 12,\n help: 'Optional, AWS Secret with SES permissions'\n },\n ]\n},\n\n onboard: {\n title: 'Onboard Domain',\n fields: [\n {\n type: 'header',\n text: 'Receiving',\n level: 6,\n className: 'mt-2'\n },\n {\n name: 'receiving_enabled',\n type: 'switch',\n label: 'Enable Inbound Receiving',\n columns: 12\n },\n {\n name: 's3_inbound_bucket',\n type: 'text',\n label: 'Inbound S3 Bucket',\n placeholder: 'my-inbound-bucket',\n columns: 12,\n help: 'Required if receiving is enabled.'\n },\n {\n name: 's3_inbound_prefix',\n type: 'text',\n label: 'Inbound S3 Prefix',\n placeholder: 'inbound/example.com/',\n columns: 12\n },\n\n {\n type: 'header',\n text: 'MAIL FROM (optional)',\n level: 6,\n className: 'mt-3'\n },\n {\n name: 'ensure_mail_from',\n type: 'switch',\n label: 'Ensure MAIL FROM Setup',\n columns: 12\n },\n {\n name: 'mail_from_subdomain',\n type: 'text',\n label: 'MAIL FROM Subdomain',\n placeholder: 'feedback',\n columns: 12\n },\n\n {\n type: 'header',\n text: 'DNS',\n level: 6,\n className: 'mt-3'\n },\n {\n name: 'dns_mode',\n type: 'select',\n label: 'DNS Mode',\n options: [\n { value: 'manual', text: 'Manual (show records)' },\n { value: 'godaddy', text: 'GoDaddy (apply via API)' }\n ],\n value: 'manual',\n columns: 12\n },\n {\n name: 'godaddy_key',\n type: 'text',\n label: 'GoDaddy API Key',\n columns: 12,\n help: 'Required when DNS Mode = GoDaddy.'\n },\n {\n name: 'godaddy_secret',\n type: 'password',\n label: 'GoDaddy API Secret',\n columns: 12\n },\n\n {\n type: 'header',\n text: 'Webhook Endpoints',\n level: 6,\n className: 'mt-3'\n },\n {\n name: 'endpoints.bounce',\n type: 'text',\n label: 'Bounce Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/bounce',\n columns: 12\n },\n {\n name: 'endpoints.complaint',\n type: 'text',\n label: 'Complaint Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/complaint',\n columns: 12\n },\n {\n name: 'endpoints.delivery',\n type: 'text',\n label: 'Delivery Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/delivery',\n columns: 12\n },\n {\n name: 'endpoints.inbound',\n type: 'text',\n label: 'Inbound Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/inbound',\n columns: 12\n }\n ]\n }\n};\n\n/**\n * Mailbox - Represents a single email address within a domain.\n * Endpoint: /api/aws/email/mailbox\n * Fields (typical):\n * - domain: FK (domain id) or name (server may accept name)\n * - email: full address\n * - allow_inbound: boolean\n * - allow_outbound: boolean\n * - async_handler: \"package.module:function\" for task dispatch on inbound\n */\nclass Mailbox extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/mailbox',\n ...options\n });\n }\n}\n\nMailbox.sendEmail = async function(data) {\n return await rest.POST('/api/aws/email/send', data);\n};\n\n/**\n * MailboxList - Collection of Mailboxes\n */\nclass MailboxList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Mailbox,\n endpoint: '/api/aws/email/mailbox',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for Mailbox CRUD\n */\nconst MailboxForms = {\n create: {\n title: 'Add Mailbox',\n fields: [\n {\n type: 'collection',\n name: 'domain',\n label: 'Domain',\n Collection: EmailDomainList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search domains...',\n emptyFetch: false,\n required: true,\n debounceMs: 300, // Search debounce delay\n columns: 12\n },\n {\n name: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'support@example.com',\n required: true,\n columns: 12\n },\n {\n name: 'allow_inbound',\n type: 'switch',\n label: 'Allow Inbound',\n columns: 6\n },\n {\n name: 'allow_outbound',\n type: 'switch',\n label: 'Allow Outbound',\n defaultValue: true,\n columns: 6\n },\n {\n name: 'is_system_default',\n type: 'switch',\n label: 'System Default',\n columns: 6\n },\n {\n name: 'is_domain_default',\n type: 'switch',\n label: 'Domain Default',\n columns: 6\n },\n {\n name: 'async_handler',\n type: 'text',\n label: 'Async Handler (optional)',\n placeholder: 'myapp.handlers.process_support',\n columns: 12,\n help: 'Module:function to process inbound messages via task system'\n }\n ]\n },\n\n edit: {\n title: 'Edit Mailbox',\n fields: [\n {\n name: 'email',\n type: 'email',\n label: 'Email Address',\n required: true,\n columns: 12\n },\n {\n name: 'allow_inbound',\n type: 'switch',\n label: 'Allow Inbound',\n columns: 6\n },\n {\n name: 'allow_outbound',\n type: 'switch',\n label: 'Allow Outbound',\n columns: 6\n },\n {\n name: 'is_system_default',\n type: 'switch',\n label: 'System Default',\n columns: 6\n },\n {\n name: 'is_domain_default',\n type: 'switch',\n label: 'Domain Default',\n columns: 6\n },\n {\n name: 'async_handler',\n type: 'text',\n label: 'Async Handler (optional)',\n placeholder: 'myapp.handlers.process_support',\n columns: 12\n }\n ]\n }\n};\n\n/**\n * SentMessage - Outbound messages sent via SES; read-only in UI\n * Endpoint: /api/aws/email/sent\n */\nclass SentMessage extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/sent',\n ...options\n });\n }\n}\n\n/**\n * SentMessageList - Collection of SentMessage\n */\nclass SentMessageList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: SentMessage,\n endpoint: '/api/aws/email/sent',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms for SentMessage (read-only details)\n */\nconst SentMessageForms = {\n view: {\n title: 'Sent Message Details',\n fields: [\n { name: 'id', type: 'text', label: 'ID', readonly: true, cols: 6 },\n { name: 'ses_message_id', type: 'text', label: 'SES Message ID', readonly: true, cols: 6 },\n { name: 'from_email', type: 'text', label: 'From', readonly: true, cols: 12 },\n { name: 'to', type: 'textarea', label: 'To', readonly: true, rows: 2, cols: 12 },\n { name: 'cc', type: 'textarea', label: 'CC', readonly: true, rows: 2, cols: 12 },\n { name: 'bcc', type: 'textarea', label: 'BCC', readonly: true, rows: 2, cols: 12 },\n { name: 'subject', type: 'text', label: 'Subject', readonly: true, cols: 12 },\n { name: 'status', type: 'text', label: 'Status', readonly: true, cols: 6 },\n { name: 'status_reason', type: 'textarea', label: 'Status Reason', readonly: true, rows: 3, cols: 12 },\n { name: 'created', type: 'text', label: 'Created', readonly: true, cols: 6 }\n ]\n }\n};\n\n/**\n * EmailTemplate - DB template entries (Django templated), CRUD supported\n * Endpoint: /api/aws/email/template\n */\nclass EmailTemplate extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/template',\n ...options\n });\n }\n}\n\n/**\n * EmailTemplateList - Collection of EmailTemplate\n */\nclass EmailTemplateList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: EmailTemplate,\n endpoint: '/api/aws/email/template',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for EmailTemplate CRUD\n */\nconst EmailTemplateForms = {\n create: {\n title: 'Add Email Template',\n fields: [\n { name: 'name', type: 'text', label: 'Name', required: true, cols: 12 },\n { name: 'subject_template', type: 'text', label: 'Subject Template', cols: 12 },\n {\n type: 'tabset',\n name: 'settingsTabs',\n tabs: [\n {\n label: 'HTML',\n fields: [\n { name: 'html_template', type: 'htmlpreview', label: 'HTML Template', rows: 16, cols: 12 },\n ],\n },\n {\n label: 'TEXT',\n fields: [\n { name: 'text_template', type: 'textarea', label: 'Text Template', rows: 16, cols: 12 }\n ]\n }\n ]\n }\n ]\n },\n edit: {\n title: 'Edit Email Template',\n fields: [\n { name: 'name', type: 'text', label: 'Name', required: true, cols: 12 },\n { name: 'subject_template', type: 'text', label: 'Subject Template', cols: 12 },\n {\n type: 'tabset',\n name: 'settingsTabs',\n tabs: [\n {\n label: 'HTML',\n fields: [\n { name: 'html_template', type: 'textarea', label: 'HTML Template', rows: 16, cols: 12 },\n ],\n },\n {\n label: 'TEXT',\n fields: [\n { name: 'text_template', type: 'textarea', label: 'Text Template', rows: 16, cols: 12 }\n ]\n }\n ]\n }\n ]\n }\n};\n\n// Wire form statics so admin TablePages can drop inline form configuration.\nEmailDomain.ADD_FORM = EmailDomainForms.create;\nEmailDomain.EDIT_FORM = EmailDomainForms.edit;\nMailbox.ADD_FORM = MailboxForms.create;\nMailbox.EDIT_FORM = MailboxForms.edit;\nEmailTemplate.ADD_FORM = EmailTemplateForms.create;\nEmailTemplate.EDIT_FORM = EmailTemplateForms.edit;\n\nexport {\n EmailDomain,\n EmailDomainList,\n EmailDomainForms,\n Mailbox,\n MailboxList,\n MailboxForms,\n SentMessage,\n SentMessageList,\n SentMessageForms,\n EmailTemplate,\n EmailTemplateList,\n EmailTemplateForms\n};\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * Constants\n * ========================= */\n\nconst PublicMessageKindOptions = [\n { value: 'contact_us', label: 'Contact Us' },\n { value: 'support', label: 'Support' },\n];\n\nconst PublicMessageStatusOptions = [\n { value: 'open', label: 'Open' },\n { value: 'closed', label: 'Closed' },\n];\n\nconst PublicMessageSeverityOptions = [\n { value: 'low', label: 'Low' },\n { value: 'normal', label: 'Normal' },\n { value: 'high', label: 'High' },\n];\n\nconst PublicMessageCategoryOptions = [\n { value: 'billing', label: 'Billing' },\n { value: 'account', label: 'Account' },\n { value: 'bug', label: 'Bug' },\n { value: 'other', label: 'Other' },\n];\n\n// Friendly labels for known metadata keys. Unknown keys are humanized at render time.\nconst PublicMessageMetadataLabels = {\n company: 'Company',\n category: 'Category',\n severity: 'Severity',\n referrer: 'Referrer',\n landing_page: 'Landing Page',\n utm_source: 'UTM Source',\n utm_medium: 'UTM Medium',\n utm_campaign: 'UTM Campaign',\n utm_term: 'UTM Term',\n utm_content: 'UTM Content',\n};\n\n/* =========================\n * PublicMessage Model\n * ========================= */\n\nclass PublicMessage extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/account/public_message',\n });\n }\n}\n\n/* =========================\n * PublicMessage Collection\n * ========================= */\n\nclass PublicMessageList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: PublicMessage,\n endpoint: '/api/account/public_message',\n size: 25,\n ...options,\n });\n }\n}\n\nexport {\n PublicMessage,\n PublicMessageList,\n PublicMessageKindOptions,\n PublicMessageStatusOptions,\n PublicMessageSeverityOptions,\n PublicMessageCategoryOptions,\n PublicMessageMetadataLabels,\n};\n","/**\n * Phonehub.js\n * Models and Collections for PhoneHub phone numbers and SMS with helper actions.\n *\n * Endpoints (all require authentication unless noted):\n * - Phone Number\n * - POST /api/phonehub/number/normalize\n * - POST /api/phonehub/number/lookup\n * - GET /api/phonehub/number\n * - GET /api/phonehub/number/:id\n * - PUT /api/phonehub/number/:id\n * - DELETE /api/phonehub/number/:id\n *\n * - SMS\n * - POST /api/phonehub/sms/send\n * - GET /api/phonehub/sms\n * - GET /api/phonehub/sms/:id\n *\n * Notes on response shapes:\n * - List endpoints typically return { status: true, data: [...], count, size, start }\n * - Single item endpoints typically return { status: true, data: {...} }\n * - Action endpoints (normalize, lookup, send) return { status: true, data: {...} } or { status: false, error }\n */\n\nimport Model from '@core/Model.js';\nimport Collection from '@core/Collection.js';\nimport rest from '@core/Rest.js';\nimport { GroupList } from '@core/models/Group.js';\n\n// ======================================================\n// PhoneNumber Model & Collection\n// ======================================================\n\n/**\n * PhoneNumber - Represents a cached phone number lookup result.\n */\nclass PhoneNumber extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/phonehub/number',\n ...options\n });\n }\n\n /**\n * Normalize an arbitrary phone_number string to E.164 format.\n * @param {string} phoneNumber - Raw phone number input.\n * @param {string} [countryCode='US'] - Optional country code (default US).\n * @returns {Promise<{success: boolean, phone_number?: string, data?: object, error?: string, response?: any}>}\n */\n static async normalize(phoneNumber, countryCode = 'US') {\n const url = '/api/phonehub/number/normalize';\n const payload = {\n phone_number: phoneNumber\n };\n if (countryCode) payload.country_code = countryCode;\n\n const resp = await rest.POST(url, payload);\n const body = resp?.data ?? resp; // rest wrapper or raw\n const ok = body?.status === true || body?.success === true;\n\n if (ok) {\n const normalized = body?.data?.phone_number ?? body?.phone_number;\n return { success: true, phone_number: normalized, data: body?.data ?? body, response: resp };\n }\n return { success: false, error: body?.error || 'Normalization failed', response: resp };\n }\n\n /**\n * Lookup phone number details (carrier, line_type, owner, etc.)\n * @param {string} phoneNumber - E.164 or raw phone number.\n * @param {object} [options] - { force_refresh?: boolean, group?: number }\n * @returns {Promise<{success: boolean, model?: PhoneNumber, data?: object, error?: string, response?: any}>}\n */\n static async lookup(phoneNumber, options = {}) {\n const url = '/api/phonehub/number/lookup';\n const resp = await rest.POST(url, {\n phone_number: phoneNumber,\n ...options\n });\n const body = resp?.data ?? resp;\n const ok = body?.status === true || body?.success === true;\n\n if (ok) {\n const data = body?.data ?? {};\n const model = new PhoneNumber(data, { endpoint: '/api/phonehub/number' });\n return { success: true, model, data, response: resp };\n }\n return { success: false, error: body?.error || 'Phone lookup failed', response: resp };\n }\n\n\n}\n\n/**\n * PhoneNumberList - Paginated collection of PhoneNumber models.\n */\nclass PhoneNumberList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: PhoneNumber,\n endpoint: '/api/phonehub/number',\n size: 10,\n ...options\n });\n }\n\n\n}\n\n// ======================================================\n// SMS Model & Collection\n// ======================================================\n\n/**\n * SMS - Represents an SMS message (sent or received).\n */\nclass SMS extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/phonehub/sms',\n ...options\n });\n }\n\n /**\n * Send SMS via PhoneHub (Twilio under the hood).\n * @param {object} params - { to_number, body, from_number?, group?, metadata? }\n * @returns {Promise<{success: boolean, model?: SMS, data?: object, error?: string, response?: any}>}\n */\n static async send(params = {}) {\n const url = '/api/phonehub/sms/send';\n const resp = await rest.POST(url, params);\n const body = resp?.data ?? resp;\n const ok = body?.status === true || body?.success === true;\n\n if (ok) {\n const data = body?.data ?? {};\n const model = new SMS(data, { endpoint: '/api/phonehub/sms' });\n return { success: true, model, data, response: resp };\n }\n return { success: false, error: body?.error || 'Failed to send SMS', response: resp };\n }\n\n\n\n\n}\n\n/**\n * SMSList - Paginated collection of SMS models.\n */\nclass SMSList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: SMS,\n endpoint: '/api/phonehub/sms',\n size: 10,\n ...options\n });\n }\n\n\n}\n\n// ======================================================\n// PhoneConfig Model & Collection\n// ======================================================\n\n/**\n * PhoneConfig - Per-group (or system-default) SMS provider configuration.\n *\n * One row holds the provider choice plus its credentials. Per-credential\n * auto-setters on the backend route credential body keys through encrypted\n * storage on the same POST that updates scalar fields, so create / edit /\n * test_connection all share `/api/phonehub/config[/<pk>]`.\n *\n * Endpoints:\n * GET /api/phonehub/config - List\n * GET /api/phonehub/config/<id> - Get\n * POST /api/phonehub/config - Create\n * POST /api/phonehub/config/<id> - Update / test_connection\n * DELETE /api/phonehub/config/<id> - Delete\n */\nclass PhoneConfig extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/phonehub/config',\n ...options\n });\n }\n}\n\nclass PhoneConfigList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: PhoneConfig,\n endpoint: '/api/phonehub/config',\n size: 25,\n ...options\n });\n }\n}\n\n// Credential fields that must never be round-tripped from a GET response —\n// the backend graph excludes them, but the frontend also strips blanks before\n// save so we never overwrite a stored secret with an empty string.\nconst PHONE_CONFIG_SECRET_FIELDS = [\n 'twilio_account_sid',\n 'twilio_auth_token',\n 'aws_access_key_id',\n 'aws_secret_access_key',\n 'mojo_api_key'\n];\n\nconst PHONE_CONFIG_PROVIDER_OPTIONS = [\n { value: 'twilio', label: 'Twilio' },\n { value: 'aws', label: 'AWS SNS' },\n { value: 'mojo', label: 'Mojo Remote Instance' }\n];\n\nconst SECRET_PLACEHOLDER = '•••••••• (leave blank to keep existing)';\n\nconst PHONE_CONFIG_COMMON_FIELDS = [\n { name: 'name', type: 'text', label: 'Name', required: true, columns: 8,\n placeholder: 'e.g. Primary Twilio, Backup AWS, Mojo Bridge' },\n { type: 'collection', name: 'group', label: 'Group',\n Collection: GroupList, labelField: 'name', valueField: 'id',\n placeholder: 'Search groups…', emptyFetch: false, debounceMs: 300,\n columns: 4, help: 'Leave blank for the System Default config.' },\n { name: 'provider', type: 'select', label: 'Provider', required: true,\n options: PHONE_CONFIG_PROVIDER_OPTIONS, columns: 6 },\n { name: 'lookup_cache_days', type: 'number', label: 'Lookup cache (days)',\n columns: 6, help: 'Carrier-lookup cache lifetime per number.' },\n { name: 'is_active', type: 'switch', label: 'Active', columns: 4 },\n { name: 'test_mode', type: 'switch', label: 'Test mode', columns: 4,\n help: 'Use the provider sandbox / test endpoint.' },\n { name: 'lookup_enabled', type: 'switch', label: 'Lookup', columns: 4,\n help: 'Auto-run carrier lookups on new numbers.' }\n];\n\nconst PHONE_CONFIG_TWILIO_FIELDS = [\n { type: 'header', label: 'Twilio credentials', columns: 12,\n showWhen: { field: 'provider', value: 'twilio' } },\n { name: 'twilio_from_number', type: 'text', label: 'Twilio From Number',\n placeholder: '+15551234567', columns: 6,\n showWhen: { field: 'provider', value: 'twilio' } },\n { name: 'twilio_account_sid', type: 'password', label: 'Twilio Account SID',\n placeholder: SECRET_PLACEHOLDER, columns: 6, autocomplete: 'off',\n showWhen: { field: 'provider', value: 'twilio' } },\n { name: 'twilio_auth_token', type: 'password', label: 'Twilio Auth Token',\n placeholder: SECRET_PLACEHOLDER, columns: 12, autocomplete: 'new-password',\n showWhen: { field: 'provider', value: 'twilio' } }\n];\n\nconst PHONE_CONFIG_AWS_FIELDS = [\n { type: 'header', label: 'AWS SNS credentials', columns: 12,\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_region', type: 'text', label: 'AWS Region', value: 'us-east-1',\n placeholder: 'us-east-1', columns: 6,\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_sender_id', type: 'text', label: 'Sender ID',\n placeholder: 'Optional alphanumeric sender (region-dependent)', columns: 6,\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_access_key_id', type: 'password', label: 'Access Key ID',\n placeholder: SECRET_PLACEHOLDER, columns: 6, autocomplete: 'off',\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_secret_access_key', type: 'password', label: 'Secret Access Key',\n placeholder: SECRET_PLACEHOLDER, columns: 6, autocomplete: 'new-password',\n showWhen: { field: 'provider', value: 'aws' } }\n];\n\nconst PHONE_CONFIG_MOJO_FIELDS = [\n { type: 'header', label: 'Mojo Remote credentials', columns: 12,\n showWhen: { field: 'provider', value: 'mojo' } },\n { name: 'mojo_remote_url', type: 'url', label: 'Remote Mojo URL',\n placeholder: 'https://sms.example.com', columns: 12,\n showWhen: { field: 'provider', value: 'mojo' } },\n { name: 'mojo_api_key', type: 'password', label: 'Mojo API Key',\n placeholder: SECRET_PLACEHOLDER, columns: 12, autocomplete: 'new-password',\n help: 'Paste the token shown once when the API key was provisioned on the remote mojo. We never display it after save.',\n showWhen: { field: 'provider', value: 'mojo' } }\n];\n\nconst PHONE_CONFIG_FIELDS = [\n ...PHONE_CONFIG_COMMON_FIELDS,\n ...PHONE_CONFIG_TWILIO_FIELDS,\n ...PHONE_CONFIG_AWS_FIELDS,\n ...PHONE_CONFIG_MOJO_FIELDS\n];\n\nconst PhoneConfigForms = {\n create: {\n title: 'New Phone Config',\n fields: PHONE_CONFIG_FIELDS,\n defaults: {\n provider: 'twilio',\n is_active: true,\n test_mode: false,\n lookup_enabled: true,\n lookup_cache_days: 90\n }\n },\n edit: {\n title: 'Edit Phone Config',\n fields: PHONE_CONFIG_FIELDS\n }\n};\n\nPhoneConfig.ADD_FORM = PhoneConfigForms.create;\nPhoneConfig.EDIT_FORM = PhoneConfigForms.edit;\nPhoneConfig.SECRET_FIELDS = PHONE_CONFIG_SECRET_FIELDS;\nPhoneConfig.PROVIDER_OPTIONS = PHONE_CONFIG_PROVIDER_OPTIONS;\n// Open the Add dialog wide enough for the provider-conditional credential rows.\nPhoneConfig.FORM_DIALOG_CONFIG = { size: 'lg', submitText: 'Create' };\n\n// Exported API\nexport {\n PhoneNumber,\n PhoneNumberList,\n SMS,\n SMSList,\n PhoneConfig,\n PhoneConfigList,\n PhoneConfigForms\n};\n\nexport default {\n PhoneNumber,\n PhoneNumberList,\n SMS,\n SMSList,\n PhoneConfig,\n PhoneConfigList,\n PhoneConfigForms\n};","/**\n * JobRunner Model - Job Engine Runner/Worker management\n * Manages worker processes that execute jobs\n */\n\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nclass JobRunner extends Model {\n constructor(data = {}) {\n // Map runner_id to id for proper Model handling\n if (data.runner_id && !data.id) {\n data.id = data.runner_id;\n }\n \n super(data, {\n endpoint: '/api/jobs/runners',\n idAttribute: 'runner_id' // Tell the model to use runner_id as the ID field\n });\n }\n\n // Ping this runner to test connectivity\n async ping(timeout = 2.0) {\n const app = this.getApp();\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n\n const response = await app.rest.POST('/api/jobs/runners/ping', {\n runner_id: this.get('runner_id'),\n timeout: timeout\n });\n\n if (response.success && response.data.status) {\n // Update ping status\n this.set('last_heartbeat', new Date().toISOString());\n this.set('ping_status', response.data.ping_status || 'success');\n }\n\n return response;\n }\n\n // Shutdown this runner gracefully or forcefully\n async shutdown(graceful = true) {\n const app = this.getApp();\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n\n const response = await app.rest.POST('/api/jobs/runners/shutdown', {\n runner_id: this.get('runner_id'),\n graceful: graceful\n });\n\n if (response.success && response.data.status) {\n // Update status to shutting down (alive becomes false)\n this.set('alive', false);\n }\n\n return response;\n }\n\n // Get channels handled by this runner\n getChannels() {\n return this.get('channels') || [];\n }\n\n // Get runner status with appropriate styling based on alive field\n getStatusBadgeClass() {\n const alive = this.get('alive');\n return alive ? 'bg-success' : 'bg-danger';\n }\n\n // Get status icon based on alive field\n getStatusIcon() {\n const alive = this.get('alive');\n return alive ? 'bi-check-circle-fill' : 'bi-x-octagon-fill';\n }\n\n // Check if runner is active (alive)\n isActive() {\n return this.get('alive') === true;\n }\n\n // Check if runner is healthy (active and recent heartbeat)\n isHealthy() {\n if (!this.isActive()) return false;\n \n const lastHeartbeat = this.get('last_heartbeat');\n if (!lastHeartbeat) return false;\n \n // Consider healthy if heartbeat within last 2 minutes\n const heartbeatAge = (Date.now() - new Date(lastHeartbeat).getTime()) / 1000;\n return heartbeatAge < 120;\n }\n\n // Get formatted heartbeat age\n getFormattedHeartbeatAge() {\n const lastHeartbeat = this.get('last_heartbeat');\n if (!lastHeartbeat) return 'Never';\n \n const heartbeatAge = (Date.now() - new Date(lastHeartbeat).getTime()) / 1000;\n \n if (heartbeatAge < 60) return `${Math.round(heartbeatAge)}s ago`;\n if (heartbeatAge < 3600) return `${Math.round(heartbeatAge / 60)}m ago`;\n return `${Math.round(heartbeatAge / 3600)}h ago`;\n }\n\n // Get current utilization (from jobs processed vs capacity)\n getUtilization() {\n const processed = this.get('jobs_processed') || 0;\n const failed = this.get('jobs_failed') || 0;\n const total = processed + failed;\n // Since we don't have max capacity from API, return based on recent activity\n return total > 10 ? 100 : Math.min(total * 10, 100);\n }\n\n // Get formatted uptime based on started timestamp\n getFormattedUptime() {\n const started = this.get('started');\n if (!started) return 'Unknown';\n \n const startTime = new Date(started);\n const now = new Date();\n const diffMs = now - startTime;\n const diffSeconds = Math.floor(diffMs / 1000);\n \n if (diffSeconds < 60) return `${diffSeconds}s`;\n if (diffSeconds < 3600) return `${Math.floor(diffSeconds / 60)}m`;\n if (diffSeconds < 86400) return `${Math.floor(diffSeconds / 3600)}h`;\n return `${Math.floor(diffSeconds / 86400)}d`;\n }\n\n // Get worker capacity info\n getWorkerInfo() {\n const processed = this.get('jobs_processed') || 0;\n const failed = this.get('jobs_failed') || 0;\n return {\n processed,\n failed,\n total: processed + failed,\n alive: this.get('alive'),\n utilization: this.getUtilization()\n };\n }\n\n // Get display name for runner\n getDisplayName() {\n const runnerId = this.get('runner_id');\n if (!runnerId) return 'Unknown Runner';\n \n // Extract hostname-like portion if it exists\n const parts = runnerId.split('-');\n return parts.length > 1 ? parts[0] : runnerId;\n }\n\n // Check if runner can be controlled\n canControl() {\n return this.get('alive') === true;\n }\n}\n\nclass JobRunnerList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: JobRunner,\n endpoint: '/api/jobs/runners',\n ...options\n });\n }\n\n // Get only active runners\n getActive() {\n return this.where(runner => runner.isActive());\n }\n\n // Get runners by channel\n getByChannel(channel) {\n return this.where(runner => runner.getChannels().includes(channel));\n }\n\n // Get healthy runners\n getHealthy() {\n return this.where(runner => runner.isHealthy());\n }\n\n // Get total jobs processed across all runners\n getTotalProcessed() {\n return this.models.reduce((total, runner) => {\n return total + (runner.get('jobs_processed') || 0);\n }, 0);\n }\n\n // Get total jobs failed across all runners\n getTotalFailed() {\n return this.models.reduce((total, runner) => {\n return total + (runner.get('jobs_failed') || 0);\n }, 0);\n }\n\n // Get overall system health percentage (alive runners / total runners)\n getSystemHealth() {\n if (this.models.length === 0) return 0;\n const aliveRunners = this.models.filter(runner => runner.get('alive')).length;\n return Math.round((aliveRunners / this.models.length) * 100);\n }\n\n // Get unique channels across all runners\n getAllChannels() {\n const channels = new Set();\n this.models.forEach(runner => {\n runner.getChannels().forEach(channel => channels.add(channel));\n });\n return Array.from(channels).sort();\n }\n}\n\n// Static methods for system-wide runner management\nJobRunner.ping = async function(runnerId, timeout = 2.0) {\n const app = typeof window !== 'undefined' && window.app;\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n \n return await app.rest.POST('/api/jobs/runners/ping', {\n runner_id: runnerId,\n timeout\n });\n};\n\nJobRunner.shutdown = async function(runnerId, graceful = true) {\n const app = typeof window !== 'undefined' && window.app;\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n \n return await app.rest.POST('/api/jobs/runners/shutdown', {\n runner_id: runnerId,\n graceful\n });\n};\n\nJobRunner.broadcast = async function(command, data = {}, timeout = 2.0) {\n const app = typeof window !== 'undefined' && window.app;\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n \n return await app.rest.POST('/api/jobs/runners/broadcast', {\n command,\n data,\n timeout\n });\n};\n\n// Broadcast commands\nJobRunner.broadcastStatus = async function(timeout = 2.0) {\n return JobRunner.broadcast('status', {}, timeout);\n};\n\nJobRunner.broadcastShutdown = async function(timeout = 2.0) {\n return JobRunner.broadcast('shutdown', {}, timeout);\n};\n\nJobRunner.broadcastPause = async function(timeout = 2.0) {\n return JobRunner.broadcast('pause', {}, timeout);\n};\n\nJobRunner.broadcastResume = async function(timeout = 2.0) {\n return JobRunner.broadcast('resume', {}, timeout);\n};\n\nJobRunner.broadcastReload = async function(timeout = 2.0) {\n return JobRunner.broadcast('reload', {}, timeout);\n};\n\nconst JobRunnerForms = {\n broadcast: {\n title: 'Broadcast Command',\n fields: [\n {\n name: 'command',\n type: 'select',\n label: 'Command',\n required: true,\n options: [\n { value: 'status', label: 'Status Check' },\n { value: 'pause', label: 'Pause Processing' },\n { value: 'resume', label: 'Resume Processing' },\n { value: 'reload', label: 'Reload Configuration' },\n { value: 'shutdown', label: 'Shutdown All Runners' }\n ],\n help: 'Command to send to all runners'\n },\n {\n name: 'timeout',\n type: 'number',\n label: 'Timeout (seconds)',\n value: 2.0,\n min: 0.5,\n max: 10.0,\n step: 0.5,\n help: 'How long to wait for responses'\n }\n ]\n }\n};\n\nexport { JobRunner, JobRunnerList, JobRunnerForms };","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/**\n * BouncerDevice - A tracked device fingerprint in the Bouncer fraud-detection system.\n * Maps to REST endpoints under /api/account/bouncer/device\n *\n * Key fields: muid, duid, fingerprint_id, risk_tier, event_count,\n * block_count, last_seen_ip, linked_muids, last_seen\n *\n * Endpoints:\n * GET /api/account/bouncer/device - List devices\n * GET /api/account/bouncer/device/<id> - Get device details\n * POST /api/account/bouncer/device/<id> - Update device\n * DELETE /api/account/bouncer/device/<id> - Delete device\n */\nclass BouncerDevice extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/account/bouncer/device',\n ...options\n });\n }\n}\n\n/**\n * BouncerDeviceList - Collection of BouncerDevice records.\n * Filter by account or risk tier via query params.\n */\nclass BouncerDeviceList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: BouncerDevice,\n endpoint: '/api/account/bouncer/device',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * BouncerSignal - A captured request signal evaluated by the Bouncer risk engine.\n * Maps to REST endpoints under /api/account/bouncer/signal\n *\n * Key fields: muid, stage, ip_address, page_type, risk_score,\n * decision, triggered_signals, raw_signals, server_signals\n *\n * Endpoints:\n * GET /api/account/bouncer/signal - List signals\n * GET /api/account/bouncer/signal/<id> - Get signal details\n * POST /api/account/bouncer/signal/<id> - Update signal\n * DELETE /api/account/bouncer/signal/<id> - Delete signal\n */\nclass BouncerSignal extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/account/bouncer/signal',\n ...options\n });\n }\n}\n\n/**\n * BouncerSignalList - Collection of BouncerSignal records.\n * Filter by muid, decision, or risk_score via query params.\n */\nclass BouncerSignalList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: BouncerSignal,\n endpoint: '/api/account/bouncer/signal',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * BouncerSignature - A detection signature used by Bouncer to match known threat patterns.\n * Maps to REST endpoints under /api/account/bouncer/signature\n *\n * Key fields: sig_type, value, source, confidence, hit_count,\n * block_count, is_active, expires_at, notes\n *\n * Endpoints:\n * GET /api/account/bouncer/signature - List signatures\n * POST /api/account/bouncer/signature - Create a signature\n * GET /api/account/bouncer/signature/<id> - Get signature details\n * POST /api/account/bouncer/signature/<id> - Update signature\n * DELETE /api/account/bouncer/signature/<id> - Delete signature\n */\nclass BouncerSignature extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/account/bouncer/signature',\n ...options\n });\n }\n}\n\n/**\n * BouncerSignatureList - Collection of BouncerSignature records.\n * Filter by sig_type, is_active, or source via query params.\n */\nclass BouncerSignatureList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: BouncerSignature,\n endpoint: '/api/account/bouncer/signature',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for BouncerSignature\n */\nconst BouncerSignatureForms = {\n create: {\n title: 'Create Signature',\n fields: [\n {\n name: 'sig_type',\n type: 'select',\n label: 'Signature Type',\n required: true,\n columns: 6,\n options: [\n { value: 'user_agent', label: 'User Agent' },\n { value: 'ip_pattern', label: 'IP Pattern' },\n { value: 'fingerprint', label: 'Fingerprint' },\n { value: 'behavior', label: 'Behavior' },\n { value: 'header', label: 'Header' },\n { value: 'cookie', label: 'Cookie' }\n ]\n },\n {\n name: 'value',\n type: 'text',\n label: 'Value',\n required: true,\n columns: 6,\n help: 'The pattern or value to match against.'\n },\n {\n name: 'confidence',\n type: 'number',\n label: 'Confidence',\n columns: 6,\n default: 80,\n min: 0,\n max: 100,\n help: 'Confidence level from 0 to 100.'\n },\n {\n name: 'notes',\n type: 'textarea',\n label: 'Notes',\n columns: 12,\n help: 'Optional notes about this signature.'\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n columns: 6,\n default: true\n }\n ]\n },\n\n edit: {\n title: 'Edit Signature',\n fields: [\n {\n name: 'sig_type',\n type: 'select',\n label: 'Signature Type',\n required: true,\n columns: 6,\n options: [\n { value: 'user_agent', label: 'User Agent' },\n { value: 'ip_pattern', label: 'IP Pattern' },\n { value: 'fingerprint', label: 'Fingerprint' },\n { value: 'behavior', label: 'Behavior' },\n { value: 'header', label: 'Header' },\n { value: 'cookie', label: 'Cookie' }\n ]\n },\n {\n name: 'value',\n type: 'text',\n label: 'Value',\n required: true,\n columns: 6,\n help: 'The pattern or value to match against.'\n },\n {\n name: 'confidence',\n type: 'number',\n label: 'Confidence',\n columns: 6,\n default: 80,\n min: 0,\n max: 100,\n help: 'Confidence level from 0 to 100.'\n },\n {\n name: 'notes',\n type: 'textarea',\n label: 'Notes',\n columns: 12,\n help: 'Optional notes about this signature.'\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n columns: 6,\n default: true\n }\n ]\n }\n};\n\n// Wire form statics so admin TablePages can drop inline form configuration.\nBouncerSignature.ADD_FORM = BouncerSignatureForms.create;\nBouncerSignature.EDIT_FORM = BouncerSignatureForms.edit;\n\nexport { BouncerDevice, BouncerDeviceList, BouncerSignal, BouncerSignalList, BouncerSignature, BouncerSignatureList, BouncerSignatureForms };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * Constants\n * ========================= */\n\nconst IPSetKindOptions = [\n { value: 'country', label: 'Country — Block all traffic from a country' },\n { value: 'abuse', label: 'Abuse Feed — Import known attacker IPs' },\n { value: 'datacenter', label: 'Datacenter — Block datacenter/hosting ranges' },\n { value: 'custom', label: 'Custom — Define your own CIDR list' },\n];\n\nconst IPSetKindBadgeOptions = [\n { value: 'country', label: 'Country' },\n { value: 'abuse', label: 'Abuse Feed' },\n { value: 'datacenter', label: 'Datacenter' },\n { value: 'custom', label: 'Custom' },\n];\n\nconst IPSetSourceOptions = [\n { value: 'ipdeny', label: 'IPDeny (Country Zones)' },\n { value: 'abuseipdb', label: 'AbuseIPDB' },\n { value: 'manual', label: 'Manual' },\n];\n\nconst CommonBlockCountries = [\n { value: 'cn', label: 'China' },\n { value: 'ru', label: 'Russia' },\n { value: 'kp', label: 'North Korea' },\n { value: 'ir', label: 'Iran' },\n { value: 'ng', label: 'Nigeria' },\n { value: 'ro', label: 'Romania' },\n { value: 'br', label: 'Brazil' },\n { value: 'in', label: 'India' },\n { value: 'pk', label: 'Pakistan' },\n { value: 'id', label: 'Indonesia' },\n { value: 'vn', label: 'Vietnam' },\n { value: 'ua', label: 'Ukraine' },\n { value: 'th', label: 'Thailand' },\n { value: 'ph', label: 'Philippines' },\n { value: 'bd', label: 'Bangladesh' },\n { value: 'eg', label: 'Egypt' },\n { value: 'tr', label: 'Turkey' },\n { value: 'mx', label: 'Mexico' },\n { value: 'ar', label: 'Argentina' },\n { value: 'co', label: 'Colombia' },\n];\n\n/* =========================\n * IPSet Model\n * ========================= */\n\nclass IPSet extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/ipset',\n });\n }\n}\n\n/* =========================\n * IPSet Collection\n * ========================= */\n\nclass IPSetList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IPSet,\n endpoint: '/api/incident/ipset',\n ...options,\n });\n }\n}\n\n/* =========================\n * Forms\n * ========================= */\n\nconst IPSetForms = {\n create: {\n title: 'Create IP Set',\n size: 'md',\n fields: [\n {\n name: 'kind',\n type: 'select',\n label: 'What do you want to block?',\n required: true,\n options: IPSetKindOptions,\n value: 'country',\n columns: 12\n },\n // ── Country fields ──\n {\n name: 'country_code',\n type: 'select',\n label: 'Country',\n required: true,\n options: CommonBlockCountries,\n help: 'Select a country to block. CIDRs are fetched automatically from IPDeny.',\n columns: 8,\n showWhen: { field: 'kind', value: 'country' }\n },\n // ── Abuse feed fields ──\n {\n name: 'source_key',\n type: 'text',\n label: 'API Key',\n required: true,\n placeholder: 'Your AbuseIPDB API key',\n help: 'Get a free key at abuseipdb.com. Never stored in plaintext.',\n columns: 12,\n showWhen: { field: 'kind', value: 'abuse' }\n },\n // ── Datacenter fields ──\n {\n name: 'source_url',\n type: 'url',\n label: 'Source URL',\n required: true,\n placeholder: 'https://example.com/datacenter-ranges.txt',\n help: 'URL to a plain text file with one CIDR per line.',\n columns: 12,\n showWhen: { field: 'kind', value: 'datacenter' }\n },\n // ── Custom fields ──\n {\n name: 'data',\n type: 'textarea',\n label: 'CIDR List',\n rows: 8,\n placeholder: '# One CIDR per line\\n192.0.2.0/24\\n198.51.100.0/24\\n203.0.113.0/24',\n help: 'Enter IP ranges in CIDR notation. Lines starting with # are ignored.',\n columns: 12,\n showWhen: { field: 'kind', value: 'custom' }\n },\n // ── Shared fields (non-country) ──\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'e.g., abuse_ips, dc_aws',\n help: 'Unique identifier. Used as the kernel ipset name.',\n columns: 6,\n showWhen: { field: 'kind', value: 'country', negate: true }\n },\n {\n name: 'description',\n type: 'text',\n label: 'Description',\n placeholder: 'Human-readable label',\n columns: 6,\n showWhen: { field: 'kind', value: 'country', negate: true }\n },\n // ── Always visible ──\n {\n name: 'is_enabled',\n type: 'switch',\n label: 'Enable immediately',\n value: true,\n help: 'When enabled, CIDRs are synced to the fleet and traffic is blocked.',\n columns: 4\n },\n ]\n },\n\n edit: {\n title: 'Edit IP Set',\n size: 'md',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n columns: 6\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Kind',\n options: IPSetKindBadgeOptions,\n disabled: true,\n columns: 3\n },\n {\n name: 'is_enabled',\n type: 'switch',\n label: 'Enabled',\n columns: 3\n },\n {\n name: 'description',\n type: 'text',\n label: 'Description',\n columns: 12\n },\n {\n name: 'source',\n type: 'select',\n label: 'Source',\n options: IPSetSourceOptions,\n columns: 6\n },\n {\n name: 'source_url',\n type: 'url',\n label: 'Source URL',\n columns: 6\n },\n {\n name: 'source_key',\n type: 'text',\n label: 'API Key',\n placeholder: 'Leave blank to keep current key',\n help: 'Write-only — current value is never shown.',\n columns: 12\n },\n ]\n }\n};\n\n// IPSet.EDIT_FORM is wired so IPSetTablePage can drop the inline `formEdit:`.\n// No ADD_FORM is registered: the page owns a custom `onAdd` flow that\n// transforms a country code into name/source/description before save —\n// see IPSetTablePage._handleAdd() (commit 5 of the UX sweep).\nIPSet.EDIT_FORM = IPSetForms.edit;\n\nexport {\n IPSet,\n IPSetList,\n IPSetForms,\n IPSetKindOptions,\n IPSetKindBadgeOptions,\n IPSetSourceOptions,\n CommonBlockCountries\n};\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * Model\n * ========================= */\nclass S3Bucket extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/aws/s3/bucket',\n });\n }\n}\n\n/* =========================\n * Collection\n * ========================= */\nclass S3BucketList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: S3Bucket,\n endpoint: '/api/aws/s3/bucket',\n size: 10,\n ...options,\n });\n }\n}\n\n/* =========================\n * Forms\n * ========================= */\nconst S3BucketForms = {\n create: {\n title: 'Add S3 Bucket',\n fields: [\n {\n name: 'bucket_name',\n type: 'text',\n label: 'Name',\n placeholder: 'bucket name',\n help: 'Enter a universally unique name for the bucket',\n required: true,\n cols: 12,\n },\n {\n name: 'is_public',\n type: 'switch',\n label: 'Is Public',\n cols: 12,\n },\n ],\n },\n\n // Provide an edit form even though legacy only had ADD_FORM\n edit: {\n title: 'Edit S3 Bucket',\n fields: [\n {\n name: 'bucket_name',\n type: 'text',\n label: 'Name',\n placeholder: 'bucket name',\n help: 'Enter a universally unique name for the bucket',\n required: true,\n cols: 12,\n },\n {\n name: 'is_public',\n type: 'switch',\n label: 'Is Public',\n cols: 12,\n },\n ],\n },\n};\n\n// Wire form statics so S3BucketTablePage can drop inline form configuration.\nS3Bucket.ADD_FORM = S3BucketForms.create;\nS3Bucket.EDIT_FORM = S3BucketForms.edit;\n\nexport { S3Bucket, S3BucketList, S3BucketForms };\n","/**\n * ScheduledTask - User-defined recurring or one-off tasks\n *\n * Each task belongs to the authenticated user. Supports three task types:\n * - job: Run a backend job function\n * - webhook: POST to a URL\n * - llm: Run an LLM prompt via the assistant\n *\n * Endpoints:\n * GET /api/jobs/scheduled_task - List tasks\n * POST /api/jobs/scheduled_task - Create a task\n * GET /api/jobs/scheduled_task/<id> - Get task detail\n * PUT /api/jobs/scheduled_task/<id> - Update a task\n * DELETE /api/jobs/scheduled_task/<id> - Delete a task\n */\n\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nclass ScheduledTask extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/jobs/scheduled_task',\n ...options\n });\n }\n}\n\nclass ScheduledTaskList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: ScheduledTask,\n endpoint: '/api/jobs/scheduled_task',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * TaskResult - Read-only execution result records\n *\n * Endpoints:\n * GET /api/jobs/task_result - List results\n * GET /api/jobs/task_result/<id> - Get result detail\n */\nclass TaskResult extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/jobs/task_result',\n ...options\n });\n }\n}\n\nclass TaskResultList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: TaskResult,\n endpoint: '/api/jobs/task_result',\n size: 25,\n ...options\n });\n }\n}\n\nconst DAY_LABELS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\n\nconst ScheduledTaskForms = {\n create: {\n title: 'Create Scheduled Task',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n placeholder: 'Daily report',\n required: true,\n columns: 12\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Description',\n placeholder: 'What this task does...',\n columns: 12\n },\n {\n name: 'task_type',\n type: 'select',\n label: 'Task Type',\n required: true,\n columns: 6,\n options: [\n { value: 'llm', label: 'LLM Prompt' },\n { value: 'job', label: 'Backend Job' },\n { value: 'webhook', label: 'Webhook' }\n ]\n },\n {\n name: 'enabled',\n type: 'switch',\n label: 'Enabled',\n columns: 6,\n value: true\n },\n {\n name: 'run_times',\n type: 'text',\n label: 'Run Times (HH:MM)',\n placeholder: '09:00',\n required: true,\n columns: 6,\n help: 'Comma-separated 24h times, max 2. e.g. \"09:00, 17:00\"'\n },\n {\n name: 'run_days',\n type: 'text',\n label: 'Run Days',\n placeholder: '0,1,2,3,4',\n columns: 6,\n help: 'Comma-separated day numbers (Mon=0). Leave empty for every day.'\n },\n {\n name: 'run_once',\n type: 'switch',\n label: 'Run Once',\n columns: 6,\n help: 'Task runs once then disables itself.'\n },\n {\n name: 'max_retries',\n type: 'number',\n label: 'Max Retries',\n columns: 6,\n value: 0\n },\n {\n name: 'notify',\n type: 'text',\n label: 'Notify',\n placeholder: 'in_app, email',\n columns: 12,\n help: 'Comma-separated: email, in_app, sms, push'\n }\n ]\n },\n\n edit: {\n title: 'Edit Scheduled Task',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n columns: 12\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Description',\n columns: 12\n },\n {\n name: 'enabled',\n type: 'switch',\n label: 'Enabled',\n columns: 6\n },\n {\n name: 'run_times',\n type: 'text',\n label: 'Run Times (HH:MM)',\n required: true,\n columns: 6,\n help: 'Comma-separated 24h times, max 2.'\n },\n {\n name: 'run_days',\n type: 'text',\n label: 'Run Days',\n columns: 6,\n help: 'Comma-separated day numbers (Mon=0). Leave empty for every day.'\n },\n {\n name: 'run_once',\n type: 'switch',\n label: 'Run Once',\n columns: 6\n },\n {\n name: 'max_retries',\n type: 'number',\n label: 'Max Retries',\n columns: 6\n },\n {\n name: 'notify',\n type: 'text',\n label: 'Notify',\n placeholder: 'in_app, email',\n columns: 12,\n help: 'Comma-separated: email, in_app, sms, push'\n }\n ]\n }\n};\n\nexport { ScheduledTask, ScheduledTaskList, TaskResult, TaskResultList, ScheduledTaskForms, DAY_LABELS };\n"],"names":["LoginEvent","Model","constructor","data","super","endpoint","LoginEventList","Collection","options","ModelClass","IncidentStats","requiresId","IncidentEvent","IncidentEventList","size","IncidentEventForms","edit","title","fields","name","type","label","placeholder","Incident","COMPONENTS","editable","force_top","cols","IncidentList","IncidentForms","create","tabs","required","columns","value","example","rows","IncidentRuleSet","IncidentRuleSetList","IncidentRule","IncidentRuleList","IncidentHistory","IncidentHistoryList","RelatedIncidentsList","sourceIp","ruleSet","group","hostname","category","status","params","rest","ordering","source_ip","rule_set","ADD_FORM","EDIT_FORM","BundleByOptions","MatchByOptions","ComparatorOptions","ValueTypeOptions","CommonEventFields","description","meta","CommonCategoryOptions","CommonScopeOptions","RuleSet","RuleSetList","BundleMinutesOptions","RuleSetForms","tooltip","allowCustom","html","Rule","RuleList","RuleForms","showDescription","help","start","end","step","CREATE_FORM","PushDeviceView","View","className","this","model","getTemplate","onInit","dataView","DataView","containerId","format","addChild","PushDevice","PushDeviceList","PushTemplate","PushTemplateList","PushConfig","PushConfigList","PushDelivery","PushDeliveryList","PushConfigForms","GroupList","labelField","valueField","PushTemplateForms","defaultParams","is_active","VIEW_CLASS","Ticket","TicketList","TicketCategories","ticket","bug","feature","incident","security","fulfillment","new_user","new_group","qa","TicketCategoriesOptions","Object","entries","map","key","TicketForms","UserList","TicketNote","TicketNoteList","AssistantConversation","AssistantConversationList","AssistantSkill","AssistantSkillList","Job","cancel","response","save","cancel_request","success","set","retry","delay","retry_request","new_job_id","newJobId","originalJobId","original_job_id","getDetailedStatus","get_status","cloneJob","newPayload","publishData","publish_job","payload","job_id","templateJobId","template_job_id","isActive","get","includes","isScheduled","runAt","ms","Date","getTime","Number","isFinite","now","isTerminal","canRetry","canCancel","getStatusBadgeClass","pending","running","completed","failed","canceled","expired","getStatusIcon","getEvents","getFormattedDuration","duration","toFixed","getQueuePosition","hasExpired","expiresAt","getRunnerId","getPayload","getMetadata","JobList","fetchByStatus","fetch","fetchByChannel","channel","fetchPending","fetchRunning","fetchCompleted","fetchFailed","fetchScheduled","scheduled","JobForms","publish","min","max","clone","async","jobData","POST","getStats","GET","getHealth","test","tests","clearStuck","clearChannel","confirm","cleanConsumers","purgeJobs","days_old","JobLog","JobLogList","JobEvent","JobEventList","JobsEngineStats","SimilarJobsList","func","ActiveJobsList","runnerId","runner_id","EmailDomain","onboard","id","showError","error","url","buildUrl","err","message","audit","method","toUpperCase","reconcile","onboardById","auditById","reconcileById","EmailDomainList","EmailDomainForms","readonly","text","credentials","level","Mailbox","sendEmail","MailboxList","MailboxForms","maxItems","emptyFetch","debounceMs","defaultValue","SentMessage","SentMessageList","SentMessageForms","view","EmailTemplate","EmailTemplateList","EmailTemplateForms","PublicMessageKindOptions","PublicMessageStatusOptions","PublicMessageSeverityOptions","PublicMessageCategoryOptions","PublicMessageMetadataLabels","company","severity","referrer","landing_page","utm_source","utm_medium","utm_campaign","utm_term","utm_content","PublicMessage","PublicMessageList","PhoneNumber","normalize","phoneNumber","countryCode","phone_number","country_code","resp","body","lookup","PhoneNumberList","SMS","send","SMSList","PhoneConfig","PhoneConfigList","PHONE_CONFIG_PROVIDER_OPTIONS","SECRET_PLACEHOLDER","PHONE_CONFIG_FIELDS","showWhen","field","autocomplete","PhoneConfigForms","defaults","provider","test_mode","lookup_enabled","lookup_cache_days","SECRET_FIELDS","PROVIDER_OPTIONS","FORM_DIALOG_CONFIG","submitText","Phonehub","JobRunner","idAttribute","ping","timeout","app","getApp","Error","toISOString","ping_status","shutdown","graceful","getChannels","isHealthy","lastHeartbeat","getFormattedHeartbeatAge","heartbeatAge","Math","round","getUtilization","total","getFormattedUptime","started","startTime","diffMs","diffSeconds","floor","getWorkerInfo","processed","alive","utilization","getDisplayName","parts","split","length","canControl","JobRunnerList","getActive","where","runner","getByChannel","getHealthy","getTotalProcessed","models","reduce","getTotalFailed","getSystemHealth","aliveRunners","filter","getAllChannels","channels","Set","forEach","add","Array","from","sort","window","broadcast","command","broadcastStatus","broadcastShutdown","broadcastPause","broadcastResume","broadcastReload","JobRunnerForms","BouncerDevice","BouncerDeviceList","BouncerSignal","BouncerSignalList","BouncerSignature","BouncerSignatureList","BouncerSignatureForms","default","IPSetKindOptions","IPSetKindBadgeOptions","IPSetSourceOptions","CommonBlockCountries","IPSet","IPSetList","IPSetForms","negate","disabled","S3Bucket","S3BucketList","S3BucketForms","ScheduledTask","ScheduledTaskList","TaskResult","TaskResultList","DAY_LABELS","ScheduledTaskForms"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-models-C8VPjEPG.js","sources":["../../src/extensions/admin/models/LoginEvent.js","../../src/extensions/admin/models/Incident.js","../../src/extensions/admin/messaging/push/PushDeviceView.js","../../src/extensions/admin/models/Push.js","../../src/extensions/admin/models/Tickets.js","../../src/extensions/admin/models/Assistant.js","../../src/extensions/admin/models/Job.js","../../src/extensions/admin/models/Email.js","../../src/extensions/admin/models/PublicMessage.js","../../src/extensions/admin/models/Phonehub.js","../../src/extensions/admin/models/JobRunner.js","../../src/extensions/admin/models/Bouncer.js","../../src/extensions/admin/models/IPSet.js","../../src/extensions/admin/models/AWS.js","../../src/extensions/admin/models/ScheduledTask.js"],"sourcesContent":["/**\n * LoginEvent - Model for login event records with geolocation data\n * Used for login location maps and anomaly detection in admin portals.\n *\n * API: GET /api/account/logins\n * Permissions: manage_users + security + users\n */\n\nimport Model from '@core/Model.js';\nimport Collection from '@core/Collection.js';\n\nclass LoginEvent extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/account/logins',\n });\n }\n}\n\nclass LoginEventList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: LoginEvent,\n endpoint: '/api/account/logins',\n ...options,\n });\n }\n}\n\nexport { LoginEvent, LoginEventList };\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * IncidentEvent\n * ========================= */\n class IncidentStats extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/stats',\n requiresId: false\n });\n }\n }\n\n\nclass IncidentEvent extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event',\n });\n }\n}\n\nclass IncidentEventList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentEvent,\n endpoint: '/api/incident/event',\n size: 10,\n ...options,\n });\n }\n}\n\nconst IncidentEventForms = {\n edit: {\n title: 'Edit Incident Event',\n fields: [\n {\n name: 'category',\n type: 'select',\n label: 'Category',\n placeholder: 'Select category',\n options: () => Incident.COMPONENTS,\n editable: true,\n force_top: true,\n cols: 6,\n },\n {\n name: 'incident',\n type: 'text',\n label: 'Incident',\n placeholder: 'Enter Incident ID',\n cols: 6,\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Description',\n placeholder: 'Enter Description',\n cols: 12,\n },\n {\n name: 'details',\n type: 'textarea',\n label: 'Details',\n placeholder: 'Enter Details',\n cols: 12,\n },\n {\n name: 'component',\n type: 'text',\n label: 'Component',\n placeholder: 'Enter Component',\n cols: 8,\n },\n {\n name: 'component_id',\n type: 'text',\n label: 'Component ID',\n placeholder: 'Enter Component ID',\n cols: 4,\n },\n ],\n },\n};\n\n/* =========================\n * Incident\n * ========================= */\nclass Incident extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/incident',\n });\n }\n}\n\nclass IncidentList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Incident,\n endpoint: '/api/incident/incident',\n size: 10,\n ...options,\n });\n }\n}\n\nconst IncidentForms = {\n create: {\n title: 'Create Incident',\n fields: [\n {\n type: 'tabset',\n name: 'settingsTabs',\n tabs: [\n {\n label: 'General',\n fields: [\n {\n name: 'title',\n type: 'text',\n label: 'Title',\n required: true,\n columns: 12\n },\n {\n name: 'details',\n type: 'textarea',\n label: 'Details',\n required: true,\n columns: 12\n },\n\n ]\n },\n {\n label: 'Advanced',\n fields: [\n {\n name: 'priority',\n type: 'select',\n label: 'Priority',\n options: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],\n value: 5,\n columns: 6\n },\n {\n name: 'status',\n type: 'select',\n label: 'Status',\n value: 'open',\n options: ['open', 'investigating', 'resolved', 'closed', \"paused\", \"ignored\"],\n columns: 6\n },\n {\n name: 'category',\n type: 'text',\n label: 'Category',\n value: 'manual',\n columns: 6\n },\n ]\n },\n {\n label: 'Metadata',\n fields: [\n {\n name: 'metadata',\n type: 'json',\n label: 'Metadata',\n value: { \"example\": \"hello world\" },\n rows: 15,\n columns: 12\n }\n ]\n }\n ]\n },\n\n ]\n },\n edit: {\n title: 'Edit Incident',\n fields: [\n {\n name: 'category',\n type: 'text',\n label: 'Category',\n cols: 6,\n },\n {\n name: 'status',\n type: 'select',\n label: 'Status',\n placeholder: 'Select Status',\n options: ['open', 'investigating', 'resolved', 'closed', 'paused', 'ignored'],\n cols: 3,\n },\n {\n name: 'priority',\n type: 'text',\n label: 'Priority',\n },\n {\n name: 'details',\n type: 'textarea',\n label: 'Description',\n placeholder: 'Enter Name',\n cols: 12,\n },\n {\n name: 'model_name',\n type: 'text',\n label: 'Model',\n placeholder: 'Enter Model',\n cols: 8,\n },\n {\n name: 'model_id',\n type: 'text',\n label: 'Model ID',\n placeholder: 'Enter Model ID',\n cols: 4,\n },\n ],\n },\n};\n\n/* =========================\n * RuleSet / Rule\n * ========================= */\nclass IncidentRuleSet extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset',\n });\n }\n}\n\nclass IncidentRuleSetList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentRuleSet,\n endpoint: '/api/incident/event/ruleset',\n size: 10,\n ...options,\n });\n }\n}\n\nclass IncidentRule extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset/rule',\n });\n }\n}\n\nclass IncidentRuleList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentRule,\n endpoint: '/api/incident/event/ruleset/rule',\n size: 10,\n ...options,\n });\n }\n}\n\n/* =========================\n * IncidentHistory\n * ========================= */\nclass IncidentHistory extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/incident/history',\n });\n }\n}\n\nclass IncidentHistoryList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IncidentHistory,\n endpoint: '/api/incident/incident/history',\n size: 10,\n ...options,\n });\n }\n}\n\n/**\n * RelatedIncidentsList - Incidents related by source / rule / group / host / category / status.\n *\n * Backs IncidentView's \"Related Incidents\" section. Pass any subset of:\n * - `sourceIp` → `?source_ip=<ip>`\n * - `ruleSet` → `?rule_set=<id>`\n * - `group` → `?group=<id>`\n * - `hostname` → `?hostname=<host>`\n * - `category` → `?category=<value>`\n * - `status` → `?status=<value>`\n *\n * Note: Incident has no `user` FK — only `group`. Don't pass `user`;\n * use `group` to scope to a user's primary group.\n *\n * @example\n * const related = new RelatedIncidentsList({\n * sourceIp: incident.get('source_ip'),\n * ruleSet: incident.get('rule_set'),\n * status: 'new'\n * });\n * await related.fetch();\n */\nclass RelatedIncidentsList extends IncidentList {\n constructor(options = {}) {\n const {\n sourceIp,\n ruleSet,\n group,\n hostname,\n category,\n status,\n params = {},\n ...rest\n } = options;\n\n const filterParams = {\n ordering: '-modified',\n ...(sourceIp != null ? { source_ip: sourceIp } : {}),\n ...(ruleSet != null ? { rule_set: ruleSet } : {}),\n ...(group != null ? { group: group } : {}),\n ...(hostname != null ? { hostname: hostname } : {}),\n ...(category != null ? { category: category } : {}),\n ...(status != null ? { status: status } : {}),\n ...params\n };\n\n super({\n params: filterParams,\n ...rest,\n });\n }\n}\n\n\n// Wire form statics so admin TablePages can drop inline form configuration.\nIncident.ADD_FORM = IncidentForms.create;\nIncident.EDIT_FORM = IncidentForms.edit;\nIncidentEvent.EDIT_FORM = IncidentEventForms.edit;\n\nexport {\n IncidentEvent,\n IncidentEventList,\n IncidentEventForms,\n Incident,\n IncidentList,\n IncidentForms,\n IncidentRuleSet,\n IncidentRuleSetList,\n IncidentRule,\n IncidentRuleList,\n IncidentHistory,\n IncidentHistoryList,\n RelatedIncidentsList\n};\n\n/* =========================\n * RuleSet\n * ========================= */\n\n// Bundle By Options\nconst BundleByOptions = [\n { value: 0, label: 'No Bundling' },\n { value: 1, label: 'By Hostname' },\n { value: 2, label: 'By Model Name' },\n { value: 3, label: 'By Model Name + ID' },\n { value: 4, label: 'By Source IP' },\n { value: 5, label: 'By Hostname + Model Name' },\n { value: 6, label: 'By Hostname + Model Name + ID' },\n { value: 7, label: 'By Source IP + Model Name' },\n { value: 8, label: 'By Source IP + Model Name + ID' },\n { value: 9, label: 'By Source IP + Hostname' }\n];\n\n// Match By Options\nconst MatchByOptions = [\n { value: 0, label: 'ALL (must match all rules)' },\n { value: 1, label: 'ANY (match any rule)' }\n];\n\n// Comparator Options\nconst ComparatorOptions = [\n { value: '==', label: 'Equal (==)' },\n { value: 'eq', label: 'Equal (eq)' },\n { value: '>', label: 'Greater Than (>)' },\n { value: '>=', label: 'Greater Than or Equal (>=)' },\n { value: '<', label: 'Less Than (<)' },\n { value: '<=', label: 'Less Than or Equal (<=)' },\n { value: 'contains', label: 'Contains' },\n { value: 'regex', label: 'Regular Expression' }\n];\n\n// Value Type Options\nconst ValueTypeOptions = [\n { value: 'str', label: 'String' },\n { value: 'int', label: 'Integer' },\n { value: 'float', label: 'Float' },\n { value: 'bool', label: 'Boolean' }\n];\n\n// Common Event Fields for ComboInput\nconst CommonEventFields = [\n { value: 'level', label: 'Level', description: 'Event level (error, warning, info, debug)', meta: { type: 'str' } },\n { value: 'source_ip', label: 'Source IP Address', description: 'IP address of the event source', meta: { type: 'str' } },\n { value: 'rule_id', label: 'Rule ID', description: 'Numeric rule identifier', meta: { type: 'int' } },\n { value: 'hostname', label: 'Hostname', description: 'Hostname where event occurred', meta: { type: 'str' } },\n { value: 'component', label: 'Component', description: 'System component name', meta: { type: 'str' } },\n { value: 'component_id', label: 'Component ID', description: 'Component identifier', meta: { type: 'str' } },\n { value: 'category', label: 'Category', description: 'Event category (ossec, auth, api_error, etc.)', meta: { type: 'str' } },\n { value: 'description', label: 'Description', description: 'Event description text', meta: { type: 'str' } },\n { value: 'details', label: 'Details', description: 'Additional event details', meta: { type: 'str' } },\n { value: 'alert_id', label: 'Alert ID', description: 'Numeric alert identifier', meta: { type: 'int' } },\n { value: 'severity', label: 'Severity', description: 'Numeric severity level', meta: { type: 'int' } },\n { value: 'user', label: 'User', description: 'Username associated with event', meta: { type: 'str' } },\n { value: 'action', label: 'Action', description: 'Action that triggered the event', meta: { type: 'str' } },\n { value: 'status', label: 'Status', description: 'Status value or code', meta: { type: 'str' } },\n { value: 'status_code', label: 'Status Code', description: 'Numeric status code (e.g., HTTP status)', meta: { type: 'int' } },\n { value: 'message', label: 'Message', description: 'Event message text', meta: { type: 'str' } },\n { value: 'path', label: 'Path', description: 'File path or URL path', meta: { type: 'str' } },\n { value: 'title', label: 'Title', description: 'OSSEC Title', meta: { type: 'str' } },\n { value: 'country_code', label: 'Country Code', description: 'Country code associated with event', meta: { type: 'str' } },\n { value: 'region', label: 'Region', description: 'Region associated with event', meta: { type: 'str' } },\n { value: 'city', label: 'City', description: 'City associated with event', meta: { type: 'str' } },\n { value: 'http_user_agent', label: 'HTTP User Agent', description: 'User agent string associated with event', meta: { type: 'str' } },\n { value: 'request_path', label: 'Request Path', description: 'Request path associated with event', meta: { type: 'str' } },\n { value: 'method', label: 'Method', description: 'HTTP method or function name', meta: { type: 'str' } }\n];\n\nconst CommonCategoryOptions = [\n // Scopes\n 'global', 'account', 'ossec', 'api', 'realtime',\n // Auth & Login\n 'auth', 'login:unknown', 'invalid_password',\n 'sms:login_unknown', 'totp:login_unknown',\n 'reset:unknown', 'magic:unknown', 'token:unknown',\n // Permissions\n 'api_denied', 'unauthenticated',\n 'view_permission_denied', 'edit_permission_denied',\n 'group_member_permission_denied', 'user_permission_denied',\n // Security\n 'security_alert',\n // MFA\n 'totp:confirm_failed', 'totp:login_failed', 'totp:recovery_used',\n 'sms:otp_failed',\n // Email & SMS\n 'email:no_mailbox', 'email:send_failed', 'sms:send_failed',\n // Account Changes\n 'email_change:bad_password', 'email_change:requested',\n 'account:deactivate_requested',\n 'phone_verify:invalid', 'email_verify:invalid',\n // OAuth\n 'oauth:unlink_guard_error',\n // Errors\n 'rest_error', 'mojo_rest_error', 'rest_value_error'\n];\n\n// Keep backward compat alias\nconst CommonScopeOptions = CommonCategoryOptions;\n\nclass RuleSet extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset',\n });\n }\n}\n\nclass RuleSetList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: RuleSet,\n endpoint: '/api/incident/event/ruleset',\n ...options,\n });\n }\n}\n\nconst BundleMinutesOptions = [\n { value: 0, label: \"Disabled — each event gets its own incident\" },\n { value: 5, label: \"5 minutes\" },\n { value: 10, label: \"10 minutes\" },\n { value: 15, label: \"15 minutes\" },\n { value: 30, label: \"30 minutes\" },\n { value: 60, label: \"1 hour\" },\n { value: 120, label: \"2 hours\" },\n { value: 360, label: \"6 hours\" },\n { value: 720, label: \"12 hours\" },\n { value: 1440, label: \"1 day\" },\n { value: null, label: \"No limit — bundle forever\" }\n];\n\nconst RuleSetForms = {\n create: {\n title: 'Create RuleSet',\n size: 'lg',\n fields: [\n {\n type: 'tabset',\n name: 'rulesetTabs',\n tabs: [\n {\n label: 'General',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'e.g., Brute Force Detection',\n columns: 6\n },\n {\n name: 'match_by',\n type: 'select',\n label: 'Match Logic',\n value: 0,\n options: MatchByOptions,\n tooltip: 'ALL = every condition must match. ANY = at least one',\n columns: 6\n },\n {\n name: 'category',\n type: 'combo',\n label: 'Scope / Category',\n required: true,\n options: CommonCategoryOptions,\n allowCustom: true,\n placeholder: 'Type or select...',\n tooltip: 'Scope or event category to match. Use * as a catch-all',\n columns: 6\n },\n {\n name: 'priority',\n type: 'number',\n label: 'Evaluation Priority',\n value: 10,\n required: true,\n tooltip: 'Lower number = evaluated first',\n columns: 6\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n value: true,\n tooltip: 'Inactive rules are skipped during event processing',\n columns: 6\n },\n {\n name: 'metadata.delete_on_resolution',\n type: 'switch',\n label: 'Delete on Resolution',\n value: false,\n tooltip: 'Incidents are permanently deleted when resolved or closed (CASCADE)',\n columns: 6\n }\n ]\n },\n {\n label: 'Bundling',\n fields: [\n {\n name: 'bundle_by',\n type: 'select',\n label: 'Bundle By',\n value: 4,\n options: BundleByOptions,\n tooltip: 'How to group related events into one incident',\n columns: 6\n },\n {\n name: 'bundle_minutes',\n type: 'select',\n label: 'Bundle Window',\n value: 30,\n options: BundleMinutesOptions,\n tooltip: 'Events outside this window create a new incident',\n columns: 6\n },\n {\n name: 'bundle_by_rule_set',\n type: 'switch',\n label: 'Bundle by RuleSet',\n value: true,\n tooltip: 'Group events matched by this rule into the same incident',\n columns: 6\n }\n ]\n },\n {\n label: 'Thresholds',\n fields: [\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-info-circle me-1\"></i>\n <strong>How thresholds work:</strong> Events accumulate in \"pending\" status.\n Once trigger count is reached, the handler fires and the incident becomes \"new\".\n Leave empty to fire immediately on the first event.\n </div>`\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mb-1\"><span class=\"badge bg-secondary me-1\">1</span> Count — events before fire</div>`\n },\n {\n name: 'trigger_count',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire immediately on first event',\n tooltip: 'Number of events before the handler fires',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">2</span> Within window — count only events in this many minutes</div>`\n },\n {\n name: 'trigger_window',\n type: 'number',\n label: '',\n placeholder: 'Empty = count all events regardless of age',\n tooltip: 'Only count events within this many minutes',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">3</span> Re-trigger — re-fire handler every N additional events</div>`\n },\n {\n name: 'retrigger_every',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire once only',\n tooltip: 'Re-fire handler every N additional events after initial trigger',\n columns: 12\n }\n ]\n },\n {\n label: 'Handler',\n fields: [\n {\n name: 'handler',\n type: 'text',\n label: 'Handler Chain',\n placeholder: 'e.g., block://?ttl=3600,ticket://?priority=8',\n tooltip: 'Chain multiple handlers with commas',\n columns: 12\n },\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-light border small mb-0\">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>`\n }\n ]\n },\n {\n label: 'Agent',\n fields: [\n {\n type: 'html', columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-stars me-1\"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>`\n },\n {\n name: 'metadata.agent_prompt',\n type: 'textarea',\n label: 'Agent Prompt',\n rows: 12,\n columns: 12,\n placeholder: 'You are a security analyst triaging…',\n tooltip: 'Free-form prompt the LLM handler receives alongside the structured incident summary'\n }\n ]\n }\n ]\n }\n ]\n },\n edit: {\n title: 'Edit RuleSet',\n size: 'lg',\n fields: [\n {\n type: 'tabset',\n name: 'rulesetTabs',\n tabs: [\n {\n label: 'General',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'e.g., Brute Force Detection',\n columns: 6\n },\n {\n name: 'match_by',\n type: 'select',\n label: 'Match Logic',\n options: MatchByOptions,\n tooltip: 'ALL = every condition must match. ANY = at least one',\n columns: 6\n },\n {\n name: 'category',\n type: 'combo',\n label: 'Scope / Category',\n options: CommonCategoryOptions,\n allowCustom: true,\n required: true,\n placeholder: 'Type or select...',\n tooltip: 'Scope or event category to match. Use * as a catch-all',\n columns: 6\n },\n {\n name: 'priority',\n type: 'number',\n label: 'Evaluation Priority',\n required: true,\n tooltip: 'Lower number = evaluated first',\n columns: 6\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n tooltip: 'Inactive rules are skipped during event processing',\n columns: 6\n },\n {\n name: 'metadata.delete_on_resolution',\n type: 'switch',\n label: 'Delete on Resolution',\n tooltip: 'Incidents are permanently deleted when resolved or closed (CASCADE)',\n columns: 6\n }\n ]\n },\n {\n label: 'Bundling',\n fields: [\n {\n name: 'bundle_by',\n type: 'select',\n label: 'Bundle By',\n options: BundleByOptions,\n tooltip: 'How to group related events into one incident',\n columns: 6\n },\n {\n name: 'bundle_minutes',\n type: 'select',\n label: 'Bundle Window',\n options: BundleMinutesOptions,\n tooltip: 'Events outside this window create a new incident',\n columns: 6\n },\n {\n name: 'bundle_by_rule_set',\n type: 'switch',\n label: 'Bundle by RuleSet',\n tooltip: 'Group events matched by this rule into the same incident',\n columns: 6\n }\n ]\n },\n {\n label: 'Thresholds',\n fields: [\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-info-circle me-1\"></i>\n <strong>How thresholds work:</strong> Events accumulate in \"pending\" status.\n Once trigger count is reached, the handler fires and the incident becomes \"new\".\n Leave empty to fire immediately on the first event.\n </div>`\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mb-1\"><span class=\"badge bg-secondary me-1\">1</span> Count — events before fire</div>`\n },\n {\n name: 'trigger_count',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire immediately on first event',\n tooltip: 'Number of events before the handler fires',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">2</span> Within window — count only events in this many minutes</div>`\n },\n {\n name: 'trigger_window',\n type: 'number',\n label: '',\n placeholder: 'Empty = count all events regardless of age',\n tooltip: 'Only count events within this window toward the trigger count',\n columns: 12\n },\n {\n type: 'html', columns: 12,\n html: `<div class=\"text-muted small fw-semibold mt-3 mb-1\"><span class=\"badge bg-secondary me-1\">3</span> Re-trigger — re-fire handler every N additional events</div>`\n },\n {\n name: 'retrigger_every',\n type: 'number',\n label: '',\n placeholder: 'Empty = fire once only',\n tooltip: 'Re-fire handler every N additional events after initial trigger',\n columns: 12\n }\n ]\n },\n {\n label: 'Handler',\n fields: [\n {\n name: 'handler',\n type: 'text',\n label: 'Handler Chain',\n placeholder: 'e.g., block://?ttl=3600,ticket://?priority=8',\n tooltip: 'Chain multiple handlers with commas',\n columns: 12\n },\n {\n type: 'html',\n columns: 12,\n html: `<div class=\"alert alert-light border small mb-0\">\n <code>block://?ttl=3600</code> — Block source IP<br>\n <code>ticket://?priority=8</code> — Create ticket<br>\n <code>email://perm@manage_security</code> — Email notification<br>\n <code>sms://perm@manage_security</code> — SMS notification<br>\n <code>notify://perm@manage_security</code> — In-app + push<br>\n <code>llm://</code> — LLM triage agent<br>\n <code>job://myapp.module.function</code> — Async job\n </div>`\n }\n ]\n },\n {\n label: 'Agent',\n fields: [\n {\n type: 'html', columns: 12,\n html: `<div class=\"alert alert-info small mb-3\">\n <i class=\"bi bi-stars me-1\"></i>\n Used by the <code>llm://</code> handler when triaging incidents created by this rule.\n Saved either way — even if no <code>llm://</code> step is in the chain.\n </div>`\n },\n {\n name: 'metadata.agent_prompt',\n type: 'textarea',\n label: 'Agent Prompt',\n rows: 12,\n columns: 12,\n placeholder: 'You are a security analyst triaging…',\n tooltip: 'Free-form prompt the LLM handler receives alongside the structured incident summary'\n }\n ]\n }\n ]\n }\n ]\n }\n};\n\n/* =========================\n * Rule\n * ========================= */\nclass Rule extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/event/ruleset/rule',\n });\n }\n}\n\nclass RuleList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Rule,\n endpoint: '/api/incident/event/ruleset/rule',\n ...options,\n });\n }\n}\n\nconst RuleForms = {\n create: {\n title: 'Create Rule',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'Enter rule name',\n cols: 12\n },\n {\n name: 'field_name',\n type: 'combo',\n label: 'Field Name',\n required: true,\n placeholder: 'Select or enter field name...',\n options: CommonEventFields,\n allowCustom: true,\n showDescription: true,\n help: 'Select a common field or type a custom field name',\n cols: 8\n },\n {\n name: 'index',\n type: 'select',\n label: 'Index',\n required: true,\n start: 0,\n end: 14,\n step: 1,\n cols: 4\n },\n {\n name: 'comparator',\n type: 'select',\n label: 'Comparator',\n required: true,\n options: ComparatorOptions,\n cols: 6\n },\n {\n name: 'value_type',\n type: 'select',\n label: 'Value Type',\n required: true,\n options: ValueTypeOptions,\n value: 'str',\n cols: 6\n },\n {\n name: 'value',\n type: 'textarea',\n label: 'Value',\n required: true,\n placeholder: 'Enter comparison value',\n cols: 12\n }\n ]\n },\n edit: {\n title: 'Edit Rule',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'Enter rule name',\n cols: 12\n },\n {\n name: 'field_name',\n type: 'combo',\n label: 'Field Name',\n required: true,\n placeholder: 'Select or enter field name...',\n options: CommonEventFields,\n allowCustom: true,\n showDescription: true,\n help: 'Select a common field or type a custom field name',\n cols: 12\n },\n {\n name: 'comparator',\n type: 'select',\n label: 'Comparator',\n required: true,\n options: ComparatorOptions,\n cols: 6\n },\n {\n name: 'value_type',\n type: 'select',\n label: 'Value Type',\n required: true,\n options: ValueTypeOptions,\n cols: 6\n },\n {\n name: 'value',\n type: 'text',\n label: 'Value',\n required: true,\n placeholder: 'Enter comparison value',\n cols: 12\n }\n ]\n }\n};\n\n// Attach forms to models\nRuleSet.EDIT_FORM = RuleSetForms.edit;\nRuleSet.ADD_FORM = RuleSetForms.create;\nRuleSet.CREATE_FORM = RuleSetForms.create; // Alias for compatibility\nRuleSet.BundleByOptions = BundleByOptions;\nRuleSet.MatchByOptions = MatchByOptions;\n\nRule.EDIT_FORM = RuleForms.edit;\nRule.ADD_FORM = RuleForms.create;\nRule.CREATE_FORM = RuleForms.create; // Alias for compatibility\nRule.ComparatorOptions = ComparatorOptions;\nRule.ValueTypeOptions = ValueTypeOptions;\n\nexport {\n RuleSet,\n RuleSetList,\n RuleSetForms,\n Rule,\n RuleList,\n RuleForms,\n IncidentStats,\n BundleByOptions,\n BundleMinutesOptions,\n MatchByOptions,\n ComparatorOptions,\n ValueTypeOptions,\n CommonEventFields,\n CommonCategoryOptions,\n CommonScopeOptions\n};\n","import View from '@core/View.js';\nimport DataView from '@core/views/data/DataView.js';\n\nclass PushDeviceView extends View {\n constructor(options = {}) {\n super({\n className: 'push-device-view',\n ...options\n });\n this.model = options.model;\n }\n\n getTemplate() {\n return `\n <div class=\"p-3\">\n <h3>{{model.device_name}}</h3>\n <p class=\"text-muted\">{{model.user.display_name}}</p>\n <div data-container=\"data-view\"></div>\n </div>\n `;\n }\n\n onInit() {\n this.dataView = new DataView({\n containerId: 'data-view',\n model: this.model,\n fields: [\n { name: 'platform', label: 'Platform', format: 'badge' },\n { name: 'push_enabled', label: 'Push Enabled', format: 'boolean' },\n { name: 'app_version', label: 'App Version' },\n { name: 'os_version', label: 'OS Version' },\n { name: 'last_seen', label: 'Last Seen', format: 'datetime' },\n { name: 'push_preferences', label: 'Preferences', format: 'json' },\n ]\n });\n this.addChild(this.dataView);\n }\n}\n\nexport default PushDeviceView;\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport { GroupList } from '@core/models/Group.js';\nimport PushDeviceView from '@ext/admin/messaging/push/PushDeviceView.js';\n\n// =========================\n// PushDevice\n// =========================\nclass PushDevice extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push' });\n }\n}\n\nclass PushDeviceList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushDevice, endpoint: '/api/account/devices/push', ...options });\n }\n}\n\n// =========================\n// PushTemplate\n// =========================\nclass PushTemplate extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push/templates' });\n }\n}\n\nclass PushTemplateList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushTemplate, endpoint: '/api/account/devices/push/templates', ...options });\n }\n}\n\n// =========================\n// PushConfig\n// =========================\nclass PushConfig extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push/config' });\n }\n}\n\nclass PushConfigList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushConfig, endpoint: '/api/account/devices/push/config', ...options });\n }\n}\n\n// =========================\n// PushDelivery\n// =========================\nclass PushDelivery extends Model {\n constructor(data = {}) {\n super(data, { endpoint: '/api/account/devices/push/deliveries' });\n }\n}\n\nclass PushDeliveryList extends Collection {\n constructor(options = {}) {\n super({ ModelClass: PushDelivery, endpoint: '/api/account/devices/push/deliveries', ...options });\n }\n}\n\n// =========================\n// Forms\n// =========================\nconst PushConfigForms = {\n create: {\n title: 'Create Push Configuration',\n fields: [\n { name: 'name', label: 'Name', required: true },\n { type: 'collection', name: 'group', label: 'Group (optional)', Collection: GroupList, labelField: 'name', valueField: 'id' },\n { name: 'fcm_service_account', label: 'Service Account', type: \"textarea\", rows: 10},\n ]\n },\n edit: {\n title: 'Edit Push Configuration',\n fields: [\n { name: 'name', label: 'Name', required: true },\n { type: 'collection', name: 'group', label: 'Group (optional)', Collection: GroupList, labelField: 'name', valueField: 'id' },\n { name: 'fcm_service_account', label: 'Service Account', type: \"textarea\", rows: 10},\n { name: 'is_active', label: 'Is Active', type: 'switch', value: true },\n ]\n }\n};\n\nconst PushTemplateForms = {\n edit: {\n title: 'Edit Push Template',\n fields: [\n { name: 'name', label: 'Name', required: true },\n { name: 'category', label: 'Category', required: true },\n { \n type: 'collection', \n name: 'group', \n label: 'Group (optional)', \n Collection: GroupList, \n labelField: 'name', \n valueField: 'id',\n defaultParams: { is_active: true } // Example: filter to active groups only\n },\n { name: 'title_template', label: 'Title Template', required: true },\n { name: 'body_template', label: 'Body Template', type: 'textarea', required: true },\n { name: 'action_url', label: 'Action URL' },\n { name: 'priority', label: 'Priority', type: 'select', options: ['high', 'normal'] },\n { name: 'variables', label: 'Variables', type: 'json', help: 'JSON format' },\n { name: 'is_active', label: 'Is Active', type: 'switch' },\n ]\n }\n};\n\nPushConfigForms.create = PushConfigForms.edit;\nPushTemplateForms.create = PushTemplateForms.edit;\n\n// Wire form + view-class statics so admin TablePages can drop inline config.\nPushConfig.ADD_FORM = PushConfigForms.create;\nPushConfig.EDIT_FORM = PushConfigForms.edit;\nPushTemplate.ADD_FORM = PushTemplateForms.create;\nPushTemplate.EDIT_FORM = PushTemplateForms.edit;\nPushDevice.VIEW_CLASS = PushDeviceView;\n\n\nexport {\n PushDevice, PushDeviceList,\n PushTemplate, PushTemplateList,\n PushConfig, PushConfigList,\n PushDelivery, PushDeliveryList,\n PushConfigForms, PushTemplateForms\n};\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport { UserList } from '@core/models/User.js';\nimport { IncidentList } from './Incident.js';\n\n/* =========================\n * Ticket\n * ========================= */\nclass Ticket extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/ticket',\n });\n }\n}\n\nclass TicketList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Ticket,\n endpoint: '/api/incident/ticket',\n ...options,\n });\n }\n}\n\n\nconst TicketCategories = {\n 'ticket': 'Ticket',\n 'bug': 'Bug',\n 'feature': 'Feature Request',\n 'incident': 'Incident',\n 'security': 'Security Incident',\n 'fulfillment': 'Fulfillment',\n 'new_user': 'New User',\n 'new_group': 'New Group',\n 'qa': 'Quality Assurance'\n};\n\n// Convert TicketCategories to select options\nconst TicketCategoriesOptions = Object.entries(TicketCategories).map(([key, label]) => ({\n value: key,\n label: label\n}));\n\n\nconst TicketForms = {\n create: {\n title: 'Create Ticket',\n fields: [\n {\n name: 'title', type: 'text',\n label: 'Title', required: true, cols: 12\n },\n { name: 'description', type: 'textarea', label: 'Description', required: false, cols: 12 },\n {\n name: \"category\", type: \"select\", label: \"Category\",\n options: TicketCategoriesOptions, cols: 12, value: 'ticket' },\n {\n name: 'priority', type: 'number',\n label: 'Priority', value: 5, cols: 6\n },\n {\n name: 'status', type: 'select', label: \"Status\",\n options: [\"new\", \"open\", \"paused\", \"resolved\", \"qa\", \"ignored\"],\n cols: 6, value: 'new'\n },\n {\n type: 'collection', name: 'assignee',\n label: 'Assignee', Collection: UserList,\n labelField: 'display_name',\n valueField: 'id',\n cols: 12\n },\n {\n type: 'collection', name: 'incident',\n label: 'Incident', Collection: IncidentList,\n labelField: 'title',\n valueField: 'id',\n cols: 12\n },\n ]\n },\n edit: {\n title: 'Edit Ticket',\n fields: [\n // Description has its own dedicated edit dialog (with markdown helpers).\n { name: 'title', type: 'text', label: 'Title', required: true, cols: 12 },\n { name: \"category\", type: \"select\", label: \"Category\", options: TicketCategoriesOptions, cols: 12 },\n { name: 'priority', type: 'number', label: 'Priority', cols: 6 },\n { name: 'status', type: 'select', label: 'Status', options: [\"new\", \"open\", \"paused\", \"resolved\", \"qa\", \"ignored\"], cols: 6 },\n { type: 'collection', name: 'assignee', label: 'Assignee', Collection: UserList, labelField: 'display_name', valueField: 'id', cols: 12 },\n { type: 'collection', name: 'incident', label: 'Incident', Collection: IncidentList, labelField: 'title', valueField: 'id', cols: 12 },\n { name: 'enable_llm', type: 'checkbox', label: 'Enable AI agent', cols: 12 },\n ]\n }\n};\n\n/* =========================\n * TicketNote\n * ========================= */\nclass TicketNote extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/ticket/note',\n });\n }\n}\n\nclass TicketNoteList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: TicketNote,\n endpoint: '/api/incident/ticket/note',\n ...options,\n });\n }\n}\n\n// Wire form statics so TicketTablePage can drop inline form configuration.\nTicket.ADD_FORM = TicketForms.create;\nTicket.EDIT_FORM = TicketForms.edit;\n\nexport { Ticket, TicketList, TicketNote, TicketNoteList, TicketForms, TicketCategories };\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * AssistantConversation\n * ========================= */\nclass AssistantConversation extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/assistant/conversation',\n });\n }\n}\n\nclass AssistantConversationList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: AssistantConversation,\n endpoint: '/api/assistant/conversation',\n size: 50,\n ...options,\n });\n }\n}\n\n/* =========================\n * AssistantSkill\n * ========================= */\nclass AssistantSkill extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/assistant/skill',\n });\n }\n}\n\nclass AssistantSkillList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: AssistantSkill,\n endpoint: '/api/assistant/skill',\n size: 50,\n ...options,\n });\n }\n}\n\nexport {\n AssistantConversation,\n AssistantConversationList,\n AssistantSkill,\n AssistantSkillList\n};\n\nexport default AssistantConversation;\n","/**\n * Job Model - Async Job Engine management\n * Supports object-oriented POST_SAVE_ACTIONS pattern from Jobs API\n */\n\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport rest from '@core/Rest.js';\n\nclass Job extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/job'\n });\n }\n\n // Object-oriented actions using POST_SAVE_ACTIONS pattern\n async cancel() {\n const response = await this.save({ cancel_request: true });\n if (response.success && response.data.status) {\n // Update local status if successful\n this.set('cancel_requested', true);\n }\n return response;\n }\n\n async retry(delay = null) {\n const data = delay ?\n { retry_request: { retry: true, delay } } :\n { retry_request: true };\n\n const response = await this.save(data);\n if (response.success && response.data.status && response.data.new_job_id) {\n // Return new job ID if created\n return {\n ...response,\n newJobId: response.data.new_job_id,\n originalJobId: response.data.original_job_id\n };\n }\n return response;\n }\n\n async getDetailedStatus() {\n const response = await this.save({ get_status: true });\n if (response.success && response.data.status) {\n // Update local data with detailed status\n this.set(response.data.data);\n }\n return response;\n }\n\n async cloneJob(newPayload = {}) {\n const publishData = {\n publish_job: {\n payload: newPayload,\n ...newPayload\n }\n };\n\n const response = await this.save(publishData);\n if (response.success && response.data.status && response.data.job_id) {\n return {\n ...response,\n newJobId: response.data.job_id,\n templateJobId: response.data.template_job_id\n };\n }\n return response;\n }\n\n // Status helper methods\n isActive() {\n const status = this.get('status');\n return ['pending', 'running'].includes(status);\n }\n\n /**\n * A pending job with a future `run_at` is \"scheduled\" — it isn't\n * actively waiting in the queue, it'll be enqueued when run_at hits.\n * Treat it as a distinct UI state.\n */\n isScheduled() {\n if (this.get('status') !== 'pending') return false;\n const runAt = this.get('run_at');\n if (!runAt) return false;\n const ms = (typeof runAt === 'number' && runAt < 1e11) ? runAt * 1000 : new Date(runAt).getTime();\n return Number.isFinite(ms) && ms > Date.now();\n }\n\n isTerminal() {\n const status = this.get('status');\n return ['completed', 'failed', 'canceled', 'expired'].includes(status);\n }\n\n canRetry() {\n const status = this.get('status');\n return ['failed', 'canceled', 'expired'].includes(status) && this.get('is_retriable') !== false;\n }\n\n canCancel() {\n const status = this.get('status');\n return ['pending', 'running'].includes(status) && !this.get('cancel_requested');\n }\n\n // Get status badge class for UI\n getStatusBadgeClass() {\n const status = this.get('status');\n const classes = {\n 'pending': 'bg-primary',\n 'running': 'bg-success',\n 'completed': 'bg-info',\n 'failed': 'bg-danger',\n 'canceled': 'bg-secondary',\n 'expired': 'bg-warning'\n };\n return classes[status] || 'bg-secondary';\n }\n\n // Get status icon\n getStatusIcon() {\n const status = this.get('status');\n const icons = {\n 'pending': 'bi-hourglass',\n 'running': 'bi-arrow-repeat',\n 'completed': 'bi-check-circle',\n 'failed': 'bi-x-octagon',\n 'canceled': 'bi-x-circle',\n 'expired': 'bi-clock'\n };\n return icons[status] || 'bi-question-circle';\n }\n\n // Get recent events for timeline\n getEvents() {\n return this.get('recent_events') || [];\n }\n\n // Get formatted duration\n getFormattedDuration() {\n const duration = this.get('duration_ms');\n if (!duration || duration === 0) return 'N/A';\n\n if (duration < 1000) return `${duration}ms`;\n if (duration < 60000) return `${(duration / 1000).toFixed(1)}s`;\n if (duration < 3600000) return `${(duration / 60000).toFixed(1)}m`;\n return `${(duration / 3600000).toFixed(1)}h`;\n }\n\n // Get queue position if available\n getQueuePosition() {\n return this.get('queue_position');\n }\n\n // Check if job has expired\n hasExpired() {\n const expiresAt = this.get('expires_at');\n if (!expiresAt) return false;\n return new Date(expiresAt) < new Date();\n }\n\n // Get runner information\n getRunnerId() {\n return this.get('runner_id');\n }\n\n // Get payload data\n getPayload() {\n return this.get('payload') || {};\n }\n\n // Get metadata\n getMetadata() {\n return this.get('metadata') || {};\n }\n}\n\nclass JobList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Job,\n endpoint: '/api/jobs/job',\n ...options\n });\n }\n\n // Filter by status\n async fetchByStatus(status, params = {}) {\n return this.fetch({ status, ...params });\n }\n\n // Filter by channel\n async fetchByChannel(channel, params = {}) {\n return this.fetch({ channel, ...params });\n }\n\n // Get pending jobs\n async fetchPending(params = {}) {\n return this.fetchByStatus('pending', params);\n }\n\n // Get running jobs\n async fetchRunning(params = {}) {\n return this.fetchByStatus('running', params);\n }\n\n // Get completed jobs\n async fetchCompleted(params = {}) {\n return this.fetchByStatus('completed', params);\n }\n\n // Get failed jobs\n async fetchFailed(params = {}) {\n return this.fetchByStatus('failed', params);\n }\n\n // Get scheduled jobs (those with run_at)\n async fetchScheduled(params = {}) {\n return this.fetch({\n scheduled: true, // This may need to be adjusted based on actual API\n ...params\n });\n }\n}\n\n// Form configurations for job management\nconst JobForms = {\n publish: {\n title: 'Publish New Job',\n fields: [\n {\n name: 'func',\n type: 'text',\n label: 'Function',\n required: true,\n placeholder: 'myapp.jobs.send_email',\n help: 'Module path to job function'\n },\n {\n name: 'channel',\n type: 'text',\n label: 'Channel',\n value: 'default',\n help: 'Queue channel (default: \"default\")'\n },\n {\n name: 'payload',\n type: 'textarea',\n label: 'Payload (JSON)',\n required: true,\n rows: 8,\n placeholder: '{\\n \"key\": \"value\"\\n}',\n help: 'JSON data passed to the job function'\n },\n {\n name: 'delay',\n type: 'number',\n label: 'Delay (seconds)',\n min: 0,\n help: 'Delay execution by specified seconds'\n },\n {\n name: 'run_at',\n type: 'datetime-local',\n label: 'Run At',\n help: 'Schedule for specific date/time'\n },\n {\n name: 'max_retries',\n type: 'number',\n label: 'Max Retries',\n value: 3,\n min: 0,\n max: 10\n },\n {\n name: 'expires_in',\n type: 'number',\n label: 'Expires In (seconds)',\n value: 900,\n min: 60,\n help: 'Job will expire if not completed in this time'\n },\n {\n name: 'broadcast',\n type: 'switch',\n label: 'Broadcast to All Workers',\n help: 'Execute on all available workers'\n }\n ]\n },\n\n retry: {\n title: 'Retry Job',\n fields: [\n {\n name: 'delay',\n type: 'number',\n label: 'Delay (seconds)',\n value: 0,\n min: 0,\n help: 'Delay before retry (0 = immediate)'\n }\n ]\n },\n\n clone: {\n title: 'Clone Job',\n fields: [\n {\n name: 'channel',\n type: 'text',\n label: 'Channel',\n help: 'Override channel for cloned job'\n },\n {\n name: 'payload',\n type: 'textarea',\n label: 'Modified Payload (JSON)',\n rows: 8,\n help: 'Modified payload for cloned job'\n },\n {\n name: 'delay',\n type: 'number',\n label: 'Delay (seconds)',\n min: 0\n }\n ]\n }\n};\n\n// Static method to publish new job directly\nJob.publish = async function(jobData) {\n return await rest.POST('/api/jobs/publish', jobData);\n};\n\n// Static method to get system stats\nJob.getStats = async function() {\n const response = await rest.GET('/api/jobs/stats');\n return response.success ? response.data : null;\n};\n\n// Static method to get system health\nJob.getHealth = async function(channel = null) {\n const endpoint = channel ? `/api/jobs/health/${channel}` : '/api/jobs/health';\n const response = rest.GET(endpoint);\n return response.success ? response.data : null;\n};\n\n// Static method to run test job\nJob.test = async function() {\n return await rest.POST('/api/jobs/test', {});\n};\n\n// Static method to run test jobs\nJob.tests = async function() {\n return await rest.POST('/api/jobs/tests', {});\n};\n\nJob.clearStuck = async function(channel = null) {\n const payload = channel ? { channel } : {};\n return await rest.POST('/api/jobs/control/clear-stuck', payload);\n};\n\nJob.clearChannel = async function(channel) {\n return await rest.POST('/api/jobs/control/clear-queue', { channel, confirm:\"yes\" });\n};\n\nJob.cleanConsumers = async function() {\n return await rest.POST('/api/jobs/control/cleanup-consumers');\n};\n\nJob.purgeJobs = async function(days_old) {\n return await rest.POST('/api/jobs/control/purge', { days_old });\n};\n\n\nclass JobLog extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/logs'\n });\n }\n}\n\nclass JobLogList extends Collection {\n constructor(options = {}) {\n super({\n endpoint: '/api/jobs/logs',\n model: JobLog,\n ...options\n });\n }\n}\n\n\nclass JobEvent extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/event'\n });\n }\n}\n\nclass JobEventList extends Collection {\n constructor(options = {}) {\n super({\n endpoint: '/api/jobs/event',\n model: JobEvent,\n ...options\n });\n }\n}\n\nclass JobsEngineStats extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/jobs/stats',\n requiresId: false\n });\n }\n}\n\n/**\n * SimilarJobsList - Recent runs of the same `func`.\n *\n * Backs JobDetailsView's \"Similar Jobs\" section. Consumers pass the\n * function name (or a Job model from which to read `func`) and an\n * optional row limit; the collection's `params` apply on every fetch.\n *\n * @example\n * const sj = new SimilarJobsList({ func: model.get('func') });\n * await sj.fetch();\n * // → GET /api/jobs/job?func=<name>&ordering=-created\n */\nclass SimilarJobsList extends JobList {\n constructor(options = {}) {\n const { func, params = {}, ...rest } = options;\n super({\n params: {\n ordering: '-created',\n ...(func ? { func } : {}),\n ...params\n },\n ...rest\n });\n }\n}\n\n/**\n * ActiveJobsList - Jobs currently running on a runner.\n *\n * Backs RunnerDetailsView's \"Active Jobs\" section. Pass the runner id\n * via `runnerId` (preferred) or as a custom param.\n *\n * @example\n * const aj = new ActiveJobsList({ runnerId: runner.get('runner_id') });\n * await aj.fetch();\n * // → GET /api/jobs/job?runner_id=<id>&status=running\n */\nclass ActiveJobsList extends JobList {\n constructor(options = {}) {\n const { runnerId, params = {}, ...rest } = options;\n super({\n params: {\n status: 'running',\n ...(runnerId != null ? { runner_id: runnerId } : {}),\n ...params\n },\n ...rest\n });\n }\n}\n\nexport {\n Job, JobList, JobForms,\n JobLog, JobLogList, JobEvent,\n JobEventList, JobsEngineStats,\n SimilarJobsList, ActiveJobsList };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\nimport rest from '@core/Rest.js';\n\n\n/**\n * EmailDomain - SES/SNS/S3-backed email domain model\n * Maps to REST endpoints under /api/aws/email/domain\n *\n * Key operations:\n * - Create/Update/Delete domains\n * - Onboard: DNS records + SNS + optional receiving\n * - Audit: Drift report (verification/DKIM, topics, receipt rules)\n * - Reconcile: Safe, idempotent fixes (no DNS writes)\n *\n * Notes:\n * - Management endpoints require \"manage_aws\" permission server-side.\n * - Error handling follows the MOJO Rest response contract.\n */\nclass EmailDomain extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/domain',\n ...options\n });\n }\n\n /**\n * Onboard the domain (DNS/SNS/receiving orchestration).\n * POST /api/aws/email/domain/<id>/onboard\n *\n * @param {object} data\n * receiving_enabled?: boolean\n * s3_inbound_bucket?: string\n * s3_inbound_prefix?: string\n * ensure_mail_from?: boolean\n * mail_from_subdomain?: string\n * dns_mode?: \"manual\" | \"godaddy\"\n * godaddy_key?: string\n * godaddy_secret?: string\n * endpoints?: { bounce, complaint, delivery, inbound }\n * @param {object} options - Optional { params?: object }\n * @returns {Promise<object>} REST response\n */\n async onboard(data = {}, options = {}) {\n if (!this.id) {\n await this.showError('Cannot onboard domain without ID');\n return {\n success: false,\n status: 400,\n error: 'Missing domain id'\n };\n }\n\n try {\n const url = `${this.buildUrl(this.id)}/onboard`;\n const response = await this.rest.POST(url, data, options.params);\n\n // No guaranteed shape to merge; response contains DNS records, topics, notes, etc.\n // If backend returns updated domain fields, you can call this.set(response.data.data).\n return response;\n } catch (err) {\n return {\n success: false,\n status: err?.status || 500,\n error: err?.message || 'Failed to onboard domain'\n };\n }\n }\n\n /**\n * Audit domain configuration for drift.\n * GET or POST /api/aws/email/domain/<id>/audit\n *\n * @param {object} options\n * method?: 'GET'|'POST' (default 'GET')\n * data?: object (when method is POST)\n * params?: object (query params for GET)\n * @returns {Promise<object>} REST response\n */\n async audit(options = {}) {\n if (!this.id) {\n await this.showError('Cannot audit domain without ID');\n return {\n success: false,\n status: 400,\n error: 'Missing domain id'\n };\n }\n\n const method = (options.method || 'GET').toUpperCase();\n const url = `${this.buildUrl(this.id)}/audit`;\n\n try {\n if (method === 'POST') {\n return await this.rest.POST(url, options.data || {}, options.params);\n }\n return await this.rest.GET(url, options.params);\n } catch (err) {\n return {\n success: false,\n status: err?.status || 500,\n error: err?.message || 'Failed to audit domain'\n };\n }\n }\n\n /**\n * Reconcile domain configuration (safe fixes; no DNS writes).\n * POST /api/aws/email/domain/<id>/reconcile\n *\n * @param {object} data - Optional payload (usually none required)\n * @param {object} options - Optional { params?: object }\n * @returns {Promise<object>} REST response\n */\n async reconcile(data = {}, options = {}) {\n if (!this.id) {\n await this.showError('Cannot reconcile domain without ID');\n return {\n success: false,\n status: 400,\n error: 'Missing domain id'\n };\n }\n\n try {\n const url = `${this.buildUrl(this.id)}/reconcile`;\n return await this.rest.POST(url, data, options.params);\n } catch (err) {\n return {\n success: false,\n status: err?.status || 500,\n error: err?.message || 'Failed to reconcile domain'\n };\n }\n }\n\n /**\n * Convenience: Onboard by id without creating a separate instance.\n * @param {string|number} id\n * @param {object} data\n * @param {object} options\n */\n static async onboardById(id, data = {}, options = {}) {\n const model = new EmailDomain({ id }, options);\n return await model.onboard(data, options);\n }\n\n /**\n * Convenience: Audit by id without creating a separate instance.\n * @param {string|number} id\n * @param {object} options - see audit()\n */\n static async auditById(id, options = {}) {\n const model = new EmailDomain({ id }, options);\n return await model.audit(options);\n }\n\n /**\n * Convenience: Reconcile by id without creating a separate instance.\n * @param {string|number} id\n * @param {object} data\n * @param {object} options\n */\n static async reconcileById(id, data = {}, options = {}) {\n const model = new EmailDomain({ id }, options);\n return await model.reconcile(data, options);\n }\n}\n\n/**\n * EmailDomainList - Collection of EmailDomain\n * Supports standard MOJO list/search/sort/pagination patterns\n */\nclass EmailDomainList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: EmailDomain,\n endpoint: '/api/aws/email/domain',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for EmailDomain (for TablePage/Dialog integration)\n * NOTE: Conditional requirements (e.g., s3_inbound_bucket when receiving_enabled)\n * should be validated server-side; help text guides the admin.\n */\nconst EmailDomainForms = {\n create: {\n title: 'Add Email Domain',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Domain Name',\n placeholder: 'example.com',\n required: true,\n columns: 12,\n help: 'Enter the root domain to verify with SES (no protocol).'\n },\n {\n name: 'region',\n type: 'text',\n label: 'AWS Region (optional)',\n placeholder: 'us-east-1',\n columns: 12,\n help: 'Optional. Defaults to project AWS_REGION if omitted.'\n },\n {\n name: 'aws_key',\n type: 'text',\n label: 'AWS Key (optional)',\n placeholder: 'enter your AWS Key with SES permissions',\n columns: 12,\n help: 'Optional, AWS Key with SES permissions'\n },\n {\n name: 'aws_secret',\n type: 'text',\n label: 'AWS Secret (optional)',\n placeholder: 'enter your AWS Secret with SES permissions',\n columns: 12,\n help: 'Optional, AWS Secret with SES permissions'\n },\n {\n name: 'receiving_enabled',\n type: 'switch',\n label: 'Enable Inbound Receiving',\n columns: 12,\n help: 'Catch-all SES receipt rule to S3 + SNS; routing is done in-app.'\n }\n ]\n },\n\n edit: {\n title: 'Edit Email Domain',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Domain Name',\n placeholder: 'example.com',\n required: true,\n columns: 12,\n readonly: true,\n help: 'Domain name cannot be changed after creation.'\n },\n {\n name: 'region',\n type: 'text',\n label: 'AWS Region',\n placeholder: 'us-east-1',\n columns: 12\n },\n {\n name: 'receiving_enabled',\n type: 'switch',\n label: 'Enable Inbound Receiving',\n columns: 12\n },\n {\n name: 's3_inbound_bucket',\n type: 'text',\n label: 'Inbound S3 Bucket',\n placeholder: 'my-inbound-bucket',\n columns: 12\n },\n {\n name: 's3_inbound_prefix',\n type: 'text',\n label: 'Inbound S3 Prefix',\n placeholder: 'inbound/example.com/',\n columns: 12\n },\n {\n name: 'dns_mode',\n type: 'select',\n label: 'DNS Mode',\n options: [\n { value: 'manual', text: 'Manual (show records)' },\n { value: 'godaddy', text: 'GoDaddy (apply via API)' }\n ],\n columns: 12\n }\n ],\n },\n\n credentials: {\n fields: [\n {\n name: 'region',\n type: 'select',\n label: 'AWS Region (optional)',\n placeholder: 'us-east-1',\n options: [\n { value: 'us-east-1', text: 'US East (N. Virginia)' },\n { value: 'us-east-2', text: 'US East (Ohio)' },\n { value: 'us-west-1', text: 'US West (N. California)' },\n { value: 'us-west-2', text: 'US West (Oregon)' },\n { value: 'ca-central-1', text: 'Canada (Central)' },\n { value: 'eu-west-1', text: 'Europe (Ireland)' },\n { value: 'eu-west-2', text: 'Europe (London)' },\n { value: 'eu-west-3', text: 'Europe (Paris)' },\n { value: 'eu-central-1', text: 'Europe (Frankfurt)' },\n { value: 'eu-north-1', text: 'Europe (Stockholm)' },\n { value: 'eu-south-1', text: 'Europe (Milan)' },\n { value: 'ap-southeast-2', text: 'Asia Pacific (Sydney)' }\n ],\n columns: 12,\n help: 'Optional. Defaults to project AWS_REGION if omitted.'\n },\n {\n name: 'aws_key',\n type: 'text',\n label: 'AWS Key (optional)',\n placeholder: 'enter your AWS Key with SES permissions',\n columns: 12,\n help: 'Optional, AWS Key with SES permissions'\n },\n {\n name: 'aws_secret',\n type: 'text',\n label: 'AWS Secret (optional)',\n placeholder: 'enter your AWS Secret with SES permissions',\n columns: 12,\n help: 'Optional, AWS Secret with SES permissions'\n },\n ]\n},\n\n onboard: {\n title: 'Onboard Domain',\n fields: [\n {\n type: 'header',\n text: 'Receiving',\n level: 6,\n className: 'mt-2'\n },\n {\n name: 'receiving_enabled',\n type: 'switch',\n label: 'Enable Inbound Receiving',\n columns: 12\n },\n {\n name: 's3_inbound_bucket',\n type: 'text',\n label: 'Inbound S3 Bucket',\n placeholder: 'my-inbound-bucket',\n columns: 12,\n help: 'Required if receiving is enabled.'\n },\n {\n name: 's3_inbound_prefix',\n type: 'text',\n label: 'Inbound S3 Prefix',\n placeholder: 'inbound/example.com/',\n columns: 12\n },\n\n {\n type: 'header',\n text: 'MAIL FROM (optional)',\n level: 6,\n className: 'mt-3'\n },\n {\n name: 'ensure_mail_from',\n type: 'switch',\n label: 'Ensure MAIL FROM Setup',\n columns: 12\n },\n {\n name: 'mail_from_subdomain',\n type: 'text',\n label: 'MAIL FROM Subdomain',\n placeholder: 'feedback',\n columns: 12\n },\n\n {\n type: 'header',\n text: 'DNS',\n level: 6,\n className: 'mt-3'\n },\n {\n name: 'dns_mode',\n type: 'select',\n label: 'DNS Mode',\n options: [\n { value: 'manual', text: 'Manual (show records)' },\n { value: 'godaddy', text: 'GoDaddy (apply via API)' }\n ],\n value: 'manual',\n columns: 12\n },\n {\n name: 'godaddy_key',\n type: 'text',\n label: 'GoDaddy API Key',\n columns: 12,\n help: 'Required when DNS Mode = GoDaddy.'\n },\n {\n name: 'godaddy_secret',\n type: 'password',\n label: 'GoDaddy API Secret',\n columns: 12\n },\n\n {\n type: 'header',\n text: 'Webhook Endpoints',\n level: 6,\n className: 'mt-3'\n },\n {\n name: 'endpoints.bounce',\n type: 'text',\n label: 'Bounce Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/bounce',\n columns: 12\n },\n {\n name: 'endpoints.complaint',\n type: 'text',\n label: 'Complaint Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/complaint',\n columns: 12\n },\n {\n name: 'endpoints.delivery',\n type: 'text',\n label: 'Delivery Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/delivery',\n columns: 12\n },\n {\n name: 'endpoints.inbound',\n type: 'text',\n label: 'Inbound Endpoint',\n placeholder: 'https://portal.example.com/api/aws/sns/inbound',\n columns: 12\n }\n ]\n }\n};\n\n/**\n * Mailbox - Represents a single email address within a domain.\n * Endpoint: /api/aws/email/mailbox\n * Fields (typical):\n * - domain: FK (domain id) or name (server may accept name)\n * - email: full address\n * - allow_inbound: boolean\n * - allow_outbound: boolean\n * - async_handler: \"package.module:function\" for task dispatch on inbound\n */\nclass Mailbox extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/mailbox',\n ...options\n });\n }\n}\n\nMailbox.sendEmail = async function(data) {\n return await rest.POST('/api/aws/email/send', data);\n};\n\n/**\n * MailboxList - Collection of Mailboxes\n */\nclass MailboxList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Mailbox,\n endpoint: '/api/aws/email/mailbox',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for Mailbox CRUD\n */\nconst MailboxForms = {\n create: {\n title: 'Add Mailbox',\n fields: [\n {\n type: 'collection',\n name: 'domain',\n label: 'Domain',\n Collection: EmailDomainList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search domains...',\n emptyFetch: false,\n required: true,\n debounceMs: 300, // Search debounce delay\n columns: 12\n },\n {\n name: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'support@example.com',\n required: true,\n columns: 12\n },\n {\n name: 'allow_inbound',\n type: 'switch',\n label: 'Allow Inbound',\n columns: 6\n },\n {\n name: 'allow_outbound',\n type: 'switch',\n label: 'Allow Outbound',\n defaultValue: true,\n columns: 6\n },\n {\n name: 'is_system_default',\n type: 'switch',\n label: 'System Default',\n columns: 6\n },\n {\n name: 'is_domain_default',\n type: 'switch',\n label: 'Domain Default',\n columns: 6\n },\n {\n name: 'async_handler',\n type: 'text',\n label: 'Async Handler (optional)',\n placeholder: 'myapp.handlers.process_support',\n columns: 12,\n help: 'Module:function to process inbound messages via task system'\n }\n ]\n },\n\n edit: {\n title: 'Edit Mailbox',\n fields: [\n {\n name: 'email',\n type: 'email',\n label: 'Email Address',\n required: true,\n columns: 12\n },\n {\n name: 'allow_inbound',\n type: 'switch',\n label: 'Allow Inbound',\n columns: 6\n },\n {\n name: 'allow_outbound',\n type: 'switch',\n label: 'Allow Outbound',\n columns: 6\n },\n {\n name: 'is_system_default',\n type: 'switch',\n label: 'System Default',\n columns: 6\n },\n {\n name: 'is_domain_default',\n type: 'switch',\n label: 'Domain Default',\n columns: 6\n },\n {\n name: 'async_handler',\n type: 'text',\n label: 'Async Handler (optional)',\n placeholder: 'myapp.handlers.process_support',\n columns: 12\n }\n ]\n }\n};\n\n/**\n * SentMessage - Outbound messages sent via SES; read-only in UI\n * Endpoint: /api/aws/email/sent\n */\nclass SentMessage extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/sent',\n ...options\n });\n }\n}\n\n/**\n * SentMessageList - Collection of SentMessage\n */\nclass SentMessageList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: SentMessage,\n endpoint: '/api/aws/email/sent',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms for SentMessage (read-only details)\n */\nconst SentMessageForms = {\n view: {\n title: 'Sent Message Details',\n fields: [\n { name: 'id', type: 'text', label: 'ID', readonly: true, cols: 6 },\n { name: 'ses_message_id', type: 'text', label: 'SES Message ID', readonly: true, cols: 6 },\n { name: 'from_email', type: 'text', label: 'From', readonly: true, cols: 12 },\n { name: 'to', type: 'textarea', label: 'To', readonly: true, rows: 2, cols: 12 },\n { name: 'cc', type: 'textarea', label: 'CC', readonly: true, rows: 2, cols: 12 },\n { name: 'bcc', type: 'textarea', label: 'BCC', readonly: true, rows: 2, cols: 12 },\n { name: 'subject', type: 'text', label: 'Subject', readonly: true, cols: 12 },\n { name: 'status', type: 'text', label: 'Status', readonly: true, cols: 6 },\n { name: 'status_reason', type: 'textarea', label: 'Status Reason', readonly: true, rows: 3, cols: 12 },\n { name: 'created', type: 'text', label: 'Created', readonly: true, cols: 6 }\n ]\n }\n};\n\n/**\n * EmailTemplate - DB template entries (Django templated), CRUD supported\n * Endpoint: /api/aws/email/template\n */\nclass EmailTemplate extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/aws/email/template',\n ...options\n });\n }\n}\n\n/**\n * EmailTemplateList - Collection of EmailTemplate\n */\nclass EmailTemplateList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: EmailTemplate,\n endpoint: '/api/aws/email/template',\n size: 10,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for EmailTemplate CRUD\n */\nconst EmailTemplateForms = {\n create: {\n title: 'Add Email Template',\n fields: [\n { name: 'name', type: 'text', label: 'Name', required: true, cols: 12 },\n { name: 'subject_template', type: 'text', label: 'Subject Template', cols: 12 },\n {\n type: 'tabset',\n name: 'settingsTabs',\n tabs: [\n {\n label: 'HTML',\n fields: [\n { name: 'html_template', type: 'htmlpreview', label: 'HTML Template', rows: 16, cols: 12 },\n ],\n },\n {\n label: 'TEXT',\n fields: [\n { name: 'text_template', type: 'textarea', label: 'Text Template', rows: 16, cols: 12 }\n ]\n }\n ]\n }\n ]\n },\n edit: {\n title: 'Edit Email Template',\n fields: [\n { name: 'name', type: 'text', label: 'Name', required: true, cols: 12 },\n { name: 'subject_template', type: 'text', label: 'Subject Template', cols: 12 },\n {\n type: 'tabset',\n name: 'settingsTabs',\n tabs: [\n {\n label: 'HTML',\n fields: [\n { name: 'html_template', type: 'textarea', label: 'HTML Template', rows: 16, cols: 12 },\n ],\n },\n {\n label: 'TEXT',\n fields: [\n { name: 'text_template', type: 'textarea', label: 'Text Template', rows: 16, cols: 12 }\n ]\n }\n ]\n }\n ]\n }\n};\n\n// Wire form statics so admin TablePages can drop inline form configuration.\nEmailDomain.ADD_FORM = EmailDomainForms.create;\nEmailDomain.EDIT_FORM = EmailDomainForms.edit;\nMailbox.ADD_FORM = MailboxForms.create;\nMailbox.EDIT_FORM = MailboxForms.edit;\nEmailTemplate.ADD_FORM = EmailTemplateForms.create;\nEmailTemplate.EDIT_FORM = EmailTemplateForms.edit;\n\nexport {\n EmailDomain,\n EmailDomainList,\n EmailDomainForms,\n Mailbox,\n MailboxList,\n MailboxForms,\n SentMessage,\n SentMessageList,\n SentMessageForms,\n EmailTemplate,\n EmailTemplateList,\n EmailTemplateForms\n};\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * Constants\n * ========================= */\n\nconst PublicMessageKindOptions = [\n { value: 'contact_us', label: 'Contact Us' },\n { value: 'support', label: 'Support' },\n];\n\nconst PublicMessageStatusOptions = [\n { value: 'open', label: 'Open' },\n { value: 'closed', label: 'Closed' },\n];\n\nconst PublicMessageSeverityOptions = [\n { value: 'low', label: 'Low' },\n { value: 'normal', label: 'Normal' },\n { value: 'high', label: 'High' },\n];\n\nconst PublicMessageCategoryOptions = [\n { value: 'billing', label: 'Billing' },\n { value: 'account', label: 'Account' },\n { value: 'bug', label: 'Bug' },\n { value: 'other', label: 'Other' },\n];\n\n// Friendly labels for known metadata keys. Unknown keys are humanized at render time.\nconst PublicMessageMetadataLabels = {\n company: 'Company',\n category: 'Category',\n severity: 'Severity',\n referrer: 'Referrer',\n landing_page: 'Landing Page',\n utm_source: 'UTM Source',\n utm_medium: 'UTM Medium',\n utm_campaign: 'UTM Campaign',\n utm_term: 'UTM Term',\n utm_content: 'UTM Content',\n};\n\n/* =========================\n * PublicMessage Model\n * ========================= */\n\nclass PublicMessage extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/account/public_message',\n });\n }\n}\n\n/* =========================\n * PublicMessage Collection\n * ========================= */\n\nclass PublicMessageList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: PublicMessage,\n endpoint: '/api/account/public_message',\n size: 25,\n ...options,\n });\n }\n}\n\nexport {\n PublicMessage,\n PublicMessageList,\n PublicMessageKindOptions,\n PublicMessageStatusOptions,\n PublicMessageSeverityOptions,\n PublicMessageCategoryOptions,\n PublicMessageMetadataLabels,\n};\n","/**\n * Phonehub.js\n * Models and Collections for PhoneHub phone numbers and SMS with helper actions.\n *\n * Endpoints (all require authentication unless noted):\n * - Phone Number\n * - POST /api/phonehub/number/normalize\n * - POST /api/phonehub/number/lookup\n * - GET /api/phonehub/number\n * - GET /api/phonehub/number/:id\n * - PUT /api/phonehub/number/:id\n * - DELETE /api/phonehub/number/:id\n *\n * - SMS\n * - POST /api/phonehub/sms/send\n * - GET /api/phonehub/sms\n * - GET /api/phonehub/sms/:id\n *\n * Notes on response shapes:\n * - List endpoints typically return { status: true, data: [...], count, size, start }\n * - Single item endpoints typically return { status: true, data: {...} }\n * - Action endpoints (normalize, lookup, send) return { status: true, data: {...} } or { status: false, error }\n */\n\nimport Model from '@core/Model.js';\nimport Collection from '@core/Collection.js';\nimport rest from '@core/Rest.js';\nimport { GroupList } from '@core/models/Group.js';\n\n// ======================================================\n// PhoneNumber Model & Collection\n// ======================================================\n\n/**\n * PhoneNumber - Represents a cached phone number lookup result.\n */\nclass PhoneNumber extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/phonehub/number',\n ...options\n });\n }\n\n /**\n * Normalize an arbitrary phone_number string to E.164 format.\n * @param {string} phoneNumber - Raw phone number input.\n * @param {string} [countryCode='US'] - Optional country code (default US).\n * @returns {Promise<{success: boolean, phone_number?: string, data?: object, error?: string, response?: any}>}\n */\n static async normalize(phoneNumber, countryCode = 'US') {\n const url = '/api/phonehub/number/normalize';\n const payload = {\n phone_number: phoneNumber\n };\n if (countryCode) payload.country_code = countryCode;\n\n const resp = await rest.POST(url, payload);\n const body = resp?.data ?? resp; // rest wrapper or raw\n const ok = body?.status === true || body?.success === true;\n\n if (ok) {\n const normalized = body?.data?.phone_number ?? body?.phone_number;\n return { success: true, phone_number: normalized, data: body?.data ?? body, response: resp };\n }\n return { success: false, error: body?.error || 'Normalization failed', response: resp };\n }\n\n /**\n * Lookup phone number details (carrier, line_type, owner, etc.)\n * @param {string} phoneNumber - E.164 or raw phone number.\n * @param {object} [options] - { force_refresh?: boolean, group?: number }\n * @returns {Promise<{success: boolean, model?: PhoneNumber, data?: object, error?: string, response?: any}>}\n */\n static async lookup(phoneNumber, options = {}) {\n const url = '/api/phonehub/number/lookup';\n const resp = await rest.POST(url, {\n phone_number: phoneNumber,\n ...options\n });\n const body = resp?.data ?? resp;\n const ok = body?.status === true || body?.success === true;\n\n if (ok) {\n const data = body?.data ?? {};\n const model = new PhoneNumber(data, { endpoint: '/api/phonehub/number' });\n return { success: true, model, data, response: resp };\n }\n return { success: false, error: body?.error || 'Phone lookup failed', response: resp };\n }\n\n\n}\n\n/**\n * PhoneNumberList - Paginated collection of PhoneNumber models.\n */\nclass PhoneNumberList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: PhoneNumber,\n endpoint: '/api/phonehub/number',\n size: 10,\n ...options\n });\n }\n\n\n}\n\n// ======================================================\n// SMS Model & Collection\n// ======================================================\n\n/**\n * SMS - Represents an SMS message (sent or received).\n */\nclass SMS extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/phonehub/sms',\n ...options\n });\n }\n\n /**\n * Send SMS via PhoneHub (Twilio under the hood).\n * @param {object} params - { to_number, body, from_number?, group?, metadata? }\n * @returns {Promise<{success: boolean, model?: SMS, data?: object, error?: string, response?: any}>}\n */\n static async send(params = {}) {\n const url = '/api/phonehub/sms/send';\n const resp = await rest.POST(url, params);\n const body = resp?.data ?? resp;\n const ok = body?.status === true || body?.success === true;\n\n if (ok) {\n const data = body?.data ?? {};\n const model = new SMS(data, { endpoint: '/api/phonehub/sms' });\n return { success: true, model, data, response: resp };\n }\n return { success: false, error: body?.error || 'Failed to send SMS', response: resp };\n }\n\n\n\n\n}\n\n/**\n * SMSList - Paginated collection of SMS models.\n */\nclass SMSList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: SMS,\n endpoint: '/api/phonehub/sms',\n size: 10,\n ...options\n });\n }\n\n\n}\n\n// ======================================================\n// PhoneConfig Model & Collection\n// ======================================================\n\n/**\n * PhoneConfig - Per-group (or system-default) SMS provider configuration.\n *\n * One row holds the provider choice plus its credentials. Per-credential\n * auto-setters on the backend route credential body keys through encrypted\n * storage on the same POST that updates scalar fields, so create / edit /\n * test_connection all share `/api/phonehub/config[/<pk>]`.\n *\n * Endpoints:\n * GET /api/phonehub/config - List\n * GET /api/phonehub/config/<id> - Get\n * POST /api/phonehub/config - Create\n * POST /api/phonehub/config/<id> - Update / test_connection\n * DELETE /api/phonehub/config/<id> - Delete\n */\nclass PhoneConfig extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/phonehub/config',\n ...options\n });\n }\n}\n\nclass PhoneConfigList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: PhoneConfig,\n endpoint: '/api/phonehub/config',\n size: 25,\n ...options\n });\n }\n}\n\n// Credential fields that must never be round-tripped from a GET response —\n// the backend graph excludes them, but the frontend also strips blanks before\n// save so we never overwrite a stored secret with an empty string.\nconst PHONE_CONFIG_SECRET_FIELDS = [\n 'twilio_account_sid',\n 'twilio_auth_token',\n 'aws_access_key_id',\n 'aws_secret_access_key',\n 'mojo_api_key'\n];\n\nconst PHONE_CONFIG_PROVIDER_OPTIONS = [\n { value: 'twilio', label: 'Twilio' },\n { value: 'aws', label: 'AWS SNS' },\n { value: 'mojo', label: 'Mojo Remote Instance' }\n];\n\nconst SECRET_PLACEHOLDER = '•••••••• (leave blank to keep existing)';\n\nconst PHONE_CONFIG_COMMON_FIELDS = [\n { name: 'name', type: 'text', label: 'Name', required: true, columns: 8,\n placeholder: 'e.g. Primary Twilio, Backup AWS, Mojo Bridge' },\n { type: 'collection', name: 'group', label: 'Group',\n Collection: GroupList, labelField: 'name', valueField: 'id',\n placeholder: 'Search groups…', emptyFetch: false, debounceMs: 300,\n columns: 4, help: 'Leave blank for the System Default config.' },\n { name: 'provider', type: 'select', label: 'Provider', required: true,\n options: PHONE_CONFIG_PROVIDER_OPTIONS, columns: 6 },\n { name: 'lookup_cache_days', type: 'number', label: 'Lookup cache (days)',\n columns: 6, help: 'Carrier-lookup cache lifetime per number.' },\n { name: 'is_active', type: 'switch', label: 'Active', columns: 4 },\n { name: 'test_mode', type: 'switch', label: 'Test mode', columns: 4,\n help: 'Use the provider sandbox / test endpoint.' },\n { name: 'lookup_enabled', type: 'switch', label: 'Lookup', columns: 4,\n help: 'Auto-run carrier lookups on new numbers.' }\n];\n\nconst PHONE_CONFIG_TWILIO_FIELDS = [\n { type: 'header', label: 'Twilio credentials', columns: 12,\n showWhen: { field: 'provider', value: 'twilio' } },\n { name: 'twilio_from_number', type: 'text', label: 'Twilio From Number',\n placeholder: '+15551234567', columns: 6,\n showWhen: { field: 'provider', value: 'twilio' } },\n { name: 'twilio_account_sid', type: 'password', label: 'Twilio Account SID',\n placeholder: SECRET_PLACEHOLDER, columns: 6, autocomplete: 'off',\n showWhen: { field: 'provider', value: 'twilio' } },\n { name: 'twilio_auth_token', type: 'password', label: 'Twilio Auth Token',\n placeholder: SECRET_PLACEHOLDER, columns: 12, autocomplete: 'new-password',\n showWhen: { field: 'provider', value: 'twilio' } }\n];\n\nconst PHONE_CONFIG_AWS_FIELDS = [\n { type: 'header', label: 'AWS SNS credentials', columns: 12,\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_region', type: 'text', label: 'AWS Region', value: 'us-east-1',\n placeholder: 'us-east-1', columns: 6,\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_sender_id', type: 'text', label: 'Sender ID',\n placeholder: 'Optional alphanumeric sender (region-dependent)', columns: 6,\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_access_key_id', type: 'password', label: 'Access Key ID',\n placeholder: SECRET_PLACEHOLDER, columns: 6, autocomplete: 'off',\n showWhen: { field: 'provider', value: 'aws' } },\n { name: 'aws_secret_access_key', type: 'password', label: 'Secret Access Key',\n placeholder: SECRET_PLACEHOLDER, columns: 6, autocomplete: 'new-password',\n showWhen: { field: 'provider', value: 'aws' } }\n];\n\nconst PHONE_CONFIG_MOJO_FIELDS = [\n { type: 'header', label: 'Mojo Remote credentials', columns: 12,\n showWhen: { field: 'provider', value: 'mojo' } },\n { name: 'mojo_remote_url', type: 'url', label: 'Remote Mojo URL',\n placeholder: 'https://sms.example.com', columns: 12,\n showWhen: { field: 'provider', value: 'mojo' } },\n { name: 'mojo_api_key', type: 'password', label: 'Mojo API Key',\n placeholder: SECRET_PLACEHOLDER, columns: 12, autocomplete: 'new-password',\n help: 'Paste the token shown once when the API key was provisioned on the remote mojo. We never display it after save.',\n showWhen: { field: 'provider', value: 'mojo' } }\n];\n\nconst PHONE_CONFIG_FIELDS = [\n ...PHONE_CONFIG_COMMON_FIELDS,\n ...PHONE_CONFIG_TWILIO_FIELDS,\n ...PHONE_CONFIG_AWS_FIELDS,\n ...PHONE_CONFIG_MOJO_FIELDS\n];\n\nconst PhoneConfigForms = {\n create: {\n title: 'New Phone Config',\n fields: PHONE_CONFIG_FIELDS,\n defaults: {\n provider: 'twilio',\n is_active: true,\n test_mode: false,\n lookup_enabled: true,\n lookup_cache_days: 90\n }\n },\n edit: {\n title: 'Edit Phone Config',\n fields: PHONE_CONFIG_FIELDS\n }\n};\n\nPhoneConfig.ADD_FORM = PhoneConfigForms.create;\nPhoneConfig.EDIT_FORM = PhoneConfigForms.edit;\nPhoneConfig.SECRET_FIELDS = PHONE_CONFIG_SECRET_FIELDS;\nPhoneConfig.PROVIDER_OPTIONS = PHONE_CONFIG_PROVIDER_OPTIONS;\n// Open the Add dialog wide enough for the provider-conditional credential rows.\nPhoneConfig.FORM_DIALOG_CONFIG = { size: 'lg', submitText: 'Create' };\n\n// Exported API\nexport {\n PhoneNumber,\n PhoneNumberList,\n SMS,\n SMSList,\n PhoneConfig,\n PhoneConfigList,\n PhoneConfigForms\n};\n\nexport default {\n PhoneNumber,\n PhoneNumberList,\n SMS,\n SMSList,\n PhoneConfig,\n PhoneConfigList,\n PhoneConfigForms\n};","/**\n * JobRunner Model - Job Engine Runner/Worker management\n * Manages worker processes that execute jobs\n */\n\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nclass JobRunner extends Model {\n constructor(data = {}) {\n // Map runner_id to id for proper Model handling\n if (data.runner_id && !data.id) {\n data.id = data.runner_id;\n }\n \n super(data, {\n endpoint: '/api/jobs/runners',\n idAttribute: 'runner_id' // Tell the model to use runner_id as the ID field\n });\n }\n\n // Ping this runner to test connectivity\n async ping(timeout = 2.0) {\n const app = this.getApp();\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n\n const response = await app.rest.POST('/api/jobs/runners/ping', {\n runner_id: this.get('runner_id'),\n timeout: timeout\n });\n\n if (response.success && response.data.status) {\n // Update ping status\n this.set('last_heartbeat', new Date().toISOString());\n this.set('ping_status', response.data.ping_status || 'success');\n }\n\n return response;\n }\n\n // Shutdown this runner gracefully or forcefully\n async shutdown(graceful = true) {\n const app = this.getApp();\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n\n const response = await app.rest.POST('/api/jobs/runners/shutdown', {\n runner_id: this.get('runner_id'),\n graceful: graceful\n });\n\n if (response.success && response.data.status) {\n // Update status to shutting down (alive becomes false)\n this.set('alive', false);\n }\n\n return response;\n }\n\n // Get channels handled by this runner\n getChannels() {\n return this.get('channels') || [];\n }\n\n // Get runner status with appropriate styling based on alive field\n getStatusBadgeClass() {\n const alive = this.get('alive');\n return alive ? 'bg-success' : 'bg-danger';\n }\n\n // Get status icon based on alive field\n getStatusIcon() {\n const alive = this.get('alive');\n return alive ? 'bi-check-circle-fill' : 'bi-x-octagon-fill';\n }\n\n // Check if runner is active (alive)\n isActive() {\n return this.get('alive') === true;\n }\n\n // Check if runner is healthy (active and recent heartbeat)\n isHealthy() {\n if (!this.isActive()) return false;\n \n const lastHeartbeat = this.get('last_heartbeat');\n if (!lastHeartbeat) return false;\n \n // Consider healthy if heartbeat within last 2 minutes\n const heartbeatAge = (Date.now() - new Date(lastHeartbeat).getTime()) / 1000;\n return heartbeatAge < 120;\n }\n\n // Get formatted heartbeat age\n getFormattedHeartbeatAge() {\n const lastHeartbeat = this.get('last_heartbeat');\n if (!lastHeartbeat) return 'Never';\n \n const heartbeatAge = (Date.now() - new Date(lastHeartbeat).getTime()) / 1000;\n \n if (heartbeatAge < 60) return `${Math.round(heartbeatAge)}s ago`;\n if (heartbeatAge < 3600) return `${Math.round(heartbeatAge / 60)}m ago`;\n return `${Math.round(heartbeatAge / 3600)}h ago`;\n }\n\n // Get current utilization (from jobs processed vs capacity)\n getUtilization() {\n const processed = this.get('jobs_processed') || 0;\n const failed = this.get('jobs_failed') || 0;\n const total = processed + failed;\n // Since we don't have max capacity from API, return based on recent activity\n return total > 10 ? 100 : Math.min(total * 10, 100);\n }\n\n // Get formatted uptime based on started timestamp\n getFormattedUptime() {\n const started = this.get('started');\n if (!started) return 'Unknown';\n \n const startTime = new Date(started);\n const now = new Date();\n const diffMs = now - startTime;\n const diffSeconds = Math.floor(diffMs / 1000);\n \n if (diffSeconds < 60) return `${diffSeconds}s`;\n if (diffSeconds < 3600) return `${Math.floor(diffSeconds / 60)}m`;\n if (diffSeconds < 86400) return `${Math.floor(diffSeconds / 3600)}h`;\n return `${Math.floor(diffSeconds / 86400)}d`;\n }\n\n // Get worker capacity info\n getWorkerInfo() {\n const processed = this.get('jobs_processed') || 0;\n const failed = this.get('jobs_failed') || 0;\n return {\n processed,\n failed,\n total: processed + failed,\n alive: this.get('alive'),\n utilization: this.getUtilization()\n };\n }\n\n // Get display name for runner\n getDisplayName() {\n const runnerId = this.get('runner_id');\n if (!runnerId) return 'Unknown Runner';\n \n // Extract hostname-like portion if it exists\n const parts = runnerId.split('-');\n return parts.length > 1 ? parts[0] : runnerId;\n }\n\n // Check if runner can be controlled\n canControl() {\n return this.get('alive') === true;\n }\n}\n\nclass JobRunnerList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: JobRunner,\n endpoint: '/api/jobs/runners',\n ...options\n });\n }\n\n // Get only active runners\n getActive() {\n return this.where(runner => runner.isActive());\n }\n\n // Get runners by channel\n getByChannel(channel) {\n return this.where(runner => runner.getChannels().includes(channel));\n }\n\n // Get healthy runners\n getHealthy() {\n return this.where(runner => runner.isHealthy());\n }\n\n // Get total jobs processed across all runners\n getTotalProcessed() {\n return this.models.reduce((total, runner) => {\n return total + (runner.get('jobs_processed') || 0);\n }, 0);\n }\n\n // Get total jobs failed across all runners\n getTotalFailed() {\n return this.models.reduce((total, runner) => {\n return total + (runner.get('jobs_failed') || 0);\n }, 0);\n }\n\n // Get overall system health percentage (alive runners / total runners)\n getSystemHealth() {\n if (this.models.length === 0) return 0;\n const aliveRunners = this.models.filter(runner => runner.get('alive')).length;\n return Math.round((aliveRunners / this.models.length) * 100);\n }\n\n // Get unique channels across all runners\n getAllChannels() {\n const channels = new Set();\n this.models.forEach(runner => {\n runner.getChannels().forEach(channel => channels.add(channel));\n });\n return Array.from(channels).sort();\n }\n}\n\n// Static methods for system-wide runner management\nJobRunner.ping = async function(runnerId, timeout = 2.0) {\n const app = typeof window !== 'undefined' && window.app;\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n \n return await app.rest.POST('/api/jobs/runners/ping', {\n runner_id: runnerId,\n timeout\n });\n};\n\nJobRunner.shutdown = async function(runnerId, graceful = true) {\n const app = typeof window !== 'undefined' && window.app;\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n \n return await app.rest.POST('/api/jobs/runners/shutdown', {\n runner_id: runnerId,\n graceful\n });\n};\n\nJobRunner.broadcast = async function(command, data = {}, timeout = 2.0) {\n const app = typeof window !== 'undefined' && window.app;\n if (!app || !app.rest) {\n throw new Error('App or REST client not available');\n }\n \n return await app.rest.POST('/api/jobs/runners/broadcast', {\n command,\n data,\n timeout\n });\n};\n\n// Broadcast commands\nJobRunner.broadcastStatus = async function(timeout = 2.0) {\n return JobRunner.broadcast('status', {}, timeout);\n};\n\nJobRunner.broadcastShutdown = async function(timeout = 2.0) {\n return JobRunner.broadcast('shutdown', {}, timeout);\n};\n\nJobRunner.broadcastPause = async function(timeout = 2.0) {\n return JobRunner.broadcast('pause', {}, timeout);\n};\n\nJobRunner.broadcastResume = async function(timeout = 2.0) {\n return JobRunner.broadcast('resume', {}, timeout);\n};\n\nJobRunner.broadcastReload = async function(timeout = 2.0) {\n return JobRunner.broadcast('reload', {}, timeout);\n};\n\nconst JobRunnerForms = {\n broadcast: {\n title: 'Broadcast Command',\n fields: [\n {\n name: 'command',\n type: 'select',\n label: 'Command',\n required: true,\n options: [\n { value: 'status', label: 'Status Check' },\n { value: 'pause', label: 'Pause Processing' },\n { value: 'resume', label: 'Resume Processing' },\n { value: 'reload', label: 'Reload Configuration' },\n { value: 'shutdown', label: 'Shutdown All Runners' }\n ],\n help: 'Command to send to all runners'\n },\n {\n name: 'timeout',\n type: 'number',\n label: 'Timeout (seconds)',\n value: 2.0,\n min: 0.5,\n max: 10.0,\n step: 0.5,\n help: 'How long to wait for responses'\n }\n ]\n }\n};\n\nexport { JobRunner, JobRunnerList, JobRunnerForms };","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/**\n * BouncerDevice - A tracked device fingerprint in the Bouncer fraud-detection system.\n * Maps to REST endpoints under /api/account/bouncer/device\n *\n * Key fields: muid, duid, fingerprint_id, risk_tier, event_count,\n * block_count, last_seen_ip, linked_muids, last_seen\n *\n * Endpoints:\n * GET /api/account/bouncer/device - List devices\n * GET /api/account/bouncer/device/<id> - Get device details\n * POST /api/account/bouncer/device/<id> - Update device\n * DELETE /api/account/bouncer/device/<id> - Delete device\n */\nclass BouncerDevice extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/account/bouncer/device',\n ...options\n });\n }\n}\n\n/**\n * BouncerDeviceList - Collection of BouncerDevice records.\n * Filter by account or risk tier via query params.\n */\nclass BouncerDeviceList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: BouncerDevice,\n endpoint: '/api/account/bouncer/device',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * BouncerSignal - A captured request signal evaluated by the Bouncer risk engine.\n * Maps to REST endpoints under /api/account/bouncer/signal\n *\n * Key fields: muid, stage, ip_address, page_type, risk_score,\n * decision, triggered_signals, raw_signals, server_signals\n *\n * Endpoints:\n * GET /api/account/bouncer/signal - List signals\n * GET /api/account/bouncer/signal/<id> - Get signal details\n * POST /api/account/bouncer/signal/<id> - Update signal\n * DELETE /api/account/bouncer/signal/<id> - Delete signal\n */\nclass BouncerSignal extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/account/bouncer/signal',\n ...options\n });\n }\n}\n\n/**\n * BouncerSignalList - Collection of BouncerSignal records.\n * Filter by muid, decision, or risk_score via query params.\n */\nclass BouncerSignalList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: BouncerSignal,\n endpoint: '/api/account/bouncer/signal',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * BouncerSignature - A detection signature used by Bouncer to match known threat patterns.\n * Maps to REST endpoints under /api/account/bouncer/signature\n *\n * Key fields: sig_type, value, source, confidence, hit_count,\n * block_count, is_active, expires_at, notes\n *\n * Endpoints:\n * GET /api/account/bouncer/signature - List signatures\n * POST /api/account/bouncer/signature - Create a signature\n * GET /api/account/bouncer/signature/<id> - Get signature details\n * POST /api/account/bouncer/signature/<id> - Update signature\n * DELETE /api/account/bouncer/signature/<id> - Delete signature\n */\nclass BouncerSignature extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/account/bouncer/signature',\n ...options\n });\n }\n}\n\n/**\n * BouncerSignatureList - Collection of BouncerSignature records.\n * Filter by sig_type, is_active, or source via query params.\n */\nclass BouncerSignatureList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: BouncerSignature,\n endpoint: '/api/account/bouncer/signature',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * Forms configuration for BouncerSignature\n */\nconst BouncerSignatureForms = {\n create: {\n title: 'Create Signature',\n fields: [\n {\n name: 'sig_type',\n type: 'select',\n label: 'Signature Type',\n required: true,\n columns: 6,\n options: [\n { value: 'user_agent', label: 'User Agent' },\n { value: 'ip_pattern', label: 'IP Pattern' },\n { value: 'fingerprint', label: 'Fingerprint' },\n { value: 'behavior', label: 'Behavior' },\n { value: 'header', label: 'Header' },\n { value: 'cookie', label: 'Cookie' }\n ]\n },\n {\n name: 'value',\n type: 'text',\n label: 'Value',\n required: true,\n columns: 6,\n help: 'The pattern or value to match against.'\n },\n {\n name: 'confidence',\n type: 'number',\n label: 'Confidence',\n columns: 6,\n default: 80,\n min: 0,\n max: 100,\n help: 'Confidence level from 0 to 100.'\n },\n {\n name: 'notes',\n type: 'textarea',\n label: 'Notes',\n columns: 12,\n help: 'Optional notes about this signature.'\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n columns: 6,\n default: true\n }\n ]\n },\n\n edit: {\n title: 'Edit Signature',\n fields: [\n {\n name: 'sig_type',\n type: 'select',\n label: 'Signature Type',\n required: true,\n columns: 6,\n options: [\n { value: 'user_agent', label: 'User Agent' },\n { value: 'ip_pattern', label: 'IP Pattern' },\n { value: 'fingerprint', label: 'Fingerprint' },\n { value: 'behavior', label: 'Behavior' },\n { value: 'header', label: 'Header' },\n { value: 'cookie', label: 'Cookie' }\n ]\n },\n {\n name: 'value',\n type: 'text',\n label: 'Value',\n required: true,\n columns: 6,\n help: 'The pattern or value to match against.'\n },\n {\n name: 'confidence',\n type: 'number',\n label: 'Confidence',\n columns: 6,\n default: 80,\n min: 0,\n max: 100,\n help: 'Confidence level from 0 to 100.'\n },\n {\n name: 'notes',\n type: 'textarea',\n label: 'Notes',\n columns: 12,\n help: 'Optional notes about this signature.'\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Active',\n columns: 6,\n default: true\n }\n ]\n }\n};\n\n// Wire form statics so admin TablePages can drop inline form configuration.\nBouncerSignature.ADD_FORM = BouncerSignatureForms.create;\nBouncerSignature.EDIT_FORM = BouncerSignatureForms.edit;\n\nexport { BouncerDevice, BouncerDeviceList, BouncerSignal, BouncerSignalList, BouncerSignature, BouncerSignatureList, BouncerSignatureForms };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * Constants\n * ========================= */\n\nconst IPSetKindOptions = [\n { value: 'country', label: 'Country — Block all traffic from a country' },\n { value: 'abuse', label: 'Abuse Feed — Import known attacker IPs' },\n { value: 'datacenter', label: 'Datacenter — Block datacenter/hosting ranges' },\n { value: 'custom', label: 'Custom — Define your own CIDR list' },\n];\n\nconst IPSetKindBadgeOptions = [\n { value: 'country', label: 'Country' },\n { value: 'abuse', label: 'Abuse Feed' },\n { value: 'datacenter', label: 'Datacenter' },\n { value: 'custom', label: 'Custom' },\n];\n\nconst IPSetSourceOptions = [\n { value: 'ipdeny', label: 'IPDeny (Country Zones)' },\n { value: 'abuseipdb', label: 'AbuseIPDB' },\n { value: 'manual', label: 'Manual' },\n];\n\nconst CommonBlockCountries = [\n { value: 'cn', label: 'China' },\n { value: 'ru', label: 'Russia' },\n { value: 'kp', label: 'North Korea' },\n { value: 'ir', label: 'Iran' },\n { value: 'ng', label: 'Nigeria' },\n { value: 'ro', label: 'Romania' },\n { value: 'br', label: 'Brazil' },\n { value: 'in', label: 'India' },\n { value: 'pk', label: 'Pakistan' },\n { value: 'id', label: 'Indonesia' },\n { value: 'vn', label: 'Vietnam' },\n { value: 'ua', label: 'Ukraine' },\n { value: 'th', label: 'Thailand' },\n { value: 'ph', label: 'Philippines' },\n { value: 'bd', label: 'Bangladesh' },\n { value: 'eg', label: 'Egypt' },\n { value: 'tr', label: 'Turkey' },\n { value: 'mx', label: 'Mexico' },\n { value: 'ar', label: 'Argentina' },\n { value: 'co', label: 'Colombia' },\n];\n\n/* =========================\n * IPSet Model\n * ========================= */\n\nclass IPSet extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/incident/ipset',\n });\n }\n}\n\n/* =========================\n * IPSet Collection\n * ========================= */\n\nclass IPSetList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: IPSet,\n endpoint: '/api/incident/ipset',\n ...options,\n });\n }\n}\n\n/* =========================\n * Forms\n * ========================= */\n\nconst IPSetForms = {\n create: {\n title: 'Create IP Set',\n size: 'md',\n fields: [\n {\n name: 'kind',\n type: 'select',\n label: 'What do you want to block?',\n required: true,\n options: IPSetKindOptions,\n value: 'country',\n columns: 12\n },\n // ── Country fields ──\n {\n name: 'country_code',\n type: 'select',\n label: 'Country',\n required: true,\n options: CommonBlockCountries,\n help: 'Select a country to block. CIDRs are fetched automatically from IPDeny.',\n columns: 8,\n showWhen: { field: 'kind', value: 'country' }\n },\n // ── Abuse feed fields ──\n {\n name: 'source_key',\n type: 'text',\n label: 'API Key',\n required: true,\n placeholder: 'Your AbuseIPDB API key',\n help: 'Get a free key at abuseipdb.com. Never stored in plaintext.',\n columns: 12,\n showWhen: { field: 'kind', value: 'abuse' }\n },\n // ── Datacenter fields ──\n {\n name: 'source_url',\n type: 'url',\n label: 'Source URL',\n required: true,\n placeholder: 'https://example.com/datacenter-ranges.txt',\n help: 'URL to a plain text file with one CIDR per line.',\n columns: 12,\n showWhen: { field: 'kind', value: 'datacenter' }\n },\n // ── Custom fields ──\n {\n name: 'data',\n type: 'textarea',\n label: 'CIDR List',\n rows: 8,\n placeholder: '# One CIDR per line\\n192.0.2.0/24\\n198.51.100.0/24\\n203.0.113.0/24',\n help: 'Enter IP ranges in CIDR notation. Lines starting with # are ignored.',\n columns: 12,\n showWhen: { field: 'kind', value: 'custom' }\n },\n // ── Shared fields (non-country) ──\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n placeholder: 'e.g., abuse_ips, dc_aws',\n help: 'Unique identifier. Used as the kernel ipset name.',\n columns: 6,\n showWhen: { field: 'kind', value: 'country', negate: true }\n },\n {\n name: 'description',\n type: 'text',\n label: 'Description',\n placeholder: 'Human-readable label',\n columns: 6,\n showWhen: { field: 'kind', value: 'country', negate: true }\n },\n // ── Always visible ──\n {\n name: 'is_enabled',\n type: 'switch',\n label: 'Enable immediately',\n value: true,\n help: 'When enabled, CIDRs are synced to the fleet and traffic is blocked.',\n columns: 4\n },\n ]\n },\n\n edit: {\n title: 'Edit IP Set',\n size: 'md',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n columns: 6\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Kind',\n options: IPSetKindBadgeOptions,\n disabled: true,\n columns: 3\n },\n {\n name: 'is_enabled',\n type: 'switch',\n label: 'Enabled',\n columns: 3\n },\n {\n name: 'description',\n type: 'text',\n label: 'Description',\n columns: 12\n },\n {\n name: 'source',\n type: 'select',\n label: 'Source',\n options: IPSetSourceOptions,\n columns: 6\n },\n {\n name: 'source_url',\n type: 'url',\n label: 'Source URL',\n columns: 6\n },\n {\n name: 'source_key',\n type: 'text',\n label: 'API Key',\n placeholder: 'Leave blank to keep current key',\n help: 'Write-only — current value is never shown.',\n columns: 12\n },\n ]\n }\n};\n\n// IPSet.EDIT_FORM is wired so IPSetTablePage can drop the inline `formEdit:`.\n// No ADD_FORM is registered: the page owns a custom `onAdd` flow that\n// transforms a country code into name/source/description before save —\n// see IPSetTablePage._handleAdd() (commit 5 of the UX sweep).\nIPSet.EDIT_FORM = IPSetForms.edit;\n\nexport {\n IPSet,\n IPSetList,\n IPSetForms,\n IPSetKindOptions,\n IPSetKindBadgeOptions,\n IPSetSourceOptions,\n CommonBlockCountries\n};\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/* =========================\n * Model\n * ========================= */\nclass S3Bucket extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/aws/s3/bucket',\n });\n }\n}\n\n/* =========================\n * Collection\n * ========================= */\nclass S3BucketList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: S3Bucket,\n endpoint: '/api/aws/s3/bucket',\n size: 10,\n ...options,\n });\n }\n}\n\n/* =========================\n * Forms\n * ========================= */\nconst S3BucketForms = {\n create: {\n title: 'Add S3 Bucket',\n fields: [\n {\n name: 'bucket_name',\n type: 'text',\n label: 'Name',\n placeholder: 'bucket name',\n help: 'Enter a universally unique name for the bucket',\n required: true,\n cols: 12,\n },\n {\n name: 'is_public',\n type: 'switch',\n label: 'Is Public',\n cols: 12,\n },\n ],\n },\n\n // Provide an edit form even though legacy only had ADD_FORM\n edit: {\n title: 'Edit S3 Bucket',\n fields: [\n {\n name: 'bucket_name',\n type: 'text',\n label: 'Name',\n placeholder: 'bucket name',\n help: 'Enter a universally unique name for the bucket',\n required: true,\n cols: 12,\n },\n {\n name: 'is_public',\n type: 'switch',\n label: 'Is Public',\n cols: 12,\n },\n ],\n },\n};\n\n// Wire form statics so S3BucketTablePage can drop inline form configuration.\nS3Bucket.ADD_FORM = S3BucketForms.create;\nS3Bucket.EDIT_FORM = S3BucketForms.edit;\n\nexport { S3Bucket, S3BucketList, S3BucketForms };\n","/**\n * ScheduledTask - User-defined recurring or one-off tasks\n *\n * Each task belongs to the authenticated user. Supports three task types:\n * - job: Run a backend job function\n * - webhook: POST to a URL\n * - llm: Run an LLM prompt via the assistant\n *\n * Endpoints:\n * GET /api/jobs/scheduled_task - List tasks\n * POST /api/jobs/scheduled_task - Create a task\n * GET /api/jobs/scheduled_task/<id> - Get task detail\n * PUT /api/jobs/scheduled_task/<id> - Update a task\n * DELETE /api/jobs/scheduled_task/<id> - Delete a task\n */\n\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nclass ScheduledTask extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/jobs/scheduled_task',\n ...options\n });\n }\n}\n\nclass ScheduledTaskList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: ScheduledTask,\n endpoint: '/api/jobs/scheduled_task',\n size: 25,\n ...options\n });\n }\n}\n\n/**\n * TaskResult - Read-only execution result records\n *\n * Endpoints:\n * GET /api/jobs/task_result - List results\n * GET /api/jobs/task_result/<id> - Get result detail\n */\nclass TaskResult extends Model {\n constructor(data = {}, options = {}) {\n super(data, {\n endpoint: '/api/jobs/task_result',\n ...options\n });\n }\n}\n\nclass TaskResultList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: TaskResult,\n endpoint: '/api/jobs/task_result',\n size: 25,\n ...options\n });\n }\n}\n\nconst DAY_LABELS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\n\nconst ScheduledTaskForms = {\n create: {\n title: 'Create Scheduled Task',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n placeholder: 'Daily report',\n required: true,\n columns: 12\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Description',\n placeholder: 'What this task does...',\n columns: 12\n },\n {\n name: 'task_type',\n type: 'select',\n label: 'Task Type',\n required: true,\n columns: 6,\n options: [\n { value: 'llm', label: 'LLM Prompt' },\n { value: 'job', label: 'Backend Job' },\n { value: 'webhook', label: 'Webhook' }\n ]\n },\n {\n name: 'enabled',\n type: 'switch',\n label: 'Enabled',\n columns: 6,\n value: true\n },\n {\n name: 'run_times',\n type: 'text',\n label: 'Run Times (HH:MM)',\n placeholder: '09:00',\n required: true,\n columns: 6,\n help: 'Comma-separated 24h times, max 2. e.g. \"09:00, 17:00\"'\n },\n {\n name: 'run_days',\n type: 'text',\n label: 'Run Days',\n placeholder: '0,1,2,3,4',\n columns: 6,\n help: 'Comma-separated day numbers (Mon=0). Leave empty for every day.'\n },\n {\n name: 'run_once',\n type: 'switch',\n label: 'Run Once',\n columns: 6,\n help: 'Task runs once then disables itself.'\n },\n {\n name: 'max_retries',\n type: 'number',\n label: 'Max Retries',\n columns: 6,\n value: 0\n },\n {\n name: 'notify',\n type: 'text',\n label: 'Notify',\n placeholder: 'in_app, email',\n columns: 12,\n help: 'Comma-separated: email, in_app, sms, push'\n }\n ]\n },\n\n edit: {\n title: 'Edit Scheduled Task',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Name',\n required: true,\n columns: 12\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Description',\n columns: 12\n },\n {\n name: 'enabled',\n type: 'switch',\n label: 'Enabled',\n columns: 6\n },\n {\n name: 'run_times',\n type: 'text',\n label: 'Run Times (HH:MM)',\n required: true,\n columns: 6,\n help: 'Comma-separated 24h times, max 2.'\n },\n {\n name: 'run_days',\n type: 'text',\n label: 'Run Days',\n columns: 6,\n help: 'Comma-separated day numbers (Mon=0). Leave empty for every day.'\n },\n {\n name: 'run_once',\n type: 'switch',\n label: 'Run Once',\n columns: 6\n },\n {\n name: 'max_retries',\n type: 'number',\n label: 'Max Retries',\n columns: 6\n },\n {\n name: 'notify',\n type: 'text',\n label: 'Notify',\n placeholder: 'in_app, email',\n columns: 12,\n help: 'Comma-separated: email, in_app, sms, push'\n }\n ]\n }\n};\n\nexport { ScheduledTask, ScheduledTaskList, TaskResult, TaskResultList, ScheduledTaskForms, DAY_LABELS };\n"],"names":["LoginEvent","Model","constructor","data","super","endpoint","LoginEventList","Collection","options","ModelClass","IncidentStats","requiresId","IncidentEvent","IncidentEventList","size","IncidentEventForms","edit","title","fields","name","type","label","placeholder","Incident","COMPONENTS","editable","force_top","cols","IncidentList","IncidentForms","create","tabs","required","columns","value","example","rows","IncidentRuleSet","IncidentRuleSetList","IncidentRule","IncidentRuleList","IncidentHistory","IncidentHistoryList","RelatedIncidentsList","sourceIp","ruleSet","group","hostname","category","status","params","rest","ordering","source_ip","rule_set","ADD_FORM","EDIT_FORM","BundleByOptions","MatchByOptions","ComparatorOptions","ValueTypeOptions","CommonEventFields","description","meta","CommonCategoryOptions","CommonScopeOptions","RuleSet","RuleSetList","BundleMinutesOptions","RuleSetForms","tooltip","allowCustom","html","Rule","RuleList","RuleForms","showDescription","help","start","end","step","CREATE_FORM","PushDeviceView","View","className","this","model","getTemplate","onInit","dataView","DataView","containerId","format","addChild","PushDevice","PushDeviceList","PushTemplate","PushTemplateList","PushConfig","PushConfigList","PushDelivery","PushDeliveryList","PushConfigForms","GroupList","labelField","valueField","PushTemplateForms","defaultParams","is_active","VIEW_CLASS","Ticket","TicketList","TicketCategories","ticket","bug","feature","incident","security","fulfillment","new_user","new_group","qa","TicketCategoriesOptions","Object","entries","map","key","TicketForms","UserList","TicketNote","TicketNoteList","AssistantConversation","AssistantConversationList","AssistantSkill","AssistantSkillList","Job","cancel","response","save","cancel_request","success","set","retry","delay","retry_request","new_job_id","newJobId","originalJobId","original_job_id","getDetailedStatus","get_status","cloneJob","newPayload","publishData","publish_job","payload","job_id","templateJobId","template_job_id","isActive","get","includes","isScheduled","runAt","ms","Date","getTime","Number","isFinite","now","isTerminal","canRetry","canCancel","getStatusBadgeClass","pending","running","completed","failed","canceled","expired","getStatusIcon","getEvents","getFormattedDuration","duration","toFixed","getQueuePosition","hasExpired","expiresAt","getRunnerId","getPayload","getMetadata","JobList","fetchByStatus","fetch","fetchByChannel","channel","fetchPending","fetchRunning","fetchCompleted","fetchFailed","fetchScheduled","scheduled","JobForms","publish","min","max","clone","async","jobData","POST","getStats","GET","getHealth","test","tests","clearStuck","clearChannel","confirm","cleanConsumers","purgeJobs","days_old","JobLog","JobLogList","JobEvent","JobEventList","JobsEngineStats","SimilarJobsList","func","ActiveJobsList","runnerId","runner_id","EmailDomain","onboard","id","showError","error","url","buildUrl","err","message","audit","method","toUpperCase","reconcile","onboardById","auditById","reconcileById","EmailDomainList","EmailDomainForms","readonly","text","credentials","level","Mailbox","sendEmail","MailboxList","MailboxForms","maxItems","emptyFetch","debounceMs","defaultValue","SentMessage","SentMessageList","SentMessageForms","view","EmailTemplate","EmailTemplateList","EmailTemplateForms","PublicMessageKindOptions","PublicMessageStatusOptions","PublicMessageSeverityOptions","PublicMessageCategoryOptions","PublicMessageMetadataLabels","company","severity","referrer","landing_page","utm_source","utm_medium","utm_campaign","utm_term","utm_content","PublicMessage","PublicMessageList","PhoneNumber","normalize","phoneNumber","countryCode","phone_number","country_code","resp","body","lookup","PhoneNumberList","SMS","send","SMSList","PhoneConfig","PhoneConfigList","PHONE_CONFIG_PROVIDER_OPTIONS","SECRET_PLACEHOLDER","PHONE_CONFIG_FIELDS","showWhen","field","autocomplete","PhoneConfigForms","defaults","provider","test_mode","lookup_enabled","lookup_cache_days","SECRET_FIELDS","PROVIDER_OPTIONS","FORM_DIALOG_CONFIG","submitText","Phonehub","JobRunner","idAttribute","ping","timeout","app","getApp","Error","toISOString","ping_status","shutdown","graceful","getChannels","isHealthy","lastHeartbeat","getFormattedHeartbeatAge","heartbeatAge","Math","round","getUtilization","total","getFormattedUptime","started","startTime","diffMs","diffSeconds","floor","getWorkerInfo","processed","alive","utilization","getDisplayName","parts","split","length","canControl","JobRunnerList","getActive","where","runner","getByChannel","getHealthy","getTotalProcessed","models","reduce","getTotalFailed","getSystemHealth","aliveRunners","filter","getAllChannels","channels","Set","forEach","add","Array","from","sort","window","broadcast","command","broadcastStatus","broadcastShutdown","broadcastPause","broadcastResume","broadcastReload","JobRunnerForms","BouncerDevice","BouncerDeviceList","BouncerSignal","BouncerSignalList","BouncerSignature","BouncerSignatureList","BouncerSignatureForms","default","IPSetKindOptions","IPSetKindBadgeOptions","IPSetSourceOptions","CommonBlockCountries","IPSet","IPSetList","IPSetForms","negate","disabled","S3Bucket","S3BucketList","S3BucketForms","ScheduledTask","ScheduledTaskList","TaskResult","TaskResultList","DAY_LABELS","ScheduledTaskForms"],"mappings":"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"}
|