Updated to new metadata semantics

This commit is contained in:
Joel Collins 2020-01-29 17:53:14 +00:00
parent 32545e850c
commit b9ae730c73
10 changed files with 106 additions and 116 deletions

View file

@ -84,9 +84,9 @@
</li> </li>
<li> <li>
<a class="uk-accordion-title" href="#">Metadata</a> <a class="uk-accordion-title" href="#">Annotations</a>
<div class="uk-accordion-content"> <div class="uk-accordion-content">
<keyvalList v-model="metadata" /> <keyvalList v-model="annotations" />
</div> </div>
</li> </li>
@ -296,7 +296,7 @@ export default {
}, },
resizeDims: [640, 480], resizeDims: [640, 480],
tags: [], tags: [],
metadata: { annotations: {
Client: `${process.env.PACKAGE.name}.${process.env.PACKAGE.version}` Client: `${process.env.PACKAGE.name}.${process.env.PACKAGE.version}`
}, },
scanUri: null scanUri: null
@ -316,7 +316,7 @@ export default {
return `${this.$store.getters.baseUri}/api/v2/extensions`; return `${this.$store.getters.baseUri}/api/v2/extensions`;
}, },
settingsFovUri: function() { settingsFovUri: function() {
return `${this.$store.getters.baseUri}/api/v2/settings/fov`; return `${this.$store.getters.baseUri}/api/v2/instrument/settings/fov`;
}, },
basePayload: function() { basePayload: function() {
var payload = {}; var payload = {};
@ -339,13 +339,13 @@ export default {
}; };
} }
// Additional metadata // Additional annotations
payload.metadata = this.metadata; payload.annotations = this.annotations;
payload.tags = this.tags; payload.tags = this.tags;
// Attach notes // Attach notes
if (this.captureNotes) { if (this.captureNotes) {
payload.metadata["Notes"] = this.captureNotes; payload.annotations["Notes"] = this.captureNotes;
} }
return payload; return payload;

View file

