@oneuptime/common 14.0.0 → 14.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/Models/DatabaseModels/Index.ts +4 -0
  2. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  3. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  4. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  5. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  9. package/Server/Services/DatabaseService.ts +10 -0
  10. package/Server/Services/Index.ts +4 -0
  11. package/Server/Services/MonitorService.ts +3 -2
  12. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  13. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  14. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  15. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  16. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  17. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  18. package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
  19. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  20. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  21. package/Server/Utils/Monitor/AffectedResourceList.ts +31 -73
  22. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  23. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  24. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +181 -136
  25. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  26. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  27. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  28. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  29. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  30. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  31. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  32. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
  33. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  34. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  35. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  36. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  37. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  38. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  39. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  40. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  41. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  42. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  43. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  44. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  45. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  46. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  47. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  48. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  49. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  50. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  51. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  52. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  53. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  54. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
  55. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
  56. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  57. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  58. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  59. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  60. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  61. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
  62. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  63. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  64. package/Tests/Server/Types/Markdown.test.ts +2 -1
  65. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  66. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  67. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  68. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  69. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +405 -0
  70. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
  71. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  72. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  73. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  74. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  75. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  76. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  77. package/Tests/Types/API/Route.test.ts +56 -0
  78. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  79. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  80. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  81. package/Tests/UI/Components/Icon.test.tsx +26 -0
  82. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  83. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  84. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  85. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  86. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  87. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  88. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  89. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  90. package/Types/API/Route.ts +19 -2
  91. package/Types/API/URL.ts +26 -2
  92. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  93. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  94. package/Types/Permission.ts +90 -0
  95. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  96. package/Types/Rules/RuleRun.ts +4 -0
  97. package/UI/Components/Feed/FeedOptions.ts +427 -0
  98. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  99. package/UI/Components/Feed/useFeedItems.ts +28 -9
  100. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  101. package/UI/Components/Icon/Icon.tsx +1 -1
  102. package/Utils/LabelRuleImportExport.ts +27 -9
  103. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  104. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  105. package/Utils/Slo/SloDuration.ts +22 -6
  106. package/Utils/Slo/SloHealth.ts +8 -7
  107. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  108. package/Utils/Slo/SloOverviewText.ts +33 -0
  109. package/Utils/Slo/SloProjection.ts +4 -3
  110. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  111. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  112. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  113. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  114. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  115. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  116. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  117. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  118. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  119. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  120. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  123. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  124. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  125. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  126. package/build/dist/Server/Services/DatabaseService.js +7 -0
  127. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  128. package/build/dist/Server/Services/Index.js +4 -0
  129. package/build/dist/Server/Services/Index.js.map +1 -1
  130. package/build/dist/Server/Services/MonitorService.js +3 -2
  131. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  132. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  133. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  134. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  135. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  136. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  137. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  138. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  139. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  140. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  141. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  142. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  143. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  144. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
  145. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  146. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  147. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  148. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  149. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  150. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +22 -51
  151. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -1
  152. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  153. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  154. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +139 -109
  155. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  156. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  157. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  158. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  159. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  160. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  161. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  162. package/build/dist/Types/API/Route.js +18 -2
  163. package/build/dist/Types/API/Route.js.map +1 -1
  164. package/build/dist/Types/API/URL.js +23 -2
  165. package/build/dist/Types/API/URL.js.map +1 -1
  166. package/build/dist/Types/Permission.js +84 -0
  167. package/build/dist/Types/Permission.js.map +1 -1
  168. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  169. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  170. package/build/dist/Types/Rules/RuleRun.js +4 -0
  171. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  172. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  173. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  174. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  175. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  176. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  177. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  178. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  179. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  180. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  181. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  182. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  183. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  184. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  185. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  186. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  187. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  188. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  189. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  190. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  191. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  192. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  193. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  194. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  195. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  196. package/package.json +1 -1
