@agenticmail/enterprise 0.5.165 → 0.5.167
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-agent-MX4RTFC5.js +890 -0
- package/dist/cli.js +1 -1
- package/dist/dashboard/pages/agent-detail.js +359 -248
- package/package.json +1 -1
- package/src/cli-agent.ts +17 -0
- package/src/dashboard/pages/agent-detail.js +359 -248
|
@@ -2787,14 +2787,14 @@ function GuardrailsSection(props) {
|
|
|
2787
2787
|
var agents = props.agents || [];
|
|
2788
2788
|
var app = useApp();
|
|
2789
2789
|
var toast = app.toast;
|
|
2790
|
-
|
|
2791
2790
|
var agentData = buildAgentDataMap(agents);
|
|
2792
2791
|
|
|
2793
|
-
var _subTab = useState('
|
|
2792
|
+
var _subTab = useState('rules');
|
|
2794
2793
|
var subTab = _subTab[0]; var setSubTab = _subTab[1];
|
|
2795
|
-
|
|
2796
2794
|
var _guardrailStatus = useState(null);
|
|
2797
2795
|
var guardrailStatus = _guardrailStatus[0]; var setGuardrailStatus = _guardrailStatus[1];
|
|
2796
|
+
var _rules = useState([]);
|
|
2797
|
+
var rules = _rules[0]; var setRules = _rules[1];
|
|
2798
2798
|
var _interventions = useState([]);
|
|
2799
2799
|
var interventions = _interventions[0]; var setInterventions = _interventions[1];
|
|
2800
2800
|
var _dlpViolations = useState([]);
|
|
@@ -2803,33 +2803,55 @@ function GuardrailsSection(props) {
|
|
|
2803
2803
|
var onboardingStatus = _onboardingStatus[0]; var setOnboardingStatus = _onboardingStatus[1];
|
|
2804
2804
|
var _onboardingProgress = useState([]);
|
|
2805
2805
|
var onboardingProgress = _onboardingProgress[0]; var setOnboardingProgress = _onboardingProgress[1];
|
|
2806
|
-
var _pendingPolicies = useState([]);
|
|
2807
|
-
var pendingPolicies = _pendingPolicies[0]; var setPendingPolicies = _pendingPolicies[1];
|
|
2808
2806
|
var _pendingApprovals = useState([]);
|
|
2809
2807
|
var pendingApprovals = _pendingApprovals[0]; var setPendingApprovals = _pendingApprovals[1];
|
|
2810
2808
|
var _approvalHistory = useState([]);
|
|
2811
2809
|
var approvalHistory = _approvalHistory[0]; var setApprovalHistory = _approvalHistory[1];
|
|
2812
2810
|
var _loading = useState(true);
|
|
2813
2811
|
var loading = _loading[0]; var setLoading = _loading[1];
|
|
2812
|
+
var _showCreate = useState(false);
|
|
2813
|
+
var showCreate = _showCreate[0]; var setShowCreate = _showCreate[1];
|
|
2814
|
+
var _editRule = useState(null);
|
|
2815
|
+
var editRule = _editRule[0]; var setEditRule = _editRule[1];
|
|
2816
|
+
var _ruleForm = useState({ name: '', category: 'anomaly', ruleType: 'error_rate', action: 'alert', severity: 'medium', enabled: true, threshold: 10, windowMinutes: 60, cooldownMinutes: 30, keywords: '', patterns: '', description: '' });
|
|
2817
|
+
var ruleForm = _ruleForm[0]; var setRuleForm = _ruleForm[1];
|
|
2818
|
+
|
|
2819
|
+
var CATEGORIES = [
|
|
2820
|
+
{ value: 'anomaly', label: 'Anomaly Detection', desc: 'Unusual patterns in agent behavior', types: ['error_rate', 'cost_velocity', 'volume_spike', 'off_hours', 'session_anomaly'] },
|
|
2821
|
+
{ value: 'policy_compliance', label: 'Policy Compliance', desc: 'Ensure agents follow org policies', types: ['policy_violation', 'escalation_failure'] },
|
|
2822
|
+
{ value: 'communication', label: 'Communication', desc: 'Monitor communication quality', types: ['tone_violation', 'keyword_detection'] },
|
|
2823
|
+
{ value: 'memory', label: 'Memory', desc: 'Control memory write behavior', types: ['memory_flood'] },
|
|
2824
|
+
{ value: 'onboarding', label: 'Onboarding', desc: 'Enforce onboarding requirements', types: ['onboarding_bypass'] },
|
|
2825
|
+
{ value: 'security', label: 'Security', desc: 'Detect threats and suspicious patterns', types: ['data_leak_attempt', 'repeated_error', 'prompt_injection'] }
|
|
2826
|
+
];
|
|
2827
|
+
|
|
2828
|
+
var TYPE_LABELS = {
|
|
2829
|
+
error_rate: 'Error Rate', cost_velocity: 'Cost Velocity', volume_spike: 'Volume Spike',
|
|
2830
|
+
off_hours: 'Off-Hours Activity', session_anomaly: 'Session Anomaly',
|
|
2831
|
+
policy_violation: 'Policy Violation', escalation_failure: 'Escalation Failure',
|
|
2832
|
+
tone_violation: 'Tone Violation', keyword_detection: 'Keyword Detection',
|
|
2833
|
+
memory_flood: 'Memory Flood', onboarding_bypass: 'Onboarding Bypass',
|
|
2834
|
+
data_leak_attempt: 'Data Leak Attempt', repeated_error: 'Repeated Error', prompt_injection: 'Prompt Injection'
|
|
2835
|
+
};
|
|
2814
2836
|
|
|
2815
2837
|
var loadAll = function() {
|
|
2816
2838
|
setLoading(true);
|
|
2817
2839
|
Promise.all([
|
|
2818
2840
|
engineCall('/guardrails/status/' + agentId).catch(function() { return null; }),
|
|
2841
|
+
engineCall('/guardrails/rules?orgId=' + getOrgId()).catch(function() { return { rules: [] }; }),
|
|
2819
2842
|
engineCall('/guardrails/interventions?agentId=' + agentId).catch(function() { return { interventions: [] }; }),
|
|
2820
2843
|
engineCall('/dlp/violations?agentId=' + agentId).catch(function() { return { violations: [] }; }),
|
|
2821
2844
|
engineCall('/onboarding/status/' + agentId).catch(function() { return null; }),
|
|
2822
2845
|
engineCall('/onboarding/progress/' + agentId).catch(function() { return { progress: [] }; }),
|
|
2823
|
-
engineCall('/onboarding/pending/' + agentId).catch(function() { return { policies: [] }; }),
|
|
2824
2846
|
engineCall('/approvals/pending?agentId=' + agentId).catch(function() { return { approvals: [] }; }),
|
|
2825
2847
|
engineCall('/approvals/history?agentId=' + agentId).catch(function() { return { approvals: [] }; })
|
|
2826
2848
|
]).then(function(results) {
|
|
2827
2849
|
setGuardrailStatus(results[0]);
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2850
|
+
setRules(results[1]?.rules || []);
|
|
2851
|
+
setInterventions(results[2]?.interventions || results[2] || []);
|
|
2852
|
+
setDlpViolations(results[3]?.violations || results[3] || []);
|
|
2853
|
+
setOnboardingStatus(results[4]);
|
|
2854
|
+
setOnboardingProgress(results[5]?.progress || results[5] || []);
|
|
2833
2855
|
setPendingApprovals(results[6]?.approvals || results[6] || []);
|
|
2834
2856
|
setApprovalHistory(results[7]?.approvals || results[7] || []);
|
|
2835
2857
|
setLoading(false);
|
|
@@ -2838,67 +2860,146 @@ function GuardrailsSection(props) {
|
|
|
2838
2860
|
|
|
2839
2861
|
useEffect(function() { loadAll(); }, [agentId]);
|
|
2840
2862
|
|
|
2863
|
+
// Agent-relevant rules: either targets this agent specifically, or applies globally (no agentIds filter)
|
|
2864
|
+
var agentRules = rules.filter(function(r) {
|
|
2865
|
+
if (!r.conditions?.agentIds || r.conditions.agentIds.length === 0) return true;
|
|
2866
|
+
return r.conditions.agentIds.includes(agentId);
|
|
2867
|
+
});
|
|
2868
|
+
|
|
2841
2869
|
var pauseAgent = function() {
|
|
2842
2870
|
engineCall('/guardrails/pause/' + agentId, { method: 'POST', body: JSON.stringify({ reason: 'Manual pause from dashboard' }) })
|
|
2843
2871
|
.then(function() { toast('Agent paused', 'success'); loadAll(); })
|
|
2844
2872
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2845
2873
|
};
|
|
2846
|
-
|
|
2847
2874
|
var resumeAgent = function() {
|
|
2848
2875
|
engineCall('/guardrails/resume/' + agentId, { method: 'POST', body: JSON.stringify({ reason: 'Manual resume from dashboard' }) })
|
|
2849
2876
|
.then(function() { toast('Agent resumed', 'success'); loadAll(); })
|
|
2850
2877
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2851
2878
|
};
|
|
2852
|
-
|
|
2853
2879
|
var killAgent = function() {
|
|
2854
|
-
showConfirm({
|
|
2855
|
-
|
|
2856
|
-
message: 'Are you sure you want to kill this agent? This will immediately terminate all running processes.',
|
|
2857
|
-
warning: 'This action cannot be undone.',
|
|
2858
|
-
danger: true,
|
|
2859
|
-
confirmText: 'Kill Agent'
|
|
2860
|
-
}).then(function(confirmed) {
|
|
2861
|
-
if (!confirmed) return;
|
|
2880
|
+
showConfirm({ title: 'Kill Agent', message: 'Immediately terminate all running processes?', danger: true, confirmText: 'Kill Agent' }).then(function(ok) {
|
|
2881
|
+
if (!ok) return;
|
|
2862
2882
|
engineCall('/guardrails/kill/' + agentId, { method: 'POST', body: JSON.stringify({ reason: 'Manual kill from dashboard' }) })
|
|
2863
2883
|
.then(function() { toast('Agent killed', 'success'); loadAll(); })
|
|
2864
2884
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2865
2885
|
});
|
|
2866
2886
|
};
|
|
2867
2887
|
|
|
2888
|
+
var toggleRule = function(rule) {
|
|
2889
|
+
engineCall('/guardrails/rules/' + rule.id, { method: 'PUT', body: JSON.stringify({ enabled: !rule.enabled }) })
|
|
2890
|
+
.then(function() { toast(rule.enabled ? 'Rule disabled' : 'Rule enabled', 'success'); loadAll(); })
|
|
2891
|
+
.catch(function(err) { toast(err.message, 'error'); });
|
|
2892
|
+
};
|
|
2893
|
+
|
|
2894
|
+
var deleteRule = function(rule) {
|
|
2895
|
+
showConfirm({ title: 'Delete Rule', message: 'Delete "' + rule.name + '"? This cannot be undone.', warning: true, confirmText: 'Delete' }).then(function(ok) {
|
|
2896
|
+
if (!ok) return;
|
|
2897
|
+
engineCall('/guardrails/rules/' + rule.id, { method: 'DELETE' })
|
|
2898
|
+
.then(function() { toast('Rule deleted', 'success'); loadAll(); })
|
|
2899
|
+
.catch(function(err) { toast(err.message, 'error'); });
|
|
2900
|
+
});
|
|
2901
|
+
};
|
|
2902
|
+
|
|
2903
|
+
var openCreateRule = function() {
|
|
2904
|
+
setRuleForm({ name: '', category: 'anomaly', ruleType: 'error_rate', action: 'alert', severity: 'medium', enabled: true, threshold: 10, windowMinutes: 60, cooldownMinutes: 30, keywords: '', patterns: '', description: '' });
|
|
2905
|
+
setEditRule(null);
|
|
2906
|
+
setShowCreate(true);
|
|
2907
|
+
};
|
|
2908
|
+
|
|
2909
|
+
var openEditRule = function(rule) {
|
|
2910
|
+
setRuleForm({
|
|
2911
|
+
name: rule.name || '',
|
|
2912
|
+
category: rule.category || 'anomaly',
|
|
2913
|
+
ruleType: rule.ruleType || 'error_rate',
|
|
2914
|
+
action: rule.action || 'alert',
|
|
2915
|
+
severity: rule.severity || 'medium',
|
|
2916
|
+
enabled: rule.enabled !== false,
|
|
2917
|
+
threshold: rule.conditions?.threshold || 10,
|
|
2918
|
+
windowMinutes: rule.conditions?.windowMinutes || 60,
|
|
2919
|
+
cooldownMinutes: rule.cooldownMinutes || 30,
|
|
2920
|
+
keywords: (rule.conditions?.keywords || []).join(', '),
|
|
2921
|
+
patterns: (rule.conditions?.patterns || []).join(', '),
|
|
2922
|
+
description: rule.description || ''
|
|
2923
|
+
});
|
|
2924
|
+
setEditRule(rule);
|
|
2925
|
+
setShowCreate(true);
|
|
2926
|
+
};
|
|
2927
|
+
|
|
2928
|
+
var saveRule = function() {
|
|
2929
|
+
var body = {
|
|
2930
|
+
orgId: getOrgId(),
|
|
2931
|
+
name: ruleForm.name,
|
|
2932
|
+
description: ruleForm.description,
|
|
2933
|
+
category: ruleForm.category,
|
|
2934
|
+
ruleType: ruleForm.ruleType,
|
|
2935
|
+
action: ruleForm.action,
|
|
2936
|
+
severity: ruleForm.severity,
|
|
2937
|
+
enabled: ruleForm.enabled,
|
|
2938
|
+
cooldownMinutes: parseInt(ruleForm.cooldownMinutes) || 30,
|
|
2939
|
+
conditions: {
|
|
2940
|
+
agentIds: [agentId],
|
|
2941
|
+
threshold: parseFloat(ruleForm.threshold) || undefined,
|
|
2942
|
+
windowMinutes: parseInt(ruleForm.windowMinutes) || undefined,
|
|
2943
|
+
keywords: ruleForm.keywords ? ruleForm.keywords.split(',').map(function(k) { return k.trim(); }).filter(Boolean) : undefined,
|
|
2944
|
+
patterns: ruleForm.patterns ? ruleForm.patterns.split(',').map(function(p) { return p.trim(); }).filter(Boolean) : undefined
|
|
2945
|
+
}
|
|
2946
|
+
};
|
|
2947
|
+
var method = editRule ? 'PUT' : 'POST';
|
|
2948
|
+
var url = editRule ? '/guardrails/rules/' + editRule.id : '/guardrails/rules';
|
|
2949
|
+
engineCall(url, { method: method, body: JSON.stringify(body) })
|
|
2950
|
+
.then(function() { toast(editRule ? 'Rule updated' : 'Rule created', 'success'); setShowCreate(false); loadAll(); })
|
|
2951
|
+
.catch(function(err) { toast(err.message, 'error'); });
|
|
2952
|
+
};
|
|
2953
|
+
|
|
2868
2954
|
var initiateOnboarding = function() {
|
|
2869
2955
|
engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
|
|
2870
2956
|
.then(function() { toast('Onboarding initiated', 'success'); loadAll(); })
|
|
2871
2957
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2872
2958
|
};
|
|
2873
|
-
|
|
2874
2959
|
var forceComplete = function() {
|
|
2875
2960
|
engineCall('/onboarding/force-complete/' + agentId, { method: 'POST' })
|
|
2876
2961
|
.then(function() { toast('Onboarding force completed', 'success'); loadAll(); })
|
|
2877
2962
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2878
2963
|
};
|
|
2879
|
-
|
|
2880
2964
|
var approveRequest = function(id) {
|
|
2881
2965
|
engineCall('/approvals/' + id + '/approve', { method: 'POST', body: JSON.stringify({ decidedBy: 'dashboard-admin' }) })
|
|
2882
|
-
.then(function() { toast('
|
|
2966
|
+
.then(function() { toast('Approved', 'success'); loadAll(); })
|
|
2883
2967
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2884
2968
|
};
|
|
2885
|
-
|
|
2886
2969
|
var rejectRequest = function(id) {
|
|
2887
2970
|
engineCall('/approvals/' + id + '/reject', { method: 'POST', body: JSON.stringify({ decidedBy: 'dashboard-admin' }) })
|
|
2888
|
-
.then(function() { toast('
|
|
2971
|
+
.then(function() { toast('Rejected', 'success'); loadAll(); })
|
|
2889
2972
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2890
2973
|
};
|
|
2891
2974
|
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
}
|
|
2975
|
+
var actionColor = function(a) { return a === 'kill' ? 'var(--danger)' : a === 'pause' ? 'var(--warning)' : a === 'notify' ? 'var(--info)' : 'var(--text-muted)'; };
|
|
2976
|
+
var sevColor = function(s) { return s === 'critical' ? '#ef4444' : s === 'high' ? '#f97316' : s === 'medium' ? '#eab308' : '#64748b'; };
|
|
2977
|
+
var catIcon = function(c) { return c === 'anomaly' ? '⚡' : c === 'security' ? '🛡' : c === 'communication' ? '💬' : c === 'memory' ? '🧠' : c === 'onboarding' ? '📋' : c === 'policy_compliance' ? '📜' : '⚙'; };
|
|
2978
|
+
|
|
2979
|
+
if (loading) return h('div', { style: { padding: 40, textAlign: 'center', color: 'var(--text-muted)' } }, 'Loading guardrails...');
|
|
2895
2980
|
|
|
2896
2981
|
return h(Fragment, null,
|
|
2897
2982
|
|
|
2898
|
-
//
|
|
2899
|
-
h('div', {
|
|
2983
|
+
// Status bar
|
|
2984
|
+
h('div', { className: 'card', style: { marginBottom: 16 } },
|
|
2985
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 12, padding: '10px 16px' } },
|
|
2986
|
+
guardrailStatus && guardrailStatus.paused
|
|
2987
|
+
? h('span', { className: 'badge badge-warning' }, I.pause(), ' Paused')
|
|
2988
|
+
: h('span', { className: 'badge badge-success' }, I.shield(), ' Active'),
|
|
2989
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, (guardrailStatus?.interventionCount || 0) + ' interventions'),
|
|
2990
|
+
agentRules.length > 0 && h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, agentRules.filter(function(r) { return r.enabled; }).length + '/' + agentRules.length + ' rules active'),
|
|
2991
|
+
h('div', { style: { flex: 1 } }),
|
|
2992
|
+
guardrailStatus && !guardrailStatus.paused && h('button', { className: 'btn btn-secondary btn-sm', onClick: pauseAgent }, I.pause(), ' Pause'),
|
|
2993
|
+
guardrailStatus && guardrailStatus.paused && h('button', { className: 'btn btn-primary btn-sm', onClick: resumeAgent }, I.play(), ' Resume'),
|
|
2994
|
+
h('button', { className: 'btn btn-danger btn-sm', onClick: killAgent }, I.stop(), ' Kill'),
|
|
2995
|
+
h('button', { className: 'btn btn-ghost btn-sm', onClick: loadAll }, I.refresh())
|
|
2996
|
+
)
|
|
2997
|
+
),
|
|
2998
|
+
|
|
2999
|
+
// Sub-tabs
|
|
3000
|
+
h('div', { style: { borderBottom: '1px solid var(--border)', marginBottom: 16 } },
|
|
2900
3001
|
h('div', { className: 'tabs' },
|
|
2901
|
-
h('div', { className: 'tab' + (subTab === '
|
|
3002
|
+
h('div', { className: 'tab' + (subTab === 'rules' ? ' active' : ''), onClick: function() { setSubTab('rules'); } }, 'Rules (' + agentRules.length + ')'),
|
|
2902
3003
|
h('div', { className: 'tab' + (subTab === 'interventions' ? ' active' : ''), onClick: function() { setSubTab('interventions'); } }, 'Interventions'),
|
|
2903
3004
|
h('div', { className: 'tab' + (subTab === 'dlp' ? ' active' : ''), onClick: function() { setSubTab('dlp'); } }, 'DLP'),
|
|
2904
3005
|
h('div', { className: 'tab' + (subTab === 'onboarding' ? ' active' : ''), onClick: function() { setSubTab('onboarding'); } }, 'Onboarding'),
|
|
@@ -2906,258 +3007,268 @@ function GuardrailsSection(props) {
|
|
|
2906
3007
|
)
|
|
2907
3008
|
),
|
|
2908
3009
|
|
|
2909
|
-
// ───
|
|
2910
|
-
subTab === '
|
|
2911
|
-
h('div', {
|
|
2912
|
-
h('
|
|
2913
|
-
h('
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
3010
|
+
// ─── Rules Tab ──────────────────────────────────────
|
|
3011
|
+
subTab === 'rules' && h('div', null,
|
|
3012
|
+
h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 } },
|
|
3013
|
+
h('span', { style: { fontSize: 13, color: 'var(--text-muted)' } }, 'Guardrail rules that apply to this agent (agent-specific + global)'),
|
|
3014
|
+
h('button', { className: 'btn btn-primary btn-sm', onClick: openCreateRule }, I.plus(), ' Add Rule')
|
|
3015
|
+
),
|
|
3016
|
+
|
|
3017
|
+
// Category groups
|
|
3018
|
+
CATEGORIES.map(function(cat) {
|
|
3019
|
+
var catRules = agentRules.filter(function(r) { return r.category === cat.value; });
|
|
3020
|
+
if (catRules.length === 0) {
|
|
3021
|
+
// Show empty category with "Add" button
|
|
3022
|
+
return h('div', { key: cat.value, className: 'card', style: { marginBottom: 8 } },
|
|
3023
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '10px 16px' } },
|
|
3024
|
+
h('span', { style: { fontSize: 14 } }, catIcon(cat.value)),
|
|
3025
|
+
h('span', { style: { fontWeight: 600, fontSize: 13 } }, cat.label),
|
|
3026
|
+
h('span', { style: { fontSize: 11, color: 'var(--text-muted)', marginLeft: 4 } }, cat.desc),
|
|
3027
|
+
h('div', { style: { flex: 1 } }),
|
|
3028
|
+
h('span', { style: { fontSize: 11, color: 'var(--text-muted)' } }, 'No rules'),
|
|
3029
|
+
h('button', { className: 'btn btn-ghost btn-sm', style: { fontSize: 11 }, onClick: function() { setRuleForm(Object.assign({}, ruleForm, { category: cat.value, ruleType: cat.types[0] })); setEditRule(null); setShowCreate(true); } }, I.plus(), ' Add')
|
|
3030
|
+
)
|
|
3031
|
+
);
|
|
3032
|
+
}
|
|
3033
|
+
return h('div', { key: cat.value, className: 'card', style: { marginBottom: 8 } },
|
|
3034
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '8px 16px', borderBottom: '1px solid var(--border)' } },
|
|
3035
|
+
h('span', { style: { fontSize: 14 } }, catIcon(cat.value)),
|
|
3036
|
+
h('span', { style: { fontWeight: 600, fontSize: 13 } }, cat.label),
|
|
3037
|
+
h('span', { style: { fontSize: 11, color: 'var(--text-muted)', marginLeft: 4 } }, catRules.length + ' rule' + (catRules.length !== 1 ? 's' : '')),
|
|
3038
|
+
h('div', { style: { flex: 1 } }),
|
|
3039
|
+
h('button', { className: 'btn btn-ghost btn-sm', style: { fontSize: 11 }, onClick: function() { setRuleForm(Object.assign({}, ruleForm, { category: cat.value, ruleType: cat.types[0] })); setEditRule(null); setShowCreate(true); } }, I.plus())
|
|
3040
|
+
),
|
|
3041
|
+
catRules.map(function(rule) {
|
|
3042
|
+
var isGlobal = !rule.conditions?.agentIds || rule.conditions.agentIds.length === 0;
|
|
3043
|
+
return h('div', { key: rule.id, style: { display: 'flex', alignItems: 'center', gap: 10, padding: '8px 16px', borderBottom: '1px solid var(--border)', fontSize: 13 } },
|
|
3044
|
+
// Toggle switch
|
|
3045
|
+
h('div', {
|
|
3046
|
+
style: { width: 36, height: 20, borderRadius: 10, background: rule.enabled ? 'var(--success)' : 'var(--border)', cursor: 'pointer', position: 'relative', flexShrink: 0, transition: 'background 0.2s' },
|
|
3047
|
+
onClick: function() { toggleRule(rule); }
|
|
3048
|
+
},
|
|
3049
|
+
h('div', { style: { width: 16, height: 16, borderRadius: '50%', background: '#fff', position: 'absolute', top: 2, left: rule.enabled ? 18 : 2, transition: 'left 0.2s', boxShadow: '0 1px 3px rgba(0,0,0,0.2)' } })
|
|
3050
|
+
),
|
|
3051
|
+
// Name + type
|
|
3052
|
+
h('div', { style: { flex: 1, minWidth: 0 } },
|
|
3053
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 6 } },
|
|
3054
|
+
h('span', { style: { fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, rule.name || TYPE_LABELS[rule.ruleType] || rule.ruleType),
|
|
3055
|
+
isGlobal && h('span', { style: { fontSize: 10, padding: '1px 5px', borderRadius: 3, background: 'var(--bg-tertiary)', color: 'var(--text-muted)', border: '1px solid var(--border)' } }, 'Global')
|
|
2919
3056
|
),
|
|
2920
|
-
|
|
2921
|
-
)
|
|
2922
|
-
: h('div', { style: { padding: '12px 16px', background: 'rgba(34, 197, 94, 0.1)', border: '1px solid var(--success)', borderRadius: 8, marginBottom: 16 } },
|
|
2923
|
-
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
|
|
2924
|
-
h('span', { className: 'badge badge-success' }, I.shield(), ' Active')
|
|
2925
|
-
)
|
|
3057
|
+
rule.description && h('div', { style: { fontSize: 11, color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, rule.description)
|
|
2926
3058
|
),
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
3059
|
+
// Type badge
|
|
3060
|
+
h('span', { style: { fontSize: 10, padding: '2px 6px', borderRadius: 3, background: 'var(--bg-tertiary)', color: 'var(--text-secondary)', whiteSpace: 'nowrap' } }, TYPE_LABELS[rule.ruleType] || rule.ruleType),
|
|
3061
|
+
// Severity
|
|
3062
|
+
h('span', { style: { fontSize: 10, padding: '2px 6px', borderRadius: 3, color: '#fff', background: sevColor(rule.severity), whiteSpace: 'nowrap' } }, rule.severity),
|
|
3063
|
+
// Action
|
|
3064
|
+
h('span', { style: { fontSize: 11, color: actionColor(rule.action), fontWeight: 500 } }, rule.action),
|
|
3065
|
+
// Trigger count
|
|
3066
|
+
h('span', { style: { fontSize: 11, color: 'var(--text-muted)', minWidth: 40, textAlign: 'right' } }, (rule.triggerCount || 0) + 'x'),
|
|
3067
|
+
// Edit + Delete
|
|
3068
|
+
h('button', { className: 'btn btn-ghost btn-sm', style: { height: 24, fontSize: 11 }, onClick: function() { openEditRule(rule); } }, I.edit()),
|
|
3069
|
+
h('button', { className: 'btn btn-ghost btn-sm', style: { height: 24, fontSize: 11, color: 'var(--danger)' }, onClick: function() { deleteRule(rule); } }, I.trash())
|
|
3070
|
+
);
|
|
3071
|
+
})
|
|
3072
|
+
);
|
|
3073
|
+
})
|
|
2938
3074
|
),
|
|
2939
3075
|
|
|
2940
3076
|
// ─── Interventions Tab ──────────────────────────────
|
|
2941
|
-
subTab === 'interventions' && h('div', { className: 'card'
|
|
3077
|
+
subTab === 'interventions' && h('div', { className: 'card' },
|
|
2942
3078
|
h('div', { className: 'card-header' }, h('span', null, 'Interventions')),
|
|
2943
3079
|
interventions.length > 0
|
|
2944
|
-
? h('div', {
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
)
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
var time = inv.timestamp || inv.createdAt;
|
|
2958
|
-
var invType = inv.type || inv.interventionType || 'unknown';
|
|
2959
|
-
var severity = inv.severity || 'medium';
|
|
2960
|
-
var severityColor = severity === 'critical' ? 'badge-danger' : severity === 'high' ? 'badge-warning' : severity === 'medium' ? 'badge-info' : 'badge-neutral';
|
|
2961
|
-
var typeColor = invType === 'block' ? 'badge-danger' : invType === 'warn' ? 'badge-warning' : invType === 'audit' ? 'badge-info' : 'badge-neutral';
|
|
2962
|
-
|
|
2963
|
-
return h('tr', { key: inv.id || i },
|
|
2964
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)', whiteSpace: 'nowrap' } }, time ? new Date(time).toLocaleString() : '-'),
|
|
2965
|
-
h('td', null, h('span', { className: 'badge ' + typeColor }, invType)),
|
|
2966
|
-
h('td', null, h('span', { className: 'badge ' + severityColor }, severity)),
|
|
2967
|
-
h('td', { style: { fontSize: 13, maxWidth: 300, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, inv.description || inv.message || '-'),
|
|
2968
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)' } }, inv.resolution || inv.action || '-')
|
|
2969
|
-
);
|
|
2970
|
-
})
|
|
2971
|
-
)
|
|
2972
|
-
)
|
|
2973
|
-
)
|
|
2974
|
-
: h('div', { className: 'card-body' },
|
|
2975
|
-
h('div', { style: { textAlign: 'center', padding: 20, color: 'var(--text-muted)', fontSize: 13 } }, 'No interventions recorded.')
|
|
3080
|
+
? h('div', { style: { padding: 0 } },
|
|
3081
|
+
interventions.map(function(inv, i) {
|
|
3082
|
+
var time = inv.timestamp || inv.createdAt;
|
|
3083
|
+
var invType = inv.type || inv.interventionType || 'unknown';
|
|
3084
|
+
var severity = inv.severity || 'medium';
|
|
3085
|
+
return h('div', { key: inv.id || i, style: { display: 'flex', gap: 10, padding: '8px 16px', borderBottom: '1px solid var(--border)', fontSize: 12, alignItems: 'center' } },
|
|
3086
|
+
h('span', { style: { color: 'var(--text-muted)', minWidth: 130, whiteSpace: 'nowrap' } }, time ? new Date(time).toLocaleString() : '-'),
|
|
3087
|
+
h('span', { style: { padding: '1px 6px', borderRadius: 3, fontSize: 10, fontWeight: 600, color: '#fff', background: invType === 'block' ? '#ef4444' : invType === 'warn' ? '#eab308' : '#3b82f6' } }, invType),
|
|
3088
|
+
h('span', { style: { padding: '1px 6px', borderRadius: 3, fontSize: 10, fontWeight: 600, color: '#fff', background: sevColor(severity) } }, severity),
|
|
3089
|
+
h('span', { style: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'var(--text-secondary)' } }, inv.description || inv.message || inv.reason || '-'),
|
|
3090
|
+
h('span', { style: { color: 'var(--text-muted)', fontSize: 11 } }, inv.resolution || inv.action || '')
|
|
3091
|
+
);
|
|
3092
|
+
})
|
|
2976
3093
|
)
|
|
3094
|
+
: h('div', { style: { padding: 32, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 } }, 'No interventions recorded')
|
|
2977
3095
|
),
|
|
2978
3096
|
|
|
2979
3097
|
// ─── DLP Tab ────────────────────────────────────────
|
|
2980
|
-
subTab === 'dlp' && h('div', { className: 'card'
|
|
3098
|
+
subTab === 'dlp' && h('div', { className: 'card' },
|
|
2981
3099
|
h('div', { className: 'card-header' }, h('span', null, 'DLP Violations')),
|
|
2982
3100
|
dlpViolations.length > 0
|
|
2983
|
-
? h('div', {
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
)
|
|
2993
|
-
)
|
|
2994
|
-
|
|
2995
|
-
dlpViolations.map(function(v, i) {
|
|
2996
|
-
var time = v.timestamp || v.createdAt || v.detectedAt;
|
|
2997
|
-
var rule = v.rule || v.ruleName || v.ruleId || 'Unknown';
|
|
2998
|
-
var severity = v.severity || 'medium';
|
|
2999
|
-
var severityColor = severity === 'critical' ? 'badge-danger' : severity === 'high' ? 'badge-warning' : severity === 'medium' ? 'badge-info' : 'badge-neutral';
|
|
3000
|
-
var content = v.content || v.matchedContent || v.snippet || '';
|
|
3001
|
-
var truncatedContent = content.length > 80 ? content.substring(0, 80) + '...' : content;
|
|
3002
|
-
var violationStatus = v.status || v.action || 'detected';
|
|
3003
|
-
|
|
3004
|
-
return h('tr', { key: v.id || i },
|
|
3005
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)', whiteSpace: 'nowrap' } }, time ? new Date(time).toLocaleString() : '-'),
|
|
3006
|
-
h('td', null, h('span', { className: 'badge badge-info' }, rule)),
|
|
3007
|
-
h('td', null, h('span', { className: 'badge ' + severityColor }, severity)),
|
|
3008
|
-
h('td', { style: { fontSize: 12, fontFamily: 'var(--font-mono, monospace)', maxWidth: 250, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'var(--text-secondary)' } }, truncatedContent || '-'),
|
|
3009
|
-
h('td', null, h('span', { className: 'badge badge-neutral' }, violationStatus))
|
|
3010
|
-
);
|
|
3011
|
-
})
|
|
3012
|
-
)
|
|
3013
|
-
)
|
|
3014
|
-
)
|
|
3015
|
-
: h('div', { className: 'card-body' },
|
|
3016
|
-
h('div', { style: { textAlign: 'center', padding: 20, color: 'var(--text-muted)', fontSize: 13 } }, 'No DLP violations detected.')
|
|
3101
|
+
? h('div', { style: { padding: 0 } },
|
|
3102
|
+
dlpViolations.map(function(v, i) {
|
|
3103
|
+
var time = v.timestamp || v.createdAt || v.detectedAt;
|
|
3104
|
+
var severity = v.severity || 'medium';
|
|
3105
|
+
return h('div', { key: v.id || i, style: { display: 'flex', gap: 10, padding: '8px 16px', borderBottom: '1px solid var(--border)', fontSize: 12, alignItems: 'center' } },
|
|
3106
|
+
h('span', { style: { color: 'var(--text-muted)', minWidth: 130, whiteSpace: 'nowrap' } }, time ? new Date(time).toLocaleString() : '-'),
|
|
3107
|
+
h('span', { style: { padding: '1px 6px', borderRadius: 3, fontSize: 10, fontWeight: 600, color: '#fff', background: '#3b82f6' } }, v.rule || v.ruleName || 'Unknown'),
|
|
3108
|
+
h('span', { style: { padding: '1px 6px', borderRadius: 3, fontSize: 10, fontWeight: 600, color: '#fff', background: sevColor(severity) } }, severity),
|
|
3109
|
+
h('span', { style: { flex: 1, fontFamily: 'var(--font-mono, monospace)', fontSize: 11, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'var(--text-secondary)' } }, (v.content || v.matchedContent || v.snippet || '-').substring(0, 100)),
|
|
3110
|
+
h('span', { className: 'badge badge-neutral', style: { fontSize: 10 } }, v.status || v.action || 'detected')
|
|
3111
|
+
);
|
|
3112
|
+
})
|
|
3017
3113
|
)
|
|
3114
|
+
: h('div', { style: { padding: 32, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 } }, 'No DLP violations detected')
|
|
3018
3115
|
),
|
|
3019
3116
|
|
|
3020
3117
|
// ─── Onboarding Tab ─────────────────────────────────
|
|
3021
3118
|
subTab === 'onboarding' && h('div', null,
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
h('
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
)
|
|
3031
|
-
),
|
|
3032
|
-
h('div', { className: 'card-body' },
|
|
3033
|
-
h('div', { style: { display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 } },
|
|
3034
|
-
onboardingStatus?.onboarded
|
|
3035
|
-
? h('span', { className: 'badge badge-success' }, I.check(), ' Onboarded')
|
|
3036
|
-
: h('span', { className: 'badge badge-warning' }, 'Not Onboarded'),
|
|
3037
|
-
onboardingStatus?.status && h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Status: ' + onboardingStatus.status),
|
|
3038
|
-
onboardingStatus?.completedAt && h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Completed: ' + new Date(onboardingStatus.completedAt).toLocaleString())
|
|
3039
|
-
)
|
|
3119
|
+
h('div', { className: 'card', style: { marginBottom: 12 } },
|
|
3120
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 12, padding: '10px 16px' } },
|
|
3121
|
+
onboardingStatus?.onboarded
|
|
3122
|
+
? h('span', { className: 'badge badge-success' }, I.check(), ' Onboarded')
|
|
3123
|
+
: h('span', { className: 'badge badge-warning' }, 'Not Onboarded'),
|
|
3124
|
+
onboardingStatus?.completedAt && h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Completed: ' + new Date(onboardingStatus.completedAt).toLocaleString()),
|
|
3125
|
+
h('div', { style: { flex: 1 } }),
|
|
3126
|
+
!onboardingStatus?.onboarded && h('button', { className: 'btn btn-primary btn-sm', onClick: initiateOnboarding }, 'Start'),
|
|
3127
|
+
onboardingStatus?.status === 'in_progress' && h('button', { className: 'btn btn-secondary btn-sm', onClick: forceComplete }, 'Force Complete')
|
|
3040
3128
|
)
|
|
3041
3129
|
),
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
h('
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
)
|
|
3054
|
-
),
|
|
3055
|
-
h('tbody', null,
|
|
3056
|
-
onboardingProgress.map(function(p, i) {
|
|
3057
|
-
var pStatus = p.status || 'pending';
|
|
3058
|
-
var statusColor = pStatus === 'acknowledged' || pStatus === 'completed' ? 'badge-success' : pStatus === 'in_progress' ? 'badge-info' : 'badge-warning';
|
|
3059
|
-
|
|
3060
|
-
return h('tr', { key: p.id || i },
|
|
3061
|
-
h('td', { style: { fontWeight: 500, fontSize: 13 } }, p.policyName || p.name || p.policyId || '-'),
|
|
3062
|
-
h('td', null, h('span', { className: 'badge ' + statusColor }, pStatus)),
|
|
3063
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)' } }, p.acknowledgedAt ? new Date(p.acknowledgedAt).toLocaleString() : '-')
|
|
3064
|
-
);
|
|
3065
|
-
})
|
|
3066
|
-
)
|
|
3067
|
-
)
|
|
3068
|
-
)
|
|
3069
|
-
),
|
|
3070
|
-
|
|
3071
|
-
// Pending Policies
|
|
3072
|
-
pendingPolicies.length > 0 && h('div', { className: 'card', style: { marginBottom: 20 } },
|
|
3073
|
-
h('div', { className: 'card-header' }, h('span', null, 'Pending Policies')),
|
|
3074
|
-
h('div', { className: 'card-body' },
|
|
3075
|
-
h('div', { style: { display: 'grid', gap: 8 } },
|
|
3076
|
-
pendingPolicies.map(function(p, i) {
|
|
3077
|
-
return h('div', { key: p.id || i, style: { display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px', background: 'var(--bg-tertiary)', borderRadius: 8, border: '1px solid var(--border)' } },
|
|
3078
|
-
h('span', { className: 'badge badge-warning' }, 'Pending'),
|
|
3079
|
-
h('span', { style: { fontSize: 13, fontWeight: 500 } }, p.name || p.policyName || p.policyId || 'Unnamed Policy'),
|
|
3080
|
-
p.category && h('span', { className: 'badge badge-neutral', style: { fontSize: 11 } }, p.category)
|
|
3081
|
-
);
|
|
3082
|
-
})
|
|
3083
|
-
)
|
|
3130
|
+
onboardingProgress.length > 0 && h('div', { className: 'card' },
|
|
3131
|
+
h('div', { style: { padding: 0 } },
|
|
3132
|
+
onboardingProgress.map(function(p, i) {
|
|
3133
|
+
return h('div', { key: i, style: { display: 'flex', gap: 10, padding: '8px 16px', borderBottom: '1px solid var(--border)', fontSize: 12, alignItems: 'center' } },
|
|
3134
|
+
p.acknowledged
|
|
3135
|
+
? h('span', { style: { color: 'var(--success)', fontSize: 14 } }, '✓')
|
|
3136
|
+
: h('span', { style: { color: 'var(--text-muted)', fontSize: 14 } }, '○'),
|
|
3137
|
+
h('span', { style: { fontWeight: 500, flex: 1 } }, p.policyName || p.name || 'Policy ' + (i + 1)),
|
|
3138
|
+
p.acknowledgedAt && h('span', { style: { color: 'var(--text-muted)', fontSize: 11 } }, new Date(p.acknowledgedAt).toLocaleDateString())
|
|
3139
|
+
);
|
|
3140
|
+
})
|
|
3084
3141
|
)
|
|
3085
3142
|
)
|
|
3086
3143
|
),
|
|
3087
3144
|
|
|
3088
3145
|
// ─── Approvals Tab ──────────────────────────────────
|
|
3089
3146
|
subTab === 'approvals' && h('div', null,
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
),
|
|
3105
|
-
h('div', { style: { fontSize: 13, color: 'var(--text-secondary)', marginBottom: 12 } }, a.description || a.reason || 'No description'),
|
|
3106
|
-
h('div', { style: { display: 'flex', gap: 8 } },
|
|
3107
|
-
h('button', { className: 'btn btn-primary btn-sm', onClick: function() { approveRequest(a.id); } }, I.check(), ' Approve'),
|
|
3108
|
-
h('button', { className: 'btn btn-danger btn-sm', onClick: function() { rejectRequest(a.id); } }, I.x(), ' Reject')
|
|
3109
|
-
)
|
|
3110
|
-
);
|
|
3111
|
-
})
|
|
3112
|
-
)
|
|
3113
|
-
)
|
|
3114
|
-
: h('div', { className: 'card-body' },
|
|
3115
|
-
h('div', { style: { textAlign: 'center', padding: 20, color: 'var(--text-muted)', fontSize: 13 } }, 'No pending approvals.')
|
|
3116
|
-
)
|
|
3147
|
+
pendingApprovals.length > 0 && h('div', { className: 'card', style: { marginBottom: 12 } },
|
|
3148
|
+
h('div', { className: 'card-header' }, h('span', null, 'Pending Approvals (' + pendingApprovals.length + ')')),
|
|
3149
|
+
h('div', { style: { padding: 0 } },
|
|
3150
|
+
pendingApprovals.map(function(a) {
|
|
3151
|
+
return h('div', { key: a.id, style: { display: 'flex', gap: 10, padding: '10px 16px', borderBottom: '1px solid var(--border)', fontSize: 12, alignItems: 'center' } },
|
|
3152
|
+
h('span', { style: { flex: 1 } },
|
|
3153
|
+
h('div', { style: { fontWeight: 500, marginBottom: 2 } }, a.action || a.description || 'Pending approval'),
|
|
3154
|
+
h('div', { style: { color: 'var(--text-muted)', fontSize: 11 } }, a.requestedAt ? new Date(a.requestedAt).toLocaleString() : '')
|
|
3155
|
+
),
|
|
3156
|
+
h('button', { className: 'btn btn-primary btn-sm', style: { height: 26 }, onClick: function() { approveRequest(a.id); } }, 'Approve'),
|
|
3157
|
+
h('button', { className: 'btn btn-secondary btn-sm', style: { height: 26 }, onClick: function() { rejectRequest(a.id); } }, 'Reject')
|
|
3158
|
+
);
|
|
3159
|
+
})
|
|
3160
|
+
)
|
|
3117
3161
|
),
|
|
3118
|
-
|
|
3119
|
-
// Approval History
|
|
3120
|
-
h('div', { className: 'card', style: { marginBottom: 20 } },
|
|
3162
|
+
h('div', { className: 'card' },
|
|
3121
3163
|
h('div', { className: 'card-header' }, h('span', null, 'Approval History')),
|
|
3122
3164
|
approvalHistory.length > 0
|
|
3123
|
-
? h('div', {
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3165
|
+
? h('div', { style: { padding: 0 } },
|
|
3166
|
+
approvalHistory.map(function(a, i) {
|
|
3167
|
+
var status = a.status || a.decision || 'unknown';
|
|
3168
|
+
return h('div', { key: a.id || i, style: { display: 'flex', gap: 10, padding: '8px 16px', borderBottom: '1px solid var(--border)', fontSize: 12, alignItems: 'center' } },
|
|
3169
|
+
h('span', { style: { color: 'var(--text-muted)', minWidth: 130 } }, a.decidedAt ? new Date(a.decidedAt).toLocaleString() : '-'),
|
|
3170
|
+
h('span', { className: 'badge ' + (status === 'approved' ? 'badge-success' : status === 'rejected' ? 'badge-danger' : 'badge-neutral') }, status),
|
|
3171
|
+
h('span', { style: { flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, a.action || a.description || '-'),
|
|
3172
|
+
h('span', { style: { color: 'var(--text-muted)' } }, a.decidedBy || '')
|
|
3173
|
+
);
|
|
3174
|
+
})
|
|
3175
|
+
)
|
|
3176
|
+
: h('div', { style: { padding: 32, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 } }, 'No approval history')
|
|
3177
|
+
)
|
|
3178
|
+
),
|
|
3179
|
+
|
|
3180
|
+
// ─── Create/Edit Rule Modal ─────────────────────────
|
|
3181
|
+
showCreate && h('div', { className: 'modal-overlay', onClick: function() { setShowCreate(false); } },
|
|
3182
|
+
h('div', { className: 'modal', style: { maxWidth: 520 }, onClick: function(e) { e.stopPropagation(); } },
|
|
3183
|
+
h('div', { className: 'modal-header' },
|
|
3184
|
+
h('h2', null, editRule ? 'Edit Rule' : 'Create Guardrail Rule'),
|
|
3185
|
+
h('button', { className: 'btn btn-ghost btn-icon', onClick: function() { setShowCreate(false); } }, I.x())
|
|
3186
|
+
),
|
|
3187
|
+
h('div', { className: 'modal-body' },
|
|
3188
|
+
h('div', { className: 'form-group' },
|
|
3189
|
+
h('label', { className: 'form-label' }, 'Name *'),
|
|
3190
|
+
h('input', { className: 'input', placeholder: 'e.g. High Error Rate Alert', value: ruleForm.name, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { name: e.target.value })); } })
|
|
3191
|
+
),
|
|
3192
|
+
h('div', { className: 'form-group' },
|
|
3193
|
+
h('label', { className: 'form-label' }, 'Description'),
|
|
3194
|
+
h('input', { className: 'input', placeholder: 'What this rule monitors...', value: ruleForm.description, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { description: e.target.value })); } })
|
|
3195
|
+
),
|
|
3196
|
+
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
3197
|
+
h('div', { className: 'form-group' },
|
|
3198
|
+
h('label', { className: 'form-label' }, 'Category'),
|
|
3199
|
+
h('select', { className: 'input', value: ruleForm.category, onChange: function(e) {
|
|
3200
|
+
var cat = CATEGORIES.find(function(c) { return c.value === e.target.value; });
|
|
3201
|
+
setRuleForm(Object.assign({}, ruleForm, { category: e.target.value, ruleType: cat ? cat.types[0] : ruleForm.ruleType }));
|
|
3202
|
+
} },
|
|
3203
|
+
CATEGORIES.map(function(c) { return h('option', { key: c.value, value: c.value }, c.label); })
|
|
3204
|
+
)
|
|
3205
|
+
),
|
|
3206
|
+
h('div', { className: 'form-group' },
|
|
3207
|
+
h('label', { className: 'form-label' }, 'Rule Type'),
|
|
3208
|
+
h('select', { className: 'input', value: ruleForm.ruleType, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { ruleType: e.target.value })); } },
|
|
3209
|
+
(CATEGORIES.find(function(c) { return c.value === ruleForm.category; })?.types || []).map(function(t) { return h('option', { key: t, value: t }, TYPE_LABELS[t] || t); })
|
|
3210
|
+
)
|
|
3211
|
+
)
|
|
3212
|
+
),
|
|
3213
|
+
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 } },
|
|
3214
|
+
h('div', { className: 'form-group' },
|
|
3215
|
+
h('label', { className: 'form-label' }, 'Action'),
|
|
3216
|
+
h('select', { className: 'input', value: ruleForm.action, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { action: e.target.value })); } },
|
|
3217
|
+
h('option', { value: 'alert' }, 'Alert'),
|
|
3218
|
+
h('option', { value: 'notify' }, 'Notify'),
|
|
3219
|
+
h('option', { value: 'log' }, 'Log'),
|
|
3220
|
+
h('option', { value: 'pause' }, 'Pause Agent'),
|
|
3221
|
+
h('option', { value: 'kill' }, 'Kill Agent')
|
|
3222
|
+
)
|
|
3223
|
+
),
|
|
3224
|
+
h('div', { className: 'form-group' },
|
|
3225
|
+
h('label', { className: 'form-label' }, 'Severity'),
|
|
3226
|
+
h('select', { className: 'input', value: ruleForm.severity, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { severity: e.target.value })); } },
|
|
3227
|
+
h('option', { value: 'low' }, 'Low'),
|
|
3228
|
+
h('option', { value: 'medium' }, 'Medium'),
|
|
3229
|
+
h('option', { value: 'high' }, 'High'),
|
|
3230
|
+
h('option', { value: 'critical' }, 'Critical')
|
|
3147
3231
|
)
|
|
3232
|
+
),
|
|
3233
|
+
h('div', { className: 'form-group' },
|
|
3234
|
+
h('label', { className: 'form-label' }, 'Cooldown (min)'),
|
|
3235
|
+
h('input', { className: 'input', type: 'number', value: ruleForm.cooldownMinutes, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { cooldownMinutes: e.target.value })); } })
|
|
3236
|
+
)
|
|
3237
|
+
),
|
|
3238
|
+
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
3239
|
+
h('div', { className: 'form-group' },
|
|
3240
|
+
h('label', { className: 'form-label' }, 'Threshold'),
|
|
3241
|
+
h('input', { className: 'input', type: 'number', placeholder: 'e.g. 10', value: ruleForm.threshold, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { threshold: e.target.value })); } })
|
|
3242
|
+
),
|
|
3243
|
+
h('div', { className: 'form-group' },
|
|
3244
|
+
h('label', { className: 'form-label' }, 'Window (min)'),
|
|
3245
|
+
h('input', { className: 'input', type: 'number', placeholder: 'e.g. 60', value: ruleForm.windowMinutes, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { windowMinutes: e.target.value })); } })
|
|
3148
3246
|
)
|
|
3149
|
-
|
|
3150
|
-
|
|
3247
|
+
),
|
|
3248
|
+
(ruleForm.category === 'communication' || ruleForm.category === 'security') && h(Fragment, null,
|
|
3249
|
+
h('div', { className: 'form-group' },
|
|
3250
|
+
h('label', { className: 'form-label' }, 'Keywords (comma-separated)'),
|
|
3251
|
+
h('input', { className: 'input', placeholder: 'confidential, secret, password', value: ruleForm.keywords, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { keywords: e.target.value })); } })
|
|
3252
|
+
),
|
|
3253
|
+
h('div', { className: 'form-group' },
|
|
3254
|
+
h('label', { className: 'form-label' }, 'Patterns (comma-separated regex)'),
|
|
3255
|
+
h('input', { className: 'input', placeholder: '\\d{4}-\\d{4}-\\d{4}-\\d{4}', value: ruleForm.patterns, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { patterns: e.target.value })); } })
|
|
3151
3256
|
)
|
|
3257
|
+
),
|
|
3258
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 } },
|
|
3259
|
+
h('input', { type: 'checkbox', checked: ruleForm.enabled, onChange: function(e) { setRuleForm(Object.assign({}, ruleForm, { enabled: e.target.checked })); } }),
|
|
3260
|
+
h('label', { style: { fontSize: 13 } }, 'Enabled')
|
|
3261
|
+
),
|
|
3262
|
+
h('div', { style: { fontSize: 11, color: 'var(--text-muted)', marginTop: 8 } }, 'This rule will be scoped to this agent only. To create org-wide rules, use the Guardrails page in the sidebar.')
|
|
3263
|
+
),
|
|
3264
|
+
h('div', { className: 'modal-footer' },
|
|
3265
|
+
h('button', { className: 'btn btn-ghost', onClick: function() { setShowCreate(false); } }, 'Cancel'),
|
|
3266
|
+
h('button', { className: 'btn btn-primary', onClick: saveRule }, editRule ? 'Update Rule' : 'Create Rule')
|
|
3267
|
+
)
|
|
3152
3268
|
)
|
|
3153
3269
|
)
|
|
3154
3270
|
);
|
|
3155
3271
|
}
|
|
3156
|
-
|
|
3157
|
-
// ════════════════════════════════════════════════════════════
|
|
3158
|
-
// CONFIGURATION SECTION — Model, Description, Soul, General
|
|
3159
|
-
// ════════════════════════════════════════════════════════════
|
|
3160
|
-
|
|
3161
3272
|
function ConfigurationSection(props) {
|
|
3162
3273
|
var agentId = props.agentId;
|
|
3163
3274
|
var engineAgent = props.engineAgent;
|