Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd70b0c5

Browse files
committed
restore list ?q query param
1 parentac9864f commitd70b0c5

File tree

8 files changed

+285
-69
lines changed

8 files changed

+285
-69
lines changed

‎coderd/aitasks.go‎

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/coder/coder/v2/coderd/httpmw"
2323
"github.com/coder/coder/v2/coderd/rbac"
2424
"github.com/coder/coder/v2/coderd/rbac/policy"
25+
"github.com/coder/coder/v2/coderd/searchquery"
2526
"github.com/coder/coder/v2/coderd/taskname"
2627
"github.com/coder/coder/v2/codersdk"
2728

@@ -372,8 +373,7 @@ type tasksListResponse struct {
372373
// @ID list-tasks
373374
// @Security CoderSessionToken
374375
// @Tags Experimental
375-
// @Param owner query string false "Filter by owner (username, UUID, or 'me' for current user)"
376-
// @Param status query string false "Filter by task status (pending, initializing, active, paused, error, unknown)"
376+
// @Param q query string false "Search query for filtering tasks. Supports: owner:<username/uuid/me>, organization:<org-name/uuid>, status:<status>"
377377
// @Success 200 {object} coderd.tasksListResponse
378378
// @Router /api/experimental/tasks [get]
379379
//
@@ -384,47 +384,18 @@ func (api *API) tasksList(rw http.ResponseWriter, r *http.Request) {
384384
apiKey:=httpmw.APIKey(r)
385385

386386
// Parse query parameters for filtering tasks.
387-
ownerParam:=r.URL.Query().Get("owner")
388-
statusParam:=r.URL.Query().Get("status")
389-
390-
// Determine owner ID based on the owner parameter.
391-
varownerID uuid.UUID
392-
switchownerParam {
393-
casecodersdk.Me:
394-
ownerID=apiKey.UserID
395-
case"":
396-
// If ownerID is not set, list all tasks the user has access to.
397-
default:
398-
// Try to parse as UUID first.
399-
parsedUUID,err:=uuid.Parse(ownerParam)
400-
iferr==nil {
401-
ownerID=parsedUUID
402-
}elseiferr!=nil {
403-
// Otherwise, look up by username.
404-
user,err:=api.Database.GetUserByEmailOrUsername(ctx, database.GetUserByEmailOrUsernameParams{
405-
Username:ownerParam,
406-
})
407-
iferr!=nil {
408-
ifhttpapi.Is404Error(err) {
409-
httpapi.ResourceNotFound(rw)
410-
return
411-
}
412-
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
413-
Message:"Internal error fetching user.",
414-
Detail:err.Error(),
415-
})
416-
return
417-
}
418-
ownerID=user.ID
419-
}
387+
queryStr:=r.URL.Query().Get("q")
388+
filter,errs:=searchquery.Tasks(ctx,api.Database,queryStr,apiKey.UserID)
389+
iflen(errs)>0 {
390+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
391+
Message:"Invalid task search query.",
392+
Validations:errs,
393+
})
394+
return
420395
}
421396

