@grafana/assistant 0.0.12 → 0.0.13

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.
package/README.md CHANGED
@@ -86,7 +86,7 @@ openAssistant({
86
86
 
87
87
  ### Providing Page-Specific Context
88
88
 
89
- You can register context items that are automatically included when the assistant is opened on pages matching specific URL patterns. The `providePageContext` function works like `useState` - it returns a setter function that allows you to update the context dynamically:
89
+ You can register context items that are automatically included when the assistant is opened on pages matching specific URL patterns. The `providePageContext` function returns a setter function that allows you to update the context dynamically:
90
90
 
91
91
  ```typescript
92
92
  import { providePageContext, createContext } from '@grafana/assistant';
@@ -116,16 +116,61 @@ setContext([
116
116
  })
117
117
  ]);
118
118
 
119
- // The context will automatically be included when openAssistant is called from dashboard pages
120
- openAssistant({
121
- prompt: 'Help me analyze this dashboard'
122
- // Current context is automatically included
123
- });
124
-
125
119
  // Clean up when no longer needed
126
120
  setContext.unregister();
127
121
  ```
128
122
 
123
+ ### Using Page Context in React Components
124
+
125
+ For React components, use the `useProvidePageContext` hook which automatically handles cleanup:
126
+
127
+ ```typescript
128
+ import { useProvidePageContext, createContext } from '@grafana/assistant';
129
+
130
+ function DashboardComponent() {
131
+ const dashboardContext = createContext('structured', {
132
+ data: {
133
+ name: 'Dashboard Context',
134
+ pageType: 'dashboard'
135
+ }
136
+ });
137
+
138
+ // Automatically cleans up on unmount
139
+ const setContext = useProvidePageContext('/d/*', [dashboardContext]);
140
+
141
+ // Update context when needed
142
+ const handlePanelSelect = (panelId: string) => {
143
+ setContext([
144
+ dashboardContext,
145
+ createContext('structured', {
146
+ data: {
147
+ name: 'Panel Context',
148
+ selectedPanel: panelId
149
+ }
150
+ })
151
+ ]);
152
+ };
153
+
154
+ return <div>Dashboard content</div>;
155
+ }
156
+ ```
157
+
158
+ ### Accessing Current Page Context
159
+
160
+ Use the `usePageContext` hook to access all active context for the current page:
161
+
162
+ ```typescript
163
+ import { usePageContext } from '@grafana/assistant';
164
+
165
+ function MyComponent() {
166
+ const pageContext = usePageContext();
167
+
168
+ console.log('Active context items:', pageContext);
169
+
170
+ return <div>Page has {pageContext.length} context items</div>;
171
+ }
172
+ ```
173
+
129
174
  ### Creating Context Items
130
175
 
131
176
  The `createContext` function allows you to create structured context items that provide the assistant with additional information about your Grafana resources.
@@ -182,6 +227,7 @@ const structuredContext = createContext('structured', {
182
227
 
183
228
  // Create generic context
184
229
  const genericContext = createContext('unknown', {
230
+ id: 'my-context',
185
231
  text: 'Some additional context information'
186
232
  });
187
233
  ```
@@ -221,7 +267,7 @@ export const getExtensionConfigs = () => [
221
267
 
222
268
  ### React Hooks
223
269
 
224
- #### `useAssistant(): AssistantHook`
270
+ #### `useAssistant(): [boolean, ((props: OpenAssistantProps) => void) | undefined, (() => void) | undefined]`
225
271
 
226
272
  A React hook that provides assistant availability status and control functions.
227
273
 
@@ -230,6 +276,22 @@ A React hook that provides assistant availability status and control functions.
230
276
  - `openAssistant?: (props: OpenAssistantProps) => void` - Function to open the assistant (undefined if not available)
231
277
  - `closeAssistant?: () => void` - Function to close the assistant (undefined if not available)
232
278
 
279
+ #### `usePageContext(): ChatContextItem[]`
280
+
281
+ A React hook that returns all active context items for the current page based on registered URL patterns.
282
+
283
+ **Returns:** Array of `ChatContextItem` objects that match the current page URL.
284
+
285
+ #### `useProvidePageContext(urlPattern: string | RegExp, initialContext?: ChatContextItem[]): (context: ChatContextItem[]) => void`
286
+
287
+ A React hook for providing page context that automatically cleans up on unmount. This is the recommended way to use page context in React components.
288
+
289
+ **Parameters:**
290
+ - `urlPattern` - URL pattern (string or RegExp) to match against page URLs
291
+ - `initialContext` - Initial array of ChatContextItem to provide when the pattern matches (defaults to empty array)
292
+
293
+ **Returns:** A setter function to update the context
294
+
233
295
  ### Availability Functions
234
296
 
235
297
  #### `isAssistantAvailable(): Observable<boolean>`
@@ -274,7 +336,7 @@ Creates a context item that can be passed to the assistant to provide additional
274
336
 
275
337
  #### `providePageContext(urlPattern: string | RegExp, initialContext: ChatContextItem[]): ((context: ChatContextItem[]) => void) & { unregister: () => void }`
276
338
 
277
- Registers context items for specific pages based on URL patterns. Returns a setter function to update the context dynamically, similar to `useState`. The context will be automatically included when the assistant is opened on pages matching the pattern.
339
+ Registers context items for specific pages based on URL patterns. Returns a setter function to update the context dynamically. The context will be automatically included when the assistant is opened on pages matching the pattern.
278
340
 
279
341
  **Parameters:**
280
342
  - `urlPattern` - URL pattern (string with wildcards or RegExp) to match against page URLs
@@ -300,7 +362,105 @@ setDashboardContext([...newContext]);
300
362
  setDashboardContext.unregister();
301
363
  ```
302
364
 
365
+ ### Questions System
366
+
367
+ The questions system allows external parties to provide sample prompts with optional context for specific pages. It reuses the existing page context infrastructure but presents a simpler interface focused on questions.
368
+
369
+ #### `provideQuestions(urlPattern: string | RegExp, initialQuestions: Question[]): ((questions: Question[]) => void) & { unregister: () => void }`
370
+
371
+ Registers questions for specific pages based on URL patterns. Returns a setter function to update the questions dynamically.
372
+
373
+ **Parameters:**
374
+ - `urlPattern` - URL pattern (string with wildcards or RegExp) to match against page URLs
375
+ - `initialQuestions` - Initial array of `Question` to provide when the pattern matches
376
+
377
+ **Returns:** A setter function to update the questions, with an `unregister` method attached for cleanup
378
+
379
+ **Examples:**
380
+ ```typescript
381
+ // Register questions for dashboard pages
382
+ const setQuestions = provideQuestions("/d/*", [
383
+ {
384
+ prompt: "What metrics are available in this dashboard?",
385
+ context: [], // Optional context items created with `createContext`
386
+ },
387
+ {
388
+ prompt: "How can I optimize the queries in this dashboard?",
389
+ context: [
390
+ createContext("dashboard", {
391
+ dashboardUid: 'dashboard-uid',
392
+ dashboardTitle: 'System Overview',
393
+ folderUid: 'folder-uid',
394
+ folderTitle: 'Production'
395
+ }),
396
+ ],
397
+ },
398
+ ]);
399
+
400
+ // Update questions dynamically
401
+ setQuestions([
402
+ {
403
+ prompt: "What are the key insights from this dashboard?",
404
+ context: []
405
+ }
406
+ ]);
407
+
408
+ // Cleanup when done
409
+ setQuestions.unregister();
410
+ ```
411
+
412
+ #### `useProvideQuestions(urlPattern: string | RegExp, initialQuestions?: Question[]): (questions: Question[]) => void`
413
+
414
+ React hook for providing questions that automatically cleans up on unmount. This is the recommended way to use questions in React components.
415
+
416
+ **Parameters:**
417
+ - `urlPattern` - URL pattern (string or RegExp) to match against page URLs
418
+ - `initialQuestions` - Initial array of questions to provide when the pattern matches (defaults to empty array)
419
+
420
+ **Returns:** A setter function to update the questions
421
+
422
+ **Example:**
423
+ ```typescript
424
+ function DashboardComponent() {
425
+ const setQuestions = useProvideQuestions('/d/*', [
426
+ {
427
+ prompt: "What does this dashboard show?",
428
+ },
429
+ {
430
+ prompt: "How can I improve this dashboard?",
431
+ }
432
+ ]);
433
+
434
+ return <div>Dashboard</div>;
435
+ }
436
+ ```
437
+
438
+ #### `useQuestions(): Question[]`
303
439
 
440
+ React hook to get all questions that match the current URL. This filters the page context to only return question-type items.
441
+
442
+ **Returns:** Array of questions from all matching registrations
443
+
444
+ **Example:**
445
+ ```typescript
446
+ function AssistantComponent() {
447
+ const questions = useQuestions();
448
+
449
+ return (
450
+ <div>
451
+ <h3>Suggested Questions:</h3>
452
+ {questions.map((question, index) => (
453
+ <div key={index}>
454
+ <p>{question.prompt}</p>
455
+ {question.context && question.context.length > 0 && (
456
+ <p>Has additional context</p>
457
+ )}
458
+ </div>
459
+ ))}
460
+ </div>
461
+ );
462
+ }
463
+ ```
304
464
 
305
465
  ### Sidebar Types
306
466
 
@@ -310,7 +470,6 @@ setDashboardContext.unregister();
310
470
  type OpenAssistantProps = {
311
471
  prompt?: string;
312
472
  context?: ChatContextItem[];
313
- includePageContext?: boolean;
314
473
  };
315
474
  ```
316
475
 
@@ -318,7 +477,6 @@ Configuration object for opening the assistant.
318
477
 
319
478
  - `prompt` - Optional initial prompt to display
320
479
  - `context` - Optional context items to provide
321
- - `includePageContext` - Whether to automatically include page context for the current URL (defaults to true)
322
480
 
323
481
  #### `ChatContextItem`
324
482
 
@@ -331,7 +489,44 @@ type ChatContextItem = {
331
489
 
332
490
  A context item that provides structured information to the assistant.
333
491
 
492
+ ### Page Context Types
493
+
494
+ #### `PageContextRegistration`
334
495
 
496
+ ```typescript
497
+ interface PageContextRegistration {
498
+ id: string;
499
+ urlPattern: string | RegExp;
500
+ context: ChatContextItem[];
501
+ }
502
+ ```
503
+
504
+ Represents a registered page context mapping.
505
+
506
+ ### Questions Types
507
+
508
+ #### `Question`
509
+
510
+ ```typescript
511
+ interface Question {
512
+ prompt: string; // The sample prompt/question
513
+ context?: ChatContextItem[]; // Optional context items
514
+ }
515
+ ```
516
+
517
+ Represents a question with an optional prompt and context.
518
+
519
+ #### `QuestionRegistration`
520
+
521
+ ```typescript
522
+ interface QuestionRegistration {
523
+ id: string;
524
+ urlPattern: string | RegExp;
525
+ questions: Question[];
526
+ }
527
+ ```
528
+
529
+ Represents a registered questions mapping.
335
530
 
336
531
  ### Context Types
337
532
 
@@ -400,10 +595,7 @@ interface CreateLabelValueContextParams {
400
595
 
401
596
  ```typescript
402
597
  interface StructuredNodeDataParams {
403
- data: {
404
- name: string;
405
- [key: string]: any;
406
- };
598
+ data: Record<string, any>;
407
599
  title?: string;
408
600
  icon?: IconName;
409
601
  }
@@ -413,7 +605,8 @@ interface StructuredNodeDataParams {
413
605
 
414
606
  ```typescript
415
607
  interface NodeDataParams {
416
- text: string;
608
+ id: string;
609
+ text?: string;
417
610
  title?: string;
418
611
  icon?: IconName;
419
612
  }
@@ -483,6 +676,24 @@ const CALLBACK_EXTENSION_POINT = 'grafana-assistant-app/callback/v0-alpha';
483
676
 
484
677
  The extension point ID for registering assistant functions.
485
678
 
679
+ ### Additional Exported Types
680
+
681
+ The package also exports the following types for advanced use cases:
682
+
683
+ ```typescript
684
+ // Data types for context items
685
+ export type DashboardNodeData;
686
+ export type DatasourceNodeData;
687
+ export type FolderNodeData;
688
+ export type LabelNameNodeData;
689
+ export type LabelValueNodeData;
690
+ export type StructuredNodeData;
691
+ export type TreeNode;
692
+
693
+ // Enums
694
+ export enum ItemDataType;
695
+ ```
696
+
486
697
  ## License
487
698
 
488
699
  Apache-2.0
@@ -5,4 +5,5 @@ export * from './datasource';
5
5
  export * from './factory';
6
6
  export * from './label';
7
7
  export * from './page';
8
+ export * from './questions';
8
9
  export * from './types';
@@ -26,4 +26,6 @@ export declare function providePageContext(urlPattern: string | RegExp, initialC
26
26
  * @returns A setter function to update the context
27
27
  */
28
28
  export declare function useProvidePageContext(urlPattern: string | RegExp, initialContext?: ChatContextItem[]): (context: ChatContextItem[]) => void;
29
- export declare function usePageContext(): ChatContextItem[];
29
+ export declare function usePageContext(options?: {
30
+ allowQuestions: boolean;
31
+ }): ChatContextItem[];
@@ -0,0 +1,39 @@
1
+ import { ChatContextItem } from './types';
2
+ export interface Question {
3
+ prompt: string;
4
+ context?: ChatContextItem[];
5
+ }
6
+ export interface QuestionRegistration {
7
+ id: string;
8
+ urlPattern: string | RegExp;
9
+ questions: Question[];
10
+ }
11
+ /**
12
+ * Registers questions for specific pages based on URL patterns.
13
+ * Returns a setter function to update the questions dynamically, similar to useState.
14
+ *
15
+ * If a registration with the same URL pattern already exists, it will be replaced.
16
+ *
17
+ * @param urlPattern - URL pattern (string or RegExp) to match against page URLs
18
+ * @param initialQuestions - Initial array of questions to provide when the pattern matches
19
+ * @returns A setter function to update the questions, with an unregister method attached
20
+ */
21
+ export declare function provideQuestions(urlPattern: string | RegExp, initialQuestions: Question[]): ((questions: Question[]) => void) & {
22
+ unregister: () => void;
23
+ };
24
+ /**
25
+ * React hook for providing questions that automatically cleans up on unmount.
26
+ * This is the recommended way to use questions in React components.
27
+ *
28
+ * @param urlPattern - URL pattern (string or RegExp) to match against page URLs
29
+ * @param initialQuestions - Initial array of questions to provide when the pattern matches
30
+ * @returns A setter function to update the questions
31
+ */
32
+ export declare function useProvideQuestions(urlPattern: string | RegExp, initialQuestions?: Question[]): (questions: Question[]) => void;
33
+ /**
34
+ * React hook to get all questions that match the current URL.
35
+ * This filters the page context to only return question-type items.
36
+ *
37
+ * @returns Array of questions from all matching registrations
38
+ */
39
+ export declare function useQuestions(): Question[];
@@ -26,6 +26,7 @@ export interface TreeNode {
26
26
  title?: string;
27
27
  navigable: boolean;
28
28
  selectable?: boolean;
29
+ img?: string;
29
30
  icon?: IconName;
30
31
  data?: any;
31
32
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { createContext, ChatContextItem, DashboardNodeData, DatasourceNodeData, FolderNodeData, ItemDataType, LabelNameNodeData, LabelValueNodeData, StructuredNodeData, TreeNode, providePageContext, PageContextRegistration, usePageContext, } from './context/index';
1
+ export { createContext, ChatContextItem, DashboardNodeData, DatasourceNodeData, FolderNodeData, ItemDataType, LabelNameNodeData, LabelValueNodeData, StructuredNodeData, TreeNode, providePageContext, PageContextRegistration, usePageContext, provideQuestions, useProvideQuestions, useQuestions, Question, QuestionRegistration, } from './context/index';
2
2
  export * from './functions';
3
3
  export * from './hook';
4
4
  export * from './plugin';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- (()=>{"use strict";var e,t={d:(e,a)=>{for(var n in a)t.o(a,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:a[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},a={};function n(e){let t=5381;for(let a=0;a<e.length;a++)t=(t<<5)+t+e.charCodeAt(a);return(t>>>0).toString(16)}t.r(a),t.d(a,{CALLBACK_EXTENSION_POINT:()=>N,DashboardNodeData:()=>o,DatasourceNodeData:()=>d,FolderNodeData:()=>i,ItemDataType:()=>e,LabelNameNodeData:()=>l,LabelValueNodeData:()=>c,StructuredNodeData:()=>r,closeAssistant:()=>V,createContext:()=>p,getExposeAssistantFunctionsConfig:()=>D,isAssistantAvailable:()=>I,newFunctionNamespace:()=>U,openAssistant:()=>P,providePageContext:()=>E,useAssistant:()=>O,usePageContext:()=>y}),function(e){e.Unknown="unknown",e.Datasource="datasource",e.LabelName="label_name",e.LabelValue="label_value",e.Dashboard="dashboard",e.DashboardFolder="dashboard_folder",e.Structured="structured"}(e||(e={}));class s{constructor(e){this.params=e,this.text="",this.id=n(e.id)}formatForLLM(t){var a,n;return{type:e.Unknown,codeElementIds:t,data:{name:null!==(a=this.params.text)&&void 0!==a?a:"",text:null!==(n=this.params.text)&&void 0!==n?n:""}}}}class r{constructor(e){this.params=e,this.id=n(JSON.stringify(e.data))}formatForLLM(t){return{type:e.Structured,codeElementIds:t,data:this.params.data}}}class o extends s{constructor(e){super({...e,id:e.dashboardUid}),this.text="",this.dashboardUid=e.dashboardUid,this.dashboardTitle=e.dashboardTitle,this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.dashboardTitle}formatForLLM(t){return{type:e.Dashboard,codeElementIds:t,data:{name:this.dashboardTitle,dashboardUid:this.dashboardUid,dashboardTitle:this.dashboardTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class i extends s{constructor(e){super({...e,id:e.folderUid}),this.text="",this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.folderTitle}formatForLLM(t){return{type:e.DashboardFolder,codeElementIds:t,data:{name:this.folderTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class d extends s{constructor(e){super({...e,id:e.datasourceUid}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName,this.text=e.datasourceName}formatForLLM(t){return{type:e.Datasource,codeElementIds:t,data:{name:this.datasourceName,uid:this.datasourceUid,type:this.datasourceType,text:this.text}}}}class l extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}`}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.text=e.labelName}formatForLLM(t){return{type:e.LabelName,codeElementIds:t,data:{name:this.labelName,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName,text:this.text}}}}class c extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}-${e.labelValue}`}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.labelValue=e.labelValue,this.text=e.labelValue}formatForLLM(t){return{type:e.LabelValue,codeElementIds:t,data:{name:this.labelValue,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName,labelValue:this.labelValue,text:this.text}}}}const u={[e.Datasource]:"database",[e.LabelName]:"database",[e.LabelValue]:"database",[e.Dashboard]:"dashboard",[e.DashboardFolder]:"folder",[e.Unknown]:"circle-mono",[e.Structured]:"gf-grid"};function h(t,a){return t===e.Datasource?a.datasourceName:t===e.LabelName?a.labelName:t===e.LabelValue?a.labelValue:t===e.Dashboard?a.dashboardTitle:t===e.DashboardFolder?a.folderTitle:t===e.Structured?a.data.name:"Given Context"}function p(e,t){var a,n;const p=function(e,t){switch(e){case"datasource":return new d(t);case"label_name":return new l(t);case"label_value":return new c(t);case"dashboard":return new o(t);case"dashboard_folder":return new i(t);case"structured":return new r(t);case"unknown":return new s(t);default:return console.error(`Unknown context type: ${e}`),new s(t)}}(e,t);return{node:{id:p.id,name:null!==(a=t.title)&&void 0!==a?a:h(e,t),icon:null!==(n=t.icon)&&void 0!==n?n:u[e],navigable:!1,selectable:!0,data:p},occurrences:[]}}const f=require("@grafana/runtime"),b=require("react"),m=[],v="grafana-assistant:page-context-sync",x="grafana-assistant:page-context-update",w="grafana-assistant:page-context-remove",g="grafana-assistant:location-changed";let L=!1;function E(e,t){const a=m.findIndex((t=>{return a=t.urlPattern,n=e,"string"==typeof a&&"string"==typeof n?a===n:a instanceof RegExp&&n instanceof RegExp&&a.source===n.source&&a.flags===n.flags;var a,n}));let n;-1!==a?(n=m[a],n.context=[...t]):(n={id:`page-context-${Date.now()}-${Math.random().toString(36).slice(2,11)}`,urlPattern:e,context:[...t]},m.push(n)),window.dispatchEvent(new CustomEvent(x,{detail:n})),window.dispatchEvent(new CustomEvent(v,{detail:{registry:m}}));const s=e=>{const t=m.findIndex((e=>e.id===n.id));-1!==t&&(m[t].context=[...e],window.dispatchEvent(new CustomEvent(x,{detail:m[t]})))};return s.unregister=()=>{const e=m.findIndex((e=>e.id===n.id));-1!==e&&(m.splice(e,1),window.dispatchEvent(new CustomEvent(w,{detail:{id:n.id}})))},s}function y(){const[e,t]=(0,b.useState)([]),a=(0,f.useLocationService)(),n=(0,b.useRef)("");return(0,b.useEffect)((()=>{const e=()=>{const e=function(e,t){if(!e)return[];const a=[];for(const n of t)T(e,n.urlPattern)&&a.push(...n.context);return a}(a.getLocation().pathname,m);t(e)},s=()=>{e()},r=t=>{var n;const s=null===(n=t.detail)||void 0===n?void 0:n.pathname;s&&s===a.getLocation().pathname&&e()},o=a.getLocationObservable().subscribe((t=>{const a=t.pathname;a!==n.current&&(n.current=a,function(e){window.dispatchEvent(new CustomEvent(g,{detail:{pathname:e}}))}(a),e())}));return e(),window.addEventListener(v,s),window.addEventListener(x,s),window.addEventListener(w,s),window.addEventListener(g,r),()=>{o.unsubscribe(),window.removeEventListener(v,s),window.removeEventListener(x,s),window.removeEventListener(w,s),window.removeEventListener(g,r)}}),[a]),e}function T(e,t){if(t instanceof RegExp)return t.test(e);if("string"==typeof t){const a=t.replace(/\*\*/g,"\0DOUBLE_STAR\0").replace(/\*/g,"[^/]*").replace(/\u0000DOUBLE_STAR\u0000/g,".*").replace(/\?/g,".");return new RegExp(`^${a}$`).test(e)}return!1}L||(window.addEventListener(v,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.registry;if(a){const e=new Set(m.map((e=>e.id))),t=a.filter((t=>!e.has(t.id)));m.push(...t)}})),window.addEventListener(x,(e=>{const t=e.detail;if(t){const e=m.findIndex((e=>e.id===t.id));-1!==e?m[e]=t:m.push(t)}})),window.addEventListener(w,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.id;if(a){const e=m.findIndex((e=>e.id===a));-1!==e&&m.splice(e,1)}})),L=!0);const N="grafana-assistant-app/callback/v0-alpha";function U(e,t){return{namespace:e,functions:t}}function D(e){return{title:"callback",targets:[N],fn:()=>e.map((e=>({namespace:e.namespace,functions:e.functions})))}}const S=require("rxjs");function I(){return(0,f.getObservablePluginLinks)({extensionPointId:"grafana/extension-sidebar/v0-alpha"}).pipe((0,S.map)((e=>e.some((e=>"grafana-assistant-app"===e.pluginId&&"Grafana Assistant"===e.title)))))}const A=require("@grafana/data");class C extends A.BusEventWithPayload{}C.type="open-extension-sidebar";class F extends A.BusEventBase{}function P(e){!function(e,t,a){const n=new C({pluginId:"grafana-assistant-app",componentTitle:"Grafana Assistant",props:a});(0,f.getAppEvents)().publish(n)}(0,0,{initialPrompt:e.prompt,initialContext:e.context})}function V(){!function(){const e=new F;(0,f.getAppEvents)().publish(e)}()}function O(){const[e,t]=(0,b.useState)(!1);return(0,b.useEffect)((()=>{const e=I().subscribe((e=>t(e)));return()=>{e.unsubscribe()}}),[]),[e,e?P:void 0,e?V:void 0]}F.type="close-extension-sidebar",module.exports=a})();
1
+ (()=>{"use strict";var e,t={d:(e,a)=>{for(var n in a)t.o(a,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:a[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},a={};function n(e){let t=5381;for(let a=0;a<e.length;a++)t=(t<<5)+t+e.charCodeAt(a);return(t>>>0).toString(16)}t.r(a),t.d(a,{CALLBACK_EXTENSION_POINT:()=>I,DashboardNodeData:()=>o,DatasourceNodeData:()=>d,FolderNodeData:()=>i,ItemDataType:()=>e,LabelNameNodeData:()=>l,LabelValueNodeData:()=>u,StructuredNodeData:()=>r,closeAssistant:()=>_,createContext:()=>f,getExposeAssistantFunctionsConfig:()=>C,isAssistantAvailable:()=>F,newFunctionNamespace:()=>A,openAssistant:()=>$,providePageContext:()=>y,provideQuestions:()=>N,useAssistant:()=>k,usePageContext:()=>L,useProvideQuestions:()=>U,useQuestions:()=>D}),function(e){e.Unknown="unknown",e.Datasource="datasource",e.LabelName="label_name",e.LabelValue="label_value",e.Dashboard="dashboard",e.DashboardFolder="dashboard_folder",e.Structured="structured"}(e||(e={}));class s{constructor(e){this.params=e,this.text="",this.id=n(e.id)}formatForLLM(t){var a,n;return{type:e.Unknown,codeElementIds:t,data:{name:null!==(a=this.params.text)&&void 0!==a?a:"",text:null!==(n=this.params.text)&&void 0!==n?n:""}}}}class r{constructor(e){this.params=e,this.id=n(JSON.stringify(e.data))}formatForLLM(t){return{type:e.Structured,codeElementIds:t,data:this.params.data}}}class o extends s{constructor(e){super({...e,id:e.dashboardUid}),this.text="",this.dashboardUid=e.dashboardUid,this.dashboardTitle=e.dashboardTitle,this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.dashboardTitle}formatForLLM(t){return{type:e.Dashboard,codeElementIds:t,data:{name:this.dashboardTitle,dashboardUid:this.dashboardUid,dashboardTitle:this.dashboardTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class i extends s{constructor(e){super({...e,id:e.folderUid}),this.text="",this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.folderTitle}formatForLLM(t){return{type:e.DashboardFolder,codeElementIds:t,data:{name:this.folderTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class d extends s{constructor(e){super({...e,id:e.datasourceUid}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName,this.text=e.datasourceName}formatForLLM(t){return{type:e.Datasource,codeElementIds:t,data:{name:this.datasourceName,uid:this.datasourceUid,type:this.datasourceType,text:this.text}}}}class l extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}`}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.text=e.labelName}formatForLLM(t){return{type:e.LabelName,codeElementIds:t,data:{name:this.labelName,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName,text:this.text}}}}class u extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}-${e.labelValue}`}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.labelValue=e.labelValue,this.text=e.labelValue}formatForLLM(t){return{type:e.LabelValue,codeElementIds:t,data:{name:this.labelValue,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName,labelValue:this.labelValue,text:this.text}}}}const c={[e.Datasource]:"database",[e.LabelName]:"database",[e.LabelValue]:"database",[e.Dashboard]:"dashboard",[e.DashboardFolder]:"folder",[e.Unknown]:"circle-mono",[e.Structured]:"gf-grid"};function p(t,a){return t===e.Datasource?a.datasourceName:t===e.LabelName?a.labelName:t===e.LabelValue?a.labelValue:t===e.Dashboard?a.dashboardTitle:t===e.DashboardFolder?a.folderTitle:t===e.Structured?a.data.name:"Given Context"}function f(e,t){var a,n;const f=function(e,t){switch(e){case"datasource":return new d(t);case"label_name":return new l(t);case"label_value":return new u(t);case"dashboard":return new o(t);case"dashboard_folder":return new i(t);case"structured":return new r(t);case"unknown":return new s(t);default:return console.error(`Unknown context type: ${e}`),new s(t)}}(e,t);return{node:{id:f.id,name:null!==(a=t.title)&&void 0!==a?a:p(e,t),icon:null!==(n=t.icon)&&void 0!==n?n:c[e],navigable:!1,selectable:!0,data:f},occurrences:[]}}const h=require("@grafana/runtime"),m=require("react"),b=[],v="grafana-assistant:page-context-sync",x="grafana-assistant:page-context-update",g="grafana-assistant:page-context-remove",w="grafana-assistant:location-changed";let E=!1;function y(e,t){const a=b.findIndex((t=>{return a=t.urlPattern,n=e,"string"==typeof a&&"string"==typeof n?a===n:a instanceof RegExp&&n instanceof RegExp&&a.source===n.source&&a.flags===n.flags;var a,n}));let n;-1!==a?(n=b[a],n.context=[...t]):(n={id:`page-context-${Date.now()}-${Math.random().toString(36).slice(2,11)}`,urlPattern:e,context:[...t]},b.push(n)),window.dispatchEvent(new CustomEvent(x,{detail:n})),window.dispatchEvent(new CustomEvent(v,{detail:{registry:b}}));const s=e=>{const t=b.findIndex((e=>e.id===n.id));-1!==t&&(b[t].context=[...e],window.dispatchEvent(new CustomEvent(x,{detail:b[t]})))};return s.unregister=()=>{const e=b.findIndex((e=>e.id===n.id));-1!==e&&(b.splice(e,1),window.dispatchEvent(new CustomEvent(g,{detail:{id:n.id}})))},s}function L(e={allowQuestions:!1}){const[t,a]=(0,m.useState)([]),n=(0,h.useLocationService)(),s=(0,m.useRef)("");return(0,m.useEffect)((()=>{const e=()=>{const e=function(e,t){if(!e)return[];const a=[];for(const n of t)T(e,n.urlPattern)&&a.push(...n.context);return a}(n.getLocation().pathname,b);a(e)},t=()=>{e()},r=t=>{var a;const s=null===(a=t.detail)||void 0===a?void 0:a.pathname;s&&s===n.getLocation().pathname&&e()},o=n.getLocationObservable().subscribe((t=>{const a=t.pathname;a!==s.current&&(s.current=a,function(e){window.dispatchEvent(new CustomEvent(w,{detail:{pathname:e}}))}(a),e())}));return e(),window.addEventListener(v,t),window.addEventListener(x,t),window.addEventListener(g,t),window.addEventListener(w,r),()=>{o.unsubscribe(),window.removeEventListener(v,t),window.removeEventListener(x,t),window.removeEventListener(g,t),window.removeEventListener(w,r)}}),[n]),e.allowQuestions?t:t.filter((e=>{var t;return"question"!==(null===(t=e.node.data)||void 0===t?void 0:t.type)}))}function T(e,t){if(t instanceof RegExp)return t.test(e);if("string"==typeof t){const a=t.replace(/\*\*/g,"\0DOUBLE_STAR\0").replace(/\*/g,"[^/]*").replace(/\u0000DOUBLE_STAR\u0000/g,".*").replace(/\?/g,".");return new RegExp(`^${a}$`).test(e)}return!1}function N(e,t){const a=e=>e.map(((e,t)=>({node:{id:`question-${t}`,name:e.prompt,navigable:!1,selectable:!0,icon:"question-circle",data:{type:"question",prompt:e.prompt,context:e.context||[]}},occurrences:[]}))),n=y(e,a(t)),s=e=>{n(a(e))};return s.unregister=n.unregister,s}function U(e,t=[]){const a=e=>e.map(((e,t)=>({node:{id:`question-${t}`,name:e.prompt,navigable:!1,selectable:!0,icon:"question-circle",data:{type:"question",prompt:e.prompt,context:e.context||[]}},occurrences:[]}))),n=function(e,t=[]){const a=(0,m.useRef)(),n=(0,m.useRef)(t);return n.current=t,(0,m.useEffect)((()=>(a.current=y(e,n.current),()=>{var e;null===(e=a.current)||void 0===e||e.unregister()})),[e]),(0,m.useEffect)((()=>{a.current&&a.current(t)}),[t]),(0,m.useCallback)((e=>{var t;null===(t=a.current)||void 0===t||t.call(a,e)}),[])}(e,a(t));return e=>{n(a(e))}}function D(){const e=L({allowQuestions:!0});return S(e)}E||(window.addEventListener(v,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.registry;if(a){const e=new Set(b.map((e=>e.id))),t=a.filter((t=>!e.has(t.id)));b.push(...t)}})),window.addEventListener(x,(e=>{const t=e.detail;if(t){const e=b.findIndex((e=>e.id===t.id));-1!==e?b[e]=t:b.push(t)}})),window.addEventListener(g,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.id;if(a){const e=b.findIndex((e=>e.id===a));-1!==e&&b.splice(e,1)}})),E=!0);const S=e=>e.filter((e=>{var t;return"question"===(null===(t=e.node.data)||void 0===t?void 0:t.type)})).map((e=>{var t,a;return{prompt:(null===(t=e.node.data)||void 0===t?void 0:t.prompt)||e.node.name,context:(null===(a=e.node.data)||void 0===a?void 0:a.context)||[]}})),I="grafana-assistant-app/callback/v0-alpha";function A(e,t){return{namespace:e,functions:t}}function C(e){return{title:"callback",targets:[I],fn:()=>e.map((e=>({namespace:e.namespace,functions:e.functions})))}}const P=require("rxjs");function F(){return(0,h.getObservablePluginLinks)({extensionPointId:"grafana/extension-sidebar/v0-alpha"}).pipe((0,P.map)((e=>e.some((e=>"grafana-assistant-app"===e.pluginId&&"Grafana Assistant"===e.title)))))}const V=require("@grafana/data");class q extends V.BusEventWithPayload{}q.type="open-extension-sidebar";class O extends V.BusEventBase{}function $(e){!function(e,t,a){const n=new q({pluginId:"grafana-assistant-app",componentTitle:"Grafana Assistant",props:a});(0,h.getAppEvents)().publish(n)}(0,0,{initialPrompt:e.prompt,initialContext:e.context})}function _(){!function(){const e=new O;(0,h.getAppEvents)().publish(e)}()}function k(){const[e,t]=(0,m.useState)(!1);return(0,m.useEffect)((()=>{const e=F().subscribe((e=>t(e)));return()=>{e.unsubscribe()}}),[]),[e,e?$:void 0,e?_:void 0]}O.type="close-extension-sidebar",module.exports=a})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/assistant",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Type definitions and helper functions for Grafana Assistant",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",