diff --git a/pkg/services/serviceaccounts/models.go b/pkg/services/serviceaccounts/models.go index 90b74ee6634..71b6aec6ac9 100644 --- a/pkg/services/serviceaccounts/models.go +++ b/pkg/services/serviceaccounts/models.go @@ -158,6 +158,8 @@ type ServiceAccountProfileDTO struct { Teams []string `json:"teams" xorm:"-"` // example: false IsExternal bool `json:"isExternal,omitempty" xorm:"-"` + // example: grafana-app + RequiredBy string `json:"requiredBy,omitempty" xorm:"-"` Tokens int64 `json:"tokens,omitempty"` AccessControl map[string]bool `json:"accessControl,omitempty" xorm:"-"` diff --git a/pkg/services/serviceaccounts/proxy/service.go b/pkg/services/serviceaccounts/proxy/service.go index 4aa593ebaa3..944ba3666da 100644 --- a/pkg/services/serviceaccounts/proxy/service.go +++ b/pkg/services/serviceaccounts/proxy/service.go @@ -139,6 +139,7 @@ func (s *ServiceAccountsProxy) RetrieveServiceAccount(ctx context.Context, orgID if s.isProxyEnabled { sa.IsExternal = isExternalServiceAccount(sa.Login) + sa.RequiredBy = strings.ReplaceAll(sa.Name, serviceaccounts.ExtSvcPrefix, "") } return sa, nil diff --git a/public/api-enterprise-spec.json b/public/api-enterprise-spec.json index a9bc2297374..3a321923847 100644 --- a/public/api-enterprise-spec.json +++ b/public/api-enterprise-spec.json @@ -6771,6 +6771,10 @@ "type": "boolean", "example": false }, + "requiredBy": { + "type": "string", + "example": "grafana-app" + }, "login": { "type": "string", "example": "sa-grafana" @@ -6826,6 +6830,10 @@ "type": "boolean", "example": false }, + "requiredBy": { + "type": "string", + "example": "grafana-app" + }, "login": { "type": "string", "example": "sa-grafana" diff --git a/public/api-merged.json b/public/api-merged.json index 6f410199d4d..30cf8dcc881 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -18724,6 +18724,10 @@ "format": "int64", "example": 1 }, + "requiredBy": { + "type": "string", + "example": "grafana-app" + }, "role": { "type": "string", "example": "Editor" diff --git a/public/app/features/serviceaccounts/ServiceAccountPage.tsx b/public/app/features/serviceaccounts/ServiceAccountPage.tsx index 7456b16a932..86be0ebee93 100644 --- a/public/app/features/serviceaccounts/ServiceAccountPage.tsx +++ b/public/app/features/serviceaccounts/ServiceAccountPage.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { getTimeZone, NavModelItem } from '@grafana/data'; -import { Button, ConfirmModal, HorizontalGroup } from '@grafana/ui'; +import { Button, ConfirmModal, HorizontalGroup, IconButton } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; import { contextSrv } from 'app/core/core'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; @@ -70,7 +70,9 @@ export const ServiceAccountPageUnconnected = ({ const serviceAccountId = parseInt(match.params.id, 10); const tokenActionsDisabled = - !contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite) || serviceAccount.isDisabled; + serviceAccount.isDisabled || + serviceAccount.isExternal || + !contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite); const ableToWrite = contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite); const canReadPermissions = contextSrv.hasPermissionInMetadata( @@ -134,7 +136,7 @@ export const ServiceAccountPageUnconnected = ({
- {serviceAccount && ( + {serviceAccount && !serviceAccount.isExternal && ( + {!serviceAccount.isExternal && ( + + )} {tokens && ( )} - {canReadPermissions && } + {!serviceAccount.isExternal && canReadPermissions && ( + + )}
@@ -68,6 +68,16 @@ export function ServiceAccountProfile({ serviceAccount, timeZone, onChange }: Pr value={dateTimeFormat(serviceAccount.createdAt, { timeZone })} disabled={serviceAccount.isDisabled} /> + {serviceAccount.isExternal && serviceAccount.requiredBy && ( + + + + + + {serviceAccount.requiredBy} + + + )} diff --git a/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx b/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx index 6d62e7216cb..b5b549fdd0e 100644 --- a/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx +++ b/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx @@ -42,7 +42,7 @@ export const ServiceAccountRoleRow = ({ label, serviceAccount, roleOptions, onRo inputId={inputId} aria-label="Role" value={serviceAccount.role} - disabled={serviceAccount.isDisabled} + disabled={serviceAccount.isExternal || serviceAccount.isDisabled} onChange={onRoleChange} /> diff --git a/public/app/types/serviceaccount.ts b/public/app/types/serviceaccount.ts index 8a3d4a8ef9a..a2ae3846c54 100644 --- a/public/app/types/serviceaccount.ts +++ b/public/app/types/serviceaccount.ts @@ -35,6 +35,7 @@ export interface ServiceAccountDTO extends WithAccessControlMetadata { createdAt: string; isDisabled: boolean; isExternal?: boolean; + requiredBy?: string; teams: string[]; role: OrgRole; roles?: Role[]; diff --git a/public/openapi3.json b/public/openapi3.json index bb3c4006ccf..145a9ce9d35 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -9626,6 +9626,10 @@ "format": "int64", "type": "integer" }, + "requiredBy": { + "example": "grafana-app", + "type": "string" + }, "role": { "example": "Editor", "type": "string"