diff --git a/client/custom/components/perspectives/Footer.js b/client/custom/components/perspectives/Footer.js
new file mode 100644
index 00000000..9a16faed
--- /dev/null
+++ b/client/custom/components/perspectives/Footer.js
@@ -0,0 +1,68 @@
+import React from "react";
+import Paper from "@mui/material/Paper";
+import PropTypes from "prop-types";
+import Box from "@mui/material/Box";
+import aaltoLogo from "~/img/logos/Aalto_SCI_EN_13_BLACK_2_cropped.png";
+import hyLogo from "~/img/logos/university-of-helsinki-logo-transparent-black.png";
+import heldigLogo from "~/img/logos/heldig-logo-transparent-black.png";
+
+/**
+ * A component for creating a footer. The logos are imported inside this component.
+ */
+const Footer = (props) => {
+ return (
+ ({
+ boxShadow: "0 -20px 20px -20px #333",
+ borderRadius: 0,
+ display: "flex",
+ justifyContent: "space-evenly",
+ alignItems: "center",
+ flexWrap: "wrap",
+ rowGap: theme.spacing(2),
+ columnGap: theme.spacing(3),
+ paddingLeft: theme.spacing(2),
+ paddingRight: theme.spacing(2),
+ [theme.breakpoints.down(496)]: {
+ paddingTop: theme.spacing(2),
+ paddingBottom: theme.spacing(2),
+ },
+ minHeight: {
+ xs: props.layoutConfig.footer.reducedHeight,
+ hundredPercentHeight: props.layoutConfig.footer.reducedHeight,
+ reducedHeight: props.layoutConfig.footer.defaultHeight,
+ },
+ })}
+ >
+ ({
+ width: 143,
+ height: 29,
+ [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
+ width: 167,
+ height: 34,
+ },
+ })}
+ >
+
+
+
+ );
+};
+
+Footer.propTypes = {
+ layoutConfig: PropTypes.object.isRequired,
+};
+
+export default Footer;
diff --git a/client/src/components/perspectives/Footer.js b/client/src/components/perspectives/Footer.js
index 4c159946..031f58f2 100644
--- a/client/src/components/perspectives/Footer.js
+++ b/client/src/components/perspectives/Footer.js
@@ -1,114 +1,114 @@
-import React from 'react'
-import Paper from '@mui/material/Paper'
-import PropTypes from 'prop-types'
-import Box from '@mui/material/Box'
-import aaltoLogo from '../../img/logos/Aalto_SCI_EN_13_BLACK_2_cropped.png'
-import hyLogo from '../../img/logos/university-of-helsinki-logo-transparent-black.png'
-import heldigLogo from '../../img/logos/heldig-logo-transparent-black.png'
+import React from "react";
+import Paper from "@mui/material/Paper";
+import PropTypes from "prop-types";
+import Box from "@mui/material/Box";
+import aaltoLogo from "~/img/logos/Aalto_SCI_EN_13_BLACK_2_cropped.png";
+import hyLogo from "~/img/logos/university-of-helsinki-logo-transparent-black.png";
+import heldigLogo from "~/img/logos/heldig-logo-transparent-black.png";
/**
* A component for creating a footer. The logos are imported inside this component.
*/
-const Footer = props => {
+const Footer = (props) => {
return (
({
- boxShadow: '0 -20px 20px -20px #333',
+ sx={(theme) => ({
+ boxShadow: "0 -20px 20px -20px #333",
borderRadius: 0,
- display: 'flex',
- justifyContent: 'space-evenly',
- alignItems: 'center',
- flexWrap: 'wrap',
+ display: "flex",
+ justifyContent: "space-evenly",
+ alignItems: "center",
+ flexWrap: "wrap",
rowGap: theme.spacing(2),
columnGap: theme.spacing(3),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
[theme.breakpoints.down(496)]: {
paddingTop: theme.spacing(2),
- paddingBottom: theme.spacing(2)
+ paddingBottom: theme.spacing(2),
},
minHeight: {
xs: props.layoutConfig.footer.reducedHeight,
hundredPercentHeight: props.layoutConfig.footer.reducedHeight,
- reducedHeight: props.layoutConfig.footer.defaultHeight
- }
+ reducedHeight: props.layoutConfig.footer.defaultHeight,
+ },
})}
>
({
+ component="a"
+ href="https://www.aalto.fi/en/school-of-science"
+ target="_blank"
+ rel="noopener noreferrer"
+ sx={(theme) => ({
width: 143,
height: 29,
[theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
width: 167,
- height: 34
- }
+ height: 34,
+ },
})}
>
({
+ component="a"
+ href="https://www.helsinki.fi/en"
+ target="_blank"
+ rel="noopener noreferrer"
+ sx={(theme) => ({
width: 155,
height: 40,
[theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
width: 168,
- height: 45
- }
+ height: 45,
+ },
})}
>
({
+ component="a"
+ href="https://www.helsinki.fi/en/helsinki-centre-for-digital-humanities"
+ target="_blank"
+ rel="noopener noreferrer"
+ sx={(theme) => ({
width: 118,
height: 30,
[theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
width: 130,
- height: 33
- }
+ height: 33,
+ },
})}
>
- )
-}
+ );
+};
Footer.propTypes = {
- layoutConfig: PropTypes.object.isRequired
-}
+ layoutConfig: PropTypes.object.isRequired,
+};
-export default Footer
+export default Footer;
diff --git a/client/src/containers/SemanticPortal.js b/client/src/containers/SemanticPortal.js
index ac6521d8..0f91d423 100644
--- a/client/src/containers/SemanticPortal.js
+++ b/client/src/containers/SemanticPortal.js
@@ -1,10 +1,10 @@
-import React, { useEffect, lazy } from 'react'
-import PropTypes from 'prop-types'
-import intl from 'react-intl-universal'
-import { has } from 'lodash'
-import { connect } from 'react-redux'
-import { Route, Redirect, Switch, useLocation } from 'react-router-dom'
-import Box from '@mui/material/Box'
+import React, { useEffect, lazy } from "react";
+import PropTypes from "prop-types";
+import intl from "react-intl-universal";
+import { has } from "lodash";
+import { connect } from "react-redux";
+import { Route, Redirect, Switch, useLocation } from "react-router-dom";
+import Box from "@mui/material/Box";
import {
fetchResultCount,
fetchPaginatedResults,
@@ -37,33 +37,40 @@ import {
clientFSClearResults,
clientFSUpdateQuery,
clientFSUpdateFacet,
- fetchKnowledgeGraphMetadata
-} from '../actions'
-import { filterResults } from '../selectors'
-import {
- getScreenSize,
- usePageViews
-} from '../helpers/helpers'
-import * as apexChartsConfig from '../library_configs/ApexCharts/ApexChartsConfig'
-import * as leafletConfig from '../library_configs/Leaflet/LeafletConfig'
-import * as networkToolsGeneral from '../library_configs/Cytoscape.js/NetworkToolsGeneral'
-import * as networkToolsPortalSpecific from '../library_configs/Cytoscape.js/NetworkToolsPortalSpecific'
-import { useConfigsStore } from '../stores/configsStore'
+ fetchKnowledgeGraphMetadata,
+} from "../actions";
+import { filterResults } from "../selectors";
+import { getScreenSize, usePageViews } from "../helpers/helpers";
+import * as apexChartsConfig from "../library_configs/ApexCharts/ApexChartsConfig";
+import * as leafletConfig from "../library_configs/Leaflet/LeafletConfig";
+import * as networkToolsGeneral from "../library_configs/Cytoscape.js/NetworkToolsGeneral";
+import * as networkToolsPortalSpecific from "../library_configs/Cytoscape.js/NetworkToolsPortalSpecific";
+import { useConfigsStore } from "../stores/configsStore";
// ** Import general components **
-const TopBar = lazy(() => import('../components/main_layout/TopBar'))
-const TextPage = lazy(() => import('../components/main_layout/TextPage'))
-const Message = lazy(() => import('../components/main_layout/Message'))
-const FullTextSearch = lazy(() => import('../components/main_layout/FullTextSearch'))
-const FacetedSearchPerspective = lazy(() => import('../components/facet_results/FacetedSearchPerspective'))
-const FederatedSearchPerspective = lazy(() => import('../components/facet_results/FederatedSearchPerspective'))
-const InstancePagePerspective = lazy(() => import('../components/main_layout/InstancePagePerspective'))
-const KnowledgeGraphMetadataTable = lazy(() => import('../components/main_layout/KnowledgeGraphMetadataTable'))
+const TopBar = lazy(() => import("../components/main_layout/TopBar"));
+const TextPage = lazy(() => import("../components/main_layout/TextPage"));
+const Message = lazy(() => import("../components/main_layout/Message"));
+const FullTextSearch = lazy(
+ () => import("../components/main_layout/FullTextSearch"),
+);
+const FacetedSearchPerspective = lazy(
+ () => import("../components/facet_results/FacetedSearchPerspective"),
+);
+const FederatedSearchPerspective = lazy(
+ () => import("../components/facet_results/FederatedSearchPerspective"),
+);
+const InstancePagePerspective = lazy(
+ () => import("../components/main_layout/InstancePagePerspective"),
+);
+const KnowledgeGraphMetadataTable = lazy(
+ () => import("../components/main_layout/KnowledgeGraphMetadataTable"),
+);
// ** General components end **
// ** Import portal specific components **
-const Main = lazy(() => import('../components/perspectives/Main'))
-const Footer = lazy(() => import('../components/perspectives/Footer'))
+const Main = lazy(() => import("components/perspectives/Main"));
+const Footer = lazy(() => import("components/perspectives/Footer"));
// ** Portal specific components end **
/**
@@ -71,57 +78,53 @@ const Footer = lazy(() => import('../components/perspectives/Footer'))
* the main routes of the portal are defined here based on JSON configs, using React Router.
* Currently, it is not possible to render this component in Storybook.
*/
-const SemanticPortal = props => {
- const {
- portalConfig,
- perspectiveConfigs,
- perspectiveConfigsInfoOnlyPages
- } = useConfigsStore()
+const SemanticPortal = (props) => {
+ const { portalConfig, perspectiveConfigs, perspectiveConfigsInfoOnlyPages } =
+ useConfigsStore();
- const {
- rootUrl,
- layoutConfig,
- knowledgeGraphMetadataConfig
- } = portalConfig
+ const { rootUrl, layoutConfig, knowledgeGraphMetadataConfig } = portalConfig;
const networkConfig = {
...networkToolsGeneral,
- ...networkToolsPortalSpecific
- }
+ ...networkToolsPortalSpecific,
+ };
- const { error } = props
- const location = useLocation()
- const rootUrlWithLang = `${rootUrl}/${props.options.currentLocale}`
- const screenSize = getScreenSize()
- const federatedSearchPerspectives = []
- let noClientFSResults = true
- perspectiveConfigs.forEach(perspective => {
- if (perspective.searchMode === 'federated-search') {
- federatedSearchPerspectives.push(perspective)
- noClientFSResults = props.clientFSState && props.clientFSState.results === null
+ const { error } = props;
+ const location = useLocation();
+ const rootUrlWithLang = `${rootUrl}/${props.options.currentLocale}`;
+ const screenSize = getScreenSize();
+ const federatedSearchPerspectives = [];
+ let noClientFSResults = true;
+ perspectiveConfigs.forEach((perspective) => {
+ if (perspective.searchMode === "federated-search") {
+ federatedSearchPerspectives.push(perspective);
+ noClientFSResults =
+ props.clientFSState && props.clientFSState.results === null;
}
- })
+ });
// trigger a new "page view" event whenever a new page loads
- usePageViews()
+ usePageViews();
// set HTML title and description dynamically based on translations
useEffect(() => {
- document.title = intl.get('html.title')
- document.documentElement.lang = props.options.currentLocale
- document.querySelector('meta[name="description"]').setAttribute('content', intl.get('html.description'))
- }, [props.options.currentLocale])
+ document.title = intl.get("html.title");
+ document.documentElement.lang = props.options.currentLocale;
+ document
+ .querySelector('meta[name="description"]')
+ .setAttribute("content", intl.get("html.description"));
+ }, [props.options.currentLocale]);
return (
({
- backgroundColor: '#bdbdbd',
- overflowX: 'hidden',
- minHeight: '100%',
+ sx={(theme) => ({
+ backgroundColor: "#bdbdbd",
+ overflowX: "hidden",
+ minHeight: "100%",
[theme.breakpoints.up(layoutConfig.hundredPercentHeightBreakPoint)]: {
- overflow: 'hidden',
- height: '100%'
- }
+ overflow: "hidden",
+ height: "100%",
+ },
})}
>
{/* error messages are shown on top of the app */}
@@ -155,17 +158,14 @@ const SemanticPortal = props => {
rootUrl={rootUrlWithLang}
layoutConfig={layoutConfig}
/>
-
+
>
{/* create a route for full text search results */}
{
/>
{/* create routes for faceted search perspectives and corresponding instance pages */}
- {perspectiveConfigs.map(perspective => {
- if (!has(perspective, 'externalUrl') && perspective.searchMode === 'faceted-search') {
+ {perspectiveConfigs.map((perspective) => {
+ if (
+ !has(perspective, "externalUrl") &&
+ perspective.searchMode === "faceted-search"
+ ) {
return (
-
+
{
updatePage={props.updatePage}
updateRowsPerPage={props.updateRowsPerPage}
updateMapBounds={props.updateMapBounds}
- updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded}
+ updatePerspectiveHeaderExpanded={
+ props.updatePerspectiveHeaderExpanded
+ }
sortResults={props.sortResults}
perspective={perspective}
animationValue={props.animationValue}
animateMap={props.animateMap}
/>
- {perspective.resultClasses[perspective.id].instanceConfig &&
+ {perspective.resultClasses[perspective.id].instanceConfig && (
-
+
{
fetchInstanceAnalysis={props.fetchInstanceAnalysis}
fetchFacetConstrainSelf={props.fetchFacetConstrainSelf}
fetchGeoJSONLayers={props.fetchGeoJSONLayers}
- fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend}
+ fetchGeoJSONLayersBackend={
+ props.fetchGeoJSONLayersBackend
+ }
clearGeoJSONLayers={props.clearGeoJSONLayers}
fetchByURI={props.fetchByURI}
updatePage={props.updatePage}
@@ -256,7 +271,9 @@ const SemanticPortal = props => {
animateMap={props.animateMap}
videoPlayerState={props.videoPlayer}
updateVideoPlayerTime={props.updateVideoPlayerTime}
- updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded}
+ updatePerspectiveHeaderExpanded={
+ props.updatePerspectiveHeaderExpanded
+ }
screenSize={screenSize}
rootUrl={rootUrlWithLang}
apexChartsConfig={apexChartsConfig}
@@ -264,14 +281,15 @@ const SemanticPortal = props => {
networkConfig={networkConfig}
/>
- }
+
+ )}
- )
+ );
}
- return null
+ return null;
})}
{/* create routes for perspectives that have only instance pages */}
- {perspectiveConfigsInfoOnlyPages.map(perspective =>
+ {perspectiveConfigsInfoOnlyPages.map((perspective) => (
{
animateMap={props.animateMap}
videoPlayerState={props.videoPlayer}
updateVideoPlayerTime={props.updateVideoPlayerTime}
- updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded}
+ updatePerspectiveHeaderExpanded={
+ props.updatePerspectiveHeaderExpanded
+ }
screenSize={screenSize}
rootUrl={rootUrlWithLang}
apexChartsConfig={apexChartsConfig}
@@ -312,21 +332,26 @@ const SemanticPortal = props => {
/>
- )}
+ ))}
{/* optional: create routes for client side faceted search */}
{federatedSearchPerspectives.length > 0 &&
- federatedSearchPerspectives.map(perspective =>
-
+ federatedSearchPerspectives.map((perspective) => (
+
{
clearGeoJSONLayers={props.clearGeoJSONLayers}
/>
- )}
+ ))}
{/* create routes for top bar info buttons */}
- {!layoutConfig.topBar.externalAboutPage &&
+ {!layoutConfig.topBar.externalAboutPage && (
- {intl.getHTML('aboutThePortalPartOne')}
- {knowledgeGraphMetadataConfig.showTable &&
+ {intl.getHTML("aboutThePortalPartOne")}
+ {knowledgeGraphMetadataConfig.showTable && (
}
- {intl.getHTML('aboutThePortalPartTwo')}
+ resultClass="knowledgeGraphMetadata"
+ fetchKnowledgeGraphMetadata={
+ props.fetchKnowledgeGraphMetadata
+ }
+ knowledgeGraphMetadata={
+ props[knowledgeGraphMetadataConfig.perspective]
+ ? props[knowledgeGraphMetadataConfig.perspective]
+ .knowledgeGraphMetadata
+ : null
+ }
+ />
+ )}
+ {intl.getHTML("aboutThePortalPartTwo")}
- }
+
+ )}
{/* create a route for instructions page */}
- {!layoutConfig.topBar.externalInstructions &&
+ {!layoutConfig.topBar.externalInstructions && (
- {intl.getHTML('instructions')}
+ {intl.getHTML("instructions")}
- }
+
+ )}
>
- )
-}
+ );
+};
// state: connect the Redux store and React components
-const mapStateToProps = state => {
- const perspectiveConfigsInfoOnlyPages = useConfigsStore.getState().perspectiveConfigsInfoOnlyPages
+const mapStateToProps = (state) => {
+ const perspectiveConfigsInfoOnlyPages =
+ useConfigsStore.getState().perspectiveConfigsInfoOnlyPages;
- const perspectiveConfigs = useConfigsStore.getState().perspectiveConfigs
+ const perspectiveConfigs = useConfigsStore.getState().perspectiveConfigs;
- const stateToProps = {}
- perspectiveConfigs.forEach(perspective => {
- const { id, searchMode } = perspective
- if (searchMode && searchMode === 'federated-search') {
- const perspectiveState = state[id]
- const { clientFSResults, clientFSFacetValues } = filterResults(perspectiveState)
- stateToProps.clientFSState = perspectiveState
- stateToProps.clientFSResults = clientFSResults
- stateToProps.clientFSFacetValues = clientFSFacetValues
+ const stateToProps = {};
+ perspectiveConfigs.forEach((perspective) => {
+ const { id, searchMode } = perspective;
+ if (searchMode && searchMode === "federated-search") {
+ const perspectiveState = state[id];
+ const { clientFSResults, clientFSFacetValues } =
+ filterResults(perspectiveState);
+ stateToProps.clientFSState = perspectiveState;
+ stateToProps.clientFSResults = clientFSResults;
+ stateToProps.clientFSFacetValues = clientFSFacetValues;
} else {
- stateToProps[id] = state[id]
- stateToProps[`${id}Facets`] = state[`${id}Facets`]
+ stateToProps[id] = state[id];
+ stateToProps[`${id}Facets`] = state[`${id}Facets`];
if (has(state, `${id}FacetsConstrainSelf`)) {
- stateToProps[`${id}FacetsConstrainSelf`] = state[`${id}FacetsConstrainSelf`]
+ stateToProps[`${id}FacetsConstrainSelf`] =
+ state[`${id}FacetsConstrainSelf`];
}
}
- })
- perspectiveConfigsInfoOnlyPages.forEach(perspective => {
- const { id } = perspective
- stateToProps[id] = state[id]
- })
- stateToProps.leafletMap = state.leafletMap
- stateToProps.fullTextSearch = state.fullTextSearch
- stateToProps.animationValue = state.animation.value
- stateToProps.videoPlayer = state.videoPlayer
- stateToProps.options = state.options
- stateToProps.error = state.error
- return stateToProps
-}
+ });
+ perspectiveConfigsInfoOnlyPages.forEach((perspective) => {
+ const { id } = perspective;
+ stateToProps[id] = state[id];
+ });
+ stateToProps.leafletMap = state.leafletMap;
+ stateToProps.fullTextSearch = state.fullTextSearch;
+ stateToProps.animationValue = state.animation.value;
+ stateToProps.videoPlayer = state.videoPlayer;
+ stateToProps.options = state.options;
+ stateToProps.error = state.error;
+ return stateToProps;
+};
// actions: connect the Redux store and React components
-const mapDispatchToProps = ({
+const mapDispatchToProps = {
fetchResultCount,
fetchPaginatedResults,
fetchResults,
@@ -453,8 +489,8 @@ const mapDispatchToProps = ({
clientFSSortResults,
clientFSUpdateQuery,
clientFSUpdateFacet,
- fetchKnowledgeGraphMetadata
-})
+ fetchKnowledgeGraphMetadata,
+};
SemanticPortal.propTypes = {
/**
@@ -581,10 +617,7 @@ SemanticPortal.propTypes = {
/**
* Redux action for updating a facet in client-side faceted search.
*/
- clientFSUpdateFacet: PropTypes.func
-}
+ clientFSUpdateFacet: PropTypes.func,
+};
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(SemanticPortal)
+export default connect(mapStateToProps, mapDispatchToProps)(SemanticPortal);
diff --git a/client/webpack.client.common.js b/client/webpack.client.common.js
index b9035f7b..f7c16a76 100644
--- a/client/webpack.client.common.js
+++ b/client/webpack.client.common.js
@@ -1,16 +1,22 @@
-const path = require('path')
-require('dotenv').config()
-const HtmlWebpackPlugin = require('html-webpack-plugin')
-const { CleanWebpackPlugin } = require('clean-webpack-plugin')
-const webpack = require('webpack')
+const path = require("path");
+require("dotenv").config();
+const HtmlWebpackPlugin = require("html-webpack-plugin");
+const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+const webpack = require("webpack");
-const outputDirectory = 'dist/public'
-const apiUrl = typeof process.env.API_URL !== 'undefined' ? process.env.API_URL : 'http://localhost:3001/api/v1'
-const mapboxAccessToken = typeof process.env.MAPBOX_ACCESS_TOKEN !== 'undefined' ? process.env.MAPBOX_ACCESS_TOKEN : 'MAPBOX_ACCESS_TOKEN missing'
+const outputDirectory = "dist/public";
+const apiUrl =
+ typeof process.env.API_URL !== "undefined"
+ ? process.env.API_URL
+ : "http://localhost:3001/api/v1";
+const mapboxAccessToken =
+ typeof process.env.MAPBOX_ACCESS_TOKEN !== "undefined"
+ ? process.env.MAPBOX_ACCESS_TOKEN
+ : "MAPBOX_ACCESS_TOKEN missing";
module.exports = {
entry: {
- app: './src/index.js'
+ app: "./src/index.js",
},
plugins: [
/**
@@ -21,61 +27,71 @@ module.exports = {
*
* During rebuilds, all webpack assets that are not used anymore
* will be removed automatically.
- */
+ */
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// Load a custom template
- template: 'src/index.html',
- favicon: 'src/favicon.ico'
+ template: "src/index.html",
+ favicon: "src/favicon.ico",
}),
new webpack.DefinePlugin({
- 'process.env.API_URL': JSON.stringify(apiUrl),
- 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify(mapboxAccessToken)
- })
+ "process.env.API_URL": JSON.stringify(apiUrl),
+ "process.env.MAPBOX_ACCESS_TOKEN": JSON.stringify(mapboxAccessToken),
+ }),
],
output: {
- filename: '[name].[fullhash].js',
+ filename: "[name].[fullhash].js",
path: path.resolve(__dirname, outputDirectory),
- publicPath: '/'
+ publicPath: "/",
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
- use: ['babel-loader']
+ use: ["babel-loader"],
},
{
test: /\.s?css$/,
use: [
// Creates `style` nodes from JS strings
- 'style-loader',
+ "style-loader",
// Translates CSS into CommonJS
- 'css-loader',
+ "css-loader",
// Compiles Sass to CSS
- 'sass-loader'
- ]
+ "sass-loader",
+ ],
},
{
test: /\.(png|svg|jpg|gif)$/,
- loader: 'file-loader',
+ loader: "file-loader",
options: {
- outputPath: 'images'
- }
+ outputPath: "images",
+ },
},
{
test: /\.(woff2|woff|eot|ttf)$/,
- loader: 'file-loader',
+ loader: "file-loader",
options: {
- name: 'fonts/[name].[ext]'
- }
- }
- ]
+ name: "fonts/[name].[ext]",
+ },
+ },
+ ],
},
resolve: {
- extensions: ['.js', '.jsx']
+ extensions: [".js", ".jsx"],
+ modules: [
+ "node_modules",
+ path.resolve(__dirname, "custom"),
+ path.resolve(__dirname, "src"),
+ ],
+ alias: {
+ // maps @something to path/to/something
+ // See https://webpack.js.org/configuration/resolve/ for more information
+ "~*": path.resolve(__dirname, "src/*"),
+ },
},
experiments: {
- topLevelAwait: true
- }
-}
+ topLevelAwait: true,
+ },
+};
diff --git a/server/babel.config.js b/server/babel.config.js
index 9693100e..5166a637 100644
--- a/server/babel.config.js
+++ b/server/babel.config.js
@@ -1,41 +1,45 @@
module.exports = function (api) {
- api.cache(true)
- const presets = []
- const plugins = []
- if (process.env.BABEL_ENV === 'browser') {
+ api.cache(true);
+ const presets = [];
+ const plugins = [];
+ if (process.env.BABEL_ENV === "browser") {
presets.push([
// https://babeljs.io/docs/en/babel-preset-env
- '@babel/preset-env',
+ "@babel/preset-env",
{
/**
* Target Browserslist’s default browsers.
* https://github.com/browserslist/browserslist
*/
- targets: 'defaults',
- useBuiltIns: 'usage',
- corejs: { version: 3, proposals: true }
- }
- ])
- presets.push(['@babel/preset-react', { runtime: 'classic' }])
- plugins.push('@babel/plugin-transform-runtime')
+ targets: "defaults",
+ useBuiltIns: "usage",
+ corejs: { version: 3, proposals: true },
+ },
+ ]);
+ presets.push(["@babel/preset-react", { runtime: "classic" }]);
+ plugins.push("@babel/plugin-transform-runtime");
}
- if (process.env.BABEL_ENV === 'node') {
+ if (process.env.BABEL_ENV === "node") {
presets.push([
- '@babel/preset-env',
+ "@babel/preset-env",
{
targets: {
- node: '22'
- }
- }
- ])
+ node: "22",
+ },
+ },
+ ]);
}
// for JavaScript Standard Style library to support JSX syntax
if (process.env.BABEL_ENV === undefined) {
- presets.push(['@babel/preset-react', { runtime: 'classic' }])
+ presets.push(["@babel/preset-react", { runtime: "classic" }]);
}
+ plugins.push("babel-plugin-module-resolver", {
+ root: ["./custom", "./src"],
+ });
+
return {
presets,
- plugins
- }
-}
+ plugins,
+ };
+};
diff --git a/server/custom/sparql/Mappers.js b/server/custom/sparql/Mappers.js
new file mode 100644
index 00000000..31a6ae94
--- /dev/null
+++ b/server/custom/sparql/Mappers.js
@@ -0,0 +1 @@
+console.log("XXX");
diff --git a/server/package-lock.json b/server/package-lock.json
index 4526dde8..feac2546 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -32,6 +32,7 @@
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"babel-loader": "^8.2.2",
+ "babel-plugin-module-resolver": "5.0.2",
"concurrently": "^6.3.0",
"copy-webpack-plugin": "^7.0.0",
"cross-env": "^7.0.0",
@@ -3727,6 +3728,135 @@
"node": ">=8"
}
},
+ "node_modules/babel-plugin-module-resolver": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz",
+ "integrity": "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-babel-config": "^2.1.1",
+ "glob": "^9.3.3",
+ "pkg-up": "^3.1.0",
+ "reselect": "^4.1.7",
+ "resolve": "^1.22.8"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/glob": {
+ "version": "9.3.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
+ "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "minimatch": "^8.0.2",
+ "minipass": "^4.2.4",
+ "path-scurry": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/minimatch": {
+ "version": "8.0.7",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.7.tgz",
+ "integrity": "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/babel-plugin-module-resolver/node_modules/pkg-up": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
+ "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.13",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz",
@@ -6193,6 +6323,16 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
+ "node_modules/find-babel-config": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.1.2.tgz",
+ "integrity": "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json5": "^2.2.3"
+ }
+ },
"node_modules/find-cache-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
@@ -8203,6 +8343,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minipass": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
+ "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/mjolnir.js": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/mjolnir.js/-/mjolnir.js-2.7.3.tgz",
@@ -8878,6 +9028,40 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/path-scurry/node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
"node_modules/path-to-regexp": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
@@ -9810,6 +9994,13 @@
"node": ">=0.10.0"
}
},
+ "node_modules/reselect": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz",
+ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
diff --git a/server/package.json b/server/package.json
index 1f826acf..435b29fd 100644
--- a/server/package.json
+++ b/server/package.json
@@ -43,6 +43,7 @@
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"babel-loader": "^8.2.2",
+ "babel-plugin-module-resolver": "5.0.2",
"concurrently": "^6.3.0",
"copy-webpack-plugin": "^7.0.0",
"cross-env": "^7.0.0",