422397
// Fetch all tasks matching the filters from the database.
423-
dbTasks,err:=api.Database.ListTasks(ctx, database.ListTasksParams{
424-
OwnerID:ownerID,
425-
OrganizationID:uuid.Nil,// TODO(mafredri): ?
426-
Status:statusParam,
427-
})
398+
dbTasks,err:=api.Database.ListTasks(ctx,filter)
428399
iferr!=nil {
429400
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
430401
Message:"Internal error fetching tasks.",

‎coderd/apidoc/docs.go‎

Lines changed: 2 additions & 8 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/apidoc/swagger.json‎

Lines changed: 2 additions & 8 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/searchquery/search.go‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,39 @@ func AIBridgeInterceptions(ctx context.Context, db database.Store, query string,
391391
returnfilter,parser.Errors
392392
}
393393

394+
// Tasks parses a search query for tasks.
395+
//
396+
// Supported query parameters:
397+
// - owner: string (username, UUID, or 'me' for current user)
398+
// - organization: string (organization UUID or name)
399+
// - status: string (pending, initializing, active, paused, error, unknown)
400+
funcTasks(ctx context.Context,db database.Store,querystring,actorID uuid.UUID) (database.ListTasksParams, []codersdk.ValidationError) {
401+
filter:= database.ListTasksParams{}
402+
403+
ifquery=="" {
404+
returnfilter,nil
405+
}
406+
407+
// Always lowercase for all searches.
408+
query=strings.ToLower(query)
409+
values,errors:=searchTerms(query,func(termstring,values url.Values)error {
410+
// Default unqualified terms to owner
411+
values.Add("owner",term)
412+
returnnil
413+
})
414+
iflen(errors)>0 {
415+
returnfilter,errors
416+
}
417+
418+
parser:=httpapi.NewQueryParamParser()
419+
filter.OwnerID=parseUser(ctx,db,parser,values,"owner",actorID)
420+
filter.OrganizationID=parseOrganization(ctx,db,parser,values,"organization")
421+
filter.Status=parser.String(values,"","status")
422+
423+
parser.ErrorExcessParams(values)
424+
returnfilter,parser.Errors
425+
}
426+
394427
funcsearchTerms(querystring,defaultKeyfunc(termstring,values url.Values)error) (url.Values, []codersdk.ValidationError) {
395428
searchValues:=make(url.Values)
396429

‎coderd/searchquery/search_test.go‎

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,3 +944,199 @@ func TestSearchTemplates(t *testing.T) {
944944
})
945945
}
946946
}
947+
948+
funcTestSearchTasks(t*testing.T) {
949+
t.Parallel()
950+
951+
userID:=uuid.MustParse("10000000-0000-0000-0000-000000000001")
952+
orgID:=uuid.MustParse("20000000-0000-0000-0000-000000000001")
953+
954+
testCases:= []struct {
955+
Namestring
956+
Querystring
957+
ActorID uuid.UUID
958+
Expected database.ListTasksParams
959+
ExpectedErrorContainsstring
960+
Setupfunc(t*testing.T,db database.Store)
961+
}{
962+
{
963+
Name:"Empty",
964+
Query:"",
965+
Expected: database.ListTasksParams{},
966+
},
967+
{
968+
Name:"OwnerUsername",
969+
Query:"owner:alice",
970+
Setup:func(t*testing.T,db database.Store) {
971+
dbgen.User(t,db, database.User{
972+
ID:userID,
973+
Username:"alice",
974+
})
975+
},
976+
Expected: database.ListTasksParams{
977+
OwnerID:userID,
978+
},
979+
},
980+
{
981+
Name:"OwnerMe",
982+
Query:"owner:me",
983+
ActorID:userID,
984+
Expected: database.ListTasksParams{
985+
OwnerID:userID,
986+
},
987+
},
988+
{
989+
Name:"OwnerUUID",
990+
Query:fmt.Sprintf("owner:%s",userID),
991+
Expected: database.ListTasksParams{
992+
OwnerID:userID,
993+
},
994+
},
995+
{
996+
Name:"StatusActive",
997+
Query:"status:active",
998+
Expected: database.ListTasksParams{
999+
Status:"active",
1000+
},
1001+
},
1002+
{
1003+
Name:"StatusPending",
1004+
Query:"status:pending",
1005+
Expected: database.ListTasksParams{
1006+
Status:"pending",
1007+
},
1008+
},
1009+
{
1010+
Name:"Organization",
1011+
Query:"organization:acme",
1012+
Setup:func(t*testing.T,db database.Store) {
1013+
dbgen.Organization(t,db, database.Organization{
1014+
ID:orgID,
1015+
Name:"acme",
1016+
})
1017+
},
1018+
Expected: database.ListTasksParams{
1019+
OrganizationID:orgID,
1020+
},
1021+
},
1022+
{
1023+
Name:"OrganizationUUID",
1024+
Query:fmt.Sprintf("organization:%s",orgID),
1025+
Expected: database.ListTasksParams{
1026+
OrganizationID:orgID,
1027+
},
1028+
},
1029+
{
1030+
Name:"Combined",
1031+
Query:"owner:alice organization:acme status:active",
1032+
Setup:func(t*testing.T,db database.Store) {
1033+
dbgen.Organization(t,db, database.Organization{
1034+
ID:orgID,
1035+
Name:"acme",
1036+
})
1037+
dbgen.User(t,db, database.User{
1038+
ID:userID,
1039+
Username:"alice",
1040+
})
1041+
},
1042+
Expected: database.ListTasksParams{
1043+
OwnerID:userID,
1044+
OrganizationID:orgID,
1045+
Status:"active",
1046+
},
1047+
},
1048+
{
1049+
Name:"QuotedOwner",
1050+
Query:`owner:"alice"`,
1051+
Setup:func(t*testing.T,db database.Store) {
1052+
dbgen.User(t,db, database.User{
1053+
ID:userID,
1054+
Username:"alice",
1055+
})
1056+
},
1057+
Expected: database.ListTasksParams{
1058+
OwnerID:userID,
1059+
},
1060+
},
1061+
{
1062+
Name:"QuotedStatus",
1063+
Query:`status:"pending"`,
1064+
Expected: database.ListTasksParams{
1065+
Status:"pending",
1066+
},
1067+
},
1068+
{
1069+
Name:"DefaultToOwner",
1070+
Query:"alice",
1071+
Setup:func(t*testing.T,db database.Store) {
1072+
dbgen.User(t,db, database.User{
1073+
ID:userID,
1074+
Username:"alice",
1075+
})
1076+
},
1077+
Expected: database.ListTasksParams{
1078+
OwnerID:userID,
1079+
},
1080+
},
1081+
{
1082+
Name:"InvalidOwner",
1083+
Query:"owner:nonexistent",
1084+
ExpectedErrorContains:"does not exist",
1085+
},
1086+
{
1087+
Name:"InvalidOrganization",
1088+
Query:"organization:nonexistent",
1089+
ExpectedErrorContains:"does not exist",
1090+
},
1091+
{
1092+
Name:"ExtraParam",
1093+
Query:"owner:alice invalid:param",
1094+
Setup:func(t*testing.T,db database.Store) {
1095+
dbgen.User(t,db, database.User{
1096+
ID:userID,
1097+
Username:"alice",
1098+
})
1099+
},
1100+
ExpectedErrorContains:"is not a valid query param",
1101+
},
1102+
{
1103+
Name:"ExtraColon",
1104+
Query:"owner:alice:extra",
1105+
ExpectedErrorContains:"can only contain 1 ':'",
1106+
},
1107+
{
1108+
Name:"PrefixColon",
1109+
Query:":owner",
1110+
ExpectedErrorContains:"cannot start or end with ':'",
1111+
},
1112+
{
1113+
Name:"SuffixColon",
1114+
Query:"owner:",
1115+
ExpectedErrorContains:"cannot start or end with ':'",
1116+
},
1117+
}
1118+
1119+
for_,c:=rangetestCases {
1120+
t.Run(c.Name,func(t*testing.T) {
1121+
t.Parallel()
1122+
db,_:=dbtestutil.NewDB(t)
1123+
1124+
ifc.Setup!=nil {
1125+
c.Setup(t,db)
1126+
}
1127+
1128+
values,errs:=searchquery.Tasks(context.Background(),db,c.Query,c.ActorID)
1129+
ifc.ExpectedErrorContains!="" {
1130+
require.True(t,len(errs)>0,"expect some errors")
1131+
vars strings.Builder
1132+
for_,err:=rangeerrs {
1133+
_,_=s.WriteString(fmt.Sprintf("%s: %s\n",err.Field,err.Detail))
1134+
}
1135+
require.Contains(t,s.String(),c.ExpectedErrorContains)
1136+
}else {
1137+
require.Len(t,errs,0,"expected no error")
1138+
require.Equal(t,c.Expected,values,"expected values")
1139+
}
1140+
})
1141+
}
1142+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp