@perses-dev/plugin-system 0.54.0 → 0.55.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/cjs/components/PanelSpecEditor/PanelAnnotationsEditor.js +246 -0
  2. package/dist/cjs/components/PanelSpecEditor/PanelSpecEditor.js +16 -1
  3. package/dist/cjs/components/PluginRegistry/PluginRegistry.js +4 -0
  4. package/dist/cjs/remote/PluginRuntime.js +12 -12
  5. package/dist/cjs/remote/remotePluginLoader.js +3 -1
  6. package/dist/cjs/runtime/UsageMetricsProvider.js +4 -2
  7. package/dist/cjs/runtime/item-actions.js +9 -10
  8. package/dist/components/PanelSpecEditor/PanelAnnotationsEditor.d.ts +15 -0
  9. package/dist/components/PanelSpecEditor/PanelAnnotationsEditor.d.ts.map +1 -0
  10. package/dist/components/PanelSpecEditor/PanelAnnotationsEditor.js +238 -0
  11. package/dist/components/PanelSpecEditor/PanelAnnotationsEditor.js.map +1 -0
  12. package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts.map +1 -1
  13. package/dist/components/PanelSpecEditor/PanelSpecEditor.js +16 -1
  14. package/dist/components/PanelSpecEditor/PanelSpecEditor.js.map +1 -1
  15. package/dist/components/PluginRegistry/PluginRegistry.d.ts.map +1 -1
  16. package/dist/components/PluginRegistry/PluginRegistry.js +4 -0
  17. package/dist/components/PluginRegistry/PluginRegistry.js.map +1 -1
  18. package/dist/model/panels.d.ts +6 -0
  19. package/dist/model/panels.d.ts.map +1 -1
  20. package/dist/model/panels.js.map +1 -1
  21. package/dist/remote/PluginRuntime.js +12 -12
  22. package/dist/remote/PluginRuntime.js.map +1 -1
  23. package/dist/remote/remotePluginLoader.d.ts +5 -0
  24. package/dist/remote/remotePluginLoader.d.ts.map +1 -1
  25. package/dist/remote/remotePluginLoader.js +3 -1
  26. package/dist/remote/remotePluginLoader.js.map +1 -1
  27. package/dist/runtime/UsageMetricsProvider.d.ts +2 -0
  28. package/dist/runtime/UsageMetricsProvider.d.ts.map +1 -1
  29. package/dist/runtime/UsageMetricsProvider.js +5 -3
  30. package/dist/runtime/UsageMetricsProvider.js.map +1 -1
  31. package/dist/runtime/item-actions.d.ts +3 -0
  32. package/dist/runtime/item-actions.d.ts.map +1 -1
  33. package/dist/runtime/item-actions.js +9 -10
  34. package/dist/runtime/item-actions.js.map +1 -1
  35. package/package.json +4 -4
