Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to open old report viewers #2085

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@
<targetPath>report-viewer</targetPath>
<directory>../report-viewer/dist</directory>
</resource>
<!-- Even though it is already in the resources folder, it needs to be explicitly included to be part of the jar -->
<resource>
<targetPath>v5</targetPath>
<directory>src/main/resources/v5</directory>
</resource>
</resources>
<plugins>
<plugin>
Expand Down
5 changes: 5 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/ReportViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class ReportViewer implements HttpHandler {
private static final String REPORT_VIEWER_RESOURCE_PREFIX = "report-viewer";
private static final String INDEX_PATH = "index.html";
private static final String RESULT_PATH = "results.zip";
private static final String[] OLD_VERSION_DIRECTORIES = new String[] {"v5"};

private static final Logger logger = LoggerFactory.getLogger(ReportViewer.class);
private static final int SUCCESS_RESPONSE = 200;
Expand All @@ -45,6 +46,10 @@ public ReportViewer(File zipFile, int port) throws IOException {

this.routingTree.insertRouting("", new RoutingResources(REPORT_VIEWER_RESOURCE_PREFIX).or(new RoutingAlias(INDEX_PATH)));
this.routingTree.insertRouting(RESULT_PATH, new RoutingStaticFile(zipFile, ContentType.ZIP));
for (String version : OLD_VERSION_DIRECTORIES) {
this.routingTree.insertRouting(version, new RoutingResources(version).or(new RoutingAlias(version + "/" + INDEX_PATH)));
}

this.port = port;
}

Expand Down
9 changes: 9 additions & 0 deletions cli/src/main/resources/v5/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html lang="">
<script>
const UrlPath = window.location.pathname
const branch = UrlPath.split('/')[1]
const url = 'https://jplag.github.io/' + branch + '/'
location.replace(url)
</script>
</html>
1,017 changes: 1,017 additions & 0 deletions cli/src/main/resources/v5/assets/index-D6LlQyWf.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cli/src/main/resources/v5/assets/index-DPPiA3g-.css

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added cli/src/main/resources/v5/favicon.ico
Binary file not shown.
20 changes: 20 additions & 0 deletions cli/src/main/resources/v5/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/v5/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JPlag Report Viewer</title>
<script type="module" crossorigin src="/v5/assets/index-D6LlQyWf.js"></script>
<link rel="stylesheet" crossorigin href="/v5/assets/index-DPPiA3g-.css">
</head>
<body style="overflow: hidden">
<noscript>
<strong
>We're sorry but the JPlag Report Viewer does not work properly without JavaScript enabled.
Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
</body>
</html>
Expand Down
5 changes: 4 additions & 1 deletion report-viewer/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ coverage

test-results/
playwright-report/
tests/e2e/assets
tests/e2e/assets/*
!tests/e2e/assets/progpedia-report-v5_1_0.zip
!tests/e2e/assets/progpedia-report-v4_2_0.zip
!tests/e2e/assets/result_small_cluster.zip
59 changes: 33 additions & 26 deletions report-viewer/src/model/factories/OverviewFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@ export class OverviewFactory extends BaseFactory {
/**
* Gets the overview file based on the used mode (zip, local, single).
*/
public static async getOverview(): Promise<Overview> {
public static async getOverview(): Promise<OverviewExtractionResult> {
return this.extractOverview(JSON.parse(await this.getFile('overview.json')))
}

/**
* Creates an overview object from a json object created by JPlag
* @param json the json object
*/
private static extractOverview(json: Record<string, unknown>): Overview {
private static extractOverview(json: Record<string, unknown>): OverviewExtractionResult {
const versionField = json.jplag_version as Record<string, number>
const jplagVersion = Version.fromJsonField(versionField)

OverviewFactory.compareVersions(jplagVersion, reportViewerVersion, minimalReportVersion)
if (!OverviewFactory.compareVersions(jplagVersion, reportViewerVersion, minimalReportVersion)) {
return {
result: 'oldReport',
version: jplagVersion
}
}

const submissionFolder = json.submission_folder_path as Array<string>
const baseCodeFolder = json.base_code_folder_path as string
Expand All @@ -42,19 +47,25 @@ export class OverviewFactory extends BaseFactory {
this.saveIdToDisplayNameMap(json)
this.saveComparisonFilesLookup(json)

return new Overview(
submissionFolder,
baseCodeFolder,
language,
fileExtensions,
matchSensitivity,
dateOfExecution,
duration,
this.extractTopComparisons(json.top_comparisons as Array<Record<string, unknown>>, clusters),
this.extractDistributions(json.distributions as Record<string, Array<number>>),
clusters,
totalComparisons
)
return {
result: 'success',
overview: new Overview(
submissionFolder,
baseCodeFolder,
language,
fileExtensions,
matchSensitivity,
dateOfExecution,
duration,
this.extractTopComparisons(
json.top_comparisons as Array<Record<string, unknown>>,
clusters
),
this.extractDistributions(json.distributions as Record<string, Array<number>>),
clusters,
totalComparisons
)
}
}

private static extractDistributions(
Expand Down Expand Up @@ -153,6 +164,7 @@ export class OverviewFactory extends BaseFactory {
* @param jsonVersion the version of the json file
* @param reportViewerVersion the version of the report viewer
* @param minimalVersion the minimal report version expected
* @return true if the version is supported, false if the version is old
*/
static compareVersions(
jsonVersion: Version,
Expand All @@ -179,15 +191,10 @@ export class OverviewFactory extends BaseFactory {
}
sessionStorage.setItem('versionAlert', 'true')
}
if (jsonVersion.compareTo(minimalVersion) < 0) {
throw new Error(
"The result's version(" +
jsonVersion.toString() +
') is older than the minimal support version of the report viewer(' +
minimalVersion.toString() +
'). ' +
'Can not read the report.'
)
}
return jsonVersion.compareTo(minimalVersion) >= 0
}
}

export type OverviewExtractionResult =
| { result: 'success'; overview: Overview }
| { result: 'oldReport'; version: Version }
7 changes: 7 additions & 0 deletions report-viewer/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ComparisonViewWrapper from '@/viewWrapper/ComparisonViewWrapper.vue'
import ErrorView from '@/views/ErrorView.vue'
import InformationViewWrapper from '@/viewWrapper/InformationViewWrapper.vue'
import ClusterViewWrapper from '@/viewWrapper/ClusterViewWrapper.vue'
import OldVersionRedirectView from '@/views/OldVersionRedirectView.vue'

/**
* The router is used to navigate between the different views of the application.
Expand Down Expand Up @@ -45,6 +46,12 @@ const router = createRouter({
name: 'InfoView',
component: InformationViewWrapper
},
{
path: '/old/:version',
name: 'OldVersionRedirectView',
component: OldVersionRedirectView,
props: true
},
{
path: '/:pathMatch(.*)*',
redirect: '/error/Could not find the requested page/FileUploadView/Back to file upload'
Expand Down
10 changes: 7 additions & 3 deletions report-viewer/src/viewWrapper/ClusterViewWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { OverviewFactory } from '@/model/factories/OverviewFactory'
import ClusterView from '@/views/ClusterView.vue'
import LoadingCircle from '@/components/LoadingCircle.vue'
import type { Overview } from '@/model/Overview'
import { redirectOnError } from '@/router'
import { redirectOnError, router } from '@/router'
import VersionRepositoryReference from '@/components/VersionRepositoryReference.vue'

const props = defineProps({
Expand All @@ -33,8 +33,12 @@ const clusterIndex = computed(() => parseInt(props.clusterIndex))
const overview: Ref<Overview | null> = ref(null)

OverviewFactory.getOverview()
.then((o) => {
overview.value = o
.then((r) => {
if (r.result == 'success') {
overview.value = r.overview
} else if (r.result == 'oldReport') {
router.push({ name: 'OldVersionRedirectView', params: { version: r.version.toString() } })
}
})
.catch((error) => {
redirectOnError(error, 'Could not load cluster:\n', 'OverviewView', 'Back to overview')
Expand Down
10 changes: 7 additions & 3 deletions report-viewer/src/viewWrapper/ComparisonViewWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import ComparisonView from '@/views/ComparisonView.vue'
import type { Comparison } from '@/model/Comparison'
import { ComparisonFactory } from '@/model/factories/ComparisonFactory'
import LoadingCircle from '@/components/LoadingCircle.vue'
import { redirectOnError } from '@/router'
import { redirectOnError, router } from '@/router'
import type { Language } from '@/model/Language'
import VersionRepositoryReference from '@/components/VersionRepositoryReference.vue'
import type { BaseCodeMatch } from '@/model/BaseCodeReport'
Expand Down Expand Up @@ -55,8 +55,12 @@ const comparisonPromise = ComparisonFactory.getComparison(props.comparisonFileNa
})

OverviewFactory.getOverview()
.then((overview) => {
language.value = overview.language
.then((r) => {
if (r.result == 'success') {
language.value = r.overview.language
} else if (r.result == 'oldReport') {
router.push({ name: 'OldVersionRedirectView', params: { version: r.version.toString() } })
}
})
.catch((error) => {
redirectOnError(error, 'Could not load comparison:\n')
Expand Down
10 changes: 7 additions & 3 deletions report-viewer/src/viewWrapper/InformationViewWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { OverviewFactory } from '@/model/factories/OverviewFactory'
import InformationView from '@/views/InformationView.vue'
import type { Overview } from '@/model/Overview'
import LoadingCircle from '@/components/LoadingCircle.vue'
import { redirectOnError } from '@/router'
import { redirectOnError, router } from '@/router'
import { OptionsFactory } from '@/model/factories/OptionsFactory'
import type { CliOptions } from '@/model/CliOptions'
import VersionRepositoryReference from '@/components/VersionRepositoryReference.vue'
Expand All @@ -27,8 +27,12 @@ const overview: Ref<Overview | null> = ref(null)
const cliOptions: Ref<CliOptions | undefined> = ref(undefined)

OverviewFactory.getOverview()
.then((o) => {
overview.value = o
.then((r) => {
if (r.result == 'success') {
overview.value = r.overview
} else if (r.result == 'oldReport') {
router.push({ name: 'OldVersionRedirectView', params: { version: r.version.toString() } })
}
})
.catch((error) => {
redirectOnError(error, 'Could not load information:\n', 'OverviewView', 'Back to overview')
Expand Down
10 changes: 7 additions & 3 deletions report-viewer/src/viewWrapper/OverviewViewWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ import { OverviewFactory } from '@/model/factories/OverviewFactory'
import OverviewView from '@/views/OverviewView.vue'
import type { Overview } from '@/model/Overview'
import LoadingCircle from '@/components/LoadingCircle.vue'
import { redirectOnError } from '@/router'
import { redirectOnError, router } from '@/router'
import VersionRepositoryReference from '@/components/VersionRepositoryReference.vue'

const overview: Ref<Overview | null> = ref(null)

OverviewFactory.getOverview()
.then((o) => {
overview.value = o
.then((r) => {
if (r.result == 'success') {
overview.value = r.overview
} else if (r.result == 'oldReport') {
router.push({ name: 'OldVersionRedirectView', params: { version: r.version.toString() } })
}
})
.catch((error) => {
redirectOnError(error, 'Could not load overview:\n')
Expand Down
95 changes: 95 additions & 0 deletions report-viewer/src/views/OldVersionRedirectView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<template>
<div class="flex h-screen text-center">
<div class="w-screen">
<div>
<img
class="mx-auto mt-32 h-auto w-60"
src="@/assets/jplag-light-transparent.png"
alt="JPlag Logo"
v-if="store().uiState.useDarkMode"
/>
<img
class="mx-auto mt-32 h-auto w-60"
src="@/assets/jplag-dark-transparent.png"
alt="JPlag Logo"
v-else
/>
</div>
<Container class="mx-auto mt-10 w-fit max-w-5xl space-y-5 p-5">
<div class="space-y-2">
<h3 class="text-2xl font-bold">
You are trying to open a report from an older version of JPlag
</h3>
<p class="text-xl">
The report you are trying to open has version {{ uploadedVersion.toString() }}. <br />
The current version of JPlag is {{ reportViewerVersion.toString() }}. The report viewer
can open reports from version {{ minimalReportVersion.toString() }}<br />
You can access the old report viewer here:
</p>
</div>
<a :href="buildOldVersionLink()">
<Interactable class="mx-auto mt-2 !border-accent-dark !bg-accent !bg-opacity-50">
Open old report viewer
</Interactable>
</a>
<RouterLink :to="{ name: 'FileUploadView' }">
<Interactable class="mx-auto mt-6"> Back to file upload </Interactable>
</RouterLink>
</Container>
</div>
</div>
</template>

<script setup lang="ts">
import Container from '@/components/ContainerComponent.vue'
import Interactable from '@/components/InteractableComponent.vue'
import { store } from '@/stores/store'
import { reportViewerVersion, minimalReportVersion, Version } from '@/model/Version'
import { computed } from 'vue'

const props = defineProps({
version: {
type: String,
required: true
}
})

const uploadedVersion = computed(() => {
const parts = props.version.split('.').map(Number)
return new Version(parts[0], parts[1], parts[2])
})

/**
* @param minVersion is inclusive
* @param maxVersion is inclusive
*/
interface VersionMapEntry {
minVersion: Version
maxVersion: Version
pathName: string
}

const versionMap: VersionMapEntry[] = [
{
minVersion: new Version(4, 2, 0),
maxVersion: new Version(5, 1, 0),
pathName: 'v5'
}
]

const requestedVersion = computed(() => {
for (const entry of versionMap) {
if (
uploadedVersion.value.compareTo(entry.minVersion) >= 0 &&
uploadedVersion.value.compareTo(entry.maxVersion) <= 0
) {
return entry
}
}
return null
})

function buildOldVersionLink() {
return `${window.location.origin}/${requestedVersion.value?.pathName}/`
}
</script>
Loading
Loading