Commit bd524a46 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '20-page-titles' into 'master'

Resolve: "Page titles"

Closes #20

See merge request !21
parents 79172c95 9d93d2e1
......@@ -29,6 +29,7 @@ Add a container `<div>` to your HTML page and initialize the Genesys UI with the
apiUrl: 'https://api.sandbox.genesys-pgr.org', // Genesys API server
clientId: 'clientid@genesys', // Client ID
clientKey: 'changeme', // Client key
title: 'Genesys |', // HTML title prefix
filter: {
institute: { code: [ 'ETH013' ] }, // Genesys data filter
},
......@@ -66,6 +67,7 @@ to *@geneesys-pgr/ui-embedded*:
|`clientSecret` | **Required** | Ditto. |
|`filter` |`undefined` | Allows for narrowing the scope of requested accession data from Genesys API. <br />To filter for accessions from your genebank, use: `{ institute: { code: ['XXX000'] } }` with the FAO WIEWS Code of your genebank. Default `undefined` value will return all accessions. |
|`language`|`'en'`| Specify the language of the user interface.<br />Fully supported: `en`<br />Partially supported: `es` |
|`title`|`'Genesys | '`| HTML title prefix |
| `accession` | `{ ... }` | See *Accession* configuration options |
| `shoppingCart` | `{ ... }` | See *Shopping cart* configuration options |
......
......@@ -66,6 +66,7 @@
apiUrl: 'https://api.sandbox.genesys-pgr.org', // Genesys API server
clientId: 'TDlQz.LUmnd6YIOtWr4kjnVEFi@api.sandbox.genesys-pgr.org', // Client ID
clientKey: 'gnE1dPz5CWnbn0IsFvL8iSP1QDxBpmU0', // Client key
title: 'Alliance genebanks:', // HTML title prefix
filter: {
institute: { code: ['COL003', 'BEL084'] }, // Genesys data filter
},
......
......@@ -44,7 +44,8 @@
"react-redux": "^7.0.0",
"react-router-dom": "^5.0.0",
"redux": "^4.0.0",
"redux-thunk": "^2.0.0"
"redux-thunk": "^2.0.0",
"react-helmet-async": "^1.0.0"
},
"devDependencies": {
"@types/react": "^16.0.0",
......
......@@ -10,6 +10,7 @@ import { WithConfig } from 'config/config';
import GrinSpecies from 'ui/common/GrinSpecies';
import PdciTable from 'ui/common/PdciTable';
import Loading from 'ui/common/Loading';
import PageTitle from 'ui/common/PageTitle';
interface IAccessionDetailsPageState {
accession: AccessionDetails;
......@@ -102,13 +103,17 @@ class AccessionDetailsPage extends React.Component<IAccessionDetailsPage & WithT
if (accession === null) {
return (
<Loading/>
<>
<PageTitle title={ t('loading') } />
<Loading/>
</>
);
} else {
const details = accession.details;
const pdci = accession.pdci;
return (
<>
<PageTitle title={ t('pagetitle.accession', { accessionNumber: details.accessionNumber }) } />
<div className="d-flex justify-content-between align-items-center">
<h1>{ details.accessionNumber }</h1>
{ shoppingCart.enabled &&
......
......@@ -13,6 +13,7 @@ import { withTranslation, WithTranslation } from 'react-i18next';
import { LocalStorageCart } from 'utilities';
import { WithConfig } from 'config/config';
import Loading from 'ui/common/Loading';
import PageTitle from 'ui/common/PageTitle';
interface IAccessionListPageState {
filter: AccessionFilter;
......@@ -172,11 +173,15 @@ class AccessionListPage extends React.Component<IAccessionListPageProps & WithTr
if (accessions === null) {
return (
<Loading/>
<>
<PageTitle title={ t('pagetitle.accessionList') }/>
<Loading/>
</>
);
} else {
return (
<>
<PageTitle title={ t('pagetitle.accessionList') }/>
<h1 className="d-flex justify-content-between align-items-center">
{ t('estimatedNumberOfItems', { count: accessions.totalElements, what: t('accession.model', { count: accessions.totalElements }) }) }
{ selected.length !== 0 &&
......
......@@ -9,6 +9,7 @@ import { AccessionService } from '@genesys/client/service';
import AccessionOverviewSection from './AccessionOverviewSection';
import AccessionFilter from '@genesys/client/model/accession/AccessionFilter';
import Loading from 'ui/common/Loading';
import PageTitle from 'ui/common/PageTitle';
interface IOverviewPageProps extends React.ClassAttributes<any>, WithTranslation {
filter: AccessionFilter;
......@@ -51,6 +52,7 @@ class BrowsePage extends React.Component<IOverviewPageProps, any> {
// Accession overview
// Summary information about selected accessions
<div>
<PageTitle title={ t('pagetitle.overview') }/>
{ overviewData ?
<>
<h1>{t('accession.overview.title')}</h1>
......@@ -59,7 +61,10 @@ class BrowsePage extends React.Component<IOverviewPageProps, any> {
</p>
<AccessionOverviewSection overview={ overviewData && overviewData.overview } />
</>
: <Loading/>
:
<>
<Loading/>
</>
}
</div>
);
......
......@@ -13,6 +13,7 @@ export class Config {
public accession?: AccessionConfig;
public shoppingCart?: BaseFeatureConfig;
public recaptchaSiteKey?: string;
public title?: string = 'Genesys |'
public constructor(config: Config) {
this.apiUrl = config.apiUrl || defaultConfig.apiUrl;
......@@ -21,6 +22,7 @@ export class Config {
this.language = config.language || defaultConfig.language;
this.recaptchaSiteKey = config.recaptchaSiteKey || defaultConfig.recaptchaSiteKey;
this.filter = config.filter || defaultConfig.filter;
this.title = config.title || defaultConfig.title;
// Merge feature config
this.accession = { ...defaultConfig.accession, ...config.accession };
......@@ -43,6 +45,7 @@ export const defaultConfig: Partial<Config> = {
apiUrl: 'https://api.sandbox.genesys-pgr.org',
filter: {},
language: 'en',
title: 'Genesys | ',
accession: {
enabled: true,
pdci: true,
......
......@@ -5,6 +5,7 @@ import { applyMiddleware, compose, createStore } from 'redux';
import { log } from '@genesys/client/utilities/debug';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { HelmetProvider } from 'react-helmet-async';
// import * as cookies from 'es-cookie';
import { reconfigureServiceAxios, LoginService } from '@genesys/client/service';
......@@ -62,7 +63,9 @@ export function showGenesysUI(holdingNode: HTMLElement, config: Config) {
ReactDOM.render(
<Provider store={ store }>
<App/>
<HelmetProvider>
<App/>
</HelmetProvider>
</Provider>,
holdingNode,
);
......
......@@ -6,6 +6,13 @@
"next": "Next",
"last": "Last"
},
"pagetitle": {
"accessionList": "Accession list",
"accession": "Accession {{accessionNumber}}",
"cart": "Cart",
"overview": "Collection overview",
"apiInfo": "API information"
},
"error": {
"notFound": "Not Found",
"errorHappened": "Error happened while processing request"
......
......@@ -7,6 +7,7 @@ import { withTranslation, WithTranslation } from 'react-i18next';
import { LocalStorageCart } from 'utilities';
import { Link, RouteComponentProps } from 'react-router-dom';
import Loading from 'ui/common/Loading';
import PageTitle from 'ui/common/PageTitle';
interface ICartPageState {
accessions: Array<Accession & Record<string, any>>;
......@@ -114,6 +115,7 @@ class CartPage extends React.Component<ICartPageProps, ICartPageState> {
return (
<>
<PageTitle title={ t('pagetitle.cart') } />
<h1 className="d-flex justify-content-between align-items-center">
{ t('cart.title') }
{ selected.length === 0 ? (
......
import React from 'react';
import { ApiInfoDisplay } from './ApiInfoDisplay';
import { ApiInfoService } from '@genesys/client/service';
import PageTitle from 'ui/common/PageTitle';
import { withTranslation } from 'react-i18next';
// interface IApiInfoPage extends React.ClassAttributes<any> {}
export default class ApiInfoPage extends React.Component<any, any> {
class ApiInfoPage extends React.Component<any, any> {
public state = {
apiInfo: null,
};
......@@ -22,8 +24,15 @@ export default class ApiInfoPage extends React.Component<any, any> {
}
public render() {
const { t } = this.props;
return (
<ApiInfoDisplay data={ this.state.apiInfo }/>
<>
<PageTitle title={ t('pagetitle.apiInfo') } />
<ApiInfoDisplay data={ this.state.apiInfo }/>
</>
);
};
}
export default withTranslation()(ApiInfoPage);
import * as React from 'react';
import { WithTranslation, withTranslation } from 'react-i18next';
import { Helmet } from 'react-helmet-async';
import { stripHtml } from '@genesys/client/utilities';
import { connect } from 'react-redux';
import { WithConfig } from 'config/config';
interface IPageTitle extends React.ClassAttributes<any>, WithTranslation {
title: string;
description?: string;
}
class PageTitle extends React.Component<IPageTitle & WithConfig, any> {
public constructor(props, context) {
super(props, context);
}
public render() {
const { appConfig: { title: appTitle }, title, description, t } = this.props;
return (
<Helmet>
<title>{ t(stripHtml( appTitle ? (appTitle + ' ' + title).trim() : title)) }</title>
{ description && <meta name="description" content={ t(description) } /> }
</Helmet>
);
}
}
const mapStateToProps = (state) => ({
appConfig: state.appConfig.config,
});
export default connect(mapStateToProps)(withTranslation()(PageTitle));
......@@ -3405,6 +3405,13 @@ interpret@^1.4.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
ip-regex@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
......@@ -3921,7 +3928,7 @@ loglevelnext@^1.0.1:
es6-symbol "^3.1.1"
object.assign "^4.1.0"
loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
......@@ -5260,6 +5267,11 @@ react-dom@^16.0.0:
prop-types "^15.6.2"
scheduler "^0.19.1"
react-fast-compare@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-google-recaptcha@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz#9f6f4954ce49c1dedabc2c532347321d892d0a16"
......@@ -5268,6 +5280,17 @@ react-google-recaptcha@^2.0.0:
prop-types "^15.5.0"
react-async-script "^1.1.1"
react-helmet-async@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.0.7.tgz#b988fbc3abdc4b704982bb74b9cb4a08fcf062c1"
integrity sha512-By90p5uxAriGukbyejq2poK41DwTxpNWOpOjN8mIyX/BKrCd3+sXZ5pHUZXjHyjR5OYS7PGsOD9dbM61YxfFmA==
dependencies:
"@babel/runtime" "^7.11.2"
invariant "^2.2.4"
prop-types "^15.7.2"
react-fast-compare "^3.2.0"
shallowequal "^1.1.0"
react-i18next@^11.0.0:
version "11.7.3"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.3.tgz#256461c46baf5b3208c3c6860ca4e569fc7ed053"
......@@ -5788,6 +5811,11 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment