mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PanelEdit: v8 Panel Edit UX (#32124)
* Initial commit * Progress * Update * Progress * updates * Minor fix * fixed ts issue * fixed e2e tests * More explorations * Making progress * Panel options and field options unified * With nested categories * Starting to find something * fix paddings * Progress * Breakthrough ux layout * Progress * Updates * New way of composing options with search * added regex search * Refactoring to react note tree * Show overrides * Adding overrides radio button support * Added popular view * Separate stat/gauge/bargauge options into value options and display options * Initial work on getting library panels into viz picker flow * Fixed issues switching to panel library panel * Move search input put of LibraryPanelsView * Changing design again to have content inside boxes * Style updates * Refactoring to fix scroll issue * Option category naming * Fixed FilterInput issue * Updated snapshots * Fix padding * Updated viz picker design * Unify library panel an viz picker card * Updated card with delete action * Major refactoring back to an object model instead of searching and filtering react node tree * More refactoring * Show option category in label when searching * Nice logic for categories rendering when searching or when only child * Make getSuggestions more lazy for DataLinksEditor * Add missing repeat options and handle conditional options * Prepping options category to be more flexibly and control state from outside * Added option count to search result * Minor style tweak * Added button to close viz picker * Rewrote overrides to enable searching overrides * New search engine and tests * Searching overrides works * Hide radio buttons while searching * Added angular options back * Added memoize for all options so they are not rebuilt for every search key stroke * Added back support for category counters * Started unit test work * Refactoring and base popular options list * Initial update to e2e test, more coming to add e2e test for search features * Minor fix * Review updates * Fixing category open states * Unit test progress * Do not show visualization list mode radio button if library panels is not enabled * Use boolean * More unit tests * Increase library panels per page count and give search focus when switching list mode * field config change test and search test * Feedback updates * Minor tweaks * Minor refactorings * More minimal override collapse state
This commit is contained in:
@@ -5,7 +5,7 @@ import { DataFrame, InterpolateFunction, VariableSuggestionsScope, VariableSugge
|
||||
import { EventBus } from '../events';
|
||||
|
||||
export interface StandardEditorContext<TOptions> {
|
||||
data?: DataFrame[]; // All results
|
||||
data: DataFrame[]; // All results
|
||||
replaceVariables?: InterpolateFunction;
|
||||
eventBus?: EventBus;
|
||||
getSuggestions?: (scope?: VariableSuggestionsScope) => VariableSuggestion[];
|
||||
|
||||
@@ -58,7 +58,6 @@ export interface FieldConfigSource<TOptions extends object = any> {
|
||||
export interface FieldOverrideContext extends StandardEditorContext<any> {
|
||||
field?: Field;
|
||||
dataFrameIndex?: number; // The index for the selected field frame
|
||||
data: DataFrame[]; // All results
|
||||
}
|
||||
export interface FieldConfigEditorProps<TValue, TSettings>
|
||||
extends Omit<StandardEditorProps<TValue, TSettings>, 'item'> {
|
||||
|
||||
@@ -41,7 +41,7 @@ export interface OptionEditorConfig<TOptions, TSettings = any, TValue = any> {
|
||||
/**
|
||||
* Array of strings representing category of the option. First element in the array will make option render as collapsible section.
|
||||
*/
|
||||
category?: Array<string | undefined>;
|
||||
category?: string[];
|
||||
|
||||
/**
|
||||
* Set this value if undefined
|
||||
|
||||
@@ -61,18 +61,15 @@ export const Components = {
|
||||
},
|
||||
OptionsPane: {
|
||||
content: 'Panel editor option pane content',
|
||||
close: 'Page toolbar button Close options pane',
|
||||
open: 'Page toolbar button Open options pane',
|
||||
select: 'Panel editor option pane select',
|
||||
tab: (title: string) => `Panel editor option pane tab ${title}`,
|
||||
fieldLabel: (type: string) => `${type} field property editor`,
|
||||
},
|
||||
// not sure about the naming *DataPane*
|
||||
DataPane: {
|
||||
content: 'Panel editor data pane content',
|
||||
},
|
||||
FieldOptions: {
|
||||
propertyEditor: (type: string) => `${type} field property editor`,
|
||||
},
|
||||
toggleVizPicker: 'toggle-viz-picker',
|
||||
toggleVizOptions: 'toggle-viz-options',
|
||||
},
|
||||
PanelInspector: {
|
||||
Data: {
|
||||
|
||||
@@ -219,7 +219,7 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
|
||||
const closeOptions = (): any =>
|
||||
isOptionsOpen().then((isOpen: any) => {
|
||||
if (isOpen) {
|
||||
e2e.components.PanelEditor.OptionsPane.close().click();
|
||||
e2e.components.PanelEditor.toggleVizOptions().click();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -271,7 +271,7 @@ const isOptionsOpen = (): any =>
|
||||
const openOptions = (): any =>
|
||||
isOptionsOpen().then((isOpen: any) => {
|
||||
if (!isOpen) {
|
||||
e2e.components.PanelEditor.OptionsPane.open().click();
|
||||
e2e.components.PanelEditor.toggleVizOptions().click();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -208,6 +208,11 @@ export function getPropertiesForVariant(theme: GrafanaTheme, variant: ButtonVari
|
||||
outline: none;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: ${theme.colors.linkExternal};
|
||||
text-decoration: underline;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ interface DataLinkEditorModalContentProps {
|
||||
link: DataLink;
|
||||
index: number;
|
||||
data: DataFrame[];
|
||||
suggestions: VariableSuggestion[];
|
||||
getSuggestions: () => VariableSuggestion[];
|
||||
onSave: (index: number, ink: DataLink) => void;
|
||||
onCancel: (index: number) => void;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ interface DataLinkEditorModalContentProps {
|
||||
export const DataLinkEditorModalContent: FC<DataLinkEditorModalContentProps> = ({
|
||||
link,
|
||||
index,
|
||||
suggestions,
|
||||
getSuggestions,
|
||||
onSave,
|
||||
onCancel,
|
||||
}) => {
|
||||
@@ -27,7 +27,7 @@ export const DataLinkEditorModalContent: FC<DataLinkEditorModalContentProps> = (
|
||||
value={dirtyLink}
|
||||
index={index}
|
||||
isLast={false}
|
||||
suggestions={suggestions}
|
||||
suggestions={getSuggestions()}
|
||||
onChange={(index, link) => {
|
||||
setDirtyLink(link);
|
||||
}}
|
||||
|
||||
@@ -11,11 +11,16 @@ import { DataLinkEditorModalContent } from './DataLinkEditorModalContent';
|
||||
interface DataLinksInlineEditorProps {
|
||||
links?: DataLink[];
|
||||
onChange: (links: DataLink[]) => void;
|
||||
suggestions: VariableSuggestion[];
|
||||
getSuggestions: () => VariableSuggestion[];
|
||||
data: DataFrame[];
|
||||
}
|
||||
|
||||
export const DataLinksInlineEditor: React.FC<DataLinksInlineEditorProps> = ({ links, onChange, suggestions, data }) => {
|
||||
export const DataLinksInlineEditor: React.FC<DataLinksInlineEditorProps> = ({
|
||||
links,
|
||||
onChange,
|
||||
getSuggestions,
|
||||
data,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const [editIndex, setEditIndex] = useState<number | null>(null);
|
||||
const [isNew, setIsNew] = useState(false);
|
||||
@@ -74,7 +79,6 @@ export const DataLinksInlineEditor: React.FC<DataLinksInlineEditorProps> = ({ li
|
||||
onEdit={() => setEditIndex(i)}
|
||||
onRemove={() => onDataLinkRemove(i)}
|
||||
data={data}
|
||||
suggestions={suggestions}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -95,7 +99,7 @@ export const DataLinksInlineEditor: React.FC<DataLinksInlineEditorProps> = ({ li
|
||||
data={data}
|
||||
onSave={onDataLinkChange}
|
||||
onCancel={onDataLinkCancel}
|
||||
suggestions={suggestions}
|
||||
getSuggestions={getSuggestions}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
@@ -17,7 +17,6 @@ function setupTestContext(options: Partial<DataLinksListItemProps>) {
|
||||
onChange: jest.fn(),
|
||||
onEdit: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
suggestions: [],
|
||||
};
|
||||
|
||||
const props = { ...defaults, ...options };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { FC } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { DataFrame, DataLink, GrafanaTheme, VariableSuggestion } from '@grafana/data';
|
||||
import { DataFrame, DataLink, GrafanaTheme } from '@grafana/data';
|
||||
import { stylesFactory, useTheme } from '../../../themes';
|
||||
import { HorizontalGroup, VerticalGroup } from '../../Layout/Layout';
|
||||
import { IconButton } from '../../IconButton/IconButton';
|
||||
@@ -12,7 +12,6 @@ export interface DataLinksListItemProps {
|
||||
onChange: (index: number, link: DataLink) => void;
|
||||
onEdit: () => void;
|
||||
onRemove: () => void;
|
||||
suggestions: VariableSuggestion[];
|
||||
isEditing?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ const getInfoBoxStyles = stylesFactory((theme: GrafanaTheme, severity: AlertVari
|
||||
padding: ${theme.spacing.md};
|
||||
border-radius: ${theme.border.radius.md};
|
||||
position: relative;
|
||||
box-shadow: 0 0 30px 10px rgba(0, 0, 0, ${theme.isLight ? 0.05 : 0.2});
|
||||
z-index: 0;
|
||||
|
||||
&:before {
|
||||
|
||||
@@ -17,7 +17,7 @@ export const DataLinksValueEditor: React.FC<FieldConfigEditorProps<DataLink[], D
|
||||
links={value}
|
||||
onChange={onChange}
|
||||
data={context.data}
|
||||
suggestions={context.getSuggestions ? context.getSuggestions(VariableSuggestionsScope.Values) : []}
|
||||
getSuggestions={() => (context.getSuggestions ? context.getSuggestions(VariableSuggestionsScope.Values) : [])}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ export const SliderValueEditor: React.FC<FieldConfigEditorProps<number, SliderFi
|
||||
item,
|
||||
}) => {
|
||||
const { settings } = item;
|
||||
|
||||
const initialValue = typeof value === 'number' ? value : typeof value === 'string' ? +value : 0;
|
||||
|
||||
return (
|
||||
|
||||
@@ -135,7 +135,7 @@ const getStyles = (theme: GrafanaTheme) => {
|
||||
background: ${theme.colors.dashboardBg};
|
||||
justify-content: flex-end;
|
||||
flex-wrap: wrap;
|
||||
padding: 0 ${spacing.md} ${spacing.sm} ${spacing.md};
|
||||
padding: 0 ${spacing.sm} ${spacing.sm} ${spacing.md};
|
||||
`,
|
||||
toolbarLeft: css`
|
||||
display: flex;
|
||||
|
||||
@@ -221,7 +221,7 @@ export const getStandardFieldConfigs = () => {
|
||||
category,
|
||||
};
|
||||
|
||||
return [unit, min, max, decimals, displayName, noValue, color, thresholds, mappings, links];
|
||||
return [unit, min, max, decimals, displayName, color, noValue, thresholds, mappings, links];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user