Skip to content

Commit

Permalink
Merge branch 'main' into hide_incompatible_index_patterns
Browse files Browse the repository at this point in the history
Signed-off-by: Jincheng Wan <[email protected]>
  • Loading branch information
Kapian1234 authored Oct 21, 2024
2 parents 272d0cb + 98bf315 commit 097523f
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 12 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- fix: Remove the cache of insight agent id in node server([#343](https://github.com/opensearch-project/dashboards-assistant/pull/343))
- fix: Fix error time field and add filter for same name index patterns([#345](https://github.com/opensearch-project/dashboards-assistant/pull/345))
- refactor: Add data source info in discover url when navigating([#347](https://github.com/opensearch-project/dashboards-assistant/pull/347))
- Hide incompatible index patterns ([#354] (https://github.com/opensearch-project/dashboards-assistant/pull/354))
- feat: only display ai actions that compatible with the datasource([#350](https://github.com/opensearch-project/dashboards-assistant/pull/350))
- feat: take index pattern and query assistant input to text2viz app([#349](https://github.com/opensearch-project/dashboards-assistant/pull/349))
- feat: Hide incompatible index patterns ([#354] (https://github.com/opensearch-project/dashboards-assistant/pull/354))


### 📈 Features/Enhancements

Expand Down
38 changes: 35 additions & 3 deletions public/components/ui_action_context_menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,73 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useState, useRef } from 'react';
import React, { useState, useRef, useEffect } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { EuiButtonEmpty, EuiContextMenu, EuiPopover } from '@elastic/eui';
import { i18n } from '@osd/i18n';

import { buildContextMenuForActions } from '../../../../src/plugins/ui_actions/public';
import { AI_ASSISTANT_QUERY_EDITOR_TRIGGER } from '../ui_triggers';
import { getUiActions } from '../services';
import { DataPublicPluginSetup } from '../../../../src/plugins/data/public';

interface Props {
data: DataPublicPluginSetup;
label?: string;
}

export const ActionContextMenu = (props: Props) => {
const uiActions = getUiActions();
const actionsRef = useRef(uiActions.getTriggerActions(AI_ASSISTANT_QUERY_EDITOR_TRIGGER));
const [open, setOpen] = useState(false);
const [actionContext, setActionContext] = useState({
datasetId: props.data.query.queryString.getQuery().dataset?.id ?? '',
datasetType: props.data.query.queryString.getQuery().dataset?.type ?? '',
dataSourceId: props.data.query.queryString.getQuery().dataset?.dataSource?.id,
});

useEffect(() => {
const subscription = props.data.query.queryString.getUpdates$().subscribe((query) => {
if (query.dataset) {
setActionContext((state) => ({
...state,
datasetId: query.dataset?.id ?? '',
datasetType: query.dataset?.type ?? '',
dataSourceId: query.dataset?.dataSource?.id,
}));
}
});
return () => {
subscription.unsubscribe();
};
}, [props.data.query.queryString]);

const panels = useAsync(
() =>
buildContextMenuForActions({
actions: actionsRef.current.map((action) => ({
action,
context: {},
context: {
datasetId: actionContext.datasetId,
datasetType: actionContext.datasetType,
dataSourceId: actionContext.dataSourceId,
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
trigger: AI_ASSISTANT_QUERY_EDITOR_TRIGGER as any,
})),
closeMenu: () => setOpen(false),
title: '',
}),
[]
[actionContext.datasetId, actionContext.datasetType, actionContext.dataSourceId]
);

if (actionsRef.current.length === 0) {
return null;
}

// If context menu has no item, the action button should be disabled
const actionDisabled = (panels.value?.[0]?.items ?? []).length === 0;

return (
<EuiPopover
button={
Expand All @@ -51,6 +81,8 @@ export const ActionContextMenu = (props: Props) => {
onClick={() => setOpen(!open)}
iconSide="right"
flush="both"
isDisabled={actionDisabled}
isLoading={panels.loading}
>
{props.label ||
i18n.translate('dashboardAssistant.branding.assistantActionButton.label', {
Expand Down
13 changes: 10 additions & 3 deletions public/components/visualization/text2viz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { v4 as uuidv4 } from 'uuid';

import { useCallback } from 'react';
import { useObservable } from 'react-use';
import { useParams } from 'react-router-dom';
import { useLocation, useParams } from 'react-router-dom';
import { SourceSelector } from './source_selector';
import type { IndexPattern } from '../../../../../src/plugins/data/public';
import chatIcon from '../../assets/chat.svg';
Expand Down Expand Up @@ -52,9 +52,16 @@ import { HeaderVariant } from '../../../../../src/core/public';
import { TEXT2VEGA_INPUT_SIZE_LIMIT } from '../../../common/constants/llm';
import { FeedbackThumbs } from '../feedback_thumbs';

export const INDEX_PATTERN_URL_SEARCH_KEY = 'indexPatternId';
export const ASSISTANT_INPUT_URL_SEARCH_KEY = 'assistantInput';

export const Text2Viz = () => {
const { savedObjectId } = useParams<{ savedObjectId?: string }>();
const [selectedSource, setSelectedSource] = useState('');
const { search } = useLocation();
const searchParams = useMemo(() => new URLSearchParams(search), [search]);
const [selectedSource, setSelectedSource] = useState(
searchParams.get(INDEX_PATTERN_URL_SEARCH_KEY) ?? ''
);
const [savedObjectLoading, setSavedObjectLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const {
Expand Down Expand Up @@ -89,7 +96,7 @@ export const Text2Viz = () => {

const useUpdatedUX = uiSettings.get('home:useNewHomePage');

const [input, setInput] = useState('');
const [input, setInput] = useState(searchParams.get(ASSISTANT_INPUT_URL_SEARCH_KEY) ?? '');
const [editorInput, setEditorInput] = useState('');
const text2vegaRef = useRef(new Text2Vega(http, data.search, savedObjects));

Expand Down
53 changes: 49 additions & 4 deletions public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ import {
} from './services';
import { ConfigSchema } from '../common/types/config';
import { DataSourceService } from './services/data_source_service';
import { ASSISTANT_API, DEFAULT_USER_NAME } from '../common/constants/llm';
import {
ASSISTANT_API,
DEFAULT_USER_NAME,
TEXT2PPL_AGENT_CONFIG_ID,
TEXT2VEGA_RULE_BASED_AGENT_CONFIG_ID,
TEXT2VEGA_WITH_INSTRUCTIONS_AGENT_CONFIG_ID,
} from '../common/constants/llm';
import { IncontextInsightProps } from './components/incontext_insight';
import { AssistantService } from './services/assistant_service';
import { ActionContextMenu } from './components/ui_action_context_menu';
Expand All @@ -60,6 +66,11 @@ import {
} from './vis_nlq/saved_object_loader';
import { NLQVisualizationEmbeddableFactory } from './components/visualization/embeddable/nlq_vis_embeddable_factory';
import { NLQ_VISUALIZATION_EMBEDDABLE_TYPE } from './components/visualization/embeddable/nlq_vis_embeddable';
import {
ASSISTANT_INPUT_URL_SEARCH_KEY,
INDEX_PATTERN_URL_SEARCH_KEY,
} from './components/visualization/text2viz';
import { DEFAULT_DATA } from '../../../src/plugins/data/common';

export const [getCoreStart, setCoreStart] = createGetterSetter<CoreStart>('CoreStart');

Expand Down Expand Up @@ -260,7 +271,7 @@ export class AssistantPlugin
order: 2000,
isEnabled$: () => of(true),
getSearchBarButton: () => {
return <ActionContextMenu label={this.config.branding.label} />;
return <ActionContextMenu label={this.config.branding.label} data={setupDeps.data} />;
},
},
},
Expand Down Expand Up @@ -328,8 +339,42 @@ export class AssistantPlugin
order: 1,
getDisplayName: () => 'Generate visualization',
getIconType: () => 'visLine' as const,
execute: async () => {
core.application.navigateToApp(TEXT2VIZ_APP_ID);
// T2Viz is only compatible with data sources that have certain agents configured
isCompatible: async (context) => {
// t2viz only supports selecting index pattern at the moment
if (context.datasetType === DEFAULT_DATA.SET_TYPES.INDEX_PATTERN && context.datasetId) {
const res = await assistantServiceStart.client.agentConfigExists(
[
TEXT2VEGA_RULE_BASED_AGENT_CONFIG_ID,
TEXT2VEGA_WITH_INSTRUCTIONS_AGENT_CONFIG_ID,
TEXT2PPL_AGENT_CONFIG_ID,
],
{
dataSourceId: context.dataSourceId,
}
);
return res.exists;
}
return false;
},
execute: async (context) => {
const url = new URL(core.application.getUrlForApp(TEXT2VIZ_APP_ID, { absolute: true }));
if (context.datasetId && context.datasetType === DEFAULT_DATA.SET_TYPES.INDEX_PATTERN) {
url.searchParams.set(INDEX_PATTERN_URL_SEARCH_KEY, context.datasetId);
}
/**
* TODO: the current implementation of getting query assistant input needs to be refactored
* once query assistant is moved to dashboard-assistant repo. Currently, there is no better
* way to get the input value as the query assistant is currently implemented in OSD core.
*/
const queryAssistInputEle = document.getElementsByClassName('queryAssist__input')[0];
if (queryAssistInputEle instanceof HTMLInputElement) {
const input = queryAssistInputEle.value;
if (input) {
url.searchParams.set(ASSISTANT_INPUT_URL_SEARCH_KEY, input);
}
}
core.application.navigateToUrl(url.toString());
},
});
const savedVisNLQLoader = createVisNLQSavedObjectLoader({
Expand Down
6 changes: 5 additions & 1 deletion public/ui_triggers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ export const AI_ASSISTANT_QUERY_EDITOR_TRIGGER = 'AI_ASSISTANT_QUERY_EDITOR_TRIG

declare module '../../../src/plugins/ui_actions/public' {
export interface TriggerContextMapping {
[AI_ASSISTANT_QUERY_EDITOR_TRIGGER]: {};
[AI_ASSISTANT_QUERY_EDITOR_TRIGGER]: {
datasetId: string;
datasetType: string;
dataSourceId?: string;
};
}
}

Expand Down

0 comments on commit 097523f

Please sign in to comment.