I refactor the hide-badge thing into 3 "trade matching modes". Then, the logic for whether to hide specific badges moves into the component, and we use that same flag to decide whether to show the big word "match"!
Boom, cute owns/wants badges on "Latest items", and the item search page, and trade matches!
I'm gonna add some additional flair to the trade match case, too!
This has been bugging me for a while lol, the background was leaking out of the corners!
I had applied the styles to the `InputGroup` because I didn't realize how Chakra implements this… I had assumed that the left/right elements wouldn't also get the background.
But it turns out, `InputGroup` uses `position: absolute` stuff, and uses padding to create visual space in the `Input` below them! So, this works perfect!
Copied styles from the similar layout in the bulk converter tool! The status will flush to the right of the field header on desktop, and move below the input on mobile.
I'm gonna try and see about getting Fastly to redirect these internally, so we can get all the benefits of CDN-caching the generated image, without forcing the user through another round-trip!
This was a known oversight, that I've finally fixed because I realized this subquery probably would be just fine lol!
Now, instead of removing rows with _all_ species modeled, we remove rows with all species _for that color_ modeled.
This leaves the rest of the modeling list unchanged, but removed 10 Maraquan items that were done modeling but still on the list:
- Dyeworks Coral: Maraquan White Beaded Gown
- Dyeworks Green: Maraquan White Beaded Gown
- Dyeworks Lavender: Maraquan White Beaded Gown
- Dyeworks Purple: Maraquan Wig with Negg Accessory
- Dyeworks Lavender: Maraquan Sea Blue Gown
- Dyeworks Pink: Maraquan Sea Blue Gown
- Dyeworks Silver: Maraquan Sea Blue Gown
- Maraquan White Lace Gown
- Underwater Maraquan Markings
(I also went in the database and marked the "Maraquan Ocean Blue Contacts" with the `modeling_status_hint = "done"`, because it's not compatible with Lutari.)
I was accidentally serving images _without_ `updatedAt` with the long-term cache headers, but only in prod, not in dev
I think this is probably because I made a mistake in my Vercel route config, by including an `$updatedAt` parameter that doesn't actually exist in this case.
I'm guessing the Vercel dev server has different behavior for my mistake than the prod server. I'm guessing the dev server makes it an empty string, and the prod server makes it the literal string `$updatedAt`. Oops!
I hope this fixes it!
Oops, right, I forgot for a while that GraphQL fields have a special syntax for docstrings, and it's not just comments! This will help stuff show up in our GraphQL Playground API docs correctly 🥰
Someone asked to use the DTI API for a small client-side project, so I'm making this change to support it!
As explained in the comment, I think this should be safe regarding CSRF attacks. But it _does_ increase the risk that someday we change something elsewhere that creates a problem, like using cookies to authorize something. So, let's remember to be careful! (as I would hope we would be when adding another auth mechanism!)
I'm not sure which image url is better to return from stuff like this, and I don't actually have a use case for it anymore, so let's just clear it out until we need something like it!
Gonna have the /outfit-urls page start returning these instead, for feature parity with before
I might change the strategy on this at some point, like have it get `updatedAt` and redirect instead of generating the image. But this is simpler for now (and the Vercel cache doesn't seem to be as aggressive as I want anyway), and I can change it later!
Oops, we get a _lot_ of outfit image requests, and it's pushing the limits of our free Honeycomb plan! But I don't really need all that much detail, because there's so many.
So, we here apply sampling! `api/outfitImage` is getting a 1/10 rate, and for GraphQL, `ApiOutfitImage` is getting 1/10, and `SearchPanel` is getting 1/5.
I had to add a `addTraceContext` call, to give all the child events awareness of what operation they're being called in, too!
I haven't actually tested that this is working-working, just that the endpoints still return good data. We'll see how it shakes out in prod!
But I did add `console.log(sampleRate, shouldSample, data);` to the `samplerHook` briefly, to see the data flow through, and I reloaded a `SearchPanel` request a few times and observed a plausibly 20% success rate.
Oops, I wasn't requesting `bodyId` for item layers, so the check for `layer.bodyId !== "0"` was always true—because it was always `undefined`, even when it should have been `"0"`.
This wasn't an issue on the client, because the client _does_ request `bodyId` for caching item appearances between pets of the same body, and I didn't realize that it needs to be part of this fragment too!
Mm right, when we first render the output, `imageUrl` is `undefined`, so the output textbox renders with `value={undefined}`, which is an "uncontrolled" component that the DOM is free to change.
In practice, this isn't an issue because the textbox has `isReadOnly`, so the user can't _actually_ change it. But it's still a good idea for consistency and clarity to use an empty string instead of `undefined`, and it removes warning spam from my console!
Oops, previously the MajorErrorMessage was willing to shrink the width of the cute Grundo Programmer icon, to allow error messages with long words to avoid word breaks.
Here, we switch `1fr` for `minmax(0, 1fr)`, which allows the text zone to get smaller. (`1fr` is short for `minmax(auto, 1fr)`, which isn't capable of shrinking smaller than the natural value.)
Now, the error text is more willing to shrink by word-wrapping, than the image is by shrinking the image. Success!
Oops, my cute API idea for `speciesPickerProps` breaks `React.memo`, of course!
We could fix this by having the caller memoize the `speciesPickerProps` object, but that's too unusual and error-prone. We could also fix this by writing a custom function for `React.memo` to determine whether props match, but that seems like overkill when there's only one actual prop we're using here in practice.
So yeah, I've updated `SpeciesColorPicker` to just accept `speciesTestId` and `colorTestId` props instead!
Note that actually this component _is_ still re-rendering too often, because of a Chakra bug I just discovered and reported! So this change won't immediately improve performance, but it should stop re-rendering too often once we _also_ upgrade Chakra after this bug is fixed. https://github.com/chakra-ui/chakra-ui/issues/4080
Oops, right, I meant to use the new `impress-outfit-images.openneo.net` host for this! It works just fine from `impress-2020.openneo.net` as the backing source right now, but I want these semi-permanent URLs to be a bit more decoupled.
This is mostly for decoupling's sake: I want pretty outfit URLs that aren't dependent on the `/api/outfitImage` path structure, so that we can serve them as ~permanent pretty URLs that don't actually indicate where or how the image is stored.
This reverts commit a0121f09ea.
I didn't realize that VERCEL_URL wouldn't use the canonical URL. And thinking further about the Open Graph semantics, I think having just one canonical host makes more sense, even if it makes testing a bit more annoying in some cases.
Right, the routes are a bit confusing, `/outfits/new` matches `/outfits/:id`, but shouldn't.
I fix this at the routing level, by creating a more specific `/outfits/new` route that matches first, and just serves `index.html` right from the CDN.
To check that it's exact, I check for either a `?` or the end-of-string after `new`. That way, `/outfits/newish` correctly redirects to the SSR. (This doesn't actually matter a lot, because outfit IDs are only ever numbers and therefore can't start with "new"? But I figure, better to have an unambiguous semantic, then leave random things relying on outfit ID format assumptions.)
Ah right, this is how we get the deployed API code to know its own hostname! This way, when we do a preview deploy, /api/outfitImage will use the preview version of the GraphQL endpoint, too.
Hmm, the built copy of the HTML isn't deployed with the API function on Vercel. Ok! Let's just do the same trick as we did for the dev server, and make an HTTP request.
This is fine enough for perf because we're caching this result locally to the function, plus it should be a fast CDN-cached response anyway.
Size upgrade, wowie! (I figure sharing services probably prefer a higher-resolution image, they're not very big, and to then scale them down for the application-specific use case & device.)