Skip to content
Draft
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
9 changes: 7 additions & 2 deletions client/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export type RecordingLocationsFeatureProperties = {

export type RecordingLocationsGeoJson = FeatureCollection<Point, RecordingLocationsFeatureProperties>;

export interface SpeciesResponse {
items: Species[];
count: number;
}
export interface Species {
species_code: string;
family: string;
Expand All @@ -48,6 +52,7 @@ export interface Species {
species?: string;
id: number;
category: "single" | "multiple" | "frequency" | "noid";
in_range?: boolean;
}

export interface SpectrogramAnnotation {
Expand Down Expand Up @@ -408,8 +413,8 @@ async function getSequenceAnnotations(recordingId: string) {
);
}

async function getSpecies() {
return axiosInstance.get<Species[]>("/species/");
async function getSpecies({recordingId, grtsCellId, sampleFrameId}: {recordingId?: number, grtsCellId?: number, sampleFrameId?: number}) {
return axiosInstance.get<SpeciesResponse>("/species/", { params: { recording_id: recordingId, grts_cell_id: grtsCellId, sample_frame_id: sampleFrameId } });
}

async function patchAnnotation(
Expand Down
45 changes: 42 additions & 3 deletions client/src/components/SingleSpecieEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,46 @@
single: "primary",
multiple: "secondary",
frequency: "warning",
"suggested species by range location": "success",
noid: "",
};

const categoryPriority: Record<string, number> = {
"suggested species by range location": 0,
single: 1,
multiple: 2,
frequency: 3,
noid: 4,
};

const inRangeTooltip =
"This species is in the same range as the recording.";

const groupedItems = computed(() => {
const inRangeSpecies = props.speciesList.filter((s) => s.in_range === true);
const rest = props.speciesList.filter((s) => s.in_range !== true);

const groups: Record<string, Species[]> = {};
for (const s of props.speciesList) {
for (const s of rest) {
const cat =
s.category.charAt(0).toUpperCase() + s.category.slice(1);
if (!groups[cat]) groups[cat] = [];
groups[cat].push(s);
}
const result: Array<
{ type: "subheader"; title: string } | (Species & { category: string })
{ type: "subheader"; title: string } | Species
> = [];
const groupsOrder = ["Single", "Multiple", "Frequency", "Noid"];
if (inRangeSpecies.length > 0) {
result.push({ type: "subheader", title: "Suggested Species by Range Location" });
const sortedInRange = [...inRangeSpecies].sort((a, b) => {
const aCat = categoryPriority[a.category] ?? 999;
const bCat = categoryPriority[b.category] ?? 999;
if (aCat !== bCat) return aCat - bCat;
return a.species_code.localeCompare(b.species_code);
});
result.push(...sortedInRange);
}
const groupsOrder = ["In range", "Single", "Multiple", "Frequency", "Noid"];
groupsOrder.forEach((key) => {
result.push({ type: "subheader", title: key });
result.push(...(groups[key] ?? []));
Expand Down Expand Up @@ -115,6 +140,7 @@
categoryColors,
speciesAutocomplete,
onClearOrDeleteClick,
inRangeTooltip,
};
},
});
Expand Down Expand Up @@ -163,7 +189,8 @@
categoryColors[String(subProps.title).toLowerCase()]
? `bg-${categoryColors[String(subProps.title).toLowerCase()]}`
: ''
"

Check warning on line 192 in client/src/components/SingleSpecieEditor.vue

View workflow job for this annotation

GitHub Actions / Lint [eslint]

Expected 1 line break before closing bracket, but 2 line breaks found

>
{{ subProps.title }}
</v-list-subheader>
Expand All @@ -184,6 +211,18 @@
{{ (item.raw as Species).category }}
</v-chip>
</template>
<template
v-if="(item.raw as Species).in_range === true"
#append
>
<v-icon
v-tooltip="inRangeTooltip"
size="small"
color="#b8860b"
>
mdi-map
</v-icon>
</template>
</v-list-item>
</template>
</v-autocomplete>
Expand Down
39 changes: 36 additions & 3 deletions client/src/components/SingleSpecieInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,20 @@ export default defineComponent({

const orderedSpecies = ref<Species[]>([]);

const inRangeTooltip =
"This species is in the same range as the recording.";

function sortSpecies(species: Species[], selectedCode: string | null) {
const copied = cloneDeep(species);
copied.sort((a, b) => {
const aSelected = selectedCode === a.species_code;
const bSelected = selectedCode === b.species_code;
if (aSelected && !bSelected) return -1;
if (!aSelected && bSelected) return 1;
const aIn = a.in_range === true;
const bIn = b.in_range === true;
if (aIn && !bIn) return -1;
if (!aIn && bIn) return 1;
const aCat = categoryPriority[a.category] ?? 999;
const bCat = categoryPriority[b.category] ?? 999;
if (aCat !== bCat) return aCat - bCat;
Expand Down Expand Up @@ -131,6 +138,7 @@ export default defineComponent({
saveAndClose,
buttonLabel,
selectedSpecies,
inRangeTooltip,
};
},
});
Expand Down Expand Up @@ -232,7 +240,12 @@ export default defineComponent({
class="elevation-1 my-recordings"
>
<template #item="{ item }">
<tr :class="item.selected ? 'selected-row' : ''">
<tr
:class="[
item.selected ? 'selected-row' : '',
item.in_range === true ? 'species-in-range-row' : '',
]"
>
<td>
<v-checkbox
:model-value="item.selected"
Expand All @@ -242,7 +255,17 @@ export default defineComponent({
@update:model-value="toggleSpecies(item.species_code)"
/>
</td>
<td>{{ item.species_code }}</td>
<td class="d-flex align-center ga-1 flex-nowrap">
<span>{{ item.species_code }}</span>
<v-icon
v-if="item.in_range === true"
v-tooltip="inRangeTooltip"
size="small"
class="species-in-range-map-icon flex-shrink-0"
>
mdi-map
</v-icon>
</td>
<td>
<span
:class="
Expand Down Expand Up @@ -305,8 +328,18 @@ export default defineComponent({
</template>

<style scoped>
.selected-row {
.species-in-range-row {
background-color: rgba(212, 175, 55, 0.14);
}
.selected-row.species-in-range-row {
background-color: rgba(0, 0, 255, 0.05);
box-shadow: inset 0 0 0 1px rgba(25, 118, 210, 0.35);
}
.selected-row:not(.species-in-range-row) {
background-color: rgba(0, 0, 255, 0.05);
}
.selected-row {
/* default selected tint when not in-range handled above */
}

.text-primary {
Expand Down
43 changes: 39 additions & 4 deletions client/src/components/SpeciesInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export default defineComponent({

const orderedSpecies = ref<Species[]>([]);

const inRangeTooltip =
"This species is in the same range as the recording.";

function sortSpecies(species: Species[], selectedCodes: string[]) {
const copied = cloneDeep(species);
copied.sort((a, b) => {
Expand All @@ -83,6 +86,11 @@ export default defineComponent({
if (aSelected && !bSelected) return -1;
if (!aSelected && bSelected) return 1;

const aIn = a.in_range === true;
const bIn = b.in_range === true;
if (aIn && !bIn) return -1;
if (!aIn && bIn) return 1;

const aCat = categoryPriority[a.category] ?? 999;
const bCat = categoryPriority[b.category] ?? 999;
if (aCat !== bCat) return aCat - bCat;
Expand Down Expand Up @@ -153,6 +161,7 @@ export default defineComponent({
hasChanges,
closeDialog,
saveAndClose,
inRangeTooltip,
};
},
});
Expand Down Expand Up @@ -217,7 +226,12 @@ export default defineComponent({
class="elevation-1 my-recordings"
>
<template #item="{ item }">
<tr :class="item.selected ? 'selected-row' : ''">
<tr
:class="[
item.selected ? 'selected-row' : '',
item.in_range === true ? 'species-in-range-row' : '',
]"
>
<td>
<v-checkbox
:model-value="item.selected"
Expand All @@ -227,7 +241,19 @@ export default defineComponent({
@update:model-value="toggleSpecies(item.species_code)"
/>
</td>
<td>{{ item.species_code }}</td>
<td>
<span class="d-inline-flex align-center flex-nowrap ga-1">
<span>{{ item.species_code }}</span>
<v-icon
v-if="item.in_range === true"
v-tooltip="inRangeTooltip"
size="small"
class="species-in-range-map-icon flex-shrink-0"
>
mdi-map
</v-icon>
</span>
</td>
<td>
<span :class="categoryColors[item.category] ? `text-${categoryColors[item.category]}` : ''">
{{ item.category.charAt(0).toUpperCase() + item.category.slice(1) }}
Expand Down Expand Up @@ -270,9 +296,18 @@ export default defineComponent({
</template>

<style scoped>
.selected-row {
.species-in-range-row:not(.selected-row) {
background-color: rgba(212, 175, 55, 0.14);
}
.selected-row:not(.species-in-range-row) {
background-color: rgba(0, 0, 255, 0.05);
/* Light blue tint */
}
.selected-row.species-in-range-row {
background-color: rgba(212, 175, 55, 0.18);
box-shadow: inset 0 0 0 1px rgba(25, 118, 210, 0.35);
}
.species-in-range-map-icon {
color: #b8860b;
}

.text-primary {
Expand Down
15 changes: 14 additions & 1 deletion client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,20 @@ import { axiosInstance } from './api/api';
import { installPrompt } from './use/prompt-service';

const app = createApp(App);
const Vuetify = createVuetify({});
const Vuetify = createVuetify({
theme: {
themes: {
light: {
colors: {
primary: "#1976d2",
secondary: "#9c27b0",
warning: "#fb8c00",
golden: "#b8860b",
}
}
}
}
});

Sentry.init({
app,
Expand Down
4 changes: 2 additions & 2 deletions client/src/views/NABat/NABatSpectrogram.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ export default defineComponent({
spectroInfo.value.end_times = response.data.compressed.end_times;
viewCompressedOverlay.value = false;
}
const speciesResponse = await getSpecies();
const speciesResponse = await getSpecies({recordingId: parseInt(props.id)});
// Removing NOISE species from list and any duplicates
speciesList.value = speciesResponse.data.filter(
speciesList.value = speciesResponse.data.items.filter(
(value, index, self) => value.species_code !== "NOISE" && index === self.findIndex((t) => t.species_code === value.species_code)
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
4 changes: 2 additions & 2 deletions client/src/views/Spectrogram.vue
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,9 @@ export default defineComponent({
if (spectrogramData.value.currentUser) {
currentUser.value = spectrogramData.value.currentUser;
}
const speciesResponse = await getSpecies();
const speciesResponse = await getSpecies({recordingId: parseInt(props.id)});
// Removing NOISE species from list and any duplicates
speciesList.value = speciesResponse.data .filter(
speciesList.value = speciesResponse.data.items.filter(
(value, index, self) => index === self.findIndex((t) => t.species_code === value.species_code)
);
if (spectrogramData.value.otherUsers && spectroInfo.value) {
Expand Down