refactor: modularize report designer components and controllers into a new report-designer module.

This commit is contained in:
2025-12-04 23:53:52 +01:00
parent 44c0406fd2
commit ad0ea0c7f8
30 changed files with 236 additions and 143 deletions

View File

@@ -26,3 +26,7 @@ File riassuntivo dello stato di sviluppo di Zentral.
- Pulizia menu Zentral (rimozione voci ridondanti) e creazione nuova Dashboard principale con riepilogo moduli attivi. - Pulizia menu Zentral (rimozione voci ridondanti) e creazione nuova Dashboard principale con riepilogo moduli attivi.
- [2025-12-04 Dashboard Widgets](./devlog/2025-12-04-030000_dashboard_widgets.md) - **Completato** - [2025-12-04 Dashboard Widgets](./devlog/2025-12-04-030000_dashboard_widgets.md) - **Completato**
- Implementazione sistema widget personalizzabili (drag & drop), salvataggio preferenze utente, widget "Active Modules" e "Warehouse Stats". - Implementazione sistema widget personalizzabili (drag & drop), salvataggio preferenze utente, widget "Active Modules" e "Warehouse Stats".
- [2025-12-04 Report Designer Module](./devlog/2025-12-04-215121_report_designer_module.md) - **Completato**
- Refactoring Report Designer in modulo autonomo e abilitazione stampa PDF condizionale.
- [2025-12-04 Fix Report Designer Imports](./devlog/2025-12-04-212500_fix_report_designer_imports.md) - **Completato**
- Correzione import path nel modulo Report Designer e registrazione modulo nel backend.

View File

@@ -0,0 +1,31 @@
# Fix Report Designer Imports and Activation
## Problema
Il modulo Report Designer non si caricava a causa di percorsi di importazione errati nei componenti frontend e mancava la registrazione del modulo nel backend.
## Modifiche Apportate
### Frontend
Corretti i percorsi di importazione in:
- `DatasetManagerDialog.tsx`
- `PreviewDialog.tsx`
- `OutputFieldsEditor.tsx`
- `FilterBuilder.tsx`
- `RelationshipEditor.tsx`
- `PropertiesPanel.tsx`
- `PageNavigator.tsx`
- `ContextMenu.tsx`
- `EditorCanvas.tsx`
- `DataBindingPanel.tsx`
- `DatasetSelector.tsx`
- `EditorToolbar.tsx`
I percorsi `../../services/reportService` e `../../types/report` sono stati aggiornati a `../../../../services/reportService` e `../../../../types/report`.
### Backend
- Aggiornato `ModuleService.cs` per includere il modulo `report-designer` nel metodo `SeedDefaultModulesAsync`.
- Riavviato il backend per applicare il seeding del nuovo modulo.
## Verifica
- Attivato il modulo `report-designer` tramite l'interfaccia `/modules`.
- Verificato il caricamento corretto della pagina `/report-designer`.

View File

@@ -0,0 +1,32 @@
# Refactoring Report Designer into a Module
## Obiettivo
Trasformare la parte del report designer in un modulo a sé stante (`report-designer`).
Una volta attivato, questo modulo abilita nelle altre applicazioni la possibilità di stampare PDF.
## Stato Attuale
Il codice del report designer è sparso in `src/frontend/src/pages` e `src/backend/Zentral.API/Controllers`.
## Piano di Lavoro
1. **Frontend**:
- [x] Creare struttura modulo: `src/frontend/src/modules/report-designer/`
- [x] Spostare pagine e componenti.
- [x] Creare `routes.tsx`.
- [x] Aggiornare i riferimenti e le rotte in `App.tsx`.
- [x] Aggiornare `reportService.ts` con le nuove rotte API.
2. **Backend**:
- [x] Creare struttura modulo: `src/backend/Zentral.API/Modules/ReportDesigner/`
- [x] Spostare Controller (`ReportTemplatesController`, `ReportResourcesController`, `ReportsController`).
- [x] Aggiornare namespace e rotte API.
- [x] Spostare DTO condivisi in `AprtModels.cs` per risolvere dipendenze circolari/mancanti.
3. **Integrazione**:
- [x] Verificare build Frontend e Backend.
## Log
- 2025-12-04: Iniziato refactoring.
- 2025-12-04: Spostati file frontend e creati routes.
- 2025-12-04: Aggiornato App.tsx con ModuleGuard.
- 2025-12-04: Spostati controller backend e aggiornati namespace.
- 2025-12-04: Risolti problemi di compilazione backend spostando DTO.
- 2025-12-04: Aggiornato reportService.ts frontend.
- 2025-12-04: Completato.

