Skip to content

Commit d5be52e

Browse files
authored
Scan Navigation (#613)
* Route views by scan, not frame * Add ProjectComplete page to act as transition between projects
1 parent a7faa51 commit d5be52e

6 files changed

Lines changed: 153 additions & 64 deletions

File tree

web_client/src/components/ControlPanel.vue

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export default {
9292
...mapMutations([
9393
'setShowCrosshairs',
9494
'setStoreCrosshairs',
95+
'setCurrentFrameId',
9596
]),
9697
openScanLink() {
9798
window.open(this.currentViewData.scanLink, '_blank');
@@ -125,25 +126,26 @@ export default {
125126
}
126127
}
127128
},
128-
navigateToFrame(frameId) {
129-
if (frameId && frameId !== this.$route.params.frameId) {
129+
navigateToScan(location) {
130+
if (!location) location = 'complete';
131+
if (location && location !== this.$route.params.scanId) {
130132
this.$router
131-
.push(`/${this.currentViewData.projectId}/${frameId}` || '')
133+
.push(`/${this.currentViewData.projectId}/${location}` || '')
132134
.catch(this.handleNavigationError);
133135
}
134136
},
135137
slideToFrame(framePosition) {
136-
this.navigateToFrame(this.currentViewData.scanFramesList[framePosition - 1]);
138+
this.setCurrentFrameId(this.currentViewData.scanFramesList[framePosition - 1]);
137139
},
138140
updateImage() {
139141
if (this.direction === 'back') {
140-
this.navigateToFrame(this.previousFrame);
142+
this.setCurrentFrameId(this.previousFrame);
141143
} else if (this.direction === 'forward') {
142-
this.navigateToFrame(this.nextFrame);
144+
this.setCurrentFrameId(this.nextFrame);
143145
} else if (this.direction === 'previous') {
144-
this.navigateToFrame(this.currentViewData.upTo);
146+
this.navigateToScan(this.currentViewData.upTo);
145147
} else if (this.direction === 'next') {
146-
this.navigateToFrame(this.currentViewData.downTo);
148+
this.navigateToScan(this.currentViewData.downTo);
147149
}
148150
},
149151
handleKeyPress(direction) {
@@ -355,7 +357,6 @@ export default {
355357
<v-icon>fa-caret-up</v-icon>
356358
</v-btn>
357359
<v-btn
358-
:disabled="!currentViewData.downTo"
359360
small
360361
depressed
361362
class="transparent-btn"

web_client/src/components/ExperimentsView.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ export default {
9696
}
9797
return str;
9898
},
99-
getURLForFirstFrameInScan(scanId) {
100-
return `/${this.currentProject.id}/${this.scanFrames[scanId][0]}`;
99+
getURLForScan(scanId) {
100+
return `/${this.currentProject.id}/${scanId}`;
101101
},
102102
decisionToRating(decisions) {
103103
if (decisions.length === 0) return {};
@@ -205,7 +205,7 @@ export default {
205205
>
206206
<span>All scans</span>
207207
<v-switch
208-
:input-value="true"
208+
:input-value="reviewMode"
209209
dense
210210
style="display: inline-block; max-height: 40px; max-width: 60px;"
211211
class="px-3 ma-0"
@@ -304,7 +304,7 @@ export default {
304304
<template #activator="{ on, attrs }">
305305
<v-btn
306306
v-bind="attrs"
307-
:to="getURLForFirstFrameInScan(scan.id)"
307+
:to="getURLForScan(scan.id)"
308308
:disabled="!includeScan(scan.id)"
309309
class="ml-0 px-1 scan-name"
310310
href

web_client/src/router.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Vue from 'vue';
22
import Router from 'vue-router';
33

44
import Projects from './views/Projects.vue';
5-
import Frame from './views/Frame.vue';
5+
import Scan from './views/Scan.vue';
66

77
Vue.use(Router);
88

@@ -15,9 +15,14 @@ export default new Router({
1515
},
1616
// Order matters
1717
{
18-
path: '/:projectId?/:frameId?',
19-
name: 'frame',
20-
component: Frame,
18+
path: '/:projectId?/complete',
19+
name: 'projectComplete',
20+
component: Projects,
21+
},
22+
{
23+
path: '/:projectId?/:scanId?',
24+
name: 'scan',
25+
component: Scan,
2126
},
2227
{
2328
path: '*',

web_client/src/store/index.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -387,10 +387,8 @@ const {
387387
scanFramesList,
388388
scanPosition: experimentScansList.indexOf(scan.id) + 1,
389389
framePosition: scanFramesList.indexOf(currentFrame.id) + 1,
390-
backTo: currentFrame.previousFrame,
391-
forwardTo: currentFrame.nextFrame,
392-
upTo: state.scanFrames[upTo] ? state.scanFrames[upTo][0] : undefined,
393-
downTo: state.scanFrames[downTo] ? state.scanFrames[downTo][0] : undefined,
390+
upTo,
391+
downTo,
394392
currentFrame,
395393
currentAutoEvaluation: currentFrame.frame_evaluation,
396394
};
@@ -731,16 +729,16 @@ const {
731729
},
732730
});
733731
},
734-
async getFrame({ state, dispatch }, { frameId, projectId }) {
735-
if (!frameId) {
732+
async getScan({ state, dispatch }, { scanId, projectId }) {
733+
if (!scanId) {
736734
return undefined;
737735
}
738-
if (!state.frames[frameId]) {
736+
if (!state.scans[scanId]) {
739737
await dispatch('loadProjects');
740738
const targetProject = state.projects.filter((proj) => proj.id === projectId)[0];
741739
await dispatch('loadProject', targetProject);
742740
}
743-
return state.frames[frameId];
741+
return state.scans[scanId];
744742
},
745743
async setCurrentFrame({ commit }, frameId) {
746744
commit('setCurrentFrameId', frameId);
@@ -751,9 +749,6 @@ const {
751749
if (!frame) {
752750
throw new Error("frame id doesn't exist");
753751
}
754-
if (getters.currentFrame === frame) {
755-
return;
756-
}
757752
commit('setLoadingFrame', true);
758753
commit('setErrorLoadingFrame', false);
759754
const oldScan = getters.currentScan;

web_client/src/views/Projects.vue

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,20 @@ export default defineComponent({
2626
},
2727
inject: ['user', 'MIQAConfig'],
2828
setup() {
29+
const { switchReviewMode } = store.commit;
2930
const loadingProjects = ref(true);
3031
store.dispatch.loadProjects().then(() => {
3132
loadingProjects.value = false;
3233
});
34+
const reviewMode = computed(() => store.state.reviewMode);
35+
const complete = window.location.hash.includes('complete');
3336
const currentProject = computed(() => store.state.currentProject);
3437
const currentTaskOverview = computed(() => store.state.currentTaskOverview);
3538
const projects = computed(() => store.state.projects);
3639
const isGlobal = computed(() => store.getters.isGlobal);
3740
const selectedProjectIndex = ref(projects.value.findIndex(
3841
(project) => project.id === currentProject.value?.id,
3942
));
40-
const selectProject = (project: Project) => {
41-
store.dispatch.loadProject(project);
42-
};
4343
const selectGlobal = () => {
4444
store.dispatch.loadGlobal();
4545
};
@@ -88,29 +88,51 @@ export default defineComponent({
8888
);
8989
}
9090
91+
async function getProjectFromURL() {
92+
if (complete) {
93+
const targetProjectIndex = projects.value.findIndex(
94+
(project) => project.id === window.location.hash.split('/')[1],
95+
);
96+
const targetProject = projects.value[targetProjectIndex];
97+
if (targetProject) store.commit.setCurrentProject(targetProject);
98+
selectedProjectIndex.value = targetProjectIndex;
99+
}
100+
}
101+
91102
const overviewPoll = setInterval(refreshTaskOverview, 10000);
92103
watch(currentTaskOverview, setOverviewSections);
93104
watch(currentProject, refreshTaskOverview);
105+
watch(projects, getProjectFromURL);
94106
95107
return {
108+
reviewMode,
109+
switchReviewMode,
110+
complete,
96111
currentProject,
97112
loadingProjects,
98113
currentTaskOverview,
99114
selectedProjectIndex,
100115
projects,
101116
isGlobal,
102117
overviewPoll,
103-
selectProject,
104118
selectGlobal,
105119
overviewSections,
106120
setOverviewSections,
107121
refreshAllTaskOverviews,
122+
getProjectFromURL,
108123
};
109124
},
110125
data: () => ({
111126
creating: false,
112127
newName: '',
113128
}),
129+
watch: {
130+
projects() {
131+
this.$nextTick(() => {
132+
if (this.$refs.proceed) this.$refs.proceed.$el.focus();
133+
});
134+
},
135+
},
114136
mounted() {
115137
this.setOverviewSections();
116138
window.addEventListener('keydown', (event) => {
@@ -130,6 +152,12 @@ export default defineComponent({
130152
},
131153
methods: {
132154
...mapMutations(['setProjects', 'setCurrentProject']),
155+
selectProject(project: Project) {
156+
if (this.complete) {
157+
this.complete = false;
158+
}
159+
store.dispatch.loadProject(project);
160+
},
133161
async createProject() {
134162
if (this.creating && this.newName.length > 0) {
135163
try {
@@ -150,6 +178,26 @@ export default defineComponent({
150178
}
151179
}
152180
},
181+
async proceedToNext() {
182+
const nextProject = this.projects[this.selectedProjectIndex + 1];
183+
store.dispatch.loadProject(nextProject);
184+
this.selectedProjectIndex += 1;
185+
await djangoRest.projectTaskOverview(nextProject.id).then(
186+
(taskOverview) => {
187+
let nextScanIndex = 0;
188+
let nextScan;
189+
let nextScanState;
190+
while (
191+
!nextScan || (nextScanState === 'complete' && this.reviewMode)
192+
) {
193+
nextScan = nextProject.experiments[0].scans[nextScanIndex];
194+
nextScanState = taskOverview.scan_states[nextScan.id];
195+
nextScanIndex += 1;
196+
}
197+
this.$router.push(`/${nextProject.id}/${nextScan.id}` || '');
198+
},
199+
);
200+
},
153201
},
154202
});
155203
</script>
@@ -240,7 +288,7 @@ export default defineComponent({
240288
</v-navigation-drawer>
241289
</v-card>
242290
<div
243-
v-if="currentProject !== undefined"
291+
v-if="currentProject !== undefined && !complete"
244292
class="flex-grow-1 ma-3 pa-5"
245293
>
246294
<v-card-title v-if="isGlobal">
@@ -304,7 +352,41 @@ export default defineComponent({
304352
fill-height
305353
>
306354
<div
307-
v-if="projects.length > 0"
355+
v-if="complete"
356+
class="title text-center"
357+
>
358+
Viewed all scans in Project {{ currentProject.name }}.
359+
<div
360+
v-if="selectedProjectIndex + 1 < projects.length"
361+
>
362+
Proceed to next Project, {{ projects[selectedProjectIndex+1].name }}?
363+
<br>
364+
<v-form @submit.prevent="proceedToNext">
365+
<v-btn
366+
ref="proceed"
367+
class="my-3"
368+
type="submit"
369+
>
370+
Proceed
371+
</v-btn>
372+
</v-form>
373+
</div>
374+
<v-subheader
375+
class="mode-toggle"
376+
>
377+
<span>All scans</span>
378+
<v-switch
379+
:input-value="reviewMode"
380+
dense
381+
style="display: inline-block; max-height: 40px; max-width: 60px;"
382+
class="px-3 ma-0"
383+
@change="switchReviewMode"
384+
/>
385+
<span>Scans for my review</span>
386+
</v-subheader>
387+
</div>
388+
<div
389+
v-else-if="projects.length > 0"
308390
class="title"
309391
>
310392
Select a project
@@ -348,4 +430,8 @@ export default defineComponent({
348430
width: 100%;
349431
text-align: center;
350432
}
433+
.mode-toggle {
434+
align-items: baseline;
435+
display: inline-block;
436+
}
351437
</style>

0 commit comments

Comments
 (0)