Commit graph

1113 commits

Author SHA1 Message Date
6df1f49208 Add a limit to the modeling query
Right now it returns 50 rows; each item that needs modeling returns 1–4 rows, usually 1. So a limit of 200 should be pretty dangerous, while also creating a release valve if there's another future bug: it'll just have the problem of returning too few items, instead of the problem of crashing everything! 😅
2022-06-23 11:57:32 -07:00
c585b1236f Oops, fix crashes in the Modeling Hub!
Neopets released a new Maraquan Koi, and it revealed a mistake in our modeling query! We already knew that the Maraquan Mynci was actually the same body type as the standard Mynci colors, but now the Koi is the same way, and because there's _two_ such species, the query started reacting by assuming that a _bunch_ of items that fit both the standard Mynci and standard Koi (which is a LOT of items!!) should also fit all _Maraquan_ pets, because it fits both the Maraquan Mynci and Maraquan Koi too. (Whereas previously, that part of the query would say "oh, it just fits the Maraquan Mynci, we don't need to assume it fits ALL maraquan pets, that's probably just species-specific.")

so yeah! This change should help the query ignore Maraquan species that have the same body type as standard species. That's fine to essentially treat them like they don't exist, because we won't lose out on any modeling that way: the standard models will cover the Maraquan versions for those two species!
2022-06-20 15:21:38 -07:00
6c3f2ac61c
Update Shop Wizard URL 2022-03-11 08:37:13 -05:00
3744a476e5 Fix db transactions with pooling
Ah okay, pools support `query` and `execute` the same way connection objects do (as a shorthand for acquiring, querying, and releasing), but it doesn't have the same helpers for transactions. Makes sense: you need those queries to go to the same connection, and an API where you just call it against the pool object can't tell that it's part of the same thing!

Now, we have our transaction code explicitly acquire a connection to use for the duration of the transaction.

An alternative considered would have been to have `connectToDb` acquire a connection, and then release it at the end of the GraphQL request. That would have made app code simpler, but added a lot of additional potential surprise failure points to the infra imo (e.g. what if we're misunderstanding the GraphQL codepath and the connection never gets released? whereas here it's relatively easy to audit that there's a `finally` in the right spot.)
2022-01-08 18:49:00 -08:00
4ed6344b3d Use a connection pool
This should both fix cases where the connection closes for various reasons, by having the pool reconnect; and also should be a second way of solving some of the blocking issues we were having with large queries, by letting faster queries use parallel connections.

Idk what a reasonable number is, 10 seems to be what various guides are saying? Might tune it down if it ends up pushing various connection limits? (We could also constrain it on dev specifically, if that matters.)
2022-01-08 09:20:45 -08:00
e051290df4 Better-scoped queries for currentUserOwnsThis etc
I hypothesize that loading people's full trade lists more often than necessary is part of the cause of the recent mega slowdown!

My hypothesis is that we're clogging up the MySQL connection socket with a ton of data, which blocks all other queries until the big ones come through and parse out. (I haven't actually validated my assumption that MySQL connections send query results in serial like that, but it makes sense to me, and fits what I've been seeing.)

There's more places we could potentially optimize, like the trade list page itself… (we currently aggressively load everything when we could limit it and load the rest on the followup pages, or even paginate the followup pages…)

…but my hope is that this helps enough, by relieving the load on the homepage (latest items) and on item searches!
2022-01-07 11:37:27 -08:00
6ce8a5aea2 Update lists after click item page own/want button
This is a bit hacky, but I want to ship and I'm not in a mood for a refactor :P

Before this change, you could see a bug by doing the following:

1. Click "I own this" to own an item.
2. Click "Add a list" and add it to a list.
3. Click "I own this" to un-own the item. (This deletes it from all lists.)
4. Observe that the "Add a list" dropdown disappears.
5. Click "I own this" to own it again.
6. Observe that, before this change, the dropdown would reappear, but incorrectly say it was still in the old list. After this change, it appears with the blank "Add to list", as intended.
2021-11-30 16:52:38 -08:00
29d44c10bd Fix double-click bug unchecking own/want an item
Oops, I used the wrong property to control the checkbox state! This made it an uncontrolled component. It would always start unchecked when the page loads, regardless of actual own/want state, and then toggle based on physical clicks.

This meant that things generally worked correctly if you didn't own/want the item when you first loaded the page; but if you already did, then you would click once and send an *add* mutation instead of a remove; and then click again and be able to remove.

Now, removes only take one click!
2021-11-30 16:51:20 -08:00
e95f6abbe4 Closet list dropdowns on item page
Oooh this feature is feeling very nice :) :) We hid "not in a list" pretty smoothly I think!

A known bug: If you have the item in a list, then click the big colorful button, it will remove the item from *all* lists; and then if you click it again, it will add it to Not in a List. But! The UI will still show the lists it was in before, because we haven't updated the client cache. (It's not that bad in the middle state though, because the list dropdown stuff gets hidden.)
2021-11-30 16:36:00 -08:00
e6a94eaf80 Move a comment to satisfy VS Code emmet extension
My cute keybind to quickly wrap stuff in <Box> wasn't working in this file, and I figured out from deleting stuff and narrowing down that it was this comment. I guess Emmet's JSX parser doesn't like a comment being there! I moved it up a bit instead.
2021-11-30 15:01:05 -08:00
7c3298d5b2 Oops, fix SVG message and build error
Ah hm, not sure why this only showed up once I tried a prod deploy, but I declared `hiResMode` twice in there, because we already had fixed this bug for item layers but not pet layers!

In this change, I fix the duplicate `hiResMode` declaration, and update the new pet layers message to match the item layers message.
2021-11-27 20:01:38 -08:00
3642e4c32a Only show SVG glitch messages if SVGs are on
It's confusing to see a message that says "instead we're showing a PNG" if you don't have hi-res mode on and actually everything is PNG anyway!
2021-11-27 19:57:49 -08:00
c4e32d92f1 Fix Typescript error with caching + new Apollo
Okay, right, I guess the Apollo Server upgrade broke type checking in our weird cache control hacks! This should force them to be compatible!
2021-11-26 15:22:01 -08:00
f32de55ed0 Handle more lists, longer list names, on item page
Give the grid a fixed size, have the list name stuff get ellipsis when it's too long, and try to show all list names (which will almost certainly too long for the space) to give a better hint of what's in there.
2021-11-26 15:05:07 -08:00
ad249d03ab WIP list editing on item page
Gonna have this button pop up a little thing of your lists, with checkboxes, and I guess probably quantities once I add that concept back to 2020 😅
2021-11-26 14:49:21 -08:00
2e41f7bb0b Send Vary: Authorization cache header
I don't think this is actually relevant in-app right now, but I figured sending it is More Correct, and is likely to prevent future bugs if anything (and prevent future question about why we're _not_ sending it).

I also removed the `maxAge: 0` on `currentUser`, now that I've updated Fastly to no longer default to 5-minute caching when no cache time is specified. I can see why that's a reasonable default for Fastly, but we've been pretty careful about specifying Cache-Control headers when relevant, so the extra caching is mostly incorrect.
2021-11-23 13:00:56 -08:00
d4b115e805 Merge branch 'ansible' of github.com:matchu/impress-2020 into ansible 2021-11-23 12:42:59 -08:00
96d6d42120 Use persisted queries in dev, bc Next.js support
We had previously configured the client to not bother to try a GET request for GraphQL queries, and just jump straight to POST instead, because the `vercel dev` server for create-react-app reloaded the backend code for every request anyway, which doubled the dev response time.

The Next.js server is more efficient than this, and keeps some memory, so GET requests work similarly in dev as on prod now! (i.e. it fails the first time, but then succeeds on the second)

In this change, we remove the code to skip `createPersistedQueryLink` in development, and instead always call it. We simplify the code accordingly, too.
2021-11-23 12:35:20 -08:00
b941dce9fa Private cache headers in item search
If the user is searching for things they own or want, make sure we don't CDN cache it!

For many queries, this is taken care of in practice, because the search result includes `currentUserOwnsThis` and `currentUserWantsThis`. But I noticed in testing that, if the search result has no items, so those fields aren't actually part of the _response_, then the private header doesn't get set. So this mainly makes sure we don't accidentally cache an empty result from a user who didn't have anything they owned/wanted yet!
2021-11-16 13:09:45 -08:00
b73e2e1123 Send cache-control header for max-age=0, private
Some queries, like on `/your-outfits`, had the cache hint `max-age=0, private` set. In this case, our cache code sent no cache header, on the assumption that no header would result in no caching.

This was true on Vercel, but isn't true on our new Fastly setup! (Which makes sense, Vercel was a bit more aggressive here I think.)

This was causing an arbitrary user's data to be cached by Fastly as the result for `/your-outfits`. (We found this bug before launching the Fastly cache though, don't worry! No actual user data leaked!)

Now, as of this change, the `/your-outfits` query correctly sends a header of `Cache-Control: max-age=0, private`. This directs Fastly not to cache the result.

To fix this, we made a change to our HTTP header code, which is forked from Apollo's stuff.
2021-11-16 12:34:11 -08:00
cadf7487af Mark currentUser GQL as non-cacheable
Comments explain most of this! Vercel changed around the Cache-Control headers a bit to always essentially apply max-age:0 when scope:PRIVATE was true.

I'm noticing this isn't *fully* working yet though, because we're not getting a `Cache-Control: private` header, we're just getting no header at all. Fastly might aggressively choose to cache it anyway with etag stuff! I bet that's the fault of our caching middleware plugin thing, so I'll check on that!
2021-11-16 12:12:51 -08:00
002af474f8 Don't HTTP cache currentUserOwnsThis/wants
Hmm, I see, Vercel chews on Cache-Control headers a bit more than I'm used to, so anything marked `scope: PRIVATE` would not be cached at all.

But on a more standard server, this was coming out as privately cacheable, but for an actual amount of time (1 hour in the homepage case), because of the `maxAge` on other fields. That meant the device browser cache would hold onto the result, and not always reflect Own/Want changes upon page reload.

In this change, we set `maxAge: 0`, because we want this field to be very responsive. I also left `scope: PRIVATE`, even though I think it doesn't really matter if we're saying the field isn't cacheable anyway, because I want to set the precendent that `currentUser` fields need it, to avoid a potential gotcha if someone creates a cacheable `currentUser` field in the future. (That's important to be careful with though, because is it even okay for logouts to not clear it? TODO: Can we clear the private HTTP cache somehow? I guess we would need to include the current user ID in the URL?)
2021-11-16 12:04:16 -08:00
a67509aaec Merge branch 'main' into ansible 2021-11-16 11:23:01 -08:00
bf8fd81305 Post a message linking to Metaverse revocation 2021-11-15 17:42:02 -08:00
0a81f07849 Remove Waka values
The motivation is that I want VERCEL_URL and local net requests outta here :p and we were doing some cutesiness with leveraging the CDN cache to back the GQL fields. No more of that, folks! lol
2021-11-12 22:06:50 -08:00
7015dc3635 [WIP] Add lint exceptions for <img> tags
There are some places where we use <img> tags where I think it's actually just the right thing to do.

`next/image` is good for image optimization, but I don't think it's worth the proxying for Neopets art images that don't actually always have a higher-res version to begin with.

Idk, maybe the species faces could be a decent choice, but right now we're solving it with `srcSet`, and that's fine. Doesn't seem worth migrating, let's just move on with our lives! 😅

I'm still leaving the lint rule on though, because I think it's a helpful reminder. (I don't think it catches `<Box as="img" />` though, which is a shame, because that would be our natural default in this app!)
2021-11-02 00:55:21 -07:00
405b3ded77 [WIP] Fix app images in Next.js
Yeah, cool, now we use the `next/image` tag, and our images are showing up again!

There's still lint errors for using bare img tags in some places, but I'm not sure I really care…
2021-11-02 00:50:39 -07:00
7fd85e5e2a [WIP] Fix bug loading movies
This was a fun journey! Turns out Next 12 is using a new faster JS compiler called SWC, which had a compiler bug that triggered here!

The incorrect looping behavior caused `libraryUrl` to sometimes be `null` by the time the movie promise completes, because `layer` was set to whatever the `last` layer in the list had been. https://github.com/swc-project/swc/issues/2624

Anyway, turns out this code has been through a few refactors, and the `async` function wrapper is extraneous now! So I've just deleted it and inlined its code. Ta da! lol
2021-11-02 00:11:23 -07:00
589c48beda [WIP] Fix eslint for Next.js
Tweaked some of the default Next.js rules, fixed lint-staged for `next lint`, made a few small easy lint fixes. Feels good!

Note that using the `dirs` option in `next.config.js` was causing `lint-staged` to lint _everything_. That's why I edited `yarn lint` to specify the dirs instead: that way, that command will lint all those dirs, but they won't get included in invocations with `--file`.

There are still a few lint errors left after this commit, because our <img> tags aren't working (@next/next/no-img-element). I'll fix those when we figure out what's wrong with images!
2021-11-01 22:07:46 -07:00
567e333f9e [WIP] Run cra-to-next codemod to be on Nextjs
I'm interested in ejecting from Vercel, so I'm trying to get off their proprietary-ish create-react-app + Vercel API thing, and onto Nextjs, which is very similar in shape, but more portable.

I had to disable `craCompat` in `next.config.js` to stop us from crashing on their webpack config, see https://github.com/vercel/next.js/discussions/25858#discussioncomment-1573822

The frontend seems to work at a basic level, but network requests fail, and images don't seem to be working. I'll work on those next!

Note that this commit was forced through despite failing lint checks. We'll need to fix that up too!

Also, after the codemod, I moved `src/pages` to the more canonical location `pages`. Lint tooling seemed surprised to not find a `pages` directory, and I didn't see a config that was making it work correctly in the other location, so I figured it's that Next is willing to check `pages` or `src/pages`? But this is more canonical so yeah!
2021-11-01 21:49:23 -07:00
12d525e3ab Preload next/prev user outfits page
Even in production, scrolling is a bit slow! This will preload the pagination one click ahead.

There is a bit of a perf downside, in that if you click through the pages too fast, you'll trigger _extra_ requests. I think that's a net win though, and I'm not gonna try to get cleverer than this right now.
2021-11-01 19:50:21 -07:00
299561d1e3 Paginate the user outfits page
My main inspiration for doing this is actually our potentially-huge upcoming Vercel bill lol

From inspecting my Honeycomb dashboard, it looks like the main offender for backend CPU time usage is outfit images. And it looks like they come in big spikes, of lots of low usage and then suddenly 1,000 requests in one minute.

My suspicion is that this is from users with many saved outfits loading their outfit page, which previously would show all of them at once.

We do have `loading="lazy"` set, but not all browsers support that yet, and I've had trouble pinning down the exact behavior anyway!

Anyway, paginating makes for a better experience for those huge-list users anyway. We've been meaning to do it, so here we go!

My hope is that this drastically decreases backend CPU hours immediately 🤞 If not, we'll need to investigate in more detail where these outfit image requests are actually coming from!

Note that I added the pagination to the existing `outfits` GraphQL endpoint, rather than creating a new one. I felt comfortable doing this because it requires login anyway, so I'm confident that other clients aren't using it; and because, while this kind of thing often creates a risk of problems with frontend and backend code getting out of sync, I think someone running old frontend code will just see only their first 30 outfits (but no pagination toolbar), and get confused and refresh the page, at which point they'll see all of them. (And I actually _prefer_ that slightly confusing UX, to avoid getting more giant spikes of outfit image requests, lol :p)
2021-11-01 19:33:40 -07:00
33740af5ee Stop passing null value in SpeciesColorPicker
This is a minor change to clear a console warning, and make intended behavior clearer! You're not supposed to pass `null` as a select value, because it's ambiguous about whether you're looking for the first option or to make this an "uncontrolled component".

Here, I now provide a fallback value, which is an explicit string for the placeholder option. I made the string very explicit, to aid in debugging if it somehow leaks out from where it's supposed to be! (But I also added gating in the `onChange` event, just to be extra sure.)
2021-11-01 16:19:17 -07:00
21096ef837 Remove incorrect flexAlign prop
Huh. `flexAlign` isn't a real Chakra style prop, because it's not a real CSS style. I wonder if I meant `alignItems`? Anyway, this was getting passed down to the DOM element and triggering a console warning. Removed!
2021-11-01 16:09:56 -07:00
6ce0f59894 Remove stray onChangeHasAnimations prop
This isn't used, so it was getting passed down to the underlying DOM element and triggering a console warning! Remove it.
2021-11-01 16:09:09 -07:00
e4567d04bf Stop requesting bad outfit thumbnails in wardrobe
Oops, our cutesy feature to show an outfit thumbnail sa a placeholder while the rest of the data is loading was making spurious requests!

I put the `skip` in the wrong place 😅

This caused a request to https://outfits.openneo-assets.net/outfits/null/v/NaN/300.png, which would return a 500.

The user wouldn't see anything, because the image wouldn't show because it failed. But it's a mistake, and it's sending extra requests from the client and to the server, and it's a good one to fix!
2021-11-01 16:05:13 -07:00
086ada40f1 Polyfill Promise.any
Resolves Sentry issue IMPRESS-2020-7T
2021-11-01 16:01:05 -07:00
2fb84b0b0f Better handle editUsername when Auth0 update fails
Hmm, right, okay, we *generally* should have all users imported to Auth0, but this can fail if the cron job is behind or Auth0 rejected the data (e.g. user data in a format it doesn't support).

Previously, this would apply the name change in the database, but return Auth0's "The user does not exist." error to the GraphQL client, making it look like the update fully failed.

In this change, we handle that case differently: when the Auth0 update fails with a 404, we proceed but log a warning; and when Auth0 fails with an unexpected error, we roll back the database change in addition to raising the error to the client, to keep the behavior obvious and consistent.
2021-10-21 12:17:12 -07:00
b5865bf699 Fix email search redirect
Oh oops, I missed this path change when I changed the route to `/user/:id/lists`! This caused searching by email to redirect to the homepage, but with a valid URL in the address bar; and refreshing the page would hit the redirect defined in `vercel.json`, redirect to the new route, and load the correct page.

Fixed!
2021-10-21 11:56:55 -07:00
9b856a40b8 Sort /support/petAppearances from newest to oldest 2021-10-01 04:22:53 -07:00
4d4bc289df Update homepage Sep 30 2021-09-30 20:05:56 -07:00
0a5d8f1f74 Add search toolbar to item page
Trickier than it looks, to get the shared UI across pages without disrupting things like focus!
2021-09-30 20:04:50 -07:00
d6654b704b Search icon on homepage is now a link
Like, the little magnifying glass in the "Search all items", you can click it to get taken to the _big_ search page with the autocomplete filters and stuff
2021-09-30 19:31:51 -07:00
6efd542f49 Wire up the Remove button for item lists
Did some stuff in here for parsing the default list ID too. We skipped that when making the new list index page, but now maybe you could reasonably link to the default list? 🤔 not sure it's a huge deal though
2021-09-30 19:26:09 -07:00
64db3dd1b7 [WIP] UI for item remove button
It's code for a remove button in item lists! When you click it, you see a "TODO" alert.

Not shipping this change until it's wired up!
2021-09-30 18:12:31 -07:00
818a443dfe Delete /outfit-urls page
We didn't end up using this, we found a way to decrease AWS costs without requiring people to migrate!
2021-09-30 17:32:25 -07:00
2bd573690e Add underline to item list description links
Oops, right, a bit of a CSS oversight! Added now!
2021-09-06 14:08:43 -07:00
315744b4f7 Allow pre tag in lists
I noticed someone using `<pre>` for styling, and thought, sure why not!

I haven't added support for the code block indent thing, and I think that's probably fine?
2021-09-06 14:07:05 -07:00
cc9cd5ef28 Rewrite old closet links to use new syntax
A lot of DTI lists use old URLs to anchor-link between lists! Here, we rewrite those URLs to match what DTI 2020 expects, so that they actually correctly jump you across the page and aren't filtered out!
2021-09-06 14:05:36 -07:00
9a68bd1355 Use standard image URLs on Your Outfits page
The old URLs were glitchy because we weren't escaping the `layerUrls` param… and this will let us take better advantage of the same shared caching as other stuff!
2021-09-03 15:37:38 -07:00
ae6b012f88 Fail harder when *all* layers fail to load
This was actually being _triggered_ by the fact that the user outfits page doesn't generate great outfit image URLs! It doesn't encode the layerUrls parameter, so now that image URLs sometimes contain `&`, the parameter was being misparsed.

Example:
```
http://localhost:3000/api/outfitImage?size=300&layerUrls=https://impress-2020.openneo.net/api/assetImage?libraryUrl=https%3A%2F%2Fimages.neopets.com%2Fcp%2Fitems%2Fdata%2F000%2F000%2F054%2F54348_cf1cfe10c7%2Fall-background.js&size=300,http://images.neopets.com/cp/bio/data/000/000/041/41572_0450defb29/41572.svg,http://images.neopets.com/cp/bio/data/000/000/041/41570_83582a4a83/41570.svg,http://images.neopets.com/cp/bio/data/000/000/041/41571_7e6c072e12/41571.svg,http://images.neopets.com/cp/bio/data/000/000/041/41582_06159c1e4d/41582.svg,http://images.neopets.com/cp/bio/data/000/000/041/41574_520e661a8a/41574.svg,http://images.neopets.com/cp/bio/data/000/000/041/41573_f4f480ba37/41573.svg,https://impress-asset-images.openneo.net/object/000/000/480/480378/300x300.png?v2-1597211608000
```

would get the following list of layer URLs:
```
["https://impress-2020.openneo.net/api/assetImage?libraryUrl=https://images.neopets.com/cp/items/data/000/000/054/54348_cf1cfe10c7/all-background.js"]
```

Anyway, I'm gonna fix that (probably by just not using this layerUrls param anymore and moving to the new outfit ID + timestamp URLs), but let's also just have clearer error messages instead of just a blank image! That way, if something similar happens again, the client will fall back to alt text, instead of showing a blank image.
2021-09-03 14:55:50 -07:00
781034a568 Oops, don't crash if animation image fails
Whoops, `Promise.race` isn't quite what I wanted here. This meant that, if the image promise _fails_ before the movie _succeeds_, the outfit would crash even though it doesn't need to. (And this was happening too often, due to a bug in /api/assetImage!)

Now, we accept whichever _successful_ result loads first, or reject if they _both_ fail.

I tested this by having /api/assetImage always throw, and confirmed that it crashed the outfit before this change, and no longer does after this change!
2021-09-02 19:09:27 -07:00
f036890aa1 Use /api/assetImage for all image sizes
We update /api/assetImage to accept size as a parameter (I make it mandatory to push people into HTTP caching happy paths), and we update the GraphQL thing to use it in those cases too!

This also means that, if these images seem to go well, we could swap Classic DTI over to them… I want to turn off those RAM-heavy image converters on the VPS lol
2021-08-19 17:56:09 -07:00
7719ab8c07 Use /api/assetImage for imageUrl
In this change, we start using our new API endpoint for movie image URLs, instead of the Classic DTI image.

This should make the little fade-in phase for certain movies a little bit less jarring (the part where we preload the image before the movie loads), though I suppose that won't necessarily load as fast until it gets into the cache the first time lol. (A good reason to maybe put a more long-lived cache like Fastly in front of this stuff long-term?)

Not doing it for the smaller image sizes yet, I'm a bit worried that I don't 100% know how to teach /api/assetImage to resize without tipping over the function limit…

…oh! I should have the webpage render at different sizes! Yeah that's a great idea lol
2021-08-19 17:40:16 -07:00
f9b4852da1 Handle OFFICIAL_SWF_IS_INCORRECT for pet layers
Marking this glitch on the Yellow Lutari head today, and oops there isn't UI copy for it yet! Added!

Also fixed some bugs in here, like old text about the position of the pose picker relative to the glitch badge, and I noticed while debugging that `layerUsesHTML5` returns a truthy string instead of a boolean which seems error-prone!
2021-08-14 16:46:05 -07:00
30e6c46d48 Merge branch 'main' of github.com:matchu/impress-2020 into main 2021-08-07 21:44:37 -07:00
e2e7835214 Waka deprecation UI, to expire on Aug 21 2021-08-07 21:32:22 -07:00
fb12f817e2 Add negative word filters to search
Just a quick lil change on a whim, I hope it works well!
2021-07-29 00:25:35 -07:00
2ba18ace4d Add debug lines to appearanceOn Apollo resolver
Hmm, the item page in prod is slower than it is in dev? In dev, most items are satisfied by the preloading in ItemPagePreview, but in prod, those same items need to send a separate OutfitItemsAppearance query _way_ after (which, I think just due to queueing, waits for all the items to wait too).

There's an obvious issue in the case of all the Maraquan items lately, because we just don't do the clever cache lookups for non-standard colors at all. But I don't understand why even standard items like the 17th Birthday Party Hat are struggling!

These are just some simple debug statements, hopefully they'll tell us something about the basics of what's happening!
2021-07-21 16:03:24 -07:00
b7b4fa21ec Oops, show models needed for special colors
Right, oops, `speciesThatNeedModels` is for standard colors! Add in the special colors, too!
2021-07-17 05:47:32 -07:00
f1d24d2177 Clarify the standard colors fit info
I didn't want to use the word "basic", since "basic colors" generally means like Blue, Red, Green, Yellow… but it was the only one that fit in the space lol

I tried a lot of stuff with "Fits standard pets" and stuff and couldn't get it to work well
2021-07-12 04:46:07 -07:00
9e1d8024c1 Lmao whoops I shipped the test data 🤣 2021-07-11 21:32:14 -07:00
29ca2306af Oops, fix items drawn for multiple colors
Just a little display bug on the homepage. For an item like the "Evil Coconut Half Mask", which was specifically drawn for the standard _and_ major special colors, our previous logic would have said "Baby only" or "Maraquan only" or whatever special color it happened to find first.

Now, we only show the case "Baby only" if it _doesn't_ fit standard pets too.

Note that the Maraquan case is tricky, because the Blue Mynci can also wear Maraquan items lol! For this reason, we check for two standard bodies before declaring that it's meant for standard pets.
2021-07-11 21:27:24 -07:00
a1f3c1df13 Oops, fix bug in needed models count!
Lol to test text sizing, I added a "1" to the end of the actual number of models needed 🤣 removed it now!
2021-07-11 19:10:14 -07:00
af493f6719 Add fit info to homepage
I wasn't sure how to fill the space for items that are fully modeled, then realized some basic at-a-glance "who does this fit" would help!

The load time isn't great, I think I need to break out that dependent subquery, but maybe the stale-while-revalidate will cover it well enough at first.
2021-07-11 19:08:47 -07:00
2a5ecb688a Improve homepage modeling loading state
Add a skeleton stripe for the modeling data! Won't show up in most cases because we load fast, but it helps things a lot when it does. (Also, will we keep loading fast with the cache changes on this query?)
2021-07-11 18:16:57 -07:00
f2259d6487 Add modeling info to homepage
To make this fast, I had to tweak the GraphQL resolver a bit to run a filtered version of the query for `newestItems` instead of scanning the full database! But yeah, looking good!

I think I'm gonna want to swap out "Fully modeled" for some insight about who it fits
2021-07-11 18:09:29 -07:00
a19c2facbf Detect more animated items
Okay cool, I noticed that "A Warm Winters Night Background" sometimes animates when other things are playing, but the animations aren't _detected_. (Huh, I actually thought we just didn't schedule ticks in that case? But maybe I'm missing something.)

Anyway, some movies don't use the built-in frames construct to animate, and instead use tweens that hook into the timeline and mutate the stage. Okay! Now we detect those.

This _did_ enable the Play/Pause button on some items that don't actually animate in practice, like the "#1 Fan Room Background", which seems to have an animated string of lights in the corner that got layered incorrectly. Maybe we should add a new glitch type, to flag movies that don't actually animate?
2021-07-02 15:40:04 -07:00
dcfcbf9ff7 /api/assetImage can render movies!
Yeah wow huh, that was much less painful than I expected!

I haven't tested this very rigorously, literally just the Floating Negg Faerie Doll: https://images.neopets.com/cp/items/data/000/000/005/5735_a8feda8d08/5735.js
2021-07-02 15:19:11 -07:00
4e31a4bec7 /internal/assetImage can render movies
This is a new page, that I'm gonna use a headless browser to navigate to and screenshot the asset!
2021-07-02 14:36:08 -07:00
2f0d145e49 Move error toast out of OutfitMovieLayer
Doing this for two reasons! One is that I want the movie layer component to be a bit thinner in general - I think we might even want to move the fallback image logic out, too.

The second is that I want the onError for something else soon!
2021-07-02 14:35:27 -07:00
c8d15fa812 Oops, fix bug in pet appearance support!
Right, oops, this logic was saying "Restricts: None" whenever the appearance restricted _zero or one_ zones, lol 😅
2021-06-29 00:10:42 -07:00
b0672d589f Oops, stop showing PNG reference art
Huh, weird. So I reversed the manifest, because you want to get the *last* movie. And I figured that semantic probably extended to PNGs and SVGs too?

But actually, PNGs sometimes have *other* PNGs in the manifest that aren't the relevant asset at all, and are just reference art.

Again, I'm really not sure what the underlying semantic is here? Does the Neopets customizer just display them all, and for the items with this problem, they happen to layer in a way that's not broken?? I would really like to not do that, and I would really like to know the real semantic, but I can't find it >.>

So um, I'm going ahead and using the best semantic that solves the problems I know about? Which is, use the last movie, and use the first PNG. Fingers crossed lol!

I also didn't test this change extensively, because I'm on a train lol

I'm just trusting that this push will be better than what we had before. I tested it on the Dandan MME, which has two JS files, and it took the latter; and the Pathway of Petals Background, which has two PNG files, and it took the former. Success? 😬🤞
2021-06-27 15:34:36 -07:00
f5e5f16f87 Improve movie cancels and error handling
Oops, my inbox was getting full of uncaught promise rejections of `loadImage`!

I'm pretty sure they're caused when multiple images in a movie fail to load (e.g. network problems), but we fail to cancel them. So, the first failure would be caught as a part of `Promise.all` in `loadMovieLibrary`, but then subsequent failures wouldn't be caught by anything, and would propagate up to the console and to Sentry as uncaught errors.

In this change, we make a number of improvements to cancellation. The most relevant change for this bug is that `loadMovieLibrary` will now automatically cancel all resource promises when it throws an error! But this improved robustness also enabled us to finally offer a simple `cancel()` method on movie library promises, which we now available ourselves of at call sites, too.
2021-06-26 12:04:40 -07:00
0bffaec989 Try moving the glitch badges to the top
Experiment! Let's see if them being more prominent like this is helpful or annoying 😅

I think this is clunkier in the HTML5 Green Happy Path, but worth it for bringing attention in the error cases.

But I feel like we might tweak this over time!
2021-06-24 20:05:31 -07:00
35a1096da3 Fix movie bugs with Dandan, Electric Dress, etc
Huh, so it turns out sometimes the manifest will include old broken conversion attempts!

This fixed the "MiniMME18-S2c: Holomorphic Foliage and Dandan Set", the "Electric Dress" on various species (incl. Aisha), and yeah!

What an interesting discovery 😂
2021-06-24 18:54:48 -07:00
ea33741594 Add search footer to layout, behind a feature flag
Yeah it looks cute as a starting point! Definitely a lot to do here tho 😳
2021-06-21 14:48:08 -07:00
59fe02a4cc Prefer two-column layout on md-size screens
This is because I want to try adding a search footer to the two-column layout, like in Classic DTI—and so I want more screens that _can_ support two-column layout to use it.
2021-06-21 14:14:27 -07:00
27ebe90eef Homepage update June 21 2021-06-21 13:55:54 -07:00
47c40eaf03 Keep prev/next enabled while pages load
Right, cool, yes, this is the thing about partial data; you need to define the loading condition as "relevant data is missing, _and_ loading is still happening".
2021-06-21 13:50:49 -07:00
c2ef164ff2 Cache item search pages
Ah right okay, when the `ItemSearchResultV2` doesn't have an `id`, Apollo Cache isn't quite so strong about caching conflicting-y fields, like the different parameterizations of `items`.

With this change, we give the search result object an ID, which helps Apollo cache more confidently!

It's just a serialization of the relevant search fields 😅
2021-06-21 13:48:45 -07:00
d025f2ba7a Navigate item search by page number
The page number is a dropdown now! Wowie!
2021-06-21 10:54:31 -07:00
3537ef9a6f Use itemSearchV2 in wardrobe too
That's the last itemSearch call site! I'll probably keep it up for other clients for a while though, esp since it doesn't depend on any additional loaders or anything, it's pretty small overall

Updated the comments to reflect this, and also remembered to make them real docstrings lol!
2021-06-21 10:37:54 -07:00
fd13b1aa46 Keep showing page num while item search loads
Now, when you click Prev/Next, we show the page number while the items load, rather than blink it in and out!

This is because we're using itemSearchV2, which makes `numTotalItems` cacheable separately from the paginated `items`. Apollo Cache pretty much does this with zero config, we just have to ask for `returnPartialData`!
2021-06-21 10:31:55 -07:00
c38678cf1a Build itemSearchV2 in GQL
The main change is that we restructure the query, so that only the parts that are actually affected by pagination depend on those variables!

This will enable the Apollo Cache to trivially cache and show `numTotalItems` while waiting for other pages to load.
2021-06-21 10:30:41 -07:00
367a527a6f Better error messages on ItemSearchPage
Using that MajorErrorMessage, baby :) Helpful for debugging item search refactors lol
2021-06-21 10:21:53 -07:00
7d1872920c Add page numbers to item search
I'm gonna make this a bit more powerful later, but just for now, the text "Page 1 of 27" shows up!

I also don't like that the page number has to blink out while we load the new stuff; there are multiple solutions, but tbh I think the Apollo Cache should be the one to handle this, and that we can do it by refactoring the query structure a bit!
2021-06-21 10:21:25 -07:00
56c91e900a Better error handling when preloading layers
I'm seeing uncaught promise rejections in `loadImage`? It's hard to know exactly where it's actually coming from, those _should_ be caught?

My guess is that it's coming from canceled images, which are throwing errors even after loading? I don't totally understand how, because looking back, I don't think the `cancel` method was actually called???

Anyway, I fixed it so cancel actually _is_ called, and that we don't throw errors when the canceled image _correctly_ fails to load.

This should be more robust either way, but hopefully it also stops the flow of errors?
2021-06-21 09:34:05 -07:00
7a8c5068a7 Fade from image -> movie, instead of harsh change
We put it on top, then fade it out!
2021-06-20 12:21:11 -07:00
e2aeb90b4b Oops, fix loading state bug on homepage!
Right, when there are zero layers, we shouldn't say we're loading!

This is a consequence of the HACK below. If we didn't short-circuit the effect when length == 0, then we would go through and successfully load 0 layers.
2021-06-20 12:04:07 -07:00
6652e66af1 Show image preview while movie loads
Movies often have a lot of assets, which are more likely to be cache misses, and take script time to render! So the time until the user sees something is often huge.

Here, we start loading our PNG image at the same time. This is a filesize loading increase, but even in slow connections, it's generally worth it as a _sharp_ improvement in time until you get to see something!

One noteworthy UI weakness here is that we don't show _any_ loading indicator while the image is visible and the movie is still loading. This makes sense from a practical standpoint, but could be a problem when a movie takes a particularly long amount of time. I also want to be cognizant of whether the blink-of-content ever gets annoying! (We could make it fade out 🤔)
2021-06-20 11:54:30 -07:00
92001d514a Refactor crossOrigin handling for image loading
In my last change, I didn't try to change the APIs too much, and kept the concept of `crossOrigin` running through `getBestImageUrlForLayer`.

Now, I've moved the `safeImageUrl` call _outside_ `getBestImageUrlForLayer`, by putting it at the call site: We now call `safeImageUrl` from `loadImage` (which needs to know the `crossOrigin` flag anyway!), and at the `img` tag call site.

This simplifies all of the call sites a lot, I think!
2021-06-20 10:54:03 -07:00
c2535f811f Remove proxy for most images
I've noticed that our Fastly proxy adds a surprising amount of latency on cache misses (500-1000ms). And, while our overall hit ratio of 80% is pretty good, most misses happen at inopportune times, like loading items from search.

But now that the Neopets CDN supports HTTPS, we can safely switch back to theirs for *most* image loads. (Some features, like downloads and movies, still require CORS headers, which our proxy is still reponsible for adding.)

This forgoes some minor performance wins (like the Download button now requires separate network requests), and some potential filesize reduction opportunities (like Fastly's auto-gzip which we're today using for SVGs, and eventually using their Image Optimizer for assets), to decrease latency. We could still potentially do something more powerful for low-power connections someday… but for now, with the cache miss latency being *so* heavy, this seems like the clear win for almost certainly *all* users today.
2021-06-20 10:36:41 -07:00
beb606c6ca Oops, fix alignment in virtualized lists!
Forgot to top-align stuff! And then needed to add some padding to make sure the shadows show up.
2021-06-19 12:52:16 -07:00
be3a162a8a Virtualize item list scrolling
This helps the render time by a lot!
2021-06-19 12:36:19 -07:00
cc4e1f611f Oops, stop cutting off items on list page!
Made a mistake when refactoring to extract ClosetList! It made the full list page only show the preview 😅
2021-06-19 11:49:13 -07:00
eace28839e Highlight trade matches with pretty shadow
This makes scanning the lists WAY easier imo!
2021-06-19 11:43:51 -07:00
01ea733b10 Add right-click hint for how to download images
I have a hunch that people aren't finding the Download button! I'm not 100% sure what to do about that, but to start, I want right-clicking the image to give you a hint about it 😅
2021-06-19 11:30:44 -07:00
4903eb8d21 Show textarea even if description is blank
Now you can add description to a list that doesn't have one yet!
2021-06-19 09:46:53 -07:00
d91492ab66 Editable name/desc on list page
Decided to share the ClosetList component and give it a bit of variance, instead of figuring out how to extract all that edit state!
2021-06-19 09:44:44 -07:00