diff --git a/web/console-extensions.json b/web/console-extensions.json
index c6a0a3f1..56f36786 100644
--- a/web/console-extensions.json
+++ b/web/console-extensions.json
@@ -99,17 +99,6 @@
"insertAfter": "dashboards-virt"
}
},
- {
- "type": "console.tab",
- "properties": {
- "contextId": "dev-console-observe",
- "name": "%plugin__monitoring-plugin~Dashboards%",
- "href": "",
- "component": {
- "$codeRef": "LegacyDashboardsPage.MpCmoLegacyDashboardsPage"
- }
- }
- },
{
"type": "console.redux-reducer",
"properties": {
@@ -276,5 +265,53 @@
"path": ["/virt-monitoring/alerts/:ruleID"],
"component": { "$codeRef": "AlertsDetailsPage.MpCmoAlertsDetailsPage" }
}
+ },
+ {
+ "type": "console.page/route",
+ "properties": {
+ "exact": false,
+ "path": "/dev-monitoring/ns/:ns/alerts/:ruleID",
+ "component": { "$codeRef": "DevRedirects.AlertRedirect" }
+ }
+ },
+ {
+ "type": "console.page/route",
+ "properties": {
+ "exact": false,
+ "path": "/dev-monitoring/ns/:ns/rules/:id",
+ "component": { "$codeRef": "DevRedirects.RulesRedirect" }
+ }
+ },
+ {
+ "type": "console.page/route",
+ "properties": {
+ "exact": false,
+ "path": "/dev-monitoring/ns/:ns/silences/:id",
+ "component": { "$codeRef": "DevRedirects.SilenceRedirect" }
+ }
+ },
+ {
+ "type": "console.page/route",
+ "properties": {
+ "exact": false,
+ "path": "/dev-monitoring/ns/:ns/silences/:id/edit",
+ "component": { "$codeRef": "DevRedirects.SilenceEditRedirect" }
+ }
+ },
+ {
+ "type": "console.page/route",
+ "properties": {
+ "exact": false,
+ "path": "/dev-monitoring/ns/:ns/silences/~new",
+ "component": { "$codeRef": "DevRedirects.SilenceNewRedirect" }
+ }
+ },
+ {
+ "type": "console.page/route",
+ "properties": {
+ "exact": false,
+ "path": "/dev-monitoring/ns/:ns/metrics",
+ "component": { "$codeRef": "DevRedirects.MetricsRedirect" }
+ }
}
]
diff --git a/web/package.json b/web/package.json
index 0680a652..69683b17 100644
--- a/web/package.json
+++ b/web/package.json
@@ -192,7 +192,8 @@
"MonitoringReducer": "./store/reducers",
"IncidentsPage": "./components/Incidents/IncidentsPage",
"TargetsPage": "./components/targets-page",
- "PrometheusRedirectPage": "./components/prometheus-redirect-page",
+ "PrometheusRedirectPage": "./components/redirects/prometheus-redirect-page",
+ "DevRedirects": "./components/redirects/dev-redirects",
"MonitoringContext": "./contexts/MonitoringContext"
},
"dependencies": {
diff --git a/web/src/components/Incidents/IncidentsDetailsRowTable.tsx b/web/src/components/Incidents/IncidentsDetailsRowTable.tsx
index 2f9a64c1..0bd6a203 100644
--- a/web/src/components/Incidents/IncidentsDetailsRowTable.tsx
+++ b/web/src/components/Incidents/IncidentsDetailsRowTable.tsx
@@ -17,7 +17,7 @@ interface IncidentsDetailsRowTableProps {
}
const IncidentsDetailsRowTable = ({ alerts }: IncidentsDetailsRowTableProps) => {
- const [namespace, setNamespace] = useActiveNamespace();
+ const [, setNamespace] = useActiveNamespace();
const { perspective } = usePerspective();
const { t } = useTranslation(process.env.I18N_NAMESPACE);
@@ -34,7 +34,7 @@ const IncidentsDetailsRowTable = ({ alerts }: IncidentsDetailsRowTableProps) =>
setNamespace(ALL_NAMESPACES_KEY)}
>
{alertDetails.alertname}
@@ -63,7 +63,7 @@ const IncidentsDetailsRowTable = ({ alerts }: IncidentsDetailsRowTableProps) =>
}
return null;
- }, [alerts, perspective, namespace, setNamespace]);
+ }, [alerts, perspective, setNamespace]);
return (
diff --git a/web/src/components/MetricsPage.tsx b/web/src/components/MetricsPage.tsx
index 53e2f5a0..e8b70d3e 100644
--- a/web/src/components/MetricsPage.tsx
+++ b/web/src/components/MetricsPage.tsx
@@ -113,8 +113,7 @@ import {
t_global_spacer_sm,
t_global_font_family_mono,
} from '@patternfly/react-tokens';
-import { QueryParamProvider, StringParam, useQueryParam } from 'use-query-params';
-import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
+import { StringParam, useQueryParam } from 'use-query-params';
import { GraphUnits, isGraphUnit } from './metrics/units';
import { SimpleSelect, SimpleSelectOption } from '@patternfly/react-templates';
import { valueFormatter } from './console/console-shared/src/components/query-browser/QueryBrowserTooltip';
@@ -122,6 +121,7 @@ import { ALL_NAMESPACES_KEY } from './utils';
import { MonitoringProvider } from '../contexts/MonitoringContext';
import { DataTestIDs } from './data-test';
import { useMonitoring } from '../hooks/useMonitoring';
+import { useQueryNamespace } from './hooks/useQueryNamespace';
// Stores information about the currently focused query input
let focusedQuery;
@@ -1277,14 +1277,7 @@ const GraphUnitsDropDown: FC = () => {
const MetricsPage_: FC = () => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const [units, setUnits] = useQueryParam(QueryParams.Units, StringParam);
- const [queryNamespace, setQueryNamespace] = useQueryParam(QueryParams.Namespace, StringParam);
- const [activeNamespace, setActiveNamespace] = useActiveNamespace();
-
- useEffect(() => {
- if (queryNamespace && activeNamespace !== queryNamespace) {
- setActiveNamespace(queryNamespace);
- }
- }, [queryNamespace, activeNamespace, setActiveNamespace]);
+ const { setNamespace } = useQueryNamespace();
const dispatch = useDispatch();
@@ -1369,7 +1362,7 @@ const MetricsPage_: FC = () => {
{
dispatch(queryBrowserDeleteAllQueries());
- setQueryNamespace(namespace);
+ setNamespace(namespace);
}}
/>
@@ -1432,9 +1425,7 @@ const MetricsPage = withFallback(MetricsPage_);
export const MpCmoMetricsPage: React.FC = () => {
return (
-
-
-
+
);
};
diff --git a/web/src/components/alerting/AlertDetail/SilencedByTable.tsx b/web/src/components/alerting/AlertDetail/SilencedByTable.tsx
index 7263eb37..87b34702 100644
--- a/web/src/components/alerting/AlertDetail/SilencedByTable.tsx
+++ b/web/src/components/alerting/AlertDetail/SilencedByTable.tsx
@@ -1,11 +1,6 @@
import type { FC, MouseEvent } from 'react';
import { useState, useMemo } from 'react';
-import {
- ResourceIcon,
- Silence,
- SilenceStates,
- useActiveNamespace,
-} from '@openshift-console/dynamic-plugin-sdk';
+import { ResourceIcon, Silence, SilenceStates } from '@openshift-console/dynamic-plugin-sdk';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom-v5-compat';
import {
@@ -30,13 +25,12 @@ import { t_global_spacer_xs } from '@patternfly/react-tokens';
export const SilencedByList: FC<{ silences: Silence[] }> = ({ silences }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
const navigate = useNavigate();
const [isModalOpen, , setModalOpen, setModalClosed] = useBoolean(false);
const [silence, setSilence] = useState(null);
const editSilence = (event: MouseEvent, rowIndex: number) => {
- navigate(getEditSilenceAlertUrl(perspective, silences.at(rowIndex)?.id, namespace));
+ navigate(getEditSilenceAlertUrl(perspective, silences.at(rowIndex)?.id));
};
const rowActions = (silence: Silence): IAction[] => {
@@ -79,7 +73,7 @@ export const SilencedByList: FC<{ silences: Silence[] }> = ({ silences }) => {
{silence.name}
diff --git a/web/src/components/alerting/AlertList/AggregateAlertTableRow.tsx b/web/src/components/alerting/AlertList/AggregateAlertTableRow.tsx
index 5ac37454..f20958bb 100644
--- a/web/src/components/alerting/AlertList/AggregateAlertTableRow.tsx
+++ b/web/src/components/alerting/AlertList/AggregateAlertTableRow.tsx
@@ -1,9 +1,4 @@
-import {
- Alert,
- ResourceIcon,
- TableColumn,
- useActiveNamespace,
-} from '@openshift-console/dynamic-plugin-sdk';
+import { Alert, ResourceIcon, TableColumn } from '@openshift-console/dynamic-plugin-sdk';
import { ExpandableRowContent, Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import type { FC } from 'react';
import { useState, useMemo } from 'react';
@@ -33,7 +28,6 @@ const AggregateAlertTableRow: AggregateAlertTableRowProps = ({
const { perspective } = usePerspective();
const title = aggregatedAlert.name;
const isACMPerspective = perspective === 'acm';
- const [namespace] = useActiveNamespace();
const filteredAlerts = useMemo(
() => filterAlerts(aggregatedAlert.alerts, selectedFilters),
@@ -99,11 +93,7 @@ const AggregateAlertTableRow: AggregateAlertTableRowProps = ({
diff --git a/web/src/components/alerting/AlertList/AlertTableRow.tsx b/web/src/components/alerting/AlertList/AlertTableRow.tsx
index 30de8322..a84c52cb 100644
--- a/web/src/components/alerting/AlertList/AlertTableRow.tsx
+++ b/web/src/components/alerting/AlertList/AlertTableRow.tsx
@@ -21,7 +21,7 @@ import { DropdownItem, Flex, FlexItem } from '@patternfly/react-core';
import KebabDropdown from '../../../components/kebab-dropdown';
import type { FC } from 'react';
import { useTranslation } from 'react-i18next';
-import { useNavigate, useParams } from 'react-router-dom-v5-compat';
+import { useNavigate } from 'react-router-dom-v5-compat';
import { AlertResource, alertState } from '../../../components/utils';
import {
getAlertUrl,
@@ -35,9 +35,6 @@ const AlertTableRow: FC<{ alert: Alert }> = ({ alert }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
const navigate = useNavigate();
- const params = useParams<{ ns: string }>();
-
- const namespace = params.ns;
const state = alertState(alert);
@@ -49,7 +46,7 @@ const AlertTableRow: FC<{ alert: Alert }> = ({ alert }) => {
dropdownItems.unshift(
navigate(getNewSilenceAlertUrl(perspective, alert, namespace))}
+ onClick={() => navigate(getNewSilenceAlertUrl(perspective, alert))}
data-test={DataTestIDs.SilenceAlertDropdownItem}
>
{t('Silence alert')}
@@ -86,12 +83,7 @@ const AlertTableRow: FC<{ alert: Alert }> = ({ alert }) => {
diff --git a/web/src/components/alerting/AlertRulesDetailsPage.tsx b/web/src/components/alerting/AlertRulesDetailsPage.tsx
index 790b73e1..322d4c17 100644
--- a/web/src/components/alerting/AlertRulesDetailsPage.tsx
+++ b/web/src/components/alerting/AlertRulesDetailsPage.tsx
@@ -5,7 +5,6 @@ import {
PrometheusAlert,
ResourceIcon,
Timestamp,
- useActiveNamespace,
useResolvedExtensions,
} from '@openshift-console/dynamic-plugin-sdk';
import {
@@ -69,6 +68,7 @@ import { MonitoringProvider } from '../../contexts/MonitoringContext';
import { DataTestIDs } from '../data-test';
import { useAlerts } from '../../hooks/useAlerts';
+import { useQueryNamespace } from '../hooks/useQueryNamespace';
// Renders Prometheus template text and highlights any {{ ... }} tags that it contains
const PrometheusTemplate = ({ text }) => (
@@ -83,11 +83,10 @@ const PrometheusTemplate = ({ text }) => (
type ActiveAlertsProps = {
alerts: PrometheusAlert[];
- namespace: string;
ruleID: string;
};
-export const ActiveAlerts: FC = ({ alerts, namespace, ruleID }) => {
+export const ActiveAlerts: FC = ({ alerts, ruleID }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
const navigate = useNavigate();
@@ -110,7 +109,7 @@ export const ActiveAlerts: FC = ({ alerts, namespace, ruleID
{alertDescription(a)}
@@ -148,7 +147,7 @@ const AlertRulesDetailsPage_: FC = () => {
const { rules, rulesAlertLoading } = useAlerts();
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
+ const { namespace } = useQueryNamespace();
const rule = _.find(rules, { id: params.id });
@@ -187,10 +186,7 @@ const AlertRulesDetailsPage_: FC = () => {
-
+
{t('Alerting rules')}
@@ -316,7 +312,6 @@ const AlertRulesDetailsPage_: FC = () => {
to={getQueryBrowserUrl({
perspective: perspective,
query: rule?.query,
- namespace: namespace,
})}
>
@@ -372,7 +367,7 @@ const AlertRulesDetailsPage_: FC = () => {
{_.isEmpty(rule?.alerts) ? (
{t('None found')}
) : (
-
+
)}
diff --git a/web/src/components/alerting/AlertRulesPage.tsx b/web/src/components/alerting/AlertRulesPage.tsx
index 45fe6ba6..247491a7 100644
--- a/web/src/components/alerting/AlertRulesPage.tsx
+++ b/web/src/components/alerting/AlertRulesPage.tsx
@@ -97,7 +97,7 @@ const RuleTableRow: FC> = ({ obj }) => {
diff --git a/web/src/components/alerting/AlertUtils.tsx b/web/src/components/alerting/AlertUtils.tsx
index 25dc4941..49e36fd2 100644
--- a/web/src/components/alerting/AlertUtils.tsx
+++ b/web/src/components/alerting/AlertUtils.tsx
@@ -255,7 +255,7 @@ export const Graph: FC = ({
const GraphLink = () =>
query && perspective !== 'acm' ? (
-
+
{t('Inspect')}
) : null;
diff --git a/web/src/components/alerting/AlertingPage.tsx b/web/src/components/alerting/AlertingPage.tsx
index 38812d60..860a826d 100644
--- a/web/src/components/alerting/AlertingPage.tsx
+++ b/web/src/components/alerting/AlertingPage.tsx
@@ -13,6 +13,7 @@ import { useLocation } from 'react-router-dom';
import { AlertResource, RuleResource, SilenceResource } from '../utils';
import { useDispatch } from 'react-redux';
import { alertingClearSelectorData } from '../../store/actions';
+import { useQueryNamespace } from '../hooks/useQueryNamespace';
const CmoAlertsPage = lazy(() =>
import(/* webpackChunkName: "CmoAlertsPage" */ './AlertsPage').then((module) => ({
@@ -59,6 +60,7 @@ const AlertingPage: FC = () => {
const dispatch = useDispatch();
const [perspective] = useActivePerspective();
+ const { setNamespace } = useQueryNamespace();
const { plugin, prometheus } = useMonitoring();
@@ -100,9 +102,10 @@ const AlertingPage: FC = () => {
<>
{namespacedPages.includes(pathname) && (
- dispatch(alertingClearSelectorData(prometheus, namespace))
- }
+ onNamespaceChange={(namespace) => {
+ dispatch(alertingClearSelectorData(prometheus, namespace));
+ setNamespace(namespace);
+ }}
/>
)}
diff --git a/web/src/components/alerting/AlertsDetailsPage.tsx b/web/src/components/alerting/AlertsDetailsPage.tsx
index 6320e8eb..5d8ecdeb 100644
--- a/web/src/components/alerting/AlertsDetailsPage.tsx
+++ b/web/src/components/alerting/AlertsDetailsPage.tsx
@@ -8,7 +8,6 @@ import {
ResourceIcon,
ResourceLink,
Rule,
- useActiveNamespace,
useResolvedExtensions,
} from '@openshift-console/dynamic-plugin-sdk';
import * as _ from 'lodash-es';
@@ -90,6 +89,7 @@ import {
import { DataTestIDs } from '../data-test';
import { useAlerts } from '../../hooks/useAlerts';
import { useMonitoring } from '../../hooks/useMonitoring';
+import { useQueryNamespace } from '../hooks/useQueryNamespace';
const AlertsDetailsPage_: FC = () => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
@@ -101,7 +101,7 @@ const AlertsDetailsPage_: FC = () => {
const { alerts, rulesAlertLoading, silences } = useAlerts();
- const [namespace] = useActiveNamespace();
+ const { namespace } = useQueryNamespace();
const hideGraphs = useSelector(
(state: MonitoringState) => !!getObserveState(plugin, state).hideGraphs,
@@ -159,7 +159,7 @@ const AlertsDetailsPage_: FC = () => {
-
+
{t('Alerts')}
@@ -193,7 +193,7 @@ const AlertsDetailsPage_: FC = () => {
{state !== AlertStates.Silenced && (
{_.get(rule, 'name')}
@@ -383,7 +383,7 @@ const AlertsDetailsPage_: FC = () => {
- {silences.loaded && !_.isEmpty(alert?.silencedBy) && (
+ {silences?.loaded && !_.isEmpty(alert?.silencedBy) && (
<>
diff --git a/web/src/components/alerting/SilenceCreatePage.tsx b/web/src/components/alerting/SilenceCreatePage.tsx
index c79b8604..b8412704 100644
--- a/web/src/components/alerting/SilenceCreatePage.tsx
+++ b/web/src/components/alerting/SilenceCreatePage.tsx
@@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next';
import { getAllQueryArguments } from '../console/utils/router';
import { SilenceForm } from './SilenceForm';
import { MonitoringProvider } from '../../contexts/MonitoringContext';
-import { useActiveNamespace } from '@openshift-console/dynamic-plugin-sdk';
import { ALL_NAMESPACES_KEY } from '../utils';
+import { useQueryNamespace } from '../hooks/useQueryNamespace';
const CreateSilencePage = ({ isNamespaced }: { isNamespaced: boolean }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
@@ -23,11 +23,11 @@ const CreateSilencePage = ({ isNamespaced }: { isNamespaced: boolean }) => {
};
export const MpCmoCreateSilencePage = () => {
- const [activeNamespace] = useActiveNamespace();
+ const { namespace } = useQueryNamespace();
return (
-
+
);
};
diff --git a/web/src/components/alerting/SilenceForm.tsx b/web/src/components/alerting/SilenceForm.tsx
index 27d65a91..2e619fa7 100644
--- a/web/src/components/alerting/SilenceForm.tsx
+++ b/web/src/components/alerting/SilenceForm.tsx
@@ -1,8 +1,4 @@
-import {
- consoleFetchJSON,
- NamespaceBar,
- useActiveNamespace,
-} from '@openshift-console/dynamic-plugin-sdk';
+import { consoleFetchJSON, NamespaceBar } from '@openshift-console/dynamic-plugin-sdk';
import {
ActionGroup,
Alert,
@@ -54,6 +50,7 @@ import { DataTestIDs } from '../data-test';
import { ALL_NAMESPACES_KEY, getAlertmanagerSilencesUrl } from '../utils';
import { useAlerts } from '../../hooks/useAlerts';
import { useMonitoring } from '../../hooks/useMonitoring';
+import { useQueryNamespace } from '../hooks/useQueryNamespace';
const durationOff = '-';
@@ -133,7 +130,7 @@ const NegativeMatcherHelp = () => {
const SilenceForm_: FC = ({ defaults, Info, title, isNamespaced }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
- const [namespace] = useActiveNamespace();
+ const { namespace } = useQueryNamespace();
const { prometheus } = useMonitoring();
const navigate = useNavigate();
@@ -283,7 +280,7 @@ const SilenceForm_: FC = ({ defaults, Info, title, isNamespace
.then(({ silenceID }) => {
setError(undefined);
refetchSilencesAndAlerts();
- navigate(getSilenceAlertUrl(perspective, silenceID, namespace));
+ navigate(getSilenceAlertUrl(perspective, silenceID));
})
.catch((err) => {
const errorMessage =
diff --git a/web/src/components/alerting/SilencesDetailsPage.tsx b/web/src/components/alerting/SilencesDetailsPage.tsx
index 3e09f7ee..b2cdfc41 100644
--- a/web/src/components/alerting/SilencesDetailsPage.tsx
+++ b/web/src/components/alerting/SilencesDetailsPage.tsx
@@ -1,12 +1,7 @@
import * as _ from 'lodash-es';
import type { FC } from 'react';
-import {
- Alert,
- ResourceIcon,
- Timestamp,
- useActiveNamespace,
-} from '@openshift-console/dynamic-plugin-sdk';
+import { Alert, ResourceIcon, Timestamp } from '@openshift-console/dynamic-plugin-sdk';
import {
Breadcrumb,
BreadcrumbItem,
@@ -52,7 +47,6 @@ const SilencesDetailsPage_: FC = () => {
const { silences, rulesAlertLoading } = useAlerts();
- const [namespace] = useActiveNamespace();
const { perspective } = usePerspective();
const silence = _.find(silences?.data, { id });
@@ -72,10 +66,7 @@ const SilencesDetailsPage_: FC = () => {
-
+
{t('Silences')}
@@ -169,7 +160,7 @@ const SilencesDetailsPage_: FC = () => {
{t('Firing alerts')}
- {rulesAlertLoading.loaded ? (
+ {rulesAlertLoading?.loaded ? (
) : (
@@ -183,7 +174,7 @@ const SilencesDetailsPage_: FC = () => {
{t('Firing alerts')}
- {rulesAlertLoading.loaded ? (
+ {rulesAlertLoading?.loaded ? (
) : (
@@ -218,7 +209,6 @@ const SilencedAlertsList: FC = ({ alerts }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const navigate = useNavigate();
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
return _.isEmpty(alerts) ? (
{t('No Alerts found')}
@@ -236,7 +226,7 @@ const SilencedAlertsList: FC = ({ alerts }) => {
{a.labels.alertname}
@@ -250,7 +240,7 @@ const SilencedAlertsList: FC = ({ alerts }) => {
dropdownItems={[
navigate(getRuleUrl(perspective, a.rule, namespace))}
+ onClick={() => navigate(getRuleUrl(perspective, a.rule))}
>
{t('View alerting rule')}
,
diff --git a/web/src/components/alerting/SilencesPage.tsx b/web/src/components/alerting/SilencesPage.tsx
index a68d382c..a2c527f8 100644
--- a/web/src/components/alerting/SilencesPage.tsx
+++ b/web/src/components/alerting/SilencesPage.tsx
@@ -6,7 +6,6 @@ import {
Silence,
SilenceStates,
TableColumn,
- useActiveNamespace,
useListPageFilter,
VirtualizedTable,
} from '@openshift-console/dynamic-plugin-sdk';
@@ -281,13 +280,11 @@ const ExpireAllSilencesButton: FC = ({ setErrorMes
const { selectedSilences, setSelectedSilences } = useContext(SelectedSilencesContext);
- const [namespace] = useActiveNamespace();
-
const onClick = () => {
setInProgress();
Promise.allSettled(
[...selectedSilences].map((silenceID: string) =>
- consoleFetchJSON.delete(getFetchSilenceUrl(perspective, silenceID, namespace)),
+ consoleFetchJSON.delete(getFetchSilenceUrl(perspective, silenceID)),
),
).then((values) => {
setNotInProgress();
@@ -325,10 +322,9 @@ const SilenceTableRowWithCheckbox: FC> = ({ obj }) => (
const CreateSilenceButton: FC = memo(() => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
return (
-
+
diff --git a/web/src/components/alerting/SilencesUtils.tsx b/web/src/components/alerting/SilencesUtils.tsx
index c9e0d051..b42661b3 100644
--- a/web/src/components/alerting/SilencesUtils.tsx
+++ b/web/src/components/alerting/SilencesUtils.tsx
@@ -4,7 +4,6 @@ import {
ResourceIcon,
Silence,
SilenceStates,
- useActiveNamespace,
} from '@openshift-console/dynamic-plugin-sdk';
import {
Button,
@@ -57,7 +56,6 @@ import { DataTestIDs } from '../data-test';
export const SilenceTableRow: FC = ({ obj, showCheckbox }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
const { createdBy, endsAt, firingAlerts, id, name, startsAt, matchers } = obj;
const state = silenceState(obj);
@@ -107,7 +105,7 @@ export const SilenceTableRow: FC = ({ obj, showCheckbox })
{name}
@@ -205,14 +203,13 @@ export const SilenceState = ({ silence }) => {
export const SilenceDropdown: FC = ({ silence, toggleText }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
const navigate = useNavigate();
const [isOpen, setIsOpen, , setClosed] = useBoolean(false);
const [isModalOpen, , setModalOpen, setModalClosed] = useBoolean(false);
const editSilence = () => {
- navigate(getEditSilenceAlertUrl(perspective, silence.id, namespace));
+ navigate(getEditSilenceAlertUrl(perspective, silence.id));
};
const dropdownItems =
@@ -281,7 +278,6 @@ export const ExpireSilenceModal: FC = ({
}) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { perspective } = usePerspective();
- const [namespace] = useActiveNamespace();
const [isInProgress, , setInProgress, setNotInProgress] = useBoolean(false);
const [success, , setSuccess] = useBoolean(false);
@@ -289,7 +285,7 @@ export const ExpireSilenceModal: FC = ({
const expireSilence = () => {
setInProgress();
- const url = getFetchSilenceUrl(perspective, silenceID, namespace);
+ const url = getFetchSilenceUrl(perspective, silenceID);
consoleFetchJSON
.delete(url)
.then(() => {
diff --git a/web/src/components/console/graphs/promethues-graph.tsx b/web/src/components/console/graphs/promethues-graph.tsx
index c4229c2a..d97e22ee 100644
--- a/web/src/components/console/graphs/promethues-graph.tsx
+++ b/web/src/components/console/graphs/promethues-graph.tsx
@@ -21,7 +21,6 @@ const mapStateToProps = (state: RootState) => ({
const PrometheusGraphLink_: FC = ({
children,
query,
- namespace,
ariaChartLinkLabel,
}) => {
const { perspective } = usePerspective();
@@ -32,7 +31,7 @@ const PrometheusGraphLink_: FC = ({
const params = new URLSearchParams();
queries.forEach((q, index) => params.set(`query${index}`, q));
- const url = getMutlipleQueryBrowserUrl(perspective, params, namespace);
+ const url = getMutlipleQueryBrowserUrl(perspective, params);
return (
= forwardRef(
type PrometheusGraphLinkProps = {
canAccessMonitoring: boolean;
query: string | string[];
- namespace?: string;
ariaChartLinkLabel?: string;
};
diff --git a/web/src/components/dashboards/legacy/legacy-dashboard-page.tsx b/web/src/components/dashboards/legacy/legacy-dashboard-page.tsx
index d5935ae0..c102b1eb 100644
--- a/web/src/components/dashboards/legacy/legacy-dashboard-page.tsx
+++ b/web/src/components/dashboards/legacy/legacy-dashboard-page.tsx
@@ -1,9 +1,7 @@
-import { Overview } from '@openshift-console/dynamic-plugin-sdk';
+import { NamespaceBar, Overview } from '@openshift-console/dynamic-plugin-sdk';
import type { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom-v5-compat';
-import { QueryParamProvider } from 'use-query-params';
-import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
import { LoadingInline } from '../../../components/console/console-shared/src/components/loading/LoadingInline';
import withFallback from '../../console/console-shared/error/fallbacks/withFallback';
import { usePerspective } from '../../hooks/usePerspective';
@@ -12,16 +10,14 @@ import ErrorAlert from './error';
import { DashboardSkeletonLegacy } from './dashboard-skeleton-legacy';
import { useLegacyDashboards } from './useLegacyDashboards';
import { MonitoringProvider } from '../../../contexts/MonitoringContext';
+import { useOpenshiftProject } from './useOpenshiftProject';
type LegacyDashboardsPageProps = {
urlBoard: string;
- namespace?: string;
};
-const LegacyDashboardsPage_: FC = ({
- urlBoard,
- namespace, // only used in developer perspective
-}) => {
+const LegacyDashboardsPage_: FC = ({ urlBoard }) => {
+ const { project, setProject } = useOpenshiftProject();
const {
legacyDashboardsError,
legacyRows,
@@ -29,41 +25,42 @@ const LegacyDashboardsPage_: FC = ({
legacyDashboardsMetadata,
changeLegacyDashboard,
legacyDashboard,
- } = useLegacyDashboards(namespace, urlBoard);
+ } = useLegacyDashboards(project, urlBoard);
const { perspective } = usePerspective();
const { t } = useTranslation(process.env.I18N_NAMESPACE);
return (
-
-
- {legacyDashboardsLoading ? (
-
- ) : legacyDashboardsError ? (
-
- ) : (
-
- )}
-
-
+ <>
+ setProject(namespace)} />
+
+
+ {legacyDashboardsLoading ? (
+
+ ) : legacyDashboardsError ? (
+
+ ) : (
+
+ )}
+
+
+ >
);
};
const LegacyDashboardsPageWithFallback = withFallback(LegacyDashboardsPage_);
export const MpCmoLegacyDashboardsPage: FC = () => {
- const params = useParams<{ ns?: string; dashboardName: string }>();
+ const params = useParams<{ dashboardName: string }>();
return (
-
-
-
+
);
};
diff --git a/web/src/components/dashboards/legacy/legacy-dashboard.tsx b/web/src/components/dashboards/legacy/legacy-dashboard.tsx
index 69768342..02ced1e4 100644
--- a/web/src/components/dashboards/legacy/legacy-dashboard.tsx
+++ b/web/src/components/dashboards/legacy/legacy-dashboard.tsx
@@ -1,7 +1,6 @@
import * as _ from 'lodash-es';
import {
RedExclamationCircleIcon,
- useActiveNamespace,
useResolvedExtensions,
} from '@openshift-console/dynamic-plugin-sdk';
import {
@@ -39,7 +38,7 @@ import {
} from '../../hooks/usePerspective';
import KebabDropdown from '../../kebab-dropdown';
import { MonitoringState } from '../../../store/store';
-import { evaluateVariableTemplate } from './legacy-variable-dropdowns';
+import { evaluateVariableTemplate, Variable } from './legacy-variable-dropdowns';
import { Panel, Row } from './types';
import { QueryParams } from '../../query-params';
import { CustomDataSource } from '@openshift-console/dynamic-plugin-sdk-internal/lib/extensions/dashboard-data-source';
@@ -70,7 +69,6 @@ const QueryBrowserLink = ({
if (units) {
params.set(QueryParams.Units, units);
}
- const [namespace] = useActiveNamespace();
if (customDataSourceName) {
params.set('datasource', customDataSourceName);
@@ -79,7 +77,7 @@ const QueryBrowserLink = ({
return (
{t('Inspect')}
@@ -104,7 +102,6 @@ const Card: FC = memo(({ panel, perspective }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { plugin } = useMonitoring();
- const [namespace] = useActiveNamespace();
const pollInterval = useSelector(
(state: MonitoringState) => getObserveState(plugin, state).dashboards.pollInterval,
);
@@ -115,6 +112,9 @@ const Card: FC = memo(({ panel, perspective }) => {
(state: MonitoringState) => getObserveState(plugin, state).dashboards.variables,
);
+ // Directly use the namespace variable to prevent desync
+ const namespace = variables?.['namespace'] as Variable;
+
const ref = useRef();
const [, wasEverVisible] = useIsVisible(ref);
@@ -281,7 +281,9 @@ const Card: FC = memo(({ panel, perspective }) => {
if (!rawQueries.length) {
return null;
}
- const queries = rawQueries.map((expr) => evaluateVariableTemplate(expr, variables, timespan));
+ const queries = rawQueries.map((expr) =>
+ evaluateVariableTemplate(expr, variables, timespan, namespace?.value ?? ''),
+ );
const isLoading =
(_.some(queries, _.isUndefined) && dataSourceInfoLoading) || customDataSource === undefined;
@@ -353,7 +355,7 @@ const Card: FC = memo(({ panel, perspective }) => {
panel={panel}
pollInterval={pollInterval}
query={queries[0]}
- namespace={namespace}
+ namespace={namespace?.value ?? ''}
customDataSource={customDataSource}
/>
)}
@@ -362,7 +364,7 @@ const Card: FC = memo(({ panel, perspective }) => {
panel={panel}
pollInterval={pollInterval}
queries={queries}
- namespace={namespace}
+ namespace={namespace?.value ?? ''}
customDataSource={customDataSource}
/>
)}
diff --git a/web/src/components/dashboards/legacy/legacy-variable-dropdowns.tsx b/web/src/components/dashboards/legacy/legacy-variable-dropdowns.tsx
index 922c4ac5..99e841bf 100644
--- a/web/src/components/dashboards/legacy/legacy-variable-dropdowns.tsx
+++ b/web/src/components/dashboards/legacy/legacy-variable-dropdowns.tsx
@@ -23,7 +23,7 @@ import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { SingleTypeaheadDropdown } from '../../console/utils/single-typeahead-dropdown';
-import { getPrometheusBasePath, buildPrometheusUrl } from '../../utils';
+import { getPrometheusBasePath, buildPrometheusUrl, ALL_NAMESPACES_KEY } from '../../utils';
import { getQueryArgument, setQueryArgument } from '../../console/utils/router';
import { useSafeFetch } from '../../console/utils/safe-fetch-hook';
@@ -48,6 +48,7 @@ export const evaluateVariableTemplate = (
template: string,
variables: any,
timespan: number,
+ namespace: string,
): string => {
if (_.isEmpty(template)) {
return undefined;
@@ -81,8 +82,11 @@ export const evaluateVariableTemplate = (
result = undefined;
return false;
}
- const replacement =
+ let replacement =
v.value === MONITORING_DASHBOARDS_VARIABLE_ALL_OPTION_KEY ? '.+' : v.value || '';
+ if (v.name === 'namespace' && namespace !== ALL_NAMESPACES_KEY) {
+ replacement = namespace;
+ }
result = result.replace(re, replacement);
}
});
@@ -103,9 +107,10 @@ const LegacyDashboardsVariableOption = ({ value, isSelected, ...rest }) =>
);
-const LegacyDashboardsVariableDropdown: FC = ({ id, name, namespace }) => {
+const LegacyDashboardsVariableDropdown: FC = ({ id, name }) => {
const { t } = useTranslation(process.env.I18N_NAMESPACE);
const { plugin } = useMonitoring();
+ const [namespace] = useActiveNamespace();
const timespan = useSelector(
(state: MonitoringState) => getObserveState(plugin, state).dashboards.timespan,
@@ -115,11 +120,12 @@ const LegacyDashboardsVariableDropdown: FC = ({ id, name,
(state: MonitoringState) => getObserveState(plugin, state).dashboards.variables,
);
const variable = variables?.[name] as Variable;
+
const options = useDeepMemo(() => {
return variable?.options;
}, [variable?.options]);
- const query = evaluateVariableTemplate(variable?.query, variables, timespan);
+ const query = evaluateVariableTemplate(variable?.query, variables, timespan, namespace);
const dispatch = useDispatch();
@@ -309,7 +315,6 @@ const LegacyDashboardsVariableDropdown: FC = ({ id, name,
// Expects to be inside of a Patternfly Split Component
export const LegacyDashboardsAllVariableDropdowns: FC = () => {
- const [namespace] = useActiveNamespace();
const { plugin } = useMonitoring();
const variables = useSelector(
@@ -323,7 +328,7 @@ export const LegacyDashboardsAllVariableDropdowns: FC = () => {
return (
{Object.keys(variables).map((name: string) => (
-
+
))}
);
@@ -342,5 +347,4 @@ export type Variable = {
type VariableDropdownProps = {
id: string;
name: string;
- namespace?: string;
};
diff --git a/web/src/components/dashboards/legacy/useLegacyDashboards.ts b/web/src/components/dashboards/legacy/useLegacyDashboards.ts
index 62398af6..acc3237e 100644
--- a/web/src/components/dashboards/legacy/useLegacyDashboards.ts
+++ b/web/src/components/dashboards/legacy/useLegacyDashboards.ts
@@ -21,7 +21,8 @@ import {
import { CombinedDashboardMetadata } from '../perses/hooks/useDashboardsData';
import { useNavigate } from 'react-router-dom-v5-compat';
import { QueryParams } from '../../query-params';
-import { NumberParam, StringParam, useQueryParam } from 'use-query-params';
+import { NumberParam, useQueryParam } from 'use-query-params';
+import { ALL_NAMESPACES_KEY } from '../../utils';
export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
const { t } = useTranslation('plugin__monitoring-plugin');
@@ -31,18 +32,11 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
const safeFetch = useCallback(useSafeFetch(), []);
const [legacyDashboards, setLegacyDashboards] = useState([]);
const [legacyDashboardsError, setLegacyDashboardsError] = useState();
- const [dashboardParam] = useQueryParam(QueryParams.Dashboard, StringParam);
const [refreshInterval] = useQueryParam(QueryParams.RefreshInterval, NumberParam);
const [legacyDashboardsLoading, , , setLegacyDashboardsLoaded] = useBoolean(true);
- const [initialLoad, , , setInitialLoaded] = useBoolean(true);
+ const [initialLoad, , setInitialUnloaded, setInitialLoaded] = useBoolean(true);
const dispatch = useDispatch();
const navigate = useNavigate();
- const legacyDashboard = useMemo(() => {
- if (perspective === 'dev') {
- return dashboardParam;
- }
- return urlBoard;
- }, [perspective, dashboardParam, urlBoard]);
useEffect(() => {
safeFetch('/api/console/monitoring-dashboard-config')
@@ -50,7 +44,7 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
setLegacyDashboardsLoaded();
setLegacyDashboardsError(undefined);
let items = response.items;
- if (namespace) {
+ if (namespace && namespace !== ALL_NAMESPACES_KEY) {
items = _.filter(
items,
(item) => item.metadata?.labels['console.openshift.io/odc-dashboard'] === 'true',
@@ -83,7 +77,7 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
}, [namespace, safeFetch, setLegacyDashboardsLoaded, t]);
const legacyRows = useMemo(() => {
- const data = _.find(legacyDashboards, { name: legacyDashboard })?.data;
+ const data = _.find(legacyDashboards, { name: urlBoard })?.data;
return data?.rows?.length
? data.rows
@@ -101,17 +95,7 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
}
return acc;
}, []) ?? [];
- }, [legacyDashboard, legacyDashboards]);
-
- useEffect(() => {
- // Dashboard query argument is only set in dev perspective, so skip for admin
- if (perspective !== 'dev') {
- return;
- }
- const allVariables = getAllVariables(legacyDashboards, legacyDashboard, namespace);
- dispatch(dashboardsPatchAllVariables(allVariables));
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [namespace, legacyDashboard]);
+ }, [urlBoard, legacyDashboards]);
// Homogenize data needed for dashboards dropdown between legacy and perses dashboards
// to enable both to use the same component
@@ -140,10 +124,9 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
const queryArguments = getAllQueryArguments();
const params = new URLSearchParams(queryArguments);
- let url = getLegacyDashboardsUrl(perspective, newBoard, namespace);
- url = `${url}${perspective === 'dev' ? '&' : '?'}${params.toString()}`;
+ const url = `${getLegacyDashboardsUrl(perspective, newBoard)}?${params.toString()}`;
- if (newBoard !== legacyDashboard || initialLoad) {
+ if (newBoard !== urlBoard || initialLoad) {
if (params.get(QueryParams.Dashboard) !== newBoard) {
navigate(url, { replace: true });
}
@@ -165,7 +148,7 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
},
[
perspective,
- legacyDashboard,
+ urlBoard,
dispatch,
navigate,
namespace,
@@ -177,15 +160,24 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
useEffect(() => {
if (
- (!legacyDashboard ||
- !legacyDashboards.some((legacyBoard) => legacyBoard.name === legacyDashboard) ||
+ (!urlBoard ||
+ !legacyDashboards.some((legacyBoard) => legacyBoard.name === urlBoard) ||
initialLoad) &&
!_.isEmpty(legacyDashboards)
) {
- changeLegacyDashboard(legacyDashboard || legacyDashboards?.[0]?.name);
+ changeLegacyDashboard(urlBoard || legacyDashboards?.[0]?.name);
setInitialLoaded();
}
- }, [legacyDashboards, changeLegacyDashboard, initialLoad, setInitialLoaded, legacyDashboard]);
+ }, [legacyDashboards, changeLegacyDashboard, initialLoad, setInitialLoaded, urlBoard]);
+
+ useEffect(() => {
+ // Basically perform a full reload when changing a namespace to force the variables and the
+ // dashboard to reset. This is needed for when we transition between ALL_NS and a normal
+ // namespace, but is performed quickly and should help insure consistency when transitioning
+ // between any namespaces
+ setInitialUnloaded();
+ /* eslint-disable react-hooks/exhaustive-deps */
+ }, [namespace]);
// Clear variables on unmount
useEffect(() => {
@@ -201,7 +193,7 @@ export const useLegacyDashboards = (namespace: string, urlBoard: string) => {
legacyRows,
legacyDashboardsMetadata,
changeLegacyDashboard,
- legacyDashboard,
+ legacyDashboard: urlBoard,
};
};
@@ -227,11 +219,14 @@ const getAllVariables = (boards: Board[], newBoardName: string, namespace: strin
allVariables[v.name] = {
datasource: v.datasource,
includeAll: !!v.includeAll,
- isHidden: namespace && v.name === 'namespace' ? true : v.hide !== 0,
- isLoading: namespace ? v.type === 'query' && !namespace : v.type === 'query',
+ isHidden: v.name === 'namespace' && namespace !== ALL_NAMESPACES_KEY ? true : v.hide !== 0,
+ isLoading: v.name === 'namespace' ? false : v.type === 'query',
options: _.map(v.options, 'value'),
query: v.type === 'query' ? v.query : undefined,
- value: namespace && v.name === 'namespace' ? namespace : value || v.options?.[0]?.value,
+ value:
+ v.name === 'namespace' && namespace !== ALL_NAMESPACES_KEY
+ ? namespace
+ : value || v.options?.[0]?.value,
};
}
});
diff --git a/web/src/components/dashboards/legacy/useOpenshiftProject.ts b/web/src/components/dashboards/legacy/useOpenshiftProject.ts
new file mode 100644
index 00000000..10a8cfb6
--- /dev/null
+++ b/web/src/components/dashboards/legacy/useOpenshiftProject.ts
@@ -0,0 +1,74 @@
+import { useActiveNamespace } from '@openshift-console/dynamic-plugin-sdk';
+import { useCallback, useEffect } from 'react';
+import { QueryParams } from '../../query-params';
+import { StringParam, useQueryParam } from 'use-query-params';
+import { useDispatch, useSelector } from 'react-redux';
+import { dashboardsPatchVariable } from '../../../store/actions';
+import { MonitoringState } from '../../../store/store';
+import { getObserveState } from '../../hooks/usePerspective';
+import { useMonitoring } from '../../../hooks/useMonitoring';
+import { ALL_NAMESPACES_KEY } from '../../utils';
+
+export const useOpenshiftProject = () => {
+ const [activeNamespace, setActiveNamespace] = useActiveNamespace();
+ const [openshiftProject, setOpenshiftProject] = useQueryParam(
+ QueryParams.OpenshiftProject,
+ StringParam,
+ );
+ const { plugin } = useMonitoring();
+ const variableNamespace = useSelector(
+ (state: MonitoringState) =>
+ getObserveState(plugin, state).dashboards.variables['namespace']?.value ?? '',
+ );
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ // If the URL parameter is set, but the activeNamespace doesn't match it, then
+ // set the activeNamespace to match the URL parameter
+ if (openshiftProject && openshiftProject !== activeNamespace) {
+ setActiveNamespace(openshiftProject);
+ if (variableNamespace !== openshiftProject && openshiftProject !== ALL_NAMESPACES_KEY) {
+ dispatch(
+ dashboardsPatchVariable('namespace', {
+ // Dashboards space variable shouldn't use the ALL_NAMESPACES_KEY
+ value: openshiftProject,
+ }),
+ );
+ }
+ return;
+ }
+ if (!openshiftProject) {
+ setOpenshiftProject(activeNamespace);
+ if (variableNamespace !== activeNamespace && openshiftProject !== ALL_NAMESPACES_KEY) {
+ // Dashboards space variable shouldn't use the ALL_NAMESPACES_KEY
+ dispatch(
+ dashboardsPatchVariable('namespace', {
+ value: activeNamespace,
+ }),
+ );
+ }
+ return;
+ }
+ }, [
+ activeNamespace,
+ setActiveNamespace,
+ openshiftProject,
+ setOpenshiftProject,
+ dispatch,
+ variableNamespace,
+ ]);
+
+ const setProject = useCallback(
+ (namespace: string) => {
+ setActiveNamespace(namespace);
+ setOpenshiftProject(namespace);
+ dispatch(dashboardsPatchVariable('namespace', { value: namespace }));
+ },
+ [setActiveNamespace, setOpenshiftProject, dispatch],
+ );
+
+ return {
+ project: openshiftProject,
+ setProject,
+ };
+};
diff --git a/web/src/components/dashboards/perses/dashboard-page.tsx b/web/src/components/dashboards/perses/dashboard-page.tsx
index d8e3be2d..d2d28a03 100644
--- a/web/src/components/dashboards/perses/dashboard-page.tsx
+++ b/web/src/components/dashboards/perses/dashboard-page.tsx
@@ -1,8 +1,6 @@
import { Overview } from '@openshift-console/dynamic-plugin-sdk';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { FC } from 'react';
-import { QueryParamProvider } from 'use-query-params';
-import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
import { LoadingInline } from '../../console/console-shared/src/components/loading/LoadingInline';
import { PersesWrapper } from './PersesWrapper';
import { DashboardSkeleton } from './dashboard-skeleton';
@@ -65,11 +63,9 @@ const MonitoringDashboardsPage_: FC = () => {
const MonitoringDashboardsPageWrapper: FC = () => {
return (
-
-
-
-
-
+
+
+
);
};
diff --git a/web/src/components/dashboards/shared/dashboard-dropdown.tsx b/web/src/components/dashboards/shared/dashboard-dropdown.tsx
index d00ca5ba..bbaa5e40 100644
--- a/web/src/components/dashboards/shared/dashboard-dropdown.tsx
+++ b/web/src/components/dashboards/shared/dashboard-dropdown.tsx
@@ -9,7 +9,7 @@ import {
StackItem,
} from '@patternfly/react-core';
import type { FC } from 'react';
-import { memo } from 'react';
+import { memo, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { SingleTypeaheadDropdown } from '../../console/utils/single-typeahead-dropdown';
@@ -61,6 +61,12 @@ export const DashboardDropdown: FC = ({ items, onChange,
children: item.title,
}));
+ useEffect(() => {
+ if (items.filter((item) => item.name === selectedKey).length === 0) {
+ onChange(items.at(0)?.name);
+ }
+ }, [items, selectedKey, onChange]);
+
return (
diff --git a/web/src/components/hooks/usePerspective.tsx b/web/src/components/hooks/usePerspective.tsx
index e609b4cf..c090bb72 100644
--- a/web/src/components/hooks/usePerspective.tsx
+++ b/web/src/components/hooks/usePerspective.tsx
@@ -5,7 +5,6 @@ import * as _ from 'lodash-es';
import {
ALERTMANAGER_BASE_PATH,
ALERTMANAGER_PROXY_PATH,
- ALERTMANAGER_TENANCY_BASE_PATH,
AlertResource,
labelsToParams,
MonitoringPlugins,
@@ -62,161 +61,124 @@ export const usePerspective = (): usePerspectiveReturn => {
}
};
-export const getAlertsUrl = (perspective: Perspective, namespace?: string) => {
+export const getAlertsUrl = (perspective: Perspective) => {
switch (perspective) {
case 'acm':
return `/multicloud${AlertResource.url}`;
- case 'admin':
- return AlertResource.url;
case 'virtualization-perspective':
return `/virt-monitoring/alerts`;
- case 'dev':
+ case 'admin':
default:
- return `/dev-monitoring/ns/${namespace}/alerts`;
+ return AlertResource.url;
}
};
// There is no equivalent rules list page in the developer perspective
-export const getAlertRulesUrl = (perspective: Perspective, namespace?: string) => {
+export const getAlertRulesUrl = (perspective: Perspective) => {
switch (perspective) {
case 'acm':
return `/multicloud${RuleResource.url}`;
case 'virtualization-perspective':
return `/virt-monitoring/alertrules`;
- case 'dev':
- return `/dev-monitoring/ns/${namespace}/alertrules`;
case 'admin':
default:
return RuleResource.url;
}
};
-export const getSilencesUrl = (perspective: Perspective, namespace?: string) => {
+export const getSilencesUrl = (perspective: Perspective) => {
switch (perspective) {
case 'acm':
return `/multicloud${SilenceResource.url}`;
- case 'admin':
- return SilenceResource.url;
case 'virtualization-perspective':
return `/virt-monitoring/silences`;
- case 'dev':
+ case 'admin':
default:
- return `/dev-monitoring/ns/${namespace}/silences`;
+ return SilenceResource.url;
}
};
-export const getNewSilenceAlertUrl = (
- perspective: Perspective,
- alert: PrometheusAlert,
- namespace?: string,
-) => {
+export const getNewSilenceAlertUrl = (perspective: Perspective, alert: PrometheusAlert) => {
switch (perspective) {
case 'acm':
return `/multicloud${SilenceResource.url}/~new?${labelsToParams(alert.labels)}`;
- case 'admin':
- return `${SilenceResource.url}/~new?${labelsToParams(alert.labels)}`;
case 'virtualization-perspective':
return `/virt-monitoring/silences/~new?${labelsToParams(alert.labels)}`;
- case 'dev':
+ case 'admin':
default:
- return `/dev-monitoring/ns/${namespace}/silences/~new?${labelsToParams(alert.labels)}`;
+ return `${SilenceResource.url}/~new?${labelsToParams(alert.labels)}`;
}
};
-export const getNewSilenceUrl = (perspective: Perspective, namespace?: string) => {
+export const getNewSilenceUrl = (perspective: Perspective) => {
switch (perspective) {
case 'acm':
return `/multicloud${SilenceResource.url}/~new`;
case 'virtualization-perspective':
return `/virt-monitoring/silences/~new`;
case 'admin':
- return `${SilenceResource.url}/~new`;
- case 'dev':
default:
- return `/dev-monitoring/ns/${namespace}/silences/~new`;
+ return `${SilenceResource.url}/~new`;
}
};
-export const getRuleUrl = (perspective: Perspective, rule: Rule, namespace?: string) => {
+export const getRuleUrl = (perspective: Perspective, rule: Rule) => {
switch (perspective) {
case 'acm':
return `/multicloud${RuleResource.url}/${_.get(rule, 'id')}`;
case 'virtualization-perspective':
return `/virt-monitoring/alertrules/${rule?.id}`;
case 'admin':
- return `${RuleResource.url}/${_.get(rule, 'id')}`;
- case 'dev':
default:
- return `/dev-monitoring/ns/${namespace}/rules/${rule?.id}`;
+ return `${RuleResource.url}/${_.get(rule, 'id')}`;
}
};
-export const getSilenceAlertUrl = (perspective: Perspective, id: string, namespace?: string) => {
+export const getSilenceAlertUrl = (perspective: Perspective, id: string) => {
switch (perspective) {
case 'acm':
return `/multicloud${SilenceResource.url}/${id}`;
case 'virtualization-perspective':
return `/virt-monitoring/silences/${id}`;
case 'admin':
- return `${SilenceResource.url}/${id}`;
- case 'dev':
default:
- return `/dev-monitoring/ns/${namespace}/silences/${id}`;
+ return `${SilenceResource.url}/${id}`;
}
};
-export const getEditSilenceAlertUrl = (
- perspective: Perspective,
- id: string,
- namespace?: string,
-) => {
+export const getEditSilenceAlertUrl = (perspective: Perspective, id: string) => {
switch (perspective) {
case 'acm':
return `/multicloud${SilenceResource.url}/${id}/edit`;
- case 'admin':
- return `${SilenceResource.url}/${id}/edit`;
case 'virtualization-perspective':
return `/virt-monitoring/silences/${id}/edit`;
- case 'dev':
+ case 'admin':
default:
- return `/dev-monitoring/ns/${namespace}/silences/${id}/edit`;
+ return `${SilenceResource.url}/${id}/edit`;
}
};
-export const getAlertUrl = (
- perspective: Perspective,
- alert: PrometheusAlert,
- ruleID: string,
- namespace?: string,
-) => {
+export const getAlertUrl = (perspective: Perspective, alert: PrometheusAlert, ruleID: string) => {
switch (perspective) {
case 'acm':
return `/multicloud${AlertResource.url}/${ruleID}?${labelsToParams(alert.labels)}`;
case 'virtualization-perspective':
return `/virt-monitoring/alerts/${ruleID}?${labelsToParams(alert.labels)}`;
case 'admin':
- return `${AlertResource.url}/${ruleID}?${labelsToParams(alert.labels)}`;
- case 'dev':
default:
- return `/dev-monitoring/ns/${namespace}/alerts/${ruleID}?${labelsToParams(alert.labels)}`;
+ return `${AlertResource.url}/${ruleID}?${labelsToParams(alert.labels)}`;
}
};
-export const getFetchSilenceUrl = (
- perspective: Perspective,
- silenceID: string,
- namespace?: string,
-) => {
+export const getFetchSilenceUrl = (perspective: Perspective, silenceID: string) => {
switch (perspective) {
case 'acm':
return `${ALERTMANAGER_PROXY_PATH}/api/v2/silence/${silenceID}`;
- case 'admin':
- return `${ALERTMANAGER_BASE_PATH}/api/v2/silence/${silenceID}`;
case 'virtualization-perspective':
return `${ALERTMANAGER_BASE_PATH}/api/v2/silence/${silenceID}`;
- case 'dev':
default:
- return `${ALERTMANAGER_TENANCY_BASE_PATH}/api/v2/silence/${silenceID}?namespace=${namespace}`;
+ case 'admin':
+ return `${ALERTMANAGER_BASE_PATH}/api/v2/silence/${silenceID}`;
}
};
@@ -234,63 +196,45 @@ export const getObserveState = (plugin: MonitoringPlugins, state: MonitoringStat
export const getQueryBrowserUrl = ({
perspective,
query,
- namespace,
units,
}: {
perspective: Perspective;
query: string;
- namespace?: string;
units?: GraphUnits;
}) => {
const unitsQueryParam = units ? `&${QueryParams.Units}=${units}` : '';
switch (perspective) {
- case 'admin':
- return `/monitoring/query-browser?query0=${encodeURIComponent(query)}${unitsQueryParam}`;
- case 'dev':
- return `/dev-monitoring/ns/${namespace}/metrics?query0=${encodeURIComponent(
- query,
- )}${unitsQueryParam}`;
case 'virtualization-perspective':
return `/virt-monitoring/query-browser?query0=${encodeURIComponent(query)}${unitsQueryParam}`;
case 'acm':
- default:
return '';
+ case 'admin':
+ default:
+ return `/monitoring/query-browser?query0=${encodeURIComponent(query)}${unitsQueryParam}`;
}
};
-export const getMutlipleQueryBrowserUrl = (
- perspective: Perspective,
- params: URLSearchParams,
- namespace?: string,
-) => {
+export const getMutlipleQueryBrowserUrl = (perspective: Perspective, params: URLSearchParams) => {
switch (perspective) {
- case 'admin':
- return `/monitoring/query-browser?${params.toString()}`;
- case 'dev':
- return `/dev-monitoring/ns/${namespace}/metrics?${params.toString()}`;
case 'virtualization-perspective':
return `/virt-monitoring/query-browser?${params.toString()}`;
case 'acm':
- default:
return '';
+ case 'admin':
+ default:
+ return `/monitoring/query-browser?${params.toString()}`;
}
};
-export const getLegacyDashboardsUrl = (
- perspective: Perspective,
- boardName: string,
- namespace?: string,
-) => {
+export const getLegacyDashboardsUrl = (perspective: Perspective, boardName: string) => {
switch (perspective) {
case 'virtualization-perspective':
return `/virt-monitoring/dashboards/${boardName}`;
- case 'admin':
- return `/monitoring/dashboards/${boardName}`;
- case 'dev':
- return `/dev-monitoring/ns/${namespace}?dashboard=${boardName}`;
case 'acm':
- default:
return '';
+ case 'admin':
+ default:
+ return `/monitoring/dashboards/${boardName}`;
}
};
diff --git a/web/src/components/hooks/useQueryNamespace.ts b/web/src/components/hooks/useQueryNamespace.ts
new file mode 100644
index 00000000..5ad85f8c
--- /dev/null
+++ b/web/src/components/hooks/useQueryNamespace.ts
@@ -0,0 +1,25 @@
+import { useEffect } from 'react';
+import { StringParam, useQueryParam } from 'use-query-params';
+import { QueryParams } from '../query-params';
+import { useActiveNamespace } from '@openshift-console/dynamic-plugin-sdk';
+
+// Utility hook to syncronize the namespace parameter in the URL with the activeNamespace
+// the console uses
+export const useQueryNamespace = () => {
+ const [queryNamespace, setQueryNamespace] = useQueryParam(QueryParams.Namespace, StringParam);
+ const [activeNamespace, setActiveNamespace] = useActiveNamespace();
+
+ useEffect(() => {
+ if (queryNamespace && activeNamespace !== queryNamespace) {
+ setActiveNamespace(queryNamespace);
+ }
+ if (!queryNamespace) {
+ setQueryNamespace(activeNamespace);
+ }
+ }, [queryNamespace, activeNamespace, setActiveNamespace]);
+
+ return {
+ namespace: queryNamespace,
+ setNamespace: setQueryNamespace,
+ };
+};
diff --git a/web/src/components/query-params.ts b/web/src/components/query-params.ts
index 0255bf2c..7a43ce4b 100644
--- a/web/src/components/query-params.ts
+++ b/web/src/components/query-params.ts
@@ -7,4 +7,7 @@ export enum QueryParams {
Project = 'project',
Namespace = 'namespace',
Units = 'units',
+ // Use openshift-namespace query parameter for dashboards page since grafana variables cannot have
+ // a `-` character in their name
+ OpenshiftProject = 'openshift-project',
}
diff --git a/web/src/components/redirects/dev-redirects.tsx b/web/src/components/redirects/dev-redirects.tsx
new file mode 100644
index 00000000..db2c8bd1
--- /dev/null
+++ b/web/src/components/redirects/dev-redirects.tsx
@@ -0,0 +1,85 @@
+import type { FC } from 'react';
+import { Navigate, useParams } from 'react-router-dom-v5-compat';
+import {
+ getAlertRulesUrl,
+ getAlertsUrl,
+ getEditSilenceAlertUrl,
+ getLegacyDashboardsUrl,
+ getSilenceAlertUrl,
+} from '../hooks/usePerspective';
+import { QueryParams } from '../query-params';
+import { SilenceResource } from '../utils';
+
+export const DashboardRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.OpenshiftProject, pathParams.ns);
+
+ const dashboardName = queryParams.get(QueryParams.Dashboard);
+ queryParams.delete(QueryParams.Dashboard);
+
+ return ;
+};
+
+export const AlertRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string; ruleID: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.Namespace, pathParams.ns);
+
+ return (
+
+ );
+};
+
+export const RulesRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string; id: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.Namespace, pathParams.ns);
+
+ return (
+
+ );
+};
+
+export const SilenceRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string; id: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.Namespace, pathParams.ns);
+
+ return (
+
+ );
+};
+
+export const SilenceEditRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string; id: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.Namespace, pathParams.ns);
+
+ return (
+
+ );
+};
+
+export const SilenceNewRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.Namespace, pathParams.ns);
+
+ return ;
+};
+
+export const MetricsRedirect: FC = () => {
+ const pathParams = useParams<{ ns: string }>();
+
+ const queryParams = new URLSearchParams(window.location.search);
+ queryParams.append(QueryParams.Namespace, pathParams.ns);
+
+ return ;
+};
diff --git a/web/src/components/prometheus-redirect-page.tsx b/web/src/components/redirects/prometheus-redirect-page.tsx
similarity index 84%
rename from web/src/components/prometheus-redirect-page.tsx
rename to web/src/components/redirects/prometheus-redirect-page.tsx
index d423acfe..b09d8c11 100644
--- a/web/src/components/prometheus-redirect-page.tsx
+++ b/web/src/components/redirects/prometheus-redirect-page.tsx
@@ -1,7 +1,7 @@
import type { FC } from 'react';
import { Navigate } from 'react-router-dom-v5-compat';
-import { getAllQueryArguments } from './console/utils/router';
-import { usePerspective } from './hooks/usePerspective';
+import { getAllQueryArguments } from '../console/utils/router';
+import { usePerspective } from '../hooks/usePerspective';
// Handles links that have the Prometheus UI's URL format (expected for links in alerts sent by
// Alertmanager). The Prometheus UI specifies the PromQL query with the GET param `g0.expr`, so we
diff --git a/web/src/contexts/MonitoringContext.tsx b/web/src/contexts/MonitoringContext.tsx
index 66858757..7f7d7a62 100644
--- a/web/src/contexts/MonitoringContext.tsx
+++ b/web/src/contexts/MonitoringContext.tsx
@@ -1,5 +1,7 @@
import React from 'react';
import { MonitoringPlugins, Prometheus } from '../components/utils';
+import { QueryParamProvider } from 'use-query-params';
+import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
type MonitoringContextType = {
/** Dictates which plugin this code is being run in */
@@ -16,4 +18,8 @@ export const MonitoringContext = React.createContext({
export const MonitoringProvider: React.FC<{ monitoringContext: MonitoringContextType }> = ({
children,
monitoringContext,
-}) => {children};
+}) => (
+
+ {children}
+
+);
diff --git a/web/src/e2e-tests-app.tsx b/web/src/e2e-tests-app.tsx
index c5a06ae3..ddb60590 100644
--- a/web/src/e2e-tests-app.tsx
+++ b/web/src/e2e-tests-app.tsx
@@ -3,8 +3,6 @@ import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter, Link, Route, Routes } from 'react-router-dom-v5-compat';
import { combineReducers, createStore } from 'redux';
-import { QueryParamProvider } from 'use-query-params';
-import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5';
import { MpCmoAlertingPage } from './components/alerting/AlertingPage';
import { MpCmoAlertRulesDetailsPage } from './components/alerting/AlertRulesDetailsPage';
import { MpCmoAlertRulesPage } from './components/alerting/AlertRulesPage';
@@ -16,7 +14,7 @@ import { MpCmoSilencesDetailsPage } from './components/alerting/SilencesDetailsP
import { MpCmoSilencesPage } from './components/alerting/SilencesPage';
import { MpCmoLegacyDashboardsPage } from './components/dashboards/legacy/legacy-dashboard-page';
import { MpCmoMetricsPage } from './components/MetricsPage';
-import PrometheusRedirectPage from './components/prometheus-redirect-page';
+import PrometheusRedirectPage from './components/redirects/prometheus-redirect-page';
import { MpCmoTargetsPage } from './components/targets-page';
import i18n from './i18n';
import ObserveReducers from './store/reducers';
@@ -37,31 +35,29 @@ const App = () => (
Dashboards
Targets
-
-
- } />
+
+ } />
- } />
- } />
+ } />
+ } />
- } />
- } />
+ } />
+ } />
- } />
- } />
+ } />
+ } />
- } />
- } />
- } />
- } />
+ } />
+ } />
+ } />
+ } />
- }>
- } />
- } />
- } />
-
-
-
+ }>
+ } />
+ } />
+ } />
+
+
);
diff --git a/web/src/hooks/useAlerts.ts b/web/src/hooks/useAlerts.ts
index f48f8e15..1a3ec6c7 100644
--- a/web/src/hooks/useAlerts.ts
+++ b/web/src/hooks/useAlerts.ts
@@ -150,7 +150,12 @@ const useAlertsPoller = ({
const fetchDispatch = () =>
dispatch(fetchAlertingData(prometheus, namespace, rulesUrl, alertsSource, silencesUrl));
- usePoll(fetchDispatch, POLLING_INTERVAL_MS);
+ const dependencies = useMemo(
+ () => [namespace, rulesUrl, silencesUrl],
+ [namespace, rulesUrl, silencesUrl],
+ );
+
+ usePoll(fetchDispatch, POLLING_INTERVAL_MS, dependencies);
return { trigger: fetchDispatch };
};
| | |