Merge pull request #107 from ssb-ngi-pointer/style-dashboard
Style dashboard
This commit is contained in:
commit
b3e46f2e8d
1
go.sum
1
go.sum
|
@ -546,6 +546,7 @@ golang.org/x/net v0.0.0-20191116160921-f9c825593386 h1:ktbWvQrW08Txdxno1PiDpSxPX
|
|||
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs=
|
||||
golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
|
@ -65,6 +65,9 @@ type MembersService interface {
|
|||
// List returns a list of all the members.
|
||||
List(context.Context) ([]Member, error)
|
||||
|
||||
// Count returns the total number of members.
|
||||
Count(context.Context) (uint, error)
|
||||
|
||||
// RemoveFeed removes the feed from the list.
|
||||
RemoveFeed(context.Context, refs.FeedRef) error
|
||||
|
||||
|
@ -95,6 +98,9 @@ type DeniedKeysService interface {
|
|||
// List returns a list of all the feeds.
|
||||
List(context.Context) ([]ListEntry, error)
|
||||
|
||||
// Count returns the total number of denied keys.
|
||||
Count(context.Context) (uint, error)
|
||||
|
||||
// RemoveFeed removes the feed from the list.
|
||||
RemoveFeed(context.Context, refs.FeedRef) error
|
||||
|
||||
|
@ -141,6 +147,9 @@ type InvitesService interface {
|
|||
// List returns a list of all the valid invites
|
||||
List(ctx context.Context) ([]Invite, error)
|
||||
|
||||
// Count returns the total number of invites.
|
||||
Count(context.Context) (uint, error)
|
||||
|
||||
// Revoke removes a active invite and invalidates it for future use.
|
||||
Revoke(ctx context.Context, id int64) error
|
||||
}
|
||||
|
|
|
@ -23,6 +23,19 @@ type FakeDeniedKeysService struct {
|
|||
addReturnsOnCall map[int]struct {
|
||||
result1 error
|
||||
}
|
||||
CountStub func(context.Context) (uint, error)
|
||||
countMutex sync.RWMutex
|
||||
countArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
}
|
||||
countReturns struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}
|
||||
countReturnsOnCall map[int]struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}
|
||||
GetByIDStub func(context.Context, int64) (roomdb.ListEntry, error)
|
||||
getByIDMutex sync.RWMutex
|
||||
getByIDArgsForCall []struct {
|
||||
|
@ -165,6 +178,70 @@ func (fake *FakeDeniedKeysService) AddReturnsOnCall(i int, result1 error) {
|
|||
}{result1}
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) Count(arg1 context.Context) (uint, error) {
|
||||
fake.countMutex.Lock()
|
||||
ret, specificReturn := fake.countReturnsOnCall[len(fake.countArgsForCall)]
|
||||
fake.countArgsForCall = append(fake.countArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
}{arg1})
|
||||
stub := fake.CountStub
|
||||
fakeReturns := fake.countReturns
|
||||
fake.recordInvocation("Count", []interface{}{arg1})
|
||||
fake.countMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) CountCallCount() int {
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
return len(fake.countArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) CountCalls(stub func(context.Context) (uint, error)) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) CountArgsForCall(i int) context.Context {
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
argsForCall := fake.countArgsForCall[i]
|
||||
return argsForCall.arg1
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) CountReturns(result1 uint, result2 error) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = nil
|
||||
fake.countReturns = struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) CountReturnsOnCall(i int, result1 uint, result2 error) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = nil
|
||||
if fake.countReturnsOnCall == nil {
|
||||
fake.countReturnsOnCall = make(map[int]struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.countReturnsOnCall[i] = struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeDeniedKeysService) GetByID(arg1 context.Context, arg2 int64) (roomdb.ListEntry, error) {
|
||||
fake.getByIDMutex.Lock()
|
||||
ret, specificReturn := fake.getByIDReturnsOnCall[len(fake.getByIDArgsForCall)]
|
||||
|
@ -547,6 +624,8 @@ func (fake *FakeDeniedKeysService) Invocations() map[string][][]interface{} {
|
|||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.addMutex.RLock()
|
||||
defer fake.addMutex.RUnlock()
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
fake.getByIDMutex.RLock()
|
||||
defer fake.getByIDMutex.RUnlock()
|
||||
fake.hasFeedMutex.RLock()
|
||||
|
|
|
@ -25,6 +25,19 @@ type FakeInvitesService struct {
|
|||
result1 roomdb.Invite
|
||||
result2 error
|
||||
}
|
||||
CountStub func(context.Context) (uint, error)
|
||||
countMutex sync.RWMutex
|
||||
countArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
}
|
||||
countReturns struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}
|
||||
countReturnsOnCall map[int]struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}
|
||||
CreateStub func(context.Context, int64) (string, error)
|
||||
createMutex sync.RWMutex
|
||||
createArgsForCall []struct {
|
||||
|
@ -162,6 +175,70 @@ func (fake *FakeInvitesService) ConsumeReturnsOnCall(i int, result1 roomdb.Invit
|
|||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) Count(arg1 context.Context) (uint, error) {
|
||||
fake.countMutex.Lock()
|
||||
ret, specificReturn := fake.countReturnsOnCall[len(fake.countArgsForCall)]
|
||||
fake.countArgsForCall = append(fake.countArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
}{arg1})
|
||||
stub := fake.CountStub
|
||||
fakeReturns := fake.countReturns
|
||||
fake.recordInvocation("Count", []interface{}{arg1})
|
||||
fake.countMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) CountCallCount() int {
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
return len(fake.countArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) CountCalls(stub func(context.Context) (uint, error)) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) CountArgsForCall(i int) context.Context {
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
argsForCall := fake.countArgsForCall[i]
|
||||
return argsForCall.arg1
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) CountReturns(result1 uint, result2 error) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = nil
|
||||
fake.countReturns = struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) CountReturnsOnCall(i int, result1 uint, result2 error) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = nil
|
||||
if fake.countReturnsOnCall == nil {
|
||||
fake.countReturnsOnCall = make(map[int]struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.countReturnsOnCall[i] = struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeInvitesService) Create(arg1 context.Context, arg2 int64) (string, error) {
|
||||
fake.createMutex.Lock()
|
||||
ret, specificReturn := fake.createReturnsOnCall[len(fake.createArgsForCall)]
|
||||
|
@ -488,6 +565,8 @@ func (fake *FakeInvitesService) Invocations() map[string][][]interface{} {
|
|||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.consumeMutex.RLock()
|
||||
defer fake.consumeMutex.RUnlock()
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
fake.createMutex.RLock()
|
||||
defer fake.createMutex.RUnlock()
|
||||
fake.getByIDMutex.RLock()
|
||||
|
|
|
@ -25,6 +25,19 @@ type FakeMembersService struct {
|
|||
result1 int64
|
||||
result2 error
|
||||
}
|
||||
CountStub func(context.Context) (uint, error)
|
||||
countMutex sync.RWMutex
|
||||
countArgsForCall []struct {
|
||||
arg1 context.Context
|
||||
}
|
||||
countReturns struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}
|
||||
countReturnsOnCall map[int]struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}
|
||||
GetByFeedStub func(context.Context, refs.FeedRef) (roomdb.Member, error)
|
||||
getByFeedMutex sync.RWMutex
|
||||
getByFeedArgsForCall []struct {
|
||||
|
@ -173,6 +186,70 @@ func (fake *FakeMembersService) AddReturnsOnCall(i int, result1 int64, result2 e
|
|||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) Count(arg1 context.Context) (uint, error) {
|
||||
fake.countMutex.Lock()
|
||||
ret, specificReturn := fake.countReturnsOnCall[len(fake.countArgsForCall)]
|
||||
fake.countArgsForCall = append(fake.countArgsForCall, struct {
|
||||
arg1 context.Context
|
||||
}{arg1})
|
||||
stub := fake.CountStub
|
||||
fakeReturns := fake.countReturns
|
||||
fake.recordInvocation("Count", []interface{}{arg1})
|
||||
fake.countMutex.Unlock()
|
||||
if stub != nil {
|
||||
return stub(arg1)
|
||||
}
|
||||
if specificReturn {
|
||||
return ret.result1, ret.result2
|
||||
}
|
||||
return fakeReturns.result1, fakeReturns.result2
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) CountCallCount() int {
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
return len(fake.countArgsForCall)
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) CountCalls(stub func(context.Context) (uint, error)) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = stub
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) CountArgsForCall(i int) context.Context {
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
argsForCall := fake.countArgsForCall[i]
|
||||
return argsForCall.arg1
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) CountReturns(result1 uint, result2 error) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = nil
|
||||
fake.countReturns = struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) CountReturnsOnCall(i int, result1 uint, result2 error) {
|
||||
fake.countMutex.Lock()
|
||||
defer fake.countMutex.Unlock()
|
||||
fake.CountStub = nil
|
||||
if fake.countReturnsOnCall == nil {
|
||||
fake.countReturnsOnCall = make(map[int]struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
})
|
||||
}
|
||||
fake.countReturnsOnCall[i] = struct {
|
||||
result1 uint
|
||||
result2 error
|
||||
}{result1, result2}
|
||||
}
|
||||
|
||||
func (fake *FakeMembersService) GetByFeed(arg1 context.Context, arg2 refs.FeedRef) (roomdb.Member, error) {
|
||||
fake.getByFeedMutex.Lock()
|
||||
ret, specificReturn := fake.getByFeedReturnsOnCall[len(fake.getByFeedArgsForCall)]
|
||||
|
@ -559,6 +636,8 @@ func (fake *FakeMembersService) Invocations() map[string][][]interface{} {
|
|||
defer fake.invocationsMutex.RUnlock()
|
||||
fake.addMutex.RLock()
|
||||
defer fake.addMutex.RUnlock()
|
||||
fake.countMutex.RLock()
|
||||
defer fake.countMutex.RUnlock()
|
||||
fake.getByFeedMutex.RLock()
|
||||
defer fake.getByFeedMutex.RUnlock()
|
||||
fake.getByIDMutex.RLock()
|
||||
|
|
|
@ -104,6 +104,14 @@ func (dk DeniedKeys) List(ctx context.Context) ([]roomdb.ListEntry, error) {
|
|||
return lst, nil
|
||||
}
|
||||
|
||||
func (dk DeniedKeys) Count(ctx context.Context) (uint, error) {
|
||||
count, err := models.DeniedKeys().Count(ctx, dk.db)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint(count), nil
|
||||
}
|
||||
|
||||
// RemoveFeed removes the feed from the list.
|
||||
func (dk DeniedKeys) RemoveFeed(ctx context.Context, r refs.FeedRef) error {
|
||||
entry, err := models.DeniedKeys(qm.Where("pub_key = ?", r.Ref())).One(ctx, dk.db)
|
||||
|
|
|
@ -226,6 +226,14 @@ func (i Invites) List(ctx context.Context) ([]roomdb.Invite, error) {
|
|||
return invs, nil
|
||||
}
|
||||
|
||||
func (i Invites) Count(ctx context.Context) (uint, error) {
|
||||
count, err := models.Members().Count(ctx, i.db)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint(count), nil
|
||||
}
|
||||
|
||||
// Revoke removes a active invite and invalidates it for future use.
|
||||
func (i Invites) Revoke(ctx context.Context, id int64) error {
|
||||
return transact(i.db, func(tx *sql.Tx) error {
|
||||
|
|
|
@ -97,6 +97,14 @@ func (m Members) List(ctx context.Context) ([]roomdb.Member, error) {
|
|||
return members, nil
|
||||
}
|
||||
|
||||
func (m Members) Count(ctx context.Context) (uint, error) {
|
||||
count, err := models.Members().Count(ctx, m.db)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint(count), nil
|
||||
}
|
||||
|
||||
// RemoveFeed removes the feed from the list.
|
||||
func (m Members) RemoveFeed(ctx context.Context, r refs.FeedRef) error {
|
||||
entry, err := models.Members(qm.Where("pub_key = ?", r.Ref())).One(ctx, m.db)
|
||||
|
|
|
@ -63,11 +63,27 @@ func Handler(
|
|||
// TODO: configure 404 handler
|
||||
|
||||
mux.HandleFunc("/dashboard", r.HTML("admin/dashboard.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
lst := roomState.List()
|
||||
onlineRefs := roomState.List()
|
||||
onlineCount := len(onlineRefs)
|
||||
memberCount, err := dbs.Members.Count(req.Context())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to count members: %w", err)
|
||||
}
|
||||
inviteCount, err := dbs.Invites.Count(req.Context())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to count invites: %w", err)
|
||||
}
|
||||
deniedCount, err := dbs.DeniedKeys.Count(req.Context())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to count denied keys: %w", err)
|
||||
}
|
||||
return struct {
|
||||
Clients []string
|
||||
Count int
|
||||
}{lst, len(lst)}, nil
|
||||
OnlineRefs []string
|
||||
OnlineCount int
|
||||
MemberCount uint
|
||||
InviteCount uint
|
||||
DeniedCount uint
|
||||
}{onlineRefs, onlineCount, memberCount, inviteCount, deniedCount}, nil
|
||||
}))
|
||||
mux.HandleFunc("/menu", r.HTML("admin/menu.tmpl", func(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
return map[string]interface{}{}, nil
|
||||
|
|
|
@ -1,27 +1,38 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/router"
|
||||
"github.com/ssb-ngi-pointer/go-ssb-room/web/webassert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
refs "go.mindeco.de/ssb-refs"
|
||||
)
|
||||
|
||||
func TestDashoard(t *testing.T) {
|
||||
ts := newSession(t)
|
||||
a := assert.New(t)
|
||||
|
||||
testRef := refs.FeedRef{Algo: "test", ID: bytes.Repeat([]byte{0}, 16)}
|
||||
ts.RoomState.AddEndpoint(testRef, nil) // 1 online
|
||||
ts.MembersDB.CountReturns(4, nil) // 4 members
|
||||
ts.InvitesDB.CountReturns(3, nil) // 3 invites
|
||||
ts.DeniedKeysDB.CountReturns(2, nil) // 2 banned
|
||||
|
||||
url, err := ts.Router.Get(router.AdminDashboard).URL()
|
||||
a.Nil(err)
|
||||
|
||||
html, resp := ts.Client.GetHTML(url.String())
|
||||
a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code")
|
||||
|
||||
a.Equal("1", html.Find("#online-count").Text())
|
||||
a.Equal("4", html.Find("#member-count").Text())
|
||||
a.Equal("3", html.Find("#invite-count").Text())
|
||||
a.Equal("2", html.Find("#denied-count").Text())
|
||||
|
||||
webassert.Localized(t, html, []webassert.LocalizedElement{
|
||||
{"#welcome", "AdminDashboardWelcome"},
|
||||
{"title", "AdminDashboardTitle"},
|
||||
{"#roomCount", "AdminRoomCountPlural"},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -154,7 +154,6 @@ func TestFallbackAuth(t *testing.T) {
|
|||
}
|
||||
|
||||
webassert.Localized(t, html, []webassert.LocalizedElement{
|
||||
{"#welcome", "AdminDashboardWelcome"},
|
||||
{"title", "AdminDashboardTitle"},
|
||||
})
|
||||
|
||||
|
@ -166,9 +165,7 @@ func TestFallbackAuth(t *testing.T) {
|
|||
t.Log(html.Find("body").Text())
|
||||
}
|
||||
webassert.Localized(t, html, []webassert.LocalizedElement{
|
||||
{"#welcome", "AdminDashboardWelcome"},
|
||||
{"title", "AdminDashboardTitle"},
|
||||
{"#roomCount", "AdminRoomCountSingular"},
|
||||
})
|
||||
|
||||
testRef2 := refs.FeedRef{Algo: "test", ID: bytes.Repeat([]byte{1}, 16)}
|
||||
|
@ -178,9 +175,7 @@ func TestFallbackAuth(t *testing.T) {
|
|||
a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code")
|
||||
|
||||
webassert.Localized(t, html, []webassert.LocalizedElement{
|
||||
{"#welcome", "AdminDashboardWelcome"},
|
||||
{"title", "AdminDashboardTitle"},
|
||||
{"#roomCount", "AdminRoomCountPlural"},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -375,7 +370,6 @@ func TestAuthWithSSBClientInitHasClient(t *testing.T) {
|
|||
}
|
||||
|
||||
webassert.Localized(t, html, []webassert.LocalizedElement{
|
||||
{"#welcome", "AdminDashboardWelcome"},
|
||||
{"title", "AdminDashboardTitle"},
|
||||
})
|
||||
}
|
||||
|
@ -502,7 +496,6 @@ func TestAuthWithSSBServerInitHappyPath(t *testing.T) {
|
|||
}
|
||||
|
||||
webassert.Localized(t, html, []webassert.LocalizedElement{
|
||||
{"#welcome", "AdminDashboardWelcome"},
|
||||
{"title", "AdminDashboardTitle"},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ type testSession struct {
|
|||
AliasesDB *mockdb.FakeAliasesService
|
||||
MembersDB *mockdb.FakeMembersService
|
||||
InvitesDB *mockdb.FakeInvitesService
|
||||
DeniedKeysDB *mockdb.FakeDeniedKeysService
|
||||
PinnedDB *mockdb.FakePinnedNoticesService
|
||||
NoticeDB *mockdb.FakeNoticesService
|
||||
|
||||
|
@ -76,6 +77,7 @@ func setup(t *testing.T) *testSession {
|
|||
ts.AliasesDB = new(mockdb.FakeAliasesService)
|
||||
ts.MembersDB = new(mockdb.FakeMembersService)
|
||||
ts.InvitesDB = new(mockdb.FakeInvitesService)
|
||||
ts.DeniedKeysDB = new(mockdb.FakeDeniedKeysService)
|
||||
ts.PinnedDB = new(mockdb.FakePinnedNoticesService)
|
||||
defaultNotice := &roomdb.Notice{
|
||||
Title: "Default Notice Title",
|
||||
|
@ -118,6 +120,7 @@ func setup(t *testing.T) *testSession {
|
|||
AuthWithSSB: ts.AuthWithSSB,
|
||||
Members: ts.MembersDB,
|
||||
Invites: ts.InvitesDB,
|
||||
DeniedKeys: ts.DeniedKeysDB,
|
||||
Notices: ts.NoticeDB,
|
||||
PinnedNotices: ts.PinnedDB,
|
||||
},
|
||||
|
|
|
@ -31,8 +31,8 @@ AuthFallbackTitle = "Password sign-in"
|
|||
AuthFallbackWelcome = "Signing in with username and password is only possible if the administrator has given you one, because we do not support user registration."
|
||||
AuthFallbackInstruct = "This method is an acceptable fallback, if you have a username and password."
|
||||
|
||||
AdminDashboardTitle = "Dashboard"
|
||||
AdminDashboardWelcome = "Welcome to your dashboard"
|
||||
AdminDashboardTitle = "Room Admin Dashboard"
|
||||
|
||||
AdminAliasesTitle = "Aliases"
|
||||
AdminAliasesWelcome = "Here you can see and revoke the registered aliases of this room."
|
||||
|
|
|
@ -1,16 +1,88 @@
|
|||
{{ define "title" }}{{i18n "AdminDashboardTitle"}}{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="page-header">
|
||||
<h1 id="welcome">{{i18n "AdminDashboardWelcome"}}</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="text-xs">
|
||||
<p class="text-xl" id="roomCount">{{i18npl "AdminRoomCount" .Count}}</p>
|
||||
<ul>
|
||||
{{range .Clients}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
<h1
|
||||
class="text-3xl tracking-tight font-black text-black mt-2 mb-0"
|
||||
>{{i18n "AdminDashboardTitle"}}</h1>
|
||||
|
||||
<div class="flex flex-col-reverse sm:flex-row justify-start items-stretch ">
|
||||
<div class="sm:mr-4 mt-6 py-6 px-4 border-gray-200 border-2 rounded-3xl flex flex-col justify-start items-start">
|
||||
<div class="grid grid-rows-2 grid-flow-col gap-x-4 gap-y-0">
|
||||
{{if gt .OnlineCount 0}}
|
||||
<div class="row-span-2 w-14 h-14 bg-green-50 rounded flex flex-col justify-center items-center">
|
||||
<div class="w-3 h-3 bg-green-500 rounded-full relative">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-500 opacity-75"></span>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="row-span-2 w-14 h-14 bg-gray-100 rounded flex flex-col justify-center items-center">
|
||||
<div class="w-2 h-2 bg-gray-400 rounded-full"></div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div
|
||||
id="online-count"
|
||||
class="col-span-2 font-black text-black text-xl"
|
||||
>{{.OnlineCount}}</div>
|
||||
<div class="col-span-2 text-gray-500">Online</iv>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /row -->
|
||||
|
||||
<div class="sm:mr-4 mt-6 py-6 px-4 border-gray-200 border-2 rounded-3xl flex flex-col justify-start items-start">
|
||||
<div class="grid grid-rows-2 grid-flow-col gap-x-4 gap-y-0">
|
||||
<div class="row-span-2 w-14 h-14 bg-purple-50 rounded flex flex-col justify-center items-center">
|
||||
<svg class="text-purple-600 w-8 h-8" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M12,13C14.67,13 20,14.33 20,17V20H4V17C4,14.33 9.33,13 12,13M12,14.9C9.03,14.9 5.9,16.36 5.9,17V18.1H18.1V17C18.1,16.36 14.97,14.9 12,14.9Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
id="member-count"
|
||||
class="col-span-2 font-black text-black text-xl"
|
||||
>{{.MemberCount}}</div>
|
||||
<div class="col-span-2 text-gray-500">{{i18n "AdminMembersTitle"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:mr-4 mt-6 py-6 px-4 border-gray-200 border-2 rounded-3xl flex flex-col justify-start items-start">
|
||||
<div class="grid grid-rows-2 grid-flow-col gap-x-4 gap-y-0">
|
||||
<div class="row-span-2 w-14 h-14 bg-purple-50 rounded flex flex-col justify-center items-center">
|
||||
<svg class="text-purple-600 w-8 h-8" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4M15,5.9C16.16,5.9 17.1,6.84 17.1,8C17.1,9.16 16.16,10.1 15,10.1A2.1,2.1 0 0,1 12.9,8A2.1,2.1 0 0,1 15,5.9M4,7V10H1V12H4V15H6V12H9V10H6V7H4M15,13C12.33,13 7,14.33 7,17V20H23V17C23,14.33 17.67,13 15,13M15,14.9C17.97,14.9 21.1,16.36 21.1,17V18.1H8.9V17C8.9,16.36 12,14.9 15,14.9Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
id="invite-count"
|
||||
class="col-span-2 font-black text-black text-xl"
|
||||
>{{.InviteCount}}</div>
|
||||
<div class="col-span-2 text-gray-500">{{i18n "AdminInvitesTitle"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:mr-4 mt-6 py-6 px-4 border-gray-200 border-2 rounded-3xl flex flex-col justify-start items-start">
|
||||
<div class="grid grid-rows-2 grid-flow-col gap-x-4 gap-y-0">
|
||||
<div class="row-span-2 w-14 h-14 bg-red-50 rounded flex flex-col justify-center items-center">
|
||||
<svg class="text-red-600 w-6 h-6" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M12,0A12,12 0 0,1 24,12A12,12 0 0,1 12,24A12,12 0 0,1 0,12A12,12 0 0,1 12,0M12,2A10,10 0 0,0 2,12C2,14.4 2.85,16.6 4.26,18.33L18.33,4.26C16.6,2.85 14.4,2 12,2M12,22A10,10 0 0,0 22,12C22,9.6 21.15,7.4 19.74,5.67L5.67,19.74C7.4,21.15 9.6,22 12,22Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
id="denied-count"
|
||||
class="col-span-2 font-black text-black text-xl"
|
||||
>{{.DeniedCount}}</div>
|
||||
<div class="col-span-2 text-gray-500">{{i18n "AdminDeniedKeysTitle"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-8">
|
||||
{{if gt .OnlineCount 0}}
|
||||
<div class="ml-11 h-8 w-0.5 bg-gray-200"></div>
|
||||
{{end}}
|
||||
|
||||
{{range .OnlineRefs}}
|
||||
<div class="ml-11 h-8 w-0.5 bg-gray-200"></div>
|
||||
<div class="ml-11 relative h-3">
|
||||
<div class="absolute inline-flex w-3 h-3 bg-green-500 rounded-full -left-1 -ml-px"></div>
|
||||
<div class="absolute w-44 sm:w-auto -top-1.5 ml-5 pl-1 font-mono truncate flex-auto text-gray-700">{{.}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
Loading…
Reference in New Issue