Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert legacy color categories to new values throughout the code #2502

Conversation

KaelenProctor
Copy link
Contributor

@KaelenProctor KaelenProctor commented Dec 26, 2024

Fixes #2505

Problem

  1. Cards in cubes may still have the legacy color category values such as "l", "w", or "m" rather than the current color category types of "Lands", "White", or "Multicolored" etc
  2. These can be both on the card, and in the respective card details
  3. Exporting the cube as CSV uses the legacy values if they are on the card
  4. Importing did not convert legacy to current
  5. The Color Category sort used the new values and so anything with the legacy values got stuck in the "Other" bucket, hence could import and see no cards as they were all unsorted
  6. Cards with legacy color category could show in the card edit modal as having blank in the Color category dropdown. I think this occurred when the card details had legacy color category, but unsure. Sometimes the new value was selected, I think because the legacy values match the first letter (case insensitive) of the new values and browsers are flexible in that way
  7. In a couple places the word "Multicolor" was used instead of "Multicolored", the latter which is in the color category type (and occurred more often in the codebase)

Solution

  1. Updated the export and import process to explicitly covert from legacy to current color categories (if possible)
  2. Updated the Color Category and Color Category full sorts to also convert
  3. Converts from legacy to new whenever Card.cardColorCategory is called

Concerns

  1. I am not sure whether the card dictionary JSONs should be converted to the new values for good
  2. Should the placeholder card in carddb.getPlaceholderCard be updated?
  3. Unsure why both the Card and Card details can container color category, and why one is colorCategory and the other colorcategory
  4. Don't see any path to determine the color category as Hybrid from the card's color identity (in Card.cardColorCategory)

Testing

Existing behaviour

Used Cube's https://cubecobra.com/cube/list/jank and https://cubecobra.com/cube/list/trash-pile-test from the reported issues in Discord.

  1. Exported both as CSV, and can see the legacy values of color category in them eg.
name,CMC,Type,Color,Set,Collector Number,Rarity,Color Category,status,Finish,maybeboard,image URL,image Back URL,tags,Notes,MTGO ID
"Grim Lavamancer",1,"Creature - Human Wizard",R,"dmr","324",rare,r,Owned,Foil,false,,,"","",107333
"Ignoble Hierarch",1,"Creature - Goblin Shaman",G,"mh2","414",rare,m,Owned,Foil,false,,,"","",91101

(r and m respectively)
2. Imported those into my local cube cobra using the current master branch. Many cards were categorized as "Other" using the color category sort (the default) per screenshots. For each first screenshot shows imported, then second shows after Display -> Show unsorted is on

Cube 1
555jank-import-old1
555jank-import-old2-show-unsorted

Cube 2
trashpiletest-old1
trashpiletest-old2-show-unsorted

  1. Validated the legacy color categories in the cube JSON
    555jank-import-old5
    trashpiletest-old5

  2. Sorting by color identity works

555jank-import-old6-sorted-by-color-identity
trashpiletest-old6-sorted-by-color-identity

New behaviour

  1. The color category sorting works for the cubes imported from the previous section (no edits or anything to the cards)
    555jank-import-old6-sorted-by-color-identity
    trashpiletest-old6-sorted-by-color-identity

  2. Importing the cubes from CSV correctly has color category set
    555jank-import-new
    trashpiletest-import-new

  3. New color categories are saved in the cube JSON (on the card itself)
    converted-color-category

  4. CSV export uses the current color categories (r -> Red in comparison)

"Grim Lavamancer",1,"Creature - Human Wizard",R,"dmr","324",rare,Red,Owned,Foil,false,,,"","",107333
  1. Ran the import cards script and validated the color category values are the new ones, not the old ones

| 'Hybrid'
| 'Lands';

export const COLOR_CATEGORIES = ['White', 'Blue', 'Black', 'Red', 'Green', 'Colorless', 'Multicolored', 'Hybrid', 'Lands'] as const;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using typescript const assertions so that we can use COLOR_CATEGORIES to check if a string is within its set of values. Could not see how to do that using the ColorCategory type itself.

