More precise data for /support/petAppearances

We move to an actual GQL query, instead of approximating with /api/validPetPoses.

Notable changes are omitting glitched states from UNKNOWN, so we don't prompt Support users to fill in missing states with bad states; and omitting glitched states from standard, so that we _do_ prompt Support users to check UNKNOWN states for new _non-glitched_ versions we can start to use.
This commit is contained in:
Emi Matchu 2021-04-23 15:31:10 -07:00
parent a0107aaf7b
commit 72e4fa0ad0
2 changed files with 97 additions and 85 deletions

View file

@ -10,10 +10,6 @@ import {
} from "@chakra-ui/popover"; } from "@chakra-ui/popover";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import HangerSpinner from "./components/HangerSpinner"; import HangerSpinner from "./components/HangerSpinner";
import {
getValidPoses,
useAllValidPetPoses,
} from "./components/SpeciesColorPicker";
import { ErrorMessage, Heading1 } from "./util"; import { ErrorMessage, Heading1 } from "./util";
import useSupport from "./WardrobePage/support/useSupport"; import useSupport from "./WardrobePage/support/useSupport";
@ -27,16 +23,6 @@ function SupportPetAppearancesPage() {
return ( return (
<> <>
<Heading1 marginBottom=".5em">Support: Pet appearances</Heading1> <Heading1 marginBottom=".5em">Support: Pet appearances</Heading1>
<UnlabeledPetAppearancesList />
</>
);
}
function UnlabeledPetAppearancesList() {
const { loading, error, speciesColorPairs } = useUnlabeledPetAppearances();
return (
<Box>
<Box as="p" marginBottom="2"> <Box as="p" marginBottom="2">
These species/color combinations have some <code>UNKNOWN</code>{" "} These species/color combinations have some <code>UNKNOWN</code>{" "}
appearances that need labeled! Please take a look! appearances that need labeled! Please take a look!
@ -48,19 +34,60 @@ function UnlabeledPetAppearancesList() {
<PopoverArrow /> <PopoverArrow />
<PopoverBody fontSize="sm" textAlign="center"> <PopoverBody fontSize="sm" textAlign="center">
This includes species/color combinations that have at least one{" "} This includes species/color combinations that have at least one{" "}
<code>UNKNOWN</code> pose, and are missing at least one of the non-glitched <code>UNKNOWN</code> pose, and still need a
standard 6 mood/gender-presentation poses. non-glitched version of at least one of the standard 6
mood/gender-presentation poses.
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>
</Popover> </Popover>
</Box> </Box>
{loading && ( <UnlabeledPetAppearancesList />
</>
);
}
function UnlabeledPetAppearancesList() {
const { loading, error, data } = useQuery(gql`
query SupportUnlabeledSpeciesColorPairs {
speciesColorPairsThatNeedSupportLabeling {
id
species {
id
name
}
color {
id
name
}
}
}
`);
if (loading) {
return (
<Flex justify="center"> <Flex justify="center">
<HangerSpinner /> <HangerSpinner />
</Flex> </Flex>
)} );
{error && <ErrorMessage>{error.message}</ErrorMessage>} }
{speciesColorPairs.length > 0 && (
if (error) {
return <ErrorMessage>{error.message}</ErrorMessage>;
}
const speciesColorPairs = [
...data.speciesColorPairsThatNeedSupportLabeling,
].sort((a, b) =>
`${a.species.name} ${a.color.name}`.localeCompare(
`${b.species.name} ${b.color.name}`
)
);
if (speciesColorPairs.length === 0) {
return <>never mind, they're all done! Wow, go team!! 🎉</>;
}
return (
<Wrap> <Wrap>
{speciesColorPairs.map(({ species, color }) => ( {speciesColorPairs.map(({ species, color }) => (
<WrapItem key={`${species.id}-${color.id}`}> <WrapItem key={`${species.id}-${color.id}`}>
@ -68,8 +95,6 @@ function UnlabeledPetAppearancesList() {
</WrapItem> </WrapItem>
))} ))}
</Wrap> </Wrap>
)}
</Box>
); );
} }
@ -91,57 +116,4 @@ function SpeciesColorEditorLink({ species, color }) {
); );
} }
function useUnlabeledPetAppearances() {
const {
loading: loadingValids,
error: errorValids,
valids,
} = useAllValidPetPoses({ headers: { "Cache-Control": "no-cache" } });
const { loading: loadingGQL, error: errorGQL, data } = useQuery(gql`
query SupportUnlabeledPetAppearances {
allColors {
id
name
}
allSpecies {
id
name
}
}
`);
const loading = loadingValids || loadingGQL;
const error = errorValids || errorGQL;
const speciesColorPairs =
valids && data?.allColors && data?.allSpecies
? data?.allSpecies
.map((species) => data.allColors.map((color) => ({ species, color })))
.flat()
.filter(({ species, color }) => {
const poses = getValidPoses(valids, species.id, color.id);
const hasAllStandardPoses =
poses.has("HAPPY_MASC") &&
poses.has("HAPPY_FEM") &&
poses.has("SAD_MASC") &&
poses.has("SAD_FEM") &&
poses.has("SICK_MASC") &&
poses.has("SICK_FEM");
const hasAtLeastOneUnknownPose = poses.has("UNKNOWN");
return !hasAllStandardPoses && hasAtLeastOneUnknownPose;
})
.sort((a, b) =>
`${a.species.name} ${a.color.name}`.localeCompare(
`${b.species.name} ${b.color.name}`
)
)
: [];
return {
loading,
error,
speciesColorPairs,
};
}
export default SupportPetAppearancesPage; export default SupportPetAppearancesPage;

