diff --git a/public/app/features/alerting/unified/CloneRuleEditor.tsx b/public/app/features/alerting/unified/CloneRuleEditor.tsx index 70a050b1ea9..92745f20bde 100644 --- a/public/app/features/alerting/unified/CloneRuleEditor.tsx +++ b/public/app/features/alerting/unified/CloneRuleEditor.tsx @@ -12,7 +12,7 @@ import { generateCopiedName } from './utils/duplicate'; import { stringifyErrorLike } from './utils/misc'; import { rulerRuleToFormValues } from './utils/rule-form'; import { getRuleName, isAlertingRulerRule, isGrafanaRulerRule, isRecordingRulerRule } from './utils/rules'; -import { createUrl } from './utils/url'; +import { createRelativeUrl } from './utils/url'; export function CloneRuleEditor({ sourceRuleId }: { sourceRuleId: RuleIdentifier }) { const { loading, result: rule, error } = useRuleWithLocation({ ruleIdentifier: sourceRuleId }); @@ -40,7 +40,7 @@ export function CloneRuleEditor({ sourceRuleId }: { sourceRuleId: RuleIdentifier locationService.replace(createUrl('/alerting/list'))} + onRemove={() => locationService.replace(createRelativeUrl('/alerting/list'))} /> ); } diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPointHeader.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPointHeader.tsx index b93ab82f8d7..730f2520fa8 100644 --- a/public/app/features/alerting/unified/components/contact-points/ContactPointHeader.tsx +++ b/public/app/features/alerting/unified/components/contact-points/ContactPointHeader.tsx @@ -8,7 +8,7 @@ import ConditionalWrap from 'app/features/alerting/unified/components/Conditiona import { useExportContactPoint } from 'app/features/alerting/unified/components/contact-points/useExportContactPoint'; import { AlertmanagerAction, useAlertmanagerAbility } from '../../hooks/useAbilities'; -import { createUrl } from '../../utils/url'; +import { createRelativeUrl } from '../../utils/url'; import MoreButton from '../MoreButton'; import { ProvisioningBadge } from '../Provisioning'; import { Spacer } from '../Spacer'; @@ -96,7 +96,7 @@ export const ContactPointHeader = (props: ContactPointHeaderProps) => { {isReferencedByAnyPolicy && ( locationService.replace(createUrl('/alerting/list'))} + onRemove={() => locationService.replace(createRelativeUrl('/alerting/list'))} /> ); } @@ -90,7 +90,7 @@ function RuleModifyExport({ ruleIdentifier }: { ruleIdentifier: RuleIdentifier } locationService.replace(createUrl('/alerting/list'))} + onRemove={() => locationService.replace(createRelativeUrl('/alerting/list'))} /> ); } diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx index 3a62bf35584..c6bd4f0b985 100644 --- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx @@ -1,7 +1,7 @@ import { css, cx, keyframes } from '@emotion/css'; -import { useCallback, useEffect, useState } from 'react'; import * as React from 'react'; -import { useFormContext, Controller } from 'react-hook-form'; +import { useCallback, useEffect, useState } from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { @@ -15,7 +15,7 @@ import { useStyles2, } from '@grafana/ui'; import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form'; -import { createUrl } from 'app/features/alerting/unified/utils/url'; +import { createRelativeUrl } from 'app/features/alerting/unified/utils/url'; import { ContactPointWithMetadata } from '../../../../contact-points/utils'; @@ -144,7 +144,7 @@ export function ContactPointSelector({ function LinkToContactPoints() { const hrefToContactPoints = '/alerting/notifications'; return ( - + View or create contact points ); diff --git a/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx b/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx index 0f19f5a5b41..c37b4cd9355 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx @@ -11,7 +11,7 @@ import { PromAlertingRuleState } from 'app/types/unified-alerting-dto'; import { AlertRuleAction, useAlertRuleAbility } from '../../hooks/useAbilities'; import { createShareLink, isLocalDevEnv, isOpenSourceEdition } from '../../utils/misc'; import * as ruleId from '../../utils/rule-id'; -import { createUrl } from '../../utils/url'; +import { createRelativeUrl } from '../../utils/url'; import { DeclareIncidentMenuItem } from '../bridges/DeclareIncidentButton'; interface Props { @@ -123,9 +123,12 @@ type PropsWithIdentifier = { identifier: RuleIdentifier }; const ExportMenuItem = ({ identifier }: PropsWithIdentifier) => { const returnTo = location.pathname + location.search; - const url = createUrl(`/alerting/${encodeURIComponent(ruleId.stringifyIdentifier(identifier))}/modify-export`, { - returnTo, - }); + const url = createRelativeUrl( + `/alerting/${encodeURIComponent(ruleId.stringifyIdentifier(identifier))}/modify-export`, + { + returnTo, + } + ); return ; }; diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx index a7d8db1a21b..605601103bb 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx @@ -25,7 +25,7 @@ import { isGrafanaRulerRulePaused, isRecordingRule, } from '../../utils/rules'; -import { createUrl } from '../../utils/url'; +import { createRelativeUrl } from '../../utils/url'; import { AlertLabels } from '../AlertLabels'; import { AlertingPageWrapper } from '../AlertingPageWrapper'; import { ProvisionedResource, ProvisioningAlert } from '../Provisioning'; @@ -222,7 +222,7 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => { // TODO move somewhere else export const createListFilterLink = (values: Array<[string, string]>) => { const params = new URLSearchParams([['search', values.map(([key, value]) => `${key}:"${value}"`).join(' ')]]); - return createUrl(`/alerting/list?` + params.toString()); + return createRelativeUrl(`/alerting/list`, params); }; interface TitleProps { diff --git a/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx b/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx index 22468e81c0d..d7c5f187937 100644 --- a/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx +++ b/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx @@ -17,7 +17,7 @@ import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelect import { getPaginationStyles } from '../../styles/pagination'; import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource'; import { initialAsyncRequestState } from '../../utils/redux'; -import { createUrl } from '../../utils/url'; +import { createRelativeUrl } from '../../utils/url'; import { GrafanaRulesExporter } from '../export/GrafanaRulesExporter'; import { RulesGroup } from './RulesGroup'; @@ -86,7 +86,7 @@ export const GrafanaRules = ({ namespaces, expandAll }: Props) => { )} {grafanaRecordingRulesEnabled && ( ); } - const ruleViewUrl = createUrl(`/alerting/${GRAFANA_RULES_SOURCE_NAME}/${ruleUID}/view`, { + const ruleViewUrl = createRelativeUrl(`/alerting/${GRAFANA_RULES_SOURCE_NAME}/${ruleUID}/view`, { tab: 'history', returnTo, }); diff --git a/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx b/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx index 07bf9314061..6bd6c170688 100644 --- a/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx +++ b/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx @@ -8,7 +8,7 @@ import { isProvisionedDataSource, isVanillaPrometheusAlertManagerDataSource, } from '../../utils/datasource'; -import { createUrl } from '../../utils/url'; +import { createRelativeUrl } from '../../utils/url'; import { AlertmanagerCard } from './AlertmanagerCard'; import { useSettings } from './SettingsContext'; @@ -50,8 +50,9 @@ export const ExternalAlertmanagers = ({ onEditConfiguration }: Props) => { const isReceiving = isReceivingGrafanaAlerts(alertmanager); const isProvisioned = isProvisionedDataSource(alertmanager.dataSourceSettings); const isReadOnly = isVanillaPrometheusAlertManagerDataSource(alertmanager.dataSourceSettings.name); - - const detailHref = createUrl(DATASOURCES_ROUTES.Edit.replace(/:uid/gi, uid)); + // typescript on next line is wrong, as DATASOURCES_ROUTES.Edit is a RelativeUrl type, and replacing :uid with uid makes still a RelativeUrl + // @ts-ignore + const detailHref = createRelativeUrl(DATASOURCES_ROUTES.Edit.replace(/:uid/gi, uid)); const handleEditConfiguration = () => onEditConfiguration(name); const handleEnable = forwardingDisabled ? undefined : () => enableAlertmanager(uid); diff --git a/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx b/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx index 817318db695..0c5a0e44950 100644 --- a/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx +++ b/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx @@ -13,7 +13,7 @@ import { DataSourceRef } from '@grafana/schema'; import { Link, useStyles2 } from '@grafana/ui'; import { PANEL_STYLES } from '../../home/Insights'; -import { createUrl } from '../../utils/url'; +import { createRelativeUrl } from '../../utils/url'; import { InsightsRatingModal } from '../RatingModal'; export function getMostFiredInstancesScene(datasource: DataSourceRef, panelTitle: string) { @@ -119,7 +119,7 @@ export function RuleLink({ value, ruleUID }: { value: string; ruleUID: string }) return (
- + {value}
diff --git a/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx b/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx index ab5386974c0..9c87bcb7b23 100644 --- a/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx +++ b/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx @@ -3,7 +3,7 @@ import { lazy, Suspense } from 'react'; import { Drawer, LoadingPlaceholder, Stack, TextLink } from '@grafana/ui'; import { t } from '../../../../core/internationalization'; -import { createUrl } from '../utils/url'; +import { createRelativeUrl } from '../utils/url'; const AlertRulesDrawerContent = lazy( () => import(/* webpackChunkName: "alert-rules-drawer-content" */ './AlertRulesDrawerContent') @@ -30,7 +30,7 @@ function DrawerSubtitle({ dashboardUid }: { dashboardUid: string }) { return (
{t('dashboard.alert-rules-drawer.subtitle', 'Alert rules related to this dashboard')}
- + {t('dashboard.alert-rules-drawer.redirect-link', 'List in Grafana Alerting')}
diff --git a/public/app/features/alerting/unified/utils/misc.ts b/public/app/features/alerting/unified/utils/misc.ts index 32d283dec2b..0b1c43b5e2e 100644 --- a/public/app/features/alerting/unified/utils/misc.ts +++ b/public/app/features/alerting/unified/utils/misc.ts @@ -19,7 +19,7 @@ import { ALERTMANAGER_NAME_QUERY_KEY } from './constants'; import { getRulesSourceName, isCloudRulesSource } from './datasource'; import { getMatcherQueryParams } from './matchers'; import * as ruleId from './rule-id'; -import { createAbsoluteUrl, createUrl } from './url'; +import { createAbsoluteUrl, createRelativeUrl } from './url'; export function createViewLink(ruleSource: RulesSource, rule: CombinedRule, returnTo?: string): string { const sourceName = getRulesSourceName(ruleSource); @@ -27,13 +27,13 @@ export function createViewLink(ruleSource: RulesSource, rule: CombinedRule, retu const paramId = encodeURIComponent(ruleId.stringifyIdentifier(identifier)); const paramSource = encodeURIComponent(sourceName); - return createUrl(`/alerting/${paramSource}/${paramId}/view`, returnTo ? { returnTo } : {}); + return createRelativeUrl(`/alerting/${paramSource}/${paramId}/view`, returnTo ? { returnTo } : {}); } export function createExploreLink(datasource: DataSourceRef, query: string) { const { uid, type } = datasource; - return createUrl(`/explore`, { + return createRelativeUrl(`/explore`, { left: JSON.stringify({ datasource: datasource.uid, queries: [{ refId: 'A', datasource: { uid, type }, expr: query }], @@ -43,13 +43,13 @@ export function createExploreLink(datasource: DataSourceRef, query: string) { } export function createContactPointLink(contactPoint: string, alertManagerSourceName = ''): string { - return createUrl(`/alerting/notifications/receivers/${encodeURIComponent(contactPoint)}/edit`, { + return createRelativeUrl(`/alerting/notifications/receivers/${encodeURIComponent(contactPoint)}/edit`, { alertmanager: alertManagerSourceName, }); } export function createMuteTimingLink(muteTimingName: string, alertManagerSourceName = ''): string { - return createUrl('/alerting/routes/mute-timing/edit', { + return createRelativeUrl('/alerting/routes/mute-timing/edit', { muteName: muteTimingName, alertmanager: alertManagerSourceName, }); @@ -125,32 +125,32 @@ export function makeLabelBasedSilenceLink(alertManagerSourceName: string, labels const matcherParams = getMatcherQueryParams(labels); matcherParams.forEach((value, key) => silenceUrlParams.append(key, value)); - return createUrl('/alerting/silence/new', silenceUrlParams); + return createRelativeUrl('/alerting/silence/new', silenceUrlParams); } export function makeDataSourceLink(uid: string) { - return createUrl(`/datasources/edit/${uid}`); + return createRelativeUrl(`/datasources/edit/${uid}`); } export function makeFolderLink(folderUID: string): string { - return createUrl(`/dashboards/f/${folderUID}`); + return createRelativeUrl(`/dashboards/f/${folderUID}`); } export function makeFolderAlertsLink(folderUID: string, title: string): string { - return createUrl(`/dashboards/f/${folderUID}/${title}/alerting`); + return createRelativeUrl(`/dashboards/f/${folderUID}/${title}/alerting`); } export function makeFolderSettingsLink(uid: string): string { - return createUrl(`/dashboards/f/${uid}/settings`); + return createRelativeUrl(`/dashboards/f/${uid}/settings`); } export function makeDashboardLink(dashboardUID: string): string { - return createUrl(`/d/${encodeURIComponent(dashboardUID)}`); + return createRelativeUrl(`/d/${encodeURIComponent(dashboardUID)}`); } export function makePanelLink(dashboardUID: string, panelId: string): string { const panelParams = new URLSearchParams({ viewPanel: panelId }); - return createUrl(`/d/${encodeURIComponent(dashboardUID)}`, panelParams); + return createRelativeUrl(`/d/${encodeURIComponent(dashboardUID)}`, panelParams); } // keep retrying fn if it's error passes shouldRetry(error) and timeout has not elapsed yet diff --git a/public/app/features/alerting/unified/utils/url.test.ts b/public/app/features/alerting/unified/utils/url.test.ts new file mode 100644 index 00000000000..7a4b955f0fb --- /dev/null +++ b/public/app/features/alerting/unified/utils/url.test.ts @@ -0,0 +1,65 @@ +import { config } from '@grafana/runtime'; + +import { createAbsoluteUrl, createRelativeUrl } from './url'; + +config.appSubUrl = '/base'; +config.appUrl = 'https://example.com'; + +describe('createRelativeUrl', () => { + it('should create a relative URL with no query parameters', () => { + expect(createRelativeUrl('/test')).toBe('/base/test'); + }); + + it('should create a relative URL with string query parameters', () => { + expect(createRelativeUrl('/test', 'param1=value1¶m2=value2')).toBe('/base/test?param1=value1¶m2=value2'); + }); + + it('should create a relative URL with object query parameters', () => { + expect(createRelativeUrl('/test', { param1: 'value1', param2: 'value2' })).toBe( + '/base/test?param1=value1¶m2=value2' + ); + }); + + it('should create a relative URL with array query parameters', () => { + expect( + createRelativeUrl('/test', [ + ['param1', 'value1'], + ['param2', 'value2'], + ]) + ).toBe('/base/test?param1=value1¶m2=value2'); + }); +}); + +describe('createAbsoluteUrl', () => { + it('should create an absolute URL with no query parameters', () => { + expect(createAbsoluteUrl('/test')).toBe('https://example.com/base/test'); + }); + + it('should create an absolute URL with string query parameters', () => { + expect(createAbsoluteUrl('/test', 'param1=value1¶m2=value2')).toBe( + 'https://example.com/base/test?param1=value1¶m2=value2' + ); + }); + + it('should create an absolute URL with object query parameters', () => { + expect(createAbsoluteUrl('/test', { param1: 'value1', param2: 'value2' })).toBe( + 'https://example.com/base/test?param1=value1¶m2=value2' + ); + }); + + it('should create an absolute URL with array query parameters', () => { + expect( + createAbsoluteUrl('/test', [ + ['param1', 'value1'], + ['param2', 'value2'], + ]) + ).toBe('https://example.com/base/test?param1=value1¶m2=value2'); + }); + + it('should fallback to relative URL if base URL is invalid', () => { + const originalAppUrl = config.appUrl; + config.appUrl = 'invalid-url'; + expect(createAbsoluteUrl('/test')).toBe('/base/test'); + config.appUrl = originalAppUrl; + }); +}); diff --git a/public/app/features/alerting/unified/utils/url.ts b/public/app/features/alerting/unified/utils/url.ts index 7b2fda519aa..2ee3521b2d6 100644 --- a/public/app/features/alerting/unified/utils/url.ts +++ b/public/app/features/alerting/unified/utils/url.ts @@ -1,6 +1,10 @@ import { config } from '@grafana/runtime'; -export function createUrl(path: string, queryParams?: string[][] | Record | string | URLSearchParams) { +export type RelativeUrl = `/${string}`; +export function createRelativeUrl( + path: RelativeUrl, + queryParams?: string[][] | Record | string | URLSearchParams +) { const searchParams = new URLSearchParams(queryParams); const searchParamsString = searchParams.toString(); @@ -8,7 +12,7 @@ export function createUrl(path: string, queryParams?: string[][] | Record | string | URLSearchParams ) { const searchParams = new URLSearchParams(queryParams); @@ -18,6 +22,6 @@ export function createAbsoluteUrl( const baseUrl = new URL(config.appSubUrl + path, config.appUrl); return `${baseUrl.href}${searchParamsString ? `?${searchParamsString}` : ''}`; } catch (err) { - return createUrl(path, queryParams); + return createRelativeUrl(path, queryParams); } } diff --git a/public/app/features/datasources/types.ts b/public/app/features/datasources/types.ts index 8b0fde0a9fa..aab2e5c6163 100644 --- a/public/app/features/datasources/types.ts +++ b/public/app/features/datasources/types.ts @@ -1,5 +1,7 @@ import { DataQuery, DataSourceApi, DataSourceJsonData, DataSourcePlugin } from '@grafana/data'; +import { RelativeUrl } from '../alerting/unified/utils/url'; + export type GenericDataSourcePlugin = DataSourcePlugin>; export type DataSourceRights = { @@ -9,10 +11,10 @@ export type DataSourceRights = { }; export type DataSourcesRoutes = { - New: string; - Edit: string; - List: string; - Dashboards: string; + New: RelativeUrl; + Edit: RelativeUrl; + List: RelativeUrl; + Dashboards: RelativeUrl; }; export type DataSourceTestStatus = 'success' | 'warning' | 'error'; diff --git a/public/app/features/gops/configuration-tracker/components/Essentials.tsx b/public/app/features/gops/configuration-tracker/components/Essentials.tsx index c7a509ad1ab..0b4cddbcda9 100644 --- a/public/app/features/gops/configuration-tracker/components/Essentials.tsx +++ b/public/app/features/gops/configuration-tracker/components/Essentials.tsx @@ -2,7 +2,7 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; import { Button, Drawer, Dropdown, Icon, LinkButton, Menu, Stack, Text, Tooltip, useStyles2 } from '@grafana/ui'; -import { createUrl } from 'app/features/alerting/unified/utils/url'; +import { RelativeUrl, createRelativeUrl } from 'app/features/alerting/unified/utils/url'; import { SectionDto, SectionDtoStep, SectionsDto, StepButtonDto } from '../irmHooks'; @@ -86,22 +86,22 @@ function Step({ step }: StepProps) { } interface LinkButtonProps { - urlLink?: { url: string; queryParams?: Record }; + urlLink?: { url: RelativeUrl; queryParams?: Record }; label: string; - urlLinkOnDone?: { url: string; queryParams?: Record }; + urlLinkOnDone?: { url: RelativeUrl; queryParams?: Record }; labelOnDone?: string; done?: boolean; } function OpenLinkButton(props: LinkButtonProps) { const { urlLink, label, urlLinkOnDone, labelOnDone, done } = props; const urlToGoWhenNotDone = urlLink?.url - ? createUrl(urlLink.url, { + ? createRelativeUrl(urlLink.url, { returnTo: location.pathname + location.search, ...urlLink.queryParams, }) : ''; const urlToGoWhenDone = urlLinkOnDone?.url - ? createUrl(urlLinkOnDone.url, { + ? createRelativeUrl(urlLinkOnDone.url, { returnTo: location.pathname + location.search, ...urlLinkOnDone.queryParams, }) diff --git a/public/app/features/gops/configuration-tracker/irmHooks.ts b/public/app/features/gops/configuration-tracker/irmHooks.ts index 14fe5246d52..a18bc7fd35c 100644 --- a/public/app/features/gops/configuration-tracker/irmHooks.ts +++ b/public/app/features/gops/configuration-tracker/irmHooks.ts @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { locationService } from '@grafana/runtime'; -import { createUrl } from 'app/features/alerting/unified/utils/url'; +import { RelativeUrl, createRelativeUrl } from 'app/features/alerting/unified/utils/url'; import { isOnCallContactPointReady, @@ -16,7 +16,7 @@ import { useOnCallChatOpsConnections, useOnCallOptions } from './onCall/hooks'; import { useSloChecks } from './slo/hooks'; interface UrlLink { - url: string; + url: RelativeUrl; queryParams?: Record; } export interface StepButtonDto { @@ -113,8 +113,8 @@ export function useGetEssentialsConfiguration(): EssentialsConfigurationData { isLoading, } = useGetConfigurationForApps(); - function onIntegrationClick(integrationId: string, url: string) { - const urlToGoWithIntegration = createUrl(url + integrationId, { + function onIntegrationClick(integrationId: string, url: RelativeUrl) { + const urlToGoWithIntegration = createRelativeUrl(`${url} + ${integrationId}`, { returnTo: location.pathname + location.search, }); locationService.push(urlToGoWithIntegration); diff --git a/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx b/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx index 0790e77cd07..25f8df85cdb 100644 --- a/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx +++ b/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx @@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css'; import { useLocation } from 'react-use'; import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data'; -import { Icon, useStyles2, Stack } from '@grafana/ui'; +import { Icon, Stack, useStyles2 } from '@grafana/ui'; import alertDef from 'app/features/alerting/state/alertDef'; import { Spacer } from 'app/features/alerting/unified/components/Spacer'; import { fromCombinedRule, stringifyIdentifier } from 'app/features/alerting/unified/utils/rule-id'; @@ -12,11 +12,11 @@ import { getFirstActiveAt, isAlertingRule, } from 'app/features/alerting/unified/utils/rules'; -import { createUrl } from 'app/features/alerting/unified/utils/url'; +import { createRelativeUrl } from 'app/features/alerting/unified/utils/url'; import { PromAlertingRuleState } from 'app/types/unified-alerting-dto'; import { GRAFANA_RULES_SOURCE_NAME } from '../../../../features/alerting/unified/utils/datasource'; -import { AlertingRule, AlertInstanceTotalState, CombinedRuleWithLocation } from '../../../../types/unified-alerting'; +import { AlertInstanceTotalState, AlertingRule, CombinedRuleWithLocation } from '../../../../types/unified-alerting'; import { AlertInstances } from '../AlertInstances'; import { getStyles } from '../UnifiedAlertList'; import { UnifiedAlertListOptions } from '../types'; @@ -63,7 +63,7 @@ const UngroupedModeView = ({ rules, options, handleInstancesLimit, limitInstance ? getGrafanaInstancesTotal(ruleWithLocation.filteredInstanceTotals) : undefined; - const href = createUrl( + const href = createRelativeUrl( `/alerting/${encodeURIComponent(dataSourceName)}/${encodeURIComponent(strIndentifier)}/view`, { returnTo: returnTo ?? '' } );