mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[kibana_react] Clean up any
in public non-test files (#111261)
* first pass at any cleanup * fix types on TableListView * change generic constraint * fix lint * fix TS in no data card Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
6980064e5e
commit
0af821aaf9
16 changed files with 129 additions and 117 deletions
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiLink, EuiButton, EuiEmptyPrompt } from '@elastic/eui';
|
||||
import { EuiLink, EuiButton, EuiEmptyPrompt, EuiBasicTableColumn } from '@elastic/eui';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { attemptLoadDashboardByTitle } from '../lib';
|
||||
import { DashboardAppServices, DashboardRedirect } from '../../types';
|
||||
|
@ -231,7 +231,7 @@ const getTableColumns = (
|
|||
sortable: true,
|
||||
},
|
||||
...(savedObjectsTagging ? [savedObjectsTagging.ui.getTableColumnDefinition()] : []),
|
||||
];
|
||||
] as unknown as Array<EuiBasicTableColumn<Record<string, unknown>>>;
|
||||
};
|
||||
|
||||
const getNoItemsMessage = (
|
||||
|
|
|
@ -75,20 +75,6 @@ const Demo = ({ kibana }) => {
|
|||
export default withKibana(Demo);
|
||||
```
|
||||
|
||||
Using `<UseKibana>` render prop.
|
||||
|
||||
```tsx
|
||||
import { UseKibana } from 'kibana-react';
|
||||
|
||||
const Demo = () => {
|
||||
return (
|
||||
<UseKibana>
|
||||
{(kibana) => <div>{kibana.services.uiSettings.get('theme:darkMode') ? 'dark' : 'light'}</div>}
|
||||
</UseKibana>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## `uiSettings` service
|
||||
|
||||
Wrappers around Core's `uiSettings` service.
|
||||
|
|
|
@ -9,9 +9,9 @@ import React, { useEffect, KeyboardEventHandler } from 'react';
|
|||
import { monaco } from '@kbn/monaco';
|
||||
|
||||
function createEditorInstance() {
|
||||
const keyDownListeners: any[] = [];
|
||||
const didShowListeners: any[] = [];
|
||||
const didHideListeners: any[] = [];
|
||||
const keyDownListeners: Array<(e?: unknown) => void> = [];
|
||||
const didShowListeners: Array<(e?: unknown) => void> = [];
|
||||
const didHideListeners: Array<(e?: unknown) => void> = [];
|
||||
let areSuggestionsVisible = false;
|
||||
|
||||
const editorInstance = {
|
||||
|
@ -69,7 +69,10 @@ type MockedEditor = ReturnType<typeof createEditorInstance>;
|
|||
export const mockedEditorInstance: MockedEditor = createEditorInstance();
|
||||
|
||||
// <MonacoEditor /> mock
|
||||
const mockMonacoEditor = ({ editorWillMount, editorDidMount }: any) => {
|
||||
const mockMonacoEditor = ({
|
||||
editorWillMount,
|
||||
editorDidMount,
|
||||
}: Record<string, (...args: unknown[]) => void>) => {
|
||||
editorWillMount(monaco);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -135,7 +135,9 @@ export const CodeEditor: React.FC<Props> = ({
|
|||
const MonacoEditor: typeof ReactMonacoEditor = useMemo(() => {
|
||||
const isMockedComponent =
|
||||
typeof ReactMonacoEditor === 'function' && ReactMonacoEditor.name === 'JestMockEditor';
|
||||
return isMockedComponent ? (ReactMonacoEditor as any)() : ReactMonacoEditor;
|
||||
return isMockedComponent
|
||||
? (ReactMonacoEditor as unknown as () => typeof ReactMonacoEditor)()
|
||||
: ReactMonacoEditor;
|
||||
}, []);
|
||||
|
||||
const isReadOnly = options?.readOnly ?? false;
|
||||
|
|
|
@ -26,7 +26,7 @@ export const useKibana = <Extra extends object = {}>(): KibanaReactContextValue<
|
|||
> =>
|
||||
useContext(context as unknown as React.Context<KibanaReactContextValue<KibanaServices & Extra>>);
|
||||
|
||||
export const withKibana = <Props extends { kibana: KibanaReactContextValue<any> }>(
|
||||
export const withKibana = <Props extends { kibana: KibanaReactContextValue<{}> }>(
|
||||
type: React.ComponentType<Props>
|
||||
): React.FC<Omit<Props, 'kibana'>> => {
|
||||
const EnhancedType: React.FC<Omit<Props, 'kibana'>> = (props: Omit<Props, 'kibana'>) => {
|
||||
|
@ -36,10 +36,6 @@ export const withKibana = <Props extends { kibana: KibanaReactContextValue<any>
|
|||
return EnhancedType;
|
||||
};
|
||||
|
||||
export const UseKibana: React.FC<{
|
||||
children: (kibana: KibanaReactContextValue<any>) => React.ReactNode;
|
||||
}> = ({ children }) => <>{children(useKibana())}</>;
|
||||
|
||||
export const createKibanaReactContext = <Services extends KibanaServices>(
|
||||
services: Services
|
||||
): KibanaReactContext<Services> => {
|
||||
|
@ -58,7 +54,7 @@ export const createKibanaReactContext = <Services extends KibanaServices>(
|
|||
() => createKibanaReactContext({ ...services, ...oldValue.services, ...newServices }),
|
||||
[services, oldValue, newServices]
|
||||
);
|
||||
return createElement(context.Provider as React.ComponentType<any>, {
|
||||
return createElement(context.Provider, {
|
||||
value: newValue,
|
||||
children,
|
||||
});
|
||||
|
|
|
@ -12,6 +12,5 @@ export {
|
|||
KibanaContextProvider,
|
||||
useKibana,
|
||||
withKibana,
|
||||
UseKibana,
|
||||
} from './context';
|
||||
export { KibanaReactContext, KibanaReactContextValue, KibanaServices } from './types';
|
||||
|
|
|
@ -26,6 +26,7 @@ export const ElasticAgentCard: FunctionComponent<ElasticAgentCardProps> = ({
|
|||
title,
|
||||
href,
|
||||
button,
|
||||
layout,
|
||||
...cardRest
|
||||
}) => {
|
||||
const {
|
||||
|
@ -58,7 +59,8 @@ export const ElasticAgentCard: FunctionComponent<ElasticAgentCardProps> = ({
|
|||
image={addBasePath(`${basePathUrl}elastic_agent_card.svg`)}
|
||||
betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined}
|
||||
footer={footer}
|
||||
{...(cardRest as any)}
|
||||
layout={layout as 'vertical' | undefined}
|
||||
{...cardRest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ export const ElasticBeatsCard: FunctionComponent<ElasticBeatsCardProps> = ({
|
|||
button,
|
||||
href,
|
||||
solution, // unused for now
|
||||
layout,
|
||||
...cardRest
|
||||
}) => {
|
||||
const {
|
||||
|
@ -58,7 +59,8 @@ export const ElasticBeatsCard: FunctionComponent<ElasticBeatsCardProps> = ({
|
|||
)}
|
||||
betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined}
|
||||
footer={footer}
|
||||
{...(cardRest as any)}
|
||||
layout={layout as 'vertical' | undefined}
|
||||
{...cardRest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { EuiButton, EuiCard, EuiCardProps } from '@elastic/eui';
|
||||
import { NoDataPageActions, NO_DATA_RECOMMENDED } from '../no_data_page';
|
||||
|
@ -17,6 +18,7 @@ export const NoDataCard: FunctionComponent<NoDataPageActions> = ({
|
|||
recommended,
|
||||
title,
|
||||
button,
|
||||
layout,
|
||||
...cardRest
|
||||
}) => {
|
||||
const footer =
|
||||
|
@ -25,10 +27,16 @@ export const NoDataCard: FunctionComponent<NoDataPageActions> = ({
|
|||
return (
|
||||
<EuiCard
|
||||
paddingSize="l"
|
||||
title={title}
|
||||
// TODO: we should require both title and description to be passed in by consumers since defaults are not adequate.
|
||||
// see comment: https://github.com/elastic/kibana/pull/111261/files#r708399140
|
||||
title={title!}
|
||||
description={i18n.translate('kibana-react.noDataPage.noDataCard.description', {
|
||||
defaultMessage: `Proceed without collecting data`,
|
||||
})}
|
||||
betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined}
|
||||
footer={footer}
|
||||
{...(cardRest as any)}
|
||||
layout={layout as 'vertical' | undefined}
|
||||
{...cardRest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { ScopedHistory } from 'kibana/public';
|
||||
import { MouseEvent } from 'react';
|
||||
import { History, parsePath } from 'history';
|
||||
|
||||
interface LocationObject {
|
||||
|
@ -15,10 +16,10 @@ interface LocationObject {
|
|||
hash?: string;
|
||||
}
|
||||
|
||||
const isModifiedEvent = (event: any) =>
|
||||
const isModifiedEvent = (event: MouseEvent) =>
|
||||
!!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
||||
|
||||
const isLeftClickEvent = (event: any) => event.button === 0;
|
||||
const isLeftClickEvent = (event: MouseEvent) => event.button === 0;
|
||||
|
||||
export const toLocationObject = (to: string | LocationObject) =>
|
||||
typeof to === 'string' ? parsePath(to) : to;
|
||||
|
@ -34,7 +35,7 @@ export const reactRouterNavigate = (
|
|||
|
||||
export const reactRouterOnClickHandler =
|
||||
(history: ScopedHistory | History, to: string | LocationObject, onClickCallback?: Function) =>
|
||||
(event: any) => {
|
||||
(event: MouseEvent) => {
|
||||
if (onClickCallback) {
|
||||
onClickCallback(event);
|
||||
}
|
||||
|
@ -43,7 +44,9 @@ export const reactRouterOnClickHandler =
|
|||
return;
|
||||
}
|
||||
|
||||
if (event.target.getAttribute('target')) {
|
||||
if (
|
||||
(event.target as unknown as { getAttribute: (a: string) => unknown })?.getAttribute('target')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export interface Props {
|
|||
children: ReactNode;
|
||||
className?: string;
|
||||
resizerClassName?: string;
|
||||
onPanelWidthChange?: (arrayOfPanelWidths: number[]) => any;
|
||||
onPanelWidthChange?: (arrayOfPanelWidths: number[]) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { PanelRegistry } from './registry';
|
|||
const PanelContext = createContext({ registry: new PanelRegistry() });
|
||||
|
||||
interface ContextProps {
|
||||
children: any;
|
||||
children: JSX.Element;
|
||||
registry: PanelRegistry;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,17 +26,13 @@ import React from 'react';
|
|||
import { KibanaPageTemplate } from '../page_template';
|
||||
import { toMountPoint } from '../util';
|
||||
|
||||
interface Item {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export interface TableListViewProps {
|
||||
export interface TableListViewProps<V> {
|
||||
createItem?(): void;
|
||||
deleteItems?(items: object[]): Promise<void>;
|
||||
editItem?(item: object): void;
|
||||
deleteItems?(items: V[]): Promise<void>;
|
||||
editItem?(item: V): void;
|
||||
entityName: string;
|
||||
entityNamePlural: string;
|
||||
findItems(query: string): Promise<{ total: number; hits: object[] }>;
|
||||
findItems(query: string): Promise<{ total: number; hits: V[] }>;
|
||||
listingLimit: number;
|
||||
initialFilter: string;
|
||||
initialPageSize: number;
|
||||
|
@ -44,7 +40,7 @@ export interface TableListViewProps {
|
|||
* Should be an EuiEmptyPrompt (but TS doesn't support this typing)
|
||||
*/
|
||||
emptyPrompt?: JSX.Element;
|
||||
tableColumns: Array<EuiBasicTableColumn<any>>;
|
||||
tableColumns: Array<EuiBasicTableColumn<V>>;
|
||||
tableListTitle: string;
|
||||
toastNotifications: ToastsStart;
|
||||
/**
|
||||
|
@ -63,8 +59,8 @@ export interface TableListViewProps {
|
|||
searchFilters?: SearchFilterConfig[];
|
||||
}
|
||||
|
||||
export interface TableListViewState {
|
||||
items: object[];
|
||||
export interface TableListViewState<V> {
|
||||
items: V[];
|
||||
hasInitialFetchReturned: boolean;
|
||||
isFetchingItems: boolean;
|
||||
isDeletingItems: boolean;
|
||||
|
@ -81,11 +77,14 @@ export interface TableListViewState {
|
|||
// and not supporting server-side paging.
|
||||
// This component does not try to tackle these problems (yet) and is just feature matching the legacy component
|
||||
// TODO support server side sorting/paging once title and description are sortable on the server.
|
||||
class TableListView extends React.Component<TableListViewProps, TableListViewState> {
|
||||
class TableListView<V extends {}> extends React.Component<
|
||||
TableListViewProps<V>,
|
||||
TableListViewState<V>
|
||||
> {
|
||||
private pagination = {};
|
||||
private _isMounted = false;
|
||||
|
||||
constructor(props: TableListViewProps) {
|
||||
constructor(props: TableListViewProps<V>) {
|
||||
super(props);
|
||||
|
||||
this.pagination = {
|
||||
|
@ -134,7 +133,7 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
|
|||
this.setState({
|
||||
hasInitialFetchReturned: true,
|
||||
isFetchingItems: false,
|
||||
items: !filter ? sortBy(response.hits, 'title') : response.hits,
|
||||
items: !filter ? sortBy<V>(response.hits, 'title') : response.hits,
|
||||
totalItems: response.total,
|
||||
showLimitError: response.total > this.props.listingLimit,
|
||||
});
|
||||
|
@ -404,17 +403,17 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
|
|||
|
||||
const selection = this.props.deleteItems
|
||||
? {
|
||||
onSelectionChange: (obj: Item[]) => {
|
||||
onSelectionChange: (obj: V[]) => {
|
||||
this.setState({
|
||||
selectedIds: obj
|
||||
.map((item) => item.id)
|
||||
.filter((id: undefined | string): id is string => Boolean(id)),
|
||||
.map((item) => (item as Record<string, undefined | string>)?.id)
|
||||
.filter((id): id is string => Boolean(id)),
|
||||
});
|
||||
},
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const actions: EuiTableActionsColumnType<any>['actions'] = [
|
||||
const actions: EuiTableActionsColumnType<V>['actions'] = [
|
||||
{
|
||||
name: i18n.translate('kibana-react.tableListView.listing.table.editActionName', {
|
||||
defaultMessage: 'Edit',
|
||||
|
@ -427,7 +426,7 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
|
|||
),
|
||||
icon: 'pencil',
|
||||
type: 'icon',
|
||||
enabled: ({ error }: { error: string }) => !error,
|
||||
enabled: (v) => !(v as unknown as { error: string })?.error,
|
||||
onClick: this.props.editItem,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -60,12 +60,12 @@ export const MountPointPortal: React.FC<MountPointPortalProps> = ({ children, se
|
|||
}
|
||||
};
|
||||
|
||||
class MountPointPortalErrorBoundary extends Component<{}, { error?: any }> {
|
||||
class MountPointPortalErrorBoundary extends Component<{}, { error?: unknown }> {
|
||||
state = {
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
static getDerivedStateFromError(error: any) {
|
||||
static getDerivedStateFromError(error: unknown) {
|
||||
return { error };
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export function test(value: any) {
|
||||
export function test(value?: Record<string, unknown>) {
|
||||
return value && value.__reactMount__;
|
||||
}
|
||||
|
||||
export function print(value: any, serialize: any) {
|
||||
export function print(
|
||||
value: Record<string, unknown>,
|
||||
serialize: (args: Record<string, unknown>) => { replace: (s1: string, s2: string) => unknown }
|
||||
) {
|
||||
// there is no proper way to correctly indent multiline values
|
||||
// so the trick here is to use the Object representation and rewriting the root object name
|
||||
return serialize({
|
||||
|
|
|
@ -8,7 +8,15 @@
|
|||
|
||||
import React from 'react';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { EuiBetaBadge, EuiButton, EuiEmptyPrompt, EuiIcon, EuiLink, EuiBadge } from '@elastic/eui';
|
||||
import {
|
||||
EuiBetaBadge,
|
||||
EuiButton,
|
||||
EuiEmptyPrompt,
|
||||
EuiIcon,
|
||||
EuiLink,
|
||||
EuiBadge,
|
||||
EuiBasicTableColumn,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { ApplicationStart } from 'kibana/public';
|
||||
|
@ -86,61 +94,62 @@ export const getTableColumns = (
|
|||
application: ApplicationStart,
|
||||
kbnUrlStateStorage: IKbnUrlStateStorage,
|
||||
taggingApi?: SavedObjectsTaggingApi
|
||||
) => [
|
||||
{
|
||||
field: 'title',
|
||||
name: i18n.translate('visualize.listing.table.titleColumnName', {
|
||||
defaultMessage: 'Title',
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field: string, { editApp, editUrl, title, error, type }: VisualizationListItem) =>
|
||||
// In case an error occurs i.e. the vis has wrong type, we render the vis but without the link
|
||||
!error ? (
|
||||
<RedirectAppLinks application={application} className="visListingTable__titleLink">
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiLink
|
||||
href={getVisualizeListItemLink(application, kbnUrlStateStorage, editApp, editUrl)}
|
||||
onClick={() => {
|
||||
doTelemetryForAddEvent(typeof type === 'string' ? type : type?.name);
|
||||
}}
|
||||
data-test-subj={`visListingTitleLink-${title.split(' ').join('-')}`}
|
||||
>
|
||||
{field}
|
||||
</EuiLink>
|
||||
</RedirectAppLinks>
|
||||
) : (
|
||||
field
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'typeTitle',
|
||||
name: i18n.translate('visualize.listing.table.typeColumnName', {
|
||||
defaultMessage: 'Type',
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field: string, record: VisualizationListItem) =>
|
||||
!record.error ? (
|
||||
<span>
|
||||
{renderItemTypeIcon(record)}
|
||||
{record.typeTitle}
|
||||
{getBadge(record)}
|
||||
</span>
|
||||
) : (
|
||||
<EuiBadge iconType="alert" color="warning">
|
||||
{record.error}
|
||||
</EuiBadge>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'description',
|
||||
name: i18n.translate('visualize.listing.table.descriptionColumnName', {
|
||||
defaultMessage: 'Description',
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field: string, record: VisualizationListItem) => <span>{record.description}</span>,
|
||||
},
|
||||
...(taggingApi ? [taggingApi.ui.getTableColumnDefinition()] : []),
|
||||
];
|
||||
) =>
|
||||
[
|
||||
{
|
||||
field: 'title',
|
||||
name: i18n.translate('visualize.listing.table.titleColumnName', {
|
||||
defaultMessage: 'Title',
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field: string, { editApp, editUrl, title, error, type }: VisualizationListItem) =>
|
||||
// In case an error occurs i.e. the vis has wrong type, we render the vis but without the link
|
||||
!error ? (
|
||||
<RedirectAppLinks application={application} className="visListingTable__titleLink">
|
||||
{/* eslint-disable-next-line @elastic/eui/href-or-on-click */}
|
||||
<EuiLink
|
||||
href={getVisualizeListItemLink(application, kbnUrlStateStorage, editApp, editUrl)}
|
||||
onClick={() => {
|
||||
doTelemetryForAddEvent(typeof type === 'string' ? type : type?.name);
|
||||
}}
|
||||
data-test-subj={`visListingTitleLink-${title.split(' ').join('-')}`}
|
||||
>
|
||||
{field}
|
||||
</EuiLink>
|
||||
</RedirectAppLinks>
|
||||
) : (
|
||||
field
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'typeTitle',
|
||||
name: i18n.translate('visualize.listing.table.typeColumnName', {
|
||||
defaultMessage: 'Type',
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field: string, record: VisualizationListItem) =>
|
||||
!record.error ? (
|
||||
<span>
|
||||
{renderItemTypeIcon(record)}
|
||||
{record.typeTitle}
|
||||
{getBadge(record)}
|
||||
</span>
|
||||
) : (
|
||||
<EuiBadge iconType="alert" color="warning">
|
||||
{record.error}
|
||||
</EuiBadge>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'description',
|
||||
name: i18n.translate('visualize.listing.table.descriptionColumnName', {
|
||||
defaultMessage: 'Description',
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field: string, record: VisualizationListItem) => <span>{record.description}</span>,
|
||||
},
|
||||
...(taggingApi ? [taggingApi.ui.getTableColumnDefinition()] : []),
|
||||
] as unknown as Array<EuiBasicTableColumn<Record<string, unknown>>>;
|
||||
|
||||
export const getNoItemsMessage = (createItem: () => void) => (
|
||||
<EuiEmptyPrompt
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue