@praxisui/charts 3.0.0-beta.1 → 3.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -110,6 +110,124 @@ export class ChartDemoComponent {
110
110
 
111
111
  See the public exports in `projects/praxis-charts/src/public-api.ts`.
112
112
 
113
+ ## Runtime Model
114
+
115
+ O runtime atual de `@praxisui/charts` opera em duas trilhas principais:
116
+
117
+ - `dataSource.kind = "local"` para datasets entregues diretamente ao componente
118
+ - `dataSource.kind = "remote"` para datasets remotos, com foco canônico em `praxis.stats`
119
+
120
+ No modo remoto, o componente:
121
+
122
+ - emite `queryRequest`
123
+ - chama `PraxisChartStatsApiService`
124
+ - transforma a resposta agregada em `PraxisChartDataRow[]`
125
+ - renderiza o estado `loading`, `empty`, `error` ou `ready`
126
+
127
+ ### Versão Pedagógica de Alto Nível
128
+
129
+ Esta é a leitura adequada para documentação pública e landing pages.
130
+
131
+ ```mermaid
132
+ sequenceDiagram
133
+ participant Host as Host
134
+ participant Chart as praxis-chart
135
+ participant Stats as PraxisChartStatsApiService
136
+ participant Backend as API Praxis Stats
137
+
138
+ Host->>Chart: fornece config local ou remote
139
+ alt fonte local
140
+ Chart->>Chart: transforma dados locais e renderiza
141
+ else fonte remota
142
+ Chart-->>Host: emite queryRequest
143
+ Chart->>Stats: executa consulta praxis.stats
144
+ Stats->>Backend: POST /stats/*
145
+ Backend-->>Stats: retorna buckets/pontos agregados
146
+ Stats-->>Chart: entrega linhas canônicas
147
+ Chart->>Chart: renderiza loading, ready, empty ou error
148
+ end
149
+ ```
150
+
151
+ Leitura pedagógica:
152
+
153
+ 1. **O host entrega um contrato declarativo**, não opções brutas do engine.
154
+ 2. **O componente resolve a fonte de dados**: local ou remota.
155
+ 3. **Quando a fonte é remota, a integração canônica é `praxis.stats`**.
156
+ 4. **O chart renderiza estados de UX e a visualização final a partir de linhas canônicas**.
157
+
158
+ ### Versão Detalhada e Fiel ao Runtime Atual
159
+
160
+ ```mermaid
161
+ sequenceDiagram
162
+ participant Host as Host
163
+ participant Chart as PraxisChartComponent
164
+ participant Mapper as Canonical Mapper / config remoto
165
+ participant Stats as PraxisChartStatsApiService
166
+ participant Backend as API /stats
167
+ participant Engine as Chart Engine Adapter
168
+
169
+ Host->>Chart: [config] e opcionalmente [data]
170
+ alt data explicito fornecido
171
+ Chart->>Chart: resolvedData = data input
172
+ else fonte local
173
+ Chart->>Chart: resolvedData = dataSource.items
174
+ else fonte remote
175
+ Chart->>Chart: buildRemoteSignature(config)
176
+ Chart-->>Host: queryRequest({ chartId, dataSource, query })
177
+ Chart->>Stats: execute(event, config)
178
+ Stats->>Stats: valida statsPath + statsRequest
179
+ Stats->>Backend: POST {statsPath}
180
+ Backend-->>Stats: envelope com data agregada
181
+ Stats->>Stats: converte buckets/points em PraxisChartDataRow[]
182
+ Stats-->>Chart: rows remotas resolvidas
183
+ end
184
+
185
+ Chart->>Chart: resolve loadState (loading/empty/error/ready)
186
+ alt ready
187
+ Chart->>Engine: render(host, { config, data })
188
+ else not ready
189
+ Chart->>Engine: destroy()
190
+ end
191
+ ```
192
+
193
+ ### Limites Atuais do Contrato Canônico
194
+
195
+ O mapper `x-ui.chart -> PraxisChartConfig` já impõe limites importantes que precisam aparecer na documentação pública:
196
+
197
+ - `source.kind` suportado hoje: `praxis.stats` e `derived`
198
+ - `source.kind = "praxis.stats"` exige `source.resource` e `source.operation`
199
+ - agregações suportadas: `count`, `sum`, `avg`, `min`, `max`
200
+ - `distinct-count` ainda não está implementado
201
+ - charts `pie` e `donut` aceitam apenas uma métrica
202
+ - charts cartesianos `praxis.stats` podem declarar múltiplas métricas apenas em `group-by` e `timeseries`
203
+ - `distribution` continua single-métrica
204
+ - `combo` exige pelo menos duas métricas e, no modo `praxis.stats`, suporta apenas `group-by` ou `timeseries`
205
+ - `axis: "secondary"` é exclusivo de `combo`
206
+ - `selectionChange` e `crossFilter` declarativos ainda não estão implementados
207
+ - `theme.variant` e `theme.palette` por token ainda não estão implementados
208
+
209
+ ## Fluxo Canonico de `praxis.stats`
210
+
211
+ Quando o contrato remoto vem do mapper canônico, o caminho gerado hoje segue a forma:
212
+
213
+ - `{resourcePath}/stats/group-by`
214
+ - `{resourcePath}/stats/timeseries`
215
+ - `{resourcePath}/stats/distribution`
216
+
217
+ O `PraxisChartStatsApiService`:
218
+
219
+ - monta a URL final usando `API_URL`
220
+ - normaliza o path remoto
221
+ - envia `statsRequest` via `POST`
222
+ - converte buckets/pontos em linhas canônicas para o runtime do chart
223
+
224
+ Observação importante:
225
+
226
+ - o runtime atual assume envelope com `data`
227
+ - `queryRequest` é emitido para observabilidade do host antes da execução remota
228
+ - a execução remota automática hoje está acoplada a `praxis.stats`; não existe ainda um hook público de override do request dentro do componente
229
+ - a trilha canônica `x-ui.chart -> PraxisChartConfig -> praxis.stats` já promove múltiplas métricas para charts cartesianos suportados; para evitar semântica enganosa, `combo` segue sendo o único caso com eixo secundário e mistura heterogênea de séries
230
+
113
231
  ## Current Scope
114
232
 
115
233
  This first published version is focused on the core runtime:
@@ -118,6 +236,16 @@ This first published version is focused on the core runtime:
118
236
  - canonical chart contracts and runtime models
119
237
  - the initial ECharts-based engine adapter
120
238
  - metadata and mapping hooks for registry and dynamic widget composition
239
+ - remote execution focused on canonical `praxis.stats`
240
+
241
+ ## Current Non-Goals
242
+
243
+ The current runtime does not yet expose as stable public surface:
244
+
245
+ - direct host control over raw ECharts options as the primary contract
246
+ - declarative cross-filter orchestration
247
+ - declarative selectionChange runtime actions
248
+ - palette token indirection or theme variants from `x-ui.chart`
121
249
 
122
250
  ## Notes for Hosts
123
251
 
@@ -1113,7 +1113,7 @@ const PRAXIS_CHART_COMPONENT_METADATA = {
1113
1113
  {
1114
1114
  name: 'queryRequest',
1115
1115
  type: 'PraxisChartQueryRequestEvent',
1116
- description: 'Emitted before a remote praxis.stats datasource is resolved, allowing host-side observability or overrides.',
1116
+ description: 'Emitted before a remote praxis.stats datasource is resolved, allowing host-side observability of the outgoing request.',
1117
1117
  },
1118
1118
  {
1119
1119
  name: 'loadStateChange',
@@ -1617,8 +1617,13 @@ class PraxisChartCanonicalContractMapperService {
1617
1617
  throw new Error('x-ui.chart combo charts over praxis.stats currently support only group-by or timeseries operations in @praxisui/charts.');
1618
1618
  }
1619
1619
  }
1620
- if (contract.source.kind === 'praxis.stats' && contract.metrics.length > 1 && contract.kind !== 'combo') {
1621
- throw new Error('x-ui.chart praxis.stats currently supports a single metric per chart in @praxisui/charts.');
1620
+ if (contract.kind !== 'combo' && contract.metrics.some((metric) => metric.axis === 'secondary')) {
1621
+ throw new Error('x-ui.chart axis="secondary" is supported only for combo charts in @praxisui/charts.');
1622
+ }
1623
+ if (contract.source.kind === 'praxis.stats'
1624
+ && contract.source.operation === 'distribution'
1625
+ && contract.metrics.length > 1) {
1626
+ throw new Error('x-ui.chart praxis.stats distribution currently supports only a single metric in @praxisui/charts.');
1622
1627
  }
1623
1628
  if (contract.kind === 'horizontal-bar' && contract.orientation && contract.orientation !== 'horizontal') {
1624
1629
  throw new Error('x-ui.chart kind="horizontal-bar" requires orientation="horizontal" when orientation is provided.');
@@ -1640,6 +1645,7 @@ class PraxisChartCanonicalContractMapperService {
1640
1645
  const firstDimension = contract.dimensions?.[0];
1641
1646
  const firstMetric = contract.metrics?.[0];
1642
1647
  const secondaryMetric = contract.metrics?.find((metric) => metric.axis === 'secondary');
1648
+ const metricCount = contract.metrics?.length ?? 0;
1643
1649
  if (contract.kind === 'pie' || contract.kind === 'donut') {
1644
1650
  return {
1645
1651
  x: {
@@ -1669,7 +1675,7 @@ class PraxisChartCanonicalContractMapperService {
1669
1675
  type: firstDimension?.role === 'time' ? 'time' : 'category',
1670
1676
  },
1671
1677
  y: {
1672
- label: this.toLabel(firstMetric?.label),
1678
+ label: metricCount > 1 ? undefined : this.toLabel(firstMetric?.label),
1673
1679
  type: 'value',
1674
1680
  },
1675
1681
  ySecondary: contract.kind === 'combo' && secondaryMetric
@@ -2518,6 +2524,72 @@ const PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA = {
2518
2524
  },
2519
2525
  },
2520
2526
  };
2527
+ const PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR = {
2528
+ schemaMeta: {
2529
+ schemaId: 'api/human-resources/vw-analytics-folha-pagamento|post|response|tenant:demo|locale:pt-BR',
2530
+ schemaHash: 'published-hash-payroll-multi-metric-bar-v1',
2531
+ resourcePath: 'api/human-resources/vw-analytics-folha-pagamento',
2532
+ operation: 'post',
2533
+ schemaType: 'response',
2534
+ source: 'backend',
2535
+ },
2536
+ widget: {
2537
+ kind: 'x-ui.chart',
2538
+ key: 'payroll-multi-metric-bar',
2539
+ layout: { col: 1, row: 13, colSpan: 12, rowSpan: 4 },
2540
+ shell: {
2541
+ title: 'Comparativo por departamento',
2542
+ subtitle: 'Bar chart multi-metrico sobre praxis.stats group-by',
2543
+ },
2544
+ chart: {
2545
+ version: '0.1.0',
2546
+ kind: 'bar',
2547
+ preset: 'comparison',
2548
+ chartId: 'payroll-multi-metric-bar',
2549
+ title: { key: 'charts.payroll.multiMetric.title', fallback: 'Comparativo por departamento' },
2550
+ subtitle: {
2551
+ key: 'charts.payroll.multiMetric.subtitle',
2552
+ fallback: 'Massa liquida e desconto medio via group-by sem eixo secundario',
2553
+ },
2554
+ height: 340,
2555
+ source: {
2556
+ kind: 'praxis.stats',
2557
+ resource: 'api/human-resources/vw-analytics-folha-pagamento',
2558
+ operation: 'group-by',
2559
+ options: {
2560
+ orderBy: 'value-desc',
2561
+ limit: 8,
2562
+ },
2563
+ },
2564
+ dimensions: [
2565
+ {
2566
+ field: 'departamento',
2567
+ label: 'Departamento',
2568
+ role: 'category',
2569
+ },
2570
+ ],
2571
+ metrics: [
2572
+ {
2573
+ field: 'salarioLiquido',
2574
+ label: 'Massa liquida',
2575
+ aggregation: 'sum',
2576
+ color: '#1263b4',
2577
+ },
2578
+ {
2579
+ field: 'pctDesconto',
2580
+ label: 'Desconto medio',
2581
+ aggregation: 'avg',
2582
+ color: '#0f766e',
2583
+ },
2584
+ ],
2585
+ legend: { enabled: true },
2586
+ tooltip: { enabled: true },
2587
+ theme: {
2588
+ palette: ['#1263b4', '#0f766e'],
2589
+ },
2590
+ },
2591
+ },
2592
+ };
2521
2593
  const PRAXIS_CHART_BACKEND_MOCK_SCATTER = {
2522
2594
  schemaMeta: {
2523
2595
  schemaId: 'api/human-resources/vw-analytics-folha-pagamento|post|response|tenant:demo|locale:pt-BR',
@@ -2650,6 +2722,7 @@ function buildPraxisChartMockWidgetPage(adapter) {
2650
2722
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_DONUT)),
2651
2723
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_HORIZONTAL_BAR)),
2652
2724
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA)),
2725
+ withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR)),
2653
2726
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_SCATTER)),
2654
2727
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_COMBO)),
2655
2728
  ],
