diff --git a/src/app/App.js b/src/app/App.js
index a64a77bd..67cf57d6 100644
--- a/src/app/App.js
+++ b/src/app/App.js
@@ -72,7 +72,7 @@ const MaintenanceAlert = () => (
width='300'
/>
- Animl is currently undergoing evolution. Check back soon!
+ Animl is undergoing evolution. Check back soon!
);
diff --git a/src/components/ErrorAlerts.js b/src/components/ErrorAlerts.js
index 17ce4a92..f1f1c1d6 100644
--- a/src/components/ErrorAlerts.js
+++ b/src/components/ErrorAlerts.js
@@ -28,6 +28,8 @@ import {
dismissCamerasError,
} from '../features/cameras/camerasSlice';
import {
+ selectImagesErrors,
+ dismissImagesError,
selectImageContextErrors,
dismissImageContextError,
selectStatsErrors,
@@ -44,6 +46,7 @@ const ErrorAlerts = () => {
const depsErrors = useSelector(selectDeploymentsErrors);
const modelsErrors = useSelector(selectModelsErrors);
const camerasErrors = useSelector(selectCamerasErrors);
+ const imagesErrors = useSelector(selectImagesErrors);
const imageContextErrors = useSelector(selectImageContextErrors);
const statsErrors = useSelector(selectStatsErrors);
@@ -54,8 +57,9 @@ const ErrorAlerts = () => {
enrichErrors(depsErrors, 'Deployment Error', 'deployments'),
enrichErrors(modelsErrors, 'Model Error', 'models'),
enrichErrors(camerasErrors, 'Camera Error', 'cameras'),
+ enrichErrors(imagesErrors, 'Error Fetching Images', 'images'),
enrichErrors(imageContextErrors, 'Image Error', 'imageContext'),
- enrichErrors(statsErrors, 'Stats Error', 'stats'),
+ enrichErrors(statsErrors, 'Error Getting Stats', 'stats'),
];
const errors = enrichedErrors.reduce((acc, curr) => (
@@ -108,6 +112,7 @@ const dismissErrorActions = {
'deployments': (i) => dismissDeploymentsError(i),
'models': (i) => dismissModelsError(i),
'cameras': (i) => dismissCamerasError(i),
+ 'images': (i) => dismissImagesError(i),
'imageContext': (i) => dismissImageContextError(i),
'stats': (i) => dismissStatsError(i)
};
diff --git a/src/features/images/ImagesStatsModal.js b/src/features/images/ImagesStatsModal.js
index 69ef350d..dcf6c074 100644
--- a/src/features/images/ImagesStatsModal.js
+++ b/src/features/images/ImagesStatsModal.js
@@ -14,6 +14,41 @@ const NoneFoundAlert = styled('div', {
color: '$gray600',
});
+const StatsDisplay = styled('div', {
+ border: '1px solid $gray400',
+ maxHeight: '50vh',
+ overflowY: 'scroll',
+});
+
+const StyledStatsDisclaimer = styled('div', {
+ paddingTop: 10,
+ fontSize: '$3',
+ color: '$gray600',
+});
+
+const StatsDisclaimer = () => (
+
+ NOTE: this is a WIP. Be mindful of the following:
+
+ -
+ each reviewer's "reviewedCount" is the total number
+ of images they have edited in some way (validated/invalidated
+ a label, added objects, etc.). Because multiple users can edit the same
+ image, and because images that have been edited can still be
+ considered "not reviewed" (e.g., if a user invalidated all labels on
+ all objects, but did't mark it empty), the sum of all reviewers
+ "reviewedCounts" very likely will not equal the "reviewedCount"
+ "reviewed" quantity
+
+ -
+ the quantities in the "labelList" are for locked objects
+ with validated labels only, so they do not include ML
+ predicted labels that need review
+
+
+
+)
+
const ImagesStatsModal = ({ filters }) => {
const dispatch = useDispatch();
@@ -39,7 +74,14 @@ const ImagesStatsModal = ({ filters }) => {
We couldn't find any images that matched this set of filters.
}
- {stats &&
{JSON.stringify(stats, null, 2)}
}
+ {stats &&
+ <>
+
+ {JSON.stringify(stats, null, 2)}
+
+
+ >
+ }
);
};
diff --git a/src/features/images/ImagesTable.js b/src/features/images/ImagesTable.js
index a7c6ade0..729f5906 100644
--- a/src/features/images/ImagesTable.js
+++ b/src/features/images/ImagesTable.js
@@ -496,7 +496,10 @@ function makeRows(workingImages, focusIndex) {
/>;
const hasObjs = image.objects.length > 0;
const hasUnlockedObjs = image.objects.some((obj) => obj.locked === false);
- const reviewed = (!hasObjs || hasUnlockedObjs)
+ const hasAllInvalidatedLabels = !image.objects.some((obj) => (
+ obj.labels.some((lbl) => !lbl.validation || lbl.validation.validated)
+ ));
+ const reviewed = (!hasObjs || hasUnlockedObjs || hasAllInvalidatedLabels)
?
: ;
diff --git a/src/features/images/imagesSlice.js b/src/features/images/imagesSlice.js
index a0264214..d75b4539 100644
--- a/src/features/images/imagesSlice.js
+++ b/src/features/images/imagesSlice.js
@@ -90,6 +90,11 @@ export const imagesSlice = createSlice({
state.images = state.images.concat(payload.images.images);
},
+ dismissImagesError: (state, { payload }) => {
+ const index = payload;
+ state.loadingStates.image.errors.splice(index, 1);
+ },
+
preFocusImageStart: (state, { payload }) => {
state.preFocusImage = payload;
},
@@ -185,6 +190,7 @@ export const {
getImagesStart,
getImagesSuccess,
getImagesFailure,
+ dismissImagesError,
preFocusImageStart,
preFocusImageEnd,
getImageContextStart,
@@ -327,6 +333,7 @@ export const selectHasNext = state => state.images.pageInfo.hasNext;
export const selectImages = state => state.images.images;
export const selectImagesCount = state => state.images.pageInfo.count;
export const selectImagesLoading = state => state.images.loadingStates.images;
+export const selectImagesErrors = state => state.images.loadingStates.images.errors;
export const selectVisibleRows = state => state.images.visibleRows;
export const selectPreFocusImage = state => state.images.preFocusImage;
export const selectImageContextLoading = state => state.images.loadingStates.imageContext;