LiveChannelEditor.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { css } from '@emotion/css';
  2. import React, { PureComponent } from 'react';
  3. import {
  4. LiveChannelScope,
  5. LiveChannelAddress,
  6. SelectableValue,
  7. StandardEditorProps,
  8. GrafanaTheme,
  9. } from '@grafana/data';
  10. import { Select, Alert, Label, stylesFactory } from '@grafana/ui';
  11. import { config } from 'app/core/config';
  12. import { LivePanelOptions } from './types';
  13. type Props = StandardEditorProps<LiveChannelAddress, any, LivePanelOptions>;
  14. const scopes: Array<SelectableValue<LiveChannelScope>> = [
  15. { label: 'Grafana', value: LiveChannelScope.Grafana, description: 'Core grafana live features' },
  16. { label: 'Data Sources', value: LiveChannelScope.DataSource, description: 'Data sources with live support' },
  17. { label: 'Plugins', value: LiveChannelScope.Plugin, description: 'Plugins with live support' },
  18. ];
  19. interface State {
  20. namespaces: Array<SelectableValue<string>>;
  21. paths: Array<SelectableValue<string>>;
  22. }
  23. export class LiveChannelEditor extends PureComponent<Props, State> {
  24. state: State = {
  25. namespaces: [],
  26. paths: [],
  27. };
  28. async componentDidMount() {
  29. this.updateSelectOptions();
  30. }
  31. async componentDidUpdate(oldProps: Props) {
  32. if (this.props.value !== oldProps.value) {
  33. this.updateSelectOptions();
  34. }
  35. }
  36. async updateSelectOptions() {
  37. this.setState({
  38. namespaces: [],
  39. paths: [],
  40. });
  41. }
  42. onScopeChanged = (v: SelectableValue<LiveChannelScope>) => {
  43. if (v.value) {
  44. this.props.onChange({
  45. scope: v.value,
  46. namespace: undefined as unknown as string,
  47. path: undefined as unknown as string,
  48. } as LiveChannelAddress);
  49. }
  50. };
  51. onNamespaceChanged = (v: SelectableValue<string>) => {
  52. const update = {
  53. scope: this.props.value?.scope,
  54. path: undefined as unknown as string,
  55. } as LiveChannelAddress;
  56. if (v.value) {
  57. update.namespace = v.value;
  58. }
  59. this.props.onChange(update);
  60. };
  61. onPathChanged = (v: SelectableValue<string>) => {
  62. const { value, onChange } = this.props;
  63. const update = {
  64. scope: value.scope,
  65. namespace: value.namespace,
  66. } as LiveChannelAddress;
  67. if (v.value) {
  68. update.path = v.value;
  69. }
  70. onChange(update);
  71. };
  72. render() {
  73. const { namespaces, paths } = this.state;
  74. const { scope, namespace, path } = this.props.value;
  75. const style = getStyles(config.theme);
  76. return (
  77. <>
  78. <Alert title="Grafana Live" severity="info">
  79. This supports real-time event streams in grafana core. This feature is under heavy development. Expect the
  80. intefaces and structures to change as this becomes more production ready.
  81. </Alert>
  82. <div>
  83. <div className={style.dropWrap}>
  84. <Label>Scope</Label>
  85. <Select options={scopes} value={scopes.find((s) => s.value === scope)} onChange={this.onScopeChanged} />
  86. </div>
  87. {scope && (
  88. <div className={style.dropWrap}>
  89. <Label>Namespace</Label>
  90. <Select
  91. options={namespaces}
  92. value={
  93. namespaces.find((s) => s.value === namespace) ??
  94. (namespace ? { label: namespace, value: namespace } : undefined)
  95. }
  96. onChange={this.onNamespaceChanged}
  97. allowCustomValue={true}
  98. backspaceRemovesValue={true}
  99. />
  100. </div>
  101. )}
  102. {scope && namespace && (
  103. <div className={style.dropWrap}>
  104. <Label>Path</Label>
  105. <Select
  106. options={paths}
  107. value={findPathOption(paths, path)}
  108. onChange={this.onPathChanged}
  109. allowCustomValue={true}
  110. backspaceRemovesValue={true}
  111. />
  112. </div>
  113. )}
  114. </div>
  115. </>
  116. );
  117. }
  118. }
  119. function findPathOption(paths: Array<SelectableValue<string>>, path?: string): SelectableValue<string> | undefined {
  120. const v = paths.find((s) => s.value === path);
  121. if (v) {
  122. return v;
  123. }
  124. if (path) {
  125. return { label: path, value: path };
  126. }
  127. return undefined;
  128. }
  129. const getStyles = stylesFactory((theme: GrafanaTheme) => ({
  130. dropWrap: css`
  131. margin-bottom: ${theme.spacing.sm};
  132. `,
  133. }));