From 4efaf25f06a449833e64d750ae49d85b4a310924 Mon Sep 17 00:00:00 2001 From: Oleksii Savran Date: Thu, 19 Nov 2020 16:02:23 +0200 Subject: [PATCH 1/5] Redux --- .eslintrc | 4 +- package.json | 7 +- src/accession/AccessionDetailsPage.tsx | 7 +- src/accession/AccessionListPage.tsx | 7 +- src/accession/AccessionOverviewSection.tsx | 28 +++----- src/accession/OverviewPage.tsx | 7 +- {config => src/config}/config.ts | 0 src/core/actions/appConfig.ts | 7 ++ src/core/actions/decoding.ts | 16 +++++ src/core/constants/appConfig.ts | 1 + src/core/constants/decoding.ts | 1 + src/core/reducer/appConfig.ts | 24 +++++++ src/core/reducer/decoding.ts | 23 +++++++ src/core/reducer/index.ts | 11 +++ src/genesys.tsx | 19 +++-- src/ui/core/App.tsx | 32 +++++++-- yarn.lock | 80 ++++++++++++++++------ 17 files changed, 220 insertions(+), 54 deletions(-) rename {config => src/config}/config.ts (100%) create mode 100644 src/core/actions/appConfig.ts create mode 100644 src/core/actions/decoding.ts create mode 100644 src/core/constants/appConfig.ts create mode 100644 src/core/constants/decoding.ts create mode 100644 src/core/reducer/appConfig.ts create mode 100644 src/core/reducer/decoding.ts create mode 100644 src/core/reducer/index.ts diff --git a/.eslintrc b/.eslintrc index ff1824d..c76f459 100644 --- a/.eslintrc +++ b/.eslintrc @@ -34,7 +34,7 @@ "error", { "types": { - // "object": false + "object": "false" } } ], @@ -120,7 +120,7 @@ "import/no-internal-modules": "off", "import/order": "off", "indent": [2, 2, {"SwitchCase": 1}], - // "no-restricted-imports": ["error", {"patterns": ["../*"]}], + "no-restricted-imports": ["error", {"patterns": ["../*"]}], "max-classes-per-file": [ "error", 10 diff --git a/package.json b/package.json index 26c7325..b57d69f 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,15 @@ "es-cookie": "^1.0.0", "history": "^4.0.0", "i18next": "^19.0.0", + "immutability-helper": "^3.0.0", "react": "^16.0.0", "react-dom": "^16.0.0", "react-google-recaptcha": "^2.0.0", "react-i18next": "^11.0.0", - "react-router-dom": "^5.0.0" + "react-redux": "^7.0.0", + "react-router-dom": "^5.0.0", + "redux": "^4.0.0", + "redux-thunk": "^2.0.0" }, "devDependencies": { "@types/react": "^16.0.0", @@ -63,6 +67,7 @@ "html-webpack-plugin": "4.0.0-alpha", "mini-css-extract-plugin": "^0.9.0", "optimize-css-assets-webpack-plugin": "^5.0.0", + "redux-devtools-extension": "^2.13.8", "rimraf": "^3.0.0", "script-ext-html-webpack-plugin": "^2.0.0", "tslint": "^6.0.0", diff --git a/src/accession/AccessionDetailsPage.tsx b/src/accession/AccessionDetailsPage.tsx index cdaa7a5..8c923ea 100644 --- a/src/accession/AccessionDetailsPage.tsx +++ b/src/accession/AccessionDetailsPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { connect } from 'react-redux'; import { AccessionService } from '@genesys/client/service'; import { Property } from 'ui/common/Property'; @@ -221,4 +222,8 @@ class AccessionDetailsPage extends React.Component ({ + apiUrl: state.appConfig.config.apiUrl, +}); + +export default connect(mapStateToProps)(withTranslation()(AccessionDetailsPage)); diff --git a/src/accession/AccessionListPage.tsx b/src/accession/AccessionListPage.tsx index 40d1ecb..7a649cf 100644 --- a/src/accession/AccessionListPage.tsx +++ b/src/accession/AccessionListPage.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { parse } from 'query-string'; +import { connect } from 'react-redux'; import { AccessionService } from '@genesys/client/service'; import AccessionFilter from '@genesys/client/model/accession/AccessionFilter'; @@ -240,4 +241,8 @@ class AccessionListPage extends React.Component ({ + filter: state.appConfig.config.filter, +}); + +export default connect(mapStateToProps)(withTranslation()(AccessionListPage)); diff --git a/src/accession/AccessionOverviewSection.tsx b/src/accession/AccessionOverviewSection.tsx index 39caf5b..d1d8099 100644 --- a/src/accession/AccessionOverviewSection.tsx +++ b/src/accession/AccessionOverviewSection.tsx @@ -3,39 +3,25 @@ import { withTranslation, WithTranslation } from 'react-i18next'; // model import AccessionOverview from '@genesys/client/model/accession/AccessionOverview'; import PropertiesCard from 'ui/common/PropertiesCard'; -import { VocabularyService } from '@genesys/client/service'; +import { connect } from 'react-redux'; -interface IAccessionOverviewPageState { - countryCodes: object; -} interface IAccessionOverviewPageProps extends React.ClassAttributes { overview: AccessionOverview; + countryCodes: Record; } -class AccessionOverviewSection extends React.Component { +class AccessionOverviewSection extends React.Component { public constructor(props) { super(props); - - this.state = { - countryCodes: null, - } } private overviewKeys = ['institute.code', 'institute.country.code3', 'cropName', 'crop.shortName', 'sampStat', 'taxonomy.genus', 'taxonomy.genusSpecies', 'taxonomy.grinTaxonomySpecies.name', 'taxonomy.currentTaxonomySpecies.name', 'countryOfOrigin.code3', 'donorCode', 'mlsStatus', 'available', 'duplSite', 'sgsv', 'storage', 'breederCode', 'aegis']; - public async componentDidMount() { - const codes = await VocabularyService.decode3166Alpha3Terms(this.props.i18n.language); - this.setState({ countryCodes: codes }) - } - public render() { - const { overview, t } = this.props; - - const { countryCodes } = this.state; - + const { overview, t, countryCodes } = this.props; if (!overview) { return null; @@ -206,4 +192,8 @@ class AccessionOverviewSection extends React.Component ({ + countryCodes: state.decoding.codes, +}); + +export default connect(mapStateToProps)(withTranslation()(AccessionOverviewSection)); diff --git a/src/accession/OverviewPage.tsx b/src/accession/OverviewPage.tsx index a41d593..531caaa 100644 --- a/src/accession/OverviewPage.tsx +++ b/src/accession/OverviewPage.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { WithTranslation, withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; // Models import { AccessionService } from '@genesys/client/service'; @@ -63,4 +64,8 @@ class BrowsePage extends React.Component { } } -export default withTranslation()(BrowsePage); +const mapStateToProps = (state) => ({ + filter: state.appConfig.config.filter, +}); + +export default connect(mapStateToProps)(withTranslation()(BrowsePage)); diff --git a/config/config.ts b/src/config/config.ts similarity index 100% rename from config/config.ts rename to src/config/config.ts diff --git a/src/core/actions/appConfig.ts b/src/core/actions/appConfig.ts new file mode 100644 index 0000000..cf25416 --- /dev/null +++ b/src/core/actions/appConfig.ts @@ -0,0 +1,7 @@ +import { RECEIVE_APP_CONFIG } from 'core/constants/appConfig'; +import { Config } from 'config/config'; + +export const setConfig = (config: Config) => ({ + type: RECEIVE_APP_CONFIG, + payload: config, +}); diff --git a/src/core/actions/decoding.ts b/src/core/actions/decoding.ts new file mode 100644 index 0000000..7bc5362 --- /dev/null +++ b/src/core/actions/decoding.ts @@ -0,0 +1,16 @@ +import { VocabularyService } from '@genesys/client/service'; +import { RECEIVE_COUNTRY_CODES_DECODED } from 'core/constants/decoding'; + +export const getCountryCodes = (lang: string) => (dispatch) => { + return VocabularyService + .decode3166Alpha3Terms(lang) + .then((codes) => { + dispatch({ + type: RECEIVE_COUNTRY_CODES_DECODED, + payload: codes, + }); + }) + .catch((e) => { + console.log('Loading country codes decoding failed: ', e); + }) +}; diff --git a/src/core/constants/appConfig.ts b/src/core/constants/appConfig.ts new file mode 100644 index 0000000..6628515 --- /dev/null +++ b/src/core/constants/appConfig.ts @@ -0,0 +1 @@ +export const RECEIVE_APP_CONFIG = 'core/appConfig/RECEIVE'; diff --git a/src/core/constants/decoding.ts b/src/core/constants/decoding.ts new file mode 100644 index 0000000..62c6eca --- /dev/null +++ b/src/core/constants/decoding.ts @@ -0,0 +1 @@ +export const RECEIVE_COUNTRY_CODES_DECODED = 'core/decoding/RECEIVE'; diff --git a/src/core/reducer/appConfig.ts b/src/core/reducer/appConfig.ts new file mode 100644 index 0000000..9a48d5e --- /dev/null +++ b/src/core/reducer/appConfig.ts @@ -0,0 +1,24 @@ +import update from 'immutability-helper'; + +import { RECEIVE_APP_CONFIG } from 'core/constants/appConfig'; +import { Config } from 'config/config'; + +const INITIAL_STATE: { + config: Partial, +} = { + config: null, +}; + +export default (state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) => { + + switch (action.type) { + case RECEIVE_APP_CONFIG: { + return update(state, { + config: { $set: action.payload }, + }); + } + + default: + return state; + } +} diff --git a/src/core/reducer/decoding.ts b/src/core/reducer/decoding.ts new file mode 100644 index 0000000..5a57e86 --- /dev/null +++ b/src/core/reducer/decoding.ts @@ -0,0 +1,23 @@ +import update from 'immutability-helper'; + +import { RECEIVE_COUNTRY_CODES_DECODED } from 'core/constants/decoding'; + +const INITIAL_STATE: { + codes: Record, +} = { + codes: null, +}; + +export default (state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) => { + + switch (action.type) { + case RECEIVE_COUNTRY_CODES_DECODED: { + return update(state, { + codes: { $set: action.payload }, + }); + } + + default: + return state; + } +} diff --git a/src/core/reducer/index.ts b/src/core/reducer/index.ts new file mode 100644 index 0000000..8256d9e --- /dev/null +++ b/src/core/reducer/index.ts @@ -0,0 +1,11 @@ +import { combineReducers } from 'redux'; +import appConfig from 'core/reducer/appConfig'; +import decoding from './decoding'; + +const rootReducer = () => (combineReducers({ + appConfig, + decoding, +})); + + +export default rootReducer; diff --git a/src/genesys.tsx b/src/genesys.tsx index 4a4690a..a1cb5ce 100644 --- a/src/genesys.tsx +++ b/src/genesys.tsx @@ -1,16 +1,24 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import initI18n from './i18n'; +import { applyMiddleware, compose, createStore } from 'redux'; import { log } from '@genesys/client/utilities/debug'; +import thunk from 'redux-thunk'; +import { Provider } from 'react-redux'; // import * as cookies from 'es-cookie'; import { reconfigureServiceAxios, LoginService } from '@genesys/client/service'; import App from 'ui/core/App'; import ApiAccessError from 'ui/core/ApiAccessError'; -import { Config, DefaultConfig } from '../config/config'; +import { Config, DefaultConfig } from 'config/config'; +import rootReducer from 'core/reducer'; +import { setConfig } from 'core/actions/appConfig'; import OverviewPage from 'accession/OverviewPage'; -// declare const window: Window & { devToolsExtension: any, __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any, initialLanguage: any, initialI18nStore: any, localeMapping: any }; +declare const window: Window & { devToolsExtension: any, __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any }; +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +const initialState = {}; +const store = composeEnhancers(applyMiddleware(thunk))(createStore)(rootReducer(), initialState); // const AUTH_COOKIE = 'GENESYS_AUTH'; console.log('Loading Genesys UI library'); @@ -44,15 +52,18 @@ function checkAccessTokens(apiUrl: string, clientId: string, clientSecret: strin }; export function showGenesysUI(holdingNode: HTMLElement, config: Config = DefaultConfig, language: string = 'en') { - const { apiUrl, clientId, clientKey, filter } = config; + const { apiUrl, clientId, clientKey } = config; reconfigureServiceAxios({ apiUrl }); initI18n(language); + store.dispatch(setConfig(config)); checkAccessTokens(apiUrl, clientId, clientKey).then( (result) => { ReactDOM.render( - , + + + , holdingNode, ); }).catch((err) => { diff --git a/src/ui/core/App.tsx b/src/ui/core/App.tsx index c30dde9..7929abb 100644 --- a/src/ui/core/App.tsx +++ b/src/ui/core/App.tsx @@ -1,22 +1,33 @@ import React from 'react'; +import { connect } from 'react-redux'; import { HashRouter as Router, Route, Switch } from 'react-router-dom'; import NotFound from 'ui/core/NotFound'; import ApiInfoPage from 'serverinfo/ApiInfoPage'; import AccessionList from 'accession/AccessionListPage'; import AccessionDetails from 'accession/AccessionDetailsPage'; import { createHashHistory } from 'history'; +import { bindActionCreators } from 'redux'; +import { getCountryCodes } from 'core/actions/decoding'; +import { withTranslation, WithTranslation } from 'react-i18next'; + import CartPage from 'request/CartPage'; import OverviewPage from 'accession/OverviewPage'; import RequestPage from 'request/RequestPage'; const hashHistory = createHashHistory({}); -interface IAppProps extends React.ClassAttributes { +interface IAppProps extends React.ClassAttributes, WithTranslation { apiUrl: string; filter: object; + getCountryCodes: (lang: string) => Promise>; } -export default class App extends React.Component { +class App extends React.Component { + public componentDidMount() { + const { getCountryCodes, i18n } = this.props; + getCountryCodes(i18n.language); + } + public render() { const { apiUrl } = this.props; console.log('Using filter', this.props.filter); @@ -25,11 +36,11 @@ export default class App extends React.Component {
- } /> - }/> + + - }/> + @@ -45,4 +56,15 @@ export default class App extends React.Component { }; } +const mapStateToProps = (state) => ({ + apiUrl: state.appConfig.config.apiUrl, + filter: state.appConfig.config.filter, +}); + +const mapDispatchToProps = (dispatch) => bindActionCreators({ + getCountryCodes, +}, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(App)); + export { hashHistory as history }; diff --git a/yarn.lock b/yarn.lock index e6da51b..1d94368 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "14.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.8.tgz#2127bd81949a95c8b7d3240f3254352d72563aec" - integrity sha512-z/5Yd59dCKI5kbxauAJgw6dLPzW+TNOItNE00PkpzNwUIEwdj/Lsqwq94H5DdYBX7C13aRA0CY32BK76+neEUA== + version "14.14.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.9.tgz#04afc9a25c6ff93da14deabd65dc44485b53c8d6" + integrity sha512-JsoLXFppG62tWTklIoO4knA+oDTYsmqWxHRvd4lpmfQRNhX6osheUOWETP2jMoV/2bEHuMra8Pp3Dmo/stBFcw== "@types/prop-types@*": version "15.7.3" @@ -104,9 +104,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^16.0.0": - version "16.9.56" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.56.tgz#ea25847b53c5bec064933095fc366b1462e2adf0" - integrity sha512-gIkl4J44G/qxbuC6r2Xh+D3CGZpJ+NdWTItAPmZbR5mUS+JQ8Zvzpl0ea5qT/ZT3ZNTUcDKUVqV3xBE8wv/DyQ== + version "16.14.0" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.0.tgz#bc022cfe1609899b0f2196376b267724e7300f0e" + integrity sha512-jJjHo1uOe+NENRIBvF46tJimUvPnmbQ41Ax0pEm7pRvhPg+wuj8VMOHHiMvaGmZRzRrCtm7KnL5OOE/6kHPK8w== dependencies: "@types/prop-types" "*" csstype "^3.0.2" @@ -597,9 +597,9 @@ awesome-typescript-loader@^5.0.0: webpack-log "^1.2.0" axe-core@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.0.tgz#93d395e6262ecdde5cb52a5d06533d0a0c7bb4cd" - integrity sha512-9atDIOTDLsWL+1GbBec6omflaT5Cxh88J0GtJtGfCVIXpI02rXHkju59W5mMqWa7eiC5OR168v3TK3kUKBW98g== + version "4.1.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.1.tgz#70a7855888e287f7add66002211a423937063eaf" + integrity sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ== axobject-query@^2.2.0: version "2.2.0" @@ -2064,9 +2064,9 @@ ejs@^2.6.1: integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== electron-to-chromium@^1.3.591: - version "1.3.601" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.601.tgz#881824eaef0b2f97c89e1abb5835fdd224997d34" - integrity sha512-ctRyXD9y0mZu8pgeNwBUhLP3Guyr5YuqkfLKYmpTwYx7o9JtCEJme9JVX4xBXPr5ZNvr/iBXUvHLFEVJQThATg== + version "1.3.603" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.603.tgz#1b71bec27fb940eccd79245f6824c63d5f7e8abf" + integrity sha512-J8OHxOeJkoSLgBXfV9BHgKccgfLMHh+CoeRo6wJsi6m0k3otaxS/5vrHpMNSEYY4MISwewqanPOuhAtuE8riQQ== elliptic@^6.5.3: version "6.5.3" @@ -3093,7 +3093,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -3292,6 +3292,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +immutability-helper@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.1.1.tgz#2b86b2286ed3b1241c9e23b7b21e0444f52f77b7" + integrity sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -5271,11 +5276,22 @@ react-i18next@^11.0.0: "@babel/runtime" "^7.3.1" html-parse-stringify2 "2.0.1" -react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-redux@^7.0.0: + version "7.2.2" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.2.tgz#03862e803a30b6b9ef8582dadcc810947f74b736" + integrity sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA== + dependencies: + "@babel/runtime" "^7.12.1" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.13.1" + react-router-dom@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" @@ -5369,6 +5385,24 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" +redux-devtools-extension@^2.13.8: + version "2.13.8" + resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" + integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== + +redux-thunk@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + +redux@^4.0.0: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" @@ -5778,7 +5812,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.2: +side-channel@^1.0.2, side-channel@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3" integrity sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g== @@ -6046,16 +6080,17 @@ string-width@^4.1.0: strip-ansi "^6.0.0" string.prototype.matchall@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e" - integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz#24243399bc31b0a49d19e2b74171a15653ec996a" + integrity sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.17.0" + es-abstract "^1.18.0-next.1" has-symbols "^1.0.1" internal-slot "^1.0.2" regexp.prototype.flags "^1.3.0" - side-channel "^1.0.2" + side-channel "^1.0.3" string.prototype.trimend@^1.0.1: version "1.0.2" @@ -6172,6 +6207,11 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" -- GitLab From 224787fd153b68b58d416892387be853ae798c39 Mon Sep 17 00:00:00 2001 From: Oleksii Savran Date: Thu, 19 Nov 2020 17:36:08 +0200 Subject: [PATCH 2/5] Config: Introducing feature configuration --- entrypoints/client.tsx | 5 ++- src/accession/AccessionListPage.tsx | 60 ++++++++++++++++------------- src/config/config.ts | 17 ++++++++ src/genesys.tsx | 4 +- src/ui/core/App.tsx | 17 ++++---- 5 files changed, 65 insertions(+), 38 deletions(-) diff --git a/entrypoints/client.tsx b/entrypoints/client.tsx index 008474d..e54d285 100644 --- a/entrypoints/client.tsx +++ b/entrypoints/client.tsx @@ -7,4 +7,7 @@ showGenesysUI(document.getElementById('genesys'), { clientKey: 'changeme', apiUrl: 'http://localhost:8080', filter: { institute: { code: [ 'COL003', 'BEL084', 'ETH013' ] } }, -}, queryLang); + accession: { enabled: true }, + language: { locale: queryLang, enableSwitch: true }, + request: { enabled: false }, +}); diff --git a/src/accession/AccessionListPage.tsx b/src/accession/AccessionListPage.tsx index 7a649cf..eacc45c 100644 --- a/src/accession/AccessionListPage.tsx +++ b/src/accession/AccessionListPage.tsx @@ -23,6 +23,7 @@ interface IAccessionListPageState { interface IAccessionListPageProps { filter: AccessionFilter; location: any; + cartEnabled: boolean; } class AccessionListPage extends React.Component { @@ -164,7 +165,7 @@ class AccessionListPage extends React.Component selectedUUIDs.add(uuid)); @@ -188,48 +189,54 @@ class AccessionListPage extends React.Component - - - + { cartEnabled && ( + + + + ) } { t('accession.crop') } { t('accession.acceNumb') } { t('accession.accessionName') } { t('accession.taxonomy') } { t('accession.countryOfOrigin') } { t('accession.sampStat') } - { t('list.availability') } + { cartEnabled && ( { t('list.availability') } ) } { accessions.content.map((a, i) => ( - - {this.canAddToCart(a) && - - } - + { cartEnabled && ( + + { this.canAddToCart(a) && + + } + + ) } { a.cropName } { a.accessionNumber } { a.accessionName } { a.countryOfOrigin && a.countryOfOrigin.name } { a.sampStat && t(`accession.sampleStatus.${a.sampStat}`) } - - {this.renderCartButton(a, i)} - + { cartEnabled && + + { this.renderCartButton(a, i) } + + } )) } @@ -243,6 +250,7 @@ class AccessionListPage extends React.Component ({ filter: state.appConfig.config.filter, + cartEnabled: state.appConfig.config.request.enabled, }); export default connect(mapStateToProps)(withTranslation()(AccessionListPage)); diff --git a/src/config/config.ts b/src/config/config.ts index c320485..25eee72 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -4,6 +4,11 @@ export class Config { public clientKey: string; public filter: Record; + // module config + public accession: BaseFeatureConfig; + public language: Partial; + public request: BaseFeatureConfig; + public constructor(config: Config) { this.apiUrl = config.apiUrl; this.clientId = config.clientId; @@ -12,9 +17,21 @@ export class Config { } } +export class BaseFeatureConfig { + public enabled: boolean; +} + +class LanguageConfig { + public locale: string; + public enableSwitch: boolean; +} + export const DefaultConfig = new Config( { apiUrl: 'https://api.sandbox.genesys-pgr.org', clientId: 'clientid@genesys', clientKey: 'changeme', filter: {}, + language: { locale: 'en', enableSwitch: true }, + accession: { enabled: true }, + request: { enabled: true }, }) diff --git a/src/genesys.tsx b/src/genesys.tsx index a1cb5ce..dc9001f 100644 --- a/src/genesys.tsx +++ b/src/genesys.tsx @@ -51,11 +51,11 @@ function checkAccessTokens(apiUrl: string, clientId: string, clientSecret: strin return appLogin; }; -export function showGenesysUI(holdingNode: HTMLElement, config: Config = DefaultConfig, language: string = 'en') { +export function showGenesysUI(holdingNode: HTMLElement, config: Config = DefaultConfig) { const { apiUrl, clientId, clientKey } = config; reconfigureServiceAxios({ apiUrl }); - initI18n(language); + initI18n(config.language.locale); store.dispatch(setConfig(config)); checkAccessTokens(apiUrl, clientId, clientKey).then( (result) => { diff --git a/src/ui/core/App.tsx b/src/ui/core/App.tsx index 7929abb..0e8e14c 100644 --- a/src/ui/core/App.tsx +++ b/src/ui/core/App.tsx @@ -9,7 +9,7 @@ import { createHashHistory } from 'history'; import { bindActionCreators } from 'redux'; import { getCountryCodes } from 'core/actions/decoding'; import { withTranslation, WithTranslation } from 'react-i18next'; - +import { Config } from 'config/config'; import CartPage from 'request/CartPage'; import OverviewPage from 'accession/OverviewPage'; import RequestPage from 'request/RequestPage'; @@ -17,8 +17,7 @@ import RequestPage from 'request/RequestPage'; const hashHistory = createHashHistory({}); interface IAppProps extends React.ClassAttributes, WithTranslation { - apiUrl: string; - filter: object; + config: Config; getCountryCodes: (lang: string) => Promise>; } @@ -29,8 +28,9 @@ class App extends React.Component { } public render() { - const { apiUrl } = this.props; - console.log('Using filter', this.props.filter); + const { config } = this.props; + const { apiUrl, request } = config; + return ( <> @@ -39,9 +39,9 @@ class App extends React.Component { - + { request.enabled && } - + { request.enabled && } @@ -57,8 +57,7 @@ class App extends React.Component { } const mapStateToProps = (state) => ({ - apiUrl: state.appConfig.config.apiUrl, - filter: state.appConfig.config.filter, + config: state.appConfig.config, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ -- GitLab From b08f2c8cace6dd2e8c3f129ed2342e523cedb48b Mon Sep 17 00:00:00 2001 From: Oleksii Savran Date: Fri, 20 Nov 2020 11:36:04 +0200 Subject: [PATCH 3/5] showOverview with Redux --- entrypoints/client.tsx | 14 ++++++++++---- src/accession/AccessionOverviewSection.tsx | 2 +- src/config/config.ts | 11 ++++++++--- src/core/reducer/decoding.ts | 6 +++--- src/genesys.tsx | 15 +++++++++------ 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/entrypoints/client.tsx b/entrypoints/client.tsx index e54d285..221b40a 100644 --- a/entrypoints/client.tsx +++ b/entrypoints/client.tsx @@ -1,13 +1,19 @@ -import { showGenesysUI } from 'genesys'; +import { + showGenesysUI, + // showOverview, // for testing +} from 'genesys'; const queryLang = document.location.search && document.location.search.substr(1) || undefined; -showGenesysUI(document.getElementById('genesys'), { +const config = { clientId: 'defaultclient@localhost', clientKey: 'changeme', apiUrl: 'http://localhost:8080', filter: { institute: { code: [ 'COL003', 'BEL084', 'ETH013' ] } }, accession: { enabled: true }, language: { locale: queryLang, enableSwitch: true }, - request: { enabled: false }, -}); + request: { enabled: true }, +}; + +showGenesysUI(document.getElementById('genesys'), config); +// showOverview(document.getElementById('genesys'), config); diff --git a/src/accession/AccessionOverviewSection.tsx b/src/accession/AccessionOverviewSection.tsx index d1d8099..a23a46e 100644 --- a/src/accession/AccessionOverviewSection.tsx +++ b/src/accession/AccessionOverviewSection.tsx @@ -193,7 +193,7 @@ class AccessionOverviewSection extends React.Component ({ - countryCodes: state.decoding.codes, + countryCodes: state.decoding.countryCodes, }); export default connect(mapStateToProps)(withTranslation()(AccessionOverviewSection)); diff --git a/src/config/config.ts b/src/config/config.ts index 25eee72..def0816 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -5,15 +5,20 @@ export class Config { public filter: Record; // module config - public accession: BaseFeatureConfig; public language: Partial; - public request: BaseFeatureConfig; + public accession?: BaseFeatureConfig; + public request?: BaseFeatureConfig; public constructor(config: Config) { this.apiUrl = config.apiUrl; this.clientId = config.clientId; this.clientKey = config.clientKey; this.filter = config.filter; + + // features + this.accession = config.accession || {} as BaseFeatureConfig; + this.request = config.request || {} as BaseFeatureConfig; + this.language = config.language || { locale: 'en' }; } } @@ -34,4 +39,4 @@ export const DefaultConfig = new Config( { language: { locale: 'en', enableSwitch: true }, accession: { enabled: true }, request: { enabled: true }, -}) +}); diff --git a/src/core/reducer/decoding.ts b/src/core/reducer/decoding.ts index 5a57e86..94dfa35 100644 --- a/src/core/reducer/decoding.ts +++ b/src/core/reducer/decoding.ts @@ -3,9 +3,9 @@ import update from 'immutability-helper'; import { RECEIVE_COUNTRY_CODES_DECODED } from 'core/constants/decoding'; const INITIAL_STATE: { - codes: Record, + countryCodes: Record, } = { - codes: null, + countryCodes: null, }; export default (state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) => { @@ -13,7 +13,7 @@ export default (state = INITIAL_STATE, action: { type?: string, payload?: any } switch (action.type) { case RECEIVE_COUNTRY_CODES_DECODED: { return update(state, { - codes: { $set: action.payload }, + countryCodes: { $set: action.payload }, }); } diff --git a/src/genesys.tsx b/src/genesys.tsx index dc9001f..eb9757f 100644 --- a/src/genesys.tsx +++ b/src/genesys.tsx @@ -52,10 +52,10 @@ function checkAccessTokens(apiUrl: string, clientId: string, clientSecret: strin }; export function showGenesysUI(holdingNode: HTMLElement, config: Config = DefaultConfig) { - const { apiUrl, clientId, clientKey } = config; + const { apiUrl, clientId, clientKey, language } = config; reconfigureServiceAxios({ apiUrl }); - initI18n(config.language.locale); + initI18n(language.locale); store.dispatch(setConfig(config)); checkAccessTokens(apiUrl, clientId, clientKey).then( (result) => { @@ -76,16 +76,19 @@ export function showGenesysUI(holdingNode: HTMLElement, config: Config = Default } -export function showOverview(holdingNode: HTMLElement, config: Config = DefaultConfig, language: string = 'en') { - const { apiUrl, clientId, clientKey, filter } = config; +export function showOverview(holdingNode: HTMLElement, config: Config = DefaultConfig) { + const { apiUrl, clientId, clientKey, language } = config; reconfigureServiceAxios({ apiUrl }); - initI18n(language); + initI18n(language.locale); + store.dispatch(setConfig(config)); checkAccessTokens(apiUrl, clientId, clientKey).then( (result) => { ReactDOM.render( - , + + + , holdingNode, ); }).catch((err) => { -- GitLab From 874063845657c8a8432acdf71e73f9742424347f Mon Sep 17 00:00:00 2001 From: Oleksii Savran Date: Fri, 20 Nov 2020 15:39:39 +0200 Subject: [PATCH 4/5] Config: Added default configuration options --- entrypoints/client.tsx | 2 -- src/config/config.ts | 20 ++++++++++---------- src/core/reducer/appConfig.ts | 4 +++- src/genesys.tsx | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/entrypoints/client.tsx b/entrypoints/client.tsx index 221b40a..45291a5 100644 --- a/entrypoints/client.tsx +++ b/entrypoints/client.tsx @@ -10,9 +10,7 @@ const config = { clientKey: 'changeme', apiUrl: 'http://localhost:8080', filter: { institute: { code: [ 'COL003', 'BEL084', 'ETH013' ] } }, - accession: { enabled: true }, language: { locale: queryLang, enableSwitch: true }, - request: { enabled: true }, }; showGenesysUI(document.getElementById('genesys'), config); diff --git a/src/config/config.ts b/src/config/config.ts index def0816..31b92e5 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -1,24 +1,24 @@ export class Config { - public apiUrl: string; + public apiUrl?: string; public clientId: string; public clientKey: string; - public filter: Record; + public filter?: Record; // module config - public language: Partial; + public language?: Partial; public accession?: BaseFeatureConfig; public request?: BaseFeatureConfig; public constructor(config: Config) { - this.apiUrl = config.apiUrl; + this.apiUrl = config.apiUrl || defaultConfig.apiUrl; this.clientId = config.clientId; this.clientKey = config.clientKey; - this.filter = config.filter; + this.filter = config.filter || defaultConfig.filter; // features - this.accession = config.accession || {} as BaseFeatureConfig; - this.request = config.request || {} as BaseFeatureConfig; - this.language = config.language || { locale: 'en' }; + this.accession = config.accession || defaultConfig.accession; + this.request = config.request || defaultConfig.request; + this.language = config.language || defaultConfig.language; } } @@ -31,7 +31,7 @@ class LanguageConfig { public enableSwitch: boolean; } -export const DefaultConfig = new Config( { +export const defaultConfig = { apiUrl: 'https://api.sandbox.genesys-pgr.org', clientId: 'clientid@genesys', clientKey: 'changeme', @@ -39,4 +39,4 @@ export const DefaultConfig = new Config( { language: { locale: 'en', enableSwitch: true }, accession: { enabled: true }, request: { enabled: true }, -}); +}; diff --git a/src/core/reducer/appConfig.ts b/src/core/reducer/appConfig.ts index 9a48d5e..4fd0c28 100644 --- a/src/core/reducer/appConfig.ts +++ b/src/core/reducer/appConfig.ts @@ -13,8 +13,10 @@ export default (state = INITIAL_STATE, action: { type?: string, payload?: any } switch (action.type) { case RECEIVE_APP_CONFIG: { + const config = new Config(action.payload); + return update(state, { - config: { $set: action.payload }, + config: { $set: config }, }); } diff --git a/src/genesys.tsx b/src/genesys.tsx index eb9757f..f60e7f9 100644 --- a/src/genesys.tsx +++ b/src/genesys.tsx @@ -10,7 +10,7 @@ import { Provider } from 'react-redux'; import { reconfigureServiceAxios, LoginService } from '@genesys/client/service'; import App from 'ui/core/App'; import ApiAccessError from 'ui/core/ApiAccessError'; -import { Config, DefaultConfig } from 'config/config'; +import { Config } from 'config/config'; import rootReducer from 'core/reducer'; import { setConfig } from 'core/actions/appConfig'; import OverviewPage from 'accession/OverviewPage'; @@ -51,7 +51,7 @@ function checkAccessTokens(apiUrl: string, clientId: string, clientSecret: strin return appLogin; }; -export function showGenesysUI(holdingNode: HTMLElement, config: Config = DefaultConfig) { +export function showGenesysUI(holdingNode: HTMLElement, config: Config) { const { apiUrl, clientId, clientKey, language } = config; reconfigureServiceAxios({ apiUrl }); @@ -76,7 +76,7 @@ export function showGenesysUI(holdingNode: HTMLElement, config: Config = Default } -export function showOverview(holdingNode: HTMLElement, config: Config = DefaultConfig) { +export function showOverview(holdingNode: HTMLElement, config: Config) { const { apiUrl, clientId, clientKey, language } = config; reconfigureServiceAxios({ apiUrl }); -- GitLab From 083460e9733928488122a41ee9caed7dd16c4108 Mon Sep 17 00:00:00 2001 From: Matija Obreza Date: Fri, 20 Nov 2020 18:46:23 +0100 Subject: [PATCH 5/5] Config: renamed to appConfig, updated configuration property names - added WithConfig - updated merging of configuration options --- entrypoints/client.tsx | 14 +++++---- src/accession/AccessionDetailsPage.tsx | 40 ++++++++++++++------------ src/accession/AccessionListPage.tsx | 22 +++++++------- src/config/config.ts | 30 +++++++++---------- src/core/reducer/appConfig.ts | 2 +- src/genesys.tsx | 6 ++-- src/ui/core/App.tsx | 16 +++++------ 7 files changed, 65 insertions(+), 65 deletions(-) diff --git a/entrypoints/client.tsx b/entrypoints/client.tsx index 45291a5..595b775 100644 --- a/entrypoints/client.tsx +++ b/entrypoints/client.tsx @@ -1,3 +1,4 @@ +import { Config } from 'config/config'; import { showGenesysUI, // showOverview, // for testing @@ -5,13 +6,16 @@ import { const queryLang = document.location.search && document.location.search.substr(1) || undefined; -const config = { +const genesysConfig: Config = { + apiUrl: 'http://localhost:8080', clientId: 'defaultclient@localhost', clientKey: 'changeme', - apiUrl: 'http://localhost:8080', filter: { institute: { code: [ 'COL003', 'BEL084', 'ETH013' ] } }, - language: { locale: queryLang, enableSwitch: true }, + language: queryLang, + shoppingCart: { + enabled: true, + }, }; -showGenesysUI(document.getElementById('genesys'), config); -// showOverview(document.getElementById('genesys'), config); +showGenesysUI(document.getElementById('genesys'), genesysConfig); +// showOverview(document.getElementById('genesys'), genesysConfig); diff --git a/src/accession/AccessionDetailsPage.tsx b/src/accession/AccessionDetailsPage.tsx index 8c923ea..6aa79fb 100644 --- a/src/accession/AccessionDetailsPage.tsx +++ b/src/accession/AccessionDetailsPage.tsx @@ -6,6 +6,7 @@ import { Property } from 'ui/common/Property'; import AccessionDetails from '@genesys/client/model/accession/AccessionDetails'; import { WithTranslation, withTranslation } from 'react-i18next'; import { LocalStorageCart } from 'utilities'; +import { WithConfig } from 'config/config'; interface IAccessionDetailsPageState { accession: AccessionDetails; @@ -14,10 +15,9 @@ interface IAccessionDetailsPageState { interface IAccessionDetailsPage { match: any; - apiUrl: string; } -class AccessionDetailsPage extends React.Component { +class AccessionDetailsPage extends React.Component { public constructor(props) { super(props); } @@ -92,7 +92,7 @@ class AccessionDetailsPage extends React.Component } -
- {cartItems.includes(this.props.match.params.uuid) ? - - : - this.renderAddToCart() - } -
+ { shoppingCart.enabled && +
+ { cartItems.includes(this.props.match.params.uuid) ? + + : + this.renderAddToCart() + } +
+ } ); } @@ -223,7 +225,7 @@ class AccessionDetailsPage extends React.Component ({ - apiUrl: state.appConfig.config.apiUrl, + appConfig: state.appConfig.config, }); export default connect(mapStateToProps)(withTranslation()(AccessionDetailsPage)); diff --git a/src/accession/AccessionListPage.tsx b/src/accession/AccessionListPage.tsx index eacc45c..0095278 100644 --- a/src/accession/AccessionListPage.tsx +++ b/src/accession/AccessionListPage.tsx @@ -11,6 +11,7 @@ import Pagination from 'ui/common/Pagination'; import { AccessionFilters } from './AccessionFilters'; import { withTranslation, WithTranslation } from 'react-i18next'; import { LocalStorageCart } from 'utilities'; +import { WithConfig } from 'config/config'; interface IAccessionListPageState { filter: AccessionFilter; @@ -21,17 +22,15 @@ interface IAccessionListPageState { } interface IAccessionListPageProps { - filter: AccessionFilter; location: any; - cartEnabled: boolean; } -class AccessionListPage extends React.Component { +class AccessionListPage extends React.Component { public constructor(props) { super(props); this.state = { - filter: this.props.filter, + filter: this.props.appConfig.filter, accessions: null, selected: [], isAllSelected: false, @@ -70,7 +69,7 @@ class AccessionListPage extends React.Component selectedUUIDs.add(uuid)); @@ -189,7 +188,7 @@ class AccessionListPage extends React.Component - { cartEnabled && ( + { shoppingCart.enabled && ( { t('accession.taxonomy') } { t('accession.countryOfOrigin') } { t('accession.sampStat') } - { cartEnabled && ( { t('list.availability') } ) } + { shoppingCart.enabled && ( { t('list.availability') } ) } { accessions.content.map((a, i) => ( - { cartEnabled && ( + { shoppingCart.enabled && ( { this.canAddToCart(a) && { a.countryOfOrigin && a.countryOfOrigin.name } { a.sampStat && t(`accession.sampleStatus.${a.sampStat}`) } - { cartEnabled && + { shoppingCart.enabled && { this.renderCartButton(a, i) } @@ -249,8 +248,7 @@ class AccessionListPage extends React.Component ({ - filter: state.appConfig.config.filter, - cartEnabled: state.appConfig.config.request.enabled, + appConfig: state.appConfig.config, }); export default connect(mapStateToProps)(withTranslation()(AccessionListPage)); diff --git a/src/config/config.ts b/src/config/config.ts index 31b92e5..aae5169 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -1,3 +1,7 @@ +export interface WithConfig { + appConfig: Config; +} + export class Config { public apiUrl?: string; public clientId: string; @@ -5,20 +9,21 @@ export class Config { public filter?: Record; // module config - public language?: Partial; + public language?: string = 'en'; public accession?: BaseFeatureConfig; - public request?: BaseFeatureConfig; + public shoppingCart?: BaseFeatureConfig; public constructor(config: Config) { this.apiUrl = config.apiUrl || defaultConfig.apiUrl; this.clientId = config.clientId; this.clientKey = config.clientKey; + this.language = config.language || defaultConfig.language; this.filter = config.filter || defaultConfig.filter; - // features - this.accession = config.accession || defaultConfig.accession; - this.request = config.request || defaultConfig.request; - this.language = config.language || defaultConfig.language; + // Merge feature config + this.accession = { ...defaultConfig.accession, ...config.accession }; + this.shoppingCart = { ...defaultConfig.shoppingCart, ...config.shoppingCart }; + // console.log('Source and merged configuration', config, this); } } @@ -26,17 +31,10 @@ export class BaseFeatureConfig { public enabled: boolean; } -class LanguageConfig { - public locale: string; - public enableSwitch: boolean; -} - -export const defaultConfig = { +export const defaultConfig: Partial = { apiUrl: 'https://api.sandbox.genesys-pgr.org', - clientId: 'clientid@genesys', - clientKey: 'changeme', filter: {}, - language: { locale: 'en', enableSwitch: true }, + language: 'en', accession: { enabled: true }, - request: { enabled: true }, + shoppingCart: { enabled: false }, }; diff --git a/src/core/reducer/appConfig.ts b/src/core/reducer/appConfig.ts index 4fd0c28..baa53c6 100644 --- a/src/core/reducer/appConfig.ts +++ b/src/core/reducer/appConfig.ts @@ -4,7 +4,7 @@ import { RECEIVE_APP_CONFIG } from 'core/constants/appConfig'; import { Config } from 'config/config'; const INITIAL_STATE: { - config: Partial, + config: Config, } = { config: null, }; diff --git a/src/genesys.tsx b/src/genesys.tsx index f60e7f9..ff46ba6 100644 --- a/src/genesys.tsx +++ b/src/genesys.tsx @@ -55,7 +55,7 @@ export function showGenesysUI(holdingNode: HTMLElement, config: Config) { const { apiUrl, clientId, clientKey, language } = config; reconfigureServiceAxios({ apiUrl }); - initI18n(language.locale); + initI18n(language); store.dispatch(setConfig(config)); checkAccessTokens(apiUrl, clientId, clientKey).then( (result) => { @@ -80,14 +80,14 @@ export function showOverview(holdingNode: HTMLElement, config: Config) { const { apiUrl, clientId, clientKey, language } = config; reconfigureServiceAxios({ apiUrl }); - initI18n(language.locale); + initI18n(language); store.dispatch(setConfig(config)); checkAccessTokens(apiUrl, clientId, clientKey).then( (result) => { ReactDOM.render( - + , holdingNode, ); diff --git a/src/ui/core/App.tsx b/src/ui/core/App.tsx index 0e8e14c..8fc00a7 100644 --- a/src/ui/core/App.tsx +++ b/src/ui/core/App.tsx @@ -9,27 +9,25 @@ import { createHashHistory } from 'history'; import { bindActionCreators } from 'redux'; import { getCountryCodes } from 'core/actions/decoding'; import { withTranslation, WithTranslation } from 'react-i18next'; -import { Config } from 'config/config'; +import { WithConfig } from 'config/config'; import CartPage from 'request/CartPage'; import OverviewPage from 'accession/OverviewPage'; import RequestPage from 'request/RequestPage'; const hashHistory = createHashHistory({}); -interface IAppProps extends React.ClassAttributes, WithTranslation { - config: Config; +interface IAppProps extends React.ClassAttributes { getCountryCodes: (lang: string) => Promise>; } -class App extends React.Component { +class App extends React.Component { public componentDidMount() { const { getCountryCodes, i18n } = this.props; getCountryCodes(i18n.language); } public render() { - const { config } = this.props; - const { apiUrl, request } = config; + const { appConfig: { apiUrl, shoppingCart } } = this.props; return ( <> @@ -39,9 +37,9 @@ class App extends React.Component { - { request.enabled && } + { shoppingCart.enabled && } - { request.enabled && } + { shoppingCart.enabled && } @@ -57,7 +55,7 @@ class App extends React.Component { } const mapStateToProps = (state) => ({ - config: state.appConfig.config, + appConfig: state.appConfig.config, }); const mapDispatchToProps = (dispatch) => bindActionCreators({ -- GitLab