dashboard widgets
This commit is contained in:
@@ -23,7 +23,15 @@ import {
|
||||
findOperation,
|
||||
providedFieldsFor,
|
||||
} from '../data/connectors.js';
|
||||
import {
|
||||
getLayout,
|
||||
hasCustomLayout,
|
||||
resetLayout,
|
||||
saveLayout,
|
||||
validateLayout,
|
||||
} from '../data/dashboardLayouts.js';
|
||||
import { collectScopes } from '../data/flowScope.js';
|
||||
import { widgets } from '../data/widgets.js';
|
||||
import { listIncidents } from '../data/incidentStore.js';
|
||||
import { getSummary } from '../data/mock.js';
|
||||
import { findPersonByEmail, listPeople } from '../data/people.js';
|
||||
@@ -78,6 +86,88 @@ dashboardRouter.get('/incidents', (_req, res) => {
|
||||
res.json({ items: listIncidents() });
|
||||
});
|
||||
|
||||
// ------------------------------------------------------- rozlozeni dashboardu
|
||||
|
||||
dashboardRouter.get('/widgets', (_req, res) => {
|
||||
res.json({ items: widgets });
|
||||
});
|
||||
|
||||
/**
|
||||
* Rozlozeni je vzdy za konkretni firmu, i kdyz uzivatel kouka na pohled "vse".
|
||||
* Jinak by clovek ve dvou firmach nemel kam ulozit dve ruzna nastaveni.
|
||||
*/
|
||||
function layoutTenant(req: Request, res: Response): string | null {
|
||||
const access = accessFor(req.user!);
|
||||
const requested = typeof req.query.tenantId === 'string' ? req.query.tenantId : undefined;
|
||||
const tenantId = requested ?? access.defaultTenantId;
|
||||
|
||||
if (!tenantId) {
|
||||
res.status(403).json({ error: 'no_tenant', message: 'Účet nepatří do žádné firmy.' });
|
||||
return null;
|
||||
}
|
||||
if (!access.tenants.some((tenant) => tenant.id === tenantId)) {
|
||||
console.warn(`[layout] ${req.user!.email}: pokus o firmu ${tenantId} bez clenstvi`);
|
||||
res.status(404).json({ error: 'not_found', message: 'Firma neexistuje, nebo do ní nepatříte.' });
|
||||
return null;
|
||||
}
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
dashboardRouter.get('/layout', (req, res) => {
|
||||
const tenantId = layoutTenant(req, res);
|
||||
if (!tenantId) return;
|
||||
|
||||
return res.json({
|
||||
tenantId,
|
||||
items: getLayout(req.user!.id, tenantId),
|
||||
custom: hasCustomLayout(req.user!.id, tenantId),
|
||||
});
|
||||
});
|
||||
|
||||
const layoutSchema = z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
id: z.string().min(1),
|
||||
widgetId: z.string().min(1),
|
||||
size: z.enum(['third', 'half', 'full']),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
dashboardRouter.put('/layout', (req, res) => {
|
||||
const tenantId = layoutTenant(req, res);
|
||||
if (!tenantId) return;
|
||||
|
||||
const parsed = layoutSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({
|
||||
error: 'validation_error',
|
||||
message: parsed.error.issues[0]?.message ?? 'Neplatné rozložení.',
|
||||
});
|
||||
}
|
||||
|
||||
const problems = validateLayout(parsed.data.items);
|
||||
if (problems.length > 0) {
|
||||
console.warn(`[layout] ${req.user!.email}: neplatne rozlozeni - ${problems.join(' ')}`);
|
||||
return res.status(400).json({ error: 'validation_error', message: problems[0] });
|
||||
}
|
||||
|
||||
const items = saveLayout(req.user!.id, tenantId, parsed.data.items);
|
||||
return res.json({ tenantId, items, custom: true });
|
||||
});
|
||||
|
||||
/** Vraceni na vychozi. Zamerne DELETE - je to smazani ulozeneho nastaveni. */
|
||||
dashboardRouter.delete('/layout', (req, res) => {
|
||||
const tenantId = layoutTenant(req, res);
|
||||
if (!tenantId) return;
|
||||
|
||||
return res.json({
|
||||
tenantId,
|
||||
items: resetLayout(req.user!.id, tenantId),
|
||||
custom: false,
|
||||
});
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------- tickety
|
||||
|
||||
/** Resitele vybrane firmy. Klient je potrebuje do nabidky prirazeni i do prehledu. */
|
||||
|
||||
Reference in New Issue
Block a user