@@ -0,0 +1,246 @@
1
+ // Copyright The Perses Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ "use strict";
14
+ Object.defineProperty(exports, "__esModule", {
15
+ value: true
16
+ });
17
+ Object.defineProperty(exports, "PanelAnnotationsEditor", {
18
+ enumerable: true,
19
+ get: function() {
20
+ return PanelAnnotationsEditor;
21
+ }
22
+ });
23
+ const _jsxruntime = require("react/jsx-runtime");
24
+ const _react = require("react");
25
+ const _material = require("@mui/material");
26
+ const _Plus = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Plus"));
27
+ const _Pencil = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Pencil"));
28
+ const _TrashCan = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/TrashCan"));
29
+ const _ArrowUp = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowUp"));
30
+ const _ArrowDown = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowDown"));
31
+ const _context = require("../../context");
32
+ const _Annotations = require("../Annotations");
33
+ function _interop_require_default(obj) {
34
+ return obj && obj.__esModule ? obj : {
35
+ default: obj
36
+ };
37
+ }
38
+ const TableCell = (0, _material.styled)(_material.TableCell)(({ theme })=>({
39
+ borderBottom: `solid 1px ${theme.palette.divider}`
40
+ }));
41
+ function findDuplicateNames(specs) {
42
+ const seen = new Set();
43
+ const duplicates = new Set();
44
+ for (const spec of specs){
45
+ const name = spec.display.name;
46
+ if (seen.has(name)) {
47
+ duplicates.add(name);
48
+ }
49
+ seen.add(name);
50
+ }
51
+ return Array.from(duplicates);
52
+ }
53
+ function PanelAnnotationsEditor({ value, onChange, isReadonly }) {
54
+ const [target, setTarget] = (0, _react.useState)(null);
55
+ const [formAction, setFormAction] = (0, _react.useState)('update');
56
+ const duplicateNames = (0, _react.useMemo)(()=>findDuplicateNames(value), [
57
+ value
58
+ ]);
59
+ const initialSpec = (0, _react.useMemo)(()=>{
60
+ if (target?.kind === 'new') {
61
+ return {
62
+ display: {
63
+ name: 'NewAnnotation'
64
+ },
65
+ plugin: {}
66
+ };
67
+ }
68
+ if (target?.kind === 'edit') {
69
+ return value[target.index];
70
+ }
71
+ return undefined;
72
+ }, [
73
+ target,
74
+ value
75
+ ]);
76
+ const removeAnnotation = (index)=>{
77
+ onChange(value.filter((_, i)=>i !== index));
78
+ };
79
+ const changeAnnotationOrder = (index, direction)=>{
80
+ const step = direction === 'up' ? -1 : 1;
81
+ const swapWith = index + step;
82
+ const current = value[index];
83
+ const adjacent = value[swapWith];
84
+ if (!current || !adjacent) {
85
+ return;
86
+ }
87
+ const next = [
88
+ ...value
89
+ ];
90
+ next[index] = adjacent;
91
+ next[swapWith] = current;
92
+ onChange(next);
93
+ };
94
+ const toggleAnnotationVisibility = (index, visible)=>{
95
+ onChange(value.map((spec, i)=>i === index ? {
96
+ ...spec,
97
+ display: {
98
+ ...spec.display,
99
+ hidden: !visible
100
+ }
101
+ } : spec));
102
+ };
103
+ const handleSave = (definition)=>{
104
+ if (target?.kind === 'new') {
105
+ onChange([
106
+ ...value,
107
+ definition
108
+ ]);
109
+ } else if (target?.kind === 'edit') {
110
+ onChange(value.map((spec, i)=>i === target.index ? definition : spec));
111
+ }
112
+ setTarget(null);
113
+ };
114
+ if (target !== null && initialSpec) {
115
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_context.ValidationProvider, {
116
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Annotations.AnnotationEditorForm, {
117
+ initialAnnotationSpec: initialSpec,
118
+ action: formAction,
119
+ isDraft: true,
120
+ isReadonly: isReadonly,
121
+ onActionChange: setFormAction,
122
+ onSave: handleSave,
123
+ onClose: ()=>setTarget(null)
124
+ })
125
+ });
126
+ }
127
+ return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
128
+ spacing: 2,
129
+ padding: 1,
130
+ children: [
131
+ duplicateNames.map((name)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Alert, {
132
+ severity: "error",
133
+ children: `Duplicate annotation name: ${name}`
134
+ }, name)),
135
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TableContainer, {
136
+ children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Table, {
137
+ "aria-label": "table of panel annotations",
138
+ children: [
139
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TableHead, {
140
+ children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.TableRow, {
141
+ children: [
142
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
143
+ children: "Visibility"
144
+ }),
145
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
146
+ children: "Name"
147
+ }),
148
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
149
+ children: "Type"
150
+ }),
151
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
152
+ children: "Description"
153
+ }),
154
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
155
+ align: "right",
156
+ children: "Actions"
157
+ })
158
+ ]
159
+ })
160
+ }),
161
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TableBody, {
162
+ children: value.map((annotation, index)=>/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.TableRow, {
163
+ children: [
164
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
165
+ component: "th",
166
+ scope: "row",
167
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Switch, {
168
+ checked: annotation.display?.hidden !== true,
169
+ disabled: isReadonly,
170
+ onChange: (e)=>toggleAnnotationVisibility(index, e.target.checked)
171
+ })
172
+ }),
173
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
174
+ component: "th",
175
+ scope: "row",
176
+ sx: {
177
+ fontWeight: 'bold'
178
+ },
179
+ children: annotation.display.name
180
+ }),
181
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
182
+ children: annotation.plugin.kind
183
+ }),
184
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(TableCell, {
185
+ children: annotation.display?.description ?? ''
186
+ }),
187
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(TableCell, {
188
+ align: "right",
189
+ sx: {
190
+ whiteSpace: 'nowrap'
191
+ },
192
+ children: [
193
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
194
+ onClick: ()=>changeAnnotationOrder(index, 'up'),
195
+ disabled: isReadonly || index === 0,
196
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ArrowUp.default, {})
197
+ }),
198
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
199
+ onClick: ()=>changeAnnotationOrder(index, 'down'),
200
+ disabled: isReadonly || index === value.length - 1,
201
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ArrowDown.default, {})
202
+ }),
203
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
204
+ onClick: ()=>{
205
+ setFormAction('update');
206
+ setTarget({
207
+ kind: 'edit',
208
+ index
209
+ });
210
+ },
211
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Pencil.default, {})
212
+ }),
213
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
214
+ disabled: isReadonly,
215
+ onClick: ()=>removeAnnotation(index),
216
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_TrashCan.default, {})
217
+ })
218
+ ]
219
+ })
220
+ ]
221
+ }, `${annotation.display.name}-${index}`))
222
+ })
223
+ ]
224
+ })
225
+ }),
226
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
227
+ display: "flex",
228
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
229
+ variant: "contained",
230
+ startIcon: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Plus.default, {}),
231
+ sx: {
232
+ marginLeft: 'auto'
233
+ },
234
+ disabled: isReadonly,
235
+ onClick: ()=>{
236
+ setFormAction('create');
237
+ setTarget({
238
+ kind: 'new'
239
+ });
240
+ },
241
+ children: "Add Annotation"
242
+ })
243
+ })
244
+ ]
245
+ });
246
+ }
@@ -28,6 +28,7 @@ const _LinksEditor = require("../LinksEditor");
28
28
  const _runtime = require("../../runtime");
