react-semaphor 0.1.545 → 0.1.547
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/dist/analytics-protocol/index.js +408 -442
- package/dist/assistant-context/index.js +1 -1
- package/dist/assistant-protocol/index.js +100 -76
- package/dist/brand-studio/index.js +4 -4
- package/dist/briefings/index.js +6 -6
- package/dist/chunks/{add-to-dashboard-BuAqfA2Y.js → add-to-dashboard-BQRAAnc3.js} +55 -33
- package/dist/chunks/{analytics-base-schemas-BFAoRlkU.js → analytics-base-schemas-BKs3flFS.js} +2 -2
- package/dist/chunks/applied-constraints-DU-wndZ7.js +47 -0
- package/dist/chunks/{assistant-chat-D7sWTypJ.js → assistant-chat-CK84cPAB.js} +2826 -2595
- package/dist/chunks/{bookmark-state-CXw7lZ50.js → bookmark-state-Cu-a5ie_.js} +8 -15
- package/dist/chunks/comparison-window-caption-C2xF-eWw.js +1433 -0
- package/dist/chunks/{context-ClREvqCZ.js → context-BerEBuFR.js} +11 -6
- package/dist/chunks/custom-visual-inputs-ChL54gGm.js +295 -0
- package/dist/chunks/{dashboard-B1tMju0u.js → dashboard-DCk26-6i.js} +1 -1
- package/dist/chunks/{dashboard-briefing-launcher-CePgIu0Z.js → dashboard-briefing-launcher-CQ1eYsGy.js} +1291 -1277
- package/dist/chunks/dashboard-controls-BMeZjF7r.js +2307 -0
- package/dist/chunks/{dashboard-json-CoYRPqxx.js → dashboard-json-BZqCoanC.js} +5 -5
- package/dist/chunks/{document-dashboard-inputs-BesAHZvB.js → document-dashboard-inputs-tYd7ao0o.js} +877 -979
- package/dist/chunks/{edit-dashboard-visual-JPtNfJRb.js → edit-dashboard-visual-Bv3MHM_G.js} +2157 -2243
- package/dist/chunks/filter-reach-copy-CGWsL_ez.js +3480 -0
- package/dist/chunks/{filter-value-text-ff7osJr7.js → filter-value-text-Ddf55Ku1.js} +9 -9
- package/dist/chunks/global-date-filter-utils-BhAu8zIM.js +12137 -0
- package/dist/chunks/index-CtoK1Lgu.js +586 -0
- package/dist/chunks/{index-DRWiuqyd.js → index-DmrLP5Ro.js} +105 -104
- package/dist/chunks/list-filter-DsaTbM3J.js +15 -0
- package/dist/chunks/matrix-analytical-definition-B9vW-osb.js +717 -0
- package/dist/chunks/{matrix-card-DjwWcCo8.js → matrix-card-LiMEipvq.js} +3 -3
- package/dist/chunks/{matrix-formatter-DnCyRXJE.js → matrix-formatter-DWEeC0_c.js} +44 -44
- package/dist/chunks/{matrix-member-presentation-CQGdVks6.js → matrix-member-presentation-DqzG-UhQ.js} +1 -1
- package/dist/chunks/{matrix-operation-contract-8OIO4gob.js → matrix-operation-contract-D6vYkZK4.js} +72 -72
- package/dist/chunks/{metric-comparison-DEwi9uc2.js → metric-comparison-zpGw4lD6.js} +2 -2
- package/dist/chunks/normalize-dashboard-for-dirty-check-XKgH3GFX.js +119 -0
- package/dist/chunks/{pivot-header-presentation-DHcx1XGQ.js → pivot-header-presentation-CQnIDtUv.js} +1 -1
- package/dist/chunks/{pivot-result-identity-DJhXXcns.js → pivot-result-identity-C-Q1j1Wb.js} +1 -1
- package/dist/chunks/{pivot-result-lifecycle-DM4CyGKs.js → pivot-result-lifecycle-pwq3b7LC.js} +571 -380
- package/dist/chunks/{raw-temporal-contract-C51YG48G.js → raw-temporal-contract-WuXA8jBP.js} +1 -1
- package/dist/chunks/{raw-temporal-presentation-C3mUgnEx.js → raw-temporal-presentation-DypB7sMX.js} +8 -8
- package/dist/chunks/{report-preferences-dialog-DUtuUL_5.js → report-preferences-dialog-DoVyriYC.js} +154 -155
- package/dist/chunks/{report-runtime-context-Dq8XyODK.js → report-runtime-context-hWiTCzFV.js} +2 -2
- package/dist/chunks/resolve-dashboard-input-context-D0JDUa4h.js +5576 -0
- package/dist/chunks/{saved-dashboard-context-LrF_kW0l.js → saved-dashboard-context-BfAH5j4L.js} +34 -34
- package/dist/chunks/{selection-reducer-Dj_8xD69.js → selection-reducer-CJzkTZio.js} +15 -15
- package/dist/chunks/{semaphor-ready-indicator-BxF96Yhv.js → semaphor-ready-indicator-CRm17oIP.js} +51771 -52574
- package/dist/chunks/{shelf-drop-preview-context-CNaM_Gmh.js → shelf-drop-preview-context-vy6P9THz.js} +7 -7
- package/dist/chunks/{source-entity-resolution-BYn9giz3.js → source-entity-resolution-BIGRvtbG.js} +13 -13
- package/dist/chunks/{switch-uDtPgQlQ.js → switch-CEBOR4n7.js} +3 -3
- package/dist/chunks/{table-export-sheet-YzMioA7Y.js → table-export-sheet-4X9mAG3V.js} +1 -1
- package/dist/chunks/table-settings-WysCBj62.js +614 -0
- package/dist/chunks/{temporal-bucket-D7NBrrtL.js → temporal-bucket-CQOSbv9-.js} +26 -26
- package/dist/chunks/{token-types-DBbZVQsm.js → token-types-BMqRmT-C.js} +1 -1
- package/dist/chunks/{use-create-flow-overlay-state-CjB7ig1o.js → use-create-flow-overlay-state-Csx_Xjsh.js} +101 -101
- package/dist/chunks/{validators-DMHTpf7a.js → validators-C-aOQlTB.js} +713 -658
- package/dist/chunks/{relative-date-label-Bk2j94pA.js → zoned-wall-clock-MulfA26h.js} +64 -21
- package/dist/dashboard/index.js +2 -2
- package/dist/dashboard-authoring/index.js +1895 -1163
- package/dist/data-app-sdk/index.js +6 -6
- package/dist/data-app-sdk-adapters/index.js +3 -3
- package/dist/data-app-sdk-validation/index.js +14 -14
- package/dist/format-utils/index.js +133 -133
- package/dist/index.js +192 -186
- package/dist/layouts/index.js +5 -242
- package/dist/report-runtime-context/index.js +2 -2
- package/dist/shared/index.js +4 -5
- package/dist/style.css +1 -1
- package/dist/surfboard/index.js +2 -2
- package/dist/types/components/index.d.ts +2 -0
- package/dist/types/components/surfboard/arrange-layout-button.d.ts +8 -0
- package/dist/types/components/surfboard/filter/types.d.ts +7 -0
- package/dist/types/components/surfboard/screen-size-preview-button.d.ts +10 -0
- package/dist/types/components/visual/matrix-table/matrix-card-view.d.ts +3 -0
- package/dist/types/index.js +6 -6
- package/dist/types/lib/charts/table-chart-types.d.ts +4 -0
- package/dist/types/lib/charts/types.d.ts +2 -2
- package/dist/types/lib/dashboard-inputs/dashboard-filter-mapping-authoring.d.ts +346 -21
- package/dist/types/lib/dashboard-inputs/dashboard-filter-value-identity.d.ts +65 -0
- package/dist/types/lib/dashboard-inputs/dashboard-input-values.d.ts +6 -0
- package/dist/types/lib/dashboard-inputs/filter-settings.d.ts +2 -0
- package/dist/types/lib/dashboard-inputs/prepare-loaded-dashboard.d.ts +15 -0
- package/dist/types/lib/dashboard-inputs/resolve-selection-input.d.ts +3 -3
- package/dist/types/lib/hooks/use-dashboard-card.d.ts +2 -0
- package/dist/types/lib/matrix-table/matrix-delivery-policy.d.ts +1 -1
- package/dist/types/lib/matrix-table/matrix-editor.d.ts +52 -0
- package/dist/types/lib/matrix-table/matrix-runtime-types.d.ts +9 -1
- package/dist/types/lib/matrix-table/matrix-runtime.d.ts +5 -1
- package/dist/types/lib/query-context/dashboard-filter-mapping-resolution.d.ts +149 -10
- package/dist/types/lib/stores/dashboard-store.d.ts +137 -6
- package/dist/types/lib/types/common-types.d.ts +8 -0
- package/dist/types/lib/types/explorer-types.d.ts +10 -0
- package/dist/types/lib/types/semantic-types.d.ts +84 -0
- package/dist/types/lib/utils/build-saved-editor-card.d.ts +20 -0
- package/dist/types/lib/utils/card-type-change.d.ts +16 -0
- package/dist/types/lib/utils/field-availability-context.d.ts +25 -0
- package/dist/types/lib/utils/field-placement.d.ts +96 -0
- package/dist/types/lib/utils/field-state-calculator.d.ts +161 -0
- package/dist/types/lib/utils/qualified-entity-name.d.ts +2 -0
- package/dist/types/shared/analytics-protocol/applied-constraints.d.ts +57 -1
- package/dist/types/shared/analytics-protocol/field-provenance.d.ts +89 -0
- package/dist/types/shared/analytics-protocol/index.d.ts +2 -0
- package/dist/types/shared/analytics-protocol/query-policies.d.ts +52 -0
- package/dist/types/shared/analytics-protocol/time-window-schema.d.ts +1 -1
- package/dist/types/shared/analytics-protocol/time-window.d.ts +40 -1
- package/dist/types/shared/assistant-context/saved-dashboard-context.d.ts +4 -1
- package/dist/types/shared/assistant-protocol/answer-text.d.ts +20 -0
- package/dist/types/shared/assistant-protocol/context.d.ts +29 -29
- package/dist/types/shared/assistant-protocol/index.d.ts +1 -0
- package/dist/types/shared/assistant-protocol/limits.d.ts +6 -1
- package/dist/types/shared/assistant-protocol/parts.d.ts +43 -3
- package/dist/types/shared/assistant-protocol/request.d.ts +14 -2
- package/dist/types/shared/dashboard-authoring/calculated-field-identity.d.ts +3 -0
- package/dist/types/shared/dashboard-authoring/changes/card-query-part.d.ts +487 -0
- package/dist/types/shared/dashboard-authoring/changes/card-types.d.ts +34 -0
- package/dist/types/shared/dashboard-authoring/changes/dashboard-change.d.ts +7886 -0
- package/dist/types/shared/dashboard-authoring/changes/diagnostics.d.ts +45 -0
- package/dist/types/shared/dashboard-authoring/changes/read-card-query.d.ts +54 -0
- package/dist/types/shared/dashboard-authoring/changes/resolve-dashboard-changes.d.ts +96 -0
- package/dist/types/shared/dashboard-authoring/click-to-filter-settings.d.ts +3 -3
- package/dist/types/shared/dashboard-authoring/column-catalog.d.ts +32 -0
- package/dist/types/shared/dashboard-authoring/contracts.d.ts +0 -55
- package/dist/types/shared/dashboard-authoring/control-execution-contract.d.ts +24 -14
- package/dist/types/shared/dashboard-authoring/dashboard-card-source-index.d.ts +9 -1
- package/dist/types/shared/dashboard-authoring/dashboard-filter-automatic-target.d.ts +4 -4
- package/dist/types/shared/dashboard-authoring/dashboard-filter-mapping-contract.d.ts +3 -1
- package/dist/types/shared/dashboard-authoring/dashboard-filter-mapping-types.d.ts +27 -1
- package/dist/types/shared/dashboard-authoring/dashboard-filter-value-compatibility.d.ts +12 -3
- package/dist/types/shared/dashboard-authoring/dashboard-input-scope.d.ts +26 -0
- package/dist/types/shared/dashboard-authoring/filter-applicability.d.ts +75 -0
- package/dist/types/shared/dashboard-authoring/filter-reach-copy.d.ts +18 -0
- package/dist/types/shared/dashboard-authoring/filter-reach-preview.d.ts +97 -0
- package/dist/types/shared/dashboard-authoring/index.d.ts +22 -2
- package/dist/types/shared/dashboard-authoring/operations/apply-dashboard-operations.d.ts +10 -37
- package/dist/types/shared/dashboard-authoring/operations/operation-types.d.ts +189 -0
- package/dist/types/shared/dashboard-authoring/outline/outline-dashboard.d.ts +101 -0
- package/dist/types/shared/dashboard-authoring/outline/outline-filters.d.ts +100 -0
- package/dist/types/shared/dashboard-authoring/semantic-auto-join-card.d.ts +22 -0
- package/dist/types/shared/dashboard-authoring/validators.d.ts +1 -2
- package/dist/types/shared/layouts/engine/grid.d.ts +25 -0
- package/dist/types/shared/layouts/engine/index.d.ts +4 -0
- package/dist/types/shared/layouts/engine/sheet-layout.d.ts +7 -0
- package/dist/types/shared/layouts/engine/types.d.ts +125 -0
- package/dist/types/shared/layouts/index.d.ts +1 -2
- package/package.json +2 -2
- package/dist/chunks/apply-dashboard-operations-CZEMsx8E.js +0 -2080
- package/dist/chunks/calendar-day-equality-dvoQp1xW.js +0 -410
- package/dist/chunks/comparison-window-caption-D4E6IHPD.js +0 -1624
- package/dist/chunks/custom-visual-inputs-DLCD9Y5V.js +0 -329
- package/dist/chunks/dashboard-controls-Cq05n3e0.js +0 -2315
- package/dist/chunks/dashboard-filter-value-compatibility-CwQ_iSNb.js +0 -108
- package/dist/chunks/matrix-analytical-definition-C7Gb0e12.js +0 -117
- package/dist/chunks/normalize-dashboard-for-dirty-check-Bk3VYv_q.js +0 -67
- package/dist/chunks/numeric-presentation-7X_IrD58.js +0 -5226
- package/dist/chunks/resolve-dashboard-input-context-DJ2tICwz.js +0 -9415
- package/dist/chunks/stable-serialize-CfqXeiBP.js +0 -6
- package/dist/chunks/table-settings-CLZocegs.js +0 -501
- package/dist/chunks/use-debounced-dirty-check-BwAbnX_5.js +0 -59
- package/dist/chunks/zoned-wall-clock-BkxV9jS2.js +0 -46
- package/dist/types/shared/dashboard-authoring/change-compiler.d.ts +0 -7
- package/dist/types/shared/dashboard-authoring/layout-compiler.d.ts +0 -2
- package/dist/types/shared/layouts/create-frame-layouts.d.ts +0 -27
- package/dist/types/shared/layouts/frame-layouts.d.ts +0 -23
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joinability types: the response of GET /api/v1/domains/[domainId]/joinability,
|
|
3
|
+
* used by field draggability states in the query builder.
|
|
4
|
+
*
|
|
5
|
+
* The domain template contract (datasets, fields, metrics, relationships) has one
|
|
6
|
+
* owner, semaphor-app (`src/lib/semantic/template/contract.ts`); it is not copied
|
|
7
|
+
* here. If a react-semaphor consumer ever needs template types, move the contract
|
|
8
|
+
* into react-semaphor's shared contracts and have the app import it, rather than
|
|
9
|
+
* copy it (domain template 2.1, ledger P2-20).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Joinability map for a semantic domain
|
|
13
|
+
*
|
|
14
|
+
* Maps each dataset to the datasets it can join with, including both direct (1-hop)
|
|
15
|
+
* and indirect (2-hop) joins. This is a lightweight topology representation used by
|
|
16
|
+
* the frontend for UX feedback (field draggability states).
|
|
17
|
+
*
|
|
18
|
+
* The backend generates this from the full relationship definitions and serves it
|
|
19
|
+
* via GET /api/v1/domains/[domainId]/joinability
|
|
20
|
+
*/
|
|
21
|
+
export interface JoinabilityMap {
|
|
22
|
+
[datasetName: string]: {
|
|
23
|
+
/**
|
|
24
|
+
* Datasets that can be joined directly (1-hop)
|
|
25
|
+
* Example: orders.canJoinTo = ['customers', 'products']
|
|
26
|
+
*/
|
|
27
|
+
canJoinTo: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Datasets that require multi-hop joins (2-hop)
|
|
30
|
+
* Key: target dataset name
|
|
31
|
+
* Value: array of intermediate datasets to traverse
|
|
32
|
+
*
|
|
33
|
+
* Example: orders.indirectJoins = { countries: ['stores'] }
|
|
34
|
+
* Means: orders → stores → countries
|
|
35
|
+
*/
|
|
36
|
+
indirectJoins: {
|
|
37
|
+
[targetDataset: string]: string[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Datasets related by an ACTIVE relationship that is not set to join
|
|
41
|
+
* automatically. The query engine will not auto-join these; the user
|
|
42
|
+
* has to enable automatic join on the relationship or configure the
|
|
43
|
+
* join on the chart. Drives the "Requires setup" field state.
|
|
44
|
+
* Optional: older servers omit it.
|
|
45
|
+
*/
|
|
46
|
+
manualJoins?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Direct neighbours connected by MORE THAN ONE active auto-join
|
|
49
|
+
* relationship, with the count. The engine picks by join priority,
|
|
50
|
+
* so this is informational ("Multiple relationships; highest
|
|
51
|
+
* priority is used"), never blocking. Optional.
|
|
52
|
+
*/
|
|
53
|
+
ambiguousJoins?: {
|
|
54
|
+
[targetDataset: string]: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Cardinality of the direct auto-join, from THIS dataset's side.
|
|
58
|
+
* `one_to_many` means one row here matches many rows there, so an
|
|
59
|
+
* aggregate over this dataset's values joined to that dataset may
|
|
60
|
+
* repeat. `unknown` when the relationship has no authored cardinality
|
|
61
|
+
* (the planner refuses repeat-sensitive measures across it).
|
|
62
|
+
* Informational; drives a warning, never a block. Optional.
|
|
63
|
+
*/
|
|
64
|
+
cardinality?: {
|
|
65
|
+
[targetDataset: string]: 'one_to_one' | 'one_to_many' | 'many_to_one' | 'many_to_many' | 'unknown';
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Response from the joinability map API
|
|
71
|
+
*/
|
|
72
|
+
export interface JoinabilityMapResponse {
|
|
73
|
+
/** Lightweight joinability map for field state calculation */
|
|
74
|
+
joinabilityMap: JoinabilityMap;
|
|
75
|
+
/** Minimal dataset information */
|
|
76
|
+
datasets: Array<{
|
|
77
|
+
name: string;
|
|
78
|
+
label: string;
|
|
79
|
+
type: string;
|
|
80
|
+
table?: string | null;
|
|
81
|
+
catalog?: string | null;
|
|
82
|
+
schema?: string | null;
|
|
83
|
+
}>;
|
|
84
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TCard } from '../types/common-types.js';
|
|
2
|
+
type BuildSavedEditorCardOptions = {
|
|
3
|
+
isDevMode: boolean;
|
|
4
|
+
cardSql?: string;
|
|
5
|
+
selectedSchemaName?: string;
|
|
6
|
+
selectedDatabaseName?: string;
|
|
7
|
+
selectedTableName?: string;
|
|
8
|
+
selectedConnectionId?: string;
|
|
9
|
+
remoteChartSettings?: unknown;
|
|
10
|
+
stripConfig: (config: TCard['config']) => TCard['config'];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The card the editor saves. The editor's picker selection (database,
|
|
14
|
+
* schema, table, data model) is not written onto the card: a card's source is
|
|
15
|
+
* its `dataSource`, so Done with no change leaves the card as it was
|
|
16
|
+
* (MCP dashboard editing ledger V-50, V-58). A stored card's older copies of
|
|
17
|
+
* the picker stay as they are, read by nothing at run time.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildSavedEditorCard(card: TCard, { isDevMode, cardSql, selectedSchemaName, selectedDatabaseName, selectedTableName, selectedConnectionId, remoteChartSettings, stripConfig, }: BuildSavedEditorCardOptions): TCard;
|
|
20
|
+
export {};
|
|
@@ -8,6 +8,11 @@ export type CardTypeChangeOptions = {
|
|
|
8
8
|
catalogLoading?: boolean;
|
|
9
9
|
/** A plugin visual chosen as `custom`. */
|
|
10
10
|
customVisual?: TCustomCardPreferences;
|
|
11
|
+
/**
|
|
12
|
+
* Mints the ids the conversion needs (Matrix field instances), in order.
|
|
13
|
+
* Default `crypto.randomUUID`; a replayed change passes its stored ids (DE-D54).
|
|
14
|
+
*/
|
|
15
|
+
createId?: () => string;
|
|
11
16
|
};
|
|
12
17
|
export type CardTypeChange = {
|
|
13
18
|
status: 'refused';
|
|
@@ -19,6 +24,8 @@ export type CardTypeChange = {
|
|
|
19
24
|
card: TCard;
|
|
20
25
|
/** Labels of authored parts the new type could not keep. */
|
|
21
26
|
leftOut: readonly string[];
|
|
27
|
+
/** Chart-scoped preference keys the new type drops (DE-D43). */
|
|
28
|
+
droppedPreferences: readonly (keyof TCardPreferences)[];
|
|
22
29
|
crossedMatrixBoundary: boolean;
|
|
23
30
|
forcesSqlMode: boolean;
|
|
24
31
|
};
|
|
@@ -28,3 +35,12 @@ export type CardTypeChange = {
|
|
|
28
35
|
* the editor store applies the result.
|
|
29
36
|
*/
|
|
30
37
|
export declare function changeCardType(card: TCard, type: TCard['type'], options?: CardTypeChangeOptions): CardTypeChange;
|
|
38
|
+
/**
|
|
39
|
+
* A type change as a person makes it in the editor (MCP dashboard editing
|
|
40
|
+
* DE-D51, ledger P2-01): the chart picker is `changeCardType`; between table
|
|
41
|
+
* kinds the table editor's tabs are `switchTableType`. A detail table is
|
|
42
|
+
* reached only through the tabs, so a change into or out of one goes through
|
|
43
|
+
* a table, as the editor's two steps do. The dashboard reducer's `retype`
|
|
44
|
+
* calls this; the editor keeps calling each half from its own control.
|
|
45
|
+
*/
|
|
46
|
+
export declare function changeCardTypeAsEditor(card: TCard, type: TCard['type'], options?: CardTypeChangeOptions): CardTypeChange;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TCard } from '../types/common-types.js';
|
|
2
|
+
import { AutoJoinMetadata } from '../types/query-types.js';
|
|
3
|
+
import { JoinabilityMapResponse } from '../types/semantic-types.js';
|
|
4
|
+
import { FieldStateContext } from './field-state-calculator.js';
|
|
5
|
+
/**
|
|
6
|
+
* Everything `calculateFieldState` needs about a visual, except the
|
|
7
|
+
* selected fields (which differ per call). Built by ONE function so the
|
|
8
|
+
* field list, the click gate, the drop gate, and the matrix editor judge
|
|
9
|
+
* the same card from the same facts: the same join plan (the authored
|
|
10
|
+
* one, which is also right for matrix cards), the same auto-resolved
|
|
11
|
+
* base, the same relationship map, aliases, labels, mode, and data-source
|
|
12
|
+
* anchor. A caller that assembles these by hand will eventually disagree
|
|
13
|
+
* with the others; do not.
|
|
14
|
+
*/
|
|
15
|
+
export type FieldAvailabilityContext = Omit<FieldStateContext, 'selectedFields'> & {
|
|
16
|
+
/** The semantic domain the card reads, when any. */
|
|
17
|
+
semanticDomainId?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function buildFieldAvailabilityContext(input: {
|
|
20
|
+
card: Pick<TCard, 'type' | 'config' | 'dataSource'> | null | undefined;
|
|
21
|
+
joinabilityData?: JoinabilityMapResponse | null;
|
|
22
|
+
autoJoinMetadata?: AutoJoinMetadata;
|
|
23
|
+
/** Labels the caller knows from elsewhere (entity groups); catalog labels win. */
|
|
24
|
+
extraDatasetLabels?: Record<string, string>;
|
|
25
|
+
}): FieldAvailabilityContext;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { TCard, TCardPreferences } from '../types/common-types.js';
|
|
2
|
+
import { CardConfig, ContainerId, Field } from '../types/explorer-types.js';
|
|
3
|
+
import { MatrixCardCatalog } from '../matrix-table/matrix-card-adapter.js';
|
|
4
|
+
import { MatrixEditorChange } from '../matrix-table/matrix-editor.js';
|
|
5
|
+
import { FieldAvailabilityContext } from './field-availability-context.js';
|
|
6
|
+
import { FieldStateResult } from './field-state-calculator.js';
|
|
7
|
+
/**
|
|
8
|
+
* Field placement: the one rule for putting a field on a shelf.
|
|
9
|
+
*
|
|
10
|
+
* Every entry point (drop, move, reorder, click) and the drag preview call
|
|
11
|
+
* `evaluateFieldPlacement`; only `placeField` in `useFieldManagement` commits
|
|
12
|
+
* its outcome. The rules restate today's drag behavior per placement kind; see
|
|
13
|
+
* docs/implementation-plans/shelf-drop-placement/PLAN.md, "Placement rules".
|
|
14
|
+
*
|
|
15
|
+
* Evaluation is side-effect-free during the call: no id minting, store access,
|
|
16
|
+
* notifications, clock or random reads. New ids arrive in the context.
|
|
17
|
+
*/
|
|
18
|
+
export type ShelfZone = Exclude<ContainerId, 'source'>;
|
|
19
|
+
export declare const SHELF_ZONES: readonly ShelfZone[];
|
|
20
|
+
export type FieldPlacement = {
|
|
21
|
+
/** The field-list field, or the pill being moved. */
|
|
22
|
+
field: Field;
|
|
23
|
+
/** 'source' is the field list. */
|
|
24
|
+
from: ContainerId;
|
|
25
|
+
to: ShelfZone;
|
|
26
|
+
/** Pill to insert in front of; absent means the end. */
|
|
27
|
+
beforeId?: string;
|
|
28
|
+
};
|
|
29
|
+
export type FieldPlacementKind = 'add' | 'move' | 'copy-to-sort' | 'reorder';
|
|
30
|
+
export type FieldPlacementNotice = {
|
|
31
|
+
kind: 'join-required';
|
|
32
|
+
fieldState?: FieldStateResult;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'invalid-field-type';
|
|
35
|
+
reason: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'already-on-shelf';
|
|
38
|
+
zone: ShelfZone;
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'sort-needs-shelf-field';
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'cannot-sort-from-pivot';
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'matrix-refused';
|
|
45
|
+
message: string;
|
|
46
|
+
};
|
|
47
|
+
export type FieldPlacementCommit = {
|
|
48
|
+
cardKind: 'standard';
|
|
49
|
+
config: CardConfig;
|
|
50
|
+
/** null leaves the card's preferences untouched. */
|
|
51
|
+
preferences: TCardPreferences | null;
|
|
52
|
+
} | {
|
|
53
|
+
cardKind: 'matrix';
|
|
54
|
+
change: MatrixEditorChange;
|
|
55
|
+
};
|
|
56
|
+
export type FieldPlacementOutcome = {
|
|
57
|
+
kind: 'placed';
|
|
58
|
+
commit: FieldPlacementCommit;
|
|
59
|
+
}
|
|
60
|
+
/** A standard reorder onto its own slot. */
|
|
61
|
+
| {
|
|
62
|
+
kind: 'unchanged';
|
|
63
|
+
} | {
|
|
64
|
+
kind: 'refused';
|
|
65
|
+
notice: FieldPlacementNotice;
|
|
66
|
+
};
|
|
67
|
+
export type FieldPlacementContext = {
|
|
68
|
+
availability: FieldAvailabilityContext;
|
|
69
|
+
/** Ignored for standard cards. */
|
|
70
|
+
matrixCatalog: MatrixCardCatalog;
|
|
71
|
+
/** A string exactly when `needsNewFieldId` is true. */
|
|
72
|
+
newFieldId: string | null;
|
|
73
|
+
};
|
|
74
|
+
/** Reserved id for standard-card previews. Never matches a minted id and never reaches the store. */
|
|
75
|
+
export declare const PLACEMENT_PREVIEW_FIELD_ID = "__placement-preview__";
|
|
76
|
+
/**
|
|
77
|
+
* Reserved id for Matrix previews. The Matrix spec validates instance ids as
|
|
78
|
+
* UUIDs, so the preview needs one; minted ids are random v4 UUIDs and never
|
|
79
|
+
* equal this fixed value. Never reaches the store.
|
|
80
|
+
*/
|
|
81
|
+
export declare const MATRIX_PLACEMENT_PREVIEW_ID = "00000000-0000-4000-8000-000000000000";
|
|
82
|
+
/** The preview id for a card type. */
|
|
83
|
+
export declare function placementPreviewId(cardType: TCard['type'] | undefined): string;
|
|
84
|
+
export declare function classifyFieldPlacement(placement: Pick<FieldPlacement, 'from' | 'to'>): FieldPlacementKind;
|
|
85
|
+
/** Standard cards: every kind except reorder. Matrix: only from the field list. */
|
|
86
|
+
export declare function needsNewFieldId(cardType: TCard['type'] | undefined, placement: Pick<FieldPlacement, 'from' | 'to'>): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* A standard card's shelf as the editor shows it: stored fields with their
|
|
89
|
+
* shelf identity resolved and a label defaulted from the name.
|
|
90
|
+
*/
|
|
91
|
+
export declare function readStandardShelf(config: CardConfig | undefined, zone: ContainerId): Field[];
|
|
92
|
+
export declare function evaluateStandardPlacement(card: TCard, placement: FieldPlacement, context: FieldPlacementContext): FieldPlacementOutcome;
|
|
93
|
+
/** The one evaluation. Dispatches on card type. Side-effect-free. */
|
|
94
|
+
export declare function evaluateFieldPlacement(card: TCard, placement: FieldPlacement, context: FieldPlacementContext): FieldPlacementOutcome;
|
|
95
|
+
/** Preview text for the shelf header while a field hovers it. */
|
|
96
|
+
export declare function placementNoticeReason(notice: FieldPlacementNotice, shelfLabel: string): string;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Field, JoinPlan } from '../types/explorer-types.js';
|
|
2
|
+
import { JoinabilityMap } from '../types/semantic-types.js';
|
|
3
|
+
import { AutoJoinMetadata } from '../types/query-types.js';
|
|
4
|
+
import { resolveFieldDatasetDependencies, FieldDatasetDependency } from './field-dependencies.js';
|
|
5
|
+
import { getQualifiedEntityName } from './qualified-entity-name.js';
|
|
6
|
+
export interface DatasetIdentityAlias {
|
|
7
|
+
name: string;
|
|
8
|
+
table?: string | null;
|
|
9
|
+
catalog?: string | null;
|
|
10
|
+
schema?: string | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Field draggability states for the query builder
|
|
14
|
+
*
|
|
15
|
+
* - **base**: Field is from the base dataset (first dataset selected)
|
|
16
|
+
* - **draggable**: Field has a direct relationship to base dataset (1-hop)
|
|
17
|
+
* - **indirect**: Field requires a multi-hop join (2-hop via intermediate dataset)
|
|
18
|
+
* - **setup**: A relationship exists but the engine will not use it on its
|
|
19
|
+
* own (not set to auto-join). The user can fix this; until then the field
|
|
20
|
+
* is blocked exactly like `unreachable`.
|
|
21
|
+
* - **unreachable**: No relationship path exists to this field's dataset
|
|
22
|
+
*
|
|
23
|
+
* Calculated fields take the worst state among the datasets they read from.
|
|
24
|
+
*/
|
|
25
|
+
export type FieldDraggableState = 'base' | 'draggable' | 'indirect' | 'setup' | 'unreachable'
|
|
26
|
+
/**
|
|
27
|
+
* Nothing is on the shelves and the dataset is not one of the chart's
|
|
28
|
+
* data-source datasets. Not a fault to fix: the customer chose their
|
|
29
|
+
* datasets and this field reads another one. Blocked, with the path to
|
|
30
|
+
* using it (add the dataset) offered as information.
|
|
31
|
+
*/
|
|
32
|
+
| 'absent';
|
|
33
|
+
/** Per-dataset availability, attached to calculated-field results. */
|
|
34
|
+
export interface FieldDependencyState {
|
|
35
|
+
/** Catalog dataset name. */
|
|
36
|
+
entityName: string;
|
|
37
|
+
/** Customer-facing dataset label. */
|
|
38
|
+
label: string;
|
|
39
|
+
state: FieldDraggableState;
|
|
40
|
+
/** Customer-facing sentence when the dataset is not simply available. */
|
|
41
|
+
reason?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Result of field state calculation
|
|
45
|
+
*/
|
|
46
|
+
export interface FieldStateResult {
|
|
47
|
+
/** The calculated draggability state */
|
|
48
|
+
state: FieldDraggableState;
|
|
49
|
+
/** For indirect joins: the path through intermediate datasets */
|
|
50
|
+
joinPath?: string[];
|
|
51
|
+
/** `joinPath` as readers see it: dataset labels, in path order. */
|
|
52
|
+
joinPathLabels?: string[];
|
|
53
|
+
/** Short tooltip text explaining the state (row `title`). */
|
|
54
|
+
tooltip?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Customer-facing explanation when the field cannot be added as-is.
|
|
57
|
+
* Precise: names the dataset and the actual problem.
|
|
58
|
+
*/
|
|
59
|
+
reason?: string;
|
|
60
|
+
/** The one thing the user can do about `reason`, when there is one. */
|
|
61
|
+
action?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Dataset labels that `reason` mentions, so the UI can set them off from
|
|
64
|
+
* the surrounding sentence (a chip) without parsing the text.
|
|
65
|
+
*/
|
|
66
|
+
mentions?: string[];
|
|
67
|
+
/**
|
|
68
|
+
* Non-blocking caution from governed catalog metadata, for example a
|
|
69
|
+
* one-to-many join that can repeat an aggregate. Shown in the preview.
|
|
70
|
+
*/
|
|
71
|
+
warning?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Datasets a calculated field reads from, each with its own state.
|
|
74
|
+
* Undefined for base fields (their dataset is their group).
|
|
75
|
+
*/
|
|
76
|
+
dependencies?: FieldDependencyState[];
|
|
77
|
+
/**
|
|
78
|
+
* False when availability could not be checked (relationship map still
|
|
79
|
+
* loading, or a dependency could not be traced). UI must not present
|
|
80
|
+
* such a field as verified-ready.
|
|
81
|
+
*/
|
|
82
|
+
verified?: boolean;
|
|
83
|
+
/** Indicates if this field is already selected/in the query */
|
|
84
|
+
isSelected?: boolean;
|
|
85
|
+
}
|
|
86
|
+
/** States that block adding the field to the query. */
|
|
87
|
+
export declare function isBlockedFieldState(state: FieldDraggableState | undefined): boolean;
|
|
88
|
+
export interface FieldStateContext {
|
|
89
|
+
joinabilityMap: JoinabilityMap | null;
|
|
90
|
+
selectedFields: Field[];
|
|
91
|
+
joinPlan?: JoinPlan;
|
|
92
|
+
autoJoinMetadata?: AutoJoinMetadata;
|
|
93
|
+
baseEntityName?: string;
|
|
94
|
+
datasetAliases?: DatasetIdentityAlias[];
|
|
95
|
+
/**
|
|
96
|
+
* Whether the card reads from a semantic domain. Drives the fallback when
|
|
97
|
+
* `joinabilityMap` is null:
|
|
98
|
+
* - true -> the map is still loading: report `verified: false`.
|
|
99
|
+
* - false -> physical datasets: reachability comes from the join plan.
|
|
100
|
+
* - undefined (legacy callers) -> everything draggable, as before.
|
|
101
|
+
*/
|
|
102
|
+
hasSemanticDomain?: boolean;
|
|
103
|
+
/** Customer-facing dataset labels keyed by dataset name. */
|
|
104
|
+
datasetLabels?: Record<string, string>;
|
|
105
|
+
/**
|
|
106
|
+
* The datasets the chart's data source lists (`DataSource.selectedEntities`),
|
|
107
|
+
* in order. When nothing is on the shelves yet, these ARE the chart's
|
|
108
|
+
* datasets: a calculated field's dependencies are judged against them,
|
|
109
|
+
* so the card talks about the dataset the customer actually picked
|
|
110
|
+
* instead of the calculation's own first input.
|
|
111
|
+
*/
|
|
112
|
+
dataSourceEntities?: DatasetAnchorRef[];
|
|
113
|
+
}
|
|
114
|
+
/** Minimal entity reference the calculator needs to identify a dataset. */
|
|
115
|
+
export type DatasetAnchorRef = Parameters<typeof getQualifiedEntityName>[0];
|
|
116
|
+
/**
|
|
117
|
+
* Customer-facing words for a state, in one place. The row tag under a
|
|
118
|
+
* dependency and the title of the refusal toast both read from here.
|
|
119
|
+
*/
|
|
120
|
+
export declare function getFieldStateCopy(state: FieldDraggableState | undefined): {
|
|
121
|
+
/** Short tag beside a blocking dependency; null when nothing blocks. */
|
|
122
|
+
tag: string | null;
|
|
123
|
+
/** Title of the refusal toast. */
|
|
124
|
+
toastTitle: string;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Calculate the draggability state for a field in the query builder
|
|
128
|
+
*
|
|
129
|
+
* This determines whether a field can be dragged based on:
|
|
130
|
+
* - Current selected fields (what's already in the query)
|
|
131
|
+
* - Joinability map (what relationships exist between datasets)
|
|
132
|
+
* - For calculated fields: the datasets their inputs read from
|
|
133
|
+
*
|
|
134
|
+
* **Fallback behavior**:
|
|
135
|
+
* - No joinability map and no `hasSemanticDomain` flag: all fields draggable
|
|
136
|
+
* (legacy callers, no restrictions)
|
|
137
|
+
* - No fields selected yet: base fields are draggable (first selection
|
|
138
|
+
* establishes the base dataset); calculated fields are judged against the
|
|
139
|
+
* data source's datasets when there are any, else against their own first
|
|
140
|
+
* dataset
|
|
141
|
+
*/
|
|
142
|
+
export declare function calculateFieldState(field: Field, context: FieldStateContext): FieldStateResult;
|
|
143
|
+
/** One data-source dataset's connection to the visual's base, for the Datasets panel. */
|
|
144
|
+
export interface DataSourceConnection {
|
|
145
|
+
/** Dataset identity (name in semantic mode, qualified table in physical). */
|
|
146
|
+
entityName: string;
|
|
147
|
+
label: string;
|
|
148
|
+
state: FieldDraggableState;
|
|
149
|
+
reason?: string;
|
|
150
|
+
action?: string;
|
|
151
|
+
mentions?: string[];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* How each selected dataset connects to the visual's base dataset, using
|
|
155
|
+
* the same identity, base cascade, and per-dataset evaluation as the field
|
|
156
|
+
* list. The Datasets panel shows this at selection time so the customer
|
|
157
|
+
* learns about an unconnected dataset before the first drag. Order and
|
|
158
|
+
* verdicts match `calculateFieldState` for a field of that dataset.
|
|
159
|
+
*/
|
|
160
|
+
export declare function describeDataSourceConnections(context: FieldStateContext): DataSourceConnection[];
|
|
161
|
+
export { resolveFieldDatasetDependencies, type FieldDatasetDependency };
|
|
@@ -17,6 +17,33 @@ export type AppliedConstraintField = {
|
|
|
17
17
|
label?: string;
|
|
18
18
|
qualifiedName?: string;
|
|
19
19
|
};
|
|
20
|
+
/** To-one only with key proof (relationship filter reach RF-D12); anything else is to-many. */
|
|
21
|
+
export type SemaphorRelationshipDirection = 'to_one' | 'to_many';
|
|
22
|
+
/**
|
|
23
|
+
* The route a filter value took to a card through the domain's modeled
|
|
24
|
+
* relationships (relationship filter reach). Applied as "keep the card's rows
|
|
25
|
+
* that have at least one matching related row", so no row repeats.
|
|
26
|
+
*/
|
|
27
|
+
export type SemaphorRelationshipRoute = {
|
|
28
|
+
/** Ordered from the base dataset to the value's dataset; non-empty, no repeats. */
|
|
29
|
+
relationshipIds: string[];
|
|
30
|
+
/** The card's dataset the route starts from, for wording ("Projects with ..."). */
|
|
31
|
+
base?: {
|
|
32
|
+
name: string;
|
|
33
|
+
label?: string;
|
|
34
|
+
};
|
|
35
|
+
/** The datasets after the base, in order, for wording ("through Project"). */
|
|
36
|
+
datasets: Array<{
|
|
37
|
+
name: string;
|
|
38
|
+
label?: string;
|
|
39
|
+
}>;
|
|
40
|
+
direction: SemaphorRelationshipDirection;
|
|
41
|
+
/** For a to-many route: the dataset its first to-many step reaches (the copy's "matching {D}"). */
|
|
42
|
+
matchingDataset?: {
|
|
43
|
+
name: string;
|
|
44
|
+
label?: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
20
47
|
export type AppliedFilterCondition = {
|
|
21
48
|
/** The filter the condition came from: a dashboard input, a request filter, a time window. */
|
|
22
49
|
filterId: string;
|
|
@@ -41,6 +68,8 @@ export type AppliedFilterCondition = {
|
|
|
41
68
|
* Absent when it applied to the whole answer.
|
|
42
69
|
*/
|
|
43
70
|
measures?: string[];
|
|
71
|
+
/** The condition reached the card through these relationships. */
|
|
72
|
+
through?: SemaphorRelationshipRoute;
|
|
44
73
|
};
|
|
45
74
|
export type SemaphorAppliedConstraint = ({
|
|
46
75
|
kind: 'filter';
|
|
@@ -61,7 +90,13 @@ export type SemaphorAppliedConstraint = ({
|
|
|
61
90
|
grain?: MetricComparisonWindowGrain;
|
|
62
91
|
};
|
|
63
92
|
/** Why a condition was left out of the executed query. */
|
|
64
|
-
export type SemaphorSkippedConstraintReason = 'dataset_not_reachable' | 'field_not_resolvable' | 'missing_metadata' | 'unsupported_calculated_filter'
|
|
93
|
+
export type SemaphorSkippedConstraintReason = 'dataset_not_reachable' | 'field_not_resolvable' | 'missing_metadata' | 'unsupported_calculated_filter'
|
|
94
|
+
/** The relationships connect, but this card can't take the value through them. */
|
|
95
|
+
| 'relationship_unsupported'
|
|
96
|
+
/** No active modeled relationship connects the value's dataset to the card. */
|
|
97
|
+
| 'relationship_missing'
|
|
98
|
+
/** More than one equally preferred route connects them; the author chooses one. */
|
|
99
|
+
| 'relationship_ambiguous';
|
|
65
100
|
export type SemaphorSkippedConstraint = {
|
|
66
101
|
filterId?: string;
|
|
67
102
|
field?: AppliedConstraintField;
|
|
@@ -72,3 +107,24 @@ export type SemaphorQueryConstraints = {
|
|
|
72
107
|
applied: SemaphorAppliedConstraint[];
|
|
73
108
|
skipped: SemaphorSkippedConstraint[];
|
|
74
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Per filter, whether a card query applied it and why not (relationship
|
|
112
|
+
* filter reach RF-D22): built by the server from its one per-card
|
|
113
|
+
* resolution, keyed by the filter's id, never from the deduped evidence.
|
|
114
|
+
*/
|
|
115
|
+
export type SemaphorFilterReachEntry = {
|
|
116
|
+
filterId: string;
|
|
117
|
+
status: 'applied';
|
|
118
|
+
through?: SemaphorRelationshipRoute;
|
|
119
|
+
} | {
|
|
120
|
+
filterId: string;
|
|
121
|
+
status: 'skipped';
|
|
122
|
+
reason: SemaphorSkippedConstraintReason;
|
|
123
|
+
} | {
|
|
124
|
+
filterId: string;
|
|
125
|
+
status: 'blocked';
|
|
126
|
+
message: string;
|
|
127
|
+
};
|
|
128
|
+
export declare function readRelationshipRoute(value: unknown): SemaphorRelationshipRoute | undefined;
|
|
129
|
+
/** Reads `filterReach` from a raw `/api/v1/query` response body; [] when absent or malformed. */
|
|
130
|
+
export declare function readFilterReach(responseBody: unknown): SemaphorFilterReachEntry[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A column's aggregate and label, written with what they record about where
|
|
3
|
+
* they came from, in one place (MCP dashboard editing, ledger V-18). Every
|
|
4
|
+
* producer writes through here (the editor's aggregate menu and rename, the
|
|
5
|
+
* governed compiler, the MCP's stated labels) and every reader asks here, so
|
|
6
|
+
* the value and its provenance always tell one story. Before, the editor's
|
|
7
|
+
* aggregate menu changed `aggregate` and `aggregateOrigin` but left the
|
|
8
|
+
* compiler's record (`effectiveAggregate`, `aggregateSource`) stale, and the
|
|
9
|
+
* compiler copied a catalog `aggregateOrigin: "default"` onto an aggregate the
|
|
10
|
+
* caller chose.
|
|
11
|
+
*/
|
|
12
|
+
export type MetricAggregateSource = 'semantic_model' | 'caller_override' | 'default_sum';
|
|
13
|
+
/** A measure's aggregate and its provenance, as a saved column carries them (structural: any field type fits). */
|
|
14
|
+
export type MetricAggregateProvenance<A extends string = string> = {
|
|
15
|
+
aggregate?: A;
|
|
16
|
+
aggregateOrigin?: 'default' | 'explicit';
|
|
17
|
+
semanticAggregate?: A;
|
|
18
|
+
effectiveAggregate?: A;
|
|
19
|
+
aggregateSource?: MetricAggregateSource;
|
|
20
|
+
/** The field's type, which decides the default aggregate (`defaultMetricAggregate`). */
|
|
21
|
+
dataType?: string;
|
|
22
|
+
};
|
|
23
|
+
/** A column's label and its provenance. */
|
|
24
|
+
export type LabelProvenance = {
|
|
25
|
+
label?: string;
|
|
26
|
+
labelOrigin?: 'semantic' | 'override';
|
|
27
|
+
derivedLabel?: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* The aggregate a measure gets when nobody chooses one, the one rule the
|
|
31
|
+
* editor (a field dropped on the measures), the governed compiler and every
|
|
32
|
+
* reader share: the semantic model's, else SUM for a number (or a type not
|
|
33
|
+
* known) and COUNT for anything else.
|
|
34
|
+
*/
|
|
35
|
+
export declare function defaultMetricAggregate<A extends string>(semanticAggregate: A | undefined, dataType?: string): A | 'SUM' | 'COUNT';
|
|
36
|
+
/**
|
|
37
|
+
* The compiler's record of a measure's aggregate: the aggregate it runs, and
|
|
38
|
+
* whether that is the default or an override. Asking for SUM on a SUM measure
|
|
39
|
+
* is not an override (Analytics MCP focus 1.4b).
|
|
40
|
+
*/
|
|
41
|
+
export declare function metricAggregateRecord<A extends string>(input: {
|
|
42
|
+
aggregate: A;
|
|
43
|
+
semanticAggregate?: A;
|
|
44
|
+
dataType?: string;
|
|
45
|
+
}): {
|
|
46
|
+
effectiveAggregate: A;
|
|
47
|
+
aggregateSource: MetricAggregateSource;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* What to set on a measure for a new aggregate: the aggregate, whether
|
|
51
|
+
* someone chose it (`aggregateOrigin`), and, when the column carries the
|
|
52
|
+
* compiler's record, that record refreshed. A patch, for the editor's column
|
|
53
|
+
* updates; `withMetricAggregate` applies it.
|
|
54
|
+
*/
|
|
55
|
+
export declare function metricAggregatePatch<A extends string>(column: Pick<MetricAggregateProvenance<A>, 'semanticAggregate' | 'effectiveAggregate' | 'aggregateSource' | 'dataType'>, aggregate: A, origin: 'default' | 'explicit'): MetricAggregateProvenance<A>;
|
|
56
|
+
/** A measure with a new aggregate and its provenance (`metricAggregatePatch`). */
|
|
57
|
+
export declare function withMetricAggregate<T extends MetricAggregateProvenance>(column: T, aggregate: NonNullable<T['aggregate']>, origin: 'default' | 'explicit'): T;
|
|
58
|
+
/**
|
|
59
|
+
* The aggregate a measure runs: `aggregate`, which the query builder reads;
|
|
60
|
+
* the compiler's record only when it is all the column has. Readers ask here,
|
|
61
|
+
* so a column saved with a stale record is still read as it runs.
|
|
62
|
+
*/
|
|
63
|
+
export declare function metricColumnAggregate<A extends string>(column: Pick<MetricAggregateProvenance<A>, 'aggregate' | 'effectiveAggregate'>): A | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Whether someone chose a measure's aggregate rather than it being the
|
|
66
|
+
* default: the one reading of every stored shape. A column written here says
|
|
67
|
+
* so in `aggregateOrigin`; one saved before carries either the editor's mark,
|
|
68
|
+
* the compiler's record (an override, or a default the aggregate no longer
|
|
69
|
+
* equals because an editor change left the record stale), or neither (read as
|
|
70
|
+
* chosen, so a query states it).
|
|
71
|
+
*/
|
|
72
|
+
export declare function isMetricAggregateChosen(column: MetricAggregateProvenance): boolean;
|
|
73
|
+
/** The keys an authored label sets together. */
|
|
74
|
+
export declare const AUTHORED_LABEL_KEYS: readonly string[];
|
|
75
|
+
/**
|
|
76
|
+
* What to set for a label someone wrote: an override, which the editor never
|
|
77
|
+
* refreshes as a generated label, and no `derivedLabel`, so the field display
|
|
78
|
+
* rule reads it as authored even when it repeats the synthesized text. A
|
|
79
|
+
* patch for the editor's column updates (`derivedLabel: undefined` drops it
|
|
80
|
+
* when saved); `withAuthoredLabel` applies it to a column.
|
|
81
|
+
*/
|
|
82
|
+
export declare function authoredLabelPatch(label: string): LabelProvenance;
|
|
83
|
+
/** A column with a label someone wrote (`authoredLabelPatch`). */
|
|
84
|
+
export declare function withAuthoredLabel<T extends LabelProvenance>(column: T, label: string): T;
|
|
85
|
+
/**
|
|
86
|
+
* What to set for a generated label (an aggregate's "Average of Sales"): the
|
|
87
|
+
* label as a refreshable semantic hint, unless someone wrote the label.
|
|
88
|
+
*/
|
|
89
|
+
export declare function generatedLabelPatch(column: Pick<LabelProvenance, 'labelOrigin'>, label: string): LabelProvenance;
|
|
@@ -28,6 +28,8 @@ export * from './relative-date-label.js';
|
|
|
28
28
|
export * from './operation-temporal-state.js';
|
|
29
29
|
export * from './aggregate-expression.js';
|
|
30
30
|
export * from './measure-aggregation-profile.js';
|
|
31
|
+
export * from './field-provenance.js';
|
|
32
|
+
export * from './query-policies.js';
|
|
31
33
|
export * from './analytics-refusal.js';
|
|
32
34
|
export * from './visual-choice.js';
|
|
33
35
|
/**
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small pure policies of how a query runs, shared by the governed compiler
|
|
3
|
+
* and the query builder (semaphor-app) and by whatever reads a saved card
|
|
4
|
+
* back (MCP dashboard editing, ledger V-19). Each was written once on the
|
|
5
|
+
* compiling side and again, inverted, on the reading side; a change to one
|
|
6
|
+
* copy would have broken the other silently. Grounding and SQL generation
|
|
7
|
+
* stay app-owned: these are the string and ordering rules only.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The sort a query gets when it states none: the grouped date ascending;
|
|
11
|
+
* else, when something is grouped, the primary measure (the first when none
|
|
12
|
+
* is named) descending; else none.
|
|
13
|
+
*/
|
|
14
|
+
export declare function defaultQuerySort<T>(parts: {
|
|
15
|
+
groupedDate?: T;
|
|
16
|
+
measures: readonly T[];
|
|
17
|
+
grouped: boolean;
|
|
18
|
+
primaryMeasure?: T;
|
|
19
|
+
}): {
|
|
20
|
+
target: T;
|
|
21
|
+
direction: 'asc' | 'desc';
|
|
22
|
+
} | undefined;
|
|
23
|
+
/** The saved condition operators that run a LIKE pattern. */
|
|
24
|
+
export type SavedPatternOperator = 'contains' | 'startsWith' | 'endsWith' | 'like' | 'not like';
|
|
25
|
+
export declare const SAVED_PATTERN_OPERATORS: ReadonlySet<string>;
|
|
26
|
+
/** A LIKE wildcard: `%` or `_`. */
|
|
27
|
+
export declare function hasLikeWildcard(value: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The LIKE pattern a saved condition runs (the query builder's rule):
|
|
30
|
+
* `contains` matches anywhere, `startsWith` and `endsWith` at one end, and
|
|
31
|
+
* `like` and `not like` run the value as written.
|
|
32
|
+
*/
|
|
33
|
+
export declare function savedConditionPattern(operator: SavedPatternOperator, value: string): {
|
|
34
|
+
pattern: string;
|
|
35
|
+
negate: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The pattern a public `contains` filter runs (the compiler's rule): the
|
|
39
|
+
* value wrapped in `%...%`, unless it already holds a wildcard.
|
|
40
|
+
*/
|
|
41
|
+
export declare function containsFilterPattern(value: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* A saved pattern condition as the public `contains` / `not_contains` filter
|
|
44
|
+
* that runs the same pattern again, or undefined when none does (a pattern
|
|
45
|
+
* without a wildcard matches a value exactly). Checked against
|
|
46
|
+
* `containsFilterPattern` itself, so the reading can never drift from the
|
|
47
|
+
* compiler.
|
|
48
|
+
*/
|
|
49
|
+
export declare function statedPatternFilter(operator: SavedPatternOperator, value: string): {
|
|
50
|
+
operator: 'contains' | 'not_contains';
|
|
51
|
+
value: string;
|
|
52
|
+
} | undefined;
|