commit
f7500052ad
34 changed files with 6072 additions and 8787 deletions
|
|
@ -14,6 +14,7 @@ module.exports = {
|
|||
'react/jsx-key': 'warn',
|
||||
'react/no-unescaped-entities': 'warn',
|
||||
'react/jsx-no-target-blank': 'warn',
|
||||
'react-hooks/exhaustive-deps': 'warn',
|
||||
'no-restricted-imports': 'warn',
|
||||
eqeqeq: 'warn',
|
||||
'no-duplicate-imports': 'warn',
|
||||
|
|
|
|||
|
|
@ -39,22 +39,39 @@
|
|||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@grafana/data": "7.5.7",
|
||||
"@grafana/runtime": "7.5.7",
|
||||
"@grafana/toolkit": "7.5.7",
|
||||
"@grafana/ui": "8.2.1",
|
||||
"@types/dompurify": "^2.0.2",
|
||||
"@types/lodash-es": "^4.17.3",
|
||||
"@types/moment-timezone": "^0.5.12",
|
||||
"@types/react-copy-to-clipboard": "^4.3.0",
|
||||
"@types/react-responsive": "^8.0.2",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/throttle-debounce": "^2.1.0",
|
||||
"copy-webpack-plugin": "5.1.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.10",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
|
||||
"@babel/plugin-syntax-decorators": "^7.18.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-react-constant-elements": "^7.18.12",
|
||||
"@babel/plugin-transform-typescript": "^7.18.12",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@grafana/data": "^9.1.1",
|
||||
"@grafana/runtime": "^9.1.1",
|
||||
"@grafana/toolkit": "^9.1.1",
|
||||
"@grafana/ui": "^9.1.1",
|
||||
"@types/dompurify": "^2.3.4",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-responsive": "^8.0.5",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/throttle-debounce": "^5.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"dompurify": "^2.3.12",
|
||||
"eslint-plugin-rulesdir": "^0.2.1",
|
||||
"lint-staged": "^10.2.11",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment-timezone": "^0.5.35",
|
||||
"plop": "^2.7.4",
|
||||
"webpack-bundle-analyzer": "^4.4.2"
|
||||
"postcss-loader": "^7.0.1",
|
||||
"ts-loader": "^9.3.1",
|
||||
"webpack-bundle-analyzer": "^4.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
|
@ -63,12 +80,9 @@
|
|||
"@types/query-string": "^6.3.0",
|
||||
"change-case": "^4.1.1",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"dompurify": "^2.0.12",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"lodash-es": "^4.17.15",
|
||||
"mobx": "^5.13.0",
|
||||
"mobx-react": "^6.1.1",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"mobx": "5.13.0",
|
||||
"mobx-react": "6.1.1",
|
||||
"rc-table": "^7.17.1",
|
||||
"react-copy-to-clipboard": "^5.0.2",
|
||||
"react-emoji-render": "^1.2.4",
|
||||
|
|
@ -76,6 +90,7 @@
|
|||
"react-router-dom": "^5.2.0",
|
||||
"react-sortable-hoc": "^1.11.0",
|
||||
"react-string-replace": "^0.4.4",
|
||||
"sass-loader": "^13.0.2",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"throttle-debounce": "^2.1.0"
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ const AlertTemplatesForm = (props: AlertTemplatesFormProps) => {
|
|||
<VerticalGroup>
|
||||
<Text type="secondary">
|
||||
<p>
|
||||
<a href="https://jinja.palletsprojects.com/en/3.0.x/" target="_blank">
|
||||
<a href="https://jinja.palletsprojects.com/en/3.0.x/" target="_blank" rel="noreferrer">
|
||||
Jinja2
|
||||
</a>
|
||||
{activeGroup === 'slack' && ', Slack markdown'}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ interface CollapseProps {
|
|||
className?: string;
|
||||
contentClassName?: string;
|
||||
headerWithBackground?: boolean;
|
||||
children?: any
|
||||
}
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ interface PluginLinkProps extends LocationUpdate {
|
|||
disabled?: boolean;
|
||||
className?: string;
|
||||
wrap?: boolean;
|
||||
children: any
|
||||
}
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const cx = cn.bind(styles);
|
|||
|
||||
interface PolicyNoteProps {
|
||||
type?: 'success' | 'info' | 'danger';
|
||||
children?: any;
|
||||
}
|
||||
|
||||
function getIcon(type: PolicyNoteProps['type']) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const cx = cn.bind(styles);
|
|||
interface SourceCodeProps {
|
||||
noMaxHeight?: boolean;
|
||||
showCopyToClipboard?: boolean;
|
||||
children?: any
|
||||
}
|
||||
|
||||
const SourceCode: FC<SourceCodeProps> = (props) => {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import styles from 'components/Tag/Tag.module.css';
|
|||
interface TagProps {
|
||||
color: string;
|
||||
className?: string;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
.root {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.type_secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.type_primary {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.type_disabled {
|
||||
color: var(--disabled-text-color);
|
||||
}
|
||||
|
||||
.type_warning {
|
||||
color: var(--warning-text-color);
|
||||
}
|
||||
|
||||
.type_link {
|
||||
color: var(--primary-text-link);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.type_success {
|
||||
color: #6ccf8e;
|
||||
}
|
||||
|
||||
.strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.no-wrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.keyboard {
|
||||
margin: 0 0.2em;
|
||||
padding: 0.15em 0.4em 0.1em;
|
||||
font-size: 90%;
|
||||
background: hsla(0, 0%, 58.8%, 0.06);
|
||||
border: solid hsla(0, 0%, 39.2%, 0.2);
|
||||
border-width: 1px 1px 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.size_small {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.size_large {
|
||||
font-size: 20px;
|
||||
}
|
||||
59
grafana-plugin/src/components/Text/Text.module.scss
Normal file
59
grafana-plugin/src/components/Text/Text.module.scss
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
.root {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.text {
|
||||
&--primary {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
&--secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
&--disabled {
|
||||
color: var(--disabled-text-color);
|
||||
}
|
||||
&--warning {
|
||||
color: var(--warning-text-color);
|
||||
}
|
||||
&--link {
|
||||
color: var(--primary-text-link);
|
||||
text-decoration: underline;
|
||||
}
|
||||
&--success {
|
||||
color: var(--green-5);
|
||||
}
|
||||
&--strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
&--underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&--small {
|
||||
font-size: 12px;
|
||||
}
|
||||
&--large {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-wrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.keyboard {
|
||||
margin: 0 0.2em;
|
||||
padding: 0.15em 0.4em 0.1em;
|
||||
font-size: 90%;
|
||||
background: hsla(0, 0%, 58.8%, 0.06);
|
||||
border: solid hsla(0, 0%, 39.2%, 0.2);
|
||||
border-width: 1px 1px 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
import React, { FC, HTMLAttributes, ChangeEvent, useState, useCallback } from 'react';
|
||||
|
||||
import { IconButton, Modal, Field, Input, HorizontalGroup, Button, Icon, VerticalGroup } from '@grafana/ui';
|
||||
import { IconButton, Modal, Input, HorizontalGroup, Button, VerticalGroup } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
import { TimelineProps } from 'components/Timeline/Timeline';
|
||||
import { TimelineItemProps } from 'components/Timeline/TimelineItem';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openNotification } from 'utils';
|
||||
|
||||
import styles from './Text.module.css';
|
||||
import styles from './Text.module.scss';
|
||||
|
||||
interface TextProps extends HTMLAttributes<HTMLElement> {
|
||||
type?: 'primary' | 'secondary' | 'disabled' | 'link' | 'success' | 'warning';
|
||||
|
|
@ -78,13 +75,13 @@ const Text: TextType = (props) => {
|
|||
return (
|
||||
<span
|
||||
onClick={onClick}
|
||||
className={cx('root', className, {
|
||||
[`type_${type}`]: true,
|
||||
[`size_${size}`]: true,
|
||||
strong,
|
||||
underline,
|
||||
keyboard,
|
||||
className={cx('root', 'text', className, {
|
||||
[`text--${type}`]: true,
|
||||
[`text--${size}`]: true,
|
||||
'text--strong': strong,
|
||||
'text--underline': underline,
|
||||
'no-wrap': !wrap,
|
||||
keyboard
|
||||
})}
|
||||
>
|
||||
{hidden ? PLACEHOLDER : children}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
|
||||
import { HorizontalGroup, TimeOfDayPicker } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { Moment } from 'moment';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
import styles from './TimeRange.module.css';
|
||||
|
|
@ -39,7 +38,7 @@ function getMoments(from: string, to: string) {
|
|||
return [fromMoment, toMoment];
|
||||
}
|
||||
|
||||
function getRangeStrings(from: Moment, to: Moment) {
|
||||
function getRangeStrings(from: moment.Moment, to: moment.Moment) {
|
||||
const fromString = from.clone().utc().format('HH:mm:00');
|
||||
const toString = to.clone().utc().format('HH:mm:00');
|
||||
|
||||
|
|
@ -49,8 +48,10 @@ function getRangeStrings(from: Moment, to: Moment) {
|
|||
const TimeRange = (props: TimeRangeProps) => {
|
||||
const { className, from: f, to: t, onChange, disabled } = props;
|
||||
|
||||
const [from, setFrom] = useState<Moment>(getMoments(f, t)[0]);
|
||||
const [to, setTo] = useState<Moment>(getMoments(f, t)[1]);
|
||||
// @ts-ignore
|
||||
const [from, setFrom] = useState<moment.Moment>(getMoments(f, t)[0]);
|
||||
// @ts-ignore
|
||||
const [to, setTo] = useState<moment.Moment>(getMoments(f, t)[1]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!f || !t) {
|
||||
|
|
@ -59,7 +60,7 @@ const TimeRange = (props: TimeRangeProps) => {
|
|||
}, []);
|
||||
|
||||
const handleChangeFrom = useCallback(
|
||||
(value: Moment) => {
|
||||
(value: moment.Moment) => {
|
||||
setFrom(value);
|
||||
|
||||
if (value.isSame(to, 'minute')) {
|
||||
|
|
@ -74,7 +75,7 @@ const TimeRange = (props: TimeRangeProps) => {
|
|||
);
|
||||
|
||||
const handleChangeTo = useCallback(
|
||||
(value: Moment) => {
|
||||
(value: moment.Moment) => {
|
||||
setTo(value);
|
||||
|
||||
if (value.isSame(from, 'minute')) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const cx = cn.bind(styles);
|
|||
|
||||
export interface TimelineProps {
|
||||
className?: string;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
interface TimelineType extends React.FC<TimelineProps> {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export interface TimelineItemProps {
|
|||
color?: string;
|
||||
number?: number;
|
||||
badge?: number;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
const TimelineItem: React.FC<TimelineItemProps> = (props) => {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export default VerticalTabsBar;
|
|||
|
||||
interface TabProps {
|
||||
id: string;
|
||||
children?: any
|
||||
}
|
||||
|
||||
export const VerticalTab: FC<TabProps> = ({ children }) => {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ const ChannelFilterForm = observer((props: ChannelFilterFormProps) => {
|
|||
description={
|
||||
<>
|
||||
Use{' '}
|
||||
<a href="https://regex101.com/" target="_blank">
|
||||
<a href="https://regex101.com/" target="_blank" rel="noreferrer">
|
||||
python style
|
||||
</a>{' '}
|
||||
regex to filter incidents based on a expression
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import styles from './DefaultPageLayout.module.css';
|
|||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
interface DefaultPageLayoutProps extends AppRootProps {}
|
||||
interface DefaultPageLayoutProps extends AppRootProps {
|
||||
children?: any;
|
||||
}
|
||||
|
||||
enum AlertID {
|
||||
CONNECTIVITY_WARNING = 'Connectivity Warning',
|
||||
|
|
@ -107,7 +109,7 @@ const DefaultPageLayout: FC<DefaultPageLayoutProps> = observer((props) => {
|
|||
{`Current plugin version: ${plugin.version}, current engine version: ${store.backendVersion}`}
|
||||
<br />
|
||||
Please see{' '}
|
||||
<a href={'https://grafana.com/docs/oncall/latest/open-source/#update-grafana-oncall-oss'} target="_blank">
|
||||
<a href={'https://grafana.com/docs/oncall/latest/open-source/#update-grafana-oncall-oss'} target="_blank" rel="noreferrer">
|
||||
the update instructions
|
||||
</a>
|
||||
.
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ const EscalationChainSteps = observer((props: EscalationChainStepsProps) => {
|
|||
|
||||
const escalationPolicyIds = escalationPolicyStore.escalationChainToEscalationPolicy[id];
|
||||
const isSlackInstalled = Boolean(store.teamStore.currentTeam?.slack_team_identity);
|
||||
const isTelegramInstalled = Boolean(store.telegramChannelStore?.currentTeamToTelegramChannel?.length > 0);
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<SortableList useDragHandle className={cx('steps')} axis="y" lockAxis="y" onSortEnd={handleSortEnd}>
|
||||
{addonBefore}
|
||||
{escalationPolicyIds ? (
|
||||
|
|
@ -79,6 +79,7 @@ const EscalationChainSteps = observer((props: EscalationChainStepsProps) => {
|
|||
<EscalationPolicy
|
||||
key={`item-${escalationPolicy.id}`}
|
||||
index={index}
|
||||
// @ts-ignore
|
||||
data={escalationPolicy}
|
||||
number={index + offset + 1}
|
||||
color={STEP_COLORS[index] || COLOR_RED}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ const HeartbeatForm = observer(({ alertReceveChannelId, onUpdate }: HeartBeatMod
|
|||
<p>
|
||||
<Text>
|
||||
Use the following unique Grafana link to send GET and POST requests:{' '}
|
||||
<a href={heartbeat?.link} target="_blank">
|
||||
<a href={heartbeat?.link} target="_blank" rel="noreferrer">
|
||||
{heartbeat?.link}
|
||||
</a>
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { Component } from 'react';
|
|||
|
||||
import { SelectableValue, TimeRange } from '@grafana/data';
|
||||
import {
|
||||
HorizontalGroup,
|
||||
IconButton,
|
||||
InlineSwitch,
|
||||
MultiSelect,
|
||||
|
|
@ -10,14 +9,13 @@ import {
|
|||
Select,
|
||||
LoadingPlaceholder,
|
||||
Input,
|
||||
VerticalGroup,
|
||||
Icon,
|
||||
} from '@grafana/ui';
|
||||
import { capitalCase } from 'change-case';
|
||||
import cn from 'classnames/bind';
|
||||
import { debounce, isEmpty, isUndefined, omit, omitBy, pickBy } from 'lodash-es';
|
||||
import { debounce, isEmpty, isUndefined, omitBy } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
import moment from 'moment';
|
||||
import moment from 'moment-timezone';
|
||||
import Emoji from 'react-emoji-render';
|
||||
|
||||
import CardButton from 'components/CardButton/CardButton';
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ const Autoresolve = ({ alertReceiveChannelId, onSwitchToTemplate, alertGroupId }
|
|||
store.alertReceiveChannelStore.templates[alertReceiveChannelId],
|
||||
'resolve_condition_template'
|
||||
);
|
||||
// @ts-ignore
|
||||
if (autoresolveCondition == ['invalid template']) {
|
||||
setAutoresolveConditionInvalid(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ const PersonalNotificationSettings = observer((props: PersonalNotificationSettin
|
|||
return (
|
||||
<div className={cx('root')}>
|
||||
{title}
|
||||
{/* @ts-ignore */}
|
||||
<SortableList
|
||||
helperClass={cx('sortable-helper')}
|
||||
className={cx('steps')}
|
||||
|
|
@ -126,6 +127,7 @@ const PersonalNotificationSettings = observer((props: PersonalNotificationSettin
|
|||
>
|
||||
{notificationPolicies.map((notificationPolicy: NotificationPolicyType, index: number) => (
|
||||
<NotificationPolicy
|
||||
// @ts-ignore
|
||||
userAction={userAction}
|
||||
key={notificationPolicy.id}
|
||||
index={index}
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ export const PluginConfigPage = (props: Props) => {
|
|||
<VerticalGroup>
|
||||
<Text type="secondary">
|
||||
Run hobby, dev or production backend:{' '}
|
||||
<a href="https://github.com/grafana/oncall#getting-started" target="_blank">
|
||||
<a href="https://github.com/grafana/oncall#getting-started" target="_blank" rel="noreferrer">
|
||||
<Text type="link">getting started.</Text>
|
||||
</a>
|
||||
</Text>
|
||||
|
|
@ -259,15 +259,15 @@ export const PluginConfigPage = (props: Props) => {
|
|||
<Text type="secondary">
|
||||
Need help?
|
||||
<br />- Talk to the OnCall team in the #grafana-oncall channel at{' '}
|
||||
<a href="https://slack.grafana.com/" target="_blank">
|
||||
<a href="https://slack.grafana.com/" target="_blank" rel="noreferrer">
|
||||
<Text type="link">Slack</Text>
|
||||
</a>
|
||||
<br />- Ask questions at{' '}
|
||||
<a href="https://github.com/grafana/oncall/discussions/categories/q-a" target="_blank">
|
||||
<a href="https://github.com/grafana/oncall/discussions/categories/q-a" target="_blank" rel="noreferrer">
|
||||
<Text type="link">GitHub Discussions</Text>
|
||||
</a>{' '}
|
||||
or file bugs at{' '}
|
||||
<a href="https://github.com/grafana/oncall/issues" target="_blank">
|
||||
<a href="https://github.com/grafana/oncall/issues" target="_blank" rel="noreferrer">
|
||||
<Text type="link">GitHub Issues</Text>
|
||||
</a>
|
||||
</Text>
|
||||
|
|
@ -285,7 +285,7 @@ Seek for such a line: “Your invite token: <<LONG TOKEN>> , use it in the Graf
|
|||
>
|
||||
<>
|
||||
<Input id="onCallInvitationToken" onChange={handleInvitationTokenChange} />
|
||||
<a href="https://github.com/grafana/oncall/blob/dev/DEVELOPER.md#frontend-setup" target="_blank">
|
||||
<a href="https://github.com/grafana/oncall/blob/dev/DEVELOPER.md#frontend-setup" target="_blank" rel="noreferrer">
|
||||
<Text size="small" type="link">
|
||||
How to re-issue the invite token?
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ const TelegramModal = (props: TelegramModalProps) => {
|
|||
<div className={cx('telegram-instruction-container')}>
|
||||
<Text>
|
||||
5. Click{' '}
|
||||
<a className={cx('telegram-bot')} href={botLink} target="_blank">
|
||||
<a className={cx('telegram-bot')} href={botLink} target="_blank" rel="noreferrer">
|
||||
{botLink}
|
||||
</a>{' '}
|
||||
to add the OnCall bot to your contacts. Add the bot to your channel as an Admin. Allow it to{' '}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const TelegramInfo = observer((props: TelegramInfoProps) => {
|
|||
<>
|
||||
{telegramConfigured || !store.hasFeature(AppFeature.LiveSettings) ? (
|
||||
<VerticalGroup>
|
||||
<a href={`${botLink}/?start=${verificationCode}`} target="_blank">
|
||||
<a href={`${botLink}/?start=${verificationCode}`} target="_blank" rel="noreferrer">
|
||||
<Button size="sm" fill="outline">
|
||||
Connect automatically
|
||||
</Button>
|
||||
|
|
@ -46,7 +46,7 @@ const TelegramInfo = observer((props: TelegramInfoProps) => {
|
|||
<HorizontalGroup>
|
||||
<Text>
|
||||
1) Go to{' '}
|
||||
<a className={cx('verification-code')} href={botLink} target="_blank">
|
||||
<a className={cx('verification-code')} href={botLink} target="_blank" rel="noreferrer">
|
||||
{botLink}
|
||||
</a>
|
||||
</Text>
|
||||
|
|
|
|||
5
grafana-plugin/src/index.d.ts
vendored
5
grafana-plugin/src/index.d.ts
vendored
|
|
@ -11,3 +11,8 @@ declare module '*.css';
|
|||
declare module '*.jpg';
|
||||
declare module '*.png';
|
||||
declare module '*.svg';
|
||||
|
||||
declare module '*.scss' {
|
||||
const content: Record<string, string>;
|
||||
export default content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
|
|||
Copy Link
|
||||
</Button>
|
||||
</CopyToClipboard>
|
||||
<a href={incident.permalink} target="_blank">
|
||||
<a href={incident.permalink} target="_blank" rel="noreferrer">
|
||||
<Button variant="primary" size="sm" icon="slack">
|
||||
View in Slack
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { IconButton, ValuePicker, WithContextMenu, ButtonCascader } from '@grafana/ui';
|
||||
import { ButtonCascader } from '@grafana/ui';
|
||||
import { ComponentSize } from '@grafana/ui/types/size';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
|
||||
|
|
@ -19,7 +20,7 @@ const SilenceDropdown = observer((props: SilenceDropdownProps) => {
|
|||
const { onSelect, className, disabled = false, buttonSize } = props;
|
||||
|
||||
const onSelectCallback = useCallback(
|
||||
([value, ...rest]) => {
|
||||
([value]) => {
|
||||
onSelect(Number(value));
|
||||
},
|
||||
[onSelect]
|
||||
|
|
@ -44,7 +45,7 @@ const SilenceDropdown = observer((props: SilenceDropdownProps) => {
|
|||
label: silenceOption.display_name,
|
||||
}))}
|
||||
value={undefined}
|
||||
buttonProps={{ size: buttonSize }}
|
||||
buttonProps={{ size: buttonSize as ComponentSize }}
|
||||
>
|
||||
Silence
|
||||
</ButtonCascader>
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class MigrationToolPage extends React.Component<MigrationToolProps, MigrationToo
|
|||
<ol>
|
||||
<li>
|
||||
Ask all users from your Amixr.IO workspace to{' '}
|
||||
<a href="https://grafana.com/auth/sign-up/create-user" target="_blank">
|
||||
<a href="https://grafana.com/auth/sign-up/create-user" target="_blank" rel="noreferrer">
|
||||
sign up
|
||||
</a>{' '}
|
||||
in the Grafana Cloud.
|
||||
|
|
@ -101,7 +101,7 @@ class MigrationToolPage extends React.Component<MigrationToolProps, MigrationToo
|
|||
</p>
|
||||
<p>
|
||||
For any technical assistance please reach out to our team in{' '}
|
||||
<a href="https://slack.grafana.com/" target="_blank">
|
||||
<a href="https://slack.grafana.com/" target="_blank" rel="noreferrer">
|
||||
Grafana Slack channel #grafana-oncall
|
||||
</a>
|
||||
. We’ll be happy to give you a hand and help you with migration on a call.
|
||||
|
|
@ -112,13 +112,13 @@ class MigrationToolPage extends React.Component<MigrationToolProps, MigrationToo
|
|||
<ul>
|
||||
<li>
|
||||
Matvey Kukuy (ex-CEO of Amixr):{' '}
|
||||
<a href="mailto:matvey.kukuy@grafana.com" target="_blank">
|
||||
<a href="mailto:matvey.kukuy@grafana.com" target="_blank" rel="noreferrer">
|
||||
matvey.kukuy@grafana.com
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Ildar Iskhakov (ex-CTO of Amixr):{' '}
|
||||
<a href="mailto:ildar.iskhakov@grafana.com" target="_blank">
|
||||
<a href="mailto:ildar.iskhakov@grafana.com" target="_blank" rel="noreferrer">
|
||||
ildar.iskhakov@grafana.com
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
import { Moment } from 'moment';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
import { Schedule } from 'models/schedule/schedule.types';
|
||||
|
||||
const DATE_FORMAT = 'HH:mm YYYY-MM-DD';
|
||||
|
||||
function isToday(m: Moment, currentMoment: Moment) {
|
||||
function isToday(m: moment.Moment) {
|
||||
return m.isSame('day');
|
||||
}
|
||||
|
||||
function isYesterday(m: Moment, currentMoment: Moment) {
|
||||
function isYesterday(m: moment.Moment, currentMoment: moment.Moment) {
|
||||
return m.diff(currentMoment, 'days') === -1;
|
||||
}
|
||||
|
||||
function isTomorrow(m: Moment, currentMoment: Moment) {
|
||||
function isTomorrow(m: moment.Moment, currentMoment: moment.Moment) {
|
||||
return m.diff(currentMoment, 'days') === 1;
|
||||
}
|
||||
|
||||
|
|
@ -25,8 +24,8 @@ export function prepareForEdit(schedule: Schedule) {
|
|||
};
|
||||
}
|
||||
|
||||
function humanize(m: Moment, currentMoment: Moment) {
|
||||
if (isToday(m, currentMoment)) {
|
||||
function humanize(m: moment.Moment, currentMoment: moment.Moment) {
|
||||
if (isToday(m)) {
|
||||
return 'Today';
|
||||
}
|
||||
if (isYesterday(m, currentMoment)) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
:root {
|
||||
--maintenance-background: repeating-linear-gradient(45deg, #f6ba52, #f6ba52 20px, #ffd180 20px, #ffd180 40px);
|
||||
--gren-5: #6ccf8e;
|
||||
--green-6: #73d13d;
|
||||
--red-5: #ff4d4f;
|
||||
--orange-5: #ffa940;
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@
|
|||
"noUnusedLocals": false,
|
||||
"strict": false,
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitAny": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
|
||||
const CircularDependencyPlugin = require('circular-dependency-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
const MONACO_DIR = path.resolve(__dirname, './node_modules/monaco-editor');
|
||||
|
||||
|
|
@ -13,20 +11,78 @@ Object.defineProperty(RegExp.prototype, 'toJSON', {
|
|||
|
||||
module.exports.getWebpackConfig = (config, options) => {
|
||||
const cssLoader = config.module.rules.find((rule) => rule.test.toString() === '/\\.css$/');
|
||||
const tsxLoader = config.module.rules.find((rule) => rule.test.toString() === '/\\.tsx?$/');
|
||||
|
||||
cssLoader.exclude.push(/\.module\.css$/, MONACO_DIR);
|
||||
|
||||
const grafanaRules = config.module.rules.filter((a) => a.test.toString() !== /\.s[ac]ss$/.toString());
|
||||
|
||||
const newConfig = {
|
||||
...config,
|
||||
module: {
|
||||
...config.module,
|
||||
rules: [
|
||||
...config.module.rules,
|
||||
...grafanaRules,
|
||||
|
||||
{
|
||||
test: /\.(ts|tsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
cacheCompression: false,
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
'@babel/preset-typescript',
|
||||
{
|
||||
allowNamespaces: true,
|
||||
allowDeclareFields: true,
|
||||
},
|
||||
],
|
||||
['@babel/preset-react'],
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
'@babel/plugin-transform-typescript',
|
||||
{
|
||||
allowNamespaces: true,
|
||||
allowDeclareFields: true,
|
||||
},
|
||||
],
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
[
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
{
|
||||
loose: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
'@babel/plugin-proposal-decorators',
|
||||
{
|
||||
legacy: true,
|
||||
},
|
||||
],
|
||||
'@babel/plugin-transform-react-constant-elements',
|
||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
],
|
||||
},
|
||||
},
|
||||
'ts-loader',
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.module\.css$/,
|
||||
exclude: /node_modules/,
|
||||
//use: ['style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader'],
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
|
|
@ -41,8 +97,29 @@ module.exports.getWebpackConfig = (config, options) => {
|
|||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.module\.scss$/i,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
sourceMap: true,
|
||||
modules: {
|
||||
localIdentName: options.production ? '[name]__[hash:base64]' : '[path][name]__[local]',
|
||||
},
|
||||
},
|
||||
},
|
||||
'postcss-loader',
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
...config.plugins,
|
||||
new CircularDependencyPlugin({
|
||||
|
|
@ -56,9 +133,10 @@ module.exports.getWebpackConfig = (config, options) => {
|
|||
allowAsyncCycles: false,
|
||||
// set the current working directory for displaying module paths
|
||||
cwd: process.cwd(),
|
||||
}),
|
||||
//new BundleAnalyzerPlugin(),
|
||||
})
|
||||
// new BundleAnalyzerPlugin(),
|
||||
],
|
||||
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
symlinks: false,
|
||||
|
|
@ -66,7 +144,7 @@ module.exports.getWebpackConfig = (config, options) => {
|
|||
},
|
||||
};
|
||||
|
||||
/* fs.writeFile('webpack-conf.json', JSON.stringify(newConfig.resolve, null, 2), function (err) {
|
||||
/* fs.writeFile('webpack-conf.json', JSON.stringify(newConfig, null, 2), function (err) {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
|
|
|
|||
14467
grafana-plugin/yarn.lock
14467
grafana-plugin/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue