2026-01-02 13:41:09 +00:00
|
|
|
// Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
2021-11-10 12:49:41 +00:00
|
|
|
|
2024-05-17 13:31:19 +00:00
|
|
|
import {
|
|
|
|
|
useNotifications,
|
|
|
|
|
NotificationTypes,
|
|
|
|
|
} from '#shared/components/CommonNotifications/index.ts'
|
2024-08-12 08:59:35 +00:00
|
|
|
import type { GraphQLHandlerError } from '#shared/types/error.ts'
|
2024-05-17 13:31:19 +00:00
|
|
|
import { GraphQLErrorTypes } from '#shared/types/error.ts'
|
2022-07-20 14:41:44 +00:00
|
|
|
import type {
|
2021-11-09 11:28:00 +00:00
|
|
|
BaseHandlerOptions,
|
|
|
|
|
CommonHandlerOptions,
|
|
|
|
|
CommonHandlerOptionsParameter,
|
|
|
|
|
OperationResult,
|
|
|
|
|
OperationReturn,
|
2023-04-24 12:50:55 +00:00
|
|
|
} from '#shared/types/server/apollo/handler.ts'
|
2024-04-18 08:49:56 +00:00
|
|
|
import getUuid from '#shared/utils/getUuid.ts'
|
2021-11-09 11:28:00 +00:00
|
|
|
|
2024-05-17 13:31:19 +00:00
|
|
|
import type { ApolloError, OperationVariables } from '@apollo/client/core'
|
2024-08-12 08:59:35 +00:00
|
|
|
import type { GraphQLFormattedError } from 'graphql'
|
2024-05-17 13:31:19 +00:00
|
|
|
import type { Ref } from 'vue'
|
|
|
|
|
|
2025-06-11 17:45:28 +00:00
|
|
|
export abstract class BaseHandler<
|
2021-11-09 11:28:00 +00:00
|
|
|
TResult = OperationResult,
|
2023-05-31 07:54:09 +00:00
|
|
|
TVariables extends OperationVariables = OperationVariables,
|
2025-06-11 17:45:28 +00:00
|
|
|
TOperationReturn extends OperationReturn<TResult, TVariables> = OperationReturn<
|
2021-11-09 11:28:00 +00:00
|
|
|
TResult,
|
|
|
|
|
TVariables
|
2025-06-11 17:45:28 +00:00
|
|
|
>,
|
2021-11-09 11:28:00 +00:00
|
|
|
THandlerOptions = BaseHandlerOptions,
|
|
|
|
|
> {
|
|
|
|
|
public operationResult!: TOperationReturn
|
|
|
|
|
|
|
|
|
|
protected baseHandlerOptions: BaseHandlerOptions = {
|
|
|
|
|
errorShowNotification: true,
|
2023-11-08 09:38:22 +00:00
|
|
|
errorNotificationMessage: '',
|
2022-05-31 09:56:31 +00:00
|
|
|
errorNotificationType: NotificationTypes.Error,
|
2021-11-09 11:28:00 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-15 22:41:22 +00:00
|
|
|
public handlerOptions!: CommonHandlerOptions<THandlerOptions>
|
2021-11-09 11:28:00 +00:00
|
|
|
|
2024-08-16 10:30:32 +00:00
|
|
|
protected handlerId: string
|
2024-04-18 08:49:56 +00:00
|
|
|
|
2021-11-09 11:28:00 +00:00
|
|
|
constructor(
|
2021-11-15 22:41:22 +00:00
|
|
|
operationResult: TOperationReturn,
|
2021-11-09 11:28:00 +00:00
|
|
|
handlerOptions?: CommonHandlerOptionsParameter<THandlerOptions>,
|
|
|
|
|
) {
|
2021-11-15 22:41:22 +00:00
|
|
|
this.operationResult = operationResult
|
2021-11-09 11:28:00 +00:00
|
|
|
|
|
|
|
|
this.handlerOptions = this.mergedHandlerOptions(handlerOptions)
|
|
|
|
|
|
2024-04-18 08:49:56 +00:00
|
|
|
this.handlerId = getUuid()
|
|
|
|
|
|
2021-11-15 22:41:22 +00:00
|
|
|
this.initialize()
|
2021-11-09 11:28:00 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-15 22:41:22 +00:00
|
|
|
protected initialize(): void {
|
2021-11-09 11:28:00 +00:00
|
|
|
this.operationResult.onError((error) => {
|
|
|
|
|
this.handleError(error)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public loading(): Ref<boolean> {
|
|
|
|
|
return this.operationResult.loading
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public operationError(): Ref<Maybe<ApolloError>> {
|
|
|
|
|
return this.operationResult.error
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-28 10:01:02 +00:00
|
|
|
public onError(callback: (error: ApolloError) => void): void {
|
|
|
|
|
this.operationResult.onError(callback)
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-09 11:28:00 +00:00
|
|
|
protected handleError(error: ApolloError): void {
|
|
|
|
|
const options = this.handlerOptions
|
|
|
|
|
|
2022-12-13 14:16:23 +00:00
|
|
|
let triggerNotification = options.errorShowNotification
|
|
|
|
|
|
|
|
|
|
const { graphQLErrors, networkError } = error
|
|
|
|
|
let errorHandler: GraphQLHandlerError
|
|
|
|
|
|
|
|
|
|
if (graphQLErrors.length > 0) {
|
2024-08-12 08:59:35 +00:00
|
|
|
const { message, extensions }: GraphQLFormattedError = graphQLErrors[0]
|
2025-06-11 17:45:28 +00:00
|
|
|
let type = (extensions?.type as GraphQLErrorTypes) || GraphQLErrorTypes.UnknownError
|
2024-02-09 18:06:53 +00:00
|
|
|
|
|
|
|
|
// When it's not a known type, use the unknown error type.
|
|
|
|
|
if (!Object.values(GraphQLErrorTypes).includes(type)) {
|
|
|
|
|
type = GraphQLErrorTypes.UnknownError
|
|
|
|
|
}
|
2022-12-13 14:16:23 +00:00
|
|
|
|
|
|
|
|
errorHandler = {
|
2023-02-21 15:45:01 +00:00
|
|
|
type,
|
2022-12-13 14:16:23 +00:00
|
|
|
message,
|
|
|
|
|
}
|
|
|
|
|
} else if (networkError) {
|
|
|
|
|
errorHandler = {
|
|
|
|
|
type: GraphQLErrorTypes.NetworkError,
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errorHandler = {
|
2023-02-20 09:55:34 +00:00
|
|
|
type: GraphQLErrorTypes.UnknownError,
|
2022-12-13 14:16:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-21 15:45:01 +00:00
|
|
|
if (errorHandler.type === GraphQLErrorTypes.NotAuthorized) {
|
|
|
|
|
triggerNotification = false
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-13 14:16:23 +00:00
|
|
|
if (options.errorCallback) {
|
2023-02-21 15:45:01 +00:00
|
|
|
const trigger = options.errorCallback(errorHandler)
|
|
|
|
|
|
|
|
|
|
if (typeof trigger === 'boolean') {
|
|
|
|
|
triggerNotification = trigger
|
|
|
|
|
}
|
2022-12-13 14:16:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (triggerNotification) {
|
2022-11-30 09:00:58 +00:00
|
|
|
// TODO enable and fix all tests
|
|
|
|
|
// if (import.meta.env.DEV) {
|
|
|
|
|
// console.error(error)
|
|
|
|
|
// }
|
2022-03-16 11:45:07 +00:00
|
|
|
useNotifications().notify({
|
2025-10-02 14:06:32 +00:00
|
|
|
id: this.handlerId, // TODO maybe for network error we should have the same id for all?
|
2025-06-11 17:45:28 +00:00
|
|
|
message: this.errorNotificationMessage(errorHandler.type, errorHandler.message),
|
2022-03-16 11:45:07 +00:00
|
|
|
type: options.errorNotificationType,
|
2021-11-09 11:28:00 +00:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected mergedHandlerOptions(
|
|
|
|
|
handlerOptions?: CommonHandlerOptionsParameter<THandlerOptions>,
|
|
|
|
|
): CommonHandlerOptions<THandlerOptions> {
|
|
|
|
|
// The merged type is always safe as a 'CommonHandlerOptions<THandlerOptions>' type.
|
|
|
|
|
return Object.assign(
|
|
|
|
|
this.baseHandlerOptions,
|
|
|
|
|
handlerOptions,
|
|
|
|
|
) as CommonHandlerOptions<THandlerOptions>
|
|
|
|
|
}
|
2023-11-08 09:38:22 +00:00
|
|
|
|
2025-06-11 17:45:28 +00:00
|
|
|
private errorNotificationMessage(errorType: GraphQLErrorTypes, errorMessage?: string): string {
|
2026-01-12 13:03:17 +00:00
|
|
|
const defaultErrorNotificationMessage = __('An error occurred during the operation.')
|
2023-11-08 09:38:22 +00:00
|
|
|
|
2024-02-09 18:06:53 +00:00
|
|
|
const fallbackErrorMessage =
|
|
|
|
|
errorType === GraphQLErrorTypes.UnknownError || !errorMessage
|
|
|
|
|
? defaultErrorNotificationMessage
|
|
|
|
|
: errorMessage
|
|
|
|
|
|
|
|
|
|
return this.handlerOptions.errorNotificationMessage || fallbackErrorMessage
|
2023-11-08 09:38:22 +00:00
|
|
|
}
|
2021-11-09 11:28:00 +00:00
|
|
|
}
|