diff --git a/CHANGELOG.md b/CHANGELOG.md
index 45b4a5a..69727fa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/main/configs/test/config.json b/main/configs/test/config.json
index f457c55..669843b 100644
--- a/main/configs/test/config.json
+++ b/main/configs/test/config.json
@@ -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"
+ ]
+ }
}
]
}
\ No newline at end of file
diff --git a/main/src/components/ErrorDisplay/ErrorDisplay.jsx b/main/src/components/ErrorDisplay/ErrorDisplay.jsx
new file mode 100644
index 0000000..210877f
--- /dev/null
+++ b/main/src/components/ErrorDisplay/ErrorDisplay.jsx
@@ -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 (
+
+
+
+ {msg}
+
+
+ );
+}
+
+export default ErrorDisplay;
\ No newline at end of file
diff --git a/main/src/components/ListResultTable/QueryResultList/QueryResultList.jsx b/main/src/components/ListResultTable/QueryResultList/QueryResultList.jsx
index 3528a2b..dd0f4d6 100644
--- a/main/src/components/ListResultTable/QueryResultList/QueryResultList.jsx
+++ b/main/src/components/ListResultTable/QueryResultList/QueryResultList.jsx
@@ -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";
@@ -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
} else if (meta.noSources) {
- icon = SearchOffIcon;
- msg = "The result list is empty (no sources found)."
+ return
} else if (meta.resultEmpty) {
- icon = SearchOffIcon;
- msg = "The result list is empty."
+ return
}
-
- return (
-
-
-
- {msg}
-
-
- );
}
const MyDatagrid = (props) => {
diff --git a/main/src/components/ListResultTable/QueryResultList/TableHeader/TableHeader.jsx b/main/src/components/ListResultTable/QueryResultList/TableHeader/TableHeader.jsx
index 6d16402..956ad50 100644
--- a/main/src/components/ListResultTable/QueryResultList/TableHeader/TableHeader.jsx
+++ b/main/src/components/ListResultTable/QueryResultList/TableHeader/TableHeader.jsx
@@ -46,7 +46,7 @@ function TableHeader({ children }) {
<>
*": { verticalAlign: "middle" } }}
+ sx={{ height: "100%", fontWeight: "bold", "& > *": { verticalAlign: "middle" } }}
>
{sortingAllowed ? {
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);
@@ -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}`);
@@ -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]);
@@ -55,6 +63,11 @@ const TemplatedListResultTable = (props) => {
return false;
}
+ if (waitingForVariableOptionsError) {
+ // LOG console.log(`TemplatedListResultTable failure while waiting for variable options: ${waitingForVariableOptionsError}`);
+ return ;
+ }
+
if (waitingForVariableOptions) {
// LOG console.log('TemplatedListResultTable waiting for variable options.');
return ;
diff --git a/main/src/dataProvider/SparqlDataProvider.js b/main/src/dataProvider/SparqlDataProvider.js
index 44b5d6e..6fdb34b 100644
--- a/main/src/dataProvider/SparqlDataProvider.js
+++ b/main/src/dataProvider/SparqlDataProvider.js
@@ -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;
}
diff --git a/test/cypress/e2e/indirect-variables.cy.js b/test/cypress/e2e/indirect-variables.cy.js
index cf4f2b7..3deeef2 100644
--- a/test/cypress/e2e/indirect-variables.cy.js
+++ b/test/cypress/e2e/indirect-variables.cy.js
@@ -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");;
+ });
});