View file

@ -4,6 +4,7 @@ import {
capitalize, capitalize,
getPoseFromPetState, getPoseFromPetState,
getRestrictedZoneIds, getRestrictedZoneIds,
normalizeRow,
oneWeek, oneWeek,
oneDay, oneDay,
oneHour, oneHour,
@ -115,6 +116,11 @@ const typeDefs = gql`
# version here (even if the standard pose picker is still showing outdated # version here (even if the standard pose picker is still showing outdated
# cached canonical poses). # cached canonical poses).
petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]! petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]!
# The SpeciesColorPairs that don't have all 6 standard poses labeled yet,
# and have at least one UNKNOWN pose to label. For Support users, on
# /support/petAppearances.
speciesColorPairsThatNeedSupportLabeling: [SpeciesColorPair!]!
} }
`; `;
@ -387,6 +393,40 @@ const resolvers = {
const petStates = await petStatesForPetTypeLoader.load(petType.id); const petStates = await petStatesForPetTypeLoader.load(petType.id);
return petStates.map((petState) => ({ id: petState.id })); return petStates.map((petState) => ({ id: petState.id }));
}, },
speciesColorPairsThatNeedSupportLabeling: async (
_,
__,
{ db, petTypeLoader }
) => {
const [rows] = await db.query(
`
SELECT * FROM pet_types WHERE
-- Does not have all 6 standard poses
(
SELECT COUNT(DISTINCT mood_id, female)
FROM pet_states
WHERE
pet_type_id = pet_types.id AND mood_id IS NOT NULL AND female IS NOT NULL AND glitched = 0
) < 6
-- And has at least one of the UNKNOWN pose
AND (
SELECT COUNT(*)
FROM pet_states
WHERE
pet_type_id = pet_types.id
AND mood_id IS NULL AND female IS NULL
AND (unconverted = 0 OR unconverted IS NULL)
AND glitched = 0
) >= 1;
`
);
const petTypes = rows.map(normalizeRow);
// Prime the cache, so the resolvers downstream don't re-query for them.
petTypes.forEach((petType) => petTypeLoader.prime(petType.id, petType));
return petTypes.map(({ id }) => ({ id }));
},
}, },
}; };