Commit c79eaadb authored by Axel Bocciarelli's avatar Axel Bocciarelli

Merge branch 'config' into 'master'

Flatten config folder

See merge request !435
parents 2aa60a4e 2dd739e9
Pipeline #32507 passed with stages
in 7 minutes and 43 seconds
......@@ -17,7 +17,7 @@ Currently, datahub depends on:
- [Installation](#installation)
- [Configuration](#configuration)
- [Developments](#developments)
- [Development](#development)
# Installation
......@@ -39,11 +39,10 @@ Currently, datahub depends on:
Datahub configuration is spread among different files located in <kbd>src/config</kbd>. These files are:
- [icat.js](#icatjs) : configure access to the metadata catalogue.
- [icatPlus.js](#icatplusjs) : configure access to the ICAT+ server
- [techniques.js](#techniquesjs) : configure the known techniques
- [gui.config.js](#guiconfigjs) : configuration file for the logbook (to be moved to config.js)
- [config.js](#configjs) : UI general configuration of the GUI
- `icat.js` - configure access to metadata catalogue
- `icatPlus.js` - configure access to ICAT+ server
- [`techniques.js`](#techniquesjs) - configure known techniques
- [`ui.js`](#uijs) - general UI configuration
Some of the configuration options in these files are stored in [environment variables](#environment-variables).
......@@ -61,7 +60,7 @@ The following portal configuration variables are declared in <kbd>.env</kbd>:
In development, you can override any of these variables by creating a file called `.env.local`. This file is ignored from version control.
## techniques.js
## `techniques.js`
The file [techniques.js](src/config/techniques/techniques.js) complements short named techniques as stored in ICAT metadata catalogue. It maps a short name to a description and display settings.
......@@ -81,23 +80,12 @@ color: "#97E0FE"
},
```
## gui.config.js
## `ui.js`
Edit the file [gui.config.js](src/config/gui.config.js) with your favorite text editor and set the GUI configuration following the indications below.
<!--START configurationGUI -->
<!--START ui -->
```js
```
<!--END configurationGUI -->
## ui.config.js
<!--START config -->
```js
var UI = {
const UI = {
status: {
offline: {
enabled: false,
......@@ -105,20 +93,21 @@ var UI = {
},
},
menu: {
applicationTittle: 'Data Portal',
applicationTitle: 'Data Portal',
isSearchVisible: true,
isClosedDataVisible: true,
isOpenDataVisible: true,
isMySelectionVisible: true,
},
sampleTracking: {
//** Makes visible or invisible the menus and tabs related to sample tracking */
enabled: true,
},
loginForm: {
header: '',
/** Text displayed on top of the username sigin form. Someone can customize the text as: User office account, ESRF Account, Umbrella account, etc... */
usernameLabel: 'Username',
sso: {
title: 'Sign in with SSO',
buttonText: 'ESRF SSO',
},
ssoBtnLabel: 'Sign in with ESRF SSO',
},
investigationContainer: {
isDatasetListVisible: true,
......@@ -147,19 +136,22 @@ var UI = {
* When it is set to false, the event list is not refreshed but the amount of new events which arriived is shown.*/
AUTOREFRESH_EVENTLIST: true,
/* Time interval between requests checking whether new events arrived. (in milliseconds) */
AUTOREFRESH_DELAY: 20000,
AUTOREFRESH_DELAY: 60000,
},
dangerousGoodsHelp:
'Please ensure you reply correctly to this question after consultation with your lab safety referent and/or the transport company. This question is for ESRF internal use only - you must correctly declare your parcel in the official transport documents',
footer: {
text: 'European Synchrotron Radiation Facility',
},
samplePageTemplateURL: 'https://smis.esrf.fr/misapps/SMISWebClient/protected/samplesheet/view.do?pk=',
};
export default UI;
```
<!--END config -->
<!--END ui -->
# Developments
# Development
- [Tests](#tests)
- [Code quality](#code-quality)
......
......@@ -14176,6 +14176,155 @@
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
},
"replace": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/replace/-/replace-1.2.0.tgz",
"integrity": "sha512-e3AP5GkRk+N/Qm1MUBaMhEHr4X3sHNI44a8m4ww6/qShJphTsStxSezbYtFNTFGCXZtWrwz4McVvCEwBv+ebAw==",
"dev": true,
"requires": {
"chalk": "2.4.2",
"minimatch": "3.0.4",
"yargs": "^15.3.1"
},
"dependencies": {
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"dev": true,
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
......
......@@ -11,9 +11,9 @@
"build": "react-scripts build",
"start": "react-scripts start",
"test": "react-scripts test --env=jsdom-fourteen",
"doc": "npm run Readme:ConfigDoc:ICAT && npm run Readme:ConfigDoc:ICAT:ReplaceCodeSection && npm run Readme:ConfigDoc:ICATPlus && npm run Readme:ConfigDoc:ICATPlus:ReplaceCodeSection && npm run Readme:ConfigDoc:Config && npm run Readme:ConfigDoc:Config:ReplaceCodeSection",
"Readme:ConfigDoc:Config": "node ./node_modules/jscat/bin/jscat src/config/ui/config.js | node ./node_modules/injectmd/bin/cli.js -t config -i Readme.md",
"Readme:ConfigDoc:Config:ReplaceCodeSection": "./node_modules/replace/bin/replace.js '<!--START config -->' '<!--START config -->\n```js' Readme.md && ./node_modules/replace/bin/replace.js '<!--END config -->' '```\n<!--END config -->' Readme.md",
"doc": "run-s doc:*",
"doc:inject": "node ./node_modules/jscat/bin/jscat src/config/ui.js | node ./node_modules/injectmd/bin/cli.js -t config -i README.md",
"doc:replace": "./node_modules/replace/bin/replace.js '<!--START ui -->\n```js' '<!--START ui -->\n```js' README.md && ./node_modules/replace/bin/replace.js '```\n<!--END ui -->' '```\n<!--END ui -->' README.md",
"complexity-report": "./node_modules/.bin/es6-plato -r -d ./public/report src",
"lint": "run-p lint:*",
"lint:eslint": "eslint \"**/*.{js,jsx}\" --max-warnings=0",
......@@ -82,6 +82,7 @@
"prettier": "2.0.5",
"prop-types": "^15.7.2",
"react-doc-generator": "^1.2.5",
"replace": "^1.2.0",
"typescript": "^3.9.7"
},
"jest": {
......
......@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Route, Switch, Redirect, useLocation } from 'react-router-dom';
import Footer from './components/Footer';
import UI from './config/ui/config';
import UI from './config/ui';
import AddressesPage from './containers/AddressesPage';
import LoginPage from './containers/LoginPage';
import MyDataPage from './containers/MyDataPage';
......
import axios from 'axios';
import ICATPLUS from '../config/icat/icatPlus';
import ICATPLUS from '../config/icatPlus';
import {
LOGGED_IN,
LOGIN_ERROR,
......@@ -7,7 +7,7 @@ import {
LOG_OUT,
} from '../constants/actionTypes';
import keycloak from '../keycloak';
import ICAT from '../config/icat/icat';
import ICAT from '../config/icat';
export function doLogOut(params = { expired: false }) {
return { type: LOG_OUT, ...params };
......
import ICATPLUS from '../../config/icat/icatPlus';
import ICATPLUS from '../../config/icatPlus';
/** To be removed from here */
const IDS = {
......
......@@ -8,7 +8,7 @@ import {
} from '../../constants/parameterTypes';
import DOIBadge from '../doi/DOIBadge';
import ResponsiveTable from '../Table/ResponsiveTable';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
class DataCollectionTable extends React.Component {
doiFormatter(cell) {
......
......@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { Glyphicon } from 'react-bootstrap';
import moment from 'moment';
import TECHNIQUES from '../../config/techniques/techniques';
import TECHNIQUES from '../../config/techniques';
import { FILE_COUNT, VOLUME } from '../../constants/parameterTypes';
import { getDatasetParameterByName, stringifyBytesSize } from '../../helpers';
import ResponsiveTable from '../Table/ResponsiveTable';
......
import React from 'react';
import { Badge, Panel, Tab, Tabs } from 'react-bootstrap';
import TECHNIQUES from '../../config/techniques/techniques';
import TECHNIQUES from '../../config/techniques';
import { FILE_COUNT } from '../../constants/parameterTypes';
import { getDatasetParameterByPrefixName } from '../../helpers';
import DatasetFileTree from '../File/DatasetFileTree';
......
import React from 'react';
import UI from '../config/ui/config';
import UI from '../config/ui';
import logo from '../images/ebs.gif';
import styles from './Footer.module.css';
......
......@@ -16,7 +16,7 @@ import {
LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_PLAINTEXT_FORMAT,
LOCALSTORAGE_KEY_EDITED_EVENT_CONTENT_IN_HTML_FORMAT,
} from '../../../constants/eventTypes';
import UI from '../../../config/ui/config';
import UI from '../../../config/ui';
import { getFileByEventId, uploadFile } from '../../../api/icat/icatPlus';
const EDITOR_ID_FOR_CREATION = 'myEditorForCreation';
......
import PropTypes from 'prop-types';
import React from 'react';
import ReactPaginate from 'react-paginate';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
/* This class handles the display of pages for the logbook */
class LogbookPager extends React.Component {
......
......@@ -14,7 +14,7 @@ import {
Row,
} from 'react-bootstrap';
import { GithubPicker } from 'react-color';
import UI from '../../../config/ui/config';
import UI from '../../../config/ui';
function renderPopoverColorPickerBottom(callback) {
return (
......
......@@ -2,7 +2,7 @@ import { intersectionWith } from 'lodash-es';
import PropTypes from 'prop-types';
import React from 'react';
import CreatableSelect from 'react-select/lib/Creatable';
import UI from '../../../config/ui/config';
import UI from '../../../config/ui';
class TagSelector extends React.Component {
constructor(props) {
......
import React from 'react';
import { Button } from 'react-bootstrap';
import ICAT from '../../config/icat/icat';
import ICAT from '../../config/icat';
import { doSignIn } from '../../actions/login';
import { useDispatch } from 'react-redux';
......
......@@ -8,7 +8,7 @@ import {
FormGroup,
ControlLabel,
} from 'react-bootstrap';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
import ErrorUserMessage from '../UserMessages/ErrorUserMessage';
import AnonymousSignIn from './AnonymousSignIn';
import { useSelector, useDispatch } from 'react-redux';
......
import React from 'react';
import { Panel, Tab, Tabs } from 'react-bootstrap';
import ICAT from '../../config/icat/icat';
import ICAT from '../../config/icat';
import SSO from './SSO';
import LoginForm from './LoginForm';
......
import React from 'react';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
import Loader from '../Loader';
import ErrorUserMessage from '../UserMessages/ErrorUserMessage';
import AnonymousSignIn from './AnonymousSignIn';
......@@ -49,7 +49,7 @@ function SSO() {
bsSize="large"
onClick={handleClick}
>
{UI.loginForm.sso.title}
{UI.loginForm.ssoBtnLabel}
</Button>
<AnonymousSignIn />
......
......@@ -2,7 +2,7 @@ import React from 'react';
import { Glyphicon, Nav, Navbar, NavDropdown, NavItem } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';
import { Link } from 'react-router-dom';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
import BreadCrumbs from '../Breadcrumbs/BreadCrumbs';
import ManagerMenu from './ManagerMenu';
import keycloak from '../../keycloak';
......
import React, { useState } from 'react';
import { Alert, Button, HelpBlock, Modal } from 'react-bootstrap';
import { useForm } from 'react-hook-form';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
function DangerousGoodsModal(props) {
const { onConfirm, onCloseModal, isProcessing } = props;
......
......@@ -3,7 +3,7 @@ import { Badge, Glyphicon, Nav, NavItem } from 'react-bootstrap';
import { useSelector } from 'react-redux';
import { useParams } from 'react-router';
import { LinkContainer } from 'react-router-bootstrap';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
function TabContainerMenu(props) {
const { doi } = props;
......
const ICAT_PLUS = {
const ICATPLUS = {
/** URL of ICAT+ server */
server: process.env.REACT_APP_ICATPLUS_URL,
};
export default ICAT_PLUS;
export default ICATPLUS;
const ALIAS = {
const PARAMETERS = {
InstrumentMonochromator_energy: 'Energy',
InstrumentMonochromator_wavelength: 'Wavelength',
InstrumentMonochromatorCrystal_d_spacing: 'd_spacing',
......@@ -7,4 +7,4 @@ const ALIAS = {
InstrumentMonochromatorCrystal_usage: 'Usage',
};
export default ALIAS;
export default PARAMETERS;
......@@ -20,10 +20,7 @@ const UI = {
header: '',
/** Text displayed on top of the username sigin form. Someone can customize the text as: User office account, ESRF Account, Umbrella account, etc... */
usernameLabel: 'Username',
sso: {
title: 'Sign in with ESRF SSO',
buttonText: 'ESRF SSO', // deprecated
},
ssoBtnLabel: 'Sign in with ESRF SSO',
},
investigationContainer: {
isDatasetListVisible: true,
......
......@@ -16,7 +16,7 @@ import NewOrEditEventPanel from '../../components/Logbook/NewOrEditEventPanel';
import OverlayBox from '../../components/Logbook/OverlayBox';
import PublicEventPanel from '../../components/Logbook/PublicEventPanel';
import UserMessage from '../../components/UserMessage';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
import {
ERROR_MESSAGE_TYPE,
INFO_MESSAGE_TYPE,
......@@ -860,9 +860,7 @@ class LogbookContainer extends React.Component {
*/
isAppProperlyConfigured() {
if (!UI.logbook) {
console.log(
'[ERROR] [CONFIG] logbook section is missing in File src/config/ui/config'
);
console.log('[ERROR] [CONFIG] logbook section is missing from UI config');
return false;
}
if (!UI.logbook.SORT_EVENTS_BY) {
......
import escapeStringRegexp from 'escape-string-regexp';
import UI from '../../config/ui/config';
import UI from '../../config/ui';
import { DOC_VIEW } from '../../constants/eventTypes';
import moment from 'moment';
......
......@@ -4,7 +4,7 @@ import maintenanceImage from '../images/maintenance.jpg';
import maintenanceImage2 from '../images/maintenance2.jpg';
import maintenanceImage3 from '../images/maintenance3.jpg';
import maintenanceImage4 from '../images/maintenance4.jpg';
import UI from '../config/ui/config';
import UI from '../config/ui';
import Menu from '../components/Menu/Menu';
import Footer from '../components/Footer';
......
......@@ -12,8 +12,8 @@ import { Col, Grid, Label, Row } from 'react-bootstrap';
import { connect } from 'react-redux';
import { setBreadCrumbs } from '../actions/breadcrumbs';
import { getFileByEventId } from '../api/icat/icatPlus';
import ICATPLUS from '../config/icat/icatPlus';
import TECHNIQUES from '../config/techniques/techniques';
import ICATPLUS from '../config/icatPlus';
import TECHNIQUES from '../config/techniques';
import { stringifyBytesSize } from '../helpers';
import { INVESTIGATION_DATE_FORMAT } from '../constants';
......
......@@ -2,7 +2,7 @@ import moment from 'moment';
import { store } from '../store';
import { doLogOut, doSignIn } from '../actions/login';
import keycloak from '../keycloak';
import ICAT from '../config/icat/icat';
import ICAT from '../config/icat';
export function getRemainingSessionTime(expirationTime) {
return moment(expirationTime).diff(moment());
......
......@@ -4,8 +4,9 @@ import {
ITEM_TYPES,
ITEM_TYPE_DEFS,
} from '../constants';
import ALIAS from '../config/parameters/alias';
import uiConfig from '../config/ui/config';
import uiConfig from '../config/ui';
import PARAMETERS from '../config/parameters';
export function filterInvestigations(investigations, predicate) {
return {
......@@ -32,7 +33,7 @@ export function getDatasetParameterByPrefixName(dataset, prefix) {
const parameters = JSON.parse(JSON.stringify(dataset.parameters));
return parameters
.filter((p) => p.name.startsWith(prefix))
.map((p) => ({ ...p, name: ALIAS[p.name] || p.name }));
.map((p) => ({ ...p, name: PARAMETERS[p.name] || p.name }));
}
export function getDatasetParameterValueByName(dataset, name) {
......
import Keycloak from 'keycloak-js';
import ICAT from './config/icat/icat';
import ICAT from './config/icat';
const keycloak = ICAT.authentication.sso.enabled
? new Keycloak(ICAT.authentication.sso.configuration)
......
import { Resource } from 'rest-hooks';
import ICATPLUS from '../config/icat/icatPlus';
import ICATPLUS from '../config/icatPlus';
import { store } from '../store';
export default class AddressResource extends Resource {
......
import { Resource } from 'rest-hooks';
import ICATPLUS from '../config/icat/icatPlus';
import ICATPLUS from '../config/icatPlus';
import { store } from '../store';
export default class ItemResource extends Resource {
......
import { Resource } from 'rest-hooks';
import ICATPLUS from '../config/icat/icatPlus';
import ICATPLUS from '../config/icatPlus';
import { store } from '../store';
import AddressResource from './address';
......
import { Resource } from 'rest-hooks';
import ICATPLUS from '../config/icat/icatPlus';
import ICATPLUS from '../config/icatPlus';
import { store } from '../store';
export default class SampleResource extends Resource {
......