diff --git a/api/graphql/graph/repository.generated.go b/api/graphql/graph/repository.generated.go index dcc351c9e41708467edfcec9f83e295af18f1c75..81e39832ce30d106fd54672bbf7e2a362f121fa8 100644 --- a/api/graphql/graph/repository.generated.go +++ b/api/graphql/graph/repository.generated.go @@ -19,7 +19,6 @@ import ( type RepositoryResolver interface { Name(ctx context.Context, obj *models.Repository) (*string, error) - LocalName(ctx context.Context, obj *models.Repository) (string, error) AllBugs(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int, query *string) (*models.BugConnection, error) Bug(ctx context.Context, obj *models.Repository, prefix string) (models.BugWrapper, error) AllIdentities(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) @@ -451,50 +450,6 @@ func (ec *executionContext) fieldContext_Repository_name(_ context.Context, fiel return fc, nil } -func (ec *executionContext) _Repository_localName(ctx context.Context, field graphql.CollectedField, obj *models.Repository) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Repository_localName(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Repository().LocalName(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Repository_localName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Repository", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _Repository_allBugs(ctx context.Context, field graphql.CollectedField, obj *models.Repository) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Repository_allBugs(ctx, field) if err != nil { @@ -990,8 +945,6 @@ func (ec *executionContext) fieldContext_RepositoryConnection_nodes(_ context.Co switch field.Name { case "name": return ec.fieldContext_Repository_name(ctx, field) - case "localName": - return ec.fieldContext_Repository_localName(ctx, field) case "allBugs": return ec.fieldContext_Repository_allBugs(ctx, field) case "bug": @@ -1194,8 +1147,6 @@ func (ec *executionContext) fieldContext_RepositoryEdge_node(_ context.Context, switch field.Name { case "name": return ec.fieldContext_Repository_name(ctx, field) - case "localName": - return ec.fieldContext_Repository_localName(ctx, field) case "allBugs": return ec.fieldContext_Repository_allBugs(ctx, field) case "bug": @@ -1270,42 +1221,6 @@ func (ec *executionContext) _Repository(ctx context.Context, sel ast.SelectionSe continue } - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - case "localName": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Repository_localName(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue - } - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "allBugs": field := field diff --git a/api/graphql/graph/root.generated.go b/api/graphql/graph/root.generated.go index 6320d8779370f5d145cd5a6b9e7b3a76f1c354f5..885d556efc903fddff6ced9d8427cda6548fbaf1 100644 --- a/api/graphql/graph/root.generated.go +++ b/api/graphql/graph/root.generated.go @@ -1112,8 +1112,6 @@ func (ec *executionContext) fieldContext_Query_repository(ctx context.Context, f switch field.Name { case "name": return ec.fieldContext_Repository_name(ctx, field) - case "localName": - return ec.fieldContext_Repository_localName(ctx, field) case "allBugs": return ec.fieldContext_Repository_allBugs(ctx, field) case "bug": diff --git a/api/graphql/graph/root_.generated.go b/api/graphql/graph/root_.generated.go index b1efaede20aa290f4c550cb56f821f9c7791693c..a6a5ef1939b78093be919c22390b9d332cf42578 100644 --- a/api/graphql/graph/root_.generated.go +++ b/api/graphql/graph/root_.generated.go @@ -385,7 +385,6 @@ type ComplexityRoot struct { AllIdentities func(childComplexity int, after *string, before *string, first *int, last *int) int Bug func(childComplexity int, prefix string) int Identity func(childComplexity int, prefix string) int - LocalName func(childComplexity int) int Name func(childComplexity int) int UserIdentity func(childComplexity int) int ValidLabels func(childComplexity int, after *string, before *string, first *int, last *int) int @@ -1857,13 +1856,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Repository.Identity(childComplexity, args["prefix"].(string)), true - case "Repository.localName": - if e.complexity.Repository.LocalName == nil { - break - } - - return e.complexity.Repository.LocalName(childComplexity), true - case "Repository.name": if e.complexity.Repository.Name == nil { break @@ -2736,9 +2728,6 @@ type OperationEdge { """The name of the repository. Null for the default (unnamed) repository.""" name: String - """The local directory name of the repository (basename only, no path).""" - localName: String! - """All the bugs""" allBugs( """Returns the elements in the list that come after the specified cursor.""" diff --git a/api/graphql/schema/repository.graphql b/api/graphql/schema/repository.graphql index a50e8773adafb396b0494d08a255ab276de09ddd..f72ea69fd28c4ab3485f083c78dddc53a6e0c9e4 100644 --- a/api/graphql/schema/repository.graphql +++ b/api/graphql/schema/repository.graphql @@ -2,9 +2,6 @@ type Repository { """The name of the repository. Null for the default (unnamed) repository.""" name: String - """The local directory name of the repository (basename only, no path).""" - localName: String! - """All the bugs""" allBugs( """Returns the elements in the list that come after the specified cursor.""" diff --git a/webui2/src/components/bugs/IssueFilters.tsx b/webui2/src/components/bugs/IssueFilters.tsx index fade722c393cd9c9175a7993dd9f3c1e3c7b544a..45d420ab561c7fd409b15a249d3c4f1d78b08be7 100644 --- a/webui2/src/components/bugs/IssueFilters.tsx +++ b/webui2/src/components/bugs/IssueFilters.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import { ChevronDown, Tag, User, X, Search, Check } from 'lucide-react' +import { ArrowUpDown, ChevronDown, Tag, User, X, Search, Check } from 'lucide-react' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { LabelBadge } from './LabelBadge' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' @@ -26,6 +26,15 @@ function authorQueryValue(i: { login?: string | null; name?: string | null; huma return i.login || i.name || i.humanId } +export type SortValue = 'creation-desc' | 'creation-asc' | 'edit-desc' | 'edit-asc' + +const SORT_OPTIONS: { value: SortValue; label: string }[] = [ + { value: 'creation-desc', label: 'Newest' }, + { value: 'creation-asc', label: 'Oldest' }, + { value: 'edit-desc', label: 'Recently updated' }, + { value: 'edit-asc', label: 'Least recently updated' }, +] + interface IssueFiltersProps { selectedLabels: string[] onLabelsChange: (labels: string[]) => void @@ -33,6 +42,8 @@ interface IssueFiltersProps { onAuthorChange: (humanId: string | null, queryValue: string | null) => void /** humanIds of authors appearing in the current bug list, used to rank the initial suggestions */ recentAuthorIds?: string[] + sort: SortValue + onSortChange: (sort: SortValue) => void } // Label and author filter dropdowns shown in the issue list header bar. @@ -52,6 +63,8 @@ export function IssueFilters({ selectedAuthorId, onAuthorChange, recentAuthorIds = [], + sort, + onSortChange, }: IssueFiltersProps) { const { user } = useAuth() const repo = useRepo() @@ -135,7 +148,7 @@ export function IssueFilters({ const selectedAuthorIdentity = allIdentities.find((i) => i.humanId === selectedAuthorId) return ( -