@@ -0,0 +1,346 @@
1
+ import React, { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, } from "react";
2
+ import IconProp from "../../../Types/Icon/IconProp";
3
+ import useTranslateValue from "../../Utils/Translation";
4
+ import Icon from "../Icon/Icon";
5
+ import { DEFAULT_FEED_SORT_ORDER, FEED_OPTIONS_TEXT, FEED_SORT_ORDER_OPTIONS, getFeedOptionsSummary, isDefaultFeedOptions, translateFeedOptionsText, } from "./FeedOptions";
6
+ // A short checklist is scanned by eye; a longer one gets a search box.
7
+ export const FEED_EVENT_TYPE_SEARCH_THRESHOLD = 8;
8
+ export const FEED_OPTIONS_PANEL_WIDTH_PX = 288;
9
+ // The panel never comes closer than this to either edge of the viewport.
10
+ export const FEED_OPTIONS_VIEWPORT_GUTTER_PX = 16;
11
+ /*
12
+ * Where the panel goes. It lines its right edge up with the trigger's, like
13
+ * every other header menu, and slides back inside the viewport when that
14
+ * would cross an edge. That happens on phones and tablets: the card header
15
+ * stacks there and puts this button, the first of the header's controls, at
16
+ * the left of the row, so a right-aligned panel would open off the screen.
17
+ */
18
+ export const getFeedOptionsPanelPlacement = (data) => {
19
+ const width = Math.max(Math.min(FEED_OPTIONS_PANEL_WIDTH_PX, data.viewportWidth - 2 * FEED_OPTIONS_VIEWPORT_GUTTER_PX), 0);
20
+ const lowestLeft = FEED_OPTIONS_VIEWPORT_GUTTER_PX;
21
+ const highestLeft = Math.max(data.viewportWidth - FEED_OPTIONS_VIEWPORT_GUTTER_PX - width, lowestLeft);
22
+ const left = Math.min(Math.max(data.triggerRight - width, lowestLeft), highestLeft);
23
+ return {
24
+ left: left - data.triggerLeft,
25
+ width,
26
+ };
27
+ };
28
+ /*
29
+ * The one control in a feed's header for everything about what the feed
30
+ * shows: the time order and the event type filter. It opens a small panel
31
+ * rather than a menu, because the reader ticks several boxes in one visit and
32
+ * a menu closes on every pick. Changes apply as they are made - there is no
33
+ * Apply button to forget - and the trigger is tinted, with a count of the
34
+ * chosen event types, whenever the feed is not showing its default view.
35
+ */
36
+ const FeedOptionsButton = (props) => {
37
+ const { translateString } = useTranslateValue();
38
+ const uniqueId = useId();
39
+ const buttonId = `feed-options-button-${uniqueId}`;
40
+ const summaryId = `feed-options-summary-${uniqueId}`;
41
+ const panelId = `feed-options-panel-${uniqueId}`;
42
+ const sortHeadingId = `feed-options-sort-${uniqueId}`;
43
+ const eventTypesHeadingId = `feed-options-event-types-${uniqueId}`;
44
+ const [isOpen, setIsOpen] = useState(false);
45
+ const [searchText, setSearchText] = useState("");
46
+ const [placement, setPlacement] = useState(null);
47
+ const containerRef = useRef(null);
48
+ const triggerRef = useRef(null);
49
+ const sortRadioRefs = useRef([]);
50
+ const eventTypeListRef = useRef(null);
51
+ const selectedEventTypes = useMemo(() => {
52
+ return new Set(props.value.eventTypes);
53
+ }, [props.value.eventTypes]);
54
+ const selectedCount = props.value.eventTypes.length;
55
+ const isCustomized = !isDefaultFeedOptions(props.value);
56
+ const isOldestFirst = props.value.sortOrder !== DEFAULT_FEED_SORT_ORDER;
57
+ const translate = (text, values) => {
58
+ return translateFeedOptionsText({
59
+ text,
60
+ values,
61
+ translate: translateString,
62
+ });
63
+ };
64
+ const summary = getFeedOptionsSummary({
65
+ options: props.value,
66
+ eventTypeCount: props.eventTypeOptions.length,
67
+ translate: translateString,
68
+ });
69
+ const showSearch = props.eventTypeOptions.length > FEED_EVENT_TYPE_SEARCH_THRESHOLD;
70
+ /*
71
+ * Labels are shown - and searched and ordered - in the reader's language.
72
+ * A label with no translation yet stays in English.
73
+ */
74
+ const translatedEventTypeOptions = props.eventTypeOptions
75
+ .map((option) => {
76
+ return Object.assign(Object.assign({}, option), { label: translate(option.label) });
77
+ })
78
+ .sort((a, b) => {
79
+ return a.label.localeCompare(b.label);
80
+ });
81
+ const searchTerm = searchText.trim().toLowerCase();
82
+ const visibleEventTypeOptions = searchTerm
83
+ ? translatedEventTypeOptions.filter((option) => {
84
+ return option.label.toLowerCase().includes(searchTerm);
85
+ })
86
+ : translatedEventTypeOptions;
87
+ const close = (shouldReturnFocus) => {
88
+ var _a;
89
+ setIsOpen(false);
90
+ setSearchText("");
91
+ if (shouldReturnFocus) {
92
+ (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
93
+ }
94
+ };
95
+ /*
96
+ * Dismiss on a press outside the trigger and panel. The listener sits on
97
+ * the container that holds both, so pressing the trigger to close the panel
98
+ * is a toggle, not a dismissal followed by a re-open.
99
+ */
100
+ useEffect(() => {
101
+ if (!isOpen) {
102
+ return undefined;
103
+ }
104
+ const onPointerDown = (event) => {
105
+ const target = event.target;
106
+ if (containerRef.current &&
107
+ target instanceof Node &&
108
+ !containerRef.current.contains(target)) {
109
+ setIsOpen(false);
110
+ setSearchText("");
111
+ }
112
+ };
113
+ document.addEventListener("mousedown", onPointerDown);
114
+ return () => {
115
+ document.removeEventListener("mousedown", onPointerDown);
116
+ };
117
+ }, [isOpen]);
118
+ const placePanel = useCallback(() => {
119
+ const container = containerRef.current;
120
+ if (!container) {
121
+ return;
122
+ }
123
+ const rect = container.getBoundingClientRect();
124
+ setPlacement(getFeedOptionsPanelPlacement({
125
+ triggerLeft: rect.left,
126
+ triggerRight: rect.right,
127
+ viewportWidth: document.documentElement.clientWidth || window.innerWidth,
128
+ }));
129
+ }, []);
130
+ // Placed before paint, so the panel never flashes off-screen first.
131
+ useLayoutEffect(() => {
132
+ if (!isOpen) {
133
+ setPlacement(null);
134
+ return undefined;
135
+ }
136
+ placePanel();
137
+ window.addEventListener("resize", placePanel);
138
+ return () => {
139
+ window.removeEventListener("resize", placePanel);
140
+ };
141
+ }, [isOpen, placePanel]);
142
+ // Opening moves focus onto the chosen sort order, the panel's first control.
143
+ useEffect(() => {
144
+ var _a;
145
+ if (!isOpen) {
146
+ return;
147
+ }
148
+ const selectedIndex = FEED_SORT_ORDER_OPTIONS.findIndex((option) => {
149
+ return option.value === props.value.sortOrder;
150
+ });
151
+ (_a = sortRadioRefs.current[Math.max(selectedIndex, 0)]) === null || _a === void 0 ? void 0 : _a.focus();
152
+ // Only on open: re-focusing on every sort change would fight the keyboard.
153
+ }, [isOpen]);
154
+ const setSortOrder = (sortOrder) => {
155
+ if (sortOrder === props.value.sortOrder) {
156
+ return;
157
+ }
158
+ props.onChange(Object.assign(Object.assign({}, props.value), { sortOrder }));
159
+ };
160
+ const toggleEventType = (eventType) => {
161
+ const nextSelected = new Set(selectedEventTypes);
162
+ if (nextSelected.has(eventType)) {
163
+ nextSelected.delete(eventType);
164
+ }
165
+ else {
166
+ nextSelected.add(eventType);
167
+ }
168
+ // Keep the checklist's order, not the order the boxes were ticked in.
169
+ props.onChange(Object.assign(Object.assign({}, props.value), { eventTypes: props.eventTypeOptions
170
+ .map((option) => {
171
+ return option.value;
172
+ })
173
+ .filter((value) => {
174
+ return nextSelected.has(value);
175
+ }) }));
176
+ };
177
+ /*
178
+ * "Show all" and "Reset to default" hide themselves once they have done
179
+ * their job. Focus on a button that unmounts falls to the page body, out of
180
+ * the panel, where Escape no longer closes it - so both hand focus to the
181
+ * control the reader is most likely to reach for next.
182
+ */
183
+ const focusSortOrder = (sortOrder) => {
184
+ var _a;
185
+ const index = FEED_SORT_ORDER_OPTIONS.findIndex((option) => {
186
+ return option.value === sortOrder;
187
+ });
188
+ (_a = sortRadioRefs.current[Math.max(index, 0)]) === null || _a === void 0 ? void 0 : _a.focus();
189
+ };
190
+ const clearEventTypes = () => {
191
+ var _a;
192
+ props.onChange(Object.assign(Object.assign({}, props.value), { eventTypes: [] }));
193
+ const firstCheckbox = ((_a = eventTypeListRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('input[type="checkbox"]')) || null;
194
+ if (firstCheckbox) {
195
+ firstCheckbox.focus();
196
+ }
197
+ else {
198
+ focusSortOrder(props.value.sortOrder);
199
+ }
200
+ };
201
+ const resetOptions = () => {
202
+ props.onChange({
203
+ sortOrder: DEFAULT_FEED_SORT_ORDER,
204
+ eventTypes: [],
205
+ });
206
+ focusSortOrder(DEFAULT_FEED_SORT_ORDER);
207
+ };
208
+ const onContainerKeyDown = (event) => {
209
+ if (isOpen && event.key === "Escape") {
210
+ event.preventDefault();
211
+ event.stopPropagation();
212
+ close(true);
213
+ }
214
+ };
215
+ /*
216
+ * Tabbing out of the panel closes it. Only focus that lands on something
217
+ * outside counts: a press on the panel's own padding moves focus to the
218
+ * panel itself (it is focusable for exactly this reason), which keeps
219
+ * Escape working.
220
+ */
221
+ const onContainerBlur = (event) => {
222
+ const nextFocus = event.relatedTarget;
223
+ if (isOpen &&
224
+ nextFocus instanceof Node &&
225
+ containerRef.current &&
226
+ !containerRef.current.contains(nextFocus)) {
227
+ setIsOpen(false);
228
+ setSearchText("");
229
+ }
230
+ };
231
+ // Arrow keys move between the two sort orders, as in any radio group.
232
+ const onSortKeyDown = (event, index) => {
233
+ var _a;
234
+ let nextIndex = null;
235
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
236
+ nextIndex = (index + 1) % FEED_SORT_ORDER_OPTIONS.length;
237
+ }
238
+ else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
239
+ nextIndex =
240
+ (index - 1 + FEED_SORT_ORDER_OPTIONS.length) %
241
+ FEED_SORT_ORDER_OPTIONS.length;
242
+ }
243
+ if (nextIndex === null) {
244
+ return;
245
+ }
246
+ event.preventDefault();
247
+ const nextOption = FEED_SORT_ORDER_OPTIONS[nextIndex];
248
+ if (nextOption) {
249
+ setSortOrder(nextOption.value);
250
+ (_a = sortRadioRefs.current[nextIndex]) === null || _a === void 0 ? void 0 : _a.focus();
251
+ }
252
+ };
253
+ /*
254
+ * The visible label is the button's name, and the state behind it - order
255
+ * and filter - its description, so a screen reader says each once. The
256
+ * label is only drawn from xl up: beside the feed's other header controls
257
+ * it would squeeze the card title into a sliver on tablets. Oldest first
258
+ * swaps the funnel for the sort glyph, so a reversed feed does not rely on
259
+ * the tint alone to say so.
260
+ */
261
+ const getTrigger = () => {
262
+ return (React.createElement("button", { ref: triggerRef, id: buttonId, type: "button", "data-testid": "feed-options-button", className: `inline-flex min-h-[2.375rem] items-center gap-2 rounded-lg border px-3.5 py-2 text-sm font-medium shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-150 cursor-pointer select-none ${isCustomized
263
+ ? "border-indigo-300 bg-indigo-50 text-indigo-700 hover:bg-indigo-100 hover:border-indigo-400"
264
+ : "border-gray-300 bg-white text-gray-700 hover:bg-gray-50 hover:border-gray-400 hover:text-gray-900"}`, title: summary, "aria-describedby": summaryId, "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-controls": isOpen ? panelId : undefined, onClick: () => {
265
+ if (isOpen) {
266
+ close(false);
267
+ }
268
+ else {
269
+ setIsOpen(true);
270
+ }
271
+ } },
272
+ React.createElement(Icon, { icon: isOldestFirst ? IconProp.BarsArrowUp : IconProp.Filter, className: `h-4 w-4 ${isCustomized ? "text-indigo-500" : "text-gray-500"}` }),
273
+ React.createElement("span", { className: "sr-only xl:not-sr-only", "data-testid": "feed-options-label" }, translate(FEED_OPTIONS_TEXT.triggerLabel)),
274
+ selectedCount > 0 && (React.createElement("span", { "data-testid": "feed-options-count", className: "inline-flex min-w-[1.25rem] justify-center rounded-full bg-indigo-600 px-1.5 text-xs font-semibold leading-5 text-white", "aria-hidden": "true" }, selectedCount)),
275
+ React.createElement(Icon, { icon: IconProp.ChevronDown, className: `h-3.5 w-3.5 ml-0.5 ${isCustomized ? "text-indigo-400" : "text-gray-400"}` })));
276
+ };
277
+ const getSortSection = () => {
278
+ return (React.createElement("div", { className: "border-b border-gray-100 p-3" },
279
+ React.createElement("div", { id: sortHeadingId, className: "text-xs font-semibold uppercase tracking-wide text-gray-500" }, translate(FEED_OPTIONS_TEXT.sortHeading)),
280
+ React.createElement("div", { role: "radiogroup", "aria-labelledby": sortHeadingId, className: "mt-2 grid grid-cols-2 gap-1 rounded-lg bg-gray-100 p-1" }, FEED_SORT_ORDER_OPTIONS.map((option, index) => {
281
+ const isSelected = option.value === props.value.sortOrder;
282
+ return (React.createElement("button", { key: option.value, ref: (element) => {
283
+ sortRadioRefs.current[index] = element;
284
+ }, type: "button", role: "radio", "aria-checked": isSelected, tabIndex: isSelected ? 0 : -1, "data-testid": `feed-options-sort-${option.value}`, className: `inline-flex items-center justify-center gap-1.5 rounded-md px-2 py-1.5 text-sm transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 ${isSelected
285
+ ? "bg-white font-semibold text-gray-900 shadow-sm ring-1 ring-indigo-400"
286
+ : "font-normal text-gray-600 hover:text-gray-900"}`, onClick: () => {
287
+ setSortOrder(option.value);
288
+ }, onKeyDown: (event) => {
289
+ onSortKeyDown(event, index);
290
+ } },
291
+ React.createElement(Icon, { icon: option.icon, className: `h-4 w-4 ${isSelected ? "text-indigo-500" : "text-gray-400"}` }),
292
+ translate(option.label)));
293
+ }))));
294
+ };
295
+ const getEventTypeSection = () => {
296
+ return (React.createElement("div", { className: "p-3" },
297
+ React.createElement("div", { className: "flex items-center justify-between" },
298
+ React.createElement("div", { id: eventTypesHeadingId, className: "text-xs font-semibold uppercase tracking-wide text-gray-500" }, translate(FEED_OPTIONS_TEXT.eventTypesHeading)),
299
+ selectedCount > 0 && (React.createElement("button", { type: "button", "data-testid": "feed-options-clear-event-types", className: "-my-1 rounded px-1.5 py-1 text-xs font-medium text-indigo-600 hover:text-indigo-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500", onClick: clearEventTypes }, translate(FEED_OPTIONS_TEXT.showAll)))),
300
+ React.createElement("p", { className: "mt-1 text-xs text-gray-500", "data-testid": "feed-options-event-type-summary", "aria-live": "polite" }, selectedCount === 0
301
+ ? translate(FEED_OPTIONS_TEXT.showingEveryEventType)
302
+ : translate(FEED_OPTIONS_TEXT.showingSomeEventTypes, {
303
+ selected: selectedCount,
304
+ total: props.eventTypeOptions.length,
305
+ })),
306
+ showSearch && (React.createElement("div", { className: "relative mt-2" },
307
+ React.createElement(Icon, { icon: IconProp.Search, className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" }),
308
+ React.createElement("input", { type: "text", value: searchText, "aria-label": translate(FEED_OPTIONS_TEXT.searchPlaceholder), placeholder: translate(FEED_OPTIONS_TEXT.searchPlaceholder), "data-testid": "feed-options-search", className: "block w-full rounded-md border border-gray-300 bg-white py-1.5 pl-8 pr-2 text-sm text-gray-900 placeholder-gray-500 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500", onChange: (event) => {
309
+ setSearchText(event.target.value);
310
+ } }),
311
+ React.createElement("span", { className: "sr-only", "aria-live": "polite", "data-testid": "feed-options-search-results" }, searchTerm
312
+ ? translate(FEED_OPTIONS_TEXT.searchResults, {
313
+ count: visibleEventTypeOptions.length,
314
+ })
315
+ : ""))),
316
+ React.createElement("div", { role: "group", "aria-labelledby": eventTypesHeadingId },
317
+ React.createElement("ul", { ref: eventTypeListRef, role: "list", className: "-mx-1 mt-2 max-h-64 overflow-y-auto", "data-testid": "feed-options-event-types" },
318
+ visibleEventTypeOptions.map((option) => {
319
+ const isChecked = selectedEventTypes.has(option.value);
320
+ return (React.createElement("li", { key: option.value },
321
+ React.createElement("label", { className: "flex cursor-pointer items-center gap-2.5 rounded-md px-1.5 py-1.5 text-sm text-gray-700 hover:bg-gray-50" },
322
+ React.createElement("input", { type: "checkbox", checked: isChecked, "data-testid": `feed-options-event-type-${option.value}`, className: "h-4 w-4 shrink-0 cursor-pointer rounded border-gray-300 accent-indigo-600 text-indigo-600 focus:ring-indigo-500", onChange: () => {
323
+ toggleEventType(option.value);
324
+ } }),
325
+ option.icon && (React.createElement(Icon, { icon: option.icon, className: "h-4 w-4 shrink-0 text-gray-400" })),
326
+ React.createElement("span", { className: "truncate" }, option.label))));
327
+ }),
328
+ visibleEventTypeOptions.length === 0 && (React.createElement("li", { className: "px-1.5 py-2 text-sm text-gray-500" }, props.eventTypeOptions.length === 0
329
+ ? translate(FEED_OPTIONS_TEXT.noEventTypes)
330
+ : translate(FEED_OPTIONS_TEXT.noSearchMatches, {
331
+ search: searchText.trim(),
332
+ })))))));
333
+ };
334
+ return (React.createElement("div", { ref: containerRef, className: "relative inline-block text-left", onKeyDown: onContainerKeyDown, onBlur: onContainerBlur },
335
+ getTrigger(),
336
+ React.createElement("span", { id: summaryId, className: "sr-only", "data-testid": "feed-options-summary" }, summary),
337
+ isOpen && (React.createElement("div", { id: panelId, role: "dialog", tabIndex: -1, "aria-label": translate(FEED_OPTIONS_TEXT.panelLabel), "data-testid": "feed-options-panel", style: placement
338
+ ? { left: `${placement.left}px`, width: `${placement.width}px` }
339
+ : undefined, className: `absolute z-50 mt-2 origin-top-right rounded-lg bg-white shadow-xl ring-1 ring-gray-200 focus:outline-none ${placement ? "" : "right-0 w-72"}` },
340
+ getSortSection(),
341
+ getEventTypeSection(),
342
+ isCustomized && (React.createElement("div", { className: "flex justify-end border-t border-gray-100 px-3 py-2" },
343
+ React.createElement("button", { type: "button", "data-testid": "feed-options-reset", className: "-my-1 rounded px-1.5 py-1 text-xs font-medium text-gray-600 hover:text-gray-900 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500", onClick: resetOptions }, translate(FEED_OPTIONS_TEXT.reset))))))));
344
+ };
345
+ export default FeedOptionsButton;
346
+ //# sourceMappingURL=FeedOptionsButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeedOptionsButton.js","sourceRoot":"","sources":["../../../../../UI/Components/Feed/FeedOptionsButton.tsx"],"names":[],"mappings":"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"}
@@ -3,7 +3,8 @@ import { DEFAULT_LIMIT, LIMIT_PER_PROJECT, } from "../../../Types/Database/Limit
3
3
  import API from "../../Utils/API/API";
4
4
  /*
5
5
  * Every dashboard activity feed follows the same paging contract: read the
6
- * newest top N rows and replace that window when the reader asks for more.
6
+ * first N rows in the reader's chosen order (newest first unless they asked
7
+ * for oldest first) and replace that window when the reader asks for more.
7
8
  * Re-reading from zero matters for a live feed. Offset-appending can duplicate
8
9
  * or skip a row when a new event arrives between page requests.
9
10
  */
@@ -15,8 +16,17 @@ const useFeedItems = (props) => {
15
16
  const [loadMoreError, setLoadMoreError] = useState(undefined);
16
17
  const [hasMore, setHasMore] = useState(false);
17
18
  const [loadedResourceKey, setLoadedResourceKey] = useState(null);
18
- const activeResourceKeyRef = useRef(props.resourceKey);
19
- activeResourceKeyRef.current = props.resourceKey;
19
+ /*
20
+ * The resource and the view together name the feed being shown. Everything
21
+ * below that guards against a stale response or resets the window keys on
22
+ * this, so a response for the previous view is dropped the same way as a
23
+ * response for the previous resource.
24
+ */
25
+ const feedKey = props.viewKey === undefined
26
+ ? props.resourceKey
27
+ : `${props.resourceKey}\u0000${props.viewKey}`;
28
+ const activeResourceKeyRef = useRef(feedKey);
29
+ activeResourceKeyRef.current = feedKey;
20
30
  const previousResourceKeyRef = useRef(null);
21
31
  const currentLimitRef = useRef(DEFAULT_LIMIT);
22
32
  const fetchGenerationRef = useRef(0);
@@ -99,8 +109,8 @@ const useFeedItems = (props) => {
99
109
  });
100
110
  }, [fetchItems]);
