Skip to content

Commit

Permalink
enh: incorporate disabling auth into ui
Browse files Browse the repository at this point in the history
  • Loading branch information
anibalsolon committed Jan 18, 2024
1 parent 8415ab0 commit 480fd45
Show file tree
Hide file tree
Showing 10 changed files with 1,287 additions and 129 deletions.
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ services:
- ./ui/src:/ui/src #don't copy node_modules which might be compiled for mac (vite won't work)
environment:
VITE_APIHOST: http://localhost:8082
VITE_BRAINLIFE_AUTHENTICATION: ${BRAINLIFE_AUTHENTICATION}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
ports:
Expand Down
1,131 changes: 1,131 additions & 0 deletions ui/package-lock.json

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions ui/src/BaseConvertPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
</a>
</el-tooltip>
</div>
<ManageUsersDialog></ManageUsersDialog>

<ManageUsersDialog v-if="hasAuth"></ManageUsersDialog>

<div style="width: 135px; padding: 0 10px">
<el-button style="color: black; width: 100%; font-family: inherit" @click="handleSignout"
Expand Down Expand Up @@ -109,15 +110,14 @@ import Finalize from './Finalize.vue';
import Feedback from './Feedback.vue';
import ManageUsersDialog from './components/dialogs/ManageUsersDialog.vue';
import { IObject } from './store';
import { hasAuth, createEventsTSV } from './lib';
//https://github.com/element-plus/element-plus/issues/436#issuecomment-961386582
import { ElNotification } from 'element-plus';
import 'element-plus/es/components/notification/style/css';
import { setSectionIDs, funcQA, fmapQA, dwiQA, setRun, setVolumeThreshold } from './libUnsafe';
import { createEventsTSV } from './lib';
import niivue from './components/niivue.vue';
export default defineComponent({
Expand Down Expand Up @@ -163,6 +163,10 @@ export default defineComponent({
...mapState(['session', 'ezbids', 'events', 'page', 'config']),
...mapGetters(['getBIDSEntities', 'getBIDSMetadata', 'findSession', 'findSubject']),
hasAuth() {
return hasAuth();
},
backLabel(): string | null {
switch (this.page) {
case 'upload':
Expand Down
6 changes: 5 additions & 1 deletion ui/src/Finalize.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
>
<p>Or send the dataset to other cloud resources.</p>
<p>
<el-dropdown>
<el-dropdown v-if="hasAuth">
<el-button style="margin-right: 10px">
Send to <b>Brainlife.io</b>&nbsp;
<font-awesome-icon :icon="['fas', 'angle-down']" />
Expand Down Expand Up @@ -127,6 +127,7 @@ import showfile from './components/showfile.vue';
import axios from './axios.instance';
import { ElNotification } from 'element-plus';
import { hasAuth } from './lib';
export default defineComponent({
components: {
Expand All @@ -142,6 +143,9 @@ export default defineComponent({
computed: {
...mapState(['ezbids', 'config', 'bidsSchema', 'session', 'events']),
hasAuth() {
return hasAuth();
},
},
mounted() {
Expand Down
9 changes: 6 additions & 3 deletions ui/src/LandingPageHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
type="text"
style="font-size: var(--el-font-size-extra-large); font-family: unset; color: #3482e9"
@click="redirectToBrainlifeAuth"
>{{ hasJWT ? 'GET STARTED' : 'LOG IN / REGISTER' }}</el-button
>{{ !hasAuth || hasJWT ? 'GET STARTED' : 'LOG IN / REGISTER' }}</el-button
>
</el-menu-item>
</el-menu>
Expand All @@ -32,11 +32,14 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { mapState } from 'vuex';
import { hasJWT } from './lib';
import { hasJWT, hasAuth } from './lib';
export default defineComponent({
computed: {
...mapState(['config']),
hasAuth() {
return hasAuth();
},
hasJWT() {
return hasJWT();
},
Expand All @@ -46,7 +49,7 @@ export default defineComponent({
window.open('https://brainlife.io/team/', '_blank');
},
redirectToBrainlifeAuth() {
if (hasJWT()) {
if (!hasAuth() || hasJWT()) {
this.$router.push('/convert');
return;
}
Expand Down
2 changes: 2 additions & 0 deletions ui/src/axios.instance.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import axios from 'axios';
import { ElNotification } from 'element-plus';
import router from './routes';
import { hasAuth } from './lib';

const axiosInstance = axios.create({
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
});

axiosInstance.interceptors.request.use((config) => {
if (!hasAuth()) return config;
const token = localStorage.getItem('jwt');
if (token) {
config.headers = {
Expand Down
35 changes: 21 additions & 14 deletions ui/src/components/dialogs/ManageUsersDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
:value="allowedUserProfiles.length === 0 ? undefined : allowedUserProfiles.length"
style="width: 135px"
>
<el-button class="share-session-button" type="primary" @click="dialogIsVisible = true">
Share session
</el-button>
<el-button class="share-session-button" type="primary" @click="handleOpen"> Share session </el-button>
</el-badge>
</div>
<el-dialog
Expand Down Expand Up @@ -118,18 +116,27 @@ export default defineComponent({
return decoded.sub === this.session.ownerId;
},
},
mounted() {
// TODO this should not be cached, we should only show the user once the full email has been typed (for privacy)
axios
.get<{ count: number; profiles: Profile[] }>(`${this.config.authhost}/profile/list?limit=6000`)
.then((res) => {
this.profiles = res?.data?.profiles ? [...res.data.profiles] : [];
})
.catch((e) => {
console.error(e);
});
},
methods: {
handleOpen() {
this.dialogIsVisible = true;
if (this.profiles.length > 0) return;
this.isLoading = true;
// TODO this should not be cached, we should only show the user once the full email has been typed (for privacy)
axios
.get<{ count: number; profiles: Profile[] }>(`${this.config.authhost}/profile/list?limit=6000`)
.then((res) => {
this.profiles = res?.data?.profiles ? [...res.data.profiles] : [];
})
.catch((e) => {
console.error(e);
})
.finally(() => {
this.isLoading = false;
});
},
handleClose() {
this.dialogIsVisible = false;
},
Expand Down
177 changes: 97 additions & 80 deletions ui/src/lib.ts
Original file line number Diff line number Diff line change
@@ -1,113 +1,130 @@
import { IEzbids, IEvents, IBIDSEvent } from './store'
import { IEzbids, IEvents, IBIDSEvent } from './store';
import axios from './axios.instance';
//import { parseEvents } from './libUnsafe'

export function createEventsTSV(ezbids: IEzbids, events: IEvents) {
ezbids.objects.forEach(object => {
object.items.filter(i => !!i.events).forEach(item => {
function fixUnit(v: any, unit: any) {
switch (unit) {
case "ms": return v / 1000;
case "us": return v / 1000000;
default:
return Number(v);
}
}

item.eventsBIDS = [];

//emit all values
item.events.forEach((event: any) => {

//compute onset
let onset = null;
switch (events.columns.onsetLogic) {
case "add":
// @ts-ignore
onset = parseFloat(event[events.columns.onset]) + parseFloat(event[events.columns.onset2]);
break;
case "subtract":
// @ts-ignore
onset = parseFloat(event[events.columns.onset]) - parseFloat(event[events.columns.onset2]);
break;
default:
// @ts-ignore
onset = parseFloat(event[events.columns.onset]);
}
onset = fixUnit(onset, events.columns.onsetUnit);

//compute duration
let duration = null;
switch (events.columns.durationLogic) {
case "add":
// @ts-ignore
duration = parseFloat(event[events.columns.duration]) + parseFloat(event[events.columns.duration2]);
break;
case "subtract":
// @ts-ignore
duration = parseFloat(event[events.columns.duration]) - parseFloat(event[events.columns.duration2]);
break;
default:
// @ts-ignore
duration = parseFloat(event[events.columns.duration]);
ezbids.objects.forEach((object) => {
object.items
.filter((i) => !!i.events)
.forEach((item) => {
function fixUnit(v: any, unit: any) {
switch (unit) {
case 'ms':
return v / 1000;
case 'us':
return v / 1000000;
default:
return Number(v);
}
}
duration = fixUnit(duration, events.columns.durationUnit);

const rec: IBIDSEvent = {
onset,
duration,
};
item.eventsBIDS = [];

//rest is optional
if (events.columns.sample) {
switch (events.columns.sampleLogic) {
case "add":
//emit all values
item.events.forEach((event: any) => {
//compute onset
let onset = null;
switch (events.columns.onsetLogic) {
case 'add':
// @ts-ignore
rec.sample = parseFloat(event[events.columns.sample]) + parseFloat(event[events.columns.sample2]);
onset = parseFloat(event[events.columns.onset]) + parseFloat(event[events.columns.onset2]);
break;
case "subtract":
case 'subtract':
// @ts-ignore
rec.sample = parseFloat(event[events.columns.sample]) - parseFloat(event[events.columns.sample2]);
onset = parseFloat(event[events.columns.onset]) - parseFloat(event[events.columns.onset2]);
break;
default:
rec.sample = parseFloat(event[events.columns.sample]);
// @ts-ignore
onset = parseFloat(event[events.columns.onset]);
}
}
if (events.columns.responseTime) {
let responseTime = null;
switch (events.columns.responseTimeLogic) {
case "add":
onset = fixUnit(onset, events.columns.onsetUnit);

//compute duration
let duration = null;
switch (events.columns.durationLogic) {
case 'add':
// @ts-ignore
responseTime = parseFloat(event[events.columns.responseTime]) + parseFloat(event[events.columns.responseTime2]);
duration =
parseFloat(event[events.columns.duration]) +
parseFloat(event[events.columns.duration2]);
break;
case "subtract":
case 'subtract':
// @ts-ignore
responseTime = parseFloat(event[events.columns.responseTime]) - parseFloat(event[events.columns.responseTime2]);
duration =
parseFloat(event[events.columns.duration]) -
parseFloat(event[events.columns.duration2]);
break;
default:
// @ts-ignore
responseTime = parseFloat(event[events.columns.responseTime]);
duration = parseFloat(event[events.columns.duration]);
}
rec.response_time = fixUnit(responseTime, events.columns.responseTimeUnit);
}
duration = fixUnit(duration, events.columns.durationUnit);

const rec: IBIDSEvent = {
onset,
duration,
};

if (events.columns.trialType) rec.trial_type = event[events.columns.trialType];
if (events.columns.value) rec.value = event[events.columns.value];
if (events.columns.HED) rec.HED = event[events.columns.HED];
if (events.columns.stim_file) rec.stim_file = event[events.columns.stim_file];
//rest is optional
if (events.columns.sample) {
switch (events.columns.sampleLogic) {
case 'add':
// @ts-ignore
rec.sample =
parseFloat(event[events.columns.sample]) +
parseFloat(event[events.columns.sample2]);
break;
case 'subtract':
// @ts-ignore
rec.sample =
parseFloat(event[events.columns.sample]) -
parseFloat(event[events.columns.sample2]);
break;
default:
rec.sample = parseFloat(event[events.columns.sample]);
}
}
if (events.columns.responseTime) {
let responseTime = null;
switch (events.columns.responseTimeLogic) {
case 'add':
// @ts-ignore
responseTime =
parseFloat(event[events.columns.responseTime]) +
parseFloat(event[events.columns.responseTime2]);
break;
case 'subtract':
// @ts-ignore
responseTime =
parseFloat(event[events.columns.responseTime]) -
parseFloat(event[events.columns.responseTime2]);
break;
default:
// @ts-ignore
responseTime = parseFloat(event[events.columns.responseTime]);
}
rec.response_time = fixUnit(responseTime, events.columns.responseTimeUnit);
}

(item.eventsBIDS as IBIDSEvent[]).push(rec);
if (events.columns.trialType) rec.trial_type = event[events.columns.trialType];
if (events.columns.value) rec.value = event[events.columns.value];
if (events.columns.HED) rec.HED = event[events.columns.HED];
if (events.columns.stim_file) rec.stim_file = event[events.columns.stim_file];

(item.eventsBIDS as IBIDSEvent[]).push(rec);
});
});
});
});
}

export function hasAuth() {
return import.meta.env.VITE_BRAINLIFE_AUTHENTICATION === 'true';
}

export function hasJWT() {
return !!retrieveJWT();
}

export function retrieveJWT() {
return localStorage.getItem('jwt')
}
return localStorage.getItem('jwt');
}
Loading

0 comments on commit 480fd45

Please sign in to comment.