mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Refactor code for improved readability and consistency
- Simplified arrow function syntax in MasterPassword.tsx and DashboardAPI.ts - Consolidated logger.debug statements in PublicDashboard.ts and DashboardDomainAPI.ts - Reformatted multi-line statements for better clarity in various files - Updated migration files for consistent naming conventions and formatting - Enhanced code structure in DashboardDomainService.ts and MonitorTelemetryMonitor.ts - Incremented version number to 10.0.40
This commit is contained in:
@@ -2075,10 +2075,7 @@ const BaseAPIFeatureSet: FeatureSet = {
|
||||
new StatusPageDomainAPI().getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new DashboardAPI().getRouter(),
|
||||
);
|
||||
app.use(`/${APP_NAME.toLocaleLowerCase()}`, new DashboardAPI().getRouter());
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
|
||||
@@ -22,16 +22,30 @@ const BlankCanvasElement: FunctionComponent<ComponentProps> = (
|
||||
if (!props.isEditMode && props.dashboardViewConfig.components.length === 0) {
|
||||
return (
|
||||
<div className="mx-3 mt-4 rounded-lg border border-dashed border-gray-200 bg-gray-50/50 text-center py-20 px-10">
|
||||
<div className="mx-auto w-14 h-14 rounded-full bg-white border border-gray-200 flex items-center justify-center mb-4"
|
||||
<div
|
||||
className="mx-auto w-14 h-14 rounded-full bg-white border border-gray-200 flex items-center justify-center mb-4"
|
||||
style={{ boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.04)" }}
|
||||
>
|
||||
<svg className="w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25a2.25 2.25 0 0 1-2.25-2.25v-2.25Z" />
|
||||
<svg
|
||||
className="w-6 h-6 text-gray-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25a2.25 2.25 0 0 1-2.25-2.25v-2.25Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-sm font-semibold text-gray-700 mb-1">No widgets yet</h3>
|
||||
<h3 className="text-sm font-semibold text-gray-700 mb-1">
|
||||
No widgets yet
|
||||
</h3>
|
||||
<p className="text-sm text-gray-400 max-w-sm mx-auto">
|
||||
Click <strong className="text-gray-500">Edit</strong> to start adding charts, values, gauges, and more to this dashboard.
|
||||
Click <strong className="text-gray-500">Edit</strong> to start adding
|
||||
charts, values, gauges, and more to this dashboard.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -88,7 +88,8 @@ const ComponentSettingsSideOver: FunctionComponent<ComponentProps> = (
|
||||
{component.componentType} Widget
|
||||
</span>
|
||||
<span className="text-xs text-gray-400">
|
||||
{component.widthInDashboardUnits} x {component.heightInDashboardUnits} units
|
||||
{component.widthInDashboardUnits} x{" "}
|
||||
{component.heightInDashboardUnits} units
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ const DashboardBaseComponentElement: FunctionComponent<ComponentProps> = (
|
||||
}
|
||||
|
||||
if (props.isSelected && props.isEditMode) {
|
||||
className += " !border-blue-400 ring-2 ring-blue-50 shadow-lg shadow-blue-100/50";
|
||||
className +=
|
||||
" !border-blue-400 ring-2 ring-blue-50 shadow-lg shadow-blue-100/50";
|
||||
}
|
||||
|
||||
if (!props.isEditMode) {
|
||||
@@ -386,7 +387,8 @@ const DashboardBaseComponentElement: FunctionComponent<ComponentProps> = (
|
||||
widthOfComponent +
|
||||
(SpaceBetweenUnitsInPx - 2) * (widthOfComponent - 1)
|
||||
}px`,
|
||||
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.04), 0 1px 2px -1px rgba(0, 0, 0, 0.03)",
|
||||
boxShadow:
|
||||
"0 1px 3px 0 rgba(0, 0, 0, 0.04), 0 1px 2px -1px rgba(0, 0, 0, 0.03)",
|
||||
}}
|
||||
key={component.componentId?.toString() || Math.random().toString()}
|
||||
ref={dashboardComponentRef}
|
||||
|
||||
@@ -171,9 +171,7 @@ const DashboardChartComponentElement: FunctionComponent<ComponentProps> = (
|
||||
<Icon icon={IconProp.ChartBar} />
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400 text-center max-w-48">
|
||||
{error}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 text-center max-w-48">{error}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
const [metricResults, setMetricResults] = React.useState<
|
||||
Array<AggregatedResult>
|
||||
>([]);
|
||||
const [aggregationType, setAggregationType] =
|
||||
React.useState<AggregationType>(AggregationType.Avg);
|
||||
const [aggregationType, setAggregationType] = React.useState<AggregationType>(
|
||||
AggregationType.Avg,
|
||||
);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = React.useState<boolean>(true);
|
||||
|
||||
@@ -132,8 +133,18 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center w-full h-full gap-1.5">
|
||||
<div className="w-10 h-10 rounded-full bg-gray-50 flex items-center justify-center">
|
||||
<svg className="w-5 h-5 text-gray-300" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 6a7.5 7.5 0 1 0 7.5 7.5h-7.5V6Z" />
|
||||
<svg
|
||||
className="w-5 h-5 text-gray-300"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M10.5 6a7.5 7.5 0 1 0 7.5 7.5h-7.5V6Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400 text-center max-w-40">{error}</p>
|
||||
@@ -152,8 +163,18 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center w-full h-full gap-1.5">
|
||||
<div className="w-10 h-10 rounded-full bg-emerald-50 flex items-center justify-center">
|
||||
<svg className="w-5 h-5 text-emerald-300" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 6a7.5 7.5 0 1 0 7.5 7.5h-7.5V6Z" />
|
||||
<svg
|
||||
className="w-5 h-5 text-emerald-300"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M10.5 6a7.5 7.5 0 1 0 7.5 7.5h-7.5V6Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="text-xs font-medium text-gray-500">
|
||||
@@ -211,10 +232,7 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
|
||||
// Determine color based on thresholds
|
||||
let gaugeColor: string = "#10b981"; // green
|
||||
if (
|
||||
criticalThreshold !== undefined &&
|
||||
aggregatedValue >= criticalThreshold
|
||||
) {
|
||||
if (criticalThreshold !== undefined && aggregatedValue >= criticalThreshold) {
|
||||
gaugeColor = "#ef4444"; // red
|
||||
} else if (
|
||||
warningThreshold !== undefined &&
|
||||
@@ -322,7 +340,9 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
<stop offset="50%" stopColor={gaugeColor} stopOpacity="0.85" />
|
||||
<stop offset="100%" stopColor={gaugeColor} stopOpacity="1" />
|
||||
</linearGradient>
|
||||
<filter id={`gauge-glow-${props.componentId?.toString() || "default"}`}>
|
||||
<filter
|
||||
id={`gauge-glow-${props.componentId?.toString() || "default"}`}
|
||||
>
|
||||
<feGaussianBlur stdDeviation="3" result="blur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="blur" />
|
||||
@@ -350,21 +370,19 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
/>
|
||||
)}
|
||||
{/* Threshold markers */}
|
||||
{thresholdMarkers.map(
|
||||
(marker: ThresholdMarker, index: number) => {
|
||||
return (
|
||||
<circle
|
||||
key={index}
|
||||
cx={marker.x}
|
||||
cy={marker.y}
|
||||
r={3}
|
||||
fill={marker.color}
|
||||
stroke="white"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
);
|
||||
},
|
||||
)}
|
||||
{thresholdMarkers.map((marker: ThresholdMarker, index: number) => {
|
||||
return (
|
||||
<circle
|
||||
key={index}
|
||||
cx={marker.x}
|
||||
cy={marker.y}
|
||||
r={3}
|
||||
fill={marker.color}
|
||||
stroke="white"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{/* Needle tip dot at current position */}
|
||||
{percentage > 0 && (
|
||||
<circle
|
||||
@@ -407,10 +425,16 @@ const DashboardGaugeComponentElement: FunctionComponent<ComponentProps> = (
|
||||
className="flex justify-between w-full px-2 mt-0.5"
|
||||
style={{ maxWidth: `${gaugeSize + 10}px` }}
|
||||
>
|
||||
<span className="text-gray-300 tabular-nums" style={{ fontSize: "10px" }}>
|
||||
<span
|
||||
className="text-gray-300 tabular-nums"
|
||||
style={{ fontSize: "10px" }}
|
||||
>
|
||||
{minValue}
|
||||
</span>
|
||||
<span className="text-gray-300 tabular-nums" style={{ fontSize: "10px" }}>
|
||||
<span
|
||||
className="text-gray-300 tabular-nums"
|
||||
style={{ fontSize: "10px" }}
|
||||
>
|
||||
{maxValue}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,10 @@ import InBetween from "Common/Types/BaseDatabase/InBetween";
|
||||
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
|
||||
import OneUptimeDate from "Common/Types/Date";
|
||||
import Query from "Common/Types/BaseDatabase/Query";
|
||||
import { queryStringToFilter, LogFilter } from "Common/Types/Log/LogQueryToFilter";
|
||||
import {
|
||||
queryStringToFilter,
|
||||
LogFilter,
|
||||
} from "Common/Types/Log/LogQueryToFilter";
|
||||
|
||||
export interface ComponentProps extends DashboardBaseComponentProps {
|
||||
component: DashboardLogStreamComponent;
|
||||
@@ -31,13 +34,21 @@ const getSeverityColor: (severity: string) => SeverityColor = (
|
||||
): SeverityColor => {
|
||||
const lower: string = severity.toLowerCase();
|
||||
if (lower === "fatal") {
|
||||
return { dot: "bg-purple-500", text: "text-purple-700", bg: "bg-purple-50" };
|
||||
return {
|
||||
dot: "bg-purple-500",
|
||||
text: "text-purple-700",
|
||||
bg: "bg-purple-50",
|
||||
};
|
||||
}
|
||||
if (lower === "error") {
|
||||
return { dot: "bg-red-500", text: "text-red-700", bg: "bg-red-50" };
|
||||
}
|
||||
if (lower === "warning") {
|
||||
return { dot: "bg-yellow-500", text: "text-yellow-700", bg: "bg-yellow-50" };
|
||||
return {
|
||||
dot: "bg-yellow-500",
|
||||
text: "text-yellow-700",
|
||||
bg: "bg-yellow-50",
|
||||
};
|
||||
}
|
||||
if (lower === "information") {
|
||||
return { dot: "bg-blue-500", text: "text-blue-700", bg: "bg-blue-50" };
|
||||
@@ -115,26 +126,25 @@ const DashboardLogStreamComponentElement: FunctionComponent<ComponentProps> = (
|
||||
}
|
||||
}
|
||||
|
||||
const listResult: ListResult<Log> =
|
||||
await AnalyticsModelAPI.getList<Log>({
|
||||
modelType: Log,
|
||||
query: query,
|
||||
limit: maxRows,
|
||||
skip: 0,
|
||||
select: {
|
||||
time: true,
|
||||
severityText: true,
|
||||
body: true,
|
||||
serviceId: true,
|
||||
traceId: true,
|
||||
spanId: true,
|
||||
attributes: true,
|
||||
},
|
||||
sort: {
|
||||
time: SortOrder.Descending,
|
||||
},
|
||||
requestOptions: {},
|
||||
});
|
||||
const listResult: ListResult<Log> = await AnalyticsModelAPI.getList<Log>({
|
||||
modelType: Log,
|
||||
query: query,
|
||||
limit: maxRows,
|
||||
skip: 0,
|
||||
select: {
|
||||
time: true,
|
||||
severityText: true,
|
||||
body: true,
|
||||
serviceId: true,
|
||||
traceId: true,
|
||||
spanId: true,
|
||||
attributes: true,
|
||||
},
|
||||
sort: {
|
||||
time: SortOrder.Descending,
|
||||
},
|
||||
requestOptions: {},
|
||||
});
|
||||
|
||||
setLogs(listResult.data);
|
||||
setError("");
|
||||
|
||||
@@ -124,7 +124,11 @@ const DashboardTableComponentElement: FunctionComponent<ComponentProps> = (
|
||||
</div>
|
||||
{Array.from({ length: 5 }).map((_: unknown, i: number) => {
|
||||
return (
|
||||
<div key={i} className="flex gap-4" style={{ opacity: 1 - i * 0.15 }}>
|
||||
<div
|
||||
key={i}
|
||||
className="flex gap-4"
|
||||
style={{ opacity: 1 - i * 0.15 }}
|
||||
>
|
||||
<div className="h-3 w-28 bg-gray-50 rounded"></div>
|
||||
<div className="h-3 w-14 bg-gray-50 rounded ml-auto"></div>
|
||||
</div>
|
||||
@@ -185,20 +189,27 @@ const DashboardTableComponentElement: FunctionComponent<ComponentProps> = (
|
||||
<table className="w-full text-sm text-left">
|
||||
<thead className="text-xs text-gray-400 uppercase bg-gray-50/80 sticky top-0 border-b border-gray-100">
|
||||
<tr>
|
||||
<th className="px-4 py-2.5 font-medium tracking-wider" style={{ width: "45%" }}>
|
||||
<th
|
||||
className="px-4 py-2.5 font-medium tracking-wider"
|
||||
style={{ width: "45%" }}
|
||||
>
|
||||
Timestamp
|
||||
</th>
|
||||
<th className="px-4 py-2.5 font-medium tracking-wider text-right" style={{ width: "25%" }}>
|
||||
<th
|
||||
className="px-4 py-2.5 font-medium tracking-wider text-right"
|
||||
style={{ width: "25%" }}
|
||||
>
|
||||
Value
|
||||
</th>
|
||||
<th className="px-4 py-2.5 font-medium tracking-wider" style={{ width: "30%" }}>
|
||||
</th>
|
||||
<th
|
||||
className="px-4 py-2.5 font-medium tracking-wider"
|
||||
style={{ width: "30%" }}
|
||||
></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-50">
|
||||
{displayData.map((item: AggregatedModel, index: number) => {
|
||||
const roundedValue: number =
|
||||
Math.round(item.value * 100) / 100;
|
||||
const roundedValue: number = Math.round(item.value * 100) / 100;
|
||||
const barWidth: number =
|
||||
maxDataValue > 0
|
||||
? (Math.abs(roundedValue) / maxDataValue) * 100
|
||||
|
||||
@@ -19,7 +19,10 @@ const DashboardTextComponentElement: FunctionComponent<ComponentProps> = (
|
||||
}
|
||||
|
||||
const textClassName: string = `flex items-center justify-center h-full text-gray-800 leading-snug ${props.component.arguments.isBold ? "font-semibold" : "font-normal"} ${props.component.arguments.isItalic ? "italic" : ""} ${props.component.arguments.isUnderline ? "underline decoration-gray-300 underline-offset-4" : ""}`;
|
||||
const textHeightInxPx: number = Math.min(props.dashboardComponentHeightInPx * 0.35, 64);
|
||||
const textHeightInxPx: number = Math.min(
|
||||
props.dashboardComponentHeightInPx * 0.35,
|
||||
64,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full px-2">
|
||||
|
||||
@@ -302,10 +302,7 @@ const DashboardValueComponentElement: FunctionComponent<ComponentProps> = (
|
||||
const criticalThreshold: number | undefined =
|
||||
props.component.arguments.criticalThreshold;
|
||||
|
||||
if (
|
||||
criticalThreshold !== undefined &&
|
||||
aggregatedValue >= criticalThreshold
|
||||
) {
|
||||
if (criticalThreshold !== undefined && aggregatedValue >= criticalThreshold) {
|
||||
valueColorClass = "text-red-600";
|
||||
bgStyle = {
|
||||
background:
|
||||
@@ -393,8 +390,7 @@ const DashboardValueComponentElement: FunctionComponent<ComponentProps> = (
|
||||
<span
|
||||
className="text-gray-400 font-normal"
|
||||
style={{
|
||||
fontSize:
|
||||
valueHeightInPx > 0 ? `${valueHeightInPx * 0.3}px` : "",
|
||||
fontSize: valueHeightInPx > 0 ? `${valueHeightInPx * 0.3}px` : "",
|
||||
}}
|
||||
>
|
||||
{unit ? ` ${unit}` : ""}
|
||||
@@ -407,7 +403,9 @@ const DashboardValueComponentElement: FunctionComponent<ComponentProps> = (
|
||||
className={`flex items-center gap-0.5 mt-0.5 ${
|
||||
trendDirection === "up" ? "text-emerald-500" : "text-red-500"
|
||||
}`}
|
||||
style={{ fontSize: `${Math.max(Math.min(titleHeightInPx, 12), 10)}px` }}
|
||||
style={{
|
||||
fontSize: `${Math.max(Math.min(titleHeightInPx, 12), 10)}px`,
|
||||
}}
|
||||
>
|
||||
<span>{trendDirection === "up" ? "\u2191" : "\u2193"}</span>
|
||||
<span className="font-medium tabular-nums">
|
||||
|
||||
@@ -32,7 +32,9 @@ export interface ComponentProps {
|
||||
onAutoRefreshIntervalChange: (interval: AutoRefreshInterval) => void;
|
||||
isRefreshing?: boolean | undefined;
|
||||
variables?: Array<DashboardVariable> | undefined;
|
||||
onVariableValueChange?: ((variableId: string, value: string) => void) | undefined;
|
||||
onVariableValueChange?:
|
||||
| ((variableId: string, value: string) => void)
|
||||
| undefined;
|
||||
canResetZoom?: boolean | undefined;
|
||||
onResetZoom?: (() => void) | undefined;
|
||||
}
|
||||
@@ -46,17 +48,18 @@ const DashboardToolbar: FunctionComponent<ComponentProps> = (
|
||||
|
||||
const isSaving: boolean = props.isSaving;
|
||||
|
||||
const hasComponents: boolean = !!(
|
||||
const hasComponents: boolean = Boolean(
|
||||
props.dashboardViewConfig &&
|
||||
props.dashboardViewConfig.components &&
|
||||
props.dashboardViewConfig.components.length > 0
|
||||
props.dashboardViewConfig.components &&
|
||||
props.dashboardViewConfig.components.length > 0,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="mx-3 mt-3 mb-2 rounded-lg bg-white border border-gray-200"
|
||||
style={{
|
||||
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.05), 0 1px 2px -1px rgba(0, 0, 0, 0.04)",
|
||||
boxShadow:
|
||||
"0 1px 3px 0 rgba(0, 0, 0, 0.05), 0 1px 2px -1px rgba(0, 0, 0, 0.04)",
|
||||
}}
|
||||
>
|
||||
{/* Accent top bar */}
|
||||
@@ -82,7 +85,8 @@ const DashboardToolbar: FunctionComponent<ComponentProps> = (
|
||||
)}
|
||||
{hasComponents && !isEditMode && (
|
||||
<span className="text-xs text-gray-400 tabular-nums">
|
||||
{props.dashboardViewConfig.components.length} widget{props.dashboardViewConfig.components.length !== 1 ? "s" : ""}
|
||||
{props.dashboardViewConfig.components.length} widget
|
||||
{props.dashboardViewConfig.components.length !== 1 ? "s" : ""}
|
||||
</span>
|
||||
)}
|
||||
{/* Refreshing indicator */}
|
||||
|
||||
@@ -88,7 +88,11 @@ const CriteriaFilterElement: FunctionComponent<ComponentProps> = (
|
||||
|
||||
// Auto-select MetricValue for metric-only monitor types (Kubernetes, Metrics)
|
||||
useEffect(() => {
|
||||
if (isMetricOnly && criteriaFilter && criteriaFilter.checkOn !== CheckOn.MetricValue) {
|
||||
if (
|
||||
isMetricOnly &&
|
||||
criteriaFilter &&
|
||||
criteriaFilter.checkOn !== CheckOn.MetricValue
|
||||
) {
|
||||
props.onChange?.({
|
||||
...criteriaFilter,
|
||||
checkOn: CheckOn.MetricValue,
|
||||
@@ -194,24 +198,26 @@ const CriteriaFilterElement: FunctionComponent<ComponentProps> = (
|
||||
<div className="rounded-md p-2 bg-gray-50 my-5 border-gray-200 border-solid border-2">
|
||||
{/* Hide Filter Type dropdown for metric-only monitors since MetricValue is the only option */}
|
||||
{!isMetricOnly && (
|
||||
<div className="">
|
||||
<FieldLabelElement title="Filter Type" />
|
||||
<Dropdown
|
||||
value={checkOnOptions.find((i: DropdownOption) => {
|
||||
return i.value === criteriaFilter?.checkOn;
|
||||
})}
|
||||
options={checkOnOptions}
|
||||
onChange={(value: DropdownValue | Array<DropdownValue> | null) => {
|
||||
props.onChange?.({
|
||||
checkOn: value?.toString() as CheckOn,
|
||||
filterType: undefined,
|
||||
value: undefined,
|
||||
evaluateOverTime: false,
|
||||
evaluateOverTimeOptions: undefined,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="">
|
||||
<FieldLabelElement title="Filter Type" />
|
||||
<Dropdown
|
||||
value={checkOnOptions.find((i: DropdownOption) => {
|
||||
return i.value === criteriaFilter?.checkOn;
|
||||
})}
|
||||
options={checkOnOptions}
|
||||
onChange={(
|
||||
value: DropdownValue | Array<DropdownValue> | null,
|
||||
) => {
|
||||
props.onChange?.({
|
||||
checkOn: value?.toString() as CheckOn,
|
||||
filterType: undefined,
|
||||
value: undefined,
|
||||
evaluateOverTime: false,
|
||||
evaluateOverTimeOptions: undefined,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{criteriaFilter?.checkOn &&
|
||||
@@ -239,7 +245,11 @@ const CriteriaFilterElement: FunctionComponent<ComponentProps> = (
|
||||
<div className="mt-1">
|
||||
<FieldLabelElement
|
||||
title={isMetricOnly ? "Metric" : "Select Metric Variable"}
|
||||
description={isMetricOnly ? "Which metric query should this alert rule check?" : undefined}
|
||||
description={
|
||||
isMetricOnly
|
||||
? "Which metric query should this alert rule check?"
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<Dropdown
|
||||
value={selectedMetricVariableOption}
|
||||
@@ -264,7 +274,11 @@ const CriteriaFilterElement: FunctionComponent<ComponentProps> = (
|
||||
<div className="mt-1">
|
||||
<FieldLabelElement
|
||||
title={isMetricOnly ? "Aggregation" : "Select Aggregation"}
|
||||
description={isMetricOnly ? "How to combine multiple data points (e.g. Average, Max, Min)." : undefined}
|
||||
description={
|
||||
isMetricOnly
|
||||
? "How to combine multiple data points (e.g. Average, Max, Min)."
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<Dropdown
|
||||
value={metricAggregationValue}
|
||||
@@ -385,7 +399,9 @@ const CriteriaFilterElement: FunctionComponent<ComponentProps> = (
|
||||
<div className="mt-1">
|
||||
<FieldLabelElement
|
||||
title={isMetricOnly ? "Condition" : "Filter Condition"}
|
||||
description={isMetricOnly ? "When should this alert trigger?" : undefined}
|
||||
description={
|
||||
isMetricOnly ? "When should this alert trigger?" : undefined
|
||||
}
|
||||
/>
|
||||
<Dropdown
|
||||
value={filterConditionValue}
|
||||
@@ -415,7 +431,9 @@ const CriteriaFilterElement: FunctionComponent<ComponentProps> = (
|
||||
<div className="mt-1">
|
||||
<FieldLabelElement
|
||||
title={isMetricOnly ? "Threshold" : "Value"}
|
||||
description={isMetricOnly ? "The value to compare against." : undefined}
|
||||
description={
|
||||
isMetricOnly ? "The value to compare against." : undefined
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
placeholder={valuePlaceholder}
|
||||
|
||||
@@ -221,8 +221,10 @@ const KubernetesMonitorStepForm: FunctionComponent<ComponentProps> = (
|
||||
const clusterIdentifier: string =
|
||||
monitorStepKubernetesMonitor.clusterIdentifier;
|
||||
|
||||
// Get a dummy monitor step from the template to extract the kubernetes config
|
||||
// Build even without a cluster so the metricViewConfig is populated for the METRIC dropdown
|
||||
/*
|
||||
* Get a dummy monitor step from the template to extract the kubernetes config
|
||||
* Build even without a cluster so the metricViewConfig is populated for the METRIC dropdown
|
||||
*/
|
||||
const dummyStep: MonitorStep = template.getMonitorStep({
|
||||
clusterIdentifier: clusterIdentifier || "",
|
||||
onlineMonitorStatusId: ObjectID.generate(),
|
||||
|
||||
@@ -248,12 +248,14 @@ const MonitorCriteriaInstanceElement: FunctionComponent<ComponentProps> = (
|
||||
{/* Filters Section - Collapsible */}
|
||||
<CollapsibleSection
|
||||
title={
|
||||
props.monitorType === MonitorType.Kubernetes || props.monitorType === MonitorType.Metrics
|
||||
props.monitorType === MonitorType.Kubernetes ||
|
||||
props.monitorType === MonitorType.Metrics
|
||||
? "Alert Rules"
|
||||
: "Filters"
|
||||
}
|
||||
description={
|
||||
props.monitorType === MonitorType.Kubernetes || props.monitorType === MonitorType.Metrics
|
||||
props.monitorType === MonitorType.Kubernetes ||
|
||||
props.monitorType === MonitorType.Metrics
|
||||
? "Define when this alert should trigger based on metric values."
|
||||
: "Add criteria for different monitor properties."
|
||||
}
|
||||
@@ -266,12 +268,14 @@ const MonitorCriteriaInstanceElement: FunctionComponent<ComponentProps> = (
|
||||
<div className="mb-3">
|
||||
<FieldLabelElement
|
||||
title={
|
||||
props.monitorType === MonitorType.Kubernetes || props.monitorType === MonitorType.Metrics
|
||||
props.monitorType === MonitorType.Kubernetes ||
|
||||
props.monitorType === MonitorType.Metrics
|
||||
? "Match Condition"
|
||||
: "Filter Condition"
|
||||
}
|
||||
description={
|
||||
props.monitorType === MonitorType.Kubernetes || props.monitorType === MonitorType.Metrics
|
||||
props.monitorType === MonitorType.Kubernetes ||
|
||||
props.monitorType === MonitorType.Metrics
|
||||
? "Should all rules match, or just any one of them?"
|
||||
: "Select All if you want all the criteria to be met. Select any if you like any criteria to be met."
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ const WorkspaceSummaryTable: FunctionComponent<ComponentProps> = (
|
||||
},
|
||||
title: "What to Include",
|
||||
description:
|
||||
"Choose which sections appear in the summary. Select \"All\" to include everything, or pick specific sections.",
|
||||
'Choose which sections appear in the summary. Select "All" to include everything, or pick specific sections.',
|
||||
fieldType: FormFieldSchemaType.CustomComponent,
|
||||
required: false,
|
||||
stepId: "content",
|
||||
@@ -503,8 +503,9 @@ const WorkspaceSummaryTable: FunctionComponent<ComponentProps> = (
|
||||
elementProps: CustomElementProps,
|
||||
): ReactElement => {
|
||||
const currentItems: Array<WorkspaceNotificationSummaryItem> =
|
||||
(value.summaryItems as Array<WorkspaceNotificationSummaryItem>) ||
|
||||
[WorkspaceNotificationSummaryItem.All];
|
||||
(value.summaryItems as Array<WorkspaceNotificationSummaryItem>) || [
|
||||
WorkspaceNotificationSummaryItem.All,
|
||||
];
|
||||
|
||||
const isAllSelected: boolean = currentItems.includes(
|
||||
WorkspaceNotificationSummaryItem.All,
|
||||
@@ -542,9 +543,7 @@ const WorkspaceSummaryTable: FunctionComponent<ComponentProps> = (
|
||||
key={item}
|
||||
title={item}
|
||||
disabled={isAllSelected}
|
||||
value={
|
||||
isAllSelected || currentItems.includes(item)
|
||||
}
|
||||
value={isAllSelected || currentItems.includes(item)}
|
||||
onChange={(checked: boolean) => {
|
||||
if (elementProps.onChange) {
|
||||
let newItems: Array<WorkspaceNotificationSummaryItem> =
|
||||
|
||||
@@ -42,15 +42,13 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
const [selectedDashboardDomain, setSelectedDashboardDomain] =
|
||||
useState<DashboardDomain | null>(null);
|
||||
|
||||
const [verifyCnameLoading, setVerifyCnameLoading] =
|
||||
useState<boolean>(false);
|
||||
const [verifyCnameLoading, setVerifyCnameLoading] = useState<boolean>(false);
|
||||
|
||||
const [orderSslLoading, setOrderSslLoading] = useState<boolean>(false);
|
||||
|
||||
const [error, setError] = useState<string>("");
|
||||
|
||||
const [showOrderSSLModal, setShowOrderSSLModal] =
|
||||
useState<boolean>(false);
|
||||
const [showOrderSSLModal, setShowOrderSSLModal] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -72,9 +70,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
description: `Important: Please add a CNAME record pointing to ${DashboardCNameRecord} for these domains for this to work.`,
|
||||
}}
|
||||
refreshToggle={refreshToggle}
|
||||
onBeforeCreate={(
|
||||
item: DashboardDomain,
|
||||
): Promise<DashboardDomain> => {
|
||||
onBeforeCreate={(item: DashboardDomain): Promise<DashboardDomain> => {
|
||||
if (!props.currentProject || !props.currentProject._id) {
|
||||
throw new BadDataException("Project ID cannot be null");
|
||||
}
|
||||
@@ -272,9 +268,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
if (!item.isCnameVerified) {
|
||||
return (
|
||||
<span>
|
||||
<span className="font-semibold">
|
||||
Action Required:
|
||||
</span>{" "}
|
||||
<span className="font-semibold">Action Required:</span>{" "}
|
||||
Please add your CNAME record.
|
||||
</span>
|
||||
);
|
||||
@@ -283,8 +277,8 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
if (item.isCustomCertificate) {
|
||||
return (
|
||||
<span>
|
||||
No action is required. Please allow 30 minutes for
|
||||
the certificate to be provisioned.
|
||||
No action is required. Please allow 30 minutes for the
|
||||
certificate to be provisioned.
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -292,9 +286,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
if (!item.isSslOrdered) {
|
||||
return (
|
||||
<span>
|
||||
<span className="font-semibold">
|
||||
Action Required:
|
||||
</span>{" "}
|
||||
<span className="font-semibold">Action Required:</span>{" "}
|
||||
Please order SSL certificate.
|
||||
</span>
|
||||
);
|
||||
@@ -304,16 +296,16 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
return (
|
||||
<span>
|
||||
No action is required. This SSL certificate will be
|
||||
provisioned in 1 hour. If this does not happen.
|
||||
Please contact support.
|
||||
provisioned in 1 hour. If this does not happen. Please
|
||||
contact support.
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
Certificate Provisioned. We will automatically renew
|
||||
this certificate. No action required.{" "}
|
||||
Certificate Provisioned. We will automatically renew this
|
||||
certificate. No action required.{" "}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
@@ -328,8 +320,8 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
DashboardCNameRecord ? (
|
||||
<div>
|
||||
<span>
|
||||
Please add CNAME record to your domain. Details of
|
||||
the CNAME records are:
|
||||
Please add CNAME record to your domain. Details of the CNAME
|
||||
records are:
|
||||
</span>
|
||||
<br />
|
||||
<br />
|
||||
@@ -356,14 +348,13 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
) : (
|
||||
<div>
|
||||
<span>
|
||||
Custom Domains not enabled for this OneUptime
|
||||
installation. Please contact your server admin to
|
||||
enable this feature. To enable this feature, if you
|
||||
are using Docker compose, the
|
||||
<b>DASHBOARD_CNAME_RECORD</b> environment variable
|
||||
must be set when starting the OneUptime cluster. If
|
||||
you are using Helm and Kubernetes then set
|
||||
dashboard.cnameRecord in the values.yaml file.
|
||||
Custom Domains not enabled for this OneUptime installation.
|
||||
Please contact your server admin to enable this feature. To
|
||||
enable this feature, if you are using Docker compose, the
|
||||
<b>DASHBOARD_CNAME_RECORD</b> environment variable must be
|
||||
set when starting the OneUptime cluster. If you are using
|
||||
Helm and Kubernetes then set dashboard.cnameRecord in the
|
||||
values.yaml file.
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
@@ -381,13 +372,9 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
setVerifyCnameLoading(true);
|
||||
setError("");
|
||||
|
||||
const response:
|
||||
| HTTPResponse<JSONObject>
|
||||
| HTTPErrorResponse =
|
||||
const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
||||
await API.get<JSONObject>({
|
||||
url: URL.fromString(
|
||||
APP_API_URL.toString(),
|
||||
).addRoute(
|
||||
url: URL.fromString(APP_API_URL.toString()).addRoute(
|
||||
`/${
|
||||
new DashboardDomain().crudApiPath
|
||||
}/verify-cname/${selectedDashboardDomain?.id?.toString()}`,
|
||||
@@ -401,9 +388,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
}
|
||||
|
||||
setShowCnameModal(false);
|
||||
setRefreshToggle(
|
||||
OneUptimeDate.getCurrentDate().toString(),
|
||||
);
|
||||
setRefreshToggle(OneUptimeDate.getCurrentDate().toString());
|
||||
setSelectedDashboardDomain(null);
|
||||
} catch (err) {
|
||||
setError(API.getFriendlyMessage(err));
|
||||
@@ -420,18 +405,16 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
description={
|
||||
DashboardCNameRecord ? (
|
||||
<div>
|
||||
Please click on the button below to order SSL for this
|
||||
domain. We will use LetsEncrypt to order a certificate.
|
||||
This process is secure and completely free. The
|
||||
certificate takes 3 hours to provision after its been
|
||||
ordered.
|
||||
Please click on the button below to order SSL for this domain.
|
||||
We will use LetsEncrypt to order a certificate. This process
|
||||
is secure and completely free. The certificate takes 3 hours
|
||||
to provision after its been ordered.
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<span>
|
||||
Custom Domains not enabled for this OneUptime
|
||||
installation. Please contact your server admin to
|
||||
enable this feature.
|
||||
Custom Domains not enabled for this OneUptime installation.
|
||||
Please contact your server admin to enable this feature.
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
@@ -449,13 +432,9 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
setOrderSslLoading(true);
|
||||
setError("");
|
||||
|
||||
const response:
|
||||
| HTTPResponse<JSONObject>
|
||||
| HTTPErrorResponse =
|
||||
const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
||||
await API.get<JSONObject>({
|
||||
url: URL.fromString(
|
||||
APP_API_URL.toString(),
|
||||
).addRoute(
|
||||
url: URL.fromString(APP_API_URL.toString()).addRoute(
|
||||
`/${
|
||||
new DashboardDomain().crudApiPath
|
||||
}/order-ssl/${selectedDashboardDomain?.id?.toString()}`,
|
||||
@@ -469,9 +448,7 @@ const DashboardCustomDomains: FunctionComponent<PageComponentProps> = (
|
||||
}
|
||||
|
||||
setShowOrderSSLModal(false);
|
||||
setRefreshToggle(
|
||||
OneUptimeDate.getCurrentDate().toString(),
|
||||
);
|
||||
setRefreshToggle(OneUptimeDate.getCurrentDate().toString());
|
||||
setSelectedDashboardDomain(null);
|
||||
} catch (err) {
|
||||
setError(API.getFriendlyMessage(err));
|
||||
|
||||
@@ -59,9 +59,7 @@ const DashboardSideMenu: FunctionComponent<ComponentProps> = (
|
||||
link={{
|
||||
title: "Authentication",
|
||||
to: RouteUtil.populateRouteParams(
|
||||
RouteMap[
|
||||
PageMap.DASHBOARD_VIEW_AUTHENTICATION_SETTINGS
|
||||
] as Route,
|
||||
RouteMap[PageMap.DASHBOARD_VIEW_AUTHENTICATION_SETTINGS] as Route,
|
||||
{ modelId: props.modelId },
|
||||
),
|
||||
}}
|
||||
|
||||
@@ -242,7 +242,8 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
|
||||
title: "Show Status History Chart",
|
||||
fieldType: FormFieldSchemaType.Toggle,
|
||||
required: false,
|
||||
description: "Show resource status history chart. The number of days is configured in Status Page Settings.",
|
||||
description:
|
||||
"Show resource status history chart. The number of days is configured in Status Page Settings.",
|
||||
defaultValue: true,
|
||||
stepId: "advanced",
|
||||
},
|
||||
|
||||
@@ -278,7 +278,9 @@ const Delete: FunctionComponent<PageComponentProps> = (): ReactElement => {
|
||||
boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.03)",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "0.75rem" }}>
|
||||
<div
|
||||
style={{ display: "flex", alignItems: "center", gap: "0.75rem" }}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
||||
@@ -450,8 +450,10 @@ const registerCustomDomainFallback: () => void = (): void => {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Check if this custom domain belongs to a PublicDashboard.
|
||||
// If so, serve the PublicDashboard SPA instead of StatusPage.
|
||||
/*
|
||||
* Check if this custom domain belongs to a PublicDashboard.
|
||||
* If so, serve the PublicDashboard SPA instead of StatusPage.
|
||||
*/
|
||||
const requestHostname: string = getRequestHostname(req);
|
||||
|
||||
if (requestHostname && (await isDashboardDomain(requestHostname))) {
|
||||
|
||||
@@ -163,8 +163,10 @@ router.post(
|
||||
MarkdownContentType.Email,
|
||||
);
|
||||
|
||||
// Send response immediately so the request doesn't timeout.
|
||||
// Emails are sent in the background.
|
||||
/*
|
||||
* Send response immediately so the request doesn't timeout.
|
||||
* Emails are sent in the background.
|
||||
*/
|
||||
Response.sendJsonObjectResponse(req, res, {
|
||||
message:
|
||||
"Broadcast email job has been started. Emails will be sent in the background.",
|
||||
|
||||
@@ -4,7 +4,6 @@ import RouteParams from "./Utils/RouteParams";
|
||||
import PublicDashboardUtil from "./Utils/PublicDashboard";
|
||||
import { PUBLIC_DASHBOARD_API_URL } from "./Utils/Config";
|
||||
import API from "./Utils/API";
|
||||
import Route from "Common/Types/API/Route";
|
||||
import URL from "Common/Types/API/URL";
|
||||
import { JSONObject } from "Common/Types/JSON";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
@@ -42,13 +41,12 @@ const MasterPassword: React.LazyExoticComponent<
|
||||
});
|
||||
});
|
||||
|
||||
const NotFoundPage: React.LazyExoticComponent<
|
||||
AllPagesModule["NotFoundPage"]
|
||||
> = lazy(() => {
|
||||
return import("./Pages/AllPages").then((m: AllPagesModule) => {
|
||||
return { default: m.NotFoundPage };
|
||||
const NotFoundPage: React.LazyExoticComponent<AllPagesModule["NotFoundPage"]> =
|
||||
lazy(() => {
|
||||
return import("./Pages/AllPages").then((m: AllPagesModule) => {
|
||||
return { default: m.NotFoundPage };
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const ForbiddenPage: React.LazyExoticComponent<
|
||||
AllPagesModule["ForbiddenPage"]
|
||||
@@ -123,8 +121,7 @@ const App: () => JSX.Element = () => {
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
const name: string =
|
||||
(response.data["name"] as string) || "Dashboard";
|
||||
const name: string = (response.data["name"] as string) || "Dashboard";
|
||||
setDashboardName(name);
|
||||
document.title = name;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Re-export the DashboardCanvas from the Dashboard FeatureSet
|
||||
// The PublicDashboard app reuses the same canvas rendering logic
|
||||
/*
|
||||
* Re-export the DashboardCanvas from the Dashboard FeatureSet
|
||||
* The PublicDashboard app reuses the same canvas rendering logic
|
||||
*/
|
||||
export {
|
||||
default,
|
||||
type ComponentProps,
|
||||
|
||||
@@ -33,7 +33,6 @@ import MoreMenuItem from "Common/UI/Components/MoreMenu/MoreMenuItem";
|
||||
import IconProp from "Common/Types/Icon/IconProp";
|
||||
import Button, { ButtonStyleType } from "Common/UI/Components/Button/Button";
|
||||
import DashboardVariableSelector from "./DashboardVariableSelector";
|
||||
import DashboardBaseComponent from "Common/Types/Dashboard/DashboardComponents/DashboardBaseComponent";
|
||||
import NavBar from "Common/UI/Components/Navbar/NavBar";
|
||||
import NavBarItem from "Common/UI/Components/Navbar/NavBarItem";
|
||||
import PageMap from "../../Utils/PageMap";
|
||||
@@ -97,10 +96,10 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
|
||||
const hasComponents: boolean = !!(
|
||||
const hasComponents: boolean = Boolean(
|
||||
dashboardViewConfig &&
|
||||
dashboardViewConfig.components &&
|
||||
dashboardViewConfig.components.length > 0
|
||||
dashboardViewConfig.components &&
|
||||
dashboardViewConfig.components.length > 0,
|
||||
);
|
||||
|
||||
const fetchDashboardViewConfig: PromiseVoidFunction =
|
||||
@@ -159,7 +158,9 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
// Auto-refresh
|
||||
const triggerRefresh: () => void = useCallback(() => {
|
||||
setIsRefreshing(true);
|
||||
setRefreshTick((prev: number) => prev + 1);
|
||||
setRefreshTick((prev: number) => {
|
||||
return prev + 1;
|
||||
});
|
||||
setTimeout(() => {
|
||||
setIsRefreshing(false);
|
||||
}, 500);
|
||||
@@ -224,9 +225,7 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<NavBar
|
||||
className="bg-white flex text-center justify-between py-2 mt-5 rounded-lg shadow px-5"
|
||||
>
|
||||
<NavBar className="bg-white flex text-center justify-between py-2 mt-5 rounded-lg shadow px-5">
|
||||
<NavBarItem
|
||||
id="overview-nav-bar-item"
|
||||
title="Overview"
|
||||
@@ -248,8 +247,7 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
<div
|
||||
className="h-0.5 rounded-t-lg"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(90deg, #6366f1 0%, #8b5cf6 100%)",
|
||||
background: "linear-gradient(90deg, #6366f1 0%, #8b5cf6 100%)",
|
||||
}}
|
||||
></div>
|
||||
<div className="flex items-center justify-between px-5 py-3">
|
||||
@@ -341,10 +339,7 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
<RangeStartAndEndDateView
|
||||
dashboardStartAndEndDate={startAndEndDate}
|
||||
onChange={(newRange: RangeStartAndEndDateTime) => {
|
||||
setTimeRangeStack([
|
||||
...timeRangeStack,
|
||||
startAndEndDate,
|
||||
]);
|
||||
setTimeRangeStack([...timeRangeStack, startAndEndDate]);
|
||||
setStartAndEndDate(newRange);
|
||||
}}
|
||||
/>
|
||||
@@ -360,14 +355,12 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
value: string,
|
||||
) => {
|
||||
setDashboardVariables(
|
||||
dashboardVariables.map(
|
||||
(v: DashboardVariable) => {
|
||||
if (v.id === variableId) {
|
||||
return { ...v, currentValue: value };
|
||||
}
|
||||
return v;
|
||||
},
|
||||
),
|
||||
dashboardVariables.map((v: DashboardVariable) => {
|
||||
if (v.id === variableId) {
|
||||
return { ...v, currentValue: value };
|
||||
}
|
||||
return v;
|
||||
}),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -390,9 +383,7 @@ const DashboardViewPage: FunctionComponent<ComponentProps> = (
|
||||
}}
|
||||
dashboardTotalWidth={dashboardTotalWidth}
|
||||
startAndEndDate={startAndEndDate}
|
||||
onStartAndEndDateChange={(
|
||||
newRange: RangeStartAndEndDateTime,
|
||||
) => {
|
||||
onStartAndEndDateChange={(newRange: RangeStartAndEndDateTime) => {
|
||||
setTimeRangeStack([...timeRangeStack, startAndEndDate]);
|
||||
setStartAndEndDate(newRange);
|
||||
}}
|
||||
|
||||
@@ -150,10 +150,7 @@ const MasterPasswordPage: FunctionComponent<ComponentProps> = (
|
||||
maxPrimaryButtonWidth={true}
|
||||
isLoading={isSubmitting}
|
||||
error={formError || undefined}
|
||||
onSubmit={(
|
||||
values: JSONObject,
|
||||
onSubmitSuccessful?: () => void,
|
||||
) => {
|
||||
onSubmit={(values: JSONObject, onSubmitSuccessful?: () => void) => {
|
||||
void handleFormSubmit(values, onSubmitSuccessful);
|
||||
}}
|
||||
footer={<></>}
|
||||
|
||||
@@ -40,9 +40,7 @@ export const getPublicDashboardData: (
|
||||
req.hostname?.toString() || req.headers["host"]?.toString() || "";
|
||||
if (host) {
|
||||
dashboardIdOrDomain = host;
|
||||
logger.debug(
|
||||
`Found domain in request headers: ${dashboardIdOrDomain}`,
|
||||
);
|
||||
logger.debug(`Found domain in request headers: ${dashboardIdOrDomain}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ import BaseAPI from "Common/UI/Utils/API/API";
|
||||
|
||||
export default class API extends BaseAPI {
|
||||
public static override getDefaultHeaders(): Headers {
|
||||
const dashboardId: ObjectID | null =
|
||||
PublicDashboardUtil.getDashboardId();
|
||||
const dashboardId: ObjectID | null = PublicDashboardUtil.getDashboardId();
|
||||
|
||||
if (!dashboardId) {
|
||||
return {};
|
||||
|
||||
@@ -23,7 +23,8 @@ export default class PublicDashboardUtil {
|
||||
}
|
||||
|
||||
public static setRequiresMasterPassword(value: boolean): void {
|
||||
const storageKey: string = PublicDashboardUtil.getRequiresMasterPasswordStorageKey();
|
||||
const storageKey: string =
|
||||
PublicDashboardUtil.getRequiresMasterPasswordStorageKey();
|
||||
LocalStorage.setItem(storageKey, value);
|
||||
|
||||
if (!value) {
|
||||
@@ -32,7 +33,8 @@ export default class PublicDashboardUtil {
|
||||
}
|
||||
|
||||
public static requiresMasterPassword(): boolean {
|
||||
const storageKey: string = PublicDashboardUtil.getRequiresMasterPasswordStorageKey();
|
||||
const storageKey: string =
|
||||
PublicDashboardUtil.getRequiresMasterPasswordStorageKey();
|
||||
return Boolean(LocalStorage.getItem(storageKey));
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,7 @@ export class RouteUtil {
|
||||
const id: ObjectID = LocalStorage.getItem("dashboardId") as ObjectID;
|
||||
|
||||
if (id) {
|
||||
route = tempRoute.addRouteParam(
|
||||
RouteParams.DashboardId,
|
||||
id.toString(),
|
||||
);
|
||||
route = tempRoute.addRouteParam(RouteParams.DashboardId, id.toString());
|
||||
}
|
||||
|
||||
return tempRoute;
|
||||
|
||||
@@ -126,8 +126,7 @@ const Overview: FunctionComponent<PageComponentProps> = (
|
||||
scheduledMaintenanceStateTimelines,
|
||||
setScheduledMaintenanceStateTimelines,
|
||||
] = useState<Array<ScheduledMaintenanceStateTimeline>>([]);
|
||||
const uptimeHistoryDays: number =
|
||||
statusPage?.showUptimeHistoryInDays || 90;
|
||||
const uptimeHistoryDays: number = statusPage?.showUptimeHistoryInDays || 90;
|
||||
const startDate: Date = OneUptimeDate.getSomeDaysAgo(uptimeHistoryDays);
|
||||
const endDate: Date = OneUptimeDate.getCurrentDate();
|
||||
const [currentStatus, setCurrentStatus] = useState<MonitorStatus | null>(
|
||||
|
||||
@@ -224,8 +224,7 @@ export default class DashboardDomain extends BaseModel {
|
||||
type: TableColumnType.Entity,
|
||||
modelType: Dashboard,
|
||||
title: "Dashboard",
|
||||
description:
|
||||
"Relation to Dashboard Resource in which this object belongs",
|
||||
description: "Relation to Dashboard Resource in which this object belongs",
|
||||
})
|
||||
@ManyToOne(
|
||||
() => {
|
||||
|
||||
@@ -34,11 +34,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
.getCrudApiPath()
|
||||
?.toString()}/seo/:dashboardIdOrDomain`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
const dashboardIdOrDomain: string = req.params[
|
||||
"dashboardIdOrDomain"
|
||||
@@ -46,10 +42,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
|
||||
let dashboardId: ObjectID | null = null;
|
||||
|
||||
if (
|
||||
dashboardIdOrDomain &&
|
||||
dashboardIdOrDomain.includes(".")
|
||||
) {
|
||||
if (dashboardIdOrDomain && dashboardIdOrDomain.includes(".")) {
|
||||
// This is a domain - resolve to dashboard ID
|
||||
const dashboardDomain: DashboardDomain | null =
|
||||
await DashboardDomainService.findOneBy({
|
||||
@@ -114,8 +107,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
_id: dashboard._id?.toString() || "",
|
||||
title: dashboard.name || "Dashboard",
|
||||
description:
|
||||
dashboard.description ||
|
||||
"View dashboard metrics and insights.",
|
||||
dashboard.description || "View dashboard metrics and insights.",
|
||||
});
|
||||
} catch (err) {
|
||||
next(err);
|
||||
@@ -125,20 +117,12 @@ export default class DashboardAPI extends BaseAPI<
|
||||
|
||||
// Domain resolution endpoint
|
||||
this.router.post(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/domain`,
|
||||
`${new this.entityType().getCrudApiPath()?.toString()}/domain`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
if (!req.body["domain"]) {
|
||||
throw new BadDataException(
|
||||
"domain is required in request body",
|
||||
);
|
||||
throw new BadDataException("domain is required in request body");
|
||||
}
|
||||
|
||||
const domain: string = req.body["domain"] as string;
|
||||
@@ -160,9 +144,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
});
|
||||
|
||||
if (!dashboardDomain) {
|
||||
throw new BadDataException(
|
||||
"No dashboard found with this domain",
|
||||
);
|
||||
throw new BadDataException("No dashboard found with this domain");
|
||||
}
|
||||
|
||||
const objectId: ObjectID = dashboardDomain.dashboardId!;
|
||||
@@ -182,11 +164,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
.getCrudApiPath()
|
||||
?.toString()}/metadata/:dashboardId`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
const dashboardId: ObjectID = new ObjectID(
|
||||
req.params["dashboardId"] as string,
|
||||
@@ -214,11 +192,9 @@ export default class DashboardAPI extends BaseAPI<
|
||||
return Response.sendJsonObjectResponse(req, res, {
|
||||
_id: dashboard._id?.toString() || "",
|
||||
name: dashboard.name || "Dashboard",
|
||||
description:
|
||||
dashboard.description || "",
|
||||
description: dashboard.description || "",
|
||||
isPublicDashboard: dashboard.isPublicDashboard || false,
|
||||
enableMasterPassword:
|
||||
dashboard.enableMasterPassword || false,
|
||||
enableMasterPassword: dashboard.enableMasterPassword || false,
|
||||
});
|
||||
} catch (err) {
|
||||
next(err);
|
||||
@@ -231,11 +207,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
.getCrudApiPath()
|
||||
?.toString()}/master-password/:dashboardId`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
if (!req.params["dashboardId"]) {
|
||||
throw new BadDataException("Dashboard ID not found");
|
||||
@@ -277,10 +249,7 @@ export default class DashboardAPI extends BaseAPI<
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!dashboard.enableMasterPassword ||
|
||||
!dashboard.masterPassword
|
||||
) {
|
||||
if (!dashboard.enableMasterPassword || !dashboard.masterPassword) {
|
||||
throw new BadDataException(
|
||||
"Master password has not been configured for this dashboard.",
|
||||
);
|
||||
|
||||
@@ -29,11 +29,7 @@ export default class DashboardDomainAPI extends BaseAPI<
|
||||
this.router.get(
|
||||
`${new this.entityType().getCrudApiPath()?.toString()}/verify-cname/:id`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
if (!DashboardCNameRecord) {
|
||||
return Response.sendErrorResponse(
|
||||
@@ -101,8 +97,9 @@ export default class DashboardDomainAPI extends BaseAPI<
|
||||
);
|
||||
}
|
||||
|
||||
const isValid: boolean =
|
||||
await DashboardDomainService.isCnameValid(domain.fullDomain!);
|
||||
const isValid: boolean = await DashboardDomainService.isCnameValid(
|
||||
domain.fullDomain!,
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
return Response.sendErrorResponse(
|
||||
@@ -125,11 +122,7 @@ export default class DashboardDomainAPI extends BaseAPI<
|
||||
this.router.get(
|
||||
`${new this.entityType().getCrudApiPath()?.toString()}/order-ssl/:id`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
if (!DashboardCNameRecord) {
|
||||
return Response.sendErrorResponse(
|
||||
@@ -230,9 +223,7 @@ export default class DashboardDomainAPI extends BaseAPI<
|
||||
|
||||
await DashboardDomainService.orderCert(domain);
|
||||
|
||||
logger.debug(
|
||||
"SSL Provisioned for domain - " + domain.fullDomain,
|
||||
);
|
||||
logger.debug("SSL Provisioned for domain - " + domain.fullDomain);
|
||||
|
||||
return Response.sendEmptySuccessResponse(req, res);
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,42 +1,97 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1774524742177 implements MigrationInterface {
|
||||
name = 'MigrationName1774524742177'
|
||||
name = "MigrationName1774524742177";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "DashboardDomain" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "domainId" uuid NOT NULL, "dashboardId" uuid NOT NULL, "subdomain" character varying(100) NOT NULL, "fullDomain" character varying(100) NOT NULL, "createdByUserId" uuid, "cnameVerificationToken" character varying(100) NOT NULL, "isCnameVerified" boolean NOT NULL DEFAULT false, "isSslOrdered" boolean NOT NULL DEFAULT false, "isSslProvisioned" boolean NOT NULL DEFAULT false, "deletedByUserId" uuid, "customCertificate" text, "customCertificateKey" text, "isCustomCertificate" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_3897ff3212d5d8ddbdeca684bf6" PRIMARY KEY ("_id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_8c0e357d0490d45c89ee673005" ON "DashboardDomain" ("projectId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_0f58973f28172817bf9c1b34e7" ON "DashboardDomain" ("domainId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_601f68ad16b421ede8b06b3f40" ON "DashboardDomain" ("dashboardId") `);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" ADD "isPublicDashboard" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" ADD "enableMasterPassword" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" ADD "masterPassword" character varying(64)`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" ADD "ipWhitelist" text`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_8c0e357d0490d45c89ee673005c" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_0f58973f28172817bf9c1b34e73" FOREIGN KEY ("domainId") REFERENCES "Domain"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_601f68ad16b421ede8b06b3f40c" FOREIGN KEY ("dashboardId") REFERENCES "Dashboard"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_de80950ba9f0d034f5c47940b3c" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_de0c87b9c94b5dfeb21f1ce106f" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_de0c87b9c94b5dfeb21f1ce106f"`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_de80950ba9f0d034f5c47940b3c"`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_601f68ad16b421ede8b06b3f40c"`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_0f58973f28172817bf9c1b34e73"`);
|
||||
await queryRunner.query(`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_8c0e357d0490d45c89ee673005c"`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" DROP COLUMN "ipWhitelist"`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" DROP COLUMN "masterPassword"`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" DROP COLUMN "enableMasterPassword"`);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" DROP COLUMN "isPublicDashboard"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_601f68ad16b421ede8b06b3f40"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_0f58973f28172817bf9c1b34e7"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_8c0e357d0490d45c89ee673005"`);
|
||||
await queryRunner.query(`DROP TABLE "DashboardDomain"`);
|
||||
}
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "DashboardDomain" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "domainId" uuid NOT NULL, "dashboardId" uuid NOT NULL, "subdomain" character varying(100) NOT NULL, "fullDomain" character varying(100) NOT NULL, "createdByUserId" uuid, "cnameVerificationToken" character varying(100) NOT NULL, "isCnameVerified" boolean NOT NULL DEFAULT false, "isSslOrdered" boolean NOT NULL DEFAULT false, "isSslProvisioned" boolean NOT NULL DEFAULT false, "deletedByUserId" uuid, "customCertificate" text, "customCertificateKey" text, "isCustomCertificate" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_3897ff3212d5d8ddbdeca684bf6" PRIMARY KEY ("_id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_8c0e357d0490d45c89ee673005" ON "DashboardDomain" ("projectId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_0f58973f28172817bf9c1b34e7" ON "DashboardDomain" ("domainId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_601f68ad16b421ede8b06b3f40" ON "DashboardDomain" ("dashboardId") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" ADD "isPublicDashboard" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" ADD "enableMasterPassword" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" ADD "masterPassword" character varying(64)`,
|
||||
);
|
||||
await queryRunner.query(`ALTER TABLE "Dashboard" ADD "ipWhitelist" text`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_8c0e357d0490d45c89ee673005c" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_0f58973f28172817bf9c1b34e73" FOREIGN KEY ("domainId") REFERENCES "Domain"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_601f68ad16b421ede8b06b3f40c" FOREIGN KEY ("dashboardId") REFERENCES "Dashboard"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_de80950ba9f0d034f5c47940b3c" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" ADD CONSTRAINT "FK_de0c87b9c94b5dfeb21f1ce106f" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_de0c87b9c94b5dfeb21f1ce106f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_de80950ba9f0d034f5c47940b3c"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_601f68ad16b421ede8b06b3f40c"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_0f58973f28172817bf9c1b34e73"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "DashboardDomain" DROP CONSTRAINT "FK_8c0e357d0490d45c89ee673005c"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" DROP COLUMN "ipWhitelist"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" DROP COLUMN "masterPassword"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" DROP COLUMN "enableMasterPassword"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "Dashboard" DROP COLUMN "isPublicDashboard"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_601f68ad16b421ede8b06b3f40"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_0f58973f28172817bf9c1b34e7"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."IDX_8c0e357d0490d45c89ee673005"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "DashboardDomain"`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1774524742178 implements MigrationInterface {
|
||||
name = 'MigrationName1774524742178'
|
||||
name = "MigrationName1774524742178";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "StatusPage" ADD "showUptimeHistoryInDays" integer NOT NULL DEFAULT 90`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "StatusPage" DROP COLUMN "showUptimeHistoryInDays"`);
|
||||
}
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPage" ADD "showUptimeHistoryInDays" integer NOT NULL DEFAULT 90`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "StatusPage" DROP COLUMN "showUptimeHistoryInDays"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,5 +547,5 @@ export default [
|
||||
MigrationName1774355321449,
|
||||
MigrationName1774357353502,
|
||||
MigrationName1774524742177,
|
||||
MigrationName1774524742178
|
||||
MigrationName1774524742178,
|
||||
];
|
||||
|
||||
@@ -34,9 +34,7 @@ export class Service extends DatabaseService<DashboardDomain> {
|
||||
const domain: DomainModel | null = await DomainService.findOneBy({
|
||||
query: {
|
||||
_id:
|
||||
createBy.data.domainId?.toString() ||
|
||||
createBy.data.domain?._id ||
|
||||
"",
|
||||
createBy.data.domainId?.toString() || createBy.data.domain?._id || "",
|
||||
},
|
||||
select: { domain: true, isVerified: true },
|
||||
props: {
|
||||
@@ -175,9 +173,7 @@ export class Service extends DatabaseService<DashboardDomain> {
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(
|
||||
"SSL ordered for domain: " + dashboardDomain.fullDomain,
|
||||
);
|
||||
logger.debug("SSL ordered for domain: " + dashboardDomain.fullDomain);
|
||||
|
||||
await this.updateOneById({
|
||||
id: dashboardDomain.id!,
|
||||
@@ -308,9 +304,7 @@ export class Service extends DatabaseService<DashboardDomain> {
|
||||
|
||||
const token: string = dashboardDomain.cnameVerificationToken!;
|
||||
|
||||
logger.debug(
|
||||
"Checking for CNAME " + fullDomain + " with token " + token,
|
||||
);
|
||||
logger.debug("Checking for CNAME " + fullDomain + " with token " + token);
|
||||
|
||||
try {
|
||||
const result: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
||||
@@ -643,9 +637,7 @@ export class Service extends DatabaseService<DashboardDomain> {
|
||||
try {
|
||||
await this.orderCert(domain);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
"Cannot order cert for domain: " + domain.fullDomain,
|
||||
);
|
||||
logger.error("Cannot order cert for domain: " + domain.fullDomain);
|
||||
logger.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1448,7 +1448,7 @@ export class Service extends DatabaseService<WorkspaceNotificationSummary> {
|
||||
for (const [, td] of tlMap) {
|
||||
// For ack: if not explicitly acknowledged but resolved, use resolve time as ack time
|
||||
const eventTime: Date | undefined =
|
||||
kind === "ack" ? (td.ackAt || td.resolvedAt) : td.resolvedAt;
|
||||
kind === "ack" ? td.ackAt || td.resolvedAt : td.resolvedAt;
|
||||
if (eventTime && td.declaredAt) {
|
||||
total += OneUptimeDate.getMinutesBetweenTwoDates(
|
||||
td.declaredAt,
|
||||
|
||||
@@ -682,7 +682,9 @@ ${contextBlock}
|
||||
// Cluster context
|
||||
const clusterDetails: Array<string> = [];
|
||||
clusterDetails.push(`- Cluster: ${breakdown.clusterName}`);
|
||||
clusterDetails.push(`- Metric: ${breakdown.metricFriendlyName} (\`${breakdown.metricName}\`)`);
|
||||
clusterDetails.push(
|
||||
`- Metric: ${breakdown.metricFriendlyName} (\`${breakdown.metricName}\`)`,
|
||||
);
|
||||
|
||||
if (breakdown.attributes["k8s.namespace.name"]) {
|
||||
clusterDetails.push(
|
||||
@@ -695,23 +697,15 @@ ${contextBlock}
|
||||
);
|
||||
|
||||
// Affected resources
|
||||
if (
|
||||
breakdown.affectedResources &&
|
||||
breakdown.affectedResources.length > 0
|
||||
) {
|
||||
if (breakdown.affectedResources && breakdown.affectedResources.length > 0) {
|
||||
const resourceLines: Array<string> = [];
|
||||
|
||||
// Sort by metric value descending (worst first)
|
||||
const sortedResources: Array<KubernetesAffectedResource> = [
|
||||
...breakdown.affectedResources,
|
||||
].sort(
|
||||
(
|
||||
a: KubernetesAffectedResource,
|
||||
b: KubernetesAffectedResource,
|
||||
) => {
|
||||
return b.metricValue - a.metricValue;
|
||||
},
|
||||
);
|
||||
].sort((a: KubernetesAffectedResource, b: KubernetesAffectedResource) => {
|
||||
return b.metricValue - a.metricValue;
|
||||
});
|
||||
|
||||
// Show top 10 affected resources
|
||||
const resourcesToShow: Array<KubernetesAffectedResource> =
|
||||
@@ -798,9 +792,7 @@ ${contextBlock}
|
||||
metricName === "k8s.pod.phase" &&
|
||||
breakdown.attributes["k8s.pod.phase"] === "Pending"
|
||||
) {
|
||||
lines.push(
|
||||
`Pods are stuck in Pending phase and unable to be scheduled.`,
|
||||
);
|
||||
lines.push(`Pods are stuck in Pending phase and unable to be scheduled.`);
|
||||
lines.push(
|
||||
`Common causes: insufficient CPU/memory resources on nodes, node affinity/taint restrictions preventing scheduling, PersistentVolumeClaim pending, or resource quota exceeded.`,
|
||||
);
|
||||
@@ -811,7 +803,7 @@ ${contextBlock}
|
||||
}
|
||||
} else if (
|
||||
metricName === "k8s.node.condition_ready" ||
|
||||
metricName.includes("node") && metricName.includes("condition")
|
||||
(metricName.includes("node") && metricName.includes("condition"))
|
||||
) {
|
||||
lines.push(`One or more nodes have transitioned to a NotReady state.`);
|
||||
if (topResource.nodeName) {
|
||||
@@ -827,7 +819,7 @@ ${contextBlock}
|
||||
);
|
||||
} else if (
|
||||
metricName === "k8s.node.cpu.utilization" ||
|
||||
metricName.includes("cpu") && metricName.includes("utilization")
|
||||
(metricName.includes("cpu") && metricName.includes("utilization"))
|
||||
) {
|
||||
lines.push(`Node CPU utilization has exceeded the configured threshold.`);
|
||||
if (topResource.nodeName) {
|
||||
@@ -843,7 +835,7 @@ ${contextBlock}
|
||||
);
|
||||
} else if (
|
||||
metricName === "k8s.node.memory.usage" ||
|
||||
metricName.includes("memory") && metricName.includes("usage")
|
||||
(metricName.includes("memory") && metricName.includes("usage"))
|
||||
) {
|
||||
lines.push(
|
||||
`Node memory utilization has exceeded the configured threshold.`,
|
||||
@@ -879,7 +871,7 @@ ${contextBlock}
|
||||
);
|
||||
} else if (
|
||||
metricName === "k8s.job.failed_pods" ||
|
||||
metricName.includes("job") && metricName.includes("fail")
|
||||
(metricName.includes("job") && metricName.includes("fail"))
|
||||
) {
|
||||
lines.push(`Kubernetes Job has failed pods.`);
|
||||
if (topResource.workloadName) {
|
||||
@@ -916,9 +908,7 @@ ${contextBlock}
|
||||
metricName === "k8s.daemonset.misscheduled_nodes" ||
|
||||
metricName.includes("daemonset")
|
||||
) {
|
||||
lines.push(
|
||||
`DaemonSet has misscheduled or unavailable nodes.`,
|
||||
);
|
||||
lines.push(`DaemonSet has misscheduled or unavailable nodes.`);
|
||||
if (topResource.workloadName) {
|
||||
lines.push(
|
||||
`DaemonSet \`${topResource.workloadName}\` has **${topResource.metricValue}** misscheduled node(s).`,
|
||||
|
||||
@@ -1023,8 +1023,10 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
||||
logger.debug("Sending message to Microsoft Teams with data:");
|
||||
logger.debug(data);
|
||||
|
||||
// Teams adaptive cards have a ~28KB payload limit.
|
||||
// Split message blocks into chunks of 40 to avoid hitting the limit.
|
||||
/*
|
||||
* Teams adaptive cards have a ~28KB payload limit.
|
||||
* Split message blocks into chunks of 40 to avoid hitting the limit.
|
||||
*/
|
||||
const maxBlocksPerCard: number = 40;
|
||||
const allMessageBlocks: Array<WorkspaceMessageBlock> =
|
||||
data.workspaceMessagePayload.messageBlocks;
|
||||
|
||||
@@ -1140,11 +1140,7 @@ export default class SlackUtil extends WorkspaceBase {
|
||||
blocks: blocks,
|
||||
});
|
||||
} else {
|
||||
for (
|
||||
let i: number = 0;
|
||||
i < blocks.length;
|
||||
i += maxBlocksPerMessage
|
||||
) {
|
||||
for (let i: number = 0; i < blocks.length; i += maxBlocksPerMessage) {
|
||||
const chunk: Array<JSONObject> = blocks.slice(
|
||||
i,
|
||||
i + maxBlocksPerMessage,
|
||||
|
||||
@@ -95,7 +95,11 @@ const ComponentSettingsModal: FunctionComponent<ComponentProps> = (
|
||||
>
|
||||
<Icon
|
||||
icon={IconProp.Label}
|
||||
style={{ color: "#64748b", width: "0.875rem", height: "0.875rem" }}
|
||||
style={{
|
||||
color: "#64748b",
|
||||
width: "0.875rem",
|
||||
height: "0.875rem",
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
@@ -199,7 +203,11 @@ const ComponentSettingsModal: FunctionComponent<ComponentProps> = (
|
||||
>
|
||||
<Icon
|
||||
icon={IconProp.Settings}
|
||||
style={{ color: "#64748b", width: "0.875rem", height: "0.875rem" }}
|
||||
style={{
|
||||
color: "#64748b",
|
||||
width: "0.875rem",
|
||||
height: "0.875rem",
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
@@ -247,7 +255,11 @@ const ComponentSettingsModal: FunctionComponent<ComponentProps> = (
|
||||
>
|
||||
<Icon
|
||||
icon={IconProp.Link}
|
||||
style={{ color: "#64748b", width: "0.875rem", height: "0.875rem" }}
|
||||
style={{
|
||||
color: "#64748b",
|
||||
width: "0.875rem",
|
||||
height: "0.875rem",
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
@@ -291,7 +303,11 @@ const ComponentSettingsModal: FunctionComponent<ComponentProps> = (
|
||||
>
|
||||
<Icon
|
||||
icon={IconProp.ArrowCircleRight}
|
||||
style={{ color: "#64748b", width: "0.875rem", height: "0.875rem" }}
|
||||
style={{
|
||||
color: "#64748b",
|
||||
width: "0.875rem",
|
||||
height: "0.875rem",
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
|
||||
@@ -165,10 +165,7 @@ const ComponentsModal: FunctionComponent<ComponentProps> = (
|
||||
{/* Component cards grid */}
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
{categoryComponents.map(
|
||||
(
|
||||
componentMetadata: ComponentMetadata,
|
||||
j: number,
|
||||
) => {
|
||||
(componentMetadata: ComponentMetadata, j: number) => {
|
||||
const isSelected: boolean =
|
||||
selectedComponentMetadata !== null &&
|
||||
selectedComponentMetadata.id ===
|
||||
@@ -178,9 +175,7 @@ const ComponentsModal: FunctionComponent<ComponentProps> = (
|
||||
<div
|
||||
key={j}
|
||||
onClick={() => {
|
||||
setSelectedComponentMetadata(
|
||||
componentMetadata,
|
||||
);
|
||||
setSelectedComponentMetadata(componentMetadata);
|
||||
}}
|
||||
className="cursor-pointer transition-all duration-150"
|
||||
style={{
|
||||
@@ -219,9 +214,7 @@ const ComponentsModal: FunctionComponent<ComponentProps> = (
|
||||
<Icon
|
||||
icon={componentMetadata.iconProp}
|
||||
style={{
|
||||
color: isSelected
|
||||
? "#ffffff"
|
||||
: "#64748b",
|
||||
color: isSelected ? "#ffffff" : "#64748b",
|
||||
width: "1rem",
|
||||
height: "1rem",
|
||||
}}
|
||||
@@ -234,9 +227,7 @@ const ComponentsModal: FunctionComponent<ComponentProps> = (
|
||||
style={{
|
||||
fontSize: "0.8125rem",
|
||||
fontWeight: 600,
|
||||
color: isSelected
|
||||
? "#4338ca"
|
||||
: "#1e293b",
|
||||
color: isSelected ? "#4338ca" : "#1e293b",
|
||||
margin: 0,
|
||||
lineHeight: "1.25rem",
|
||||
}}
|
||||
@@ -246,9 +237,7 @@ const ComponentsModal: FunctionComponent<ComponentProps> = (
|
||||
<p
|
||||
style={{
|
||||
fontSize: "0.75rem",
|
||||
color: isSelected
|
||||
? "#6366f1"
|
||||
: "#94a3b8",
|
||||
color: isSelected ? "#6366f1" : "#94a3b8",
|
||||
margin: 0,
|
||||
marginTop: "2px",
|
||||
lineHeight: "1rem",
|
||||
|
||||
@@ -200,8 +200,7 @@ export const SubscriptionPlans: Array<SubscriptionPlan> =
|
||||
export const StatusPageCNameRecord: string =
|
||||
env("STATUS_PAGE_CNAME_RECORD") || "";
|
||||
|
||||
export const DashboardCNameRecord: string =
|
||||
env("DASHBOARD_CNAME_RECORD") || "";
|
||||
export const DashboardCNameRecord: string = env("DASHBOARD_CNAME_RECORD") || "";
|
||||
|
||||
export const AnalyticsKey: string = env("ANALYTICS_KEY") || "";
|
||||
export const AnalyticsHost: string = env("ANALYTICS_HOST");
|
||||
|
||||
@@ -80,8 +80,7 @@ export default class DashboardChartComponentUtil extends DashboardBaseComponentU
|
||||
|
||||
componentArguments.push({
|
||||
name: "Additional Queries",
|
||||
description:
|
||||
"Add multiple metric queries to overlay on the same chart",
|
||||
description: "Add multiple metric queries to overlay on the same chart",
|
||||
required: false,
|
||||
type: ComponentInputType.MetricsQueryConfigs,
|
||||
id: "metricQueryConfigs",
|
||||
|
||||
@@ -76,8 +76,7 @@ export default class DashboardGaugeComponentUtil extends DashboardBaseComponentU
|
||||
|
||||
componentArguments.push({
|
||||
name: "Warning Threshold",
|
||||
description:
|
||||
"Values above this threshold will be shown in yellow",
|
||||
description: "Values above this threshold will be shown in yellow",
|
||||
required: false,
|
||||
type: ComponentInputType.Number,
|
||||
id: "warningThreshold",
|
||||
@@ -86,8 +85,7 @@ export default class DashboardGaugeComponentUtil extends DashboardBaseComponentU
|
||||
|
||||
componentArguments.push({
|
||||
name: "Critical Threshold",
|
||||
description:
|
||||
"Values above this threshold will be shown in red",
|
||||
description: "Values above this threshold will be shown in red",
|
||||
required: false,
|
||||
type: ComponentInputType.Number,
|
||||
id: "criticalThreshold",
|
||||
|
||||
@@ -488,7 +488,8 @@ const monitorKubernetes: MonitorKubernetesFunction = async (data: {
|
||||
|
||||
if (resourceFilters.workloadName && resourceFilters.workloadType) {
|
||||
const workloadType: string = resourceFilters.workloadType.toLowerCase();
|
||||
attributes[`resource.k8s.${workloadType}.name`] = resourceFilters.workloadName;
|
||||
attributes[`resource.k8s.${workloadType}.name`] =
|
||||
resourceFilters.workloadName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,10 +570,14 @@ const monitorKubernetes: MonitorKubernetesFunction = async (data: {
|
||||
|
||||
if (metricAttrs["resource.k8s.deployment.name"]) {
|
||||
workloadType = "Deployment";
|
||||
workloadName = metricAttrs["resource.k8s.deployment.name"] as string;
|
||||
workloadName = metricAttrs[
|
||||
"resource.k8s.deployment.name"
|
||||
] as string;
|
||||
} else if (metricAttrs["resource.k8s.statefulset.name"]) {
|
||||
workloadType = "StatefulSet";
|
||||
workloadName = metricAttrs["resource.k8s.statefulset.name"] as string;
|
||||
workloadName = metricAttrs[
|
||||
"resource.k8s.statefulset.name"
|
||||
] as string;
|
||||
} else if (metricAttrs["resource.k8s.daemonset.name"]) {
|
||||
workloadType = "DaemonSet";
|
||||
workloadName = metricAttrs["resource.k8s.daemonset.name"] as string;
|
||||
@@ -584,7 +589,9 @@ const monitorKubernetes: MonitorKubernetesFunction = async (data: {
|
||||
workloadName = metricAttrs["resource.k8s.cronjob.name"] as string;
|
||||
} else if (metricAttrs["resource.k8s.replicaset.name"]) {
|
||||
workloadType = "ReplicaSet";
|
||||
workloadName = metricAttrs["resource.k8s.replicaset.name"] as string;
|
||||
workloadName = metricAttrs[
|
||||
"resource.k8s.replicaset.name"
|
||||
] as string;
|
||||
}
|
||||
|
||||
// Build unique key for deduplication
|
||||
|
||||
Reference in New Issue
Block a user