@player-ui/react 0.8.0--canary.307.9621 → 0.8.0-next.0
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/cjs/index.cjs +664 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/index.legacy-esm.js +611 -0
- package/dist/index.mjs +611 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +30 -64
- package/src/__tests__/__snapshots__/app.test.tsx.snap +139 -0
- package/src/__tests__/app.test.tsx +244 -0
- package/src/__tests__/helpers/simple-asset-plugin.tsx +114 -0
- package/src/__tests__/hooks.test.tsx +8 -0
- package/src/app.tsx +3 -3
- package/src/asset/__tests__/index.test.tsx +129 -0
- package/src/asset/index.tsx +10 -10
- package/src/hooks.tsx +7 -8
- package/src/index.tsx +8 -8
- package/src/manager/__tests__/managed-player.test.tsx +454 -0
- package/src/manager/managed-player.tsx +31 -36
- package/src/manager/request-time.tsx +8 -8
- package/src/manager/types.ts +12 -12
- package/src/player.tsx +24 -43
- package/src/plugins/onupdate-plugin.ts +3 -3
- package/src/plugins/tapstate-plugin.ts +4 -4
- package/src/utils/__tests__/helpers.test.ts +39 -0
- package/src/utils/__tests__/url.test.ts +14 -0
- package/src/utils/helpers.ts +15 -12
- package/src/utils/index.tsx +6 -6
- package/src/utils/player-context.ts +2 -2
- package/src/utils/shared-constants.tsx +2 -2
- package/src/utils/url.ts +2 -2
- package/src/utils/use-asset-props.tsx +2 -2
- package/src/utils/use-logger.ts +3 -3
- package/types/app.d.ts +14 -0
- package/types/asset/index.d.ts +16 -0
- package/types/hooks.d.ts +17 -0
- package/types/index.d.ts +9 -0
- package/types/manager/managed-player.d.ts +93 -0
- package/types/manager/request-time.d.ts +7 -0
- package/types/manager/types.d.ts +125 -0
- package/types/player.d.ts +86 -0
- package/types/plugins/onupdate-plugin.d.ts +12 -0
- package/types/plugins/tapstate-plugin.d.ts +12 -0
- package/types/utils/helpers.d.ts +17 -0
- package/types/utils/index.d.ts +7 -0
- package/types/utils/player-context.d.ts +16 -0
- package/types/utils/shared-constants.d.ts +5 -0
- package/types/utils/url.d.ts +5 -0
- package/types/utils/use-asset-props.d.ts +7 -0
- package/types/utils/use-logger.d.ts +6 -0
- package/dist/index.cjs.js +0 -690
- package/dist/index.d.ts +0 -397
- package/dist/index.esm.js +0 -658
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { test, expect, vitest } from "vitest";
|
|
2
|
+
import React, { Suspense } from "react";
|
|
3
|
+
import { makeFlow } from "@player-ui/make-flow";
|
|
4
|
+
import { render, act, configure, waitFor } from "@testing-library/react";
|
|
5
|
+
import {
|
|
6
|
+
MetricsCorePlugin,
|
|
7
|
+
RequestTimeWebPlugin,
|
|
8
|
+
} from "@player-ui/metrics-plugin";
|
|
9
|
+
import { ManagedPlayer } from "../managed-player";
|
|
10
|
+
import type { FlowManager, FallbackProps } from "../types";
|
|
11
|
+
import { SimpleAssetPlugin } from "../../__tests__/helpers/simple-asset-plugin";
|
|
12
|
+
|
|
13
|
+
vitest.mock("@player-ui/metrics-plugin", async () => {
|
|
14
|
+
const actual: object = await vitest.importActual("@player-ui/metrics-plugin");
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
RequestTimeWebPlugin: vitest.fn().mockImplementation(() => {
|
|
19
|
+
return { apply: vitest.fn() };
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
configure({ testIdAttribute: "id" });
|
|
25
|
+
|
|
26
|
+
const testOptions = { legacyRoot: true };
|
|
27
|
+
|
|
28
|
+
test("requestTime should be available", async () => {
|
|
29
|
+
const manager: FlowManager = {
|
|
30
|
+
next: vitest
|
|
31
|
+
.fn()
|
|
32
|
+
.mockReturnValueOnce(
|
|
33
|
+
Promise.resolve({
|
|
34
|
+
value: makeFlow({
|
|
35
|
+
id: "flow-1",
|
|
36
|
+
type: "collection",
|
|
37
|
+
values: [
|
|
38
|
+
{
|
|
39
|
+
asset: {
|
|
40
|
+
id: "action",
|
|
41
|
+
type: "action",
|
|
42
|
+
value: "Next",
|
|
43
|
+
label: "Continue",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
}),
|
|
48
|
+
}),
|
|
49
|
+
)
|
|
50
|
+
.mockReturnValueOnce(
|
|
51
|
+
Promise.resolve({
|
|
52
|
+
value: makeFlow({
|
|
53
|
+
id: "flow-2",
|
|
54
|
+
type: "collection",
|
|
55
|
+
values: [
|
|
56
|
+
{
|
|
57
|
+
asset: {
|
|
58
|
+
id: "action",
|
|
59
|
+
type: "action",
|
|
60
|
+
value: "Next",
|
|
61
|
+
label: "Continue",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
}),
|
|
66
|
+
}),
|
|
67
|
+
)
|
|
68
|
+
.mockReturnValue(Promise.resolve({ done: true })),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const onComplete = vitest.fn();
|
|
72
|
+
const onError = vitest.fn();
|
|
73
|
+
|
|
74
|
+
const container = render(
|
|
75
|
+
<Suspense fallback="loading">
|
|
76
|
+
<ManagedPlayer
|
|
77
|
+
manager={manager}
|
|
78
|
+
plugins={[new SimpleAssetPlugin(), new MetricsCorePlugin()]}
|
|
79
|
+
onComplete={onComplete}
|
|
80
|
+
onError={onError}
|
|
81
|
+
/>
|
|
82
|
+
</Suspense>,
|
|
83
|
+
testOptions,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(manager.next).toBeCalledWith(undefined);
|
|
87
|
+
const view = await container.findByTestId("flow-1");
|
|
88
|
+
expect(view).toBeInTheDocument();
|
|
89
|
+
|
|
90
|
+
await act(async () => {
|
|
91
|
+
const nextButton = await container.findByText("Continue");
|
|
92
|
+
nextButton.click();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(manager.next).toBeCalledTimes(2);
|
|
96
|
+
|
|
97
|
+
const view2 = await container.findByTestId("flow-2");
|
|
98
|
+
expect(view2).toBeInTheDocument();
|
|
99
|
+
|
|
100
|
+
await act(async () => {
|
|
101
|
+
const nextButton = await container.findByText("Continue");
|
|
102
|
+
nextButton.click();
|
|
103
|
+
});
|
|
104
|
+
const getRequestTime = (RequestTimeWebPlugin as any).mock.calls[0][0];
|
|
105
|
+
expect(getRequestTime()).toBeDefined();
|
|
106
|
+
expect(onComplete).toBeCalled();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("handles dummy flows", async () => {
|
|
110
|
+
const manager: FlowManager = {
|
|
111
|
+
next: vitest
|
|
112
|
+
.fn()
|
|
113
|
+
.mockReturnValueOnce(
|
|
114
|
+
Promise.resolve({
|
|
115
|
+
value: makeFlow({
|
|
116
|
+
id: "flow-1",
|
|
117
|
+
type: "collection",
|
|
118
|
+
values: [
|
|
119
|
+
{
|
|
120
|
+
asset: {
|
|
121
|
+
id: "action",
|
|
122
|
+
type: "action",
|
|
123
|
+
value: "Next",
|
|
124
|
+
label: "Continue",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
}),
|
|
129
|
+
}),
|
|
130
|
+
)
|
|
131
|
+
.mockReturnValueOnce(
|
|
132
|
+
Promise.resolve({
|
|
133
|
+
value: {
|
|
134
|
+
...makeFlow({
|
|
135
|
+
id: "flow-2",
|
|
136
|
+
type: "collection",
|
|
137
|
+
values: [
|
|
138
|
+
{
|
|
139
|
+
asset: {
|
|
140
|
+
id: "action",
|
|
141
|
+
type: "action",
|
|
142
|
+
value: "Next",
|
|
143
|
+
label: "Continue",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
}),
|
|
148
|
+
data: { foo: "bar" },
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
)
|
|
152
|
+
.mockReturnValue(Promise.resolve({ done: true })),
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const onComplete = vitest.fn();
|
|
156
|
+
const onError = vitest.fn();
|
|
157
|
+
|
|
158
|
+
const screen = render(
|
|
159
|
+
<Suspense fallback="loading">
|
|
160
|
+
<ManagedPlayer
|
|
161
|
+
manager={manager}
|
|
162
|
+
plugins={[new SimpleAssetPlugin()]}
|
|
163
|
+
onComplete={onComplete}
|
|
164
|
+
onError={onError}
|
|
165
|
+
/>
|
|
166
|
+
</Suspense>,
|
|
167
|
+
testOptions,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
expect(manager.next).toBeCalledWith(undefined);
|
|
171
|
+
const view = await screen.findByTestId("flow-1");
|
|
172
|
+
expect(view).toBeInTheDocument();
|
|
173
|
+
|
|
174
|
+
await act(async () => {
|
|
175
|
+
const nextButton = await screen.findByText("Continue");
|
|
176
|
+
nextButton.click();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(manager.next).toBeCalledTimes(2);
|
|
180
|
+
|
|
181
|
+
const view2 = await screen.findByTestId("flow-2");
|
|
182
|
+
expect(view2).toBeInTheDocument();
|
|
183
|
+
|
|
184
|
+
await act(async () => {
|
|
185
|
+
const nextButton = await screen.findByText("Continue");
|
|
186
|
+
nextButton.click();
|
|
187
|
+
});
|
|
188
|
+
expect(onComplete).toBeCalledWith(
|
|
189
|
+
expect.objectContaining({
|
|
190
|
+
status: "completed",
|
|
191
|
+
data: { foo: "bar" },
|
|
192
|
+
}),
|
|
193
|
+
);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("handles FlowManager error", async () => {
|
|
197
|
+
const manager: FlowManager = {
|
|
198
|
+
next: vitest
|
|
199
|
+
.fn()
|
|
200
|
+
.mockReturnValueOnce(
|
|
201
|
+
Promise.resolve({
|
|
202
|
+
value: makeFlow({
|
|
203
|
+
id: "flow-1",
|
|
204
|
+
type: "collection",
|
|
205
|
+
values: [
|
|
206
|
+
{
|
|
207
|
+
asset: {
|
|
208
|
+
id: "action",
|
|
209
|
+
type: "action",
|
|
210
|
+
value: "Next",
|
|
211
|
+
label: "Continue",
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
}),
|
|
216
|
+
}),
|
|
217
|
+
)
|
|
218
|
+
.mockImplementationOnce(() => {
|
|
219
|
+
throw new Error();
|
|
220
|
+
})
|
|
221
|
+
.mockImplementationOnce(() => {
|
|
222
|
+
throw new Error();
|
|
223
|
+
})
|
|
224
|
+
.mockReturnValue(Promise.resolve({ done: true })),
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const onComplete = vitest.fn();
|
|
228
|
+
const onError = vitest.fn();
|
|
229
|
+
/**
|
|
230
|
+
*
|
|
231
|
+
*/
|
|
232
|
+
const MyFallback = (props: FallbackProps) => (
|
|
233
|
+
<div>
|
|
234
|
+
<button type="button" onClick={props?.retry}>
|
|
235
|
+
Retry
|
|
236
|
+
</button>
|
|
237
|
+
<button type="button" onClick={props?.reset}>
|
|
238
|
+
Reset
|
|
239
|
+
</button>
|
|
240
|
+
</div>
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const screen = render(
|
|
244
|
+
<Suspense fallback="loading">
|
|
245
|
+
<ManagedPlayer
|
|
246
|
+
manager={manager}
|
|
247
|
+
plugins={[new SimpleAssetPlugin()]}
|
|
248
|
+
fallbackComponent={MyFallback}
|
|
249
|
+
onComplete={onComplete}
|
|
250
|
+
onError={onError}
|
|
251
|
+
/>
|
|
252
|
+
</Suspense>,
|
|
253
|
+
testOptions,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
expect(manager.next).toBeCalledWith(undefined);
|
|
257
|
+
const view = await screen.findByTestId("flow-1");
|
|
258
|
+
expect(view).toBeInTheDocument();
|
|
259
|
+
|
|
260
|
+
await act(async () => {
|
|
261
|
+
const nextButton = await screen.findByText("Continue");
|
|
262
|
+
nextButton.click();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(manager.next).toBeCalledTimes(2);
|
|
266
|
+
|
|
267
|
+
await act(async () => {
|
|
268
|
+
const nextButton = await screen.findByText("Retry");
|
|
269
|
+
nextButton.click();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(manager.next).toBeCalledTimes(3);
|
|
273
|
+
|
|
274
|
+
await act(async () => {
|
|
275
|
+
const nextButton = await screen.findByText("Reset");
|
|
276
|
+
nextButton.click();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(manager.next).toBeCalledTimes(4);
|
|
280
|
+
expect(onError).toBeCalledTimes(2);
|
|
281
|
+
expect(onComplete).toBeCalled();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test("handles flow error", async () => {
|
|
285
|
+
const manager: FlowManager = {
|
|
286
|
+
next: vitest
|
|
287
|
+
.fn()
|
|
288
|
+
.mockReturnValueOnce(
|
|
289
|
+
Promise.resolve({
|
|
290
|
+
value: makeFlow({
|
|
291
|
+
id: "flow-1",
|
|
292
|
+
type: "collection",
|
|
293
|
+
values: [
|
|
294
|
+
{
|
|
295
|
+
asset: {
|
|
296
|
+
id: "action",
|
|
297
|
+
type: "action",
|
|
298
|
+
value: "Next",
|
|
299
|
+
label: "Continue",
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
}),
|
|
304
|
+
}),
|
|
305
|
+
)
|
|
306
|
+
.mockReturnValueOnce(
|
|
307
|
+
Promise.resolve({
|
|
308
|
+
value: makeFlow({
|
|
309
|
+
id: "flow-2",
|
|
310
|
+
type: "action",
|
|
311
|
+
exp: "err(",
|
|
312
|
+
label: "Error",
|
|
313
|
+
}),
|
|
314
|
+
}),
|
|
315
|
+
)
|
|
316
|
+
.mockReturnValueOnce(
|
|
317
|
+
Promise.resolve({
|
|
318
|
+
value: makeFlow({
|
|
319
|
+
id: "flow-2",
|
|
320
|
+
type: "action",
|
|
321
|
+
exp: "err(",
|
|
322
|
+
label: "Error",
|
|
323
|
+
}),
|
|
324
|
+
}),
|
|
325
|
+
)
|
|
326
|
+
.mockReturnValue(Promise.resolve({ done: true })),
|
|
327
|
+
};
|
|
328
|
+
const onComplete = vitest.fn();
|
|
329
|
+
const onError = vitest.fn();
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
*
|
|
333
|
+
*/
|
|
334
|
+
const MyFallback = (props: FallbackProps) => (
|
|
335
|
+
<div>
|
|
336
|
+
<button type="button" onClick={props?.retry}>
|
|
337
|
+
Retry
|
|
338
|
+
</button>
|
|
339
|
+
<button type="button" onClick={props?.reset}>
|
|
340
|
+
Reset
|
|
341
|
+
</button>
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const screen = render(
|
|
346
|
+
<Suspense fallback="loading">
|
|
347
|
+
<ManagedPlayer
|
|
348
|
+
manager={manager}
|
|
349
|
+
plugins={[new SimpleAssetPlugin()]}
|
|
350
|
+
fallbackComponent={MyFallback}
|
|
351
|
+
onComplete={onComplete}
|
|
352
|
+
onError={onError}
|
|
353
|
+
/>
|
|
354
|
+
</Suspense>,
|
|
355
|
+
testOptions,
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
expect(manager.next).toBeCalledWith(undefined);
|
|
359
|
+
const view = await screen.findByTestId("flow-1");
|
|
360
|
+
expect(view).toBeInTheDocument();
|
|
361
|
+
|
|
362
|
+
await act(async () => {
|
|
363
|
+
const nextButton = await screen.findByText("Continue");
|
|
364
|
+
nextButton.click();
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
await waitFor(() => expect(manager.next).toBeCalledTimes(2));
|
|
368
|
+
|
|
369
|
+
const view2 = await screen.findByTestId("flow-2");
|
|
370
|
+
expect(view2).toBeInTheDocument();
|
|
371
|
+
|
|
372
|
+
await act(async () => {
|
|
373
|
+
view2.click();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const retryButton = await screen.findByText("Retry");
|
|
377
|
+
expect(retryButton).toBeInTheDocument();
|
|
378
|
+
|
|
379
|
+
await act(async () => {
|
|
380
|
+
retryButton.click();
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
expect(manager.next).toBeCalledTimes(3);
|
|
384
|
+
|
|
385
|
+
const view3 = await screen.findByTestId("flow-2");
|
|
386
|
+
expect(view3).toBeInTheDocument();
|
|
387
|
+
|
|
388
|
+
await act(async () => {
|
|
389
|
+
view3.click();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const resetButton = await screen.findByText("Retry");
|
|
393
|
+
expect(resetButton).toBeInTheDocument();
|
|
394
|
+
|
|
395
|
+
await act(async () => {
|
|
396
|
+
resetButton.click();
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
expect(manager.next).toBeCalledTimes(4);
|
|
400
|
+
expect(onError).toBeCalledTimes(2);
|
|
401
|
+
|
|
402
|
+
expect(onComplete).toBeCalled();
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
test("handles terminating with data", async () => {
|
|
406
|
+
vitest.useRealTimers();
|
|
407
|
+
const manager: FlowManager = {
|
|
408
|
+
next: vitest.fn().mockReturnValueOnce(
|
|
409
|
+
Promise.resolve({
|
|
410
|
+
value: {
|
|
411
|
+
...makeFlow({
|
|
412
|
+
id: "flow-1",
|
|
413
|
+
type: "collection",
|
|
414
|
+
values: [
|
|
415
|
+
{
|
|
416
|
+
asset: {
|
|
417
|
+
id: "action",
|
|
418
|
+
type: "action",
|
|
419
|
+
value: "Next",
|
|
420
|
+
label: "Continue",
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
],
|
|
424
|
+
}),
|
|
425
|
+
data: {
|
|
426
|
+
returns: { id: "123" },
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
}),
|
|
430
|
+
),
|
|
431
|
+
terminate: vitest.fn(),
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const onComplete = vitest.fn();
|
|
435
|
+
const onError = vitest.fn();
|
|
436
|
+
|
|
437
|
+
let renderResult;
|
|
438
|
+
act(() => {
|
|
439
|
+
renderResult = render(
|
|
440
|
+
<Suspense fallback="loading">
|
|
441
|
+
<ManagedPlayer
|
|
442
|
+
manager={manager}
|
|
443
|
+
plugins={[new SimpleAssetPlugin()]}
|
|
444
|
+
onComplete={onComplete}
|
|
445
|
+
onError={onError}
|
|
446
|
+
/>
|
|
447
|
+
</Suspense>,
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
await renderResult.findByTestId("flow-1");
|
|
452
|
+
(renderResult as any).unmount();
|
|
453
|
+
expect(manager.terminate).toBeCalledWith({ returns: { id: "123" } });
|
|
454
|
+
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React from "react";
|
|
2
2
|
import type {
|
|
3
3
|
FlowManager,
|
|
4
4
|
ManagedPlayerProps,
|
|
5
5
|
ManagedPlayerState,
|
|
6
6
|
ManagerMiddleware,
|
|
7
7
|
ManagedPlayerContext,
|
|
8
|
-
} from
|
|
9
|
-
import { useRequestTime } from
|
|
10
|
-
import type { ReactPlayerOptions } from
|
|
11
|
-
import { ReactPlayer } from
|
|
8
|
+
} from "./types";
|
|
9
|
+
import { useRequestTime } from "./request-time";
|
|
10
|
+
import type { ReactPlayerOptions } from "../player";
|
|
11
|
+
import { ReactPlayer } from "../player";
|
|
12
12
|
|
|
13
13
|
/** noop middleware */
|
|
14
14
|
function identityMiddleware<T>(next: Promise<T>) {
|
|
@@ -60,16 +60,11 @@ class ManagedState {
|
|
|
60
60
|
/** the config to use when creating a player */
|
|
61
61
|
playerConfig: ReactPlayerOptions;
|
|
62
62
|
}) {
|
|
63
|
-
const playerConfig: ReactPlayerOptions = {
|
|
64
|
-
...options.playerConfig,
|
|
65
|
-
suspend: true,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
63
|
const initialState: ManagedPlayerState = {
|
|
69
|
-
value:
|
|
64
|
+
value: "not_started",
|
|
70
65
|
context: {
|
|
71
|
-
playerConfig,
|
|
72
|
-
reactPlayer: new ReactPlayer(playerConfig),
|
|
66
|
+
playerConfig: options.playerConfig,
|
|
67
|
+
reactPlayer: new ReactPlayer(options.playerConfig),
|
|
73
68
|
manager: options.manager,
|
|
74
69
|
},
|
|
75
70
|
};
|
|
@@ -81,21 +76,21 @@ class ManagedState {
|
|
|
81
76
|
|
|
82
77
|
/** reset starts from nothing */
|
|
83
78
|
public reset() {
|
|
84
|
-
if (this.state?.value ===
|
|
79
|
+
if (this.state?.value === "error") {
|
|
85
80
|
const { playerConfig, manager } = this.state.context;
|
|
86
81
|
this.start({ playerConfig, manager });
|
|
87
82
|
} else {
|
|
88
|
-
throw new Error(
|
|
83
|
+
throw new Error("Flow must be in error state to reset");
|
|
89
84
|
}
|
|
90
85
|
}
|
|
91
86
|
|
|
92
87
|
/** restart starts from the last result */
|
|
93
88
|
public restart() {
|
|
94
|
-
if (this.state?.value ===
|
|
89
|
+
if (this.state?.value === "error") {
|
|
95
90
|
const { playerConfig, manager, prevResult, reactPlayer } =
|
|
96
91
|
this.state.context;
|
|
97
92
|
this.setState({
|
|
98
|
-
value:
|
|
93
|
+
value: "completed",
|
|
99
94
|
context: {
|
|
100
95
|
playerConfig,
|
|
101
96
|
manager,
|
|
@@ -104,7 +99,7 @@ class ManagedState {
|
|
|
104
99
|
},
|
|
105
100
|
});
|
|
106
101
|
} else {
|
|
107
|
-
throw new Error(
|
|
102
|
+
throw new Error("Flow must be in error state to restart");
|
|
108
103
|
}
|
|
109
104
|
}
|
|
110
105
|
|
|
@@ -128,7 +123,7 @@ class ManagedState {
|
|
|
128
123
|
}
|
|
129
124
|
} catch (e) {
|
|
130
125
|
this.setState({
|
|
131
|
-
value:
|
|
126
|
+
value: "error",
|
|
132
127
|
context: {
|
|
133
128
|
manager,
|
|
134
129
|
reactPlayer,
|
|
@@ -141,16 +136,16 @@ class ManagedState {
|
|
|
141
136
|
|
|
142
137
|
private async processState(
|
|
143
138
|
state: ManagedPlayerState,
|
|
144
|
-
context: ManagedPlayerContext
|
|
139
|
+
context: ManagedPlayerContext,
|
|
145
140
|
): Promise<ManagedPlayerState | undefined> {
|
|
146
|
-
if (state.value ===
|
|
141
|
+
if (state.value === "not_started" || state.value === "completed") {
|
|
147
142
|
const prevResult =
|
|
148
|
-
state.value ===
|
|
143
|
+
state.value === "completed" ? state.context.result : undefined;
|
|
149
144
|
|
|
150
145
|
const middleware = this.middleware?.next ?? identityMiddleware;
|
|
151
146
|
|
|
152
147
|
return {
|
|
153
|
-
value:
|
|
148
|
+
value: "pending",
|
|
154
149
|
context: {
|
|
155
150
|
...context,
|
|
156
151
|
prevResult,
|
|
@@ -159,12 +154,12 @@ class ManagedState {
|
|
|
159
154
|
};
|
|
160
155
|
}
|
|
161
156
|
|
|
162
|
-
if (state.value ===
|
|
157
|
+
if (state.value === "pending") {
|
|
163
158
|
const nextResult = await state.context.next;
|
|
164
159
|
|
|
165
160
|
if (nextResult.done) {
|
|
166
161
|
return {
|
|
167
|
-
value:
|
|
162
|
+
value: "ended",
|
|
168
163
|
context: {
|
|
169
164
|
...context,
|
|
170
165
|
result: state.context.prevResult,
|
|
@@ -173,7 +168,7 @@ class ManagedState {
|
|
|
173
168
|
}
|
|
174
169
|
|
|
175
170
|
return {
|
|
176
|
-
value:
|
|
171
|
+
value: "loaded",
|
|
177
172
|
context: {
|
|
178
173
|
...context,
|
|
179
174
|
prevResult: state.context.prevResult,
|
|
@@ -182,9 +177,9 @@ class ManagedState {
|
|
|
182
177
|
};
|
|
183
178
|
}
|
|
184
179
|
|
|
185
|
-
if (state.value ===
|
|
180
|
+
if (state.value === "loaded") {
|
|
186
181
|
return {
|
|
187
|
-
value:
|
|
182
|
+
value: "running",
|
|
188
183
|
context: {
|
|
189
184
|
...context,
|
|
190
185
|
flow: state.context.flow,
|
|
@@ -194,11 +189,11 @@ class ManagedState {
|
|
|
194
189
|
};
|
|
195
190
|
}
|
|
196
191
|
|
|
197
|
-
if (state.value ===
|
|
192
|
+
if (state.value === "running") {
|
|
198
193
|
const result = await state.context.result;
|
|
199
194
|
|
|
200
195
|
return {
|
|
201
|
-
value:
|
|
196
|
+
value: "completed",
|
|
202
197
|
context: {
|
|
203
198
|
...context,
|
|
204
199
|
result,
|
|
@@ -225,7 +220,7 @@ export const usePersistentStateMachine = (options: {
|
|
|
225
220
|
middleware?: ManagerMiddleware;
|
|
226
221
|
}) => {
|
|
227
222
|
const keyRef = React.useRef<ManagedPlayerStateKey>({
|
|
228
|
-
_key: Symbol(
|
|
223
|
+
_key: Symbol("managed-player"),
|
|
229
224
|
});
|
|
230
225
|
|
|
231
226
|
const managedState =
|
|
@@ -270,11 +265,11 @@ export const ManagedPlayer = (props: ManagedPlayerProps) => {
|
|
|
270
265
|
});
|
|
271
266
|
|
|
272
267
|
React.useEffect(() => {
|
|
273
|
-
if (state?.value ===
|
|
268
|
+
if (state?.value === "ended") {
|
|
274
269
|
props.onComplete?.(state?.context.result);
|
|
275
|
-
} else if (state?.value ===
|
|
270
|
+
} else if (state?.value === "error") {
|
|
276
271
|
props.onError?.(state?.context.error);
|
|
277
|
-
} else if (state?.value ===
|
|
272
|
+
} else if (state?.value === "running") {
|
|
278
273
|
props.onStartedFlow?.();
|
|
279
274
|
}
|
|
280
275
|
}, [state]);
|
|
@@ -283,13 +278,13 @@ export const ManagedPlayer = (props: ManagedPlayerProps) => {
|
|
|
283
278
|
return () => {
|
|
284
279
|
const playerState = state?.context.reactPlayer.player.getState();
|
|
285
280
|
|
|
286
|
-
if (state?.value ===
|
|
281
|
+
if (state?.value === "running" && playerState?.status === "in-progress") {
|
|
287
282
|
props.manager.terminate?.(playerState.controllers.data.serialize());
|
|
288
283
|
}
|
|
289
284
|
};
|
|
290
285
|
}, [props.manager, state?.context.reactPlayer.player, state?.value]);
|
|
291
286
|
|
|
292
|
-
if (state?.value ===
|
|
287
|
+
if (state?.value === "error") {
|
|
293
288
|
if (props.fallbackComponent) {
|
|
294
289
|
return (
|
|
295
290
|
<props.fallbackComponent
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useMemo } from
|
|
2
|
-
import type { Player } from
|
|
3
|
-
import type { MetricsCorePlugin } from
|
|
1
|
+
import { useCallback, useEffect, useRef, useMemo } from "react";
|
|
2
|
+
import type { Player } from "@player-ui/player";
|
|
3
|
+
import type { MetricsCorePlugin } from "@player-ui/metrics-plugin";
|
|
4
4
|
import {
|
|
5
5
|
MetricsCorePluginSymbol,
|
|
6
6
|
RequestTimeWebPlugin,
|
|
7
|
-
} from
|
|
8
|
-
import type { ReactPlayerPlugin } from
|
|
7
|
+
} from "@player-ui/metrics-plugin";
|
|
8
|
+
import type { ReactPlayerPlugin } from "../player";
|
|
9
9
|
|
|
10
10
|
type RequestTime = {
|
|
11
11
|
/** request start time */
|
|
@@ -34,7 +34,7 @@ export const useRequestTime = () => {
|
|
|
34
34
|
|
|
35
35
|
/** wrap a promise with tracking it's time in flight */
|
|
36
36
|
function withRequestTime<Type>(nextPromise: Promise<Type>): Promise<Type> {
|
|
37
|
-
const getTime = typeof performance ===
|
|
37
|
+
const getTime = typeof performance === "undefined" ? Date : performance;
|
|
38
38
|
requestTimeRef.current = { start: getTime.now() };
|
|
39
39
|
|
|
40
40
|
return nextPromise.finally(() => {
|
|
@@ -47,13 +47,13 @@ export const useRequestTime = () => {
|
|
|
47
47
|
|
|
48
48
|
const RequestTimeMetricsPlugin: ReactPlayerPlugin = useMemo(() => {
|
|
49
49
|
return {
|
|
50
|
-
name:
|
|
50
|
+
name: "RequestTimeMetricsPlugin",
|
|
51
51
|
apply(player: Player): void {
|
|
52
52
|
player.applyTo<MetricsCorePlugin>(
|
|
53
53
|
MetricsCorePluginSymbol,
|
|
54
54
|
(metricsCorePlugin) => {
|
|
55
55
|
new RequestTimeWebPlugin(getRequestTime).apply(metricsCorePlugin);
|
|
56
|
-
}
|
|
56
|
+
},
|
|
57
57
|
);
|
|
58
58
|
},
|
|
59
59
|
};
|