react-semaphor 0.1.546 → 0.1.548

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.
Files changed (59) hide show
  1. package/dist/analytics-protocol/index.js +71 -68
  2. package/dist/assistant-context/index.js +1 -1
  3. package/dist/briefings/index.js +1 -1
  4. package/dist/chunks/applied-constraints-DU-wndZ7.js +47 -0
  5. package/dist/chunks/{assistant-chat-BPXhulAx.js → assistant-chat-DCcWsoGm.js} +106 -106
  6. package/dist/chunks/{bookmark-state-C4vetoa0.js → bookmark-state-Cu-a5ie_.js} +2 -8
  7. package/dist/chunks/{custom-visual-inputs-CkJW9pBS.js → custom-visual-inputs-BTRnwsfd.js} +1 -1
  8. package/dist/chunks/{dashboard-C3CoKbGY.js → dashboard-BZHL9a-z.js} +1 -1
  9. package/dist/chunks/{dashboard-briefing-launcher-Be4h-7My.js → dashboard-briefing-launcher-DML-cAzB.js} +528 -528
  10. package/dist/chunks/{dashboard-controls-bxPrlSyp.js → dashboard-controls-BGoBTPS7.js} +45 -45
  11. package/dist/chunks/{dashboard-json-BrjxIiRt.js → dashboard-json-iHPsdn3j.js} +1 -1
  12. package/dist/chunks/{document-dashboard-inputs-CRVHpIHp.js → document-dashboard-inputs-B2AqPfrq.js} +94 -94
  13. package/dist/chunks/{edit-dashboard-visual-DYYYDjY6.js → edit-dashboard-visual-CLEFFf2T.js} +281 -281
  14. package/dist/chunks/{column-catalog-BYnochWQ.js → filter-reach-copy-ByzGadUk.js} +978 -861
  15. package/dist/chunks/{global-date-filter-utils-9d6m9-FE.js → global-date-filter-utils-CeeFJ1CP.js} +4070 -3792
  16. package/dist/chunks/{index-DkQkMKa1.js → index-DeDHr3iz.js} +30 -30
  17. package/dist/chunks/{raw-temporal-presentation-CBzrDOjM.js → raw-temporal-presentation-CrUM2I_o.js} +1 -1
  18. package/dist/chunks/{report-preferences-dialog-4QEZWe5U.js → report-preferences-dialog-CM7kXmXp.js} +59 -59
  19. package/dist/chunks/{resolve-dashboard-input-context-UpK_LBpL.js → resolve-dashboard-input-context-BmWF9hSl.js} +1511 -1612
  20. package/dist/chunks/{saved-dashboard-context-D_I3Lxk0.js → saved-dashboard-context-qtfzl9Eb.js} +5 -5
  21. package/dist/chunks/{semaphor-ready-indicator-4zpRHE-X.js → semaphor-ready-indicator-Ol6VcaR7.js} +36548 -35855
  22. package/dist/chunks/{shelf-drop-preview-context-Cfw7TRAx.js → shelf-drop-preview-context-C2SEC3I9.js} +80 -80
  23. package/dist/chunks/{source-entity-resolution-BIGRvtbG.js → source-entity-resolution-D195CrYS.js} +221 -192
  24. package/dist/chunks/{table-settings-CunhoDUi.js → table-settings-WysCBj62.js} +133 -124
  25. package/dist/chunks/{use-create-flow-overlay-state-DZBZiiD-.js → use-create-flow-overlay-state-CbGIjaVD.js} +2 -2
  26. package/dist/dashboard/index.js +2 -2
  27. package/dist/dashboard-authoring/index.js +1419 -1340
  28. package/dist/data-app-sdk-validation/index.js +1 -1
  29. package/dist/index.js +14 -14
  30. package/dist/surfboard/index.js +2 -2
  31. package/dist/types/components/surfboard/filter/types.d.ts +7 -0
  32. package/dist/types/components/surfboard/screen-size-preview-button.d.ts +7 -4
  33. package/dist/types/components/visual/matrix-table/matrix-card-view.d.ts +3 -0
  34. package/dist/types/index.js +2 -2
  35. package/dist/types/lib/dashboard-inputs/dashboard-filter-mapping-authoring.d.ts +383 -22
  36. package/dist/types/lib/dashboard-inputs/dashboard-filter-value-identity.d.ts +65 -0
  37. package/dist/types/lib/dashboard-inputs/resolve-selection-input.d.ts +3 -3
  38. package/dist/types/lib/hooks/use-dashboard-card.d.ts +2 -0
  39. package/dist/types/lib/matrix-table/matrix-delivery-policy.d.ts +1 -1
  40. package/dist/types/lib/matrix-table/matrix-runtime-types.d.ts +9 -1
  41. package/dist/types/lib/matrix-table/matrix-runtime.d.ts +5 -1
  42. package/dist/types/lib/query-context/dashboard-filter-mapping-resolution.d.ts +83 -13
  43. package/dist/types/lib/stores/dashboard-store.d.ts +12 -0
  44. package/dist/types/shared/analytics-protocol/applied-constraints.d.ts +57 -1
  45. package/dist/types/shared/assistant-protocol/context.d.ts +8 -8
  46. package/dist/types/shared/dashboard-authoring/changes/diagnostics.d.ts +2 -0
  47. package/dist/types/shared/dashboard-authoring/changes/resolve-dashboard-changes.d.ts +7 -0
  48. package/dist/types/shared/dashboard-authoring/click-to-filter-settings.d.ts +3 -3
  49. package/dist/types/shared/dashboard-authoring/dashboard-filter-automatic-target.d.ts +4 -4
  50. package/dist/types/shared/dashboard-authoring/dashboard-filter-mapping-contract.d.ts +3 -1
  51. package/dist/types/shared/dashboard-authoring/dashboard-filter-mapping-types.d.ts +27 -1
  52. package/dist/types/shared/dashboard-authoring/dashboard-filter-value-compatibility.d.ts +12 -3
  53. package/dist/types/shared/dashboard-authoring/filter-reach-copy.d.ts +18 -0
  54. package/dist/types/shared/dashboard-authoring/filter-reach-preview.d.ts +97 -0
  55. package/dist/types/shared/dashboard-authoring/index.d.ts +5 -1
  56. package/dist/types/shared/dashboard-authoring/outline/outline-dashboard.d.ts +7 -0
  57. package/dist/types/shared/dashboard-authoring/outline/outline-filters.d.ts +26 -4
  58. package/dist/types/shared/dashboard-authoring/semantic-auto-join-card.d.ts +22 -0
  59. package/package.json +1 -1
