mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 00:13:46 +01:00
Sort tags by name while scraping or merging scenes (#5752)
* Sort tags by name while scraping scenes * TagStore.All should sort by sort_name first * Sort tag by sort name/name in TagIDSelect --------- Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
parent
0f2bc3e01d
commit
db06eae7cb
7 changed files with 42 additions and 5 deletions
|
|
@ -62,7 +62,11 @@ func (r *queryResolver) FindTags(ctx context.Context, tagFilter *models.TagFilte
|
|||
func (r *queryResolver) AllTags(ctx context.Context) (ret []*models.Tag, err error) {
|
||||
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Tag.All(ctx)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/pkg/match"
|
||||
|
|
@ -207,6 +208,10 @@ func (r *queryResolver) ScrapeSingleScene(ctx context.Context, source scraper.So
|
|||
return nil, fmt.Errorf("%w: scraper_id or stash_box_index must be set", ErrInput)
|
||||
}
|
||||
|
||||
for i := range ret {
|
||||
slices.SortFunc(ret[i].Tags, models.ScrapedTagSortFunction)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package models
|
|||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
|
||||
|
|
@ -400,6 +401,10 @@ type ScrapedTag struct {
|
|||
|
||||
func (ScrapedTag) IsScrapedContent() {}
|
||||
|
||||
func ScrapedTagSortFunction(a, b *ScrapedTag) int {
|
||||
return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name))
|
||||
}
|
||||
|
||||
// A movie from a scraping operation...
|
||||
type ScrapedMovie struct {
|
||||
StoredID *string `json:"stored_id"`
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ func FilterTags(excludeRegexps []*regexp.Regexp, tags []*models.ScrapedTag) (new
|
|||
return tags, nil
|
||||
}
|
||||
|
||||
newTags = make([]*models.ScrapedTag, 0, len(tags))
|
||||
|
||||
for _, t := range tags {
|
||||
ignore := false
|
||||
for _, reg := range excludeRegexps {
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ func (qb *TagStore) All(ctx context.Context) ([]*models.Tag, error) {
|
|||
table := qb.table()
|
||||
|
||||
return qb.getMany(ctx, qb.selectDataset().Order(
|
||||
table.Col("name").Asc(),
|
||||
goqu.L("COALESCE(tags.sort_name, tags.name) COLLATE NATURAL_CI").Asc(),
|
||||
table.Col(idColumn).Asc(),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1018,6 +1018,7 @@ type StashBoxConfig struct {
|
|||
GuidelinesURL string `json:"guidelines_url"`
|
||||
RequireSceneDraft bool `json:"require_scene_draft"`
|
||||
EditUpdateLimit int `json:"edit_update_limit"`
|
||||
RequireTagRole bool `json:"require_tag_role"`
|
||||
}
|
||||
|
||||
type StringCriterionInput struct {
|
||||
|
|
@ -2143,6 +2144,8 @@ const (
|
|||
// May grant and rescind invite tokens and resind invite keys
|
||||
RoleEnumManageInvites RoleEnum = "MANAGE_INVITES"
|
||||
RoleEnumBot RoleEnum = "BOT"
|
||||
RoleEnumReadOnly RoleEnum = "READ_ONLY"
|
||||
RoleEnumEditTags RoleEnum = "EDIT_TAGS"
|
||||
)
|
||||
|
||||
var AllRoleEnum = []RoleEnum{
|
||||
|
|
@ -2154,11 +2157,13 @@ var AllRoleEnum = []RoleEnum{
|
|||
RoleEnumInvite,
|
||||
RoleEnumManageInvites,
|
||||
RoleEnumBot,
|
||||
RoleEnumReadOnly,
|
||||
RoleEnumEditTags,
|
||||
}
|
||||
|
||||
func (e RoleEnum) IsValid() bool {
|
||||
switch e {
|
||||
case RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumAdmin, RoleEnumInvite, RoleEnumManageInvites, RoleEnumBot:
|
||||
case RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumAdmin, RoleEnumInvite, RoleEnumManageInvites, RoleEnumBot, RoleEnumReadOnly, RoleEnumEditTags:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -36,7 +36,10 @@ export type SelectObject = {
|
|||
title?: string | null;
|
||||
};
|
||||
|
||||
export type Tag = Pick<GQL.Tag, "id" | "name" | "aliases" | "image_path">;
|
||||
export type Tag = Pick<
|
||||
GQL.Tag,
|
||||
"id" | "name" | "sort_name" | "aliases" | "image_path"
|
||||
>;
|
||||
type Option = SelectOption<Tag>;
|
||||
|
||||
type FindTagsResult = Awaited<
|
||||
|
|
@ -293,7 +296,20 @@ const _TagIDSelect: React.FC<IFilterProps & IFilterIDProps<Tag>> = (props) => {
|
|||
|
||||
const load = async () => {
|
||||
const items = await loadObjectsByID(ids);
|
||||
setValues(items);
|
||||
|
||||
// #4684 - sort items by sort name/name
|
||||
const sortedItems = [...items];
|
||||
sortedItems.sort((a, b) => {
|
||||
const aName = a.sort_name || a.name;
|
||||
const bName = b.sort_name || b.name;
|
||||
|
||||
if (aName && bName) {
|
||||
return aName.localeCompare(bName);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
setValues(sortedItems);
|
||||
};
|
||||
|
||||
load();
|
||||
|
|
|
|||
Loading…
Reference in a new issue