InlineEditBody.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { get as lodashGet } from 'lodash';
  2. import React, { useMemo } from 'react';
  3. import { useObservable } from 'react-use';
  4. import { PanelOptionsEditorBuilder, StandardEditorContext } from '@grafana/data';
  5. import { PanelOptionsSupplier } from '@grafana/data/src/panel/PanelPlugin';
  6. import { NestedValueAccess } from '@grafana/data/src/utils/OptionsUIBuilders';
  7. import { FrameState } from 'app/features/canvas/runtime/frame';
  8. import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
  9. import { fillOptionsPaneItems } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions';
  10. import { setOptionImmutably } from 'app/features/dashboard/components/PanelEditor/utils';
  11. import { activePanelSubject, InstanceState } from './CanvasPanel';
  12. import { getElementEditor } from './editor/elementEditor';
  13. import { getLayerEditor } from './editor/layerEditor';
  14. export const InlineEditBody = () => {
  15. const activePanel = useObservable(activePanelSubject);
  16. const instanceState = activePanel?.panel.context?.instanceState;
  17. const pane = useMemo(() => {
  18. const state: InstanceState = instanceState;
  19. if (!state) {
  20. return new OptionsPaneCategoryDescriptor({ id: 'root', title: 'root' });
  21. }
  22. const supplier = (builder: PanelOptionsEditorBuilder<any>, context: StandardEditorContext<any>) => {
  23. builder.addNestedOptions(getLayerEditor(instanceState));
  24. const selection = state.selected;
  25. if (selection?.length === 1) {
  26. const element = selection[0];
  27. if (!(element instanceof FrameState)) {
  28. builder.addNestedOptions(
  29. getElementEditor({
  30. category: [`Selected element (${element.options.name})`],
  31. element,
  32. scene: state.scene,
  33. })
  34. );
  35. }
  36. }
  37. };
  38. return getOptionsPaneCategoryDescriptor({}, supplier);
  39. }, [instanceState]);
  40. return (
  41. <div>
  42. <div>{pane.items.map((v) => v.render())}</div>
  43. <div>
  44. {pane.categories.map((c) => {
  45. return (
  46. <div key={c.props.id}>
  47. <h5>{c.props.title}</h5>
  48. <div>{c.items.map((s) => s.render())}</div>
  49. </div>
  50. );
  51. })}
  52. </div>
  53. </div>
  54. );
  55. };
  56. // 🤮🤮🤮🤮 this oddly does not actually do anything, but structure is required. I'll try to clean it up...
  57. function getOptionsPaneCategoryDescriptor<T = any>(
  58. props: any,
  59. supplier: PanelOptionsSupplier<T>
  60. ): OptionsPaneCategoryDescriptor {
  61. const context: StandardEditorContext<unknown, unknown> = {
  62. data: props.input,
  63. options: props.options,
  64. };
  65. const root = new OptionsPaneCategoryDescriptor({ id: 'root', title: 'root' });
  66. const getOptionsPaneCategory = (categoryNames?: string[]): OptionsPaneCategoryDescriptor => {
  67. if (categoryNames?.length) {
  68. const key = categoryNames[0];
  69. let sub = root.categories.find((v) => v.props.id === key);
  70. if (!sub) {
  71. sub = new OptionsPaneCategoryDescriptor({ id: key, title: key });
  72. root.categories.push(sub);
  73. }
  74. return sub;
  75. }
  76. return root;
  77. };
  78. const access: NestedValueAccess = {
  79. getValue: (path: string) => lodashGet(props.options, path),
  80. onChange: (path: string, value: any) => {
  81. props.onChange(setOptionImmutably(props.options as any, path, value));
  82. },
  83. };
  84. // Use the panel options loader
  85. fillOptionsPaneItems(supplier, access, getOptionsPaneCategory, context);
  86. return root;
  87. }