{"version":3,"file":"ServiceAccountPage.bc7c35b63b03ccc89628.js","mappings":"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","sources":["webpack://grafana/./public/app/features/serviceaccounts/ServiceAccountPermissions.tsx","webpack://grafana/./public/app/features/serviceaccounts/components/ServiceAccountProfileRow.tsx","webpack://grafana/./public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx","webpack://grafana/./public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx","webpack://grafana/./public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx","webpack://grafana/./public/app/features/serviceaccounts/state/actionsServiceAccountPage.ts","webpack://grafana/./public/app/features/serviceaccounts/ServiceAccountPage.tsx","webpack://grafana/./public/app/features/serviceaccounts/components/CreateTokenModal.tsx","webpack://grafana/./public/app/features/serviceaccounts/state/actions.ts"],"sourcesContent":["import React from 'react';\n\nimport { Permissions } from 'app/core/components/AccessControl';\nimport { contextSrv } from 'app/core/services/context_srv';\n\nimport { AccessControlAction, ServiceAccountDTO } from '../../types';\n\ntype ServiceAccountPermissionsProps = {\n serviceAccount: ServiceAccountDTO;\n};\n\nexport const ServiceAccountPermissions = (props: ServiceAccountPermissionsProps) => {\n const canSetPermissions = contextSrv.hasPermissionInMetadata(\n AccessControlAction.ServiceAccountsPermissionsWrite,\n props.serviceAccount\n );\n\n return (\n \n );\n};\n","import { css, cx } from '@emotion/css';\nimport React, { useEffect, useRef, useState } from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { ConfirmButton, Input, Label, LegacyInputStatus, useStyles2 } from '@grafana/ui';\n\ninterface Props {\n label: string;\n value?: string;\n inputType?: string;\n disabled?: boolean;\n onChange?: (value: string) => void;\n}\n\nexport const ServiceAccountProfileRow = ({ label, value, inputType, disabled, onChange }: Props): JSX.Element => {\n const inputElem = useRef(null);\n const [inputValue, setInputValue] = useState(value);\n const [isEditing, setIsEditing] = useState(false);\n const styles = useStyles2(getStyles);\n const inputId = `${label}-input`;\n\n useEffect(() => {\n if (isEditing) {\n focusInput();\n }\n }, [isEditing]);\n\n const onEditClick = () => {\n setIsEditing(true);\n };\n\n const onCancelClick = () => {\n setIsEditing(false);\n setInputValue(value || '');\n };\n\n const onInputChange = (event: React.ChangeEvent, status?: LegacyInputStatus) => {\n if (status === LegacyInputStatus.Invalid) {\n return;\n }\n setInputValue(event.target.value);\n };\n\n const onInputBlur = (event: React.FocusEvent, status?: LegacyInputStatus) => {\n if (status === LegacyInputStatus.Invalid) {\n return;\n }\n setInputValue(event.target.value);\n };\n\n const focusInput = () => {\n inputElem?.current?.focus();\n };\n\n const onSave = () => {\n setIsEditing(false);\n if (onChange) {\n onChange(inputValue!);\n }\n };\n\n return (\n \n \n \n \n \n {!disabled && isEditing ? (\n \n ) : (\n {value}\n )}\n \n \n {onChange && (\n \n Edit\n \n )}\n \n \n );\n};\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n disabled: css`\n color: ${theme.colors.text.secondary};\n `,\n };\n};\n","import React from 'react';\n\nimport { Label } from '@grafana/ui';\nimport { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';\nimport { contextSrv } from 'app/core/core';\nimport { OrgRolePicker } from 'app/features/admin/OrgRolePicker';\nimport { AccessControlAction, OrgRole, Role, ServiceAccountDTO } from 'app/types';\n\ninterface Props {\n label: string;\n serviceAccount: ServiceAccountDTO;\n onRoleChange: (role: OrgRole) => void;\n roleOptions: Role[];\n}\n\nexport const ServiceAccountRoleRow = ({ label, serviceAccount, roleOptions, onRoleChange }: Props): JSX.Element => {\n const inputId = `${label}-input`;\n const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount);\n\n return (\n \n \n \n \n {contextSrv.licensedAccessControlEnabled() ? (\n \n \n \n ) : (\n <>\n \n \n \n \n \n )}\n \n );\n};\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { dateTimeFormat, GrafanaTheme2, OrgRole, TimeZone } from '@grafana/data';\nimport { Label, TextLink, useStyles2 } from '@grafana/ui';\nimport { fetchRoleOptions } from 'app/core/components/RolePicker/api';\nimport { contextSrv } from 'app/core/core';\nimport { AccessControlAction, Role, ServiceAccountDTO } from 'app/types';\n\nimport { ServiceAccountProfileRow } from './ServiceAccountProfileRow';\nimport { ServiceAccountRoleRow } from './ServiceAccountRoleRow';\n\ninterface Props {\n serviceAccount: ServiceAccountDTO;\n timeZone: TimeZone;\n onChange: (serviceAccount: ServiceAccountDTO) => void;\n}\n\nexport function ServiceAccountProfile({ serviceAccount, timeZone, onChange }: Props): JSX.Element {\n const styles = useStyles2(getStyles);\n const ableToWrite = contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite);\n const [roles, setRoleOptions] = React.useState([]);\n\n const onRoleChange = (role: OrgRole) => {\n onChange({ ...serviceAccount, role: role });\n };\n\n const onNameChange = (newValue: string) => {\n onChange({ ...serviceAccount, name: newValue });\n };\n\n React.useEffect(() => {\n async function fetchOptions() {\n try {\n if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {\n let options = await fetchRoleOptions(serviceAccount.orgId);\n setRoleOptions(options);\n }\n } catch (e) {\n console.error('Error loading options for service account');\n }\n }\n if (contextSrv.licensedAccessControlEnabled()) {\n fetchOptions();\n }\n }, [serviceAccount.orgId]);\n\n return (\n
\n

Information

\n \n \n \n \n \n \n {serviceAccount.isExternal && serviceAccount.requiredBy && (\n \n \n \n \n )}\n \n
\n \n \n {serviceAccount.requiredBy}\n
\n
\n );\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => ({\n section: css`\n margin-bottom: ${theme.spacing(4)};\n `,\n});\n","import { css, cx } from '@emotion/css';\nimport React from 'react';\n\nimport { dateTimeFormat, GrafanaTheme2, TimeZone } from '@grafana/data';\nimport { DeleteButton, Icon, Tooltip, useStyles2, useTheme2 } from '@grafana/ui';\nimport { ApiKey } from 'app/types';\n\ninterface Props {\n tokens: ApiKey[];\n timeZone: TimeZone;\n tokenActionsDisabled?: boolean;\n onDelete: (token: ApiKey) => void;\n}\n\nexport const ServiceAccountTokensTable = ({ tokens, timeZone, tokenActionsDisabled, onDelete }: Props): JSX.Element => {\n const theme = useTheme2();\n const styles = getStyles(theme);\n\n return (\n \n \n \n \n \n \n \n \n \n \n {tokens.map((key) => {\n return (\n \n \n \n \n \n \n \n \n );\n })}\n \n
NameExpiresCreatedLast used at\n \n
{key.name}\n \n {formatDate(timeZone, key.created)}{formatLastUsedAtDate(timeZone, key.lastUsedAt)}{key.isRevoked && }\n onDelete(key)}\n disabled={tokenActionsDisabled}\n />\n
\n );\n};\n\nfunction formatLastUsedAtDate(timeZone: TimeZone, lastUsedAt?: string): string {\n if (!lastUsedAt) {\n return 'Never';\n }\n return dateTimeFormat(lastUsedAt, { timeZone });\n}\n\nfunction formatDate(timeZone: TimeZone, expiration?: string): string {\n if (!expiration) {\n return 'No expiration date';\n }\n return dateTimeFormat(expiration, { timeZone });\n}\n\nfunction formatSecondsLeftUntilExpiration(secondsUntilExpiration: number): string {\n const days = Math.ceil(secondsUntilExpiration / (3600 * 24));\n const daysFormat = days > 1 ? `${days} days` : `${days} day`;\n return `Expires in ${daysFormat}`;\n}\n\nconst TokenRevoked = () => {\n const styles = useStyles2(getStyles);\n return (\n \n Revoked\n \n \n \n \n \n \n );\n};\n\ninterface TokenExpirationProps {\n timeZone: TimeZone;\n token: ApiKey;\n}\n\nconst TokenExpiration = ({ timeZone, token }: TokenExpirationProps) => {\n const styles = useStyles2(getStyles);\n if (!token.expiration) {\n return Never;\n }\n if (token.secondsUntilExpiration) {\n return (\n \n {formatSecondsLeftUntilExpiration(token.secondsUntilExpiration)}\n \n );\n }\n if (token.hasExpired) {\n return (\n \n Expired\n \n \n \n \n \n \n );\n }\n return {formatDate(timeZone, token.expiration)};\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n tableRow: (hasExpired: boolean | undefined) => css`\n color: ${hasExpired ? theme.colors.text.secondary : theme.colors.text.primary};\n `,\n tooltipContainer: css`\n margin-left: ${theme.spacing(1)};\n `,\n toolTipIcon: css`\n color: ${theme.colors.error.text};\n `,\n secondsUntilExpiration: css`\n color: ${theme.colors.warning.text};\n `,\n hasExpired: css`\n color: ${theme.colors.error.text};\n `,\n neverExpire: css`\n color: ${theme.colors.text.secondary};\n `,\n section: css`\n margin-bottom: ${theme.spacing(4)};\n `,\n});\n","import { getBackendSrv, locationService } from '@grafana/runtime';\nimport { accessControlQueryParam } from 'app/core/utils/accessControl';\nimport { ServiceAccountDTO, ThunkResult } from 'app/types';\n\nimport { ServiceAccountToken } from '../components/CreateTokenModal';\n\nimport {\n serviceAccountFetchBegin,\n serviceAccountFetchEnd,\n serviceAccountLoaded,\n serviceAccountTokensLoaded,\n} from './reducers';\n\nconst BASE_URL = `/api/serviceaccounts`;\n\nexport function loadServiceAccount(saID: number): ThunkResult {\n return async (dispatch) => {\n dispatch(serviceAccountFetchBegin());\n try {\n const response = await getBackendSrv().get(`${BASE_URL}/${saID}`, accessControlQueryParam());\n dispatch(serviceAccountLoaded(response));\n } catch (error) {\n console.error(error);\n } finally {\n dispatch(serviceAccountFetchEnd());\n }\n };\n}\n\nexport function updateServiceAccount(serviceAccount: ServiceAccountDTO): ThunkResult {\n return async (dispatch) => {\n await getBackendSrv().patch(`${BASE_URL}/${serviceAccount.id}?accesscontrol=true`, {\n ...serviceAccount,\n });\n dispatch(loadServiceAccount(serviceAccount.id));\n };\n}\n\nexport function deleteServiceAccount(serviceAccountId: number): ThunkResult {\n return async () => {\n await getBackendSrv().delete(`${BASE_URL}/${serviceAccountId}`);\n locationService.push('/org/serviceaccounts');\n };\n}\n\nexport function createServiceAccountToken(\n saID: number,\n token: ServiceAccountToken,\n onTokenCreated: (key: string) => void\n): ThunkResult {\n return async (dispatch) => {\n const result = await getBackendSrv().post(`${BASE_URL}/${saID}/tokens`, token);\n onTokenCreated(result.key);\n dispatch(loadServiceAccountTokens(saID));\n };\n}\n\nexport function deleteServiceAccountToken(saID: number, id: number): ThunkResult {\n return async (dispatch) => {\n await getBackendSrv().delete(`${BASE_URL}/${saID}/tokens/${id}`);\n dispatch(loadServiceAccountTokens(saID));\n };\n}\n\nexport function loadServiceAccountTokens(saID: number): ThunkResult {\n return async (dispatch) => {\n try {\n const response = await getBackendSrv().get(`${BASE_URL}/${saID}/tokens`);\n dispatch(serviceAccountTokensLoaded(response));\n } catch (error) {\n console.error(error);\n }\n };\n}\n","import React, { useEffect, useState } from 'react';\nimport { connect, ConnectedProps } from 'react-redux';\n\nimport { getTimeZone, NavModelItem } from '@grafana/data';\nimport { Button, ConfirmModal, HorizontalGroup, IconButton } from '@grafana/ui';\nimport { Page } from 'app/core/components/Page/Page';\nimport { contextSrv } from 'app/core/core';\nimport { GrafanaRouteComponentProps } from 'app/core/navigation/types';\nimport { AccessControlAction, ApiKey, ServiceAccountDTO, StoreState } from 'app/types';\n\nimport { ServiceAccountPermissions } from './ServiceAccountPermissions';\nimport { CreateTokenModal, ServiceAccountToken } from './components/CreateTokenModal';\nimport { ServiceAccountProfile } from './components/ServiceAccountProfile';\nimport { ServiceAccountTokensTable } from './components/ServiceAccountTokensTable';\nimport { fetchACOptions } from './state/actions';\nimport {\n createServiceAccountToken,\n deleteServiceAccount,\n deleteServiceAccountToken,\n loadServiceAccount,\n loadServiceAccountTokens,\n updateServiceAccount,\n} from './state/actionsServiceAccountPage';\n\ninterface OwnProps extends GrafanaRouteComponentProps<{ id: string }> {\n serviceAccount?: ServiceAccountDTO;\n tokens: ApiKey[];\n isLoading: boolean;\n}\n\nfunction mapStateToProps(state: StoreState) {\n return {\n serviceAccount: state.serviceAccountProfile.serviceAccount,\n tokens: state.serviceAccountProfile.tokens,\n isLoading: state.serviceAccountProfile.isLoading,\n timezone: getTimeZone(state.user),\n };\n}\n\nconst mapDispatchToProps = {\n createServiceAccountToken,\n deleteServiceAccount,\n deleteServiceAccountToken,\n loadServiceAccount,\n loadServiceAccountTokens,\n updateServiceAccount,\n};\n\nconst connector = connect(mapStateToProps, mapDispatchToProps);\n\nexport type Props = OwnProps & ConnectedProps;\n\nexport const ServiceAccountPageUnconnected = ({\n match,\n serviceAccount,\n tokens,\n timezone,\n isLoading,\n createServiceAccountToken,\n deleteServiceAccount,\n deleteServiceAccountToken,\n loadServiceAccount,\n loadServiceAccountTokens,\n updateServiceAccount,\n}: Props): JSX.Element => {\n const [newToken, setNewToken] = useState('');\n const [isTokenModalOpen, setIsTokenModalOpen] = useState(false);\n const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);\n const [isDisableModalOpen, setIsDisableModalOpen] = useState(false);\n\n const serviceAccountId = parseInt(match.params.id, 10);\n const tokenActionsDisabled =\n serviceAccount.isDisabled ||\n serviceAccount.isExternal ||\n !contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite);\n\n const ableToWrite = contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite);\n const canReadPermissions = contextSrv.hasPermissionInMetadata(\n AccessControlAction.ServiceAccountsPermissionsRead,\n serviceAccount!\n );\n\n const pageNav: NavModelItem = {\n text: serviceAccount.name,\n img: serviceAccount.avatarUrl,\n subTitle: 'Manage settings for an individual service account.',\n };\n\n useEffect(() => {\n loadServiceAccount(serviceAccountId);\n loadServiceAccountTokens(serviceAccountId);\n if (contextSrv.licensedAccessControlEnabled()) {\n fetchACOptions();\n }\n }, [loadServiceAccount, loadServiceAccountTokens, serviceAccountId]);\n\n const onProfileChange = (serviceAccount: ServiceAccountDTO) => {\n updateServiceAccount(serviceAccount);\n };\n\n const showDeleteServiceAccountModal = (show: boolean) => () => {\n setIsDeleteModalOpen(show);\n };\n\n const showDisableServiceAccountModal = (show: boolean) => () => {\n setIsDisableModalOpen(show);\n };\n\n const handleServiceAccountDelete = () => {\n deleteServiceAccount(serviceAccount.id);\n };\n\n const handleServiceAccountDisable = () => {\n updateServiceAccount({ ...serviceAccount, isDisabled: true });\n setIsDisableModalOpen(false);\n };\n\n const handleServiceAccountEnable = () => {\n updateServiceAccount({ ...serviceAccount, isDisabled: false });\n };\n\n const onDeleteServiceAccountToken = (key: ApiKey) => {\n deleteServiceAccountToken(serviceAccount?.id, key.id!);\n };\n\n const onCreateToken = (token: ServiceAccountToken) => {\n createServiceAccountToken(serviceAccount?.id, token, setNewToken);\n };\n\n const onTokenModalClose = () => {\n setIsTokenModalOpen(false);\n setNewToken('');\n };\n\n return (\n \n \n
\n {serviceAccount && !serviceAccount.isExternal && (\n \n \n Delete service account\n \n {serviceAccount.isDisabled ? (\n \n Enable service account\n \n ) : (\n \n Disable service account\n \n )}\n \n )}\n {serviceAccount && serviceAccount.isExternal && (\n \n \n \n )}\n {serviceAccount && (\n \n )}\n \n

Tokens

\n {!serviceAccount.isExternal && (\n \n )}\n
\n {tokens && (\n \n )}\n {!serviceAccount.isExternal && canReadPermissions && (\n \n )}\n
\n\n \n \n \n
\n
\n );\n};\n\nexport default connector(ServiceAccountPageUnconnected);\n","import { css } from '@emotion/css';\nimport React, { useEffect, useState } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { config } from '@grafana/runtime';\nimport {\n Button,\n ClipboardButton,\n DatePickerWithInput,\n Field,\n Input,\n Modal,\n RadioButtonGroup,\n useStyles2,\n} from '@grafana/ui';\n\nconst EXPIRATION_OPTIONS = [\n { label: 'No expiration', value: false },\n { label: 'Set expiration date', value: true },\n];\n\nexport type ServiceAccountToken = {\n name: string;\n secondsToLive?: number;\n};\n\ninterface Props {\n isOpen: boolean;\n token: string;\n serviceAccountLogin: string;\n onCreateToken: (token: ServiceAccountToken) => void;\n onClose: () => void;\n}\n\nexport const CreateTokenModal = ({ isOpen, token, serviceAccountLogin, onCreateToken, onClose }: Props) => {\n const tomorrow = new Date();\n tomorrow.setDate(tomorrow.getDate() + 1);\n\n const maxExpirationDate = new Date();\n if (config.tokenExpirationDayLimit !== undefined && config.tokenExpirationDayLimit > -1) {\n maxExpirationDate.setDate(maxExpirationDate.getDate() + config.tokenExpirationDayLimit + 1);\n } else {\n maxExpirationDate.setDate(8640000000000000);\n }\n const defaultExpirationDate = config.tokenExpirationDayLimit !== undefined && config.tokenExpirationDayLimit > 0;\n\n const [defaultTokenName, setDefaultTokenName] = useState('');\n const [newTokenName, setNewTokenName] = useState('');\n const [isWithExpirationDate, setIsWithExpirationDate] = useState(defaultExpirationDate);\n const [newTokenExpirationDate, setNewTokenExpirationDate] = useState(tomorrow);\n const [isExpirationDateValid, setIsExpirationDateValid] = useState(newTokenExpirationDate !== '');\n const styles = useStyles2(getStyles);\n\n useEffect(() => {\n // Generate new token name every time we open modal\n if (isOpen) {\n setDefaultTokenName(`${serviceAccountLogin}-${uuidv4()}`);\n }\n }, [serviceAccountLogin, isOpen]);\n\n const onExpirationDateChange = (value: Date | string) => {\n const isValid = value !== '';\n setIsExpirationDateValid(isValid);\n setNewTokenExpirationDate(value);\n };\n\n const onGenerateToken = () => {\n onCreateToken({\n name: newTokenName || defaultTokenName,\n secondsToLive: isWithExpirationDate ? getSecondsToLive(newTokenExpirationDate) : undefined,\n });\n };\n\n const onCloseInternal = () => {\n setNewTokenName('');\n setDefaultTokenName('');\n setIsWithExpirationDate(defaultExpirationDate);\n setNewTokenExpirationDate(tomorrow);\n setIsExpirationDateValid(newTokenExpirationDate !== '');\n onClose();\n };\n\n const modalTitle = !token ? 'Add service account token' : 'Service account token created';\n\n return (\n \n {!token ? (\n
\n \n {\n setNewTokenName(e.currentTarget.value);\n }}\n />\n \n \n \n \n {isWithExpirationDate && (\n \n \n \n )}\n \n \n \n
\n ) : (\n <>\n \n
\n \n token}\n >\n Copy clipboard\n \n
\n \n \n token} onClipboardCopy={onCloseInternal}>\n Copy to clipboard and close\n \n \n \n \n )}\n \n );\n};\n\nconst getSecondsToLive = (date: Date | string) => {\n const dateAsDate = new Date(date);\n const now = new Date();\n\n return Math.ceil((dateAsDate.getTime() - now.getTime()) / 1000);\n};\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n modal: css`\n width: 550px;\n `,\n modalContent: css`\n overflow: visible;\n `,\n modalTokenRow: css`\n display: flex;\n `,\n modalCopyToClipboardButton: css`\n margin-left: ${theme.spacing(0.5)};\n `,\n };\n};\n","import { debounce } from 'lodash';\n\nimport { getBackendSrv } from '@grafana/runtime';\nimport { fetchRoleOptions } from 'app/core/components/RolePicker/api';\nimport { contextSrv } from 'app/core/services/context_srv';\nimport { AccessControlAction, ServiceAccountDTO, ServiceAccountStateFilter, ThunkResult } from 'app/types';\n\nimport { ServiceAccountToken } from '../components/CreateTokenModal';\n\nimport {\n acOptionsLoaded,\n pageChanged,\n queryChanged,\n rolesFetchBegin,\n rolesFetchEnd,\n serviceAccountsFetchBegin,\n serviceAccountsFetched,\n serviceAccountsFetchEnd,\n stateFilterChanged,\n} from './reducers';\n\nconst BASE_URL = `/api/serviceaccounts`;\n\nexport function fetchACOptions(): ThunkResult {\n return async (dispatch) => {\n try {\n if (contextSrv.licensedAccessControlEnabled() && contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {\n const options = await fetchRoleOptions();\n dispatch(acOptionsLoaded(options));\n }\n } catch (error) {\n console.error(error);\n }\n };\n}\n\ninterface FetchServiceAccountsParams {\n withLoadingIndicator: boolean;\n}\n\nexport function fetchServiceAccounts(\n { withLoadingIndicator }: FetchServiceAccountsParams = { withLoadingIndicator: false }\n): ThunkResult {\n return async (dispatch, getState) => {\n try {\n if (contextSrv.hasPermission(AccessControlAction.ServiceAccountsRead)) {\n if (withLoadingIndicator) {\n dispatch(serviceAccountsFetchBegin());\n }\n const { perPage, page, query, serviceAccountStateFilter } = getState().serviceAccounts;\n const result = await getBackendSrv().get(\n `/api/serviceaccounts/search?perpage=${perPage}&page=${page}&query=${query}${getStateFilter(\n serviceAccountStateFilter\n )}&accesscontrol=true`\n );\n\n if (\n contextSrv.licensedAccessControlEnabled() &&\n contextSrv.hasPermission(AccessControlAction.ActionUserRolesList)\n ) {\n dispatch(rolesFetchBegin());\n const orgId = contextSrv.user.orgId;\n const userIds = result?.serviceAccounts.map((u: ServiceAccountDTO) => u.id);\n const roles = await getBackendSrv().post(`/api/access-control/users/roles/search`, { userIds, orgId });\n result.serviceAccounts.forEach((u: ServiceAccountDTO) => {\n u.roles = roles ? roles[u.id] || [] : [];\n });\n dispatch(rolesFetchEnd());\n }\n\n dispatch(serviceAccountsFetched(result));\n }\n } catch (error) {\n console.error(error);\n } finally {\n dispatch(serviceAccountsFetchEnd());\n }\n };\n}\n\nconst fetchServiceAccountsWithDebounce = debounce((dispatch) => dispatch(fetchServiceAccounts()), 500, {\n leading: true,\n});\n\nexport function updateServiceAccount(serviceAccount: ServiceAccountDTO): ThunkResult {\n return async (dispatch) => {\n await getBackendSrv().patch(`${BASE_URL}/${serviceAccount.id}?accesscontrol=true`, {\n ...serviceAccount,\n });\n dispatch(fetchServiceAccounts());\n };\n}\n\nexport function deleteServiceAccount(serviceAccountId: number): ThunkResult {\n return async (dispatch) => {\n await getBackendSrv().delete(`${BASE_URL}/${serviceAccountId}`);\n dispatch(fetchServiceAccounts());\n };\n}\n\nexport function createServiceAccountToken(\n saID: number,\n token: ServiceAccountToken,\n onTokenCreated: (key: string) => void\n): ThunkResult {\n return async (dispatch) => {\n const result = await getBackendSrv().post(`${BASE_URL}/${saID}/tokens`, token);\n onTokenCreated(result.key);\n dispatch(fetchServiceAccounts());\n };\n}\n\n// search / filtering of serviceAccounts\nconst getStateFilter = (value: ServiceAccountStateFilter) => {\n switch (value) {\n case ServiceAccountStateFilter.WithExpiredTokens:\n return '&expiredTokens=true';\n case ServiceAccountStateFilter.Disabled:\n return '&disabled=true';\n case ServiceAccountStateFilter.External:\n return '&external=true';\n default:\n return '';\n }\n};\n\nexport function changeQuery(query: string): ThunkResult {\n return async (dispatch) => {\n dispatch(queryChanged(query));\n fetchServiceAccountsWithDebounce(dispatch);\n };\n}\n\nexport function changeStateFilter(filter: ServiceAccountStateFilter): ThunkResult {\n return async (dispatch) => {\n dispatch(stateFilterChanged(filter));\n dispatch(fetchServiceAccounts());\n };\n}\n\nexport function changePage(page: number): ThunkResult {\n return async (dispatch) => {\n dispatch(pageChanged(page));\n dispatch(fetchServiceAccounts());\n };\n}\n"],"names":["ServiceAccountPermissions","props","canSetPermissions","ServiceAccountProfileRow","label","value","inputType","disabled","onChange","inputElem","inputValue","setInputValue","isEditing","setIsEditing","styles","getStyles","inputId","focusInput","onEditClick","onCancelClick","onInputChange","event","status","onInputBlur","onSave","Label","ConfirmButton","theme","ServiceAccountRoleRow","serviceAccount","roleOptions","onRoleChange","canUpdateRole","UserRolePicker","OrgRolePicker","ServiceAccountProfile","timeZone","ableToWrite","roles","setRoleOptions","role","onNameChange","newValue","fetchOptions","options","TextLink","ServiceAccountTokensTable","tokens","tokenActionsDisabled","onDelete","key","TokenExpiration","formatDate","formatLastUsedAtDate","TokenRevoked","DeleteButton","lastUsedAt","expiration","formatSecondsLeftUntilExpiration","secondsUntilExpiration","days","Tooltip","Icon","token","hasExpired","BASE_URL","loadServiceAccount","saID","dispatch","response","accessControl","error","updateServiceAccount","deleteServiceAccount","serviceAccountId","createServiceAccountToken","onTokenCreated","result","loadServiceAccountTokens","deleteServiceAccountToken","id","mapStateToProps","state","mapDispatchToProps","connector","ServiceAccountPageUnconnected","match","timezone","isLoading","newToken","setNewToken","isTokenModalOpen","setIsTokenModalOpen","isDeleteModalOpen","setIsDeleteModalOpen","isDisableModalOpen","setIsDisableModalOpen","canReadPermissions","pageNav","onProfileChange","showDeleteServiceAccountModal","show","showDisableServiceAccountModal","handleServiceAccountDelete","handleServiceAccountDisable","handleServiceAccountEnable","onDeleteServiceAccountToken","onCreateToken","onTokenModalClose","Page","Button","IconButton","ConfirmModal","CreateTokenModal","EXPIRATION_OPTIONS","isOpen","serviceAccountLogin","onClose","tomorrow","maxExpirationDate","defaultExpirationDate","defaultTokenName","setDefaultTokenName","newTokenName","setNewTokenName","isWithExpirationDate","setIsWithExpirationDate","newTokenExpirationDate","setNewTokenExpirationDate","isExpirationDateValid","setIsExpirationDateValid","onExpirationDateChange","onGenerateToken","getSecondsToLive","onCloseInternal","modalTitle","e","date","dateAsDate","now","fetchACOptions","fetchServiceAccounts","withLoadingIndicator","getState","perPage","page","query","serviceAccountStateFilter","getStateFilter","orgId","userIds","u","fetchServiceAccountsWithDebounce","changeQuery","changeStateFilter","filter","changePage"],"sourceRoot":""}