Tag Folders folder filter showing only folders

This commit is contained in:
Wolfsblvt 2024-05-15 02:06:11 +02:00
parent 8c55e1b05b
commit bb2f553c46
3 changed files with 44 additions and 15 deletions

View File

@ -191,7 +191,7 @@ import { NOTE_MODULE_NAME, initAuthorsNote, metadata_keys, setFloatingPrompt, sh
import { registerPromptManagerMigration } from './scripts/PromptManager.js'; import { registerPromptManagerMigration } from './scripts/PromptManager.js';
import { getRegexedString, regex_placement } from './scripts/extensions/regex/engine.js'; import { getRegexedString, regex_placement } from './scripts/extensions/regex/engine.js';
import { initLogprobs, saveLogprobsForActiveMessage } from './scripts/logprobs.js'; import { initLogprobs, saveLogprobsForActiveMessage } from './scripts/logprobs.js';
import { FILTER_TYPES, FilterHelper } from './scripts/filters.js'; import { FILTER_STATES, FILTER_TYPES, FilterHelper, isFilterState } from './scripts/filters.js';
import { getCfgPrompt, getGuidanceScale, initCfg } from './scripts/cfg-scale.js'; import { getCfgPrompt, getGuidanceScale, initCfg } from './scripts/cfg-scale.js';
import { import {
force_output_sequence, force_output_sequence,
@ -1387,7 +1387,7 @@ function verifyCharactersSearchSortRule() {
* @typedef {object} Entity - Object representing a display entity * @typedef {object} Entity - Object representing a display entity
* @property {Character|Group|import('./scripts/tags.js').Tag|*} item - The item * @property {Character|Group|import('./scripts/tags.js').Tag|*} item - The item
* @property {string|number} id - The id * @property {string|number} id - The id
* @property {string} type - The type of this entity (character, group, tag) * @property {'character'|'group'|'tag'} type - The type of this entity (character, group, tag)
* @property {Entity[]} [entities] - An optional list of entities relevant for this item * @property {Entity[]} [entities] - An optional list of entities relevant for this item
* @property {number} [hidden] - An optional number representing how many hidden entities this entity contains * @property {number} [hidden] - An optional number representing how many hidden entities this entity contains
*/ */
@ -1462,7 +1462,8 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) {
const subCount = subEntities.length; const subCount = subEntities.length;
subEntities = filterByTagState(entities, { subForEntity: entity }); subEntities = filterByTagState(entities, { subForEntity: entity });
if (doFilter) { if (doFilter) {
subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false }); // sub entities filter "hacked" because folder filter should not be applied there, so even in "only folders" mode characters show up
subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED } });
} }
entity.entities = subEntities; entity.entities = subEntities;
entity.hidden = subCount - subEntities.length; entity.hidden = subCount - subEntities.length;
@ -1471,8 +1472,13 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) {
// Second run filters, hiding whatever should be filtered later // Second run filters, hiding whatever should be filtered later
if (doFilter) { if (doFilter) {
entities = filterByTagState(entities, { globalDisplayFilters: true }); const beforeFinalEntities = filterByTagState(entities, { globalDisplayFilters: true });
entities = entitiesFilter.applyFilters(entities); entities = entitiesFilter.applyFilters(beforeFinalEntities);
// Magic for folder filter. If that one is enabled, and no folders are display anymore, we remove that filter to actually show the characters.
if (isFilterState(entitiesFilter.getFilterData(FILTER_TYPES.FOLDER), FILTER_STATES.SELECTED) && entities.filter(x => x.type == 'tag').length == 0) {
entities = entitiesFilter.applyFilters(beforeFinalEntities, { tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED } });
}
} }
if (doSort) { if (doSort) {

View File

@ -258,9 +258,8 @@ export class FilterHelper {
*/ */
folderFilter(data) { folderFilter(data) {
const state = this.filterData[FILTER_TYPES.FOLDER]; const state = this.filterData[FILTER_TYPES.FOLDER];
// Slightly different than the other filters, as a positive folder filter means it doesn't filter anything (folders get "not hidden" at another place), // Filter directly on folder. Special rules on still displaying characters with active folder filter are implemented in 'getEntitiesList' directly.
// while a negative state should then filter out all folders. const isFolder = entity => entity.type === 'tag';
const isFolder = entity => isFilterState(state, FILTER_STATES.SELECTED) ? true : entity.type === 'tag';
return this.filterDataByState(data, state, isFolder); return this.filterDataByState(data, state, isFolder);
} }
@ -342,15 +341,40 @@ export class FilterHelper {
* Applies all filters to the given data. * Applies all filters to the given data.
* @param {any[]} data - The data to filter. * @param {any[]} data - The data to filter.
* @param {object} options - Optional call parameters * @param {object} options - Optional call parameters
* @param {boolean|FilterType} [options.clearScoreCache=true] - Whether the score * @param {boolean} [options.clearScoreCache=true] - Whether the score cache should be cleared.
* @param {Object.<FilterType, any>} [options.tempOverrides={}] - Temporarily override specific filters for this filter application
* @returns {any[]} The filtered data. * @returns {any[]} The filtered data.
*/ */
applyFilters(data, { clearScoreCache = true } = {}) { applyFilters(data, { clearScoreCache = true, tempOverrides = {} } = {}) {
if (clearScoreCache) this.clearScoreCache(); if (clearScoreCache) this.clearScoreCache();
return Object.values(this.filterFunctions)
.reduce((data, fn) => fn(data), data); // Save original filter states
const originalStates = {};
for (const key in tempOverrides) {
originalStates[key] = this.filterData[key];
this.filterData[key] = tempOverrides[key];
}
try {
const result = Object.values(this.filterFunctions)
.reduce((data, fn) => fn(data), data);
// Restore original filter states
for (const key in originalStates) {
this.filterData[key] = originalStates[key];
}
return result;
} catch (error) {
// Restore original filter states in case of an error
for (const key in originalStates) {
this.filterData[key] = originalStates[key];
}
throw error;
}
} }
/** /**
* Cache scores for a specific filter type * Cache scores for a specific filter type
* @param {FilterType} type - The type of data being cached * @param {FilterType} type - The type of data being cached

View File

@ -63,7 +63,7 @@ export const tag_filter_types = {
const ACTIONABLE_TAGS = { const ACTIONABLE_TAGS = {
FAV: { id: '1', sort_order: 1, name: 'Show only favorites', color: 'rgba(255, 255, 0, 0.5)', action: filterByFav, icon: 'fa-solid fa-star', class: 'filterByFavorites' }, FAV: { id: '1', sort_order: 1, name: 'Show only favorites', color: 'rgba(255, 255, 0, 0.5)', action: filterByFav, icon: 'fa-solid fa-star', class: 'filterByFavorites' },
GROUP: { id: '0', sort_order: 2, name: 'Show only groups', color: 'rgba(100, 100, 100, 0.5)', action: filterByGroups, icon: 'fa-solid fa-users', class: 'filterByGroups' }, GROUP: { id: '0', sort_order: 2, name: 'Show only groups', color: 'rgba(100, 100, 100, 0.5)', action: filterByGroups, icon: 'fa-solid fa-users', class: 'filterByGroups' },
FOLDER: { id: '4', sort_order: 3, name: 'Always show folders', color: 'rgba(120, 120, 120, 0.5)', action: filterByFolder, icon: 'fa-solid fa-folder-plus', class: 'filterByFolder' }, FOLDER: { id: '4', sort_order: 3, name: 'Show only folders', color: 'rgba(120, 120, 120, 0.5)', action: filterByFolder, icon: 'fa-solid fa-folder-plus', class: 'filterByFolder' },
VIEW: { id: '2', sort_order: 4, name: 'Manage tags', color: 'rgba(150, 100, 100, 0.5)', action: onViewTagsListClick, icon: 'fa-solid fa-gear', class: 'manageTags' }, VIEW: { id: '2', sort_order: 4, name: 'Manage tags', color: 'rgba(150, 100, 100, 0.5)', action: onViewTagsListClick, icon: 'fa-solid fa-gear', class: 'manageTags' },
HINT: { id: '3', sort_order: 5, name: 'Show Tag List', color: 'rgba(150, 100, 100, 0.5)', action: onTagListHintClick, icon: 'fa-solid fa-tags', class: 'showTagList' }, HINT: { id: '3', sort_order: 5, name: 'Show Tag List', color: 'rgba(150, 100, 100, 0.5)', action: onTagListHintClick, icon: 'fa-solid fa-tags', class: 'showTagList' },
UNFILTER: { id: '5', sort_order: 6, name: 'Clear all filters', action: onClearAllFiltersClick, icon: 'fa-solid fa-filter-circle-xmark', class: 'clearAllFilters' }, UNFILTER: { id: '5', sort_order: 6, name: 'Clear all filters', action: onClearAllFiltersClick, icon: 'fa-solid fa-filter-circle-xmark', class: 'clearAllFilters' },
@ -174,9 +174,8 @@ function filterByTagState(entities, { globalDisplayFilters = false, subForEntity
} }
// Hide folders that have 0 visible sub entities after the first filtering round // Hide folders that have 0 visible sub entities after the first filtering round
const alwaysFolder = isFilterState(entitiesFilter.getFilterData(FILTER_TYPES.FOLDER), FILTER_STATES.SELECTED);
if (entity.type === 'tag') { if (entity.type === 'tag') {
return alwaysFolder || entity.entities.length > 0; return entity.entities.length > 0;
} }
return true; return true;