Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix ClickHouse outage crashing all dashboard pages (#151)

* Fix ClickHouse outage crashing all dashboard pages

* fix betterer

* add logging on warehouse error to let back-end know. given empty returns are to prevent front-end issues

authored by

Juan Mrad and committed by
GitHub
0d285da8 027ba66e

+282 -128
+45 -45
.betterer.results
··· 108 108 "client/src/webpages/dashboard/mrt/manual_review_job/v2/ManualReviewJobFieldsComponent.tsx:3836324260": [ 109 109 [180, 37, 3, "Unexpected any. Specify a different type.", "193409811"] 110 110 ], 111 - "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:855557376": [ 111 + "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:646936726": [ 112 112 [699, 32, 3, "Unexpected any. Specify a different type.", "193409811"], 113 113 [745, 32, 3, "Unexpected any. Specify a different type.", "193409811"] 114 114 ], 115 - "client/src/webpages/dashboard/overview/OverviewChart.tsx:3135116127": [ 116 - [370, 32, 3, "Unexpected any. Specify a different type.", "193409811"] 115 + "client/src/webpages/dashboard/overview/OverviewChart.tsx:3688972282": [ 116 + [372, 32, 3, "Unexpected any. Specify a different type.", "193409811"] 117 117 ], 118 118 "client/src/webpages/dashboard/rules/dashboard/ReportingRulesDashboard.tsx:1325204439": [ 119 119 [146, 30, 3, "Unexpected any. Specify a different type.", "193409811"] ··· 121 121 "client/src/webpages/dashboard/rules/dashboard/RulesDashboard.tsx:329939153": [ 122 122 [192, 30, 3, "Unexpected any. Specify a different type.", "193409811"] 123 123 ], 124 - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ 125 - [311, 21, 3, "Unexpected any. Specify a different type.", "193409811"], 126 - [340, 19, 3, "Unexpected any. Specify a different type.", "193409811"], 127 - [399, 52, 3, "Unexpected any. Specify a different type.", "193409811"], 128 - [412, 52, 3, "Unexpected any. Specify a different type.", "193409811"], 129 - [424, 28, 3, "Unexpected any. Specify a different type.", "193409811"], 130 - [441, 30, 3, "Unexpected any. Specify a different type.", "193409811"], 131 - [663, 20, 3, "Unexpected any. Specify a different type.", "193409811"] 124 + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ 125 + [312, 21, 3, "Unexpected any. Specify a different type.", "193409811"], 126 + [341, 19, 3, "Unexpected any. Specify a different type.", "193409811"], 127 + [400, 52, 3, "Unexpected any. Specify a different type.", "193409811"], 128 + [413, 52, 3, "Unexpected any. Specify a different type.", "193409811"], 129 + [425, 28, 3, "Unexpected any. Specify a different type.", "193409811"], 130 + [442, 30, 3, "Unexpected any. Specify a different type.", "193409811"], 131 + [664, 20, 3, "Unexpected any. Specify a different type.", "193409811"] 132 132 ], 133 - "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:2709633326": [ 133 + "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:1979519000": [ 134 134 [198, 32, 3, "Unexpected any. Specify a different type.", "193409811"], 135 135 [244, 32, 3, "Unexpected any. Specify a different type.", "193409811"] 136 136 ], ··· 143 143 [442, 42, 3, "Unexpected any. Specify a different type.", "193409811"], 144 144 [454, 32, 3, "Unexpected any. Specify a different type.", "193409811"] 145 145 ], 146 - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ 147 - [74, 20, 3, "Unexpected any. Specify a different type.", "193409811"], 148 - [75, 40, 3, "Unexpected any. Specify a different type.", "193409811"], 149 - [122, 12, 3, "Unexpected any. Specify a different type.", "193409811"], 150 - [122, 20, 3, "Unexpected any. Specify a different type.", "193409811"], 151 - [125, 24, 3, "Unexpected any. Specify a different type.", "193409811"], 152 - [132, 52, 3, "Unexpected any. Specify a different type.", "193409811"], 153 - [145, 52, 3, "Unexpected any. Specify a different type.", "193409811"] 146 + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ 147 + [75, 20, 3, "Unexpected any. Specify a different type.", "193409811"], 148 + [76, 40, 3, "Unexpected any. Specify a different type.", "193409811"], 149 + [123, 12, 3, "Unexpected any. Specify a different type.", "193409811"], 150 + [123, 20, 3, "Unexpected any. Specify a different type.", "193409811"], 151 + [126, 24, 3, "Unexpected any. Specify a different type.", "193409811"], 152 + [133, 52, 3, "Unexpected any. Specify a different type.", "193409811"], 153 + [146, 52, 3, "Unexpected any. Specify a different type.", "193409811"] 154 154 ], 155 155 "client/src/webpages/dashboard/rules/info/insights/RuleInsightsSamplesTable.tsx:3800335297": [ 156 156 [611, 25, 3, "Unexpected any. Specify a different type.", "193409811"], ··· 190 190 191 191 exports[`No explicit any in server`] = { 192 192 value: `{ 193 - "server/api.ts:2797771380": [ 193 + "server/api.ts:3876308530": [ 194 194 [218, 36, 3, "Unexpected any. Specify a different type.", "193409811"], 195 195 [240, 36, 3, "Unexpected any. Specify a different type.", "193409811"], 196 196 [329, 32, 3, "Unexpected any. Specify a different type.", "193409811"] ··· 209 209 "server/condition_evaluator/leafCondition.ts:2941598758": [ 210 210 [212, 47, 3, "Unexpected any. Specify a different type.", "193409811"] 211 211 ], 212 - "server/graphql/datasources/RuleApi.ts:1256100272": [ 213 - [637, 31, 3, "Unexpected any. Specify a different type.", "193409811"], 214 - [777, 28, 3, "Unexpected any. Specify a different type.", "193409811"] 212 + "server/graphql/datasources/RuleApi.ts:3532264016": [ 213 + [636, 31, 3, "Unexpected any. Specify a different type.", "193409811"], 214 + [776, 28, 3, "Unexpected any. Specify a different type.", "193409811"] 215 215 ], 216 216 "server/graphql/datasources/UserApi.ts:3075210134": [ 217 217 [52, 22, 3, "Unexpected any. Specify a different type.", "193409811"], ··· 237 237 [299, 11, 3, "Unexpected any. Specify a different type.", "193409811"], 238 238 [362, 13, 3, "Unexpected any. Specify a different type.", "193409811"] 239 239 ], 240 - "server/graphql/resolvers.ts:460245623": [ 241 - [101, 73, 3, "Unexpected any. Specify a different type.", "193409811"] 240 + "server/graphql/resolvers.ts:3046460183": [ 241 + [104, 12, 3, "Unexpected any. Specify a different type.", "193409811"] 242 242 ], 243 243 "server/lib/cache/utils/TimerSet.ts:767817500": [ 244 244 [9, 31, 3, "Unexpected any. Specify a different type.", "193409811"], ··· 457 457 "client/src/webpages/dashboard/mrt/manual_review_job/v2/ManualReviewJobFieldsComponent.tsx:3836324260": [ 458 458 [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"] 459 459 ], 460 - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ 461 - [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"] 460 + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ 461 + [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"] 462 462 ], 463 463 "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsSamplesTable.tsx:1919031301": [ 464 464 [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"] 465 465 ], 466 - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ 467 - [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"], 468 - [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"], 469 - [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"], 470 - [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"] 466 + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ 467 + [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"], 468 + [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"], 469 + [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"], 470 + [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"] 471 471 ], 472 472 "client/src/webpages/dashboard/rules/info/insights/RuleInsightsSamplesTable.tsx:3800335297": [ 473 473 [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 602 "client/src/webpages/dashboard/mrt/visualization/ManualReviewCustomCharts.tsx:1220234216": [ 603 603 [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"] 604 604 ], 605 - "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:855557376": [ 605 + "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx:646936726": [ 606 606 [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"] 607 607 ], 608 608 "client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsFilterBy.tsx:1436988477": [ ··· 611 611 "client/src/webpages/dashboard/mrt/visualization/ManualReviewDefaultCharts.tsx:4210841634": [ 612 612 [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"] 613 613 ], 614 - "client/src/webpages/dashboard/mrt/visualization/TimeToActionChart.tsx:1046490420": [ 614 + "client/src/webpages/dashboard/mrt/visualization/TimeToActionChart.tsx:3215425267": [ 615 615 [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"] 616 616 ], 617 617 "client/src/webpages/dashboard/ncmec/NcmecReportsDashboard.tsx:1586911903": [ ··· 623 623 "client/src/webpages/dashboard/rules/dashboard/RulesDashboard.tsx:329939153": [ 624 624 [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"] 625 625 ], 626 - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ 627 - [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"] 626 + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ 627 + [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"] 628 628 ], 629 629 "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsActionsChart.tsx:3492200963": [ 630 630 [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 632 "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsSamplesTable.tsx:1919031301": [ 633 633 [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"] 634 634 ], 635 - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ 636 - [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"] 635 + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ 636 + [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"] 637 637 ], 638 638 "client/src/webpages/dashboard/rules/info/insights/RuleInsightsSamplesPlayVideoButton.tsx:3799970987": [ 639 639 [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 776 [0, 0, 71, "\'@/icons/lni/Direction/chevron-down.svg?react\' import is restricted from being used by a pattern.", "3704341756"], 777 777 [1, 0, 67, "\'@/icons/lni/Direction/chevron-up.svg?react\' import is restricted from being used by a pattern.", "3710687196"] 778 778 ], 779 - "client/src/webpages/dashboard/overview/Overview.tsx:2096950063": [ 780 - [10, 0, 123, "\'@/icons\' import is restricted from being used.", "3974909531"] 779 + "client/src/webpages/dashboard/overview/Overview.tsx:380900289": [ 780 + [14, 0, 123, "\'@/icons\' import is restricted from being used.", "3974909531"] 781 781 ], 782 - "client/src/webpages/dashboard/overview/OverviewCard.tsx:3946409475": [ 782 + "client/src/webpages/dashboard/overview/OverviewCard.tsx:3308999316": [ 783 783 [8, 0, 61, "\'@/icons\' import is restricted from being used.", "8406751"], 784 784 [9, 0, 69, "\'@/icons/lni/Direction/arrow-right.svg?react\' import is restricted from being used by a pattern.", "2180497308"], 785 785 [10, 0, 81, "\'@/icons/lni/Direction/arrows-horizontal.svg?react\' import is restricted from being used by a pattern.", "3736456476"] ··· 798 798 [0, 0, 71, "\'@/icons/lni/Direction/chevron-down.svg?react\' import is restricted from being used by a pattern.", "3704341756"], 799 799 [1, 0, 67, "\'@/icons/lni/Direction/chevron-up.svg?react\' import is restricted from being used by a pattern.", "3710687196"] 800 800 ], 801 - "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:2980923118": [ 801 + "client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx:3285237740": [ 802 802 [3, 0, 62, "\'@/icons\' import is restricted from being used.", "469112768"] 803 803 ], 804 - "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:2709633326": [ 804 + "client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx:1979519000": [ 805 805 [8, 0, 36, "\'@/icons\' import is restricted from being used.", "1234727599"], 806 806 [9, 0, 73, "\'@/icons/lni/Web and Technology/download.svg?react\' import is restricted from being used by a pattern.", "3283715369"] 807 807 ], 808 808 "client/src/webpages/dashboard/rules/info/insights/ReportingRuleInsightsActionsChart.tsx:3492200963": [ 809 809 [1, 0, 43, "\'@/icons\' import is restricted from being used.", "3049589739"] 810 810 ], 811 - "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:1036947335": [ 811 + "client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx:3754111732": [ 812 812 [1, 0, 62, "\'@/icons\' import is restricted from being used.", "469112768"] 813 813 ], 814 814 "client/src/webpages/dashboard/rules/rule_form/ReportingRuleForm.tsx:2940997571": [
+71 -5
client/src/graphql/generated.ts
··· 3147 3147 readonly action?: Maybe<GQLAction>; 3148 3148 readonly actionStatistics: ReadonlyArray<GQLActionData>; 3149 3149 readonly allOrgs: ReadonlyArray<GQLOrg>; 3150 - readonly allRuleInsights: GQLAllRuleInsights; 3150 + readonly allRuleInsights?: Maybe<GQLAllRuleInsights>; 3151 3151 readonly apiKey: Scalars['String']; 3152 3152 readonly appealSettings?: Maybe<GQLAppealSettings>; 3153 3153 readonly availableIntegrations: ReadonlyArray<GQLIntegrationMetadata>; ··· 3177 3177 readonly hashBanks: ReadonlyArray<GQLHashBank>; 3178 3178 readonly integrationConfig: GQLIntegrationConfigQueryResponse; 3179 3179 readonly inviteUserToken: GQLInviteUserTokenResponse; 3180 + readonly isWarehouseAvailable: Scalars['Boolean']; 3180 3181 readonly itemActionHistory: ReadonlyArray<GQLItemAction>; 3181 3182 readonly itemSubmissions: ReadonlyArray<GQLItemSubmissions>; 3182 3183 readonly itemType?: Maybe<GQLItemType>; ··· 18225 18226 } | null; 18226 18227 }; 18227 18228 18229 + export type GQLIsWarehouseAvailableQueryVariables = Exact<{ 18230 + [key: string]: never; 18231 + }>; 18232 + 18233 + export type GQLIsWarehouseAvailableQuery = { 18234 + readonly __typename: 'Query'; 18235 + readonly isWarehouseAvailable: boolean; 18236 + }; 18237 + 18228 18238 export type GQLTotalPendingJobsQueryVariables = Exact<{ [key: string]: never }>; 18229 18239 18230 18240 export type GQLTotalPendingJobsQuery = { ··· 19096 19106 19097 19107 export type GQLRulesDashboardInsightsQuery = { 19098 19108 readonly __typename: 'Query'; 19099 - readonly allRuleInsights: { 19109 + readonly allRuleInsights?: { 19100 19110 readonly __typename: 'AllRuleInsights'; 19101 19111 readonly actionedSubmissionsByPolicyByDay: ReadonlyArray<{ 19102 19112 readonly __typename: 'CountByPolicyByDay'; ··· 19133 19143 readonly date: Date | string; 19134 19144 readonly count: number; 19135 19145 }>; 19136 - }; 19146 + } | null; 19137 19147 }; 19138 19148 19139 19149 export type GQLPolicyRollupDataQueryVariables = Exact<{ [key: string]: never }>; ··· 19635 19645 }; 19636 19646 } 19637 19647 | null; 19638 - readonly allRuleInsights: { 19648 + readonly allRuleInsights?: { 19639 19649 readonly __typename: 'AllRuleInsights'; 19640 19650 readonly totalSubmissionsByDay: ReadonlyArray<{ 19641 19651 readonly __typename: 'CountByDay'; 19642 19652 readonly date: Date | string; 19643 19653 readonly count: number; 19644 19654 }>; 19645 - }; 19655 + } | null; 19646 19656 }; 19647 19657 19648 19658 export type GQLLeafConditionWithResultFieldsFragment = { ··· 33722 33732 GQLGetNcmecReportQuery, 33723 33733 GQLGetNcmecReportQueryVariables 33724 33734 >; 33735 + export const GQLIsWarehouseAvailableDocument = gql` 33736 + query IsWarehouseAvailable { 33737 + isWarehouseAvailable 33738 + } 33739 + `; 33740 + 33741 + /** 33742 + * __useGQLIsWarehouseAvailableQuery__ 33743 + * 33744 + * To run a query within a React component, call `useGQLIsWarehouseAvailableQuery` and pass it any options that fit your needs. 33745 + * When your component renders, `useGQLIsWarehouseAvailableQuery` returns an object from Apollo Client that contains loading, error, and data properties 33746 + * you can use to render your UI. 33747 + * 33748 + * @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; 33749 + * 33750 + * @example 33751 + * const { data, loading, error } = useGQLIsWarehouseAvailableQuery({ 33752 + * variables: { 33753 + * }, 33754 + * }); 33755 + */ 33756 + export function useGQLIsWarehouseAvailableQuery( 33757 + baseOptions?: Apollo.QueryHookOptions< 33758 + GQLIsWarehouseAvailableQuery, 33759 + GQLIsWarehouseAvailableQueryVariables 33760 + >, 33761 + ) { 33762 + const options = { ...defaultOptions, ...baseOptions }; 33763 + return Apollo.useQuery< 33764 + GQLIsWarehouseAvailableQuery, 33765 + GQLIsWarehouseAvailableQueryVariables 33766 + >(GQLIsWarehouseAvailableDocument, options); 33767 + } 33768 + export function useGQLIsWarehouseAvailableLazyQuery( 33769 + baseOptions?: Apollo.LazyQueryHookOptions< 33770 + GQLIsWarehouseAvailableQuery, 33771 + GQLIsWarehouseAvailableQueryVariables 33772 + >, 33773 + ) { 33774 + const options = { ...defaultOptions, ...baseOptions }; 33775 + return Apollo.useLazyQuery< 33776 + GQLIsWarehouseAvailableQuery, 33777 + GQLIsWarehouseAvailableQueryVariables 33778 + >(GQLIsWarehouseAvailableDocument, options); 33779 + } 33780 + export type GQLIsWarehouseAvailableQueryHookResult = ReturnType< 33781 + typeof useGQLIsWarehouseAvailableQuery 33782 + >; 33783 + export type GQLIsWarehouseAvailableLazyQueryHookResult = ReturnType< 33784 + typeof useGQLIsWarehouseAvailableLazyQuery 33785 + >; 33786 + export type GQLIsWarehouseAvailableQueryResult = Apollo.QueryResult< 33787 + GQLIsWarehouseAvailableQuery, 33788 + GQLIsWarehouseAvailableQueryVariables 33789 + >; 33725 33790 export const GQLTotalPendingJobsDocument = gql` 33726 33791 query TotalPendingJobs { 33727 33792 getTotalPendingJobsCount ··· 37893 37958 AllNCMECReports: 'AllNCMECReports', 37894 37959 Permissions: 'Permissions', 37895 37960 GetNCMECReport: 'GetNCMECReport', 37961 + IsWarehouseAvailable: 'IsWarehouseAvailable', 37896 37962 TotalPendingJobs: 'TotalPendingJobs', 37897 37963 RuleNamesAndIds: 'RuleNamesAndIds', 37898 37964 DataForOverviewCharts: 'DataForOverviewCharts',
+1 -1
client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsCard.tsx
··· 156 156 ) : null} 157 157 </div> 158 158 ) : ( 159 - <div className="text-coop-alert-red">Error finding value</div> 159 + <div className="text-sm text-slate-400">No data available.</div> 160 160 )} 161 161 </div> 162 162 <div className="pl-2 rounded">{icon}</div>
+2 -2
client/src/webpages/dashboard/mrt/visualization/ManualReviewDashboardInsightsChart.tsx
··· 1073 1073 1074 1074 const emptyChart = ( 1075 1075 <div className="flex flex-col items-center justify-center p-6 rounded gap-3 bg-slate-100"> 1076 - <div className="text-xl"> 1077 - We didn't find any results for this query. Try another one! 1076 + <div className="text-sm text-slate-400"> 1077 + No data available for the selected time period. 1078 1078 </div> 1079 1079 <CoopButton 1080 1080 title="Reset Filters"
+1 -1
client/src/webpages/dashboard/mrt/visualization/TimeToActionChart.tsx
··· 219 219 220 220 const emptyChart = ( 221 221 <div className="flex flex-col items-center justify-center h-full gap-3 p-6 bg-indigo-100 rounded"> 222 - <div className="text-xl">We didn't find any results for this query.</div> 222 + <div className="text-sm text-slate-400">No data available for the selected time period.</div> 223 223 <CoopButton 224 224 title="Reset Filters" 225 225 onClick={() => getEmptyFilterState(timeWindow)}
+26 -1
client/src/webpages/dashboard/overview/Overview.tsx
··· 7 7 SelectTrigger, 8 8 SelectValue, 9 9 } from '@/coop-ui/Select'; 10 - import { useGQLDashboardOrgQuery } from '@/graphql/generated'; 10 + import { 11 + useGQLDashboardOrgQuery, 12 + useGQLIsWarehouseAvailableQuery, 13 + } from '@/graphql/generated'; 14 + import { TriangleAlert } from 'lucide-react'; 11 15 import { 12 16 FileExclamationFilled, 13 17 FlowChartAltFilled, ··· 16 20 UsersFilled, 17 21 } from '@/icons'; 18 22 import { LookbackLength } from '@/utils/time'; 23 + import { gql } from '@apollo/client'; 19 24 import { makeEnumLike } from '@roostorg/types'; 20 25 import { startOfHour, subDays } from 'date-fns'; 21 26 import { useState } from 'react'; ··· 44 49 } 45 50 } 46 51 52 + gql` 53 + query IsWarehouseAvailable { 54 + isWarehouseAvailable 55 + } 56 + `; 57 + 47 58 export default function Overview() { 48 59 const { loading, error } = useGQLDashboardOrgQuery(); 60 + const { data: warehouseData } = useGQLIsWarehouseAvailableQuery({ 61 + fetchPolicy: 'cache-first', 62 + pollInterval: 60_000, 63 + }); 49 64 const [timeDivision, setTimeDivision] = useState<TimeDivisionOptions>('DAY'); 50 65 const [customTimeWindow, setCustomTimeWindow] = useState({ 51 66 start: startOfHour(subDays(new Date(), 7)), ··· 197 212 <FullScreenLoading /> 198 213 ) : ( 199 214 <div className="flex flex-col w-full gap-4 mb-12"> 215 + {warehouseData?.isWarehouseAvailable === false && ( 216 + <div className="flex items-center gap-3 p-3 border border-solid rounded-lg bg-amber-50 border-amber-200 text-amber-800"> 217 + <TriangleAlert className="w-5 h-5 text-amber-500 shrink-0" /> 218 + <span className="text-sm"> 219 + The analytics database is currently unavailable. Some charts and 220 + statistics may show incomplete data until the service is 221 + restored. 222 + </span> 223 + </div> 224 + )} 200 225 <div className="flex flex-col w-full gap-4 sm:flex-row">{cards}</div> 201 226 <div className="flex w-full"> 202 227 <ErrorBoundary
+16 -26
client/src/webpages/dashboard/overview/OverviewCard.tsx
··· 368 368 ? sum(previousManualActions.map((it) => it.count)) 369 369 : undefined; 370 370 371 - if ( 372 - totalActionsError || 373 - previousTotalActionsError || 374 - jobsPendingError || 375 - violationsPerPolicyError || 376 - automatedVsManualError || 377 - previousAutomatedVsManualError || 378 - policiesError || 379 - rulesError || 380 - totalActionsByRuleError 381 - ) { 382 - throw ( 383 - totalActionsError ?? 384 - previousTotalActionsError ?? 385 - jobsPendingError ?? 386 - violationsPerPolicyError ?? 387 - automatedVsManualError ?? 388 - previousAutomatedVsManualError ?? 389 - policiesError ?? 390 - rulesError ?? 391 - // eslint-disable-next-line 392 - totalActionsByRuleError! 393 - ); 394 - } 371 + const hasError = 372 + totalActionsError ?? 373 + previousTotalActionsError ?? 374 + jobsPendingError ?? 375 + violationsPerPolicyError ?? 376 + automatedVsManualError ?? 377 + previousAutomatedVsManualError ?? 378 + policiesError ?? 379 + rulesError ?? 380 + totalActionsByRuleError; 395 381 396 382 const loading = 397 383 totalActionsLoading || ··· 534 520 ); 535 521 536 522 const errorComponent = ( 537 - <div className="py-4 text-coop-alert-red">Error finding value</div> 523 + <div className="py-4 text-sm text-slate-400">No data available.</div> 538 524 ); 539 525 540 526 const component = useMemo(() => { ··· 591 577 <div className="text-base font-bold">{title}</div> 592 578 <Icon className={`flex w-6 h-6 ${iconColor}`} /> 593 579 </div> 594 - {loading ? ( 580 + {hasError ? ( 581 + <div className="py-4 text-sm text-slate-400"> 582 + Analytics data is temporarily unavailable. 583 + </div> 584 + ) : loading ? ( 595 585 <div className="self-start pt-4"> 596 586 <ComponentLoading /> 597 587 </div>
+18 -2
client/src/webpages/dashboard/overview/OverviewChart.tsx
··· 180 180 181 181 const emptyChart = ( 182 182 <div className="flex flex-col items-center justify-center gap-3 p-6 rounded bg-slate-100"> 183 - <div className="text-xl">We didn't find any results for this query</div> 183 + <div className="text-sm text-slate-400"> 184 + No data available for the selected time period. 185 + </div> 184 186 </div> 185 187 ); 186 188 ··· 417 419 )); 418 420 419 421 if (error || decisionsError || actionStatsError) { 420 - throw error ?? decisionsError ?? actionStatsError!; 422 + return ( 423 + <div className="flex flex-col w-full p-6 bg-white border border-solid rounded-lg border-slate-200"> 424 + <div className="flex pb-6"> 425 + <div className="flex items-start gap-2"> 426 + <Icon className={`flex w-6 h-6 ${iconColor}`} /> 427 + <div className="pb-2 text-lg font-bold">{title}</div> 428 + </div> 429 + </div> 430 + <div className="flex flex-col items-center justify-center gap-3 p-6 rounded bg-slate-100"> 431 + <div className="text-sm text-slate-400"> 432 + Analytics data is temporarily unavailable. 433 + </div> 434 + </div> 435 + </div> 436 + ); 421 437 } 422 438 423 439 const loading = decisionsLoading || actionStatsLoading;
+1 -1
client/src/webpages/dashboard/overview/OverviewTable.tsx
··· 97 97 98 98 const emptyChart = ( 99 99 <div className="flex flex-col items-center justify-center gap-3 p-6 rounded bg-slate-100"> 100 - <div className="text-xl">We didn't find any results for this query</div> 100 + <div className="text-sm text-slate-400">No data available for the selected time period.</div> 101 101 </div> 102 102 ); 103 103
+8 -1
client/src/webpages/dashboard/rules/dashboard/visualization/RulesDashboardInsights.tsx
··· 2 2 3 3 import { DateRangePicker } from '@/coop-ui/DateRangePicker'; 4 4 import { InvestmentFilled, PieChartAltFilled } from '@/icons'; 5 + import { TriangleAlert } from 'lucide-react'; 5 6 import { truncateAndFormatLargeNumber } from '@/utils/number'; 6 7 import { 7 8 BarChartOutlined, ··· 880 881 ); 881 882 882 883 if (error || policiesError) { 883 - throw error ?? policiesError!; 884 + return ( 885 + <RuleInsightsEmptyCard 886 + icon={<TriangleAlert />} 887 + title="Analytics Unavailable" 888 + subtitle="We couldn't load the analytics data. The analytics service may be temporarily down. Other parts of Coop are unaffected." 889 + /> 890 + ); 884 891 } 885 892 886 893 return (
+2 -2
client/src/webpages/dashboard/rules/dashboard/visualization/rulesDashboardInsightsChart.tsx
··· 419 419 420 420 const emptyChart = ( 421 421 <div className="flex flex-col items-center justify-center gap-3 p-6 rounded bg-slate-100"> 422 - <div className="text-xl"> 423 - We didn't find any results for this query. Try another one! 422 + <div className="text-sm text-slate-400"> 423 + No data available for the selected time period. 424 424 </div> 425 425 <CoopButton 426 426 title="Reset Filters"
+10 -1
client/src/webpages/dashboard/rules/info/insights/RuleInsightsActionsChart.tsx
··· 1 1 import { DateRangePicker } from '@/coop-ui/DateRangePicker'; 2 2 import { InvestmentFilled, PieChartAltFilled } from '@/icons'; 3 + import { TriangleAlert } from 'lucide-react'; 3 4 import { truncateAndFormatLargeNumber } from '@/utils/number'; 4 5 import { BarChartOutlined, LineChartOutlined } from '@ant-design/icons'; 5 6 import { gql } from '@apollo/client'; ··· 383 384 ); 384 385 385 386 if (error) { 386 - return <div />; 387 + return ( 388 + <div className="flex justify-between w-full p-4 bg-white border border-gray-200 border-solid rounded-lg text-start"> 389 + <RuleInsightsEmptyCard 390 + icon={<TriangleAlert />} 391 + title="Analytics Unavailable" 392 + subtitle="We couldn't load the analytics data. The analytics service may be temporarily down. Other parts of Coop are unaffected." 393 + /> 394 + </div> 395 + ); 387 396 } 388 397 389 398 return (
+2
server/api.ts
··· 520 520 return { 521 521 ...safePick(deps, [ 522 522 'ApiKeyService', 523 + 'DataWarehouse', 523 524 'DerivedFieldsService', 524 525 'getItemTypeEventuallyConsistent', 525 526 'getEnabledRulesForItemTypeEventuallyConsistent', ··· 535 536 'Sequelize', 536 537 'SignalsService', 537 538 'SigningKeyPairService', 539 + 'Tracer', 538 540 'UserManagementService', 539 541 'UserStatisticsService', 540 542 'UserHistoryQueries',
+11 -12
server/graphql/datasources/RuleApi.ts
··· 574 574 } 575 575 576 576 async getAllRuleInsights(orgId: string) { 577 - const [ 578 - actionedSubmissionsByDay, 579 - actionedSubmissionsByPolicyByDay, 580 - actionedSubmissionsByTagByDay, 581 - actionedSubmissionsByActionByDay, 582 - totalSubmissionsByDay, 583 - ] = await Promise.all([ 577 + const results = await Promise.allSettled([ 584 578 this.actionStats.getActionedSubmissionCountsByDay(orgId), 585 579 this.actionStats.getActionedSubmissionCountsByPolicyByDay(orgId), 586 580 this.actionStats.getActionedSubmissionCountsByTagByDay(orgId), ··· 588 582 this.ruleInsights.getContentSubmissionCountsByDay(orgId), 589 583 ]); 590 584 585 + const valueOrEmpty = <T,>(r: PromiseSettledResult<readonly T[]>): readonly T[] => 586 + r.status === 'fulfilled' ? r.value : []; 587 + 591 588 return { 592 - actionedSubmissionsByDay, 593 - actionedSubmissionsByPolicyByDay, 594 - actionedSubmissionsByTagByDay, 595 - actionedSubmissionsByActionByDay, 596 - totalSubmissionsByDay, 589 + actionedSubmissionsByDay: valueOrEmpty(results[0]), 590 + actionedSubmissionsByPolicyByDay: valueOrEmpty(results[1]), 591 + actionedSubmissionsByTagByDay: valueOrEmpty(results[2]), 592 + actionedSubmissionsByActionByDay: valueOrEmpty(results[3]), 593 + totalSubmissionsByDay: valueOrEmpty( 594 + results[4] as PromiseSettledResult<readonly { date: string; count: number }[]>, 595 + ), 597 596 }; 598 597 } 599 598
+8 -2
server/graphql/generated.ts
··· 3216 3216 readonly action?: Maybe<GQLAction>; 3217 3217 readonly actionStatistics: ReadonlyArray<GQLActionData>; 3218 3218 readonly allOrgs: ReadonlyArray<GQLOrg>; 3219 - readonly allRuleInsights: GQLAllRuleInsights; 3219 + readonly allRuleInsights?: Maybe<GQLAllRuleInsights>; 3220 3220 readonly apiKey: Scalars['String']; 3221 3221 readonly appealSettings?: Maybe<GQLAppealSettings>; 3222 3222 readonly availableIntegrations: ReadonlyArray<GQLIntegrationMetadata>; ··· 3246 3246 readonly hashBanks: ReadonlyArray<GQLHashBank>; 3247 3247 readonly integrationConfig: GQLIntegrationConfigQueryResponse; 3248 3248 readonly inviteUserToken: GQLInviteUserTokenResponse; 3249 + readonly isWarehouseAvailable: Scalars['Boolean']; 3249 3250 readonly itemActionHistory: ReadonlyArray<GQLItemAction>; 3250 3251 readonly itemSubmissions: ReadonlyArray<GQLItemSubmissions>; 3251 3252 readonly itemType?: Maybe<GQLItemType>; ··· 11747 11748 ContextType 11748 11749 >; 11749 11750 allRuleInsights?: Resolver< 11750 - GQLResolversTypes['AllRuleInsights'], 11751 + Maybe<GQLResolversTypes['AllRuleInsights']>, 11751 11752 ParentType, 11752 11753 ContextType 11753 11754 >; ··· 11913 11914 ParentType, 11914 11915 ContextType, 11915 11916 RequireFields<GQLQueryInviteUserTokenArgs, 'token'> 11917 + >; 11918 + isWarehouseAvailable?: Resolver< 11919 + GQLResolversTypes['Boolean'], 11920 + ParentType, 11921 + ContextType 11916 11922 >; 11917 11923 itemActionHistory?: Resolver< 11918 11924 ReadonlyArray<GQLResolversTypes['ItemAction']>,
+35 -23
server/graphql/modules/actionStatistics.ts
··· 101 101 } as const; 102 102 const sources = input.filterBy.sources.map((it) => a[it]); 103 103 104 - return context.dataSources.ruleAPI.getActionStatistics({ 105 - ...input, 106 - filterBy: { 107 - ...input.filterBy, 108 - sources, 109 - startDate: new Date(input.filterBy.startDate), 110 - endDate: new Date(input.filterBy.endDate), 111 - }, 112 - orgId: user.orgId, 113 - }); 104 + try { 105 + return await context.dataSources.ruleAPI.getActionStatistics({ 106 + ...input, 107 + filterBy: { 108 + ...input.filterBy, 109 + sources, 110 + startDate: new Date(input.filterBy.startDate), 111 + endDate: new Date(input.filterBy.endDate), 112 + }, 113 + orgId: user.orgId, 114 + }); 115 + } catch (e) { 116 + // eslint-disable-next-line no-console 117 + console.error('actionStatistics: warehouse query failed:', (e as Error).message); 118 + return []; 119 + } 114 120 }, 115 121 116 122 async topPolicyViolations(_, { input }, context) { ··· 119 125 throw new AuthenticationError('Authenticated user required'); 120 126 } 121 127 122 - const policyViolations = 123 - await context.dataSources.ruleAPI.getPoliciesSortedByViolationCount({ 124 - filterBy: { 125 - startDate: new Date(input.filterBy.startDate), 126 - endDate: new Date(input.filterBy.endDate), 127 - }, 128 - timeZone: input.timeZone, 129 - orgId: user.orgId, 130 - }); 131 - return policyViolations.map((it) => ({ 132 - count: it.count, 133 - policyId: it.policy_id, 134 - })); 128 + try { 129 + const policyViolations = 130 + await context.dataSources.ruleAPI.getPoliciesSortedByViolationCount({ 131 + filterBy: { 132 + startDate: new Date(input.filterBy.startDate), 133 + endDate: new Date(input.filterBy.endDate), 134 + }, 135 + timeZone: input.timeZone, 136 + orgId: user.orgId, 137 + }); 138 + return policyViolations.map((it) => ({ 139 + count: it.count, 140 + policyId: it.policy_id, 141 + })); 142 + } catch (e) { 143 + // eslint-disable-next-line no-console 144 + console.error('topPolicyViolations: warehouse query failed:', (e as Error).message); 145 + return []; 146 + } 135 147 }, 136 148 137 149 async recentUserStrikeActions(_, { input }, context) {
+23 -2
server/graphql/resolvers.ts
··· 98 98 return null; 99 99 } 100 100 101 - // TODO: this response type actually isn't right; remove cast and fix errors. 102 - return context.dataSources.ruleAPI.getAllRuleInsights(user.orgId) as any; 101 + try { 102 + // TODO: this response type actually isn't right; remove cast and fix errors. 103 + return (await context.dataSources.ruleAPI.getAllRuleInsights( 104 + user.orgId, 105 + )) as any; 106 + } catch (e) { 107 + // eslint-disable-next-line no-console 108 + console.error('allRuleInsights: warehouse query failed:', (e as Error).message); 109 + return null; 110 + } 111 + }, 112 + async isWarehouseAvailable(_, __, context) { 113 + try { 114 + await context.services.DataWarehouse.query( 115 + 'SELECT 1', 116 + context.services.Tracer, 117 + ); 118 + return true; 119 + } catch (e) { 120 + // eslint-disable-next-line no-console 121 + console.error('isWarehouseAvailable: warehouse health check failed:', (e as Error).message); 122 + return false; 123 + } 103 124 }, 104 125 }; 105 126
+2 -1
server/graphql/schema.ts
··· 473 473 myOrg: Org 474 474 userFromToken(token: String!): ID 475 475 inviteUserToken(token: String!): InviteUserTokenResponse! @publicResolver 476 - allRuleInsights: AllRuleInsights! 476 + allRuleInsights: AllRuleInsights 477 + isWarehouseAvailable: Boolean! 477 478 } 478 479 479 480 type Mutation {