@agenticmail/enterprise 0.5.164 → 0.5.166
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/dashboard/pages/agent-detail.js +523 -358
- package/package.json +1 -1
- package/src/dashboard/pages/agent-detail.js +523 -358
|
@@ -1998,13 +1998,37 @@ function MemorySection(props) {
|
|
|
1998
1998
|
var filterCategory = _filterCat[0]; var setFilterCategory = _filterCat[1];
|
|
1999
1999
|
var _filterImp = useState('');
|
|
2000
2000
|
var filterImportance = _filterImp[0]; var setFilterImportance = _filterImp[1];
|
|
2001
|
+
var _dateFrom = useState('');
|
|
2002
|
+
var dateFrom = _dateFrom[0]; var setDateFrom = _dateFrom[1];
|
|
2003
|
+
var _dateTo = useState('');
|
|
2004
|
+
var dateTo = _dateTo[0]; var setDateTo = _dateTo[1];
|
|
2005
|
+
var _page = useState(1);
|
|
2006
|
+
var page = _page[0]; var setPage = _page[1];
|
|
2007
|
+
var _expanded = useState(null);
|
|
2008
|
+
var expandedId = _expanded[0]; var setExpandedId = _expanded[1];
|
|
2001
2009
|
var _showCreate = useState(false);
|
|
2002
2010
|
var showCreateModal = _showCreate[0]; var setShowCreateModal = _showCreate[1];
|
|
2003
2011
|
var _form = useState({ title: '', content: '', category: 'org_knowledge', importance: 'normal', tags: '' });
|
|
2004
2012
|
var createForm = _form[0]; var setCreateForm = _form[1];
|
|
2005
2013
|
|
|
2014
|
+
var PAGE_SIZE = 10;
|
|
2015
|
+
|
|
2016
|
+
var MEMORY_CATEGORIES = [
|
|
2017
|
+
{ value: 'org_knowledge', label: 'Org Knowledge' },
|
|
2018
|
+
{ value: 'preference', label: 'Preference' },
|
|
2019
|
+
{ value: 'interaction_pattern', label: 'Interaction Pattern' },
|
|
2020
|
+
{ value: 'context', label: 'Context' },
|
|
2021
|
+
{ value: 'skill', label: 'Skill' },
|
|
2022
|
+
{ value: 'processed_email', label: 'Processed Email' },
|
|
2023
|
+
{ value: 'procedure', label: 'Procedure' },
|
|
2024
|
+
{ value: 'relationship', label: 'Relationship' },
|
|
2025
|
+
{ value: 'reflection', label: 'Reflection' },
|
|
2026
|
+
{ value: 'domain_expertise', label: 'Domain Expertise' },
|
|
2027
|
+
{ value: 'error_pattern', label: 'Error Pattern' }
|
|
2028
|
+
];
|
|
2029
|
+
|
|
2006
2030
|
var buildQueryParams = function() {
|
|
2007
|
-
var params = '?limit=
|
|
2031
|
+
var params = '?limit=200';
|
|
2008
2032
|
if (searchQuery) params += '&search=' + encodeURIComponent(searchQuery);
|
|
2009
2033
|
if (filterCategory) params += '&category=' + filterCategory;
|
|
2010
2034
|
if (filterImportance) params += '&importance=' + filterImportance;
|
|
@@ -2012,9 +2036,8 @@ function MemorySection(props) {
|
|
|
2012
2036
|
};
|
|
2013
2037
|
|
|
2014
2038
|
var loadMemories = function() {
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
.then(function(d) { setMemories(d.memories || []); })
|
|
2039
|
+
engineCall('/memory/agent/' + agentId + buildQueryParams())
|
|
2040
|
+
.then(function(d) { setMemories(d.memories || []); setPage(1); })
|
|
2018
2041
|
.catch(function() {});
|
|
2019
2042
|
};
|
|
2020
2043
|
|
|
@@ -2024,38 +2047,24 @@ function MemorySection(props) {
|
|
|
2024
2047
|
.catch(function() {});
|
|
2025
2048
|
};
|
|
2026
2049
|
|
|
2027
|
-
var loadAll = function() {
|
|
2028
|
-
loadMemories();
|
|
2029
|
-
loadStats();
|
|
2030
|
-
};
|
|
2050
|
+
var loadAll = function() { loadMemories(); loadStats(); };
|
|
2031
2051
|
|
|
2032
|
-
useEffect(loadAll, []);
|
|
2052
|
+
useEffect(function() { loadAll(); }, [agentId]);
|
|
2033
2053
|
useEffect(function() { loadMemories(); }, [filterCategory, filterImportance]);
|
|
2034
2054
|
|
|
2035
|
-
var handleSearch = function() {
|
|
2036
|
-
loadMemories();
|
|
2037
|
-
};
|
|
2055
|
+
var handleSearch = function() { loadMemories(); };
|
|
2038
2056
|
|
|
2039
2057
|
var createMemory = function() {
|
|
2040
|
-
if (!createForm.title || !createForm.content) { toast('Title and content are required', 'error'); return; }
|
|
2041
|
-
var tagsArray = createForm.tags ? createForm.tags.split(',').map(function(s) { return s.trim(); }).filter(Boolean) : [];
|
|
2042
2058
|
var body = {
|
|
2043
2059
|
agentId: agentId,
|
|
2044
|
-
orgId: getOrgId(),
|
|
2045
2060
|
title: createForm.title,
|
|
2046
2061
|
content: createForm.content,
|
|
2047
2062
|
category: createForm.category,
|
|
2048
2063
|
importance: createForm.importance,
|
|
2049
|
-
|
|
2050
|
-
tags: tagsArray
|
|
2064
|
+
tags: createForm.tags ? createForm.tags.split(',').map(function(t) { return t.trim(); }).filter(Boolean) : []
|
|
2051
2065
|
};
|
|
2052
2066
|
engineCall('/memory', { method: 'POST', body: JSON.stringify(body) })
|
|
2053
|
-
.then(function() {
|
|
2054
|
-
toast('Memory created', 'success');
|
|
2055
|
-
setShowCreateModal(false);
|
|
2056
|
-
setCreateForm({ title: '', content: '', category: 'org_knowledge', importance: 'normal', tags: '' });
|
|
2057
|
-
loadAll();
|
|
2058
|
-
})
|
|
2067
|
+
.then(function() { toast('Memory created', 'success'); setShowCreateModal(false); setCreateForm({ title: '', content: '', category: 'org_knowledge', importance: 'normal', tags: '' }); loadAll(); })
|
|
2059
2068
|
.catch(function(e) { toast(e.message, 'error'); });
|
|
2060
2069
|
};
|
|
2061
2070
|
|
|
@@ -2063,7 +2072,7 @@ function MemorySection(props) {
|
|
|
2063
2072
|
showConfirm({
|
|
2064
2073
|
title: 'Delete Memory',
|
|
2065
2074
|
message: 'Are you sure you want to delete this memory entry? This action cannot be undone.',
|
|
2066
|
-
|
|
2075
|
+
warning: true,
|
|
2067
2076
|
confirmText: 'Delete'
|
|
2068
2077
|
}).then(function(confirmed) {
|
|
2069
2078
|
if (!confirmed) return;
|
|
@@ -2076,13 +2085,13 @@ function MemorySection(props) {
|
|
|
2076
2085
|
var pruneStale = function() {
|
|
2077
2086
|
showConfirm({
|
|
2078
2087
|
title: 'Prune Stale Memories',
|
|
2079
|
-
message: 'This will remove expired and stale memory entries for this agent.
|
|
2088
|
+
message: 'This will remove expired and stale memory entries for this agent.',
|
|
2080
2089
|
warning: true,
|
|
2081
2090
|
confirmText: 'Prune'
|
|
2082
2091
|
}).then(function(confirmed) {
|
|
2083
2092
|
if (!confirmed) return;
|
|
2084
2093
|
engineCall('/memory/agent/' + agentId + '/prune', { method: 'POST' })
|
|
2085
|
-
.then(function(d) { toast('Pruned ' + (d.
|
|
2094
|
+
.then(function(d) { toast('Pruned ' + (d.deleted || 0) + ' entries', 'success'); loadAll(); })
|
|
2086
2095
|
.catch(function(e) { toast(e.message, 'error'); });
|
|
2087
2096
|
});
|
|
2088
2097
|
};
|
|
@@ -2090,7 +2099,7 @@ function MemorySection(props) {
|
|
|
2090
2099
|
var runDecay = function() {
|
|
2091
2100
|
showConfirm({
|
|
2092
2101
|
title: 'Run Confidence Decay',
|
|
2093
|
-
message: 'This will reduce
|
|
2102
|
+
message: 'This will reduce confidence of memories not accessed recently. Decay rate: 10%.',
|
|
2094
2103
|
warning: true,
|
|
2095
2104
|
confirmText: 'Run Decay'
|
|
2096
2105
|
}).then(function(confirmed) {
|
|
@@ -2101,116 +2110,161 @@ function MemorySection(props) {
|
|
|
2101
2110
|
});
|
|
2102
2111
|
};
|
|
2103
2112
|
|
|
2104
|
-
//
|
|
2113
|
+
// Date filter client-side
|
|
2114
|
+
var filtered = memories;
|
|
2115
|
+
if (dateFrom) {
|
|
2116
|
+
var fromTs = new Date(dateFrom).getTime();
|
|
2117
|
+
filtered = filtered.filter(function(m) { return m.createdAt && new Date(m.createdAt).getTime() >= fromTs; });
|
|
2118
|
+
}
|
|
2119
|
+
if (dateTo) {
|
|
2120
|
+
var toTs = new Date(dateTo + 'T23:59:59').getTime();
|
|
2121
|
+
filtered = filtered.filter(function(m) { return m.createdAt && new Date(m.createdAt).getTime() <= toTs; });
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
var totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
|
|
2125
|
+
var paged = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
|
|
2126
|
+
|
|
2127
|
+
// Stats
|
|
2105
2128
|
var totalMemories = memoryStats ? (memoryStats.totalEntries || memoryStats.total || 0) : 0;
|
|
2106
2129
|
var categoriesUsed = memoryStats && memoryStats.byCategory ? Object.keys(memoryStats.byCategory).length : 0;
|
|
2107
2130
|
var avgConfidence = memoryStats && memoryStats.avgConfidence != null ? ((memoryStats.avgConfidence * 100).toFixed(0) + '%') : '-';
|
|
2108
2131
|
var sourcesCount = memoryStats && memoryStats.bySource ? Object.keys(memoryStats.bySource).length : 0;
|
|
2109
2132
|
|
|
2133
|
+
var catColor = function(c) {
|
|
2134
|
+
var m = { preference: '#8b5cf6', interaction_pattern: '#ec4899', context: '#3b82f6', skill: '#10b981', processed_email: '#6366f1', org_knowledge: '#f59e0b', procedure: '#14b8a6', relationship: '#f43f5e', reflection: '#a855f7', domain_expertise: '#0ea5e9', error_pattern: '#ef4444' };
|
|
2135
|
+
return m[c] || '#64748b';
|
|
2136
|
+
};
|
|
2137
|
+
var impColor = function(i) {
|
|
2138
|
+
var m = { critical: '#ef4444', high: '#f43f5e', normal: '#3b82f6', low: '#64748b' };
|
|
2139
|
+
return m[i] || '#64748b';
|
|
2140
|
+
};
|
|
2141
|
+
|
|
2142
|
+
var fmtDate = function(d) { if (!d) return '-'; var dt = new Date(d); return dt.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }); };
|
|
2143
|
+
var fmtTime = function(d) { if (!d) return ''; var dt = new Date(d); return dt.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' }); };
|
|
2144
|
+
|
|
2110
2145
|
return h('div', { className: 'card' },
|
|
2111
2146
|
h('div', { className: 'card-header', style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' } },
|
|
2112
2147
|
h('h3', { style: { margin: 0, fontSize: 15, fontWeight: 600 } }, 'Memory'),
|
|
2113
|
-
h('
|
|
2148
|
+
h('div', { style: { display: 'flex', gap: 6 } },
|
|
2149
|
+
h('button', { className: 'btn btn-ghost btn-sm', onClick: pruneStale, title: 'Prune stale entries' }, I.trash()),
|
|
2150
|
+
h('button', { className: 'btn btn-ghost btn-sm', onClick: runDecay, title: 'Run confidence decay' }, I.clock()),
|
|
2151
|
+
h('button', { className: 'btn btn-ghost btn-sm', onClick: loadAll }, I.refresh()),
|
|
2152
|
+
h('button', { className: 'btn btn-primary btn-sm', onClick: function() { setShowCreateModal(true); } }, I.plus(), ' Add')
|
|
2153
|
+
)
|
|
2114
2154
|
),
|
|
2115
|
-
h('div', { className: 'card-body' },
|
|
2116
|
-
|
|
2117
|
-
//
|
|
2118
|
-
h('div', {
|
|
2119
|
-
h('
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
),
|
|
2123
|
-
h('div', {
|
|
2124
|
-
|
|
2125
|
-
h('div', { className: 'stat-label' }, 'Categories Used')
|
|
2126
|
-
),
|
|
2127
|
-
h('div', { className: 'stat-card' },
|
|
2128
|
-
h('div', { className: 'stat-value' }, avgConfidence),
|
|
2129
|
-
h('div', { className: 'stat-label' }, 'Avg Confidence')
|
|
2130
|
-
),
|
|
2131
|
-
h('div', { className: 'stat-card' },
|
|
2132
|
-
h('div', { className: 'stat-value' }, sourcesCount),
|
|
2133
|
-
h('div', { className: 'stat-label' }, 'Sources')
|
|
2134
|
-
)
|
|
2155
|
+
h('div', { className: 'card-body', style: { padding: 0 } },
|
|
2156
|
+
|
|
2157
|
+
// Compact stats bar
|
|
2158
|
+
h('div', { style: { display: 'flex', gap: 24, padding: '10px 16px', borderBottom: '1px solid var(--border)', fontSize: 13 } },
|
|
2159
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Total: ', h('strong', null, totalMemories)),
|
|
2160
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Categories: ', h('strong', null, categoriesUsed)),
|
|
2161
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Avg Conf: ', h('strong', null, avgConfidence)),
|
|
2162
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Sources: ', h('strong', null, sourcesCount)),
|
|
2163
|
+
h('div', { style: { flex: 1 } }),
|
|
2164
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Showing ', h('strong', null, filtered.length), ' of ', totalMemories)
|
|
2135
2165
|
),
|
|
2136
2166
|
|
|
2137
|
-
// Filter
|
|
2138
|
-
h('div', { style: { display: 'flex', gap:
|
|
2139
|
-
h('
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
})
|
|
2147
|
-
),
|
|
2148
|
-
h('button', { className: 'btn btn-ghost btn-sm', onClick: handleSearch }, I.search()),
|
|
2149
|
-
h('select', { className: 'input', style: { maxWidth: 170 }, value: filterCategory, onChange: function(e) { setFilterCategory(e.target.value); } },
|
|
2167
|
+
// Filter row
|
|
2168
|
+
h('div', { style: { display: 'flex', gap: 6, padding: '8px 16px', borderBottom: '1px solid var(--border)', flexWrap: 'wrap', alignItems: 'center' } },
|
|
2169
|
+
h('input', {
|
|
2170
|
+
className: 'input', style: { flex: 1, minWidth: 140, height: 30, fontSize: 12 },
|
|
2171
|
+
placeholder: 'Search...', value: searchQuery,
|
|
2172
|
+
onChange: function(e) { setSearchQuery(e.target.value); },
|
|
2173
|
+
onKeyDown: function(e) { if (e.key === 'Enter') handleSearch(); }
|
|
2174
|
+
}),
|
|
2175
|
+
h('select', { className: 'input', style: { width: 130, height: 30, fontSize: 12 }, value: filterCategory, onChange: function(e) { setFilterCategory(e.target.value); } },
|
|
2150
2176
|
h('option', { value: '' }, 'All Categories'),
|
|
2151
2177
|
MEMORY_CATEGORIES.map(function(c) { return h('option', { key: c.value, value: c.value }, c.label); })
|
|
2152
2178
|
),
|
|
2153
|
-
h('select', { className: 'input', style: {
|
|
2154
|
-
h('option', { value: '' }, 'All
|
|
2179
|
+
h('select', { className: 'input', style: { width: 110, height: 30, fontSize: 12 }, value: filterImportance, onChange: function(e) { setFilterImportance(e.target.value); } },
|
|
2180
|
+
h('option', { value: '' }, 'All Levels'),
|
|
2155
2181
|
h('option', { value: 'critical' }, 'Critical'),
|
|
2156
2182
|
h('option', { value: 'high' }, 'High'),
|
|
2157
2183
|
h('option', { value: 'normal' }, 'Normal'),
|
|
2158
2184
|
h('option', { value: 'low' }, 'Low')
|
|
2159
2185
|
),
|
|
2160
|
-
h('
|
|
2161
|
-
h('
|
|
2162
|
-
h('
|
|
2163
|
-
h('button', { className: 'btn btn-ghost btn-sm', style: {
|
|
2186
|
+
h('input', { type: 'date', className: 'input', style: { width: 120, height: 30, fontSize: 12 }, value: dateFrom, onChange: function(e) { setDateFrom(e.target.value); setPage(1); }, title: 'From date' }),
|
|
2187
|
+
h('span', { style: { fontSize: 11, color: 'var(--text-muted)' } }, '–'),
|
|
2188
|
+
h('input', { type: 'date', className: 'input', style: { width: 120, height: 30, fontSize: 12 }, value: dateTo, onChange: function(e) { setDateTo(e.target.value); setPage(1); }, title: 'To date' }),
|
|
2189
|
+
(dateFrom || dateTo) && h('button', { className: 'btn btn-ghost btn-sm', style: { height: 30, fontSize: 11 }, onClick: function() { setDateFrom(''); setDateTo(''); } }, 'Clear')
|
|
2164
2190
|
),
|
|
2165
2191
|
|
|
2166
|
-
//
|
|
2167
|
-
|
|
2168
|
-
? h('div', { style: { padding:
|
|
2169
|
-
: h(
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2192
|
+
// Table-style compact list
|
|
2193
|
+
filtered.length === 0
|
|
2194
|
+
? h('div', { style: { padding: 32, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 } }, 'No memories found')
|
|
2195
|
+
: h(Fragment, null,
|
|
2196
|
+
// Header row
|
|
2197
|
+
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 100px 70px 60px 70px 36px', gap: 8, padding: '6px 16px', borderBottom: '1px solid var(--border)', fontSize: 11, fontWeight: 600, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.5px' } },
|
|
2198
|
+
h('span', null, 'Memory'),
|
|
2199
|
+
h('span', null, 'Category'),
|
|
2200
|
+
h('span', null, 'Level'),
|
|
2201
|
+
h('span', null, 'Conf'),
|
|
2202
|
+
h('span', null, 'Date'),
|
|
2203
|
+
h('span', null, '')
|
|
2204
|
+
),
|
|
2205
|
+
// Rows
|
|
2206
|
+
paged.map(function(m) {
|
|
2207
|
+
var isExpanded = expandedId === m.id;
|
|
2208
|
+
var conf = m.confidence != null ? Math.round(m.confidence * 100) : 0;
|
|
2209
|
+
var confBar = conf >= 80 ? 'var(--success)' : conf >= 50 ? 'var(--warning)' : 'var(--danger)';
|
|
2210
|
+
return h('div', { key: m.id },
|
|
2211
|
+
// Compact row
|
|
2212
|
+
h('div', {
|
|
2213
|
+
style: { display: 'grid', gridTemplateColumns: '1fr 100px 70px 60px 70px 36px', gap: 8, padding: '8px 16px', borderBottom: '1px solid var(--border)', cursor: 'pointer', fontSize: 13, alignItems: 'center', transition: 'background 0.1s', background: isExpanded ? 'var(--bg-tertiary)' : 'transparent' },
|
|
2214
|
+
onClick: function() { setExpandedId(isExpanded ? null : m.id); },
|
|
2215
|
+
onMouseEnter: function(e) { if (!isExpanded) e.currentTarget.style.background = 'var(--bg-secondary)'; },
|
|
2216
|
+
onMouseLeave: function(e) { if (!isExpanded) e.currentTarget.style.background = 'transparent'; }
|
|
2217
|
+
},
|
|
2218
|
+
// Title + preview
|
|
2219
|
+
h('div', { style: { overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' } },
|
|
2220
|
+
h('span', { style: { fontWeight: 500 } }, m.title || 'Untitled'),
|
|
2221
|
+
m.content && h('span', { style: { color: 'var(--text-muted)', marginLeft: 8, fontSize: 12 } }, m.content.substring(0, 60) + (m.content.length > 60 ? '...' : ''))
|
|
2186
2222
|
),
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
//
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2223
|
+
// Category badge
|
|
2224
|
+
h('span', { style: { display: 'inline-block', padding: '1px 6px', borderRadius: 3, fontSize: 10, fontWeight: 600, color: '#fff', background: catColor(m.category), whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, (m.category || '').replace(/_/g, ' ')),
|
|
2225
|
+
// Importance
|
|
2226
|
+
h('span', { style: { fontSize: 11, color: impColor(m.importance), fontWeight: 500 } }, m.importance || 'normal'),
|
|
2227
|
+
// Confidence bar
|
|
2228
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 4 } },
|
|
2229
|
+
h('div', { style: { flex: 1, height: 4, borderRadius: 2, background: 'var(--border)' } },
|
|
2230
|
+
h('div', { style: { width: conf + '%', height: '100%', borderRadius: 2, background: confBar } })
|
|
2231
|
+
),
|
|
2232
|
+
h('span', { style: { fontSize: 10, color: 'var(--text-muted)', minWidth: 24 } }, conf + '%')
|
|
2196
2233
|
),
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2234
|
+
// Date
|
|
2235
|
+
h('span', { style: { fontSize: 11, color: 'var(--text-muted)', whiteSpace: 'nowrap' } }, fmtDate(m.createdAt)),
|
|
2236
|
+
// Expand indicator
|
|
2237
|
+
h('span', { style: { fontSize: 10, color: 'var(--text-muted)', textAlign: 'center' } }, isExpanded ? '▲' : '▼')
|
|
2238
|
+
),
|
|
2239
|
+
// Expanded detail
|
|
2240
|
+
isExpanded && h('div', { style: { padding: '10px 16px 12px', background: 'var(--bg-tertiary)', borderBottom: '1px solid var(--border)', fontSize: 12, lineHeight: 1.6 } },
|
|
2241
|
+
h('div', { style: { color: 'var(--text)', marginBottom: 8, whiteSpace: 'pre-wrap', maxHeight: 200, overflow: 'auto' } }, m.content || '(empty)'),
|
|
2242
|
+
h('div', { style: { display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center', fontSize: 11, color: 'var(--text-muted)' } },
|
|
2243
|
+
h('span', null, 'Source: ', h('strong', null, m.source || '-')),
|
|
2244
|
+
h('span', null, 'Created: ', h('strong', null, fmtDate(m.createdAt)), ' ', fmtTime(m.createdAt)),
|
|
2245
|
+
m.lastAccessedAt && h('span', null, 'Last accessed: ', h('strong', null, fmtDate(m.lastAccessedAt))),
|
|
2246
|
+
m.tags && m.tags.length > 0 && h('span', null, 'Tags: ', m.tags.join(', ')),
|
|
2203
2247
|
h('div', { style: { flex: 1 } }),
|
|
2204
|
-
h('button', { className: 'btn btn-ghost btn-sm', style: { color: 'var(--danger)' }, onClick: function() { deleteMemory(m.id); } }, I.trash(), ' Delete')
|
|
2248
|
+
h('button', { className: 'btn btn-ghost btn-sm', style: { color: 'var(--danger)', height: 24, fontSize: 11 }, onClick: function(e) { e.stopPropagation(); deleteMemory(m.id); } }, I.trash(), ' Delete')
|
|
2205
2249
|
)
|
|
2206
|
-
)
|
|
2207
|
-
|
|
2250
|
+
)
|
|
2251
|
+
);
|
|
2252
|
+
}),
|
|
2253
|
+
|
|
2254
|
+
// Pagination
|
|
2255
|
+
totalPages > 1 && h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4, padding: '10px 16px', borderTop: '1px solid var(--border)' } },
|
|
2256
|
+
h('button', { className: 'btn btn-ghost btn-sm', disabled: page <= 1, onClick: function() { setPage(1); }, style: { fontSize: 11, height: 28 } }, '«'),
|
|
2257
|
+
h('button', { className: 'btn btn-ghost btn-sm', disabled: page <= 1, onClick: function() { setPage(page - 1); }, style: { fontSize: 11, height: 28 } }, '‹'),
|
|
2258
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)', padding: '0 8px' } }, 'Page ', h('strong', null, page), ' of ', h('strong', null, totalPages)),
|
|
2259
|
+
h('button', { className: 'btn btn-ghost btn-sm', disabled: page >= totalPages, onClick: function() { setPage(page + 1); }, style: { fontSize: 11, height: 28 } }, '›'),
|
|
2260
|
+
h('button', { className: 'btn btn-ghost btn-sm', disabled: page >= totalPages, onClick: function() { setPage(totalPages); }, style: { fontSize: 11, height: 28 } }, '»')
|
|
2208
2261
|
)
|
|
2262
|
+
)
|
|
2209
2263
|
),
|
|
2210
2264
|
|
|
2211
2265
|
// Create Memory Modal
|
|
2212
2266
|
showCreateModal && h('div', { className: 'modal-overlay', onClick: function() { setShowCreateModal(false); } },
|
|
2213
|
-
h('div', { className: 'modal', style: { maxWidth:
|
|
2267
|
+
h('div', { className: 'modal', style: { maxWidth: 500 }, onClick: function(e) { e.stopPropagation(); } },
|
|
2214
2268
|
h('div', { className: 'modal-header' },
|
|
2215
2269
|
h('h2', null, 'Create Memory'),
|
|
2216
2270
|
h('button', { className: 'btn btn-ghost btn-icon', onClick: function() { setShowCreateModal(false); } }, I.x())
|
|
@@ -2222,7 +2276,7 @@ function MemorySection(props) {
|
|
|
2222
2276
|
),
|
|
2223
2277
|
h('div', { className: 'form-group' },
|
|
2224
2278
|
h('label', { className: 'form-label' }, 'Content *'),
|
|
2225
|
-
h('textarea', { className: 'input', style: { minHeight:
|
|
2279
|
+
h('textarea', { className: 'input', style: { minHeight: 100 }, placeholder: 'Memory content...', value: createForm.content, onChange: function(e) { setCreateForm(Object.assign({}, createForm, { content: e.target.value })); } })
|
|
2226
2280
|
),
|
|
2227
2281
|
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
2228
2282
|
h('div', { className: 'form-group' },
|
|
@@ -2243,12 +2297,12 @@ function MemorySection(props) {
|
|
|
2243
2297
|
),
|
|
2244
2298
|
h('div', { className: 'form-group' },
|
|
2245
2299
|
h('label', { className: 'form-label' }, 'Tags (comma-separated)'),
|
|
2246
|
-
h('input', { className: 'input', placeholder: 'tag1, tag2
|
|
2300
|
+
h('input', { className: 'input', placeholder: 'tag1, tag2', value: createForm.tags, onChange: function(e) { setCreateForm(Object.assign({}, createForm, { tags: e.target.value })); } })
|
|
2247
2301
|
)
|
|
2248
2302
|
),
|
|
2249
2303
|
h('div', { className: 'modal-footer' },
|
|
2250
2304
|
h('button', { className: 'btn btn-ghost', onClick: function() { setShowCreateModal(false); } }, 'Cancel'),
|
|
2251
|
-
h('button', { className: 'btn btn-primary', onClick: createMemory }, 'Create
|
|
2305
|
+
h('button', { className: 'btn btn-primary', onClick: createMemory }, 'Create')
|
|
2252
2306
|
)
|
|
2253
2307
|
)
|
|
2254
2308
|
)
|
|
@@ -2733,14 +2787,14 @@ function GuardrailsSection(props) {
|
|
|
2733
2787
|
var agents = props.agents || [];
|
|
2734
2788
|
var app = useApp();
|
|
2735
2789
|
var toast = app.toast;
|
|
2736
|
-
|
|
2737
2790
|
var agentData = buildAgentDataMap(agents);
|
|
2738
2791
|
|
|
2739
|
-
var _subTab = useState('
|
|
2792
|
+
var _subTab = useState('rules');
|
|
2740
2793
|
var subTab = _subTab[0]; var setSubTab = _subTab[1];
|
|
2741
|
-
|
|
2742
2794
|
var _guardrailStatus = useState(null);
|
|
2743
2795
|
var guardrailStatus = _guardrailStatus[0]; var setGuardrailStatus = _guardrailStatus[1];
|
|
2796
|
+
var _rules = useState([]);
|
|
2797
|
+
var rules = _rules[0]; var setRules = _rules[1];
|
|
2744
2798
|
var _interventions = useState([]);
|
|
2745
2799
|
var interventions = _interventions[0]; var setInterventions = _interventions[1];
|
|
2746
2800
|
var _dlpViolations = useState([]);
|
|
@@ -2749,33 +2803,55 @@ function GuardrailsSection(props) {
|
|
|
2749
2803
|
var onboardingStatus = _onboardingStatus[0]; var setOnboardingStatus = _onboardingStatus[1];
|
|
2750
2804
|
var _onboardingProgress = useState([]);
|
|
2751
2805
|
var onboardingProgress = _onboardingProgress[0]; var setOnboardingProgress = _onboardingProgress[1];
|
|
2752
|
-
var _pendingPolicies = useState([]);
|
|
2753
|
-
var pendingPolicies = _pendingPolicies[0]; var setPendingPolicies = _pendingPolicies[1];
|
|
2754
2806
|
var _pendingApprovals = useState([]);
|
|
2755
2807
|
var pendingApprovals = _pendingApprovals[0]; var setPendingApprovals = _pendingApprovals[1];
|
|
2756
2808
|
var _approvalHistory = useState([]);
|
|
2757
2809
|
var approvalHistory = _approvalHistory[0]; var setApprovalHistory = _approvalHistory[1];
|
|
2758
2810
|
var _loading = useState(true);
|
|
2759
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
|
+
};
|
|
2760
2836
|
|
|
2761
2837
|
var loadAll = function() {
|
|
2762
2838
|
setLoading(true);
|
|
2763
2839
|
Promise.all([
|
|
2764
2840
|
engineCall('/guardrails/status/' + agentId).catch(function() { return null; }),
|
|
2841
|
+
engineCall('/guardrails/rules?orgId=' + getOrgId()).catch(function() { return { rules: [] }; }),
|
|
2765
2842
|
engineCall('/guardrails/interventions?agentId=' + agentId).catch(function() { return { interventions: [] }; }),
|
|
2766
2843
|
engineCall('/dlp/violations?agentId=' + agentId).catch(function() { return { violations: [] }; }),
|
|
2767
2844
|
engineCall('/onboarding/status/' + agentId).catch(function() { return null; }),
|
|
2768
2845
|
engineCall('/onboarding/progress/' + agentId).catch(function() { return { progress: [] }; }),
|
|
2769
|
-
engineCall('/onboarding/pending/' + agentId).catch(function() { return { policies: [] }; }),
|
|
2770
2846
|
engineCall('/approvals/pending?agentId=' + agentId).catch(function() { return { approvals: [] }; }),
|
|
2771
2847
|
engineCall('/approvals/history?agentId=' + agentId).catch(function() { return { approvals: [] }; })
|
|
2772
2848
|
]).then(function(results) {
|
|
2773
2849
|
setGuardrailStatus(results[0]);
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
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] || []);
|
|
2779
2855
|
setPendingApprovals(results[6]?.approvals || results[6] || []);
|
|
2780
2856
|
setApprovalHistory(results[7]?.approvals || results[7] || []);
|
|
2781
2857
|
setLoading(false);
|
|
@@ -2784,67 +2860,146 @@ function GuardrailsSection(props) {
|
|
|
2784
2860
|
|
|
2785
2861
|
useEffect(function() { loadAll(); }, [agentId]);
|
|
2786
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
|
+
|
|
2787
2869
|
var pauseAgent = function() {
|
|
2788
2870
|
engineCall('/guardrails/pause/' + agentId, { method: 'POST', body: JSON.stringify({ reason: 'Manual pause from dashboard' }) })
|
|
2789
2871
|
.then(function() { toast('Agent paused', 'success'); loadAll(); })
|
|
2790
2872
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2791
2873
|
};
|
|
2792
|
-
|
|
2793
2874
|
var resumeAgent = function() {
|
|
2794
2875
|
engineCall('/guardrails/resume/' + agentId, { method: 'POST', body: JSON.stringify({ reason: 'Manual resume from dashboard' }) })
|
|
2795
2876
|
.then(function() { toast('Agent resumed', 'success'); loadAll(); })
|
|
2796
2877
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2797
2878
|
};
|
|
2798
|
-
|
|
2799
2879
|
var killAgent = function() {
|
|
2800
|
-
showConfirm({
|
|
2801
|
-
|
|
2802
|
-
message: 'Are you sure you want to kill this agent? This will immediately terminate all running processes.',
|
|
2803
|
-
warning: 'This action cannot be undone.',
|
|
2804
|
-
danger: true,
|
|
2805
|
-
confirmText: 'Kill Agent'
|
|
2806
|
-
}).then(function(confirmed) {
|
|
2807
|
-
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;
|
|
2808
2882
|
engineCall('/guardrails/kill/' + agentId, { method: 'POST', body: JSON.stringify({ reason: 'Manual kill from dashboard' }) })
|
|
2809
2883
|
.then(function() { toast('Agent killed', 'success'); loadAll(); })
|
|
2810
2884
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2811
2885
|
});
|
|
2812
2886
|
};
|
|
2813
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
|
+
|
|
2814
2954
|
var initiateOnboarding = function() {
|
|
2815
2955
|
engineCall('/onboarding/initiate/' + agentId, { method: 'POST', body: JSON.stringify({ orgId: getOrgId() }) })
|
|
2816
2956
|
.then(function() { toast('Onboarding initiated', 'success'); loadAll(); })
|
|
2817
2957
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2818
2958
|
};
|
|
2819
|
-
|
|
2820
2959
|
var forceComplete = function() {
|
|
2821
2960
|
engineCall('/onboarding/force-complete/' + agentId, { method: 'POST' })
|
|
2822
2961
|
.then(function() { toast('Onboarding force completed', 'success'); loadAll(); })
|
|
2823
2962
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2824
2963
|
};
|
|
2825
|
-
|
|
2826
2964
|
var approveRequest = function(id) {
|
|
2827
2965
|
engineCall('/approvals/' + id + '/approve', { method: 'POST', body: JSON.stringify({ decidedBy: 'dashboard-admin' }) })
|
|
2828
|
-
.then(function() { toast('
|
|
2966
|
+
.then(function() { toast('Approved', 'success'); loadAll(); })
|
|
2829
2967
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2830
2968
|
};
|
|
2831
|
-
|
|
2832
2969
|
var rejectRequest = function(id) {
|
|
2833
2970
|
engineCall('/approvals/' + id + '/reject', { method: 'POST', body: JSON.stringify({ decidedBy: 'dashboard-admin' }) })
|
|
2834
|
-
.then(function() { toast('
|
|
2971
|
+
.then(function() { toast('Rejected', 'success'); loadAll(); })
|
|
2835
2972
|
.catch(function(err) { toast(err.message, 'error'); });
|
|
2836
2973
|
};
|
|
2837
2974
|
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
}
|
|
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...');
|
|
2841
2980
|
|
|
2842
2981
|
return h(Fragment, null,
|
|
2843
2982
|
|
|
2844
|
-
//
|
|
2845
|
-
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 } },
|
|
2846
3001
|
h('div', { className: 'tabs' },
|
|
2847
|
-
h('div', { className: 'tab' + (subTab === '
|
|
3002
|
+
h('div', { className: 'tab' + (subTab === 'rules' ? ' active' : ''), onClick: function() { setSubTab('rules'); } }, 'Rules (' + agentRules.length + ')'),
|
|
2848
3003
|
h('div', { className: 'tab' + (subTab === 'interventions' ? ' active' : ''), onClick: function() { setSubTab('interventions'); } }, 'Interventions'),
|
|
2849
3004
|
h('div', { className: 'tab' + (subTab === 'dlp' ? ' active' : ''), onClick: function() { setSubTab('dlp'); } }, 'DLP'),
|
|
2850
3005
|
h('div', { className: 'tab' + (subTab === 'onboarding' ? ' active' : ''), onClick: function() { setSubTab('onboarding'); } }, 'Onboarding'),
|
|
@@ -2852,258 +3007,268 @@ function GuardrailsSection(props) {
|
|
|
2852
3007
|
)
|
|
2853
3008
|
),
|
|
2854
3009
|
|
|
2855
|
-
// ───
|
|
2856
|
-
subTab === '
|
|
2857
|
-
h('div', {
|
|
2858
|
-
h('
|
|
2859
|
-
h('
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
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')
|
|
2865
3056
|
),
|
|
2866
|
-
|
|
2867
|
-
)
|
|
2868
|
-
: h('div', { style: { padding: '12px 16px', background: 'rgba(34, 197, 94, 0.1)', border: '1px solid var(--success)', borderRadius: 8, marginBottom: 16 } },
|
|
2869
|
-
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
|
|
2870
|
-
h('span', { className: 'badge badge-success' }, I.shield(), ' Active')
|
|
2871
|
-
)
|
|
3057
|
+
rule.description && h('div', { style: { fontSize: 11, color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, rule.description)
|
|
2872
3058
|
),
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
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
|
+
})
|
|
2884
3074
|
),
|
|
2885
3075
|
|
|
2886
3076
|
// ─── Interventions Tab ──────────────────────────────
|
|
2887
|
-
subTab === 'interventions' && h('div', { className: 'card'
|
|
3077
|
+
subTab === 'interventions' && h('div', { className: 'card' },
|
|
2888
3078
|
h('div', { className: 'card-header' }, h('span', null, 'Interventions')),
|
|
2889
3079
|
interventions.length > 0
|
|
2890
|
-
? h('div', {
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
)
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
var time = inv.timestamp || inv.createdAt;
|
|
2904
|
-
var invType = inv.type || inv.interventionType || 'unknown';
|
|
2905
|
-
var severity = inv.severity || 'medium';
|
|
2906
|
-
var severityColor = severity === 'critical' ? 'badge-danger' : severity === 'high' ? 'badge-warning' : severity === 'medium' ? 'badge-info' : 'badge-neutral';
|
|
2907
|
-
var typeColor = invType === 'block' ? 'badge-danger' : invType === 'warn' ? 'badge-warning' : invType === 'audit' ? 'badge-info' : 'badge-neutral';
|
|
2908
|
-
|
|
2909
|
-
return h('tr', { key: inv.id || i },
|
|
2910
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)', whiteSpace: 'nowrap' } }, time ? new Date(time).toLocaleString() : '-'),
|
|
2911
|
-
h('td', null, h('span', { className: 'badge ' + typeColor }, invType)),
|
|
2912
|
-
h('td', null, h('span', { className: 'badge ' + severityColor }, severity)),
|
|
2913
|
-
h('td', { style: { fontSize: 13, maxWidth: 300, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, inv.description || inv.message || '-'),
|
|
2914
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)' } }, inv.resolution || inv.action || '-')
|
|
2915
|
-
);
|
|
2916
|
-
})
|
|
2917
|
-
)
|
|
2918
|
-
)
|
|
2919
|
-
)
|
|
2920
|
-
: h('div', { className: 'card-body' },
|
|
2921
|
-
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
|
+
})
|
|
2922
3093
|
)
|
|
3094
|
+
: h('div', { style: { padding: 32, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 } }, 'No interventions recorded')
|
|
2923
3095
|
),
|
|
2924
3096
|
|
|
2925
3097
|
// ─── DLP Tab ────────────────────────────────────────
|
|
2926
|
-
subTab === 'dlp' && h('div', { className: 'card'
|
|
3098
|
+
subTab === 'dlp' && h('div', { className: 'card' },
|
|
2927
3099
|
h('div', { className: 'card-header' }, h('span', null, 'DLP Violations')),
|
|
2928
3100
|
dlpViolations.length > 0
|
|
2929
|
-
? h('div', {
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
)
|
|
2939
|
-
)
|
|
2940
|
-
|
|
2941
|
-
dlpViolations.map(function(v, i) {
|
|
2942
|
-
var time = v.timestamp || v.createdAt || v.detectedAt;
|
|
2943
|
-
var rule = v.rule || v.ruleName || v.ruleId || 'Unknown';
|
|
2944
|
-
var severity = v.severity || 'medium';
|
|
2945
|
-
var severityColor = severity === 'critical' ? 'badge-danger' : severity === 'high' ? 'badge-warning' : severity === 'medium' ? 'badge-info' : 'badge-neutral';
|
|
2946
|
-
var content = v.content || v.matchedContent || v.snippet || '';
|
|
2947
|
-
var truncatedContent = content.length > 80 ? content.substring(0, 80) + '...' : content;
|
|
2948
|
-
var violationStatus = v.status || v.action || 'detected';
|
|
2949
|
-
|
|
2950
|
-
return h('tr', { key: v.id || i },
|
|
2951
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)', whiteSpace: 'nowrap' } }, time ? new Date(time).toLocaleString() : '-'),
|
|
2952
|
-
h('td', null, h('span', { className: 'badge badge-info' }, rule)),
|
|
2953
|
-
h('td', null, h('span', { className: 'badge ' + severityColor }, severity)),
|
|
2954
|
-
h('td', { style: { fontSize: 12, fontFamily: 'var(--font-mono, monospace)', maxWidth: 250, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'var(--text-secondary)' } }, truncatedContent || '-'),
|
|
2955
|
-
h('td', null, h('span', { className: 'badge badge-neutral' }, violationStatus))
|
|
2956
|
-
);
|
|
2957
|
-
})
|
|
2958
|
-
)
|
|
2959
|
-
)
|
|
2960
|
-
)
|
|
2961
|
-
: h('div', { className: 'card-body' },
|
|
2962
|
-
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
|
+
})
|
|
2963
3113
|
)
|
|
3114
|
+
: h('div', { style: { padding: 32, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 } }, 'No DLP violations detected')
|
|
2964
3115
|
),
|
|
2965
3116
|
|
|
2966
3117
|
// ─── Onboarding Tab ─────────────────────────────────
|
|
2967
3118
|
subTab === 'onboarding' && h('div', null,
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
h('
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
)
|
|
2977
|
-
),
|
|
2978
|
-
h('div', { className: 'card-body' },
|
|
2979
|
-
h('div', { style: { display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 } },
|
|
2980
|
-
onboardingStatus?.onboarded
|
|
2981
|
-
? h('span', { className: 'badge badge-success' }, I.check(), ' Onboarded')
|
|
2982
|
-
: h('span', { className: 'badge badge-warning' }, 'Not Onboarded'),
|
|
2983
|
-
onboardingStatus?.status && h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Status: ' + onboardingStatus.status),
|
|
2984
|
-
onboardingStatus?.completedAt && h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Completed: ' + new Date(onboardingStatus.completedAt).toLocaleString())
|
|
2985
|
-
)
|
|
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')
|
|
2986
3128
|
)
|
|
2987
3129
|
),
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
h('
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
)
|
|
3000
|
-
),
|
|
3001
|
-
h('tbody', null,
|
|
3002
|
-
onboardingProgress.map(function(p, i) {
|
|
3003
|
-
var pStatus = p.status || 'pending';
|
|
3004
|
-
var statusColor = pStatus === 'acknowledged' || pStatus === 'completed' ? 'badge-success' : pStatus === 'in_progress' ? 'badge-info' : 'badge-warning';
|
|
3005
|
-
|
|
3006
|
-
return h('tr', { key: p.id || i },
|
|
3007
|
-
h('td', { style: { fontWeight: 500, fontSize: 13 } }, p.policyName || p.name || p.policyId || '-'),
|
|
3008
|
-
h('td', null, h('span', { className: 'badge ' + statusColor }, pStatus)),
|
|
3009
|
-
h('td', { style: { fontSize: 12, color: 'var(--text-muted)' } }, p.acknowledgedAt ? new Date(p.acknowledgedAt).toLocaleString() : '-')
|
|
3010
|
-
);
|
|
3011
|
-
})
|
|
3012
|
-
)
|
|
3013
|
-
)
|
|
3014
|
-
)
|
|
3015
|
-
),
|
|
3016
|
-
|
|
3017
|
-
// Pending Policies
|
|
3018
|
-
pendingPolicies.length > 0 && h('div', { className: 'card', style: { marginBottom: 20 } },
|
|
3019
|
-
h('div', { className: 'card-header' }, h('span', null, 'Pending Policies')),
|
|
3020
|
-
h('div', { className: 'card-body' },
|
|
3021
|
-
h('div', { style: { display: 'grid', gap: 8 } },
|
|
3022
|
-
pendingPolicies.map(function(p, i) {
|
|
3023
|
-
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)' } },
|
|
3024
|
-
h('span', { className: 'badge badge-warning' }, 'Pending'),
|
|
3025
|
-
h('span', { style: { fontSize: 13, fontWeight: 500 } }, p.name || p.policyName || p.policyId || 'Unnamed Policy'),
|
|
3026
|
-
p.category && h('span', { className: 'badge badge-neutral', style: { fontSize: 11 } }, p.category)
|
|
3027
|
-
);
|
|
3028
|
-
})
|
|
3029
|
-
)
|
|
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
|
+
})
|
|
3030
3141
|
)
|
|
3031
3142
|
)
|
|
3032
3143
|
),
|
|
3033
3144
|
|
|
3034
3145
|
// ─── Approvals Tab ──────────────────────────────────
|
|
3035
3146
|
subTab === 'approvals' && h('div', null,
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
),
|
|
3051
|
-
h('div', { style: { fontSize: 13, color: 'var(--text-secondary)', marginBottom: 12 } }, a.description || a.reason || 'No description'),
|
|
3052
|
-
h('div', { style: { display: 'flex', gap: 8 } },
|
|
3053
|
-
h('button', { className: 'btn btn-primary btn-sm', onClick: function() { approveRequest(a.id); } }, I.check(), ' Approve'),
|
|
3054
|
-
h('button', { className: 'btn btn-danger btn-sm', onClick: function() { rejectRequest(a.id); } }, I.x(), ' Reject')
|
|
3055
|
-
)
|
|
3056
|
-
);
|
|
3057
|
-
})
|
|
3058
|
-
)
|
|
3059
|
-
)
|
|
3060
|
-
: h('div', { className: 'card-body' },
|
|
3061
|
-
h('div', { style: { textAlign: 'center', padding: 20, color: 'var(--text-muted)', fontSize: 13 } }, 'No pending approvals.')
|
|
3062
|
-
)
|
|
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
|
+
)
|
|
3063
3161
|
),
|
|
3064
|
-
|
|
3065
|
-
// Approval History
|
|
3066
|
-
h('div', { className: 'card', style: { marginBottom: 20 } },
|
|
3162
|
+
h('div', { className: 'card' },
|
|
3067
3163
|
h('div', { className: 'card-header' }, h('span', null, 'Approval History')),
|
|
3068
3164
|
approvalHistory.length > 0
|
|
3069
|
-
? h('div', {
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
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); })
|
|
3093
3210
|
)
|
|
3094
3211
|
)
|
|
3095
|
-
|
|
3096
|
-
|
|
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')
|
|
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 })); } })
|
|
3246
|
+
)
|
|
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 })); } })
|
|
3097
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
|
+
)
|
|
3098
3268
|
)
|
|
3099
3269
|
)
|
|
3100
3270
|
);
|
|
3101
3271
|
}
|
|
3102
|
-
|
|
3103
|
-
// ════════════════════════════════════════════════════════════
|
|
3104
|
-
// CONFIGURATION SECTION — Model, Description, Soul, General
|
|
3105
|
-
// ════════════════════════════════════════════════════════════
|
|
3106
|
-
|
|
3107
3272
|
function ConfigurationSection(props) {
|
|
3108
3273
|
var agentId = props.agentId;
|
|
3109
3274
|
var engineAgent = props.engineAgent;
|