Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saved queries new UI #8469

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/8469.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Enhances the saved query UX ([#8469](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8469))
4 changes: 2 additions & 2 deletions src/plugins/data/public/query/query_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ export class QueryService {
queryString: this.queryStringManager,
savedQueries: createSavedQueryService(
savedObjectsClient,
this.queryStringManager,
application
{ application, uiSettings },
this.queryStringManager
),
state$: this.state$,
timefilter: this.timefilter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import { createSavedQueryService } from './saved_query_service';
import { FilterStateStore } from '../../../common';
import { SavedQueryAttributes } from './types';
import { applicationServiceMock, uiSettingsServiceMock } from '../../../../../core/public/mocks';

const savedQueryAttributes: SavedQueryAttributes = {
title: 'foo',
Expand Down Expand Up @@ -89,7 +90,11 @@ const {
getSavedQueryCount,
} = createSavedQueryService(
// @ts-ignore
mockSavedObjectsClient
mockSavedObjectsClient,
{
application: applicationServiceMock.create(),
uiSettings: uiSettingsServiceMock.createStartContract(),
}
);

describe('saved query service', () => {
Expand Down
51 changes: 29 additions & 22 deletions src/plugins/data/public/query/saved_query/saved_query_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,37 @@
import { first } from 'rxjs/operators';
import { SavedQueryAttributes, SavedQuery, SavedQueryService } from './types';
import { QueryStringContract } from '../query_string';
import { UI_SETTINGS } from '../../../common';

type SerializedSavedQueryAttributes = SavedObjectAttributes &
SavedQueryAttributes & {
query: {
query: string;
language: string;
};
};
type SerializedSavedQueryAttributes = SavedObjectAttributes & SavedQueryAttributes;

export const createSavedQueryService = (
savedObjectsClient: SavedObjectsClientContract,
queryStringManager?: QueryStringContract,
application?: CoreStart['application']
coreStartServices: { application: CoreStart['application']; uiSettings: CoreStart['uiSettings'] },
queryStringManager?: QueryStringContract
): SavedQueryService => {
const { application, uiSettings } = coreStartServices;
const queryEnhancementEnabled = uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED);

const saveQuery = async (attributes: SavedQueryAttributes, { overwrite = false } = {}) => {
if (!attributes.title.length) {
// title is required extra check against circumventing the front end
throw new Error('Cannot create saved query without a title');
}

const query = {
const query: SerializedSavedQueryAttributes['query'] = {
query:
typeof attributes.query.query === 'string'
? attributes.query.query
: JSON.stringify(attributes.query.query),
language: attributes.query.language,
};

const queryObject: SerializedSavedQueryAttributes = {
if (queryEnhancementEnabled && attributes.query.dataset) {
query.dataset = attributes.query.dataset;

Check warning on line 63 in src/plugins/data/public/query/saved_query/saved_query_service.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/query/saved_query/saved_query_service.ts#L63

Added line #L63 was not covered by tests
}

const queryObject: SavedQueryAttributes = {
title: attributes.title.trim(), // trim whitespace before save as an extra precaution against circumventing the front end
description: attributes.description,
query,
Expand All @@ -75,6 +77,10 @@
queryObject.timefilter = attributes.timefilter;
}

if (queryEnhancementEnabled && attributes.isTemplate) {
queryObject.isTemplate = true;

Check warning on line 81 in src/plugins/data/public/query/saved_query/saved_query_service.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/query/saved_query/saved_query_service.ts#L81

Added line #L81 was not covered by tests
}

let rawQueryResponse;
if (!overwrite) {
rawQueryResponse = await savedObjectsClient.create('query', queryObject, {
Expand Down Expand Up @@ -126,8 +132,7 @@
parseSavedQueryObject(savedObject)
);

const currentAppId =
(await application?.currentAppId$?.pipe(first()).toPromise()) ?? Promise.resolve(undefined);
const currentAppId = (await application?.currentAppId$?.pipe(first()).toPromise()) ?? undefined;
const languageService = queryStringManager?.getLanguageService();

// Filtering saved queries based on language supported by cirrent application
Expand Down Expand Up @@ -159,11 +164,8 @@
return await savedObjectsClient.delete('query', id);
};

const parseSavedQueryObject = (savedQuery: {
id: string;
attributes: SerializedSavedQueryAttributes;
}) => {
const queryString = savedQuery.attributes.query.query;
const parseSavedQueryObject = (savedQuery: SavedQuery) => {
const queryString = savedQuery.attributes.query.query as string;
let parsedQuery;
try {
parsedQuery = JSON.parse(queryString);
Expand All @@ -172,7 +174,7 @@
parsedQuery = queryString;
}

const savedQueryItems: SavedQueryAttributes = {
const savedQueryItem: SavedQueryAttributes = {
title: savedQuery.attributes.title || '',
description: savedQuery.attributes.description || '',
query: {
Expand All @@ -181,15 +183,20 @@
},
};

if (queryEnhancementEnabled) {
savedQueryItem.query.dataset = savedQuery.attributes.query.dataset;
savedQueryItem.isTemplate = !!savedQuery.attributes.isTemplate;

Check warning on line 188 in src/plugins/data/public/query/saved_query/saved_query_service.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/query/saved_query/saved_query_service.ts#L187-L188

Added lines #L187 - L188 were not covered by tests
}

if (savedQuery.attributes.filters) {
savedQueryItems.filters = savedQuery.attributes.filters;
savedQueryItem.filters = savedQuery.attributes.filters;
}
if (savedQuery.attributes.timefilter) {
savedQueryItems.timefilter = savedQuery.attributes.timefilter;
savedQueryItem.timefilter = savedQuery.attributes.timefilter;
}
return {
id: savedQuery.id,
attributes: savedQueryItems,
attributes: savedQueryItem,
};
};

Expand Down
3 changes: 3 additions & 0 deletions src/plugins/data/public/query/saved_query/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export interface SavedQuery {
export interface SavedQueryAttributes {
title: string;
description: string;
// If isTemplate is true, then saved query cannot be updated/deleted from the UI and
// will show up under Templates tab for saved queries
isTemplate?: boolean;
query: Query;
filters?: Filter[];
timefilter?: SavedQueryTimeFilter;
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/public/ui/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
@import "./dataset_selector/index";
@import "./query_editor/index";
@import "./shard_failure_modal/shard_failure_modal";
@import "./saved_query_flyouts/saved_query_flyouts";
22 changes: 14 additions & 8 deletions src/plugins/data/public/ui/filter_bar/filter_options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@
unpinFilter,
UI_SETTINGS,
IIndexPattern,
isQueryStringFilter,
} from '../../../common';
import { FilterEditor } from './filter_editor';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { SavedQueryManagementComponent } from '../saved_query_management';
import { SavedQuery, SavedQueryService } from '../../query';
import { SavedQueryMeta } from '../saved_query_form';

interface Props {
intl: InjectedIntl;
Expand All @@ -69,14 +69,15 @@
savedQueryService: SavedQueryService;
// Show when user has privileges to save
showSaveQuery?: boolean;
onSave: () => void;
onSaveAsNew: () => void;
onInitiateSave: () => void;
onInitiateSaveAsNew: () => void;
onLoad: (savedQuery: SavedQuery) => void;
onClearSavedQuery: () => void;
onFiltersUpdated?: (filters: Filter[]) => void;
loadedSavedQuery?: SavedQuery;
useSaveQueryMenu: boolean;
isQueryEditorControl: boolean;
saveQuery: (savedQueryMeta: SavedQueryMeta, saveAsNew?: boolean) => Promise<void>;
}
const maxFilterWidth = 600;

Expand All @@ -88,6 +89,7 @@
const uiSettings = opensearchDashboards.services.uiSettings;
const isPinned = uiSettings!.get(UI_SETTINGS.FILTERS_PINNED_BY_DEFAULT);
const useNewHeader = Boolean(uiSettings!.get(UI_SETTINGS.NEW_HOME_PAGE));
const useNewSavedQueryUI = Boolean(uiSettings!.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED));
const index = Array.isArray(props.indexPatterns) ? props.indexPatterns[0]?.id : undefined;
const newFilter = buildEmptyFilter(isPinned, index);

Expand Down Expand Up @@ -285,8 +287,8 @@
];

const handleSave = () => {
if (props.onSave) {
props.onSave();
if (props.onInitiateSave) {
props.onInitiateSave();

Check warning on line 291 in src/plugins/data/public/ui/filter_bar/filter_options.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/public/ui/filter_bar/filter_options.tsx#L291

Added line #L291 was not covered by tests
}
setIsPopoverOpen(false);
};
Expand All @@ -297,15 +299,17 @@
<SavedQueryManagementComponent
showSaveQuery={props.showSaveQuery}
loadedSavedQuery={props.loadedSavedQuery}
onSave={handleSave}
onSaveAsNew={props.onSaveAsNew!}
onInitiateSave={handleSave}
onInitiateSaveAsNew={props.onInitiateSaveAsNew!}
onLoad={props.onLoad!}
savedQueryService={props.savedQueryService!}
onClearSavedQuery={props.onClearSavedQuery!}
closeMenuPopover={() => {
setIsPopoverOpen(false);
}}
key={'savedQueryManagement'}
useNewSavedQueryUI={useNewSavedQueryUI}
saveQuery={props.saveQuery}
/>,
]}
data-test-subj="save-query-panel"
Expand Down Expand Up @@ -364,6 +368,8 @@
defaultMessage: 'See saved queries',
});

const iconForQueryEditorControlPopoverBtn = useNewSavedQueryUI ? 'boxesHorizontal' : 'folderOpen';

const savedQueryPopoverButton = (
<EuiSmallButtonEmpty
onClick={togglePopover}
Expand All @@ -373,7 +379,7 @@
title={label}
>
<EuiIcon
type={props.isQueryEditorControl ? 'folderOpen' : 'save'}
type={props.isQueryEditorControl ? iconForQueryEditorControlPopoverBtn : 'save'}
className="euiQuickSelectPopover__buttonText"
/>
</EuiSmallButtonEmpty>
Expand Down
Loading
Loading