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";
|
} 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,28 +34,67 @@ 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 />
|
||||||
<Flex justify="center">
|
</>
|
||||||
<HangerSpinner />
|
);
|
||||||
</Flex>
|
}
|
||||||
)}
|
|
||||||
{error && <ErrorMessage>{error.message}</ErrorMessage>}
|
function UnlabeledPetAppearancesList() {
|
||||||
{speciesColorPairs.length > 0 && (
|
const { loading, error, data } = useQuery(gql`
|
||||||
<Wrap>
|
query SupportUnlabeledSpeciesColorPairs {
|
||||||
{speciesColorPairs.map(({ species, color }) => (
|
speciesColorPairsThatNeedSupportLabeling {
|
||||||
<WrapItem key={`${species.id}-${color.id}`}>
|
id
|
||||||
<SpeciesColorEditorLink species={species} color={color} />
|
species {
|
||||||
</WrapItem>
|
id
|
||||||
))}
|
name
|
||||||
</Wrap>
|
}
|
||||||
)}
|
color {
|
||||||
</Box>
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Flex justify="center">
|
||||||
|
<HangerSpinner />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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}`}>
|
||||||
|
<SpeciesColorEditorLink species={species} color={color} />
|
||||||
|
</WrapItem>
|
||||||
|
))}
|
||||||
|
</Wrap>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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 }));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue