@oneuptime/common 11.7.0 ā 11.7.2
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/DashboardDomain.ts +1 -0
- package/Models/DatabaseModels/Incident.ts +2 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/Monitor.ts +1 -0
- package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -0
- package/Models/DatabaseModels/NetworkSite.ts +1 -0
- package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +1 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +1 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +2 -0
- package/Models/DatabaseModels/Probe.ts +13 -13
- package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -0
- package/Models/DatabaseModels/StatusPage.ts +1 -0
- package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
- package/Models/DatabaseModels/StatusPageDomain.ts +1 -0
- package/Models/DatabaseModels/WorkspaceNotificationSummary.ts +1 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +11 -0
- package/Server/API/BaseAPI.ts +17 -1
- package/Server/API/CommonAPI.ts +32 -0
- package/Server/API/MicrosoftTeamsAPI.ts +99 -2
- package/Server/API/ProbeAPI.ts +2 -0
- package/Server/API/SlackAPI.ts +62 -0
- package/Server/API/StatusPageAPI.ts +157 -192
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.ts +89 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.ts +61 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.ts +280 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/DatabaseService.ts +11 -3
- package/Server/Services/MonitorGroupService.ts +145 -0
- package/Server/Services/MonitorService.ts +231 -30
- package/Server/Services/ProbeService.ts +319 -16
- package/Server/Services/StatusPageService.ts +72 -42
- package/Server/Services/WorkspaceNotificationRuleService.ts +232 -2
- package/Server/Utils/Database/PostgresErrorTranslator.ts +131 -0
- package/Server/Utils/Monitor/MonitorResource.ts +88 -35
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +21 -1
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +158 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +706 -6
- package/Tests/Models/DatabaseModels/ProbeColumnAccessControl.test.ts +103 -0
- package/Tests/Server/API/BaseAPIUpdateNoOp.test.ts +135 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +317 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +228 -0
- package/Tests/Server/API/ProbeAPI.test.ts +6 -0
- package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +167 -0
- package/Tests/Server/Services/AddHotQueryIndexesMigration.test.ts +255 -0
- package/Tests/Server/Services/AddHotQueryIndexesSecondPassMigration.test.ts +258 -0
- package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +1 -1
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +121 -0
- package/Tests/Server/Services/HeartbeatWriteFastPathSafety.test.ts +200 -0
- package/Tests/Server/Services/HookFreeWriteSafetySecondPass.test.ts +181 -0
- package/Tests/Server/Services/MonitorGroupServiceBatchedStatuses.test.ts +513 -0
- package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +492 -0
- package/Tests/Server/Services/MonitorServiceProbeSelection.test.ts +401 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +453 -0
- package/Tests/Server/Services/ProbeAuthKeyCacheAndHeartbeat.test.ts +679 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +3 -3
- package/Tests/Server/Services/StatusPageDomainResolutionCache.test.ts +245 -0
- package/Tests/Server/Services/StatusPageOverviewTimelineWindow.test.ts +283 -0
- package/Tests/Server/Services/StatusPageServiceMcp.test.ts +17 -1
- package/Tests/Server/Services/StatusPageServiceMonitorGroupBatching.test.ts +331 -0
- package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +12 -12
- package/Tests/Server/Services/WorkspaceNotificationRuleChats.test.ts +1390 -0
- package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +4 -4
- package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +1 -3
- package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +1 -3
- package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +1 -1
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +5 -5
- package/Tests/Server/Utils/Alert/AlertPrivacyFilter.test.ts +187 -0
- package/Tests/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.test.ts +170 -0
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +125 -0
- package/Tests/Server/Utils/Incident/IncidentPrivacyFilter.test.ts +264 -0
- package/Tests/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.test.ts +175 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +181 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +2 -2
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +341 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +2175 -0
- package/Tests/Server/Utils/Workspace/SlackChannelsList.test.ts +585 -0
- package/Tests/Types/Billing/MeteredPlan.test.ts +46 -0
- package/Tests/Types/DateUserTimezone.test.ts +205 -0
- package/Tests/Types/DateUserTimezoneOverridesBrowser.test.ts +73 -0
- package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +219 -1
- package/Tests/UI/Components/BulkUpdateForm.test.tsx +174 -0
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +315 -0
- package/Tests/UI/Components/ModelDetailSelect.test.tsx +229 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1258 -0
- package/Tests/UI/Components/ModelTableExportFromColumns.test.ts +153 -0
- package/Tests/UI/Components/MonacoLoader.test.ts +67 -0
- package/Tests/UI/Components/MonacoRuntime.test.ts +121 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +212 -3
- package/Tests/UI/Components/TimePicker/TimePicker.test.tsx +11 -0
- package/Tests/UI/Utils/Project.test.ts +809 -0
- package/Tests/UI/Utils/TableColumnsToCsv.test.ts +360 -0
- package/Tests/Utils/Alerts/AlertMetricType.test.ts +143 -0
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +219 -0
- package/Tests/Utils/Incident/IncidentMetricType.test.ts +174 -0
- package/Tests/Utils/Monitor/MonitorProbeSelectionUtil.test.ts +145 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +263 -0
- package/Types/Date.ts +119 -50
- package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +4 -0
- package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +25 -10
- package/Types/Workspace/WorkspaceMessagePayload.ts +1 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +63 -8
- package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
- package/UI/Components/CodeEditor/MonacoLoader.ts +36 -0
- package/UI/Components/Forms/Fields/FormField.tsx +13 -3
- package/UI/Components/Forms/ModelForm.tsx +41 -18
- package/UI/Components/Input/Input.tsx +6 -1
- package/UI/Components/ModelDetail/CardModelDetail.tsx +23 -1
- package/UI/Components/ModelDetail/ModelDetail.tsx +46 -1
- package/UI/Components/ModelTable/BaseModelTable.tsx +300 -30
- package/UI/Components/ModelTable/Column.ts +12 -0
- package/UI/Components/ModelTable/ExportFromColumns.ts +57 -0
- package/UI/Components/Navbar/NavBar.tsx +66 -1
- package/UI/Components/Table/Table.tsx +52 -13
- package/UI/Components/Table/Types/Column.ts +18 -0
- package/UI/Components/TimePicker/TimePicker.tsx +8 -4
- package/UI/Utils/Project.ts +214 -18
- package/UI/Utils/TableColumnsToCsv.ts +86 -6
- package/UI/Utils/User.ts +19 -0
- package/UI/esbuild-config.js +34 -0
- package/Utils/Monitor/MonitorProbeSelectionUtil.ts +72 -0
- package/build/dist/Models/DatabaseModels/DashboardDomain.js +1 -0
- package/build/dist/Models/DatabaseModels/DashboardDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +2 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +1 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSite.js +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +2 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Probe.js +13 -13
- package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js +1 -0
- package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +12 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +21 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +72 -2
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProbeAPI.js +2 -0
- package/build/dist/Server/API/ProbeAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +44 -0
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +98 -152
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js +254 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +10 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/MonitorGroupService.js +118 -0
- package/build/dist/Server/Services/MonitorGroupService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +198 -24
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +238 -9
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +46 -39
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +178 -3
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +80 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +67 -29
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +31 -14
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +117 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +549 -7
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Date.js +106 -35
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +17 -7
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +37 -11
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +2 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +34 -0
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +1 -0
- package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -3
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +37 -17
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +6 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +22 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js +31 -1
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +234 -21
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ExportFromColumns.js +30 -0
- package/build/dist/UI/Components/ModelTable/ExportFromColumns.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +39 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +31 -11
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/TimePicker/TimePicker.js +4 -4
- package/build/dist/UI/Components/TimePicker/TimePicker.js.map +1 -1
- package/build/dist/UI/Utils/Project.js +161 -15
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/UI/Utils/TableColumnsToCsv.js +67 -6
- package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -1
- package/build/dist/UI/Utils/User.js +19 -0
- package/build/dist/UI/Utils/User.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js +52 -0
- package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js.map +1 -0
- package/package.json +4 -3
- package/Server/Infrastructure/Postgres/SchemaMigrations/1773414578773-MigrationName.ts +0 -79
- package/Server/Infrastructure/Postgres/SchemaMigrations/1773500000000-MigrationName.ts +0 -41
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.ts +0 -17
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773414578773-MigrationName.js +0 -34
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773414578773-MigrationName.js.map +0 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773500000000-MigrationName.js +0 -22
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773500000000-MigrationName.js.map +0 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js +0 -12
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js.map +0 -1
|
@@ -15,6 +15,24 @@ export default interface Column<T extends GenericObject> {
|
|
|
15
15
|
alignItem?: AlignItem | undefined;
|
|
16
16
|
key?: keyof T | null; //can be null because actions column does not have a key.
|
|
17
17
|
hideOnMobile?: boolean | undefined; // Hide column on mobile devices
|
|
18
|
+
/*
|
|
19
|
+
* Every field that backs this cell, in declaration order. A ModelTable
|
|
20
|
+
* column may declare more than one - e.g. the alert "Affected Resources"
|
|
21
|
+
* cell spans hosts / kubernetesClusters / dockerHosts / podmanHosts /
|
|
22
|
+
* services - while `key` only ever holds the first one, because that is the
|
|
23
|
+
* one used for sorting and for the default renderer. CSV export reads all
|
|
24
|
+
* of them so it does not silently drop the rest. Defaults to [key].
|
|
25
|
+
*/
|
|
26
|
+
exportKeys?: Array<string> | undefined;
|
|
27
|
+
/*
|
|
28
|
+
* Exact text for this column's CSV cell, overriding the value read off the
|
|
29
|
+
* row. Use it when the rendered cell is built from something the row does
|
|
30
|
+
* not carry under the column's own field (data fetched alongside the table,
|
|
31
|
+
* a computed summary, several fields combined into one phrase).
|
|
32
|
+
*/
|
|
33
|
+
getExportValue?: ((item: T) => string) | undefined;
|
|
34
|
+
// Leave this column out of the CSV export entirely.
|
|
35
|
+
disableCsvExport?: boolean | undefined;
|
|
18
36
|
getElement?:
|
|
19
37
|
| ((item: T, onBeforeFetchData?: T | undefined) => ReactElement)
|
|
20
38
|
| undefined;
|
|
@@ -81,8 +81,12 @@ const TimePicker: FunctionComponent<ComponentProps> = (
|
|
|
81
81
|
return toDate(props.value) || OneUptimeDate.getCurrentDate();
|
|
82
82
|
}, [props.value]);
|
|
83
83
|
|
|
84
|
-
const [hours24, setHours24] = useState<number>(
|
|
85
|
-
|
|
84
|
+
const [hours24, setHours24] = useState<number>(
|
|
85
|
+
OneUptimeDate.getLocalHours(initialDate),
|
|
86
|
+
);
|
|
87
|
+
const [minutes, setMinutes] = useState<number>(
|
|
88
|
+
OneUptimeDate.getLocalMinutes(initialDate),
|
|
89
|
+
);
|
|
86
90
|
|
|
87
91
|
const hoursInputRef: React.MutableRefObject<HTMLInputElement | null> =
|
|
88
92
|
useRef<HTMLInputElement | null>(null);
|
|
@@ -99,8 +103,8 @@ const TimePicker: FunctionComponent<ComponentProps> = (
|
|
|
99
103
|
if (!d) {
|
|
100
104
|
return;
|
|
101
105
|
}
|
|
102
|
-
setHours24(
|
|
103
|
-
setMinutes(
|
|
106
|
+
setHours24(OneUptimeDate.getLocalHours(d));
|
|
107
|
+
setMinutes(OneUptimeDate.getLocalMinutes(d));
|
|
104
108
|
}, [props.value]);
|
|
105
109
|
|
|
106
110
|
const emitChange: (h24: number, m: number) => void = (
|
package/UI/Utils/Project.ts
CHANGED
|
@@ -4,7 +4,7 @@ import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBas
|
|
|
4
4
|
import SubscriptionPlan, {
|
|
5
5
|
PlanType,
|
|
6
6
|
} from "../../Types/Billing/SubscriptionPlan";
|
|
7
|
-
import { JSONObject } from "../../Types/JSON";
|
|
7
|
+
import { JSONObject, JSONValue } from "../../Types/JSON";
|
|
8
8
|
import ObjectID from "../../Types/ObjectID";
|
|
9
9
|
import Project from "../../Models/DatabaseModels/Project";
|
|
10
10
|
import SubscriptionStatus, {
|
|
@@ -14,29 +14,193 @@ import Navigation from "./Navigation";
|
|
|
14
14
|
import SessionStorage from "./SessionStorage";
|
|
15
15
|
import Telemetry from "./Telemetry/Telemetry";
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Session storage key that pins a browser tab to the project it is showing.
|
|
19
|
+
* Session storage (and not local storage) so two tabs can show two different
|
|
20
|
+
* projects at the same time.
|
|
21
|
+
*/
|
|
22
|
+
export const CURRENT_PROJECT_ID_STORAGE_KEY: string = "current_project_id";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Local storage key that remembers the last project the user opened on this
|
|
26
|
+
* browser. Unlike {@link CURRENT_PROJECT_ID_STORAGE_KEY} this survives closing
|
|
27
|
+
* the tab, which is what makes the dashboard reopen on the project the user
|
|
28
|
+
* left off on instead of always falling back to the first project.
|
|
29
|
+
*/
|
|
30
|
+
export const LAST_ACCESSED_PROJECT_ID_STORAGE_KEY: string =
|
|
31
|
+
"last_accessed_project_id";
|
|
32
|
+
|
|
17
33
|
export default class ProjectUtil {
|
|
34
|
+
/**
|
|
35
|
+
* The project the user is currently looking at, resolved in priority order:
|
|
36
|
+
*
|
|
37
|
+
* 1. `/dashboard/:projectId/...` in the URL - the page the user actually
|
|
38
|
+
* opened, so a deep link always wins over anything we have cached.
|
|
39
|
+
* 2. `current_project_id` in session storage - keeps this tab on the project
|
|
40
|
+
* it was already showing while the user moves around routes that do not
|
|
41
|
+
* carry a project id (e.g. `/dashboard`).
|
|
42
|
+
* 3. `last_accessed_project_id` in local storage - the project this user last
|
|
43
|
+
* opened on this browser, so closing the tab and coming back to
|
|
44
|
+
* `/dashboard` reopens that project rather than the first one.
|
|
45
|
+
*/
|
|
18
46
|
public static getCurrentProjectId(): ObjectID | null {
|
|
19
|
-
|
|
20
|
-
const currentProjectId: string | undefined = SessionStorage.getItem(
|
|
21
|
-
`current_project_id`,
|
|
22
|
-
) as string;
|
|
47
|
+
const projectIdInUrl: ObjectID | null = this.getProjectIdFromUrl();
|
|
23
48
|
|
|
24
|
-
if (
|
|
25
|
-
return
|
|
49
|
+
if (projectIdInUrl) {
|
|
50
|
+
return projectIdInUrl;
|
|
26
51
|
}
|
|
27
52
|
|
|
28
|
-
|
|
53
|
+
const projectIdInSession: ObjectID | null = this.toProjectId(
|
|
54
|
+
SessionStorage.getItem(CURRENT_PROJECT_ID_STORAGE_KEY),
|
|
55
|
+
);
|
|
29
56
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
57
|
+
if (projectIdInSession) {
|
|
58
|
+
return projectIdInSession;
|
|
32
59
|
}
|
|
33
60
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
return this.getLastAccessedProjectId();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The project id in the current URL, if the user is on a project scoped route
|
|
66
|
+
* like `/dashboard/:projectId/...`. Returns null on routes that carry no
|
|
67
|
+
* project id (`/dashboard`, `/dashboard/welcome`, ...).
|
|
68
|
+
*/
|
|
69
|
+
public static getProjectIdFromUrl(): ObjectID | null {
|
|
70
|
+
const projectId: string | undefined = Navigation.getFirstParam(2);
|
|
71
|
+
|
|
72
|
+
if (!projectId || projectId.includes(":projectId")) {
|
|
73
|
+
return null;
|
|
37
74
|
}
|
|
38
75
|
|
|
39
|
-
return
|
|
76
|
+
return this.toProjectId(projectId);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The last project this user opened on this browser. Persisted in local
|
|
81
|
+
* storage so it outlives the tab. It is cleared on logout (which clears all
|
|
82
|
+
* of local storage) and when the project is deleted.
|
|
83
|
+
*/
|
|
84
|
+
public static getLastAccessedProjectId(): ObjectID | null {
|
|
85
|
+
return this.toProjectId(
|
|
86
|
+
LocalStorage.getItem(LAST_ACCESSED_PROJECT_ID_STORAGE_KEY),
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public static setLastAccessedProjectId(
|
|
91
|
+
projectId: ObjectID | string | null | undefined,
|
|
92
|
+
): void {
|
|
93
|
+
const id: ObjectID | null = this.toProjectId(projectId);
|
|
94
|
+
|
|
95
|
+
if (!id) {
|
|
96
|
+
// Never persist junk - an unusable value would only shadow the fallbacks.
|
|
97
|
+
this.clearLastAccessedProjectId();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
LocalStorage.setItem(LAST_ACCESSED_PROJECT_ID_STORAGE_KEY, id.toString());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public static clearLastAccessedProjectId(): void {
|
|
105
|
+
LocalStorage.removeItem(LAST_ACCESSED_PROJECT_ID_STORAGE_KEY);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Picks the project the dashboard should load out of the projects the user
|
|
110
|
+
* has access to.
|
|
111
|
+
*
|
|
112
|
+
* Candidates are tried in order - current project (URL / this tab), then the
|
|
113
|
+
* last project opened on this browser, then the first project the user has
|
|
114
|
+
* access to. A candidate that is not in `projects` is skipped, because the
|
|
115
|
+
* user may have left, lost access to, or deleted it since.
|
|
116
|
+
*/
|
|
117
|
+
public static getProjectToSelect(data: {
|
|
118
|
+
projects: Array<Project>;
|
|
119
|
+
currentProjectId?: ObjectID | null | undefined;
|
|
120
|
+
lastAccessedProjectId?: ObjectID | null | undefined;
|
|
121
|
+
}): Project | null {
|
|
122
|
+
const projects: Array<Project> = this.getSelectableProjects(data.projects);
|
|
123
|
+
|
|
124
|
+
const candidateIds: Array<ObjectID | null | undefined> = [
|
|
125
|
+
data.currentProjectId,
|
|
126
|
+
data.lastAccessedProjectId,
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
for (const candidateId of candidateIds) {
|
|
130
|
+
if (!candidateId) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const project: Project | undefined = projects.find((project: Project) => {
|
|
135
|
+
return project._id?.toString() === candidateId.toString();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (project) {
|
|
139
|
+
return project;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return projects[0] || null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* {@link getProjectToSelect} with the candidates read off storage / the URL.
|
|
148
|
+
*/
|
|
149
|
+
public static getProjectToLoad(projects: Array<Project>): Project | null {
|
|
150
|
+
return this.getProjectToSelect({
|
|
151
|
+
projects: projects,
|
|
152
|
+
currentProjectId: this.getCurrentProjectId(),
|
|
153
|
+
lastAccessedProjectId: this.getLastAccessedProjectId(),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The project the dashboard should switch to now that the list of projects
|
|
159
|
+
* the user has access to has (re)loaded, or null when whatever is already
|
|
160
|
+
* selected should stand.
|
|
161
|
+
*
|
|
162
|
+
* A selection is left alone as long as the user still has access to it -
|
|
163
|
+
* otherwise a project the user just picked (or just created) would be
|
|
164
|
+
* overruled by whatever we happened to have remembered.
|
|
165
|
+
*/
|
|
166
|
+
public static getProjectToSelectOnProjectsLoaded(data: {
|
|
167
|
+
projects: Array<Project>;
|
|
168
|
+
selectedProject?: Project | null | undefined;
|
|
169
|
+
}): Project | null {
|
|
170
|
+
const projects: Array<Project> = this.getSelectableProjects(data.projects);
|
|
171
|
+
|
|
172
|
+
if (projects.length === 0) {
|
|
173
|
+
// Nothing to select yet - the list is still loading, or the user has no projects.
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const selectedProjectId: string | undefined =
|
|
178
|
+
data.selectedProject?._id?.toString();
|
|
179
|
+
|
|
180
|
+
const isSelectionStillAccessible: boolean = Boolean(
|
|
181
|
+
selectedProjectId &&
|
|
182
|
+
projects.some((project: Project) => {
|
|
183
|
+
return project._id?.toString() === selectedProjectId;
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
if (isSelectionStillAccessible) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return this.getProjectToLoad(projects);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The projects that can actually be opened - a project without an id cannot
|
|
196
|
+
* be navigated to (`/dashboard/undefined`), so it is never a candidate.
|
|
197
|
+
*/
|
|
198
|
+
private static getSelectableProjects(
|
|
199
|
+
projects: Array<Project> | null | undefined,
|
|
200
|
+
): Array<Project> {
|
|
201
|
+
return (projects || []).filter((project: Project) => {
|
|
202
|
+
return Boolean(project?._id);
|
|
203
|
+
});
|
|
40
204
|
}
|
|
41
205
|
|
|
42
206
|
public static setIsSubscriptionInactiveOrOverdue(data: {
|
|
@@ -91,12 +255,19 @@ export default class ProjectUtil {
|
|
|
91
255
|
public static getCurrentProject(): Project | null {
|
|
92
256
|
const currentProjectId: string | undefined =
|
|
93
257
|
this.getCurrentProjectId()?.toString();
|
|
94
|
-
|
|
258
|
+
|
|
259
|
+
if (!currentProjectId) {
|
|
95
260
|
return null;
|
|
96
261
|
}
|
|
262
|
+
|
|
97
263
|
const projectJson: JSONObject = LocalStorage.getItem(
|
|
98
264
|
`project_${currentProjectId}`,
|
|
99
265
|
) as JSONObject;
|
|
266
|
+
|
|
267
|
+
if (!projectJson) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
|
|
100
271
|
return BaseModel.fromJSON(projectJson, Project) as Project;
|
|
101
272
|
}
|
|
102
273
|
|
|
@@ -107,7 +278,10 @@ export default class ProjectUtil {
|
|
|
107
278
|
project = BaseModel.toJSON(project, Project);
|
|
108
279
|
}
|
|
109
280
|
LocalStorage.setItem(`project_${currentProjectId}`, project);
|
|
110
|
-
SessionStorage.setItem(
|
|
281
|
+
SessionStorage.setItem(CURRENT_PROJECT_ID_STORAGE_KEY, currentProjectId);
|
|
282
|
+
|
|
283
|
+
// Remember this project for the next time the user opens the dashboard.
|
|
284
|
+
this.setLastAccessedProjectId(currentProjectId);
|
|
111
285
|
|
|
112
286
|
// Keep RUM span context in sync with the project being viewed.
|
|
113
287
|
if (currentProjectId) {
|
|
@@ -118,8 +292,18 @@ export default class ProjectUtil {
|
|
|
118
292
|
public static clearCurrentProject(): void {
|
|
119
293
|
const currentProjectId: string | undefined =
|
|
120
294
|
this.getCurrentProjectId()?.toString();
|
|
121
|
-
|
|
122
|
-
|
|
295
|
+
|
|
296
|
+
if (currentProjectId) {
|
|
297
|
+
LocalStorage.removeItem(`project_${currentProjectId}`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
SessionStorage.removeItem(CURRENT_PROJECT_ID_STORAGE_KEY);
|
|
301
|
+
|
|
302
|
+
/*
|
|
303
|
+
* The project is gone (or the user is leaving it), so it must not be
|
|
304
|
+
* reopened the next time the dashboard loads.
|
|
305
|
+
*/
|
|
306
|
+
this.clearLastAccessedProjectId();
|
|
123
307
|
}
|
|
124
308
|
|
|
125
309
|
public static getCurrentPlan(): PlanType | null {
|
|
@@ -137,4 +321,16 @@ export default class ProjectUtil {
|
|
|
137
321
|
getAllEnvVars(),
|
|
138
322
|
);
|
|
139
323
|
}
|
|
324
|
+
|
|
325
|
+
private static toProjectId(
|
|
326
|
+
value: JSONValue | ObjectID | string | null | undefined,
|
|
327
|
+
): ObjectID | null {
|
|
328
|
+
const id: string | undefined = value?.toString();
|
|
329
|
+
|
|
330
|
+
if (id && ObjectID.isValidUUID(id)) {
|
|
331
|
+
return new ObjectID(id);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
140
336
|
}
|
|
@@ -262,9 +262,58 @@ export default class TableColumnsToCsv {
|
|
|
262
262
|
return null;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
/*
|
|
266
|
+
* The fields a column contributes to the export. A ModelTable column can
|
|
267
|
+
* declare several (a cell that renders hosts + clusters + services in one
|
|
268
|
+
* place), and BaseModelTable forwards all of them as exportKeys; `key`
|
|
269
|
+
* alone is only the first. Falls back to the single key for tables that
|
|
270
|
+
* build their Table columns by hand.
|
|
271
|
+
*/
|
|
272
|
+
public static getExportKeys<T extends GenericObject>(
|
|
273
|
+
column: Column<T>,
|
|
274
|
+
): Array<string> {
|
|
275
|
+
if (column.exportKeys && column.exportKeys.length > 0) {
|
|
276
|
+
return column.exportKeys;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (column.key === null || column.key === undefined) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return [String(column.key)];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/*
|
|
287
|
+
* A column that renders entirely through getElement still has to declare a
|
|
288
|
+
* field so the row gets fetched at all, and the convention for that is
|
|
289
|
+
* `field: { _id: true }` - the "Owners" column on alerts, incidents,
|
|
290
|
+
* monitors and friends. The id is plumbing, not the cell's value, so
|
|
291
|
+
* exporting it writes a raw UUID under a header like "Owners". Treat such a
|
|
292
|
+
* column as presentational and leave it out, the same way a column with no
|
|
293
|
+
* key at all is left out. A column that genuinely shows the id says so with
|
|
294
|
+
* FieldType.ObjectID, and one that wants its rendered content in the file
|
|
295
|
+
* says so with getExportValue.
|
|
296
|
+
*/
|
|
297
|
+
public static isPlaceholderIdColumn<T extends GenericObject>(
|
|
298
|
+
column: Column<T>,
|
|
299
|
+
): boolean {
|
|
300
|
+
if (!column.getElement) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (column.type === FieldType.ObjectID) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const keys: Array<string> = this.getExportKeys(column);
|
|
309
|
+
|
|
310
|
+
return keys.length === 1 && keys[0] === "_id";
|
|
311
|
+
}
|
|
312
|
+
|
|
265
313
|
/*
|
|
266
314
|
* Columns that can be exported: everything except the Actions column (which
|
|
267
|
-
* only holds buttons)
|
|
315
|
+
* only holds buttons), columns that opted out, columns without a data key
|
|
316
|
+
* (purely presentational), and placeholder id columns.
|
|
268
317
|
*/
|
|
269
318
|
public static getExportableColumns<T extends GenericObject>(
|
|
270
319
|
columns: Columns<T>,
|
|
@@ -274,7 +323,20 @@ export default class TableColumnsToCsv {
|
|
|
274
323
|
return false;
|
|
275
324
|
}
|
|
276
325
|
|
|
277
|
-
if (column.
|
|
326
|
+
if (column.disableCsvExport) {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// An explicit export value makes even a keyless column exportable.
|
|
331
|
+
if (column.getExportValue) {
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (this.getExportKeys(column).length === 0) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (this.isPlaceholderIdColumn(column)) {
|
|
278
340
|
return false;
|
|
279
341
|
}
|
|
280
342
|
|
|
@@ -286,13 +348,31 @@ export default class TableColumnsToCsv {
|
|
|
286
348
|
item: T,
|
|
287
349
|
column: Column<T>,
|
|
288
350
|
): string {
|
|
289
|
-
if (column.
|
|
290
|
-
return "";
|
|
351
|
+
if (column.getExportValue) {
|
|
352
|
+
return column.getExportValue(item) || "";
|
|
291
353
|
}
|
|
292
354
|
|
|
293
|
-
|
|
355
|
+
/*
|
|
356
|
+
* Every declared field goes into the one cell, joined the same way a
|
|
357
|
+
* multi-value field is, so a cell that renders several relations exports
|
|
358
|
+
* all of them. Blanks are dropped (only one of the relations is usually
|
|
359
|
+
* set) and repeats are collapsed (the same entity reachable through two
|
|
360
|
+
* of them should not be listed twice).
|
|
361
|
+
*/
|
|
362
|
+
const values: Array<string> = [];
|
|
363
|
+
|
|
364
|
+
for (const key of this.getExportKeys(column)) {
|
|
365
|
+
const formatted: string = this.formatValueForCsv(
|
|
366
|
+
this.getRawValueByPath(item, key),
|
|
367
|
+
column.type,
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
if (formatted.length > 0 && !values.includes(formatted)) {
|
|
371
|
+
values.push(formatted);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
294
374
|
|
|
295
|
-
return
|
|
375
|
+
return values.join("; ");
|
|
296
376
|
}
|
|
297
377
|
|
|
298
378
|
/*
|
package/UI/Utils/User.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { JSONObject, JSONValue } from "../../Types/JSON";
|
|
|
10
10
|
import Name from "../../Types/Name";
|
|
11
11
|
import ObjectID from "../../Types/ObjectID";
|
|
12
12
|
import Timezone from "../../Types/Timezone";
|
|
13
|
+
import OneUptimeDate from "../../Types/Date";
|
|
13
14
|
import API from "../Utils/API/API";
|
|
14
15
|
import Cookie from "./Cookie";
|
|
15
16
|
import CookieName from "../../Types/CookieName";
|
|
@@ -62,6 +63,22 @@ export default class UserUtil {
|
|
|
62
63
|
|
|
63
64
|
public static setSavedUserTimezone(timezone: Timezone): void {
|
|
64
65
|
LocalStorage.setItem("user_timezone", timezone);
|
|
66
|
+
OneUptimeDate.setUserTimezone(timezone);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Hand the timezone the user picked in User Settings to OneUptimeDate so
|
|
71
|
+
* every date the UI renders and every date the user types is resolved in
|
|
72
|
+
* that zone instead of whatever zone the browser reports. Call this once at
|
|
73
|
+
* app startup, before anything renders.
|
|
74
|
+
*/
|
|
75
|
+
public static initializeUserTimezone(): void {
|
|
76
|
+
try {
|
|
77
|
+
OneUptimeDate.setUserTimezone(this.getSavedUserTimezone() || null);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// A missing / unreadable local storage must not stop the app from booting.
|
|
80
|
+
Logger.error(err as Error);
|
|
81
|
+
}
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
public static getDismissedTimezonePrompt(): Timezone | null {
|
|
@@ -199,6 +216,8 @@ export default class UserUtil {
|
|
|
199
216
|
LocalStorage.clear();
|
|
200
217
|
SessionStorage.clear();
|
|
201
218
|
Cookie.clearAllCookies();
|
|
219
|
+
// The next user on this browser must not inherit this user's timezone.
|
|
220
|
+
OneUptimeDate.setUserTimezone(null);
|
|
202
221
|
|
|
203
222
|
API.post({
|
|
204
223
|
url: URL.fromString(IDENTITY_URL.toString()).addRoute("/logout"),
|
package/UI/esbuild-config.js
CHANGED
|
@@ -182,6 +182,25 @@ function createFileLoaderPlugin() {
|
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
// Copy Monaco's runtime next to the bundle so the editor loads from this
|
|
186
|
+
// install instead of cdn.jsdelivr.net, which is unreachable when self-hosted
|
|
187
|
+
// offline. Only min/vs is copied - the rest of the package is sources and
|
|
188
|
+
// type definitions the browser never asks for.
|
|
189
|
+
//
|
|
190
|
+
// Every frontend gets a copy. Forms/Fields/FormField.tsx imports CodeEditor
|
|
191
|
+
// directly, so every service that renders a form pulls the editor into its
|
|
192
|
+
// bundle - there is no service to skip. Gating this on the built output only
|
|
193
|
+
// looked selective; it matched all five services and risked a silent offline
|
|
194
|
+
// 404 the moment a code field showed up somewhere unexpected.
|
|
195
|
+
function copyMonacoAssets(outdir) {
|
|
196
|
+
const source = path.join(resolvePackageRoot("monaco-editor"), "min", "vs");
|
|
197
|
+
const destination = path.resolve(path.dirname(outdir), "assets/monaco/vs");
|
|
198
|
+
|
|
199
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
200
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
201
|
+
fs.cpSync(source, destination, { recursive: true });
|
|
202
|
+
}
|
|
203
|
+
|
|
185
204
|
// Read environment variables from .env file
|
|
186
205
|
function readEnvFile(pathToFile) {
|
|
187
206
|
if (!fs.existsSync(pathToFile)) {
|
|
@@ -265,6 +284,11 @@ function createConfig(options) {
|
|
|
265
284
|
splitting: true,
|
|
266
285
|
publicPath,
|
|
267
286
|
define: {
|
|
287
|
+
// Monaco resolves its runtime against this at load time. import.meta is
|
|
288
|
+
// empty at the es2017 target, so the path has to come from the build.
|
|
289
|
+
"process.env.MONACO_ASSET_PATH": JSON.stringify(
|
|
290
|
+
`${publicPath.replace(/dist\/$/, "")}assets/monaco/vs`,
|
|
291
|
+
),
|
|
268
292
|
"process.env.NODE_ENV": JSON.stringify(
|
|
269
293
|
isDev ? "development" : "production",
|
|
270
294
|
),
|
|
@@ -319,6 +343,9 @@ async function build(config, serviceName) {
|
|
|
319
343
|
try {
|
|
320
344
|
const result = await esbuild.build(config);
|
|
321
345
|
|
|
346
|
+
copyMonacoAssets(config.outdir);
|
|
347
|
+
console.log(`š¦ Copied Monaco assets for ${serviceName}`);
|
|
348
|
+
|
|
322
349
|
if (isAnalyze && result.metafile) {
|
|
323
350
|
const analyzeText = await esbuild.analyzeMetafile(result.metafile);
|
|
324
351
|
console.log(`\nš Bundle analysis for ${serviceName}:`);
|
|
@@ -345,6 +372,13 @@ async function build(config, serviceName) {
|
|
|
345
372
|
async function watch(config, serviceName) {
|
|
346
373
|
try {
|
|
347
374
|
const context = await esbuild.context(config);
|
|
375
|
+
|
|
376
|
+
// The copy no longer reads the built output, so it can run before the
|
|
377
|
+
// first build instead of forcing an extra one just to have something to
|
|
378
|
+
// inspect. context.watch() does the initial build on its own.
|
|
379
|
+
copyMonacoAssets(config.outdir);
|
|
380
|
+
console.log(`š¦ Copied Monaco assets for ${serviceName}`);
|
|
381
|
+
|
|
348
382
|
await context.watch();
|
|
349
383
|
console.log(`š Watching ${serviceName} for changes...`);
|
|
350
384
|
} catch (error) {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Which probes a brand-new monitor starts out with.
|
|
3
|
+
*
|
|
4
|
+
* The server applies this same rule in
|
|
5
|
+
* MonitorService.addDefaultProbesToMonitor (as a database query rather than a
|
|
6
|
+
* filter over a list). The create form uses it to pre-select the probe picker,
|
|
7
|
+
* so what the user sees before pressing "Create Monitor" is what they would
|
|
8
|
+
* have got anyway - and can now change.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export interface ProbeSelectionCandidate {
|
|
12
|
+
id: string;
|
|
13
|
+
isGlobalProbe: boolean;
|
|
14
|
+
shouldAutoEnableProbeOnNewMonitors: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class MonitorProbeSelectionUtil {
|
|
18
|
+
/*
|
|
19
|
+
* A probe is auto-enabled on new monitors when it opts in with
|
|
20
|
+
* shouldAutoEnableProbeOnNewMonitors - except that global probes are skipped
|
|
21
|
+
* entirely for projects that turned off "add global probes by default".
|
|
22
|
+
*/
|
|
23
|
+
public static getDefaultSelectedProbeIds(data: {
|
|
24
|
+
probes: Array<ProbeSelectionCandidate>;
|
|
25
|
+
doNotAddGlobalProbesByDefaultOnNewMonitors?: boolean | undefined;
|
|
26
|
+
}): Array<string> {
|
|
27
|
+
const skipGlobalProbes: boolean =
|
|
28
|
+
data.doNotAddGlobalProbesByDefaultOnNewMonitors === true;
|
|
29
|
+
|
|
30
|
+
const selected: Array<string> = [];
|
|
31
|
+
|
|
32
|
+
for (const probe of data.probes || []) {
|
|
33
|
+
if (!probe || !probe.id) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!probe.shouldAutoEnableProbeOnNewMonitors) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (probe.isGlobalProbe && skipGlobalProbes) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
selected.push(probe.id);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return MonitorProbeSelectionUtil.dedupeProbeIds(selected);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* Probe ids reach the server as plain strings and the same probe can be
|
|
53
|
+
* offered by more than one source, so duplicates have to go: MonitorProbe
|
|
54
|
+
* has no unique index and MonitorProbeService rejects the second insert with
|
|
55
|
+
* "Probe is already added to this monitor."
|
|
56
|
+
*/
|
|
57
|
+
public static dedupeProbeIds(probeIds: Array<string>): Array<string> {
|
|
58
|
+
const seen: Set<string> = new Set<string>();
|
|
59
|
+
const deduped: Array<string> = [];
|
|
60
|
+
|
|
61
|
+
for (const probeId of probeIds || []) {
|
|
62
|
+
if (!probeId || seen.has(probeId)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
seen.add(probeId);
|
|
67
|
+
deduped.push(probeId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return deduped;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -351,6 +351,7 @@ __decorate([
|
|
|
351
351
|
description: "Full domain of your dashboard (like dashboard.acmeinc.com). This is autogenerated and is derived from subdomain and domain.",
|
|
352
352
|
example: "dashboard.acmeinc.com",
|
|
353
353
|
}),
|
|
354
|
+
Index(),
|
|
354
355
|
Column({
|
|
355
356
|
nullable: false,
|
|
356
357
|
type: ColumnType.ShortText,
|