@@ -0,0 +1,65 @@
1
+ import { TFilter, TFilterValue } from '../../components/surfboard/filter/types.js';
2
+ import { NormalizedFilterDashboardInput } from '../types/common-types.js';
3
+ import { DashboardFilterLogicalValueField, DashboardFilterOptionSource, DashboardFilterRelationshipTarget, DashboardFilterTargetField, DashboardFilterTargetSource } from '../../shared/dashboard-authoring/index.js';
4
+ import { SemaphorConnectionCapabilities } from '../../shared/analytics-protocol/index.js';
5
+ export type DashboardFilterSourceResolutionContext = {
6
+ connectionType?: string;
7
+ capabilities?: Pick<SemaphorConnectionCapabilities, 'dialect' | 'prefixLevels'>;
8
+ };
9
+ /**
10
+ * Resolves the concrete source carried by an Option Source field, falling
11
+ * back to the Option Source declaration for older field refs that omit it.
12
+ */
13
+ export declare function resolveDashboardFilterOptionFieldSource(field: DashboardFilterOptionSource['valueField'], fallbackSource: DashboardFilterOptionSource['source']): DashboardFilterTargetSource;
14
+ export declare function resolveDashboardFilterBackingSourceResolution(filter: TFilter, context?: DashboardFilterSourceResolutionContext): import('../../shared/analytics-protocol/index.js').SemaphorSourceEntityResolution<Record<string, unknown>>;
15
+ /** Resolves the one source that owns an ordinary dashboard filter field. */
16
+ export declare function resolveDashboardFilterBackingSource(filter: TFilter, context?: DashboardFilterSourceResolutionContext): DashboardFilterTargetSource | undefined;
17
+ /**
18
+ * Metadata authoring may inspect a complete persisted qualified source even
19
+ * when stale selected-entity inventory no longer contains it. Runtime source
20
+ * resolution remains fail-closed through resolveDashboardFilterBackingSource.
21
+ */
22
+ export declare function resolveDashboardFilterMappingCandidateSource(filter: TFilter, context?: DashboardFilterSourceResolutionContext): DashboardFilterTargetSource | undefined;
23
+ /**
24
+ * Resolves every proven identity by which the selected filter field may map.
25
+ * A physical dataset selected within a semantic domain legitimately has both
26
+ * a physical backing identity and a semantic projection; the consuming card
27
+ * chooses the identity present in its own executable-source inventory.
28
+ */
29
+ export declare function resolveDashboardFilterMappingSources(filter: TFilter): DashboardFilterTargetSource[];
30
+ /**
31
+ * Authoring counterpart to resolveDashboardFilterMappingSources. It may carry
32
+ * a complete qualified backing candidate when persisted entity inventory is
33
+ * stale, while the semantic projection still requires a resolved entity.
34
+ */
35
+ export declare function resolveDashboardFilterMappingCandidateSources(filter: TFilter, context?: DashboardFilterSourceResolutionContext): DashboardFilterTargetSource[];
36
+ /** Resolves the ordinary filter field used as the pre-Option-Source value key. */
37
+ export declare function deriveDashboardFilterLogicalSelectionField(filter: TFilter): Pick<DashboardFilterTargetField, 'name'> | undefined;
38
+ /** The filter's logical value field: its Option Source's value field, else its own field. */
39
+ export declare function filterInputLogicalValueField(input: NormalizedFilterDashboardInput, filterValue?: TFilterValue): DashboardFilterLogicalValueField | undefined;
40
+ /** The sources a filter's values belong to: its Option Source's, else its own field's. */
41
+ export declare function filterInputValueSources(input: NormalizedFilterDashboardInput): DashboardFilterTargetSource[];
42
+ /**
43
+ * The source-qualified fields whose values a toolbar filter holds. A filter
44
+ * with an option source has exactly one; an ordinary filter has one per
45
+ * source it is proven to address.
46
+ */
47
+ export declare function dashboardFilterInputValueFields(input: NormalizedFilterDashboardInput): DashboardFilterTargetField[];
48
+ /**
49
+ * Whether an author-chosen relationship route (RF-D10) still ends at the
50
+ * filter's value field: the field the filter's values belong to (its Option
51
+ * Source's value field when it has one). A route chosen for another field,
52
+ * as after the Option Source moves to another dataset, can't run and is stale
53
+ * until chosen again. The card target decision, the Cards tab draft and save
54
+ * validation all ask here (relationship filter reach ledger R-12).
55
+ */
56
+ export declare function relationshipTargetFollowsValueField(input: NormalizedFilterDashboardInput, target: DashboardFilterRelationshipTarget): boolean;
57
+ /**
58
+ * The target that saves an author's choice of a relationship route (RF-D10):
59
+ * the route's ids and the filter's value field as its semantic dataset in the
60
+ * card's domain, the field `relationshipTargetFollowsValueField` checks. A
61
+ * value field can also have a physical identity (a physical dataset in a
62
+ * semantic domain); the route ends at the semantic one. The server preview
63
+ * builds the Cards tab's choices here (ledger R-16).
64
+ */
65
+ export declare function relationshipRouteTarget(input: NormalizedFilterDashboardInput, domainId: string, relationshipIds: readonly string[]): DashboardFilterRelationshipTarget | undefined;
@@ -1,5 +1,5 @@
1
1
  import { SelectionField, SelectionInputValue } from '../../shared/analytics-protocol/selection-contract.js';
2
- import { DashboardFilterTarget } from '../../shared/dashboard-authoring/index.js';
2
+ import { DashboardFilterFieldTarget } from '../../shared/dashboard-authoring/index.js';
3
3
  import { ScopedDashboardInputTarget } from '../../shared/dashboard-authoring/dashboard-input-scope.js';
4
4
  import { NormalizedFilterDashboardInput, SelectionDashboardInput, TCard } from '../types/common-types.js';
5
5
  import { FilterCondition } from '../types/explorer-types.js';
@@ -19,7 +19,7 @@ export type SelectionBlockReason = 'ambiguousAutomaticTarget' | 'staleBinding' |
19
19
  export type SelectionConditionDisposition = {
20
20
  status: 'apply';
21
21
  clickedFieldKey: string;
22
- target: DashboardFilterTarget;
22
+ target: DashboardFilterFieldTarget;
23
23
  provenance: 'automatic' | 'bound' | 'borrowedFromFilter';
24
24
  /** Set when provenance is 'borrowedFromFilter'. */
25
25
  borrowedFromInputId?: string;
@@ -57,7 +57,7 @@ export declare function findBorrowedSelectionBinding(params: {
57
57
  filterInputs: NormalizedFilterDashboardInput[];
58
58
  }): {
59
59
  inputId: string;
60
- target: DashboardFilterTarget;
60
+ target: DashboardFilterFieldTarget;
61
61
  } | undefined;
62
62
  /**
63
63
  * Decides what one source card's selection does on one target card. A viewer's
@@ -21,6 +21,7 @@ export declare function useCard(cardId: string): {
21
21
  resolvedPrimaryDateField: import('../types/semantic-runtime-types.js').ResolvedPrimaryDateField | undefined;
22
22
  effectiveCardConfig: import('../types/index.js').CardConfig | undefined;
23
23
  isCurrentQueryResult: boolean;
24
+ filterReach: import('../../shared/analytics-protocol/index.js').SemaphorFilterReachEntry[];
24
25
  };
25
26
  export declare function useDashboardCard(card: TCard): {
26
27
  isPending: boolean;
@@ -42,4 +43,5 @@ export declare function useDashboardCard(card: TCard): {
42
43
  resolvedPrimaryDateField: import('../types/semantic-runtime-types.js').ResolvedPrimaryDateField | undefined;
43
44
  effectiveCardConfig: import('../types/index.js').CardConfig | undefined;
44
45
  isCurrentQueryResult: boolean;
46
+ filterReach: import('../../shared/analytics-protocol/index.js').SemaphorFilterReachEntry[];
45
47
  };
@@ -31,4 +31,4 @@ export declare function matrixDeliveryOptions(allowDownload?: boolean, content?:
31
31
  formats: ("csv" | "xlsx" | "pdf" | "png")[];
32
32
  };
33
33
  /** Matrix delivery requires an effective capture, never resident cells. */
34
- export declare function resolveMatrixExportEngine(card: TCard | null | undefined, hasContext: boolean): "window" | "unavailable" | "ordinary";
34
+ export declare function resolveMatrixExportEngine(card: TCard | null | undefined, hasContext: boolean): "unavailable" | "window" | "ordinary";
@@ -1,4 +1,4 @@
1
- import { MatrixAxis, MatrixAxisPage, MatrixCellBlock, MatrixCoordinate, MatrixFailure, MatrixPageRequest, MatrixPath, MatrixPresentation, MatrixSpec, MatrixViewState, MatrixWindow, MatrixIndexedWindowOutcome, MatrixWindowRequest, OperationTemporalState, SemaphorScalarValue } from '../../shared/analytics-protocol/index.js';
1
+ import { MatrixAxis, MatrixAxisPage, MatrixCellBlock, MatrixCoordinate, MatrixFailure, MatrixPageRequest, MatrixPath, MatrixPresentation, MatrixSpec, MatrixViewState, MatrixWindow, MatrixIndexedWindowOutcome, MatrixWindowRequest, OperationTemporalState, SemaphorScalarValue, SemaphorFilterReachEntry } from '../../shared/analytics-protocol/index.js';
2
2
  export type MatrixRuntimeError = {
3
3
  failure: MatrixFailure;
4
4
  retryKey: string | null;
@@ -124,6 +124,12 @@ export type MatrixDataset = {
124
124
  * or seeded dataset continues on the same instant.
125
125
  */
126
126
  temporalState?: OperationTemporalState;
127
+ /**
128
+ * The per-filter report its latest window returned (relationship filter
129
+ * reach RF-D13): a restored dataset shows rows without running a window, so
130
+ * its filter info reads the report saved with them (ledger R-03).
131
+ */
132
+ filterReach?: readonly SemaphorFilterReachEntry[];
127
133
  };
128
134
  /** What a mounted runtime exposes to History. */
129
135
  export type MatrixLiveView = {
@@ -208,6 +214,8 @@ export type MatrixWindowExecutor = (input: {
208
214
  /** A window outcome and the operation state the server ran it on. */
209
215
  export type MatrixWindowExecution = MatrixIndexedWindowOutcome & {
210
216
  temporalState?: OperationTemporalState;
217
+ /** The per-filter report for this window, as `/api/v1/query` returns it for other cards. */
218
+ filterReach?: SemaphorFilterReachEntry[];
211
219
  };
212
220
  export type MatrixRuntimeInput = {
213
221
  spec: MatrixSpec;
@@ -1,5 +1,5 @@
1
+ import { SemaphorFilterReachEntry, MatrixAxis, MatrixCoordinate, MatrixPath, MatrixSort, MatrixViewState } from '../../shared/analytics-protocol/index.js';
1
2
  import { QueryClient } from '@tanstack/react-query';
2
- import { MatrixAxis, MatrixCoordinate, MatrixPath, MatrixSort, MatrixViewState } from '../../shared/analytics-protocol/index.js';
3
3
  import { MatrixCellAddress, MatrixCellState, MatrixDatasetRetention, MatrixRuntimeInput, MatrixRuntimeSnapshot, MatrixViewport, MatrixVisibleCoverage, MatrixWindowExecutor } from './matrix-runtime-types.js';
4
4
  /** Owns acquisition, errors, generation fencing and retention for exactly one card. */
5
5
  export declare class MatrixRuntimeController {
@@ -26,6 +26,8 @@ export declare class MatrixRuntimeController {
26
26
  * every page and expansion sends it, so they all run on one instant.
27
27
  */
28
28
  private temporalState?;
29
+ /** The latest window's per-filter report (relationship filter reach RF-D13). */
30
+ private filterReach;
29
31
  private error?;
30
32
  private notice?;
31
33
  private blockingFailures;
@@ -73,6 +75,8 @@ export declare class MatrixRuntimeController {
73
75
  * Value, null and empty cells are complete; unloaded and loading cells, axis
74
76
  * pages still loading, and queued or active work are not.
75
77
  */
78
+ /** Which filters the latest window's source applied, and why not, as the server reported it. */
79
+ readFilterReach: () => SemaphorFilterReachEntry[];
76
80
  readVisibleCoverage: () => MatrixVisibleCoverage;
77
81
  /** Used by explicit refresh/retry integrations; latest-issued response wins. */
78
82
  refetchCell: (coordinate: MatrixCoordinate) => void;
@@ -1,6 +1,7 @@
1
1
  import { TFilterValue } from '../../components/surfboard/filter/types.js';
2
2
  import { NormalizedFilterDashboardInput, ResolvedDashboardInput, TCard } from '../types/common-types.js';
3
- import { DashboardFilterLogicalValueField, DashboardFilterTarget, DashboardFilterTargetField, DashboardFilterTargetSource, buildDashboardCardSourceIndex } from '../../shared/dashboard-authoring/index.js';
3
+ import { DashboardFilterLogicalValueField, DashboardFilterFieldTarget, DashboardFilterTargetField, DashboardFilterTargetSource, buildDashboardCardSourceIndex } from '../../shared/dashboard-authoring/index.js';
4
+ import { SemaphorRelationshipRoute, SemaphorSkippedConstraintReason } from '../../shared/analytics-protocol/index.js';
4
5
  import { Field } from '../types/explorer-types.js';
5
6
  export type DashboardFilterMappingSkipReason = 'outsideScope' | 'noSelection' | 'explicitlyExcluded' | 'notApplicable';
6
7
  export type DashboardFilterMappingBlockReason = 'ambiguousAutomaticTarget' | 'staleBinding' | 'invalidSelection' | 'incompatibleValueType' | 'unsupportedTarget';
@@ -35,7 +36,7 @@ export type DashboardFilterMappingResolution = {
35
36
  * use, so the server resolves both to the same table alias. Pass the card's
36
37
  * grounded executable source when validation returned one.
37
38
  */
38
- export declare function explorerFieldFromMappingTarget(target: DashboardFilterTarget, source?: DashboardFilterTargetField['source']): Field;
39
+ export declare function explorerFieldFromMappingTarget(target: DashboardFilterFieldTarget, source?: DashboardFilterTargetField['source']): Field;
39
40
  /** Date and datetime are interchangeable; every other type must match exactly. */
40
41
  export declare function dashboardFilterDataTypesAreCompatible(sourceType: string, targetType: DashboardFilterTargetField['dataType']): boolean;
41
42
  /**
@@ -47,13 +48,7 @@ export declare function automaticTargetCandidates(params: {
47
48
  valueField: DashboardFilterLogicalValueField;
48
49
  valueSources: DashboardFilterTargetSource[];
49
50
  sourceIndex: ReturnType<typeof buildDashboardCardSourceIndex>;
50
- }): DashboardFilterTarget[];
51
- /**
52
- * The source-qualified fields whose values a toolbar filter holds. A filter
53
- * with an option source has exactly one; an ordinary filter has one per
54
- * source it is proven to address.
55
- */
56
- export declare function dashboardFilterInputValueFields(input: NormalizedFilterDashboardInput): DashboardFilterTargetField[];
51
+ }): DashboardFilterFieldTarget[];
57
52
  export type DashboardFilterTargetValidation = {
58
53
  status: 'valid';
59
54
  /** The card's own copy of the source the target addresses. */
@@ -71,7 +66,7 @@ export type DashboardFilterTargetValidation = {
71
66
  */
72
67
  export declare function validateDashboardFilterTargetForCard(params: {
73
68
  sourceIndex: ReturnType<typeof buildDashboardCardSourceIndex>;
74
- target: DashboardFilterTarget;
69
+ target: DashboardFilterFieldTarget;
75
70
  }): DashboardFilterTargetValidation;
76
71
  /**
77
72
  * Where a filter input lands on a card: the one decision execution
@@ -87,7 +82,7 @@ export type DashboardFilterCardTarget = {
87
82
  } | {
88
83
  status: 'bound';
89
84
  bindingId: string;
90
- target: DashboardFilterTarget;
85
+ target: DashboardFilterFieldTarget;
91
86
  validation: Extract<DashboardFilterTargetValidation, {
92
87
  status: 'valid';
93
88
  }>;
@@ -103,7 +98,7 @@ export type DashboardFilterCardTarget = {
103
98
  status: 'sql';
104
99
  } | {
105
100
  status: 'automatic';
106
- target: DashboardFilterTarget;
101
+ target: DashboardFilterFieldTarget;
107
102
  }
108
103
  /**
109
104
  * The card's data takes the filter's field (the one applicability rule) but
@@ -113,6 +108,22 @@ export type DashboardFilterCardTarget = {
113
108
  */
114
109
  | {
115
110
  status: 'passthrough';
111
+ }
112
+ /**
113
+ * The value's dataset is one the card's query doesn't use, in the card's
114
+ * semantic domain: the value is sent as it is and the server decides,
115
+ * through the domain's relationships, whether and how it reaches the card
116
+ * (relationship filter reach row 7r). The browser loads no relationships.
117
+ * With `route`, the author chose the relationships (a mapping `relationship`
118
+ * target, RF-D10): the value carries their ids and the server resolves
119
+ * exactly them or blocks the card.
120
+ */
121
+ | {
122
+ status: 'relationship';
123
+ route?: {
124
+ bindingId: string;
125
+ relationshipIds: string[];
126
+ };
116
127
  } | {
117
128
  status: 'ambiguous';
118
129
  } | {
@@ -134,7 +145,56 @@ export type DashboardFilterCardReach =
134
145
  /** More than one field of the card could take it: the card blocks until it is mapped. */
135
146
  | 'ambiguous'
136
147
  /** The mapping binds a target the card can't run or no longer has: the card blocks until it is mapped again. */
137
- | 'blocked' | 'notApplicable';
148
+ | 'blocked'
149
+ /**
150
+ * The server decides when the card runs, through the domain's
151
+ * relationships: it may apply the value or skip it with a reason. A reader
152
+ * never counts it as reached.
153
+ */
154
+ | 'relationship'
155
+ /** A server-side resolver confirmed the route the card will apply (RF-D15). */
156
+ | 'relationshipApplied' | 'notApplicable';
157
+ /** How a filter reaches a card, with the route or the reason a resolver gave (RF-D15). */
158
+ export type DashboardFilterCardReachDetail = {
159
+ reach: DashboardFilterCardReach;
160
+ /** With 'relationshipApplied'. */
161
+ route?: SemaphorRelationshipRoute;
162
+ /** With 'notApplicable' from a resolver. */
163
+ reason?: SemaphorSkippedConstraintReason;
164
+ /** With reason 'relationship_ambiguous'. */
165
+ candidates?: SemaphorRelationshipRoute[];
166
+ /** With 'blocked' from a resolver. */
167
+ message?: string;
168
+ /**
169
+ * With 'automatic' from a resolver: a card the target decision sends to the
170
+ * server to place applies the value on data its query already uses, so no
171
+ * route is needed (ledger R-05).
172
+ */
173
+ kept?: true;
174
+ };
175
+ /**
176
+ * Supplied by semaphor-app to server-side readers (RF-D15). Synchronous: the
177
+ * app preloads each card's domain. In the browser readers have none and
178
+ * report `relationship` unresolved.
179
+ */
180
+ export type DashboardRelationshipReachResolver = (query: {
181
+ card: TCard;
182
+ value: TFilterValue;
183
+ }) => {
184
+ status: 'applied';
185
+ route: SemaphorRelationshipRoute;
186
+ }
187
+ /** The card's query already uses the value's dataset: it applies as any filter. */
188
+ | {
189
+ status: 'kept';
190
+ } | {
191
+ status: 'skipped';
192
+ reason: SemaphorSkippedConstraintReason;
193
+ candidates?: SemaphorRelationshipRoute[];
194
+ } | {
195
+ status: 'blocked';
196
+ message: string;
197
+ };
138
198
  /**
139
199
  * Whether a filter in scope reaches a card, read without a value, from the
140
200
  * decision execution makes (`decideDashboardFilterCardTarget`). The dashboard
@@ -142,6 +202,16 @@ export type DashboardFilterCardReach =
142
202
  * (MCP dashboard editing SPEC 3.6, 5.4).
143
203
  */
144
204
  export declare function describeDashboardFilterCardReach(input: NormalizedFilterDashboardInput, card: TCard): DashboardFilterCardReach;
205
+ /**
206
+ * `describeDashboardFilterCardReach` with the route or reason. With a
207
+ * resolver (server-side readers, RF-D15) a `relationship` card is resolved
208
+ * the way the card query resolves it: applied with its route, not applicable
209
+ * with the reason, or blocked. The value is the filter's own field, as the
210
+ * card would send it; no policy step depends on the operator.
211
+ */
212
+ export declare function describeDashboardFilterCardReachDetail(input: NormalizedFilterDashboardInput, card: TCard, options?: {
213
+ relationshipReach?: DashboardRelationshipReachResolver;
214
+ }): DashboardFilterCardReachDetail;
145
215
  export declare function resolveDashboardFilterMappings({ card, inputs, resolvedInputs, activeFilterValues, shouldApplyDashboardFilters, }: {
146
216
  card: TCard;
147
217
  inputs: NormalizedFilterDashboardInput[];
@@ -107,6 +107,12 @@ export type DashboardStore = {
107
107
  * on load, on entering or leaving edit mode, and when an editable size is chosen.
108
108
  */
109
109
  layoutPreviewBreakpoint: Breakpoint | null;
110
+ /**
111
+ * Whether the screen-size bar is open (responsive layouts RL-D21). Closed by
112
+ * default: the editor edits Desktop and the bar appears only when someone
113
+ * opens it. Closed on load and on entering or leaving edit mode.
114
+ */
115
+ screenSizesOpen: boolean;
110
116
  theme?: 'light' | 'dark' | 'system';
111
117
  themeStyle?: StyleProps;
112
118
  filteringCards?: TCard[];
@@ -357,6 +363,12 @@ type Actions = {
357
363
  editSheetLayout: (sheetId: string, breakpoint: GridEditBreakpoint, items: LayoutItem[]) => void;
358
364
  /** Shows a screen size look-only, or ends the preview with null (RL-D19). */
359
365
  setLayoutPreviewBreakpoint: (breakpoint: Breakpoint | null) => void;
366
+ /**
367
+ * Opens or closes the screen-size bar (RL-D21). Opening in view mode starts a
368
+ * look-only preview at the size shown now; closing ends any preview and
369
+ * returns the editor to Desktop.
370
+ */
371
+ setScreenSizesOpen: (open: boolean) => void;
360
372
  /** The screen size the editor edits: Desktop, Tablet or Phone (RL-D11). */
361
373
  setLayoutEditBreakpoint: (breakpoint: EditableBreakpoint) => void;
362
374
  /** "Back to automatic" for a customized Tablet or Phone layout, through the layout engine (`reset_to_automatic`). */
@@ -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[];
@@ -247,14 +247,14 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
247
247
  kind: "set";
248
248
  text: string;
249
249
  fingerprint: string;
250
- omittedValues?: number | undefined;
251
250
  notApplied?: "opened_from_another_dashboard" | undefined;
251
+ omittedValues?: number | undefined;
252
252
  }, {
253
253
  kind: "set";
254
254
  text: string;
255
255
  fingerprint: string;
256
- omittedValues?: number | undefined;
257
256
  notApplied?: "opened_from_another_dashboard" | undefined;
257
+ omittedValues?: number | undefined;
258
258
  }>, z.ZodObject<{
259
259
  kind: z.ZodLiteral<"varies">;
260
260
  }, "strict", z.ZodTypeAny, {
@@ -268,8 +268,8 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
268
268
  kind: "set";
269
269
  text: string;
270
270
  fingerprint: string;
271
- omittedValues?: number | undefined;
272
271
  notApplied?: "opened_from_another_dashboard" | undefined;
272
+ omittedValues?: number | undefined;
273
273
  } | {
274
274
  kind: "varies";
275
275
  };
@@ -281,8 +281,8 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
281
281
  kind: "set";
282
282
  text: string;
283
283
  fingerprint: string;
284
- omittedValues?: number | undefined;
285
284
  notApplied?: "opened_from_another_dashboard" | undefined;
285
+ omittedValues?: number | undefined;
286
286
  } | {
287
287
  kind: "varies";
288
288
  };
@@ -610,8 +610,8 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
610
610
  kind: "set";
611
611
  text: string;
612
612
  fingerprint: string;
613
- omittedValues?: number | undefined;
614
613
  notApplied?: "opened_from_another_dashboard" | undefined;
614
+ omittedValues?: number | undefined;
615
615
  } | {
616
616
  kind: "varies";
617
617
  };
@@ -702,8 +702,8 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
702
702
  kind: "set";
703
703
  text: string;
704
704
  fingerprint: string;
705
- omittedValues?: number | undefined;
706
705
  notApplied?: "opened_from_another_dashboard" | undefined;
706
+ omittedValues?: number | undefined;
707
707
  } | {
708
708
  kind: "varies";
709
709
  };
@@ -794,8 +794,8 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
794
794
  kind: "set";
795
795
  text: string;
796
796
  fingerprint: string;
797
- omittedValues?: number | undefined;
798
797
  notApplied?: "opened_from_another_dashboard" | undefined;
798
+ omittedValues?: number | undefined;
799
799
  } | {
800
800
  kind: "varies";
801
801
  };
@@ -886,8 +886,8 @@ export declare const assistantContextSchema: z.ZodEffects<z.ZodObject<{
886
886
  kind: "set";
887
887
  text: string;
888
888
  fingerprint: string;
889
- omittedValues?: number | undefined;
890
889
  notApplied?: "opened_from_another_dashboard" | undefined;
890
+ omittedValues?: number | undefined;
891
891
  } | {
892
892
  kind: "varies";
893
893
  };
@@ -12,6 +12,8 @@ export type ChangeProblemCode = 'invalid_change' | 'invalid_change_target' | 'co
12
12
  export type ChangeWarningCode =
13
13
  /** In-scope cards the filter doesn't reach. */
14
14
  'filter_not_reaching_cards'
15
+ /** In-scope cards on another dataset of the filter's domain: decided when each card runs, through the relationships. */
16
+ | 'filter_reach_through_relationships'
15
17
  /** The compiled card stores the window as fixed dates. */
16
18
  | 'window_saved_as_fixed_dates'
17
19
  /** A type change leaves out fields or preferences. */
@@ -2,6 +2,7 @@ import { TDashboard } from '../../../lib/types/common-types.js';
2
2
  import { DataSource, Field } from '../../../lib/types/explorer-types.js';
3
3
  import { TChartType } from '../../../lib/charts/types.js';
4
4
  import { CalendarContext } from '../../report-runtime-context/index.js';
5
+ import { DashboardRelationshipReachResolver } from '../../../lib/query-context/dashboard-filter-mapping-resolution.js';
5
6
  import { DashboardOperation, OperationContext, OperationDescription } from '../operations/apply-dashboard-operations.js';
6
7
  import { CardQueryPart } from './card-query-part.js';
7
8
  import { FieldRef, MetricCardQuery, RecordsCardQuery } from './dashboard-change.js';
@@ -59,6 +60,12 @@ export type ChangeServices = {
59
60
  }): Promise<FieldRef[]>;
60
61
  /** A new unique id (a UUID: Matrix ids must be UUIDs, ledger P1-04). */
61
62
  newId(): string;
63
+ /**
64
+ * Server side only: resolves relationship reach the way the card query
65
+ * does, with each card's domain preloaded (relationship filter reach
66
+ * RF-D15). Without one, those cards read as decided when they run.
67
+ */
68
+ relationshipReach?: DashboardRelationshipReachResolver;
62
69
  };
63
70
  export type ChangeRef = {
64
71
  ref: string;
@@ -3,7 +3,7 @@ import { SelectionField } from '../analytics-protocol/selection-contract.js';
3
3
  import { DashboardInputScope, TCard } from '../../lib/types/common-types.js';
4
4
  import { Field } from '../../lib/types/explorer-types.js';
5
5
  import { buildDashboardCardSourceIndex, DashboardCardFilterSourceInventory } from './dashboard-card-source-index.js';
6
- import { DashboardFilterTarget } from './dashboard-filter-mapping-types.js';
6
+ import { DashboardFilterFieldTarget } from './dashboard-filter-mapping-types.js';
7
7
  /** Which fields a click on this card carries. */
8
8
  export type ClickToFilterFieldsRule =
9
9
  /** Table: every dimension column on the row. Matrix: the full path. Chart: every dimension of the clicked mark. */
@@ -31,8 +31,8 @@ export type ClickToFilterCardMapping = {
31
31
  /** Target card. */
32
32
  cardId: string;
33
33
  clickedFieldKey: string;
34
- /** Same target shape toolbar filter mappings persist. */
35
- target: DashboardFilterTarget;
34
+ /** A field of the target card: a click applies its value to a field the card executes (ledger R-11). */
35
+ target: DashboardFilterFieldTarget;
36
36
  }
37
37
  /** "Not applied": this target never receives this source's clicks. */
38
38
  | {
@@ -1,10 +1,10 @@
1
- import { DashboardFilterTarget, DashboardFilterTargetField } from './dashboard-filter-mapping-types.js';
1
+ import { DashboardFilterFieldTarget, DashboardFilterTarget, DashboardFilterTargetField } from './dashboard-filter-mapping-types.js';
2
2
  export type DashboardFilterLogicalValueField = Pick<DashboardFilterTargetField, 'name' | 'sourceField'> & {
3
3
  dataType: DashboardFilterTargetField['dataType'];
4
4
  };
5
5
  export type DashboardFilterAutomaticTargetResolution = {
6
6
  status: 'matched';
7
- target: DashboardFilterTarget;
7
+ target: DashboardFilterFieldTarget;
8
8
  } | {
9
9
  status: 'ambiguous';
10
10
  } | {
@@ -22,7 +22,7 @@ export declare function dashboardFilterTargetMatchesLogicalValue(target: Dashboa
22
22
  */
23
23
  export declare function resolveDashboardFilterAutomaticTarget(params: {
24
24
  logicalValueField: DashboardFilterLogicalValueField;
25
- candidates: DashboardFilterTarget[];
25
+ candidates: DashboardFilterFieldTarget[];
26
26
  }): DashboardFilterAutomaticTargetResolution;
27
27
  /**
28
28
  * Reuses an accepted, source-qualified target as the default for later config
@@ -33,5 +33,5 @@ export declare function resolveDashboardFilterAutomaticTarget(params: {
33
33
  */
34
34
  export declare function resolveDashboardFilterInheritedTarget(params: {
35
35
  logicalValueField: DashboardFilterLogicalValueField;
36
- acceptedTargets: DashboardFilterTarget[];
36
+ acceptedTargets: DashboardFilterFieldTarget[];
37
37
  }): DashboardFilterAutomaticTargetResolution;
@@ -1,6 +1,8 @@
1
1
  import { DashboardInput, NormalizedDashboardInput, TCard } from '../../lib/types/common-types.js';
2
2
  import { TFilter } from '../../components/surfboard/filter/types.js';
3
- export type DashboardFilterMappingContractIssueCode = 'invalid_input' | 'both_filter_definitions' | 'missing_filter_definition' | 'orphaned_filter_reference' | 'invalid_filter_reference' | 'duplicate_filter_reference' | 'global_date_reference' | 'unsupported_mapped_scope' | 'invalid_application' | 'duplicate_card_application' | 'unknown_card' | 'invalid_binding_id' | 'unsupported_target' | 'invalid_target_field' | 'unknown_target_data_type' | 'unavailable_card_source' | 'invalid_option_source' | 'invalid_option_dependencies' | 'invalid_option_population';
3
+ export type DashboardFilterMappingContractIssueCode = 'invalid_input' | 'both_filter_definitions' | 'missing_filter_definition' | 'orphaned_filter_reference' | 'invalid_filter_reference' | 'duplicate_filter_reference' | 'global_date_reference' | 'unsupported_mapped_scope' | 'invalid_application' | 'duplicate_card_application' | 'unknown_card' | 'invalid_binding_id' | 'unsupported_target' | 'invalid_target_field' | 'unknown_target_data_type' | 'unavailable_card_source'
4
+ /** A relationship target's ids are empty, not strings, or repeat (RF-D10). */
5
+ | 'invalid_relationship_route' | 'invalid_option_source' | 'invalid_option_dependencies' | 'invalid_option_population';
4
6
  export type DashboardFilterMappingContractIssue = {
5
7
  code: DashboardFilterMappingContractIssueCode;
6
8
  path: string;
@@ -20,10 +20,36 @@ export type DashboardFilterTargetField = {
20
20
  /** Catalog-grounded physical column used when it differs from the semantic name. */
21
21
  sourceField?: string;
22
22
  };
23
- export type DashboardFilterTarget = {
23
+ /**
24
+ * An author-chosen route to a card through the domain's relationships
25
+ * (relationship filter reach RF-D10), for a filter whose value's dataset the
26
+ * card doesn't use and reaches by more than one equally preferred path. The
27
+ * card sends the value as it is with these ids; the server resolves exactly
28
+ * them, or blocks the card while the value is set (P-1).
29
+ */
30
+ export type DashboardFilterRelationshipTarget = {
31
+ kind: 'relationship';
32
+ /** The value's field on its own dataset (the filter's own field). */
33
+ field: DashboardFilterTargetField;
34
+ /** Ordered from the card's base dataset to `field.source`'s dataset; non-empty, no repeats. */
35
+ relationshipIds: string[];
36
+ };
37
+ /**
38
+ * A field of the card the filter's value applies to directly. Field-only
39
+ * code (card field catalogs, automatic targeting, click-to-filter, compiling
40
+ * a card condition) takes this type, so a new target kind never reaches it
41
+ * unchecked (relationship filter reach hotspot H-05).
42
+ */
43
+ export type DashboardFilterFieldTarget = {
24
44
  kind: 'field';
25
45
  field: DashboardFilterTargetField;
26
46
  };
47
+ /**
48
+ * Every target a filter mapping persists. Code that takes both kinds handles
49
+ * each one explicitly (an exhaustive `switch`), so the compiler names it when
50
+ * a kind is added; both kinds carry `field`, so reading it never proves which.
51
+ */
52
+ export type DashboardFilterTarget = DashboardFilterFieldTarget | DashboardFilterRelationshipTarget;
27
53
  export type DashboardFilterBoundCardApplication = {
28
54
  kind: 'bound';
29
55
  cardId: string;