@effect-app/vue 2.52.3 → 2.52.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/experimental/commander.d.ts +120 -0
  3. package/dist/experimental/commander.d.ts.map +1 -0
  4. package/dist/experimental/commander.js +206 -0
  5. package/dist/experimental/confirm.d.ts +12 -0
  6. package/dist/experimental/confirm.d.ts.map +1 -0
  7. package/dist/experimental/confirm.js +14 -0
  8. package/dist/experimental/intl.d.ts +32 -0
  9. package/dist/experimental/intl.d.ts.map +1 -0
  10. package/dist/experimental/intl.js +4 -0
  11. package/dist/experimental/makeExperimental.d.ts +59 -26
  12. package/dist/experimental/makeExperimental.d.ts.map +1 -1
  13. package/dist/experimental/makeExperimental.js +8 -16
  14. package/dist/experimental/toast.d.ts +54 -0
  15. package/dist/experimental/toast.d.ts.map +1 -0
  16. package/dist/experimental/toast.js +4 -0
  17. package/dist/experimental/withToast.d.ts +17 -0
  18. package/dist/experimental/withToast.d.ts.map +1 -0
  19. package/dist/experimental/withToast.js +36 -0
  20. package/dist/makeClient.js +6 -6
  21. package/dist/makeIntl.d.ts +1 -1
  22. package/dist/makeIntl.d.ts.map +1 -1
  23. package/dist/makeIntl.js +9 -4
  24. package/package.json +19 -11
  25. package/src/experimental/commander.ts +567 -0
  26. package/src/experimental/confirm.ts +20 -0
  27. package/src/experimental/intl.ts +5 -0
  28. package/src/experimental/makeExperimental.ts +7 -25
  29. package/src/experimental/toast.ts +14 -0
  30. package/src/experimental/withToast.ts +58 -0
  31. package/src/makeClient.ts +5 -5
  32. package/src/makeIntl.ts +8 -3
  33. package/test/Mutation.test.ts +22 -41
  34. package/test/dist/stubs.d.ts +58 -21
  35. package/test/dist/stubs.d.ts.map +1 -1
  36. package/test/dist/stubs.js +28 -22
  37. package/test/stubs.ts +65 -61
  38. package/dist/experimental/useCommand.d.ts +0 -74
  39. package/dist/experimental/useCommand.d.ts.map +0 -1
  40. package/dist/experimental/useCommand.js +0 -198
  41. package/dist/experimental/useConfirm.d.ts +0 -7
  42. package/dist/experimental/useConfirm.d.ts.map +0 -1
  43. package/dist/experimental/useConfirm.js +0 -9
  44. package/dist/experimental/useWithToast.d.ts +0 -23
  45. package/dist/experimental/useWithToast.d.ts.map +0 -1
  46. package/dist/experimental/useWithToast.js +0 -31
  47. package/src/experimental/useCommand.ts +0 -563
  48. package/src/experimental/useConfirm.ts +0 -17
  49. package/src/experimental/useWithToast.ts +0 -65