View File

@@ -1,4 +1,5 @@
using System.Text.Json; using System.Text.Json;
using Zentral.API.Services.Reports;
using Zentral.Domain.Entities; using Zentral.Domain.Entities;
using Zentral.Infrastructure.Data; using Zentral.Infrastructure.Data;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@@ -4,10 +4,10 @@ using Zentral.Infrastructure.Data;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Zentral.API.Controllers; namespace Zentral.API.Modules.ReportDesigner.Controllers;
[ApiController] [ApiController]
[Route("api/report-resources")] [Route("api/report-designer/resources")]
public class ReportResourcesController : ControllerBase public class ReportResourcesController : ControllerBase
{ {
private readonly ZentralDbContext _context; private readonly ZentralDbContext _context;

View File

@@ -4,10 +4,10 @@ using Zentral.Infrastructure.Data;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Zentral.API.Controllers; namespace Zentral.API.Modules.ReportDesigner.Controllers;
[ApiController] [ApiController]
[Route("api/report-templates")] [Route("api/report-designer/templates")]
public class ReportTemplatesController : ControllerBase public class ReportTemplatesController : ControllerBase
{ {
private readonly ZentralDbContext _context; private readonly ZentralDbContext _context;

View File

@@ -4,10 +4,10 @@ using Zentral.Infrastructure.Data;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Zentral.API.Controllers; namespace Zentral.API.Modules.ReportDesigner.Controllers;
[ApiController] [ApiController]
[Route("api/reports")] [Route("api/report-designer/reports")]
public class ReportsController : ControllerBase public class ReportsController : ControllerBase
{ {
private readonly ReportGeneratorService _reportGenerator; private readonly ReportGeneratorService _reportGenerator;
@@ -1226,65 +1226,4 @@ public class ReportsController : ControllerBase
#endregion #endregion
} }
// DTOs // DTOs moved to AprtModels.cs
public class DebugBindingRequest
{
public List<DataSourceSelection> DataSources { get; set; } = new();
public string? PropertyName { get; set; }
}
public class PreviewReportRequest
{
public int TemplateId { get; set; }
public List<DataSourceSelection> DataSources { get; set; } = new();
}
public class DataSourceSelection
{
public string DatasetId { get; set; } = string.Empty;
public int EntityId { get; set; }
public string? Alias { get; set; }
}
public class DatasetTypeDto
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Icon { get; set; } = string.Empty;
public string Category { get; set; } = "Principale";
public bool IsVirtual { get; set; } = false;
}
public class EntityListItemDto
{
public int Id { get; set; }
public string Label { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string? SecondaryInfo { get; set; }
public string? Status { get; set; }
}
public class DataSchemaDto
{
public string EntityType { get; set; } = string.Empty;
public string DatasetId { get; set; } = string.Empty;
public List<DataFieldDto> Fields { get; set; } = new();
public List<DataCollectionDto> ChildCollections { get; set; } = new();
}
public class DataFieldDto
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = "string";
public string Label { get; set; } = string.Empty;
public string? Group { get; set; }
}
public class DataCollectionDto
{
public string Name { get; set; } = string.Empty;
public string Label { get; set; } = string.Empty;
public string? Description { get; set; }
public List<DataFieldDto> Fields { get; set; } = new();
}

View File

@@ -507,6 +507,20 @@ public class ModuleService
RoutePath = "/hr", RoutePath = "/hr",
IsAvailable = true, IsAvailable = true,
CreatedAt = DateTime.UtcNow CreatedAt = DateTime.UtcNow
},
new AppModule
{
Code = "report-designer",
Name = "Report Designer",
Description = "Creazione e personalizzazione di report e stampe",
Icon = "Print",
BasePrice = 1000m,
MonthlyMultiplier = 1.2m,
SortOrder = 80,
IsCore = false,
RoutePath = "/report-designer",
IsAvailable = true,
CreatedAt = DateTime.UtcNow
} }
}; };

View File

