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

feat(566): add custom filters #578

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
6 changes: 3 additions & 3 deletions packages/core/src/environment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { core, devspace } from '@sap/bas-sdk';
import type { GuidedAnswersQueryFilterOptions, IDE } from '@sap/guided-answers-extension-types';
import type { FilterStack, IDE } from '@sap/guided-answers-extension-types';
import environmentJson from './environment.json';

const devSpaceComponentsMap: { [devspace: string]: string[] } = environmentJson.devSpaceComponentsMap;
Expand Down Expand Up @@ -42,8 +42,8 @@ export async function getDevSpace(): Promise<string> {
* @param ide - runtime IDE, VSCODE or SBAS
* @returns - filters for given ide
*/
export async function getFiltersForIde(ide: IDE): Promise<GuidedAnswersQueryFilterOptions> {
const filterOptions: GuidedAnswersQueryFilterOptions = {};
export async function getFiltersForIde(ide: IDE): Promise<FilterStack> {
const filterOptions: FilterStack = {};
let components: Set<string> = new Set();
let basDevSpace;

Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/guided-answers-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
GuidedAnswerNode,
GuidedAnswerNodeId,
GuidedAnswersFeedback,
GuidedAnswersQueryFilterOptions,
FilterStack,
GuidedAnswersQueryOptions,
GuidedAnswersQueryPagingOptions,
GuidedAnswerTree,
Expand Down Expand Up @@ -96,21 +96,21 @@ function convertImageSrc(body: string, host: string): string {
* Convert query filter options to URL get parameter string.
*
* @param filters - optional filters
* @param filters.component - optional component filter
* @param filters.product - optional product filter
* @param filters.component - component filter
* @param filters.product - product filter
* @param paging - optional paging, if not provided set to high response size with 0 offset
* @returns - URL get parameters as string
*/
function convertQueryOptionsToGetParams(
filters: GuidedAnswersQueryFilterOptions = {},
filters: FilterStack = {},
paging: GuidedAnswersQueryPagingOptions = { responseSize: DEFAULT_MAX_RESULTS, offset: 0 }
): string {
const parameters = [
// Filter parameters
...Object.keys(filters).map(
(filterName) =>
`${filterName}=${filters[filterName as keyof typeof filters]
?.map((filterValue) => encodeURIComponent(`"${filterValue}"`))
.map((filterValue) => encodeURIComponent(`"${filterValue}"`))
.join(',')}`
),
// Paging parameters
Expand Down
34 changes: 34 additions & 0 deletions packages/ide-extension/src/custom-filters/customFilters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Memento } from 'vscode';
import type { FilterStack } from '@sap/guided-answers-extension-types';
import { logError } from '../logger/logger';

let globalStateApi: Memento;

/**
* Initialize the custom filters functionality by passing VSCode global state.
*
* @param globalState - VSCodes global state for extension
*/
export function initCustomFilters(globalState: Memento) {
globalStateApi = globalState;
}

/**
* Return the list of stored custom filters.
*
* @returns - list of custom filters
*/
export function getAllCustomFilters(): FilterStack[] {
return globalStateApi?.get<FilterStack[]>('customFilters') ?? [];
}

/**
* Update the stored custom filters.
*
* @param customFilters - array of custom filters
*/
export function updateCustomFilters(customFilters: FilterStack[]) {
globalStateApi
.update('customFilters', customFilters)
.then(undefined, (error) => logError(`Error updating customFilters.`, error));
}
1 change: 1 addition & 0 deletions packages/ide-extension/src/custom-filters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getAllCustomFilters, initCustomFilters, updateCustomFilters } from './customFilters';
2 changes: 2 additions & 0 deletions packages/ide-extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { GuidedAnswersUriHandler } from './links';
import type { StartOptions } from './types';
import { initBookmarks } from './bookmarks';
import { initLastVisited } from './last-visited';
import { initCustomFilters } from './custom-filters';

/**
* Activate function is called by VSCode when the extension gets active.
Expand All @@ -23,6 +24,7 @@ export function activate(context: ExtensionContext): void {
try {
initBookmarks(context.globalState);
initLastVisited(context.globalState);
initCustomFilters(context.globalState);
} catch (error) {
logError(`Error during initialization of functionality that relies on VSCode's global state storage.`, error);
}
Expand Down
17 changes: 13 additions & 4 deletions packages/ide-extension/src/panel/guidedAnswersPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SYNCHRONIZE_BOOKMARK,
UPDATE_BOOKMARKS,
UPDATE_LAST_VISITED_GUIDES,
UPDATE_CUSTOM_FILTERS,
updateGuidedAnswerTrees,
updateActiveNode,
updateNetworkStatus,
Expand All @@ -34,7 +35,8 @@ import {
goToAllAnswers,
updateBookmark,
getLastVisitedGuides,
setQuickFilters
getAutoFilters,
getCustomFilters
} from '@sap/guided-answers-extension-types';
import { getFiltersForIde, getGuidedAnswerApi } from '@sap/guided-answers-extension-core';
import { getHtml } from './html';
Expand All @@ -45,6 +47,7 @@ import { setCommonProperties, trackAction, trackEvent } from '../telemetry';
import { extractLinkInfo, generateExtensionLink, generateWebLink } from '../links/link-info';
import { getAllBookmarks, updateBookmarks } from '../bookmarks';
import { updateLastVisitedGuides, getAllLastVisitedGuides } from '../last-visited';
import { getAllCustomFilters, updateCustomFilters } from '../custom-filters';

/**
* Class that represents the Guided Answers panel, which hosts the webview UI.
Expand Down Expand Up @@ -164,13 +167,14 @@ export class GuidedAnswersPanel {
if (this.startOptions) {
await this.processStartOptions(this.startOptions);
}
await this.loadQuickFilters(this.ide);
await this.loadAutoFilters(this.ide);
this.postActionToWebview(
getBetaFeatures(workspace.getConfiguration('sap.ux.guidedAnswer').get<boolean>('betaFeatures') ?? false)
);
this.postActionToWebview(updateNetworkStatus('OK'));
this.postActionToWebview(getBookmarks(getAllBookmarks()));
this.postActionToWebview(getLastVisitedGuides(getAllLastVisitedGuides()));
this.postActionToWebview(getCustomFilters(getAllCustomFilters()));
}

/**
Expand Down Expand Up @@ -214,12 +218,12 @@ export class GuidedAnswersPanel {
*
* @param ide - environment like VSCODE or BAS
*/
private async loadQuickFilters(ide: IDE): Promise<void> {
private async loadAutoFilters(ide: IDE): Promise<void> {
try {
const filters = await getFiltersForIde(ide);
logger.logInfo(`Filters for environment '${ide}':`, filters);
if (Object.keys(filters).length > 0) {
this.postActionToWebview(setQuickFilters([filters]));
this.postActionToWebview(getAutoFilters([filters]));
}
} catch (error: any) {
logger.logError(`Error while retrieving context information, error was:`, error);
Expand Down Expand Up @@ -379,6 +383,11 @@ export class GuidedAnswersPanel {
);
break;
}
case UPDATE_CUSTOM_FILTERS: {
updateCustomFilters(action.payload);
this.postActionToWebview(getCustomFilters(getAllCustomFilters()));
break;
}
default: {
// Nothing to do if the action is not handled
}
Expand Down
14 changes: 7 additions & 7 deletions packages/ide-extension/test/panel/guidedAnswersPanel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
RESTORE_STATE,
SEND_TELEMETRY,
GET_BOOKMARKS,
AppState,
SYNCHRONIZE_BOOKMARK,
UPDATE_BOOKMARKS,
GET_LAST_VISITED_GUIDES,
Expand All @@ -34,7 +33,8 @@ import type {
GuidedAnswerTree,
GuidedAnswerTreeId,
GuidedAnswerTreeSearchResult,
LastVisitedGuide
LastVisitedGuide,
AppState
} from '@sap/guided-answers-extension-types';
import { GuidedAnswersPanel, GuidedAnswersSerializer } from '../../src/panel/guidedAnswersPanel';
import * as logger from '../../src/logger/logger';
Expand All @@ -58,7 +58,7 @@ const getWebViewPanelMock = (onDidReceiveMessage: (callback: WebviewMessageCallb
onDidChangeViewState: jest.fn(),
onDidDispose: jest.fn(),
reveal: jest.fn()
} as unknown as WebviewPanel);
}) as unknown as WebviewPanel;

const getApiMock = (firstNodeId?: number): GuidedAnswerAPI =>
({
Expand All @@ -78,7 +78,7 @@ const getApiMock = (firstNodeId?: number): GuidedAnswerAPI =>
getTrees: () => Promise.resolve([{ TREE_ID: 1 }, { TREE_ID: 2 }, { TREE_ID: 3 }]),
sendFeedbackOutcome: jest.fn(),
sendFeedbackComment: jest.fn()
} as unknown as GuidedAnswerAPI);
}) as unknown as GuidedAnswerAPI;

const delay = async (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms));
Expand Down Expand Up @@ -132,7 +132,7 @@ describe('GuidedAnswersPanel', () => {
expect(loggerMock.info).toBeCalledWith('Webview is ready to receive actions');
});

test('GuidedAnswersPanel for SBAS, should set quick filters', async () => {
test('GuidedAnswersPanel for SBAS, should set auto filters', async () => {
// Mock setup
let onDidReceiveMessageMock: WebviewMessageCallback = () => {};
const webViewPanelMock = getWebViewPanelMock((callback: WebviewMessageCallback) => {
Expand All @@ -152,9 +152,9 @@ describe('GuidedAnswersPanel', () => {
expect(loggerMock.info).toBeCalledWith('Webview is ready to receive actions');
expect(getFiltersForIdeSpy).toBeCalledWith('SBAS');
const searchCall = (webViewPanelMock.webview.postMessage as jest.Mock).mock.calls.find((c) =>
c.find((p: { type: string }) => p.type === 'SET_QUICK_FILTERS')
c.find((p: { type: string }) => p.type === 'SET_AUTO_FILTERS')
)[0];
expect(searchCall).toEqual({ type: 'SET_QUICK_FILTERS', payload: [{ component: ['AB-CD', 'EFG-H'] }] });
expect(searchCall).toEqual({ type: 'SET_AUTO_FILTERS', payload: [{ component: ['AB-CD', 'EFG-H'] }] });
});

test('GuidedAnswersPanel for SBAS with error in getFiltersForIde(), should log error', async () => {
Expand Down
24 changes: 19 additions & 5 deletions packages/types/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ import type {
UpdateLastVisitedGuides,
UpdateBookmarksPayload,
GoToHomePage,
SetQuickFilters,
GuidedAnswersQueryFilterOptions
GetAutoFilters,
GetCustomFilters,
UpdateCustomFilters,
FilterStack
} from './types';
import {
EXECUTE_COMMAND,
Expand Down Expand Up @@ -84,7 +86,9 @@ import {
GET_LAST_VISITED_GUIDES,
UPDATE_LAST_VISITED_GUIDES,
GO_TO_HOME_PAGE,
SET_QUICK_FILTERS
GET_AUTO_FILTERS,
GET_CUSTOM_FILTERS,
UPDATE_CUSTOM_FILTERS
} from './types';

export const updateGuidedAnswerTrees = (payload: UpdateGuidedAnswerTrees['payload']): UpdateGuidedAnswerTrees => ({
Expand Down Expand Up @@ -243,7 +247,17 @@ export const updateLastVisitedGuide = (payload: LastVisitedGuide[]): UpdateLastV
payload
});

export const setQuickFilters = (payload: GuidedAnswersQueryFilterOptions[]): SetQuickFilters => ({
type: SET_QUICK_FILTERS,
export const getAutoFilters = (payload: FilterStack[]): GetAutoFilters => ({
type: GET_AUTO_FILTERS,
payload
});

export const getCustomFilters = (payload: FilterStack[]): GetCustomFilters => ({
type: GET_CUSTOM_FILTERS,
payload
});

export const updateCustomFilters = (payload: FilterStack[]): UpdateCustomFilters => ({
type: UPDATE_CUSTOM_FILTERS,
payload
});
38 changes: 26 additions & 12 deletions packages/types/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ export interface GuidedAnswerTree {

export interface GuidedAnswersQueryOptions {
query?: string;
filters?: GuidedAnswersQueryFilterOptions;
filters?: FilterStack;
paging?: GuidedAnswersQueryPagingOptions;
}

export interface GuidedAnswersQueryFilterOptions {
component?: string[];
product?: string[];
export interface FilterStack {
component: string[];
product: string[];
}

export interface GuidedAnswersQueryPagingOptions {
Expand Down Expand Up @@ -219,7 +219,9 @@ export type GuidedAnswerActions =
| UpdateGuidedAnswerTrees
| UpdateNetworkStatus
| WebviewReady
| SetQuickFilters;
| GetAutoFilters
| GetCustomFilters
| UpdateCustomFilters;

export type NetworkStatus = 'OK' | 'LOADING' | 'ERROR';

Expand All @@ -232,15 +234,15 @@ export interface AppState {
activeNodeSharing: ShareNodeLinks | null;
betaFeatures: boolean;
guideFeedback: null | boolean;
selectedProductFilters: string[];
selectedComponentFilters: string[];
selectedFilters: FilterStack;
pageSize: number;
feedbackStatus: boolean;
feedbackResponse: boolean;
bookmarks: Bookmarks;
activeScreen: 'HOME' | 'SEARCH' | 'NODE';
lastVisitedGuides: LastVisitedGuide[];
quickFilters: GuidedAnswersQueryFilterOptions[];
autoFilters: FilterStack[];
customFilters: FilterStack[];
}

export const UPDATE_GUIDED_ANSWER_TREES = 'UPDATE_GUIDED_ANSWER_TREES';
Expand Down Expand Up @@ -447,8 +449,20 @@ export interface SynchronizeBookmark {
payload: Bookmark;
}

export const SET_QUICK_FILTERS = 'SET_QUICK_FILTERS';
export interface SetQuickFilters {
type: typeof SET_QUICK_FILTERS;
payload: GuidedAnswersQueryFilterOptions[];
export const GET_AUTO_FILTERS = 'GET_AUTO_FILTERS';
export interface GetAutoFilters {
type: typeof GET_AUTO_FILTERS;
payload: FilterStack[];
}

export const GET_CUSTOM_FILTERS = 'GET_CUSTOM_FILTERS';
export interface GetCustomFilters {
type: typeof GET_CUSTOM_FILTERS;
payload: FilterStack[];
}

export const UPDATE_CUSTOM_FILTERS = 'UPDATE_CUSTOM_FILTERS';
export interface UpdateCustomFilters {
type: typeof UPDATE_CUSTOM_FILTERS;
payload: FilterStack[];
}
4 changes: 3 additions & 1 deletion packages/webapp/src/webview/i18n/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@
"COPIED_TO_CLIPBOARD_DESC": "Copy this link to share via email or messages. When pasted into the search input field of the Guided Answers extension, it will navigate you straight to this node.",
"VIEW_ON_WEBSITE": "View on the GA website",
"COPY_WITH_INSTRUCTIONS": "Copy link with instructions",
"COPY_WITH_INSTRUCTIONS_TEXT": "To resolve your reported issue, open Guided Answers extension by SAP, and follow the steps mentioned in the guide.\n If your IDE is VSCode, please click on the following link: {{-extensionLink}} .\n If your IDE is SAP Business Application Studio, then launch Guided Answers via the command \"SAP: Open Guided Answers\" and paste the following guide shortlink into the search input field: {{-extensionLink}} ."
"COPY_WITH_INSTRUCTIONS_TEXT": "To resolve your reported issue, open Guided Answers extension by SAP, and follow the steps mentioned in the guide.\n If your IDE is VSCode, please click on the following link: {{-extensionLink}} .\n If your IDE is SAP Business Application Studio, then launch Guided Answers via the command \"SAP: Open Guided Answers\" and paste the following guide shortlink into the search input field: {{-extensionLink}} .",
"CLEAR": "Clear",
"SAVE": "Save"
}
3 changes: 2 additions & 1 deletion packages/webapp/src/webview/state/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ export {
getLastVisitedGuides,
updateBookmark,
synchronizeBookmark,
updateLastVisitedGuide
updateLastVisitedGuide,
updateCustomFilters
} from '@sap/guided-answers-extension-types';
Loading