Identities are loading; starting to think through workflow
Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
parent
1ed1b1d1ea
commit
e8de846ed0
@ -26,20 +26,30 @@ div {
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
||||
.Identity {
|
||||
.Face {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
margin: 0.125rem;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.Identity:hover {
|
||||
border: 1px solid yellow;
|
||||
.Face:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Identity .Title {
|
||||
.Face .Image {
|
||||
border: 0.25rem solid transparent;
|
||||
}
|
||||
|
||||
.Face:hover .Image {
|
||||
border: 0.25rem solid yellow;
|
||||
}
|
||||
|
||||
.Face.Selected .Image {
|
||||
border: 0.25rem solid blue;
|
||||
}
|
||||
|
||||
.Face .Title {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -50,7 +60,9 @@ div {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.Identity .Face {
|
||||
.Face .Image {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 8rem;
|
||||
height: 8rem;
|
||||
background-size: contain !important;
|
||||
@ -58,16 +70,18 @@ div {
|
||||
background-position: 50% 50% !important;;
|
||||
}
|
||||
|
||||
|
||||
.Cluster {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: scroll;
|
||||
flex-grow: 1;
|
||||
border: 1px solid red;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.Cluster .Face.Selected {
|
||||
/* filter: grayscale(100%); */
|
||||
}
|
||||
|
||||
.Cluster .Info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -3,6 +3,21 @@ import React, { useState, useMemo, useEffect } from 'react';
|
||||
import { useApi } from './useApi';
|
||||
import './App.css';
|
||||
|
||||
const Face = ({ faceId, onClick, title }: any) => {
|
||||
const idPath = String(faceId % 100).padStart(2, '0');
|
||||
return (
|
||||
<div onClick={(e) => { onClick(e, faceId) }}
|
||||
className='Face'>
|
||||
<div className='Image'
|
||||
style={{
|
||||
background: `url("/faces/${idPath}/${faceId}.jpg")`,
|
||||
}}>
|
||||
<div className='Title'>{title}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type ClusterProps = {
|
||||
id: number
|
||||
};
|
||||
@ -23,48 +38,113 @@ const Cluster = ({ id }: ClusterProps) => {
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
|
||||
|
||||
const relatedFacesJSX = useMemo(() => {
|
||||
const faceClicked = (e: any, id: any) => {
|
||||
if (!identity) {
|
||||
return;
|
||||
}
|
||||
const el = e.currentTarget;
|
||||
const face = identity.relatedFaces.find(item => item.faceId === id);
|
||||
el.classList.toggle('Selected');
|
||||
console.log(face);
|
||||
}
|
||||
if (identity === undefined) {
|
||||
return <></>;
|
||||
}
|
||||
return identity.relatedFaces.map((face) => {
|
||||
const idPath = String(face.faceId % 100).padStart(2, '0');
|
||||
return (
|
||||
<div key={face.faceId}
|
||||
className='Identity'>
|
||||
<div className='Title'>
|
||||
{face.distance}
|
||||
</div>
|
||||
<div className='Face'
|
||||
style={{
|
||||
background: `url("/faces/${idPath}/${face.faceId}.jpg")`,
|
||||
}} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return identity.relatedFaces.map(face =>
|
||||
<Face key={face.faceId}
|
||||
faceId={face.faceId}
|
||||
onClick={faceClicked}
|
||||
title={face.distance}/>
|
||||
);
|
||||
}, [identity]);
|
||||
|
||||
const lastNameChanged = (e: any) => {
|
||||
setIdentity(Object.assign(
|
||||
{},
|
||||
identity, {
|
||||
lastName: e.currentTarget.value
|
||||
}
|
||||
));
|
||||
};
|
||||
const firstNameChanged = (e: any) => {
|
||||
setIdentity(Object.assign(
|
||||
{},
|
||||
identity, {
|
||||
firstName: e.currentTarget.value
|
||||
}
|
||||
));
|
||||
};
|
||||
const middleNameChanged = (e: any) => {
|
||||
setIdentity(Object.assign(
|
||||
{},
|
||||
identity, {
|
||||
middleName: e.currentTarget.value
|
||||
}
|
||||
));
|
||||
};
|
||||
const displayNameChanged = (e: any) => {
|
||||
setIdentity(Object.assign(
|
||||
{},
|
||||
identity, {
|
||||
displayName: e.currentTarget.value
|
||||
}
|
||||
));
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (<div className='Cluster'>
|
||||
{loading && `Loading ${id}...`}
|
||||
</div>);
|
||||
}
|
||||
|
||||
if (identity === undefined) {
|
||||
return (<div className='Cluster'>
|
||||
Select identity to load.
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='Cluster'>
|
||||
{ loading && `Loading ${id}`}
|
||||
{ identity !== undefined && <div className="Info">
|
||||
<div>{identity.lastName}</div>
|
||||
<div>{identity.firstName}</div>
|
||||
<div>{identity.middleName}</div>
|
||||
<div>{identity.displayName}</div>
|
||||
<div className="Info">
|
||||
<form>
|
||||
<div><label>Last name:<input type="text"
|
||||
value={identity.lastName}
|
||||
onChange={lastNameChanged}/>
|
||||
</label></div>
|
||||
<div><label>First name:<input type="text"
|
||||
value={identity.firstName}
|
||||
onChange={firstNameChanged} />
|
||||
</label></div>
|
||||
<div><label>Middle name:<input type="text"
|
||||
value={identity.middleName}
|
||||
onChange={middleNameChanged} />
|
||||
</label></div>
|
||||
<div><label>Display name:<input type="text"
|
||||
value={identity.displayName}
|
||||
onChange={displayNameChanged} />
|
||||
</label></div>
|
||||
<div>Faces: {identity.relatedFaces.length}</div>
|
||||
</div> }
|
||||
{ identity !== undefined && <div className="Faces">
|
||||
</form>
|
||||
</div>
|
||||
<div className="Faces">
|
||||
{ relatedFacesJSX }
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type Face = {
|
||||
distance: number,
|
||||
type FaceData = {
|
||||
faceId: number,
|
||||
photoId: number
|
||||
lastName: string,
|
||||
firstName: string,
|
||||
middleName: string,
|
||||
displayName: string,
|
||||
identityId: number,
|
||||
distance: number,
|
||||
descriptors: any[]
|
||||
};
|
||||
|
||||
type Identity = {
|
||||
@ -74,7 +154,7 @@ type Identity = {
|
||||
descriptors: number[],
|
||||
id: number
|
||||
displayName: string,
|
||||
relatedFaces: Face[]
|
||||
relatedFaces: FaceData[]
|
||||
};
|
||||
|
||||
interface IdentitiesProps {
|
||||
@ -83,8 +163,6 @@ interface IdentitiesProps {
|
||||
};
|
||||
|
||||
const Identities = ({ identities, setIdentity } : IdentitiesProps) => {
|
||||
|
||||
|
||||
const identitiesJSX = useMemo(() => {
|
||||
const loadIdentity = (id: number): void => {
|
||||
if (setIdentity) {
|
||||
@ -93,19 +171,11 @@ const Identities = ({ identities, setIdentity } : IdentitiesProps) => {
|
||||
};
|
||||
return identities.map((identity) => {
|
||||
const face = identity.relatedFaces[0];
|
||||
const idPath = String(face.faceId % 100).padStart(2, '0');
|
||||
return (
|
||||
<div key={face.faceId}
|
||||
<Face key={face.faceId}
|
||||
faceId={face.faceId}
|
||||
onClick={() => loadIdentity(identity.id)}
|
||||
className='Identity'>
|
||||
<div className='Title'>
|
||||
{identity.displayName}
|
||||
</div>
|
||||
<div className='Face'
|
||||
style={{
|
||||
background: `url("/faces/${idPath}/${face.faceId}.jpg")`,
|
||||
}}/>
|
||||
</div>
|
||||
title={identity.displayName}/>
|
||||
);
|
||||
});
|
||||
}, [ setIdentity, identities ]);
|
||||
@ -133,7 +203,7 @@ const App = () => {
|
||||
return (
|
||||
<div className="App">
|
||||
<div className="Worksheet">
|
||||
{ loading && <div>Loading...</div> }
|
||||
{ loading && <div style={{margin:'1rem'}}>Loading...</div> }
|
||||
{ !loading && identity !== 0 && <Cluster id={identity} />}
|
||||
{ !loading && identity === 0 && <div className="Cluster">
|
||||
Select identity to edit
|
||||
|
@ -8,31 +8,30 @@ type UseApi = {
|
||||
};
|
||||
|
||||
const useApi = (_url: string, _options?: {}) : UseApi => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [data, setData] = useState(undefined);
|
||||
const [error, setError] = useState<any>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (_url === '' || loading) {
|
||||
if (_url === '') {
|
||||
return;
|
||||
}
|
||||
const fetchApi = async () => {
|
||||
console.log(`Fetching ${_url}...`);
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await window.fetch(_url, _options);
|
||||
const data = await res.json();
|
||||
setData(data);
|
||||
setLoading(false);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
setError(e)
|
||||
} finally {
|
||||
setLoading(false);
|
||||
};
|
||||
};
|
||||
|
||||
fetchApi();
|
||||
}, [_url, _options, loading]);
|
||||
}, [_url, _options]);
|
||||
|
||||
return { loading, data, error };
|
||||
};
|
||||
|
7
reset-identities.sh
Normal file
7
reset-identities.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
. .env
|
||||
cat << EOF | ./query.sh
|
||||
update faces set identityId=NULL where identityId is not null;
|
||||
delete from identities where id>0;
|
||||
delete from sqlite_sequence where name='identities';
|
||||
EOF
|
Loading…
x
Reference in New Issue
Block a user