@@ -398,3 +398,66 @@ public class ReportImageDto
public long FileSize { get; set; } public long FileSize { get; set; }
public bool Attivo { get; set; } = true; public bool Attivo { get; set; } = true;
} }
// DTOs moved from ReportsController
public class DebugBindingRequest
{
public List<DataSourceSelection> DataSources { get; set; } = new();
public string? PropertyName { get; set; }
}
public class PreviewReportRequest
{
public int TemplateId { get; set; }
public List<DataSourceSelection> DataSources { get; set; } = new();
}
public class DataSourceSelection
{
public string DatasetId { get; set; } = string.Empty;
public int EntityId { get; set; }
public string? Alias { get; set; }
}
public class DatasetTypeDto
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Icon { get; set; } = string.Empty;
public string Category { get; set; } = "Principale";
public bool IsVirtual { get; set; } = false;
}
public class EntityListItemDto
{
public int Id { get; set; }
public string Label { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string? SecondaryInfo { get; set; }
public string? Status { get; set; }
}
public class DataSchemaDto
{
public string EntityType { get; set; } = string.Empty;
public string DatasetId { get; set; } = string.Empty;
public List<DataFieldDto> Fields { get; set; } = new();
public List<DataCollectionDto> ChildCollections { get; set; } = new();
}
public class DataFieldDto
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = "string";
public string Label { get; set; } = string.Empty;
public string? Group { get; set; }
}
public class DataCollectionDto
{
public string Name { get; set; } = string.Empty;
public string Label { get; set; } = string.Empty;
public string? Description { get; set; }
public List<DataFieldDto> Fields { get; set; } = new();
}

View File

@@ -8,8 +8,7 @@ import { AppLanguageProvider } from "./contexts/LanguageContext";
import Layout from "./components/Layout"; import Layout from "./components/Layout";
import Dashboard from "./pages/Dashboard"; import Dashboard from "./pages/Dashboard";
import ReportTemplatesPage from "./pages/ReportTemplatesPage"; import ReportDesignerRoutes from "./modules/report-designer/routes";
import ReportEditorPage from "./pages/ReportEditorPage";
import ModulesAdminPage from "./pages/ModulesAdminPage"; import ModulesAdminPage from "./pages/ModulesAdminPage";
import ModulePurchasePage from "./pages/ModulePurchasePage"; import ModulePurchasePage from "./pages/ModulePurchasePage";
import AutoCodesAdminPage from "./pages/AutoCodesAdminPage"; import AutoCodesAdminPage from "./pages/AutoCodesAdminPage";
@@ -59,17 +58,14 @@ function App() {
<Route path="/" element={<Layout />}> <Route path="/" element={<Layout />}>
<Route index element={<Dashboard />} /> <Route index element={<Dashboard />} />
{/* Report Designer Module */}
<Route <Route
path="report-templates" path="report-designer/*"
element={<ReportTemplatesPage />} element={
/> <ModuleGuard moduleCode="report-designer">
<Route <ReportDesignerRoutes />
path="report-editor" </ModuleGuard>
element={<ReportEditorPage />} }
/>
<Route
path="report-editor/:id"
element={<ReportEditorPage />}
/> />
{/* Admin */} {/* Admin */}
<Route path="modules" element={<ModulesAdminPage />} /> <Route path="modules" element={<ModulesAdminPage />} />

View File

@@ -166,7 +166,7 @@ export default function Sidebar({ onClose }: { onClose?: () => void }) {
{ id: 'modules', label: t('menu.modules'), icon: <ModulesIcon />, path: '/modules' }, { id: 'modules', label: t('menu.modules'), icon: <ModulesIcon />, path: '/modules' },
{ id: 'autocodes', label: t('menu.autoCodes'), icon: <AutoCodeIcon />, path: '/admin/auto-codes' }, { id: 'autocodes', label: t('menu.autoCodes'), icon: <AutoCodeIcon />, path: '/admin/auto-codes' },
{ id: 'customfields', label: t('menu.customFields'), icon: <AutoCodeIcon />, path: '/admin/custom-fields' }, { id: 'customfields', label: t('menu.customFields'), icon: <AutoCodeIcon />, path: '/admin/custom-fields' },
{ id: 'reports', label: t('menu.reports'), icon: <PrintIcon />, path: '/report-templates' }, { id: 'reports', label: t('menu.reports'), icon: <PrintIcon />, path: '/report-designer', moduleCode: 'report-designer' },
], ],
}, },
]; ];

View File

