mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Stack: Use the component from grafana/ui (#77543)
* grafana/ui: Move Stack out of unstable * grafana/ui: Replace imports * Replace the import from experimental * Cleanup * Remove invalid prop * Add flexGrow * Remove Stack used in Field * Remove import
This commit is contained in:
parent
c0d8a7132e
commit
25779bb6e5
@ -1,5 +1,5 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
|
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
|
||||||
|
|
||||||
@ -40,11 +40,12 @@ interface StackProps extends Omit<React.HTMLAttributes<HTMLElement>, 'className'
|
|||||||
direction?: ResponsiveProp<Direction>;
|
direction?: ResponsiveProp<Direction>;
|
||||||
wrap?: ResponsiveProp<Wrap>;
|
wrap?: ResponsiveProp<Wrap>;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
flexGrow?: ResponsiveProp<CSSProperties['flexGrow']>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Stack = React.forwardRef<HTMLDivElement, StackProps>(
|
export const Stack = React.forwardRef<HTMLDivElement, StackProps>(
|
||||||
({ gap = 1, alignItems, justifyContent, direction, wrap, children, ...rest }, ref) => {
|
({ gap = 1, alignItems, justifyContent, direction, wrap, children, flexGrow, ...rest }, ref) => {
|
||||||
const styles = useStyles2(getStyles, gap, alignItems, justifyContent, direction, wrap);
|
const styles = useStyles2(getStyles, gap, alignItems, justifyContent, direction, wrap, flexGrow);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className={styles.flex} {...rest}>
|
<div ref={ref} className={styles.flex} {...rest}>
|
||||||
@ -62,28 +63,32 @@ const getStyles = (
|
|||||||
alignItems: StackProps['alignItems'],
|
alignItems: StackProps['alignItems'],
|
||||||
justifyContent: StackProps['justifyContent'],
|
justifyContent: StackProps['justifyContent'],
|
||||||
direction: StackProps['direction'],
|
direction: StackProps['direction'],
|
||||||
wrap: StackProps['wrap']
|
wrap: StackProps['wrap'],
|
||||||
|
flexGrow: StackProps['flexGrow']
|
||||||
) => {
|
) => {
|
||||||
return {
|
return {
|
||||||
flex: css([
|
flex: css([
|
||||||
{
|
{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
},
|
},
|
||||||
getResponsiveStyle<Direction>(theme, direction, (val) => ({
|
getResponsiveStyle(theme, direction, (val) => ({
|
||||||
flexDirection: val,
|
flexDirection: val,
|
||||||
})),
|
})),
|
||||||
getResponsiveStyle<Wrap>(theme, wrap, (val) => ({
|
getResponsiveStyle(theme, wrap, (val) => ({
|
||||||
flexWrap: val,
|
flexWrap: val,
|
||||||
})),
|
})),
|
||||||
getResponsiveStyle<AlignItems>(theme, alignItems, (val) => ({
|
getResponsiveStyle(theme, alignItems, (val) => ({
|
||||||
alignItems: val,
|
alignItems: val,
|
||||||
})),
|
})),
|
||||||
getResponsiveStyle<JustifyContent>(theme, justifyContent, (val) => ({
|
getResponsiveStyle(theme, justifyContent, (val) => ({
|
||||||
justifyContent: val,
|
justifyContent: val,
|
||||||
})),
|
})),
|
||||||
getResponsiveStyle<ThemeSpacingTokens>(theme, gap, (val) => ({
|
getResponsiveStyle(theme, gap, (val) => ({
|
||||||
gap: theme.spacing(val),
|
gap: theme.spacing(val),
|
||||||
})),
|
})),
|
||||||
|
getResponsiveStyle(theme, flexGrow, (val) => ({
|
||||||
|
flexGrow: val,
|
||||||
|
})),
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Form, Select, Stack } from '@grafana/ui';
|
||||||
import { Button, Form, Select } from '@grafana/ui';
|
|
||||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
||||||
import { ServiceAccountPicker } from 'app/core/components/Select/ServiceAccountPicker';
|
import { ServiceAccountPicker } from 'app/core/components/Select/ServiceAccountPicker';
|
||||||
import { TeamPicker } from 'app/core/components/Select/TeamPicker';
|
import { TeamPicker } from 'app/core/components/Select/TeamPicker';
|
||||||
|
@ -3,8 +3,7 @@ import React, { MouseEventHandler } from 'react';
|
|||||||
import { DraggableProvided } from 'react-beautiful-dnd';
|
import { DraggableProvided } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, IconButton, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, IconButton, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface QueryOperationRowHeaderProps {
|
export interface QueryOperationRowHeaderProps {
|
||||||
actionsElement?: React.ReactNode;
|
actionsElement?: React.ReactNode;
|
||||||
@ -73,7 +72,7 @@ export const QueryOperationRowHeader = ({
|
|||||||
{headerElement}
|
{headerElement}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Stack gap={1} alignItems="center" wrap={false}>
|
<Stack gap={1} alignItems="center">
|
||||||
{actionsElement}
|
{actionsElement}
|
||||||
{draggable && (
|
{draggable && (
|
||||||
<div onMouseMove={reportDragMousePosition} {...dragHandleProps}>
|
<div onMouseMove={reportDragMousePosition} {...dragHandleProps}>
|
||||||
|
@ -4,8 +4,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { useDebounce } from 'react-use';
|
import { useDebounce } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Card, FilterInput, Icon, Pagination, Select, TagList, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Card, FilterInput, Icon, Pagination, Select, TagList, useStyles2 } from '@grafana/ui';
|
|
||||||
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
|
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
|
||||||
import { getQueryParamValue } from 'app/core/utils/query';
|
import { getQueryParamValue } from 'app/core/utils/query';
|
||||||
import { FolderState, useDispatch } from 'app/types';
|
import { FolderState, useDispatch } from 'app/types';
|
||||||
|
@ -4,9 +4,8 @@ import { keyBy, startCase } from 'lodash';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { DataSourceInstanceSettings, GrafanaTheme2, PanelData, RelativeTimeRange } from '@grafana/data';
|
import { DataSourceInstanceSettings, GrafanaTheme2, PanelData, RelativeTimeRange } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { Badge, useStyles2 } from '@grafana/ui';
|
import { Badge, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { mapRelativeTimeRangeToOption } from '@grafana/ui/src/components/DateTimePickers/RelativeTimeRangePicker/utils';
|
import { mapRelativeTimeRangeToOption } from '@grafana/ui/src/components/DateTimePickers/RelativeTimeRangePicker/utils';
|
||||||
|
|
||||||
import { AlertQuery } from '../../../types/unified-alerting-dto';
|
import { AlertQuery } from '../../../types/unified-alerting-dto';
|
||||||
|
@ -4,8 +4,7 @@ import React, { useEffect, useMemo, useState } from 'react';
|
|||||||
import { useAsyncFn } from 'react-use';
|
import { useAsyncFn } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2, UrlQueryMap } from '@grafana/data';
|
import { GrafanaTheme2, UrlQueryMap } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Alert, LoadingPlaceholder, Tab, TabContent, TabsBar, useStyles2, withErrorBoundary, Stack } from '@grafana/ui';
|
||||||
import { Alert, LoadingPlaceholder, Tab, TabContent, TabsBar, useStyles2, withErrorBoundary } from '@grafana/ui';
|
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
import { ObjectMatcher, Route, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
import { ObjectMatcher, Route, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
|
@ -3,8 +3,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { useAsyncFn, useInterval } from 'react-use';
|
import { useAsyncFn, useInterval } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, useStyles2, withErrorBoundary, Stack } from '@grafana/ui';
|
||||||
import { Button, useStyles2, withErrorBoundary } from '@grafana/ui';
|
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ import classnames from 'classnames';
|
|||||||
import React, { ReactElement, ReactNode, useRef } from 'react';
|
import React, { ReactElement, ReactNode, useRef } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Popover as GrafanaPopover, PopoverController, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Popover as GrafanaPopover, PopoverController, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface HoverCardProps {
|
export interface HoverCardProps {
|
||||||
children: ReactElement;
|
children: ReactElement;
|
||||||
|
@ -3,8 +3,7 @@ import React, { ReactNode } from 'react';
|
|||||||
import tinycolor2 from 'tinycolor2';
|
import tinycolor2 from 'tinycolor2';
|
||||||
|
|
||||||
import { GrafanaTheme2, IconName } from '@grafana/data';
|
import { GrafanaTheme2, IconName } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export type LabelSize = 'md' | 'sm';
|
export type LabelSize = 'md' | 'sm';
|
||||||
|
|
||||||
@ -22,7 +21,7 @@ const Label = ({ label, value, icon, color, size = 'md' }: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper} role="listitem">
|
<div className={styles.wrapper} role="listitem">
|
||||||
<Stack direction="row" gap={0} alignItems="stretch" wrap={false}>
|
<Stack direction="row" gap={0} alignItems="stretch">
|
||||||
<div className={styles.label}>
|
<div className={styles.label}>
|
||||||
<Stack direction="row" gap={0.5} alignItems="center">
|
<Stack direction="row" gap={0.5} alignItems="center">
|
||||||
{icon && <Icon name={icon} />} {label ?? ''}
|
{icon && <Icon name={icon} />} {label ?? ''}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import React, { ComponentProps, HTMLAttributes } from 'react';
|
import React, { ComponentProps, HTMLAttributes } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, IconName, useStyles2, Text, Stack } from '@grafana/ui';
|
||||||
import { Icon, IconName, useStyles2, Text } from '@grafana/ui';
|
|
||||||
|
|
||||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||||
icon?: IconName;
|
icon?: IconName;
|
||||||
@ -22,7 +21,7 @@ const MetaText = ({ children, icon, color = 'secondary', ...rest }: Props) => {
|
|||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
<Text variant="bodySmall" color={color}>
|
<Text variant="bodySmall" color={color}>
|
||||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
<Stack direction="row" alignItems="center" gap={0.5} wrap={'wrap'}>
|
||||||
{icon && <Icon size="sm" name={icon} />}
|
{icon && <Icon size="sm" name={icon} />}
|
||||||
{children}
|
{children}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { forwardRef, Ref } from 'react';
|
import React, { forwardRef, Ref } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, ButtonProps, Icon, Stack } from '@grafana/ui';
|
||||||
import { Button, ButtonProps, Icon } from '@grafana/ui';
|
|
||||||
|
|
||||||
const MoreButton = forwardRef(function MoreButton(props: ButtonProps, ref: Ref<HTMLButtonElement>) {
|
const MoreButton = forwardRef(function MoreButton(props: ButtonProps, ref: Ref<HTMLButtonElement>) {
|
||||||
return (
|
return (
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { useStyles2, Stack } from '@grafana/ui';
|
||||||
import { useStyles2 } from '@grafana/ui';
|
|
||||||
import { AlertmanagerGroup, AlertState } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertmanagerGroup, AlertState } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { AlertLabels } from '../AlertLabels';
|
import { AlertLabels } from '../AlertLabels';
|
||||||
|
@ -3,8 +3,7 @@ import { debounce } from 'lodash';
|
|||||||
import React, { FormEvent, useEffect, useMemo } from 'react';
|
import React, { FormEvent, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Label, Tooltip, Input, Icon, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Label, Tooltip, Input, Icon, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { logInfo, LogMessages } from '../../Analytics';
|
import { logInfo, LogMessages } from '../../Analytics';
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import { Link } from 'react-router-dom';
|
|||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
|
|
||||||
import { dateTime, GrafanaTheme2 } from '@grafana/data';
|
import { dateTime, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
@ -23,6 +22,7 @@ import {
|
|||||||
Tab,
|
Tab,
|
||||||
Pagination,
|
Pagination,
|
||||||
Button,
|
Button,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
||||||
import { receiverTypeNames } from 'app/plugins/datasource/alertmanager/consts';
|
import { receiverTypeNames } from 'app/plugins/datasource/alertmanager/consts';
|
||||||
|
@ -3,8 +3,7 @@ import { uniqueId } from 'lodash';
|
|||||||
import React, { FC, useCallback, useState } from 'react';
|
import React, { FC, useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { DataFrame, dateTimeFormat, GrafanaTheme2, isTimeSeriesFrames, LoadingState, PanelData } from '@grafana/data';
|
import { DataFrame, dateTimeFormat, GrafanaTheme2, isTimeSeriesFrames, LoadingState, PanelData } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { AutoSizeInput, Button, clearButtonStyles, IconButton, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { AutoSizeInput, Button, clearButtonStyles, IconButton, useStyles2 } from '@grafana/ui';
|
|
||||||
import { ClassicConditions } from 'app/features/expressions/components/ClassicConditions';
|
import { ClassicConditions } from 'app/features/expressions/components/ClassicConditions';
|
||||||
import { Math } from 'app/features/expressions/components/Math';
|
import { Math } from 'app/features/expressions/components/Math';
|
||||||
import { Reduce } from 'app/features/expressions/components/Reduce';
|
import { Reduce } from 'app/features/expressions/components/Reduce';
|
||||||
@ -288,7 +287,7 @@ const Header: FC<HeaderProps> = ({
|
|||||||
return (
|
return (
|
||||||
<header className={styles.header.wrapper}>
|
<header className={styles.header.wrapper}>
|
||||||
<Stack direction="row" gap={0.5} alignItems="center">
|
<Stack direction="row" gap={0.5} alignItems="center">
|
||||||
<Stack direction="row" gap={1} alignItems="center" wrap={false}>
|
<Stack direction="row" gap={1} alignItems="center">
|
||||||
{!editingRefId && (
|
{!editingRefId && (
|
||||||
<button type="button" className={cx(clearButton, styles.editable)} onClick={() => setEditMode('refId')}>
|
<button type="button" className={cx(clearButton, styles.editable)} onClick={() => setEditMode('refId')}>
|
||||||
<div className={styles.expression.refId}>{refId}</div>
|
<div className={styles.expression.refId}>{refId}</div>
|
||||||
|
@ -4,8 +4,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { useFieldArray, useFormContext } from 'react-hook-form';
|
import { useFieldArray, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Field, FieldSet, Icon, Input, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Field, FieldSet, Icon, Input, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { MuteTimingFields } from '../../types/mute-timing-form';
|
import { MuteTimingFields } from '../../types/mute-timing-form';
|
||||||
import { DAYS_OF_THE_WEEK, defaultTimeInterval, MONTHS, validateArrayField } from '../../utils/mute-timings';
|
import { DAYS_OF_THE_WEEK, defaultTimeInterval, MONTHS, validateArrayField } from '../../utils/mute-timings';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { IconButton, LinkButton, Link, useStyles2, ConfirmModal, Stack } from '@grafana/ui';
|
||||||
import { IconButton, LinkButton, Link, useStyles2, ConfirmModal } from '@grafana/ui';
|
|
||||||
import { MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
|
import { MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
|
||||||
import { useDispatch } from 'app/types/store';
|
import { useDispatch } from 'app/types/store';
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import pluralize from 'pluralize';
|
import pluralize from 'pluralize';
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Badge, Stack } from '@grafana/ui';
|
||||||
import { Badge } from '@grafana/ui';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
active?: number;
|
active?: number;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Select, SelectCommonProps, Text, Stack } from '@grafana/ui';
|
||||||
import { Select, SelectCommonProps, Text } from '@grafana/ui';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RECEIVER_META_KEY,
|
RECEIVER_META_KEY,
|
||||||
@ -36,7 +35,7 @@ interface ReceiversProps {
|
|||||||
|
|
||||||
const ReceiversSummary = ({ receivers }: ReceiversProps) => {
|
const ReceiversSummary = ({ receivers }: ReceiversProps) => {
|
||||||
return (
|
return (
|
||||||
<Stack direction="row" wrap={false}>
|
<Stack direction="row">
|
||||||
{receivers.map((receiver, index) => (
|
{receivers.map((receiver, index) => (
|
||||||
<Stack key={receiver.uid ?? index} direction="row" gap={0.5}>
|
<Stack key={receiver.uid ?? index} direction="row" gap={0.5}>
|
||||||
{receiver[RECEIVER_PLUGIN_META_KEY]?.icon && (
|
{receiver[RECEIVER_PLUGIN_META_KEY]?.icon && (
|
||||||
|
@ -2,7 +2,6 @@ import { css } from '@emotion/css';
|
|||||||
import React, { ReactNode, useState } from 'react';
|
import React, { ReactNode, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Field,
|
Field,
|
||||||
@ -17,6 +16,7 @@ import {
|
|||||||
useStyles2,
|
useStyles2,
|
||||||
Badge,
|
Badge,
|
||||||
FieldValidationMessage,
|
FieldValidationMessage,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { MatcherOperator, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
import { MatcherOperator, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import { debounce } from 'lodash';
|
|||||||
import React, { useCallback, useEffect, useRef } from 'react';
|
import React, { useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Field, Icon, Input, Label as LabelElement, Select, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Field, Icon, Input, Label as LabelElement, Select, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
import { ObjectMatcher, Receiver, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
import { ObjectMatcher, Receiver, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { useURLSearchParams } from '../../hooks/useURLSearchParams';
|
import { useURLSearchParams } from '../../hooks/useURLSearchParams';
|
||||||
|
@ -3,8 +3,7 @@ import { take, takeRight, uniqueId } from 'lodash';
|
|||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { getTagColorsFromName, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { getTagColorsFromName, useStyles2 } from '@grafana/ui';
|
|
||||||
import { ObjectMatcher } from 'app/plugins/datasource/alertmanager/types';
|
import { ObjectMatcher } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { HoverCard } from '../HoverCard';
|
import { HoverCard } from '../HoverCard';
|
||||||
@ -23,7 +22,7 @@ const Matchers: FC<MatchersProps> = ({ matchers }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span data-testid="label-matchers">
|
<span data-testid="label-matchers">
|
||||||
<Stack direction="row" gap={1} alignItems="center">
|
<Stack direction="row" gap={1} alignItems="center" wrap={'wrap'}>
|
||||||
{firstFew.map((matcher) => (
|
{firstFew.map((matcher) => (
|
||||||
<MatcherBadge key={uniqueId()} matcher={matcher} />
|
<MatcherBadge key={uniqueId()} matcher={matcher} />
|
||||||
))}
|
))}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { groupBy } from 'lodash';
|
import { groupBy } from 'lodash';
|
||||||
import React, { FC, useCallback, useMemo, useState } from 'react';
|
import React, { FC, useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Icon, Modal, ModalProps, Spinner, Stack } from '@grafana/ui';
|
||||||
import { Button, Icon, Modal, ModalProps, Spinner } from '@grafana/ui';
|
|
||||||
import {
|
import {
|
||||||
AlertmanagerGroup,
|
AlertmanagerGroup,
|
||||||
AlertState,
|
AlertState,
|
||||||
@ -239,7 +238,7 @@ const useAlertGroupsModal = (): [
|
|||||||
closeOnBackdropClick={true}
|
closeOnBackdropClick={true}
|
||||||
closeOnEscape={true}
|
closeOnEscape={true}
|
||||||
title={
|
title={
|
||||||
<Stack direction="row" alignItems="center" gap={1} flexGrow={1}>
|
<Stack direction="row" alignItems="center" gap={1} wrap={'wrap'}>
|
||||||
<Stack direction="row" alignItems="center" gap={0.5}>
|
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||||
<Icon name="x" /> Matchers
|
<Icon name="x" /> Matchers
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -6,8 +6,18 @@ import { Link } from 'react-router-dom';
|
|||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import {
|
||||||
import { Badge, Button, Dropdown, getTagColorsFromName, Icon, Menu, Text, Tooltip, useStyles2 } from '@grafana/ui';
|
Badge,
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
Icon,
|
||||||
|
Menu,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
Tooltip,
|
||||||
|
getTagColorsFromName,
|
||||||
|
useStyles2,
|
||||||
|
} from '@grafana/ui';
|
||||||
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
||||||
import { AlertmanagerGroup, ObjectMatcher, Receiver, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertmanagerGroup, ObjectMatcher, Receiver, RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||||
import { ReceiversState } from 'app/types';
|
import { ReceiversState } from 'app/types';
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Alert, LinkButton, Stack } from '@grafana/ui';
|
||||||
import { Alert, LinkButton } from '@grafana/ui';
|
|
||||||
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { AlertmanagerAction, useAlertmanagerAbility } from '../../hooks/useAbilities';
|
import { AlertmanagerAction, useAlertmanagerAbility } from '../../hooks/useAbilities';
|
||||||
|
@ -4,8 +4,7 @@ import { Link } from 'react-router-dom';
|
|||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Dropdown, Icon, Menu, MenuItem, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Dropdown, Icon, Menu, MenuItem, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { GrafanaReceiversExporter } from '../export/GrafanaReceiversExporter';
|
import { GrafanaReceiversExporter } from '../export/GrafanaReceiversExporter';
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import React, { useMemo, useState } from 'react';
|
|||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
|
|
||||||
import { dateTime, dateTimeFormat } from '@grafana/data';
|
import { dateTime, dateTimeFormat } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Badge, Button, ConfirmModal, Icon, Modal, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Badge, Button, ConfirmModal, Icon, Modal, useStyles2 } from '@grafana/ui';
|
|
||||||
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
||||||
import { ContactPointsState, NotifiersState, ReceiversState, useDispatch } from 'app/types';
|
import { ContactPointsState, NotifiersState, ReceiversState, useDispatch } from 'app/types';
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { useStyles2, Stack } from '@grafana/ui';
|
||||||
import { useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { HoverCard } from '../HoverCard';
|
import { HoverCard } from '../HoverCard';
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ export function TemplateDataDocs() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap={2} flexGrow={1}>
|
<Stack gap={2}>
|
||||||
<TemplateDataTable
|
<TemplateDataTable
|
||||||
caption={<h4 className={styles.header}>Template Data</h4>}
|
caption={<h4 className={styles.header}>Template Data</h4>}
|
||||||
dataItems={GlobalTemplateData}
|
dataItems={GlobalTemplateData}
|
||||||
|
@ -7,7 +7,6 @@ import { useLocation } from 'react-router-dom';
|
|||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { isFetchError } from '@grafana/runtime';
|
import { isFetchError } from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
@ -21,6 +20,7 @@ import {
|
|||||||
Tab,
|
Tab,
|
||||||
TabsBar,
|
TabsBar,
|
||||||
useStyles2,
|
useStyles2,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { useCleanup } from 'app/core/hooks/useCleanup';
|
import { useCleanup } from 'app/core/hooks/useCleanup';
|
||||||
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
@ -4,8 +4,7 @@ import React, { useState } from 'react';
|
|||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Card, Modal, RadioButtonGroup, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Card, Modal, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
|
||||||
import { TestTemplateAlert } from 'app/plugins/datasource/alertmanager/types';
|
import { TestTemplateAlert } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { KeyValueField } from '../../../api/templateApi';
|
import { KeyValueField } from '../../../api/templateApi';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, LinkButton, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, LinkButton, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { ReceiverPluginMetadata } from './useReceiversMetadata';
|
import { ReceiverPluginMetadata } from './useReceiversMetadata';
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FieldArrayWithId, useFormContext } from 'react-hook-form';
|
import { FieldArrayWithId, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { InputControl, Text, Stack } from '@grafana/ui';
|
||||||
import { InputControl, Text } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { RuleFormValues } from '../../types/rule-form';
|
import { RuleFormValues } from '../../types/rule-form';
|
||||||
import { Annotation, annotationDescriptions, annotationLabels } from '../../utils/constants';
|
import { Annotation, annotationDescriptions, annotationLabels } from '../../utils/constants';
|
||||||
|
@ -5,8 +5,7 @@ import { useFieldArray, useFormContext } from 'react-hook-form';
|
|||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Field, Input, Text, TextArea, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Field, Input, Text, TextArea, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { DashboardModel } from '../../../../dashboard/state';
|
import { DashboardModel } from '../../../../dashboard/state';
|
||||||
import { RuleFormValues } from '../../types/rule-form';
|
import { RuleFormValues } from '../../types/rule-form';
|
||||||
|
@ -4,8 +4,19 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import {
|
||||||
import { AsyncSelect, Button, Field, Input, InputControl, Label, Modal, Text, useStyles2 } from '@grafana/ui';
|
AsyncSelect,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Field,
|
||||||
|
Input,
|
||||||
|
InputControl,
|
||||||
|
Label,
|
||||||
|
Modal,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
useStyles2,
|
||||||
|
} from '@grafana/ui';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import { createFolder } from 'app/features/manage-dashboards/state/actions';
|
import { createFolder } from 'app/features/manage-dashboards/state/actions';
|
||||||
@ -134,108 +145,103 @@ export function FolderAndGroup({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div>
|
<Stack alignItems="center">
|
||||||
{
|
|
||||||
<Field
|
|
||||||
label={
|
|
||||||
<Label htmlFor="folder" description={'Select a folder to store your rule.'}>
|
|
||||||
Folder
|
|
||||||
</Label>
|
|
||||||
}
|
|
||||||
className={styles.formInput}
|
|
||||||
error={errors.folder?.message}
|
|
||||||
invalid={!!errors.folder?.message}
|
|
||||||
data-testid="folder-picker"
|
|
||||||
>
|
|
||||||
<Stack direction="row" alignItems="center">
|
|
||||||
{(!isCreatingFolder && (
|
|
||||||
<>
|
|
||||||
<InputControl
|
|
||||||
render={({ field: { ref, ...field } }) => (
|
|
||||||
<div style={{ width: 420 }}>
|
|
||||||
<RuleFolderPicker
|
|
||||||
inputId="folder"
|
|
||||||
{...field}
|
|
||||||
enableReset={true}
|
|
||||||
onChange={({ title, uid }) => {
|
|
||||||
field.onChange({ title, uid });
|
|
||||||
resetGroup();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
name="folder"
|
|
||||||
rules={{
|
|
||||||
required: { value: true, message: 'Select a folder' },
|
|
||||||
validate: {
|
|
||||||
pathSeparator: (folder: Folder) => checkForPathSeparator(folder.title),
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text color="secondary">or</Text>
|
|
||||||
<Button
|
|
||||||
onClick={onOpenFolderCreationModal}
|
|
||||||
type="button"
|
|
||||||
icon="plus"
|
|
||||||
fill="outline"
|
|
||||||
variant="secondary"
|
|
||||||
disabled={!contextSrv.hasPermission(AccessControlAction.FoldersCreate)}
|
|
||||||
>
|
|
||||||
New folder
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)) || <div>Creating new folder...</div>}
|
|
||||||
</Stack>
|
|
||||||
</Field>
|
|
||||||
}
|
|
||||||
{isCreatingFolder && (
|
|
||||||
<FolderCreationModal onCreate={handleFolderCreation} onClose={() => setIsCreatingFolder(false)} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Field
|
<Field
|
||||||
label="Evaluation group"
|
label={
|
||||||
data-testid="group-picker"
|
<Label htmlFor="folder" description={'Select a folder to store your rule.'}>
|
||||||
description="Rules within the same group are evaluated sequentially over the same time interval."
|
Folder
|
||||||
|
</Label>
|
||||||
|
}
|
||||||
className={styles.formInput}
|
className={styles.formInput}
|
||||||
error={errors.group?.message}
|
error={errors.folder?.message}
|
||||||
invalid={!!errors.group?.message}
|
invalid={!!errors.folder?.message}
|
||||||
|
data-testid="folder-picker"
|
||||||
>
|
>
|
||||||
<Stack direction="row" alignItems="center">
|
{(!isCreatingFolder && (
|
||||||
<InputControl
|
<InputControl
|
||||||
render={({ field: { ref, ...field }, fieldState }) => (
|
render={({ field: { ref, ...field } }) => (
|
||||||
<div style={{ width: 420 }}>
|
<div style={{ width: 420 }}>
|
||||||
<AsyncSelect
|
<RuleFolderPicker
|
||||||
disabled={!folder || loading}
|
inputId="folder"
|
||||||
inputId="group"
|
|
||||||
key={uniqueId()}
|
|
||||||
{...field}
|
{...field}
|
||||||
onChange={(group) => {
|
enableReset={true}
|
||||||
field.onChange(group.label ?? '');
|
onChange={({ title, uid }) => {
|
||||||
|
field.onChange({ title, uid });
|
||||||
|
resetGroup();
|
||||||
}}
|
}}
|
||||||
isLoading={loading}
|
|
||||||
invalid={Boolean(folder) && !group && Boolean(fieldState.error)}
|
|
||||||
loadOptions={debouncedSearch}
|
|
||||||
cacheOptions
|
|
||||||
loadingMessage={'Loading groups...'}
|
|
||||||
defaultValue={defaultGroupValue}
|
|
||||||
defaultOptions={groupOptions}
|
|
||||||
getOptionLabel={(option: SelectableValue<string>) => (
|
|
||||||
<div>
|
|
||||||
<span>{option.label}</span>
|
|
||||||
{option['isProvisioned'] && (
|
|
||||||
<>
|
|
||||||
{' '}
|
|
||||||
<ProvisioningBadge />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
placeholder={'Select an evaluation group...'}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
name="folder"
|
||||||
|
rules={{
|
||||||
|
required: { value: true, message: 'Select a folder' },
|
||||||
|
validate: {
|
||||||
|
pathSeparator: (folder: Folder) => checkForPathSeparator(folder.title),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)) || <div>Creating new folder...</div>}
|
||||||
|
</Field>
|
||||||
|
<Box marginTop={2.5} gap={1} display={'flex'} alignItems={'center'}>
|
||||||
|
<Text color="secondary">or</Text>
|
||||||
|
<Button
|
||||||
|
onClick={onOpenFolderCreationModal}
|
||||||
|
type="button"
|
||||||
|
icon="plus"
|
||||||
|
fill="outline"
|
||||||
|
variant="secondary"
|
||||||
|
disabled={!contextSrv.hasPermission(AccessControlAction.FoldersCreate)}
|
||||||
|
>
|
||||||
|
New folder
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{isCreatingFolder && (
|
||||||
|
<FolderCreationModal onCreate={handleFolderCreation} onClose={() => setIsCreatingFolder(false)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Stack alignItems="center">
|
||||||
|
<div style={{ width: 420 }}>
|
||||||
|
<Field
|
||||||
|
label="Evaluation group"
|
||||||
|
data-testid="group-picker"
|
||||||
|
description="Rules within the same group are evaluated sequentially over the same time interval."
|
||||||
|
className={styles.formInput}
|
||||||
|
error={errors.group?.message}
|
||||||
|
invalid={!!errors.group?.message}
|
||||||
|
>
|
||||||
|
<InputControl
|
||||||
|
render={({ field: { ref, ...field }, fieldState }) => (
|
||||||
|
<AsyncSelect
|
||||||
|
disabled={!folder || loading}
|
||||||
|
inputId="group"
|
||||||
|
key={uniqueId()}
|
||||||
|
{...field}
|
||||||
|
onChange={(group) => {
|
||||||
|
field.onChange(group.label ?? '');
|
||||||
|
}}
|
||||||
|
isLoading={loading}
|
||||||
|
invalid={Boolean(folder) && !group && Boolean(fieldState.error)}
|
||||||
|
loadOptions={debouncedSearch}
|
||||||
|
cacheOptions
|
||||||
|
loadingMessage={'Loading groups...'}
|
||||||
|
defaultValue={defaultGroupValue}
|
||||||
|
defaultOptions={groupOptions}
|
||||||
|
getOptionLabel={(option: SelectableValue<string>) => (
|
||||||
|
<div>
|
||||||
|
<span>{option.label}</span>
|
||||||
|
{option['isProvisioned'] && (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
<ProvisioningBadge />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
placeholder={'Select an evaluation group...'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
name="group"
|
name="group"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{
|
||||||
@ -245,19 +251,21 @@ export function FolderAndGroup({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Text color="secondary">or</Text>
|
</Field>
|
||||||
<Button
|
</div>
|
||||||
onClick={onOpenEvaluationGroupCreationModal}
|
<Box marginTop={4} gap={1} display={'flex'} alignItems={'center'}>
|
||||||
type="button"
|
<Text color="secondary">or</Text>
|
||||||
icon="plus"
|
<Button
|
||||||
fill="outline"
|
onClick={onOpenEvaluationGroupCreationModal}
|
||||||
variant="secondary"
|
type="button"
|
||||||
disabled={!folder}
|
icon="plus"
|
||||||
>
|
fill="outline"
|
||||||
New evaluation group
|
variant="secondary"
|
||||||
</Button>
|
disabled={!folder}
|
||||||
</Stack>
|
>
|
||||||
</Field>
|
New evaluation group
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
{isCreatingEvaluationGroup && (
|
{isCreatingEvaluationGroup && (
|
||||||
<EvaluationGroupCreationModal
|
<EvaluationGroupCreationModal
|
||||||
onCreate={handleEvalGroupCreation}
|
onCreate={handleEvalGroupCreation}
|
||||||
@ -265,7 +273,7 @@ export function FolderAndGroup({
|
|||||||
groupfoldersForGrafana={groupfoldersForGrafana}
|
groupfoldersForGrafana={groupfoldersForGrafana}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,19 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||||||
import { RegisterOptions, useFormContext } from 'react-hook-form';
|
import { RegisterOptions, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import {
|
||||||
import { Field, Icon, IconButton, Input, InputControl, Label, Switch, Text, Tooltip, useStyles2 } from '@grafana/ui';
|
Field,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
InputControl,
|
||||||
|
Label,
|
||||||
|
Stack,
|
||||||
|
Switch,
|
||||||
|
Text,
|
||||||
|
Tooltip,
|
||||||
|
useStyles2,
|
||||||
|
} from '@grafana/ui';
|
||||||
|
|
||||||
import { CombinedRuleGroup, CombinedRuleNamespace } from '../../../../../types/unified-alerting';
|
import { CombinedRuleGroup, CombinedRuleNamespace } from '../../../../../types/unified-alerting';
|
||||||
import { logInfo, LogMessages } from '../../Analytics';
|
import { logInfo, LogMessages } from '../../Analytics';
|
||||||
|
@ -3,7 +3,6 @@ import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { FieldArrayMethodProps, useFieldArray, useFormContext } from 'react-hook-form';
|
import { FieldArrayMethodProps, useFieldArray, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Field,
|
Field,
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
Input,
|
Input,
|
||||||
LoadingPlaceholder,
|
LoadingPlaceholder,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, Text, Toggletip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, Text, Toggletip, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
interface NeedHelpInfoProps {
|
interface NeedHelpInfoProps {
|
||||||
contentText: string | JSX.Element;
|
contentText: string | JSX.Element;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, Text, Stack } from '@grafana/ui';
|
||||||
import { Icon, Text } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { RuleFormType, RuleFormValues } from '../../types/rule-form';
|
import { RuleFormType, RuleFormValues } from '../../types/rule-form';
|
||||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
|
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
|
||||||
|
@ -10,9 +10,8 @@ import {
|
|||||||
rangeUtil,
|
rangeUtil,
|
||||||
RelativeTimeRange,
|
RelativeTimeRange,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { getDataSourceSrv } from '@grafana/runtime';
|
import { getDataSourceSrv } from '@grafana/runtime';
|
||||||
import { Button, Card, Icon } from '@grafana/ui';
|
import { Button, Card, Icon, Stack } from '@grafana/ui';
|
||||||
import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow';
|
import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow';
|
||||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||||
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
|
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
|
@ -12,9 +12,8 @@ import {
|
|||||||
RelativeTimeRange,
|
RelativeTimeRange,
|
||||||
ThresholdsConfig,
|
ThresholdsConfig,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { DataQuery } from '@grafana/schema';
|
import { DataQuery } from '@grafana/schema';
|
||||||
import { GraphTresholdsStyleMode, Icon, InlineField, Input, Tooltip, useStyles2 } from '@grafana/ui';
|
import { GraphTresholdsStyleMode, Icon, InlineField, Input, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { QueryEditorRow } from 'app/features/query/components/QueryEditorRow';
|
import { QueryEditorRow } from 'app/features/query/components/QueryEditorRow';
|
||||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import { css, cx } from '@emotion/css';
|
|||||||
import React, { ReactElement } from 'react';
|
import React, { ReactElement } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { FieldSet, Text, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { FieldSet, Text, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface RuleEditorSectionProps {
|
export interface RuleEditorSectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
import { OldFolderPicker, Props as FolderPickerProps } from 'app/core/components/Select/OldFolderPicker';
|
import { OldFolderPicker, Props as FolderPickerProps } from 'app/core/components/Select/OldFolderPicker';
|
||||||
import { PermissionLevelString, SearchQueryType } from 'app/types';
|
import { PermissionLevelString, SearchQueryType } from 'app/types';
|
||||||
|
|
||||||
|
@ -4,9 +4,8 @@ import { DeepMap, FieldError, FormProvider, useForm, UseFormWatch } from 'react-
|
|||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { Button, ConfirmModal, CustomScrollbar, HorizontalGroup, Spinner, useStyles2 } from '@grafana/ui';
|
import { Button, ConfirmModal, CustomScrollbar, HorizontalGroup, Spinner, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
|
@ -2,8 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { useAsync } from 'react-use';
|
import { useAsync } from 'react-use';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, CustomScrollbar, LinkButton, LoadingPlaceholder, Stack } from '@grafana/ui';
|
||||||
import { Button, CustomScrollbar, LinkButton, LoadingPlaceholder } from '@grafana/ui';
|
|
||||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
|
|
||||||
|
@ -5,9 +5,20 @@ import { useFormContext } from 'react-hook-form';
|
|||||||
|
|
||||||
import { getDefaultRelativeTimeRange, GrafanaTheme2 } from '@grafana/data';
|
import { getDefaultRelativeTimeRange, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config, getDataSourceSrv } from '@grafana/runtime';
|
import { config, getDataSourceSrv } from '@grafana/runtime';
|
||||||
import { Alert, Button, Dropdown, Field, Icon, InputControl, Menu, MenuItem, Tooltip, useStyles2 } from '@grafana/ui';
|
import {
|
||||||
|
Alert,
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
Field,
|
||||||
|
Icon,
|
||||||
|
InputControl,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
Stack,
|
||||||
|
Tooltip,
|
||||||
|
useStyles2,
|
||||||
|
} from '@grafana/ui';
|
||||||
import { Text } from '@grafana/ui/src/components/Text/Text';
|
import { Text } from '@grafana/ui/src/components/Text/Text';
|
||||||
import { isExpressionQuery } from 'app/features/expressions/guards';
|
import { isExpressionQuery } from 'app/features/expressions/guards';
|
||||||
import { ExpressionDatasourceUID, ExpressionQueryType, expressionTypes } from 'app/features/expressions/types';
|
import { ExpressionDatasourceUID, ExpressionQueryType, expressionTypes } from 'app/features/expressions/types';
|
||||||
|
@ -2,9 +2,8 @@ import React from 'react';
|
|||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { DataSourceJsonData } from '@grafana/schema';
|
import { DataSourceJsonData } from '@grafana/schema';
|
||||||
import { RadioButtonGroup, Text } from '@grafana/ui';
|
import { RadioButtonGroup, Text, Stack } from '@grafana/ui';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { ExpressionDatasourceUID } from 'app/features/expressions/types';
|
import { ExpressionDatasourceUID } from 'app/features/expressions/types';
|
||||||
import { AccessControlAction } from 'app/types';
|
import { AccessControlAction } from 'app/types';
|
||||||
|
@ -3,8 +3,7 @@ import { isEmpty } from 'lodash';
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data/src';
|
import { GrafanaTheme2 } from '@grafana/data/src';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { useStyles2, Stack } from '@grafana/ui';
|
||||||
import { useStyles2 } from '@grafana/ui';
|
|
||||||
import { dispatch } from 'app/store/store';
|
import { dispatch } from 'app/store/store';
|
||||||
|
|
||||||
import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler';
|
import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler';
|
||||||
|
@ -4,9 +4,18 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { useObservable, useToggle } from 'react-use';
|
import { useObservable, useToggle } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2, LoadingState, PanelData, RelativeTimeRange } from '@grafana/data';
|
import { GrafanaTheme2, LoadingState, PanelData, RelativeTimeRange } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config, isFetchError } from '@grafana/runtime';
|
import { config, isFetchError } from '@grafana/runtime';
|
||||||
import { Alert, Button, Collapse, Icon, IconButton, LoadingPlaceholder, useStyles2, VerticalGroup } from '@grafana/ui';
|
import {
|
||||||
|
Alert,
|
||||||
|
Button,
|
||||||
|
Collapse,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
LoadingPlaceholder,
|
||||||
|
Stack,
|
||||||
|
VerticalGroup,
|
||||||
|
useStyles2,
|
||||||
|
} from '@grafana/ui';
|
||||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||||
|
|
||||||
import { DEFAULT_PER_PAGE_PAGINATION } from '../../../../../core/constants';
|
import { DEFAULT_PER_PAGE_PAGINATION } from '../../../../../core/constants';
|
||||||
@ -164,7 +173,7 @@ export function RuleViewer({ match }: RuleViewerProps) {
|
|||||||
{isProvisioned && <ProvisioningAlert resource={ProvisionedResource.AlertRule} />}
|
{isProvisioned && <ProvisioningAlert resource={ProvisionedResource.AlertRule} />}
|
||||||
<RuleViewerLayoutContent>
|
<RuleViewerLayoutContent>
|
||||||
<div>
|
<div>
|
||||||
<Stack direction="row" alignItems="center" wrap={false} gap={1}>
|
<Stack direction="row" alignItems="center" gap={1}>
|
||||||
<Icon name="bell" size="lg" /> <span className={styles.title}>{rule.name}</span>
|
<Icon name="bell" size="lg" /> <span className={styles.title}>{rule.name}</span>
|
||||||
</Stack>
|
</Stack>
|
||||||
<RuleState rule={rule} isCreating={false} isDeleting={false} />
|
<RuleState rule={rule} isCreating={false} isDeleting={false} />
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Alert, Button, Icon, LoadingPlaceholder, Tab, TabContent, TabsBar, Text, Stack } from '@grafana/ui';
|
||||||
import { Alert, Button, Icon, LoadingPlaceholder, Tab, TabContent, TabsBar, Text } from '@grafana/ui';
|
|
||||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||||
import { GrafanaAlertState } from 'app/types/unified-alerting-dto';
|
import { GrafanaAlertState } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ import React, { useEffect, useMemo } from 'react';
|
|||||||
import { FormProvider, RegisterOptions, useForm, useFormContext } from 'react-hook-form';
|
import { FormProvider, RegisterOptions, useForm, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Badge, Button, Field, Input, Label, LinkButton, Modal, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Badge, Button, Field, Input, Label, LinkButton, Modal, useStyles2 } from '@grafana/ui';
|
|
||||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||||
import { useCleanup } from 'app/core/hooks/useCleanup';
|
import { useCleanup } from 'app/core/hooks/useCleanup';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
@ -235,41 +234,41 @@ export function EditCloudGroupModal(props: ModalProps): React.ReactElement {
|
|||||||
<form onSubmit={(e) => e.preventDefault()} key={JSON.stringify(defaultValues)}>
|
<form onSubmit={(e) => e.preventDefault()} key={JSON.stringify(defaultValues)}>
|
||||||
<>
|
<>
|
||||||
{!props.hideFolder && (
|
{!props.hideFolder && (
|
||||||
<Field
|
<Stack gap={1} alignItems={'center'}>
|
||||||
label={
|
<Field
|
||||||
<Label
|
className={styles.formInput}
|
||||||
htmlFor="namespaceName"
|
label={
|
||||||
description={
|
<Label
|
||||||
!isGrafanaManagedGroup &&
|
htmlFor="namespaceName"
|
||||||
'Change the current namespace name. Moving groups between namespaces is not supported'
|
description={
|
||||||
}
|
!isGrafanaManagedGroup &&
|
||||||
>
|
'Change the current namespace name. Moving groups between namespaces is not supported'
|
||||||
{nameSpaceLabel}
|
}
|
||||||
</Label>
|
>
|
||||||
}
|
{nameSpaceLabel}
|
||||||
invalid={!!errors.namespaceName}
|
</Label>
|
||||||
error={errors.namespaceName?.message}
|
}
|
||||||
>
|
invalid={!!errors.namespaceName}
|
||||||
<Stack gap={1} direction="row">
|
error={errors.namespaceName?.message}
|
||||||
|
>
|
||||||
<Input
|
<Input
|
||||||
id="namespaceName"
|
id="namespaceName"
|
||||||
readOnly={intervalEditOnly || isGrafanaManagedGroup}
|
readOnly={intervalEditOnly || isGrafanaManagedGroup}
|
||||||
{...register('namespaceName', {
|
{...register('namespaceName', {
|
||||||
required: 'Namespace name is required.',
|
required: 'Namespace name is required.',
|
||||||
})}
|
})}
|
||||||
className={styles.formInput}
|
|
||||||
/>
|
/>
|
||||||
{isGrafanaManagedGroup && props.folderUrl && (
|
</Field>
|
||||||
<LinkButton
|
{isGrafanaManagedGroup && props.folderUrl && (
|
||||||
href={props.folderUrl}
|
<LinkButton
|
||||||
title="Go to folder"
|
href={props.folderUrl}
|
||||||
variant="secondary"
|
title="Go to folder"
|
||||||
icon="folder-open"
|
variant="secondary"
|
||||||
target="_blank"
|
icon="folder-open"
|
||||||
/>
|
target="_blank"
|
||||||
)}
|
/>
|
||||||
</Stack>
|
)}
|
||||||
</Field>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
<Field
|
<Field
|
||||||
label={<Label htmlFor="groupName">Evaluation group name</Label>}
|
label={<Label htmlFor="groupName">Evaluation group name</Label>}
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data/src/themes';
|
import { GrafanaTheme2 } from '@grafana/data/src/themes';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { CallToActionCard, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { CallToActionCard, useStyles2 } from '@grafana/ui';
|
|
||||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||||
|
|
||||||
import { logInfo, LogMessages } from '../../Analytics';
|
import { logInfo, LogMessages } from '../../Analytics';
|
||||||
@ -16,7 +15,7 @@ export const NoRulesSplash = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{"You haven't created any alert rules yet"}</p>
|
<p>{"You haven't created any alert rules yet"}</p>
|
||||||
<Stack direction="row" gap={1} alignItems="stretch" flexGrow={1}>
|
<Stack gap={1}>
|
||||||
<div className={styles.newRuleCard}>
|
<div className={styles.newRuleCard}>
|
||||||
<EmptyListCTA
|
<EmptyListCTA
|
||||||
title=""
|
title=""
|
||||||
|
@ -4,7 +4,6 @@ import React, { useState } from 'react';
|
|||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ClipboardButton,
|
ClipboardButton,
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
useStyles2,
|
useStyles2,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
|
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Spinner, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Spinner, useStyles2 } from '@grafana/ui';
|
|
||||||
import { CombinedRule } from 'app/types/unified-alerting';
|
import { CombinedRule } from 'app/types/unified-alerting';
|
||||||
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import { isUndefined, omitBy, sum } from 'lodash';
|
|||||||
import pluralize from 'pluralize';
|
import pluralize from 'pluralize';
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Badge, Stack } from '@grafana/ui';
|
||||||
import { Badge } from '@grafana/ui';
|
|
||||||
import {
|
import {
|
||||||
AlertGroupTotals,
|
AlertGroupTotals,
|
||||||
AlertInstanceTotalState,
|
AlertInstanceTotalState,
|
||||||
|
@ -3,8 +3,7 @@ import React, { useEffect, useRef, useState } from 'react';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { DataSourceInstanceSettings, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { DataSourceInstanceSettings, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Field, Icon, Input, Label, RadioButtonGroup, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Field, Icon, Input, Label, RadioButtonGroup, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-dto';
|
import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import pluralize from 'pluralize';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Badge, ConfirmModal, HorizontalGroup, Icon, Spinner, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Badge, ConfirmModal, HorizontalGroup, Icon, Spinner, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
import { CombinedRuleGroup, CombinedRuleNamespace } from 'app/types/unified-alerting';
|
import { CombinedRuleGroup, CombinedRuleNamespace } from 'app/types/unified-alerting';
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ import { groupBy, uniqueId } from 'lodash';
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
import { dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
|
import { dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, TagList, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, TagList, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { Label } from '../../Label';
|
import { Label } from '../../Label';
|
||||||
import { AlertStateTag } from '../AlertStateTag';
|
import { AlertStateTag } from '../AlertStateTag';
|
||||||
@ -64,7 +63,7 @@ export const LogRecordViewerByTimestamp = React.memo(
|
|||||||
<AlertStateTag state={line.previous} size="sm" muted />
|
<AlertStateTag state={line.previous} size="sm" muted />
|
||||||
<Icon name="arrow-right" size="sm" />
|
<Icon name="arrow-right" size="sm" />
|
||||||
<AlertStateTag state={line.current} />
|
<AlertStateTag state={line.current} />
|
||||||
<Stack direction="row">{line.values && <AlertInstanceValues record={line.values} />}</Stack>
|
<Stack>{line.values && <AlertInstanceValues record={line.values} />}</Stack>
|
||||||
<div>
|
<div>
|
||||||
{line.labels && (
|
{line.labels && (
|
||||||
<TagList
|
<TagList
|
||||||
@ -112,7 +111,7 @@ export function LogRecordViewerByInstance({ records, commonLabels }: LogRecordVi
|
|||||||
<AlertStateTag state={line.previous} size="sm" muted />
|
<AlertStateTag state={line.previous} size="sm" muted />
|
||||||
<Icon name="arrow-right" size="sm" />
|
<Icon name="arrow-right" size="sm" />
|
||||||
<AlertStateTag state={line.current} />
|
<AlertStateTag state={line.current} />
|
||||||
<Stack direction="row">{line.values && <AlertInstanceValues record={line.values} />}</Stack>
|
<Stack>{line.values && <AlertInstanceValues record={line.values} />}</Stack>
|
||||||
<div>{dateTimeFormat(timestamp)}</div>
|
<div>{dateTimeFormat(timestamp)}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@ -134,7 +133,7 @@ const Timestamp = ({ time }: TimestampProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.timestampWrapper}>
|
<div className={styles.timestampWrapper}>
|
||||||
<Stack direction="row" alignItems="center" gap={1}>
|
<Stack alignItems="center" gap={1}>
|
||||||
<Icon name="clock-nine" size="sm" />
|
<Icon name="clock-nine" size="sm" />
|
||||||
<span className={styles.timestampText}>{dateTimeFormat(dateTime)}</span>
|
<span className={styles.timestampText}>{dateTimeFormat(dateTime)}</span>
|
||||||
<small>({formatDistanceToNowStrict(dateTime)} ago)</small>
|
<small>({formatDistanceToNowStrict(dateTime)} ago)</small>
|
||||||
|
@ -4,8 +4,7 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { DataFrame, dateTime, GrafanaTheme2, TimeRange } from '@grafana/data';
|
import { DataFrame, dateTime, GrafanaTheme2, TimeRange } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Alert, Button, Field, Icon, Input, Label, TagList, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Alert, Button, Field, Icon, Input, Label, TagList, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { stateHistoryApi } from '../../../api/stateHistoryApi';
|
import { stateHistoryApi } from '../../../api/stateHistoryApi';
|
||||||
import { combineMatcherStrings } from '../../../utils/alertmanager';
|
import { combineMatcherStrings } from '../../../utils/alertmanager';
|
||||||
|
@ -3,8 +3,7 @@ import { groupBy } from 'lodash';
|
|||||||
import React, { FormEvent, useCallback, useState } from 'react';
|
import React, { FormEvent, useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { AlertState, dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
|
import { AlertState, dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Alert, Field, Icon, Input, Label, LoadingPlaceholder, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Alert, Field, Icon, Input, Label, LoadingPlaceholder, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
import { StateHistoryItem, StateHistoryItemData } from 'app/types/unified-alerting';
|
import { StateHistoryItem, StateHistoryItemData } from 'app/types/unified-alerting';
|
||||||
import { GrafanaAlertStateWithReason, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
import { GrafanaAlertStateWithReason, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import { debounce, uniqueId } from 'lodash';
|
|||||||
import React, { FormEvent, useState } from 'react';
|
import React, { FormEvent, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Field, Icon, Input, Label, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Field, Icon, Input, Label, Tooltip, useStyles2 } from '@grafana/ui';
|
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
|
|
||||||
import { parseMatchers } from '../../utils/alertmanager';
|
import { parseMatchers } from '../../utils/alertmanager';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
|
||||||
import { dateMath, GrafanaTheme2 } from '@grafana/data';
|
import { dateMath, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { CollapsableSection, Icon, Link, LinkButton, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { CollapsableSection, Icon, Link, LinkButton, useStyles2 } from '@grafana/ui';
|
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
import { AlertmanagerAlert, Silence, SilenceState } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertmanagerAlert, Silence, SilenceState } from 'app/plugins/datasource/alertmanager/types';
|
||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
|
@ -3,9 +3,8 @@ import React from 'react';
|
|||||||
import SVG from 'react-inlinesvg';
|
import SVG from 'react-inlinesvg';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { EmbeddedScene, SceneFlexLayout, SceneFlexItem, SceneReactObject } from '@grafana/scenes';
|
import { EmbeddedScene, SceneFlexLayout, SceneFlexItem, SceneReactObject } from '@grafana/scenes';
|
||||||
import { Icon, useStyles2, useTheme2 } from '@grafana/ui';
|
import { Icon, useStyles2, useTheme2, Stack } from '@grafana/ui';
|
||||||
|
|
||||||
export const getOverviewScene = () => {
|
export const getOverviewScene = () => {
|
||||||
return new EmbeddedScene({
|
return new EmbeddedScene({
|
||||||
@ -48,7 +47,7 @@ export default function GettingStarted({ showWelcomeHeader }: { showWelcomeHeade
|
|||||||
</ContentBox>
|
</ContentBox>
|
||||||
<ContentBox className={styles.gettingStartedBlock}>
|
<ContentBox className={styles.gettingStartedBlock}>
|
||||||
<h3>Get started</h3>
|
<h3>Get started</h3>
|
||||||
<Stack direction="column" alignItems="space-between">
|
<Stack direction="column">
|
||||||
<ul className={styles.list}>
|
<ul className={styles.list}>
|
||||||
<li>
|
<li>
|
||||||
<strong>Create an alert rule</strong> by adding queries and expressions from multiple data sources.
|
<strong>Create an alert rule</strong> by adding queries and expressions from multiple data sources.
|
||||||
|
@ -4,7 +4,6 @@ import React, { useState } from 'react';
|
|||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Field,
|
Field,
|
||||||
@ -17,6 +16,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
useStyles2,
|
useStyles2,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
|
|
||||||
import { getSupportedTransTypeDetails, getTransformOptions } from './types';
|
import { getSupportedTransTypeDetails, getTransformOptions } from './types';
|
||||||
@ -56,7 +56,7 @@ export const TransformationsEditor = (props: Props) => {
|
|||||||
<div>
|
<div>
|
||||||
{fields.map((fieldVal, index) => {
|
{fields.map((fieldVal, index) => {
|
||||||
return (
|
return (
|
||||||
<Stack direction="row" key={fieldVal.id} alignItems="top">
|
<Stack direction="row" key={fieldVal.id} alignItems="flex-start">
|
||||||
<Field
|
<Field
|
||||||
label={
|
label={
|
||||||
<Stack gap={0.5}>
|
<Stack gap={0.5}>
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
SelectableValue,
|
SelectableValue,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { getDataSourceSrv, locationService } from '@grafana/runtime';
|
import { getDataSourceSrv, locationService } from '@grafana/runtime';
|
||||||
import { AnnotationPanelFilter } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen';
|
import { AnnotationPanelFilter } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen';
|
||||||
import {
|
import {
|
||||||
@ -23,6 +22,7 @@ import {
|
|||||||
MultiSelect,
|
MultiSelect,
|
||||||
Select,
|
Select,
|
||||||
useStyles2,
|
useStyles2,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { ColorValueEditor } from 'app/core/components/OptionsUI/color';
|
import { ColorValueEditor } from 'app/core/components/OptionsUI/color';
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
|
@ -3,7 +3,6 @@ import React, { useMemo, useEffect } from 'react';
|
|||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
|
|
||||||
import { PanelPlugin, GrafanaTheme2, FeatureState } from '@grafana/data';
|
import { PanelPlugin, GrafanaTheme2, FeatureState } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
@ -21,6 +20,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
ClipboardButton,
|
ClipboardButton,
|
||||||
Icon,
|
Icon,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import { PanelModel } from 'app/features/dashboard/state';
|
import { PanelModel } from 'app/features/dashboard/state';
|
||||||
|
@ -6,7 +6,6 @@ import { Subscription } from 'rxjs';
|
|||||||
|
|
||||||
import { FieldConfigSource, GrafanaTheme2, NavModel, NavModelItem, PageLayoutType } from '@grafana/data';
|
import { FieldConfigSource, GrafanaTheme2, NavModel, NavModelItem, PageLayoutType } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -19,6 +18,7 @@ import {
|
|||||||
ToolbarButton,
|
ToolbarButton,
|
||||||
ToolbarButtonRow,
|
ToolbarButtonRow,
|
||||||
withTheme2,
|
withTheme2,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||||
import { Page } from 'app/core/components/Page/Page';
|
import { Page } from 'app/core/components/Page/Page';
|
||||||
|
@ -3,10 +3,9 @@ import React, { useMemo, useState } from 'react';
|
|||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { Dashboard } from '@grafana/schema';
|
import { Dashboard } from '@grafana/schema';
|
||||||
import { Button, Checkbox, Form, TextArea, useStyles2 } from '@grafana/ui';
|
import { Button, Checkbox, Form, TextArea, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
|
|
||||||
import { GenAIDashboardChangesButton } from '../../GenAI/GenAIDashboardChangesButton';
|
import { GenAIDashboardChangesButton } from '../../GenAI/GenAIDashboardChangesButton';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, ClipboardButton, HorizontalGroup, TextArea, Stack } from '@grafana/ui';
|
||||||
import { Button, ClipboardButton, HorizontalGroup, TextArea } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { SaveDashboardFormProps } from '../types';
|
import { SaveDashboardFormProps } from '../types';
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Tooltip, Button, Stack } from '@grafana/ui';
|
||||||
import { Tooltip, Button } from '@grafana/ui';
|
|
||||||
|
|
||||||
type VersionsButtonsType = {
|
type VersionsButtonsType = {
|
||||||
hasMore: boolean;
|
hasMore: boolean;
|
||||||
|
@ -2,8 +2,7 @@ import { css, cx } from '@emotion/css';
|
|||||||
import React, { FormEvent } from 'react';
|
import React, { FormEvent } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, ButtonSelect, Icon, InlineFieldRow, Input, Select, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, ButtonSelect, Icon, InlineFieldRow, Input, Select, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import alertDef, { EvalFunction } from '../../alerting/state/alertDef';
|
import alertDef, { EvalFunction } from '../../alerting/state/alertDef';
|
||||||
import { ClassicCondition, ReducerType } from '../types';
|
import { ClassicCondition, ReducerType } from '../types';
|
||||||
@ -73,7 +72,7 @@ export const Condition = ({ condition, index, onChange, onRemoveCondition, refId
|
|||||||
condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange;
|
condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack direction="row">
|
<Stack>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<InlineFieldRow>
|
<InlineFieldRow>
|
||||||
{index === 0 ? (
|
{index === 0 ? (
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React, { ChangeEvent } from 'react';
|
import React, { ChangeEvent } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, InlineField, InlineLabel, TextArea, Toggletip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, InlineField, InlineLabel, TextArea, Toggletip, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { ExpressionQuery } from '../types';
|
import { ExpressionQuery } from '../types';
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ export const Math = ({ labelWidth, onChange, query, onRunQuery }: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack direction="row">
|
<Stack>
|
||||||
<InlineField
|
<InlineField
|
||||||
label={
|
label={
|
||||||
<InlineLabel width="auto">
|
<InlineLabel width="auto">
|
||||||
|
@ -4,9 +4,8 @@ import { Subscription } from 'rxjs';
|
|||||||
|
|
||||||
import { LoadingState, PanelData } from '@grafana/data';
|
import { LoadingState, PanelData } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { Button, ClipboardButton, JSONFormatter, LoadingPlaceholder } from '@grafana/ui';
|
import { Button, ClipboardButton, JSONFormatter, LoadingPlaceholder, Stack } from '@grafana/ui';
|
||||||
import { Trans } from 'app/core/internationalization';
|
import { Trans } from 'app/core/internationalization';
|
||||||
import { backendSrv } from 'app/core/services/backend_srv';
|
import { backendSrv } from 'app/core/services/backend_srv';
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { locationUtil, SelectableValue } from '@grafana/data';
|
import { locationUtil, SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -17,6 +16,7 @@ import {
|
|||||||
TextLink,
|
TextLink,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Label,
|
Label,
|
||||||
|
Stack,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { getConfig } from 'app/core/config';
|
import { getConfig } from 'app/core/config';
|
||||||
import { OrgRole, useDispatch } from 'app/types';
|
import { OrgRole, useDispatch } from 'app/types';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { useStyles2, Icon, Stack } from '@grafana/ui';
|
||||||
import { useStyles2, Icon } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { Version, CatalogPlugin, PluginIconName } from '../types';
|
import { Version, CatalogPlugin, PluginIconName } from '../types';
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ import {
|
|||||||
onUpdateDatasourceSecureJsonDataOption,
|
onUpdateDatasourceSecureJsonDataOption,
|
||||||
updateDatasourcePluginResetOption,
|
updateDatasourcePluginResetOption,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Field, Icon, Label, SecretTextArea, Tooltip, Stack } from '@grafana/ui';
|
||||||
import { Field, Icon, Label, SecretTextArea, Tooltip } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface Props<T extends DataSourceJsonData, S> {
|
export interface Props<T extends DataSourceJsonData, S> {
|
||||||
editorProps: DataSourcePluginOptionsEditorProps<T, S>;
|
editorProps: DataSourcePluginOptionsEditorProps<T, S>;
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useAsync } from 'react-use';
|
import { useAsync } from 'react-use';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Card, Stack } from '@grafana/ui';
|
||||||
import { Card } from '@grafana/ui';
|
|
||||||
import { Page } from 'app/core/components/Page/Page';
|
import { Page } from 'app/core/components/Page/Page';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
@ -16,8 +16,7 @@ import {
|
|||||||
GroupByOperationID,
|
GroupByOperationID,
|
||||||
GroupByTransformerOptions,
|
GroupByTransformerOptions,
|
||||||
} from '@grafana/data/src/transformations/transformers/groupBy';
|
} from '@grafana/data/src/transformations/transformers/groupBy';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { useTheme2, Select, StatsPicker, InlineField, Stack } from '@grafana/ui';
|
||||||
import { useTheme2, Select, StatsPicker, InlineField } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { useAllFieldNamesFromDataFrames } from '../utils';
|
import { useAllFieldNamesFromDataFrames } from '../utils';
|
||||||
|
|
||||||
@ -84,7 +83,7 @@ export const GroupByFieldConfiguration = ({ fieldName, config, onConfigChange }:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InlineField className={styles.label} label={fieldName} grow shrink>
|
<InlineField className={styles.label} label={fieldName} grow shrink>
|
||||||
<Stack gap={0.5} direction="row" wrap={false}>
|
<Stack gap={0.5} direction="row">
|
||||||
<div className={styles.operation}>
|
<div className={styles.operation}>
|
||||||
<Select options={options} value={config?.operation} placeholder="Ignored" onChange={onChange} isClearable />
|
<Select options={options} value={config?.operation} placeholder="Ignored" onChange={onChange} isClearable />
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,7 @@ import {
|
|||||||
LabelsToFieldsMode,
|
LabelsToFieldsMode,
|
||||||
LabelsToFieldsOptions,
|
LabelsToFieldsOptions,
|
||||||
} from '@grafana/data/src/transformations/transformers/labelsToFields';
|
} from '@grafana/data/src/transformations/transformers/labelsToFields';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { InlineField, InlineFieldRow, RadioButtonGroup, Select, FilterPill, Stack } from '@grafana/ui';
|
||||||
import { InlineField, InlineFieldRow, RadioButtonGroup, Select, FilterPill } from '@grafana/ui';
|
|
||||||
|
|
||||||
const modes: Array<SelectableValue<LabelsToFieldsMode>> = [
|
const modes: Array<SelectableValue<LabelsToFieldsMode>> = [
|
||||||
{ value: LabelsToFieldsMode.Columns, label: 'Columns' },
|
{ value: LabelsToFieldsMode.Columns, label: 'Columns' },
|
||||||
@ -81,7 +80,7 @@ export const LabelsAsFieldsTransformerEditor = ({
|
|||||||
</InlineFieldRow>
|
</InlineFieldRow>
|
||||||
<InlineFieldRow>
|
<InlineFieldRow>
|
||||||
<InlineField label={'Labels'} labelWidth={labelWidth}>
|
<InlineField label={'Labels'} labelWidth={labelWidth}>
|
||||||
<Stack gap={1} wrap>
|
<Stack gap={1} wrap={'wrap'}>
|
||||||
{labelNames.map((o, i) => {
|
{labelNames.map((o, i) => {
|
||||||
const label = o.label!;
|
const label = o.label!;
|
||||||
return (
|
return (
|
||||||
|
@ -3,9 +3,8 @@ import React, { ReactElement } from 'react';
|
|||||||
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { Button, useStyles2 } from '@grafana/ui';
|
import { Button, useStyles2, Stack } from '@grafana/ui';
|
||||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||||
|
|
||||||
import { VariablesDependenciesButton } from '../inspect/VariablesDependenciesButton';
|
import { VariablesDependenciesButton } from '../inspect/VariablesDependenciesButton';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { MetadataInspectorProps } from '@grafana/data';
|
import { MetadataInspectorProps } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/ui';
|
||||||
|
|
||||||
import { TestData } from './dataquery.gen';
|
import { TestData } from './dataquery.gen';
|
||||||
import { TestDataDataSource } from './datasource';
|
import { TestDataDataSource } from './datasource';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/ui';
|
||||||
import { OperationExplainedBox } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox';
|
import { OperationExplainedBox } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox';
|
||||||
import { OperationListExplained } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained';
|
import { OperationListExplained } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained';
|
||||||
import { RawQuery } from 'app/plugins/datasource/prometheus/querybuilder/shared/RawQuery';
|
import { RawQuery } from 'app/plugins/datasource/prometheus/querybuilder/shared/RawQuery';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/ui';
|
||||||
|
|
||||||
import { LokiDatasource } from '../../datasource';
|
import { LokiDatasource } from '../../datasource';
|
||||||
import { LokiVisualQuery, LokiVisualQueryBinary } from '../types';
|
import { LokiVisualQuery, LokiVisualQueryBinary } from '../types';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/ui';
|
||||||
|
|
||||||
import { PrometheusDatasource } from '../../datasource';
|
import { PrometheusDatasource } from '../../datasource';
|
||||||
import { PromVisualQuery, PromVisualQueryBinary } from '../types';
|
import { PromVisualQuery, PromVisualQueryBinary } from '../types';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/ui';
|
||||||
|
|
||||||
import promqlGrammar from '../../promql';
|
import promqlGrammar from '../../promql';
|
||||||
import { promQueryModeller } from '../PromQueryModeller';
|
import { promQueryModeller } from '../PromQueryModeller';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
feedbackUrl?: string;
|
feedbackUrl?: string;
|
||||||
|
@ -3,8 +3,7 @@ import React, { useEffect, useId, useState } from 'react';
|
|||||||
import { Draggable } from 'react-beautiful-dnd';
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Icon, InlineField, Tooltip, useTheme2, Stack } from '@grafana/ui';
|
||||||
import { Button, Icon, InlineField, Tooltip, useTheme2 } from '@grafana/ui';
|
|
||||||
import { isConflictingFilter } from 'app/plugins/datasource/loki/querybuilder/operationUtils';
|
import { isConflictingFilter } from 'app/plugins/datasource/loki/querybuilder/operationUtils';
|
||||||
import { LokiOperationId } from 'app/plugins/datasource/loki/querybuilder/types';
|
import { LokiOperationId } from 'app/plugins/datasource/loki/querybuilder/types';
|
||||||
|
|
||||||
@ -96,7 +95,7 @@ export function OperationEditor({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles.paramValue}>
|
<div className={styles.paramValue}>
|
||||||
<Stack gap={0.5} direction="row" alignItems="center" wrap={false}>
|
<Stack gap={0.5} direction="row" alignItems="center">
|
||||||
<Editor
|
<Editor
|
||||||
index={paramIndex}
|
index={paramIndex}
|
||||||
paramDef={paramDef}
|
paramDef={paramDef}
|
||||||
|
@ -4,8 +4,7 @@ import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
|||||||
import { useMountedState, usePrevious } from 'react-use';
|
import { useMountedState, usePrevious } from 'react-use';
|
||||||
|
|
||||||
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Button, Cascader, CascaderOption, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Button, Cascader, CascaderOption, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { OperationEditor } from './OperationEditor';
|
import { OperationEditor } from './OperationEditor';
|
||||||
import { QueryBuilderOperation, QueryWithOperations, VisualQueryModeller } from './types';
|
import { QueryBuilderOperation, QueryWithOperations, VisualQueryModeller } from './types';
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React, { ComponentType } from 'react';
|
import React, { ComponentType } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { AutoSizeInput, Button, Checkbox, Select, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { AutoSizeInput, Button, Checkbox, Select, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { QueryBuilderOperationParamDef, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
import { QueryBuilderOperationParamDef, QueryBuilderOperationParamEditorProps } from '../shared/types';
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ function SelectInputParamEditor({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap={0.5} direction="row" alignItems="center" wrap={false}>
|
<Stack gap={0.5} direction="row" alignItems="center">
|
||||||
<Select
|
<Select
|
||||||
id={getOperationParamId(operationId, index)}
|
id={getOperationParamId(operationId, index)}
|
||||||
value={valueOption}
|
value={valueOption}
|
||||||
|
@ -2,8 +2,7 @@ import { css } from '@emotion/css';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { useStyles2, Stack } from '@grafana/ui';
|
||||||
import { useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
@ -3,8 +3,7 @@ import { uniqueId } from 'lodash';
|
|||||||
import React, { HTMLProps, useRef } from 'react';
|
import React, { HTMLProps, useRef } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Switch, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Switch, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'value' | 'ref'> {
|
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'value' | 'ref'> {
|
||||||
value?: boolean;
|
value?: boolean;
|
||||||
|
@ -3,9 +3,8 @@ import React from 'react';
|
|||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
|
|
||||||
import { getValueFormat, GrafanaTheme2 } from '@grafana/data';
|
import { getValueFormat, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { Collapse, Icon, Tooltip, useStyles2 } from '@grafana/ui';
|
import { Collapse, Icon, Tooltip, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { QueryStats } from 'app/plugins/datasource/loki/types';
|
import { QueryStats } from 'app/plugins/datasource/loki/types';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@ -27,7 +26,7 @@ export function QueryOptionGroup({ title, children, collapsedInfo, queryStats }:
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onToggle={toggleOpen}
|
onToggle={toggleOpen}
|
||||||
label={
|
label={
|
||||||
<Stack gap={0} wrap={false}>
|
<Stack gap={0}>
|
||||||
<h6 className={styles.title}>{title}</h6>
|
<h6 className={styles.title}>{title}</h6>
|
||||||
{!isOpen && (
|
{!isOpen && (
|
||||||
<div className={styles.description}>
|
<div className={styles.description}>
|
||||||
|
@ -3,8 +3,7 @@ import React from 'react';
|
|||||||
import { useLocation } from 'react-use';
|
import { useLocation } from 'react-use';
|
||||||
|
|
||||||
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
|
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Icon, useStyles2, Stack } from '@grafana/ui';
|
||||||
import { Icon, useStyles2 } from '@grafana/ui';
|
|
||||||
import alertDef from 'app/features/alerting/state/alertDef';
|
import alertDef from 'app/features/alerting/state/alertDef';
|
||||||
import { Spacer } from 'app/features/alerting/unified/components/Spacer';
|
import { Spacer } from 'app/features/alerting/unified/components/Spacer';
|
||||||
import { fromCombinedRule, stringifyIdentifier } from 'app/features/alerting/unified/utils/rule-id';
|
import { fromCombinedRule, stringifyIdentifier } from 'app/features/alerting/unified/utils/rule-id';
|
||||||
@ -84,7 +83,7 @@ const UngroupedModeView = ({ rules, options, handleInstancesLimit, limitInstance
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.alertNameWrapper}>
|
<div className={styles.alertNameWrapper}>
|
||||||
<div className={styles.instanceDetails}>
|
<div className={styles.instanceDetails}>
|
||||||
<Stack direction="row" gap={1} wrap={false}>
|
<Stack direction="row" gap={1}>
|
||||||
<div className={styles.alertName} title={ruleWithLocation.name}>
|
<div className={styles.alertName} title={ruleWithLocation.name}>
|
||||||
{ruleWithLocation.name}
|
{ruleWithLocation.name}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
|
||||||
import { BarGaugeDisplayMode, BarGaugeValueMode, TableBarGaugeCellOptions } from '@grafana/schema';
|
import { BarGaugeDisplayMode, BarGaugeValueMode, TableBarGaugeCellOptions } from '@grafana/schema';
|
||||||
import { Field, RadioButtonGroup } from '@grafana/ui';
|
import { Field, RadioButtonGroup, Stack } from '@grafana/ui';
|
||||||
|
|
||||||
import { TableCellEditorProps } from '../TableCellOptionEditor';
|
import { TableCellEditorProps } from '../TableCellOptionEditor';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user