From d5be52ecc3159f1a596f6a3ace5abd7bb5780206 Mon Sep 17 00:00:00 2001 From: Anne Haley Date: Tue, 11 Oct 2022 13:13:34 -0400 Subject: [PATCH] Scan Navigation (#613) * Route views by scan, not frame * Add ProjectComplete page to act as transition between projects --- web_client/src/components/ControlPanel.vue | 19 ++-- web_client/src/components/ExperimentsView.vue | 8 +- web_client/src/router.ts | 13 ++- web_client/src/store/index.ts | 17 ++-- web_client/src/views/Projects.vue | 98 +++++++++++++++++-- web_client/src/views/{Frame.vue => Scan.vue} | 62 ++++++------ 6 files changed, 153 insertions(+), 64 deletions(-) rename web_client/src/views/{Frame.vue => Scan.vue} (87%) diff --git a/web_client/src/components/ControlPanel.vue b/web_client/src/components/ControlPanel.vue index 0a85cd40..53da6f38 100644 --- a/web_client/src/components/ControlPanel.vue +++ b/web_client/src/components/ControlPanel.vue @@ -92,6 +92,7 @@ export default { ...mapMutations([ 'setShowCrosshairs', 'setStoreCrosshairs', + 'setCurrentFrameId', ]), openScanLink() { window.open(this.currentViewData.scanLink, '_blank'); @@ -125,25 +126,26 @@ export default { } } }, - navigateToFrame(frameId) { - if (frameId && frameId !== this.$route.params.frameId) { + navigateToScan(location) { + if (!location) location = 'complete'; + if (location && location !== this.$route.params.scanId) { this.$router - .push(`/${this.currentViewData.projectId}/${frameId}` || '') + .push(`/${this.currentViewData.projectId}/${location}` || '') .catch(this.handleNavigationError); } }, slideToFrame(framePosition) { - this.navigateToFrame(this.currentViewData.scanFramesList[framePosition - 1]); + this.setCurrentFrameId(this.currentViewData.scanFramesList[framePosition - 1]); }, updateImage() { if (this.direction === 'back') { - this.navigateToFrame(this.previousFrame); + this.setCurrentFrameId(this.previousFrame); } else if (this.direction === 'forward') { - this.navigateToFrame(this.nextFrame); + this.setCurrentFrameId(this.nextFrame); } else if (this.direction === 'previous') { - this.navigateToFrame(this.currentViewData.upTo); + this.navigateToScan(this.currentViewData.upTo); } else if (this.direction === 'next') { - this.navigateToFrame(this.currentViewData.downTo); + this.navigateToScan(this.currentViewData.downTo); } }, handleKeyPress(direction) { @@ -355,7 +357,6 @@ export default { fa-caret-up All scans proj.id === projectId)[0]; await dispatch('loadProject', targetProject); } - return state.frames[frameId]; + return state.scans[scanId]; }, async setCurrentFrame({ commit }, frameId) { commit('setCurrentFrameId', frameId); @@ -751,9 +749,6 @@ const { if (!frame) { throw new Error("frame id doesn't exist"); } - if (getters.currentFrame === frame) { - return; - } commit('setLoadingFrame', true); commit('setErrorLoadingFrame', false); const oldScan = getters.currentScan; diff --git a/web_client/src/views/Projects.vue b/web_client/src/views/Projects.vue index 17163462..39b57a8c 100644 --- a/web_client/src/views/Projects.vue +++ b/web_client/src/views/Projects.vue @@ -26,10 +26,13 @@ export default defineComponent({ }, inject: ['user', 'MIQAConfig'], setup() { + const { switchReviewMode } = store.commit; const loadingProjects = ref(true); store.dispatch.loadProjects().then(() => { loadingProjects.value = false; }); + const reviewMode = computed(() => store.state.reviewMode); + const complete = window.location.hash.includes('complete'); const currentProject = computed(() => store.state.currentProject); const currentTaskOverview = computed(() => store.state.currentTaskOverview); const projects = computed(() => store.state.projects); @@ -37,9 +40,6 @@ export default defineComponent({ const selectedProjectIndex = ref(projects.value.findIndex( (project) => project.id === currentProject.value?.id, )); - const selectProject = (project: Project) => { - store.dispatch.loadProject(project); - }; const selectGlobal = () => { store.dispatch.loadGlobal(); }; @@ -88,11 +88,26 @@ export default defineComponent({ ); } + async function getProjectFromURL() { + if (complete) { + const targetProjectIndex = projects.value.findIndex( + (project) => project.id === window.location.hash.split('/')[1], + ); + const targetProject = projects.value[targetProjectIndex]; + if (targetProject) store.commit.setCurrentProject(targetProject); + selectedProjectIndex.value = targetProjectIndex; + } + } + const overviewPoll = setInterval(refreshTaskOverview, 10000); watch(currentTaskOverview, setOverviewSections); watch(currentProject, refreshTaskOverview); + watch(projects, getProjectFromURL); return { + reviewMode, + switchReviewMode, + complete, currentProject, loadingProjects, currentTaskOverview, @@ -100,17 +115,24 @@ export default defineComponent({ projects, isGlobal, overviewPoll, - selectProject, selectGlobal, overviewSections, setOverviewSections, refreshAllTaskOverviews, + getProjectFromURL, }; }, data: () => ({ creating: false, newName: '', }), + watch: { + projects() { + this.$nextTick(() => { + if (this.$refs.proceed) this.$refs.proceed.$el.focus(); + }); + }, + }, mounted() { this.setOverviewSections(); window.addEventListener('keydown', (event) => { @@ -130,6 +152,12 @@ export default defineComponent({ }, methods: { ...mapMutations(['setProjects', 'setCurrentProject']), + selectProject(project: Project) { + if (this.complete) { + this.complete = false; + } + store.dispatch.loadProject(project); + }, async createProject() { if (this.creating && this.newName.length > 0) { try { @@ -150,6 +178,26 @@ export default defineComponent({ } } }, + async proceedToNext() { + const nextProject = this.projects[this.selectedProjectIndex + 1]; + store.dispatch.loadProject(nextProject); + this.selectedProjectIndex += 1; + await djangoRest.projectTaskOverview(nextProject.id).then( + (taskOverview) => { + let nextScanIndex = 0; + let nextScan; + let nextScanState; + while ( + !nextScan || (nextScanState === 'complete' && this.reviewMode) + ) { + nextScan = nextProject.experiments[0].scans[nextScanIndex]; + nextScanState = taskOverview.scan_states[nextScan.id]; + nextScanIndex += 1; + } + this.$router.push(`/${nextProject.id}/${nextScan.id}` || ''); + }, + ); + }, }, }); @@ -240,7 +288,7 @@ export default defineComponent({
@@ -304,7 +352,41 @@ export default defineComponent({ fill-height >
+ Viewed all scans in Project {{ currentProject.name }}. +
+ Proceed to next Project, {{ projects[selectedProjectIndex+1].name }}? +
+ + + Proceed + + +
+ + All scans + + Scans for my review + +
+
Select a project @@ -348,4 +430,8 @@ export default defineComponent({ width: 100%; text-align: center; } +.mode-toggle { + align-items: baseline; + display: inline-block; +} diff --git a/web_client/src/views/Frame.vue b/web_client/src/views/Scan.vue similarity index 87% rename from web_client/src/views/Frame.vue rename to web_client/src/views/Scan.vue index 69c98e03..a56a418d 100644 --- a/web_client/src/views/Frame.vue +++ b/web_client/src/views/Scan.vue @@ -1,7 +1,7 @@