29
29
  const _OptionsEditorTabs = require("../OptionsEditorTabs");
30
30
  const _MultiQueryEditor = require("../MultiQueryEditor");
31
+ const _PanelAnnotationsEditor = require("./PanelAnnotationsEditor");
31
32
  const PanelSpecEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
32
33
  const { control, panelDefinition, onQueriesChange, onQueryRun, onPluginSpecChange, onJSONChange } = props;
33
34
  const { kind } = panelDefinition.spec.plugin;
@@ -44,7 +45,7 @@ const PanelSpecEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
44
45
  if (!plugin) {
45
46
  throw new Error(`Missing implementation for panel plugin with kind '${kind}'`);
46
47
  }
47
- const { panelOptionsEditorComponents, hideQueryEditor } = plugin;
48
+ const { panelOptionsEditorComponents, hideQueryEditor, supportsAnnotations } = plugin;
48
49
  let tabs = [];
49
50
  if (!hideQueryEditor) {
50
51
  tabs.push({
@@ -88,6 +89,20 @@ const PanelSpecEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
88
89
  })
89
90
  })));
90
91
  }
92
+ // annotations are common to all panel plugins, but only shown for plugins that render them
93
+ if (supportsAnnotations) {
94
+ tabs.push({
95
+ label: 'Annotations',
96
+ content: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
97
+ control: control,
98
+ name: "panelDefinition.spec.annotations",
99
+ render: ({ field })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelAnnotationsEditor.PanelAnnotationsEditor, {
100
+ value: panelDefinition.spec.annotations ?? [],
101
+ onChange: (annotations)=>field.onChange(annotations)
102
+ })
103
+ })
104
+ });
105
+ }
91
106
  // always show json editor and links editor by default
