Skip to content

Commit

Permalink
GDB-7784 implement show saved queries action (#44)
Browse files Browse the repository at this point in the history
* GDB-7784 implement show saved queries action

## What
Introduce a show saved queries action.

## Why
Save query action exists in current implementation in the GDB WB. It allows the user to load and see the available saved queries then for each query additional actions can be performed, e.g. select, edit, delete.

## How
* Add custom button in the yasqe buttons extension point. The button rises an event for loading of the saved queries. Handling of this event is responsibility of the client who then must set the queries list in the config. Setting the queries in the config triggers the popup to appear.
* Add a saved queries popup which implements the visualization of the saved queries list. Each saved query is represented as a link and can be
selected via click which then opens the query in a new yasgui tab. The dialog can be closed via click outside.
* Implemented tests.

* Fix review notes. Changed the model of the saved query response in order to be more convenient and readable. Improved styling of the saved queries popup.

* Fixed test
  • Loading branch information
svilenvelikov authored Jan 16, 2023
1 parent 08954a2 commit 1870d6c
Show file tree
Hide file tree
Showing 23 changed files with 633 additions and 30 deletions.
12 changes: 10 additions & 2 deletions cypress/e2e/editor-actions/configure-actions.spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@ describe('Configure editor actions', () => {
ActionsPageSteps.visit();
});

it('Should see all custom actions by default', () => {
YasqeSteps.getCreateSavedQueryButton().should('be.visible');
it('Should see all custom actions by default in particular order', () => {
YasqeSteps.getActionButtons().should('have.length', 2);
YasqeSteps.getActionButton(0).should('have.attr', 'title', 'Create saved query');
YasqeSteps.getActionButton(1).should('have.attr', 'title', 'Show saved queries');
});

it('Should be able to toggle yasqe action buttons', () => {
// Toggle save query action
ActionsPageSteps.hideSaveQueryAction();
YasqeSteps.getCreateSavedQueryButton().should('not.exist');
ActionsPageSteps.showSaveQueryAction();
YasqeSteps.getCreateSavedQueryButton().should('be.visible');
// Toggle show saved queries action
ActionsPageSteps.hideShowSavedQueriesAction();
YasqeSteps.getShowSavedQueriesButton().should('not.exist');
ActionsPageSteps.showShowSavedQueriesAction();
YasqeSteps.getShowSavedQueriesButton().should('be.visible');
});
});
59 changes: 59 additions & 0 deletions cypress/e2e/editor-actions/show-saved-queries.spec.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {YasqeSteps} from "../../steps/yasqe-steps";
import {QueryStubs} from "../../stubs/query-stubs";
import ActionsPageSteps from "../../steps/actions-page-steps";
import {YasguiSteps} from "../../steps/yasgui-steps";

describe('Show saved queries action', () => {
beforeEach(() => {
QueryStubs.stubDefaultQueryResponse();
// Given I have opened a page with the yasgui
// And there is an open tab with sparql query in it
ActionsPageSteps.visit();
});

it('Should open a popup with the saved queries list', () => {
// When I click on show saved queries button
YasqeSteps.showSavedQueries();
// Then I expect that a popup with a saved queries list to be opened
YasqeSteps.getSavedQueriesPopup().should('be.visible');
YasqeSteps.getSavedQueries().should('have.length', 12);
YasqeSteps.verifySavedQueries([
{queryName: 'Add statements'},
{queryName: 'Clear graph'},
{queryName: 'new query'},
{queryName: 'q1'},
{queryName: 'q2'},
{queryName: 'q3'},
{queryName: 'q4'},
{queryName: 'q5'},
{queryName: 'q6'},
{queryName: 'q7'},
{queryName: 'q8'},
{queryName: 'q9'}
]);
});

it('Should be able to select a query from the list', () => {
// Given I have opened the saved queries popup
YasqeSteps.showSavedQueries();
YasqeSteps.getSavedQueriesPopup().should('be.visible');
// When I select a query from the list
YasqeSteps.selectSavedQuery(1);
// Then I expect that the popup should be closed
YasqeSteps.getSavedQueriesPopup().should('not.exist');
// And the query will be populated in a new tab in the yasgui
YasguiSteps.getTabs().should('have.length', 2);
YasguiSteps.getCurrentTab().should('contain', 'Clear graph');
YasqeSteps.getTabQuery(1).should('equal', 'CLEAR GRAPH <http://example>');
});

it('Should be able to close the popup by clicking outside', () => {
// Given I have opened the saved queries popup
YasqeSteps.showSavedQueries();
YasqeSteps.getSavedQueriesPopup().should('be.visible');
// When I click outside of the popup
cy.get('body').click();
// Then the popup should be closed
YasqeSteps.getSavedQueriesPopup().should('not.exist');
});
});
8 changes: 8 additions & 0 deletions cypress/steps/actions-page-steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ export default class ActionsPageSteps {
static showSaveQueryAction() {
cy.get('#showSaveQueryAction').click();
}

static hideShowSavedQueriesAction() {
cy.get('#hideLoadSavedQueriesAction').click();
}

static showShowSavedQueriesAction() {
cy.get('#showLoadSavedQueriesAction').click();
}
}
4 changes: 4 additions & 0 deletions cypress/steps/yasgui-steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export class YasguiSteps {
return cy.get('.tab');
}

static getCurrentTab() {
return cy.get('.tab.active');
}

static openANewTab() {
cy.get('button.addTab').click();
}
Expand Down
44 changes: 44 additions & 0 deletions cypress/steps/yasqe-steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ export class YasqeSteps {
return cy.get(".yasqe:visible");
}

static getActionsToolbar() {
return this.getEditor().find('.yasqe_buttons');
}

static getActionButtons() {
return this.getActionsToolbar().find('.custom-button');
}

static getActionButton(index: number) {
return this.getActionButtons().eq(index);
}

static getExecuteQueryButton() {
return cy.get('.yasqe_queryButton');
}
Expand Down Expand Up @@ -86,4 +98,36 @@ export class YasqeSteps {
static getControlBar() {
return cy.get('.controlbar');
}

static getShowSavedQueriesButton() {
return cy.get('.yasqe_showSavedQueriesButton');
}

static showSavedQueries() {
this.getShowSavedQueriesButton().click();
}

static getSavedQueriesPopup() {
return cy.get('.saved-queries-popup');
}

static getSavedQueries() {
return this.getSavedQueriesPopup().find('.saved-query');
}

static verifySavedQueries(data: {queryName: string}[]) {
this.getSavedQueries().each((el, index) => {
cy.wrap(el).should('contain', data[index].queryName);
})
}

static selectSavedQuery(index: number) {
this.getSavedQueries().eq(index).find('a').click();
}

static getTabQuery(tabIndex: number) {
return cy.get('.yasqe .CodeMirror').then((el) => {
return el[tabIndex].CodeMirror.getValue();
});
}
}
38 changes: 38 additions & 0 deletions ontotext-yasgui-web-component/docs/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,44 @@ export class ServiceName {
}
```

# Integration events - Actions

In result of certain operations in the yasgui component are raised events that are responsibility
of the client to handle properly and to respond in the expected way.

* **queryExecuted: EventEmitter\<QueryEvent>**:
* Description: Event emitted when before query to be executed.
* Response: None
* **queryResponse: EventEmitter\<QueryResponseEvent>**
* Description: Event emitted when after query response is returned.
* Response: None
* **createSavedQuery: EventEmitter\<SaveQueryData>**:
* Description: Event emitted when saved query payload is collected and the query should be saved by the component client.
* Response: The client must set in the config following data.
```
{
savedQuery: {
saveSuccess: boolean; // if save was successful or not
errorMessage: string[]; // if any error happen then messages must be passed back
}
};
```
* **loadSavedQueries: EventEmitter\<boolean>**:
* Description: Event emitted when saved queries is expected to be loaded by the component client and provided back in order to be displayed.
* Response: The client must set in the config following data:
```
{
savedQueries: {
data: {
queryName: string;
query: string;
owner: string;
isPublic: boolean;
}[]
}
}
```

# Useful References
1. [State Management with State Tunnel in StencilJS](https://www.joshmorony.com/state-management-with-state-tunnel-in-stencil-js/)
2. [Using Services/Providers to Share Data in a StencilJS Application](https://www.joshmorony.com/using-services-providers-to-share-data-in-a-stencil-js-application/)
33 changes: 32 additions & 1 deletion ontotext-yasgui-web-component/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { ExternalYasguiConfiguration } from "./models/external-yasgui-configuration";
import { QueryEvent, QueryResponseEvent } from "./models/event";
import { SaveQueryData } from "./models/model";
import { SavedQueriesData, SaveQueryData } from "./models/model";
export namespace Components {
/**
* This is the custom web component which is adapter for the yasgui library. It allows as to
Expand Down Expand Up @@ -42,6 +42,9 @@ export namespace Components {
*/
"data": SaveQueryData;
}
interface SavedQueriesPopup {
"data": SavedQueriesData;
}
interface YasguiTooltip {
"dataTooltip": string;
"placement": string;
Expand All @@ -56,6 +59,10 @@ export interface SaveQueryDialogCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLSaveQueryDialogElement;
}
export interface SavedQueriesPopupCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLSavedQueriesPopupElement;
}
declare global {
/**
* This is the custom web component which is adapter for the yasgui library. It allows as to
Expand Down Expand Up @@ -85,6 +92,12 @@ declare global {
prototype: HTMLSaveQueryDialogElement;
new (): HTMLSaveQueryDialogElement;
};
interface HTMLSavedQueriesPopupElement extends Components.SavedQueriesPopup, HTMLStencilElement {
}
var HTMLSavedQueriesPopupElement: {
prototype: HTMLSavedQueriesPopupElement;
new (): HTMLSavedQueriesPopupElement;
};
interface HTMLYasguiTooltipElement extends Components.YasguiTooltip, HTMLStencilElement {
}
var HTMLYasguiTooltipElement: {
Expand All @@ -94,6 +107,7 @@ declare global {
interface HTMLElementTagNameMap {
"ontotext-yasgui": HTMLOntotextYasguiElement;
"save-query-dialog": HTMLSaveQueryDialogElement;
"saved-queries-popup": HTMLSavedQueriesPopupElement;
"yasgui-tooltip": HTMLYasguiTooltipElement;
}
}
Expand Down Expand Up @@ -127,6 +141,10 @@ declare namespace LocalJSX {
* Event emitted when saved query payload is collected and the query should be saved by the component client.
*/
"onCreateSavedQuery"?: (event: OntotextYasguiCustomEvent<SaveQueryData>) => void;
/**
* Event emitted when saved queries is expected to be loaded by the component client and provided back in order to be displayed.
*/
"onLoadSavedQueries"?: (event: OntotextYasguiCustomEvent<boolean>) => void;
/**
* Event emitted when before query to be executed.
*/
Expand All @@ -150,6 +168,17 @@ declare namespace LocalJSX {
*/
"onInternalSaveQueryEvent"?: (event: SaveQueryDialogCustomEvent<SaveQueryData>) => void;
}
interface SavedQueriesPopup {
"data"?: SavedQueriesData;
/**
* Event fired when the saved queries popup should be closed.
*/
"onInternalCloseSavedQueriesPopupEvent"?: (event: SavedQueriesPopupCustomEvent<any>) => void;
/**
* Event fired when a saved query is selected from the list.
*/
"onInternalSaveQuerySelectedEvent"?: (event: SavedQueriesPopupCustomEvent<SaveQueryData>) => void;
}
interface YasguiTooltip {
"dataTooltip"?: string;
"placement"?: string;
Expand All @@ -158,6 +187,7 @@ declare namespace LocalJSX {
interface IntrinsicElements {
"ontotext-yasgui": OntotextYasgui;
"save-query-dialog": SaveQueryDialog;
"saved-queries-popup": SavedQueriesPopup;
"yasgui-tooltip": YasguiTooltip;
}
}
Expand All @@ -183,6 +213,7 @@ declare module "@stencil/core" {
*/
"ontotext-yasgui": LocalJSX.OntotextYasgui & JSXBase.HTMLAttributes<HTMLOntotextYasguiElement>;
"save-query-dialog": LocalJSX.SaveQueryDialog & JSXBase.HTMLAttributes<HTMLSaveQueryDialogElement>;
"saved-queries-popup": LocalJSX.SavedQueriesPopup & JSXBase.HTMLAttributes<HTMLSavedQueriesPopupElement>;
"yasgui-tooltip": LocalJSX.YasguiTooltip & JSXBase.HTMLAttributes<HTMLYasguiTooltipElement>;
}
}
Expand Down
Loading

0 comments on commit 1870d6c

Please sign in to comment.