mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Add number of tokens to the service accounts view (#44919)
* feat: add serviceaccountDTO * WIP * feat: listing number of tokens for a given service account * nit: removed fmt * Update pkg/services/serviceaccounts/database/database.go * Update public/app/features/serviceaccounts/ServiceAccountsListPage.tsx * fixes * align DTOProfile data to the frontend * reviewed myself fixes * fix: tests fix
This commit is contained in:
parent
788f77b7da
commit
79340c087f
@ -33,6 +33,11 @@ type ServiceAccountsAPI struct {
|
|||||||
apiKeyStore APIKeyStore
|
apiKeyStore APIKeyStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serviceAccountIdDTO struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewServiceAccountsAPI(
|
func NewServiceAccountsAPI(
|
||||||
cfg *setting.Cfg,
|
cfg *setting.Cfg,
|
||||||
service serviceaccounts.Service,
|
service serviceaccounts.Service,
|
||||||
@ -88,11 +93,11 @@ func (api *ServiceAccountsAPI) CreateServiceAccount(c *models.ReqContext) respon
|
|||||||
case err != nil:
|
case err != nil:
|
||||||
return response.Error(http.StatusInternalServerError, "Failed to create service account", err)
|
return response.Error(http.StatusInternalServerError, "Failed to create service account", err)
|
||||||
}
|
}
|
||||||
result := models.UserIdDTO{
|
sa := &serviceAccountIdDTO{
|
||||||
Message: "Service account created",
|
|
||||||
Id: user.Id,
|
Id: user.Id,
|
||||||
|
Message: "Service account created",
|
||||||
}
|
}
|
||||||
return response.JSON(http.StatusCreated, result)
|
return response.JSON(http.StatusCreated, sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ServiceAccountsAPI) DeleteServiceAccount(ctx *models.ReqContext) response.Response {
|
func (api *ServiceAccountsAPI) DeleteServiceAccount(ctx *models.ReqContext) response.Response {
|
||||||
|
@ -129,7 +129,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
|||||||
user *tests.TestUser
|
user *tests.TestUser
|
||||||
expectedCode int
|
expectedCode int
|
||||||
acmock *accesscontrolmock.Mock
|
acmock *accesscontrolmock.Mock
|
||||||
userID int
|
Id int
|
||||||
}
|
}
|
||||||
testCases := []testRetrieveSATestCase{
|
testCases := []testRetrieveSATestCase{
|
||||||
{
|
{
|
||||||
@ -157,9 +157,9 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
|||||||
expectedCode: http.StatusForbidden,
|
expectedCode: http.StatusForbidden,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "should be not found when the user doesnt exist",
|
desc: "should be not found when the user doesnt exist",
|
||||||
user: nil,
|
user: nil,
|
||||||
userID: 12,
|
Id: 12,
|
||||||
acmock: tests.SetupMockAccesscontrol(
|
acmock: tests.SetupMockAccesscontrol(
|
||||||
t,
|
t,
|
||||||
func(c context.Context, siu *models.SignedInUser) ([]*accesscontrol.Permission, error) {
|
func(c context.Context, siu *models.SignedInUser) ([]*accesscontrol.Permission, error) {
|
||||||
@ -182,7 +182,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
serviceAccountRequestScenario(t, http.MethodGet, serviceaccountIDPath, tc.user, func(httpmethod string, endpoint string, user *tests.TestUser) {
|
serviceAccountRequestScenario(t, http.MethodGet, serviceaccountIDPath, tc.user, func(httpmethod string, endpoint string, user *tests.TestUser) {
|
||||||
scopeID := tc.userID
|
scopeID := tc.Id
|
||||||
if tc.user != nil {
|
if tc.user != nil {
|
||||||
createdUser := tests.SetupUserServiceAccount(t, store, *tc.user)
|
createdUser := tests.SetupUserServiceAccount(t, store, *tc.user)
|
||||||
scopeID = int(createdUser.Id)
|
scopeID = int(createdUser.Id)
|
||||||
@ -198,7 +198,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
|||||||
actualBody := map[string]interface{}{}
|
actualBody := map[string]interface{}{}
|
||||||
err := json.Unmarshal(actual.Body.Bytes(), &actualBody)
|
err := json.Unmarshal(actual.Body.Bytes(), &actualBody)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, scopeID, int(actualBody["userId"].(float64)))
|
require.Equal(t, scopeID, int(actualBody["id"].(float64)))
|
||||||
require.Equal(t, tc.user.Login, actualBody["login"].(string))
|
require.Equal(t, tc.user.Login, actualBody["login"].(string))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ func NewServiceAccountsStore(store *sqlstore.SQLStore) *ServiceAccountsStoreImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, sa *serviceaccounts.CreateServiceaccountForm) (user *models.User, err error) {
|
func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, sa *serviceaccounts.CreateServiceaccountForm) (saDTO *serviceaccounts.ServiceAccountDTO, err error) {
|
||||||
// create a new service account - "user" with empty permissions
|
// create a new service account - "user" with empty permissions
|
||||||
generatedLogin := "Service-Account-" + uuid.New().String()
|
generatedLogin := "Service-Account-" + uuid.New().String()
|
||||||
cmd := models.CreateUserCommand{
|
cmd := models.CreateUserCommand{
|
||||||
@ -38,7 +38,13 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccount(ctx context.Context, sa
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create user: %v", err)
|
return nil, fmt.Errorf("failed to create user: %v", err)
|
||||||
}
|
}
|
||||||
return newuser, nil
|
return &serviceaccounts.ServiceAccountDTO{
|
||||||
|
Id: newuser.Id,
|
||||||
|
Name: newuser.Name,
|
||||||
|
Login: newuser.Login,
|
||||||
|
OrgId: newuser.OrgId,
|
||||||
|
Tokens: 0,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceAccountsStoreImpl) DeleteServiceAccount(ctx context.Context, orgID, serviceaccountID int64) error {
|
func (s *ServiceAccountsStoreImpl) DeleteServiceAccount(ctx context.Context, orgID, serviceaccountID int64) error {
|
||||||
@ -132,33 +138,48 @@ func (s *ServiceAccountsStoreImpl) ListTokens(ctx context.Context, orgID int64,
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceAccountsStoreImpl) ListServiceAccounts(ctx context.Context, orgID, serviceAccountID int64) ([]*models.OrgUserDTO, error) {
|
func (s *ServiceAccountsStoreImpl) ListServiceAccounts(ctx context.Context, orgID, serviceAccountID int64) ([]*serviceaccounts.ServiceAccountDTO, error) {
|
||||||
query := models.GetOrgUsersQuery{OrgId: orgID, IsServiceAccount: true}
|
query := models.GetOrgUsersQuery{OrgId: orgID, IsServiceAccount: true}
|
||||||
if serviceAccountID > 0 {
|
if serviceAccountID > 0 {
|
||||||
query.UserID = serviceAccountID
|
query.UserID = serviceAccountID
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.sqlStore.GetOrgUsers(ctx, &query)
|
err := s.sqlStore.GetOrgUsers(ctx, &query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
saDTOs := make([]*serviceaccounts.ServiceAccountDTO, len(query.Result))
|
||||||
return query.Result, err
|
for i, user := range query.Result {
|
||||||
|
saDTOs[i] = &serviceaccounts.ServiceAccountDTO{
|
||||||
|
Id: user.UserId,
|
||||||
|
OrgId: user.OrgId,
|
||||||
|
Name: user.Name,
|
||||||
|
Login: user.Login,
|
||||||
|
}
|
||||||
|
tokens, err := s.ListTokens(ctx, user.OrgId, user.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
saDTOs[i].Tokens = int64(len(tokens))
|
||||||
|
}
|
||||||
|
return saDTOs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveServiceAccountByID returns a service account by its ID
|
// RetrieveServiceAccountByID returns a service account by its ID
|
||||||
func (s *ServiceAccountsStoreImpl) RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*models.OrgUserDTO, error) {
|
func (s *ServiceAccountsStoreImpl) RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*serviceaccounts.ServiceAccountProfileDTO, error) {
|
||||||
query := models.GetOrgUsersQuery{UserID: serviceAccountID, OrgId: orgID, IsServiceAccount: true}
|
query := models.GetOrgUsersQuery{UserID: serviceAccountID, OrgId: orgID, IsServiceAccount: true}
|
||||||
err := s.sqlStore.GetOrgUsers(ctx, &query)
|
err := s.sqlStore.GetOrgUsers(ctx, &query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(query.Result) != 1 {
|
if len(query.Result) != 1 {
|
||||||
return nil, serviceaccounts.ErrServiceAccountNotFound
|
return nil, serviceaccounts.ErrServiceAccountNotFound
|
||||||
}
|
}
|
||||||
|
saProfile := &serviceaccounts.ServiceAccountProfileDTO{
|
||||||
return query.Result[0], err
|
Id: query.Result[0].UserId,
|
||||||
|
Name: query.Result[0].Name,
|
||||||
|
Login: query.Result[0].Login,
|
||||||
|
}
|
||||||
|
return saProfile, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(s []int64, e int64) bool {
|
func contains(s []int64, e int64) bool {
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
@ -50,7 +49,7 @@ func ProvideServiceAccountsService(
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *ServiceAccountsService) CreateServiceAccount(ctx context.Context, saForm *serviceaccounts.CreateServiceaccountForm) (*models.User, error) {
|
func (sa *ServiceAccountsService) CreateServiceAccount(ctx context.Context, saForm *serviceaccounts.CreateServiceaccountForm) (*serviceaccounts.ServiceAccountDTO, error) {
|
||||||
if !sa.features.IsEnabled(featuremgmt.FlagServiceAccounts) {
|
if !sa.features.IsEnabled(featuremgmt.FlagServiceAccounts) {
|
||||||
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
|
sa.log.Debug(ServiceAccountFeatureToggleNotFound)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package serviceaccounts
|
package serviceaccounts
|
||||||
|
|
||||||
import "github.com/grafana/grafana/pkg/services/accesscontrol"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ScopeAll = "serviceaccounts:*"
|
ScopeAll = "serviceaccounts:*"
|
||||||
@ -22,3 +26,23 @@ type CreateServiceaccountForm struct {
|
|||||||
OrgID int64 `json:"-"`
|
OrgID int64 `json:"-"`
|
||||||
Name string `json:"name" binding:"Required"`
|
Name string `json:"name" binding:"Required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServiceAccountDTO struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Login string `json:"login"`
|
||||||
|
OrgId int64 `json:"orgId"`
|
||||||
|
Tokens int64 `json:"tokens"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountProfileDTO struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Login string `json:"login"`
|
||||||
|
OrgId int64 `json:"orgId"`
|
||||||
|
IsDisabled bool `json:"isDisabled"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
AvatarUrl string `json:"avatarUrl"`
|
||||||
|
AccessControl map[string]bool `json:"accessControl,omitempty"`
|
||||||
|
}
|
||||||
|
@ -6,15 +6,16 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// this should reflect the api
|
||||||
type Service interface {
|
type Service interface {
|
||||||
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error)
|
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*ServiceAccountDTO, error)
|
||||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*models.User, error)
|
CreateServiceAccount(ctx context.Context, saForm *CreateServiceaccountForm) (*ServiceAccountDTO, error)
|
||||||
ListServiceAccounts(ctx context.Context, orgID, serviceAccountID int64) ([]*models.OrgUserDTO, error)
|
ListServiceAccounts(ctx context.Context, orgID, serviceAccountID int64) ([]*ServiceAccountDTO, error)
|
||||||
RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*models.OrgUserDTO, error)
|
RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*ServiceAccountProfileDTO, error)
|
||||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||||
UpgradeServiceAccounts(ctx context.Context) error
|
UpgradeServiceAccounts(ctx context.Context) error
|
||||||
ConvertToServiceAccounts(ctx context.Context, keys []int64) error
|
ConvertToServiceAccounts(ctx context.Context, keys []int64) error
|
||||||
|
@ -29,7 +29,7 @@ func SetupUserServiceAccount(t *testing.T, sqlStore *sqlstore.SQLStore, testUser
|
|||||||
// create mock for serviceaccountservice
|
// create mock for serviceaccountservice
|
||||||
type ServiceAccountMock struct{}
|
type ServiceAccountMock struct{}
|
||||||
|
|
||||||
func (s *ServiceAccountMock) CreateServiceAccount(ctx context.Context, saForm *serviceaccounts.CreateServiceaccountForm) (*models.User, error) {
|
func (s *ServiceAccountMock) CreateServiceAccount(ctx context.Context, saForm *serviceaccounts.CreateServiceaccountForm) (*serviceaccounts.ServiceAccountDTO, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ type ServiceAccountsStoreMock struct {
|
|||||||
Calls Calls
|
Calls Calls
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceAccountsStoreMock) CreateServiceAccount(ctx context.Context, cmd *serviceaccounts.CreateServiceaccountForm) (*models.User, error) {
|
func (s *ServiceAccountsStoreMock) CreateServiceAccount(ctx context.Context, cmd *serviceaccounts.CreateServiceaccountForm) (*serviceaccounts.ServiceAccountDTO, error) {
|
||||||
// now we can test that the mock has these calls when we call the function
|
// now we can test that the mock has these calls when we call the function
|
||||||
s.Calls.CreateServiceAccount = append(s.Calls.CreateServiceAccount, []interface{}{ctx, cmd})
|
s.Calls.CreateServiceAccount = append(s.Calls.CreateServiceAccount, []interface{}{ctx, cmd})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -95,12 +95,12 @@ func (s *ServiceAccountsStoreMock) ListTokens(ctx context.Context, orgID int64,
|
|||||||
s.Calls.ListTokens = append(s.Calls.ListTokens, []interface{}{ctx, orgID, serviceAccount})
|
s.Calls.ListTokens = append(s.Calls.ListTokens, []interface{}{ctx, orgID, serviceAccount})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (s *ServiceAccountsStoreMock) ListServiceAccounts(ctx context.Context, orgID int64, serviceAccountID int64) ([]*models.OrgUserDTO, error) {
|
func (s *ServiceAccountsStoreMock) ListServiceAccounts(ctx context.Context, orgID int64, serviceAccountID int64) ([]*serviceaccounts.ServiceAccountDTO, error) {
|
||||||
s.Calls.ListServiceAccounts = append(s.Calls.ListServiceAccounts, []interface{}{ctx, orgID})
|
s.Calls.ListServiceAccounts = append(s.Calls.ListServiceAccounts, []interface{}{ctx, orgID})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceAccountsStoreMock) RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*models.OrgUserDTO, error) {
|
func (s *ServiceAccountsStoreMock) RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*serviceaccounts.ServiceAccountProfileDTO, error) {
|
||||||
s.Calls.RetrieveServiceAccount = append(s.Calls.RetrieveServiceAccount, []interface{}{ctx, orgID, serviceAccountID})
|
s.Calls.RetrieveServiceAccount = append(s.Calls.RetrieveServiceAccount, []interface{}{ctx, orgID, serviceAccountID})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,11 @@ export function ServiceAccountProfile({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleServiceAccountDelete = () => onServiceAccountDelete(serviceaccount.userId);
|
const handleServiceAccountDelete = () => onServiceAccountDelete(serviceaccount.id);
|
||||||
|
|
||||||
const handleServiceAccountDisable = () => onServiceAccountDisable(serviceaccount.userId);
|
const handleServiceAccountDisable = () => onServiceAccountDisable(serviceaccount.id);
|
||||||
|
|
||||||
const handleServiceAccountEnable = () => onServiceAccountEnable(serviceaccount.userId);
|
const handleServiceAccountEnable = () => onServiceAccountEnable(serviceaccount.id);
|
||||||
|
|
||||||
const onServiceAccountNameChange = (newValue: string) => {
|
const onServiceAccountNameChange = (newValue: string) => {
|
||||||
onServiceAccountUpdate({
|
onServiceAccountUpdate({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useEffect } from 'react';
|
import React, { memo, useEffect } from 'react';
|
||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
import { LinkButton, useStyles2 } from '@grafana/ui';
|
import { Icon, LinkButton, useStyles2 } from '@grafana/ui';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
|
|
||||||
import Page from 'app/core/components/Page/Page';
|
import Page from 'app/core/components/Page/Page';
|
||||||
@ -67,7 +67,7 @@ const ServiceAccountsListPage: React.FC<Props> = ({ loadServiceAccounts, navMode
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{serviceAccounts.map((serviceaccount: ServiceAccountDTO) => (
|
{serviceAccounts.map((serviceaccount: ServiceAccountDTO) => (
|
||||||
<ServiceAccountListItem serviceaccount={serviceaccount} key={serviceaccount.userId} />
|
<ServiceAccountListItem serviceaccount={serviceaccount} key={serviceaccount.id} />
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -88,11 +88,11 @@ const getServiceAccountsAriaLabel = (name: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ServiceAccountListItem = memo(({ serviceaccount }: ServiceAccountListItemProps) => {
|
const ServiceAccountListItem = memo(({ serviceaccount }: ServiceAccountListItemProps) => {
|
||||||
const editUrl = `org/serviceaccounts/${serviceaccount.userId}`;
|
const editUrl = `org/serviceaccounts/${serviceaccount.id}`;
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={serviceaccount.userId}>
|
<tr key={serviceaccount.id}>
|
||||||
<td className="width-4 text-center link-td">
|
<td className="width-4 text-center link-td">
|
||||||
<a href={editUrl} aria-label={getServiceAccountsAriaLabel(serviceaccount.name)}>
|
<a href={editUrl} aria-label={getServiceAccountsAriaLabel(serviceaccount.name)}>
|
||||||
<img
|
<img
|
||||||
@ -143,7 +143,10 @@ const ServiceAccountListItem = memo(({ serviceaccount }: ServiceAccountListItemP
|
|||||||
title="tokens"
|
title="tokens"
|
||||||
aria-label={getServiceAccountsAriaLabel(serviceaccount.name)}
|
aria-label={getServiceAccountsAriaLabel(serviceaccount.name)}
|
||||||
>
|
>
|
||||||
0
|
<span>
|
||||||
|
<Icon name={'key-skeleton-alt'}></Icon>
|
||||||
|
</span>
|
||||||
|
{serviceaccount.tokens}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { ThunkResult } from '../../../types';
|
import { ThunkResult } from '../../../types';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv } from '@grafana/runtime';
|
||||||
import { ServiceAccountDTO } from 'app/types';
|
|
||||||
import { serviceAccountLoaded, serviceAccountsLoaded, serviceAccountTokensLoaded } from './reducers';
|
import { serviceAccountLoaded, serviceAccountsLoaded, serviceAccountTokensLoaded } from './reducers';
|
||||||
|
|
||||||
const BASE_URL = `/api/serviceaccounts`;
|
const BASE_URL = `/api/serviceaccounts`;
|
||||||
|
|
||||||
export function loadServiceAccount(id: number): ThunkResult<void> {
|
export function loadServiceAccount(saID: number): ThunkResult<void> {
|
||||||
return async (dispatch) => {
|
return async (dispatch) => {
|
||||||
try {
|
try {
|
||||||
const response = await getBackendSrv().get(`${BASE_URL}/${id}`);
|
const response = await getBackendSrv().get(`${BASE_URL}/${saID}`);
|
||||||
dispatch(serviceAccountLoaded(response));
|
dispatch(serviceAccountLoaded(response));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@ -45,10 +44,10 @@ export function loadServiceAccounts(): ThunkResult<void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateServiceAccount(serviceAccount: ServiceAccountDTO): ThunkResult<void> {
|
export function updateServiceAccount(saID: number): ThunkResult<void> {
|
||||||
return async (dispatch) => {
|
return async (dispatch) => {
|
||||||
// TODO: implement on backend
|
// TODO: implement on backend
|
||||||
await getBackendSrv().patch(`${BASE_URL}/${serviceAccount.userId}`, {});
|
await getBackendSrv().patch(`${BASE_URL}/${saID}`, {});
|
||||||
dispatch(loadServiceAccounts());
|
dispatch(loadServiceAccounts());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ export const getServiceAccounts = (state: ServiceAccountsState) => {
|
|||||||
const regex = new RegExp(state.searchQuery, 'i');
|
const regex = new RegExp(state.searchQuery, 'i');
|
||||||
|
|
||||||
return state.serviceAccounts.filter((serviceaccount) => {
|
return state.serviceAccounts.filter((serviceaccount) => {
|
||||||
return regex.test(serviceaccount.login) || regex.test(serviceaccount.email) || regex.test(serviceaccount.name);
|
return regex.test(serviceaccount.name) || regex.test(serviceaccount.login);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,15 +25,13 @@ export interface ServiceAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ServiceAccountDTO extends WithAccessControlMetadata {
|
export interface ServiceAccountDTO extends WithAccessControlMetadata {
|
||||||
|
id: number;
|
||||||
orgId: number;
|
orgId: number;
|
||||||
userId: number;
|
tokens: number;
|
||||||
email: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
avatarUrl?: string;
|
|
||||||
login: string;
|
login: string;
|
||||||
|
avatarUrl?: string;
|
||||||
role: string;
|
role: string;
|
||||||
lastSeenAt: string;
|
|
||||||
lastSeenAtAge: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServiceAccountProfileState {
|
export interface ServiceAccountProfileState {
|
||||||
|
Loading…
Reference in New Issue
Block a user