@peasant-labs/fairtrade 0.0.3 → 0.0.5
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/lib/ChartLine-Dlp6-CLL.js +264 -0
- package/dist/lib/InUseShell-DZvmRdj-.js +1532 -0
- package/dist/lib/analytics.css +1 -0
- package/dist/lib/analytics.js +1052 -0
- package/dist/lib/commons.css +1 -0
- package/dist/lib/commons.js +3275 -0
- package/dist/lib/components.css +1 -1
- package/dist/lib/graph.css +1 -0
- package/dist/lib/graph.js +823 -0
- package/dist/lib/tokens.css +1 -1
- package/dist/lib/tokens.json +1 -1
- package/dist/lib/types/Intensity.d.ts +3 -3
- package/dist/lib/types/MapCanvas.d.ts +37 -5
- package/dist/lib/types/RoleRoster.d.ts +12 -1
- package/dist/lib/types/analytics/ChartCard.d.ts +18 -0
- package/dist/lib/types/analytics/ContributorTable.d.ts +16 -0
- package/dist/lib/types/analytics/ProjectOverview.d.ts +40 -0
- package/dist/lib/types/analytics/format.d.ts +48 -0
- package/dist/lib/types/analytics/index.d.ts +24 -0
- package/dist/lib/types/analytics/metrics.d.ts +130 -0
- package/dist/lib/types/analytics/stats.d.ts +23 -0
- package/dist/lib/types/analytics/time.d.ts +32 -0
- package/dist/lib/types/analytics/types.d.ts +453 -0
- package/dist/lib/types/commons/Explore.d.ts +6 -0
- package/dist/lib/types/commons/Manage.d.ts +34 -0
- package/dist/lib/types/commons/index.d.ts +24 -0
- package/dist/lib/types/commons/providers.d.ts +8 -0
- package/dist/lib/types/commons/types.d.ts +356 -0
- package/dist/lib/types/graph/ChangeDetail.d.ts +28 -0
- package/dist/lib/types/graph/Changes.d.ts +21 -0
- package/dist/lib/types/graph/CodeMap.d.ts +49 -0
- package/dist/lib/types/graph/CodeMapComposition.d.ts +85 -0
- package/dist/lib/types/graph/changeGraph.d.ts +106 -0
- package/dist/lib/types/graph/index.d.ts +30 -0
- package/dist/lib/types/graph/types.d.ts +579 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/inuse/InUseShell.d.ts +50 -0
- package/dist/lib/ui-oBFnHPFe.js +11146 -0
- package/dist/lib/ui.js +4 -12693
- package/package.json +37 -6
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcript visibility level.
|
|
3
|
+
* @typedef {'public' | 'private' | 'shared'} TranscriptVisibility
|
|
4
|
+
*/
|
|
5
|
+
/** Canonical TranscriptVisibility values. @type {readonly TranscriptVisibility[]} */
|
|
6
|
+
export const TRANSCRIPT_VISIBILITIES: readonly TranscriptVisibility[];
|
|
7
|
+
/**
|
|
8
|
+
* Collective acceptance mode: who can join.
|
|
9
|
+
* Grounded in backend migration 005 — CHECK (acceptance_mode IN
|
|
10
|
+
* ('open','verified_only','curated')).
|
|
11
|
+
* @typedef {'open' | 'verified_only' | 'curated'} AcceptanceMode
|
|
12
|
+
*/
|
|
13
|
+
/** Canonical AcceptanceMode values. @type {readonly AcceptanceMode[]} */
|
|
14
|
+
export const ACCEPTANCE_MODES: readonly AcceptanceMode[];
|
|
15
|
+
/**
|
|
16
|
+
* Collective data access policy: who can read transcripts.
|
|
17
|
+
* Grounded in backend handler/groups.go canReadData + migration 008
|
|
18
|
+
* (data_access default 'members_only').
|
|
19
|
+
* @typedef {'members_only' | 'contributors' | 'public'} DataAccessPolicy
|
|
20
|
+
*/
|
|
21
|
+
/** Canonical DataAccessPolicy values. @type {readonly DataAccessPolicy[]} */
|
|
22
|
+
export const DATA_ACCESS_POLICIES: readonly DataAccessPolicy[];
|
|
23
|
+
/**
|
|
24
|
+
* Transcript deletion policy for a collective.
|
|
25
|
+
* Grounded in backend migration 016 — CHECK (transcript_deletion_policy IN
|
|
26
|
+
* ('user_choice','mandatory')).
|
|
27
|
+
* @typedef {'user_choice' | 'mandatory'} TranscriptDeletionPolicy
|
|
28
|
+
*/
|
|
29
|
+
/** Canonical TranscriptDeletionPolicy values. @type {readonly TranscriptDeletionPolicy[]} */
|
|
30
|
+
export const TRANSCRIPT_DELETION_POLICIES: readonly TranscriptDeletionPolicy[];
|
|
31
|
+
/**
|
|
32
|
+
* A member's role within a collective. The `members` list carries
|
|
33
|
+
* owner/member/contributor; the `pendingMembers` list carries `pending`
|
|
34
|
+
* (the backend's ListGroupPendingMembers query filters `gm.role = 'pending'`),
|
|
35
|
+
* so this union — shared by both lists via CollectiveMemberPayload — includes it.
|
|
36
|
+
* Grounded in backend handler/groups.go (Role: "owner"/"member"/"contributor")
|
|
37
|
+
* + sqlc ListGroupPendingMembers (WHERE gm.role = 'pending').
|
|
38
|
+
* @typedef {'owner' | 'member' | 'contributor' | 'pending'} CollectiveRole
|
|
39
|
+
*/
|
|
40
|
+
/** Canonical CollectiveRole values. @type {readonly CollectiveRole[]} */
|
|
41
|
+
export const COLLECTIVE_ROLES: readonly CollectiveRole[];
|
|
42
|
+
/**
|
|
43
|
+
* Transcript visibility level.
|
|
44
|
+
*/
|
|
45
|
+
export type TranscriptVisibility = "public" | "private" | "shared";
|
|
46
|
+
/**
|
|
47
|
+
* Collective acceptance mode: who can join.
|
|
48
|
+
* Grounded in backend migration 005 — CHECK (acceptance_mode IN
|
|
49
|
+
* ('open','verified_only','curated')).
|
|
50
|
+
*/
|
|
51
|
+
export type AcceptanceMode = "open" | "verified_only" | "curated";
|
|
52
|
+
/**
|
|
53
|
+
* Collective data access policy: who can read transcripts.
|
|
54
|
+
* Grounded in backend handler/groups.go canReadData + migration 008
|
|
55
|
+
* (data_access default 'members_only').
|
|
56
|
+
*/
|
|
57
|
+
export type DataAccessPolicy = "members_only" | "contributors" | "public";
|
|
58
|
+
/**
|
|
59
|
+
* Transcript deletion policy for a collective.
|
|
60
|
+
* Grounded in backend migration 016 — CHECK (transcript_deletion_policy IN
|
|
61
|
+
* ('user_choice','mandatory')).
|
|
62
|
+
*/
|
|
63
|
+
export type TranscriptDeletionPolicy = "user_choice" | "mandatory";
|
|
64
|
+
/**
|
|
65
|
+
* A member's role within a collective. The `members` list carries
|
|
66
|
+
* owner/member/contributor; the `pendingMembers` list carries `pending`
|
|
67
|
+
* (the backend's ListGroupPendingMembers query filters `gm.role = 'pending'`),
|
|
68
|
+
* so this union — shared by both lists via CollectiveMemberPayload — includes it.
|
|
69
|
+
* Grounded in backend handler/groups.go (Role: "owner"/"member"/"contributor")
|
|
70
|
+
* + sqlc ListGroupPendingMembers (WHERE gm.role = 'pending').
|
|
71
|
+
*/
|
|
72
|
+
export type CollectiveRole = "owner" | "member" | "contributor" | "pending";
|
|
73
|
+
/**
|
|
74
|
+
* Current Explore browse filters mirrored by the host.
|
|
75
|
+
*/
|
|
76
|
+
export type ExploreFilters = {
|
|
77
|
+
query: string;
|
|
78
|
+
provider: string;
|
|
79
|
+
topics: string[];
|
|
80
|
+
order: string;
|
|
81
|
+
page: number;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Surface props for the lifted Explore component.
|
|
85
|
+
* The component consumes one cooked payload and owns its own browse state; hosts may also supply
|
|
86
|
+
* navigation slots for transcript/profile/collective exits.
|
|
87
|
+
*/
|
|
88
|
+
export type ExploreSurfaceProps = {
|
|
89
|
+
data: ExplorePayload;
|
|
90
|
+
className?: string;
|
|
91
|
+
onFiltersChange?: (filters: ExploreFilters) => void;
|
|
92
|
+
onOpenTranscript?: (transcript: ExploreTranscriptPayload) => void;
|
|
93
|
+
onOpenProfile?: (owner: ExploreOwnerPayload) => void;
|
|
94
|
+
onOpenCollective?: (collective: CollectiveResultPayload) => void;
|
|
95
|
+
transcriptHref?: (transcript: ExploreTranscriptPayload) => string;
|
|
96
|
+
profileHref?: (owner: ExploreOwnerPayload) => string;
|
|
97
|
+
collectiveHref?: (collective: CollectiveResultPayload) => string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* The AUTHENTICATED VIEWER's role in a collective — a CollectiveRole, OR the
|
|
101
|
+
* empty string when the viewer is not a member / anonymous. The backend GetGroup
|
|
102
|
+
* handler defaults `your_role` to "" for non-members (handler/groups.go:
|
|
103
|
+
* `yourRole := ""`), so this distinct type is required wherever the viewer's own
|
|
104
|
+
* role is exposed (your_role + the per-viewer Group.role), as opposed to a
|
|
105
|
+
* concrete member row's role.
|
|
106
|
+
*/
|
|
107
|
+
export type ViewerRole = CollectiveRole | "";
|
|
108
|
+
/**
|
|
109
|
+
* One tag attached to a transcript in the Explore list.
|
|
110
|
+
*/
|
|
111
|
+
export type TagPayload = {
|
|
112
|
+
id: string;
|
|
113
|
+
name: string;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* The author (owner) of a transcript as shown in the Explore list.
|
|
117
|
+
*/
|
|
118
|
+
export type ExploreOwnerPayload = {
|
|
119
|
+
githubUsername: string;
|
|
120
|
+
displayName: string | null;
|
|
121
|
+
avatarUrl: string | null;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* One transcript row in the Explore browse list.
|
|
125
|
+
* Cooked from TranscriptListItem (frontend/src/lib/types.ts): snake_case fields
|
|
126
|
+
* are renamed to camelCase; fields not needed by the Explore surface are omitted.
|
|
127
|
+
*/
|
|
128
|
+
export type ExploreTranscriptPayload = {
|
|
129
|
+
id: string;
|
|
130
|
+
title: string | null;
|
|
131
|
+
visibility: TranscriptVisibility;
|
|
132
|
+
/**
|
|
133
|
+
* e.g. "claude-code", "opencode"
|
|
134
|
+
*/
|
|
135
|
+
modelProvider: string;
|
|
136
|
+
modelName: string | null;
|
|
137
|
+
harnessVersion: string | null;
|
|
138
|
+
/**
|
|
139
|
+
* ISO-8601 datetime or null
|
|
140
|
+
*/
|
|
141
|
+
sessionStart: string | null;
|
|
142
|
+
/**
|
|
143
|
+
* ISO-8601 datetime or null
|
|
144
|
+
*/
|
|
145
|
+
sessionEnd: string | null;
|
|
146
|
+
turnCount: number | null;
|
|
147
|
+
tokenCount: number | null;
|
|
148
|
+
toolCallCount: number | null;
|
|
149
|
+
durationMs: number | null;
|
|
150
|
+
gitBranch: string | null;
|
|
151
|
+
projectName: string | null;
|
|
152
|
+
tags: TagPayload[];
|
|
153
|
+
owner: ExploreOwnerPayload;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Paginated list of transcripts for the Explore browse view.
|
|
157
|
+
* Cooked from TranscriptListResponse.
|
|
158
|
+
*/
|
|
159
|
+
export type ExploreTranscriptListPayload = {
|
|
160
|
+
transcripts: ExploreTranscriptPayload[];
|
|
161
|
+
/**
|
|
162
|
+
* total matching transcripts (for pagination)
|
|
163
|
+
*/
|
|
164
|
+
total: number;
|
|
165
|
+
/**
|
|
166
|
+
* current page (1-based)
|
|
167
|
+
*/
|
|
168
|
+
page: number;
|
|
169
|
+
/**
|
|
170
|
+
* page size
|
|
171
|
+
*/
|
|
172
|
+
limit: number;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* One collective result from a collective search (useSearchCollectives).
|
|
176
|
+
* Cooked from CollectiveSearchResult (frontend/src/lib/types.ts).
|
|
177
|
+
*/
|
|
178
|
+
export type CollectiveResultPayload = {
|
|
179
|
+
id: string;
|
|
180
|
+
name: string;
|
|
181
|
+
description: string | null;
|
|
182
|
+
linkedGithubOrg: string | null;
|
|
183
|
+
memberCount: number;
|
|
184
|
+
transcriptCount: number;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* One popular tag with its usage count.
|
|
188
|
+
* Cooked from TagWithCount (frontend/src/lib/types.ts).
|
|
189
|
+
*/
|
|
190
|
+
export type PopularTagPayload = {
|
|
191
|
+
id: string;
|
|
192
|
+
name: string;
|
|
193
|
+
usageCount: number;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* The Explore surface prop payload. The adapter maps the three hook results
|
|
197
|
+
* (useTranscripts, useSearchCollectives, usePopularTags) into this single
|
|
198
|
+
* cooked shape; the lifted <Explore> component never calls hooks directly.
|
|
199
|
+
*
|
|
200
|
+
* Query parameters (q, sort, page, provider, tags) are not embedded in the
|
|
201
|
+
* payload — they live as component-level props that the host passes alongside
|
|
202
|
+
* the payload (the adapter is called when any of them changes).
|
|
203
|
+
*/
|
|
204
|
+
export type ExplorePayload = {
|
|
205
|
+
/**
|
|
206
|
+
* browsing results (page + facet filters applied)
|
|
207
|
+
*/
|
|
208
|
+
transcripts: ExploreTranscriptListPayload;
|
|
209
|
+
/**
|
|
210
|
+
* collective search results (empty when no query)
|
|
211
|
+
*/
|
|
212
|
+
collectives: CollectiveResultPayload[];
|
|
213
|
+
/**
|
|
214
|
+
* top tags for the facet rail (cap set by caller)
|
|
215
|
+
*/
|
|
216
|
+
popularTags: PopularTagPayload[];
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* One member of a collective.
|
|
220
|
+
* Cooked from GroupMember (frontend/src/lib/types.ts).
|
|
221
|
+
*/
|
|
222
|
+
export type CollectiveMemberPayload = {
|
|
223
|
+
id: string;
|
|
224
|
+
githubUsername: string;
|
|
225
|
+
displayName: string | null;
|
|
226
|
+
avatarUrl: string | null;
|
|
227
|
+
/**
|
|
228
|
+
* owner/member/contributor for the members list; "pending" for the pendingMembers list
|
|
229
|
+
*/
|
|
230
|
+
role: CollectiveRole;
|
|
231
|
+
/**
|
|
232
|
+
* ISO-8601 datetime
|
|
233
|
+
*/
|
|
234
|
+
joinedAt: string;
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* One transcript published to the collective (lightweight row).
|
|
238
|
+
* Cooked from GroupTranscript (which extends Transcript with owner fields).
|
|
239
|
+
*/
|
|
240
|
+
export type CollectiveTranscriptPayload = {
|
|
241
|
+
id: string;
|
|
242
|
+
title: string | null;
|
|
243
|
+
visibility: TranscriptVisibility;
|
|
244
|
+
modelProvider: string;
|
|
245
|
+
modelName: string | null;
|
|
246
|
+
/**
|
|
247
|
+
* ISO-8601 datetime or null
|
|
248
|
+
*/
|
|
249
|
+
sessionStart: string | null;
|
|
250
|
+
turnCount: number | null;
|
|
251
|
+
tokenCount: number | null;
|
|
252
|
+
ownerUsername: string;
|
|
253
|
+
ownerAvatarUrl: string | null;
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Aggregate statistics for a collective's transcript corpus.
|
|
257
|
+
* Mirrors GroupTranscriptStats from frontend/src/lib/types.ts.
|
|
258
|
+
*/
|
|
259
|
+
export type CollectiveStatsPayload = {
|
|
260
|
+
totalTranscripts: number;
|
|
261
|
+
contributorCount: number;
|
|
262
|
+
totalTurns: number;
|
|
263
|
+
totalDurationMs: number;
|
|
264
|
+
totalTokens: number;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Model usage breakdown for a collective.
|
|
268
|
+
* Mirrors GroupModelBreakdown from frontend/src/lib/types.ts.
|
|
269
|
+
*/
|
|
270
|
+
export type CollectiveModelBreakdownPayload = {
|
|
271
|
+
modelProvider: string;
|
|
272
|
+
transcriptCount: number;
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* One contributor to a collective's transcript corpus.
|
|
276
|
+
* Mirrors GroupContributor from frontend/src/lib/types.ts.
|
|
277
|
+
*/
|
|
278
|
+
export type CollectiveContributorPayload = {
|
|
279
|
+
id: string;
|
|
280
|
+
githubUsername: string;
|
|
281
|
+
avatarUrl: string | null;
|
|
282
|
+
transcriptCount: number;
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* The collective's own metadata.
|
|
286
|
+
* Cooked from Group (frontend/src/lib/types.ts): snake_case → camelCase.
|
|
287
|
+
*/
|
|
288
|
+
export type CollectivePayload = {
|
|
289
|
+
id: string;
|
|
290
|
+
name: string;
|
|
291
|
+
description: string | null;
|
|
292
|
+
linkedGithubOrg: string | null;
|
|
293
|
+
displayMembers: boolean;
|
|
294
|
+
transcriptDeletionPolicy: TranscriptDeletionPolicy;
|
|
295
|
+
/**
|
|
296
|
+
* user id of the creator
|
|
297
|
+
*/
|
|
298
|
+
createdBy: string;
|
|
299
|
+
/**
|
|
300
|
+
* ISO-8601 datetime
|
|
301
|
+
*/
|
|
302
|
+
createdAt: string;
|
|
303
|
+
/**
|
|
304
|
+
* ISO-8601 datetime
|
|
305
|
+
*/
|
|
306
|
+
updatedAt: string;
|
|
307
|
+
acceptanceMode: AcceptanceMode;
|
|
308
|
+
dataAccess: DataAccessPolicy;
|
|
309
|
+
/**
|
|
310
|
+
* the authenticated viewer's role; "" when not a member / anonymous
|
|
311
|
+
*/
|
|
312
|
+
role: ViewerRole;
|
|
313
|
+
/**
|
|
314
|
+
* ISO-8601 datetime when the user joined; null if not a member
|
|
315
|
+
*/
|
|
316
|
+
memberSince: string | null;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* The Manage surface prop payload. The adapter maps the useGroup hook result
|
|
320
|
+
* into this single cooked shape; the lifted <Manage> component never calls
|
|
321
|
+
* hooks directly.
|
|
322
|
+
*
|
|
323
|
+
* Mutation callbacks (onCreateGroup, onUpdateGroup, onJoinGroup,
|
|
324
|
+
* onPromoteMember, onRemoveMember, onAddMember, onDeleteGroup) are
|
|
325
|
+
* component-level props defined in the surface slice — NOT fields in this
|
|
326
|
+
* payload. The payload carries only the READ data model.
|
|
327
|
+
*
|
|
328
|
+
* FIXTURE GAP: pendingMembers is optional on the wire (`pending_members?`)
|
|
329
|
+
* and absent from the current mock fixture. The adapter normalizes it to `[]`
|
|
330
|
+
* when absent; the mock fixture must be filled by the surface slice worker.
|
|
331
|
+
*/
|
|
332
|
+
export type ManagePayload = {
|
|
333
|
+
collective: CollectivePayload;
|
|
334
|
+
/**
|
|
335
|
+
* approved members
|
|
336
|
+
*/
|
|
337
|
+
members: CollectiveMemberPayload[];
|
|
338
|
+
/**
|
|
339
|
+
* pending join requests (may be [] when not yet seeded)
|
|
340
|
+
*/
|
|
341
|
+
pendingMembers: CollectiveMemberPayload[];
|
|
342
|
+
/**
|
|
343
|
+
* published transcripts (paginated externally)
|
|
344
|
+
*/
|
|
345
|
+
transcripts: CollectiveTranscriptPayload[];
|
|
346
|
+
stats: CollectiveStatsPayload;
|
|
347
|
+
/**
|
|
348
|
+
* usage breakdown by model provider
|
|
349
|
+
*/
|
|
350
|
+
models: CollectiveModelBreakdownPayload[];
|
|
351
|
+
contributors: CollectiveContributorPayload[];
|
|
352
|
+
/**
|
|
353
|
+
* authenticated viewer's role; "" when not a member / anonymous
|
|
354
|
+
*/
|
|
355
|
+
yourRole: ViewerRole;
|
|
356
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} props
|
|
3
|
+
* @param {import('./types.js').ChangeDetailPayload} props.payload the cooked change-detail payload
|
|
4
|
+
* @param {(file: import('./types.js').FileChangePayload) => import('./types.js').ChangeDiffPayload | null | undefined} [props.getDiff]
|
|
5
|
+
* resolve the lazy per-file diff (the separate ChangeDiffPayload) for an opened file; return
|
|
6
|
+
* null/undefined while loading, or a ChangeDiffPayload whose host-side `error` sentinel is set
|
|
7
|
+
* (with empty hunks) when the fetch failed — the surface then renders an error row, not a spinner
|
|
8
|
+
* @param {string} [props.title] editorial title; default derived from the branch name
|
|
9
|
+
* @param {string} [props.annotation] the saved user label (host-owned)
|
|
10
|
+
* @param {(value: string) => void} [props.onSaveAnnotation]
|
|
11
|
+
* @param {() => void} [props.onRemoveAnnotation]
|
|
12
|
+
* @param {() => void} [props.onOpenMap] the "see this work on the code map" exit (host owns the route)
|
|
13
|
+
* @param {() => void} [props.onShare] the "share … conversations" exit (host owns share UX)
|
|
14
|
+
* @param {() => void} [props.onCopyRecap] the "copy recap" exit (host owns the clipboard recap)
|
|
15
|
+
* @param {Record<string, boolean>} [props.initialOpenFiles] files open on first render (path → open?)
|
|
16
|
+
*/
|
|
17
|
+
export default function ChangeDetail({ payload, getDiff, title, annotation, onSaveAnnotation, onRemoveAnnotation, onOpenMap, onShare, onCopyRecap, initialOpenFiles, }: {
|
|
18
|
+
payload: import("./types.js").ChangeDetailPayload;
|
|
19
|
+
getDiff?: (file: import("./types.js").FileChangePayload) => import("./types.js").ChangeDiffPayload | null | undefined;
|
|
20
|
+
title?: string;
|
|
21
|
+
annotation?: string;
|
|
22
|
+
onSaveAnnotation?: (value: string) => void;
|
|
23
|
+
onRemoveAnnotation?: () => void;
|
|
24
|
+
onOpenMap?: () => void;
|
|
25
|
+
onShare?: () => void;
|
|
26
|
+
onCopyRecap?: () => void;
|
|
27
|
+
initialOpenFiles?: Record<string, boolean>;
|
|
28
|
+
}): any;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} props
|
|
3
|
+
* @param {import('./types.js').ChangesPayload} props.payload the cooked changes payload (adapter output)
|
|
4
|
+
* @param {string} [props.projectLabel] the head label (e.g. "peasant-labs/peasant"); host-supplied (not a payload field)
|
|
5
|
+
* @param {string} [props.selectedId] id of the active commit/tip row (the scarce amber treatment)
|
|
6
|
+
* @param {(commit: import('./changeGraph.js').CommitGraphRow) => void} [props.onSelectChange] a row was chosen (open its change detail)
|
|
7
|
+
* @param {() => void} [props.onOpenMap] the "open the map" affordance was pressed
|
|
8
|
+
* @param {boolean} [props.hasMore] more history exists below the window (→ "show older")
|
|
9
|
+
* @param {() => void} [props.onShowOlder] "show older" was pressed
|
|
10
|
+
* @param {number} [props.nowMs] pins relative-time humanisation (default Date.now()); the harness fixes it for byte-stable captures
|
|
11
|
+
*/
|
|
12
|
+
export default function Changes({ payload, projectLabel, selectedId, onSelectChange, onOpenMap, hasMore, onShowOlder, nowMs, }: {
|
|
13
|
+
payload: import("./types.js").ChangesPayload;
|
|
14
|
+
projectLabel?: string;
|
|
15
|
+
selectedId?: string;
|
|
16
|
+
onSelectChange?: (commit: import("./changeGraph.js").CommitGraphRow) => void;
|
|
17
|
+
onOpenMap?: () => void;
|
|
18
|
+
hasMore?: boolean;
|
|
19
|
+
onShowOlder?: () => void;
|
|
20
|
+
nowMs?: number;
|
|
21
|
+
}): any;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMap — the lifted code-topology surface over the shared MapCanvas.
|
|
3
|
+
*
|
|
4
|
+
* The payload remains the cooked topology contract from @peasant-labs/fairtrade/graph:
|
|
5
|
+
* geometry stays derived here, activity edges stay in the host rail, and the host
|
|
6
|
+
* feeds interaction state through props so demo and app render the same behavior.
|
|
7
|
+
*
|
|
8
|
+
* @param {object} props
|
|
9
|
+
* @param {import('./types.js').CodeMapPayload} props.payload
|
|
10
|
+
* @param {{level:'project'|'package'|'file', expanded?: Iterable<string>}} [props.zoom]
|
|
11
|
+
* @param {(zoom:{level:'project'|'package'|'file', expanded:string[]})=>void} [props.onZoomChange]
|
|
12
|
+
* @param {string|null} [props.selectedId]
|
|
13
|
+
* @param {(id:string|null, node:import('./types.js').MapNodePayload|null)=>void} [props.onSelect]
|
|
14
|
+
* @param {(id:string)=>void} [props.onExpand]
|
|
15
|
+
* @param {Iterable<string>} [props.highlightedIds]
|
|
16
|
+
* @param {Record<string,'new'|'removed'>} [props.nodeDeltas]
|
|
17
|
+
* @param {Record<string,'new'|'removed'>} [props.structureEdgeDeltas]
|
|
18
|
+
* @param {number|string} [props.height]
|
|
19
|
+
* @param {string} [props.ariaLabel]
|
|
20
|
+
* @param {string} [props.className]
|
|
21
|
+
*/
|
|
22
|
+
export default function CodeMap({ payload, zoom, onZoomChange, selectedId, onSelect, onExpand, highlightedIds, nodeDeltas, structureEdgeDeltas, height, ariaLabel, className, }: {
|
|
23
|
+
payload: import("./types.js").CodeMapPayload;
|
|
24
|
+
zoom?: {
|
|
25
|
+
level: "project" | "package" | "file";
|
|
26
|
+
expanded?: Iterable<string>;
|
|
27
|
+
};
|
|
28
|
+
onZoomChange?: (zoom: {
|
|
29
|
+
level: "project" | "package" | "file";
|
|
30
|
+
expanded: string[];
|
|
31
|
+
}) => void;
|
|
32
|
+
selectedId?: string | null;
|
|
33
|
+
onSelect?: (id: string | null, node: import("./types.js").MapNodePayload | null) => void;
|
|
34
|
+
onExpand?: (id: string) => void;
|
|
35
|
+
highlightedIds?: Iterable<string>;
|
|
36
|
+
nodeDeltas?: Record<string, "new" | "removed">;
|
|
37
|
+
structureEdgeDeltas?: Record<string, "new" | "removed">;
|
|
38
|
+
height?: number | string;
|
|
39
|
+
ariaLabel?: string;
|
|
40
|
+
className?: string;
|
|
41
|
+
}): any;
|
|
42
|
+
/**
|
|
43
|
+
* @param {import('./types.js').CodeMapPayload | undefined} payload
|
|
44
|
+
* @returns {{nodes: Array<object>, edges: Array<object>}}
|
|
45
|
+
*/
|
|
46
|
+
export function codeMapPayloadToMapData(payload: import("./types.js").CodeMapPayload | undefined): {
|
|
47
|
+
nodes: Array<object>;
|
|
48
|
+
edges: Array<object>;
|
|
49
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMapComposition — the FULL map surface (full-lift): the
|
|
3
|
+
* RailShell frame (sticky toolbar + canvas + rail), the persistent visual-
|
|
4
|
+
* channel legend, and the shared <CodeMap> canvas, composed once here so the
|
|
5
|
+
* demo GraphMap mockup and every consuming app (peasant, village) render the
|
|
6
|
+
* SAME toolbar/rail-shell/legend/interaction composition — not just the same
|
|
7
|
+
* canvas wrapped in each host's own hand-rolled shell.
|
|
8
|
+
*
|
|
9
|
+
* Before this component, only the canvas itself (<CodeMap>) was shared; the
|
|
10
|
+
* surrounding toolbar, rail shell, and legend were reimplemented per host
|
|
11
|
+
* (review finding: "CodeMap boundary only lifts the canvas wrapper").
|
|
12
|
+
* Composition-level pieces that are inherently
|
|
13
|
+
* host-specific — the RAIL's content (real API data vs. demo mock data) and
|
|
14
|
+
* the canvas region's loading/empty/error states (peasant's WS/REST fetch
|
|
15
|
+
* lifecycle vs. the demo's static fixture) — stay host-owned via the `rail`
|
|
16
|
+
* and `canvasSlot` slots below; everything else (frame, legend, interaction
|
|
17
|
+
* wiring) is now ONE implementation.
|
|
18
|
+
*
|
|
19
|
+
* @param {object} props
|
|
20
|
+
* @param {import('./types.js').CodeMapPayload} [props.payload] forwarded to <CodeMap> when `canvasSlot` is omitted
|
|
21
|
+
* @param {{level:'project'|'package'|'file', expanded?: Iterable<string>}} [props.zoom]
|
|
22
|
+
* @param {(zoom:{level:'project'|'package'|'file', expanded:string[]})=>void} [props.onZoomChange]
|
|
23
|
+
* @param {string|null} [props.selectedId]
|
|
24
|
+
* @param {(id:string|null, node:import('./types.js').MapNodePayload|null)=>void} [props.onSelect]
|
|
25
|
+
* @param {(id:string)=>void} [props.onExpand]
|
|
26
|
+
* @param {Iterable<string>} [props.highlightedIds]
|
|
27
|
+
* @param {Record<string,'new'|'removed'>} [props.nodeDeltas]
|
|
28
|
+
* @param {Record<string,'new'|'removed'>} [props.structureEdgeDeltas]
|
|
29
|
+
* @param {number|string} [props.height=480] canvas height, forwarded to <CodeMap>
|
|
30
|
+
* @param {string} [props.ariaLabel='code map'] forwarded to <CodeMap>
|
|
31
|
+
* @param {React.ReactNode} [props.canvasSlot] override the canvas region entirely
|
|
32
|
+
* (e.g. a host's loading/disconnected/error states); when omitted, renders
|
|
33
|
+
* <CodeMap> from the props above — the demo mockup and any host without
|
|
34
|
+
* custom fetch-lifecycle states can rely on the default.
|
|
35
|
+
* @param {React.ReactNode} props.rail the rail's content (host-specific:
|
|
36
|
+
* real API data vs. demo mock data) — compose with the kit's <RailSection>.
|
|
37
|
+
* @param {React.ReactNode} [props.toolbar] optional extra sticky toolbar content
|
|
38
|
+
* ABOVE the canvas (e.g. a connection indicator) — the canvas's OWN shared
|
|
39
|
+
* grain/search toolbar (owned by <CodeMap>/<MapCanvas>) is unaffected either way.
|
|
40
|
+
* @param {string} [props.sheetTitle='code area'] RailShell's mobile bottom-sheet title
|
|
41
|
+
* @param {React.ReactNode} [props.sheetMeta]
|
|
42
|
+
* @param {'left'|'right'} [props.railSide='right']
|
|
43
|
+
* @param {React.ReactNode|false} [props.legend] override the default legend; `false` hides it
|
|
44
|
+
* @param {string} [props.canvasWrapperClassName] extra class on the canvas region wrapper
|
|
45
|
+
* @param {React.CSSProperties} [props.canvasWrapperStyle] inline style on the canvas region wrapper
|
|
46
|
+
* (e.g. a host's own responsive height clamp)
|
|
47
|
+
* @param {string} [props.className] extra class on the root
|
|
48
|
+
*/
|
|
49
|
+
export default function CodeMapComposition({ payload, zoom, onZoomChange, selectedId, onSelect, onExpand, highlightedIds, nodeDeltas, structureEdgeDeltas, height, ariaLabel, canvasSlot, rail, toolbar, sheetTitle, sheetMeta, railSide, legend, canvasWrapperClassName, canvasWrapperStyle, className, }: {
|
|
50
|
+
payload?: import("./types.js").CodeMapPayload;
|
|
51
|
+
zoom?: {
|
|
52
|
+
level: "project" | "package" | "file";
|
|
53
|
+
expanded?: Iterable<string>;
|
|
54
|
+
};
|
|
55
|
+
onZoomChange?: (zoom: {
|
|
56
|
+
level: "project" | "package" | "file";
|
|
57
|
+
expanded: string[];
|
|
58
|
+
}) => void;
|
|
59
|
+
selectedId?: string | null;
|
|
60
|
+
onSelect?: (id: string | null, node: import("./types.js").MapNodePayload | null) => void;
|
|
61
|
+
onExpand?: (id: string) => void;
|
|
62
|
+
highlightedIds?: Iterable<string>;
|
|
63
|
+
nodeDeltas?: Record<string, "new" | "removed">;
|
|
64
|
+
structureEdgeDeltas?: Record<string, "new" | "removed">;
|
|
65
|
+
height?: number | string;
|
|
66
|
+
ariaLabel?: string;
|
|
67
|
+
canvasSlot?: React.ReactNode;
|
|
68
|
+
rail: React.ReactNode;
|
|
69
|
+
toolbar?: React.ReactNode;
|
|
70
|
+
sheetTitle?: string;
|
|
71
|
+
sheetMeta?: React.ReactNode;
|
|
72
|
+
railSide?: "left" | "right";
|
|
73
|
+
legend?: React.ReactNode | false;
|
|
74
|
+
canvasWrapperClassName?: string;
|
|
75
|
+
canvasWrapperStyle?: React.CSSProperties;
|
|
76
|
+
className?: string;
|
|
77
|
+
}): any;
|
|
78
|
+
/**
|
|
79
|
+
* The persistent legend explaining the canvas's four orthogonal visual channels
|
|
80
|
+
* (peasant spec §4/§5: WIDTH ∝ loc, monochrome FILL ∝ coverage, folder/file ICON,
|
|
81
|
+
* amber SELECTION, clay VIOLATION badge) — so the picture never needs decoding.
|
|
82
|
+
* Lifted here from the peasant app (was app-only chrome, spec-legend drift risk)
|
|
83
|
+
* so demo and every consuming app show the SAME legend for the SAME canvas.
|
|
84
|
+
*/
|
|
85
|
+
export function DefaultMapLegend(): any;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Humanise an absolute epoch-ms time into a short relative label ("5h ago",
|
|
3
|
+
* "3d ago", "1wk ago"). Pure: depends only on (timeMs, nowMs). Returns '' when
|
|
4
|
+
* the time is missing so the kit simply omits the label.
|
|
5
|
+
*
|
|
6
|
+
* @param {number | null | undefined} timeMs
|
|
7
|
+
* @param {number} nowMs
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export function humanizeAge(timeMs: number | null | undefined, nowMs: number): string;
|
|
11
|
+
/**
|
|
12
|
+
* Derive the CommitGraph dataset (+ reverted list + counts) from a ChangesPayload.
|
|
13
|
+
*
|
|
14
|
+
* Lane assignment is deterministic: open changes sort by tip time (newest first,
|
|
15
|
+
* branch name as a tiebreak) and take lanes 1..N in that order. Each open change
|
|
16
|
+
* contributes a tip row inserted just above the first recent commit at/older than
|
|
17
|
+
* its tip time; its `parents` point at its merge-base (baseHash) when that commit
|
|
18
|
+
* is in the window. Merged changes flip `merged` on their merge commit and add the
|
|
19
|
+
* (synthetic) branch tip as a second parent so the kit draws the join elbow.
|
|
20
|
+
*
|
|
21
|
+
* @param {ChangesPayload} payload
|
|
22
|
+
* @param {{ nowMs: number }} opts `nowMs` pins relative-time humanisation (determinism)
|
|
23
|
+
* @returns {ChangesGraph}
|
|
24
|
+
*/
|
|
25
|
+
export function buildChangesGraph(payload: ChangesPayload, { nowMs }: {
|
|
26
|
+
nowMs: number;
|
|
27
|
+
}): ChangesGraph;
|
|
28
|
+
export type ChangesPayload = import("./types.js").ChangesPayload;
|
|
29
|
+
export type ChangeSummaryPayload = import("./types.js").ChangeSummaryPayload;
|
|
30
|
+
export type CommitRefPayload = import("./types.js").CommitRefPayload;
|
|
31
|
+
/**
|
|
32
|
+
* One row in the kit CommitGraph dataset (mirrors the `Commit` shape documented
|
|
33
|
+
* on src/ui/CommitGraph.jsx). Time order = array order (newest first); the graph
|
|
34
|
+
* is implicit in `lane` + `parents`.
|
|
35
|
+
*/
|
|
36
|
+
export type CommitGraphRow = {
|
|
37
|
+
/**
|
|
38
|
+
* stable key (commit hash, or `tip:<branch>` for an open tip)
|
|
39
|
+
*/
|
|
40
|
+
id: string;
|
|
41
|
+
/**
|
|
42
|
+
* 0 = the default-branch line; >0 = a branch lane
|
|
43
|
+
*/
|
|
44
|
+
lane: number;
|
|
45
|
+
/**
|
|
46
|
+
* parent row ids (>1 ⇒ a merge)
|
|
47
|
+
*/
|
|
48
|
+
parents?: string[];
|
|
49
|
+
/**
|
|
50
|
+
* the commit subject / branch label (USER CONTENT — case preserved)
|
|
51
|
+
*/
|
|
52
|
+
message: string;
|
|
53
|
+
/**
|
|
54
|
+
* branch name chip (USER CONTENT — case preserved)
|
|
55
|
+
*/
|
|
56
|
+
branch?: string;
|
|
57
|
+
/**
|
|
58
|
+
* a recorded session sits behind this commit (→ filled dot + sparkle)
|
|
59
|
+
*/
|
|
60
|
+
session?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* this commit merged a branch back in (→ merged chip)
|
|
63
|
+
*/
|
|
64
|
+
merged?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* this row is an open branch tip (→ tip affordance)
|
|
67
|
+
*/
|
|
68
|
+
tip?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* humanised relative time (e.g. "5h ago")
|
|
71
|
+
*/
|
|
72
|
+
time?: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* A reverted line of work, surfaced under the graph (the demo's "reverted" chip).
|
|
76
|
+
*/
|
|
77
|
+
export type RevertedChange = {
|
|
78
|
+
branch: string;
|
|
79
|
+
mergedAtMs?: number | null;
|
|
80
|
+
/**
|
|
81
|
+
* humanised relative time of the merge
|
|
82
|
+
*/
|
|
83
|
+
when?: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* The derived Changes view model: the CommitGraph dataset + the reverted list +
|
|
87
|
+
* the head counts the surface caption shows.
|
|
88
|
+
*/
|
|
89
|
+
export type ChangesGraph = {
|
|
90
|
+
/**
|
|
91
|
+
* newest first; lane 0 is the default branch
|
|
92
|
+
*/
|
|
93
|
+
commits: CommitGraphRow[];
|
|
94
|
+
/**
|
|
95
|
+
* merged-then-reverted changes (listed under the graph)
|
|
96
|
+
*/
|
|
97
|
+
reverted: RevertedChange[];
|
|
98
|
+
/**
|
|
99
|
+
* number of open changes
|
|
100
|
+
*/
|
|
101
|
+
openCount: number;
|
|
102
|
+
/**
|
|
103
|
+
* number of merged changes
|
|
104
|
+
*/
|
|
105
|
+
mergedCount: number;
|
|
106
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { default as Changes } from "./Changes.jsx";
|
|
2
|
+
export { default as ChangeDetail } from "./ChangeDetail.jsx";
|
|
3
|
+
export type MapNodeKind = import("./types.js").MapNodeKind;
|
|
4
|
+
export type ChangeBinding = import("./types.js").ChangeBinding;
|
|
5
|
+
export type EdgeViolationKind = import("./types.js").EdgeViolationKind;
|
|
6
|
+
export type FileChangeStatus = import("./types.js").FileChangeStatus;
|
|
7
|
+
export type DiffLineKind = import("./types.js").DiffLineKind;
|
|
8
|
+
export type CommitRefPayload = import("./types.js").CommitRefPayload;
|
|
9
|
+
export type MapEdgePayload = import("./types.js").MapEdgePayload;
|
|
10
|
+
export type ActivityEdgePayload = import("./types.js").ActivityEdgePayload;
|
|
11
|
+
export type EdgeViolationPayload = import("./types.js").EdgeViolationPayload;
|
|
12
|
+
export type MapNodePayload = import("./types.js").MapNodePayload;
|
|
13
|
+
export type MapSlicePayload = import("./types.js").MapSlicePayload;
|
|
14
|
+
export type ChangeSummaryPayload = import("./types.js").ChangeSummaryPayload;
|
|
15
|
+
export type ChangesPayload = import("./types.js").ChangesPayload;
|
|
16
|
+
export type TaskSummaryPayload = import("./types.js").TaskSummaryPayload;
|
|
17
|
+
export type ChangeSessionPayload = import("./types.js").ChangeSessionPayload;
|
|
18
|
+
export type UnusualSignalPayload = import("./types.js").UnusualSignalPayload;
|
|
19
|
+
export type FrictionClusterPayload = import("./types.js").FrictionClusterPayload;
|
|
20
|
+
export type FileChangePayload = import("./types.js").FileChangePayload;
|
|
21
|
+
export type ChangeDetailPayload = import("./types.js").ChangeDetailPayload;
|
|
22
|
+
export type DiffLinePayload = import("./types.js").DiffLinePayload;
|
|
23
|
+
export type DiffHunkPayload = import("./types.js").DiffHunkPayload;
|
|
24
|
+
export type ChangeDiffPayload = import("./types.js").ChangeDiffPayload;
|
|
25
|
+
export type CodeMapPayload = import("./types.js").CodeMapPayload;
|
|
26
|
+
export { default as CodeMap, codeMapPayloadToMapData } from "./CodeMap.jsx";
|
|
27
|
+
export { default as CodeMapComposition, DefaultMapLegend } from "./CodeMapComposition.jsx";
|
|
28
|
+
export { GraphAppShell, GraphSectionNav, GRAPH_APP_SECTIONS } from "../inuse/InUseShell.jsx";
|
|
29
|
+
export { buildChangesGraph, humanizeAge } from "./changeGraph.js";
|
|
30
|
+
export { MAP_NODE_KINDS, CHANGE_BINDINGS, EDGE_VIOLATION_KINDS, FILE_CHANGE_STATUSES, DIFF_LINE_KINDS } from "./types.js";
|