Skip to content

Commit

Permalink
Merge pull request #228 from VariantEffect/release-2024.2.1
Browse files Browse the repository at this point in the history
Release 2024.2.1
  • Loading branch information
ashsny authored Jun 29, 2024
2 parents 4f49d1f + aaa170b commit da77b7a
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 21 deletions.
14 changes: 14 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,23 @@
import ConfirmDialog from 'primevue/confirmdialog'
import Toast from 'primevue/toast'
import 'primeflex/primeflex.css'
import {mapActions, mapState} from 'vuex'
export default {
components: {ConfirmDialog, Toast},
computed: mapState('toast', ['toasts']),
watch: {
toasts: {
deep: true,
handler: function(newValue) {
if (newValue.length > 0) {
this.$toast.add(newValue[0])
this.removeDequeuedToasts(1)
}
}
}
},
methods: mapActions('toast', ['removeDequeuedToasts'])
}
</script>
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/HighlightsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
<!-- Link publication identifiers to their MaveDB page -->
<template v-if="this.field == 'publication-identifiers' && col.field == 'identifier'" #body="slotProps">
<a
:href="`${config.appBaseUrl}/#/publication-identifiers/${slotProps.data.dbName}/${slotProps.data[col.field]}`">{{
:href="`${config.appBaseUrl}/publication-identifiers/${slotProps.data.dbName}/${encodeURIComponent(slotProps.data[col.field])}`">{{
slotProps.data[col.field] }}</a>
</template>
<!-- Link keywords and Doi Identifiers to an internal MaveDB search page -->
Expand Down Expand Up @@ -135,7 +135,7 @@
<!-- Link publication identifiers to their MaveDB page -->
<template v-if="this.field == 'publication-identifiers' && col.field == 'identifier'" #body="slotProps">
<a
:href="`${config.appBaseUrl}/#/publication-identifiers/${slotProps.data.dbName}/${slotProps.data[col.field]}`">{{
:href="`${config.appBaseUrl}/publication-identifiers/${slotProps.data.dbName}/${encodeURIComponent(slotProps.data[col.field])}`">{{
slotProps.data[col.field] }}</a>
</template>
<!-- Link keywords to an internal MaveDB search page -->
Expand Down
4 changes: 2 additions & 2 deletions src/components/screens/ExperimentView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<li v-html="markdownToHtml(publication.referenceHtml)"></li>
<div>
Publication: <a
:href="`${config.appBaseUrl}/#/publication-identifiers/${publication.dbName}/${publication.identifier}`">{{
:href="`${config.appBaseUrl}/publication-identifiers/${publication.dbName}/${encodeURIComponent(publication.identifier)}`">{{
publication.identifier }}</a>
</div>
<div>
Expand All @@ -74,7 +74,7 @@
<li v-html="markdownToHtml(publication.referenceHtml)"></li>
<div>
Publication: <a
:href="`${config.appBaseUrl}/#/publication-identifiers/${publication.dbName}/${publication.identifier}`">{{
:href="`${config.appBaseUrl}/publication-identifiers/${publication.dbName}/${encodeURIComponent(publication.identifier)}`">{{
publication.identifier }}</a>
</div>
<div>
Expand Down
7 changes: 5 additions & 2 deletions src/components/screens/ScoreSetView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
<li v-html="markdownToHtml(publication.referenceHtml)"></li>
<div>
Publication: <a
:href="`${config.appBaseUrl}/#/publication-identifiers/${publication.dbName}/${publication.identifier}`">{{
:href="`${config.appBaseUrl}/publication-identifiers/${publication.dbName}/${encodeURIComponent(publication.identifier)}`">{{
publication.identifier }}</a>
</div>
<div>
Expand All @@ -159,7 +159,7 @@
<li v-html="markdownToHtml(publication.referenceHtml)"></li>
<div>
Publication: <a
:href="`${config.appBaseUrl}/#/publication-identifiers/${publication.dbName}/${publication.identifier}`">{{
:href="`${config.appBaseUrl}/publication-identifiers/${publication.dbName}/${encodeURIComponent(publication.identifier)}`">{{
publication.identifier }}</a>
</div>
<div>
Expand Down Expand Up @@ -505,6 +505,9 @@ export default {
.urn}&outputType=${params
.outputType}&URL=${encodeURIComponent(params.URL)}`;
window.location.href = submitGalaxyUrl;
localStorage.removeItem('galaxyUrl');
localStorage.removeItem('toolId');
localStorage.removeItem('requestFromGalaxy');
}
} catch (error) {
console.error('Error sending data:', error);
Expand Down
63 changes: 54 additions & 9 deletions src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

import axios from 'axios'

import {idToken as orcidIdToken} from '@/lib/orcid'
import config from '@/config'
import {
idToken as orcidIdToken,
isAuthenticated as orcidIsAuthenticated,
signOut as orcidSignOut
} from '@/lib/orcid'
import store from '@/store/index'
import authStore from '@/store/modules/auth'

export interface AuthorizationHeader {
Expand Down Expand Up @@ -35,20 +41,59 @@ export function authHeader(): AuthorizationHeader {
}

/**
* Add a bearer authorization token to all requests made using Axios.
* Determine whether a URL refers to a MaveDB API endpoint.
*/
function urlBelongsToApi(url: string) {
return (url.startsWith(config.apiBaseUrl))
}

/**
* Add a bearer authorization token to all requests to the MaveDB API made using Axios.
*
* If you wish to supply MaveDB credentials with all Axios requests, call this function at application startup time (or
* page load time, in a single-page application).
* Call this function at application startup time (or page load time, in a single-page application) to supply MaveDB
* credentials with all Axios requests to MaveDB API endpoints.
*/
export function installAxiosAuthHeaderInterceptor() {
axios.interceptors.request.use((config) => {
const token = orcidIdToken.value
const activeRoles = authStore.state.activeRoles
// If the request URL belongs to the MaveDB API, add authorization headers.
if (config.url && urlBelongsToApi(config.url)) {
const token = orcidIdToken.value
const activeRoles = authStore.state.activeRoles

if (token) {
config.headers.Authorization = `Bearer ${token}`
config.headers['X-Active-Roles'] = activeRoles
if (token) {
config.headers.Authorization = `Bearer ${token}`
config.headers['X-Active-Roles'] = activeRoles
}
}

return config
})
}

export function installAxiosUnauthorizedResponseInterceptor() {
axios.interceptors.response.use(
(response) => response,
async (error) => {
if (error && !error.config?.isSessionCheck && error.response?.status && error.response?.status == 401) {
try {
// @ts-ignore: We need to pass a custom property in the request configuration.
await axios.get(`${config.apiBaseUrl}/users/me`, {isSessionCheck: true})
} catch (error: any) {
if (error.response?.status == 401) {
// The user's session has expired. This may happen after several requests issued around the same time, so
// only take action if the user has not yet been signed out.
if (orcidIsAuthenticated.value) {
orcidSignOut()
store.dispatch('toast/enqueueToast', {
severity: 'info',
summary: 'Your ORCID session has ended. Please log in again.',
life: 5000
})
}
}
}
}
return Promise.reject(error)
}
)
}
17 changes: 14 additions & 3 deletions src/lib/item-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const itemTypes = {
httpOptions: {
list: {
method: 'get',
url: `${config.apiBaseUrl}/publication-identifiers/pubmed`
url: `${config.apiBaseUrl}/publication-identifiers/PubMed`
}
}
},
Expand All @@ -52,7 +52,7 @@ const itemTypes = {
httpOptions: {
list: {
method: 'get',
url: `${config.apiBaseUrl}/publication-identifiers/biorxiv`
url: `${config.apiBaseUrl}/publication-identifiers/bioRxiv`
}
}
},
Expand All @@ -63,7 +63,18 @@ const itemTypes = {
httpOptions: {
list: {
method: 'get',
url: `${config.apiBaseUrl}/publication-identifiers/medrxiv`
url: `${config.apiBaseUrl}/publication-identifiers/medRxiv`
}
}
},
'crossrefPublicationIdentifier': {
name: 'crossrefPublicationIdentifier', // TODO Redundant, change this structure
restCollectionName: 'publication-identifiers',
primaryKey: 'identifier',
httpOptions: {
list: {
method: 'get',
url: `${config.apiBaseUrl}/publication-identifiers/Crossref`
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Tooltip from 'primevue/tooltip';
import {createApp} from 'vue'

import App from '@/App.vue'
import {installAxiosAuthHeaderInterceptor} from '@/lib/auth'
import {installAxiosAuthHeaderInterceptor, installAxiosUnauthorizedResponseInterceptor} from '@/lib/auth'
import {initializeAuthentication as initializeOrcidAuthentication} from '@/lib/orcid'
import router from '@/router'
import store from '@/store'
Expand Down Expand Up @@ -46,3 +46,4 @@ createApp(App)

// Monkey-patch Axios so that all requests will have the user's credentials.
installAxiosAuthHeaderInterceptor()
installAxiosUnauthorizedResponseInterceptor()
5 changes: 5 additions & 0 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ const routes = [{
path: '/publication-identifiers/medrxiv/:identifier',
component: PublicationIdentifierView,
props: (route) => ({itemId: route.params.identifier, name: route.name, dbId: 'medRxiv'})
}, {
name: 'crossrefPublicationIdentifier',
path: '/publication-identifiers/crossref/:identifier',
component: PublicationIdentifierView,
props: (route) => ({itemId: route.params.identifier, name: route.name, dbId: 'Crossref'})
}, {
path: '/oidc-callback',
name: 'oidcCallback',
Expand Down
13 changes: 11 additions & 2 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,33 @@ import {createStore} from 'vuex'

import authModule from '@/store/modules/auth'
import layoutModule from '@/store/modules/layout'
import toastModule from '@/store/modules/toast'

// Unfortunately, typed Vuex stores are painful to use, especially with multiple modules. We'll continue using any for
// now. Now that we do not use a Vuex module for authentication, we can migrate to Pinia.

const store = createStore({
state: {
routeProps: {},
routeProps: {
galaxyUrl: localStorage.getItem('galaxyUrl'),
toolId: localStorage.getItem('toolId'),
requestFromGalaxy: localStorage.getItem('requestFromGalaxy'),
},
},
mutations: {
setRouteProps(state: any, props: any) {
state.routeProps = props;
localStorage.setItem('galaxyUrl', props.galaxyUrl);
localStorage.setItem('toolId', props.toolId);
localStorage.setItem('requestFromGalaxy', props.requestFromGalaxy);
},
},
actions: {
},
modules: {
auth: authModule,
layout: layoutModule
layout: layoutModule,
toast: toastModule
}
})

Expand Down
28 changes: 28 additions & 0 deletions src/store/modules/toast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const module = {
namespaced: true,

state: {
toasts: []
},

mutations: {
enqueueToast(state, toast) {
state.toasts.push(toast)
console.log(state.toasts)
},
removeDequeuedToasts(state, numToasts) {
state.toasts.splice(0, Math.min(numToasts, state.toasts.length))
}
},

actions: {
enqueueToast({commit}, toast) {
commit('enqueueToast', toast)
},
removeDequeuedToasts({commit}, numToasts) {
commit('removeDequeuedToasts', numToasts)
}
}
}

export default module

0 comments on commit da77b7a

Please # to comment.