diff --git a/ui/src/actions/beamline.js b/ui/src/actions/beamline.js index bb96c0304..388cfdd19 100644 --- a/ui/src/actions/beamline.js +++ b/ui/src/actions/beamline.js @@ -4,12 +4,6 @@ import { sendPrepareBeamlineForNewSample, } from '../api/beamline'; import { sendLogFrontEndTraceBack } from '../api/log'; -// The different states a beamline attribute can assume. -export const STATE = { - IDLE: 'READY', - BUSY: 'BUSY', - ABORT: 'UNUSABLE', -}; // Action types export const BL_UPDATE_HARDWARE_OBJECT = 'BL_UPDATE_HARDWARE_OBJECT'; diff --git a/ui/src/actions/login.js b/ui/src/actions/login.js index 826baa56b..4501e5581 100644 --- a/ui/src/actions/login.js +++ b/ui/src/actions/login.js @@ -7,12 +7,8 @@ import { fetchAvailableWorkflows } from '../api/workflow'; import { fetchAvailableTasks, fetchQueueState } from '../api/queue'; import { showErrorPanel, applicationFetched } from './general'; -import { - fetchLoginInfo, - sendLogIn, - sendSignOut, - sendSSOLogIn, -} from '../api/login'; +import { sendSignOut } from '../api/login'; +import { fetchLoginInfo, sendLogIn, sendSSOLogIn } from '../api/loginBase'; import { fetchDetectorInfo } from '../api/detector'; import { fetchSampleChangerInitialState } from '../api/sampleChanger'; import { fetchHarvesterInitialState } from '../api/harvester'; @@ -27,21 +23,6 @@ export function setLoginInfo(loginInfo) { }; } -export function resetLoginInfo() { - return setLoginInfo({ - beamlineName: '', - synchrotronName: '', - loginType: '', - user: '', - proposalList: [], - selectedProposal: '', - selectedProposalID: '', - loggedIn: false, - rootPath: '', - useSSO: false, - }); -} - export function showProposalsForm() { return { type: 'SHOW_PROPOSALS_FORM', @@ -99,7 +80,7 @@ export function ssoLogIn() { export function signOut() { return async (dispatch) => { - dispatch(resetLoginInfo()); // disconnect sockets before actually logging out (cf. `App.jsx`) + dispatch(setLoginInfo({ loggedIn: false })); // disconnect sockets before actually logging out (cf. `App.jsx`) dispatch(applicationFetched(false)); try { diff --git a/ui/src/api/api.js b/ui/src/api/api.js new file mode 100644 index 000000000..c94d52dc9 --- /dev/null +++ b/ui/src/api/api.js @@ -0,0 +1,15 @@ +/* eslint-disable promise/prefer-await-to-callbacks */ +import baseApi from './apiBase'; +import { fetchLoginInfo } from './loginBase'; +import { store } from '../store'; + +const api = baseApi + .options({ credendials: 'include' }) + .catcher(401, async (error) => { + // Replicate `getLoginInfo` action (to avoid import cycle) + const loginInfo = await fetchLoginInfo(); + store.dispatch({ type: 'SET_LOGIN_INFO', loginInfo }); + throw error; + }); + +export default api; diff --git a/ui/src/api/index.js b/ui/src/api/apiBase.js similarity index 60% rename from ui/src/api/index.js rename to ui/src/api/apiBase.js index 83fb03938..5f80ef2f8 100644 --- a/ui/src/api/index.js +++ b/ui/src/api/apiBase.js @@ -1,9 +1,8 @@ import wretch from 'wretch'; import safeJsonAddon from './addons/safeJson'; -const api = wretch('/mxcube/api/v0.1') +const baseApi = wretch('/mxcube/api/v0.1') .addon(safeJsonAddon()) - .options({ credendials: 'include' }) .headers({ Accept: 'application/json' }); -export default api; +export default baseApi; diff --git a/ui/src/api/beamline.js b/ui/src/api/beamline.js index 0475af15d..a2dbfd682 100644 --- a/ui/src/api/beamline.js +++ b/ui/src/api/beamline.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/beamline'); diff --git a/ui/src/api/detector.js b/ui/src/api/detector.js index 7b3ea8d2b..f8a34fb0c 100644 --- a/ui/src/api/detector.js +++ b/ui/src/api/detector.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/detector'); diff --git a/ui/src/api/diffractometer.js b/ui/src/api/diffractometer.js index edd0fd5ae..007a40a61 100644 --- a/ui/src/api/diffractometer.js +++ b/ui/src/api/diffractometer.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/diffractometer'); diff --git a/ui/src/api/harvester.js b/ui/src/api/harvester.js index 4aea7ccef..439973083 100644 --- a/ui/src/api/harvester.js +++ b/ui/src/api/harvester.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/harvester'); diff --git a/ui/src/api/lims.js b/ui/src/api/lims.js index 2cb6beba6..c1546d370 100644 --- a/ui/src/api/lims.js +++ b/ui/src/api/lims.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/lims'); diff --git a/ui/src/api/log.js b/ui/src/api/log.js index 62e1b8def..0b8f0e20f 100644 --- a/ui/src/api/log.js +++ b/ui/src/api/log.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/log'); diff --git a/ui/src/api/login.js b/ui/src/api/login.js index 47a08668c..d128d225d 100644 --- a/ui/src/api/login.js +++ b/ui/src/api/login.js @@ -1,23 +1,11 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/login'); -export function sendLogIn(proposal, password, previousUser) { - return endpoint.post({ proposal, password, previousUser }, '/').safeJson(); -} - -export function sendSSOLogIn() { - window.location = 'mxcube/api/v0.1/login/ssologin'; -} - export function sendSignOut() { return endpoint.headers({ Accept: '*/*' }).get('/signout').res(); } -export function fetchLoginInfo() { - return endpoint.get('/login_info').safeJson(); -} - export function sendFeedback(sender, content) { return endpoint.post({ sender, content }, '/send_feedback').res(); } diff --git a/ui/src/api/loginBase.js b/ui/src/api/loginBase.js new file mode 100644 index 000000000..3e2aa2e18 --- /dev/null +++ b/ui/src/api/loginBase.js @@ -0,0 +1,19 @@ +/** + * Unauthenticated `/login/*` endpoints. + * Separate from authenticated endpoints to avoid import cycle with `api.js`. + */ +import baseApi from './apiBase'; + +const endpoint = baseApi.url('/login'); + +export function sendLogIn(proposal, password, previousUser) { + return endpoint.post({ proposal, password, previousUser }, '/').safeJson(); +} + +export function sendSSOLogIn() { + window.location = 'mxcube/api/v0.1/login/ssologin'; +} + +export function fetchLoginInfo() { + return endpoint.get('/login_info').safeJson(); +} diff --git a/ui/src/api/main.js b/ui/src/api/main.js index 1a3daeb98..fa1a772ae 100644 --- a/ui/src/api/main.js +++ b/ui/src/api/main.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; export function fetchUIProperties() { return api.get('/uiproperties').safeJson(); diff --git a/ui/src/api/queue.js b/ui/src/api/queue.js index bc011ff90..e7644bfc3 100644 --- a/ui/src/api/queue.js +++ b/ui/src/api/queue.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/queue'); diff --git a/ui/src/api/remoteAccess.js b/ui/src/api/remoteAccess.js index 881ca1293..49ef76ee6 100644 --- a/ui/src/api/remoteAccess.js +++ b/ui/src/api/remoteAccess.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/ra'); diff --git a/ui/src/api/sampleChanger.js b/ui/src/api/sampleChanger.js index f1624f65a..d8c5ca7e1 100644 --- a/ui/src/api/sampleChanger.js +++ b/ui/src/api/sampleChanger.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/sample_changer'); diff --git a/ui/src/api/sampleview.js b/ui/src/api/sampleview.js index 804629465..89484886c 100644 --- a/ui/src/api/sampleview.js +++ b/ui/src/api/sampleview.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/sampleview'); diff --git a/ui/src/api/workflow.js b/ui/src/api/workflow.js index 0aadeb03d..9190c34aa 100644 --- a/ui/src/api/workflow.js +++ b/ui/src/api/workflow.js @@ -1,4 +1,4 @@ -import api from '.'; +import api from './api'; const endpoint = api.url('/workflow'); diff --git a/ui/src/reducers/beamline.js b/ui/src/reducers/beamline.js index 3d7ce02db..e9e25547e 100644 --- a/ui/src/reducers/beamline.js +++ b/ui/src/reducers/beamline.js @@ -1,7 +1,13 @@ /* eslint-disable sonarjs/no-duplicate-string */ -import { STATE } from '../actions/beamline'; import { RUNNING, HW_STATE } from '../constants'; +// The different states a beamline attribute can assume. +export const STATE = { + IDLE: 'READY', + BUSY: 'BUSY', + ABORT: 'UNUSABLE', +}; + /** * Initial redux state for beamline hardwareObjects, object containing each beamline * attribute (name, attribute object). Each attribute object in turn have the