92
107
  tabs.push({
93
108
  label: 'Links',
@@ -51,8 +51,12 @@ function PluginRegistry(props) {
51
51
  const resource = pluginIndexes.pluginResourcesByNameKindRegistryVersion.get(resourceKey);
52
52
  if (!resource) continue;
53
53
  const pluginModule = await loadPluginModule(resource);
54
+ // Try to get the plugin implementation from the module using the versioned export first
54
55
  const plugin = pluginModule?.[resourceKey];
55
56
  if (plugin) return plugin;
57
+ // If the plugin module doesn't have a versioned export, fallback to the plugin name
58
+ const versionlessPlugin = pluginModule?.[name];
59
+ if (versionlessPlugin) return versionlessPlugin;
56
60
  }
57
61
  throw new Error(`A ${name} plugin for kind '${kind}' is not installed`);
58
62
  }, [
@@ -148,11 +148,11 @@ const getPluginRuntime = ()=>{
148
148
  }
149
149
  },
150
150
  '@perses-dev/spec': {
151
- version: '0.2.0-rc.0',
151
+ version: '0.3.0-beta.0',
152
152
  lib: ()=>require('@perses-dev/spec'),
153
153
  shareConfig: {
154
154
  singleton: true,
155
- requiredVersion: '^0.2.0-rc.0'
155
+ requiredVersion: '^0.3.0-beta.0'
156
156
  }
157
157
  },
158
158
  '@perses-dev/core': {
@@ -164,43 +164,43 @@ const getPluginRuntime = ()=>{
164
164
  }
165
165
  },
166
166
  '@perses-dev/client': {
167
- version: '0.54.0-rc.1',
167
+ version: '0.55.0-beta.0',
168
168
  lib: ()=>require('@perses-dev/client'),
169
169
  shareConfig: {
170
170
  singleton: true,
171
- requiredVersion: '^0.54.0-rc.1'
171
+ requiredVersion: '^0.55.0-beta.0'
172
172
  }
173
173
  },
174
174
  '@perses-dev/components': {
175
- version: '0.54.0-rc.1',
175
+ version: '0.55.0-beta.0',
176
176
  lib: ()=>require('@perses-dev/components'),
177
177
  shareConfig: {
178
178
  singleton: true,
179
- requiredVersion: '^0.54.0-rc.1'
179
+ requiredVersion: '^0.55.0-beta.0'
180
180
  }
181
181
  },
182
182
  '@perses-dev/plugin-system': {
183
- version: '0.54.0-rc.1',
183
+ version: '0.55.0-beta.0',
184
184
  lib: ()=>require('@perses-dev/plugin-system'),
185
185
  shareConfig: {
186
186
  singleton: true,
187
- requiredVersion: '^0.54.0-rc.1'
187
+ requiredVersion: '^0.55.0-beta.0'
188
188
  }
189
189
  },
190
190
  '@perses-dev/explore': {
191
- version: '0.54.0-rc.1',
191
+ version: '0.55.0-beta.0',
192
192
  lib: ()=>require('@perses-dev/explore'),
193
193
  shareConfig: {
194
194
  singleton: true,
195
- requiredVersion: '^0.54.0-rc.1'
195
+ requiredVersion: '^0.55.0-beta.0'
196
196
  }
197
197
  },
198
198
  '@perses-dev/dashboards': {
199
- version: '0.54.0-rc.1',
199
+ version: '0.55.0-beta.0',
200
200
  lib: ()=>require('@perses-dev/dashboards'),
201
201
  shareConfig: {
202
202
  singleton: true,
203
- requiredVersion: '^0.54.0-rc.1'
203
+ requiredVersion: '^0.55.0-beta.0'
204
204
  }
205
205
  },
206
206
  // Below are the shared modules that are used by the plugins, this can be part of the SDK
@@ -21,6 +21,7 @@ Object.defineProperty(exports, "remotePluginLoader", {
21
21
  }
22
22
  });
