diff --git a/controllers/application.go b/controllers/application.go
index cbd10a90..7b0dd5a8 100644
--- a/controllers/application.go
+++ b/controllers/application.go
@@ -33,13 +33,17 @@ func (c *ApiController) GetApplications() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetApplications(owner)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetApplicationCount(owner)))
- applications := object.GetPaginationApplications(owner, paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetApplicationCount(owner, field, value)))
+ applications := object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(applications, paginator.Nums())
}
}
diff --git a/controllers/organization.go b/controllers/organization.go
index 03894bb0..c347e585 100644
--- a/controllers/organization.go
+++ b/controllers/organization.go
@@ -33,13 +33,17 @@ func (c *ApiController) GetOrganizations() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedOrganizations(object.GetOrganizations(owner))
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetOrganizationCount(owner)))
- organizations := object.GetMaskedOrganizations(object.GetPaginationOrganizations(owner, paginator.Offset(), limit))
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetOrganizationCount(owner, field, value)))
+ organizations := object.GetMaskedOrganizations(object.GetPaginationOrganizations(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
c.ResponseOk(organizations, paginator.Nums())
}
}
diff --git a/controllers/provider.go b/controllers/provider.go
index c10c6f8e..b0dd6448 100644
--- a/controllers/provider.go
+++ b/controllers/provider.go
@@ -16,7 +16,6 @@ package controllers
import (
"encoding/json"
-
"github.com/astaxie/beego/utils/pagination"
"github.com/casbin/casdoor/object"
"github.com/casbin/casdoor/util"
@@ -33,13 +32,17 @@ func (c *ApiController) GetProviders() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedProviders(object.GetProviders(owner))
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetProviderCount(owner)))
- providers := object.GetMaskedProviders(object.GetPaginationProviders(owner, paginator.Offset(), limit))
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetProviderCount(owner, field, value)))
+ providers := object.GetMaskedProviders(object.GetPaginationProviders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
c.ResponseOk(providers, paginator.Nums())
}
}
diff --git a/controllers/record.go b/controllers/record.go
index a0955ed0..b217982b 100644
--- a/controllers/record.go
+++ b/controllers/record.go
@@ -31,13 +31,17 @@ import (
func (c *ApiController) GetRecords() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetRecords()
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRecordCount()))
- records := object.GetPaginationRecords(paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRecordCount(field, value)))
+ records := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(records, paginator.Nums())
}
}
diff --git a/controllers/resource.go b/controllers/resource.go
index c7355c67..683cf164 100644
--- a/controllers/resource.go
+++ b/controllers/resource.go
@@ -35,13 +35,17 @@ func (c *ApiController) GetResources() {
user := c.Input().Get("user")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetResources(owner, user)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetResourceCount(owner, user)))
- resources := object.GetPaginationResources(owner, user, paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetResourceCount(owner, user, field, value)))
+ resources := object.GetPaginationResources(owner, user, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(resources, paginator.Nums())
}
}
diff --git a/controllers/syncer.go b/controllers/syncer.go
index a924934a..0f2d5cdd 100644
--- a/controllers/syncer.go
+++ b/controllers/syncer.go
@@ -33,13 +33,17 @@ func (c *ApiController) GetSyncers() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetSyncers(owner)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSyncerCount(owner)))
- syncers := object.GetPaginationSyncers(owner, paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSyncerCount(owner, field, value)))
+ syncers := object.GetPaginationSyncers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(syncers, paginator.Nums())
}
}
diff --git a/controllers/token.go b/controllers/token.go
index 4cd58b2b..e77a0543 100644
--- a/controllers/token.go
+++ b/controllers/token.go
@@ -35,13 +35,17 @@ func (c *ApiController) GetTokens() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetTokens(owner)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetTokenCount(owner)))
- tokens := object.GetPaginationTokens(owner, paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetTokenCount(owner, field, value)))
+ tokens := object.GetPaginationTokens(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(tokens, paginator.Nums())
}
}
diff --git a/controllers/user.go b/controllers/user.go
index 78f4da96..ce2b4342 100644
--- a/controllers/user.go
+++ b/controllers/user.go
@@ -33,13 +33,17 @@ import (
func (c *ApiController) GetGlobalUsers() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedUsers(object.GetGlobalUsers())
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalUserCount()))
- users := object.GetPaginationGlobalUsers(paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalUserCount(field, value)))
+ users := object.GetPaginationGlobalUsers(paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(users, paginator.Nums())
}
}
@@ -55,13 +59,17 @@ func (c *ApiController) GetUsers() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedUsers(object.GetUsers(owner))
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetUserCount(owner)))
- users := object.GetPaginationUsers(owner, paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetUserCount(owner, field, value)))
+ users := object.GetPaginationUsers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(users, paginator.Nums())
}
}
@@ -322,7 +330,7 @@ func (c *ApiController) GetUserCount() {
count := 0
if isOnline == "" {
- count = object.GetUserCount(owner)
+ count = object.GetUserCount(owner, "", "")
} else {
count = object.GetOnlineUserCount(owner, util.ParseInt(isOnline))
}
diff --git a/controllers/webhook.go b/controllers/webhook.go
index af5a9ebb..e2c0e9de 100644
--- a/controllers/webhook.go
+++ b/controllers/webhook.go
@@ -33,13 +33,17 @@ func (c *ApiController) GetWebhooks() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
+ field := c.Input().Get("field")
+ value := c.Input().Get("value")
+ sortField := c.Input().Get("sortField")
+ sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetWebhooks(owner)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
- paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetWebhookCount(owner)))
- webhooks := object.GetPaginationWebhooks(owner, paginator.Offset(), limit)
+ paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetWebhookCount(owner, field, value)))
+ webhooks := object.GetPaginationWebhooks(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(webhooks, paginator.Nums())
}
}
diff --git a/object/adapter.go b/object/adapter.go
index 32c6066b..c08cedaa 100644
--- a/object/adapter.go
+++ b/object/adapter.go
@@ -16,6 +16,7 @@ package object
import (
"fmt"
+ "github.com/casbin/casdoor/util"
"runtime"
"github.com/astaxie/beego"
@@ -166,3 +167,22 @@ func (a *Adapter) createTable() {
panic(err)
}
}
+
+func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
+ session := adapter.Engine.Limit(limit, offset).Where("1=1")
+ if owner != "" {
+ session = session.And("owner=?", owner)
+ }
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ if sortField == "" || sortOrder == "" {
+ sortField = "created_time"
+ }
+ if sortOrder == "ascend" {
+ session = session.Asc(util.SnakeString(sortField))
+ } else {
+ session = session.Desc(util.SnakeString(sortField))
+ }
+ return session
+}
\ No newline at end of file
diff --git a/object/application.go b/object/application.go
index 870e727b..1f0cab9e 100644
--- a/object/application.go
+++ b/object/application.go
@@ -53,8 +53,12 @@ type Application struct {
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
}
-func GetApplicationCount(owner string) int {
- count, err := adapter.Engine.Count(&Application{Owner: owner})
+func GetApplicationCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Application{})
if err != nil {
panic(err)
}
@@ -72,9 +76,10 @@ func GetApplications(owner string) []*Application {
return applications
}
-func GetPaginationApplications(owner string, offset, limit int) []*Application {
+func GetPaginationApplications(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Application {
applications := []*Application{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&applications, &Application{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&applications)
if err != nil {
panic(err)
}
diff --git a/object/organization.go b/object/organization.go
index 1119a956..47ecf628 100644
--- a/object/organization.go
+++ b/object/organization.go
@@ -15,6 +15,8 @@
package object
import (
+ "fmt"
+
"github.com/casbin/casdoor/cred"
"github.com/casbin/casdoor/util"
"xorm.io/core"
@@ -36,8 +38,12 @@ type Organization struct {
EnableSoftDeletion bool `json:"enableSoftDeletion"`
}
-func GetOrganizationCount(owner string) int {
- count, err := adapter.Engine.Count(&Organization{Owner: owner})
+func GetOrganizationCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Organization{})
if err != nil {
panic(err)
}
@@ -55,9 +61,10 @@ func GetOrganizations(owner string) []*Organization {
return organizations
}
-func GetPaginationOrganizations(owner string, offset, limit int) []*Organization {
+func GetPaginationOrganizations(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Organization {
organizations := []*Organization{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&organizations, &Provider{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&organizations)
if err != nil {
panic(err)
}
diff --git a/object/provider.go b/object/provider.go
index 849185ed..0b3ae9bd 100644
--- a/object/provider.go
+++ b/object/provider.go
@@ -80,8 +80,12 @@ func GetMaskedProviders(providers []*Provider) []*Provider {
return providers
}
-func GetProviderCount(owner string) int {
- count, err := adapter.Engine.Count(&Provider{Owner: owner})
+func GetProviderCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Provider{})
if err != nil {
panic(err)
}
@@ -99,9 +103,10 @@ func GetProviders(owner string) []*Provider {
return providers
}
-func GetPaginationProviders(owner string, offset, limit int) []*Provider {
+func GetPaginationProviders(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Provider {
providers := []*Provider{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&providers, &Provider{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&providers)
if err != nil {
panic(err)
}
diff --git a/object/record.go b/object/record.go
index e79b54eb..35750d6e 100644
--- a/object/record.go
+++ b/object/record.go
@@ -99,8 +99,12 @@ func AddRecord(record *Record) bool {
return affected != 0
}
-func GetRecordCount() int {
- count, err := adapter.Engine.Count(&Record{})
+func GetRecordCount(field, value string) int {
+ session := adapter.Engine.Where("1=1")
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Record{})
if err != nil {
panic(err)
}
@@ -118,9 +122,10 @@ func GetRecords() []*Record {
return records
}
-func GetPaginationRecords(offset, limit int) []*Record {
+func GetPaginationRecords(offset, limit int, field, value, sortField, sortOrder string) []*Record {
records := []*Record{}
- err := adapter.Engine.Desc("id").Limit(limit, offset).Find(&records)
+ session := GetSession("", offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&records)
if err != nil {
panic(err)
}
diff --git a/object/resource.go b/object/resource.go
index c9156642..93310564 100644
--- a/object/resource.go
+++ b/object/resource.go
@@ -39,8 +39,12 @@ type Resource struct {
Description string `xorm:"varchar(1000)" json:"description"`
}
-func GetResourceCount(owner string, user string) int {
- count, err := adapter.Engine.Count(&Resource{Owner: owner, User: user})
+func GetResourceCount(owner, user, field, value string) int {
+ session := adapter.Engine.Where("owner=? and user=?", owner, user)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Resource{})
if err != nil {
panic(err)
}
@@ -63,14 +67,15 @@ func GetResources(owner string, user string) []*Resource {
return resources
}
-func GetPaginationResources(owner, user string, offset, limit int) []*Resource {
+func GetPaginationResources(owner, user string, offset, limit int, field, value, sortField, sortOrder string) []*Resource {
if owner == "built-in" {
owner = ""
user = ""
}
resources := []*Resource{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&resources, &Resource{Owner: owner, User: user})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&resources, &Resource{User: user})
if err != nil {
panic(err)
}
diff --git a/object/syncer.go b/object/syncer.go
index 076be4a7..ce40e884 100644
--- a/object/syncer.go
+++ b/object/syncer.go
@@ -54,8 +54,12 @@ type Syncer struct {
Adapter *Adapter `xorm:"-" json:"-"`
}
-func GetSyncerCount(owner string) int {
- count, err := adapter.Engine.Count(&Syncer{Owner: owner})
+func GetSyncerCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Syncer{})
if err != nil {
panic(err)
}
@@ -73,9 +77,10 @@ func GetSyncers(owner string) []*Syncer {
return syncers
}
-func GetPaginationSyncers(owner string, offset, limit int) []*Syncer {
+func GetPaginationSyncers(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Syncer {
syncers := []*Syncer{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&syncers, &Syncer{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&syncers)
if err != nil {
panic(err)
}
diff --git a/object/token.go b/object/token.go
index 80cb04cd..8fcbcc0d 100644
--- a/object/token.go
+++ b/object/token.go
@@ -53,8 +53,12 @@ type TokenWrapper struct {
Scope string `json:"scope"`
}
-func GetTokenCount(owner string) int {
- count, err := adapter.Engine.Count(&Token{Owner: owner})
+func GetTokenCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Token{})
if err != nil {
panic(err)
}
@@ -72,9 +76,10 @@ func GetTokens(owner string) []*Token {
return tokens
}
-func GetPaginationTokens(owner string, offset, limit int) []*Token {
+func GetPaginationTokens(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Token {
tokens := []*Token{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&tokens, &Token{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&tokens)
if err != nil {
panic(err)
}
diff --git a/object/user.go b/object/user.go
index 66c25bb8..b23ba0b2 100644
--- a/object/user.go
+++ b/object/user.go
@@ -86,8 +86,12 @@ type User struct {
Properties map[string]string `json:"properties"`
}
-func GetGlobalUserCount() int {
- count, err := adapter.Engine.Count(&User{})
+func GetGlobalUserCount(field, value string) int {
+ session := adapter.Engine.Where("1=1")
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&User{})
if err != nil {
panic(err)
}
@@ -105,9 +109,10 @@ func GetGlobalUsers() []*User {
return users
}
-func GetPaginationGlobalUsers(offset, limit int) []*User {
+func GetPaginationGlobalUsers(offset, limit int, field, value, sortField, sortOrder string) []*User {
users := []*User{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&users)
+ session := GetSession("", offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&users)
if err != nil {
panic(err)
}
@@ -115,8 +120,12 @@ func GetPaginationGlobalUsers(offset, limit int) []*User {
return users
}
-func GetUserCount(owner string) int {
- count, err := adapter.Engine.Count(&User{Owner: owner})
+func GetUserCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&User{})
if err != nil {
panic(err)
}
@@ -153,9 +162,10 @@ func GetSortedUsers(owner string, sorter string, limit int) []*User {
return users
}
-func GetPaginationUsers(owner string, offset, limit int) []*User {
+func GetPaginationUsers(owner string, offset, limit int, field, value, sortField, sortOrder string) []*User {
users := []*User{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&users, &User{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&users)
if err != nil {
panic(err)
}
diff --git a/object/webhook.go b/object/webhook.go
index c6db31df..e64bd7a2 100644
--- a/object/webhook.go
+++ b/object/webhook.go
@@ -33,8 +33,12 @@ type Webhook struct {
Organization string `xorm:"varchar(100) index" json:"organization"`
}
-func GetWebhookCount(owner string) int {
- count, err := adapter.Engine.Count(&Webhook{Owner: owner})
+func GetWebhookCount(owner, field, value string) int {
+ session := adapter.Engine.Where("owner=?", owner)
+ if field != "" && value != "" {
+ session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value))
+ }
+ count, err := session.Count(&Webhook{})
if err != nil {
panic(err)
}
@@ -52,9 +56,10 @@ func GetWebhooks(owner string) []*Webhook {
return webhooks
}
-func GetPaginationWebhooks(owner string, offset, limit int) []*Webhook {
+func GetPaginationWebhooks(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Webhook {
webhooks := []*Webhook{}
- err := adapter.Engine.Desc("created_time").Limit(limit, offset).Find(&webhooks, &Webhook{Owner: owner})
+ session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
+ err := session.Find(&webhooks)
if err != nil {
panic(err)
}
diff --git a/util/string.go b/util/string.go
index eab4527d..65e9d823 100644
--- a/util/string.go
+++ b/util/string.go
@@ -162,3 +162,21 @@ func WriteBytesToPath(b []byte, path string) {
panic(err)
}
}
+
+// SnakeString XxYy to xx_yy
+func SnakeString(s string) string {
+ data := make([]byte, 0, len(s)*2)
+ j := false
+ num := len(s)
+ for i := 0; i < num; i++ {
+ d := s[i]
+ if i > 0 && d >= 'A' && d <= 'Z' && j {
+ data = append(data, '_')
+ }
+ if d != '_' {
+ j = true
+ }
+ data = append(data, d)
+ }
+ return strings.ToLower(string(data[:]))
+}
diff --git a/web/package.json b/web/package.json
index 44532b7e..4acdf558 100644
--- a/web/package.json
+++ b/web/package.json
@@ -16,6 +16,7 @@
"i18n-iso-countries": "^7.0.0",
"i18next": "^19.8.9",
"moment": "^2.29.1",
+ "qs": "^6.10.2",
"react": "^17.0.2",
"react-codemirror2": "^7.2.1",
"react-cropper": "^2.1.7",
@@ -23,6 +24,7 @@
"react-dom": "^17.0.2",
"react-github-corner": "^2.5.0",
"react-helmet": "^6.1.0",
+ "react-highlight-words": "^0.17.0",
"react-i18next": "^11.8.7",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
diff --git a/web/src/ApplicationListPage.js b/web/src/ApplicationListPage.js
index 73e600a7..d8cb982b 100644
--- a/web/src/ApplicationListPage.js
+++ b/web/src/ApplicationListPage.js
@@ -20,32 +20,10 @@ import moment from "moment";
import * as Setting from "./Setting";
import * as ApplicationBackend from "./backend/ApplicationBackend";
import i18next from "i18next";
+import BaseListPage from "./BaseListPage";
+import * as ProviderBackend from "./backend/ProviderBackend";
-class ApplicationListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- applications: null,
- total: 0,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.getApplications(1, 10);
- }
-
- getApplications(page, pageSize) {
- ApplicationBackend.getApplications("admin", page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- applications: res.data,
- total: res.data2
- });
- }
- });
- }
+class ApplicationListPage extends BaseListPage {
newApplication() {
const randomName = Setting.getRandomName();
@@ -80,10 +58,6 @@ class ApplicationListPage extends React.Component {
ApplicationBackend.addApplication(newApplication)
.then((res) => {
Setting.showMessage("success", `Application added successfully`);
- this.setState({
- applications: Setting.prependRow(this.state.applications, newApplication),
- total: this.state.total + 1
- });
this.props.history.push(`/applications/${newApplication.name}`);
}
)
@@ -93,12 +67,12 @@ class ApplicationListPage extends React.Component {
}
deleteApplication(i) {
- ApplicationBackend.deleteApplication(this.state.applications[i])
+ ApplicationBackend.deleteApplication(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Application deleted successfully`);
this.setState({
- applications: Setting.deleteRow(this.state.applications, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -115,7 +89,8 @@ class ApplicationListPage extends React.Component {
key: 'name',
width: '150px',
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -129,7 +104,7 @@ class ApplicationListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '160px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -139,7 +114,8 @@ class ApplicationListPage extends React.Component {
dataIndex: 'displayName',
key: 'displayName',
// width: '100px',
- sorter: (a, b) => a.displayName.localeCompare(b.displayName),
+ sorter: true,
+ ...this.getColumnSearchProps('displayName'),
},
{
title: 'Logo',
@@ -159,7 +135,8 @@ class ApplicationListPage extends React.Component {
dataIndex: 'organization',
key: 'organization',
width: '150px',
- sorter: (a, b) => a.organization.localeCompare(b.organization),
+ sorter: true,
+ ...this.getColumnSearchProps('organization'),
render: (text, record, index) => {
return (
@@ -172,6 +149,7 @@ class ApplicationListPage extends React.Component {
title: i18next.t("general:Providers"),
dataIndex: 'providers',
key: 'providers',
+ ...this.getColumnSearchProps('providers'),
// width: '600px',
render: (text, record, index) => {
const providers = text;
@@ -247,12 +225,10 @@ class ApplicationListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getApplications(page, pageSize),
- onShowSizeChange: (current, size) => this.getApplications(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -264,21 +240,33 @@ class ApplicationListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={applications === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.applications)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ this.setState({ loading: true });
+ ApplicationBackend.getApplications("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default ApplicationListPage;
diff --git a/web/src/BaseListPage.js b/web/src/BaseListPage.js
new file mode 100644
index 00000000..b38dd0e3
--- /dev/null
+++ b/web/src/BaseListPage.js
@@ -0,0 +1,138 @@
+// Copyright 2021 The casbin Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import React from "react";
+import {Button, Input, Space} from "antd";
+import {SearchOutlined} from "@ant-design/icons";
+import Highlighter from "react-highlight-words";
+
+class BaseListPage extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ classes: props,
+ data: [],
+ pagination: {
+ current: 1,
+ pageSize: 10,
+ },
+ loading: false,
+ searchText: '',
+ searchedColumn: '',
+ };
+ }
+
+ UNSAFE_componentWillMount() {
+ const { pagination } = this.state;
+ this.fetch({ pagination });
+ }
+
+ getColumnSearchProps = dataIndex => ({
+ filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
+
+ {
+ this.searchInput = node;
+ }}
+ placeholder={`Search ${dataIndex}`}
+ value={selectedKeys[0]}
+ onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
+ onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
+ style={{ marginBottom: 8, display: 'block' }}
+ />
+
+ this.handleSearch(selectedKeys, confirm, dataIndex)}
+ icon={ }
+ size="small"
+ style={{ width: 90 }}
+ >
+ Search
+
+ this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
+ Reset
+
+ {
+ confirm({ closeDropdown: false });
+ this.setState({
+ searchText: selectedKeys[0],
+ searchedColumn: dataIndex,
+ });
+ }}
+ >
+ Filter
+
+
+
+ ),
+ filterIcon: filtered => ,
+ onFilter: (value, record) =>
+ record[dataIndex]
+ ? record[dataIndex].toString().toLowerCase().includes(value.toLowerCase())
+ : '',
+ onFilterDropdownVisibleChange: visible => {
+ if (visible) {
+ setTimeout(() => this.searchInput.select(), 100);
+ }
+ },
+ render: text =>
+ this.state.searchedColumn === dataIndex ? (
+
+ ) : (
+ text
+ ),
+ });
+
+ handleSearch = (selectedKeys, confirm, dataIndex) => {
+ this.fetch({searchText: selectedKeys[0], searchedColumn: dataIndex, pagination: this.state.pagination});
+ };
+
+ handleReset = clearFilters => {
+ clearFilters();
+ const { pagination } = this.state;
+ this.fetch({ pagination });
+ };
+
+ handleTableChange = (pagination, filters, sorter) => {
+ this.fetch({
+ sortField: sorter.field,
+ sortOrder: sorter.order,
+ pagination,
+ ...filters,
+ searchText: this.state.searchText,
+ searchedColumn: this.state.searchedColumn,
+ });
+ };
+
+ render() {
+ return (
+
+ {
+ this.renderTable(this.state.data)
+ }
+
+ );
+ }
+}
+
+export default BaseListPage;
\ No newline at end of file
diff --git a/web/src/OrganizationListPage.js b/web/src/OrganizationListPage.js
index cc913891..4dd23b95 100644
--- a/web/src/OrganizationListPage.js
+++ b/web/src/OrganizationListPage.js
@@ -19,32 +19,9 @@ import moment from "moment";
import * as Setting from "./Setting";
import * as OrganizationBackend from "./backend/OrganizationBackend";
import i18next from "i18next";
+import BaseListPage from "./BaseListPage";
-class OrganizationListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- organizations: null,
- total: 0
- };
- }
-
- UNSAFE_componentWillMount() {
- this.getOrganizations(1, 10);
- }
-
- getOrganizations(page, pageSize) {
- OrganizationBackend.getOrganizations("admin", page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- organizations: res.data,
- total: res.data2
- });
- }
- });
- }
+class OrganizationListPage extends BaseListPage {
newOrganization() {
const randomName = Setting.getRandomName();
@@ -69,10 +46,6 @@ class OrganizationListPage extends React.Component {
OrganizationBackend.addOrganization(newOrganization)
.then((res) => {
Setting.showMessage("success", `Organization added successfully`);
- this.setState({
- organizations: Setting.prependRow(this.state.organizations, newOrganization),
- total: this.state.total + 1
- });
this.props.history.push(`/organizations/${newOrganization.name}`);
}
)
@@ -82,12 +55,12 @@ class OrganizationListPage extends React.Component {
}
deleteOrganization(i) {
- OrganizationBackend.deleteOrganization(this.state.organizations[i])
+ OrganizationBackend.deleteOrganization(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Organization deleted successfully`);
this.setState({
- organizations: Setting.deleteRow(this.state.organizations, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -104,7 +77,8 @@ class OrganizationListPage extends React.Component {
key: 'name',
width: '120px',
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -118,7 +92,7 @@ class OrganizationListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '160px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -128,7 +102,8 @@ class OrganizationListPage extends React.Component {
dataIndex: 'displayName',
key: 'displayName',
// width: '100px',
- sorter: (a, b) => a.displayName.localeCompare(b.displayName),
+ sorter: true,
+ ...this.getColumnSearchProps('displayName'),
},
{
title: i18next.t("organization:Favicon"),
@@ -148,7 +123,8 @@ class OrganizationListPage extends React.Component {
dataIndex: 'websiteUrl',
key: 'websiteUrl',
width: '300px',
- sorter: (a, b) => a.websiteUrl.localeCompare(b.websiteUrl),
+ sorter: true,
+ ...this.getColumnSearchProps('websiteUrl'),
render: (text, record, index) => {
return (
@@ -162,14 +138,21 @@ class OrganizationListPage extends React.Component {
dataIndex: 'passwordType',
key: 'passwordType',
width: '150px',
- sorter: (a, b) => a.passwordType.localeCompare(b.passwordType),
+ sorter: true,
+ filterMultiple: false,
+ filters: [
+ {text: 'plain', value: 'plain'},
+ {text: 'salt', value: 'salt'},
+ {text: 'md5-salt', value: 'md5-salt'},
+ ],
},
{
title: i18next.t("general:Password salt"),
dataIndex: 'passwordSalt',
key: 'passwordSalt',
width: '150px',
- sorter: (a, b) => a.passwordSalt.localeCompare(b.passwordSalt),
+ sorter: true,
+ ...this.getColumnSearchProps('passwordSalt'),
},
{
title: i18next.t("organization:Default avatar"),
@@ -189,7 +172,7 @@ class OrganizationListPage extends React.Component {
dataIndex: 'enableSoftDeletion',
key: 'enableSoftDeletion',
width: '140px',
- sorter: (a, b) => a.enableSoftDeletion - b.enableSoftDeletion,
+ sorter: true,
render: (text, record, index) => {
return (
@@ -221,12 +204,10 @@ class OrganizationListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getOrganizations(page, pageSize),
- onShowSizeChange: (current, size) => this.getOrganizations(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -238,21 +219,37 @@ class OrganizationListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={organizations === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.organizations)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ if (params.passwordType !== undefined && params.passwordType !== null) {
+ field = "passwordType";
+ value = params.passwordType;
+ }
+ this.setState({ loading: true });
+ OrganizationBackend.getOrganizations("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default OrganizationListPage;
diff --git a/web/src/ProviderEditPage.js b/web/src/ProviderEditPage.js
index dcc2370c..5b1bd02c 100644
--- a/web/src/ProviderEditPage.js
+++ b/web/src/ProviderEditPage.js
@@ -64,60 +64,6 @@ class ProviderEditPage extends React.Component {
});
}
- getProviderTypeOptions(provider) {
- if (provider.category === "OAuth") {
- return (
- [
- {id: 'Google', name: 'Google'},
- {id: 'GitHub', name: 'GitHub'},
- {id: 'QQ', name: 'QQ'},
- {id: 'WeChat', name: 'WeChat'},
- {id: 'Facebook', name: 'Facebook'},
- {id: 'DingTalk', name: 'DingTalk'},
- {id: 'Weibo', name: 'Weibo'},
- {id: 'Gitee', name: 'Gitee'},
- {id: 'LinkedIn', name: 'LinkedIn'},
- {id: 'WeCom', name: 'WeCom'},
- {id: 'Lark', name: 'Lark'},
- {id: 'GitLab', name: 'GitLab'},
- {id: 'Apple', name: 'Apple'},
- {id: 'AzureAD', name: 'AzureAD'},
- {id: 'Slack', name: 'Slack'},
- ]
- );
- } else if (provider.category === "Email") {
- return (
- [
- {id: 'Default', name: 'Default'},
- ]
- );
- } else if (provider.category === "SMS") {
- return (
- [
- {id: 'Aliyun SMS', name: 'Aliyun SMS'},
- {id: 'Tencent Cloud SMS', name: 'Tencent Cloud SMS'},
- {id: 'Volc Engine SMS', name: 'Volc Engine SMS'},
- ]
- );
- } else if (provider.category === "Storage") {
- return (
- [
- {id: 'Local File System', name: 'Local File System'},
- {id: 'AWS S3', name: 'AWS S3'},
- {id: 'Aliyun OSS', name: 'Aliyun OSS'},
- {id: 'Tencent Cloud COS', name: 'Tencent Cloud COS'},
- ]
- );
- } else if (provider.category === "SAML") {
- return ([
- {id: 'Aliyun IDaaS', name: 'Aliyun IDaaS'},
- {id: 'Keycloak', name: 'Keycloak'},
- ]);
- } else {
- return [];
- }
- }
-
getClientIdLabel() {
switch (this.state.provider.category) {
case "Email":
@@ -252,7 +198,7 @@ class ProviderEditPage extends React.Component {
}
})}>
{
- this.getProviderTypeOptions(this.state.provider).map((providerType, index) => {providerType.name} )
+ Setting.getProviderTypeOptions(this.state.provider.category).map((providerType, index) => {providerType.name} )
}
diff --git a/web/src/ProviderListPage.js b/web/src/ProviderListPage.js
index 8b468410..3882f1ee 100644
--- a/web/src/ProviderListPage.js
+++ b/web/src/ProviderListPage.js
@@ -20,32 +20,9 @@ import * as Setting from "./Setting";
import * as ProviderBackend from "./backend/ProviderBackend";
import * as Provider from "./auth/Provider";
import i18next from "i18next";
+import BaseListPage from "./BaseListPage";
-class ProviderListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- providers: null,
- total: 0,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.getProviders(1, 10);
- }
-
- getProviders(page, pageSize) {
- ProviderBackend.getProviders("admin", page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- providers: res.data,
- total: res.data2
- });
- }
- });
- }
+class ProviderListPage extends BaseListPage {
newProvider() {
const randomName = Setting.getRandomName();
@@ -71,10 +48,6 @@ class ProviderListPage extends React.Component {
ProviderBackend.addProvider(newProvider)
.then((res) => {
Setting.showMessage("success", `Provider added successfully`);
- this.setState({
- providers: Setting.prependRow(this.state.providers, newProvider),
- total: this.state.total + 1
- });
this.props.history.push(`/providers/${newProvider.name}`);
}
)
@@ -84,12 +57,12 @@ class ProviderListPage extends React.Component {
}
deleteProvider(i) {
- ProviderBackend.deleteProvider(this.state.providers[i])
+ ProviderBackend.deleteProvider(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Provider deleted successfully`);
this.setState({
- providers: Setting.deleteRow(this.state.providers, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -106,7 +79,8 @@ class ProviderListPage extends React.Component {
key: 'name',
width: '120px',
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -120,7 +94,7 @@ class ProviderListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '180px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -130,14 +104,23 @@ class ProviderListPage extends React.Component {
dataIndex: 'displayName',
key: 'displayName',
// width: '100px',
- sorter: (a, b) => a.displayName.localeCompare(b.displayName),
+ sorter: true,
+ ...this.getColumnSearchProps('displayName'),
},
{
title: i18next.t("provider:Category"),
dataIndex: 'category',
key: 'category',
+ filterMultiple: false,
+ filters: [
+ {text: 'OAuth', value: 'OAuth'},
+ {text: 'Email', value: 'Email'},
+ {text: 'SMS', value: 'SMS'},
+ {text: 'Storage', value: 'Storage'},
+ {text: 'SAML', value: 'SAML'},
+ ],
width: '100px',
- sorter: (a, b) => a.category.localeCompare(b.category),
+ sorter: true,
},
{
title: i18next.t("provider:Type"),
@@ -145,7 +128,15 @@ class ProviderListPage extends React.Component {
key: 'type',
width: '80px',
align: 'center',
- sorter: (a, b) => a.type.localeCompare(b.type),
+ filterMultiple: false,
+ filters: [
+ {text: 'OAuth', value: 'OAuth', children: Setting.getProviderTypeOptions('OAuth').map((o) => {return {text:o.id, value:o.name}})},
+ {text: 'Email', value: 'Email', children: Setting.getProviderTypeOptions('Email').map((o) => {return {text:o.id, value:o.name}})},
+ {text: 'SMS', value: 'SMS', children: Setting.getProviderTypeOptions('SMS').map((o) => {return {text:o.id, value:o.name}})},
+ {text: 'Storage', value: 'Storage', children: Setting.getProviderTypeOptions('Storage').map((o) => {return {text:o.id, value:o.name}})},
+ {text: 'SAML', value: 'SAML', children: Setting.getProviderTypeOptions('SAML').map((o) => {return {text:o.id, value:o.name}})},
+ ],
+ sorter: true,
render: (text, record, index) => {
return Provider.getProviderLogoWidget(record);
}
@@ -155,7 +146,8 @@ class ProviderListPage extends React.Component {
dataIndex: 'clientId',
key: 'clientId',
width: '100px',
- sorter: (a, b) => a.clientId.localeCompare(b.clientId),
+ sorter: true,
+ ...this.getColumnSearchProps('clientId'),
render: (text, record, index) => {
return Setting.getShortText(text);
}
@@ -172,7 +164,8 @@ class ProviderListPage extends React.Component {
dataIndex: 'providerUrl',
key: 'providerUrl',
width: '150px',
- sorter: (a, b) => a.providerUrl.localeCompare(b.providerUrl),
+ sorter: true,
+ ...this.getColumnSearchProps('providerUrl'),
render: (text, record, index) => {
return (
@@ -206,12 +199,10 @@ class ProviderListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getProviders(page, pageSize),
- onShowSizeChange: (current, size) => this.getProviders(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -223,21 +214,40 @@ class ProviderListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={providers === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.providers)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ if (params.category !== undefined && params.category !== null) {
+ field = "category";
+ value = params.category;
+ } else if (params.type !== undefined && params.type !== null) {
+ field = "type";
+ value = params.type;
+ }
+ this.setState({ loading: true });
+ ProviderBackend.getProviders("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default ProviderListPage;
diff --git a/web/src/RecordListPage.js b/web/src/RecordListPage.js
index b87289ae..bc4d3fd6 100644
--- a/web/src/RecordListPage.js
+++ b/web/src/RecordListPage.js
@@ -19,31 +19,15 @@ import * as Setting from "./Setting";
import * as RecordBackend from "./backend/RecordBackend";
import i18next from "i18next";
import moment from "moment";
+import BaseListPage from "./BaseListPage";
+import * as ProviderBackend from "./backend/ProviderBackend";
-class RecordListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- records: null,
- total: 0,
- };
- }
+class RecordListPage extends BaseListPage {
UNSAFE_componentWillMount() {
- this.getRecords(1, 20);
- }
-
- getRecords(page, pageSize) {
- RecordBackend.getRecords(page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- records: res.data,
- total: res.data2
- });
- }
- });
+ this.state.pagination.pageSize = 20;
+ const { pagination } = this.state;
+ this.fetch({ pagination });
}
newRecord() {
@@ -68,21 +52,24 @@ class RecordListPage extends React.Component {
dataIndex: 'name',
key: 'name',
width: '320px',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
},
{
title: i18next.t("general:ID"),
dataIndex: 'id',
key: 'id',
width: '90px',
- sorter: (a, b) => a.id - b.id,
+ sorter: true,
+ ...this.getColumnSearchProps('id'),
},
{
title: i18next.t("general:Client IP"),
dataIndex: 'clientIp',
key: 'clientIp',
width: '150px',
- sorter: (a, b) => a.clientIp.localeCompare(b.clientIp),
+ sorter: true,
+ ...this.getColumnSearchProps('clientIp'),
render: (text, record, index) => {
return (
@@ -96,7 +83,7 @@ class RecordListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '180px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -106,7 +93,8 @@ class RecordListPage extends React.Component {
dataIndex: 'organization',
key: 'organization',
width: '80px',
- sorter: (a, b) => a.organization.localeCompare(b.organization),
+ sorter: true,
+ ...this.getColumnSearchProps('organization'),
render: (text, record, index) => {
return (
@@ -120,7 +108,8 @@ class RecordListPage extends React.Component {
dataIndex: 'user',
key: 'user',
width: '120px',
- sorter: (a, b) => a.user.localeCompare(b.user),
+ sorter: true,
+ ...this.getColumnSearchProps('user'),
render: (text, record, index) => {
return (
@@ -134,21 +123,35 @@ class RecordListPage extends React.Component {
dataIndex: 'method',
key: 'method',
width: '100px',
- sorter: (a, b) => a.method.localeCompare(b.method),
+ sorter: true,
+ filterMultiple: false,
+ filters: [
+ {text: 'GET', value: 'GET'},
+ {text: 'HEAD', value: 'HEAD'},
+ {text: 'POST', value: 'POST'},
+ {text: 'PUT', value: 'PUT'},
+ {text: 'DELETE', value: 'DELETE'},
+ {text: 'CONNECT', value: 'CONNECT'},
+ {text: 'OPTIONS', value: 'OPTIONS'},
+ {text: 'TRACE', value: 'TRACE'},
+ {text: 'PATCH', value: 'PATCH'},
+ ],
},
{
title: i18next.t("general:Request URI"),
dataIndex: 'requestUri',
key: 'requestUri',
// width: '300px',
- sorter: (a, b) => a.requestUri.localeCompare(b.requestUri),
+ sorter: true,
+ ...this.getColumnSearchProps('requestUri'),
},
{
title: i18next.t("general:Action"),
dataIndex: 'action',
key: 'action',
width: '200px',
- sorter: (a, b) => a.action.localeCompare(b.action),
+ sorter: true,
+ ...this.getColumnSearchProps('action'),
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return text;
@@ -159,7 +162,7 @@ class RecordListPage extends React.Component {
dataIndex: 'isTriggered',
key: 'isTriggered',
width: '140px',
- sorter: (a, b) => a.isTriggered - b.isTriggered,
+ sorter: true,
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
if (!["signup", "login", "logout", "update-user"].includes(record.action)) {
@@ -174,13 +177,11 @@ class RecordListPage extends React.Component {
];
const paginationProps = {
- pageSize: 20,
- total: this.state.total,
+ total: this.state.pagination.total,
+ pageSize: this.state.pagination.pageSize,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getRecords(page, pageSize),
- onShowSizeChange: (current, size) => this.getRecords(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -191,21 +192,37 @@ class RecordListPage extends React.Component {
{i18next.t("general:Records")}
)}
- loading={records === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.records)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ if (params.method !== undefined && params.method !== null) {
+ field = "method";
+ value = params.method;
+ }
+ this.setState({ loading: true });
+ RecordBackend.getRecords(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default RecordListPage;
diff --git a/web/src/ResourceListPage.js b/web/src/ResourceListPage.js
index 8b72aa1c..ace420ed 100644
--- a/web/src/ResourceListPage.js
+++ b/web/src/ResourceListPage.js
@@ -20,42 +20,34 @@ import * as Setting from "./Setting";
import * as ResourceBackend from "./backend/ResourceBackend";
import i18next from "i18next";
import {Link} from "react-router-dom";
+import BaseListPage from "./BaseListPage";
+import * as ProviderBackend from "./backend/ProviderBackend";
-class ResourceListPage extends React.Component {
+class ResourceListPage extends BaseListPage {
constructor(props) {
super(props);
this.state = {
classes: props,
- resources: null,
+ data: [],
+ pagination: {
+ current: 1,
+ pageSize: 10,
+ },
+ loading: false,
+ searchText: '',
+ searchedColumn: '',
fileList: [],
uploading: false,
- total: 0,
};
}
- UNSAFE_componentWillMount() {
- this.getResources(1, 10);
- }
-
- getResources(page, pageSize) {
- ResourceBackend.getResources(this.props.account.owner, this.props.account.name, page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- resources: res.data,
- total: res.data2
- });
- }
- });
- }
-
deleteResource(i) {
- ResourceBackend.deleteResource(this.state.resources[i])
+ ResourceBackend.deleteResource(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Resource deleted successfully`);
this.setState({
- resources: Setting.deleteRow(this.state.resources, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -100,7 +92,8 @@ class ResourceListPage extends React.Component {
key: 'provider',
width: '150px',
fixed: 'left',
- sorter: (a, b) => a.provider.localeCompare(b.provider),
+ sorter: true,
+ ...this.getColumnSearchProps('provider'),
render: (text, record, index) => {
return (
@@ -114,7 +107,8 @@ class ResourceListPage extends React.Component {
dataIndex: 'application',
key: 'application',
width: '80px',
- sorter: (a, b) => a.application.localeCompare(b.application),
+ sorter: true,
+ ...this.getColumnSearchProps('application'),
render: (text, record, index) => {
return (
@@ -128,7 +122,8 @@ class ResourceListPage extends React.Component {
dataIndex: 'user',
key: 'user',
width: '80px',
- sorter: (a, b) => a.user.localeCompare(b.user),
+ sorter: true,
+ ...this.getColumnSearchProps('user'),
render: (text, record, index) => {
return (
@@ -142,21 +137,23 @@ class ResourceListPage extends React.Component {
dataIndex: 'parent',
key: 'parent',
width: '80px',
- sorter: (a, b) => a.parent.localeCompare(b.parent),
+ sorter: true,
+ ...this.getColumnSearchProps('parent'),
},
{
title: i18next.t("general:Name"),
dataIndex: 'name',
key: 'name',
width: '150px',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
},
{
title: i18next.t("general:Created time"),
dataIndex: 'createdTime',
key: 'createdTime',
width: '150px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -166,7 +163,8 @@ class ResourceListPage extends React.Component {
dataIndex: 'tag',
key: 'tag',
width: '80px',
- sorter: (a, b) => a.tag.localeCompare(b.tag),
+ sorter: true,
+ ...this.getColumnSearchProps('tag'),
},
// {
// title: i18next.t("resource:File name"),
@@ -180,21 +178,23 @@ class ResourceListPage extends React.Component {
dataIndex: 'fileType',
key: 'fileType',
width: '80px',
- sorter: (a, b) => a.fileType.localeCompare(b.fileType),
+ sorter: true,
+ ...this.getColumnSearchProps('fileType'),
},
{
title: i18next.t("resource:Format"),
dataIndex: 'fileFormat',
key: 'fileFormat',
width: '80px',
- sorter: (a, b) => a.fileFormat.localeCompare(b.fileFormat),
+ sorter: true,
+ ...this.getColumnSearchProps('fileFormat'),
},
{
title: i18next.t("resource:File size"),
dataIndex: 'fileSize',
key: 'fileSize',
width: '100px',
- sorter: (a, b) => a.fileSize - b.fileSize,
+ sorter: true,
render: (text, record, index) => {
return Setting.getFriendlyFileSize(text);
}
@@ -266,12 +266,10 @@ class ResourceListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getResources(page, pageSize),
- onShowSizeChange: (current, size) => this.getResources(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -286,21 +284,33 @@ class ResourceListPage extends React.Component {
}
)}
- loading={resources === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.resources)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ this.setState({ loading: true });
+ ResourceBackend.getResources(this.props.account.owner, this.props.account.name, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default ResourceListPage;
diff --git a/web/src/Setting.js b/web/src/Setting.js
index 2007c33c..372b90b3 100644
--- a/web/src/Setting.js
+++ b/web/src/Setting.js
@@ -382,6 +382,60 @@ export function getProviderLogo(provider) {
)
}
+export function getProviderTypeOptions(category) {
+ if (category === "OAuth") {
+ return (
+ [
+ {id: 'Google', name: 'Google'},
+ {id: 'GitHub', name: 'GitHub'},
+ {id: 'QQ', name: 'QQ'},
+ {id: 'WeChat', name: 'WeChat'},
+ {id: 'Facebook', name: 'Facebook'},
+ {id: 'DingTalk', name: 'DingTalk'},
+ {id: 'Weibo', name: 'Weibo'},
+ {id: 'Gitee', name: 'Gitee'},
+ {id: 'LinkedIn', name: 'LinkedIn'},
+ {id: 'WeCom', name: 'WeCom'},
+ {id: 'Lark', name: 'Lark'},
+ {id: 'GitLab', name: 'GitLab'},
+ {id: 'Apple', name: 'Apple'},
+ {id: 'AzureAD', name: 'AzureAD'},
+ {id: 'Slack', name: 'Slack'},
+ ]
+ );
+ } else if (category === "Email") {
+ return (
+ [
+ {id: 'Default', name: 'Default'},
+ ]
+ );
+ } else if (category === "SMS") {
+ return (
+ [
+ {id: 'Aliyun SMS', name: 'Aliyun SMS'},
+ {id: 'Tencent Cloud SMS', name: 'Tencent Cloud SMS'},
+ {id: 'Volc Engine SMS', name: 'Volc Engine SMS'},
+ ]
+ );
+ } else if (category === "Storage") {
+ return (
+ [
+ {id: 'Local File System', name: 'Local File System'},
+ {id: 'AWS S3', name: 'AWS S3'},
+ {id: 'Aliyun OSS', name: 'Aliyun OSS'},
+ {id: 'Tencent Cloud COS', name: 'Tencent Cloud COS'},
+ ]
+ );
+ } else if (category === "SAML") {
+ return ([
+ {id: 'Aliyun IDaaS', name: 'Aliyun IDaaS'},
+ {id: 'Keycloak', name: 'Keycloak'},
+ ]);
+ } else {
+ return [];
+ }
+}
+
export function renderLogo(application) {
if (application === null) {
return null;
diff --git a/web/src/SyncerListPage.js b/web/src/SyncerListPage.js
index 4142525e..ebfb470f 100644
--- a/web/src/SyncerListPage.js
+++ b/web/src/SyncerListPage.js
@@ -19,32 +19,10 @@ import moment from "moment";
import * as Setting from "./Setting";
import * as SyncerBackend from "./backend/SyncerBackend";
import i18next from "i18next";
+import BaseListPage from "./BaseListPage";
+import * as ProviderBackend from "./backend/ProviderBackend";
-class SyncerListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- syncers: null,
- total: 0,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.getSyncers(1, 10);
- }
-
- getSyncers(page, pageSize) {
- SyncerBackend.getSyncers("admin", page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- syncers: res.data,
- total: res.data2
- });
- }
- });
- }
+class SyncerListPage extends BaseListPage {
newSyncer() {
const randomName = Setting.getRandomName();
@@ -74,10 +52,6 @@ class SyncerListPage extends React.Component {
SyncerBackend.addSyncer(newSyncer)
.then((res) => {
Setting.showMessage("success", `Syncer added successfully`);
- this.setState({
- syncers: Setting.prependRow(this.state.syncers, newSyncer),
- total: this.state.total + 1
- });
this.props.history.push(`/syncers/${newSyncer.name}`);
}
)
@@ -87,12 +61,12 @@ class SyncerListPage extends React.Component {
}
deleteSyncer(i) {
- SyncerBackend.deleteSyncer(this.state.syncers[i])
+ SyncerBackend.deleteSyncer(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Syncer deleted successfully`);
this.setState({
- syncers: Setting.deleteRow(this.state.syncers, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -108,7 +82,8 @@ class SyncerListPage extends React.Component {
dataIndex: 'organization',
key: 'organization',
width: '120px',
- sorter: (a, b) => a.organization.localeCompare(b.organization),
+ sorter: true,
+ ...this.getColumnSearchProps('organization'),
render: (text, record, index) => {
return (
@@ -123,7 +98,8 @@ class SyncerListPage extends React.Component {
key: 'name',
width: '150px',
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -137,7 +113,7 @@ class SyncerListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '180px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -147,35 +123,44 @@ class SyncerListPage extends React.Component {
dataIndex: 'type',
key: 'type',
width: '100px',
- sorter: (a, b) => a.type.localeCompare(b.type),
+ sorter: true,
+ filterMultiple: false,
+ filters: [
+ {text: 'Database', value: 'Database'},
+ {text: 'LDAP', value: 'LDAP'},
+ ],
},
{
title: i18next.t("provider:Host"),
dataIndex: 'host',
key: 'host',
width: '120px',
- sorter: (a, b) => a.host.localeCompare(b.host),
+ sorter: true,
+ ...this.getColumnSearchProps('host'),
},
{
title: i18next.t("provider:Port"),
dataIndex: 'port',
key: 'port',
width: '100px',
- sorter: (a, b) => a.port - b.port,
+ sorter: true,
+ ...this.getColumnSearchProps('port'),
},
{
title: i18next.t("general:User"),
dataIndex: 'user',
key: 'user',
width: '120px',
- sorter: (a, b) => a.user.localeCompare(b.user),
+ sorter: true,
+ ...this.getColumnSearchProps('user'),
},
{
title: i18next.t("general:Password"),
dataIndex: 'password',
key: 'password',
width: '120px',
- sorter: (a, b) => a.password.localeCompare(b.password),
+ sorter: true,
+ ...this.getColumnSearchProps('password'),
},
{
title: i18next.t("syncer:Database type"),
@@ -189,28 +174,29 @@ class SyncerListPage extends React.Component {
dataIndex: 'database',
key: 'database',
width: '120px',
- sorter: (a, b) => a.database.localeCompare(b.database),
+ sorter: true,
},
{
title: i18next.t("syncer:Table"),
dataIndex: 'table',
key: 'table',
width: '120px',
- sorter: (a, b) => a.table.localeCompare(b.table),
+ sorter: true,
},
{
title: i18next.t("syncer:Sync interval"),
dataIndex: 'syncInterval',
key: 'syncInterval',
width: '120px',
- sorter: (a, b) => a.syncInterval.localeCompare(b.syncInterval),
+ sorter: true,
+ ...this.getColumnSearchProps('syncInterval'),
},
{
title: i18next.t("syncer:Is enabled"),
dataIndex: 'isEnabled',
key: 'isEnabled',
width: '120px',
- sorter: (a, b) => a.isEnabled - b.isEnabled,
+ sorter: true,
render: (text, record, index) => {
return (
@@ -240,12 +226,10 @@ class SyncerListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getSyncers(page, pageSize),
- onShowSizeChange: (current, size) => this.getSyncers(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -257,21 +241,37 @@ class SyncerListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={syncers === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.syncers)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ if (params.type !== undefined && params.type !== null) {
+ field = "type";
+ value = params.type;
+ }
+ this.setState({ loading: true });
+ SyncerBackend.getSyncers("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default SyncerListPage;
diff --git a/web/src/TokenListPage.js b/web/src/TokenListPage.js
index 44df318d..b4c48cab 100644
--- a/web/src/TokenListPage.js
+++ b/web/src/TokenListPage.js
@@ -19,32 +19,10 @@ import moment from "moment";
import * as Setting from "./Setting";
import * as TokenBackend from "./backend/TokenBackend";
import i18next from "i18next";
+import * as ResourceBackend from "./backend/ResourceBackend";
+import BaseListPage from "./BaseListPage";
-class TokenListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- tokens: null,
- total: 0,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.getTokens(1, 10);
- }
-
- getTokens(page, pageSize) {
- TokenBackend.getTokens("admin", page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- tokens: res.data,
- total: res.data2
- });
- }
- });
- }
+class TokenListPage extends BaseListPage {
newToken() {
const randomName = Setting.getRandomName();
@@ -67,10 +45,6 @@ class TokenListPage extends React.Component {
TokenBackend.addToken(newToken)
.then((res) => {
Setting.showMessage("success", `Token added successfully`);
- this.setState({
- tokens: Setting.prependRow(this.state.tokens, newToken),
- total: this.state.total + 1
- });
this.props.history.push(`/tokens/${newToken.name}`);
}
)
@@ -80,12 +54,12 @@ class TokenListPage extends React.Component {
}
deleteToken(i) {
- TokenBackend.deleteToken(this.state.tokens[i])
+ TokenBackend.deleteToken(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Token deleted successfully`);
this.setState({
- tokens: Setting.deleteRow(this.state.tokens, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -102,7 +76,8 @@ class TokenListPage extends React.Component {
key: 'name',
width: (Setting.isMobile()) ? "100px" : "300px",
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -116,7 +91,7 @@ class TokenListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '160px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -126,7 +101,8 @@ class TokenListPage extends React.Component {
dataIndex: 'application',
key: 'application',
width: '120px',
- sorter: (a, b) => a.application.localeCompare(b.application),
+ sorter: true,
+ ...this.getColumnSearchProps('application'),
render: (text, record, index) => {
return (
@@ -140,7 +116,8 @@ class TokenListPage extends React.Component {
dataIndex: 'organization',
key: 'organization',
width: '120px',
- sorter: (a, b) => a.organization.localeCompare(b.organization),
+ sorter: true,
+ ...this.getColumnSearchProps('organization'),
render: (text, record, index) => {
return (
@@ -154,7 +131,8 @@ class TokenListPage extends React.Component {
dataIndex: 'user',
key: 'user',
width: '120px',
- sorter: (a, b) => a.user.localeCompare(b.user),
+ sorter: true,
+ ...this.getColumnSearchProps('user'),
render: (text, record, index) => {
return (
@@ -168,7 +146,8 @@ class TokenListPage extends React.Component {
dataIndex: 'code',
key: 'code',
// width: '150px',
- sorter: (a, b) => a.code.localeCompare(b.code),
+ sorter: true,
+ ...this.getColumnSearchProps('code'),
render: (text, record, index) => {
return Setting.getClickable(text);
}
@@ -178,8 +157,9 @@ class TokenListPage extends React.Component {
dataIndex: 'accessToken',
key: 'accessToken',
// width: '150px',
- sorter: (a, b) => a.accessToken.localeCompare(b.accessToken),
+ sorter: true,
ellipsis: true,
+ ...this.getColumnSearchProps('accessToken'),
render: (text, record, index) => {
return Setting.getClickable(text);
}
@@ -189,14 +169,16 @@ class TokenListPage extends React.Component {
dataIndex: 'expiresIn',
key: 'expiresIn',
width: '120px',
- sorter: (a, b) => a.expiresIn - b.expiresIn,
+ sorter: true,
+ ...this.getColumnSearchProps('expiresIn'),
},
{
title: i18next.t("token:Scope"),
dataIndex: 'scope',
key: 'scope',
width: '100px',
- sorter: (a, b) => a.scope.localeCompare(b.scope),
+ sorter: true,
+ ...this.getColumnSearchProps('scope'),
},
// {
// title: i18next.t("token:Token type"),
@@ -228,12 +210,10 @@ class TokenListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getTokens(page, pageSize),
- onShowSizeChange: (current, size) => this.getTokens(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -245,21 +225,33 @@ class TokenListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={tokens === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.tokens)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ this.setState({ loading: true });
+ TokenBackend.getTokens("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default TokenListPage;
diff --git a/web/src/UserListPage.js b/web/src/UserListPage.js
index 8650361b..f496b22d 100644
--- a/web/src/UserListPage.js
+++ b/web/src/UserListPage.js
@@ -19,46 +19,26 @@ import moment from "moment";
import * as Setting from "./Setting";
import * as UserBackend from "./backend/UserBackend";
import i18next from "i18next";
+import BaseListPage from "./BaseListPage";
+import * as ProviderBackend from "./backend/ProviderBackend";
-class UserListPage extends React.Component {
+class UserListPage extends BaseListPage {
constructor(props) {
super(props);
this.state = {
classes: props,
- users: null,
organizationName: props.match.params.organizationName,
- total: 0,
+ data: [],
+ pagination: {
+ current: 1,
+ pageSize: 10,
+ },
+ loading: false,
+ searchText: '',
+ searchedColumn: '',
};
}
- UNSAFE_componentWillMount() {
- this.getUsers(1, 10);
- }
-
- getUsers(page, pageSize) {
- if (this.state.organizationName === undefined) {
- UserBackend.getGlobalUsers(page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- users: res.data,
- total: res.data2
- });
- }
- });
- } else {
- UserBackend.getUsers(this.state.organizationName, page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- users: res.data,
- total: res.data2
- });
- }
- });
- }
- }
-
newUser() {
const randomName = Setting.getRandomName();
return {
@@ -90,10 +70,6 @@ class UserListPage extends React.Component {
UserBackend.addUser(newUser)
.then((res) => {
Setting.showMessage("success", `User added successfully`);
- this.setState({
- users: Setting.prependRow(this.state.users, newUser),
- total: this.state.total + 1
- });
this.props.history.push(`/users/${newUser.owner}/${newUser.name}`);
}
)
@@ -103,12 +79,12 @@ class UserListPage extends React.Component {
}
deleteUser(i) {
- UserBackend.deleteUser(this.state.users[i])
+ UserBackend.deleteUser(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `User deleted successfully`);
this.setState({
- users: Setting.deleteRow(this.state.users, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -132,7 +108,8 @@ class UserListPage extends React.Component {
key: 'owner',
width: (Setting.isMobile()) ? "100px" : "120px",
fixed: 'left',
- sorter: (a, b) => a.owner.localeCompare(b.owner),
+ sorter: true,
+ ...this.getColumnSearchProps('owner'),
render: (text, record, index) => {
return (
@@ -147,7 +124,8 @@ class UserListPage extends React.Component {
key: 'signupApplication',
width: (Setting.isMobile()) ? "100px" : "120px",
fixed: 'left',
- sorter: (a, b) => a.owner.localeCompare(b.owner),
+ sorter: true,
+ ...this.getColumnSearchProps('signupApplication'),
render: (text, record, index) => {
return (
@@ -162,7 +140,8 @@ class UserListPage extends React.Component {
key: 'name',
width: (Setting.isMobile()) ? "80px" : "100px",
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -176,7 +155,7 @@ class UserListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '160px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -186,7 +165,8 @@ class UserListPage extends React.Component {
dataIndex: 'displayName',
key: 'displayName',
width: '100px',
- sorter: (a, b) => a.displayName.localeCompare(b.displayName),
+ sorter: true,
+ ...this.getColumnSearchProps('displayName'),
},
{
title: i18next.t("general:Avatar"),
@@ -206,7 +186,8 @@ class UserListPage extends React.Component {
dataIndex: 'email',
key: 'email',
width: '160px',
- sorter: (a, b) => a.email.localeCompare(b.email),
+ sorter: true,
+ ...this.getColumnSearchProps('email'),
render: (text, record, index) => {
return (
@@ -220,7 +201,8 @@ class UserListPage extends React.Component {
dataIndex: 'phone',
key: 'phone',
width: '120px',
- sorter: (a, b) => a.phone.localeCompare(b.phone),
+ sorter: true,
+ ...this.getColumnSearchProps('phone'),
},
// {
// title: 'Phone',
@@ -234,28 +216,31 @@ class UserListPage extends React.Component {
dataIndex: 'affiliation',
key: 'affiliation',
width: '120px',
- sorter: (a, b) => a.affiliation.localeCompare(b.affiliation),
+ sorter: true,
+ ...this.getColumnSearchProps('affiliation'),
},
{
title: i18next.t("user:Country/Region"),
dataIndex: 'region',
key: 'region',
width: '120px',
- sorter: (a, b) => a.region.localeCompare(b.region),
+ sorter: true,
+ ...this.getColumnSearchProps('region'),
},
{
title: i18next.t("user:Tag"),
dataIndex: 'tag',
key: 'tag',
width: '100px',
- sorter: (a, b) => a.tag.localeCompare(b.tag),
+ sorter: true,
+ ...this.getColumnSearchProps('tag'),
},
{
title: i18next.t("user:Is admin"),
dataIndex: 'isAdmin',
key: 'isAdmin',
width: '110px',
- sorter: (a, b) => a.isAdmin - b.isAdmin,
+ sorter: true,
render: (text, record, index) => {
return (
@@ -267,7 +252,7 @@ class UserListPage extends React.Component {
dataIndex: 'isGlobalAdmin',
key: 'isGlobalAdmin',
width: '110px',
- sorter: (a, b) => a.isGlobalAdmin - b.isGlobalAdmin,
+ sorter: true,
render: (text, record, index) => {
return (
@@ -279,7 +264,7 @@ class UserListPage extends React.Component {
dataIndex: 'isForbidden',
key: 'isForbidden',
width: '110px',
- sorter: (a, b) => a.isForbidden - b.isForbidden,
+ sorter: true,
render: (text, record, index) => {
return (
@@ -291,7 +276,7 @@ class UserListPage extends React.Component {
dataIndex: 'isDeleted',
key: 'isDeleted',
width: '110px',
- sorter: (a, b) => a.isDeleted - b.isDeleted,
+ sorter: true,
render: (text, record, index) => {
return (
@@ -321,12 +306,10 @@ class UserListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getUsers(page, pageSize),
- onShowSizeChange: (current, size) => this.getUsers(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -338,21 +321,51 @@ class UserListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={users === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.users)
- }
-
- );
- }
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ this.setState({ loading: true });
+ if (this.state.organizationName === undefined) {
+ UserBackend.getGlobalUsers(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
+ }
+ });
+ } else {
+ UserBackend.getUsers(this.state.organizationName, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
+ }
+ });
+ }
+ };
}
export default UserListPage;
diff --git a/web/src/WebhookListPage.js b/web/src/WebhookListPage.js
index 4613b57d..0cb40347 100644
--- a/web/src/WebhookListPage.js
+++ b/web/src/WebhookListPage.js
@@ -19,32 +19,10 @@ import moment from "moment";
import * as Setting from "./Setting";
import * as WebhookBackend from "./backend/WebhookBackend";
import i18next from "i18next";
+import BaseListPage from "./BaseListPage";
+import * as ProviderBackend from "./backend/ProviderBackend";
-class WebhookListPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- classes: props,
- webhooks: null,
- total: 0,
- };
- }
-
- UNSAFE_componentWillMount() {
- this.getWebhooks(1, 10);
- }
-
- getWebhooks(page, pageSize) {
- WebhookBackend.getWebhooks("admin", page, pageSize)
- .then((res) => {
- if (res.status === "ok") {
- this.setState({
- webhooks: res.data,
- total: res.data2
- });
- }
- });
- }
+class WebhookListPage extends BaseListPage {
newWebhook() {
const randomName = Setting.getRandomName();
@@ -64,10 +42,6 @@ class WebhookListPage extends React.Component {
WebhookBackend.addWebhook(newWebhook)
.then((res) => {
Setting.showMessage("success", `Webhook added successfully`);
- this.setState({
- webhooks: Setting.prependRow(this.state.webhooks, newWebhook),
- total: this.state.total + 1
- });
this.props.history.push(`/webhooks/${newWebhook.name}`);
}
)
@@ -77,12 +51,12 @@ class WebhookListPage extends React.Component {
}
deleteWebhook(i) {
- WebhookBackend.deleteWebhook(this.state.webhooks[i])
+ WebhookBackend.deleteWebhook(this.state.data[i])
.then((res) => {
Setting.showMessage("success", `Webhook deleted successfully`);
this.setState({
- webhooks: Setting.deleteRow(this.state.webhooks, i),
- total: this.state.total - 1
+ data: Setting.deleteRow(this.state.data, i),
+ pagination: {total: this.state.pagination.total - 1},
});
}
)
@@ -98,7 +72,8 @@ class WebhookListPage extends React.Component {
dataIndex: 'organization',
key: 'organization',
width: '80px',
- sorter: (a, b) => a.organization.localeCompare(b.organization),
+ sorter: true,
+ ...this.getColumnSearchProps('organization'),
render: (text, record, index) => {
return (
@@ -113,7 +88,8 @@ class WebhookListPage extends React.Component {
key: 'name',
width: '150px',
fixed: 'left',
- sorter: (a, b) => a.name.localeCompare(b.name),
+ sorter: true,
+ ...this.getColumnSearchProps('name'),
render: (text, record, index) => {
return (
@@ -127,7 +103,7 @@ class WebhookListPage extends React.Component {
dataIndex: 'createdTime',
key: 'createdTime',
width: '180px',
- sorter: (a, b) => a.createdTime.localeCompare(b.createdTime),
+ sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
}
@@ -137,7 +113,8 @@ class WebhookListPage extends React.Component {
dataIndex: 'url',
key: 'url',
width: '300px',
- sorter: (a, b) => a.url.localeCompare(b.url),
+ sorter: true,
+ ...this.getColumnSearchProps('url'),
render: (text, record, index) => {
return (
@@ -153,14 +130,20 @@ class WebhookListPage extends React.Component {
dataIndex: 'contentType',
key: 'contentType',
width: '150px',
- sorter: (a, b) => a.contentType.localeCompare(b.contentType),
+ sorter: true,
+ filterMultiple: false,
+ filters: [
+ {text: 'application/json', value: 'application/json'},
+ {text: 'application/x-www-form-urlencoded', value: 'application/x-www-form-urlencoded'},
+ ]
},
{
title: i18next.t("webhook:Events"),
dataIndex: 'events',
key: 'events',
// width: '100px',
- sorter: (a, b) => a.events.localeCompare(b.events),
+ sorter: true,
+ ...this.getColumnSearchProps('events'),
render: (text, record, index) => {
return Setting.getTags(text);
}
@@ -188,12 +171,10 @@ class WebhookListPage extends React.Component {
];
const paginationProps = {
- total: this.state.total,
+ total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
- showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.total),
- onChange: (page, pageSize) => this.getWebhooks(page, pageSize),
- onShowSizeChange: (current, size) => this.getWebhooks(current, size),
+ showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
@@ -205,21 +186,37 @@ class WebhookListPage extends React.Component {
{i18next.t("general:Add")}
)}
- loading={webhooks === null}
+ loading={this.state.loading}
+ onChange={this.handleTableChange}
/>
);
}
- render() {
- return (
-
- {
- this.renderTable(this.state.webhooks)
+ fetch = (params = {}) => {
+ let field = params.searchedColumn, value = params.searchText;
+ let sortField = params.sortField, sortOrder = params.sortOrder;
+ if (params.contentType !== undefined && params.contentType !== null) {
+ field = "contentType";
+ value = params.contentType;
+ }
+ this.setState({ loading: true });
+ WebhookBackend.getWebhooks("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
+ .then((res) => {
+ if (res.status === "ok") {
+ this.setState({
+ loading: false,
+ data: res.data,
+ pagination: {
+ ...params.pagination,
+ total: res.data2,
+ },
+ searchText: params.searchText,
+ searchedColumn: params.searchedColumn,
+ });
}
-
- );
- }
+ });
+ };
}
export default WebhookListPage;
diff --git a/web/src/backend/ApplicationBackend.js b/web/src/backend/ApplicationBackend.js
index f1a5cc63..3efbe549 100644
--- a/web/src/backend/ApplicationBackend.js
+++ b/web/src/backend/ApplicationBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getApplications(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-applications?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getApplications(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-applications?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/OrganizationBackend.js b/web/src/backend/OrganizationBackend.js
index 4864ea4d..d2494925 100644
--- a/web/src/backend/OrganizationBackend.js
+++ b/web/src/backend/OrganizationBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getOrganizations(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-organizations?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getOrganizations(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-organizations?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/ProviderBackend.js b/web/src/backend/ProviderBackend.js
index 0ddbdcef..cd1611a0 100644
--- a/web/src/backend/ProviderBackend.js
+++ b/web/src/backend/ProviderBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getProviders(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-providers?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getProviders(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-providers?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/RecordBackend.js b/web/src/backend/RecordBackend.js
index a49e3c71..72269e57 100644
--- a/web/src/backend/RecordBackend.js
+++ b/web/src/backend/RecordBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getRecords(page, pageSize) {
- return fetch(`${Setting.ServerUrl}/api/get-records?pageSize=${pageSize}&p=${page}`, {
+export function getRecords(page, pageSize, field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-records?pageSize=${pageSize}&p=${page}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/ResourceBackend.js b/web/src/backend/ResourceBackend.js
index 79acb988..91f61f3f 100644
--- a/web/src/backend/ResourceBackend.js
+++ b/web/src/backend/ResourceBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getResources(owner, user, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-resources?owner=${owner}&user=${user}&p=${page}&pageSize=${pageSize}`, {
+export function getResources(owner, user, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-resources?owner=${owner}&user=${user}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/SyncerBackend.js b/web/src/backend/SyncerBackend.js
index 21d87b2c..0eec9bf3 100644
--- a/web/src/backend/SyncerBackend.js
+++ b/web/src/backend/SyncerBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getSyncers(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-syncers?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getSyncers(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-syncers?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/TokenBackend.js b/web/src/backend/TokenBackend.js
index 22b7ee57..0100b6fa 100644
--- a/web/src/backend/TokenBackend.js
+++ b/web/src/backend/TokenBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getTokens(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-tokens?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getTokens(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-tokens?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/UserBackend.js b/web/src/backend/UserBackend.js
index 3ee4313a..a43d1b93 100644
--- a/web/src/backend/UserBackend.js
+++ b/web/src/backend/UserBackend.js
@@ -15,15 +15,15 @@
import * as Setting from "../Setting";
import i18next from "i18next";
-export function getGlobalUsers(page, pageSize) {
- return fetch(`${Setting.ServerUrl}/api/get-global-users?p=${page}&pageSize=${pageSize}`, {
+export function getGlobalUsers(page, pageSize, field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-global-users?p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
}
-export function getUsers(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-users?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getUsers(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-users?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/src/backend/WebhookBackend.js b/web/src/backend/WebhookBackend.js
index c662fafd..92a862ef 100644
--- a/web/src/backend/WebhookBackend.js
+++ b/web/src/backend/WebhookBackend.js
@@ -14,8 +14,8 @@
import * as Setting from "../Setting";
-export function getWebhooks(owner, page = "", pageSize = "") {
- return fetch(`${Setting.ServerUrl}/api/get-webhooks?owner=${owner}&p=${page}&pageSize=${pageSize}`, {
+export function getWebhooks(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
+ return fetch(`${Setting.ServerUrl}/api/get-webhooks?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include"
}).then(res => res.json());
diff --git a/web/yarn.lock b/web/yarn.lock
index 78a4ee4b..96ed7dd5 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -5721,6 +5721,11 @@ hex-color-regex@^1.1.0:
resolved "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
+highlight-words-core@^1.2.0:
+ version "1.2.2"
+ resolved "https://registry.npm.taobao.org/highlight-words-core/download/highlight-words-core-1.2.2.tgz#1eff6d7d9f0a22f155042a00791237791b1eeaaa"
+ integrity sha1-Hv9tfZ8KIvFVBCoAeRI3eRse6qo=
+
history@^4.9.0:
version "4.10.1"
resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
@@ -7479,6 +7484,11 @@ media-typer@0.3.0:
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+memoize-one@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.npmmirror.com/memoize-one/download/memoize-one-4.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmemoize-one%2Fdownload%2Fmemoize-one-4.1.0.tgz#a2387c58c03fff27ca390c31b764a79addf3f906"
+ integrity sha1-ojh8WMA//yfKOQwxt2Snmt3z+QY=
+
memory-fs@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@@ -9254,7 +9264,7 @@ prompts@2.4.0, prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
-prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -9343,6 +9353,13 @@ qs@6.7.0:
resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+qs@^6.10.2:
+ version "6.10.2"
+ resolved "https://registry.npmmirror.com/qs/download/qs-6.10.2.tgz#c1431bea37fc5b24c5bdbafa20f16bdf2a4b9ffe"
+ integrity sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==
+ dependencies:
+ side-channel "^1.0.4"
+
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
@@ -9873,6 +9890,15 @@ react-helmet@^6.1.0:
react-fast-compare "^3.1.1"
react-side-effect "^2.1.0"
+react-highlight-words@^0.17.0:
+ version "0.17.0"
+ resolved "https://registry.npm.taobao.org/react-highlight-words/download/react-highlight-words-0.17.0.tgz#e79a559a2de301548339d7216264d6cd0f1eed6f"
+ integrity sha1-55pVmi3jAVSDOdchYmTWzQ8e7W8=
+ dependencies:
+ highlight-words-core "^1.2.0"
+ memoize-one "^4.0.0"
+ prop-types "^15.5.8"
+
react-i18next@^11.8.7:
version "11.8.12"
resolved "https://registry.npmjs.org/react-i18next/-/react-i18next-11.8.12.tgz#6a9f57277062fb6a6129cad4db5e6198d5c60b58"