@ -193,7 +193,7 @@ export default {
return `${this.$store.getters.baseUri}/api/v2/actions/stage/zero`; return `${this.$store.getters.baseUri}/api/v2/actions/stage/zero`;
}, },
positionStatusUri: function() { positionStatusUri: function() {
return `${this.$store.getters.baseUri}/api/v2/status/stage/position`; return `${this.$store.getters.baseUri}/api/v2/instrument/state/stage/position`;
}, },
pluginsUri: function() { pluginsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/extensions`; return `${this.$store.getters.baseUri}/api/v2/extensions`;

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="host-input"> <div class="host-input">
<div v-if="status && $store.getters.ready"> <div v-if="configuration && $store.getters.ready">
<div> <div>
<div class="uk-margin-small-bottom"> <div class="uk-margin-small-bottom">
<b>Host:</b> <b>Host:</b>
@ -17,7 +17,7 @@
</div> </div>
<div> <div>
<b>Server version:</b> <br /> <b>Server version:</b> <br />
{{ status.version }} {{ configuration.application.version }}
</div> </div>
<hr /> <hr />
@ -25,16 +25,16 @@
<div class="uk-margin-small-bottom"> <div class="uk-margin-small-bottom">
<b>Camera:</b> <b>Camera:</b>
<br /> <br />
<div v-if="status.camera.board"> <div v-if="configuration.camera.type != 'MissingCamera'">
{{ status.camera.board }} {{ configuration.camera.type }}
</div> </div>
<div v-else class="uk-text-danger"><b>No camera connected</b></div> <div v-else class="uk-text-danger"><b>No camera connected</b></div>
</div> </div>
<div> <div>
<b>Stage:</b> <b>Stage:</b>
<br /> <br />
<div v-if="status.stage.board"> <div v-if="configuration.stage.type != 'MissingStage'">
{{ status.stage.board }} {{ configuration.stage.type }}
</div> </div>
<div v-else class="uk-text-danger"><b>No stage connected</b></div> <div v-else class="uk-text-danger"><b>No stage connected</b></div>
</div> </div>
@ -86,7 +86,7 @@ export default {
data: function() { data: function() {
return { return {
status: null, configuration: null,
settings: null, settings: null,
systemActionLinks: {} systemActionLinks: {}
}; };
@ -94,10 +94,10 @@ export default {
computed: { computed: {
settingsUri: function() { settingsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/settings`; return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
}, },
statusUri: function() { configurationUri: function() {
return `${this.$store.getters.baseUri}/api/v2/status`; return `${this.$store.getters.baseUri}/api/v2/instrument/configuration`;
}, },
actionsUri: function() { actionsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/actions`; return `${this.$store.getters.baseUri}/api/v2/actions`;
@ -105,13 +105,13 @@ export default {
}, },
created: function() { created: function() {
// Watch for host 'ready', then update status // Watch for host 'ready', then update configuration
this.$store.watch( this.$store.watch(
(state, getters) => { (state, getters) => {
return getters.ready; return getters.ready;
}, },
() => { () => {
this.updateStatus(); this.updateConfiguration();
this.updateSettings(); this.updateSettings();
this.updateSystemActions(); this.updateSystemActions();
} }
@ -119,11 +119,11 @@ export default {
}, },
methods: { methods: {
updateStatus: function() { updateConfiguration: function() {
axios axios
.get(this.statusUri) .get(this.configurationUri)
.then(response => { .then(response => {
this.status = response.data; this.configuration = response.data;
}) })
.catch(error => { .catch(error => {
this.modalError(error); // Let mixin handle error this.modalError(error); // Let mixin handle error

View file

@ -1,28 +1,28 @@
<template> <template>
<div v-if="camera_settings" id="cameraSettings"> <div v-if="settings" id="cameraSettings">
<form @submit.prevent="applyConfigRequest"> <form @submit.prevent="applyConfigRequest">
<div v-if="camera_settings.picamera_settings"> <div v-if="settings.picamera">
<!--PiCamera settings block--> <!--PiCamera settings block-->
<div v-if="camera_settings.picamera_settings.shutter_speed"> <div v-if="settings.picamera.shutter_speed">
<label class="uk-form-label" for="form-stacked-text" <label class="uk-form-label" for="form-stacked-text"
>Exposure time</label >Exposure time</label
> >
<div class="uk-form-controls"> <div class="uk-form-controls">
<input <input
v-model="camera_settings.picamera_settings.shutter_speed" v-model="settings.picamera.shutter_speed"
class="uk-input uk-form-small" class="uk-input uk-form-small"
type="number" type="number"
/> />
</div> </div>
</div> </div>
<div v-if="camera_settings.picamera_settings.analog_gain"> <div v-if="settings.picamera.analog_gain">
<label class="uk-form-label" for="form-stacked-text" <label class="uk-form-label" for="form-stacked-text"
>Analogue gain</label >Analogue gain</label
> >
<div class="uk-form-controls"> <div class="uk-form-controls">
<input <input
v-model="camera_settings.picamera_settings.analog_gain" v-model="settings.picamera.analog_gain"
class="uk-input uk-form-small" class="uk-input uk-form-small"
type="number" type="number"
step="0.000001" step="0.000001"
@ -30,13 +30,13 @@
</div> </div>
</div> </div>
<div v-if="camera_settings.picamera_settings.digital_gain"> <div v-if="settings.picamera.digital_gain">
<label class="uk-form-label" for="form-stacked-text" <label class="uk-form-label" for="form-stacked-text"
>Digital gain</label >Digital gain</label
> >
<div class="uk-form-controls"> <div class="uk-form-controls">
<input <input
v-model="camera_settings.picamera_settings.digital_gain" v-model="settings.picamera.digital_gain"
class="uk-input uk-form-small" class="uk-input uk-form-small"
type="number" type="number"
step="0.000001" step="0.000001"
@ -85,7 +85,7 @@ export default {
data: function() { data: function() {
return { return {
camera_settings: null, settings: null,
recalibrationUri: null, recalibrationUri: null,
isCalibrating: false isCalibrating: false
}; };
@ -93,7 +93,7 @@ export default {
computed: { computed: {
settingsUri: function() { settingsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/settings`; return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
}, },
pluginsUri: function() { pluginsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/extensions`; return `${this.$store.getters.baseUri}/api/v2/extensions`;
@ -110,7 +110,7 @@ export default {
axios axios
.get(this.settingsUri) .get(this.settingsUri)
.then(response => { .then(response => {
this.camera_settings = response.data.camera_settings; this.settings = response.data.camera;
}) })
.catch(error => { .catch(error => {
this.modalError(error); // Let mixin handle error this.modalError(error); // Let mixin handle error
@ -139,11 +139,11 @@ export default {
applyConfigRequest: function() { applyConfigRequest: function() {
console.log("Applying config to the microscope"); console.log("Applying config to the microscope");
var payload = { var payload = {
camera_settings: { camera: {
picamera_settings: { picamera: {
shutter_speed: this.camera_settings.picamera_settings.shutter_speed, shutter_speed: this.settings.picamera.shutter_speed,
analog_gain: this.camera_settings.picamera_settings.analog_gain, analog_gain: this.settings.picamera.analog_gain,
digital_gain: this.camera_settings.picamera_settings.digital_gain digital_gain: this.settings.picamera.digital_gain
} }
} }
}; };

View file

@ -11,7 +11,7 @@
<label class="uk-form-label" for="form-stacked-text">x</label> <label class="uk-form-label" for="form-stacked-text">x</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<input <input
v-model="settings.stage_settings.backlash.x" v-model="settings.stage.backlash.x"
class="uk-input uk-form-small" class="uk-input uk-form-small"
type="number" type="number"
/> />
@ -22,7 +22,7 @@
<label class="uk-form-label" for="form-stacked-text">y</label> <label class="uk-form-label" for="form-stacked-text">y</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<input <input
v-model="settings.stage_settings.backlash.y" v-model="settings.stage.backlash.y"
class="uk-input uk-form-small" class="uk-input uk-form-small"
type="number" type="number"
/> />
@ -33,7 +33,7 @@
<label class="uk-form-label" for="form-stacked-text">z</label> <label class="uk-form-label" for="form-stacked-text">z</label>
<div class="uk-form-controls"> <div class="uk-form-controls">
<input <input
v-model="settings.stage_settings.backlash.z" v-model="settings.stage.backlash.z"
class="uk-input uk-form-small" class="uk-input uk-form-small"
type="number" type="number"
/> />
@ -80,7 +80,7 @@ export default {
computed: { computed: {
settingsUri: function() { settingsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/settings`; return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
} }
}, },
@ -103,8 +103,8 @@ export default {
applyConfigRequest: function() { applyConfigRequest: function() {
var payload = { var payload = {
name: this.settings.name, name: this.settings.name,
stage_settings: { stage: {
backlash: this.settings.stage_settings.backlash backlash: this.settings.stage.backlash
} }
}; };

View file

@ -326,7 +326,7 @@ export default {
}, },
checkServerVersion: function() { checkServerVersion: function() {
var versionUri = `${this.$store.getters.baseUri}/api/v2/status/version`; var versionUri = `${this.$store.getters.baseUri}/api/v2/instrument/configuration/application/version`;
axios axios
.get(versionUri) .get(versionUri)
.then(response => { .then(response => {
@ -383,7 +383,7 @@ export default {
saveHost: function() { saveHost: function() {
// URI to get hostname directly from settings // URI to get hostname directly from settings
var hostnameUri = `${this.$store.getters.baseUri}/api/v2/settings/name`; var hostnameUri = `${this.$store.getters.baseUri}/api/v2/instrument/settings/name`;
axios axios
.get(hostnameUri) .get(hostnameUri)
.then(response => { .then(response => {

View file

@ -8,7 +8,7 @@
<img <img
class="uk-width-1-1" class="uk-width-1-1"
:data-src="thumbURL" :data-src="thumbURL"
:alt="captureState.metadata.id" :alt="captureState.metadata.image.id"
width="300" width="300"
height="225" height="225"
uk-img uk-img
@ -34,7 +34,7 @@
<div <div
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand" class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"
> >
<time>{{ betterTimestring }}</time> <time>{{ captureState.metadata.image.acquisitionDate }}</time>
</div> </div>
<div <div
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto" class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto"
@ -77,13 +77,13 @@
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<h2 class="uk-modal-title">{{ fileName }}</h2> <h2 class="uk-modal-title">{{ fileName }}</h2>
<p><b>Path: </b>{{ captureState.path }}</p> <p><b>Path: </b>{{ captureState.path }}</p>
<p><b>Time: </b>{{ betterTimestring }}</p> <p><b>Time: </b>{{ captureState.metadata.image.acquisitionDate }}</p>
<p><b>ID: </b>{{ captureState.metadata.id }}</p> <p><b>ID: </b>{{ captureState.metadata.image.id }}</p>
<p><b>Format: </b>{{ captureState.metadata.format }}</p> <p><b>Format: </b>{{ captureState.metadata.image.format }}</p>
<hr /> <hr />
<div v-for="(value, key) in customMetadata" :key="key"> <div v-for="(value, key) in annotations" :key="key">
<p> <p>
<b>{{ key }}: </b>{{ value }} <b>{{ key }}: </b>{{ value }}
</p> </p>
@ -93,14 +93,14 @@
<div class="uk-flex-bottom" uk-grid> <div class="uk-flex-bottom" uk-grid>
<div class="uk-width-2-3"> <div class="uk-width-2-3">
<keyvalList v-model="newCustomMetadata" /> <keyvalList v-model="newAnnotations" />
</div> </div>
<div class="uk-width-1-3"> <div class="uk-width-1-3">
<button <button
class="uk-button uk-button-primary uk-form-small uk-width-1-1" class="uk-button uk-button-primary uk-form-small uk-width-1-1"
@click="handleMetadataSubmit()" @click="handleAnnotationsSubmit()"
> >
Add metadata Add annotation
</button> </button>
</div> </div>
</div> </div>
@ -171,15 +171,15 @@ export default {
return { return {
tags: [], tags: [],
newTag: "", newTag: "",
customMetadata: {}, annotations: {},
newCustomMetadata: {} newAnnotations: {}
}; };
}, },
computed: { computed: {
fileName: function() { fileName: function() {
return this.captureState.filename // If this.captureState.filename exists return this.captureState.name // If this.captureState.filename exists
? this.captureState.filename // Use this.captureState.filename ? this.captureState.name // Use this.captureState.filename
: this.captureState.metadata.filename; // Otherwise use old this.captureState.metadata.filename : this.captureState.metadata.filename; // Otherwise use old this.captureState.metadata.filename
}, },
tagModalID: function() { tagModalID: function() {
@ -203,23 +203,17 @@ export default {
tagsURL: function() { tagsURL: function() {
return this.captureState.links.tags.href; return this.captureState.links.tags.href;
}, },
metadataURL: function() { annotationsURL: function() {
return this.captureState.links.metadata.href; return this.captureState.links.annotations.href;
}, },
captureURL: function() { captureURL: function() {
return this.captureState.links.self.href; return this.captureState.links.self.href;
},
betterTimestring: function() {
var dtSplit = this.captureState.metadata.time.split("_");
var date = dtSplit[0];
var time = dtSplit[1].replace(/-/g, ":");
return date + " " + time;
} }
}, },
created: function() { created: function() {
this.getTagRequest(); this.getTagRequest();
this.getMetadataRequest(); this.getAnnotationsRequest();
}, },
methods: { methods: {
@ -231,9 +225,9 @@ export default {
UIkit.modal(event.target.parentNode).hide(); UIkit.modal(event.target.parentNode).hide();
}, },
handleMetadataSubmit: function() { handleAnnotationsSubmit: function() {
this.putMetadataRequest(this.newCustomMetadata); this.putAnnotationsRequest(this.newAnnotations);
this.newCustomMetadata = {}; this.newAnnotations = {};
}, },
delCaptureConfirm: function() { delCaptureConfirm: function() {
@ -269,13 +263,13 @@ export default {
}); });
}, },
putMetadataRequest: function(metadataObject) { putAnnotationsRequest: function(annotationsObject) {
// Send metadata PUT request // Send metadata PUT request
axios axios
.put(this.metadataURL, metadataObject) .put(this.annotationsURL, annotationsObject)
.then(() => { .then(() => {
// Update metadata object // Update metadata object
this.getMetadataRequest(); this.getAnnotationsRequest();
}) })
.catch(error => { .catch(error => {
this.modalError(error); // Let mixin handle error this.modalError(error); // Let mixin handle error
@ -315,12 +309,12 @@ export default {
}); });
}, },
getMetadataRequest: function() { getAnnotationsRequest: function() {
// Send tag request // Send tag request
axios axios
.get(this.metadataURL) .get(this.annotationsURL)
.then(response => { .then(response => {
this.customMetadata = response.data.custom; this.annotations = response.data;
}) })
.catch(error => { .catch(error => {
this.modalError(error); // Let mixin handle error this.modalError(error); // Let mixin handle error
@ -328,7 +322,7 @@ export default {
}, },
makeModalName: function(prefix) { makeModalName: function(prefix) {
return prefix + this.captureState.metadata.id; return prefix + this.captureState.metadata.image.id;
} }
} }
}; };

View file

@ -7,13 +7,11 @@
<img <img
class="uk-width-1-1" class="uk-width-1-1"
:data-src="thumbnail" :data-src="thumbnail"
:alt="metadata.scan_id" :alt="metadata.id"
width="300" width="300"
height="225" height="225"
uk-img uk-img
@click=" @click="$root.$emit('globalUpdateCaptureFolder', metadata.id)"
$root.$emit('globalUpdateCaptureFolder', metadata.custom.scan_id)
"
/> />
</a> </a>
</div> </div>
@ -24,14 +22,14 @@
uk-grid uk-grid
> >
<div class="uk-margin-remove-top uk-padding-remove uk-width-expand"> <div class="uk-margin-remove-top uk-padding-remove uk-width-expand">
<b>Scan:</b> {{ metadata.custom.basename }} <b>{{ metadata.type || "Dataset" }}: </b> {{ metadata.name }}
</div> </div>
</div> </div>
<div <div
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand" class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-expand"
> >
<time>{{ betterTimestring }}</time> <time>{{ metadata.acquisitionDate }}</time>
</div> </div>
<div <div
class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto" class="uk-text-meta uk-margin-remove-top uk-padding-remove uk-width-auto"
@ -54,10 +52,12 @@
<div class="uk-modal-dialog uk-modal-body"> <div class="uk-modal-dialog uk-modal-body">
<button class="uk-modal-close-default" type="button" uk-close></button> <button class="uk-modal-close-default" type="button" uk-close></button>
<h2 class="uk-modal-title">{{ metadata.basename }}</h2> <h2 class="uk-modal-title">{{ metadata.basename }}</h2>
<p><b>Time: </b>{{ betterTimestring }}</p> <p><b>Time: </b>{{ metadata.acquisitionDate }}</p>
<p><b>Scan ID: </b>{{ metadata.custom.scan_id }}</p> <p><b>ID: </b>{{ metadata.id }}</p>
<div v-for="(value, key) in metadata.custom" :key="key"> <hr />
<div v-for="(value, key) in metadata.annotations" :key="key">
<p> <p>
<b>{{ key }}: </b>{{ value }} <b>{{ key }}: </b>{{ value }}
</p> </p>
@ -95,12 +95,6 @@ export default {
}, },
metadataModalTarget: function() { metadataModalTarget: function() {
return "#" + this.metadataModalID; return "#" + this.metadataModalID;
},
betterTimestring: function() {
var dtSplit = this.metadata.custom.time.split("_");
var date = dtSplit[0];
var time = dtSplit[1].replace(/-/g, ":");
return date + " " + time;
} }
}, },

View file

@ -127,7 +127,7 @@ export default {
// Return an array of unique tags across all captures // Return an array of unique tags across all captures
var tags = []; var tags = [];
for (var capture of this.captures) { for (var capture of this.captures) {
for (var tag of capture.metadata.tags) { for (var tag of capture.metadata.image.tags) {
if (!tags.includes(tag)) { if (!tags.includes(tag)) {
tags.push(tag); tags.push(tag);
} }
@ -140,11 +140,8 @@ export default {
// List of captures that are not part of a scan // List of captures that are not part of a scan
var captures = []; var captures = [];
for (var capture of this.captures) { for (var capture of this.captures) {
// Filter by selected tags
var tags = capture.metadata.tags;
// Add to capture list if matched // Add to capture list if matched
if (!tags.includes(this.scanTag)) { if (!capture.metadata.dataset) {
captures.push(capture); captures.push(capture);
} }
} }
@ -157,11 +154,12 @@ export default {
var scans = {}; var scans = {};
for (var capture of this.captures) { for (var capture of this.captures) {
var custom = capture.metadata.custom; var annotations = capture.metadata.image.annotations;
var tags = capture.metadata.tags; var tags = capture.metadata.image.tags;
var dataset = capture.metadata.dataset;
if ("scan_id" in custom) { if (dataset) {
var id = custom["scan_id"]; var id = dataset["id"];
// If this scan ID hasn't been seen before // If this scan ID hasn't been seen before
if (!(id in scans)) { if (!(id in scans)) {
@ -169,21 +167,22 @@ export default {
scans[id].isScan = true; scans[id].isScan = true;
scans[id].captures = []; scans[id].captures = [];
scans[id].metadata = { scans[id].metadata = {
filename: custom.basename, name: dataset.name,
time: custom.time, acquisitionDate: dataset.acquisitionDate,
id: custom.scan_id id: dataset.id,
type: dataset.type
}; };
scans[id].metadata.tags = []; scans[id].metadata.tags = [];
scans[id].metadata.custom = {}; scans[id].metadata.annotations = {};
} }
// Add the capture object to the scan // Add the capture object to the scan
scans[id].captures.push(capture); scans[id].captures.push(capture);
// Add missing scan metadata, prioritising first capture // Add missing scan metadata, prioritising first capture
for (var key of Object.keys(custom)) { for (var key of Object.keys(annotations)) {
if (!(key in scans[id].metadata.custom)) { if (!(key in scans[id].metadata.annotations)) {
scans[id].metadata.custom[key] = custom[key]; scans[id].metadata.annotations[key] = annotations[key];
} }
} }
@ -196,9 +195,9 @@ export default {
// Create a preview thumbnail // Create a preview thumbnail
if (!("thumbnail" in scans[id])) { if (!("thumbnail" in scans[id])) {
scans[id].thumbnail = `${ scans[
capture.links.download.href id
}?thumbnail=true`; ].thumbnail = `${capture.links.download.href}?thumbnail=true`;
} }
} }
} }
@ -231,12 +230,15 @@ export default {
var captures = {}; var captures = {};
for (var item of this.filteredItems) { for (var item of this.filteredItems) {
// If it's a dataset
if ("captures" in item) { if ("captures" in item) {
for (var capture of item.captures) { for (var capture of item.captures) {
captures[capture.metadata.id] = capture; // Get the ID of each capture in the set
captures[capture.metadata.image.id] = capture;
} }
} else { } else {
captures[item.metadata.id] = item; // If it's a single capture, get the ID of the capture
captures[item.metadata.image.id] = item;
} }
} }

View file

@ -70,7 +70,7 @@ export default {
}/api/v2/actions/camera/preview/stop`; }/api/v2/actions/camera/preview/stop`;
}, },
settingsUri: function() { settingsUri: function() {
return `${this.$store.getters.baseUri}/api/v2/settings`; return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
} }
}, },