@@ -1,563 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { asResult, type MakeIntlReturn, reportRuntimeError } from "@effect-app/vue"
3
- import { reportMessage } from "@effect-app/vue/errorReporter"
4
- import { type Result } from "@effect-atom/atom/Result"
5
- import { Cause, Context, Effect, type Exit, flow, Match, Option, Runtime, S } from "effect-app"
6
- import { SupportedErrors } from "effect-app/client"
7
- import { OperationFailure, OperationSuccess } from "effect-app/Operations"
8
- import { type RuntimeFiber } from "effect/Fiber"
9
- import { type YieldWrap } from "effect/Utils"
10
- import { computed, type ComputedRef } from "vue"
11
- import { type makeUseConfirm } from "./useConfirm.js"
12
- import { type makeUseWithToast } from "./useWithToast.js"
13
-
14
- export const DefaultIntl = {
15
- de: {
16
- "handle.confirmation": "{action} bestätigen?",
17
- "handle.waiting": "{action} wird ausgeführt...",
18
- "handle.success": "{action} erfolgreich",
19
- "handle.with_errors": "{action} fehlgeschlagen",
20
- "handle.with_warnings": "{action} erfolgreich, mit Warnungen",
21
- "handle.error_response":
22
- "Die Anfrage war nicht erfolgreich:\n{error}\nWir wurden benachrichtigt und werden das Problem in Kürze beheben.",
23
- "handle.response_error": "Die Antwort konnte nicht verarbeitet werden:\n{error}",
24
- "handle.request_error": "Die Anfrage konnte nicht gesendet werden:\n{error}",
25
- "handle.unexpected_error2": "{action} unerwarteter Fehler, probieren sie es in kurze nochmals."
26
- },
27
- en: {
28
- "handle.confirmation": "Confirm {action}?",
29
- "handle.waiting": "{action} executing...",
30
- "handle.success": "{action} Success",
31
- "handle.with_errors": "{action} Failed",
32
- "handle.with_warnings": "{action}, with warnings",
33
- "handle.error_response":
34
- "There was an error in processing the response:\n{error}\nWe have been notified and will fix the problem shortly.",
35
- "handle.request_error": "There was an error in the request:\n{error}",
36
- "handle.response_error": "The request was not successful:\n{error}",
37
- "handle.unexpected_error2": "{action} unexpected error, please try again shortly."
38
- }
39
- }
40
-
41
- export class CommandContext extends Context.Tag("CommandContext")<
42
- CommandContext,
43
- { action: string }
44
- >() {}
45
-
46
- export interface CommandProps<A, E> {
47
- action: string
48
- result: Result<A, E>
49
- waiting: boolean
50
- }
51
-
52
- export const makeUseCommand = <Locale extends string, RT>(
53
- // NOTE: underscores to not collide with auto exports in nuxt apps
54
- _useIntl: MakeIntlReturn<Locale>["useIntl"],
55
- _useConfirm: ReturnType<typeof makeUseConfirm>,
56
- _useWithToast: ReturnType<typeof makeUseWithToast>,
57
- runtime: Runtime.Runtime<RT>
58
- ) =>
59
- () => {
60
- const withToast = _useWithToast()
61
- const { intl } = _useIntl()
62
- const { confirmOrInterrupt } = _useConfirm()
63
-
64
- const runFork = Runtime.runFork(runtime)
65
-
66
- type CommandOut<Args extends Array<any>, A, E> = ComputedRef<
67
- ((...a: Args) => RuntimeFiber<Exit.Exit<A, E>, never>) & CommandProps<A, E>
68
- >
69
-
70
- type CommandOutHelper<Args extends Array<any>, Eff extends Effect.Effect<any, any, any>> = CommandOut<
71
- Args,
72
- Effect.Effect.Success<Eff>,
73
- Effect.Effect.Error<Eff>
74
- >
75
-
76
- type Gen = {
77
- <Eff extends YieldWrap<Effect.Effect<any, any, RT | CommandContext>>, AEff, Args extends Array<any>>(
78
- body: (...args: Args) => Generator<Eff, AEff, never>
79
- ): CommandOut<
80
- Args,
81
- AEff,
82
- [Eff] extends [never] ? never
83
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
84
- : never
85
- >
86
- <
87
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
88
- AEff,
89
- Args extends Array<any>,
90
- A extends Effect.Effect<any, any, RT | CommandContext>
91
- >(
92
- body: (...args: Args) => Generator<Eff, AEff, never>,
93
- a: (
94
- _: Effect.Effect<
95
- AEff,
96
- [Eff] extends [never] ? never
97
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
98
- : never,
99
- [Eff] extends [never] ? never
100
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
101
- : never
102
- > /* TODO ,
103
- ...args: NoInfer<Args> */
104
- ) => A
105
- ): CommandOutHelper<Args, A>
106
- <
107
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
108
- AEff,
109
- Args extends Array<any>,
110
- A,
111
- B extends Effect.Effect<any, any, RT | CommandContext>
112
- >(
113
- body: (...args: Args) => Generator<Eff, AEff, never>,
114
- a: (
115
- _: Effect.Effect<
116
- AEff,
117
- [Eff] extends [never] ? never
118
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
119
- : never,
120
- [Eff] extends [never] ? never
121
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
122
- : never
123
- > /* TODO ,
124
- ...args: NoInfer<Args> */
125
- ) => A,
126
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B
127
- ): CommandOutHelper<Args, B>
128
- <
129
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
130
- AEff,
131
- Args extends Array<any>,
132
- A,
133
- B,
134
- C extends Effect.Effect<any, any, RT | CommandContext>
135
- >(
136
- body: (...args: Args) => Generator<Eff, AEff, never>,
137
- a: (
138
- _: Effect.Effect<
139
- AEff,
140
- [Eff] extends [never] ? never
141
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
142
- : never,
143
- [Eff] extends [never] ? never
144
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
145
- : never
146
- > /* TODO ,
147
- ...args: NoInfer<Args> */
148
- ) => A,
149
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
150
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C
151
- ): CommandOutHelper<Args, C>
152
- <
153
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
154
- AEff,
155
- Args extends Array<any>,
156
- A,
157
- B,
158
- C,
159
- D extends Effect.Effect<any, any, RT | CommandContext>
160
- >(
161
- body: (...args: Args) => Generator<Eff, AEff, never>,
162
- a: (
163
- _: Effect.Effect<
164
- AEff,
165
- [Eff] extends [never] ? never
166
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
167
- : never,
168
- [Eff] extends [never] ? never
169
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
170
- : never
171
- > /* TODO ,
172
- ...args: NoInfer<Args> */
173
- ) => A,
174
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
175
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C,
176
- d: (_: C /* TODO , ...args: NoInfer<Args> */) => D
177
- ): CommandOutHelper<Args, D>
178
- <
179
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
180
- AEff,
181
- Args extends Array<any>,
182
- A,
183
- B,
184
- C,
185
- D,
186
- E extends Effect.Effect<any, any, RT | CommandContext>
187
- >(
188
- body: (...args: Args) => Generator<Eff, AEff, never>,
189
- a: (
190
- _: Effect.Effect<
191
- AEff,
192
- [Eff] extends [never] ? never
193
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
194
- : never,
195
- [Eff] extends [never] ? never
196
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
197
- : never
198
- > /* TODO ,
199
- ...args: NoInfer<Args> */
200
- ) => A,
201
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
202
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C,
203
- d: (_: C /* TODO , ...args: NoInfer<Args> */) => D,
204
- e: (_: D /* TODO , ...args: NoInfer<Args> */) => E
205
- ): CommandOutHelper<Args, E>
206
- <
207
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
208
- AEff,
209
- Args extends Array<any>,
210
- A,
211
- B,
212
- C,
213
- D,
214
- E,
215
- F extends Effect.Effect<any, any, RT | CommandContext>
216
- >(
217
- body: (...args: Args) => Generator<Eff, AEff, never>,
218
- a: (
219
- _: Effect.Effect<
220
- AEff,
221
- [Eff] extends [never] ? never
222
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
223
- : never,
224
- [Eff] extends [never] ? never
225
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
226
- : never
227
- > /* TODO ,
228
- ...args: NoInfer<Args> */
229
- ) => A,
230
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
231
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C,
232
- d: (_: C /* TODO , ...args: NoInfer<Args> */) => D,
233
- e: (_: D /* TODO , ...args: NoInfer<Args> */) => E,
234
- f: (_: E /* TODO , ...args: NoInfer<Args> */) => F
235
- ): CommandOutHelper<Args, F>
236
- <
237
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
238
- AEff,
239
- Args extends Array<any>,
240
- A,
241
- B,
242
- C,
243
- D,
244
- E,
245
- F,
246
- G extends Effect.Effect<any, any, RT | CommandContext>
247
- >(
248
- body: (...args: Args) => Generator<Eff, AEff, never>,
249
- a: (
250
- _: Effect.Effect<
251
- AEff,
252
- [Eff] extends [never] ? never
253
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
254
- : never,
255
- [Eff] extends [never] ? never
256
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
257
- : never
258
- > /* TODO ,
259
- ...args: NoInfer<Args> */
260
- ) => A,
261
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
262
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C,
263
- d: (_: C /* TODO , ...args: NoInfer<Args> */) => D,
264
- e: (_: D /* TODO , ...args: NoInfer<Args> */) => E,
265
- f: (_: E /* TODO , ...args: NoInfer<Args> */) => F,
266
- g: (_: F /* TODO , ...args: NoInfer<Args> */) => G
267
- ): CommandOutHelper<Args, G>
268
- <
269
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
270
- AEff,
271
- Args extends Array<any>,
272
- A,
273
- B,
274
- C,
275
- D,
276
- E,
277
- F,
278
- G,
279
- H extends Effect.Effect<any, any, RT | CommandContext>
280
- >(
281
- body: (...args: Args) => Generator<Eff, AEff, never>,
282
- a: (
283
- _: Effect.Effect<
284
- AEff,
285
- [Eff] extends [never] ? never
286
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
287
- : never,
288
- [Eff] extends [never] ? never
289
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
290
- : never
291
- > /* TODO ,
292
- ...args: NoInfer<Args> */
293
- ) => A,
294
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
295
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C,
296
- d: (_: C /* TODO , ...args: NoInfer<Args> */) => D,
297
- e: (_: D /* TODO , ...args: NoInfer<Args> */) => E,
298
- f: (_: E /* TODO , ...args: NoInfer<Args> */) => F,
299
- g: (_: F /* TODO , ...args: NoInfer<Args> */) => G,
300
- h: (_: G /* TODO , ...args: NoInfer<Args> */) => H
301
- ): CommandOutHelper<Args, H>
302
- <
303
- Eff extends YieldWrap<Effect.Effect<any, any, any>>,
304
- AEff,
305
- Args extends Array<any>,
306
- A,
307
- B,
308
- C,
309
- D,
310
- E,
311
- F,
312
- G,
313
- H,
314
- I extends Effect.Effect<any, any, RT | CommandContext>
315
- >(
316
- body: (...args: Args) => Generator<Eff, AEff, never>,
317
- a: (
318
- _: Effect.Effect<
319
- AEff,
320
- [Eff] extends [never] ? never
321
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer E, infer _R>>] ? E
322
- : never,
323
- [Eff] extends [never] ? never
324
- : [Eff] extends [YieldWrap<Effect.Effect<infer _A, infer _E, infer R>>] ? R
325
- : never
326
- > /* TODO ,
327
- ...args: NoInfer<Args> */
328
- ) => A,
329
- b: (_: A /* TODO , ...args: NoInfer<Args> */) => B,
330
- c: (_: B /* TODO , ...args: NoInfer<Args> */) => C,
331
- d: (_: C /* TODO , ...args: NoInfer<Args> */) => D,
332
- e: (_: D /* TODO , ...args: NoInfer<Args> */) => E,
333
- f: (_: E /* TODO , ...args: NoInfer<Args> */) => F,
334
- g: (_: F /* TODO , ...args: NoInfer<Args> */) => G,
335
- h: (_: G /* TODO , ...args: NoInfer<Args> */) => H,
336
- i: (_: H /* TODO , ...args: NoInfer<Args> */) => I
337
- ): CommandOutHelper<Args, I>
338
- }
339
-
340
- const makeCommand =
341
- (actionName: string, errorDef?: Error) =>
342
- <Args extends ReadonlyArray<any>, A, E, R extends RT | CommandContext>(
343
- handler: (...args: Args) => Effect.Effect<A, E, R>
344
- ) => {
345
- const limit = Error.stackTraceLimit
346
- Error.stackTraceLimit = 2
347
- const localErrorDef = new Error()
348
- Error.stackTraceLimit = limit
349
- if (!errorDef) {
350
- errorDef = localErrorDef
351
- }
352
- const action = intl.value.formatMessage({
353
- id: `action.${actionName}`,
354
- defaultMessage: actionName
355
- })
356
- const context = { action }
357
-
358
- const errorReporter = <A, E, R>(self: Effect.Effect<A, E, R>) =>
359
- self.pipe(
360
- Effect.tapErrorCause(
361
- Effect.fnUntraced(function*(cause) {
362
- if (Cause.isInterruptedOnly(cause)) {
363
- console.info(`Interrupted while trying to ${actionName}`)
364
- return
365
- }
366
-
367
- const fail = Cause.failureOption(cause)
368
- if (Option.isSome(fail)) {
369
- // if (fail.value._tag === "SuppressErrors") {
370
- // console.info(
371
- // `Suppressed error trying to ${action}`,
372
- // fail.value,
373
- // )
374
- // return
375
- // }
376
- const message = `Failure trying to ${actionName}`
377
- yield* reportMessage(message, {
378
- action: actionName,
379
- error: fail.value
380
- })
381
- return
382
- }
383
-
384
- const extra = {
385
- action,
386
- message: `Unexpected Error trying to ${actionName}`
387
- }
388
- yield* reportRuntimeError(cause, extra)
389
- })
390
- )
391
- )
392
-
393
- const theHandler = flow(
394
- handler,
395
- // all must be within the Effect.fn to fit within the Span
396
- Effect.provideService(CommandContext, context),
397
- (_) => Effect.annotateCurrentSpan({ action }).pipe(Effect.zipRight(_)),
398
- errorReporter
399
- )
400
-
401
- const [result, mut] = asResult(theHandler)
402
-
403
- return computed(() =>
404
- Object.assign(
405
- (...args: Args) => {
406
- const limit = Error.stackTraceLimit
407
- Error.stackTraceLimit = 2
408
- const errorCall = new Error()
409
- Error.stackTraceLimit = limit
410
-
411
- let cache: false | string = false
412
- const captureStackTrace = () => {
413
- if (cache !== false) {
414
- return cache
415
- }
416
- if (errorCall.stack) {
417
- const stackDef = errorDef!.stack!.trim().split("\n")
418
- const stackCall = errorCall.stack.trim().split("\n")
419
- let endStackDef = stackDef.slice(2).join("\n").trim()
420
- if (!endStackDef.includes(`(`)) {
421
- endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
422
- }
423
- let endStackCall = stackCall.slice(2).join("\n").trim()
424
- if (!endStackCall.includes(`(`)) {
425
- endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
426
- }
427
- cache = `${endStackDef}\n${endStackCall}`
428
- return cache
429
- }
430
- }
431
- return runFork(Effect.withSpan(mut(...args), actionName, { captureStackTrace }))
432
- }, /* make sure always create a new one, or the state won't properly propagate */
433
- {
434
- action,
435
- result: result.value,
436
- waiting: result.value.waiting
437
- } as CommandProps<A, E>
438
- )
439
- )
440
- }
441
-
442
- return {
443
- /** Version of confirmOrInterrupt that automatically includes the action name in the default messages */
444
- confirmOrInterrupt: Effect.fnUntraced(function*(
445
- message: string | undefined = undefined
446
- ) {
447
- const context = yield* CommandContext
448
- yield* confirmOrInterrupt(
449
- message
450
- ?? intl.value.formatMessage(
451
- { id: "handle.confirmation" },
452
- { action: context.action }
453
- )
454
- )
455
- }),
456
- /** Version of withDefaultToast that automatically includes the action name in the default messages and uses intl */
457
- withDefaultToast: <A, E>(errorRenderer?: (e: E) => string | undefined) =>
458
- (
459
- self: Effect.Effect<A, E, CommandContext>
460
- ) =>
461
- Effect.gen(function*() {
462
- const { action } = yield* CommandContext
463
-
464
- const defaultWarnMessage = intl.value.formatMessage(
465
- { id: "handle.with_warnings" },
466
- { action }
467
- )
468
- const defaultErrorMessage = intl.value.formatMessage(
469
- { id: "handle.with_errors" },
470
- { action }
471
- )
472
- function renderError(e: E): string {
473
- if (errorRenderer) {
474
- const m = errorRenderer(e)
475
- if (m) {
476
- return m
477
- }
478
- }
479
- if (!S.is(SupportedErrors)(e) && !S.ParseResult.isParseError(e)) {
480
- if (typeof e === "object" && e !== null) {
481
- if ("message" in e) {
482
- return `${e.message}`
483
- }
484
- if ("_tag" in e) {
485
- return `${e._tag}`
486
- }
487
- }
488
- return ""
489
- }
490
- const e2: SupportedErrors | S.ParseResult.ParseError = e
491
- return Match.value(e2).pipe(
492
- Match.tags({
493
- ParseError: (e) => {
494
- console.warn(e.toString())
495
- return intl.value.formatMessage({ id: "validation.failed" })
496
- }
497
- }),
498
- Match.orElse((e) => `${e.message ?? e._tag ?? e}`)
499
- )
500
- }
501
-
502
- return yield* self.pipe(
503
- withToast({
504
- onWaiting: intl.value.formatMessage(
505
- { id: "handle.waiting" },
506
- { action }
507
- ),
508
- onSuccess: (a) =>
509
- intl.value.formatMessage({ id: "handle.success" }, { action })
510
- + (S.is(OperationSuccess)(a) && a.message ? "\n" + a.message : ""),
511
- onFailure: Option.match({
512
- onNone: () =>
513
- intl.value.formatMessage(
514
- { id: "handle.unexpected_error2" },
515
- {
516
- action,
517
- error: "" // TODO consider again Cause.pretty(cause), // will be reported to Sentry/Otel anyway.. and we shouldn't bother users with error dumps?
518
- }
519
- ),
520
- onSome: (e) =>
521
- S.is(OperationFailure)(e)
522
- ? {
523
- level: "warn",
524
- message: defaultWarnMessage + e.message ? "\n" + e.message : ""
525
- }
526
- : `${defaultErrorMessage}:\n` + renderError(e)
527
- })
528
- })
529
- )
530
- }),
531
- /**
532
- * Define a Command
533
- * @param actionName The internal name of the action. will be used as Span. will be used to lookup user facing name via intl. `action.${actionName}`
534
- * @returns A function that can be called to execute the mutation, like directly in a `@click` handler. Error reporting is built-in.
535
- * the Effects **only** have access to the `CommandContext` service, which contains the user-facing action name.
536
- * The function also has the following properties:
537
- * - action: The user-facing name of the action, as defined in the intl messages. Can be used e.g as Button label.
538
- * - result: The Result of the mutation
539
- * - waiting: Whether the mutation is currently in progress. (shorthand for .result.waiting). Can be used e.g as Button loading/disabled state.
540
- * Reporting status to the user is recommended to use the `withDefaultToast` helper, or render the .result inline
541
- */
542
- fn: (actionName: string): Gen =>
543
- // TODO constrain/type combinators
544
- (
545
- fn: any,
546
- // TODO: combinators can freely take A, E, R and change it to whatever they want, as long as the end result Requires not more than CommandContext | R
547
- ...combinators: any[]
548
- ): any => {
549
- const limit = Error.stackTraceLimit
550
- Error.stackTraceLimit = 2
551
- const errorDef = new Error()
552
- Error.stackTraceLimit = limit
553
-
554
- return makeCommand(actionName, errorDef)(Effect.fnUntraced(fn, ...combinators as [any]) as any)
555
- },
556
-
557
- alt: makeCommand as (
558
- actionName: string
559
- ) => <Args extends ReadonlyArray<any>, A, E, R extends RT | CommandContext>(
560
- handler: (...args: Args) => Effect.Effect<A, E, R>
561
- ) => ComputedRef<((...a: Args) => RuntimeFiber<Exit.Exit<A, E>, never>) & CommandProps<A, E>>
562
- }
563
- }
@@ -1,17 +0,0 @@
1
- import { Effect } from "effect-app"
2
- import { type MakeIntlReturn } from "../makeIntl.js"
3
-
4
- export const makeUseConfirm = <Locale extends string>(_useIntl: MakeIntlReturn<Locale>["useIntl"]) => () => {
5
- const { intl } = _useIntl()
6
- const getDefaultMessage = () =>
7
- intl.value.formatMessage({ id: "confirm.default", defaultMessage: "Sind sie Sicher?" })
8
-
9
- const confirm = (message = getDefaultMessage()) => Effect.sync(() => window.confirm(message))
10
-
11
- const confirmOrInterrupt = (message = getDefaultMessage()) =>
12
- confirm(message).pipe(
13
- Effect.flatMap((result) => (result ? Effect.void : Effect.interrupt))
14
- )
15
-
16
- return { confirm, confirmOrInterrupt }
17
- }
@@ -1,65 +0,0 @@
1
- import { Cause, Effect, type Option } from "effect-app"
2
-
3
- export interface ToastOptions<A, E, Args extends ReadonlyArray<unknown>> {
4
- onWaiting: string | ((...args: Args) => string)
5
- onSuccess: string | ((a: A, ...args: Args) => string)
6
- onFailure:
7
- | string
8
- | ((
9
- error: Option.Option<E>,
10
- ...args: Args
11
- ) => string | { level: "warn" | "error"; message: string })
12
- }
13
-
14
- export type ToastId = string | number
15
- export type ToastOpts = { id?: ToastId; timeout?: number }
16
-
17
- export type UseToast = () => {
18
- error: (message: string, options?: ToastOpts) => ToastId
19
- warning: (message: string, options?: ToastOpts) => ToastId
20
- success: (message: string, options?: ToastOpts) => ToastId
21
- info: (message: string, options?: ToastOpts) => ToastId
22
- dismiss: (id: ToastId) => void
23
- }
24
-
25
- export const makeUseWithToast = (useToast: UseToast) => () => {
26
- const toast = useToast()
27
- return <A, E, Args extends ReadonlyArray<unknown>, R>(
28
- options: ToastOptions<A, E, Args>
29
- ) =>
30
- Effect.fnUntraced(function*(self: Effect.Effect<A, E, R>, ...args: Args) {
31
- const toastId = toast.info(
32
- // .loading
33
- typeof options.onWaiting === "string"
34
- ? options.onWaiting
35
- : options.onWaiting(...args)
36
- )
37
- return yield* self.pipe(
38
- Effect.tap((a) => {
39
- toast.success(
40
- typeof options.onSuccess === "string"
41
- ? options.onSuccess
42
- : options.onSuccess(a, ...args),
43
- { id: toastId, timeout: 3_000 }
44
- )
45
- }),
46
- Effect.tapErrorCause((cause) =>
47
- Effect.sync(() => {
48
- if (Cause.isInterruptedOnly(cause)) {
49
- toast.dismiss(toastId)
50
- return
51
- }
52
- const t = typeof options.onFailure === "string"
53
- ? options.onFailure
54
- : options.onFailure(Cause.failureOption(cause), ...args)
55
- if (typeof t === "object") {
56
- return t.level === "warn"
57
- ? toast.warning(t.message, { id: toastId, timeout: 5_000 })
58
- : toast.error(t.message, { id: toastId, timeout: 5_000 })
59
- }
60
- toast.error(t, { id: toastId, timeout: 5_000 })
61
- })
62
- )
63
- )
64
- })
65
- }