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

Fix downloading UI #456

Merged
merged 7 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 8 additions & 6 deletions rdwatch/scoring/views/model_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
NullIf,
Substr,
)
from django.http import Http404, HttpRequest
from django.http import Http404, HttpRequest, HttpResponseNotFound
from django.shortcuts import get_object_or_404

from rdwatch.core.db.functions import BoundingBox, ExtractEpoch
Expand Down Expand Up @@ -506,12 +506,14 @@ def list_model_runs(

@router.get('/{id}/', response={200: ModelRunDetailSchema})
def get_model_run(request: HttpRequest, id: UUID4):
try:
EvaluationRun.objects.get(pk=id)
if EvaluationRun.objects.filter(pk=id).exists():
data = get_queryset()
except EvaluationRun.DoesNotExist:
get_object_or_404(AnnotationProposalSet.objects.get(pk=id))
data = get_queryset_proposal()
elif AnnotationProposalSet.objects.filter(pk=id).exists():
data = get_object_or_404(get_queryset_proposal(), id=id)
else:
return HttpResponseNotFound(
f'Neither an EvaluationRun or AnnotationProposalSet exists for uuid: {id}'
)

fetch_counts = SatelliteFetching.objects.filter(
model_run_uuid=id, status=SatelliteFetching.Status.RUNNING
Expand Down
16 changes: 13 additions & 3 deletions vue/src/components/ModelRunCard.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import TimeSlider from "./TimeSlider.vue";
import { ApiService, ModelRun } from "../client";
import { Ref, computed, onBeforeMount, onBeforeUnmount, ref, withDefaults } from "vue";
import { Ref, computed, onBeforeMount, onBeforeUnmount, ref, watch, withDefaults } from "vue";
import { timeRangeFormat } from "../utils";
import ImagesDownloadDialog from "./ImagesDownloadDialog.vue";
import { DownloadSettings } from "../client/services/ApiService";
Expand Down Expand Up @@ -50,13 +50,23 @@ const updateDownloading = async () => {

}

watch(() => props.modelRun.downloading, () => {
downloading.value = props.modelRun.downloading;
if (downloading.value) {
setTimeout(() => {
updateDownloading();
loopingInterval = setInterval(updateDownloading, 5000);
}, 2000);
}
});

const startDownload = debounce((data: DownloadSettings) => {
downloadImages.value = false;
ApiService.getModelRunImages(props.modelRun.id.toString(), data)
downloading.value = props.modelRun.numsites;
setTimeout(() => {
updateDownloading();
loopingInterval = setInterval(updateDownloading, 10000);
loopingInterval = setInterval(updateDownloading, 5000);
}, 2000);
}, 5000, { leading: true });

Expand All @@ -70,7 +80,7 @@ onBeforeMount(() => {
loopingInterval = null;
}
if (props.modelRun.downloading > 0 && loopingInterval === null)
loopingInterval = setInterval(updateDownloading, 10000);
loopingInterval = setInterval(updateDownloading, 5000);
})

onBeforeUnmount(() => {
Expand Down
31 changes: 31 additions & 0 deletions vue/src/components/ModelRunList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,37 @@ async function loadModelRuns() {
}
}

// Used to update downloading status after an image download has been started.
const checkDownloading = async () => {
if (request !== undefined) {
console.log('Cancelling request');
request.cancel();
}
const { mode, performer } = props.filters; // unwrap performer and mode arrays
request = ApiService.getModelRuns({
limit,
...props.filters,
mode,
performer,
proposal: props.compact ? 'PROPOSAL' : undefined, // if compact we are doing proposal adjudication
});
const modelRunList = await request;
request = undefined;
// sort list to show ground truth near the top
const modelRunResults = modelRunList.items;

for (let i = 0; i< state.modelRuns.length; i += 1) {
const currentModelRun = state.modelRuns[i];
const found = modelRunResults.find((item) => item.id === currentModelRun.id);
if (found) {
if (found.downloading) {
state.modelRuns[i].downloading = found.downloading;
}
}
}
};

watch(() => state.downloadingCheck, () => checkDownloading());

const loadingSatelliteTimestamps = ref(false);

Expand Down
1 change: 1 addition & 0 deletions vue/src/components/annotationViewer/AnnotationList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ const startDownload = async (data: DownloadSettings) => {
imageDownloadDialog.value = false;
if (id) {
await ApiService.getObservationImages(id, data);
state.downloadingCheck += 1;
// Now we get the results to see if the service is running
setTimeout(() => getSiteProposals(), 1000);
}
Expand Down
38 changes: 24 additions & 14 deletions vue/src/components/siteList/SiteList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ const props = defineProps<{
modelRuns: string[];
}>();

const emit = defineEmits<{
(e: "image-download", modelRunId: string): void;
}>();

const baseModifiedList: Ref<SiteDisplay[]> = ref([]);
const modifiedList: Ref<SiteDisplay[]> = ref([]);
const imageDownloadDialog = ref(false);
const imageTimeRange: Ref<{min: number, max: number} | null> = ref(null);
const imageDownloadingId: Ref<null | string> = ref(null)
const modelRunTitleList: Ref<string[]> = ref([])
const imageDownloadingModelRunId: Ref<null | string | undefined> = ref(null)
const modelRunTitleList: Ref<string[]> = ref([])
const totalCount: Ref<number> = ref(0);
const filter = ref("");
let downloadCheckInterval: NodeJS.Timeout | null = null;
Expand Down Expand Up @@ -65,7 +70,6 @@ const getSites = async (modelRun: string, initRun = false) => {
let downloadingAny = false;
if (results.sites) {
const modList: SiteDisplay[] = [];
let selected: SiteDisplay | null = null;
const details = results.modelRunDetails ? {
title: results.modelRunDetails.title,
version: results.modelRunDetails.version,
Expand All @@ -90,6 +94,7 @@ const getSites = async (modelRun: string, initRun = false) => {
modList.push({
number: item.number,
id: item.id,
modelRunId: modelRun,
name,
filename: item.filename,
bbox: item.bbox,
Expand All @@ -114,9 +119,6 @@ const getSites = async (modelRun: string, initRun = false) => {
totalCount.value += 1;
});
// We need to start checking if there are downloading sites to update every once in a while
if (selected !== null) {
selectSite(selected);
}
if (downloadingAny && downloadCheckInterval === null) {
checkDownloading();
}
Expand All @@ -138,7 +140,12 @@ const getAllSiteProposals = async (initRun = false) => {
} else {
modifiedList.value = mainList;
}
modifiedList.value.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
modifiedList.value.sort((a, b) => {
if (a.selected === b.selected) {
return a.name.localeCompare(b.name);
}
return a.selected ? -1 : 1;
});
}
onMounted(() => getAllSiteProposals(true));
onUnmounted(() => {
Expand Down Expand Up @@ -190,14 +197,11 @@ const selectSite = async (selectedSite: SiteDisplay, deselect= false) => {
updatedList.push(item);
})
updatedList.sort((a, b) => {
if (a.selected === b.selected) {
return 0;
}
if (a.selected) {
return -1;
}
return 1;
});
if (a.selected === b.selected) {
return a.name.localeCompare(b.name);
}
return a.selected ? -1 : 1;
});
modifiedList.value = updatedList;
if (!deselect) {
nextTick(() => {
Expand Down Expand Up @@ -257,13 +261,19 @@ const setImageDownloadDialog = (item: SiteDisplay) => {
}
imageDownloadDialog.value = true;
imageDownloadingId.value = item.id;
imageDownloadingModelRunId.value = item.modelRunId;
};

const startDownload = async (data: DownloadSettings) => {
const id = imageDownloadingId.value;
imageDownloadDialog.value = false;
if (id) {
await ApiService.getObservationImages(id, data);
// Notify the ModelRunList that downloading is happening
if (imageDownloadingModelRunId.value) {
emit('image-download', imageDownloadingModelRunId.value);
}
state.downloadingCheck += 1;
// Now we get the results to see if the service is running
setTimeout(() => getAllSiteProposals(), 1000);
}
Expand Down
1 change: 1 addition & 0 deletions vue/src/components/siteList/SiteListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface SiteDisplay {
number: number;
id: string;
uuid?: string;
modelRunId?: string;
name: string;
bbox: { xmin: number; ymin: number; xmax: number; ymax: number };
startDate: number;
Expand Down
3 changes: 3 additions & 0 deletions vue/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ export const state = reactive<{
// Region map is used to index names and owners with ids
regionMap: RegionMapType;
regionList: RegionDetail[];
// Downloading Check - used to indicate to the modelRunList to check for downloading images
downloadingCheck: number;
}>({
appVersion: '',
errorText: '',
Expand Down Expand Up @@ -278,6 +280,7 @@ export const state = reactive<{
groundTruthLinks: {},
regionMap: {},
regionList: [],
downloadingCheck: 0,
});

export const filteredSatelliteTimeList = computed(() => {
Expand Down
Loading