From ec05c772cb54c4d41f85dc47d967beffa093bd61 Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Mon, 25 Mar 2024 18:18:23 -0700 Subject: [PATCH 01/10] got rid of imports --- src/components/Accordion.jsx | 19 ++++- src/features/images/ImagesStatsModal.jsx | 101 ++++++++++++++++++++++- 2 files changed, 113 insertions(+), 7 deletions(-) diff --git a/src/components/Accordion.jsx b/src/components/Accordion.jsx index db487c13..eb3c8886 100644 --- a/src/components/Accordion.jsx +++ b/src/components/Accordion.jsx @@ -5,7 +5,7 @@ import IconButton from './IconButton.jsx'; import { indigo } from '@radix-ui/colors'; -const SelectedCount = styled('span', { +export const SelectedCount = styled('span', { background: indigo.indigo4, fontSize: '$2', fontWeight: '$5', @@ -14,7 +14,7 @@ const SelectedCount = styled('span', { borderRadius: '$2', }); -const Label = styled('span', { +export const Label = styled('span', { marginRight: '$4', }); @@ -31,7 +31,7 @@ const ExpandButton = styled('div', { paddingRight: '$2', }) -const AccordionHeader = styled('div', { +export const AccordionHeader = styled('div', { display: 'flex', alignItems: 'center', fontWeight: '$3', @@ -47,6 +47,19 @@ const AccordionHeader = styled('div', { cursor: 'pointer', }, }); +export const AccordionHeaderNoHover = styled('div', { + display: 'flex', + alignItems: 'center', + fontWeight: '$3', + fontFamily: '$sourceSansPro', + height: '$7', + borderBottom: '1px solid $border', + color: '$textDark', + backgroundColor: '$backgroundLight', + padding: '$0 $2 $0 $2', + position: 'relative', + +}); const Accordion = (props) => { const [expanded, setExpanded] = useState(props.expandedDefault); diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index b14301da..f0cce859 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -5,19 +5,67 @@ import { fetchStats, fetchTask, selectStatsLoading, selectImagesStats } from '.. import { selectActiveFilters } from '../filters/filtersSlice.js'; import { SimpleSpinner, SpinnerOverlay } from '../../components/Spinner'; import NoneFoundAlert from '../../components/NoneFoundAlert'; +import Accordion from '../../components/Accordion'; +import {Label, SelectedCount, AccordionHeaderNoHover} from '../../components/Accordion.jsx'; +import { CheckboxLabel } from '../../components/CheckboxLabel.jsx'; -const StatsDisplay = styled('div', { +const StatsInnerDisplay = styled('div', { border: '1px solid $border', maxHeight: '50vh', overflowY: 'scroll', + }); +const StatsDisplay = styled('div', { + height: '100%', + display: 'flex', + flexDirection: 'column', + gap: '5px', + userSelect: 'none', + touchAction: 'none' +}); + + +const StatsItemNoList = ({label, count}) => { + return ( + + + {count} + + ); +}; +let mappings = {}; +mappings = {imageCount: "Image Count:", reviewedCount: "Reviewed Images:", + reviewerList: "Reviewer List:", notReviewed: "Not Reviewed:", labelList: "Label List:", + multiReviewerCount: "Multi Reviewer Count:", userId: "User:", reviewed: "Reviewed:"}; +function mapLabel(s) { + return (mappings[s] == undefined) ? (s + ":") : mappings[s]; +} +const StatsItem = ({stat}) => { + let value = stat['value'] + const condition = Number.isInteger(value) + return ( + <> + {condition ? + : + + {value.map((v, index) => ( + {v['key']} {v['value']} + ))} + + } + + ); +}; +//will actually be a function that returns either a label or list if const StyledStatsDisclaimer = styled('div', { paddingTop: 10, fontSize: '$3', color: '$textMedium', }); + const StatsDisclaimer = () => ( NOTE: this is a WIP. Be mindful of the following: @@ -38,6 +86,8 @@ const StatsDisclaimer = () => ( ); + + const ImagesStatsModal = ({ open }) => { const dispatch = useDispatch(); const filters = useSelector(selectActiveFilters); @@ -50,6 +100,7 @@ const ImagesStatsModal = ({ open }) => { const noErrors = !errors || errors.length === 0; if (open && stats === null && !noneFound && !isLoading && noErrors) { dispatch(fetchStats(filters)); + } }, [open, stats, imagesStatsLoading, filters, dispatch]); @@ -59,7 +110,46 @@ const ImagesStatsModal = ({ open }) => { dispatch(fetchTask(imagesStatsLoading.taskId)); } }, [getStatsPending, stats, dispatch]); + + + const Stats = []; + /** Parses JSON array */ + function parseArray(value) { + let arr = []; let j = 0; let arraykey = ""; + for (let k = 0; k < value.length; k++) { + let arrayval = ""; + for (const [key, val] of Object.entries(value[k])) { + arraykey = (arraykey == "") ? (mapLabel(key)) : arraykey; + arrayval = (arrayval == "") ? (arrayval + val) : (arrayval + ", " + mapLabel(key) + " " + val); + } + arr[j++] = {"key": arraykey, "value": arrayval}; + } + return arr; + } + /** Converts stats to key/value pairs*/ + function ConvertStats(stats) { + let i = 0; + for (const [key, value] of Object.entries(stats)) { + if (Number.isInteger(value)) { + Stats[i++] = {"key": mapLabel(key), "value": value}; + } + else { + if (Array.isArray(value)) { + Stats[i++] = {"key": mapLabel(key), "value": parseArray(value)} + } else { + let arr = []; let j = 0; + for (const [objkey, objval] of Object.entries(value)) { + arr[j++] = {"key": mapLabel(objkey), "value": objval} + } + Stats[i++] = {"key": mapLabel(key), "value": arr} + } + } + } + } + if (stats != null) { + ConvertStats(stats); + } return (
{imagesStatsLoading.isLoading && ( @@ -70,10 +160,14 @@ const ImagesStatsModal = ({ open }) => { {imagesStatsLoading.noneFound && ( We couldn't find any images that matched this set of filters. )} - {stats && ( + {stats && Stats && (Stats.length > 0) && ( <> -
{JSON.stringify(stats, null, 2)}
+ + {Stats.map((stat, index) => ( + + ))} +
@@ -81,5 +175,4 @@ const ImagesStatsModal = ({ open }) => {
); }; - export default ImagesStatsModal; From a44e2a083d88154dc2decb37687f9aad7bc18b63 Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Mon, 25 Mar 2024 21:33:58 -0700 Subject: [PATCH 02/10] added imagesStatsLoading --- src/features/images/ImagesStatsModal.jsx | 31 +++++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index f0cce859..6fdc8a73 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -1,7 +1,12 @@ import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { styled } from '../../theme/stitches.config'; -import { fetchStats, fetchTask, selectStatsLoading, selectImagesStats } from '../tasks/tasksSlice.js'; +import { + fetchStats, + fetchTask, + selectStatsLoading, + selectImagesStats, +} from '../tasks/tasksSlice.js'; import { selectActiveFilters } from '../filters/filtersSlice.js'; import { SimpleSpinner, SpinnerOverlay } from '../../components/Spinner'; import NoneFoundAlert from '../../components/NoneFoundAlert'; @@ -71,16 +76,16 @@ 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 + 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 + the quantities in the "labelList" are for locked objects with validated{' '} + labels only, so they do not include ML predicted labels that need review
@@ -104,12 +109,12 @@ const ImagesStatsModal = ({ open }) => { } }, [open, stats, imagesStatsLoading, filters, dispatch]); - const getStatsPending = imagesStatsLoading.isLoading && imagesStatsLoading.taskId; useEffect(() => { + const getStatsPending = imagesStatsLoading.isLoading && imagesStatsLoading.taskId; if (getStatsPending) { dispatch(fetchTask(imagesStatsLoading.taskId)); } - }, [getStatsPending, stats, dispatch]); + }, [imagesStatsLoading, dispatch]); const Stats = []; @@ -158,7 +163,9 @@ const ImagesStatsModal = ({ open }) => { )} {imagesStatsLoading.noneFound && ( - We couldn't find any images that matched this set of filters. + + We couldn't find any images that matched this set of filters. + )} {stats && Stats && (Stats.length > 0) && ( <> From b5a8aedc19d4c3eb8ac11d8044e73ba92927c988 Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Mon, 25 Mar 2024 21:51:26 -0700 Subject: [PATCH 03/10] fix to disclaimer message --- src/features/images/ImagesStatsModal.jsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index 891fff48..fc42e367 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -40,7 +40,7 @@ const StatsItemNoList = ({label, count}) => { }; let mappings = {}; -mappings = {imageCount: "Image Count:", reviewedCount: "Reviewed Images:", +mappings = {imageCount: "Image Count:", reviewedCount: "Reviewed Count:", reviewerList: "Reviewer List:", notReviewed: "Not Reviewed:", labelList: "Label List:", multiReviewerCount: "Multi Reviewer Count:", userId: "User:", reviewed: "Reviewed:"}; function mapLabel(s) { @@ -63,7 +63,7 @@ const StatsItem = ({stat}) => { ); }; -//will actually be a function that returns either a label or list if + const StyledStatsDisclaimer = styled('div', { paddingTop: 10, fontSize: '$3', @@ -76,23 +76,23 @@ const StatsDisclaimer = () => ( NOTE: this is a WIP. Be mindful of the following:
  • - each reviewer's "reviewedCount" is the total number of images they + each reviewer's "Reviewed Count" 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 - each reviewer's "reviewedCount" is the total number of images they + objects, but did't mark it empty), the sum of all reviewers "Reviewed Counts" + very likely will not equal the "Reviewed Count" "reviewed" quantity + each reviewer's "Reviewed Count" 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 + objects, but did't mark it empty), the sum of all reviewers "Reviewed Counts" + very likely will not equal the "Reviewed Count" "reviewed" quantity
  • - the quantities in the "labelList" are for locked objects with validated{' '} + the quantities in the "Label List" are for locked objects with validated{' '} labels only, so they do not include ML predicted labels that need review - the quantities in the "labelList" are for locked objects with validated{' '} + the quantities in the "Label List" are for locked objects with validated{' '} labels only, so they do not include ML predicted labels that need review
From 712a62d850587c7c20504c2104b68c0a0f667c5b Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Tue, 2 Apr 2024 14:59:15 -0700 Subject: [PATCH 04/10] Dashboard feature --- package-lock.json | 264 ++++++++++++++++++++ package.json | 1 + src/features/images/ImagesStatsModal.jsx | 295 +++++++++++++++-------- 3 files changed, 466 insertions(+), 94 deletions(-) diff --git a/package-lock.json b/package-lock.json index e7a34faf..f289bcc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,6 +72,7 @@ "react-window": "^1.8.5", "react-window-infinite-loader": "^1.0.5", "react-with-direction": "^1.3.1", + "recharts": "^2.12.3", "redux-undo-redo": "^2.1.1", "use-resize-observer": "^9.1.0", "yup": "^0.32.8" @@ -15978,6 +15979,60 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -17782,6 +17837,116 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, "node_modules/dayjs": { "version": "1.11.10", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", @@ -17812,6 +17977,11 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "node_modules/decode-uri-component": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", @@ -19059,6 +19229,11 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -19171,6 +19346,14 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -20256,6 +20439,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/intrinsic-scale": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/intrinsic-scale/-/intrinsic-scale-3.0.4.tgz", @@ -23867,6 +24058,20 @@ "react": "^16 || ^17 || ^18" } }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -24065,6 +24270,44 @@ "node": ">= 4" } }, + "node_modules/recharts": { + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.3.tgz", + "integrity": "sha512-vE/F7wTlokf5mtCqVDJlVKelCjliLSJ+DJxj79XlMREm7gpV7ljwbrwE3CfeaoDlOaLX+6iwHaVRn9587YkwIg==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^16.10.2", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -26027,6 +26270,27 @@ "node": ">= 0.8" } }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/vite": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", diff --git a/package.json b/package.json index 962bdae9..6bb04edb 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "react-window": "^1.8.5", "react-window-infinite-loader": "^1.0.5", "react-with-direction": "^1.3.1", + "recharts": "^2.12.3", "redux-undo-redo": "^2.1.1", "use-resize-observer": "^9.1.0", "yup": "^0.32.8" diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index fc42e367..dfa2e560 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -10,57 +10,88 @@ import { import { selectActiveFilters } from '../filters/filtersSlice.js'; import { SimpleSpinner, SpinnerOverlay } from '../../components/Spinner'; import NoneFoundAlert from '../../components/NoneFoundAlert'; -import Accordion from '../../components/Accordion'; -import {Label, SelectedCount, AccordionHeaderNoHover} from '../../components/Accordion.jsx'; -import { CheckboxLabel } from '../../components/CheckboxLabel.jsx'; - -const StatsInnerDisplay = styled('div', { +import {SelectedCount} from '../../components/Accordion.jsx'; +import { indigo } from '@radix-ui/colors'; +import { + ComposedChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, +} from 'recharts'; +const StatsDash = styled('div', { border: '1px solid $border', - maxHeight: '50vh', - overflowY: 'scroll', - -}); -const StatsDisplay = styled('div', { - height: '100%', - display: 'flex', - flexDirection: 'column', - gap: '5px', - userSelect: 'none', - touchAction: 'none' + display: 'grid', + gridTemplateColumns: '1fr 1fr 1fr', + gridTemplateRows: '1fr 1fr 1fr', + background: '$backgroundDark', + borderRadius: '5px', + padding: '10px', + gap: '10px' }); - - -const StatsItemNoList = ({label, count}) => { - return ( - - - {count} - - ); -}; - +const Label = styled('div', { + marginBottom: '20px' +}) let mappings = {}; -mappings = {imageCount: "Image Count:", reviewedCount: "Reviewed Count:", - reviewerList: "Reviewer List:", notReviewed: "Not Reviewed:", labelList: "Label List:", - multiReviewerCount: "Multi Reviewer Count:", userId: "User:", reviewed: "Reviewed:"}; +mappings = {imageCount: "Image Count", reviewedCount: "Reviewed Count", + reviewerList: "Reviewer List", notReviewed: "Not Reviewed", labelList: "Label List", + multiReviewerCount: "Multi Reviewer Count", userId: "User", reviewed: "Reviewed"}; + function mapLabel(s) { return (mappings[s] == undefined) ? (s + ":") : mappings[s]; } -const StatsItem = ({stat}) => { - let value = stat['value'] - const condition = Number.isInteger(value) + +function changeCard(color, row, col, cspan, rspan) { + const StatsCard = styled('div', { + background: color, + padding: '15px', + borderRadius: '5px', + width: '100%', + height: '100%', + overflowX: 'scroll', + overflowY: 'scroll', + gridColumn: col + " / span " + cspan, + gridRow: row + " / span " + rspan, + }); + return StatsCard; +} + + +const StatsItem = ({name, stat}) => { + switch (name) { + case "imageCount": { + return ( + + ); + } + case "reviewedCount": { + return ( + + ); + } + case "reviewerList": { + return ( + + ); + } + case "labelList": { + return ( + + ); + } + case "multiReviewerCount": { + return ( + + ); + } + } return ( - <> - {condition ? - : - - {value.map((v, index) => ( - {v['key']} {v['value']} - ))} - - } - + + There is nothing to display for the statistic: {name} + ); }; @@ -99,7 +130,121 @@ const StatsDisclaimer = () => ( ); +const RatioCard = ({label, tnum, bnum, row, col, cspan, rspan}) => { + const StatsCard = changeCard('white', row, col, cspan, rspan) + const Container = styled('div', { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between' + }) + const NumerContainer = styled('div', { + width: '100%', + }) + const LargeNumber = styled(SelectedCount, { + fontSize: '30px', + width: '100%', + marginLeft: '5px', + + }) + const SmallNumber = styled('div', { + width: '100%', + textAlign: 'right', + alignSelf: 'flex-end' + }) + + return ( + + + + + {tnum} + + {bnum !== null && + / {bnum}} + + + ); +} + +const ListCard = ({label, list, row, col, cspan, rspan}) => { + const StatsCard = changeCard('white', row, col, cspan, rspan) + const Table = styled('div', { + maxWidth: '100%', + display: 'flex', + flexDirection: 'column', + overflow: 'scroll', + borderRadius: '5px', + border: '1px solid $border', + maxHeight: '102px' + }); + const Row = styled('div', { + display: 'flex', + flexDirection: 'row', + maxHeight: '50px', + }); + const TableCell = styled('div', { + borderBottom: '1px solid $border', + textAlign: 'left', + minWidth: '200px', + marginRight: '1px', + padding: '$2', + overflowX: 'scroll' + }); + const Header = () => { + let headers = list[0] + return( + + {Object.keys(headers).map((keyName, i) => ( + {mapLabel(keyName)} + )) + } + + ); + } + return ( + + + +
+ {list.map((stat, index) => ( + + {Object.keys(stat).map((keyName, i) => ( + {stat[keyName]} + )) + } + + ))} +
+
+ ); +} +const GraphCard = ({label, list, row, col, cspan, rspan}) => { + const StatsCard = changeCard('white', row, col, cspan, rspan) + const data = [] + for (const [objkey, objval] of Object.entries(list)) { + data.push({"name": objkey, "Total Labels": objval}) + } + return ( + + + + + + + + + + + + + ); +} const ImagesStatsModal = ({ open }) => { const dispatch = useDispatch(); @@ -117,52 +262,14 @@ const ImagesStatsModal = ({ open }) => { } }, [open, stats, imagesStatsLoading, filters, dispatch]); + useEffect(() => { const getStatsPending = imagesStatsLoading.isLoading && imagesStatsLoading.taskId; if (getStatsPending) { dispatch(fetchTask(imagesStatsLoading.taskId)); } }, [imagesStatsLoading, dispatch]); - - - const Stats = []; - /** Parses JSON array */ - function parseArray(value) { - let arr = []; let j = 0; let arraykey = ""; - for (let k = 0; k < value.length; k++) { - let arrayval = ""; - for (const [key, val] of Object.entries(value[k])) { - arraykey = (arraykey == "") ? (mapLabel(key)) : arraykey; - arrayval = (arrayval == "") ? (arrayval + val) : (arrayval + ", " + mapLabel(key) + " " + val); - } - arr[j++] = {"key": arraykey, "value": arrayval}; - } - return arr; - } - /** Converts stats to key/value pairs*/ - function ConvertStats(stats) { - let i = 0; - for (const [key, value] of Object.entries(stats)) { - if (Number.isInteger(value)) { - Stats[i++] = {"key": mapLabel(key), "value": value}; - } - else { - if (Array.isArray(value)) { - Stats[i++] = {"key": mapLabel(key), "value": parseArray(value)} - } else { - let arr = []; let j = 0; - for (const [objkey, objval] of Object.entries(value)) { - arr[j++] = {"key": mapLabel(objkey), "value": objval} - } - Stats[i++] = {"key": mapLabel(key), "value": arr} - } - } - } - } - if (stats != null) { - ConvertStats(stats); - } return (
{imagesStatsLoading.isLoading && ( @@ -175,19 +282,19 @@ const ImagesStatsModal = ({ open }) => { We couldn't find any images that matched this set of filters. )} - {stats && Stats && (Stats.length > 0) && ( - <> - - - {Stats.map((stat, index) => ( - - ))} - - - - + {stats && ( +
+ + {Object.keys(stats).map((keyName, i) => ( + + )) + } + + +
)}
); }; export default ImagesStatsModal; + From 7af74622a872cfeac2cde1caf01a028a383f3ee4 Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Wed, 17 Apr 2024 12:09:43 -0700 Subject: [PATCH 05/10] fixed quotes --- src/features/images/ImagesStatsModal.jsx | 194 ++++++++++++----------- 1 file changed, 102 insertions(+), 92 deletions(-) diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index dfa2e560..9efd9ec0 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -12,28 +12,56 @@ import { SimpleSpinner, SpinnerOverlay } from '../../components/Spinner'; import NoneFoundAlert from '../../components/NoneFoundAlert'; import {SelectedCount} from '../../components/Accordion.jsx'; import { indigo } from '@radix-ui/colors'; +import InfoIcon from '../../components/InfoIcon'; +import Warning from '../../components/Warning'; import { - ComposedChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, + BarChart, + ResponsiveContainer } from 'recharts'; + const StatsDash = styled('div', { border: '1px solid $border', - display: 'grid', - gridTemplateColumns: '1fr 1fr 1fr', - gridTemplateRows: '1fr 1fr 1fr', + display: 'flex', + flexDirection: 'column', background: '$backgroundDark', borderRadius: '5px', padding: '10px', - gap: '10px' + gap: '10px', + minWidth: '660px' }); -const Label = styled('div', { - marginBottom: '20px' -}) + +let reviewedCount = "The total number of images that are edited in some way. Note that this does not include " + +"images which a user invalidated all labels on all objects, but didn't mark it empty. Because multiple users can edit the same image, the sum of all reviewers \"Reviewed Counts\" very likely will not equal the \"Reviewed Count\"." + +let reviewerList = "Each reviewer's \"Reviewed Count\" 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 \"Reviewed Counts\" very likely will not equal the \"Reviewed Count\"." + +let labelList= "The quantities in the \"Label List\" are for locked objects with validated labels only, so they do not include ML predicted labels that need review." + +let multiReviewerCount = "Total number of images with multiple reviewers." +let imagesCount= "Total number of images." + + +const Heading = ({label, content}) => { + const Content = styled('div', { + maxWidth: '300px', + lineHeight: '17px' + }); + return( +
+ +
+ ) +} + let mappings = {}; mappings = {imageCount: "Image Count", reviewedCount: "Reviewed Count", reviewerList: "Reviewer List", notReviewed: "Not Reviewed", labelList: "Label List", @@ -43,7 +71,7 @@ function mapLabel(s) { return (mappings[s] == undefined) ? (s + ":") : mappings[s]; } -function changeCard(color, row, col, cspan, rspan) { +function changeCard(color) { const StatsCard = styled('div', { background: color, padding: '15px', @@ -51,87 +79,56 @@ function changeCard(color, row, col, cspan, rspan) { width: '100%', height: '100%', overflowX: 'scroll', - overflowY: 'scroll', - gridColumn: col + " / span " + cspan, - gridRow: row + " / span " + rspan, + overflowY: 'scroll' }); return StatsCard; } - const StatsItem = ({name, stat}) => { switch (name) { case "imageCount": { return ( - + ); } case "reviewedCount": { return ( + content={reviewedCount}> ); } case "reviewerList": { + stat = [] + if (stat.length === 0) { + break; + } return ( - + ); } case "labelList": { + if (Object.keys(stat).length === 0) { + break; + } return ( - + ); } case "multiReviewerCount": { return ( - + ); } } return ( - - There is nothing to display for the statistic: {name} - + + Error: There is nothing to display for the statistic "{name}" + ); }; -const StyledStatsDisclaimer = styled('div', { - paddingTop: 10, - fontSize: '$3', - color: '$textMedium', -}); - - -const StatsDisclaimer = () => ( - - NOTE: this is a WIP. Be mindful of the following: -
    -
  • - each reviewer's "Reviewed Count" 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 "Reviewed Counts" - very likely will not equal the "Reviewed Count" "reviewed" quantity - each reviewer's "Reviewed Count" 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 "Reviewed Counts" - very likely will not equal the "Reviewed Count" "reviewed" quantity -
  • -
  • - the quantities in the "Label List" are for locked objects with validated{' '} - labels only, so they do not include ML predicted labels that need review - the quantities in the "Label List" are for locked objects with validated{' '} - labels only, so they do not include ML predicted labels that need review -
  • -
-
-); - -const RatioCard = ({label, tnum, bnum, row, col, cspan, rspan}) => { - const StatsCard = changeCard('white', row, col, cspan, rspan) +const RatioCard = ({label, tnum, bnum, content}) => { + const StatsCard = changeCard('white') const Container = styled('div', { display: 'flex', flexDirection: 'row', @@ -139,22 +136,20 @@ const RatioCard = ({label, tnum, bnum, row, col, cspan, rspan}) => { }) const NumerContainer = styled('div', { width: '100%', + marginTop: '15px' }) const LargeNumber = styled(SelectedCount, { fontSize: '30px', width: '100%', - marginLeft: '5px', - }) const SmallNumber = styled('div', { width: '100%', textAlign: 'right', alignSelf: 'flex-end' }) - return ( - + {tnum} @@ -166,10 +161,9 @@ const RatioCard = ({label, tnum, bnum, row, col, cspan, rspan}) => { ); } -const ListCard = ({label, list, row, col, cspan, rspan}) => { - const StatsCard = changeCard('white', row, col, cspan, rspan) +const ListCard = ({label, list, content}) => { + const StatsCard = changeCard('white') const Table = styled('div', { - maxWidth: '100%', display: 'flex', flexDirection: 'column', overflow: 'scroll', @@ -186,6 +180,7 @@ const ListCard = ({label, list, row, col, cspan, rspan}) => { borderBottom: '1px solid $border', textAlign: 'left', minWidth: '200px', + width: '100%', marginRight: '1px', padding: '$2', overflowX: 'scroll' @@ -193,17 +188,17 @@ const ListCard = ({label, list, row, col, cspan, rspan}) => { const Header = () => { let headers = list[0] return( - + {Object.keys(headers).map((keyName, i) => ( {mapLabel(keyName)} )) - } - + } + ); } return ( - +
{list.map((stat, index) => ( @@ -219,28 +214,38 @@ const ListCard = ({label, list, row, col, cspan, rspan}) => { ); } -const GraphCard = ({label, list, row, col, cspan, rspan}) => { - const StatsCard = changeCard('white', row, col, cspan, rspan) +const GraphCard = ({label, list, content}) => { + const StatsCard = changeCard('white') + let width = 0 const data = [] for (const [objkey, objval] of Object.entries(list)) { data.push({"name": objkey, "Total Labels": objval}) + width = Math.max(width, objkey.length) + } + width = (width - 6) * 9 + 60 + data.sort(function(a , b){return b["Total Labels"] - a["Total Labels"]}) + function GetHeight() { + return 250 + ((data.length > 12) ? ((data.length - 12) * 20) : 0); } + return ( - - - - - - - - - + +
+ + + + + + + + + + +
); @@ -269,7 +274,7 @@ const ImagesStatsModal = ({ open }) => { dispatch(fetchTask(imagesStatsLoading.taskId)); } }, [imagesStatsLoading, dispatch]); - + return (
{imagesStatsLoading.isLoading && ( @@ -285,16 +290,21 @@ const ImagesStatsModal = ({ open }) => { {stats && (
- {Object.keys(stats).map((keyName, i) => ( - - )) - } +
+ + + +
+
+ +
+
+ +
-
)}
); }; export default ImagesStatsModal; - From 710a01c06488fb0b4b9cb628d68dab7d973cda53 Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Wed, 17 Apr 2024 12:10:56 -0700 Subject: [PATCH 06/10] removed test statement --- src/features/images/ImagesStatsModal.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index 9efd9ec0..9badbf63 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -98,7 +98,6 @@ const StatsItem = ({name, stat}) => { ); } case "reviewerList": { - stat = [] if (stat.length === 0) { break; } From c744f159e4b3fcdff96e80b8c2db26d3b409a7b0 Mon Sep 17 00:00:00 2001 From: nevoniuk Date: Wed, 17 Apr 2024 22:36:01 -0700 Subject: [PATCH 07/10] reviwed error handling --- src/features/images/ImagesStatsModal.jsx | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index 9badbf63..b43bdbe3 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -98,17 +98,11 @@ const StatsItem = ({name, stat}) => { ); } case "reviewerList": { - if (stat.length === 0) { - break; - } return ( ); } case "labelList": { - if (Object.keys(stat).length === 0) { - break; - } return ( ); @@ -273,7 +267,7 @@ const ImagesStatsModal = ({ open }) => { dispatch(fetchTask(imagesStatsLoading.taskId)); } }, [imagesStatsLoading, dispatch]); - + return (
{imagesStatsLoading.isLoading && ( @@ -289,17 +283,23 @@ const ImagesStatsModal = ({ open }) => { {stats && (
-
- - - -
-
- -
-
- -
+
+ + + +
+ + {Object.keys(stats["labelList"]).length !== 0 && +
+ +
+ } + + {stats["reviewerList"].length !== 0 && +
+ +
+ }
)} From 1876ec317689b1ac326b9a1f3c532aa14e4ba22f Mon Sep 17 00:00:00 2001 From: Nathaniel Rindlaub Date: Thu, 4 Apr 2024 09:24:11 -0700 Subject: [PATCH 08/10] Update deps --- package-lock.json | 864 ++++++++++++++++++++++++++++++---------------- 1 file changed, 569 insertions(+), 295 deletions(-) diff --git a/package-lock.json b/package-lock.json index f289bcc6..36eda194 100644 --- a/package-lock.json +++ b/package-lock.json @@ -244,6 +244,301 @@ "node": ">= 10.14.2" } }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.6.tgz", + "integrity": "sha512-647OSi6xBb8FbwFqX9zsJxOzu685AWtrOUWHfOkbKD+5LOpGORw+GQo0F9rWZnB68rLQyfKUZWJeaD00pGv5fw==", + "peer": true, + "dependencies": { + "@react-native-community/cli-clean": "12.3.6", + "@react-native-community/cli-config": "12.3.6", + "@react-native-community/cli-debugger-ui": "12.3.6", + "@react-native-community/cli-doctor": "12.3.6", + "@react-native-community/cli-hermes": "12.3.6", + "@react-native-community/cli-plugin-metro": "12.3.6", + "@react-native-community/cli-server-api": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "@react-native-community/cli-types": "12.3.6", + "chalk": "^4.1.2", + "commander": "^9.4.1", + "deepmerge": "^4.3.0", + "execa": "^5.0.0", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0", + "graceful-fs": "^4.1.3", + "prompts": "^2.4.2", + "semver": "^7.5.2" + }, + "bin": { + "react-native": "build/bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-clean": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.6.tgz", + "integrity": "sha512-gUU29ep8xM0BbnZjwz9MyID74KKwutq9x5iv4BCr2im6nly4UMf1B1D+V225wR7VcDGzbgWjaezsJShLLhC5ig==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "execa": "^5.0.0" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-config": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.6.tgz", + "integrity": "sha512-JGWSYQ9EAK6m2v0abXwFLEfsqJ1zkhzZ4CV261QZF9MoUNB6h57a274h1MLQR9mG6Tsh38wBUuNfEPUvS1vYew==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "cosmiconfig": "^5.1.0", + "deepmerge": "^4.3.0", + "glob": "^7.1.3", + "joi": "^17.2.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-debugger-ui": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.6.tgz", + "integrity": "sha512-SjUKKsx5FmcK9G6Pb6UBFT0s9JexVStK5WInmANw75Hm7YokVvHEgtprQDz2Uvy5znX5g2ujzrkIU//T15KQzA==", + "peer": true, + "dependencies": { + "serve-static": "^1.13.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-doctor": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.6.tgz", + "integrity": "sha512-fvBDv2lTthfw4WOQKkdTop2PlE9GtfrlNnpjB818MhcdEnPjfQw5YaTUcnNEGsvGomdCs1MVRMgYXXwPSN6OvQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-config": "12.3.6", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-platform-ios": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "command-exists": "^1.2.8", + "deepmerge": "^4.3.0", + "envinfo": "^7.10.0", + "execa": "^5.0.0", + "hermes-profile-transformer": "^0.0.6", + "node-stream-zip": "^1.9.1", + "ora": "^5.4.1", + "semver": "^7.5.2", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1", + "yaml": "^2.2.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-doctor/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "peer": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-hermes": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.6.tgz", + "integrity": "sha512-sNGwfOCl8OAIjWCkwuLpP8NZbuO0dhDI/2W7NeOGDzIBsf4/c4MptTrULWtGIH9okVPLSPX0NnRyGQ+mSwWyuQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "hermes-profile-transformer": "^0.0.6" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-platform-android": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.6.tgz", + "integrity": "sha512-DeDDAB8lHpuGIAPXeeD9Qu2+/wDTFPo99c8uSW49L0hkmZJixzvvvffbGQAYk32H0TmaI7rzvzH+qzu7z3891g==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.2.4", + "glob": "^7.1.3", + "logkitty": "^0.7.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-platform-ios": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.6.tgz", + "integrity": "sha512-3eZ0jMCkKUO58wzPWlvAPRqezVKm9EPZyaPyHbRPWU8qw7JqkvnRlWIaYDGpjCJgVW4k2hKsEursLtYKb188tg==", + "peer": true, + "dependencies": { + "@react-native-community/cli-tools": "12.3.6", + "chalk": "^4.1.2", + "execa": "^5.0.0", + "fast-xml-parser": "^4.0.12", + "glob": "^7.1.3", + "ora": "^5.4.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-plugin-metro": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.6.tgz", + "integrity": "sha512-3jxSBQt4fkS+KtHCPSyB5auIT+KKIrPCv9Dk14FbvOaEh9erUWEm/5PZWmtboW1z7CYeNbFMeXm9fM2xwtVOpg==", + "peer": true + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-server-api": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.6.tgz", + "integrity": "sha512-80NIMzo8b2W+PL0Jd7NjiJW9mgaT8Y8wsIT/lh6mAvYH7mK0ecDJUYUTAAv79Tbo1iCGPAr3T295DlVtS8s4yQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-debugger-ui": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "compression": "^1.7.1", + "connect": "^3.6.5", + "errorhandler": "^1.5.1", + "nocache": "^3.0.1", + "pretty-format": "^26.6.2", + "serve-static": "^1.13.1", + "ws": "^7.5.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-server-api/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-tools": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.6.tgz", + "integrity": "sha512-FPEvZn19UTMMXUp/piwKZSh8cMEfO8G3KDtOwo53O347GTcwNrKjgZGtLSPELBX2gr+YlzEft3CoRv2Qmo83fQ==", + "peer": true, + "dependencies": { + "appdirsjs": "^1.2.4", + "chalk": "^4.1.2", + "find-up": "^5.0.0", + "mime": "^2.4.1", + "node-fetch": "^2.6.0", + "open": "^6.2.0", + "ora": "^5.4.1", + "semver": "^7.5.2", + "shell-quote": "^1.7.3", + "sudo-prompt": "^9.0.0" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli-types": { + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.6.tgz", + "integrity": "sha512-xPqTgcUtZowQ8WKOkI9TLGBwH2bGggOC4d2FFaIRST3gTcjrEeGRNeR5aXCzJFIgItIft8sd7p2oKEdy90+01Q==", + "peer": true, + "dependencies": { + "joi": "^17.2.1" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native-community/cli/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "peer": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native/community-cli-plugin": { + "version": "0.73.17", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.17.tgz", + "integrity": "sha512-F3PXZkcHg+1ARIr6FRQCQiB7ZAA+MQXGmq051metRscoLvgYJwj7dgC8pvgy0kexzUkHu5BNKrZeySzUft3xuQ==", + "peer": true, + "dependencies": { + "@react-native-community/cli-server-api": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "@react-native/dev-middleware": "0.73.8", + "@react-native/metro-babel-transformer": "0.73.15", + "chalk": "^4.0.0", + "execa": "^5.1.1", + "metro": "^0.80.3", + "metro-config": "^0.80.3", + "metro-core": "^0.80.3", + "node-fetch": "^2.2.0", + "readline": "^1.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native/dev-middleware": { + "version": "0.73.8", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.8.tgz", + "integrity": "sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==", + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.73.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^1.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "node-fetch": "^2.2.0", + "open": "^7.0.3", + "serve-static": "^1.13.1", + "temp-dir": "^2.0.0", + "ws": "^6.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@aws-amplify/core/node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@aws-amplify/core/node_modules/@react-native/virtualized-lists": { "version": "0.73.4", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.73.4.tgz", @@ -260,27 +555,128 @@ "react-native": "*" } }, - "node_modules/@aws-amplify/core/node_modules/@types/yargs": { - "version": "15.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", - "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "node_modules/@aws-amplify/core/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "peer": true, "dependencies": { - "@types/yargs-parser": "*" + "sprintf-js": "~1.0.2" } }, - "node_modules/@aws-amplify/core/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/@aws-amplify/core/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/@aws-amplify/core/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "peer": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" }, "engines": { - "node": ">=12" + "node": ">=4" + } + }, + "node_modules/@aws-amplify/core/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@aws-amplify/core/node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@aws-amplify/core/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@aws-amplify/core/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "peer": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@aws-amplify/core/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@aws-amplify/core/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@aws-amplify/core/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "peer": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@aws-amplify/core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/@aws-amplify/core/node_modules/memoize-one": { @@ -289,6 +685,85 @@ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", "peer": true }, + "node_modules/@aws-amplify/core/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@aws-amplify/core/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "peer": true + }, + "node_modules/@aws-amplify/core/node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "peer": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@aws-amplify/core/node_modules/open/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@aws-amplify/core/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@aws-amplify/core/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "peer": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@aws-amplify/core/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "peer": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@aws-amplify/core/node_modules/pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -316,25 +791,19 @@ "node": ">=0.10.0" } }, - "node_modules/@aws-amplify/core/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "peer": true - }, "node_modules/@aws-amplify/core/node_modules/react-native": { - "version": "0.73.4", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.4.tgz", - "integrity": "sha512-VtS+Yr6OOTIuJGDECIYWzNU8QpJjASQYvMtfa/Hvm/2/h5GdB6W9H9TOmh13x07Lj4AOhNMx3XSsz6TdrO4jIg==", + "version": "0.73.6", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.6.tgz", + "integrity": "sha512-oqmZe8D2/VolIzSPZw+oUd6j/bEmeRHwsLn1xLA5wllEYsZ5zNuMsDus235ONOnCRwexqof/J3aztyQswSmiaA==", "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.6.3", - "@react-native-community/cli": "12.3.2", - "@react-native-community/cli-platform-android": "12.3.2", - "@react-native-community/cli-platform-ios": "12.3.2", + "@react-native-community/cli": "12.3.6", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-platform-ios": "12.3.6", "@react-native/assets-registry": "0.73.1", "@react-native/codegen": "0.73.3", - "@react-native/community-cli-plugin": "0.73.16", + "@react-native/community-cli-plugin": "0.73.17", "@react-native/gradle-plugin": "0.73.4", "@react-native/js-polyfills": "0.73.1", "@react-native/normalize-colors": "0.73.2", @@ -394,6 +863,15 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "peer": true }, + "node_modules/@aws-amplify/core/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@aws-amplify/core/node_modules/scheduler": { "version": "0.24.0-canary-efb381bbf-20230505", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", @@ -403,35 +881,51 @@ "loose-envify": "^1.1.0" } }, + "node_modules/@aws-amplify/core/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@aws-amplify/core/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/@aws-amplify/core/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/@aws-amplify/core/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "peer": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">= 4.0.0" } }, - "node_modules/@aws-amplify/core/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/@aws-amplify/core/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "peer": true + }, + "node_modules/@aws-amplify/core/node_modules/yaml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">=10" + "node": ">= 14" } }, "node_modules/@aws-amplify/core/node_modules/yargs": { @@ -846,19 +1340,6 @@ "react-dom": "^16.8 || ^17.0 || ^18.0" } }, - "node_modules/@aws-amplify/ui-react/node_modules/@radix-ui/react-portal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.0.tgz", - "integrity": "sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, "node_modules/@aws-amplify/ui-react/node_modules/@radix-ui/react-roving-focus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.0.tgz", @@ -1318,19 +1799,6 @@ "node": ">=12.0.0" } }, - "node_modules/@aws-sdk/client-lex-runtime-service/node_modules/@aws-crypto/ie11-detection": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz", - "integrity": "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/client-lex-runtime-service/node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@aws-sdk/client-lex-runtime-service/node_modules/@aws-crypto/sha256-browser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz", @@ -3460,19 +3928,6 @@ "node": ">=12.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/ie11-detection": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz", - "integrity": "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@aws-sdk/client-sso/node_modules/@aws-crypto/sha256-browser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz", @@ -6092,17 +6547,6 @@ "node": ">= 12.0.0" } }, - "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/@aws-sdk/is-array-buffer": { - "version": "3.186.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.186.0.tgz", - "integrity": "sha512-fObm+P6mjWYzxoFY4y2STHBmSdgKbIAXez0xope563mox62I8I4hhVPUCaDVydXvDpJv8tbedJMk0meJl22+xA==", - "dependencies": { - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/@aws-sdk/node-config-provider": { "version": "3.186.0", "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.186.0.tgz", @@ -6153,22 +6597,6 @@ "node": ">= 12.0.0" } }, - "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/@aws-sdk/signature-v4": { - "version": "3.186.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.186.0.tgz", - "integrity": "sha512-18i96P5c4suMqwSNhnEOqhq4doqqyjH4fn0YV3F8TkekHPIWP4mtIJ0PWAN4eievqdtcKgD/GqVO6FaJG9texw==", - "dependencies": { - "@aws-sdk/is-array-buffer": "3.186.0", - "@aws-sdk/types": "3.186.0", - "@aws-sdk/util-hex-encoding": "3.186.0", - "@aws-sdk/util-middleware": "3.186.0", - "@aws-sdk/util-uri-escape": "3.186.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/@aws-sdk/types": { "version": "3.186.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.186.0.tgz", @@ -6187,28 +6615,6 @@ "tslib": "^2.3.1" } }, - "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/@aws-sdk/util-hex-encoding": { - "version": "3.186.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.186.0.tgz", - "integrity": "sha512-UL9rdgIZz1E/jpAfaKH8QgUxNK9VP5JPgoR0bSiaefMjnsoBh0x/VVMsfUyziOoJCMLebhJzFowtwrSKEGsxNg==", - "dependencies": { - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/@aws-sdk/util-uri-escape": { - "version": "3.186.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.186.0.tgz", - "integrity": "sha512-imtOrJFpIZAipAg8VmRqYwv1G/x4xzyoxOJ48ZSn1/ZGnKEEnB6n6E9gwYRebi4mlRuMSVeZwCPLq0ey5hReeQ==", - "dependencies": { - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/@aws-sdk/util-hex-encoding": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.6.1.tgz", @@ -10518,23 +10924,6 @@ } } }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", - "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz", @@ -10728,23 +11117,6 @@ } } }, - "node_modules/@radix-ui/react-form/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", - "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-hover-card": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.7.tgz", @@ -14130,15 +14502,6 @@ "node": ">=4" } }, - "node_modules/@react-native-community/cli-config/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/@react-native-community/cli-debugger-ui": { "version": "12.3.2", "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.2.tgz", @@ -14325,15 +14688,6 @@ "node": ">= 10.14.2" } }, - "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { - "version": "15.0.19", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", - "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", - "peer": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@react-native-community/cli-server-api/node_modules/pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -14763,12 +15117,6 @@ "ms": "2.0.0" } }, - "node_modules/@react-native/dev-middleware/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true - }, "node_modules/@react-native/dev-middleware/node_modules/open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", @@ -17629,12 +17977,6 @@ "ms": "2.0.0" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true - }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -18717,20 +19059,36 @@ } }, "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, "hasInstallScript": true, "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", "next-tick": "^1.1.0" }, "engines": { "node": ">=0.10" } }, + "node_modules/es5-ext/node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", @@ -19651,9 +20009,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -20461,17 +20819,11 @@ } }, "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "peer": true }, - "node_modules/is_js": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz", - "integrity": "sha512-8Y5EHSH+TonfUHX2g3pMJljdbGavg55q4jmHzghJCdqYDbdNROC8uw/YFQwIRCRqRJT1EY3pJefz+kglw+o7sg==", - "dev": true - }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -22122,19 +22474,6 @@ "node": ">=4" } }, - "node_modules/metro-config/node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", - "peer": true, - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/metro-config/node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -22161,15 +22500,6 @@ "node": ">=4" } }, - "node_modules/metro-config/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/metro-core": { "version": "0.80.5", "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.5.tgz", @@ -22216,12 +22546,6 @@ "ms": "2.0.0" } }, - "node_modules/metro-file-map/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true - }, "node_modules/metro-minify-terser": { "version": "0.80.5", "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.5.tgz", @@ -23407,55 +23731,6 @@ "node": ">=6" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "peer": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "peer": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "peer": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -24836,13 +25111,12 @@ } }, "node_modules/serverless-finch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/serverless-finch/-/serverless-finch-4.0.3.tgz", - "integrity": "sha512-w27qMmF+jeCthrmzMIeb1ffg6czJVIBVY+5FtKfG0c15dBVDSMnNPJbhdjKTT6q27VwfyjJ92rNuT4JG9BKQUg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/serverless-finch/-/serverless-finch-4.0.4.tgz", + "integrity": "sha512-jpZmtM/ggtccMOA27OkQL0CkCMDfK7xALl4Zl/hBiysyKh562Xya3V7eukbTf4tZOJvBlC6+AGpsxMOaCBn4tQ==", "dev": true, "dependencies": { "@serverless/utils": "^6.0.2", - "is_js": "^0.9.0", "mime": "^3.0.0", "minimatch": "^5.0.1" }, @@ -26292,9 +26566,9 @@ } }, "node_modules/vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "dependencies": { "esbuild": "^0.18.10", From 2630f52e000031ff5c52a5bde00c2be91d8f1c01 Mon Sep 17 00:00:00 2001 From: Nathaniel Rindlaub Date: Thu, 9 May 2024 16:20:57 -0700 Subject: [PATCH 09/10] Code review updates --- src/features/images/ImagesStatsModal.jsx | 328 +++++++++++------------ 1 file changed, 151 insertions(+), 177 deletions(-) diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index b43bdbe3..d392dfc0 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -10,10 +10,9 @@ import { import { selectActiveFilters } from '../filters/filtersSlice.js'; import { SimpleSpinner, SpinnerOverlay } from '../../components/Spinner'; import NoneFoundAlert from '../../components/NoneFoundAlert'; -import {SelectedCount} from '../../components/Accordion.jsx'; +import { SelectedCount } from '../../components/Accordion.jsx'; import { indigo } from '@radix-ui/colors'; import InfoIcon from '../../components/InfoIcon'; -import Warning from '../../components/Warning'; import { Bar, XAxis, @@ -22,7 +21,7 @@ import { Tooltip, Legend, BarChart, - ResponsiveContainer + ResponsiveContainer, } from 'recharts'; const StatsDash = styled('div', { @@ -33,216 +32,184 @@ const StatsDash = styled('div', { borderRadius: '5px', padding: '10px', gap: '10px', - minWidth: '660px' + minWidth: '660px', }); -let reviewedCount = "The total number of images that are edited in some way. Note that this does not include " + -"images which a user invalidated all labels on all objects, but didn't mark it empty. Because multiple users can edit the same image, the sum of all reviewers \"Reviewed Counts\" very likely will not equal the \"Reviewed Count\"." +const reviewedCount = + 'The total number of images that are edited in some way. Note that this does not include ' + + 'images which a user invalidated all labels on all objects, but didn\'t mark it empty. Because multiple users can edit the same image, the sum of all reviewers "Reviewed Counts" very likely will not equal the "Reviewed Count".'; -let reviewerList = "Each reviewer's \"Reviewed Count\" 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 \"Reviewed Counts\" very likely will not equal the \"Reviewed Count\"." +const reviewerList = + 'Each reviewer\'s "Reviewed Count" 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 "Reviewed Counts" very likely will not equal the "Reviewed Count".'; -let labelList= "The quantities in the \"Label List\" are for locked objects with validated labels only, so they do not include ML predicted labels that need review." +const labelList = + 'The quantities in the "Label List" are for locked objects with validated labels only, so they do not include ML predicted labels that need review.'; -let multiReviewerCount = "Total number of images with multiple reviewers." -let imagesCount= "Total number of images." +const multiReviewerCount = 'Total number of images with multiple reviewers.'; +const imagesCount = 'Total number of images. test'; - -const Heading = ({label, content}) => { +const Heading = ({ label, content }) => { const Content = styled('div', { maxWidth: '300px', - lineHeight: '17px' + lineHeight: '17px', }); - return( -
- + return ( +
+
- ) -} + ); +}; -let mappings = {}; -mappings = {imageCount: "Image Count", reviewedCount: "Reviewed Count", - reviewerList: "Reviewer List", notReviewed: "Not Reviewed", labelList: "Label List", - multiReviewerCount: "Multi Reviewer Count", userId: "User", reviewed: "Reviewed"}; +const mappings = { + imageCount: 'Image Count', + reviewedCount: 'Reviewed Count', + reviewerList: 'Reviewer List', + notReviewed: 'Not Reviewed', + labelList: 'Label List', + multiReviewerCount: 'Multi Reviewer Count', + userId: 'User', + reviewed: 'Reviewed', +}; function mapLabel(s) { - return (mappings[s] == undefined) ? (s + ":") : mappings[s]; + return mappings[s] == undefined ? s + ':' : mappings[s]; } -function changeCard(color) { - const StatsCard = styled('div', { - background: color, - padding: '15px', - borderRadius: '5px', - width: '100%', - height: '100%', - overflowX: 'scroll', - overflowY: 'scroll' - }); - return StatsCard; -} +const StatsCard = styled('div', { + background: '$loContrast', + padding: '15px', + borderRadius: '5px', + width: '100%', + height: '100%', + overflowX: 'scroll', + overflowY: 'scroll', +}); -const StatsItem = ({name, stat}) => { - switch (name) { - case "imageCount": { - return ( - - ); - } - case "reviewedCount": { - return ( - - ); - } - case "reviewerList": { - return ( - - ); - } - case "labelList": { - return ( - - ); - } - case "multiReviewerCount": { - return ( - - ); - } - } - return ( - - Error: There is nothing to display for the statistic "{name}" - - ); -}; +const Container = styled('div', { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', +}); +const NumerContainer = styled('div', { + width: '100%', + marginTop: '15px', +}); +const LargeNumber = styled(SelectedCount, { + fontSize: '30px', + width: '100%', +}); +const SmallNumber = styled('div', { + width: '100%', + textAlign: 'right', + alignSelf: 'flex-end', +}); -const RatioCard = ({label, tnum, bnum, content}) => { - const StatsCard = changeCard('white') - const Container = styled('div', { - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between' - }) - const NumerContainer = styled('div', { - width: '100%', - marginTop: '15px' - }) - const LargeNumber = styled(SelectedCount, { - fontSize: '30px', - width: '100%', - }) - const SmallNumber = styled('div', { - width: '100%', - textAlign: 'right', - alignSelf: 'flex-end' - }) +const RatioCard = ({ label, tnum, bnum, content }) => { return ( - + {tnum} - {bnum !== null && - / {bnum}} + {bnum && / {bnum}} ); -} +}; -const ListCard = ({label, list, content}) => { - const StatsCard = changeCard('white') - const Table = styled('div', { - display: 'flex', - flexDirection: 'column', - overflow: 'scroll', - borderRadius: '5px', - border: '1px solid $border', - maxHeight: '102px' - }); - const Row = styled('div', { - display: 'flex', - flexDirection: 'row', - maxHeight: '50px', - }); - const TableCell = styled('div', { - borderBottom: '1px solid $border', - textAlign: 'left', - minWidth: '200px', - width: '100%', - marginRight: '1px', - padding: '$2', - overflowX: 'scroll' - }); +const Table = styled('div', { + display: 'flex', + flexDirection: 'column', + overflow: 'scroll', + borderRadius: '5px', + border: '1px solid $border', + maxHeight: '102px', +}); + +const Row = styled('div', { + display: 'flex', + flexDirection: 'row', + maxHeight: '50px', +}); + +const TableCell = styled('div', { + borderBottom: '1px solid $border', + textAlign: 'left', + minWidth: '200px', + width: '100%', + marginRight: '1px', + padding: '$2', + overflowX: 'scroll', +}); + +const ListCard = ({ label, list, content }) => { const Header = () => { - let headers = list[0] - return( + let headers = list[0]; + return ( {Object.keys(headers).map((keyName, i) => ( - {mapLabel(keyName)} - )) - } + + {mapLabel(keyName)} + + ))} ); - } + }; return ( - -
-
+ +
+
{list.map((stat, index) => ( {Object.keys(stat).map((keyName, i) => ( - {stat[keyName]} - )) - } + {stat[keyName]} + ))} ))} -
+
); -} +}; -const GraphCard = ({label, list, content}) => { - const StatsCard = changeCard('white') - let width = 0 - const data = [] +const GraphCard = ({ label, list, content }) => { + let width = 0; + const data = []; for (const [objkey, objval] of Object.entries(list)) { - data.push({"name": objkey, "Total Labels": objval}) - width = Math.max(width, objkey.length) + data.push({ name: objkey, 'Total Labels': objval }); + width = Math.max(width, objkey.length); } - width = (width - 6) * 9 + 60 - data.sort(function(a , b){return b["Total Labels"] - a["Total Labels"]}) + width = (width - 6) * 9 + 60; + data.sort(function (a, b) { + return b['Total Labels'] - a['Total Labels']; + }); function GetHeight() { - return 250 + ((data.length > 12) ? ((data.length - 12) * 20) : 0); + return 250 + (data.length > 12 ? (data.length - 12) * 20 : 0); } return ( - -
+ +
- + - + - +
- ); -} +}; const ImagesStatsModal = ({ open }) => { const dispatch = useDispatch(); @@ -256,11 +223,9 @@ const ImagesStatsModal = ({ open }) => { const noErrors = !errors || errors.length === 0; if (open && stats === null && !noneFound && !isLoading && noErrors) { dispatch(fetchStats(filters)); - } }, [open, stats, imagesStatsLoading, filters, dispatch]); - useEffect(() => { const getStatsPending = imagesStatsLoading.isLoading && imagesStatsLoading.taskId; if (getStatsPending) { @@ -281,27 +246,36 @@ const ImagesStatsModal = ({ open }) => { )} {stats && ( -
- -
- - - -
- - {Object.keys(stats["labelList"]).length !== 0 && -
- -
- } - - {stats["reviewerList"].length !== 0 && -
- -
- } -
-
+ +
+ + + +
+ {Object.keys(stats['labelList']).length !== 0 && ( +
+ +
+ )} + {stats['reviewerList'].length !== 0 && ( +
+ +
+ )} +
)}
); From 3a8f7a645b0709ba4ad5ed7590b881175bf94766 Mon Sep 17 00:00:00 2001 From: Nathaniel Rindlaub Date: Mon, 13 May 2024 11:37:52 -0700 Subject: [PATCH 10/10] Light polish --- src/components/HydratedModal.jsx | 2 +- src/components/Modal.jsx | 6 +- src/features/images/ImagesStatsModal.jsx | 124 +++++++++++------------ 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/components/HydratedModal.jsx b/src/components/HydratedModal.jsx index 41a7cd6a..0fa0f929 100644 --- a/src/components/HydratedModal.jsx +++ b/src/components/HydratedModal.jsx @@ -36,7 +36,7 @@ const HydratedModal = () => { const modalContentMap = { 'stats-modal': { title: 'Stats', - size: 'md', + size: 'lg', content: , callBackOnClose: () => dispatch(clearStats()), }, diff --git a/src/components/Modal.jsx b/src/components/Modal.jsx index a166cd99..a1ec4ee1 100644 --- a/src/components/Modal.jsx +++ b/src/components/Modal.jsx @@ -7,7 +7,7 @@ import PanelHeader from './PanelHeader'; const ModalBody = styled('div', { padding: '$3', minHeight: '$7', - maxHeight: 'calc(85vh - $7)', + maxHeight: 'calc(95vh - $7)', overflowY: 'scroll', position: 'relative', }); @@ -42,7 +42,7 @@ const StyledContent = styled(DialogPrimitive.Content, { left: '50%', transform: 'translate(-50%, -50%)', width: '90vw', - maxHeight: '85vh', + maxHeight: '95vh', '&:focus': { outline: 'none' }, variants: { @@ -56,7 +56,7 @@ const StyledContent = styled(DialogPrimitive.Content, { }, lg: { width: '95vw', - // height: '95vh', + maxHeight: '95vh', }, }, }, diff --git a/src/features/images/ImagesStatsModal.jsx b/src/features/images/ImagesStatsModal.jsx index d392dfc0..a61e956b 100644 --- a/src/features/images/ImagesStatsModal.jsx +++ b/src/features/images/ImagesStatsModal.jsx @@ -10,7 +10,6 @@ import { import { selectActiveFilters } from '../filters/filtersSlice.js'; import { SimpleSpinner, SpinnerOverlay } from '../../components/Spinner'; import NoneFoundAlert from '../../components/NoneFoundAlert'; -import { SelectedCount } from '../../components/Accordion.jsx'; import { indigo } from '@radix-ui/colors'; import InfoIcon from '../../components/InfoIcon'; import { @@ -25,7 +24,6 @@ import { } from 'recharts'; const StatsDash = styled('div', { - border: '1px solid $border', display: 'flex', flexDirection: 'column', background: '$backgroundDark', @@ -37,51 +35,40 @@ const StatsDash = styled('div', { const reviewedCount = 'The total number of images that are edited in some way. Note that this does not include ' + - 'images which a user invalidated all labels on all objects, but didn\'t mark it empty. Because multiple users can edit the same image, the sum of all reviewers "Reviewed Counts" very likely will not equal the "Reviewed Count".'; + 'images which a user invalidated all labels on all objects, but didn\'t mark it empty. Because multiple users can edit the same image, the sum of all reviewers "Reviewed Counts" very likely will not equal the total number of images "Reviewed".'; + +const notReviewedCount = + 'The total number of images that either have unlocked objects that still require review or have no objects and have not been marked empty.'; const reviewerList = 'Each reviewer\'s "Reviewed Count" 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 "Reviewed Counts" very likely will not equal the "Reviewed Count".'; const labelList = - 'The quantities in the "Label List" are for locked objects with validated labels only, so they do not include ML predicted labels that need review.'; + 'The quantities in this chart are of locked objects with validated labels only, so they do not include ML predicted labels that need review.'; -const multiReviewerCount = 'Total number of images with multiple reviewers.'; -const imagesCount = 'Total number of images. test'; +// const multiReviewerCount = 'Total number of images with multiple reviewers.'; -const Heading = ({ label, content }) => { - const Content = styled('div', { - maxWidth: '300px', - lineHeight: '17px', - }); - return ( -
- -
- ); -}; +const imagesCount = 'Total number of images.'; -const mappings = { - imageCount: 'Image Count', - reviewedCount: 'Reviewed Count', - reviewerList: 'Reviewer List', - notReviewed: 'Not Reviewed', - labelList: 'Label List', - multiReviewerCount: 'Multi Reviewer Count', - userId: 'User', - reviewed: 'Reviewed', -}; +const Content = styled('div', { + maxWidth: '300px', + lineHeight: '17px', +}); -function mapLabel(s) { - return mappings[s] == undefined ? s + ':' : mappings[s]; -} +const Heading = ({ label, content }) => ( +
+ +
+); const StatsCard = styled('div', { background: '$loContrast', padding: '15px', + border: '1px solid $border', borderRadius: '5px', width: '100%', height: '100%', @@ -94,14 +81,19 @@ const Container = styled('div', { flexDirection: 'row', justifyContent: 'space-between', }); + const NumerContainer = styled('div', { width: '100%', marginTop: '15px', }); -const LargeNumber = styled(SelectedCount, { + +const LargeNumber = styled('span', { fontSize: '30px', + fontWeight: '$5', + color: indigo.indigo11, width: '100%', }); + const SmallNumber = styled('div', { width: '100%', textAlign: 'right', @@ -128,7 +120,7 @@ const Table = styled('div', { overflow: 'scroll', borderRadius: '5px', border: '1px solid $border', - maxHeight: '102px', + maxHeight: '300px', }); const Row = styled('div', { @@ -152,9 +144,13 @@ const ListCard = ({ label, list, content }) => { let headers = list[0]; return ( - {Object.keys(headers).map((keyName, i) => ( - - {mapLabel(keyName)} + {Object.keys(headers).map((keyName) => ( + + {keyName == 'userId' + ? 'User' + : keyName === 'reviewedCount' + ? 'Reviewed Count' + : keyName} ))} @@ -180,33 +176,34 @@ const ListCard = ({ label, list, content }) => { const GraphCard = ({ label, list, content }) => { let width = 0; const data = []; + for (const [objkey, objval] of Object.entries(list)) { data.push({ name: objkey, 'Total Labels': objval }); width = Math.max(width, objkey.length); } - width = (width - 6) * 9 + 60; + data.sort(function (a, b) { return b['Total Labels'] - a['Total Labels']; }); - function GetHeight() { - return 250 + (data.length > 12 ? (data.length - 12) * 20 : 0); - } + + width = (width - 6) * 9 + 60; return ( -
- - - - - - - - - - -
+ 12 ? (data.length - 12) * 20 : 0)} + > + + + + + + + + +
); }; @@ -233,6 +230,8 @@ const ImagesStatsModal = ({ open }) => { } }, [imagesStatsLoading, dispatch]); + console.log('stats: ', stats); + return (
{imagesStatsLoading.isLoading && ( @@ -248,28 +247,29 @@ const ImagesStatsModal = ({ open }) => { {stats && (
- +
{Object.keys(stats['labelList']).length !== 0 && (
- +
)} {stats['reviewerList'].length !== 0 && (