2020-03-20 22:15:04 +08:00
|
|
|
import React, { useCallback } from 'react';
|
2020-02-09 21:34:42 +08:00
|
|
|
import cloneDeep from 'lodash/cloneDeep';
|
|
|
|
import {
|
|
|
|
FieldConfigSource,
|
|
|
|
DataFrame,
|
2020-04-07 21:02:08 +08:00
|
|
|
FieldConfigPropertyItem,
|
2020-02-11 20:48:36 +08:00
|
|
|
VariableSuggestionsScope,
|
2020-02-17 14:27:21 +08:00
|
|
|
PanelPlugin,
|
2020-02-14 20:46:08 +08:00
|
|
|
SelectableValue,
|
2020-02-09 21:34:42 +08:00
|
|
|
} from '@grafana/data';
|
2020-03-20 22:15:04 +08:00
|
|
|
import { Forms, fieldMatchersUI, ValuePicker, useTheme } from '@grafana/ui';
|
2020-02-11 20:48:36 +08:00
|
|
|
import { getDataLinksVariableSuggestions } from '../../../panel/panellinks/link_srv';
|
2020-02-14 20:46:08 +08:00
|
|
|
import { OverrideEditor } from './OverrideEditor';
|
2020-03-20 22:15:04 +08:00
|
|
|
import { css } from 'emotion';
|
2020-04-10 03:22:43 +08:00
|
|
|
import groupBy from 'lodash/groupBy';
|
|
|
|
import { OptionsGroup } from './OptionsGroup';
|
2020-02-12 17:42:57 +08:00
|
|
|
|
2020-02-09 01:29:09 +08:00
|
|
|
interface Props {
|
2020-02-17 14:27:21 +08:00
|
|
|
plugin: PanelPlugin;
|
2020-02-09 01:29:09 +08:00
|
|
|
config: FieldConfigSource;
|
|
|
|
onChange: (config: FieldConfigSource) => void;
|
2020-02-12 17:42:57 +08:00
|
|
|
/* Helpful for IntelliSense */
|
2020-02-09 01:29:09 +08:00
|
|
|
data: DataFrame[];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Expects the container div to have size set and will fill it 100%
|
|
|
|
*/
|
2020-03-20 22:15:04 +08:00
|
|
|
export const OverrideFieldConfigEditor: React.FC<Props> = props => {
|
|
|
|
const theme = useTheme();
|
2020-02-09 01:29:09 +08:00
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
const onOverrideChange = (index: number, override: any) => {
|
|
|
|
const { config } = props;
|
2020-02-09 21:34:42 +08:00
|
|
|
let overrides = cloneDeep(config.overrides);
|
2020-02-14 20:46:08 +08:00
|
|
|
overrides[index] = override;
|
2020-03-20 22:15:04 +08:00
|
|
|
props.onChange({ ...config, overrides });
|
2020-02-09 21:34:42 +08:00
|
|
|
};
|
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
const onOverrideRemove = (overrideIndex: number) => {
|
|
|
|
const { config } = props;
|
2020-02-09 21:34:42 +08:00
|
|
|
let overrides = cloneDeep(config.overrides);
|
2020-02-14 20:46:08 +08:00
|
|
|
overrides.splice(overrideIndex, 1);
|
2020-03-20 22:15:04 +08:00
|
|
|
props.onChange({ ...config, overrides });
|
2020-02-09 21:34:42 +08:00
|
|
|
};
|
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
const onOverrideAdd = (value: SelectableValue<string>) => {
|
|
|
|
const { onChange, config } = props;
|
2020-02-14 20:46:08 +08:00
|
|
|
onChange({
|
|
|
|
...config,
|
|
|
|
overrides: [
|
|
|
|
...config.overrides,
|
|
|
|
{
|
|
|
|
matcher: {
|
|
|
|
id: value.value!,
|
|
|
|
},
|
|
|
|
properties: [],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
2020-02-09 21:34:42 +08:00
|
|
|
};
|
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
const renderOverrides = () => {
|
|
|
|
const { config, data, plugin } = props;
|
2020-04-06 22:24:41 +08:00
|
|
|
const { fieldConfigRegistry } = plugin;
|
2020-02-17 14:27:21 +08:00
|
|
|
|
2020-02-10 01:47:48 +08:00
|
|
|
if (config.overrides.length === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
2020-02-09 01:29:09 +08:00
|
|
|
|
2020-02-09 21:34:42 +08:00
|
|
|
return (
|
2020-02-10 01:47:48 +08:00
|
|
|
<div>
|
2020-02-09 21:34:42 +08:00
|
|
|
{config.overrides.map((o, i) => {
|
2020-02-14 04:37:24 +08:00
|
|
|
// TODO: apply matcher to retrieve fields
|
2020-02-09 21:34:42 +08:00
|
|
|
return (
|
2020-02-14 20:46:08 +08:00
|
|
|
<OverrideEditor
|
|
|
|
key={`${o.matcher.id}/${i}`}
|
|
|
|
data={data}
|
|
|
|
override={o}
|
2020-03-20 22:15:04 +08:00
|
|
|
onChange={value => onOverrideChange(i, value)}
|
|
|
|
onRemove={() => onOverrideRemove(i)}
|
2020-04-06 22:24:41 +08:00
|
|
|
registry={fieldConfigRegistry}
|
2020-02-14 20:46:08 +08:00
|
|
|
/>
|
2020-02-09 21:34:42 +08:00
|
|
|
);
|
|
|
|
})}
|
2020-02-10 01:47:48 +08:00
|
|
|
</div>
|
2020-02-09 21:34:42 +08:00
|
|
|
);
|
2020-03-20 22:15:04 +08:00
|
|
|
};
|
2020-02-09 01:29:09 +08:00
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
const renderAddOverride = () => {
|
2020-02-09 21:34:42 +08:00
|
|
|
return (
|
2020-02-10 01:47:48 +08:00
|
|
|
<ValuePicker
|
@grafana/ui: Create Icon component and replace part of the icons (#23402)
* Part1: Unicons implementation (#23197)
* Create a new Icon component
* Update icons in main sidebar
* Update icons in Useful links and in react components on main site
* Update icons in Useful links and in main top navigation
* Adjust sizing
* Update panel navigation and timepicker
* Update icons in Panel menu
* NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179)
* Update icons in add panel widget
* Resolve merge conflict
* Fix part of the test errors and type errors
* Fix storybook errors
* Update getAvailableIcons import in storybook knobs
* Fix import path
* Fix SyntaxError: Cannot use import statement outside a module in test environment error
* Remove dynamic imports
* Remove types as using @ts-ignore
* Update snapshot test
* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax
* Remove color prop from icon, remove color implemetation in mono icons
* Update navbar styling
* Move toPascalCase to utils/string
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
* Resolve type errors resulted from merge
* Part2: Unicons implementation (#23266)
* Create a new Icon component
* Update icons in main sidebar
* Update icons in Useful links and in react components on main site
* Update icons in Useful links and in main top navigation
* Adjust sizing
* Update panel navigation and timepicker
* Update icons in Panel menu
* Update icons in add panel widget
* Resolve merge conflict
* Fix part of the test errors and type errors
* Fix storybook errors
* Update getAvailableIcons import in storybook knobs
* Fix import path
* Fix SyntaxError: Cannot use import statement outside a module in test environment error
* Remove dynamic imports
* Remove types as using @ts-ignore
* Update snapshot test
* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax
* Implment icons in Tabs
* Implement icons in search items and empty list
* Update buttons
* Update button-related snapshot tests
* Update icons in modals and page headers
* Create anfular wrapper and update all icons on search screen
* Update sizing, remove colors, update snapshot tests
* Remove color prop from icon, remove color implemetation in mono icons
* Remove color props from monochrome icons
* Complete update of icons for search screen
* Update icons for infor tooltips, playlist, permissions
* Support temporarly font awesome icons used in enterprise grafana
* Part1: Unicons implementation (#23197)
* Create a new Icon component
* Update icons in main sidebar
* Update icons in Useful links and in react components on main site
* Update icons in Useful links and in main top navigation
* Adjust sizing
* Update panel navigation and timepicker
* Update icons in Panel menu
* NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179)
* Update icons in add panel widget
* Resolve merge conflict
* Fix part of the test errors and type errors
* Fix storybook errors
* Update getAvailableIcons import in storybook knobs
* Fix import path
* Fix SyntaxError: Cannot use import statement outside a module in test environment error
* Remove dynamic imports
* Remove types as using @ts-ignore
* Update snapshot test
* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax
* Remove color prop from icon, remove color implemetation in mono icons
* Update navbar styling
* Move toPascalCase to utils/string
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
* Icons update
* Add optional chaining to for isFontAwesome variable
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
* Part3: Unicons implementation (#23356)
* Create a new Icon component
* Update icons in main sidebar
* Update icons in Useful links and in react components on main site
* Update icons in Useful links and in main top navigation
* Adjust sizing
* Update panel navigation and timepicker
* Update icons in Panel menu
* Update icons in add panel widget
* Resolve merge conflict
* Fix part of the test errors and type errors
* Fix storybook errors
* Update getAvailableIcons import in storybook knobs
* Fix import path
* Fix SyntaxError: Cannot use import statement outside a module in test environment error
* Remove dynamic imports
* Remove types as using @ts-ignore
* Update snapshot test
* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax
* Implment icons in Tabs
* Implement icons in search items and empty list
* Update buttons
* Update button-related snapshot tests
* Update icons in modals and page headers
* Create anfular wrapper and update all icons on search screen
* Update sizing, remove colors, update snapshot tests
* Remove color prop from icon, remove color implemetation in mono icons
* Remove color props from monochrome icons
* Complete update of icons for search screen
* Update icons for infor tooltips, playlist, permissions
* Support temporarly font awesome icons used in enterprise grafana
* Part1: Unicons implementation (#23197)
* Create a new Icon component
* Update icons in main sidebar
* Update icons in Useful links and in react components on main site
* Update icons in Useful links and in main top navigation
* Adjust sizing
* Update panel navigation and timepicker
* Update icons in Panel menu
* NewPanelEditor: Fixed so that test alert rule works in new edit mode (#23179)
* Update icons in add panel widget
* Resolve merge conflict
* Fix part of the test errors and type errors
* Fix storybook errors
* Update getAvailableIcons import in storybook knobs
* Fix import path
* Fix SyntaxError: Cannot use import statement outside a module in test environment error
* Remove dynamic imports
* Remove types as using @ts-ignore
* Update snapshot test
* Add @iconscout/react-unicons to the shouldExclude list as it is blundled with es2015 syntax
* Remove color prop from icon, remove color implemetation in mono icons
* Update navbar styling
* Move toPascalCase to utils/string
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
* Update icons in Explore
* Update icons in alerting
* Update + and x buttons
* Update icons in configurations and settings
* Update close icons
* Update icons in rich history
* Update alert messages
* Add optional chaining to for isFontAwesome variable
* Remove icon mock, set up jest.config
* Fix navbar plus icon
* Fir enable-bacground to enableBackgournd
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
* Merge remote branch origin master to icons-unicons
* Revert "Merge remote branch origin master to icons-unicons"
This reverts commit 3f25d50a39a940883fefe73ce51219139c1ed37f.
* Size-up dashnav icons
* Fix alerting icons, panel headers, update tests
* Fix typecheck error
* Adjustments - add panel icon, spacing
* Set TerserPlugin sourceMap to false to prevent running out of memory when publishing storybook
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2020-04-08 20:33:31 +08:00
|
|
|
icon="plus-circle"
|
2020-02-10 01:47:48 +08:00
|
|
|
label="Add override"
|
2020-03-31 03:28:13 +08:00
|
|
|
variant="secondary"
|
2020-02-14 20:46:08 +08:00
|
|
|
options={fieldMatchersUI
|
|
|
|
.list()
|
|
|
|
.map<SelectableValue<string>>(i => ({ label: i.name, value: i.id, description: i.description }))}
|
2020-03-20 22:15:04 +08:00
|
|
|
onChange={value => onOverrideAdd(value)}
|
2020-02-09 21:34:42 +08:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={css`
|
|
|
|
padding: ${theme.spacing.md};
|
|
|
|
`}
|
|
|
|
>
|
|
|
|
{renderOverrides()}
|
|
|
|
{renderAddOverride()}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-04-06 22:24:41 +08:00
|
|
|
export const DefaultFieldConfigEditor: React.FC<Props> = ({ data, onChange, config, plugin }) => {
|
2020-03-20 22:15:04 +08:00
|
|
|
const setDefaultValue = useCallback(
|
|
|
|
(name: string, value: any, custom: boolean) => {
|
|
|
|
const defaults = { ...config.defaults };
|
|
|
|
const remove = value === undefined || value === null || '';
|
|
|
|
|
|
|
|
if (custom) {
|
|
|
|
if (defaults.custom) {
|
|
|
|
if (remove) {
|
|
|
|
defaults.custom = { ...defaults.custom };
|
|
|
|
delete defaults.custom[name];
|
|
|
|
} else {
|
|
|
|
defaults.custom = { ...defaults.custom, [name]: value };
|
|
|
|
}
|
|
|
|
} else if (!remove) {
|
|
|
|
defaults.custom = { [name]: value };
|
|
|
|
}
|
|
|
|
} else if (remove) {
|
|
|
|
delete (defaults as any)[name];
|
|
|
|
} else {
|
|
|
|
(defaults as any)[name] = value;
|
|
|
|
}
|
2020-02-17 14:27:21 +08:00
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
onChange({
|
|
|
|
...config,
|
|
|
|
defaults,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
[config, onChange]
|
|
|
|
);
|
|
|
|
|
|
|
|
const renderEditor = useCallback(
|
2020-04-07 21:02:08 +08:00
|
|
|
(item: FieldConfigPropertyItem) => {
|
2020-04-09 01:21:26 +08:00
|
|
|
if (item.isCustom && item.showIf && !item.showIf(config.defaults.custom)) {
|
|
|
|
return null;
|
|
|
|
}
|
2020-03-20 22:15:04 +08:00
|
|
|
const defaults = config.defaults;
|
2020-04-06 22:24:41 +08:00
|
|
|
const value = item.isCustom
|
|
|
|
? defaults.custom
|
|
|
|
? defaults.custom[item.path]
|
|
|
|
: undefined
|
|
|
|
: (defaults as any)[item.path];
|
2020-03-20 22:15:04 +08:00
|
|
|
|
2020-04-10 03:22:43 +08:00
|
|
|
const label = (
|
|
|
|
<Forms.Label description={item.description} category={item.category?.slice(1)}>
|
|
|
|
{item.name}
|
|
|
|
</Forms.Label>
|
|
|
|
);
|
|
|
|
|
2020-03-20 22:15:04 +08:00
|
|
|
return (
|
2020-04-10 03:22:43 +08:00
|
|
|
<Forms.Field label={label} key={`${item.id}/${item.isCustom}`}>
|
2020-03-20 22:15:04 +08:00
|
|
|
<item.editor
|
|
|
|
item={item}
|
|
|
|
value={value}
|
2020-04-06 22:24:41 +08:00
|
|
|
onChange={v => setDefaultValue(item.path, v, item.isCustom)}
|
2020-03-20 22:15:04 +08:00
|
|
|
context={{
|
|
|
|
data,
|
|
|
|
getSuggestions: (scope?: VariableSuggestionsScope) => getDataLinksVariableSuggestions(data, scope),
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Forms.Field>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
[config]
|
|
|
|
);
|
2020-02-12 17:42:57 +08:00
|
|
|
|
2020-04-10 03:22:43 +08:00
|
|
|
const groupedConfigs = groupBy(plugin.fieldConfigRegistry.list(), i => i.category && i.category[0]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{Object.keys(groupedConfigs).map(k => {
|
|
|
|
return (
|
|
|
|
<OptionsGroup title={k}>
|
|
|
|
<>
|
|
|
|
{groupedConfigs[k].map(c => {
|
|
|
|
return renderEditor(c);
|
|
|
|
})}
|
|
|
|
</>
|
|
|
|
</OptionsGroup>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</>
|
|
|
|
);
|
2020-03-20 22:15:04 +08:00
|
|
|
};
|