Add facilities, contracts, orders, value lists, audit log, and desktop app modules

Extends omsorgCore with full CRUD for Facility/Contract/Order plus
configurable value lists and an audit trail, and wires the omsorgapp
frontend up to the new facilities, settings, and audit-log modules;
includes a sidebar active-nav-item highlight.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Felix Kemmler
2026-08-08 23:29:16 +02:00
co-authored by Claude Sonnet 5
parent ee74ed65f5
commit e9e96a57dc
528 changed files with 96814 additions and 456 deletions
@@ -0,0 +1,34 @@
const { Configuration } = require('omsorgcore-client-ts');
const { API_BASE } = require('./config.cjs');
// Baut die Configuration für eine generierte *Api-Klasse (omsorgcore-client-ts).
// Einzige Stelle, die API_BASE mit dem generierten Client verbindet.
function configFor(accessToken) {
return new Configuration({ basePath: API_BASE, accessToken });
}
// Wandelt den Aufruf einer generierten `...Raw()`-Methode in denselben
// Vertrag um, den vorher httpClient.request(...) lieferte: { ok, status, data, error? }.
// Generierte Clients werfen bei Nicht-2xx eine ResponseError-Exception statt ein
// Ergebnisobjekt zurückzugeben - das fangen wir hier zentral ab.
async function callApi(rawPromise) {
try {
const response = await rawPromise;
const data = await response.value();
return { ok: true, status: response.raw.status, data: data === undefined ? null : data };
} catch (err) {
if (err && err.name === 'ResponseError') {
const status = err.response.status;
let data = null;
try {
data = await err.response.json();
} catch {
data = null;
}
return { ok: false, status, data };
}
return { ok: false, status: 0, data: null, error: err && err.message };
}
}
module.exports = { configFor, callApi };
@@ -0,0 +1,25 @@
const { AuditLogApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt GET /api/audit-log (AuditLogController) über den generierten Client
// (omsorgcore-client-ts) - rein lesend, keine weiteren Verben.
async function listAuditLog(
accessToken,
{ page = 1, pageSize = 50, entityType, entityId, actorUserId, category, fromUtc, toUtc } = {}
) {
const api = new AuditLogApi(configFor(accessToken));
return callApi(
api.apiAuditLogGetRaw({
page,
pageSize,
entityType: entityType || undefined,
entityId: entityId || undefined,
actorUserId: actorUserId || undefined,
category: category || undefined,
fromUtc: fromUtc ? new Date(fromUtc) : undefined,
toUtc: toUtc ? new Date(toUtc) : undefined,
})
);
}
module.exports = { listAuditLog };
+31 -16
View File
@@ -1,7 +1,9 @@
const { request } = require('./httpClient.cjs');
const { AuthApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/auth/* von omsorgCore. Kennt die Feldnamen der LoginResponse
// (camelCase, da ASP.NET Core standardmäßig camelCase-JSON ausgibt).
// Kapselt /api/auth/* von omsorgCore über den generierten Client (omsorgcore-client-ts).
// Kennt die Feldnamen der LoginResponse (camelCase, da ASP.NET Core standardmäßig
// camelCase-JSON ausgibt).
function toTokenPair(data) {
return {
accessToken: data.accessToken,
@@ -12,7 +14,8 @@ function toTokenPair(data) {
}
async function login(username, password) {
const result = await request('POST', '/api/auth/login', { body: { username, password } });
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthLoginPostRaw({ loginRequest: { username, password } }));
if (!result.ok) {
return { ok: false, status: result.status, error: result.error || result.data?.error };
}
@@ -20,47 +23,58 @@ async function login(username, password) {
}
async function refresh(refreshToken) {
const result = await request('POST', '/api/auth/refresh', { body: { refreshToken } });
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthRefreshPostRaw({ refreshRequest: { refreshToken } }));
if (!result.ok) return { ok: false, status: result.status };
return { ok: true, ...toTokenPair(result.data) };
}
async function logout(refreshToken) {
const result = await request('POST', '/api/auth/logout', { body: { refreshToken } });
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthLogoutPostRaw({ logoutRequest: { refreshToken } }));
return { ok: result.ok, status: result.status };
}
async function me(accessToken) {
const result = await request('GET', '/api/auth/me', { accessToken });
const api = new AuthApi(configFor(accessToken));
const result = await callApi(api.apiAuthMeGetRaw());
if (!result.ok) return { ok: false, status: result.status };
return { ok: true, username: result.data.username, role: result.data.role, permissions: result.data.permissions };
}
async function requestPasswordReset(username) {
const result = await request('POST', '/api/auth/forgot-password/request', { body: { username } });
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthForgotPasswordRequestPostRaw({ forgotPasswordRequestRequest: { username } }));
if (!result.ok) return { ok: false, status: result.status };
return { ok: true, status: result.data.status };
}
async function verifyPasswordResetCode(username, pin) {
const result = await request('POST', '/api/auth/forgot-password/verify', { body: { username, pin } });
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthForgotPasswordVerifyPostRaw({ forgotPasswordVerifyRequest: { username, pin } }));
if (!result.ok) return { ok: false, status: result.status, error: result.data?.error };
return { ok: true, resetToken: result.data.resetToken };
}
async function resetPassword(resetToken, newPassword) {
const result = await request('POST', '/api/auth/forgot-password/reset', { body: { resetToken, newPassword } });
return { ok: result.ok, status: result.status };
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthForgotPasswordResetPostRaw({ forgotPasswordResetRequest: { resetToken, newPassword } }));
return { ok: result.ok, status: result.status, data: result.data };
}
async function changePassword(accessToken, currentPassword, newPassword) {
const result = await request('POST', '/api/auth/change-password', {
body: { currentPassword, newPassword },
accessToken
});
const api = new AuthApi(configFor(accessToken));
const result = await callApi(api.apiAuthChangePasswordPostRaw({ changePasswordRequest: { currentPassword, newPassword } }));
return { ok: result.ok, status: result.status, data: result.data };
}
async function getPasswordPolicy() {
const api = new AuthApi(configFor(undefined));
const result = await callApi(api.apiAuthPasswordPolicyGetRaw());
if (!result.ok) return { ok: false, status: result.status };
return { ok: true, minLength: result.data.minLength };
}
module.exports = {
login,
refresh,
@@ -69,5 +83,6 @@ module.exports = {
requestPasswordReset,
verifyPasswordResetCode,
resetPassword,
changePassword
changePassword,
getPasswordPolicy
};
+13 -14
View File
@@ -1,28 +1,27 @@
const { request } = require('./httpClient.cjs');
const { EmployeesApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/employees von omsorgCore (EmployeesController). Feldnamen sind
// camelCase, da ASP.NET Core standardmäßig camelCase-JSON ausgibt.
// Kapselt /api/employees von omsorgCore (EmployeesController) über den generierten
// Client (omsorgcore-client-ts). Feldnamen sind camelCase, da ASP.NET Core
// standardmäßig camelCase-JSON ausgibt.
async function listEmployees(accessToken, { search, status, employmentType, page = 1, pageSize = 20 } = {}) {
const params = new URLSearchParams();
if (search) params.set('search', search);
if (status) params.set('status', status);
if (employmentType) params.set('employmentType', employmentType);
params.set('page', page);
params.set('pageSize', pageSize);
return request('GET', `/api/employees?${params.toString()}`, { accessToken });
const api = new EmployeesApi(configFor(accessToken));
return callApi(api.apiEmployeesGetRaw({ search, status, employmentType, page, pageSize }));
}
async function createEmployee(accessToken, payload) {
return request('POST', '/api/employees', { body: payload, accessToken });
const api = new EmployeesApi(configFor(accessToken));
return callApi(api.apiEmployeesPostRaw({ createEmployeeRequest: payload }));
}
async function getEmployee(accessToken, id) {
return request('GET', `/api/employees/${id}`, { accessToken });
const api = new EmployeesApi(configFor(accessToken));
return callApi(api.apiEmployeesIdGetRaw({ id }));
}
async function updateEmployee(accessToken, id, payload) {
return request('PUT', `/api/employees/${id}`, { body: payload, accessToken });
const api = new EmployeesApi(configFor(accessToken));
return callApi(api.apiEmployeesIdPutRaw({ id, updateEmployeeRequest: payload }));
}
module.exports = { listEmployees, createEmployee, getEmployee, updateEmployee };
@@ -0,0 +1,27 @@
const { FacilitiesApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/facilities von omsorgCore (FacilitiesController) über den generierten
// Client (omsorgcore-client-ts). Feldnamen sind camelCase, da ASP.NET Core
// standardmäßig camelCase-JSON ausgibt.
async function listFacilities(accessToken, { search, crmStatus, page = 1, pageSize = 20 } = {}) {
const api = new FacilitiesApi(configFor(accessToken));
return callApi(api.apiFacilitiesGetRaw({ search, crmStatus, page, pageSize }));
}
async function createFacility(accessToken, payload) {
const api = new FacilitiesApi(configFor(accessToken));
return callApi(api.apiFacilitiesPostRaw({ createFacilityRequest: payload }));
}
async function getFacility(accessToken, id) {
const api = new FacilitiesApi(configFor(accessToken));
return callApi(api.apiFacilitiesIdGetRaw({ id }));
}
async function updateFacility(accessToken, id, payload) {
const api = new FacilitiesApi(configFor(accessToken));
return callApi(api.apiFacilitiesIdPutRaw({ id, updateFacilityRequest: payload }));
}
module.exports = { listFacilities, createFacility, getFacility, updateFacility };
@@ -0,0 +1,22 @@
const { FacilityContactsApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/facilities/{facilityId}/contacts von omsorgCore (FacilityContactsController)
// über den generierten Client (omsorgcore-client-ts). Ansprechpartner sind eine
// 1:n-Unterressource von Facility, kein eigenständiger Endpunkt.
async function listFacilityContacts(accessToken, facilityId) {
const api = new FacilityContactsApi(configFor(accessToken));
return callApi(api.apiFacilitiesFacilityIdContactsGetRaw({ facilityId }));
}
async function createFacilityContact(accessToken, facilityId, payload) {
const api = new FacilityContactsApi(configFor(accessToken));
return callApi(api.apiFacilitiesFacilityIdContactsPostRaw({ facilityId, createFacilityContactRequest: payload }));
}
async function updateFacilityContact(accessToken, facilityId, id, payload) {
const api = new FacilityContactsApi(configFor(accessToken));
return callApi(api.apiFacilitiesFacilityIdContactsIdPutRaw({ facilityId, id, updateFacilityContactRequest: payload }));
}
module.exports = { listFacilityContacts, createFacilityContact, updateFacilityContact };
@@ -0,0 +1,26 @@
const { RolesApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/roles von omsorgCore (RolesController) über den generierten Client
// (omsorgcore-client-ts).
async function listRoles(accessToken) {
const api = new RolesApi(configFor(accessToken));
return callApi(api.apiRolesGetRaw());
}
async function getRole(accessToken, roleId) {
const api = new RolesApi(configFor(accessToken));
return callApi(api.apiRolesIdGetRaw({ id: roleId }));
}
async function createRole(accessToken, payload) {
const api = new RolesApi(configFor(accessToken));
return callApi(api.apiRolesPostRaw({ createRoleRequest: payload }));
}
async function updateRolePermissions(accessToken, roleId, payload) {
const api = new RolesApi(configFor(accessToken));
return callApi(api.apiRolesIdPermissionsPutRaw({ id: roleId, updateRolePermissionsRequest: payload }));
}
module.exports = { listRoles, getRole, createRole, updateRolePermissions };
+30 -5
View File
@@ -1,12 +1,37 @@
const { request } = require('./httpClient.cjs');
const { UsersApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/users von omsorgCore (UsersController).
// Kapselt /api/users von omsorgCore (UsersController) über den generierten Client
// (omsorgcore-client-ts).
async function listUsers(accessToken) {
return request('GET', '/api/users', { accessToken });
const api = new UsersApi(configFor(accessToken));
return callApi(api.apiUsersGetRaw());
}
async function createUser(accessToken, payload) {
return request('POST', '/api/users', { body: payload, accessToken });
const api = new UsersApi(configFor(accessToken));
return callApi(api.apiUsersPostRaw({ createUserRequest: payload }));
}
module.exports = { listUsers, createUser };
async function listPermissionOverrides(accessToken, userId) {
const api = new UsersApi(configFor(accessToken));
return callApi(api.apiUsersIdPermissionOverridesGetRaw({ id: userId }));
}
async function addPermissionOverride(accessToken, userId, payload) {
const api = new UsersApi(configFor(accessToken));
return callApi(api.apiUsersIdPermissionOverridesPostRaw({ id: userId, addUserPermissionOverrideRequest: payload }));
}
async function deletePermissionOverride(accessToken, userId, overrideId) {
const api = new UsersApi(configFor(accessToken));
return callApi(api.apiUsersIdPermissionOverridesOverrideIdDeleteRaw({ id: userId, overrideId }));
}
module.exports = {
listUsers,
createUser,
listPermissionOverrides,
addPermissionOverride,
deletePermissionOverride
};
@@ -0,0 +1,56 @@
const { ValueListsApi } = require('omsorgcore-client-ts');
const { configFor, callApi } = require('./apiClientHelpers.cjs');
// Kapselt /api/value-lists von omsorgCore (ValueListsController) über den generierten
// Client (omsorgcore-client-ts) - konfigurierbare Auswahllisten (Mitarbeiterstatus,
// Beschäftigungsart, CRM-Status, Einrichtungstyp, Vertragstyp/-status, Auftragsstatus).
async function listValueLists(accessToken) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsGetRaw());
}
async function listItems(accessToken, key) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyItemsGetRaw({ key }));
}
async function createItem(accessToken, key, payload) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyItemsPostRaw({ key, createValueListItemRequest: payload }));
}
async function updateItem(accessToken, key, id, payload) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyItemsIdPutRaw({ key, id, updateValueListItemRequest: payload }));
}
async function deleteItem(accessToken, key, id) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyItemsIdDeleteRaw({ key, id }));
}
async function getUsages(accessToken, key, id) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyItemsIdUsagesGetRaw({ key, id }));
}
async function listTransitions(accessToken, key) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyTransitionsGetRaw({ key }));
}
async function replaceTransitions(accessToken, key, payload) {
const api = new ValueListsApi(configFor(accessToken));
return callApi(api.apiValueListsKeyTransitionsPutRaw({ key, valueListTransitionRequest: payload }));
}
module.exports = {
listValueLists,
listItems,
createItem,
updateItem,
deleteItem,
getUsages,
listTransitions,
replaceTransitions
};
+98 -54
View File
@@ -1,10 +1,15 @@
const { app, BrowserWindow, ipcMain, shell, safeStorage } = require('electron');
const { app, BrowserWindow, ipcMain, safeStorage } = require('electron');
const path = require('path');
const fs = require('fs');
const authClient = require('./backend/authClient.cjs');
const httpClient = require('./backend/httpClient.cjs');
const employeesClient = require('./backend/employeesClient.cjs');
const facilitiesClient = require('./backend/facilitiesClient.cjs');
const facilityContactsClient = require('./backend/facilityContactsClient.cjs');
const usersClient = require('./backend/usersClient.cjs');
const rolesClient = require('./backend/rolesClient.cjs');
const auditLogClient = require('./backend/auditLogClient.cjs');
const valueListsClient = require('./backend/valueListsClient.cjs');
app.commandLine.appendSwitch('lang', 'de');
@@ -144,44 +149,6 @@ function authorizedRequest(method, resourcePath, body) {
return withAuthRetry((accessToken) => httpClient.request(method, resourcePath, { body, accessToken }));
}
function ensureDir(dir) { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); }
function appRoot() {
const base = path.join(app.getPath('documents'), 'Omsorg Business Controls Pro');
ensureDir(base);
ensureDir(path.join(base, 'database'));
ensureDir(path.join(base, 'documents'));
ensureDir(path.join(base, 'documents', 'employees'));
ensureDir(path.join(base, 'documents', 'customers'));
ensureDir(path.join(base, 'backups'));
return base;
}
function dbPath() { return path.join(appRoot(), 'database', 'omsorg-local-db.json'); }
function defaultData() {
return {
version: '0.1.1',
createdAt: new Date().toISOString(),
users: [
{ id:'u1', name:'Sabina Dautovic', role:'Geschäftsführung' },
{ id:'u2', name:'Malik Neumann', role:'Geschäftsführung' },
{ id:'u3', name:'Sabrina Berggötz', role:'Disposition' }
],
employees: [
{ id:'e1', name:'Dirk Artmann', qualification:'3-jährige Pflegefachkraft', status:'Aktiv' },
{ id:'e2', name:'Carina Vetter', qualification:'3-jährige Pflegefachkraft', status:'Aktiv' },
{ id:'e3', name:'Dilara Anders', qualification:'1-jährige Pflegekraft', status:'Aktiv' },
{ id:'e4', name:'Pascal Galliot', qualification:'1-jährige Pflegekraft', status:'Aktiv' }
],
customers: [],
assignments: [],
notes: []
};
}
function readDb() {
const file = dbPath();
if (!fs.existsSync(file)) fs.writeFileSync(file, JSON.stringify(defaultData(), null, 2));
return JSON.parse(fs.readFileSync(file, 'utf-8'));
}
function writeDb(data) { fs.writeFileSync(dbPath(), JSON.stringify(data, null, 2)); return data; }
function createWindow() {
mainWindow = new BrowserWindow({
width: 1440,
@@ -200,7 +167,6 @@ function createWindow() {
else mainWindow.loadFile(path.join(__dirname, '../dist/index.html'));
}
app.whenReady().then(async () => {
appRoot();
createWindow();
await bootstrapSession();
broadcastSession();
@@ -208,18 +174,6 @@ app.whenReady().then(async () => {
app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });
ipcMain.handle('db:get', () => readDb());
ipcMain.handle('db:set', (_event, data) => writeDb(data));
ipcMain.handle('app:paths', () => ({ root: appRoot(), db: dbPath() }));
ipcMain.handle('app:openRoot', () => shell.openPath(appRoot()));
ipcMain.handle('backup:create', () => {
const root = appRoot();
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupFile = path.join(root, 'backups', `backup-${stamp}.json`);
fs.copyFileSync(dbPath(), backupFile);
return backupFile;
});
ipcMain.handle('auth:login', async (_event, { username, password }) => {
const result = await authClient.login(username, password);
if (!result.ok) {
@@ -263,7 +217,17 @@ ipcMain.handle('auth:verifyPasswordResetCode', async (_event, { username, pin })
ipcMain.handle('auth:resetPassword', async (_event, { resetToken, newPassword }) => {
const result = await authClient.resetPassword(resetToken, newPassword);
return { success: result.ok };
if (!result.ok) {
const error = result.status === 400
? 'password_too_short'
: 'invalid_or_expired';
return {
success: false,
error,
message: result.status === 400 && typeof result.data === 'string' ? result.data : undefined
};
}
return { success: true };
});
// Erfolgreicher Wechsel widerruft serverseitig alle Sessions (siehe UserService.ChangeOwnPasswordAsync) -
@@ -272,12 +236,27 @@ ipcMain.handle('auth:changePassword', async (_event, { currentPassword, newPassw
if (!session.accessToken) return { success: false, error: 'not_authenticated' };
const result = await authClient.changePassword(session.accessToken, currentPassword, newPassword);
if (!result.ok) {
return { success: false, error: result.status === 401 ? 'invalid_current_password' : 'unknown' };
const error = result.status === 401
? 'invalid_current_password'
: result.status === 400
? 'password_too_short'
: 'unknown';
return {
success: false,
error,
message: result.status === 400 && typeof result.data === 'string' ? result.data : undefined
};
}
clearSession();
return { success: true };
});
ipcMain.handle('auth:getPasswordPolicy', async () => {
const result = await authClient.getPasswordPolicy();
if (!result.ok) return { success: false };
return { success: true, minLength: result.minLength };
});
// Generischer Proxy für Ressourcen ohne eigene <kategorie>Client.cjs-Datei (siehe Plan).
ipcMain.handle('api:get', (_event, resourcePath) => authorizedRequest('GET', resourcePath));
ipcMain.handle('api:post', (_event, resourcePath, body) => authorizedRequest('POST', resourcePath, body));
@@ -290,7 +269,72 @@ ipcMain.handle('employees:update', (_event, id, payload) =>
withAuthRetry((accessToken) => employeesClient.updateEmployee(accessToken, id, payload))
);
ipcMain.handle('facilities:list', (_event, params) => withAuthRetry((accessToken) => facilitiesClient.listFacilities(accessToken, params)));
ipcMain.handle('facilities:create', (_event, payload) =>
withAuthRetry((accessToken) => facilitiesClient.createFacility(accessToken, payload))
);
ipcMain.handle('facilities:update', (_event, id, payload) =>
withAuthRetry((accessToken) => facilitiesClient.updateFacility(accessToken, id, payload))
);
ipcMain.handle('facilityContacts:list', (_event, facilityId) =>
withAuthRetry((accessToken) => facilityContactsClient.listFacilityContacts(accessToken, facilityId))
);
ipcMain.handle('facilityContacts:create', (_event, facilityId, payload) =>
withAuthRetry((accessToken) => facilityContactsClient.createFacilityContact(accessToken, facilityId, payload))
);
ipcMain.handle('facilityContacts:update', (_event, facilityId, id, payload) =>
withAuthRetry((accessToken) => facilityContactsClient.updateFacilityContact(accessToken, facilityId, id, payload))
);
ipcMain.handle('users:list', () => withAuthRetry((accessToken) => usersClient.listUsers(accessToken)));
ipcMain.handle('users:create', (_event, payload) =>
withAuthRetry((accessToken) => usersClient.createUser(accessToken, payload))
);
ipcMain.handle('users:listPermissionOverrides', (_event, userId) =>
withAuthRetry((accessToken) => usersClient.listPermissionOverrides(accessToken, userId))
);
ipcMain.handle('users:addPermissionOverride', (_event, userId, payload) =>
withAuthRetry((accessToken) => usersClient.addPermissionOverride(accessToken, userId, payload))
);
ipcMain.handle('users:deletePermissionOverride', (_event, userId, overrideId) =>
withAuthRetry((accessToken) => usersClient.deletePermissionOverride(accessToken, userId, overrideId))
);
ipcMain.handle('roles:list', () => withAuthRetry((accessToken) => rolesClient.listRoles(accessToken)));
ipcMain.handle('roles:get', (_event, roleId) =>
withAuthRetry((accessToken) => rolesClient.getRole(accessToken, roleId))
);
ipcMain.handle('roles:create', (_event, payload) =>
withAuthRetry((accessToken) => rolesClient.createRole(accessToken, payload))
);
ipcMain.handle('roles:updatePermissions', (_event, roleId, payload) =>
withAuthRetry((accessToken) => rolesClient.updateRolePermissions(accessToken, roleId, payload))
);
ipcMain.handle('auditLog:list', (_event, params) =>
withAuthRetry((accessToken) => auditLogClient.listAuditLog(accessToken, params))
);
ipcMain.handle('valueLists:list', () => withAuthRetry((accessToken) => valueListsClient.listValueLists(accessToken)));
ipcMain.handle('valueLists:listItems', (_event, key) =>
withAuthRetry((accessToken) => valueListsClient.listItems(accessToken, key))
);
ipcMain.handle('valueLists:createItem', (_event, key, payload) =>
withAuthRetry((accessToken) => valueListsClient.createItem(accessToken, key, payload))
);
ipcMain.handle('valueLists:updateItem', (_event, key, id, payload) =>
withAuthRetry((accessToken) => valueListsClient.updateItem(accessToken, key, id, payload))
);
ipcMain.handle('valueLists:deleteItem', (_event, key, id) =>
withAuthRetry((accessToken) => valueListsClient.deleteItem(accessToken, key, id))
);
ipcMain.handle('valueLists:getUsages', (_event, key, id) =>
withAuthRetry((accessToken) => valueListsClient.getUsages(accessToken, key, id))
);
ipcMain.handle('valueLists:listTransitions', (_event, key) =>
withAuthRetry((accessToken) => valueListsClient.listTransitions(accessToken, key))
);
ipcMain.handle('valueLists:replaceTransitions', (_event, key, payload) =>
withAuthRetry((accessToken) => valueListsClient.replaceTransitions(accessToken, key, payload))
);
+36 -7
View File
@@ -1,10 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('omsorg', {
getDb: () => ipcRenderer.invoke('db:get'),
setDb: (data) => ipcRenderer.invoke('db:set', data),
paths: () => ipcRenderer.invoke('app:paths'),
openRoot: () => ipcRenderer.invoke('app:openRoot'),
createBackup: () => ipcRenderer.invoke('backup:create'),
auth: {
login: (username, password) => ipcRenderer.invoke('auth:login', { username, password }),
logout: () => ipcRenderer.invoke('auth:logout'),
@@ -18,7 +13,8 @@ contextBridge.exposeInMainWorld('omsorg', {
verifyPasswordResetCode: (username, pin) => ipcRenderer.invoke('auth:verifyPasswordResetCode', { username, pin }),
resetPassword: (resetToken, newPassword) => ipcRenderer.invoke('auth:resetPassword', { resetToken, newPassword }),
changePassword: (currentPassword, newPassword) =>
ipcRenderer.invoke('auth:changePassword', { currentPassword, newPassword })
ipcRenderer.invoke('auth:changePassword', { currentPassword, newPassword }),
getPasswordPolicy: () => ipcRenderer.invoke('auth:getPasswordPolicy')
},
api: {
get: (path) => ipcRenderer.invoke('api:get', path),
@@ -29,8 +25,41 @@ contextBridge.exposeInMainWorld('omsorg', {
create: (payload) => ipcRenderer.invoke('employees:create', payload),
update: (id, payload) => ipcRenderer.invoke('employees:update', id, payload)
},
facilities: {
list: (params) => ipcRenderer.invoke('facilities:list', params),
create: (payload) => ipcRenderer.invoke('facilities:create', payload),
update: (id, payload) => ipcRenderer.invoke('facilities:update', id, payload)
},
facilityContacts: {
list: (facilityId) => ipcRenderer.invoke('facilityContacts:list', facilityId),
create: (facilityId, payload) => ipcRenderer.invoke('facilityContacts:create', facilityId, payload),
update: (facilityId, id, payload) => ipcRenderer.invoke('facilityContacts:update', facilityId, id, payload)
},
users: {
list: () => ipcRenderer.invoke('users:list'),
create: (payload) => ipcRenderer.invoke('users:create', payload)
create: (payload) => ipcRenderer.invoke('users:create', payload),
listPermissionOverrides: (userId) => ipcRenderer.invoke('users:listPermissionOverrides', userId),
addPermissionOverride: (userId, payload) => ipcRenderer.invoke('users:addPermissionOverride', userId, payload),
deletePermissionOverride: (userId, overrideId) =>
ipcRenderer.invoke('users:deletePermissionOverride', userId, overrideId)
},
roles: {
list: () => ipcRenderer.invoke('roles:list'),
get: (roleId) => ipcRenderer.invoke('roles:get', roleId),
create: (payload) => ipcRenderer.invoke('roles:create', payload),
updatePermissions: (roleId, payload) => ipcRenderer.invoke('roles:updatePermissions', roleId, payload)
},
auditLog: {
list: (params) => ipcRenderer.invoke('auditLog:list', params)
},
valueLists: {
list: () => ipcRenderer.invoke('valueLists:list'),
listItems: (key) => ipcRenderer.invoke('valueLists:listItems', key),
createItem: (key, payload) => ipcRenderer.invoke('valueLists:createItem', key, payload),
updateItem: (key, id, payload) => ipcRenderer.invoke('valueLists:updateItem', key, id, payload),
deleteItem: (key, id) => ipcRenderer.invoke('valueLists:deleteItem', key, id),
getUsages: (key, id) => ipcRenderer.invoke('valueLists:getUsages', key, id),
listTransitions: (key) => ipcRenderer.invoke('valueLists:listTransitions', key),
replaceTransitions: (key, payload) => ipcRenderer.invoke('valueLists:replaceTransitions', key, payload)
}
});