@@ -2668,6 +2741,7 @@ function buildPraxisChartMockGridPage(adapter) {
2668
2741
  withShowcaseViewToggle(adapter.toGridWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_DONUT)),
2669
2742
  withShowcaseViewToggle(adapter.toGridWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_HORIZONTAL_BAR)),
2670
2743
  withShowcaseViewToggle(adapter.toGridWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA)),
2744
+ withShowcaseViewToggle(adapter.toGridWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR)),
2671
2745
  withShowcaseViewToggle(adapter.toGridWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_SCATTER)),
2672
2746
  withShowcaseViewToggle(adapter.toGridWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_COMBO)),
2673
2747
  ],
@@ -2714,6 +2788,7 @@ function buildPraxisChartInteractiveWidgetPage(adapter) {
2714
2788
  },
2715
2789
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_DONUT)),
2716
2790
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA)),
2791
+ withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR)),
2717
2792
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_SCATTER)),
2718
2793
  withShowcaseViewToggle(adapter.toWidgetInstance(PRAXIS_CHART_BACKEND_MOCK_COMBO)),
2719
2794
  ],
@@ -2768,18 +2843,25 @@ function buildPraxisChartInteractiveGridPage(adapter) {
2768
2843
  layout: { col: 1, row: 13, colSpan: 12, rowSpan: 4 },
2769
2844
  },
