Quattro nuovi componenti sgcHTML per dati strutturati: TreeGrid, PivotTable, ActivityFeed e Splitter | eSeGeCe Blog

Quattro nuovi componenti sgcHTML per dati strutturati: TreeGrid, PivotTable, ActivityFeed e Splitter

· Componenti

sgcHTML si è appena arricchito di 25 nuovi componenti, e questo è il primo di cinque articoli che li presentano per tema. Iniziamo con quattro componenti costruiti attorno a dati strutturati e in continuo cambiamento: TreeGrid per righe gerarchiche, PivotTable per aggregazioni raggruppate, ActivityFeed per un flusso di eventi in tempo reale, e Splitter per il layout a due pannelli ridimensionabile che così spesso deve contenere tutto quanto sopra. Ogni componente qui sotto è una semplice classe Delphi/C++Builder/.NET: imposti le sue proprietà, chiami HTML, ottieni in cambio markup Bootstrap 5. Nessun framework JavaScript, nessuno step di build.

TreeGrid — tabelle gerarchiche comprimibili

TsgcHTMLComponent_TreeGrid genera una tabella Bootstrap le cui righe si comprimono ed espandono, costruita a partire da semplici coppie di nodi Id / ParentId — la stessa struttura che probabilmente usi già per organigrammi, alberi di categorie o distinte base annidate. Dichiara un TsgcHTMLTreeGridColumn per ogni campo visibile, poi aggiungi i nodi; la relazione padre/figlio disegna l'albero e le frecce di espansione per te.

uses
  sgcHTML_Component_TreeGrid;

var
  oTreeGrid: TsgcHTMLComponent_TreeGrid;
  oColumn: TsgcHTMLTreeGridColumn;
begin
  oTreeGrid := TsgcHTMLComponent_TreeGrid.Create(nil);
  try
    oTreeGrid.TreeGridID := 'orgchart';
    oTreeGrid.Sortable := True;

    oColumn := oTreeGrid.Columns.Add;
    oColumn.Caption := 'Department';
    oColumn.FieldName := 'Name';

    oColumn := oTreeGrid.Columns.Add;
    oColumn.Caption := 'Headcount';
    oColumn.FieldName := 'Headcount';
    oColumn.Align := tgaRight;

    oTreeGrid.AddNode('eng', '', ['Engineering', '42']);
    oTreeGrid.AddNode('eng-be', 'eng', ['Backend', '18']);
    oTreeGrid.AddNode('eng-fe', 'eng', ['Frontend', '15']);

    WebModule.Response := oTreeGrid.HTML;   // hierarchical table + scoped CSS + toggle script
  finally
    oTreeGrid.Free;
  end;
end;

// Or bind it straight to a self-referencing dataset (Id / ParentId columns):
oTreeGrid.LoadFromDataSet(qryDepartments, 'Id', 'ParentId');

Se i tuoi dati risiedono già in una tabella auto-referenziante, puoi saltare del tutto le chiamate manuali ai nodi e passare a LoadFromDataSet i nomi dei campi padre e figlio — scorrerà il dataset e costruirà l'intero albero in un solo passaggio.

PivotTable — raggruppa, aggrega, totalizza

TsgcHTMLComponent_PivotTable prende righe piatte e produce una tabella raggruppata e aggregata con totali di riga, totali di colonna e un totale generale, il report che altrimenti costruiresti a mano in un foglio di calcolo. Dichiari RowFields e ColumnFields per il raggruppamento, una o più Measures da aggregare (somma, media, conteggio, minimo, massimo), e un elenco DataFields che indica quali colonne di origine leggere effettivamente.

uses
  sgcHTML_Component_PivotTable;

var
  oPivot: TsgcHTMLComponent_PivotTable;
  oMeasure: TsgcHTMLPivotMeasure;
begin
  oPivot := TsgcHTMLComponent_PivotTable.Create(nil);
  try
    oPivot.Caption := 'Revenue by Region and Quarter';

    oPivot.RowFields.Add.FieldName := 'Region';
    oPivot.ColumnFields.Add.FieldName := 'Quarter';

    oMeasure := oPivot.Measures.Add;
    oMeasure.SourceField := 'Amount';
    oMeasure.Caption := 'Revenue';
    oMeasure.Aggregation := paSum;
    oMeasure.Format := '#,##0.00';

    oPivot.DataFields.Add('Region');
    oPivot.DataFields.Add('Quarter');
    oPivot.DataFields.Add('Amount');

    oPivot.AddRow(['EMEA', 'Q1', '12000']);
    oPivot.AddRow(['EMEA', 'Q2', '15500']);
    oPivot.AddRow(['APAC', 'Q1', '9800']);

    WebModule.Response := oPivot.HTML;   // aggregated table + row/column/grand totals
  finally
    oPivot.Free;
  end;
end;

// Or bind it straight to a dataset (reads only RowFields/ColumnFields/Measures fields):
oPivot.LoadFromDataSet(qrySales);

Tutto ciò che viene dopo AddRow (o LoadFromDataSet) viene calcolato per te: il componente raggruppa le righe grezze, applica l'aggregazione scelta per ogni cella, e aggiunge automaticamente le righe e colonne di totale riga/colonna/generale.

ActivityFeed — un flusso di eventi live e trasmissibile

TsgcHTMLComponent_ActivityFeed genera un elenco, dal più recente al meno recente, di voci "chi ha fatto cosa" con timestamp relativi ("3 min fa", mantenuti aggiornati lato client), ed è pensato fin dall'inizio per ricevere aggiornamenti push via WebSocket, non solo per essere renderizzato una volta sola. MaxItems lo mantiene un buffer circolare — la voce più vecchia viene eliminata automaticamente una volta raggiunto il limite.

uses
  sgcHTML_Enums, sgcHTML_Component_ActivityFeed;

var
  oFeed: TsgcHTMLComponent_ActivityFeed;
begin
  oFeed := TsgcHTMLComponent_ActivityFeed.Create(nil);
  try
    oFeed.FeedID := 'timeline';
    oFeed.Title := 'Recent Activity';
    oFeed.MaxItems := 30;

    oFeed.AddActivity('Ana', 'closed', 'ticket #482', hcSuccess, 'bi bi-check-circle');
    oFeed.AddActivity('Marc', 'commented on', 'invoice #1190', hcPrimary);

    WebModule.Response := oFeed.HTML;   // feed list + scoped CSS + live relative-time script
  finally
    oFeed.Free;
  end;
end;

// Push a new item live to connected clients (out-of-band htmx fragment):
oFeed.AddActivity('Ana', 'approved', 'purchase order #77', hcSuccess);
Engine.BroadcastFragment(oFeed.GetLastItemFragmentHTML);

Quest'ultima riga è la parte interessante: GetLastItemFragmentHTML renderizza solo la voce più recente come frammento htmx out-of-band, e BroadcastFragment lo invia a ogni browser aperto tramite il server sgcWebSockets che stai già eseguendo. Nessun polling, nessun livello real-time separato da configurare.

Splitter — il contenitore a due pannelli che racchiude tutto

TsgcHTMLComponent_Splitter è il pezzo di layout: due pannelli ridimensionabili con una barra di trascinamento tra loro, orizzontale o verticale, con una dimensione minima in pixel su ciascun lato in modo che nessun pannello possa essere ridotto a zero. È esattamente il contenitore di cui ha bisogno una schermata TreeGrid-più-pannello-di-dettaglio o elenco-file-più-editor.

uses
  sgcHTML_Component_Splitter;

var
  oSplitter: TsgcHTMLComponent_Splitter;
begin
  oSplitter := TsgcHTMLComponent_Splitter.Create(nil);
  try
    oSplitter.SplitterID := 'workspace';
    oSplitter.Orientation := soHorizontal;
    oSplitter.InitialSplit := 30;
    oSplitter.MinSizeA := 180;
    oSplitter.MinSizeB := 320;
    oSplitter.GutterSize := 8;
    oSplitter.Height := '560px';
    oSplitter.PersistKey := 'workspace-split';

    oSplitter.AddPaneA('<div class="p-3"><h5>Files</h5>...</div>');
    oSplitter.AddPaneB('<div class="p-3"><h5>Editor</h5>...</div>');

    WebModule.Response := oSplitter.HTML;   // two panes + gutter + scoped CSS + drag script
  finally
    oSplitter.Free;
  end;
end;

PersistKey merita una menzione a parte: impostalo e la posizione della barra di trascinamento scelta da un visitatore verrà ricordata lato client e ripristinata alla visita successiva, così un layout di lavoro resta invariato tra una sessione e l'altra senza dover scrivere codice di gestione dello stato.

Provali

Tutti e quattro sono disponibili nell'attuale release di sgcWebSockets, con documentazione completa, riferimenti alle proprietà chiave ed esempi di codice Delphi/C++Builder/.NET sulle rispettive pagine: TreeGrid, PivotTable, ActivityFeed e Splitter. La matrice completa delle funzionalità elenca ora 83 componenti in nove famiglie — il prossimo articolo di questa serie tratta i nuovi grafici e i codici visivi.

Domande, feedback o serve aiuto con la migrazione? Contattaci — riceverai una risposta da chi ha scritto il codice.