Fixed all React warnings

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2023-01-25 13:12:46 -08:00
parent d45600f6a7
commit df764ad342
3 changed files with 101 additions and 103 deletions

View File

@ -148,8 +148,6 @@ div {
.Face .Image {
position: relative;
box-sizing: border-box;
/*width: 8rem;
height: 8rem;*/
display: flex;
justify-content: center;
}
@ -173,11 +171,18 @@ div {
align-items: flex-start;
}
.Image img {
object-fit: cover; /* contain */
width: 100%;
height: 100%;
min-width: 8rem;
min-height: 8rem;
}
.Cluster .Faces {
display: grid;
gap: 0.25rem;
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
width: 100%;
height: 100%;
flex-wrap: wrap;
}

View File

@ -10,7 +10,6 @@ import {
} from "react-router-dom";
import { VirtuosoGrid } from 'react-virtuoso'
import moment from 'moment';
//import equal from "fast-deep-equal";
import './App.css';
const base = process.env.PUBLIC_URL; /* /identities -- set in .env */
@ -130,6 +129,7 @@ const Photo = ({ photoId, onFaceClick }: any) => {
return (<div className="PhotoPanel">
<div className="Image" ref={ref}>
<img
alt={image.filename}
src={`${base}/../${image.path}thumbs/scaled/${image.filename}`.replace(/ /g, '%20')}
style={{
objectFit: 'contain',
@ -185,26 +185,20 @@ const onFaceMouseLeave = (e: any, face: FaceData) => {
e.preventDefault();
};
const Face = ({ face, onFaceClick, title, ...rest }: any) => {
const Face = ({ face, onFaceClick, title, isSelected }: any) => {
const faceId = face.faceId;
const idPath = String(faceId % 100).padStart(2, '0');
const img = faceId === -1
? <div className='UnknownFace'>?</div>
: <img src={`${base}/../faces/${idPath}/${faceId}.jpg`}
style={{
objectFit: 'cover',//'contain',
width: '100%',
height: '100%'
}} />;
: <img alt={faceId} src={`${base}/../faces/${idPath}/${faceId}.jpg`}/>;
return (
<div
data-face-id={face.faceId}
data-identity-id={face.identityId}
{...rest}
onClick={(e) => { onFaceClick(e, face) }}
onMouseEnter={(e) => { onFaceMouseEnter(e, face) }}
onMouseLeave={(e) => { onFaceMouseLeave(e, face) }}
className='Face'>
className={`Face ${isSelected ? 'Selected' : ''}`}>
<div className='Image'>
{ img }
<div className='Title'>{title}</div>
@ -215,17 +209,21 @@ const Face = ({ face, onFaceClick, title, ...rest }: any) => {
type ClusterProps = {
identity: IdentityData,
setImage(image: number): void,
setSelected(selected: number[]): void,
setIdentity(identity: IdentityData | undefined): void
setIdentity(identity: IdentityData | undefined): void,
identities: IdentityData[],
setIdentities(identiteis: IdentityData[]): void
setIdentities(identiteis: IdentityData[]): void,
setImage(image: number): void,
selected: number[],
setSelected(selected: number[]): void,
};
const Cluster = ({
identity, setIdentity,
identities, setIdentities,
setImage, setSelected }: ClusterProps) => {
selected,
setSelected,
setImage,
}: ClusterProps) => {
const lastNameChanged = (e: any) => {
setIdentity({...identity, lastName: e.currentTarget.value });
@ -240,23 +238,15 @@ const Cluster = ({
setIdentity({...identity, displayName: e.currentTarget.value });
};
const faceClicked = async (e: any, face: FaceData) => {
if (!identity) {
return;
}
const faceClicked = useCallback((e: any, face: FaceData) => {
const el = e.currentTarget;
/* Control -- select / deselect single item */
if (e.ctrlKey) {
const cluster = document.querySelector('.Cluster');
el.classList.toggle('Selected');
if (!cluster) {
return;
}
const selected = [...cluster.querySelectorAll('.Selected')]
.map((face: any) => face.getAttribute('data-face-id'));
setSelected(selected);
const tmp = [...document.querySelectorAll('.Cluster .Selected')]
.map((face: any) => +face.getAttribute('data-face-id'));
setSelected(tmp);
return;
}
@ -269,7 +259,7 @@ const Cluster = ({
e.stopPropagation();
e.preventDefault();
setImage(face.photoId);
};
}, [setSelected, setImage]);
const deleteIdentity = async () => {
try {
@ -278,7 +268,7 @@ const Cluster = ({
method: 'DELETE',
headers: { 'Content-Type': 'application/json' }
});
const updated = await res.json();
await res.json();
const index = identities
.findIndex((item: IdentityData) =>
item.identityId === identity.identityId);
@ -298,7 +288,7 @@ const Cluster = ({
'id', 'displayName', 'firstName', 'lastName', 'middleName'];
const filtered: any = Object.assign({}, identity);
for (let key in filtered) {
if (validFields.indexOf(key) == -1) {
if (validFields.indexOf(key) === -1) {
delete filtered[key]
}
}
@ -308,7 +298,7 @@ const Cluster = ({
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(filtered)
});
const updated = await res.json();
await res.json();
setIdentity({ ...identity });
} catch (error) {
console.error(error);
@ -321,7 +311,7 @@ const Cluster = ({
'id', 'displayName', 'firstName', 'lastName', 'middleName'];
const filtered: any = Object.assign({}, identity);
for (let key in filtered) {
if (validFields.indexOf(key) == -1) {
if (validFields.indexOf(key) === -1) {
delete filtered[key]
}
}
@ -339,7 +329,6 @@ const Cluster = ({
}
};
if (identity === undefined) {
return (<div className='Cluster'>
Select identity to load.
@ -375,10 +364,13 @@ const Cluster = ({
<div>Faces: {identity.relatedFaces.length}</div>
<VirtuosoGrid
data={identity.relatedFaces}
listClassName='Faces'
itemContent={(index, face) => (
itemContent={(_index, face) => (
<Face
isSelected={
selected.findIndex(
(x: number) => x === face.faceId) !== -1
}
face={face}
onFaceClick={faceClicked}
title={face.distance} />
@ -391,10 +383,6 @@ const Cluster = ({
type FaceData = {
faceId: number,
photoId: number,
/* lastName: string,
firstName: string,
middleName: string,
displayName: string,*/
identity: IdentityData,
identityId: number,
distance: number,
@ -402,7 +390,7 @@ type FaceData = {
top: number
right: number,
bottom: number,
left: number,
left: number
};
type IdentityData = {
@ -423,8 +411,7 @@ interface IdentitiesProps {
};
const Identities = ({ identities, onFaceClick } : IdentitiesProps) => {
const identitiesJSX = useMemo(() => {
return identities.map((identity) => {
const identitiesJSX = identities.map((identity) => {
const face = identity.relatedFaces[0];
return (
<div
@ -441,7 +428,6 @@ const Identities = ({ identities, onFaceClick } : IdentitiesProps) => {
</div>
);
});
}, [ identities, onFaceClick ]);
return (
<div className='Identities'>
@ -470,6 +456,19 @@ const App = () => {
);
const [selected, setSelected] = useState<number[]>([]);
/* If 'selected' changes, clear any selected face which is not in the
* selected array. */
useEffect(() => {
[...document.querySelectorAll('.Cluster .Selected')].forEach(el => {
const faceId = el.getAttribute('data-face-id');
if (faceId) {
if (selected.findIndex(item => item === +faceId) === -1) {
el.classList.remove('Selected');
}
}
});
}, [selected]);
const loadIdentity = async (identityId: number) => {
try {
const res = await window.fetch(`${base}/api/v1/identities/${identityId}`);
@ -569,7 +568,7 @@ const App = () => {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' }
});
const updated = await res.json();
await res.json();
const index = identities
.findIndex((item: IdentityData) =>
item.identityId === identity.identityId);
@ -597,6 +596,7 @@ const App = () => {
const data = await res.json();
removeFacesFromIdentities(data.faces);
deselectAll();
} catch (error) {
console.error(error);
}
@ -617,6 +617,7 @@ const App = () => {
const data = await res.json();
removeFacesFromIdentities(data.faces);
deselectAll();
} catch (error) {
console.error(error);
}
@ -647,20 +648,17 @@ const App = () => {
faces: selected
})
});
const data = await res.json();
await res.json();
removeFacesFromIdentities(selected);
deselectAll();
} catch (error) {
console.error(error);
}
};
const deselectAll = () => {
const cluster = document.querySelector('.Cluster');
if (!cluster) {
return;
}
[...cluster.querySelectorAll('.Selected')].forEach(item => {
item.classList.remove('Selected')
[...document.querySelectorAll('.Cluster .Selected')].forEach(item => {
item.classList.remove('Selected');
});
setSelected([]);
};
@ -681,24 +679,21 @@ const App = () => {
};
const identitiesOnFaceClick = (e: any, face: FaceData) => {
const identitiesEl = document.querySelector('.Identities');
if (!identitiesEl) {
return;
}
const identityId = face.identityId;
const el = e.currentTarget;
/* Control -- select / deselect single item */
if (e.ctrlKey) {
[...identitiesEl.querySelectorAll('.Selected')].forEach(item => {
let set = !el.classList.contains('Selected');
[...document.querySelectorAll('.Identities .Selected')].forEach(item => {
item.classList.remove('Selected')
});
el.classList.toggle('Selected');
const selected = [...identitiesEl.querySelectorAll('.Selected')]
.map((face: any) => face.getAttribute('data-identity-id'));
setSelectedIdentities(selected);
if (set) {
el.classList.add('Selected');
}
const tmp = [...document.querySelectorAll('.Identities .Selected')]
.map((face: any) => +face.getAttribute('data-identity-id'));
setSelectedIdentities(tmp);
return;
}
@ -711,6 +706,11 @@ const App = () => {
e.stopPropagation();
e.preventDefault();
[...document.querySelectorAll('.Cluster .Faces img')]
.forEach((img: any) => {
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
});
loadIdentity(identityId);
}
@ -728,7 +728,8 @@ const App = () => {
identities,
setIdentities,
setImage,
setSelected
selected,
setSelected,
}} /> }
{!loading && identity === undefined && <div className="Cluster">
Select identity to edit
@ -766,7 +767,8 @@ const App = () => {
<PanelResizeHandle className="Resizer" />
<Panel defaultSize={8.5} minSize={8.5} className="IdentitiesList">
{ !loading && <Identities
{... { onFaceClick: identitiesOnFaceClick, identities }}/> }
{... { onFaceClick: identitiesOnFaceClick, identities }}/>
}
</Panel>
</PanelGroup>
</div>

View File

@ -170,19 +170,6 @@ router.delete('/:id', async (req, res) => {
return res.status(200).send({});
});
const writeIdentityDescriptors = async (identity) => {
await photoDB.sequelize.query(
'UPDATE identities ' +
'SET descriptors=:descriptors' +
'WHERE id=:identityId', {
replacements: identity
}
);
};
/* Given a faceId, find the closest defined identity and return
* it as a guess -- does not modify the DB */
router.get("/faces/guess/:faceId", async (req, res) => {
@ -642,7 +629,10 @@ router.get("/:id?", async (req, res) => {
/* If id was not set, only return a single face */
if (id === undefined) {
if (identity.faceId !== -1 && identity.faceId !== null) {
where = 'faceId=:faceId';
/* Return the identity faceId, and make sure the face
* is associated with that id -- they can get out of sync
* when faces are added/removed from an identity */
where = 'faceId=:faceId AND identityId=:identityId';
} else {
where = 'identityId=:identityId';
limit = 'LIMIT 1';
@ -650,6 +640,7 @@ router.get("/:id?", async (req, res) => {
} else {
where = 'identityId=:identityId'
}
identity.relatedFaces = await photoDB.sequelize.query(
'SELECT id as faceId,identityId,photoId,distance ' +
'FROM faces ' +