@startsimpli/funnels 0.4.14 → 0.4.16

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.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @startsimpli/funnels/page — the whole Funnels screen, mounted not rebuilt.
3
+ *
4
+ * A SUBPATH AND NOT THE ROOT BARREL, deliberately (the same reasoning
5
+ * `@startsimpli/ui/foundry` writes down for itself). This module is the one
6
+ * thing in the package that needs `@startsimpli/ui` — for UnifiedTable, and so
7
+ * for repo rule #8's server-side paging. raise and market import
8
+ * `@startsimpli/funnels` for the engine and the rule editor and must not be
9
+ * made to install a UI library to get them, so the import lives behind
10
+ *
11
+ * import { FunnelsPage } from '@startsimpli/funnels/page'
12
+ *
13
+ * and `@startsimpli/ui` is an OPTIONAL peer dependency.
14
+ *
15
+ * bd startsim-em5mn.
16
+ */
17
+ export { FunnelsPage } from './FunnelsPage';
18
+ export type {
19
+ FunnelsPageProps,
20
+ FunnelListRow,
21
+ FunnelResultRow,
22
+ FunnelListQuery,
23
+ StageReached,
24
+ } from './types';
@@ -0,0 +1,102 @@
1
+ /**
2
+ * What the FunnelsPage composer is handed, and the row shapes it renders.
3
+ *
4
+ * The wire shapes below are DECLARED HERE rather than in `../types` on purpose.
5
+ * `../types` is the funnel CONTRACT — the shapes paired with
6
+ * `@startsimpli/api`'s by `contract.test.ts`, changed only in lockstep. What a
7
+ * LIST endpoint adds on top (`stage_count`, `total_runs`, `last_run_*`) and
8
+ * what `FunnelResultSerializer` emits per row are presentation payloads: this
9
+ * page is their only reader, so widening the contract for them would make two
10
+ * packages agree about something neither of them models.
11
+ *
12
+ * bd startsim-em5mn.
13
+ */
14
+ import type { FunnelApiClient } from '../api/client';
15
+ import type { Funnel, FunnelStatus } from '../types';
16
+
17
+ /**
18
+ * A funnel as a LIST answers it: the contract shape plus the rollups
19
+ * `FunnelSerializer` computes (`stage_count`, `total_runs`, `last_run_at`,
20
+ * `last_run_id`, `last_run_matched`, `created_by_name`), camelized by the
21
+ * adapter.
22
+ */
23
+ export interface FunnelListRow extends Funnel {
24
+ stageCount?: number;
25
+ totalRuns?: number;
26
+ lastRunAt?: string | null;
27
+ lastRunId?: string | null;
28
+ lastRunMatched?: number | null;
29
+ createdByName?: string | null;
30
+ }
31
+
32
+ /** Where a result stopped, named from what the run RECORDED (breakdown.py). */
33
+ export interface StageReached {
34
+ id: string;
35
+ name: string | null;
36
+ order: number | null;
37
+ }
38
+
39
+ /**
40
+ * One row of a run's results, as the control plane serves them.
41
+ *
42
+ * `context` is free-form and reaches the browser through an adapter that
43
+ * camelizes KEYS, so it is rendered as an opaque count rather than as fields:
44
+ * a key the executor wrote as `reached_stage_id` arrives as `reachedStageId`,
45
+ * and presenting that as though it were the stored name would be a lie about
46
+ * the record. `stageReached` is the answer to the same question, computed
47
+ * server-side, and is what this page reads.
48
+ */
49
+ export interface FunnelResultRow {
50
+ id: string;
51
+ entityId: string;
52
+ entityType: string;
53
+ matched: boolean;
54
+ excludedAtStage: string | null;
55
+ stageReached: StageReached | null;
56
+ exclusionReason?: string;
57
+ context?: Record<string, unknown>;
58
+ accumulatedTags?: string[];
59
+ createdAt: string;
60
+ }
61
+
62
+ /** The server-side narrowings the funnel list supports. */
63
+ export interface FunnelListQuery {
64
+ status: FunnelStatus | '';
65
+ search: string;
66
+ page: number;
67
+ }
68
+
69
+ export interface FunnelsPageProps {
70
+ /**
71
+ * The funnel client, already bound to the path family of the surface that is
72
+ * mounting this page — `foundryTenantFunnelPaths(slug)` on the control plane,
73
+ * `proxiedCentralFunnelPaths('/central-api')` inside a fork. The page never
74
+ * builds a URL of its own; that is the whole point of the injection.
75
+ */
76
+ client: FunnelApiClient;
77
+
78
+ /**
79
+ * Where the rule vocabulary comes from. SEPARATE FROM `client` because the
80
+ * two are not on the same surface: `/fields/` is mounted ONLY on central
81
+ * (`/api/v1/funnels/fields/`, scoped to the caller's company), and the
82
+ * control plane's `funnels/fields/` is shadowed by its `funnels/<id>/`
83
+ * action and 404s. See the note on `foundryTenantFunnelPaths`.
84
+ *
85
+ * Defaults to `client`, which is right for any surface that does serve the
86
+ * endpoint under its own prefix.
87
+ */
88
+ fieldsClient?: FunnelApiClient;
89
+
90
+ /**
91
+ * Whether this viewer may create, edit and run funnels (`manage_funnels`).
92
+ * Read-only viewers (`view_funnels`) still get the list, the history and the
93
+ * results. The server enforces this either way — this only keeps the page
94
+ * from offering a button that will 403.
95
+ */
96
+ canManage?: boolean;
97
+
98
+ /** Rows per page for both tables. */
99
+ pageSize?: number;
100
+
101
+ className?: string;
102
+ }