diff --git a/.betterer.results b/.betterer.results index 80c7d703..2ff4399f 100644 --- a/.betterer.results +++ b/.betterer.results @@ -108,12 +108,12 @@ exports[`No explicit any in client`] = { "client/src/webpages/dashboard/mrt/manual_review_job/v2/ManualReviewJobFieldsComponent.tsx:3836324260": [ [180, 37, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:855557376": [ + "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:646936726": [ [699, 32, 3, "Unexpected any. Specify a different type.", "193409811"], [745, 32, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "client/src/webpages/dashboard/overview/OverviewChart.tsx:3135116127": [ - [370, 32, 3, "Unexpected any. Specify a different type.", "193409811"] + "client/src/webpages/dashboard/overview/OverviewChart.tsx:3688972282": [ + [372, 32, 3, "Unexpected any. Specify a different type.", "193409811"] ], "client/src/webpages/dashboard/rules/dashboard/ReportingRulesDashboard.tsx:1325204439": [ [146, 30, 3, "Unexpected any. Specify a different type.", "193409811"] @@ -121,16 +121,16 @@ exports[`No explicit any in client`] = { "client/src/webpages/dashboard/rules/dashboard/RulesDashboard.tsx:329939153": [ [192, 30, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ - [311, 21, 3, "Unexpected any. Specify a different type.", "193409811"], - [340, 19, 3, "Unexpected any. Specify a different type.", "193409811"], - [399, 52, 3, "Unexpected any. Specify a different type.", "193409811"], - [412, 52, 3, "Unexpected any. Specify a different type.", "193409811"], - [424, 28, 3, "Unexpected any. Specify a different type.", "193409811"], - [441, 30, 3, "Unexpected any. Specify a different type.", "193409811"], - [663, 20, 3, "Unexpected any. Specify a different type.", "193409811"] + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ + [312, 21, 3, "Unexpected any. Specify a different type.", "193409811"], + [341, 19, 3, "Unexpected any. Specify a different type.", "193409811"], + [400, 52, 3, "Unexpected any. Specify a different type.", "193409811"], + [413, 52, 3, "Unexpected any. Specify a different type.", "193409811"], + [425, 28, 3, "Unexpected any. Specify a different type.", "193409811"], + [442, 30, 3, "Unexpected any. Specify a different type.", "193409811"], + [664, 20, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:2709633326": [ + "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:1979519000": [ [198, 32, 3, "Unexpected any. Specify a different type.", "193409811"], [244, 32, 3, "Unexpected any. Specify a different type.", "193409811"] ], @@ -143,14 +143,14 @@ exports[`No explicit any in client`] = { [442, 42, 3, "Unexpected any. Specify a different type.", "193409811"], [454, 32, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ - [74, 20, 3, "Unexpected any. Specify a different type.", "193409811"], - [75, 40, 3, "Unexpected any. Specify a different type.", "193409811"], - [122, 12, 3, "Unexpected any. Specify a different type.", "193409811"], - [122, 20, 3, "Unexpected any. Specify a different type.", "193409811"], - [125, 24, 3, "Unexpected any. Specify a different type.", "193409811"], - [132, 52, 3, "Unexpected any. Specify a different type.", "193409811"], - [145, 52, 3, "Unexpected any. Specify a different type.", "193409811"] + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ + [75, 20, 3, "Unexpected any. Specify a different type.", "193409811"], + [76, 40, 3, "Unexpected any. Specify a different type.", "193409811"], + [123, 12, 3, "Unexpected any. Specify a different type.", "193409811"], + [123, 20, 3, "Unexpected any. Specify a different type.", "193409811"], + [126, 24, 3, "Unexpected any. Specify a different type.", "193409811"], + [133, 52, 3, "Unexpected any. Specify a different type.", "193409811"], + [146, 52, 3, "Unexpected any. Specify a different type.", "193409811"] ], "client/src/webpages/dashboard/rules/info/insights/RuleInsightsSamplesTable.tsx:3800335297": [ [611, 25, 3, "Unexpected any. Specify a different type.", "193409811"], @@ -190,7 +190,7 @@ exports[`No explicit any in client`] = { exports[`No explicit any in server`] = { value: `{ - "server/api.ts:2797771380": [ + "server/api.ts:3876308530": [ [218, 36, 3, "Unexpected any. Specify a different type.", "193409811"], [240, 36, 3, "Unexpected any. Specify a different type.", "193409811"], [329, 32, 3, "Unexpected any. Specify a different type.", "193409811"] @@ -209,9 +209,9 @@ exports[`No explicit any in server`] = { "server/condition_evaluator/leafCondition.ts:2941598758": [ [212, 47, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "server/graphql/datasources/RuleApi.ts:1256100272": [ - [637, 31, 3, "Unexpected any. Specify a different type.", "193409811"], - [777, 28, 3, "Unexpected any. Specify a different type.", "193409811"] + "server/graphql/datasources/RuleApi.ts:3532264016": [ + [636, 31, 3, "Unexpected any. Specify a different type.", "193409811"], + [776, 28, 3, "Unexpected any. Specify a different type.", "193409811"] ], "server/graphql/datasources/UserApi.ts:3075210134": [ [52, 22, 3, "Unexpected any. Specify a different type.", "193409811"], @@ -237,8 +237,8 @@ exports[`No explicit any in server`] = { [299, 11, 3, "Unexpected any. Specify a different type.", "193409811"], [362, 13, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "server/graphql/resolvers.ts:460245623": [ - [101, 73, 3, "Unexpected any. Specify a different type.", "193409811"] + "server/graphql/resolvers.ts:3046460183": [ + [104, 12, 3, "Unexpected any. Specify a different type.", "193409811"] ], "server/lib/cache/utils/TimerSet.ts:767817500": [ [9, 31, 3, "Unexpected any. Specify a different type.", "193409811"], @@ -457,17 +457,17 @@ exports[`No counterproductive type annotations`] = { "client/src/webpages/dashboard/mrt/manual_review_job/v2/ManualReviewJobFieldsComponent.tsx:3836324260": [ [204, 33, 16, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "2813373547"] ], - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ - [663, 16, 7, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "2339939476"] + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ + [664, 16, 7, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "2339939476"] ], "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsSamplesTable.tsx:1919031301": [ [239, 15, 18, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "4144316489"] ], - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ - [75, 26, 17, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "1029763998"], - [122, 9, 6, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "1412855912"], - [122, 17, 6, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "1449682699"], - [125, 12, 15, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "2927082151"] + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ + [76, 26, 17, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "1029763998"], + [123, 9, 6, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "1412855912"], + [123, 17, 6, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "1449682699"], + [126, 12, 15, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "2927082151"] ], "client/src/webpages/dashboard/rules/info/insights/RuleInsightsSamplesTable.tsx:3800335297": [ [404, 15, 18, "When a function \`x\` is written inline and passed as an argument, it\'s usually better not to write explicit type annotations on \`x\`\'s arguments because the argument types should be able to be inferred, and the inferred type will usually be more accurate than what you\'d write manually. Plus, the inferred type will automatically update.\\n\\nIf the type for x\'s arguments is not being correctly inferred, that suggests an issue with the type definition of the function that \`x\` is being passed to.", "4144316489"] @@ -602,7 +602,7 @@ exports[`No new ant-design icon imports`] = { "client/src/webpages/dashboard/mrt/visualization/ManualReviewCustomCharts.tsx:1220234216": [ [0, 0, 49, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "3206710238"] ], - "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:855557376": [ + "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:646936726": [ [1, 0, 193, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "1459973405"] ], "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsFilterBy.tsx:1436988477": [ @@ -611,7 +611,7 @@ exports[`No new ant-design icon imports`] = { "client/src/webpages/dashboard/mrt/visualization/ManualReviewDefaultCharts.tsx:4210841634": [ [0, 0, 92, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "1150439677"] ], - "client/src/webpages/dashboard/mrt/visualization/TimeToActionChart.tsx:1046490420": [ + "client/src/webpages/dashboard/mrt/visualization/TimeToActionChart.tsx:3215425267": [ [0, 0, 112, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "1122443910"] ], "client/src/webpages/dashboard/ncmec/NcmecReportsDashboard.tsx:1586911903": [ @@ -623,8 +623,8 @@ exports[`No new ant-design icon imports`] = { "client/src/webpages/dashboard/rules/dashboard/RulesDashboard.tsx:329939153": [ [8, 0, 76, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "4151994019"] ], - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ - [5, 0, 113, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "3403673047"] + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ + [6, 0, 113, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "3403673047"] ], "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsActionsChart.tsx:3492200963": [ [2, 0, 72, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "87078707"] @@ -632,8 +632,8 @@ exports[`No new ant-design icon imports`] = { "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsSamplesTable.tsx:1919031301": [ [0, 0, 92, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "3155850297"] ], - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ - [3, 0, 72, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "87078707"] + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ + [4, 0, 72, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "87078707"] ], "client/src/webpages/dashboard/rules/info/insights/RuleInsightsSamplesPlayVideoButton.tsx:3799970987": [ [0, 0, 53, "\'@ant-design/icons\' import is restricted from being used. AntDesign icons are now deprecated in our codebase. Please use line icons instead.", "1828321615"] @@ -776,10 +776,10 @@ exports[`No new line-icon imports`] = { [0, 0, 71, "\'@/icons/lni/Direction/chevron-down.svg?react\' import is restricted from being used by a pattern.", "3704341756"], [1, 0, 67, "\'@/icons/lni/Direction/chevron-up.svg?react\' import is restricted from being used by a pattern.", "3710687196"] ], - "client/src/webpages/dashboard/overview/Overview.tsx:2096950063": [ - [10, 0, 123, "\'@/icons\' import is restricted from being used.", "3974909531"] + "client/src/webpages/dashboard/overview/Overview.tsx:380900289": [ + [14, 0, 123, "\'@/icons\' import is restricted from being used.", "3974909531"] ], - "client/src/webpages/dashboard/overview/OverviewCard.tsx:3946409475": [ + "client/src/webpages/dashboard/overview/OverviewCard.tsx:3308999316": [ [8, 0, 61, "\'@/icons\' import is restricted from being used.", "8406751"], [9, 0, 69, "\'@/icons/lni/Direction/arrow-right.svg?react\' import is restricted from being used by a pattern.", "2180497308"], [10, 0, 81, "\'@/icons/lni/Direction/arrows-horizontal.svg?react\' import is restricted from being used by a pattern.", "3736456476"] @@ -798,17 +798,17 @@ exports[`No new line-icon imports`] = { [0, 0, 71, "\'@/icons/lni/Direction/chevron-down.svg?react\' import is restricted from being used by a pattern.", "3704341756"], [1, 0, 67, "\'@/icons/lni/Direction/chevron-up.svg?react\' import is restricted from being used by a pattern.", "3710687196"] ], - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ [3, 0, 62, "\'@/icons\' import is restricted from being used.", "469112768"] ], - "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:2709633326": [ + "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:1979519000": [ [8, 0, 36, "\'@/icons\' import is restricted from being used.", "1234727599"], [9, 0, 73, "\'@/icons/lni/Web and Technology/download.svg?react\' import is restricted from being used by a pattern.", "3283715369"] ], "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsActionsChart.tsx:3492200963": [ [1, 0, 43, "\'@/icons\' import is restricted from being used.", "3049589739"] ], - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ [1, 0, 62, "\'@/icons\' import is restricted from being used.", "469112768"] ], "client/src/webpages/dashboard/rules/rule_form/ReportingRuleForm.tsx:2940997571": [ diff --git a/client/src/graphql/generated.ts b/client/src/graphql/generated.ts index af350bf7..d9b7e1b3 100644 --- a/client/src/graphql/generated.ts +++ b/client/src/graphql/generated.ts @@ -3147,7 +3147,7 @@ export type GQLQuery = { readonly action?: Maybe; readonly actionStatistics: ReadonlyArray; readonly allOrgs: ReadonlyArray; - readonly allRuleInsights: GQLAllRuleInsights; + readonly allRuleInsights?: Maybe; readonly apiKey: Scalars['String']; readonly appealSettings?: Maybe; readonly availableIntegrations: ReadonlyArray; @@ -3177,6 +3177,7 @@ export type GQLQuery = { readonly hashBanks: ReadonlyArray; readonly integrationConfig: GQLIntegrationConfigQueryResponse; readonly inviteUserToken: GQLInviteUserTokenResponse; + readonly isWarehouseAvailable: Scalars['Boolean']; readonly itemActionHistory: ReadonlyArray; readonly itemSubmissions: ReadonlyArray; readonly itemType?: Maybe; @@ -18225,6 +18226,15 @@ export type GQLGetNcmecReportQuery = { } | null; }; +export type GQLIsWarehouseAvailableQueryVariables = Exact<{ + [key: string]: never; +}>; + +export type GQLIsWarehouseAvailableQuery = { + readonly __typename: 'Query'; + readonly isWarehouseAvailable: boolean; +}; + export type GQLTotalPendingJobsQueryVariables = Exact<{ [key: string]: never }>; export type GQLTotalPendingJobsQuery = { @@ -19096,7 +19106,7 @@ export type GQLRulesDashboardInsightsQueryVariables = Exact<{ export type GQLRulesDashboardInsightsQuery = { readonly __typename: 'Query'; - readonly allRuleInsights: { + readonly allRuleInsights?: { readonly __typename: 'AllRuleInsights'; readonly actionedSubmissionsByPolicyByDay: ReadonlyArray<{ readonly __typename: 'CountByPolicyByDay'; @@ -19133,7 +19143,7 @@ export type GQLRulesDashboardInsightsQuery = { readonly date: Date | string; readonly count: number; }>; - }; + } | null; }; export type GQLPolicyRollupDataQueryVariables = Exact<{ [key: string]: never }>; @@ -19635,14 +19645,14 @@ export type GQLRulePassRateAnalyticsQuery = { }; } | null; - readonly allRuleInsights: { + readonly allRuleInsights?: { readonly __typename: 'AllRuleInsights'; readonly totalSubmissionsByDay: ReadonlyArray<{ readonly __typename: 'CountByDay'; readonly date: Date | string; readonly count: number; }>; - }; + } | null; }; export type GQLLeafConditionWithResultFieldsFragment = { @@ -33722,6 +33732,61 @@ export type GQLGetNcmecReportQueryResult = Apollo.QueryResult< GQLGetNcmecReportQuery, GQLGetNcmecReportQueryVariables >; +export const GQLIsWarehouseAvailableDocument = gql` + query IsWarehouseAvailable { + isWarehouseAvailable + } +`; + +/** + * __useGQLIsWarehouseAvailableQuery__ + * + * To run a query within a React component, call `useGQLIsWarehouseAvailableQuery` and pass it any options that fit your needs. + * When your component renders, `useGQLIsWarehouseAvailableQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGQLIsWarehouseAvailableQuery({ + * variables: { + * }, + * }); + */ +export function useGQLIsWarehouseAvailableQuery( + baseOptions?: Apollo.QueryHookOptions< + GQLIsWarehouseAvailableQuery, + GQLIsWarehouseAvailableQueryVariables + >, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery< + GQLIsWarehouseAvailableQuery, + GQLIsWarehouseAvailableQueryVariables + >(GQLIsWarehouseAvailableDocument, options); +} +export function useGQLIsWarehouseAvailableLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions< + GQLIsWarehouseAvailableQuery, + GQLIsWarehouseAvailableQueryVariables + >, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery< + GQLIsWarehouseAvailableQuery, + GQLIsWarehouseAvailableQueryVariables + >(GQLIsWarehouseAvailableDocument, options); +} +export type GQLIsWarehouseAvailableQueryHookResult = ReturnType< + typeof useGQLIsWarehouseAvailableQuery +>; +export type GQLIsWarehouseAvailableLazyQueryHookResult = ReturnType< + typeof useGQLIsWarehouseAvailableLazyQuery +>; +export type GQLIsWarehouseAvailableQueryResult = Apollo.QueryResult< + GQLIsWarehouseAvailableQuery, + GQLIsWarehouseAvailableQueryVariables +>; export const GQLTotalPendingJobsDocument = gql` query TotalPendingJobs { getTotalPendingJobsCount @@ -37893,6 +37958,7 @@ export const namedOperations = { AllNCMECReports: 'AllNCMECReports', Permissions: 'Permissions', GetNCMECReport: 'GetNCMECReport', + IsWarehouseAvailable: 'IsWarehouseAvailable', TotalPendingJobs: 'TotalPendingJobs', RuleNamesAndIds: 'RuleNamesAndIds', DataForOverviewCharts: 'DataForOverviewCharts', diff --git a/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsCard.tsx b/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsCard.tsx index 114235f2..630e2be2 100644 --- a/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsCard.tsx +++ b/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsCard.tsx @@ -156,7 +156,7 @@ const ManualReviewDashboardInsightsCard = ( ) : null} ) : ( -
Error finding value
+
No data available.
)}
{icon}
diff --git a/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx b/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx index 2a06febe..6d8d9350 100644 --- a/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx +++ b/client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx @@ -1073,8 +1073,8 @@ export default function ManualReviewDashboardInsightsChart(props: { const emptyChart = (
-
- We didn't find any results for this query. Try another one! +
+ No data available for the selected time period.
-
We didn't find any results for this query.
+
No data available for the selected time period.
getEmptyFilterState(timeWindow)} diff --git a/client/src/webpages/dashboard/overview/Overview.tsx b/client/src/webpages/dashboard/overview/Overview.tsx index c4d521da..2118a8ea 100644 --- a/client/src/webpages/dashboard/overview/Overview.tsx +++ b/client/src/webpages/dashboard/overview/Overview.tsx @@ -7,7 +7,11 @@ import { SelectTrigger, SelectValue, } from '@/coop-ui/Select'; -import { useGQLDashboardOrgQuery } from '@/graphql/generated'; +import { + useGQLDashboardOrgQuery, + useGQLIsWarehouseAvailableQuery, +} from '@/graphql/generated'; +import { TriangleAlert } from 'lucide-react'; import { FileExclamationFilled, FlowChartAltFilled, @@ -16,6 +20,7 @@ import { UsersFilled, } from '@/icons'; import { LookbackLength } from '@/utils/time'; +import { gql } from '@apollo/client'; import { makeEnumLike } from '@roostorg/types'; import { startOfHour, subDays } from 'date-fns'; import { useState } from 'react'; @@ -44,8 +49,18 @@ export function getDisplayNameForTimeDivision( } } +gql` + query IsWarehouseAvailable { + isWarehouseAvailable + } +`; + export default function Overview() { const { loading, error } = useGQLDashboardOrgQuery(); + const { data: warehouseData } = useGQLIsWarehouseAvailableQuery({ + fetchPolicy: 'cache-first', + pollInterval: 60_000, + }); const [timeDivision, setTimeDivision] = useState('DAY'); const [customTimeWindow, setCustomTimeWindow] = useState({ start: startOfHour(subDays(new Date(), 7)), @@ -197,6 +212,16 @@ export default function Overview() { ) : (
+ {warehouseData?.isWarehouseAvailable === false && ( +
+ + + The analytics database is currently unavailable. Some charts and + statistics may show incomplete data until the service is + restored. + +
+ )}
{cards}
it.count)) : undefined; - if ( - totalActionsError || - previousTotalActionsError || - jobsPendingError || - violationsPerPolicyError || - automatedVsManualError || - previousAutomatedVsManualError || - policiesError || - rulesError || - totalActionsByRuleError - ) { - throw ( - totalActionsError ?? - previousTotalActionsError ?? - jobsPendingError ?? - violationsPerPolicyError ?? - automatedVsManualError ?? - previousAutomatedVsManualError ?? - policiesError ?? - rulesError ?? - // eslint-disable-next-line - totalActionsByRuleError! - ); - } + const hasError = + totalActionsError ?? + previousTotalActionsError ?? + jobsPendingError ?? + violationsPerPolicyError ?? + automatedVsManualError ?? + previousAutomatedVsManualError ?? + policiesError ?? + rulesError ?? + totalActionsByRuleError; const loading = totalActionsLoading || @@ -534,7 +520,7 @@ export default function OverviewCard(props: { ); const errorComponent = ( -
Error finding value
+
No data available.
); const component = useMemo(() => { @@ -591,7 +577,11 @@ export default function OverviewCard(props: {
{title}
- {loading ? ( + {hasError ? ( +
+ Analytics data is temporarily unavailable. +
+ ) : loading ? (
diff --git a/client/src/webpages/dashboard/overview/OverviewChart.tsx b/client/src/webpages/dashboard/overview/OverviewChart.tsx index 52e5bd48..87986d7a 100644 --- a/client/src/webpages/dashboard/overview/OverviewChart.tsx +++ b/client/src/webpages/dashboard/overview/OverviewChart.tsx @@ -180,7 +180,9 @@ export default function OverviewChart(props: { const emptyChart = (
-
We didn't find any results for this query
+
+ No data available for the selected time period. +
); @@ -417,7 +419,21 @@ export default function OverviewChart(props: { )); if (error || decisionsError || actionStatsError) { - throw error ?? decisionsError ?? actionStatsError!; + return ( +
+
+
+ +
{title}
+
+
+
+
+ Analytics data is temporarily unavailable. +
+
+
+ ); } const loading = decisionsLoading || actionStatsLoading; diff --git a/client/src/webpages/dashboard/overview/OverviewTable.tsx b/client/src/webpages/dashboard/overview/OverviewTable.tsx index f3bfec6f..c13f9a7f 100644 --- a/client/src/webpages/dashboard/overview/OverviewTable.tsx +++ b/client/src/webpages/dashboard/overview/OverviewTable.tsx @@ -97,7 +97,7 @@ export default function OverviewTable(props: { const emptyChart = (
-
We didn't find any results for this query
+
No data available for the selected time period.
); diff --git a/client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx b/client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx index 886773bc..d9b5fa83 100644 --- a/client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx +++ b/client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx @@ -2,6 +2,7 @@ import './recharts.css'; import { DateRangePicker } from '@/coop-ui/DateRangePicker'; import { InvestmentFilled, PieChartAltFilled } from '@/icons'; +import { TriangleAlert } from 'lucide-react'; import { truncateAndFormatLargeNumber } from '@/utils/number'; import { BarChartOutlined, @@ -880,7 +881,13 @@ export default function RulesDashboardInsights() { ); if (error || policiesError) { - throw error ?? policiesError!; + return ( + } + title="Analytics Unavailable" + subtitle="We couldn't load the analytics data. The analytics service may be temporarily down. Other parts of Coop are unaffected." + /> + ); } return ( diff --git a/client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx b/client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx index b72cd89b..0891d896 100644 --- a/client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx +++ b/client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx @@ -419,8 +419,8 @@ export default function RuleDashboardInsightsChart(props: { const emptyChart = (
-
- We didn't find any results for this query. Try another one! +
+ No data available for the selected time period.
; + return ( +
+ } + title="Analytics Unavailable" + subtitle="We couldn't load the analytics data. The analytics service may be temporarily down. Other parts of Coop are unaffected." + /> +
+ ); } return ( diff --git a/server/api.ts b/server/api.ts index 27f5999e..359721dc 100644 --- a/server/api.ts +++ b/server/api.ts @@ -520,6 +520,7 @@ function makeGqlServices(deps: Dependencies) { return { ...safePick(deps, [ 'ApiKeyService', + 'DataWarehouse', 'DerivedFieldsService', 'getItemTypeEventuallyConsistent', 'getEnabledRulesForItemTypeEventuallyConsistent', @@ -535,6 +536,7 @@ function makeGqlServices(deps: Dependencies) { 'Sequelize', 'SignalsService', 'SigningKeyPairService', + 'Tracer', 'UserManagementService', 'UserStatisticsService', 'UserHistoryQueries', diff --git a/server/graphql/datasources/RuleApi.ts b/server/graphql/datasources/RuleApi.ts index 1d66c0e8..1a346449 100644 --- a/server/graphql/datasources/RuleApi.ts +++ b/server/graphql/datasources/RuleApi.ts @@ -574,13 +574,7 @@ class RuleAPI extends DataSource { } async getAllRuleInsights(orgId: string) { - const [ - actionedSubmissionsByDay, - actionedSubmissionsByPolicyByDay, - actionedSubmissionsByTagByDay, - actionedSubmissionsByActionByDay, - totalSubmissionsByDay, - ] = await Promise.all([ + const results = await Promise.allSettled([ this.actionStats.getActionedSubmissionCountsByDay(orgId), this.actionStats.getActionedSubmissionCountsByPolicyByDay(orgId), this.actionStats.getActionedSubmissionCountsByTagByDay(orgId), @@ -588,12 +582,17 @@ class RuleAPI extends DataSource { this.ruleInsights.getContentSubmissionCountsByDay(orgId), ]); + const valueOrEmpty = (r: PromiseSettledResult): readonly T[] => + r.status === 'fulfilled' ? r.value : []; + return { - actionedSubmissionsByDay, - actionedSubmissionsByPolicyByDay, - actionedSubmissionsByTagByDay, - actionedSubmissionsByActionByDay, - totalSubmissionsByDay, + actionedSubmissionsByDay: valueOrEmpty(results[0]), + actionedSubmissionsByPolicyByDay: valueOrEmpty(results[1]), + actionedSubmissionsByTagByDay: valueOrEmpty(results[2]), + actionedSubmissionsByActionByDay: valueOrEmpty(results[3]), + totalSubmissionsByDay: valueOrEmpty( + results[4] as PromiseSettledResult, + ), }; } diff --git a/server/graphql/generated.ts b/server/graphql/generated.ts index a204ead9..27af5245 100644 --- a/server/graphql/generated.ts +++ b/server/graphql/generated.ts @@ -3216,7 +3216,7 @@ export type GQLQuery = { readonly action?: Maybe; readonly actionStatistics: ReadonlyArray; readonly allOrgs: ReadonlyArray; - readonly allRuleInsights: GQLAllRuleInsights; + readonly allRuleInsights?: Maybe; readonly apiKey: Scalars['String']; readonly appealSettings?: Maybe; readonly availableIntegrations: ReadonlyArray; @@ -3246,6 +3246,7 @@ export type GQLQuery = { readonly hashBanks: ReadonlyArray; readonly integrationConfig: GQLIntegrationConfigQueryResponse; readonly inviteUserToken: GQLInviteUserTokenResponse; + readonly isWarehouseAvailable: Scalars['Boolean']; readonly itemActionHistory: ReadonlyArray; readonly itemSubmissions: ReadonlyArray; readonly itemType?: Maybe; @@ -11747,7 +11748,7 @@ export type GQLQueryResolvers< ContextType >; allRuleInsights?: Resolver< - GQLResolversTypes['AllRuleInsights'], + Maybe, ParentType, ContextType >; @@ -11914,6 +11915,11 @@ export type GQLQueryResolvers< ContextType, RequireFields >; + isWarehouseAvailable?: Resolver< + GQLResolversTypes['Boolean'], + ParentType, + ContextType + >; itemActionHistory?: Resolver< ReadonlyArray, ParentType, diff --git a/server/graphql/modules/actionStatistics.ts b/server/graphql/modules/actionStatistics.ts index a41f6f48..dbdd1ab3 100644 --- a/server/graphql/modules/actionStatistics.ts +++ b/server/graphql/modules/actionStatistics.ts @@ -101,16 +101,22 @@ const Query: GQLQueryResolvers = { } as const; const sources = input.filterBy.sources.map((it) => a[it]); - return context.dataSources.ruleAPI.getActionStatistics({ - ...input, - filterBy: { - ...input.filterBy, - sources, - startDate: new Date(input.filterBy.startDate), - endDate: new Date(input.filterBy.endDate), - }, - orgId: user.orgId, - }); + try { + return await context.dataSources.ruleAPI.getActionStatistics({ + ...input, + filterBy: { + ...input.filterBy, + sources, + startDate: new Date(input.filterBy.startDate), + endDate: new Date(input.filterBy.endDate), + }, + orgId: user.orgId, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.error('actionStatistics: warehouse query failed:', (e as Error).message); + return []; + } }, async topPolicyViolations(_, { input }, context) { @@ -119,19 +125,25 @@ const Query: GQLQueryResolvers = { throw new AuthenticationError('Authenticated user required'); } - const policyViolations = - await context.dataSources.ruleAPI.getPoliciesSortedByViolationCount({ - filterBy: { - startDate: new Date(input.filterBy.startDate), - endDate: new Date(input.filterBy.endDate), - }, - timeZone: input.timeZone, - orgId: user.orgId, - }); - return policyViolations.map((it) => ({ - count: it.count, - policyId: it.policy_id, - })); + try { + const policyViolations = + await context.dataSources.ruleAPI.getPoliciesSortedByViolationCount({ + filterBy: { + startDate: new Date(input.filterBy.startDate), + endDate: new Date(input.filterBy.endDate), + }, + timeZone: input.timeZone, + orgId: user.orgId, + }); + return policyViolations.map((it) => ({ + count: it.count, + policyId: it.policy_id, + })); + } catch (e) { + // eslint-disable-next-line no-console + console.error('topPolicyViolations: warehouse query failed:', (e as Error).message); + return []; + } }, async recentUserStrikeActions(_, { input }, context) { diff --git a/server/graphql/resolvers.ts b/server/graphql/resolvers.ts index aa568635..e906648e 100644 --- a/server/graphql/resolvers.ts +++ b/server/graphql/resolvers.ts @@ -98,8 +98,29 @@ const Query: GQLQueryResolvers = { return null; } - // TODO: this response type actually isn't right; remove cast and fix errors. - return context.dataSources.ruleAPI.getAllRuleInsights(user.orgId) as any; + try { + // TODO: this response type actually isn't right; remove cast and fix errors. + return (await context.dataSources.ruleAPI.getAllRuleInsights( + user.orgId, + )) as any; + } catch (e) { + // eslint-disable-next-line no-console + console.error('allRuleInsights: warehouse query failed:', (e as Error).message); + return null; + } + }, + async isWarehouseAvailable(_, __, context) { + try { + await context.services.DataWarehouse.query( + 'SELECT 1', + context.services.Tracer, + ); + return true; + } catch (e) { + // eslint-disable-next-line no-console + console.error('isWarehouseAvailable: warehouse health check failed:', (e as Error).message); + return false; + } }, }; diff --git a/server/graphql/schema.ts b/server/graphql/schema.ts index d17c3235..7834c395 100644 --- a/server/graphql/schema.ts +++ b/server/graphql/schema.ts @@ -473,7 +473,8 @@ const typeDefs = /* GraphQL */ ` myOrg: Org userFromToken(token: String!): ID inviteUserToken(token: String!): InviteUserTokenResponse! @publicResolver - allRuleInsights: AllRuleInsights! + allRuleInsights: AllRuleInsights + isWarehouseAvailable: Boolean! } type Mutation {