Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Avoided (infinite) display of "The list is loading. Just a moment please." for queries that should show "The result list is empty.", in cases where the user does not have the right to read the involved source(s) (#209).
- Result list sorting works again and the behavior is improved - see the issue for details (#216).
- Loading values for variables ends with an error message if a required source is not available (#218).

## [1.7.0] - 2025-04-09

Expand Down
18 changes: 18 additions & 0 deletions main/configs/test/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,24 @@
"url": "http://localhost:8080/example/index-example-file-does-not-exist",
"queryLocation": "/sourceQueries/index_example_common_lt.rq"
}
},
{
"id": "9150",
"queryGroupId": "gr-test",
"queryLocation": "musicians_variables.rq",
"name": "A templated query about musicians (indirect variables) - no sources",
"description": "Test what happens when variables cannot be loaded because no source(s) available.",
"icon": "MusicNoteIcon",
"indirectVariables": {
"queryLocations": [
"variableQueries/musicians_genre_variable.rq"
]
},
"comunicaContext": {
"sources": [
"http://localhost:8080/example/favourite-musicians-file-does-not-exist"
]
}
}
]
}
31 changes: 31 additions & 0 deletions main/src/components/ErrorDisplay/ErrorDisplay.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined';
import SearchOffIcon from '@mui/icons-material/SearchOff';
import { SvgIcon, Box } from "@mui/material";

const ErrorDisplay = (props) => {
const { errorMessage, searchingMessage } = props;
let icon;
let msg;

if (errorMessage) {
icon = ReportProblemOutlinedIcon;
msg = errorMessage;
} else if (searchingMessage) {
icon = SearchOffIcon;
msg = searchingMessage;
} else {
icon = ReportProblemOutlinedIcon;
msg = "Something unexpected happened."
}

return (
<div>
<Box display="flex" alignItems="center" sx={{ m: 3 }}>
<SvgIcon component={icon} sx={{ m: 3 }} />
<span>{msg}</span>
</Box>
</div>
);
}

