@oneuptime/common 12.0.7 → 12.0.8
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.
- package/Models/DatabaseModels/TelemetryEntity.ts +45 -0
- package/Models/DatabaseModels/TelemetryEntityRelationship.ts +26 -0
- package/Models/DatabaseModels/WorkflowLog.ts +38 -0
- package/Server/API/UserAPI.ts +16 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786551733814-MigrationName.ts +41 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786559879134-AddWorkflowLogStepTrace.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MasterAdminAuthorization.ts +11 -6
- package/Server/Services/TelemetryEntityRelationshipService.ts +3 -0
- package/Server/Services/TelemetryEntityService.ts +114 -1
- package/Server/Types/Workflow/Components/API/Utils.ts +44 -1
- package/Server/Types/Workflow/TriggerCode.ts +12 -0
- package/Server/Types/Workflow/Workflow.ts +5 -0
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +689 -0
- package/Server/Utils/VM/VMAPI.ts +56 -8
- package/Tests/App/Dashboard/MonitorCriteriaAttributeFilter.test.tsx +574 -0
- package/Tests/Server/API/UserProjectsAPI.test.ts +478 -4
- package/Tests/Server/Services/TelemetryEntityManualCreate.test.ts +248 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentHeaders.test.ts +192 -0
- package/Tests/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.test.ts +152 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +322 -0
- package/Tests/Server/Utils/VM/VMAPISubstitution.test.ts +243 -0
- package/Tests/Types/SerializableObjectDictionaryImportCycle.test.ts +197 -0
- package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +140 -0
- package/Tests/Types/Workflow/StepTrace.test.ts +235 -0
- package/Tests/Types/Workflow/TemplateSyntax.test.ts +379 -0
- package/Tests/Types/Workflow/Templates.test.ts +403 -0
- package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +459 -0
- package/Tests/UI/Components/DictionaryAttributeFilterRow.test.tsx +477 -0
- package/Tests/UI/Components/Forms/AnchoredFieldPopupKeyboard.test.tsx +382 -0
- package/Tests/UI/Components/Forms/ColorPickerPicking.test.tsx +569 -0
- package/Tests/UI/Components/Forms/ValidationJSON.test.ts +241 -0
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +42 -0
- package/Tests/UI/Components/ModalPortalDismissal.test.tsx +90 -0
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +49 -7
- package/Tests/UI/Components/TimeRangePickerDropdown.test.tsx +325 -0
- package/Tests/UI/Components/Workflow/GraphLint.test.ts +821 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.test.ts +287 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditorServerContract.test.ts +185 -0
- package/Tests/UI/Components/Workflow/ModelSchema.test.ts +174 -0
- package/Tests/UI/Components/Workflow/RunStatusWatcher.test.ts +152 -0
- package/Tests/UI/Components/Workflow/Utils.test.ts +192 -0
- package/Tests/UI/Monitor/MonitorStepCriteriaView.test.tsx +432 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +514 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +240 -0
- package/Tests/Utils/Schema/AnalyticsModelSchema.test.ts +469 -0
- package/Tests/Utils/Schema/ModelSchema.test.ts +268 -0
- package/Tests/Utils/Telemetry/EntityKeyNonTelemetry.test.ts +193 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +31 -0
- package/Types/SerializableObjectDictionary.ts +133 -39
- package/Types/Telemetry/EntitySource.ts +40 -0
- package/Types/Telemetry/EntityType.ts +27 -0
- package/Types/Telemetry/EntityTypeGroups.ts +65 -0
- package/Types/Workflow/Component.ts +29 -0
- package/Types/Workflow/Components/API.ts +35 -0
- package/Types/Workflow/Components/BaseModel.ts +7 -3
- package/Types/Workflow/StepTrace.ts +181 -0
- package/Types/Workflow/TemplateSyntax.ts +499 -0
- package/Types/Workflow/Templates.ts +316 -0
- package/UI/Components/Date/CustomTimeRangeModal.tsx +278 -0
- package/UI/Components/Date/TimeRangePickerDropdown.tsx +250 -0
- package/UI/Components/Dictionary/Dictionary.tsx +23 -6
- package/UI/Components/Forms/Fields/ColorPicker.tsx +66 -10
- package/UI/Components/Forms/Fields/IconPicker.tsx +48 -10
- package/UI/Components/Forms/Types/Field.ts +7 -0
- package/UI/Components/Forms/Validation.ts +63 -1
- package/UI/Components/Input/Input.tsx +31 -3
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +11 -216
- package/UI/Components/Modal/Modal.tsx +37 -4
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +11 -210
- package/UI/Components/Workflow/ArgumentsForm.tsx +194 -7
- package/UI/Components/Workflow/Component.tsx +28 -26
- package/UI/Components/Workflow/ComponentSettingsModal.tsx +69 -8
- package/UI/Components/Workflow/GraphLint.ts +591 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +396 -0
- package/UI/Components/Workflow/ModelSchema.ts +196 -0
- package/UI/Components/Workflow/RunForm.tsx +41 -7
- package/UI/Components/Workflow/RunStatusWatcher.ts +122 -0
- package/UI/Components/Workflow/StepTraceViewer.tsx +186 -0
- package/UI/Components/Workflow/Utils.ts +93 -1
- package/UI/Components/Workflow/Workflow.tsx +77 -4
- package/UI/Types/LayeredDismissal.ts +31 -0
- package/UI/Types/UseAnchoredFieldPopup.ts +99 -0
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +533 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +45 -7
- package/Utils/Telemetry/EntityKey.ts +66 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntity.js +47 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js +27 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowLog.js +39 -0
- package/build/dist/Models/DatabaseModels/WorkflowLog.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +16 -1
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786551733814-MigrationName.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786551733814-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786559879134-AddWorkflowLogStepTrace.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786559879134-AddWorkflowLogStepTrace.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -6
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +3 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +91 -1
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js +28 -0
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
- package/build/dist/Server/Types/Workflow/TriggerCode.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +507 -0
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -0
- package/build/dist/Server/Utils/VM/VMAPI.js +51 -4
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Types/SerializableObjectDictionary.js +133 -39
- package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
- package/build/dist/Types/Telemetry/EntitySource.js +39 -0
- package/build/dist/Types/Telemetry/EntitySource.js.map +1 -0
- package/build/dist/Types/Telemetry/EntityType.js +27 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityTypeGroups.js +57 -0
- package/build/dist/Types/Telemetry/EntityTypeGroups.js.map +1 -0
- package/build/dist/Types/Workflow/Component.js +21 -0
- package/build/dist/Types/Workflow/Component.js.map +1 -1
- package/build/dist/Types/Workflow/Components/API.js +35 -0
- package/build/dist/Types/Workflow/Components/API.js.map +1 -1
- package/build/dist/Types/Workflow/Components/BaseModel.js +7 -3
- package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
- package/build/dist/Types/Workflow/StepTrace.js +104 -0
- package/build/dist/Types/Workflow/StepTrace.js.map +1 -0
- package/build/dist/Types/Workflow/TemplateSyntax.js +326 -0
- package/build/dist/Types/Workflow/TemplateSyntax.js.map +1 -0
- package/build/dist/Types/Workflow/Templates.js +218 -0
- package/build/dist/Types/Workflow/Templates.js.map +1 -0
- package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +126 -0
- package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -0
- package/build/dist/UI/Components/Date/TimeRangePickerDropdown.js +123 -0
- package/build/dist/UI/Components/Date/TimeRangePickerDropdown.js.map +1 -0
- package/build/dist/UI/Components/Dictionary/Dictionary.js +22 -6
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js +52 -13
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/IconPicker.js +28 -12
- package/build/dist/UI/Components/Forms/Fields/IconPicker.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +44 -0
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +12 -4
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +5 -108
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +31 -5
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +5 -105
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +140 -11
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/Component.js +20 -19
- package/build/dist/UI/Components/Workflow/Component.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js +31 -3
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/GraphLint.js +396 -0
- package/build/dist/UI/Components/Workflow/GraphLint.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +225 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelSchema.js +118 -0
- package/build/dist/UI/Components/Workflow/ModelSchema.js.map +1 -0
- package/build/dist/UI/Components/Workflow/RunForm.js +22 -6
- package/build/dist/UI/Components/Workflow/RunForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/RunStatusWatcher.js +76 -0
- package/build/dist/UI/Components/Workflow/RunStatusWatcher.js.map +1 -0
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js +76 -0
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -0
- package/build/dist/UI/Components/Workflow/Utils.js +73 -1
- package/build/dist/UI/Components/Workflow/Utils.js.map +1 -1
- package/build/dist/UI/Components/Workflow/Workflow.js +51 -6
- package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
- package/build/dist/UI/Types/LayeredDismissal.js +21 -0
- package/build/dist/UI/Types/LayeredDismissal.js.map +1 -0
- package/build/dist/UI/Types/UseAnchoredFieldPopup.js +74 -1
- package/build/dist/UI/Types/UseAnchoredFieldPopup.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +386 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +35 -6
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityKey.js +52 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/package.json +1 -1
|
@@ -25,7 +25,20 @@ export interface ComponentProps {
|
|
|
25
25
|
initialValue?: undefined | string | Date;
|
|
26
26
|
id?: string | undefined;
|
|
27
27
|
ariaLabelledby?: string | undefined;
|
|
28
|
+
// Set together by fields that open a popup, so the state is on the focusable element.
|
|
29
|
+
ariaHasPopup?: "dialog" | "listbox" | "menu" | "grid" | "tree" | undefined;
|
|
30
|
+
ariaExpanded?: boolean | undefined;
|
|
31
|
+
ariaControls?: string | undefined;
|
|
32
|
+
/*
|
|
33
|
+
* For fields that render their own error text - a picker whose message sits
|
|
34
|
+
* below the whole control rather than below this input.
|
|
35
|
+
*/
|
|
36
|
+
ariaDescribedby?: string | undefined;
|
|
37
|
+
ariaInvalid?: boolean | undefined;
|
|
28
38
|
onClick?: undefined | (() => void);
|
|
39
|
+
onKeyDown?:
|
|
40
|
+
| undefined
|
|
41
|
+
| ((event: React.KeyboardEvent<HTMLInputElement>) => void);
|
|
29
42
|
placeholder?: undefined | string;
|
|
30
43
|
className?: undefined | string;
|
|
31
44
|
onChange?: undefined | ((value: string) => void);
|
|
@@ -164,8 +177,13 @@ const Input: FunctionComponent<ComponentProps> = (
|
|
|
164
177
|
spellCheck={!props.disableSpellCheck}
|
|
165
178
|
autoComplete={props.autoComplete}
|
|
166
179
|
aria-labelledby={props.ariaLabelledby}
|
|
167
|
-
aria-
|
|
168
|
-
aria-
|
|
180
|
+
aria-haspopup={props.ariaHasPopup}
|
|
181
|
+
aria-expanded={props.ariaExpanded}
|
|
182
|
+
aria-controls={props.ariaControls}
|
|
183
|
+
aria-invalid={props.error || props.ariaInvalid ? "true" : undefined}
|
|
184
|
+
aria-describedby={
|
|
185
|
+
props.error ? "input-error-message" : props.ariaDescribedby
|
|
186
|
+
}
|
|
169
187
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
170
188
|
const value: string | Date = e.target.value;
|
|
171
189
|
|
|
@@ -194,8 +212,18 @@ const Input: FunctionComponent<ComponentProps> = (
|
|
|
194
212
|
}}
|
|
195
213
|
tabIndex={props.tabIndex}
|
|
196
214
|
onKeyDown={
|
|
197
|
-
props.onEnterPress
|
|
215
|
+
props.onEnterPress || props.onKeyDown
|
|
198
216
|
? (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
217
|
+
props.onKeyDown?.(event);
|
|
218
|
+
|
|
219
|
+
/*
|
|
220
|
+
* A handler that claimed the key - a picker opening its popup
|
|
221
|
+
* on Enter, say - has already decided what it means.
|
|
222
|
+
*/
|
|
223
|
+
if (event.defaultPrevented) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
199
227
|
if (event.key === "Enter") {
|
|
200
228
|
props.onEnterPress?.();
|
|
201
229
|
}
|
|
@@ -1,233 +1,28 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
FunctionComponent,
|
|
3
|
-
ReactElement,
|
|
4
|
-
useState,
|
|
5
|
-
useRef,
|
|
6
|
-
useEffect,
|
|
7
|
-
useCallback,
|
|
8
|
-
} from "react";
|
|
9
|
-
import Icon from "../../Icon/Icon";
|
|
10
|
-
import IconProp from "../../../../Types/Icon/IconProp";
|
|
1
|
+
import React, { FunctionComponent, ReactElement } from "react";
|
|
11
2
|
import RangeStartAndEndDateTime from "../../../../Types/Time/RangeStartAndEndDateTime";
|
|
12
|
-
import
|
|
13
|
-
import InBetween from "../../../../Types/BaseDatabase/InBetween";
|
|
14
|
-
import StartAndEndDate, {
|
|
15
|
-
StartAndEndDateType,
|
|
16
|
-
} from "../../Date/StartAndEndDate";
|
|
17
|
-
import {
|
|
18
|
-
DropdownHorizontalAlignment,
|
|
19
|
-
getDropdownAlignmentClassName,
|
|
20
|
-
useDropdownHorizontalAlignment,
|
|
21
|
-
} from "../../../Utils/DropdownAlignment";
|
|
3
|
+
import TimeRangePickerDropdown from "../../Date/TimeRangePickerDropdown";
|
|
22
4
|
|
|
23
5
|
export interface LogTimeRangePickerProps {
|
|
24
6
|
value: RangeStartAndEndDateTime;
|
|
25
7
|
onChange: (value: RangeStartAndEndDateTime) => void;
|
|
26
8
|
}
|
|
27
9
|
|
|
28
|
-
// Matches the Tailwind `w-72` on the dropdown
|
|
10
|
+
// Matches the Tailwind `w-72` on the rendered dropdown (18rem).
|
|
29
11
|
export const LOG_TIME_RANGE_DROPDOWN_WIDTH_IN_PX: number = 288;
|
|
30
12
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{ range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
|
|
34
|
-
{ range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
|
|
35
|
-
{ range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
|
|
36
|
-
{ range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
|
|
37
|
-
{ range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
|
|
38
|
-
{ range: TimeRange.PAST_THREE_HOURS, label: "Past 3 Hours" },
|
|
39
|
-
{ range: TimeRange.PAST_ONE_DAY, label: "Past 1 Day" },
|
|
40
|
-
{ range: TimeRange.PAST_TWO_DAYS, label: "Past 2 Days" },
|
|
41
|
-
{ range: TimeRange.PAST_ONE_WEEK, label: "Past 1 Week" },
|
|
42
|
-
{ range: TimeRange.PAST_TWO_WEEKS, label: "Past 2 Weeks" },
|
|
43
|
-
{ range: TimeRange.PAST_ONE_MONTH, label: "Past 1 Month" },
|
|
44
|
-
{ range: TimeRange.PAST_THREE_MONTHS, label: "Past 3 Months" },
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
function formatDateShort(date: Date): string {
|
|
48
|
-
const month: string = date.toLocaleString("en-US", { month: "short" });
|
|
49
|
-
const day: number = date.getDate();
|
|
50
|
-
const hours: string = date.getHours().toString().padStart(2, "0");
|
|
51
|
-
const minutes: string = date.getMinutes().toString().padStart(2, "0");
|
|
52
|
-
return `${month} ${day}, ${hours}:${minutes}`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function getButtonLabel(value: RangeStartAndEndDateTime): string {
|
|
56
|
-
if (value.range === TimeRange.CUSTOM && value.startAndEndDate) {
|
|
57
|
-
const start: string = formatDateShort(value.startAndEndDate.startValue);
|
|
58
|
-
const end: string = formatDateShort(value.startAndEndDate.endValue);
|
|
59
|
-
return `${start} – ${end}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const preset: { range: TimeRange; label: string } | undefined =
|
|
63
|
-
PRESET_OPTIONS.find((opt: { range: TimeRange; label: string }) => {
|
|
64
|
-
return opt.range === value.range;
|
|
65
|
-
});
|
|
66
|
-
return preset ? preset.label : value.range;
|
|
67
|
-
}
|
|
13
|
+
export const LOG_TIME_RANGE_PICKER_TEST_ID_PREFIX: string =
|
|
14
|
+
"log-time-range-picker";
|
|
68
15
|
|
|
69
16
|
const LogTimeRangePicker: FunctionComponent<LogTimeRangePickerProps> = (
|
|
70
17
|
props: LogTimeRangePickerProps,
|
|
71
18
|
): ReactElement => {
|
|
72
|
-
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
73
|
-
const [showCustom, setShowCustom] = useState<boolean>(
|
|
74
|
-
props.value.range === TimeRange.CUSTOM,
|
|
75
|
-
);
|
|
76
|
-
const containerRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
|
77
|
-
null!,
|
|
78
|
-
);
|
|
79
|
-
const buttonRef: React.RefObject<HTMLButtonElement> =
|
|
80
|
-
useRef<HTMLButtonElement>(null!);
|
|
81
|
-
const dropdownRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
|
82
|
-
null!,
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const alignment: DropdownHorizontalAlignment = useDropdownHorizontalAlignment(
|
|
86
|
-
{
|
|
87
|
-
isOpen: isOpen,
|
|
88
|
-
anchorRef: buttonRef,
|
|
89
|
-
dropdownRef: dropdownRef,
|
|
90
|
-
dropdownWidthInPx: LOG_TIME_RANGE_DROPDOWN_WIDTH_IN_PX,
|
|
91
|
-
},
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
// Close on click outside
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
const handleClickOutside: (e: MouseEvent) => void = (
|
|
97
|
-
e: MouseEvent,
|
|
98
|
-
): void => {
|
|
99
|
-
if (
|
|
100
|
-
containerRef.current &&
|
|
101
|
-
!containerRef.current.contains(e.target as Node)
|
|
102
|
-
) {
|
|
103
|
-
setIsOpen(false);
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
108
|
-
return () => {
|
|
109
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
110
|
-
};
|
|
111
|
-
}, []);
|
|
112
|
-
|
|
113
|
-
// Sync showCustom when value changes externally (e.g., histogram drag)
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
setShowCustom(props.value.range === TimeRange.CUSTOM);
|
|
116
|
-
}, [props.value.range]);
|
|
117
|
-
|
|
118
|
-
const handlePresetSelect: (range: TimeRange) => void = useCallback(
|
|
119
|
-
(range: TimeRange): void => {
|
|
120
|
-
props.onChange({ range });
|
|
121
|
-
setShowCustom(false);
|
|
122
|
-
setIsOpen(false);
|
|
123
|
-
},
|
|
124
|
-
[props],
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const handleCustomDateChange: (dateRange: InBetween<Date> | null) => void =
|
|
128
|
-
useCallback(
|
|
129
|
-
(dateRange: InBetween<Date> | null): void => {
|
|
130
|
-
if (dateRange) {
|
|
131
|
-
props.onChange({
|
|
132
|
-
range: TimeRange.CUSTOM,
|
|
133
|
-
startAndEndDate: dateRange,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
[props],
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
const buttonLabel: string = getButtonLabel(props.value);
|
|
141
|
-
|
|
142
19
|
return (
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
aria-expanded={isOpen}
|
|
150
|
-
className={`inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs font-medium shadow-sm transition-colors ${
|
|
151
|
-
isOpen
|
|
152
|
-
? "border-indigo-300 bg-indigo-50 text-indigo-700"
|
|
153
|
-
: "border-gray-200 bg-white text-gray-700 hover:border-gray-300 hover:bg-gray-50"
|
|
154
|
-
}`}
|
|
155
|
-
onClick={() => {
|
|
156
|
-
setIsOpen(!isOpen);
|
|
157
|
-
}}
|
|
158
|
-
>
|
|
159
|
-
<Icon icon={IconProp.Clock} className="h-3.5 w-3.5" />
|
|
160
|
-
<span>{buttonLabel}</span>
|
|
161
|
-
<Icon
|
|
162
|
-
icon={IconProp.ChevronDown}
|
|
163
|
-
className={`h-3 w-3 transition-transform ${isOpen ? "rotate-180" : ""}`}
|
|
164
|
-
/>
|
|
165
|
-
</button>
|
|
166
|
-
|
|
167
|
-
{isOpen && (
|
|
168
|
-
<div
|
|
169
|
-
ref={dropdownRef}
|
|
170
|
-
data-testid="log-time-range-picker-dropdown"
|
|
171
|
-
data-align={alignment}
|
|
172
|
-
className={`absolute ${getDropdownAlignmentClassName(
|
|
173
|
-
alignment,
|
|
174
|
-
)} top-full z-50 mt-1 w-72 max-w-[calc(100vw-1rem)] rounded-lg border border-gray-200 bg-white shadow-lg`}
|
|
175
|
-
>
|
|
176
|
-
{/* Preset options */}
|
|
177
|
-
<div className="max-h-64 overflow-y-auto py-1">
|
|
178
|
-
{PRESET_OPTIONS.map(
|
|
179
|
-
(option: { range: TimeRange; label: string }) => {
|
|
180
|
-
const isActive: boolean = props.value.range === option.range;
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
<button
|
|
184
|
-
key={option.range}
|
|
185
|
-
type="button"
|
|
186
|
-
className={`flex w-full items-center px-3 py-1.5 text-left text-sm transition-colors ${
|
|
187
|
-
isActive
|
|
188
|
-
? "bg-indigo-50 font-medium text-indigo-700"
|
|
189
|
-
: "text-gray-700 hover:bg-gray-50"
|
|
190
|
-
}`}
|
|
191
|
-
onClick={() => {
|
|
192
|
-
handlePresetSelect(option.range);
|
|
193
|
-
}}
|
|
194
|
-
>
|
|
195
|
-
{option.label}
|
|
196
|
-
</button>
|
|
197
|
-
);
|
|
198
|
-
},
|
|
199
|
-
)}
|
|
200
|
-
|
|
201
|
-
{/* Custom option */}
|
|
202
|
-
<button
|
|
203
|
-
type="button"
|
|
204
|
-
className={`flex w-full items-center px-3 py-1.5 text-left text-sm transition-colors ${
|
|
205
|
-
props.value.range === TimeRange.CUSTOM
|
|
206
|
-
? "bg-indigo-50 font-medium text-indigo-700"
|
|
207
|
-
: "text-gray-700 hover:bg-gray-50"
|
|
208
|
-
}`}
|
|
209
|
-
onClick={() => {
|
|
210
|
-
setShowCustom(true);
|
|
211
|
-
}}
|
|
212
|
-
>
|
|
213
|
-
Custom Range...
|
|
214
|
-
</button>
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
{/* Custom date inputs */}
|
|
218
|
-
{showCustom && (
|
|
219
|
-
<div className="border-t border-gray-100 p-3">
|
|
220
|
-
<StartAndEndDate
|
|
221
|
-
type={StartAndEndDateType.DateTime}
|
|
222
|
-
value={props.value.startAndEndDate}
|
|
223
|
-
hideTimeButtons={true}
|
|
224
|
-
onValueChanged={handleCustomDateChange}
|
|
225
|
-
/>
|
|
226
|
-
</div>
|
|
227
|
-
)}
|
|
228
|
-
</div>
|
|
229
|
-
)}
|
|
230
|
-
</div>
|
|
20
|
+
<TimeRangePickerDropdown
|
|
21
|
+
value={props.value}
|
|
22
|
+
onChange={props.onChange}
|
|
23
|
+
dataTestIdPrefix={LOG_TIME_RANGE_PICKER_TEST_ID_PREFIX}
|
|
24
|
+
dropdownWidthInPx={LOG_TIME_RANGE_DROPDOWN_WIDTH_IN_PX}
|
|
25
|
+
/>
|
|
231
26
|
);
|
|
232
27
|
};
|
|
233
28
|
|
|
@@ -7,6 +7,7 @@ import ModalFooter from "./ModalFooter";
|
|
|
7
7
|
import { VeryLightGray } from "../../../Types/BrandColors";
|
|
8
8
|
import IconProp from "../../../Types/Icon/IconProp";
|
|
9
9
|
import useTranslateValue from "../../Utils/Translation";
|
|
10
|
+
import { wasPressConsumedByAnAnchoredPopup } from "../../Types/LayeredDismissal";
|
|
10
11
|
import { lockPageScroll, unlockPageScroll } from "../../Utils/PageScrollLock";
|
|
11
12
|
import React, {
|
|
12
13
|
FunctionComponent,
|
|
@@ -78,6 +79,8 @@ const Modal: FunctionComponent<ComponentProps> = (
|
|
|
78
79
|
>(props.onClose);
|
|
79
80
|
const backdropPressStartedOutsideRef: React.MutableRefObject<boolean> =
|
|
80
81
|
useRef<boolean>(false);
|
|
82
|
+
const backdropPressEndedInsideRef: React.MutableRefObject<boolean> =
|
|
83
|
+
useRef<boolean>(false);
|
|
81
84
|
const titleId: string = useId();
|
|
82
85
|
const descriptionId: string = useId();
|
|
83
86
|
|
|
@@ -332,25 +335,54 @@ const Modal: FunctionComponent<ComponentProps> = (
|
|
|
332
335
|
const onBackdropMouseDown: BackdropPressHandler = (
|
|
333
336
|
event: React.MouseEvent<HTMLDivElement>,
|
|
334
337
|
): void => {
|
|
338
|
+
backdropPressEndedInsideRef.current = false;
|
|
339
|
+
|
|
340
|
+
/*
|
|
341
|
+
* A press that a portalled popup has already spent on closing itself is
|
|
342
|
+
* not a dismissal of this dialog. Without this, clicking the backdrop to
|
|
343
|
+
* put away an open colour picker closed the picker and the form behind it
|
|
344
|
+
* in one go.
|
|
345
|
+
*/
|
|
346
|
+
if (wasPressConsumedByAnAnchoredPopup(event.nativeEvent)) {
|
|
347
|
+
backdropPressStartedOutsideRef.current = false;
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
335
351
|
backdropPressStartedOutsideRef.current = isEventOutsideModal(event);
|
|
336
352
|
};
|
|
337
353
|
|
|
354
|
+
const onBackdropMouseUp: BackdropPressHandler = (
|
|
355
|
+
event: React.MouseEvent<HTMLDivElement>,
|
|
356
|
+
): void => {
|
|
357
|
+
/*
|
|
358
|
+
* The click that follows is reported against the nearest common ancestor
|
|
359
|
+
* of press and release — this very layer — so by the time it arrives the
|
|
360
|
+
* two ends are indistinguishable. Where the release landed has to be
|
|
361
|
+
* recorded while it is still known.
|
|
362
|
+
*/
|
|
363
|
+
backdropPressEndedInsideRef.current = !isEventOutsideModal(event);
|
|
364
|
+
};
|
|
365
|
+
|
|
338
366
|
const onBackdropClick: BackdropPressHandler = (
|
|
339
367
|
event: React.MouseEvent<HTMLDivElement>,
|
|
340
368
|
): void => {
|
|
341
369
|
/*
|
|
342
|
-
* Both ends of the click have to land on the backdrop.
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
370
|
+
* Both ends of the click have to land on the backdrop. A press that
|
|
371
|
+
* wandered across the edge of the panel in either direction is a drag —
|
|
372
|
+
* selecting text in the body and releasing outside, or pressing outside and
|
|
373
|
+
* releasing on the panel — and either used to be the fastest way to lose a
|
|
374
|
+
* filled-in form.
|
|
346
375
|
*/
|
|
347
376
|
const pressStartedOutside: boolean = backdropPressStartedOutsideRef.current;
|
|
377
|
+
const pressEndedInside: boolean = backdropPressEndedInsideRef.current;
|
|
348
378
|
backdropPressStartedOutsideRef.current = false;
|
|
379
|
+
backdropPressEndedInsideRef.current = false;
|
|
349
380
|
|
|
350
381
|
if (
|
|
351
382
|
props.disableCloseOnBackdropClick ||
|
|
352
383
|
!props.onClose ||
|
|
353
384
|
!pressStartedOutside ||
|
|
385
|
+
pressEndedInside ||
|
|
354
386
|
!isEventOutsideModal(event) ||
|
|
355
387
|
!isTopmostDialog()
|
|
356
388
|
) {
|
|
@@ -391,6 +423,7 @@ const Modal: FunctionComponent<ComponentProps> = (
|
|
|
391
423
|
<div
|
|
392
424
|
className="fixed inset-0 z-50 overflow-y-auto"
|
|
393
425
|
onMouseDown={onBackdropMouseDown}
|
|
426
|
+
onMouseUp={onBackdropMouseUp}
|
|
394
427
|
onClick={onBackdropClick}
|
|
395
428
|
>
|
|
396
429
|
<div className="flex min-h-full items-end justify-center p-0 text-center sm:items-center sm:p-6">
|
|
@@ -1,227 +1,28 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
FunctionComponent,
|
|
3
|
-
ReactElement,
|
|
4
|
-
useState,
|
|
5
|
-
useRef,
|
|
6
|
-
useEffect,
|
|
7
|
-
useCallback,
|
|
8
|
-
} from "react";
|
|
9
|
-
import Icon from "../../Icon/Icon";
|
|
10
|
-
import IconProp from "../../../../Types/Icon/IconProp";
|
|
1
|
+
import React, { FunctionComponent, ReactElement } from "react";
|
|
11
2
|
import RangeStartAndEndDateTime from "../../../../Types/Time/RangeStartAndEndDateTime";
|
|
12
|
-
import
|
|
13
|
-
import InBetween from "../../../../Types/BaseDatabase/InBetween";
|
|
14
|
-
import StartAndEndDate, {
|
|
15
|
-
StartAndEndDateType,
|
|
16
|
-
} from "../../Date/StartAndEndDate";
|
|
17
|
-
import {
|
|
18
|
-
DropdownHorizontalAlignment,
|
|
19
|
-
getDropdownAlignmentClassName,
|
|
20
|
-
useDropdownHorizontalAlignment,
|
|
21
|
-
} from "../../../Utils/DropdownAlignment";
|
|
3
|
+
import TimeRangePickerDropdown from "../../Date/TimeRangePickerDropdown";
|
|
22
4
|
|
|
23
5
|
export interface TelemetryTimeRangePickerProps {
|
|
24
6
|
value: RangeStartAndEndDateTime;
|
|
25
7
|
onChange: (value: RangeStartAndEndDateTime) => void;
|
|
26
8
|
}
|
|
27
9
|
|
|
28
|
-
// Matches the Tailwind `w-72` on the dropdown
|
|
10
|
+
// Matches the Tailwind `w-72` on the rendered dropdown (18rem).
|
|
29
11
|
export const TIME_RANGE_DROPDOWN_WIDTH_IN_PX: number = 288;
|
|
30
12
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
{ range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
|
|
34
|
-
{ range: TimeRange.PAST_THIRTY_MINS, label: "Past 30 Minutes" },
|
|
35
|
-
{ range: TimeRange.PAST_ONE_HOUR, label: "Past 1 Hour" },
|
|
36
|
-
{ range: TimeRange.PAST_TWO_HOURS, label: "Past 2 Hours" },
|
|
37
|
-
{ range: TimeRange.PAST_THREE_HOURS, label: "Past 3 Hours" },
|
|
38
|
-
{ range: TimeRange.PAST_ONE_DAY, label: "Past 1 Day" },
|
|
39
|
-
{ range: TimeRange.PAST_TWO_DAYS, label: "Past 2 Days" },
|
|
40
|
-
{ range: TimeRange.PAST_ONE_WEEK, label: "Past 1 Week" },
|
|
41
|
-
{ range: TimeRange.PAST_TWO_WEEKS, label: "Past 2 Weeks" },
|
|
42
|
-
{ range: TimeRange.PAST_ONE_MONTH, label: "Past 1 Month" },
|
|
43
|
-
{ range: TimeRange.PAST_THREE_MONTHS, label: "Past 3 Months" },
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
function formatDateShort(date: Date): string {
|
|
47
|
-
const month: string = date.toLocaleString("en-US", { month: "short" });
|
|
48
|
-
const day: number = date.getDate();
|
|
49
|
-
const hours: string = date.getHours().toString().padStart(2, "0");
|
|
50
|
-
const minutes: string = date.getMinutes().toString().padStart(2, "0");
|
|
51
|
-
return `${month} ${day}, ${hours}:${minutes}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function getButtonLabel(value: RangeStartAndEndDateTime): string {
|
|
55
|
-
if (value.range === TimeRange.CUSTOM && value.startAndEndDate) {
|
|
56
|
-
const start: string = formatDateShort(value.startAndEndDate.startValue);
|
|
57
|
-
const end: string = formatDateShort(value.startAndEndDate.endValue);
|
|
58
|
-
return `${start} – ${end}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const preset: { range: TimeRange; label: string } | undefined =
|
|
62
|
-
PRESET_OPTIONS.find((opt: { range: TimeRange; label: string }) => {
|
|
63
|
-
return opt.range === value.range;
|
|
64
|
-
});
|
|
65
|
-
return preset ? preset.label : value.range;
|
|
66
|
-
}
|
|
13
|
+
export const TELEMETRY_TIME_RANGE_PICKER_TEST_ID_PREFIX: string =
|
|
14
|
+
"telemetry-time-range-picker";
|
|
67
15
|
|
|
68
16
|
const TelemetryTimeRangePicker: FunctionComponent<
|
|
69
17
|
TelemetryTimeRangePickerProps
|
|
70
18
|
> = (props: TelemetryTimeRangePickerProps): ReactElement => {
|
|
71
|
-
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
72
|
-
const [showCustom, setShowCustom] = useState<boolean>(
|
|
73
|
-
props.value.range === TimeRange.CUSTOM,
|
|
74
|
-
);
|
|
75
|
-
const containerRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
|
76
|
-
null!,
|
|
77
|
-
);
|
|
78
|
-
const buttonRef: React.RefObject<HTMLButtonElement> =
|
|
79
|
-
useRef<HTMLButtonElement>(null!);
|
|
80
|
-
const dropdownRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
|
81
|
-
null!,
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
const alignment: DropdownHorizontalAlignment = useDropdownHorizontalAlignment(
|
|
85
|
-
{
|
|
86
|
-
isOpen: isOpen,
|
|
87
|
-
anchorRef: buttonRef,
|
|
88
|
-
dropdownRef: dropdownRef,
|
|
89
|
-
dropdownWidthInPx: TIME_RANGE_DROPDOWN_WIDTH_IN_PX,
|
|
90
|
-
},
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
const handleClickOutside: (e: MouseEvent) => void = (
|
|
95
|
-
e: MouseEvent,
|
|
96
|
-
): void => {
|
|
97
|
-
if (
|
|
98
|
-
containerRef.current &&
|
|
99
|
-
!containerRef.current.contains(e.target as Node)
|
|
100
|
-
) {
|
|
101
|
-
setIsOpen(false);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
106
|
-
return () => {
|
|
107
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
108
|
-
};
|
|
109
|
-
}, []);
|
|
110
|
-
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
setShowCustom(props.value.range === TimeRange.CUSTOM);
|
|
113
|
-
}, [props.value.range]);
|
|
114
|
-
|
|
115
|
-
const handlePresetSelect: (range: TimeRange) => void = useCallback(
|
|
116
|
-
(range: TimeRange): void => {
|
|
117
|
-
props.onChange({ range });
|
|
118
|
-
setShowCustom(false);
|
|
119
|
-
setIsOpen(false);
|
|
120
|
-
},
|
|
121
|
-
[props],
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const handleCustomDateChange: (dateRange: InBetween<Date> | null) => void =
|
|
125
|
-
useCallback(
|
|
126
|
-
(dateRange: InBetween<Date> | null): void => {
|
|
127
|
-
if (dateRange) {
|
|
128
|
-
props.onChange({
|
|
129
|
-
range: TimeRange.CUSTOM,
|
|
130
|
-
startAndEndDate: dateRange,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
[props],
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
const buttonLabel: string = getButtonLabel(props.value);
|
|
138
|
-
|
|
139
19
|
return (
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
aria-expanded={isOpen}
|
|
147
|
-
className={`inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs font-medium shadow-sm transition-colors ${
|
|
148
|
-
isOpen
|
|
149
|
-
? "border-indigo-300 bg-indigo-50 text-indigo-700"
|
|
150
|
-
: "border-gray-200 bg-white text-gray-700 hover:border-gray-300 hover:bg-gray-50"
|
|
151
|
-
}`}
|
|
152
|
-
onClick={() => {
|
|
153
|
-
setIsOpen(!isOpen);
|
|
154
|
-
}}
|
|
155
|
-
>
|
|
156
|
-
<Icon icon={IconProp.Clock} className="h-3.5 w-3.5" />
|
|
157
|
-
<span>{buttonLabel}</span>
|
|
158
|
-
<Icon
|
|
159
|
-
icon={IconProp.ChevronDown}
|
|
160
|
-
className={`h-3 w-3 transition-transform ${isOpen ? "rotate-180" : ""}`}
|
|
161
|
-
/>
|
|
162
|
-
</button>
|
|
163
|
-
|
|
164
|
-
{isOpen && (
|
|
165
|
-
<div
|
|
166
|
-
ref={dropdownRef}
|
|
167
|
-
data-testid="telemetry-time-range-picker-dropdown"
|
|
168
|
-
data-align={alignment}
|
|
169
|
-
className={`absolute ${getDropdownAlignmentClassName(
|
|
170
|
-
alignment,
|
|
171
|
-
)} top-full z-50 mt-1 w-72 max-w-[calc(100vw-1rem)] rounded-lg border border-gray-200 bg-white shadow-lg`}
|
|
172
|
-
>
|
|
173
|
-
<div className="max-h-64 overflow-y-auto py-1">
|
|
174
|
-
{PRESET_OPTIONS.map(
|
|
175
|
-
(option: { range: TimeRange; label: string }) => {
|
|
176
|
-
const isActive: boolean = props.value.range === option.range;
|
|
177
|
-
|
|
178
|
-
return (
|
|
179
|
-
<button
|
|
180
|
-
key={option.range}
|
|
181
|
-
type="button"
|
|
182
|
-
className={`flex w-full items-center px-3 py-1.5 text-left text-sm transition-colors ${
|
|
183
|
-
isActive
|
|
184
|
-
? "bg-indigo-50 font-medium text-indigo-700"
|
|
185
|
-
: "text-gray-700 hover:bg-gray-50"
|
|
186
|
-
}`}
|
|
187
|
-
onClick={() => {
|
|
188
|
-
handlePresetSelect(option.range);
|
|
189
|
-
}}
|
|
190
|
-
>
|
|
191
|
-
{option.label}
|
|
192
|
-
</button>
|
|
193
|
-
);
|
|
194
|
-
},
|
|
195
|
-
)}
|
|
196
|
-
|
|
197
|
-
<button
|
|
198
|
-
type="button"
|
|
199
|
-
className={`flex w-full items-center px-3 py-1.5 text-left text-sm transition-colors ${
|
|
200
|
-
props.value.range === TimeRange.CUSTOM
|
|
201
|
-
? "bg-indigo-50 font-medium text-indigo-700"
|
|
202
|
-
: "text-gray-700 hover:bg-gray-50"
|
|
203
|
-
}`}
|
|
204
|
-
onClick={() => {
|
|
205
|
-
setShowCustom(true);
|
|
206
|
-
}}
|
|
207
|
-
>
|
|
208
|
-
Custom Range...
|
|
209
|
-
</button>
|
|
210
|
-
</div>
|
|
211
|
-
|
|
212
|
-
{showCustom && (
|
|
213
|
-
<div className="border-t border-gray-100 p-3">
|
|
214
|
-
<StartAndEndDate
|
|
215
|
-
type={StartAndEndDateType.DateTime}
|
|
216
|
-
value={props.value.startAndEndDate}
|
|
217
|
-
hideTimeButtons={true}
|
|
218
|
-
onValueChanged={handleCustomDateChange}
|
|
219
|
-
/>
|
|
220
|
-
</div>
|
|
221
|
-
)}
|
|
222
|
-
</div>
|
|
223
|
-
)}
|
|
224
|
-
</div>
|
|
20
|
+
<TimeRangePickerDropdown
|
|
21
|
+
value={props.value}
|
|
22
|
+
onChange={props.onChange}
|
|
23
|
+
dataTestIdPrefix={TELEMETRY_TIME_RANGE_PICKER_TEST_ID_PREFIX}
|
|
24
|
+
dropdownWidthInPx={TIME_RANGE_DROPDOWN_WIDTH_IN_PX}
|
|
25
|
+
/>
|
|
225
26
|
);
|
|
226
27
|
};
|
|
227
28
|
|