2770
2845
  })),
2846
+ withShowcaseViewToggle(adapter.toGridWidgetInstance({
2847
+ ...PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR,
2848
+ widget: {
2849
+ ...PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR.widget,
2850
+ layout: { col: 1, row: 17, colSpan: 12, rowSpan: 4 },
2851
+ },
2852
+ })),
2771
2853
  withShowcaseViewToggle(adapter.toGridWidgetInstance({
2772
2854
  ...PRAXIS_CHART_BACKEND_MOCK_SCATTER,
2773
2855
  widget: {
2774
2856
  ...PRAXIS_CHART_BACKEND_MOCK_SCATTER.widget,
2775
- layout: { col: 1, row: 17, colSpan: 12, rowSpan: 4 },
2857
+ layout: { col: 1, row: 21, colSpan: 12, rowSpan: 4 },
2776
2858
  },
2777
2859
  })),
2778
2860
  withShowcaseViewToggle(adapter.toGridWidgetInstance({
2779
2861
  ...PRAXIS_CHART_BACKEND_MOCK_COMBO,
2780
2862
  widget: {
2781
2863
  ...PRAXIS_CHART_BACKEND_MOCK_COMBO.widget,
2782
- layout: { col: 1, row: 21, colSpan: 12, rowSpan: 4 },
2864
+ layout: { col: 1, row: 25, colSpan: 12, rowSpan: 4 },
2783
2865
  },
2784
2866
  })),
2785
2867
  ],
@@ -3007,6 +3089,8 @@ class PraxisChartCompositionShowcaseComponent {
3007
3089
  return 'Envelope horizontal-bar';
3008
3090
  case 'stacked-area':
3009
3091
  return 'Envelope stacked-area';
3092
+ case 'multi-metric-bar':
3093
+ return 'Envelope multi-metric bar';
3010
3094
  case 'scatter':
3011
3095
  return 'Envelope scatter';
3012
3096
  case 'combo':
@@ -3027,6 +3111,8 @@ class PraxisChartCompositionShowcaseComponent {
3027
3111
  return PRAXIS_CHART_BACKEND_MOCK_HORIZONTAL_BAR;
3028
3112
  case 'stacked-area':
3029
3113
  return PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA;
3114
+ case 'multi-metric-bar':
3115
+ return PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR;
3030
3116
  case 'scatter':
3031
3117
  return PRAXIS_CHART_BACKEND_MOCK_SCATTER;
3032
3118
  case 'combo':
@@ -3081,6 +3167,9 @@ class PraxisChartCompositionShowcaseComponent {
3081
3167
  <button type="button" [class.active]="payloadMode() === 'stacked-area'" (click)="payloadMode.set('stacked-area')">
3082
3168
  Stacked area
3083
3169
  </button>
3170
+ <button type="button" [class.active]="payloadMode() === 'multi-metric-bar'" (click)="payloadMode.set('multi-metric-bar')">
3171
+ Multi-metric bar
3172
+ </button>
3084
3173
  <button type="button" [class.active]="payloadMode() === 'scatter'" (click)="payloadMode.set('scatter')">
3085
3174
  Scatter
3086
3175
  </button>
@@ -3195,6 +3284,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3195
3284
  <button type="button" [class.active]="payloadMode() === 'stacked-area'" (click)="payloadMode.set('stacked-area')">
3196
3285
  Stacked area
3197
3286
  </button>
3287
+ <button type="button" [class.active]="payloadMode() === 'multi-metric-bar'" (click)="payloadMode.set('multi-metric-bar')">
3288
+ Multi-metric bar
3289
+ </button>
3198
3290
  <button type="button" [class.active]="payloadMode() === 'scatter'" (click)="payloadMode.set('scatter')">
3199
3291
  Scatter
3200
3292
  </button>
@@ -3272,5 +3364,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3272
3364
  * Generated bundle index. Do not edit.
3273
3365
  */
3274
3366
 
3275
- export { PRAXIS_CHART_BACKEND_MOCK_BAR, PRAXIS_CHART_BACKEND_MOCK_COMBO, PRAXIS_CHART_BACKEND_MOCK_DONUT, PRAXIS_CHART_BACKEND_MOCK_HORIZONTAL_BAR, PRAXIS_CHART_BACKEND_MOCK_SCATTER, PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA, PRAXIS_CHART_BACKEND_MOCK_TIMESERIES, PRAXIS_CHART_COMPONENT_METADATA, PRAXIS_CHART_DRILLDOWN_DATA_BY_MONTH, PRAXIS_CHART_DRILLDOWN_PANEL_METADATA, PRAXIS_CHART_ENGINE, PRAXIS_CHART_STATE_PROBE_COMPONENT_METADATA, PraxisChartBackendPayloadAdapterService, PraxisChartCanonicalContractMapperService, PraxisChartComponent, PraxisChartCompositionShowcaseComponent, PraxisChartDataTransformerService, PraxisChartDrilldownPanelComponent, PraxisChartOptionBuilderService, PraxisChartSchemaMapperService, PraxisChartStateProbeComponent, PraxisChartStatsApiService, buildPraxisChartInteractiveGridPage, buildPraxisChartInteractiveWidgetPage, buildPraxisChartMockGridPage, buildPraxisChartMockWidgetPage, providePraxisChartDrilldownPanelMetadata, providePraxisChartStateProbeMetadata, providePraxisCharts, providePraxisChartsMetadata };
3367
+ export { PRAXIS_CHART_BACKEND_MOCK_BAR, PRAXIS_CHART_BACKEND_MOCK_COMBO, PRAXIS_CHART_BACKEND_MOCK_DONUT, PRAXIS_CHART_BACKEND_MOCK_HORIZONTAL_BAR, PRAXIS_CHART_BACKEND_MOCK_MULTI_METRIC_BAR, PRAXIS_CHART_BACKEND_MOCK_SCATTER, PRAXIS_CHART_BACKEND_MOCK_STACKED_AREA, PRAXIS_CHART_BACKEND_MOCK_TIMESERIES, PRAXIS_CHART_COMPONENT_METADATA, PRAXIS_CHART_DRILLDOWN_DATA_BY_MONTH, PRAXIS_CHART_DRILLDOWN_PANEL_METADATA, PRAXIS_CHART_ENGINE, PRAXIS_CHART_STATE_PROBE_COMPONENT_METADATA, PraxisChartBackendPayloadAdapterService, PraxisChartCanonicalContractMapperService, PraxisChartComponent, PraxisChartCompositionShowcaseComponent, PraxisChartDataTransformerService, PraxisChartDrilldownPanelComponent, PraxisChartOptionBuilderService, PraxisChartSchemaMapperService, PraxisChartStateProbeComponent, PraxisChartStatsApiService, buildPraxisChartInteractiveGridPage, buildPraxisChartInteractiveWidgetPage, buildPraxisChartMockGridPage, buildPraxisChartMockWidgetPage, providePraxisChartDrilldownPanelMetadata, providePraxisChartStateProbeMetadata, providePraxisCharts, providePraxisChartsMetadata };
3276
3368
  //# sourceMappingURL=praxisui-charts.mjs.map