AngularPanels: Move angular panel infra & components to angular/app folder (#40373)

* AngularPanels: Move to app/angular folder

* Fixing issues
This commit is contained in:
Torkel Ödegaard
2021-10-13 16:59:47 +02:00
committed by GitHub
parent 1505b8c0b0
commit c4ce7a40af
41 changed files with 38 additions and 34 deletions

View File

@@ -11,7 +11,7 @@ import { PanelPlugin, PanelPluginMeta } from '@grafana/data';
import { changePanelPlugin } from 'app/features/panel/state/actions';
import { StoreState } from 'app/types';
import { getSectionOpenState, saveSectionOpenState } from './state/utils';
import { PanelCtrl } from 'app/features/panel/panel_ctrl';
import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
import { getPanelStateForModel } from 'app/features/panel/state/selectors';
interface OwnProps {

View File

@@ -5,7 +5,11 @@ import { Button, CustomScrollbar, Icon, Input, RadioButtonGroup, useStyles } fro
import { changePanelPlugin } from '../../../panel/state/actions';
import { PanelModel } from '../../state/PanelModel';
import { useDispatch, useSelector } from 'react-redux';
import { filterPluginList, getAllPanelPluginMeta, VizTypePicker } from '../VizTypePicker/VizTypePicker';
import {
filterPluginList,
getAllPanelPluginMeta,
VizTypePicker,
} from '../../../panel/components/VizTypePicker/VizTypePicker';
import { Field } from '@grafana/ui/src/components/Forms/Field';
import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
import { toggleVizPicker } from './state/reducers';

View File

@@ -14,7 +14,7 @@ import { OptionPaneRenderProps } from './types';
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
import { DynamicConfigValueEditor } from './DynamicConfigValueEditor';
import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
import { getDataLinksVariableSuggestions } from 'app/angular/panel/panellinks/link_srv';
import { OverrideCategoryTitle } from './OverrideCategoryTitle';
import { css } from '@emotion/css';

View File

@@ -1,5 +1,5 @@
import { DataLinksInlineEditor, Input, RadioButtonGroup, Select, Switch, TextArea } from '@grafana/ui';
import { getPanelLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
import { getPanelLinksVariableSuggestions } from 'app/angular/panel/panellinks/link_srv';
import React from 'react';
import { RepeatRowSelect } from '../RepeatRowSelect/RepeatRowSelect';
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { StandardEditorContext, VariableSuggestionsScope } from '@grafana/data';
import { get as lodashGet } from 'lodash';
import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
import { getDataLinksVariableSuggestions } from 'app/angular/panel/panellinks/link_srv';
import { OptionPaneRenderProps } from './types';
import { updateDefaultFieldConfigValue, setOptionImmutably } from './utils';
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';

View File

@@ -2,7 +2,7 @@ import React, { FC } from 'react';
import { Icon, IconName, Tooltip, useForceUpdate } from '@grafana/ui';
import { sanitizeUrl } from '@grafana/data/src/text/sanitize';
import { DashboardLinksDashboard } from './DashboardLinksDashboard';
import { getLinkSrv } from '../../../panel/panellinks/link_srv';
import { getLinkSrv } from '../../../../angular/panel/panellinks/link_srv';
import { DashboardModel } from '../../state';
import { DashboardLink } from '../../state/DashboardModel';

View File

@@ -2,7 +2,7 @@ import React, { useRef, useState, useLayoutEffect } from 'react';
import { Icon, ToolbarButton, Tooltip, useStyles2 } from '@grafana/ui';
import { sanitize, sanitizeUrl } from '@grafana/data/src/text/sanitize';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getLinkSrv } from '../../../panel/panellinks/link_srv';
import { getLinkSrv } from '../../../../angular/panel/panellinks/link_srv';
import { DashboardLink } from '../../state/DashboardModel';
import { DashboardSearchHit } from 'app/features/search/types';
import { selectors } from '@grafana/e2e-selectors';

View File

@@ -1,153 +0,0 @@
import React, { MouseEventHandler } from 'react';
import { GrafanaTheme2, isUnsignedPluginSignature, PanelPluginMeta, PluginState } from '@grafana/data';
import { IconButton, PluginSignatureBadge, useStyles2 } from '@grafana/ui';
import { css, cx } from '@emotion/css';
import { selectors } from '@grafana/e2e-selectors';
import { PluginStateInfo } from 'app/features/plugins/PluginStateInfo';
interface Props {
isCurrent: boolean;
plugin: PanelPluginMeta;
title: string;
onClick: MouseEventHandler<HTMLDivElement>;
onDelete?: () => void;
disabled?: boolean;
showBadge?: boolean;
description?: string;
}
export const PanelTypeCard: React.FC<Props> = ({
isCurrent,
title,
plugin,
onClick,
onDelete,
disabled,
showBadge,
description,
children,
}) => {
const styles = useStyles2(getStyles);
const cssClass = cx({
[styles.item]: true,
[styles.disabled]: disabled || plugin.state === PluginState.deprecated,
[styles.current]: isCurrent,
});
return (
<div
className={cssClass}
aria-label={selectors.components.PluginVisualization.item(plugin.name)}
onClick={disabled ? undefined : onClick}
title={isCurrent ? 'Click again to close this section' : plugin.name}
>
<img className={styles.img} src={plugin.info.logos.small} alt="" />
<div className={styles.itemContent}>
<div className={styles.name}>{title}</div>
{description ? <span className={styles.description}>{description}</span> : null}
{children}
</div>
{showBadge && (
<div className={cx(styles.badge, disabled && styles.disabled)}>
<PanelPluginBadge plugin={plugin} />
</div>
)}
{onDelete && (
<IconButton
name="trash-alt"
onClick={(e) => {
e.stopPropagation();
onDelete();
}}
aria-label="Delete button on panel type card"
/>
)}
</div>
);
};
PanelTypeCard.displayName = 'PanelTypeCard';
const getStyles = (theme: GrafanaTheme2) => {
return {
item: css`
position: relative;
display: flex;
flex-shrink: 0;
cursor: pointer;
background: ${theme.colors.background.secondary};
border-radius: ${theme.shape.borderRadius()};
box-shadow: ${theme.shadows.z1};
border: 1px solid ${theme.colors.background.secondary};
align-items: center;
padding: 8px;
width: 100%;
position: relative;
overflow: hidden;
transition: ${theme.transitions.create(['background'], {
duration: theme.transitions.duration.short,
})};
&:hover {
background: ${theme.colors.emphasize(theme.colors.background.secondary, 0.03)};
}
`,
itemContent: css`
position: relative;
width: 100%;
padding: ${theme.spacing(0, 1)};
`,
current: css`
label: currentVisualizationItem;
border: 1px solid ${theme.colors.primary.border};
background: ${theme.colors.action.selected};
`,
disabled: css`
opacity: 0.2;
filter: grayscale(1);
cursor: default;
pointer-events: none;
`,
name: css`
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: ${theme.typography.size.sm};
font-weight: ${theme.typography.fontWeightMedium};
width: 100%;
`,
description: css`
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: ${theme.colors.text.secondary};
font-size: ${theme.typography.bodySmall.fontSize};
font-weight: ${theme.typography.fontWeightLight};
width: 100%;
`,
img: css`
max-height: 38px;
width: 38px;
display: flex;
align-items: center;
`,
badge: css`
background: ${theme.colors.background.primary};
`,
};
};
interface PanelPluginBadgeProps {
plugin: PanelPluginMeta;
}
const PanelPluginBadge: React.FC<PanelPluginBadgeProps> = ({ plugin }) => {
if (isUnsignedPluginSignature(plugin.signature)) {
return <PluginSignatureBadge status={plugin.signature} />;
}
return <PluginStateInfo state={plugin.state} />;
};
PanelPluginBadge.displayName = 'PanelPluginBadge';

View File

@@ -1,118 +0,0 @@
import React, { useCallback, useMemo } from 'react';
import config from 'app/core/config';
import { VizTypePickerPlugin } from './VizTypePickerPlugin';
import { EmptySearchResult, stylesFactory, useTheme } from '@grafana/ui';
import { GrafanaTheme, PanelPluginMeta, PluginState } from '@grafana/data';
import { css } from '@emotion/css';
export interface Props {
current: PanelPluginMeta;
onTypeChange: (newType: PanelPluginMeta, withModKey: boolean) => void;
searchQuery: string;
onClose: () => void;
}
export function getAllPanelPluginMeta(): PanelPluginMeta[] {
const allPanels = config.panels;
return Object.keys(allPanels)
.filter((key) => allPanels[key]['hideFromList'] === false)
.map((key) => allPanels[key])
.sort((a: PanelPluginMeta, b: PanelPluginMeta) => a.sort - b.sort);
}
export function filterPluginList(
pluginsList: PanelPluginMeta[],
searchQuery: string,
current: PanelPluginMeta
): PanelPluginMeta[] {
if (!searchQuery.length) {
return pluginsList.filter((p) => {
if (p.state === PluginState.deprecated) {
return current.id === p.id;
}
return true;
});
}
const query = searchQuery.toLowerCase();
const first: PanelPluginMeta[] = [];
const match: PanelPluginMeta[] = [];
for (const item of pluginsList) {
if (item.state === PluginState.deprecated && current.id !== item.id) {
continue;
}
const name = item.name.toLowerCase();
const idx = name.indexOf(query);
if (idx === 0) {
first.push(item);
} else if (idx > 0) {
match.push(item);
}
}
return first.concat(match);
}
export const VizTypePicker: React.FC<Props> = ({ searchQuery, onTypeChange, current }) => {
const theme = useTheme();
const styles = getStyles(theme);
const pluginsList: PanelPluginMeta[] = useMemo(() => {
return getAllPanelPluginMeta();
}, []);
const getFilteredPluginList = useCallback((): PanelPluginMeta[] => {
return filterPluginList(pluginsList, searchQuery, current);
}, [current, pluginsList, searchQuery]);
const renderVizPlugin = (plugin: PanelPluginMeta, index: number) => {
const isCurrent = plugin.id === current.id;
const filteredPluginList = getFilteredPluginList();
const matchesQuery = filteredPluginList.indexOf(plugin) > -1;
return (
<VizTypePickerPlugin
disabled={!matchesQuery && !!searchQuery}
key={plugin.id}
isCurrent={isCurrent}
plugin={plugin}
onClick={(e) => onTypeChange(plugin, Boolean(e.metaKey || e.ctrlKey || e.altKey))}
/>
);
};
const filteredPluginList = getFilteredPluginList();
const hasResults = filteredPluginList.length > 0;
const renderList = filteredPluginList.concat(pluginsList.filter((p) => filteredPluginList.indexOf(p) === -1));
return (
<div className={styles.grid}>
{hasResults ? (
renderList.map((plugin, index) => {
if (plugin.state === PluginState.deprecated) {
return null;
}
return renderVizPlugin(plugin, index);
})
) : (
<EmptySearchResult>Could not find anything matching your query</EmptySearchResult>
)}
</div>
);
};
VizTypePicker.displayName = 'VizTypePicker';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
grid: css`
max-width: 100%;
display: grid;
grid-gap: ${theme.spacing.sm};
`,
};
});

View File

@@ -1,26 +0,0 @@
import React, { MouseEventHandler } from 'react';
import { PanelPluginMeta } from '@grafana/data';
import { PanelTypeCard } from './PanelTypeCard';
interface Props {
isCurrent: boolean;
plugin: PanelPluginMeta;
onClick: MouseEventHandler<HTMLDivElement>;
disabled: boolean;
}
export const VizTypePickerPlugin: React.FC<Props> = ({ isCurrent, plugin, onClick, disabled }) => {
return (
<PanelTypeCard
title={plugin.name}
plugin={plugin}
description={plugin.info.description}
onClick={onClick}
isCurrent={isCurrent}
disabled={disabled}
showBadge={true}
/>
);
};
VizTypePickerPlugin.displayName = 'VizTypePickerPlugin';