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:
parent
a0107aaf7b
commit
72e4fa0ad0
2 changed files with 97 additions and 85 deletions
|
@ -10,10 +10,6 @@ import {
|
|||
} from "@chakra-ui/popover";
|
||||
import { Link } from "react-router-dom";
|
||||
import HangerSpinner from "./components/HangerSpinner";
|
||||
import {
|
||||
getValidPoses,
|
||||
useAllValidPetPoses,
|
||||
} from "./components/SpeciesColorPicker";
|
||||
import { ErrorMessage, Heading1 } from "./util";
|
||||
import useSupport from "./WardrobePage/support/useSupport";
|
||||
|
||||
|
@ -27,16 +23,6 @@ function SupportPetAppearancesPage() {
|
|||
return (
|
||||
<>
|
||||
<Heading1 marginBottom=".5em">Support: Pet appearances</Heading1>
|
||||
<UnlabeledPetAppearancesList />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function UnlabeledPetAppearancesList() {
|
||||
const { loading, error, speciesColorPairs } = useUnlabeledPetAppearances();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box as="p" marginBottom="2">
|
||||
These species/color combinations have some <code>UNKNOWN</code>{" "}
|
||||
appearances that need labeled! Please take a look!
|
||||
|
@ -48,19 +34,60 @@ function UnlabeledPetAppearancesList() {
|
|||
<PopoverArrow />
|
||||
<PopoverBody fontSize="sm" textAlign="center">
|
||||
This includes species/color combinations that have at least one{" "}
|
||||
<code>UNKNOWN</code> pose, and are missing at least one of the
|
||||
standard 6 mood/gender-presentation poses.
|
||||
non-glitched <code>UNKNOWN</code> pose, and still need a
|
||||
non-glitched version of at least one of the standard 6
|
||||
mood/gender-presentation poses.
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</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">
|
||||
<HangerSpinner />
|
||||
</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>
|
||||
{speciesColorPairs.map(({ species, color }) => (
|
||||
<WrapItem key={`${species.id}-${color.id}`}>
|
||||
|
@ -68,8 +95,6 @@ function UnlabeledPetAppearancesList() {
|
|||
</WrapItem>
|
||||
))}
|
||||
</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;
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
capitalize,
|
||||
getPoseFromPetState,
|
||||
getRestrictedZoneIds,
|
||||
normalizeRow,
|
||||
oneWeek,
|
||||
oneDay,
|
||||
oneHour,
|
||||
|
@ -115,6 +116,11 @@ const typeDefs = gql`
|
|||
# version here (even if the standard pose picker is still showing outdated
|
||||
# cached canonical poses).
|
||||
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);
|
||||
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 }));
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue