Skip to content
Open
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
15 changes: 7 additions & 8 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"express": "^4.21.1",
"html-react-parser": "^1.4.4",
"immutable": "^4.0.0-rc.12",
"jsonc-parser": "^3.3.1",
"leaflet": "^1.7.1",
"leaflet-draw": "^1.0.4",
"leaflet-fullscreen": "^1.0.2",
Expand Down
9 changes: 5 additions & 4 deletions client/src/components/main_layout/InstancePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Typography from '@mui/material/Typography'
import CircularProgress from '@mui/material/CircularProgress'
import PerspectiveTabs from 'components/main_layout/PerspectiveTabs'
import ResultClassRoute from 'components/facet_results/ResultClassRoute'
import { getLocalIDFromAppLocation, createURIfromLocalID } from 'helpers/helpers'
import { getLocalIDFromAppLocation, createURIfromLocalID, createInstancePagePath } from 'helpers/helpers'
import { Route, Redirect } from 'react-router-dom'
import { has } from 'lodash'

Expand Down Expand Up @@ -116,6 +116,7 @@ class InstancePage extends React.Component {
const { classes, perspectiveState, perspectiveConfig, rootUrl, screenSize, layoutConfig } = this.props
const { fetching } = perspectiveState
const resultClass = perspectiveConfig.id
const instancePagePath = createInstancePagePath({ perspectiveConfig, localID: this.state.localID })
const defaultInstancePageTab = perspectiveConfig.defaultInstancePageTab
? perspectiveConfig.defaultInstancePageTab
: 'table'
Expand Down Expand Up @@ -146,11 +147,11 @@ class InstancePage extends React.Component {
{hasTableData &&
<>
<Route
exact path={`${rootUrl}/${resultClass}/page/${this.state.localID}`}
exact path={`${rootUrl}${instancePagePath}`}
render={routeProps =>
<Redirect
to={{
pathname: `${rootUrl}/${resultClass}/page/${this.state.localID}/${defaultInstancePageTab}`,
pathname: `${rootUrl}${instancePagePath}/${defaultInstancePageTab}`,
hash: routeProps.location.hash
}}
/>}
Expand All @@ -164,7 +165,7 @@ class InstancePage extends React.Component {
return null
}
const { tabPath } = resultClassConfig
const path = `${rootUrl}/${resultClass}/page/${this.state.localID}/${tabPath}`
const path = `${rootUrl}${instancePagePath}/${tabPath}`
return (
<ResultClassRoute
key={instancePageResultClass}
Expand Down
15 changes: 8 additions & 7 deletions client/src/containers/SemanticPortal.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import {
import { filterResults } from 'selectors'
import {
getScreenSize,
usePageViews
usePageViews,
getInstancePagePathPattern
} from 'helpers/helpers'
import * as apexChartsConfig from 'library_configs/ApexCharts/ApexChartsConfig'
import * as leafletConfig from 'library_configs/Leaflet/LeafletConfig'
Expand Down Expand Up @@ -225,13 +226,13 @@ const SemanticPortal = props => {
{perspective.resultClasses[perspective.id].instanceConfig &&
<Switch>
<Redirect
from={`/${perspective.id}/page/:id`}
from={getInstancePagePathPattern({ perspectiveConfig: perspective })}
to={{
pathname: `${rootUrlWithLang}/${perspective.id}/page/:id`,
pathname: `${rootUrlWithLang}${getInstancePagePathPattern({ perspectiveConfig: perspective })}`,
hash: location.hash
}}
/>
<Route path={`${rootUrlWithLang}/${perspective.id}/page/:id`}>
<Route path={`${rootUrlWithLang}${getInstancePagePathPattern({ perspectiveConfig: perspective })}`}>
<InstancePagePerspective
portalConfig={portalConfig}
layoutConfig={layoutConfig}
Expand Down Expand Up @@ -275,10 +276,10 @@ const SemanticPortal = props => {
{perspectiveConfigsInfoOnlyPages.map(perspective =>
<Switch key={perspective.id}>
<Redirect
from={`${rootUrl}/${perspective.id}/page/:id`}
to={`${rootUrlWithLang}/${perspective.id}/page/:id`}
from={`${rootUrl}${getInstancePagePathPattern({ perspectiveConfig: perspective })}`}
to={`${rootUrlWithLang}${getInstancePagePathPattern({ perspectiveConfig: perspective })}`}
/>
<Route path={`${rootUrlWithLang}/${perspective.id}/page/:id`}>
<Route path={`${rootUrlWithLang}${getInstancePagePathPattern({ perspectiveConfig: perspective })}`}>
<InstancePagePerspective
portalConfig={portalConfig}
layoutConfig={layoutConfig}
Expand Down
27 changes: 27 additions & 0 deletions client/src/helpers/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,33 @@ export const createURIfromLocalID = ({ localID, baseURI, URITemplate, localIDAsU
return uri
}

// The part of URITemplate before <LOCAL_ID>, with <BASE_URI> reduced to the path of baseURI:
// baseURI 'http://example.com/resource' + URITemplate '<BASE_URI>/corporation/<LOCAL_ID>'
// gives '/resource/corporation'. Only the path is used, so instance page URLs match the
// resource URI in production and still work on any other host in development.
const getInstancePageURIPrefix = ({ baseURI, URITemplate }) => {
const basePath = new URL(baseURI).pathname.replace(/\/+$/, '')
return URITemplate
.replaceAll('<BASE_URI>', basePath)
.replace(/\/?<LOCAL_ID>.*$/, '')
}

const useURIAsInstancePageUrl = perspectiveConfig =>
perspectiveConfig.instancePageUrlMode === 'uri' &&
has(perspectiveConfig, 'baseURI') && has(perspectiveConfig, 'URITemplate')

// Route pattern for a perspective's instance pages, e.g. '/resource/corporation/:id'
export const getInstancePagePathPattern = ({ perspectiveConfig }) =>
useURIAsInstancePageUrl(perspectiveConfig)
? `${getInstancePageURIPrefix(perspectiveConfig)}/:id`
: `/${perspectiveConfig.id}/page/:id`

// Path of a single instance page, e.g. '/resource/corporation/12345'
export const createInstancePagePath = ({ perspectiveConfig, localID }) =>
useURIAsInstancePageUrl(perspectiveConfig)
? `${getInstancePageURIPrefix(perspectiveConfig)}/${localID}`
: `/${perspectiveConfig.id}/page/${localID}`

export const getSpacing = (theme, value) => Number(theme.spacing(value).slice(0, -2))

export const getScreenSize = () => {
Expand Down
5 changes: 3 additions & 2 deletions client/src/stores/configsStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from 'zustand'
import { parse } from 'jsonc-parser'
import { configHelpers } from 'stores/helpers'

const apiUrl = process.env.API_URL
Expand Down Expand Up @@ -36,7 +37,7 @@ export const useConfigsStore = create((set, get) => ({
if (get().portalConfig !== null) {
return get().portalConfig
} else {
const portal = await fetch(`${CONFIGS_URL}/portalConfig.json`).then(res => res.json())
const portal = await fetch(`${CONFIGS_URL}/portalConfig.json`).then(res => res.text()).then(text => parse(text))
set({ portalConfig: portal })
return portal
}
Expand All @@ -49,7 +50,7 @@ export const useConfigsStore = create((set, get) => ({
if (file in get().jsonConfigs) {
return get().jsonConfigs[file]
} else {
const jsonFile = await fetch(`${CONFIGS_URL}/${get().portalConfig.portalID}/${file}`).then(res => res.json())
const jsonFile = await fetch(`${CONFIGS_URL}/${get().portalConfig.portalID}/${file}`).then(res => res.text()).then(text => parse(text))
set(state => ({
jsonConfigs: { ...state.jsonConfigs, [file]: jsonFile }
}))
Expand Down
14 changes: 13 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# SAMPO-UI docs

- [Introduction](pages/Introduction.md)
Sampo-ui is a data visualisation framework designed to easily configure a browsable front end for sparql endpoints.

Sampo consists of a core app and config files. A sampo app runs by mounting the configs into the core app containers,
meaning when building a portal only config files need to be created.

These docs are intended for developers using sampo-ui to build apps as well as for developers working on the sampo core.

These documentations explain the current state of version 4.

- [Portal Config](./pages/PortalConfig.md)
- [Perspectives Config](./pages/PerspectiveConfig.md)
- [Sparql Config](./pages/SparqlConfig.md)
- [Locales](./pages/Locales.md)
- [Custom Components](pages/CustomComponents.md)
- [Deployment](pages/Deployment.md)
- [Changelog](CHANGELOG.md)
1 change: 0 additions & 1 deletion docs/pages/Introduction.md

This file was deleted.

52 changes: 52 additions & 0 deletions docs/pages/Locales.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Locales

Locale config files are json config where the actual text content of the portal is written. A locale.json must be made
per language the portal uses.

Each entry in this json file refers to some ID defined either in config or in sampo core.

## General entries
The upper half of the example locale files in this repository (up until `perspectives`) contains some general locale config
that most portals will use. It is fine to copy this and edit the text to fit your portal or remove parts you do not need.


## Properties
In the `perspectives` object the text for facets and table columns gets defined. The most important thing to know here is that the same text gets used for column and facet labels and descriptions for the matching properties.

## Text pages

### Info dropdown
All pages defined in the `infoDropdown` in `portalConfig.json` must have their page content defined in locales.

For example:
```
"infoDropdown": [
{
"id": "about",
"externalLink": false,
"translatedText": "aboutPage",
"internalLink": "/about"
}
]
```
must in the root of locales have something like:
```
"aboutPage": "htmlFile:pages/about_en.html"
```
and then put the actual content of the page in said html file. The content can also be put directly in the locale json as a string, but since that gets very dirty for large pages it is not recommended.


### Dummy internal perspectives
The above part can only put these pages in the info dropdown. It is also possible to add them as perspectives, meaning
they appear as their own button in the topbar and can have a card on the front page.

To define that make a new perspective json file under ``search_perspectives`` and structure it like this:
```
{
"id": "about",
"searchMode": "dummy-internal",
"internalLink": "/about",
"hideTopPerspectiveButton": false
}
```
Then also add it in `portalConfig.json` as if it were a normal perspective.
Loading