Tag component tweaks to get rid of hardcoded tag variables (#4280)
# What this PR does - Removed the usage of `var(--` within the Tag component to help get rid of the vars file once we fully migrate to emotion - Added few other display tweaks and migrated a few stylesheets to emotion
This commit is contained in:
parent
0e59fadf38
commit
6ed7a1e3b8
37 changed files with 445 additions and 433 deletions
|
|
@ -174,6 +174,7 @@
|
|||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"throttle-debounce": "^2.1.0",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"tslib": "2.5.3"
|
||||
},
|
||||
"packageManager": "yarn@1.22.21"
|
||||
|
|
|
|||
|
|
@ -23,17 +23,15 @@ export const getCardButtonStyles = (theme: GrafanaTheme2) => {
|
|||
`,
|
||||
|
||||
rootSelected: css`
|
||||
{
|
||||
&::before {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background-image: linear-gradient(270deg, #f55f3e 0%, #f83 100%);
|
||||
}
|
||||
&::before {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background-image: ${theme.colors.gradients.brandVertical};
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { Tag } from 'components/Tag/Tag';
|
||||
import { Tag, TagColor } from 'components/Tag/Tag';
|
||||
import { Text } from 'components/Text/Text';
|
||||
|
||||
interface IntegrationTagProps {
|
||||
|
|
@ -15,7 +14,7 @@ export const IntegrationTag: FC<IntegrationTagProps> = ({ children }) => {
|
|||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<Tag className={styles.tag}>
|
||||
<Tag className={styles.tag} color={TagColor.SECONDARY}>
|
||||
<Text type="primary" size="small" className={styles.radius}>
|
||||
{children}
|
||||
</Text>
|
||||
|
|
@ -23,11 +22,9 @@ export const IntegrationTag: FC<IntegrationTagProps> = ({ children }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const getStyles = (theme: GrafanaTheme2) => ({
|
||||
export const getStyles = () => ({
|
||||
tag: css({
|
||||
height: '25px',
|
||||
background: theme.colors.background.secondary,
|
||||
border: `1px solid ${theme.colors.border.weak}`,
|
||||
}),
|
||||
radius: css({
|
||||
borderRadius: '4px',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { observer } from 'mobx-react';
|
|||
import moment from 'moment-timezone';
|
||||
import { SortableElement } from 'react-sortable-hoc';
|
||||
import reactStringReplace from 'react-string-replace';
|
||||
import { getLabelBackgroundTextColorObject } from 'styles/utils.styles';
|
||||
|
||||
import { PluginLink } from 'components/PluginLink/PluginLink';
|
||||
import { Text } from 'components/Text/Text';
|
||||
|
|
@ -28,7 +29,6 @@ import { UserGroup } from 'models/user_group/user_group.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { SelectOption, WithStoreProps } from 'state/types';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
import { getVar } from 'utils/DOM';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import { DragHandle } from './DragHandle';
|
||||
|
|
@ -80,12 +80,14 @@ class _EscalationPolicy extends React.Component<EscalationPolicyProps, any> {
|
|||
(escalationOption: EscalationPolicyOption) => escalationOption.value === step
|
||||
);
|
||||
|
||||
const { textColor: itemTextColor } = getLabelBackgroundTextColorObject('green', this.props.theme);
|
||||
|
||||
return (
|
||||
<Timeline.Item
|
||||
key={id}
|
||||
contentClassName={cx(this.styles.root)}
|
||||
number={number}
|
||||
textColor={isDisabled ? getVar('--tag-text-success') : undefined}
|
||||
textColor={isDisabled ? itemTextColor : undefined}
|
||||
backgroundClassName={backgroundClassName}
|
||||
backgroundHexNumber={backgroundHexNumber}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -17,27 +17,6 @@ export const getScheduleQualityStyles = (_theme: GrafanaTheme2) => {
|
|||
tag: css`
|
||||
font-size: 12px;
|
||||
padding: 5px 10px;
|
||||
|
||||
&--danger {
|
||||
// TODO: emotionjs
|
||||
background-color: var(--tag-background-danger);
|
||||
color: var(--tag-text-danger);
|
||||
border: 1px solid var(--tag-border-danger);
|
||||
}
|
||||
|
||||
&--warning {
|
||||
// TODO: emotionjs
|
||||
background-color: var(--tag-background-warning);
|
||||
color: var(--tag-text-warning);
|
||||
border: 1px solid var(--tag-border-warning);
|
||||
}
|
||||
|
||||
&--primary {
|
||||
// TODO: emotionjs
|
||||
background-color: var(--tag-background-success);
|
||||
color: var(--tag-text-success);
|
||||
border: 1px solid var(--tag-border-success);
|
||||
}
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import React, { FC, useEffect } from 'react';
|
|||
import { cx } from '@emotion/css';
|
||||
import { Tooltip, VerticalGroup, useStyles2 } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import { bem, getUtilStyles } from 'styles/utils.styles';
|
||||
import { getUtilStyles } from 'styles/utils.styles';
|
||||
|
||||
import { PluginLink } from 'components/PluginLink/PluginLink';
|
||||
import { ScheduleQualityDetails } from 'components/ScheduleQualityDetails/ScheduleQualityDetails';
|
||||
import { Tag } from 'components/Tag/Tag';
|
||||
import { Tag, TagColor } from 'components/Tag/Tag';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { TooltipBadge } from 'components/TooltipBadge/TooltipBadge';
|
||||
import { Schedule, ScheduleScoreQualityResult } from 'models/schedule/schedule.types';
|
||||
|
|
@ -88,7 +88,7 @@ export const ScheduleQuality: FC<ScheduleQualityProps> = observer(({ schedule })
|
|||
content={<ScheduleQualityDetails quality={quality} getScheduleQualityString={getScheduleQualityString} />}
|
||||
>
|
||||
<div className={cx(utils.cursorDefault)}>
|
||||
<Tag className={cx(styles.tag, bem(styles.tag, getTagSeverity()))}>
|
||||
<Tag className={cx(styles.tag)} color={getTagSeverity()}>
|
||||
Quality: <strong>{getScheduleQualityString(quality.total_score)}</strong>
|
||||
</Tag>
|
||||
</div>
|
||||
|
|
@ -115,11 +115,11 @@ export const ScheduleQuality: FC<ScheduleQualityProps> = observer(({ schedule })
|
|||
|
||||
function getTagSeverity() {
|
||||
if (quality?.total_score < 20) {
|
||||
return 'danger';
|
||||
return TagColor.ERROR_LABEL;
|
||||
}
|
||||
if (quality?.total_score < 60) {
|
||||
return 'warning';
|
||||
return TagColor.WARNING_LABEL;
|
||||
}
|
||||
return 'primary';
|
||||
return TagColor.SUCCESS_LABEL;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import React, { FC } from 'react';
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
import { bem, getLabelCss } from 'styles/utils.styles';
|
||||
|
||||
interface TagProps {
|
||||
color?: string;
|
||||
color?: string | TagColor;
|
||||
className?: string;
|
||||
border?: string;
|
||||
text?: string;
|
||||
|
|
@ -16,43 +16,89 @@ interface TagProps {
|
|||
size?: 'small' | 'medium';
|
||||
}
|
||||
|
||||
export enum TagColor {
|
||||
SUCCESS = 'success',
|
||||
WARNING = 'warning',
|
||||
ERROR = 'error',
|
||||
SECONDARY = 'secondary',
|
||||
INFO = 'info',
|
||||
|
||||
SUCCESS_LABEL = 'successLabel',
|
||||
WARNING_LABEL = 'warningLabel',
|
||||
ERROR_LABEL = 'errorLabel',
|
||||
}
|
||||
|
||||
export const Tag: FC<TagProps> = (props) => {
|
||||
const { color, children, className, onClick, size = 'medium' } = props;
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
const { children, color, text, className, border, onClick, size = 'medium' } = props;
|
||||
const style: React.CSSProperties = {
|
||||
backgroundColor: color,
|
||||
color: text,
|
||||
border,
|
||||
};
|
||||
|
||||
return (
|
||||
<span
|
||||
style={style}
|
||||
className={cx(styles.root, bem(styles.root, size), className)}
|
||||
className={cx(styles.root, bem(styles.root, size), getMatchingClass(), className)}
|
||||
onClick={onClick}
|
||||
ref={props.forwardedRef}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (_theme: GrafanaTheme2) => {
|
||||
return {
|
||||
root: css`
|
||||
border-radius: 2px;
|
||||
line-height: 100%;
|
||||
padding: 5px 8px;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
`,
|
||||
function getMatchingClass() {
|
||||
return styles[color]
|
||||
? // Either pick a defined style already or create one on the spot with the passed bgColor
|
||||
styles[color]
|
||||
: css`
|
||||
background-color: ${color};
|
||||
color: text;
|
||||
`;
|
||||
}
|
||||
|
||||
size: css`
|
||||
&--small {
|
||||
font-size: 12px;
|
||||
height: 24px;
|
||||
}
|
||||
`,
|
||||
};
|
||||
function getStyles(theme: GrafanaTheme2) {
|
||||
return {
|
||||
root: css`
|
||||
border-radius: 2px;
|
||||
line-height: 100%;
|
||||
padding: 5px 8px;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
`,
|
||||
|
||||
size: css`
|
||||
&--small {
|
||||
font-size: 12px;
|
||||
height: 24px;
|
||||
}
|
||||
`,
|
||||
|
||||
success: css`
|
||||
background-color: ${theme.colors.success.main};
|
||||
border: solid 1px ${theme.colors.success.main};
|
||||
color: ${theme.isDark ? '#fff' : theme.colors.success.contrastText};
|
||||
`,
|
||||
warning: css`
|
||||
background-color: ${theme.colors.warning.main};
|
||||
border: solid 1px ${theme.colors.warning.main};
|
||||
color: #fff;
|
||||
`,
|
||||
error: css`
|
||||
background-color: ${theme.colors.error.main};
|
||||
border: solid 1px ${theme.colors.error.main};
|
||||
color: ${theme.isDark ? '#fff' : theme.colors.error.contrastText};
|
||||
`,
|
||||
secondary: css`
|
||||
background-color: ${theme.colors.secondary.main};
|
||||
border: solid 1px ${theme.colors.secondary.main};
|
||||
color: ${theme.isDark ? '#fff' : theme.colors.secondary.contrastText};
|
||||
`,
|
||||
info: css`
|
||||
background-color: ${theme.colors.primary.main};
|
||||
border: solid 1px ${theme.colors.primary.main};
|
||||
color: ${theme.isDark ? '#fff' : theme.colors.info.contrastText};
|
||||
`,
|
||||
|
||||
successLabel: getLabelCss('green', theme),
|
||||
warningLabel: getLabelCss('orange', theme),
|
||||
errorLabel: getLabelCss('red', theme),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ export const getTextStyles = (theme: GrafanaTheme2) => {
|
|||
root: css`
|
||||
display: inline;
|
||||
|
||||
&:hover .icon-button {
|
||||
display: inline-block;
|
||||
&:hover [data-emotion='iconButton'] {
|
||||
display: inline-flex;
|
||||
}
|
||||
`,
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ export const Text: TextInterface = (props) => {
|
|||
styles.root,
|
||||
styles.text,
|
||||
{ [styles.maxWidth]: Boolean(maxWidth) },
|
||||
{ [bem(styles.text, `${type}`)]: true },
|
||||
{ [bem(styles.text, `${size}`)]: true },
|
||||
{ [bem(styles.text, type)]: true },
|
||||
{ [bem(styles.text, size)]: true },
|
||||
{ [bem(styles.text, `strong`)]: strong },
|
||||
{ [bem(styles.text, `underline`)]: underline },
|
||||
{ [bem(styles.text, 'clickable')]: clickable },
|
||||
|
|
@ -109,6 +109,7 @@ export const Text: TextInterface = (props) => {
|
|||
className={styles.iconButton}
|
||||
tooltip="Edit"
|
||||
tooltipPlacement="top"
|
||||
data-emotion="iconButton"
|
||||
name="pen"
|
||||
/>
|
||||
)}
|
||||
|
|
@ -124,6 +125,7 @@ export const Text: TextInterface = (props) => {
|
|||
className={styles.iconButton}
|
||||
tooltip="Copy to clipboard"
|
||||
tooltipPlacement="top"
|
||||
data-emotion="iconButton"
|
||||
name="copy"
|
||||
/>
|
||||
</CopyToClipboard>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,20 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { getLabelCss } from 'styles/utils.styles';
|
||||
|
||||
export const getTooltipBadgeStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
primary: getLabelCss('blue', theme),
|
||||
warning: getLabelCss('orange', theme),
|
||||
success: getLabelCss('green', theme),
|
||||
danger: getLabelCss('red', theme),
|
||||
|
||||
secondary: css`
|
||||
background: ${theme.colors.background.secondary};
|
||||
border: 1px solid ${theme.colors.border.weak};
|
||||
color: ${theme.colors.text.primary};
|
||||
`,
|
||||
|
||||
element: css`
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
|
@ -10,36 +22,6 @@ export const getTooltipBadgeStyles = (theme: GrafanaTheme2) => {
|
|||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
|
||||
&--primary {
|
||||
background: var(--tag-background-primary);
|
||||
border: 1px solid var(--tag-border-primary);
|
||||
color: var(--tag-text-primary);
|
||||
}
|
||||
|
||||
&--secondary {
|
||||
background: ${theme.colors.background.secondary};
|
||||
border: 1px solid ${theme.colors.border.weak};
|
||||
color: ${theme.colors.text.primary};
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background: var(--tag-background-warning);
|
||||
border: 1px solid var(--tag-border-warning);
|
||||
color: var(--tag-text-warning);
|
||||
}
|
||||
|
||||
&--success {
|
||||
background: var(--tag-background-success);
|
||||
border: 1px solid var(--tag-border-success);
|
||||
color: var(--tag-text-success);
|
||||
}
|
||||
|
||||
&--danger {
|
||||
background: var(--tag-background-danger);
|
||||
border: 1px solid var(--tag-border-danger);
|
||||
color: var(--tag-text-danger);
|
||||
}
|
||||
|
||||
&--padding {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,12 +55,7 @@ export const TooltipBadge: FC<TooltipBadgeProps> = (props) => {
|
|||
}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
styles.element,
|
||||
{ [bem(styles.element, `${borderType}`)]: true },
|
||||
{ [bem(styles.element, 'padding')]: addPadding },
|
||||
className
|
||||
)}
|
||||
className={cx(styles.element, styles[borderType], { [bem(styles.element, 'padding')]: addPadding }, className)}
|
||||
onMouseEnter={onHover}
|
||||
{...(testId ? { 'data-testid': testId } : {})}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ exports[`Unauthorized renders properly - access control enabled: false 1`] = `
|
|||
className="css-1fmhfo9"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -38,7 +38,7 @@ exports[`Unauthorized renders properly - access control enabled: false 1`] = `
|
|||
className="css-u023fv"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -78,7 +78,7 @@ exports[`Unauthorized renders properly - access control enabled: true 1`] = `
|
|||
className="css-1fmhfo9"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -96,7 +96,7 @@ exports[`Unauthorized renders properly - access control enabled: true 1`] = `
|
|||
className="css-u023fv"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -136,7 +136,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Admin 1
|
|||
className="css-1fmhfo9"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -154,7 +154,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Admin 1
|
|||
className="css-u023fv"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -194,7 +194,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Editor
|
|||
className="css-1fmhfo9"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -212,7 +212,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Editor
|
|||
className="css-u023fv"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -252,7 +252,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Viewer
|
|||
className="css-1fmhfo9"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
@ -270,7 +270,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Viewer
|
|||
className="css-u023fv"
|
||||
>
|
||||
<span
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
className="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
style={
|
||||
{
|
||||
"maxWidth": undefined,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ exports[`AddResponders should properly display the add responders button when hi
|
|||
class="css-u023fv"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Participants
|
||||
</span>
|
||||
|
|
@ -72,7 +72,7 @@ exports[`AddResponders should properly display the add responders button when hi
|
|||
class="css-u023fv"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Participants
|
||||
</span>
|
||||
|
|
@ -106,7 +106,7 @@ exports[`AddResponders should render properly in create mode 1`] = `
|
|||
class="css-u023fv"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Participants
|
||||
</span>
|
||||
|
|
@ -159,7 +159,7 @@ exports[`AddResponders should render properly in update mode 1`] = `
|
|||
class="css-u023fv"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Participants
|
||||
</span>
|
||||
|
|
@ -212,7 +212,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-u023fv"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Participants
|
||||
</span>
|
||||
|
|
@ -270,7 +270,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1287p17"
|
||||
>
|
||||
my test team
|
||||
</span>
|
||||
|
|
@ -323,7 +323,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1287p17"
|
||||
>
|
||||
my test user3
|
||||
</span>
|
||||
|
|
@ -438,7 +438,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1287p17"
|
||||
>
|
||||
my test user
|
||||
</span>
|
||||
|
|
@ -552,7 +552,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1287p17"
|
||||
>
|
||||
my test user2
|
||||
</span>
|
||||
|
|
@ -664,7 +664,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-9om60p"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
<a
|
||||
class="learn-more-link"
|
||||
|
|
@ -673,7 +673,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
<div
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ exports[`TeamResponder it renders data properly 1`] = `
|
|||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1287p17"
|
||||
>
|
||||
my test team
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ exports[`UserResponder it renders data properly 1`] = `
|
|||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium responder-name css-1287p17"
|
||||
>
|
||||
johnsmith
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect } from 'react';
|
||||
|
||||
import { VerticalGroup } from '@grafana/ui';
|
||||
import { VerticalGroup, useTheme2 } from '@grafana/ui';
|
||||
|
||||
import { Timeline } from 'components/Timeline/Timeline';
|
||||
import { MSTeamsConnector } from 'containers/AlertRules/parts/connectors/MSTeamsConnector';
|
||||
|
|
@ -9,7 +9,6 @@ import { TelegramConnector } from 'containers/AlertRules/parts/connectors/Telegr
|
|||
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { getVar } from 'utils/DOM';
|
||||
|
||||
interface ChatOpsConnectorsProps {
|
||||
channelFilterId: ChannelFilter['id'];
|
||||
|
|
@ -20,6 +19,7 @@ export const ChatOpsConnectors = (props: ChatOpsConnectorsProps) => {
|
|||
const { channelFilterId, showLineNumber = true } = props;
|
||||
|
||||
const store = useStore();
|
||||
const theme = useTheme2();
|
||||
const { organizationStore, telegramChannelStore, msteamsChannelStore } = store;
|
||||
|
||||
const isSlackInstalled = Boolean(organizationStore.currentOrganization?.slack_team_identity);
|
||||
|
|
@ -37,7 +37,7 @@ export const ChatOpsConnectors = (props: ChatOpsConnectorsProps) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Timeline.Item number={0} backgroundHexNumber={getVar('--tag-secondary')} isDisabled={!showLineNumber}>
|
||||
<Timeline.Item number={0} backgroundHexNumber={theme.colors.secondary.main} isDisabled={!showLineNumber}>
|
||||
<VerticalGroup>
|
||||
{isSlackInstalled && <SlackConnector channelFilterId={channelFilterId} />}
|
||||
{isTelegramInstalled && <TelegramConnector channelFilterId={channelFilterId} />}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ import React, { ReactElement, useCallback, useEffect } from 'react';
|
|||
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { LoadingPlaceholder, Select, useStyles2 } from '@grafana/ui';
|
||||
import { LoadingPlaceholder, Select, useStyles2, useTheme2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { get } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
import { getLabelBackgroundTextColorObject } from 'styles/utils.styles';
|
||||
|
||||
import { EscalationPolicy, EscalationPolicyProps } from 'components/Policy/EscalationPolicy';
|
||||
import { SortableList } from 'components/SortableList/SortableList';
|
||||
|
|
@ -14,7 +15,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
|
||||
import { EscalationPolicyOption } from 'models/escalation_policy/escalation_policy.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { getVar } from 'utils/DOM';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import styles from './EscalationChainSteps.module.css';
|
||||
|
|
@ -41,6 +41,7 @@ export const EscalationChainSteps = observer((props: EscalationChainStepsProps)
|
|||
|
||||
const store = useStore();
|
||||
const styles = useStyles2(getStyles);
|
||||
const theme = useTheme2();
|
||||
|
||||
const { escalationPolicyStore } = store;
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ export const EscalationChainSteps = observer((props: EscalationChainStepsProps)
|
|||
|
||||
const escalationPolicyIds = escalationPolicyStore.escalationChainToEscalationPolicy[id];
|
||||
const isSlackInstalled = Boolean(store.organizationStore.currentOrganization?.slack_team_identity);
|
||||
const { bgColor: successBgColor, textColor: successTextColor } = getLabelBackgroundTextColorObject('green', theme);
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
|
|
@ -124,8 +126,8 @@ export const EscalationChainSteps = observer((props: EscalationChainStepsProps)
|
|||
{!isDisabled && (
|
||||
<Timeline.Item
|
||||
number={(escalationPolicyIds?.length || 0) + offset + 1}
|
||||
backgroundHexNumber={isDisabled ? getVar('--tag-background-success') : getVar('--tag-secondary')}
|
||||
textColor={isDisabled ? getVar('--tag-text-success') : undefined}
|
||||
backgroundHexNumber={isDisabled ? successBgColor : theme.colors.secondary.main}
|
||||
textColor={isDisabled ? successTextColor : undefined}
|
||||
>
|
||||
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
|
||||
<Select
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export const IntegrationFormContainer = observer((props: IntegrationFormContaine
|
|||
const [filterValue, setFilterValue] = useState('');
|
||||
const [showNewIntegrationForm, setShowNewIntegrationForm] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState<ApiSchemas['AlertReceiveChannelIntegrationOptions']>(undefined);
|
||||
const [showIntegrarionsListDrawer, setShowIntegrarionsListDrawer] = useState(id === 'new');
|
||||
const [showIntegrationsListDrawer, setshowIntegrationsListDrawer] = useState(id === 'new');
|
||||
|
||||
const { alertReceiveChannelOptions } = alertReceiveChannelStore;
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export const IntegrationFormContainer = observer((props: IntegrationFormContaine
|
|||
|
||||
return (
|
||||
<>
|
||||
{showIntegrarionsListDrawer && (
|
||||
{showIntegrationsListDrawer && (
|
||||
<Drawer scrollableContent title="New Integration" onClose={onHide} closeOnMaskClick={false} width="640px">
|
||||
<div className={cx('content')}>
|
||||
<VerticalGroup>
|
||||
|
|
@ -79,7 +79,7 @@ export const IntegrationFormContainer = observer((props: IntegrationFormContaine
|
|||
</div>
|
||||
</Drawer>
|
||||
)}
|
||||
{(showNewIntegrationForm || !showIntegrarionsListDrawer) && (
|
||||
{(showNewIntegrationForm || !showIntegrationsListDrawer) && (
|
||||
<Drawer scrollableContent title={getTitle()} onClose={onHide} closeOnMaskClick={false} width="640px">
|
||||
<div className={cx('content')}>
|
||||
<VerticalGroup>
|
||||
|
|
@ -100,13 +100,13 @@ export const IntegrationFormContainer = observer((props: IntegrationFormContaine
|
|||
|
||||
function onBackClick(): void {
|
||||
setShowNewIntegrationForm(false);
|
||||
setShowIntegrarionsListDrawer(true);
|
||||
setshowIntegrationsListDrawer(true);
|
||||
}
|
||||
|
||||
function onBlockClick(option: ApiSchemas['AlertReceiveChannelIntegrationOptions']): void {
|
||||
setSelectedOption(option);
|
||||
setShowNewIntegrationForm(true);
|
||||
setShowIntegrarionsListDrawer(false);
|
||||
setshowIntegrationsListDrawer(false);
|
||||
}
|
||||
|
||||
function getTitle(): string {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Download
|
||||
</span>
|
||||
|
|
@ -54,7 +54,7 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The Grafana OnCall app is available on both the App Store and Google Play Store.
|
||||
</span>
|
||||
|
|
@ -84,7 +84,7 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
iOS
|
||||
</span>
|
||||
|
|
@ -109,7 +109,7 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
Android
|
||||
</span>
|
||||
|
|
@ -171,7 +171,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Download
|
||||
</span>
|
||||
|
|
@ -180,7 +180,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The Grafana OnCall app is available on both the App Store and Google Play Store.
|
||||
</span>
|
||||
|
|
@ -210,7 +210,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
iOS
|
||||
</span>
|
||||
|
|
@ -235,7 +235,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
Android
|
||||
</span>
|
||||
|
|
@ -297,7 +297,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Download
|
||||
</span>
|
||||
|
|
@ -306,7 +306,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The Grafana OnCall app is available on both the App Store and Google Play Store.
|
||||
</span>
|
||||
|
|
@ -336,7 +336,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
iOS
|
||||
</span>
|
||||
|
|
@ -361,7 +361,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
Android
|
||||
</span>
|
||||
|
|
@ -388,7 +388,7 @@ exports[`MobileAppConnection it shows a warning when cloud is not connected 1`]
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Please connect Grafana Cloud OnCall to use the mobile app
|
||||
</span>
|
||||
|
|
@ -438,7 +438,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
class="css-1x53p5e css-1x53p5e--bordered css-1x53p5e--shadowed css-1x53p5e--withBackGround container__box"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
There was an error disconnecting your mobile app. Please try again.
|
||||
</span>
|
||||
|
|
@ -454,7 +454,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Download
|
||||
</span>
|
||||
|
|
@ -463,7 +463,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The Grafana OnCall app is available on both the App Store and Google Play Store.
|
||||
</span>
|
||||
|
|
@ -493,7 +493,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
iOS
|
||||
</span>
|
||||
|
|
@ -518,7 +518,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
Android
|
||||
</span>
|
||||
|
|
@ -554,7 +554,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
class="css-1x53p5e css-1x53p5e--bordered css-1x53p5e--shadowed css-1x53p5e--withBackGround container__box"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
There was an error fetching your QR code. Please try again.
|
||||
</span>
|
||||
|
|
@ -570,7 +570,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Download
|
||||
</span>
|
||||
|
|
@ -579,7 +579,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The Grafana OnCall app is available on both the App Store and Google Play Store.
|
||||
</span>
|
||||
|
|
@ -609,7 +609,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
iOS
|
||||
</span>
|
||||
|
|
@ -634,7 +634,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
Android
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Download
|
||||
</span>
|
||||
|
|
@ -19,7 +19,7 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The Grafana OnCall app is available on both the App Store and Google Play Store.
|
||||
</span>
|
||||
|
|
@ -49,7 +49,7 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
iOS
|
||||
</span>
|
||||
|
|
@ -74,7 +74,7 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
src="[object Object]"
|
||||
/>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium icon-text css-1287p17"
|
||||
>
|
||||
Android
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ exports[`LinkLoginButton it renders properly 1`] = `
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-77ouhj--strong css-1287p17"
|
||||
>
|
||||
Sign in via deeplink
|
||||
</span>
|
||||
|
|
@ -19,7 +19,7 @@ exports[`LinkLoginButton it renders properly 1`] = `
|
|||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--primary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Make sure to have the app installed
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
1. Launch the OnCall backend
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Run hobby, dev or production backend. See
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
here
|
||||
</span>
|
||||
|
|
@ -47,7 +47,7 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
2. Let us know the base URL of your OnCall API
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The OnCall backend must be reachable from your Grafana installation. Some examples are:
|
||||
<br />
|
||||
|
|
@ -117,7 +117,7 @@ exports[`PluginConfigPage If onCallApiUrl is set, and updatePluginStatus returns
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
ohhh nooo a plugin connection error
|
||||
</span>
|
||||
|
|
@ -169,7 +169,7 @@ exports[`PluginConfigPage It doesn't make any network calls if the plugin config
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Connected to OnCall (v1.2.3, OpenSource)
|
||||
</span>
|
||||
|
|
@ -224,7 +224,7 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Connected to OnCall (v1.2.3, OpenSource)
|
||||
</span>
|
||||
|
|
@ -279,7 +279,7 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Connected to OnCall (v1.2.3, some-other-license)
|
||||
</span>
|
||||
|
|
@ -336,7 +336,7 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
ohhh noooo a sync issue
|
||||
</span>
|
||||
|
|
@ -391,7 +391,7 @@ exports[`PluginConfigPage Plugin reset: successful - false 1`] = `
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
There was an error resetting your plugin, try again.
|
||||
</span>
|
||||
|
|
@ -453,7 +453,7 @@ exports[`PluginConfigPage Plugin reset: successful - true 1`] = `
|
|||
1. Launch the OnCall backend
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Run hobby, dev or production backend. See
|
||||
|
||||
|
|
@ -463,7 +463,7 @@ exports[`PluginConfigPage Plugin reset: successful - true 1`] = `
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
here
|
||||
</span>
|
||||
|
|
@ -479,7 +479,7 @@ exports[`PluginConfigPage Plugin reset: successful - true 1`] = `
|
|||
2. Let us know the base URL of your OnCall API
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The OnCall backend must be reachable from your Grafana installation. Some examples are:
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ exports[`ConfigurationForm It doesn't allow the user to submit if the URL is inv
|
|||
1. Launch the OnCall backend
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Run hobby, dev or production backend. See
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ exports[`ConfigurationForm It doesn't allow the user to submit if the URL is inv
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
here
|
||||
</span>
|
||||
|
|
@ -40,7 +40,7 @@ exports[`ConfigurationForm It doesn't allow the user to submit if the URL is inv
|
|||
2. Let us know the base URL of your OnCall API
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The OnCall backend must be reachable from your Grafana installation. Some examples are:
|
||||
<br />
|
||||
|
|
@ -125,7 +125,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
1. Launch the OnCall backend
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Run hobby, dev or production backend. See
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
here
|
||||
</span>
|
||||
|
|
@ -151,7 +151,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
2. Let us know the base URL of your OnCall API
|
||||
</p>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
The OnCall backend must be reachable from your Grafana installation. Some examples are:
|
||||
<br />
|
||||
|
|
@ -195,7 +195,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
</div>
|
||||
<pre>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
ohhh nooo there was an error from the OnCall API
|
||||
</span>
|
||||
|
|
@ -204,7 +204,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
class="css-1x53p5e css-1x53p5e--withBackGround info-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--secondary css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
Need help?
|
||||
<br />
|
||||
|
|
@ -216,7 +216,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
#grafana-oncall
|
||||
</span>
|
||||
|
|
@ -232,7 +232,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
here
|
||||
</span>
|
||||
|
|
@ -247,7 +247,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--link css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
here
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ exports[`StatusMessageBlock It renders properly 1`] = `
|
|||
data-testid="status-message-block"
|
||||
>
|
||||
<span
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1d6rs0l"
|
||||
class="css-77ouhj--undefined css-77ouhj--medium css-1287p17"
|
||||
>
|
||||
helloooo
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { IconButton, VerticalGroup, HorizontalGroup, Field, Button } from '@grafana/ui';
|
||||
import { IconButton, VerticalGroup, HorizontalGroup, Field, Button, useTheme2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import Draggable from 'react-draggable';
|
||||
|
|
@ -15,7 +15,7 @@ import { Schedule, Shift } from 'models/schedule/schedule.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { getDateTime, getUTCString } from 'pages/schedule/Schedule.helpers';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { getCoords, getVar, waitForElement } from 'utils/DOM';
|
||||
import { getCoords, waitForElement } from 'utils/DOM';
|
||||
import { GRAFANA_HEADER_HEIGHT } from 'utils/consts';
|
||||
import { useDebouncedCallback } from 'utils/hooks';
|
||||
|
||||
|
|
@ -48,10 +48,11 @@ export const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
|
|||
shiftId,
|
||||
shiftStart: propsShiftStart = dayjs().startOf('day').add(1, 'day'),
|
||||
shiftEnd: propsShiftEnd,
|
||||
shiftColor = getVar('--tag-warning'),
|
||||
shiftColor: shiftColorProp,
|
||||
} = props;
|
||||
|
||||
const store = useStore();
|
||||
const theme = useTheme2();
|
||||
|
||||
const [rotationName, setRotationName] = useState<string>(shiftId === 'new' ? 'Override' : 'Update override');
|
||||
|
||||
|
|
@ -63,6 +64,7 @@ export const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
|
|||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const [errors, setErrors] = useState<{ [key: string]: string[] }>({});
|
||||
const shiftColor = shiftColorProp || theme.colors.warning.main;
|
||||
|
||||
const updateShiftStart = useCallback(
|
||||
(value) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import React, { useEffect } from 'react';
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import { COLORS } from 'styles/utils.styles';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { WorkingHours } from 'components/WorkingHours/WorkingHours';
|
||||
|
|
@ -23,6 +26,7 @@ const WEEK_IN_SECONDS = 60 * 60 * 24 * 7;
|
|||
|
||||
export const UserItem = ({ pk, shiftColor, shiftStart, shiftEnd }: UserItemProps) => {
|
||||
const { userStore } = useStore();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
useEffect(() => {
|
||||
if (!userStore.items[pk]) {
|
||||
|
|
@ -48,8 +52,16 @@ export const UserItem = ({ pk, shiftColor, shiftStart, shiftEnd }: UserItemProps
|
|||
/>
|
||||
)}
|
||||
<div className={cx('user-title')}>
|
||||
<Text strong>{name}</Text> <Text style={{ color: 'var(--always-gray)' }}>({desc})</Text>
|
||||
<Text strong>{name}</Text> <Text className={styles.gray}>({desc})</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = () => {
|
||||
return {
|
||||
gray: css`
|
||||
color: ${COLORS.ALWAYS_GREY};
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useCallback } from 'react';
|
||||
|
||||
import { Alert, Button, HorizontalGroup, InlineField, Input, VerticalGroup } from '@grafana/ui';
|
||||
import { Alert, Button, HorizontalGroup, InlineField, Input, VerticalGroup, useTheme2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
|
|
@ -11,7 +11,6 @@ import { UserSettingsTab } from 'containers/UserSettings/UserSettings.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { getVar } from 'utils/DOM';
|
||||
|
||||
import styles from 'containers/UserSettings/parts/UserSettingsParts.module.css';
|
||||
|
||||
|
|
@ -26,6 +25,7 @@ export const PhoneConnector = observer((props: PhoneConnectorProps) => {
|
|||
const { id, onTabChange } = props;
|
||||
|
||||
const store = useStore();
|
||||
const theme = useTheme2();
|
||||
const { userStore } = store;
|
||||
|
||||
const storeUser = userStore.items[id];
|
||||
|
|
@ -134,8 +134,8 @@ export const PhoneConnector = observer((props: PhoneConnectorProps) => {
|
|||
<VerticalGroup spacing="xs">
|
||||
<div className={cx('tag-container')}>
|
||||
<Tag
|
||||
color={getVar('--tag-secondary-transparent')}
|
||||
border={getVar('--border-weak')}
|
||||
color={'rgba(204, 204, 220, 0.04)'}
|
||||
border={theme.colors.border.weak}
|
||||
className={cx('tag', 'tag-left')}
|
||||
>
|
||||
<Text type="primary" size="small">
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
.navbar-star-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.header-topnavbar {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.navbar-heading {
|
||||
padding: 4px;
|
||||
border: 1px solid var(--gray-9);
|
||||
width: initial;
|
||||
font-size: 12px;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.navbar-left {
|
||||
display: flex;
|
||||
flex-basis: 100%;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.navbar-heading-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
column-gap: 8px;
|
||||
row-gap: 8px;
|
||||
margin-left: -50px;
|
||||
}
|
||||
|
||||
.irm-icon {
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #ffb375;
|
||||
color: #ffb375;
|
||||
}
|
||||
|
||||
.banners {
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:empty {
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.logo-container,
|
||||
.page-header__img {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.page-header__title {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
76
grafana-plugin/src/navbar/Header/Header.styles.ts
Normal file
76
grafana-plugin/src/navbar/Header/Header.styles.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
export const getHeaderStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
navbarStarIcon: css`
|
||||
margin-right: 4px;
|
||||
`,
|
||||
|
||||
headerTopNavbar: css`
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 32px;
|
||||
`,
|
||||
|
||||
navbarHeading: css`
|
||||
padding: 4px;
|
||||
border: 1px solid ${theme.colors.secondary.border};
|
||||
width: initial;
|
||||
font-size: 12px;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
`,
|
||||
|
||||
navbarLink: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 6px;
|
||||
`,
|
||||
|
||||
navbarLeft: css`
|
||||
display: flex;
|
||||
flex-basis: 100%;
|
||||
align-items: flex-start;
|
||||
`,
|
||||
|
||||
navbarHeadingContainer: css`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
column-gap: 8px;
|
||||
row-gap: 8px;
|
||||
margin-left: -50px;
|
||||
`,
|
||||
|
||||
irmIcon: css`
|
||||
font-size: 12px;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #ffb375;
|
||||
color: #ffb375;
|
||||
`,
|
||||
|
||||
banners: css`
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:empty {
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`,
|
||||
|
||||
logoContainer: css`
|
||||
height: 32px;
|
||||
margin-top: 2px;
|
||||
`,
|
||||
|
||||
pageHeaderImage: css`
|
||||
height: 32px;
|
||||
`,
|
||||
|
||||
pageHeaderTitle: css`
|
||||
margin-bottom: 8px;
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Card, HorizontalGroup } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { cx } from '@emotion/css';
|
||||
import { Card, HorizontalGroup, useStyles2 } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import gitHubStarSVG from 'assets/img/github_star.svg';
|
||||
|
|
@ -11,22 +11,21 @@ import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
|
|||
import { useStore } from 'state/useStore';
|
||||
import { APP_SUBTITLE } from 'utils/consts';
|
||||
|
||||
import styles from './Header.module.scss';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
import { getHeaderStyles } from './Header.styles';
|
||||
|
||||
export const Header = observer(() => {
|
||||
const store = useStore();
|
||||
const styles = useStyles2(getHeaderStyles);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={cx('root')}>
|
||||
<div className={cx('page-header__inner', { 'header-topnavbar': isTopNavbar() })}>
|
||||
<div className={cx('navbar-left')}>
|
||||
<span className={cx('page-header__logo', 'logo-container')}>
|
||||
<img className={cx('page-header__img')} src={logo} alt="Grafana OnCall" />
|
||||
<div>
|
||||
<div className={cx('page-header__inner', { [styles.headerTopNavbar]: isTopNavbar() })}>
|
||||
<div className={cx(styles.navbarLeft)}>
|
||||
<span className={cx('page-header__logo', styles.logoContainer)}>
|
||||
<img className={cx(styles.pageHeaderImage)} src={logo} alt="Grafana OnCall" />
|
||||
</span>
|
||||
<div className="page-header__info-block">{renderHeading()}</div>
|
||||
<div className={cx('page-header__info-block')}>{renderHeading()}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -38,18 +37,18 @@ export const Header = observer(() => {
|
|||
if (store.isOpenSource) {
|
||||
return (
|
||||
<div className={cx('heading')}>
|
||||
<h1 className={cx('page-header__title')}>Grafana OnCall</h1>
|
||||
<div className={cx('navbar-heading-container')}>
|
||||
<h1 className={cx(styles.pageHeaderTitle)}>Grafana OnCall</h1>
|
||||
<div className={cx(styles.navbarHeadingContainer)}>
|
||||
<div className={cx('page-header__sub-title')}>{APP_SUBTITLE}</div>
|
||||
|
||||
<Card heading={undefined} className={cx('navbar-heading')}>
|
||||
<Card heading={undefined} className={cx(styles.navbarHeading)}>
|
||||
<a
|
||||
href="https://github.com/grafana/oncall"
|
||||
className={cx('navbar-link')}
|
||||
className={cx(styles.navbarLink)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<img src={gitHubStarSVG} className={cx('navbar-star-icon')} alt="" /> Star us on GitHub
|
||||
<img src={gitHubStarSVG} className={cx(styles.navbarStarIcon)} alt="" /> Star us on GitHub
|
||||
</a>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
@ -60,7 +59,7 @@ export const Header = observer(() => {
|
|||
return (
|
||||
<>
|
||||
<HorizontalGroup>
|
||||
<h1 className={cx('page-header__title')}>Grafana OnCall</h1>
|
||||
<h1 className={cx(styles.pageHeaderTitle)}>Grafana OnCall</h1>
|
||||
</HorizontalGroup>
|
||||
<div className={cx('page-header__sub-title')}>{APP_SUBTITLE}</div>
|
||||
</>
|
||||
|
|
@ -69,8 +68,9 @@ export const Header = observer(() => {
|
|||
});
|
||||
|
||||
const Banners: React.FC = () => {
|
||||
const styles = useStyles2(getHeaderStyles);
|
||||
return (
|
||||
<div className={cx('banners')}>
|
||||
<div className={cx(styles.banners)}>
|
||||
<Alerts />
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import cn from 'classnames/bind';
|
|||
|
||||
import { Avatar } from 'components/Avatar/Avatar';
|
||||
import { PluginLink } from 'components/PluginLink/PluginLink';
|
||||
import { Tag } from 'components/Tag/Tag';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { TextEllipsisTooltip } from 'components/TextEllipsisTooltip/TextEllipsisTooltip';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
|
|
@ -13,7 +12,6 @@ import { IncidentStatus } from 'models/alertgroup/alertgroup.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { SilenceButtonCascader } from 'pages/incidents/parts/SilenceButtonCascader';
|
||||
import { move } from 'state/helpers';
|
||||
import { getVar } from 'utils/DOM';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { TEXT_ELLIPSIS_CLASS } from 'utils/consts';
|
||||
|
||||
|
|
@ -21,45 +19,6 @@ import styles from './Incident.module.scss';
|
|||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
export function getIncidentStatusTag(alert: ApiSchemas['AlertGroup']) {
|
||||
switch (alert.status) {
|
||||
case IncidentStatus.Firing:
|
||||
return (
|
||||
<Tag color={getVar('--tag-danger')} className={cx('status-tag')}>
|
||||
<Text strong size="small">
|
||||
Firing
|
||||
</Text>
|
||||
</Tag>
|
||||
);
|
||||
case IncidentStatus.Acknowledged:
|
||||
return (
|
||||
<Tag color={getVar('--tag-warning')} className={cx('status-tag')}>
|
||||
<Text strong size="small">
|
||||
Acknowledged
|
||||
</Text>
|
||||
</Tag>
|
||||
);
|
||||
case IncidentStatus.Resolved:
|
||||
return (
|
||||
<Tag color={getVar('--tag-primary')} className={cx('status-tag')}>
|
||||
<Text strong size="small">
|
||||
Resolved
|
||||
</Text>
|
||||
</Tag>
|
||||
);
|
||||
case IncidentStatus.Silenced:
|
||||
return (
|
||||
<Tag color={getVar('--tag-secondary')} className={cx('status-tag')}>
|
||||
<Text strong size="small">
|
||||
Silenced
|
||||
</Text>
|
||||
</Tag>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function renderRelatedUsers(incident: ApiSchemas['AlertGroup'], isFull = false) {
|
||||
const { related_users } = incident;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
.incident__tag {
|
||||
padding: 5px 8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.incident__icon {
|
||||
margin-right: -4px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.incident__options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.incident__option-item {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
border-left: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
min-width: 84px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-direction: row;
|
||||
|
||||
&:hover {
|
||||
background: var(--gray-9);
|
||||
}
|
||||
|
||||
&--acknowledge {
|
||||
color: var(--tag-warning);
|
||||
}
|
||||
|
||||
&--firing {
|
||||
color: var(--error-text-color);
|
||||
}
|
||||
|
||||
&--resolve {
|
||||
color: var(--success-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
.incident__option-span > div {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
export const getIncidentDropdownStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
incidentTag: css`
|
||||
padding: 5px 8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
`,
|
||||
|
||||
incidentIcon: css`
|
||||
margin-right: -4px;
|
||||
margin-left: 2px;
|
||||
`,
|
||||
|
||||
incidentOptions: css`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`,
|
||||
|
||||
incidentOptionItem: css`
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
border-left: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
min-width: 84px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-direction: row;
|
||||
color: ${theme.colors.text.primary};
|
||||
|
||||
&:hover {
|
||||
background: ${theme.colors.action.hover};
|
||||
}
|
||||
`,
|
||||
|
||||
incidentOptionEl: css`
|
||||
> div {
|
||||
margin: 0;
|
||||
}
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
|
@ -1,33 +1,31 @@
|
|||
import React, { FC, SyntheticEvent, useRef, useState } from 'react';
|
||||
|
||||
import { Icon, LoadingPlaceholder } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { cx } from '@emotion/css';
|
||||
import { Icon, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
|
||||
import { getUtilStyles } from 'styles/utils.styles';
|
||||
|
||||
import { Tag } from 'components/Tag/Tag';
|
||||
import { Tag, TagColor } from 'components/Tag/Tag';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { WithContextMenu } from 'components/WithContextMenu/WithContextMenu';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { AlertAction, IncidentStatus } from 'models/alertgroup/alertgroup.types';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import styles from 'pages/incidents/parts/IncidentDropdown.module.scss';
|
||||
import { getVar } from 'utils/DOM';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import { getIncidentDropdownStyles } from './IncidentDropdown.styles';
|
||||
import { SilenceSelect } from './SilenceSelect';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
const getIncidentTagColor = (alert: ApiSchemas['AlertGroup']) => {
|
||||
if (alert.status === IncidentStatus.Resolved) {
|
||||
return getVar('--tag-primary');
|
||||
return TagColor.SUCCESS;
|
||||
}
|
||||
if (alert.status === IncidentStatus.Firing) {
|
||||
return getVar('--tag-danger');
|
||||
return TagColor.ERROR;
|
||||
}
|
||||
if (alert.status === IncidentStatus.Acknowledged) {
|
||||
return getVar('--tag-warning');
|
||||
return TagColor.WARNING;
|
||||
}
|
||||
return getVar('--tag-secondary');
|
||||
return TagColor.SECONDARY;
|
||||
};
|
||||
|
||||
function IncidentStatusTag({
|
||||
|
|
@ -37,12 +35,13 @@ function IncidentStatusTag({
|
|||
alert: ApiSchemas['AlertGroup'];
|
||||
openMenu: React.MouseEventHandler<HTMLElement>;
|
||||
}) {
|
||||
const styles = useStyles2(getIncidentDropdownStyles);
|
||||
const forwardedRef = useRef<HTMLSpanElement>();
|
||||
|
||||
return (
|
||||
<Tag
|
||||
forwardedRef={forwardedRef}
|
||||
className={cx('incident__tag')}
|
||||
className={cx(styles.incidentTag)}
|
||||
color={getIncidentTagColor(alert)}
|
||||
onClick={() => {
|
||||
const boundingRect = forwardedRef.current.getBoundingClientRect();
|
||||
|
|
@ -50,10 +49,8 @@ function IncidentStatusTag({
|
|||
openMenu({ pageX: boundingRect.left + LEFT_MARGIN, pageY: boundingRect.top + boundingRect.height } as any);
|
||||
}}
|
||||
>
|
||||
<Text strong size="small">
|
||||
{IncidentStatus[alert.status]}
|
||||
</Text>
|
||||
<Icon className={cx('incident__icon')} name="angle-down" size="sm" />
|
||||
<Text size="small">{IncidentStatus[alert.status]}</Text>
|
||||
<Icon className={cx(styles.incidentIcon)} name="angle-down" size="sm" />
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
|
@ -71,6 +68,9 @@ export const IncidentDropdown: FC<{
|
|||
const [currentLoadingAction, setCurrentActionLoading] = useState<IncidentStatus>(undefined);
|
||||
const [forcedOpenAction, setForcedOpenAction] = useState<string>(undefined);
|
||||
|
||||
const styles = useStyles2(getIncidentDropdownStyles);
|
||||
const utilStyles = useStyles2(getUtilStyles);
|
||||
|
||||
const onClickFn = async (
|
||||
ev: React.SyntheticEvent<HTMLDivElement>,
|
||||
actionName: string,
|
||||
|
|
@ -96,15 +96,15 @@ export const IncidentDropdown: FC<{
|
|||
<WithContextMenu
|
||||
forceIsOpen={forcedOpenAction === AlertAction.Resolve}
|
||||
renderMenuItems={() => (
|
||||
<div className={cx('incident__options', { 'u-disabled': isLoading })}>
|
||||
<div className={cx(styles.incidentOptions, { [utilStyles.disabled]: isLoading })}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--firing')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.Resolve, onUnresolve, IncidentStatus.Firing)}
|
||||
>
|
||||
Firing{' '}
|
||||
{currentLoadingAction === IncidentStatus.Firing && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -123,15 +123,15 @@ export const IncidentDropdown: FC<{
|
|||
<WithContextMenu
|
||||
forceIsOpen={forcedOpenAction === AlertAction.Acknowledge}
|
||||
renderMenuItems={() => (
|
||||
<div className={cx('incident__options', { 'u-disabled': isLoading })}>
|
||||
<div className={cx(styles.incidentOptions, { [utilStyles.disabled]: isLoading })}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--unacknowledge')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.Acknowledge, onUnacknowledge, IncidentStatus.Firing)}
|
||||
>
|
||||
Unacknowledge{' '}
|
||||
{currentLoadingAction === IncidentStatus.Firing && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -139,12 +139,12 @@ export const IncidentDropdown: FC<{
|
|||
</WithPermissionControlTooltip>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--resolve')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.Acknowledge, onResolve, IncidentStatus.Resolved)}
|
||||
>
|
||||
Resolve{' '}
|
||||
{currentLoadingAction === IncidentStatus.Resolved && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -163,15 +163,15 @@ export const IncidentDropdown: FC<{
|
|||
<WithContextMenu
|
||||
forceIsOpen={forcedOpenAction === AlertAction.unResolve}
|
||||
renderMenuItems={() => (
|
||||
<div className={cx('incident__options', { 'u-disabled': isLoading })}>
|
||||
<div className={cx(styles.incidentOptions, { [utilStyles.disabled]: isLoading })}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--acknowledge')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.unResolve, onAcknowledge, IncidentStatus.Acknowledged)}
|
||||
>
|
||||
Acknowledge{' '}
|
||||
{currentLoadingAction === IncidentStatus.Acknowledged && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -179,19 +179,19 @@ export const IncidentDropdown: FC<{
|
|||
</WithPermissionControlTooltip>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--resolve')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.unResolve, onResolve, IncidentStatus.Resolved)}
|
||||
>
|
||||
Resolve{' '}
|
||||
{currentLoadingAction === IncidentStatus.Resolved && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</WithPermissionControlTooltip>
|
||||
|
||||
<div className={cx('incident__option-item')}>
|
||||
<div className={cx(styles.incidentOptionItem)}>
|
||||
<SilenceSelect
|
||||
placeholder={
|
||||
currentLoadingAction === IncidentStatus.Silenced && isLoading ? 'Loading...' : 'Silence for'
|
||||
|
|
@ -222,15 +222,15 @@ export const IncidentDropdown: FC<{
|
|||
<WithContextMenu
|
||||
forceIsOpen={forcedOpenAction === AlertAction.Silence}
|
||||
renderMenuItems={() => (
|
||||
<div className={cx('incident_options', { 'u-disabled': isLoading })}>
|
||||
<div className={cx(styles.incidentOptions, { [utilStyles.disabled]: isLoading })}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.Silence, onUnsilence, IncidentStatus.Firing)}
|
||||
>
|
||||
Unsilence{' '}
|
||||
{currentLoadingAction === IncidentStatus.Firing && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -238,12 +238,12 @@ export const IncidentDropdown: FC<{
|
|||
</WithPermissionControlTooltip>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--acknowledge')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.Silence, onAcknowledge, IncidentStatus.Acknowledged)}
|
||||
>
|
||||
Acknowledge{' '}
|
||||
{currentLoadingAction === IncidentStatus.Acknowledged && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -251,12 +251,12 @@ export const IncidentDropdown: FC<{
|
|||
</WithPermissionControlTooltip>
|
||||
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
|
||||
<div
|
||||
className={cx('incident__option-item', 'incident__option-item--resolve')}
|
||||
className={cx(styles.incidentOptionItem)}
|
||||
onClick={(e) => onClickFn(e, AlertAction.Silence, onAcknowledge, IncidentStatus.Resolved)}
|
||||
>
|
||||
Resolve{' '}
|
||||
{currentLoadingAction === IncidentStatus.Resolved && isLoading && (
|
||||
<span className={cx('incident__option-span')}>
|
||||
<span className={cx(styles.incidentOptionEl)}>
|
||||
<LoadingPlaceholder text="" />
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
export const getUtilStyles = (_theme: GrafanaTheme2) => {
|
||||
export const getUtilStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
width100: css`
|
||||
width: 100%;
|
||||
`,
|
||||
|
||||
disabled: css`
|
||||
opacity: 0.5;
|
||||
`,
|
||||
|
||||
thinLineBreak: css`
|
||||
width: 100%;
|
||||
border-top: 1px solid ${COLORS.ALWAYS_GREY};
|
||||
border-top: 1px solid ${theme.colors.secondary.main};
|
||||
margin-top: 8px;
|
||||
opacity: 15%;
|
||||
`,
|
||||
|
|
@ -24,6 +29,34 @@ export const getUtilStyles = (_theme: GrafanaTheme2) => {
|
|||
};
|
||||
};
|
||||
|
||||
export function getLabelBackgroundTextColorObject(
|
||||
color: string,
|
||||
theme: GrafanaTheme2
|
||||
): { bgColor: string; textColor: string; sourceColor: string } {
|
||||
let sourceColor = theme.visualization.getColorByName(color);
|
||||
let bgColor = '';
|
||||
let textColor = '';
|
||||
|
||||
if (theme.isDark) {
|
||||
bgColor = tinycolor(sourceColor).setAlpha(0.25).toString();
|
||||
textColor = tinycolor(sourceColor).lighten(15).toString();
|
||||
} else {
|
||||
bgColor = tinycolor(sourceColor).setAlpha(0.25).toString();
|
||||
textColor = tinycolor(sourceColor).darken(20).toString();
|
||||
}
|
||||
|
||||
return { bgColor, textColor, sourceColor };
|
||||
}
|
||||
|
||||
export function getLabelCss(color: string, theme: GrafanaTheme2) {
|
||||
const { bgColor, textColor, sourceColor } = getLabelBackgroundTextColorObject(color, theme);
|
||||
return css`
|
||||
border: 1px solid ${sourceColor};
|
||||
background-color: ${bgColor};
|
||||
color: ${textColor};
|
||||
`;
|
||||
}
|
||||
|
||||
export const bem = (...args: string[]) =>
|
||||
args.reduce((out, x, i) => {
|
||||
out += x;
|
||||
|
|
@ -39,5 +72,6 @@ export const bem = (...args: string[]) =>
|
|||
export enum COLORS {
|
||||
ALWAYS_GREY = '#ccccdc',
|
||||
GRAY_8 = '#595959',
|
||||
GRAY_9 = '#434343',
|
||||
GREEN_5 = '#6ccf8e',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ export const waitForElement = (selector: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
export const getVar = (cssVar: string): string => {
|
||||
return getComputedStyle(document.documentElement).getPropertyValue(cssVar);
|
||||
};
|
||||
|
||||
export const getCoords = (elem) => {
|
||||
// crossbrowser version
|
||||
const box = elem.getBoundingClientRect();
|
||||
|
|
|
|||
|
|
@ -13835,7 +13835,7 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
||||
|
||||
tinycolor2@1.6.0:
|
||||
tinycolor2@1.6.0, tinycolor2@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
|
||||
integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue