${{ require: t('approval.action.require'), allow: t('approval.action.allow'), deny: t('approval.action.deny') }[rule.action] ?? rule.action}
${rule.tool_pattern}
${rule.priority}
${has(rule.path_pattern) ? html`
${rule.path_pattern}
` : ''}
${has(rule.source) ? html`${rule.source}` : ''}
${has(rule.agent_id) ? html`${rule.agent_id}` : ''}
${has(rule.note) ? html`${rule.note}` : ''}
`;
}
// ── 4-state chip group ────────────────────────────────────────────────────────
_renderChipGroup(currentAction, onChange) {
const chips = [
{ action: null, label: t('approval.chip.unset') },
{ action: 'allow', label: t('approval.action.allow') },
{ action: 'require', label: t('approval.chip.req') },
{ action: 'deny', label: t('approval.action.deny') },
];
return html`
${chips.map(({ action, label }) => {
const isActive = currentAction === action;
return html`
`;
})}
`;
}
// ── Tool row ─────────────────────────────────────────────────────────────────
_renderToolRow(tool) {
const action = this._getToolAction(tool.name);
const saving = this._toolSaving.has(tool.name);
return html`
${groups.length === 0
? html`
${t('approval.matrix.loading')}
`
: groups.map(([key, tools, desc]) => this._renderCategorySection(key, tools, desc))}
`;
}
// ── File System panel ─────────────────────────────────────────────────────────
_fsAccessLabel(key) {
return {
allow_read: t('approval.fs.allow_read'),
allow_write: t('approval.fs.allow_write'),
deny: t('approval.fs.deny'),
require: t('approval.fs.require'),
}[key] ?? key;
}
_renderFsAccessSelect(value, onChange, allowUnset) {
return html`
${isOpen ? html`
${rules.length === 0
? html`
${t('approval.fs.empty')}
`
: rules.map(r => this._renderFsRow(r))}
${this._renderFsAddRow()}
${t('approval.fs.default_label')} ${t('approval.fs.default_hint')}
${this._renderFsAccessSelect(defValue, (v) => this._setFsDefault(v), true)}
` : nothing}
`;
}
// ── Side panel (Override / LowPrio) ──────────────────────────────────────────
_renderSidePanel(panelKey, title, icon, subtitle, rules, isOpen, onToggle, onAdd) {
const formActive = this._editingId !== null && this._formMode === panelKey;
return html`
${t('approval.default_bar.title')}
${t('approval.default_bar.hint')}
${this._renderChipGroup(action, (a) => this._setDefaultAction(a))}
${action === null
? html`
${t('approval.default_bar.unset')}`
: nothing}
`;
}
// ── Rules view ────────────────────────────────────────────────────────────────
render() {
if (!this._selectedGroup) return nothing;
const group = this._selectedGroup;
const isDefault = group.id === 'default';
const { overrides, lowPrio } = this._buckets(group.id);
const totalRules = this._rulesForGroup(group.id).length;
return html`
${this._error ? html`
${this._error}
` : nothing}
${this._renderSidePanel(
'override',
t('approval.sidebar.overrides'),
'bi-exclamation-triangle-fill',
t('approval.sidebar.overrides_sub'),
overrides,
this._overrideOpen,
() => { this._overrideOpen = !this._overrideOpen; },
() => this._startNew('override')
)}
${this._renderFsPanel()}
${this._renderToolMatrix()}
${this._renderSidePanel(
'lowprio',
t('approval.sidebar.lowprio'),
'bi-arrow-down-circle-fill',
t('approval.sidebar.lowprio_sub'),
lowPrio,
this._lowPrioOpen,
() => { this._lowPrioOpen = !this._lowPrioOpen; },
() => this._startNew('lowprio')
)}
${this._renderDefaultActionBar()}
`;
}
}