@@ -228,6 +229,9 @@ function CSVtoCards(csvString, carddb) {
} of camelizedRows) {
if (name) {
const upperSet = (set || '').toUpperCase();

const validatedColorCategory = convertFromLegacyCardColorCategory(colorCategory);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies when importing the CSV

@@ -195,14 +196,17 @@ function writeCard(res, card, maybe) {
} else {
imgBackUrl = '';
}

const colorCategory = cardutil.convertFromLegacyCardColorCategory(card.colorCategory);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applies when writing the CSV

@@ -203,7 +236,7 @@ export const cardColorCategory = (card: Card): ColorCategory => {
return 'Colorless';
}
if (colors.length > 1) {
return 'Multicolor';
return 'Multicolored';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found when exploring why some cards didn't show the right value in the Color Category dropdown, looked to be a recent typo. More places used Multicolored including on the Color category type

@KaelenProctor KaelenProctor marked this pull request as ready for review December 26, 2024 14:47
@lunakv
Copy link
Contributor

lunakv commented Dec 27, 2024

Ad concern 3, I'm pretty sure the idea is that "details" contains immutable information (from the user's perspective) directly loaded from the carddb JSONs, so it contains the default color category that is assigned to cards with this cardID. If a user overrides that default in their cube, it changes the color category directly on the Card object, which takes precedence over the default in "details".

Since it looks like every Card has its colorCategory set explicitly to the default when created, you're right that it could be omitted from the details, but since those are just a copy-pasted object, there's not much of a point in explicitly deleting a single value.

Ad concern 1, I'd say that depends on if the value is used anywhere (other than as a default for Card objects). If not, I think you can just change them and get rid of an inconsistency. If yes, then it depends on how much work changing all the usages is. One place I'd check for sure is card search.

Ad concern 2, I think getPlaceholderCard should reflect whatever the format of actual cards in the carddb ends up being.

Ad concern 4, who says you have to determine it based on color identity? The function gets the entire Card as input, so assuming it has details set (which I'm admittedly unsure of), you can just use CARD_CATEGORY_DETECTORS.hybrid.

A word of caution here, though. The current behavior (buggy or not) means Hybrid is a category that has to be set explicitly, and it is never assigned to cards by default. So if you change that, you are possibly creating a situation where existing hybrid cards are sorted under Multicolored, but newly added hybrid cards appear under Hybrid, which feels like undesirable behavior with wide-reaching impact. Color Category is the default primary sort for all cubes, so any changes to its behavior should ve really carefully considered.

@KaelenProctor
Copy link
Contributor Author

KaelenProctor commented Dec 28, 2024

Thanks for the feedback and additional details about my concerns!

Ad concern 1, I'd say that depends on if the value is used anywhere (other than as a default for Card objects). If not, I think you can just change them and get rid of an inconsistency. If yes, then it depends on how much work changing all the usages is. One place I'd check for sure is card search.

In my testing the conversion of the legacy to current color categories don't update on cube JSON unless the color category explicitly changes. eg if a card in the cube JSON has legacy color category "b" instead of "Black" (which the UI will convert that to "Black" for the sorting/display) and then another field on the card changes such as status, the save will not touch the color category field.

The next time the cards list is updated (via jobs/update_cards.js) the carddict.json will use the new colorcategory values. Then afterwards cards added to a cube will use the current color category saved within the card dictionary. And if the card dictionary isn't updated, the legacy to current color category conversions will continue to apply at runtime when the cube UI shows.

Ad concern 2, I think getPlaceholderCard should reflect whatever the format of actual cards in the carddb ends up being.

I've updated the color category to Colorless. I tested by manually mucking one of the card ids in a cube JSON in my local s3, such that the card could not be found and carddb.getPlaceholderCard had to execute. I was able to change the color category via the modal and validate that saved on the card, whereas the card details stayed as Colorless.
placeholder-card

Unsure why both the Card and Card details can container color category, and why one is colorCategory and the other colorcategory

Thanks for explaining. I did further testing and validated that updating the color category on a card only changes the colorCategory on the card, not within the card details.

Ad concern 4, who says you have to determine it based on color identity? The function gets the entire Card as input, so assuming it has details set (which I'm admittedly unsure of), you can just use CARD_CATEGORY_DETECTORS.hybrid.

A word of caution here, though. The current behavior (buggy or not) means Hybrid is a category that has to be set explicitly, and it is never assigned to cards by default. So if you change that, you are possibly creating a situation where existing hybrid cards are sorted under Multicolored, but newly added hybrid cards appear under Hybrid, which feels like undesirable behavior with wide-reaching impact. Color Category is the default primary sort for all cubes, so any changes to its behavior should ve really carefully considered.

Ah, that is helpful to understand. I assumed that there would be some way to detect hybrid for the color category, as you say given the totality of the card details. The current code only uses color identity but as you say it doesn't have to be limited to that, given the casting cost contains the hybrid symbols. Knowing that hybrid is only used when explicitly set makes things simple, meaning there is no additional changes necessary.

@dekkerglen dekkerglen merged commit 3a8f113 into dekkerglen:master Dec 30, 2024
1 check failed
@KaelenProctor KaelenProctor deleted the feature/legacy-color-category-conversions branch December 30, 2024 19:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace with CSV File Upload Not Working
3 participants