fix(fe2): default error skip logic & error policy (#2875)
This commit is contained in:
committed by
GitHub
parent
8f60384ec0
commit
04d0ee074f
@@ -50,7 +50,6 @@ import type { ProjectUpdateInput } from '~~/lib/common/generated/gql/graphql'
|
||||
import { useUpdateProject } from '~~/lib/projects/composables/projectManagement'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import { useTeamInternals } from '~/lib/projects/composables/team'
|
||||
import { skipLoggingErrorsIfOneFieldError } from '~/lib/common/helpers/graphql'
|
||||
|
||||
const projectPageSettingsGeneralQuery = graphql(`
|
||||
query ProjectPageSettingsGeneral($projectId: String!) {
|
||||
@@ -72,20 +71,9 @@ const updateProject = useUpdateProject()
|
||||
|
||||
const projectId = computed(() => route.params.id as string)
|
||||
|
||||
const { result: pageResult } = useQuery(
|
||||
projectPageSettingsGeneralQuery,
|
||||
() => ({
|
||||
projectId: projectId.value
|
||||
}),
|
||||
() => ({
|
||||
// Custom error policy so that a failing invitedTeam resolver (due to access rights)
|
||||
// doesn't kill the entire query
|
||||
errorPolicy: 'all',
|
||||
context: {
|
||||
skipLoggingErrors: skipLoggingErrorsIfOneFieldError('invitedTeam')
|
||||
}
|
||||
})
|
||||
)
|
||||
const { result: pageResult } = useQuery(projectPageSettingsGeneralQuery, () => ({
|
||||
projectId: projectId.value
|
||||
}))
|
||||
|
||||
const project = computed(() => pageResult.value?.project)
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsWorkspaceBillingQuery } from '~/lib/settings/graphql/queries'
|
||||
import { skipLoggingErrorsIfOneFieldError } from '~/lib/common/helpers/graphql'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesBilling_Workspace on Workspace {
|
||||
@@ -87,18 +86,9 @@ const props = defineProps<{
|
||||
workspaceId: string
|
||||
}>()
|
||||
|
||||
const { result } = useQuery(
|
||||
settingsWorkspaceBillingQuery,
|
||||
() => ({
|
||||
workspaceId: props.workspaceId
|
||||
}),
|
||||
() => ({
|
||||
errorPolicy: 'all',
|
||||
context: {
|
||||
skipLoggingErrors: skipLoggingErrorsIfOneFieldError('billing')
|
||||
}
|
||||
})
|
||||
)
|
||||
const { result } = useQuery(settingsWorkspaceBillingQuery, () => ({
|
||||
workspaceId: props.workspaceId
|
||||
}))
|
||||
|
||||
const billing = computed(() => result.value?.workspace.billing)
|
||||
const versionCount = computed(() => billing.value?.versionsCount)
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import { skipLoggingErrorsIfOneFieldError } from '~/lib/common/helpers/graphql'
|
||||
import { settingsWorkspacesMembersQuery } from '~/lib/settings/graphql/queries'
|
||||
import type { LayoutPageTabItem } from '~~/lib/layout/helpers/components'
|
||||
|
||||
@@ -48,18 +47,9 @@ const props = defineProps<{
|
||||
workspaceId: string
|
||||
}>()
|
||||
|
||||
const { result } = useQuery(
|
||||
settingsWorkspacesMembersQuery,
|
||||
() => ({
|
||||
workspaceId: props.workspaceId
|
||||
}),
|
||||
() => ({
|
||||
// Custom error policy so that a failing invitedTeam resolver (due to access rights)
|
||||
// doesn't kill the entire query
|
||||
errorPolicy: 'all',
|
||||
context: skipLoggingErrorsIfOneFieldError(['domains', 'invitedTeam'])
|
||||
})
|
||||
)
|
||||
const { result } = useQuery(settingsWorkspacesMembersQuery, () => ({
|
||||
workspaceId: props.workspaceId
|
||||
}))
|
||||
|
||||
const isAdmin = computed(() => result.value?.workspace?.role === Roles.Workspace.Admin)
|
||||
const tabItems = computed<LayoutPageTabItem[]>(() => [
|
||||
|
||||
@@ -70,7 +70,6 @@ import type {
|
||||
WorkspaceProjectList_ProjectCollectionFragment,
|
||||
WorkspaceProjectsQueryQueryVariables
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { skipLoggingErrorsIfOneFieldError } from '~/lib/common/helpers/graphql'
|
||||
import { workspaceRoute } from '~/lib/common/helpers/route'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
@@ -103,6 +102,9 @@ const {
|
||||
})
|
||||
|
||||
const token = computed(() => route.query.token as Optional<string>)
|
||||
|
||||
const pageFetchPolicy = usePageQueryStandardFetchPolicy()
|
||||
|
||||
const { result: initialQueryResult } = useQuery(
|
||||
workspacePageQuery,
|
||||
() => ({
|
||||
@@ -113,16 +115,7 @@ const { result: initialQueryResult } = useQuery(
|
||||
token: token.value || null
|
||||
}),
|
||||
() => ({
|
||||
// Custom error policy so that a failing invitedTeam resolver (due to access rights)
|
||||
// doesn't kill the entire query
|
||||
errorPolicy: 'all',
|
||||
context: {
|
||||
skipLoggingErrors: skipLoggingErrorsIfOneFieldError([
|
||||
'billing',
|
||||
'domains',
|
||||
'invitedTeam'
|
||||
])
|
||||
}
|
||||
fetchPolicy: pageFetchPolicy.value
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ import {
|
||||
incomingOverwritesExistingMergeFunction,
|
||||
mergeAsObjectsFunction
|
||||
} from '~~/lib/core/helpers/apolloSetup'
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
import { onError, type ErrorResponse } from '@apollo/client/link/error'
|
||||
import { useAppErrorState } from '~~/lib/core/composables/error'
|
||||
import { isInvalidAuth } from '~~/lib/common/helpers/graphql'
|
||||
import { isArray, isBoolean, omit } from 'lodash-es'
|
||||
import { intersection, isArray, isBoolean, omit } from 'lodash-es'
|
||||
import { useRequestId } from '~/lib/core/composables/server'
|
||||
|
||||
const appName = 'frontend-2'
|
||||
@@ -332,6 +332,21 @@ function createWsClient(params: {
|
||||
)
|
||||
}
|
||||
|
||||
const coreShouldSkipLoggingErrors = (err: ErrorResponse): boolean => {
|
||||
// These fields have special auth requirements and will often throw errors that we don't want to log
|
||||
const specialAuthFields = ['invitedTeam', 'billing', 'domains']
|
||||
const specialAuthFieldErrorCodes = ['FORBIDDEN', 'UNAUTHORIZED_ACCESS_ERROR']
|
||||
|
||||
return !!(
|
||||
err.graphQLErrors &&
|
||||
err.graphQLErrors.every(
|
||||
(e) =>
|
||||
intersection(e.path || [], specialAuthFields).length > 0 &&
|
||||
specialAuthFieldErrorCodes.includes(e.extensions?.code as string)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function createLink(params: {
|
||||
httpEndpoint: string
|
||||
wsClient?: SubscriptionClient
|
||||
@@ -349,10 +364,14 @@ function createLink(params: {
|
||||
'need a token to subscribe'
|
||||
)
|
||||
|
||||
const skipLoggingErrors = res.operation.getContext().skipLoggingErrors
|
||||
const shouldSkip = isBoolean(skipLoggingErrors)
|
||||
? skipLoggingErrors
|
||||
: skipLoggingErrors?.(res)
|
||||
let shouldSkip = coreShouldSkipLoggingErrors(res)
|
||||
const skipLoggingErrorsResolver = res.operation.getContext().skipLoggingErrors
|
||||
if (skipLoggingErrorsResolver) {
|
||||
shouldSkip = isBoolean(skipLoggingErrorsResolver)
|
||||
? skipLoggingErrorsResolver
|
||||
: skipLoggingErrorsResolver?.(res)
|
||||
}
|
||||
|
||||
if (!isSubTokenMissingError && !shouldSkip) {
|
||||
const gqlErrors: Array<GraphQLError> = isArray(res.graphQLErrors)
|
||||
? res.graphQLErrors
|
||||
@@ -484,7 +503,20 @@ const defaultConfigResolver: ApolloConfigResolver = () => {
|
||||
cache: markRaw(createCache()),
|
||||
link,
|
||||
name: appName,
|
||||
version: speckleServerVersion
|
||||
version: speckleServerVersion,
|
||||
defaultOptions: {
|
||||
// We want to retain all data even if there are errors, cause there's often fields with special auth requirements that we don't want
|
||||
// to be able to kill the entire query. Besides - in most cases partial data is better than no data at all.
|
||||
query: {
|
||||
errorPolicy: 'all'
|
||||
},
|
||||
mutate: {
|
||||
errorPolicy: 'all'
|
||||
},
|
||||
watchQuery: {
|
||||
errorPolicy: 'all'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,12 +121,6 @@ export function useCreateProject() {
|
||||
.mutate({
|
||||
mutation: createProjectMutation,
|
||||
variables: { input },
|
||||
errorPolicy: 'all',
|
||||
context: {
|
||||
skipLoggingErrors: (err) =>
|
||||
err.graphQLErrors?.length === 1 &&
|
||||
err.graphQLErrors.some((e) => e.path?.includes('invitedTeam'))
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
const newProject = data?.projectMutations.create
|
||||
|
||||
|
||||
@@ -102,15 +102,7 @@ const { result: projectPageResult } = useQuery(
|
||||
...(token.value?.length ? { token: token.value } : {})
|
||||
}),
|
||||
() => ({
|
||||
fetchPolicy: pageFetchPolicy.value,
|
||||
// Custom error policy so that a failing invitedTeam resolver (due to access rights)
|
||||
// doesn't kill the entire query
|
||||
errorPolicy: 'all'
|
||||
// context: {
|
||||
// skipLoggingErrors: (err) =>
|
||||
// err.graphQLErrors?.length === 1 &&
|
||||
// err.graphQLErrors.some((e) => !!e.path?.includes('invitedTeam'))
|
||||
// }
|
||||
fetchPolicy: pageFetchPolicy.value
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user