SubscriptionHandler.ts 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { watch } from 'vue'
  3. import type {
  4. OperationSubscriptionOptionsReturn,
  5. OperationSubscriptionsResult,
  6. WatchResultCallback,
  7. } from '#shared/types/server/apollo/handler.ts'
  8. import BaseHandler from './BaseHandler.ts'
  9. import type { FetchResult, OperationVariables } from '@apollo/client/core'
  10. import type { UseSubscriptionReturn } from '@vue/apollo-composable'
  11. import type { Ref, WatchStopHandle } from 'vue'
  12. export default class SubscriptionHandler<
  13. TResult = OperationSubscriptionsResult,
  14. TVariables extends OperationVariables = OperationVariables,
  15. > extends BaseHandler<
  16. TResult,
  17. TVariables,
  18. UseSubscriptionReturn<TResult, TVariables>
  19. > {
  20. public subscribed = false
  21. public options(): OperationSubscriptionOptionsReturn<TResult, TVariables> {
  22. return this.operationResult.options
  23. }
  24. public start(): void {
  25. this.operationResult.start()
  26. }
  27. public stop(): void {
  28. this.operationResult.stop()
  29. }
  30. public result(): Ref<Maybe<TResult> | undefined> {
  31. return this.operationResult.result
  32. }
  33. public onResult(
  34. callback: (
  35. result: FetchResult<
  36. TResult,
  37. Record<string, unknown>,
  38. Record<string, unknown>
  39. >,
  40. ) => void,
  41. ) {
  42. this.operationResult.onResult(callback)
  43. }
  44. public async onSubscribed(): Promise<Maybe<TResult> | undefined> {
  45. return new Promise((resolve, reject) => {
  46. let errorUnsubscribe!: () => void
  47. let resultUnsubscribe!: () => void
  48. const onFirstResultLoaded = () => {
  49. resultUnsubscribe()
  50. errorUnsubscribe()
  51. }
  52. resultUnsubscribe = watch(this.result(), (result) => {
  53. this.subscribed = true
  54. // Remove the watchers again after the promise was resolved.
  55. onFirstResultLoaded()
  56. return resolve(result || null)
  57. })
  58. errorUnsubscribe = watch(this.operationError(), (error) => {
  59. onFirstResultLoaded()
  60. return reject(error)
  61. })
  62. })
  63. }
  64. public watchOnResult(
  65. callback: WatchResultCallback<TResult>,
  66. ): WatchStopHandle {
  67. return watch(
  68. this.result(),
  69. (result) => {
  70. if (!result) {
  71. return
  72. }
  73. callback(result)
  74. },
  75. {
  76. // Needed for when the component is mounted after the first mount, in this case
  77. // result will already contain the data and the watch will otherwise not be triggered.
  78. immediate: true,
  79. },
  80. )
  81. }
  82. }