types improvements (#4945)
# What this PR does
- Fix some types errors when OnCall type checking runs under IRM
- Make type check required on CI
## Checklist
- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
show up in the autogenerated release notes.
This commit is contained in:
parent
4aef7b231a
commit
0b6fa6ad1d
14 changed files with 90 additions and 1084 deletions
2
.github/workflows/linting-and-tests.yml
vendored
2
.github/workflows/linting-and-tests.yml
vendored
|
|
@ -35,7 +35,7 @@ jobs:
|
|||
uses: ./.github/actions/install-frontend-dependencies
|
||||
- name: Build, lint and test frontend
|
||||
working-directory: grafana-plugin
|
||||
run: yarn lint && yarn test && yarn build
|
||||
run: yarn lint && yarn type-check && yarn test && yarn build
|
||||
|
||||
test-technical-documentation:
|
||||
name: "Test technical documentation"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ test('Integrations table shows data in Monitoring Systems and Direct Paging tabs
|
|||
await goToOnCallPage(page, 'integrations');
|
||||
|
||||
// Create 1 Direct Paging integration if it doesn't exist
|
||||
await page.getByRole('tab', { name: 'Tab Manual Direct Paging' }).click();
|
||||
await page.getByText('Manual Direct Paging').click();
|
||||
const integrationsTable = page.getByTestId('integrations-table');
|
||||
await page.waitForTimeout(2000);
|
||||
const isDirectPagingAlreadyCreated = (await integrationsTable.getByText('Direct paging').count()) >= 1;
|
||||
|
|
@ -52,7 +52,7 @@ test('Integrations table shows data in Monitoring Systems and Direct Paging tabs
|
|||
});
|
||||
|
||||
// Then after switching to Direct Paging tab only Direct Paging integration is visible
|
||||
await page.getByRole('tab', { name: 'Tab Manual Direct Paging' }).click();
|
||||
await page.getByText('Manual Direct Paging').click();
|
||||
await searchIntegrationAndAssertItsPresence({
|
||||
page,
|
||||
integrationName: WEBHOOK_INTEGRATION_NAME,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
"version": "1.0.0",
|
||||
"description": "Grafana OnCall Plugin",
|
||||
"scripts": {
|
||||
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx --max-warnings=0 ./src ./e2e-tests",
|
||||
"lint:fix": "eslint --max-warnings=0 --fix --cache --ext .js,.jsx,.ts,.tsx ./src ./e2e-tests",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx --max-warnings=20 ./src ./e2e-tests",
|
||||
"lint:fix": "eslint --max-warnings=20 --fix --ext .js,.jsx,.ts,.tsx ./src ./e2e-tests",
|
||||
"stylelint": "stylelint ./src/**/*.{css,scss,module.css,module.scss}",
|
||||
"stylelint:fix": "stylelint --fix ./src/**/*.{css,scss,module.css,module.scss}",
|
||||
"build": "NODE_ENV=production webpack -c ./webpack.config.ts --env production",
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
"sign": "npx --yes @grafana/sign-plugin@latest",
|
||||
"start": "yarn watch",
|
||||
"setversion": "setversion",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"typecheck:watch": "yarn typecheck --watch --preserveWatchOutput false",
|
||||
"type-check": "tsc --noEmit",
|
||||
"type-check:watch": "yarn type-check --watch --preserveWatchOutput false",
|
||||
"find-dead-code": "knip"
|
||||
},
|
||||
"repository": {
|
||||
|
|
@ -72,8 +72,9 @@
|
|||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/query-string": "^6.3.0",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-dom": "18.2.0",
|
||||
"@types/react-responsive": "^8.0.5",
|
||||
"@types/react-test-renderer": "^18.0.5",
|
||||
"@types/react-transition-group": "^4.4.5",
|
||||
|
|
@ -104,7 +105,7 @@
|
|||
"lint-staged": "^10.2.11",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mailslurp-client": "^15.14.1",
|
||||
"moment-timezone": "^0.5.35",
|
||||
"moment-timezone": "0.5.45",
|
||||
"openapi-typescript": "^7.0.0-next.4",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"prettier": "^2.8.7",
|
||||
|
|
@ -135,7 +136,7 @@
|
|||
"@grafana/data": "^11.1.3",
|
||||
"@grafana/faro-web-sdk": "^1.4.2",
|
||||
"@grafana/faro-web-tracing": "^1.4.2",
|
||||
"@grafana/labels": "~1.5.1",
|
||||
"@grafana/labels": "~1.6.0",
|
||||
"@grafana/runtime": "^11.1.3",
|
||||
"@grafana/scenes": "^1.28.0",
|
||||
"@grafana/schema": "^11.1.3",
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ function DeclareIncidentMenuItem({ extensions, declareIncidentLink, grafanaIncid
|
|||
);
|
||||
}
|
||||
|
||||
function renderItems(extensions: Array<Partial<PluginExtensionLink>>): JSX.Element[] {
|
||||
function renderItems(extensions: Array<Partial<PluginExtensionLink>>): ReactElement[] {
|
||||
return extensions.map((extension) => (
|
||||
<Menu.Item
|
||||
ariaLabel={extension.title}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC, PropsWithChildren } from 'react';
|
||||
import React, { FC, PropsWithChildren, ReactElement } from 'react';
|
||||
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
|
@ -8,7 +8,7 @@ import ReactModal from 'react-modal';
|
|||
ReactModal.setAppElement('#reactRoot');
|
||||
|
||||
export interface ModalProps {
|
||||
title?: string | JSX.Element;
|
||||
title?: string | ReactElement;
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
closeOnEscape?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import React, { ReactElement, useEffect } from 'react';
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
|
@ -33,7 +33,7 @@ export const PageErrorHandlingWrapper = function ({
|
|||
pageName: string;
|
||||
itemNotFoundMessage?: string;
|
||||
children: () => React.ReactNode;
|
||||
}): JSX.Element {
|
||||
}): ReactElement {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { ReactElement } from 'react';
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
|
@ -7,8 +7,8 @@ interface ScheduleBorderedAvatarProps {
|
|||
colors: string[];
|
||||
width: number;
|
||||
height: number;
|
||||
renderAvatar: () => JSX.Element;
|
||||
renderIcon: () => JSX.Element;
|
||||
renderAvatar: () => ReactElement;
|
||||
renderIcon: () => ReactElement;
|
||||
}
|
||||
|
||||
export const ScheduleBorderedAvatar = function ({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { FC, HTMLAttributes, ChangeEvent, useState, useCallback } from 'react';
|
||||
|
||||
import { cx } from '@emotion/css';
|
||||
import { IconButton, Modal, Input, Button, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { IconButton, Modal, Input, Stack, Button, useStyles2 } from '@grafana/ui';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
|
||||
|
|
@ -31,13 +31,9 @@ interface TextProps extends HTMLAttributes<HTMLElement> {
|
|||
withBackground?: boolean;
|
||||
}
|
||||
|
||||
interface TextInterface extends React.FC<TextProps> {
|
||||
Title: React.FC<TitleProps>;
|
||||
}
|
||||
|
||||
const PLACEHOLDER = '**********';
|
||||
|
||||
export const Text: TextInterface = (props) => {
|
||||
export const Text: React.FC<TextProps> & { Title: typeof Title } = (props) => {
|
||||
const {
|
||||
type,
|
||||
size = 'medium',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { ReactElement, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
|
|
@ -13,7 +13,7 @@ interface TextEllipsisTooltipProps {
|
|||
queryClassName?: string;
|
||||
placement?: string;
|
||||
className?: string;
|
||||
children: JSX.Element | JSX.Element[];
|
||||
children: ReactElement | ReactElement[];
|
||||
}
|
||||
|
||||
export const TextEllipsisTooltip: React.FC<TextEllipsisTooltipProps> = ({
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import React, { ReactElement, useEffect, useState } from 'react';
|
||||
|
||||
import { ContextMenu } from '@grafana/ui';
|
||||
|
||||
export interface WithContextMenuProps {
|
||||
children: (props: { openMenu: React.MouseEventHandler<HTMLElement> }) => JSX.Element;
|
||||
children: (props: { openMenu: React.MouseEventHandler<HTMLElement> }) => ReactElement;
|
||||
renderMenuItems: ({ closeMenu }: { closeMenu?: () => void }) => React.ReactNode;
|
||||
isOpen?: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC } from 'react';
|
||||
import React, { FC, ReactElement } from 'react';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { PluginPage } from 'PluginPage';
|
||||
|
|
@ -28,7 +28,7 @@ export const DefaultPageLayout: FC<DefaultPageLayoutProps> = observer((props) =>
|
|||
|
||||
return renderLegacyNavbar();
|
||||
|
||||
function renderTopNavbar(): JSX.Element {
|
||||
function renderTopNavbar(): ReactElement {
|
||||
return (
|
||||
<PluginPage page={page} pageNav={pageNav as any}>
|
||||
<div className={cx('root')}>{children}</div>
|
||||
|
|
@ -36,7 +36,7 @@ export const DefaultPageLayout: FC<DefaultPageLayoutProps> = observer((props) =>
|
|||
);
|
||||
}
|
||||
|
||||
function renderLegacyNavbar(): JSX.Element {
|
||||
function renderLegacyNavbar(): ReactElement {
|
||||
return (
|
||||
<PluginPage page={page}>
|
||||
<div className="page-container u-height-100">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import React, { ReactElement, useEffect, useState } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Drawer, Field, Icon, Select, Stack } from '@grafana/ui';
|
||||
|
|
@ -138,4 +138,4 @@ const _IntegrationHeartbeatForm = observer(({ alertReceveChannelId, onClose }: I
|
|||
|
||||
export const IntegrationHeartbeatForm = withMobXProviderContext(_IntegrationHeartbeatForm) as ({
|
||||
alertReceveChannelId,
|
||||
}: IntegrationHeartbeatFormProps) => JSX.Element;
|
||||
}: IntegrationHeartbeatFormProps) => ReactElement;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Button, LoadingPlaceholder, Stack } from '@grafana/ui';
|
||||
import { Button, Stack, LoadingPlaceholder } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import { FullPageError } from 'components/FullPageError/FullPageError';
|
||||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
|
|
@ -36,7 +36,7 @@ export const PluginInitializer: FC<PluginInitializerProps> = observer(({ childre
|
|||
const PluginNotConnectedFullPageError = observer(() => {
|
||||
const isOpenSource = getIsRunningOpenSourceVersion();
|
||||
const isCurrentUserAdmin = window.grafanaBootData.user.orgRole === 'Admin';
|
||||
const { push } = useHistory();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const getSubtitleExtension = () => {
|
||||
if (!isOpenSource) {
|
||||
|
|
@ -62,7 +62,9 @@ const PluginNotConnectedFullPageError = observer(() => {
|
|||
Retry
|
||||
</Button>
|
||||
{!isOpenSource && <Button onClick={() => window.open(REQUEST_HELP_URL, '_blank')}>Request help</Button>}
|
||||
{isOpenSource && isCurrentUserAdmin && <Button onClick={() => push(PLUGIN_CONFIG)}>Open configuration</Button>}
|
||||
{isOpenSource && isCurrentUserAdmin && (
|
||||
<Button onClick={() => navigate(PLUGIN_CONFIG)}>Open configuration</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</FullPageError>
|
||||
);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue