Compare commits

...

4 commits

Author SHA1 Message Date
758b62e7d5 Improve performance of Owls values in Item Getting Guide
Now we preload them all concurrently, instead of in sequence when the
template gets around to asking for them!
2024-05-27 16:21:22 -07:00
551e8941f3 Add OWLS values to non-NC-Mall NC items in Item Getting Guide
Note that there's a known performance issue here: we should try to
fetch all the OWLS values at once, instead of doing them in sequence
while rendering the page!
2024-05-27 15:53:08 -07:00
c49cf52939 Remove CSS reset that removes focus outline from all elements by default
Oh jeez, idk why this was ever in here, but yeah no, I want to be using
default browser focus outlines unless specifically overridden otherwise.
Will help keyboard navigation a lot! Yikes!!
2024-05-27 15:49:12 -07:00
b2615eaf00 Use table layout for other NC items in Item Getting Guide
To start, we just link to DTI's own NC trades. I also want to add OWLS
values in here too!
2024-05-27 14:25:12 -07:00
8 changed files with 81 additions and 7 deletions

View file

@ -16,7 +16,6 @@ caption, tbody, tfoot, thead, tr, th, td
margin: 0 margin: 0
padding: 0 padding: 0
border: 0 border: 0
outline: 0
font-size: 100% font-size: 100%
vertical-align: baseline vertical-align: baseline
background: transparent background: transparent

View file

@ -61,6 +61,17 @@
text-wrap: balance text-wrap: balance
font-style: italic font-style: italic
.subtitle
font-size: 85%
opacity: .85
a[title]
text-decoration-line: underline
text-decoration-style: dotted
&:hover, &:focus
text-decoration-style: solid
/* For wearable items that belong to a specific set that all come together, /* For wearable items that belong to a specific set that all come together,
* like a Paint Brush. */ * like a Paint Brush. */
&[data-group-type="bundle"] &[data-group-type="bundle"]

View file

@ -128,6 +128,9 @@ class ItemsController < ApplicationController
@np_items = @items.select(&:np?) @np_items = @items.select(&:np?)
@pb_items = @items.select(&:pb?) @pb_items = @items.select(&:pb?)
# Start loading the NC trade values for the non-Mall NC items.
trade_values_task = Async { Item.preload_nc_trade_values(@other_nc_items) }
# Also, PB items have some special handling: we group them by color, then # Also, PB items have some special handling: we group them by color, then
# load example pet types for the colors that don't have paint brushes. # load example pet types for the colors that don't have paint brushes.
@pb_items_by_color = @pb_items.group_by(&:pb_color). @pb_items_by_color = @pb_items.group_by(&:pb_color).
@ -144,6 +147,9 @@ class ItemsController < ApplicationController
[color, color.example_pet_type(preferred_species: species)] [color, color.example_pet_type(preferred_species: species)]
end.to_h end.to_h
# Finish loading the NC trade values.
trade_values_task.wait
render layout: "application" render layout: "application"
end end

View file

@ -156,6 +156,17 @@ module ItemsHelper
"Last updated: #{date_str} (#{time_ago_str} ago)" "Last updated: #{date_str} (#{time_ago_str} ago)"
end end
def nc_trade_value_subtitle_for(item)
value = item.nc_trade_value
return nil if value.nil?
link_to "Owls listing: #{item.nc_trade_value.value_text}",
"https://www.neopets.com/~owls",
title: 'Owls keeps track of approximate "capsule" values of NC items ' +
"for trading. Items with similar values can often be traded for one " +
"another. This is an estimate, not a rule!"
end
private private
def build_on_pet_types(species, special_color=nil, &block) def build_on_pet_types(species, special_color=nil, &block)

View file

@ -1,3 +1,6 @@
require "async"
require "async/barrier"
class Item < ApplicationRecord class Item < ApplicationRecord
include PrettyParam include PrettyParam
@ -114,15 +117,25 @@ class Item < ApplicationRecord
def nc_trade_value def nc_trade_value
return nil unless nc? return nil unless nc?
begin
# Load the trade value, if we haven't already. Note that, because the trade
# value may be nil, we also save an explicit boolean for whether we've
# already looked it up, rather than checking if the saved value is empty.
return @nc_trade_value if @nc_trade_value_loaded
@nc_trade_value = begin
Rails.logger.debug "Item #{id} (#{name}) <lookup>"
OwlsValueGuide.find_by_name(name) OwlsValueGuide.find_by_name(name)
rescue OwlsValueGuide::NotFound => error rescue OwlsValueGuide::NotFound => error
Rails.logger.debug("No NC trade value listed for #{name} (#{id})") Rails.logger.debug("No NC trade value listed for #{name} (#{id})")
return nil nil
rescue OwlsValueGuide::NetworkError => error rescue OwlsValueGuide::NetworkError => error
Rails.logger.error("Couldn't load nc_trade_value: #{error.full_message}") Rails.logger.error("Couldn't load nc_trade_value: #{error.full_message}")
return nil nil
end end
@nc_trade_value_loaded = true
@nc_trade_value
end end
# Return an OrderedHash mapping users to the number of times they # Return an OrderedHash mapping users to the number of times they
@ -599,6 +612,27 @@ class Item < ApplicationRecord
end end
end end
def self.preload_nc_trade_values(items)
# Only allow 10 trade values to be loaded at a time.
barrier = Async::Barrier.new
semaphore = Async::Semaphore.new(10, parent: barrier)
Sync do
# Load all the trade values in concurrent async tasks. (The
# `nc_trade_value` caches the value in the Item object.)
items.each do |item|
semaphore.async { item.nc_trade_value }
end
# Wait until all tasks are done.
barrier.wait
ensure
barrier.stop # If something goes wrong, clean up all tasks.
end
items
end
def self.collection_from_pet_type_and_registries(pet_type, info_registry, asset_registry, scope=Item.all) def self.collection_from_pet_type_and_registries(pet_type, info_registry, asset_registry, scope=Item.all)
# bear in mind that registries are arrays with many nil elements, # bear in mind that registries are arrays with many nil elements,
# due to how the parser works # due to how the parser works

View file

@ -28,7 +28,7 @@
= link_to t('items.show.resources.jn_items'), jn_items_url_for(item) = link_to t('items.show.resources.jn_items'), jn_items_url_for(item)
= link_to t('items.show.resources.impress_2020'), impress_2020_url_for(item) = link_to t('items.show.resources.impress_2020'), impress_2020_url_for(item)
- if item.nc_trade_value - if item.nc_trade_value
= link_to t('items.show.resources.owls', value: item.nc_trade_value.value_text), = link_to t('items.show.resources.owls', value: item.nc_trade_value_text),
"https://www.neopets.com/~owls", "https://www.neopets.com/~owls",
title: nc_trade_value_updated_at_text(item.nc_trade_value) title: nc_trade_value_updated_at_text(item.nc_trade_value)
- unless item.nc? - unless item.nc?

View file

@ -2,5 +2,8 @@
%td.thumbnail-cell %td.thumbnail-cell
= link_to item_thumbnail_for(item), item, target: "_blank", = link_to item_thumbnail_for(item), item, target: "_blank",
tabindex: "-1" tabindex: "-1"
%td.name-cell= link_to item.name, item, target: "_blank" %td.name-cell
= link_to item.name, item, target: "_blank"
- if subtitle.present?
.subtitle= subtitle
%td.actions-cell= yield %td.actions-cell= yield

View file

@ -99,7 +99,17 @@
purchased at all anymore, and can only be obtained via gifts or trades. purchased at all anymore, and can only be obtained via gifts or trades.
[mall]: https://ncmall.neopets.com/ [mall]: https://ncmall.neopets.com/
= render @other_nc_items %table.item-list
%thead
%td
%th{colspan: 2}
Total: #{pluralize @other_nc_items.size, "item"}
%tbody
- @other_nc_items.each do |item|
= render "item_list_row", item:, subtitle: nc_trade_value_subtitle_for(item) do
= button_link_to "NC Trades",
item_trades_path(item, type: "offering"),
target: "_blank", icon: search_icon
- content_for :stylesheets do - content_for :stylesheets do
= page_stylesheet_link_tag "items/sources" = page_stylesheet_link_tag "items/sources"