101
111
  useEffect(() => {
102
- const hasResourceChanged = previousResourceKeyRef.current !== props.resourceKey;
103
- previousResourceKeyRef.current = props.resourceKey;
112
+ const hasResourceChanged = previousResourceKeyRef.current !== feedKey;
113
+ previousResourceKeyRef.current = feedKey;
104
114
  if (hasResourceChanged) {
105
115
  currentLimitRef.current = DEFAULT_LIMIT;
106
116
  setFeedItems([]);
@@ -113,13 +123,13 @@ const useFeedItems = (props) => {
113
123
  }).catch(() => {
114
124
  // fetchItems converts request failures into the appropriate UI state.
115
125
  });
116
- }, [fetchItems, props.resourceKey, props.refreshToken]);
126
+ }, [fetchItems, feedKey, props.refreshToken]);
117
127
  useEffect(() => {
118
128
  return () => {
119
129
  fetchGenerationRef.current += 1;
120
130
  };
121
131
  }, []);
122
- const isCurrentFeedLoaded = loadedResourceKey === props.resourceKey;
132
+ const isCurrentFeedLoaded = loadedResourceKey === feedKey;
123
133
  return {
124
134
  feedItems,
125
135
  isLoading,
@@ -1 +1 @@
1
- {"version":3,"file":"useFeedItems.js","sourceRoot":"","sources":["../../../../../UI/Components/Feed/useFeedItems.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useFeedItems.js","sourceRoot":"","sources":["../../../../../UI/Components/Feed/useFeedItems.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
2
+ import LocalStorage from "../../Utils/LocalStorage";
3
+ import { DEFAULT_FEED_SORT_ORDER, getFeedEventTypeOptions, getFeedOptionsKey, isFeedFiltered, isFeedSortOrder, sanitizeFeedEventTypes, } from "./FeedOptions";
4
+ const SORT_ORDER_STORAGE_KEY_PREFIX = "feed-sort-order:";
5
+ // One shared empty selection, so an unfiltered render keeps its identity.
6
+ const NO_EVENT_TYPES = [];
7
+ export const getSortOrderStorageKey = (storageKey) => {
8
+ return `${SORT_ORDER_STORAGE_KEY_PREFIX}${storageKey}`;
9
+ };
10
+ /*
11
+ * Storage can be missing, blocked or hold anything, so every read falls back
12
+ * to the default order.
13
+ */
14
+ const readStoredSortOrder = (storageKey) => {
15
+ if (!storageKey) {
16
+ return DEFAULT_FEED_SORT_ORDER;
17
+ }
18
+ try {
19
+ const storedValue = LocalStorage.getItem(getSortOrderStorageKey(storageKey));
20
+ return isFeedSortOrder(storedValue) ? storedValue : DEFAULT_FEED_SORT_ORDER;
21
+ }
22
+ catch (_a) {
23
+ return DEFAULT_FEED_SORT_ORDER;
24
+ }
25
+ };
26
+ const writeStoredSortOrder = (storageKey, sortOrder) => {
27
+ if (!storageKey) {
28
+ return;
29
+ }
30
+ try {
31
+ if (sortOrder === DEFAULT_FEED_SORT_ORDER) {
32
+ LocalStorage.removeItem(getSortOrderStorageKey(storageKey));
33
+ }
34
+ else {
35
+ LocalStorage.setItem(getSortOrderStorageKey(storageKey), sortOrder);
36
+ }
37
+ }
38
+ catch (_a) {
39
+ // A preference that cannot be saved still applies to this page.
40
+ }
41
+ };
42
+ const useFeedOptions = (props) => {
43
+ /*
44
+ * Callers pass Object.values(SomeEnum), a new array on every render, so the
45
+ * list is keyed by its contents.
46
+ */
47
+ const eventTypesKey = props.eventTypes.join("\u0000");
48
+ const knownEventTypes = useMemo(() => {
49
+ return props.eventTypes;
50
+ }, [eventTypesKey]);
51
+ const [sortOrder, setSortOrder] = useState(() => {
52
+ return readStoredSortOrder(props.storageKey);
53
+ });
54
+ /*
55
+ * The selection remembers which resource it was made on. It is read through
56
+ * that, during render rather than in an effect, so the first render for a
57
+ * new resource is already unfiltered and never asks the API for the old
58
+ * resource's filter. The stale selection is also dropped (React's "adjust
59
+ * state when a prop changes" pattern), so going back to the first resource
60
+ * does not bring its old filter back either.
61
+ */
62
+ const [selection, setSelection] = useState(() => {
63
+ return {
64
+ resetKey: props.resetKey,
65
+ eventTypes: [],
66
+ };
67
+ });
68
+ const isSelectionForThisResource = selection.resetKey === props.resetKey;
69
+ if (!isSelectionForThisResource) {
70
+ setSelection({
71
+ resetKey: props.resetKey,
72
+ eventTypes: NO_EVENT_TYPES,
73
+ });
74
+ }
75
+ const selectedEventTypes = isSelectionForThisResource
76
+ ? selection.eventTypes
77
+ : NO_EVENT_TYPES;
78
+ const options = useMemo(() => {
79
+ return {
80
+ sortOrder,
81
+ eventTypes: sanitizeFeedEventTypes({
82
+ selectedEventTypes,
83
+ knownEventTypes,
84
+ }),
85
+ };
86
+ }, [sortOrder, selectedEventTypes, knownEventTypes]);
87
+ const eventTypeOptions = useMemo(() => {
88
+ return getFeedEventTypeOptions({
89
+ eventTypes: knownEventTypes,
90
+ getEventTypeLabel: props.getEventTypeLabel,
91
+ getEventTypeIcon: props.getEventTypeIcon,
92
+ });
93
+ }, [knownEventTypes, props.getEventTypeLabel, props.getEventTypeIcon]);
94
+ const setOptions = useCallback((nextOptions) => {
95
+ const nextSortOrder = isFeedSortOrder(nextOptions.sortOrder)
96
+ ? nextOptions.sortOrder
97
+ : DEFAULT_FEED_SORT_ORDER;
98
+ setSortOrder(nextSortOrder);
99
+ setSelection({
100
+ resetKey: props.resetKey,
101
+ eventTypes: sanitizeFeedEventTypes({
102
+ selectedEventTypes: nextOptions.eventTypes,
103
+ knownEventTypes,
104
+ }),
105
+ });
106
+ }, [knownEventTypes, props.resetKey]);
107
+ /*
108
+ * The stored order follows the committed state, not each setOptions call:
109
+ * two changes batched into one render would otherwise leave storage holding
110
+ * the first while the page shows the second. The first run is the value
111
+ * just read from storage, so there is nothing to write.
112
+ */
113
+ const hasCommittedSortOrderRef = useRef(false);
114
+ useEffect(() => {
115
+ if (!hasCommittedSortOrderRef.current) {
116
+ hasCommittedSortOrderRef.current = true;
117
+ return;
118
+ }
119
+ writeStoredSortOrder(props.storageKey, sortOrder);
120
+ }, [sortOrder]);
121
+ return {
122
+ options,
123
+ optionsKey: getFeedOptionsKey(options),
124
+ eventTypeOptions,
125
+ isFiltered: isFeedFiltered(options),
126
+ setOptions,
127
+ };
128
+ };
129
+ export default useFeedOptions;
130
+ //# sourceMappingURL=useFeedOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFeedOptions.js","sourceRoot":"","sources":["../../../../../UI/Components/Feed/useFeedOptions.ts"],"names":[],"mappings":"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"}
@@ -338,7 +338,7 @@ const Icon = ({ size = SizeProp.Regular, icon, className, color, thick, onClick,
338
338
  return getSvgWrapper(React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5" }));
339
339
  }
340
340
  else if (icon === IconProp.BarsArrowUp) {
341
- return getSvgWrapper(React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4.5h14.25M3 9h9.75M3 13.5h9.75m4.5-4.5v12m0 0l-3.75-3.75M17.25 21L21 17.25" }));
341
+ return getSvgWrapper(React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4.5h14.25M3 9h9.75M3 13.5h5.25m5.25-.75L17.25 9m0 0L21 12.75M17.25 9v12" }));
342
342
  }
343
343
  else if (icon === IconProp.CheckCircle) {
344
344
  return getSvgWrapper(React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }));