Scopes: Scope input UI update (#114002)
* Progress * Update * Progress * Fixes * Update * update e2e * e2e fix * More e2e fixes * fix
This commit is contained in:
@@ -169,7 +169,7 @@ test.describe(
|
||||
|
||||
await setScopes(page);
|
||||
|
||||
await expect(scopesSelectorInput).toHaveValue(/.+/);
|
||||
await expect(scopesSelectorInput).toHaveAttribute('data-value', /.+/);
|
||||
|
||||
expect(await adHocFilterPills.count()).toBe(3);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ test.describe(
|
||||
|
||||
await setScopes(page);
|
||||
|
||||
await expect(scopeSelectorInput).toHaveValue(/.+/);
|
||||
await expect(scopeSelectorInput).toHaveAttribute('data-value', /.+/);
|
||||
|
||||
const firstDbName = await scopesDashboards.first().textContent();
|
||||
const scopeDashboardsCount = await scopesDashboards.count();
|
||||
@@ -60,7 +60,7 @@ test.describe(
|
||||
|
||||
await setScopes(page);
|
||||
|
||||
await expect(scopeSelectorInput).toHaveValue(/.+/);
|
||||
await expect(scopeSelectorInput).toHaveAttribute('data-value', /.+/);
|
||||
|
||||
// assert the panel is visible and has the correct value
|
||||
const markdownContent = await getMarkdownHTMLContent(dashboardPage, selectors);
|
||||
@@ -94,7 +94,7 @@ test.describe(
|
||||
|
||||
await setScopes(page, { title: 'CUJ Dashboard 3', uid: NAVIGATE_TO });
|
||||
|
||||
await expect(scopeSelectorInput).toHaveValue(/.+/);
|
||||
await expect(scopeSelectorInput).toHaveAttribute('data-value', /.+/);
|
||||
|
||||
const pills = await adhocFilterPills.allTextContents();
|
||||
const processedPills = pills
|
||||
@@ -138,7 +138,7 @@ test.describe(
|
||||
|
||||
await setScopes(page, { title: 'CUJ Dashboard 2', uid: 'cuj-dashboard-2' });
|
||||
|
||||
await expect(scopeSelectorInput).toHaveValue(/.+/);
|
||||
await expect(scopeSelectorInput).toHaveAttribute('data-value', /.+/);
|
||||
|
||||
const pillCount = await adhocFilterPills.count();
|
||||
const pillTexts = await adhocFilterPills.allTextContents();
|
||||
|
||||
@@ -40,7 +40,7 @@ test.describe(
|
||||
await test.step('1.View and select any scope', async () => {
|
||||
await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST });
|
||||
|
||||
expect.soft(scopesSelector).toHaveValue('');
|
||||
expect.soft(scopesSelector).toHaveAttribute('data-value', '');
|
||||
|
||||
const scopes = testScopes();
|
||||
await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version
|
||||
@@ -63,14 +63,13 @@ test.describe(
|
||||
|
||||
await applyScopes(page, USE_LIVE_DATA ? undefined : selectedScopes); //used only in mocked scopes version
|
||||
|
||||
expect.soft(scopesSelector).toHaveValue(scopeTitle);
|
||||
expect.soft(scopesSelector).toHaveAttribute('data-value', scopeTitle);
|
||||
});
|
||||
|
||||
await test.step('2.Select a scope across multiple types of production entities', async () => {
|
||||
await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST });
|
||||
|
||||
expect.soft(scopesSelector).toHaveValue('');
|
||||
|
||||
expect.soft(scopesSelector).toHaveAttribute('data-value', '');
|
||||
const scopes = testScopes();
|
||||
await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version
|
||||
|
||||
@@ -94,14 +93,14 @@ test.describe(
|
||||
|
||||
await applyScopes(page, USE_LIVE_DATA ? undefined : selectedScopes); //used only in mocked scopes version
|
||||
|
||||
await expect.soft(scopesSelector).toHaveValue(scopeTitles.join(' + '));
|
||||
await expect.soft(scopesSelector).toHaveAttribute('data-value', scopeTitles.join(' + '));
|
||||
});
|
||||
|
||||
await test.step('3.View and select a recently viewed scope', async () => {
|
||||
// this step depends on the previous ones because they set recent scopes
|
||||
await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST });
|
||||
|
||||
expect.soft(scopesSelector).toHaveValue('');
|
||||
expect.soft(scopesSelector).toHaveAttribute('data-value', '');
|
||||
|
||||
const scopes = testScopes();
|
||||
await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version
|
||||
@@ -114,13 +113,13 @@ test.describe(
|
||||
|
||||
await recentScope.click();
|
||||
|
||||
await expect.soft(scopesSelector).toHaveValue(scopeName!.replace(', ', ' + '));
|
||||
await expect.soft(scopesSelector).toHaveAttribute('data-value', scopeName!.replace(', ', ' + '));
|
||||
});
|
||||
|
||||
await test.step('4.View and select a scope configured by any team', async () => {
|
||||
await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST });
|
||||
|
||||
expect.soft(scopesSelector).toHaveValue('');
|
||||
expect.soft(scopesSelector).toHaveAttribute('data-value', '');
|
||||
|
||||
const scopes = testScopes();
|
||||
await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes);
|
||||
@@ -143,7 +142,7 @@ test.describe(
|
||||
|
||||
await applyScopes(page, USE_LIVE_DATA ? undefined : []); //used only in mocked scopes version
|
||||
|
||||
expect.soft(scopesSelector).toHaveValue(new RegExp(`^${scopeTitle}`));
|
||||
expect.soft(scopesSelector).toHaveAttribute('data-value', new RegExp(`^${scopeTitle}`));
|
||||
});
|
||||
|
||||
await test.step('5.View pre-completed production entity values as I type', async () => {
|
||||
|
||||
@@ -161,6 +161,7 @@ test.describe('Scope Redirect Functionality', () => {
|
||||
|
||||
await test.step('Deselect scopes and verify no redirect', async () => {
|
||||
// Click the clear button to remove all scopes
|
||||
await page.getByTestId('scopes-selector-input').hover();
|
||||
await page.getByTestId('scopes-selector-input-clear').click();
|
||||
|
||||
// Should stay on the same dashboard (cuj-dashboard-3), not redirect
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth';
|
||||
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { ScopesSelector } from 'app/features/scopes/selector/ScopesSelector';
|
||||
import { useSelector } from 'app/types/store';
|
||||
|
||||
import { Branding } from '../../Branding/Branding';
|
||||
@@ -60,6 +61,8 @@ export const SingleTopBar = memo(function SingleTopBar({
|
||||
const breadcrumbs = buildBreadcrumbs(sectionNav, pageNav, homeNav);
|
||||
const unifiedHistoryEnabled = config.featureToggles.unifiedHistory;
|
||||
const isSmallScreen = !useMediaQueryMinWidth('sm');
|
||||
const isLargeScreen = useMediaQueryMinWidth('lg');
|
||||
const topLevelScopes = !showToolbarLevel && isLargeScreen && scopes?.state.enabled;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -78,6 +81,7 @@ export const SingleTopBar = memo(function SingleTopBar({
|
||||
</Stack>
|
||||
</ToolbarButton>
|
||||
)}
|
||||
{topLevelScopes ? <ScopesSelector /> : undefined}
|
||||
<Breadcrumbs breadcrumbs={breadcrumbs} className={styles.breadcrumbsWrapper} />
|
||||
{!showToolbarLevel && breadcrumbActions}
|
||||
</Stack>
|
||||
|
||||
@@ -112,18 +112,5 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
'&:focus-visible': getFocusStyles(theme),
|
||||
},
|
||||
]),
|
||||
|
||||
button: css({
|
||||
// height: 32,
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
|
||||
'> *': {
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1ch',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export function useChromeHeaderLevels() {
|
||||
const state = chrome.state.getValue();
|
||||
const scopes = useScopes();
|
||||
|
||||
const isLargeScreen = useMediaQueryMinWidth('xl');
|
||||
const isLargeScreen = useMediaQueryMinWidth('lg');
|
||||
|
||||
const [headerLevels, setHeaderLevels] = useState(
|
||||
getHeaderLevelsGivenState(state, scopes?.state.enabled, isLargeScreen)
|
||||
@@ -46,8 +46,8 @@ function getHeaderLevelsGivenState(
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Always use two levels scopes is enabled
|
||||
if (scopesEnabled) {
|
||||
// // Use 2 levels if scopes is enabled on smaller screens
|
||||
if (scopesEnabled && !isLargeScreen) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { css, cx } from '@emotion/css';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { IconButton, Input, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { getInputStyles, Icon, LinkButton, Spinner, Tooltip, useStyles2, Text, Stack } from '@grafana/ui';
|
||||
import { getFocusStyles } from '@grafana/ui/internal';
|
||||
|
||||
import { getPathOfNode } from './scopesTreeUtils';
|
||||
import { NodesMap, ScopesMap, SelectedScope } from './types';
|
||||
@@ -32,11 +31,9 @@ export function ScopesInput({
|
||||
onInputClick,
|
||||
onRemoveAllClick,
|
||||
}: ScopesInputProps) {
|
||||
const [tooltipVisible, setTooltipVisible] = useState(false);
|
||||
|
||||
const scopeNodeId = appliedScopes[0]?.scopeNodeId;
|
||||
const parentNodeIdFromUrl = appliedScopes[0]?.parentNodeId;
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
const { node: scopeNode, isLoading: scopeNodeLoading } = useScopeNode(scopeNodeId);
|
||||
|
||||
// Get parent from scope node if available, otherwise use parentNodeId from URL (for backward compatibility)
|
||||
@@ -44,70 +41,61 @@ export function ScopesInput({
|
||||
const { node: parentNode, isLoading: parentNodeLoading } = useScopeNode(parentNodeId);
|
||||
|
||||
// Prioritize scope node subtitle over parent node title
|
||||
const displayTitle = scopeNode?.spec.subTitle ?? parentNode?.spec.title;
|
||||
const displayTitle =
|
||||
scopeNode?.spec.subTitle ?? parentNode?.spec.title ?? (appliedScopes.length > 0 ? 'Mimir' : undefined);
|
||||
const isLoadingTitle = scopeNodeLoading || parentNodeLoading;
|
||||
const placeholderText = t('scopes.selector.input.placeholder', 'No scopes');
|
||||
|
||||
useEffect(() => {
|
||||
setTooltipVisible(false);
|
||||
}, [appliedScopes]);
|
||||
|
||||
const tooltipContent =
|
||||
appliedScopes.length > 0 ? <ScopesTooltip nodes={nodes} scopes={scopes} appliedScopes={appliedScopes} /> : <></>;
|
||||
|
||||
const scopesTitles = useMemo(
|
||||
() =>
|
||||
appliedScopes
|
||||
.map(
|
||||
(s) =>
|
||||
// If we are still loading the scope data just show the id
|
||||
scopes[s.scopeId]?.spec.title || s.scopeId
|
||||
)
|
||||
.join(' + '),
|
||||
[appliedScopes, scopes]
|
||||
const tooltipContent = (
|
||||
<ScopesTooltip
|
||||
nodes={nodes}
|
||||
scopes={scopes}
|
||||
appliedScopes={appliedScopes}
|
||||
onRemoveAllClick={onRemoveAllClick}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
|
||||
const parentNodePrefix = useMemo(
|
||||
() =>
|
||||
isLoadingTitle ? <Skeleton width={30} height={14} /> : displayTitle ? <span>{displayTitle}:</span> : undefined,
|
||||
[isLoadingTitle, displayTitle]
|
||||
);
|
||||
const scopesTitles = appliedScopes
|
||||
.map(
|
||||
(s) =>
|
||||
// If we are still loading the scope data just show the id
|
||||
scopes[s.scopeId]?.spec.title || s.scopeId
|
||||
)
|
||||
.join(' + ');
|
||||
|
||||
const input = useMemo(
|
||||
() => (
|
||||
<Input
|
||||
readOnly
|
||||
placeholder={t('scopes.selector.input.placeholder', 'Select scopes...')}
|
||||
disabled={disabled}
|
||||
loading={loading}
|
||||
value={scopesTitles}
|
||||
aria-label={t('scopes.selector.input.placeholder', 'Select scopes...')}
|
||||
data-testid="scopes-selector-input"
|
||||
prefix={parentNodePrefix}
|
||||
suffix={
|
||||
appliedScopes.length > 0 && !disabled ? (
|
||||
<IconButton
|
||||
aria-label={t('scopes.selector.input.removeAll', 'Remove all scopes')}
|
||||
name="times"
|
||||
data-testid="scopes-selector-input-clear"
|
||||
onClick={() => onRemoveAllClick()}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
onMouseOver={() => setTooltipVisible(true)}
|
||||
onMouseOut={() => setTooltipVisible(false)}
|
||||
onClick={() => {
|
||||
if (!disabled) {
|
||||
onInputClick();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[disabled, loading, onInputClick, onRemoveAllClick, appliedScopes, scopesTitles, parentNodePrefix]
|
||||
);
|
||||
const onClick = () => {
|
||||
if (!disabled) {
|
||||
onInputClick();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip content={tooltipContent} show={appliedScopes.length === 0 ? false : tooltipVisible}>
|
||||
{input}
|
||||
<Tooltip content={tooltipContent} interactive>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.fakeInput}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
aria-label={placeholderText}
|
||||
data-testid="scopes-selector-input"
|
||||
data-value={scopesTitles}
|
||||
>
|
||||
{loading && (
|
||||
<div className={styles.prefix}>
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
<span className={styles.text}>
|
||||
{!scopesTitles && !loading && <Text color="secondary">{placeholderText}</Text>}
|
||||
{!isLoadingTitle && displayTitle && <span className={styles.parentNode}>{displayTitle}</span>}
|
||||
{scopesTitles && <span>{scopesTitles}</span>}
|
||||
</span>
|
||||
|
||||
<div className={styles.suffix}>
|
||||
<Icon name="angle-down" />
|
||||
</div>
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
@@ -131,13 +119,16 @@ export interface ScopesTooltipProps {
|
||||
nodes: NodesMap;
|
||||
scopes: ScopesMap;
|
||||
appliedScopes: SelectedScope[];
|
||||
disabled?: boolean;
|
||||
onRemoveAllClick?: () => void;
|
||||
}
|
||||
|
||||
function ScopesTooltip({ nodes, scopes, appliedScopes }: ScopesTooltipProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
function ScopesTooltip({ nodes, scopes, appliedScopes, onRemoveAllClick, disabled }: ScopesTooltipProps) {
|
||||
if (appliedScopes.length === 0) {
|
||||
return t('scopes.selector.input.tooltip', 'Select scope');
|
||||
}
|
||||
|
||||
const nicePath = getScopesPath(appliedScopes, nodes);
|
||||
|
||||
const scopeNames = appliedScopes.map((s) => {
|
||||
if (s.scopeNodeId) {
|
||||
return nodes[s.scopeNodeId]?.spec.title || s.scopeNodeId;
|
||||
@@ -146,21 +137,76 @@ function ScopesTooltip({ nodes, scopes, appliedScopes }: ScopesTooltipProps) {
|
||||
}
|
||||
});
|
||||
|
||||
const parentPaths = nicePath && nicePath.length > 0 ? nicePath.join(' > ') + ' > ' : '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className={styles.scopePath}>
|
||||
{(nicePath && nicePath.length > 0 ? nicePath.join(' > ') + ' > ' : '') + scopeNames.join(', ')}
|
||||
</p>
|
||||
</>
|
||||
<Stack direction="column" gap={1} justifyContent="center" alignItems={'center'}>
|
||||
<span>{parentPaths + scopeNames.join(', ')}</span>
|
||||
{!disabled && (
|
||||
<LinkButton
|
||||
onClick={onRemoveAllClick}
|
||||
aria-label={t('scopes.selector.input.removeAll', 'Remove all scopes')}
|
||||
name="times"
|
||||
data-testid="scopes-selector-input-clear"
|
||||
size="sm"
|
||||
fill="text"
|
||||
icon="times"
|
||||
>
|
||||
<Trans i18nKey="scopes.selector.input.remove-all">Remove all</Trans>
|
||||
</LinkButton>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
const baseStyles = getInputStyles({ theme });
|
||||
|
||||
return {
|
||||
scopePath: css({
|
||||
color: theme.colors.text.primary,
|
||||
fontSize: theme.typography.pxToRem(12),
|
||||
margin: theme.spacing(0, 0),
|
||||
prefix: baseStyles.prefix,
|
||||
suffix: baseStyles.suffix,
|
||||
fakeInput: css([
|
||||
baseStyles.input,
|
||||
{
|
||||
width: 'auto',
|
||||
minWidth: 60,
|
||||
height: theme.spacing(theme.components.height.md),
|
||||
maxWidth: '40%',
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
textAlign: 'left',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
paddingRight: 28,
|
||||
flexGrow: 0,
|
||||
|
||||
'&:disabled': cx(
|
||||
baseStyles.inputDisabled,
|
||||
css({
|
||||
cursor: 'not-allowed',
|
||||
})
|
||||
),
|
||||
|
||||
// We want the focus styles to appear only when tabbing through, not when clicking the button
|
||||
// (and when focus is restored after command palette closes)
|
||||
'&:focus': {
|
||||
outline: 'unset',
|
||||
boxShadow: 'unset',
|
||||
},
|
||||
|
||||
'&:focus-visible': getFocusStyles(theme),
|
||||
},
|
||||
]),
|
||||
text: css({
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
}),
|
||||
parentNode: css({
|
||||
marginRight: theme.spacing(1),
|
||||
paddingRight: theme.spacing(1),
|
||||
borderRight: `1px solid ${theme.colors.border.weak}`,
|
||||
color: theme.colors.text.secondary,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { useScopes } from '@grafana/runtime';
|
||||
import { Button, Drawer, ErrorBoundary, ErrorWithStack, IconButton, Spinner, Text, useStyles2 } from '@grafana/ui';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
import { getModKey } from 'app/core/utils/browser';
|
||||
|
||||
import { useScopesServices } from '../ScopesContextProvider';
|
||||
@@ -17,10 +16,7 @@ import { ScopesSelectorServiceState } from './ScopesSelectorService';
|
||||
import { ScopesTree } from './ScopesTree';
|
||||
|
||||
export const ScopesSelector = () => {
|
||||
const { chrome } = useGrafana();
|
||||
const chromeState = chrome.useState();
|
||||
const menuDockedAndOpen = !chromeState.chromeless && chromeState.megaMenuDocked && chromeState.megaMenuOpen;
|
||||
const styles = useStyles2(getStyles, menuDockedAndOpen);
|
||||
const styles = useStyles2(getStyles);
|
||||
const scopes = useScopes();
|
||||
|
||||
const services = useScopesServices();
|
||||
@@ -81,7 +77,7 @@ export const ScopesSelector = () => {
|
||||
: t('scopes.dashboards.toggle.expand', 'Expand suggested dashboards list');
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<>
|
||||
<IconButton
|
||||
name="web-section-alt"
|
||||
className={styles.dashboards}
|
||||
@@ -160,20 +156,14 @@ export const ScopesSelector = () => {
|
||||
</ErrorBoundary>
|
||||
</Drawer>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2, menuDockedAndOpen: boolean) => {
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
container: css({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
paddingLeft: menuDockedAndOpen ? theme.spacing(2) : 'unset',
|
||||
}),
|
||||
dashboards: css({
|
||||
color: theme.colors.text.secondary,
|
||||
marginRight: theme.spacing(2),
|
||||
|
||||
'&:hover': css({
|
||||
color: theme.colors.text.primary,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
expandResultApplications,
|
||||
selectRecentScope,
|
||||
clearSelector,
|
||||
hoverSelector,
|
||||
} from './utils/actions';
|
||||
import {
|
||||
expectRecentScope,
|
||||
@@ -121,7 +122,8 @@ describe('Selector', () => {
|
||||
await selectResultApplicationsMimir();
|
||||
await applyScopes();
|
||||
|
||||
// recent scopes only show on top level, so we need to make sure the scopes tree is not exapnded.
|
||||
// recent scopes only show on top level, so we need to make sure the scopes tree is not expanded.
|
||||
await hoverSelector();
|
||||
await clearSelector();
|
||||
|
||||
await openSelector();
|
||||
|
||||
@@ -47,6 +47,7 @@ const type = async (selector: () => HTMLInputElement, value: string) => {
|
||||
export const updateScopes = async (service: ScopesService, scopes: string[]) =>
|
||||
act(async () => service.changeScopes(scopes));
|
||||
export const openSelector = async () => click(getSelectorInput);
|
||||
export const hoverSelector = async () => fireEvent.mouseOver(getSelectorInput());
|
||||
export const clearSelector = async () => click(getSelectorClear);
|
||||
export const applyScopes = async () => {
|
||||
await click(getSelectorApply);
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
getResultApplicationsCloudSelect,
|
||||
getResultApplicationsGrafanaSelect,
|
||||
getResultApplicationsMimirSelect,
|
||||
getSelectorInput,
|
||||
getSelectorInput as getSelectorButton,
|
||||
getTreeHeadline,
|
||||
queryAllDashboard,
|
||||
queryDashboard,
|
||||
@@ -45,8 +45,8 @@ export const expectRecentScope = (scope: string) => expectInDocument(() => getRe
|
||||
export const expectRecentScopeNotPresentInDocument = () => expectNotInDocument(queryRecentScopesSection);
|
||||
export const expectRecentScopesSection = () => expectInDocument(getRecentScopesSection);
|
||||
export const expectScopesSelectorClosed = () => expectNotInDocument(querySelectorApply);
|
||||
export const expectScopesSelectorDisabled = () => expectDisabled(getSelectorInput);
|
||||
export const expectScopesSelectorValue = (value: string) => expectValue(getSelectorInput, value);
|
||||
export const expectScopesSelectorDisabled = () => expectDisabled(getSelectorButton);
|
||||
export const expectScopesSelectorValue = (value: string) => expect(getSelectorButton().dataset.value).toBe(value);
|
||||
export const expectScopesHeadline = (value: string) => expectTextContent(getTreeHeadline, value);
|
||||
export const expectPersistedApplicationsGrafanaNotPresent = () =>
|
||||
expectNotInDocument(queryPersistedApplicationsGrafanaSelect);
|
||||
|
||||
@@ -35,7 +35,7 @@ const selectors = {
|
||||
},
|
||||
};
|
||||
|
||||
export const getSelectorInput = () => screen.getByTestId<HTMLInputElement>(selectors.selector.input);
|
||||
export const getSelectorInput = () => screen.getByTestId(selectors.selector.input);
|
||||
export const getSelectorClear = () => screen.getByTestId(selectors.selector.clear);
|
||||
export const querySelectorApply = () => screen.queryByTestId(selectors.selector.apply);
|
||||
export const getSelectorApply = () => screen.getByTestId(selectors.selector.apply);
|
||||
|
||||
@@ -12413,8 +12413,10 @@
|
||||
"cancel": "Cancel",
|
||||
"error-title": "An unexpected error happened",
|
||||
"input": {
|
||||
"placeholder": "Select scopes...",
|
||||
"removeAll": "Remove all scopes"
|
||||
"placeholder": "No scopes",
|
||||
"remove-all": "Remove all",
|
||||
"removeAll": "Remove all scopes",
|
||||
"tooltip": "Select scope"
|
||||
},
|
||||
"title": "Select scopes"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user