Don't show buttons for ongoing scans.

This commit is contained in:
Julian Stirling 2025-09-19 18:29:34 +01:00
parent 29a62a278b
commit cd6bcd196f
3 changed files with 100 additions and 56 deletions

View file

@ -17,6 +17,7 @@ from subprocess import SubprocessError
from fastapi import HTTPException from fastapi import HTTPException
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
import numpy as np import numpy as np
from pydantic import BaseModel
import labthings_fastapi as lt import labthings_fastapi as lt
@ -39,6 +40,16 @@ CSMDep = lt.deps.direct_thing_client_dependency(
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/") AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/")
class ScanListData(BaseModel):
"""The data to be sent to the Scan List tab."""
scans: list[scan_directories.ScanInfo]
"""The list of scans as ScanInfo objects"""
ongoing: Optional[str]
"""The name of the ongoing scan or None"""
class JPEGBlob(lt.blob.Blob): class JPEGBlob(lt.blob.Blob):
"""A class representing a JPEG image as a LabThings FastAPI Blob.""" """A class representing a JPEG image as a LabThings FastAPI Blob."""
@ -557,7 +568,7 @@ class SmartScanThing(lt.Thing):
"""Whether to run a final stitch at the end of a successful scan.""" """Whether to run a final stitch at the end of a successful scan."""
@lt.thing_property @lt.thing_property
def scans(self) -> list[scan_directories.ScanInfo]: def scans(self) -> ScanListData:
"""All the available scans. """All the available scans.
Each scan has a name (which can be used to access it), along with Each scan has a name (which can be used to access it), along with
@ -566,7 +577,10 @@ class SmartScanThing(lt.Thing):
uses a regular expression, and changes to the naming scheme will uses a regular expression, and changes to the naming scheme will
break it. break it.
""" """
return self._scan_dir_manager.all_scans_info() return ScanListData(
scans=self._scan_dir_manager.all_scans_info(),
ongoing=None if self._ongoing_scan is None else self._ongoing_scan.name,
)
@lt.fastapi_endpoint( @lt.fastapi_endpoint(
"get", "get",

View file

@ -14,61 +14,64 @@
/> />
</div> </div>
</div> </div>
<h3 class="uk-card-title" style="text-align: center;">{{ scanData.name }}</h3> <h3 class="uk-card-title scan-card-title">{{ scanData.name }}</h3>
<div class="button-container"> <h4 class="ongoing-msg" v-if="ongoing">Scan in progress</h4>
<div class="uk-button-group" style="width:100%"> <div class="button-container" v-if="!ongoing">
<action-button <div class="uk-button-group scan-card-buttons">
class="uk-width-1-2" <action-button
thing="smart_scan"
action="download_zip"
submit-label="Download All"
:can-terminate="false"
:submit-data="{ scan_name: scanData.name }"
:button-primary="true"
@response="downloadZipFile"
@error="modalError"
/>
<EndpointButton
class="uk-width-1-2" class="uk-width-1-2"
:buttonPrimary=true thing="smart_scan"
:isDisabled=!scanData.stitch_available action="download_zip"
:URL="downloadStitchFile" submit-label="Download All"
buttonLabel="Download JPEG" :can-terminate="false"
:submit-data="{ scan_name: scanData.name }"
:button-primary="true"
@response="downloadZipFile"
@error="modalError"
/> />
</div> <EndpointButton
<button class="uk-width-1-2"
class="uk-button uk-button-default uk-width-1-1" :buttonPrimary=true
@click="deleteScan" :isDisabled=!scanData.stitch_available
> :URL="downloadStitchFile"
Delete buttonLabel="Download JPEG"
</button> />
<action-button </div>
submit-label="Stitch Images" <button
thing="smart_scan" class="uk-button uk-button-default uk-width-1-1"
action="stitch_scan" @click="deleteScan"
v-if="scanData.can_stitch | (scanData.stitch_available & !scanData.dzi)" >
:can-terminate="true" Delete
:submit-data="{ scan_name: scanData.name }" </button>
:button-primary="false" <action-button
:modal-progress="true" submit-label="Stitch Images"
@error="modalError" thing="smart_scan"
/> action="stitch_scan"
<button v-if="scanData.can_stitch | (scanData.stitch_available & !scanData.dzi)"
v-if="scanData.dzi" class="uk-button uk-button-default uk-width-1-1" :can-terminate="true"
@click="requestViewer" :submit-data="{ scan_name: scanData.name }"
> :button-primary="false"
Show Stitched Scan :modal-progress="true"
</button> @error="modalError"
/>
<button
v-if="scanData.dzi" class="uk-button uk-button-default uk-width-1-1"
@click="requestViewer"
>
Show Stitched Scan
</button>
</div> </div>
<div> <div>
<ul> <ul>
<li>{{ scanData.number_of_images }} images</li> <li>{{ scanData.number_of_images }} images</li>
<li>created: {{ formatDate(scanData.created) }}</li> <li>created: {{ formatDate(scanData.created) }}</li>
<li>modified: {{ formatDate(scanData.modified) }}</li> <li>modified: {{ formatDate(scanData.modified) }}</li>
</ul> </ul>
<li v-if="scanData.number_of_images<3" class="warning-msg">Not enough images to stitch</li> <ul v-if="!ongoing">
<li v-else-if="!scanData.dzi & scanData.stitch_available" class="alert-msg">Interactive preview not available</li> <li v-if="scanData.number_of_images<3" class="warning-msg">Not enough images to stitch</li>
<li v-else-if=!scanData.stitch_available class="alert-msg">High quality stitch not available</li> <li v-else-if="!scanData.dzi & scanData.stitch_available" class="alert-msg">Interactive preview not available</li>
<li v-else-if=!scanData.stitch_available class="alert-msg">High quality stitch not available</li>
</ul>
</div> </div>
</div> </div>
</div> </div>
@ -92,6 +95,10 @@ export default {
scansUri: { scansUri: {
type: String, type: String,
required: true required: true
},
ongoing: {
type: Boolean,
required: true
} }
}, },
@ -124,7 +131,9 @@ export default {
}, },
requestViewer() { requestViewer() {
// Notify parent that thumbnail was clicked // Notify parent that thumbnail was clicked
this.$emit('viewer-requested', this.scanData); if (!this.ongoing) {
this.$emit('viewer-requested', this.scanData);
}
}, },
async deleteScan() { async deleteScan() {
try { try {
@ -165,9 +174,23 @@ ul {
font-weight: bold; font-weight: bold;
} }
.alert-msg{ .alert-msg {
color: orange; color: orange;
text-align: center; text-align: center;
font-weight: bold; font-weight: bold;
} }
.scan-card-buttons {
width: 100%;
}
.scan-card-title {
text-align: center;
}
.ongoing-msg {
text-align: center;
padding: 2rem 0;
}
</style> </style>

View file

@ -88,6 +88,7 @@
<scan-card <scan-card
:scan-data="scanData" :scan-data="scanData"
:scans-uri="scansUri" :scans-uri="scansUri"
:ongoing="isOngoing(scanData.name)"
@viewer-requested="showScan" @viewer-requested="showScan"
@update-requested="updateScans" @update-requested="updateScans"
/> />
@ -112,6 +113,7 @@ export default {
data: function() { data: function() {
return { return {
scans: [], scans: [],
ongoing: null,
selectedScan: null, selectedScan: null,
osdViewer: null osdViewer: null
}; };
@ -191,7 +193,9 @@ export default {
}, },
async updateScans() { async updateScans() {
try { try {
let scans = await this.readThingProperty("smart_scan", "scans"); let scans_information = await this.readThingProperty("smart_scan", "scans");
let scans = scans_information.scans
this.ongoing = scans_information.ongoing
if (!scans | (scans.length == 0)) { if (!scans | (scans.length == 0)) {
this.scans = scans; this.scans = scans;
} }
@ -208,6 +212,9 @@ export default {
this.scans = []; this.scans = [];
} }
}, },
isOngoing(name) {
return name === this.ongoing
},
async deleteAllScans() { async deleteAllScans() {
try { try {
await this.modalConfirm( await this.modalConfirm(