23
23
  const _pluginsystem = require("@perses-dev/plugin-system");
24
+ const _client = require("@perses-dev/client");
24
25
  const _PluginRuntime = require("./PluginRuntime");
25
26
  const isPluginMetadata = (plugin)=>{
26
27
  return typeof plugin === 'object' && plugin !== null && 'kind' in plugin && 'spec' in plugin && typeof plugin.spec === 'object' && plugin.spec !== null && 'name' in plugin.spec;
@@ -44,9 +45,10 @@ const paramToOptions = (options)=>{
44
45
  };
45
46
  function remotePluginLoader(options) {
46
47
  const { pluginsApiPath, pluginsAssetsPath } = paramToOptions(options);
48
+ const fetchFn = options?.fetchFn ?? _client.fetch;
47
49
  return {
48
50
  getInstalledPlugins: async ()=>{
49
- const pluginsResponse = await fetch(pluginsApiPath);
51
+ const pluginsResponse = await fetchFn(pluginsApiPath);
50
52
  const plugins = await pluginsResponse.json();
51
53
  let pluginModules = [];
52
54
  if (Array.isArray(plugins)) {
@@ -70,7 +70,7 @@ const useUsageMetrics = ()=>{
70
70
  };
71
71
  };
72
72
  const submitMetrics = async (stats)=>{
73
- await (0, _client.fetch)(`${stats.apiPrefix ?? ''}/api/v1/view`, {
73
+ await stats.fetchFn(`${stats.apiPrefix ?? ''}/api/v1/view`, {
74
74
  method: 'POST',
75
75
  headers: {
76
76
  'Content-Type': 'application/json'
@@ -84,6 +84,7 @@ const submitMetrics = async (stats)=>{
84
84
  });
85
85
  };
86
86
  const UsageMetricsProvider = ({ apiPrefix, project, dashboard, children })=>{
87
+ const { fetch } = (0, _client.useFetch)();
87
88
  const ctx = {
88
89
  project: project,
89
90
  dashboard: dashboard,
@@ -91,7 +92,8 @@ const UsageMetricsProvider = ({ apiPrefix, project, dashboard, children })=>{
91
92
  startRenderTime: Date.now(),
92
93
  renderDurationMs: 0,
93
94
  pendingQueries: new Map(),
94
- apiPrefix
95
+ apiPrefix,
96
+ fetchFn: fetch
95
97
  };
96
98
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(UsageMetricsContext.Provider, {
97
99
  value: ctx,
@@ -21,7 +21,6 @@ Object.defineProperty(exports, "executeAction", {
21
21
  }
22
22
  });
23
23
  const _components = require("@perses-dev/components");
24
- const _client = require("@perses-dev/client");
25
24
  const BODY_METHODS = new Set([
26
25
  'POST',
27
26
  'PUT',
@@ -147,7 +146,7 @@ function buildWebhookHeaders(action) {
147
146
  }
148
147
  /**
149
148
  * Execute a webhook action in individual mode (one request per selection)
150
- */ async function executeWebhookIndividual(action, selectionMap, variableState, setActionStatus) {
149
+ */ async function executeWebhookIndividual(action, selectionMap, variableState, setActionStatus, fetchFn) {
151
150
  const entries = Array.from(selectionMap.entries());
152
151
  const count = entries.length;
153
152
  const itemResults = new Map();
@@ -174,7 +173,7 @@ function buildWebhookHeaders(action) {
174
173
  body = bodyResult.text;
175
174
  }
176
175
  // Make the request
177
- const response = await (0, _client.fetch)(urlResult.text, {
176
+ const response = await fetchFn(urlResult.text, {
178
177
  method: action.method,
179
178
  headers: buildWebhookHeaders(action),
180
179
  body: body
@@ -222,7 +221,7 @@ function buildWebhookHeaders(action) {
222
221
  }
223
222
  /**
224
223
  * Execute a webhook action in batch mode (single request with all selections)
225
- */ async function executeWebhookBatch(action, selectionMap, variableState, setActionStatus) {
224
+ */ async function executeWebhookBatch(action, selectionMap, variableState, setActionStatus, fetchFn) {
226
225
  const items = Array.from(selectionMap.values());
227
226
  setActionStatus(action.name, {
228
227
  loading: true
@@ -239,7 +238,7 @@ function buildWebhookHeaders(action) {
239
238
  body = bodyResult.text;
240
239
  }
241
240
  // Make the request
242
- const response = await (0, _client.fetch)(urlResult.text, {
241
+ const response = await fetchFn(urlResult.text, {
243
242
  method: action.method,
244
243
  headers: buildWebhookHeaders(action),
245
244
  body: body
@@ -268,11 +267,11 @@ function buildWebhookHeaders(action) {
268
267
  }
269
268
  /**
270
269
  * Execute a webhook action
271
- */ async function executeWebhookAction(action, selectionMap, variableState, setActionStatus) {
270
+ */ async function executeWebhookAction(action, selectionMap, variableState, setActionStatus, fetchFn) {
272
271
  if (action.batchMode === 'batch') {
273
- return executeWebhookBatch(action, selectionMap, variableState, setActionStatus);
272
+ return executeWebhookBatch(action, selectionMap, variableState, setActionStatus, fetchFn);
274
273
  } else {
275
- return executeWebhookIndividual(action, selectionMap, variableState, setActionStatus);
274
+ return executeWebhookIndividual(action, selectionMap, variableState, setActionStatus, fetchFn);
276
275
  }
277
276
  }
278
277
  /**
@@ -285,7 +284,7 @@ function buildWebhookHeaders(action) {
285
284
  }
286
285
  }
287
286
  async function executeAction(params) {
288
- const { action, selectionMap, variableState, setActionStatus } = params;
287
+ const { action, selectionMap, variableState, setActionStatus, fetchFn } = params;
289
288
  if (selectionMap.size === 0) {
290
289
  return {
291
290
  success: true
@@ -294,7 +293,7 @@ async function executeAction(params) {
294
293
  if (action.type === 'event') {
295
294
  return executeEventAction(action, selectionMap, variableState, setActionStatus);
296
295
  } else if (action.type === 'webhook') {
297
- return executeWebhookAction(action, selectionMap, variableState, setActionStatus);
296
+ return executeWebhookAction(action, selectionMap, variableState, setActionStatus, fetchFn);
298
297
  }
299
298
  return {
300
299
  success: false,
@@ -0,0 +1,15 @@
1
+ import { ReactElement } from 'react';
2
+ import { AnnotationSpec } from '@perses-dev/spec';
3
+ export interface PanelAnnotationsEditorProps {
4
+ value: AnnotationSpec[];
5
+ onChange: (annotations: AnnotationSpec[]) => void;
6
+ isReadonly?: boolean;
7
+ }
8
+ /**
9
+ * Panel-level annotations editor, rendered as a common tab in the panel editor for panel plugins
10
+ * that declare `supportsAnnotations`. Reuses {@link AnnotationEditorForm} for the per-annotation form
11
+ * and propagates every committed change through `onChange`, so it fits the inline panel-editor flow
12
+ * (no separate apply step).
13
+ */
14
+ export declare function PanelAnnotationsEditor({ value, onChange, isReadonly }: PanelAnnotationsEditorProps): ReactElement;
15
+ //# sourceMappingURL=PanelAnnotationsEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanelAnnotationsEditor.d.ts","sourceRoot":"","sources":["../../../src/components/PanelSpecEditor/PanelAnnotationsEditor.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAqB,MAAM,OAAO,CAAC;AAqBxD,OAAO,EAAE,cAAc,EAA2B,MAAM,kBAAkB,CAAC;AAyB3E,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,2BAA2B,GAAG,YAAY,CA6IjH"}