Skip to content

Commit 2b910cb

Browse files
committed
feat(devtools): improve bridge exports, graph interactions, and inspector layout
- devtools-bridge: re-export bridge functions, add OIDC/Journey emit helpers - Graph.elm: enhanced node rendering with hover effects and improved layout - FlowView.elm: improved detail card layout and node selection - Inspector.elm: refined tab content and formatting - davinci-client: api-report updates (union type reordering)
1 parent db74aa3 commit 2b910cb

10 files changed

Lines changed: 204 additions & 56 deletions

File tree

packages/davinci-client/api-report/davinci-client.api.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,11 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
267267
resume: (input: {
268268
continueToken: string;
269269
}) => Promise<InternalErrorResponse | NodeStates>;
270-
start: <QueryParams extends OutgoingQueryParams = OutgoingQueryParams>(options?: StartOptions<QueryParams> | undefined) => Promise<ContinueNode | StartNode | ErrorNode | FailureNode | SuccessNode>;
270+
start: <QueryParams extends OutgoingQueryParams = OutgoingQueryParams>(options?: StartOptions<QueryParams> | undefined) => Promise<ContinueNode | ErrorNode | FailureNode | StartNode | SuccessNode>;
271271
update: <T extends SingleValueCollectors | MultiSelectCollector | ObjectValueCollectors | AutoCollectors>(collector: T) => Updater<T>;
272272
validate: (collector: SingleValueCollectors | ObjectValueCollectors | MultiValueCollectors | AutoCollectors) => Validator;
273273
pollStatus: (collector: PollingCollector) => Poller;
274274
getClient: () => {
275-
status: "start";
276-
} | {
277275
action: string;
278276
collectors: Collectors[];
279277
description?: string;
@@ -287,6 +285,8 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
287285
status: "error";
288286
} | {
289287
status: "failure";
288+
} | {
289+
status: "start";
290290
} | {
291291
authorization?: {
292292
code?: string;
@@ -297,7 +297,7 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
297297
getCollectors: () => Collectors[];
298298
getError: () => DaVinciError | null;
299299
getErrorCollectors: () => CollectorErrors[];
300-
getNode: () => ContinueNode | StartNode | ErrorNode | FailureNode | SuccessNode;
300+
getNode: () => ContinueNode | ErrorNode | FailureNode | StartNode | SuccessNode;
301301
getServer: () => {
302302
_links?: Links;
303303
id?: string;
@@ -306,8 +306,6 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
306306
href?: string;
307307
eventName?: string;
308308
status: "continue";
309-
} | {
310-
status: "start";
311309
} | {
312310
_links?: Links;
313311
eventName?: string;
@@ -323,6 +321,8 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
323321
interactionId?: string;
324322
interactionToken?: string;
325323
status: "failure";
324+
} | {
325+
status: "start";
326326
} | {
327327
_links?: Links;
328328
eventName?: string;

packages/davinci-client/api-report/davinci-client.types.api.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,11 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
267267
resume: (input: {
268268
continueToken: string;
269269
}) => Promise<InternalErrorResponse | NodeStates>;
270-
start: <QueryParams extends OutgoingQueryParams = OutgoingQueryParams>(options?: StartOptions<QueryParams> | undefined) => Promise<ContinueNode | StartNode | ErrorNode | FailureNode | SuccessNode>;
270+
start: <QueryParams extends OutgoingQueryParams = OutgoingQueryParams>(options?: StartOptions<QueryParams> | undefined) => Promise<ContinueNode | ErrorNode | FailureNode | StartNode | SuccessNode>;
271271
update: <T extends SingleValueCollectors | MultiSelectCollector | ObjectValueCollectors | AutoCollectors>(collector: T) => Updater<T>;
272272
validate: (collector: SingleValueCollectors | ObjectValueCollectors | MultiValueCollectors | AutoCollectors) => Validator;
273273
pollStatus: (collector: PollingCollector) => Poller;
274274
getClient: () => {
275-
status: "start";
276-
} | {
277275
action: string;
278276
collectors: Collectors[];
279277
description?: string;
@@ -287,6 +285,8 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
287285
status: "error";
288286
} | {
289287
status: "failure";
288+
} | {
289+
status: "start";
290290
} | {
291291
authorization?: {
292292
code?: string;
@@ -297,7 +297,7 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
297297
getCollectors: () => Collectors[];
298298
getError: () => DaVinciError | null;
299299
getErrorCollectors: () => CollectorErrors[];
300-
getNode: () => ContinueNode | StartNode | ErrorNode | FailureNode | SuccessNode;
300+
getNode: () => ContinueNode | ErrorNode | FailureNode | StartNode | SuccessNode;
301301
getServer: () => {
302302
_links?: Links;
303303
id?: string;
@@ -306,8 +306,6 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
306306
href?: string;
307307
eventName?: string;
308308
status: "continue";
309-
} | {
310-
status: "start";
311309
} | {
312310
_links?: Links;
313311
eventName?: string;
@@ -323,6 +321,8 @@ export function davinci<ActionType extends ActionTypes = ActionTypes>(input: {
323321
interactionId?: string;
324322
interactionToken?: string;
325323
status: "failure";
324+
} | {
325+
status: "start";
326326
} | {
327327
_links?: Links;
328328
eventName?: string;

packages/devtools-bridge/src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@ export { attachJourneyBridge } from './lib/journey-bridge.js';
44
export type { JourneyBridgeHandle } from './lib/journey-bridge.js';
55
export { attachOidcBridge } from './lib/oidc-bridge.js';
66
export type { OidcBridgeHandle } from './lib/oidc-bridge.js';
7-
export { DEVTOOLS_EVENT_NAME, emitAuthEvent, emitConfigEvent } from './lib/emit.js';
7+
export {
8+
DEVTOOLS_EVENT_NAME,
9+
emitAuthEvent,
10+
emitConfigEvent,
11+
configureDevtools,
12+
} from './lib/emit.js';
13+
export type { DevtoolsOptions } from './lib/emit.js';

packages/devtools-bridge/src/lib/bridge.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Schema, Option, pipe } from 'effect';
22
import type { SdkData } from '@forgerock/devtools-types';
33
import { SdkErrorSchema, SdkAuthorizationSchema } from '@forgerock/devtools-types';
4-
import { emitAuthEvent, emitConfigEvent } from './emit.js';
4+
import { emitAuthEvent, emitConfigEvent, configureDevtools } from './emit.js';
5+
import type { DevtoolsOptions } from './emit.js';
56

67
interface Subscribable {
78
subscribe: (listener: () => void) => () => void;
@@ -177,11 +178,19 @@ function emitNodeChange(data: SdkData): void {
177178
*
178179
* Returns a no-op handle when run outside a browser. Always call `detach()` on cleanup.
179180
*/
180-
export function attachDevToolsBridge(client: Subscribable, config?: object): BridgeHandle {
181+
export function attachDevToolsBridge(
182+
client: Subscribable,
183+
config?: object,
184+
devtoolsOptions?: DevtoolsOptions,
185+
): BridgeHandle {
181186
if (typeof window === 'undefined') {
182187
return { detach: () => undefined };
183188
}
184189

190+
if (devtoolsOptions) {
191+
configureDevtools(devtoolsOptions);
192+
}
193+
185194
let previousStatus: string | undefined;
186195
let configEmitted = false;
187196
let lastSnapshot: SessionSnapshot = snapshotSession();

packages/devtools-bridge/src/lib/emit.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,34 @@ import type { AuthEvent } from '@forgerock/devtools-types';
22

33
export const DEVTOOLS_EVENT_NAME = 'pingDevtools';
44

5+
export interface DevtoolsOptions {
6+
consoleLog?: boolean;
7+
}
8+
9+
declare global {
10+
interface Window {
11+
__PING_DEVTOOLS_STATE__?: AuthEvent[];
12+
}
13+
}
14+
15+
let options: DevtoolsOptions = {};
16+
17+
export function configureDevtools(opts: DevtoolsOptions): void {
18+
options = opts;
19+
}
20+
521
export function emitAuthEvent(event: AuthEvent): void {
622
if (typeof window === 'undefined') return;
23+
24+
if (!window.__PING_DEVTOOLS_STATE__) {
25+
window.__PING_DEVTOOLS_STATE__ = [];
26+
}
27+
window.__PING_DEVTOOLS_STATE__.push(event);
28+
29+
if (options.consoleLog) {
30+
console.log('[ping-devtools]', event.type, event);
31+
}
32+
733
window.dispatchEvent(new CustomEvent(DEVTOOLS_EVENT_NAME, { detail: event }));
834
}
935

packages/devtools-bridge/src/lib/journey-bridge.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Schema, Option, pipe } from 'effect';
2-
import { emitAuthEvent, emitConfigEvent } from './emit.js';
2+
import { emitAuthEvent, emitConfigEvent, configureDevtools } from './emit.js';
3+
import type { DevtoolsOptions } from './emit.js';
34
import type { JourneyData } from '@forgerock/devtools-types';
45

56
export interface JourneyBridgeHandle {
@@ -102,11 +103,16 @@ function extractErrorMessage(error: unknown): string {
102103
export function attachJourneyBridge(
103104
client: JourneySubscribable,
104105
config?: object,
106+
devtoolsOptions?: DevtoolsOptions,
105107
): JourneyBridgeHandle {
106108
if (typeof window === 'undefined') {
107109
return { detach: () => undefined };
108110
}
109111

112+
if (devtoolsOptions) {
113+
configureDevtools(devtoolsOptions);
114+
}
115+
110116
let configEmitted = false;
111117
let emittedRequests = new Set<string>();
112118

packages/devtools-bridge/src/lib/oidc-bridge.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Schema, Option, pipe } from 'effect';
2-
import { emitAuthEvent, emitConfigEvent } from './emit.js';
2+
import { emitAuthEvent, emitConfigEvent, configureDevtools } from './emit.js';
3+
import type { DevtoolsOptions } from './emit.js';
34
import type { OidcData } from '@forgerock/devtools-types';
45

56
export interface OidcBridgeHandle {
@@ -97,11 +98,16 @@ function mutationToOidcData(
9798
export function attachOidcBridge(
9899
client: OidcSubscribable,
99100
config?: { clientId?: string } & object,
101+
devtoolsOptions?: DevtoolsOptions,
100102
): OidcBridgeHandle {
101103
if (typeof window === 'undefined') {
102104
return { detach: () => undefined };
103105
}
104106

107+
if (devtoolsOptions) {
108+
configureDevtools(devtoolsOptions);
109+
}
110+
105111
let configEmitted = false;
106112
let emittedRequests = new Set<string>();
107113

packages/devtools-extension/src/panel/src/FlowView.elm

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Helpers
44
import Html exposing (Html)
55
import Html.Attributes exposing (..)
66
import Html.Events
7+
import Json.Encode as Encode
78
import JsonTree
89
import Set exposing (Set)
910
import Svg exposing (..)
@@ -235,10 +236,10 @@ renderArrow total index =
235236
else
236237
let
237238
x1_ =
238-
index * nodeSpacing + 40 + nodeRadius + 4
239+
index * nodeSpacing + 40 + nodeRadius + 16
239240

240241
x2_ =
241-
(index + 1) * nodeSpacing + 40 - nodeRadius - 4
242+
(index + 1) * nodeSpacing + 40 - nodeRadius - 16
242243

243244
y_ =
244245
44
@@ -297,7 +298,7 @@ viewKvRow key val =
297298
, Html.span [ Html.Attributes.class "fv-kv-val" ] [ Html.text val ]
298299
, Html.button
299300
[ Html.Attributes.class "fv-copy-btn"
300-
, Html.Attributes.attribute "data-copy" val
301+
, Html.Events.onClick (CopyToClipboard val)
301302
]
302303
[ Html.text "" ]
303304
]
@@ -365,12 +366,28 @@ viewDaVinciNodeData nodeId node expandedSubRows =
365366
(case node.collectors of
366367
Nothing -> []
367368
Just cs ->
368-
List.indexedMap
369-
(\i c ->
370-
Html.div [ Html.Attributes.class "coll-card" ]
371-
[ JsonTree.view ("Collector " ++ String.fromInt (i + 1)) c ]
372-
)
373-
cs
369+
Html.div [ Html.Attributes.class "coll-copy-all-row" ]
370+
[ Html.button
371+
[ Html.Attributes.class "fv-copy-btn coll-copy-all"
372+
, Html.Events.onClick (CopyToClipboard (Encode.encode 4 (Encode.list identity cs)))
373+
]
374+
[ Html.text "Copy all" ]
375+
]
376+
:: List.indexedMap
377+
(\i c ->
378+
Html.div [ Html.Attributes.class "coll-card" ]
379+
[ Html.div [ Html.Attributes.class "coll-card-header" ]
380+
[ Html.span [] [ Html.text ("Collector " ++ String.fromInt (i + 1)) ]
381+
, Html.button
382+
[ Html.Attributes.class "fv-copy-btn"
383+
, Html.Events.onClick (CopyToClipboard (Encode.encode 4 c))
384+
]
385+
[ Html.text "\u{2398}" ]
386+
]
387+
, JsonTree.view ("Collector " ++ String.fromInt (i + 1)) c
388+
]
389+
)
390+
cs
374391
)
375392

376393
else

0 commit comments

Comments
 (0)