/* ============================================================
KODILA — Admin: Pravice
============================================================ */
const PERMISSION_MODULES = [
{ key: 'sifranti', label: 'Šifranti' },
{ key: 'dokumenti', label: 'Dokumenti' },
{ key: 'admin', label: 'Admin panel' },
{ key: 'aplikacije', label: 'Aplikacije' },
];
function emptyPermissionMap(value) {
const map = {};
PERMISSION_MODULES.forEach(m => { map[m.key] = value; });
return map;
}
function permissionCheckboxCol(mod) {
return {
field: mod.key, headerName: mod.label, width: 130,
cellRenderer: 'agCheckboxCellRenderer', cellEditor: 'agCheckboxCellEditor',
editable: true, sortable: false, filter: false,
};
}
const PRAVICE_COLS = [
{ field: 'id', headerName: 'ID', width: 70, cellClass: 'cell-mono', pinned: 'left' },
{ field: 'fullName', headerName: 'Ime in priimek', flex: 2, minWidth: 200, cellRenderer: userNameRenderer },
{ field: 'email', headerName: 'E-pošta', minWidth: 190 },
{ field: 'groupName', headerName: 'Skupina', minWidth: 150, valueFormatter: p => p.value || 'Brez skupine' },
...PERMISSION_MODULES.map(permissionCheckboxCol),
];
/* --- Pravice po uporabnikih --- */
function PraviceUporabniki() {
const toast = useToast();
const [rows, setRows] = useState([]);
const [loading, setLoading] = useState(true);
const [selected, setSelected] = useState([]);
const load = async () => {
setLoading(true);
const { ok, data } = await api('/api/permissions');
if (ok) {
setRows(data.users.map(u => ({ ...u, ...u.permissions })));
} else {
toast('Pravic ni bilo mogoče naložiti.', 'alert');
}
setLoading(false);
};
useEffect(() => { load(); }, []);
const applyResult = (data) => {
setRows(rs => rs.map(r => r.id === data.user.id
? { ...r, groupId: data.user.groupId, groupName: data.user.groupName, ...data.user.permissions }
: r));
};
const persist = async (userId, permissions) => {
const { ok, data } = await api(`/api/permissions/users/${userId}`, { method: 'PUT', body: JSON.stringify({ permissions }) });
if (!ok) {
toast('Napaka pri shranjevanju pravic.', 'alert');
return;
}
applyResult(data);
};
const onCellValueChanged = (p) => {
const field = p.colDef.field;
if (!PERMISSION_MODULES.some(m => m.key === field)) return;
const map = {};
PERMISSION_MODULES.forEach(m => { map[m.key] = m.key === field ? !!p.newValue : !!p.data[m.key]; });
persist(p.data.id, map);
};
const bulkApply = async (grant) => {
if (!selected.length) return;
const map = emptyPermissionMap(grant);
for (const row of selected) {
await persist(row.id, map);
}
toast(grant ? 'Vse pravice dodeljene' : 'Vse pravice ponastavljene', grant ? 'check' : 'x');
};
return (
{loading
?
Nalaganje …
: (
d.id}
selectable
exportName="kodila-pravice"
exportTitle="Pravice uporabnikov"
searchPlaceholder="Išči po imenu, e-pošti…"
onCellValueChanged={onCellValueChanged}
onSelectionChange={setSelected}
actions={
<>
>
}
/>
)}
);
}
/* --- Vnosni obrazec skupine (drawer) --- */
function GroupForm({ initial, onSave, onClose }) {
const isEdit = !!(initial && initial.id);
const [name, setName] = useState(initial && initial.id ? initial.name : '');
const [perms, setPerms] = useState(initial && initial.permissions ? { ...initial.permissions } : emptyPermissionMap(false));
const [errors, setErrors] = useState({});
const [saving, setSaving] = useState(false);
const togglePerm = (key) => setPerms(p => ({ ...p, [key]: !p[key] }));
const save = async () => {
setSaving(true);
const ok = await onSave(isEdit ? initial.id : null, { name: name.trim(), permissions: perms }, isEdit, setErrors);
setSaving(false);
if (ok) onClose();
};
const fieldError = (field) => {
const codes = errors[field];
if (!codes || !codes.length) return null;
if (codes.includes('taken')) return 'Skupina s tem imenom že obstaja.';
if (codes.includes('required')) return 'Ime skupine je obvezno.';
return codes.join(', ');
};
return (
{ if (e.target.classList.contains('overlay')) onClose(); }}>
e.stopPropagation()}>
{isEdit ? 'Uredi skupino' : 'Nova skupina'}
Uporabniška skupina in nabor pravic
Osnovni podatki
setName(e.target.value)}
placeholder="npr. Prodaja"
style={fieldError('name') ? { borderColor: 'var(--danger)' } : null} />
{fieldError('name') && {fieldError('name')}}
Pravice
{PERMISSION_MODULES.map(m => (
))}
* obvezna polja
);
}
/* --- Uporabniške skupine --- */
function PraviceSkupine() {
const toast = useToast();
const [groups, setGroups] = useState([]);
const [loading, setLoading] = useState(true);
const [editing, setEditing] = useState(null);
const load = async () => {
setLoading(true);
const { ok, data } = await api('/api/groups');
if (ok) setGroups(data.groups);
else toast('Skupin ni bilo mogoče naložiti.', 'alert');
setLoading(false);
};
useEffect(() => { load(); }, []);
const save = async (id, payload, isEdit, setErrors) => {
const { ok, data } = isEdit
? await api(`/api/groups/${id}`, { method: 'PUT', body: JSON.stringify(payload) })
: await api('/api/groups', { method: 'POST', body: JSON.stringify(payload) });
if (!ok) {
setErrors(data.errors || {});
return false;
}
setGroups(gs => isEdit ? gs.map(g => g.id === data.group.id ? data.group : g) : [...gs, data.group]);
toast(isEdit ? 'Skupina posodobljena' : 'Skupina ustvarjena: ' + data.group.name, 'check');
return true;
};
const remove = async (group) => {
if (!window.confirm(`Izbrišem skupino "${group.name}"? Uporabniki v tej skupini bodo prestavljeni na "Brez skupine".`)) return;
const { ok, data } = await api(`/api/groups/${group.id}/delete`, { method: 'POST' });
if (!ok) {
toast(data.error === 'system_group_locked' ? 'Sistemske skupine ni mogoče izbrisati.' : 'Brisanje ni uspelo.', 'alert');
return;
}
setGroups(gs => gs.filter(g => g.id !== group.id));
toast('Skupina izbrisana', 'trash');
};
return (
Predloge naborov pravic, ki jih lahko dodeliš uporabnikom v modulu Uporabniki.
{loading ? (
Nalaganje …
) : (
{groups.map(g => (
{g.name}
{g.isSystem &&
sistemska
}
{g.userCount} uporabnikov
{PERMISSION_MODULES.filter(m => g.permissions[m.key]).map(m => m.label).join(', ') || 'Brez pravic'}
))}
{groups.length === 0 &&
Ni ustvarjenih skupin.
}
)}
{editing !== null && (
setEditing(null)} />
)}
);
}
const PRAVICE_TABS = [
{ id: 'uporabniki', label: 'Pravice po uporabnikih' },
{ id: 'skupine', label: 'Uporabniške skupine' },
];
function Pravice({ currentUser }) {
const [tab, setTab] = useState(PRAVICE_TABS[0].id);
return (
{PRAVICE_TABS.map(t => (
))}
{tab === 'uporabniki' &&
}
{tab === 'skupine' &&
}
);
}
Object.assign(window, { Pravice });