Fix tag hide/show toggle in Tag Management not persisting (#5226) * Initial plan * Fix tag hide/show in Tag Management: pass original tag refs instead of copies, fix inverted tooltip Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Revert unrelated package-lock.json changes Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Revert tooltip change: tooltip shows current state, not action after click Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Pre-calculate tag counts into a Map and pass to sortTags for sort-by-usage Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Revert unintended package-lock.json changes from npm install Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Use instanceof Map for counts checks, add missing JSDoc param for sortTags Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Revert unintended package-lock.json changes Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Remove legacy `count` field * Improve readability (marginally) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -326,7 +326,6 @@ const TAG_FOLDER_DEFAULT_TYPE = 'NONE'; | |||
| 326 | * @property {string} [folder_type] - The bogus folder type of this tag (based on `TAG_FOLDER_TYPES`) | 326 | * @property {string} [folder_type] - The bogus folder type of this tag (based on `TAG_FOLDER_TYPES`) |
| 327 | * @property {string} [filter_state] - The saved state of the filter chosen of this tag (based on `FILTER_STATES`) | 327 | * @property {string} [filter_state] - The saved state of the filter chosen of this tag (based on `FILTER_STATES`) |
| 328 | * @property {number} [sort_order] - A custom integer representing the sort order if tags are sorted | 328 | * @property {number} [sort_order] - A custom integer representing the sort order if tags are sorted |
| 329 | * @property {number} [count] - The number of entities that have this tag assigned | ||
| 330 | * @property {string} [color] - The background color of the tag | 329 | * @property {string} [color] - The background color of the tag |
| 331 | * @property {string} [color2] - The foreground color of the tag | 330 | * @property {string} [color2] - The foreground color of the tag |
| 332 | * @property {number} [create_date] - A number representing the date when this tag was created | 331 | * @property {number} [create_date] - A number representing the date when this tag was created |
| @@ -1764,10 +1763,11 @@ function makeTagListDraggable(tagContainer) { | |||
| 1764 | * Sorts the given tags, returning a shallow copy of it | 1763 | * Sorts the given tags, returning a shallow copy of it |
| 1765 | * | 1764 | * |
| 1766 | * @param {Tag[]} tags - The tags | 1765 | * @param {Tag[]} tags - The tags |
| 1766 | * @param {Map<string, number>} [counts=null] - Optional map of tag ID to usage count | ||
| 1767 | * @returns {Tag[]} The sorted tags | 1767 | * @returns {Tag[]} The sorted tags |
| 1768 | */ | 1768 | */ |
| 1769 | function sortTags(tags) { | 1769 | function sortTags(tags, counts = null) { |
| 1770 | return tags.slice().sort(compareTagsForSort); | 1770 | return tags.slice().sort((a, b) => compareTagsForSort(a, b, counts)); |
| 1771 | } | 1771 | } |
| 1772 | 1772 | ||
| 1773 | /** | 1773 | /** |
| @@ -1775,15 +1775,18 @@ function sortTags(tags) { | |||
| 1775 | * | 1775 | * |
| 1776 | * @param {Tag} a - First tag | 1776 | * @param {Tag} a - First tag |
| 1777 | * @param {Tag} b - Second tag | 1777 | * @param {Tag} b - Second tag |
| 1778 | * @param {Map<string, number>} [counts=null] - Optional map of tag ID to usage count | ||
| 1778 | * @returns {number} The compare result | 1779 | * @returns {number} The compare result |
| 1779 | */ | 1780 | */ |
| 1780 | function compareTagsForSort(a, b) { | 1781 | function compareTagsForSort(a, b, counts = null) { |
| 1781 | // default sort: alphabetical, case insensitive | 1782 | // default sort: alphabetical, case insensitive |
| 1782 | const defaultSort = a.name.toLowerCase().localeCompare(b.name.toLowerCase()); | 1783 | const defaultSort = a.name.toLowerCase().localeCompare(b.name.toLowerCase()); |
| 1783 | 1784 | ||
| 1784 | // sort on number of entries | 1785 | // sort on number of entries |
| 1785 | if (power_user.tag_sort_mode === tag_sort_mode.BY_ENTRIES) { | 1786 | if (power_user.tag_sort_mode === tag_sort_mode.BY_ENTRIES) { |
| 1786 | return ((b.count || 0) - (a.count || 0)) || defaultSort; | 1787 | const aCount = counts instanceof Map ? (counts.get(a.id) || 0) : 0; |
| 1788 | const bCount = counts instanceof Map ? (counts.get(b.id) || 0) : 0; | ||
| 1789 | return (bCount - aCount) || defaultSort; | ||
| 1787 | } | 1790 | } |
| 1788 | 1791 | ||
| 1789 | // alphabetical sort | 1792 | // alphabetical sort |
| @@ -2273,13 +2276,11 @@ function copyTags(data) { | |||
| 2273 | function printViewTagList(tagContainer, empty = true) { | 2276 | function printViewTagList(tagContainer, empty = true) { |
| 2274 | if (empty) tagContainer.empty(); | 2277 | if (empty) tagContainer.empty(); |
| 2275 | const everything = Object.values(tag_map).flat(); | 2278 | const everything = Object.values(tag_map).flat(); |
| 2276 | const tagsWithCounts = tags.map(tag => { | 2279 | const counts = new Map(tags.map(tag => [tag.id, everything.filter(x => x === tag.id).length])); |
| 2277 | const count = everything.filter(x => x === tag.id).length; | 2280 | const sortedTags = sortTags(tags, counts); |
| 2278 | return { ...tag, count: count }; | ||
| 2279 | }); | ||
| 2280 | const sortedTags = sortTags(tagsWithCounts); | ||
| 2281 | for (const tag of sortedTags) { | 2281 | for (const tag of sortedTags) { |
| 2282 | appendViewTagToList(tagContainer, tag, tag.count); | 2282 | const count = counts.get(tag.id) || 0; |
| 2283 | appendViewTagToList(tagContainer, tag, count); | ||
| 2283 | } | 2284 | } |
| 2284 | } | 2285 | } |
| 2285 | 2286 | ||