@@ -41,7 +41,7 @@ import {
TextFields as EditTextIcon, TextFields as EditTextIcon,
Image as ReplaceImageIcon, Image as ReplaceImageIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import type { ZrtElement } from "../../types/report"; import type { ZrtElement } from "../../../../types/report";
export interface ContextMenuPosition { export interface ContextMenuPosition {
x: number; x: number;

View File

@@ -46,7 +46,7 @@ import type {
DataSchemaDto, DataSchemaDto,
DataFieldDto, DataFieldDto,
DatasetTypeDto, DatasetTypeDto,
} from "../../types/report"; } from "../../../../types/report";
interface DataBindingPanelProps { interface DataBindingPanelProps {
schemas: DataSchemaDto[]; schemas: DataSchemaDto[];

View File

@@ -49,15 +49,15 @@ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { import {
virtualDatasetService, virtualDatasetService,
reportGeneratorService, reportGeneratorService,
} from "../../services/reportService"; } from "../../../../services/reportService";
import type { import type {
VirtualDatasetDto, VirtualDatasetDto,
VirtualDatasetConfiguration, VirtualDatasetConfiguration,
VirtualDatasetSource, VirtualDatasetSource,
DatasetTypeDto, DatasetTypeDto,
VirtualDatasetValidationResult, VirtualDatasetValidationResult,
} from "../../types/report"; } from "../../../../types/report";
import { defaultVirtualDatasetConfiguration } from "../../types/report"; import { defaultVirtualDatasetConfiguration } from "../../../../types/report";
import RelationshipEditor from "./RelationshipEditor"; import RelationshipEditor from "./RelationshipEditor";
import FilterBuilder from "./FilterBuilder"; import FilterBuilder from "./FilterBuilder";
import OutputFieldsEditor from "./OutputFieldsEditor"; import OutputFieldsEditor from "./OutputFieldsEditor";

View File

@@ -36,7 +36,7 @@ import {
ExpandMore as ExpandMoreIcon, ExpandMore as ExpandMoreIcon,
ExpandLess as ExpandLessIcon, ExpandLess as ExpandLessIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import type { DatasetTypeDto } from "../../types/report"; import type { DatasetTypeDto } from "../../../../types/report";
interface DatasetSelectorProps { interface DatasetSelectorProps {
availableDatasets: DatasetTypeDto[]; availableDatasets: DatasetTypeDto[];

View File

@@ -13,13 +13,13 @@ import type {
ZrtElement, ZrtElement,
PageSize, PageSize,
PageOrientation, PageOrientation,
} from "../../types/report"; } from "../../../../types/report";
import { import {
getPageDimensions, getPageDimensions,
mmToPx, mmToPx,
pxToMm, pxToMm,
defaultStyle, defaultStyle,
} from "../../types/report"; } from "../../../../types/report";
import type { SnapOptions } from "./EditorToolbar"; import type { SnapOptions } from "./EditorToolbar";
// Extend fabric types to include data property // Extend fabric types to include data property

View File

@@ -66,7 +66,7 @@ import {
History as HistoryIcon, History as HistoryIcon,
AutoMode as AutoSaveIcon, AutoMode as AutoSaveIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import type { ElementType } from "../../types/report"; import type { ElementType } from "../../../../types/report";
// Snap options type // Snap options type
export interface SnapOptions { export interface SnapOptions {

View File

@@ -22,12 +22,12 @@ import {
FilterList as FilterIcon, FilterList as FilterIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { useQueries } from "@tanstack/react-query"; import { useQueries } from "@tanstack/react-query";
import { reportGeneratorService } from "../../services/reportService"; import { reportGeneratorService } from "../../../../services/reportService";
import type { import type {
VirtualDatasetSource, VirtualDatasetSource,
VirtualDatasetFilter, VirtualDatasetFilter,
DatasetTypeDto, DatasetTypeDto,
} from "../../types/report"; } from "../../../../types/report";
interface FilterBuilderProps { interface FilterBuilderProps {
sources: VirtualDatasetSource[]; sources: VirtualDatasetSource[];
@@ -348,7 +348,7 @@ export default function FilterBuilder({
selectedField?.type === "date" selectedField?.type === "date"
? "YYYY-MM-DD" ? "YYYY-MM-DD"
: selectedField?.type === "number" || : selectedField?.type === "number" ||
selectedField?.type === "currency" selectedField?.type === "currency"
? "0" ? "0"
: "Testo" : "Testo"
} }

View File

@@ -30,13 +30,13 @@ import {
AttachMoney as CurrencyIcon, AttachMoney as CurrencyIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { useQueries } from "@tanstack/react-query"; import { useQueries } from "@tanstack/react-query";
import { reportGeneratorService } from "../../services/reportService"; import { reportGeneratorService } from "../../../../services/reportService";
import type { import type {
VirtualDatasetSource, VirtualDatasetSource,
VirtualDatasetOutputField, VirtualDatasetOutputField,
DatasetTypeDto, DatasetTypeDto,
DataFieldDto, DataFieldDto,
} from "../../types/report"; } from "../../../../types/report";
interface OutputFieldsEditorProps { interface OutputFieldsEditorProps {
sources: VirtualDatasetSource[]; sources: VirtualDatasetSource[];

View File

@@ -31,7 +31,7 @@ import {
KeyboardArrowUp as MoveUpIcon, KeyboardArrowUp as MoveUpIcon,
KeyboardArrowDown as MoveDownIcon, KeyboardArrowDown as MoveDownIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import type { ZrtPage, ZrtElement } from "../../types/report"; import type { ZrtPage, ZrtElement } from "../../../../types/report";
interface PageNavigatorProps { interface PageNavigatorProps {
pages: ZrtPage[]; pages: ZrtPage[];

View File

@@ -44,12 +44,12 @@ import {
ArrowBack as BackIcon, ArrowBack as BackIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { useQueries } from "@tanstack/react-query"; import { useQueries } from "@tanstack/react-query";
import { reportGeneratorService } from "../../services/reportService"; import { reportGeneratorService } from "../../../../services/reportService";
import type { import type {
DatasetTypeDto, DatasetTypeDto,
DataSourceSelection, DataSourceSelection,
EntityListItemDto, EntityListItemDto,
} from "../../types/report"; } from "../../../../types/report";
interface PreviewDialogProps { interface PreviewDialogProps {
open: boolean; open: boolean;

View File

@@ -54,8 +54,8 @@ import type {
ZrtTableColumn, ZrtTableColumn,
DataSchemaDto, DataSchemaDto,
DatasetTypeDto, DatasetTypeDto,
} from "../../types/report"; } from "../../../../types/report";
import { defaultImageSettings } from "../../types/report"; import { defaultImageSettings } from "../../../../types/report";
interface PropertiesPanelProps { interface PropertiesPanelProps {
element: ZrtElement | null; element: ZrtElement | null;

View File

@@ -21,13 +21,13 @@ import {
ArrowForward as ArrowIcon, ArrowForward as ArrowIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { useQueries } from "@tanstack/react-query"; import { useQueries } from "@tanstack/react-query";
import { reportGeneratorService } from "../../services/reportService"; import { reportGeneratorService } from "../../../../services/reportService";
import type { import type {
VirtualDatasetSource, VirtualDatasetSource,
VirtualDatasetRelationship, VirtualDatasetRelationship,
DatasetTypeDto, DatasetTypeDto,
DataSchemaDto, DataSchemaDto,
} from "../../types/report"; } from "../../../../types/report";
interface RelationshipEditorProps { interface RelationshipEditorProps {
sources: VirtualDatasetSource[]; sources: VirtualDatasetSource[];

View File

@@ -7,14 +7,14 @@ import {
useQueryClient, useQueryClient,
} from "@tanstack/react-query"; } from "@tanstack/react-query";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { useHistory } from "../hooks/useHistory"; import { useHistory } from "../../../hooks/useHistory";
import { usePanelLayout } from "../hooks/usePanelLayout"; import { usePanelLayout } from "../../../hooks/usePanelLayout";
import { useCollaborationRoom } from "../contexts/CollaborationContext"; import { useCollaborationRoom } from "../../../contexts/CollaborationContext";
import type { import type {
DataChangeMessage, DataChangeMessage,
ItemCreatedMessage, ItemCreatedMessage,
ItemDeletedMessage, ItemDeletedMessage,
} from "../services/collaboration"; } from "../../../services/collaboration";
import { import {
Box, Box,
CircularProgress, CircularProgress,
@@ -72,7 +72,7 @@ import {
reportGeneratorService, reportGeneratorService,
virtualDatasetService, virtualDatasetService,
openBlobInNewTab, openBlobInNewTab,
} from "../services/reportService"; } from "../../../services/reportService";
import type { import type {
ZrtTemplate, ZrtTemplate,
ZrtElement, ZrtElement,
@@ -85,13 +85,13 @@ import type {
DatasetTypeDto, DatasetTypeDto,
DataSourceSelection, DataSourceSelection,
ReportTemplateDto, ReportTemplateDto,
} from "../types/report"; } from "../../../types/report";
import { import {
defaultTemplate, defaultTemplate,
defaultStyle, defaultStyle,
defaultImageSettings, defaultImageSettings,
defaultPage, defaultPage,
} from "../types/report"; } from "../../../types/report";
// Panel types for mobile navigation // Panel types for mobile navigation
type MobilePanel = "pages" | "data" | "properties" | null; type MobilePanel = "pages" | "data" | "properties" | null;
@@ -632,7 +632,7 @@ export default function ReportEditorPage() {
} }
if (isNew) { if (isNew) {
navigate(`/report-editor/${result.id}`, { replace: true }); navigate(`/report-designer/editor/${result.id}`, { replace: true });
} }
}, },
onError: (error) => { onError: (error) => {

View File

@@ -38,8 +38,8 @@ import {
Description as DescriptionIcon, Description as DescriptionIcon,
} from "@mui/icons-material"; } from "@mui/icons-material";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { reportTemplateService, downloadBlob } from "../services/reportService"; import { reportTemplateService, downloadBlob } from "../../../services/reportService";
import type { ReportTemplateDto } from "../types/report"; import type { ReportTemplateDto } from "../../../types/report";
export default function ReportTemplatesPage() { export default function ReportTemplatesPage() {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -92,7 +92,7 @@ export default function ReportTemplatesPage() {
queryClient.invalidateQueries({ queryKey: ["report-templates"] }); queryClient.invalidateQueries({ queryKey: ["report-templates"] });
setImportDialog(false); setImportDialog(false);
setImportFile(null); setImportFile(null);
navigate(`/report-editor/${newTemplate.id}`); navigate(`/report-designer/editor/${newTemplate.id}`);
}, },
}); });
@@ -179,7 +179,7 @@ export default function ReportTemplatesPage() {
<Button <Button
variant="contained" variant="contained"
startIcon={<AddIcon />} startIcon={<AddIcon />}
onClick={() => navigate("/report-editor")} onClick={() => navigate("/report-designer/editor")}
> >
{t("reports.newTemplate")} {t("reports.newTemplate")}
</Button> </Button>
@@ -265,7 +265,7 @@ export default function ReportTemplatesPage() {
<Button <Button
variant="contained" variant="contained"
startIcon={<AddIcon />} startIcon={<AddIcon />}
onClick={() => navigate("/report-editor")} onClick={() => navigate("/report-designer/editor")}
fullWidth={isMobile} fullWidth={isMobile}
> >
{t("reports.createTemplate")} {t("reports.createTemplate")}
@@ -388,7 +388,7 @@ export default function ReportTemplatesPage() {
<IconButton <IconButton
size="small" size="small"
onClick={() => onClick={() =>
navigate(`/report-editor/${template.id}`) navigate(`/report-designer/editor/${template.id}`)
} }
> >
<EditIcon fontSize={isMobile ? "small" : "medium"} /> <EditIcon fontSize={isMobile ? "small" : "medium"} />
@@ -435,7 +435,7 @@ export default function ReportTemplatesPage() {
<Fab <Fab
color="primary" color="primary"
aria-label={t("reports.newTemplate")} aria-label={t("reports.newTemplate")}
onClick={() => navigate("/report-editor")} onClick={() => navigate("/report-designer/editor")}
sx={{ sx={{
position: "fixed", position: "fixed",
bottom: 16, bottom: 16,

View File

@@ -0,0 +1,13 @@
import { Routes, Route } from "react-router-dom";
import ReportTemplatesPage from "./pages/ReportTemplatesPage";
import ReportEditorPage from "./pages/ReportEditorPage";
export default function ReportDesignerRoutes() {
return (
<Routes>
<Route index element={<ReportTemplatesPage />} />
<Route path="editor" element={<ReportEditorPage />} />
<Route path="editor/:id" element={<ReportEditorPage />} />
</Routes>
);
}

View File

@@ -19,19 +19,19 @@ import type {
export const reportTemplateService = { export const reportTemplateService = {
getAll: async (categoria?: string): Promise<ReportTemplateDto[]> => { getAll: async (categoria?: string): Promise<ReportTemplateDto[]> => {
const params = categoria ? { categoria } : {}; const params = categoria ? { categoria } : {};
const response = await api.get("/report-templates", { params }); const response = await api.get("/report-designer/templates", { params });
return response.data; return response.data;
}, },
getById: async (id: number): Promise<ReportTemplateDto> => { getById: async (id: number): Promise<ReportTemplateDto> => {
const response = await api.get(`/report-templates/${id}`); const response = await api.get(`/report-designer/templates/${id}`);
return response.data; return response.data;
}, },
create: async ( create: async (
template: Partial<ReportTemplateDto>, template: Partial<ReportTemplateDto>,
): Promise<ReportTemplateDto> => { ): Promise<ReportTemplateDto> => {
const response = await api.post("/report-templates", template); const response = await api.post("/report-designer/templates", template);
return response.data; return response.data;
}, },
@@ -39,21 +39,21 @@ export const reportTemplateService = {
id: number, id: number,
template: Partial<ReportTemplateDto>, template: Partial<ReportTemplateDto>,
): Promise<ReportTemplateDto> => { ): Promise<ReportTemplateDto> => {
const response = await api.put(`/report-templates/${id}`, template); const response = await api.put(`/report-designer/templates/${id}`, template);
return response.data; return response.data;
}, },
delete: async (id: number): Promise<void> => { delete: async (id: number): Promise<void> => {
await api.delete(`/report-templates/${id}`); await api.delete(`/report-designer/templates/${id}`);
}, },
clone: async (id: number): Promise<ReportTemplateDto> => { clone: async (id: number): Promise<ReportTemplateDto> => {
const response = await api.post(`/report-templates/${id}/clone`); const response = await api.post(`/report-designer/templates/${id}/clone`);
return response.data; return response.data;
}, },
export: async (id: number): Promise<Blob> => { export: async (id: number): Promise<Blob> => {
const response = await api.get(`/report-templates/${id}/export`, { const response = await api.get(`/report-designer/templates/${id}/export`, {
responseType: "blob", responseType: "blob",
}); });
return response.data; return response.data;
@@ -62,14 +62,14 @@ export const reportTemplateService = {
import: async (file: File): Promise<ReportTemplateDto> => { import: async (file: File): Promise<ReportTemplateDto> => {
const formData = new FormData(); const formData = new FormData();
formData.append("file", file); formData.append("file", file);
const response = await api.post("/report-templates/import", formData, { const response = await api.post("/report-designer/templates/import", formData, {
headers: { "Content-Type": "multipart/form-data" }, headers: { "Content-Type": "multipart/form-data" },
}); });
return response.data; return response.data;
}, },
getCategories: async (): Promise<string[]> => { getCategories: async (): Promise<string[]> => {
const response = await api.get("/report-templates/categories"); const response = await api.get("/report-designer/templates/categories");
return response.data; return response.data;
}, },
}; };
@@ -77,12 +77,12 @@ export const reportTemplateService = {
// Fonts // Fonts
export const reportFontService = { export const reportFontService = {
getAll: async (): Promise<ReportFontDto[]> => { getAll: async (): Promise<ReportFontDto[]> => {
const response = await api.get("/report-resources/fonts"); const response = await api.get("/report-designer/resources/fonts");
return response.data; return response.data;
}, },
getById: async (id: number): Promise<ReportFontDto> => { getById: async (id: number): Promise<ReportFontDto> => {
const response = await api.get(`/report-resources/fonts/${id}`); const response = await api.get(`/report-designer/resources/fonts/${id}`);
return response.data; return response.data;
}, },
@@ -97,18 +97,18 @@ export const reportFontService = {
formData.append("fontFamily", fontFamily); formData.append("fontFamily", fontFamily);
formData.append("fontStyle", fontStyle); formData.append("fontStyle", fontStyle);
formData.append("file", file); formData.append("file", file);
const response = await api.post("/report-resources/fonts", formData, { const response = await api.post("/report-designer/resources/fonts", formData, {
headers: { "Content-Type": "multipart/form-data" }, headers: { "Content-Type": "multipart/form-data" },
}); });
return response.data; return response.data;
}, },
delete: async (id: number): Promise<void> => { delete: async (id: number): Promise<void> => {
await api.delete(`/report-resources/fonts/${id}`); await api.delete(`/report-designer/resources/fonts/${id}`);
}, },
getFamilies: async (): Promise<string[]> => { getFamilies: async (): Promise<string[]> => {
const response = await api.get("/report-resources/fonts/families"); const response = await api.get("/report-designer/resources/fonts/families");
return response.data; return response.data;
}, },
}; };
@@ -117,12 +117,12 @@ export const reportFontService = {
export const reportImageService = { export const reportImageService = {
getAll: async (categoria?: string): Promise<ReportImageDto[]> => { getAll: async (categoria?: string): Promise<ReportImageDto[]> => {
const params = categoria ? { categoria } : {}; const params = categoria ? { categoria } : {};
const response = await api.get("/report-resources/images", { params }); const response = await api.get("/report-designer/resources/images", { params });
return response.data; return response.data;
}, },
getById: async (id: number): Promise<ReportImageDto> => { getById: async (id: number): Promise<ReportImageDto> => {
const response = await api.get(`/report-resources/images/${id}`); const response = await api.get(`/report-designer/resources/images/${id}`);
return response.data; return response.data;
}, },
@@ -135,7 +135,7 @@ export const reportImageService = {
formData.append("nome", nome); formData.append("nome", nome);
formData.append("categoria", categoria); formData.append("categoria", categoria);
formData.append("file", file); formData.append("file", file);
const response = await api.post("/report-resources/images", formData, { const response = await api.post("/report-designer/resources/images", formData, {
headers: { "Content-Type": "multipart/form-data" }, headers: { "Content-Type": "multipart/form-data" },
}); });
return response.data; return response.data;
@@ -145,16 +145,16 @@ export const reportImageService = {
id: number, id: number,
data: Partial<ReportImageDto>, data: Partial<ReportImageDto>,
): Promise<ReportImageDto> => { ): Promise<ReportImageDto> => {
const response = await api.put(`/report-resources/images/${id}`, data); const response = await api.put(`/report-designer/resources/images/${id}`, data);
return response.data; return response.data;
}, },
delete: async (id: number): Promise<void> => { delete: async (id: number): Promise<void> => {
await api.delete(`/report-resources/images/${id}`); await api.delete(`/report-designer/resources/images/${id}`);
}, },
getCategories: async (): Promise<string[]> => { getCategories: async (): Promise<string[]> => {
const response = await api.get("/report-resources/images/categories"); const response = await api.get("/report-designer/resources/images/categories");
return response.data; return response.data;
}, },
}; };
@@ -162,7 +162,7 @@ export const reportImageService = {
// Report Generation // Report Generation
export const reportGeneratorService = { export const reportGeneratorService = {
generate: async (request: GenerateReportRequest): Promise<Blob> => { generate: async (request: GenerateReportRequest): Promise<Blob> => {
const response = await api.post("/reports/generate", request, { const response = await api.post("/report-designer/reports/generate", request, {
responseType: "blob", responseType: "blob",
}); });
return response.data; return response.data;
@@ -173,7 +173,7 @@ export const reportGeneratorService = {
templateId?: number, templateId?: number,
): Promise<Blob> => { ): Promise<Blob> => {
const params = templateId ? { templateId } : {}; const params = templateId ? { templateId } : {};
const response = await api.get(`/reports/evento/${eventoId}`, { const response = await api.get(`/report-designer/reports/evento/${eventoId}`, {
params, params,
responseType: "blob", responseType: "blob",
}); });
@@ -181,26 +181,26 @@ export const reportGeneratorService = {
}, },
preview: async (request: PreviewReportRequest): Promise<Blob> => { preview: async (request: PreviewReportRequest): Promise<Blob> => {
const response = await api.post("/reports/preview", request, { const response = await api.post("/report-designer/reports/preview", request, {
responseType: "blob", responseType: "blob",
}); });
return response.data; return response.data;
}, },
getSchema: async (datasetId: string): Promise<DataSchemaDto> => { getSchema: async (datasetId: string): Promise<DataSchemaDto> => {
const response = await api.get(`/reports/schema/${datasetId}`); const response = await api.get(`/report-designer/reports/schema/${datasetId}`);
return response.data; return response.data;
}, },
getAvailableDatasets: async (): Promise<DatasetTypeDto[]> => { getAvailableDatasets: async (): Promise<DatasetTypeDto[]> => {
const response = await api.get("/reports/datasets"); const response = await api.get("/report-designer/reports/datasets");
return response.data; return response.data;
}, },
getEntitiesForDataset: async ( getEntitiesForDataset: async (
datasetId: string, datasetId: string,
): Promise<EntityListItemDto[]> => { ): Promise<EntityListItemDto[]> => {
const response = await api.get(`/reports/datasets/${datasetId}/entities`); const response = await api.get(`/report-designer/reports/datasets/${datasetId}/entities`);
return response.data; return response.data;
}, },
}; };