Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
2f7fe29
added custom editor, not fully operational
EmilioTR May 13, 2024
0bdf196
experimental implememtation, still not good
EmilioTR May 13, 2024
655a49a
working qury results
EmilioTR May 16, 2024
0e28667
working query prompt and added error handling
EmilioTR May 16, 2024
4f2a5fc
First visual representation, works completely
EmilioTR May 16, 2024
1947e11
temporary attempt to save new queries and show title
EmilioTR May 28, 2024
73a8821
Merge branch 'main' into fix/54-custom-editor
EmilioTR May 30, 2024
32c088d
adding custom query shows it as a loose query in the menu
EmilioTR Jun 3, 2024
4dc09ab
Adding custom query now works with a custom group
EmilioTR Jun 3, 2024
7818a72
extracted group adding logic to the manager (more robust for extension)
EmilioTR Jun 3, 2024
9e6671f
added description and multiple source option
EmilioTR Jun 4, 2024
d6cb664
custom query editor operational
EmilioTR Jun 4, 2024
4b1eddd
Merge branch 'main' into fix/54-CE-bis
EmilioTR Jun 17, 2024
21e4782
update
EmilioTR Jun 17, 2024
e4a1a0e
formcomponent with searchParams
EmilioTR Jun 17, 2024
d35e197
Made edit operational and updated structure
EmilioTR Jun 18, 2024
f5c5472
update for a custom query using an index file
EmilioTR Jun 20, 2024
3cf244e
custom query creation is operational
EmilioTR Jun 20, 2024
45d4f02
added a little check to prevent a crash when redirecting
EmilioTR Jun 20, 2024
7d0b292
added a delete function
EmilioTR Jun 20, 2024
de22b49
added icons
EmilioTR Jun 20, 2024
dbf5029
UI updates
EmilioTR Jun 24, 2024
6830fa8
Can now also save queries
EmilioTR Jun 24, 2024
fce29f2
small UI update
EmilioTR Jun 24, 2024
b1a4079
small update
EmilioTR Jun 24, 2024
f088ba2
Added e2e tests for the custom edittor
EmilioTR Jun 24, 2024
b4a0fdd
Some text updates
mvanbrab Jun 25, 2024
a5a5e7b
Another text mod
mvanbrab Jun 25, 2024
9855a4b
extra user experience
EmilioTR Jun 25, 2024
7572d1e
Merge branch 'fix/54-CE-bis' of https://github.com/SolidLabResearch/g…
EmilioTR Jun 25, 2024
655c00c
added a check, to prevent wrong inputs
EmilioTR Jun 25, 2024
f13b9fd
updated the buttons UI
EmilioTR Jun 25, 2024
a86c981
added navigate on creation
EmilioTR Jun 25, 2024
0a55354
meeting feedback added
EmilioTR Jun 25, 2024
19b60e0
finalised custom query tests
EmilioTR Jun 25, 2024
d8e8834
Merge branch 'main' into fix/54-CE-bis
EmilioTR Jun 25, 2024
c633acc
Added custom queries to the README
mvanbrab Jun 25, 2024
e9a1703
CHANGELOG
mvanbrab Jun 25, 2024
c872eaf
changed placeholders for sources
mvanbrab Jun 25, 2024
54b9f91
JSON placeholder and initial contents format
mvanbrab Jun 26, 2024
19719e6
default SPARQL queries
mvanbrab Jun 26, 2024
c0163f8
custom editor tests work again
mvanbrab Jun 26, 2024
c4216c7
open query group when a custom query is created/deleted/editted
EmilioTR Jun 26, 2024
60059d2
source index query can use any variable name
mvanbrab Jun 26, 2024
29e879c
doc on source URLs
mvanbrab Jun 26, 2024
041421b
changed the scope of templated options to add more features
EmilioTR Jun 26, 2024
92de0dd
updated tests
EmilioTR Jun 26, 2024
46519e2
Merge branch 'fix/54-CE-bis' into fix/54-CE-bis-martin
mvanbrab Jun 26, 2024
aa7cfe7
?source in SPARQL query for sources index file
mvanbrab Jun 26, 2024
4df496c
CHANGELOG
mvanbrab Jun 26, 2024
56117ea
test fixes
EmilioTR Jun 26, 2024
6642529
Merge branch 'fix/54-CE-bis' of https://github.com/SolidLabResearch/g…
EmilioTR Jun 26, 2024
17f52cc
Code clean up
EmilioTR Jun 26, 2024
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- It is now possible to add and edit custom queries (#54).

### Changed

- For logged in users not having a username, the webID is displayed (#133).
Expand All @@ -17,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Forced CSS's to not return content type application/ld+json, which induced a CORS error on some CSS server versions (#131).
- Queries based on index file now work for any variable, not just ?object (#136).

## [1.2.1] - 2024-06-17

Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Table of contents:
* [Adding variable type](#adding-variable-type)
* [Templated queries](#templated-queries)
* [Query icons](#query-icons)
* [Custom queries](#custom-queries)
* [Representation Mapper](#representation-mapper)
* [Using the local pods](#using-the-local-pods)
* [Testing](#testing)
Expand Down Expand Up @@ -140,7 +141,7 @@ The set of sources over which a query will be executed is derived from two *opti

If both inputs are present, the query will be executed over the superset of sources.

The (auxiliary) query provided in `sourceIndex.queryLocation` is executed on `sourceIndex.url` and must result in the list of sources.
The (auxiliary) query provided in `sourceIndex.queryLocation` is executed on `sourceIndex.url` and must result in the list of source URLs.

If `sourceIndex` is used and there is no `comunicaContext.lenient` property found, one will be created with value `true`.
This makes sure that the (main) query can succeed if not all obtained sources are accessible.
Expand Down Expand Up @@ -178,6 +179,20 @@ For this to work you need to add the icon to the exports in [IconProvider.js](./
We advise to use the [Material UI icons](https://material-ui.com/components/material-icons/) as this is what's used internally in `react-admin` and it is also included in the dependencies.
Nevertheless, you can use any React component you want, just make sure it's a functional component.

## Custom queries

Besides the prepared queries in the configuration file, a user can edit custom queries:

- To create a custom query, open "Custom Query Editor" from the menu on the left.
- Complete the custom query editor form and click the "CREATE QUERY" button when ready.
- Your new query is added to the "Custom queries" group and you are redirected to the query's result view.
- If not satisfied with the query result, you can click "EDIT QUERY" to further edit your query.
When saving changes, the result is recalculated.
- Because the custom query only lives as long as your browser remembers it, a "SAVE QUERY LINK" button is provided.
Use it to generate a unique URL for this custom query. Copy that URL to your clipboard and save it.
You can then visit that URL any time later, to recreate this query.
- To clean up an unwanted custom query, there is always a button "DELETE QUERY"...

## Representation Mapper

If you want to add your own type representations
Expand Down
270 changes: 270 additions & 0 deletions cypress/e2e/custom-query-editor.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@

describe("Custom Query Editor tests", () => {

it("Create a new query", () => {

cy.visit("/#/customQuery");

cy.get('input[name="name"]').type("new query");
cy.get('textarea[name="description"]').type("new description");

cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type(`PREFIX schema: <http://schema.org/>

SELECT * WHERE {
?list schema:name ?listTitle;
schema:itemListElement [
schema:name ?bookTitle;
schema:creator [
schema:name ?authorName
]
].
}`);
cy.get('input[name="source"]').type("http://localhost:8080/example/wish-list");
cy.get('button[type="submit"]').click();


// Checking if the book query works
cy.contains("Colleen Hoover").should('exist');
});

it("Create a new query, with multiple sources", () => {

cy.visit("/#/customQuery");

cy.get('input[name="name"]').type("material query");
cy.get('textarea[name="description"]').type("this query has 3 sources");

cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type(`# Query Texon's components
# Datasources: https://css5.onto-deside.ilabt.imec.be/texon/data/dt/out/components.ttl

PREFIX oo: <http://purl.org/openorg/>
PREFIX ao: <http://purl.org/ontology/ao/core#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX d: <http://www/example.com/data/>
PREFIX o: <http://www/example.com/ont/>

SELECT DISTINCT ?component ?componentName ?recycledContentPercentage
WHERE {
?component
a o:Component ;
o:name ?componentName ;
o:recycled-content-percentage ?recycledContentPercentage ;
.
}
ORDER BY ?componentName
`);
cy.get('input[name="source"]').type("http://localhost:8080/verifiable-example/components-vc ; http://localhost:8080/verifiable-example/components-vc-incorrect-proof ; http://localhost:8080/example/components");
cy.get('button[type="submit"]').click();

// Checking if the query works
cy.contains("http://www/example.com/data/component-c01").should('exist');
});

it("Check if all possible parameters are filled in with parameterized URL", () => {

// Navigate to the URL of a saved query with completely filled-in form
cy.visit("/#/customQuery?name=Query+Name&description=Query+Description&queryString=Sparql+query+text&comunicaContextCheck=on&source=The+Comunica+Source&comunicaContext=%7B%22Advanced+Comunica+Context%22%3Atrue%7D&sourceIndexCheck=on&indexSourceUrl=Index+Source&indexSourceQuery=Index+Query+&askQueryCheck=on&askQuery=%7B%22trueText%22%3A%22+filled+in%22%2C%22falseText%22%3A%22not+filled+in%22%7D&templatedQueryCheck=on&templateOptions=%7B%22firstvariables%22%3A%5B%22only+one%22%5D%7D")

// Verify that every field is correctly filled-in
cy.get('input[name="name"]').should('have.value', 'Query Name');
cy.get('textarea[name="description"]').should('have.value', 'Query Description');
cy.get('textarea[name="queryString"]').should('have.value', 'Sparql query text');

cy.get('input[name="source"]').should('have.value', "The Comunica Source");
cy.get('textarea[name="comunicaContext"]').should('have.value', `{"Advanced Comunica Context":true}`);

cy.get('input[name="indexSourceUrl"]').should('have.value', "Index Source");
cy.get('textarea[name="indexSourceQuery"]').should('have.value', "Index Query ");

cy.get('textarea[name="askQuery"]').should('have.value', `{"trueText":" filled in","falseText":"not filled in"}`);

cy.get('textarea[name="templateOptions"]').should('have.value', `{"firstvariables":["only one"]}`);

})

it("Successfully edit a query to make it work", () => {

cy.visit("/#/customQuery");

// First create a wrong query
cy.get('input[name="name"]').type("broken query");
cy.get('textarea[name="description"]').type("just a description");

cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type("this is faultive querytext")

cy.get('input[name="source"]').type("http://localhost:8080/example/wish-list");

//Submit the faultive query
cy.get('button[type="submit"]').click();

cy.contains("Custom queries").click();
cy.contains("broken query").click();

// Verify that there are no results
cy.contains("The result list is empty.").should('exist');

// Edit the query
cy.get('button').contains("Edit Query").click();

// Give the query a new name and a correct query text
cy.get('input[name="name"]').clear();
cy.get('input[name="name"]').type("Fixed query");

cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type(`PREFIX schema: <http://schema.org/>
SELECT * WHERE {
?list schema:name ?listTitle;
schema:itemListElement [
schema:name ?bookTitle;
schema:creator [
schema:name ?authorName
]
].
}`);

// Submit the correct query
cy.get('button[type="submit"]').click();

// Now we should be on the page of the fixed query
cy.contains("Fixed query").should('exist');

// Check if the resulting list appears
cy.contains("Colleen Hoover").should('exist');

})

it("Saves the correct URL", () => {

cy.visit("/#/customQuery");

// First create a simple query
cy.get('input[name="name"]').type("new query");
cy.get('textarea[name="description"]').type("new description");

cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type(`PREFIX schema: <http://schema.org/>
SELECT * WHERE {
?list schema:name ?listTitle;
schema:itemListElement [
schema:name ?bookTitle;
schema:creator [
schema:name ?authorName
]
].
}`);
cy.get('input[name="source"]').type("http://localhost:8080/example/wish-list");
cy.get('button[type="submit"]').click();

cy.get('button').contains("Save Query").click();

cy.get('textarea[name="queryURL"]').invoke('val').then((val) => {
expect(val).to.include('?name=new+query&description=new+description&queryString=PREFIX+schema%3A+%3Chttp%3A%2F%2Fschema.org%2F%3E+%0ASELECT+*+WHERE+%7B%0A++++%3Flist+schema%3Aname+%3FlistTitle%3B%0A++++++schema%3AitemListElement+%5B%0A++++++schema%3Aname+%3FbookTitle%3B%0A++++++schema%3Acreator+%5B%0A++++++++schema%3Aname+%3FauthorName%0A++++++%5D%0A++++%5D.%0A%7D&source=http%3A%2F%2Flocalhost%3A8080%2Fexample%2Fwish-list');
});


})

it("Custom templated query", () => {

cy.visit("/#/customQuery");

cy.get('input[name="name"]').type("custom template");
cy.get('textarea[name="description"]').type("description for template");

// Query handling a variable
cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type(`PREFIX schema: <http://schema.org/>
SELECT ?name ?sameAs_url WHERE {
?list schema:name ?listTitle;
schema:name ?name;
schema:genre $genre;
schema:sameAs ?sameAs_url;
}`
);

cy.get('input[name="source"]').type("http://localhost:8080/example/favourite-musicians");
cy.get('input[name="templatedQueryCheck"]').click()

cy.get('textarea[name="templateOptions"]').clear()
cy.get('textarea[name="templateOptions"]').type(`{"variables" : {
"genre": [
"\\"Romantic\\"",
"\\"Baroque\\"",
"\\"Classical\\""
]
}}`)
cy.get('button[type="submit"]').click();


cy.get('form').within(() => {
cy.get('#genre').click();
});
cy.get('li').contains('Baroque').click();

// Comfirm query
cy.get('button[type="submit"]').click();

cy.get('.column-name').find('span').contains("Antonio Caldara").should('exist');
})

it("Custom Query With Index File", () => {

cy.visit("/#/customQuery");

cy.get('input[name="name"]').type("custom with index file");
cy.get('textarea[name="description"]').type("description for index");

// Query handling a variable
cy.get('textarea[name="queryString"]').clear();
cy.get('textarea[name="queryString"]').type(`# Query Texon's components and their materials
# Datasources: https://css5.onto-deside.ilabt.imec.be/texon/data/dt/out/components.ttl https://css5.onto-deside.ilabt.imec.be/texon/data/dt/out/boms.ttl https://css5.onto-deside.ilabt.imec.be/texon/data/dt/out/materials.ttl

PREFIX oo: <http://purl.org/openorg/>
PREFIX ao: <http://purl.org/ontology/ao/core#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX d: <http://www/example.com/data/>
PREFIX o: <http://www/example.com/ont/>

SELECT ?component ?componentName ?material ?materialName ?percentage
WHERE {
?component
a o:Component ;
o:name ?componentName ;
o:has-component-bom [
o:has-component-material-assoc [
o:percentage ?percentage ;
o:has-material ?material ;
];
];
.
?material o:name ?materialName ;
}
ORDER BY ?componentName`
);

// No Comunica Sources Required
cy.get('input[name="sourceIndexCheck"]').click()
cy.get('input[name="indexSourceUrl"]').type("http://localhost:8080/example/index-example-texon-only")

cy.get('textarea[name="indexSourceQuery"]').clear();
cy.get('textarea[name="indexSourceQuery"]').type(`PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX example: <http://localhost:8080/example/index-example-texon-only#>

SELECT ?object
WHERE {
example:index-example rdfs:seeAlso ?object .
}`
)
cy.get('button[type="submit"]').click();

cy.contains("http://www/example.com/data/component-c01").should('exist');

})

})
Loading