@startsimpli/funnels 0.4.14 → 0.4.15
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/package.json +11 -3
- package/src/api/client.paths.test.ts +20 -7
- package/src/api/client.ts +6 -0
- package/src/api/http-adapter.test.ts +68 -0
- package/src/api/http-adapter.ts +48 -0
- package/src/api/index.ts +5 -0
- package/src/api/paths.test.ts +18 -5
- package/src/api/paths.ts +52 -6
- package/src/page/FunnelsPage.test.tsx +383 -0
- package/src/page/FunnelsPage.tsx +739 -0
- package/src/page/index.ts +24 -0
- package/src/page/types.ts +102 -0
|
@@ -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
|
+
}
|