export default ErrorDisplay;
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import ActionBar from "../../ActionBar/ActionBar";
import GenericField from "../../../representationProvider/GenericField";
import TableHeader from "./TableHeader/TableHeader";
import Button from '@mui/material/Button';
import SearchOffIcon from '@mui/icons-material/SearchOff';
import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined';
import { SvgIcon, Box, Typography } from "@mui/material";
import { Box, Typography } from "@mui/material";
import ErrorDisplay from "../../../components/ErrorDisplay/ErrorDisplay";
import PropTypes from "prop-types";
import CustomQueryEditButton from "../../CustomQueryEditor/customQueryEditButton";
import IconProvider from "../../../IconProvider/IconProvider";
Expand Down Expand Up @@ -81,28 +80,14 @@ const Aside = (props) => {

const NoValuesDisplay = (props) => {
const { meta } = props;
let icon;
let msg;

if (meta.errorMessage) {
icon = ReportProblemOutlinedIcon;
msg = `Something went wrong... ${meta.errorMessage}`;
return <ErrorDisplay errorMessage={`Something went wrong... ${meta.errorMessage}`} />
} else if (meta.noSources) {
icon = SearchOffIcon;
msg = "The result list is empty (no sources found)."
return <ErrorDisplay searchingMessage="The result list is empty (no sources found)." />
} else if (meta.resultEmpty) {
icon = SearchOffIcon;
msg = "The result list is empty."
return <ErrorDisplay searchingMessage="The result list is empty." />
}

return (
<div>
<Box display="flex" alignItems="center" sx={{ m: 3 }}>
<SvgIcon component={icon} sx={{ m: 3}} />
<span>{msg}</span>
</Box>
</div>
);
}

const MyDatagrid = (props) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function TableHeader({ children }) {
<>
<TableCell
key={child.props.source}
sx={{ height: "100%", "font-weight": "bold", "& > *": { verticalAlign: "middle" } }}
sx={{ height: "100%", fontWeight: "bold", "& > *": { verticalAlign: "middle" } }}
>
{sortingAllowed ? <span
role="button"
Expand Down
21 changes: 17 additions & 4 deletions main/src/components/ListResultTable/TemplatedListResultTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useResourceContext, Loading, useDataProvider, useResourceDefinition } f
import { useLocation, useNavigate } from 'react-router-dom';
import TemplatedQueryForm from "./TemplatedQueryForm.jsx";
import QueryResultList from "./QueryResultList/QueryResultList";
import ErrorDisplay from "../../components/ErrorDisplay/ErrorDisplay";

import configManager from '../../configManager/configManager.js';

Expand All @@ -21,6 +22,7 @@ const TemplatedListResultTable = (props) => {
const navigate = useNavigate();
const query = configManager.getQueryWorkingCopyById(resource);
const [waitingForVariableOptions, setWaitingForVariableOptions] = useState(!!(query.variables || query.indirectVariables));
const [waitingForVariableOptionsError, setWaitingForVariableOptionsError] = useState("");
const [variableOptions, setVariableOptions] = useState({});
const [variableValues, setVariableValues] = useState({});
const [variablesSubmitted, setVariablesSubmitted] = useState(false);
Expand All @@ -31,6 +33,7 @@ const TemplatedListResultTable = (props) => {
// LOG console.log(`props: ${JSON.stringify(props, null, 2)}`);
// LOG console.log(`resource: ${resource}`);
// LOG console.log(`waitingForVariableOptions: ${waitingForVariableOptions}`);
// LOG console.log(`waitingForVariableOptionsError: ${waitingForVariableOptionsError}`);
// LOG console.log(`variableOptions: ${JSON.stringify(variableOptions, null, 2)}`);
// LOG console.log(`variableValues: ${JSON.stringify(variableValues, null, 2)}`);
// LOG console.log(`variablesSubmitted: ${variablesSubmitted}`);
Expand All @@ -40,10 +43,15 @@ const TemplatedListResultTable = (props) => {
useEffect(() => {
(async () => {
if (query.variables || query.indirectVariables) {
// LOG console.log('start waiting for variable options');
setVariableOptions(await dataProvider.getVariableOptions(query));
// LOG console.log('done waiting for variable options');
setWaitingForVariableOptions(false);
try {
// LOG console.log('start waiting for variable options');
setVariableOptions(await dataProvider.getVariableOptions(query));
// LOG console.log('done waiting for variable options');
setWaitingForVariableOptions(false);
} catch (error) {
// LOG console.log(`error getting variable options: ${error.message}`);
setWaitingForVariableOptionsError(error.message);
}
}
})();
}, [resource]);
Expand All @@ -55,6 +63,11 @@ const TemplatedListResultTable = (props) => {
return false;
}

if (waitingForVariableOptionsError) {
// LOG console.log(`TemplatedListResultTable failure while waiting for variable options: ${waitingForVariableOptionsError}`);
return <ErrorDisplay errorMessage={waitingForVariableOptionsError} />;
}

if (waitingForVariableOptions) {
// LOG console.log('TemplatedListResultTable waiting for variable options.');
return <Loading sx={{ height: "auto" }} loadingSecondary={"The options for the variables in this query are loading. Just a moment please."} />;
Expand Down
4 changes: 2 additions & 2 deletions main/src/dataProvider/SparqlDataProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,11 +438,11 @@ async function getVariableOptions(query) {
}
}
catch (error) {
throw new Error(`Error getting variable options: ${error.message}`);
throw new Error(`Error getting variable options... ${error.message}`);
}

if (variableOptions == {}) {
throw new Error(`The variable options are empty`);
throw new Error(`Error getting variable options... The variable options are empty`);
}
return variableOptions;
}
Expand Down
8 changes: 8 additions & 0 deletions test/cypress/e2e/indirect-variables.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ describe("Indirect variable query", () => {

});

it("Indirect with 1 variable but no sources available to get variables from", () => {

cy.visit("/");
cy.contains("For testing only").click();
cy.contains("A templated query about musicians (indirect variables) - no sources").click();

cy.contains("Error getting variable options...").should("exist");;
});
});


Expand Down