ServiceAccountsListItem.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import { cx } from '@emotion/css';
  2. import React, { memo } from 'react';
  3. import { OrgRole } from '@grafana/data';
  4. import { Button, Icon, useStyles2 } from '@grafana/ui';
  5. import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
  6. import { contextSrv } from 'app/core/core';
  7. import { AccessControlAction, Role, ServiceAccountDTO } from 'app/types';
  8. import { OrgRolePicker } from '../admin/OrgRolePicker';
  9. import { getStyles } from './ServiceAccountsListPage';
  10. type ServiceAccountListItemProps = {
  11. serviceAccount: ServiceAccountDTO;
  12. onRoleChange: (role: OrgRole, serviceAccount: ServiceAccountDTO) => void;
  13. roleOptions: Role[];
  14. builtInRoles: Record<string, Role[]>;
  15. onSetToRemove: (serviceAccount: ServiceAccountDTO) => void;
  16. };
  17. const getServiceAccountsAriaLabel = (name: string) => {
  18. return `Edit service account's ${name} details`;
  19. };
  20. const getServiceAccountsEnabledStatus = (disabled: boolean) => {
  21. return disabled ? 'Disabled' : 'Enabled';
  22. };
  23. const ServiceAccountListItem = memo(
  24. ({ serviceAccount, onRoleChange, roleOptions, builtInRoles, onSetToRemove }: ServiceAccountListItemProps) => {
  25. const editUrl = `org/serviceaccounts/${serviceAccount.id}`;
  26. const styles = useStyles2(getStyles);
  27. const canUpdateRole = contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsWrite, serviceAccount);
  28. const displayRolePicker =
  29. contextSrv.hasPermission(AccessControlAction.ActionRolesList) &&
  30. contextSrv.hasPermission(AccessControlAction.ActionUserRolesList);
  31. const enableRolePicker = contextSrv.hasPermission(AccessControlAction.OrgUsersWrite) && canUpdateRole;
  32. return (
  33. <tr key={serviceAccount.id}>
  34. <td className="width-4 text-center link-td">
  35. <a href={editUrl} aria-label={getServiceAccountsAriaLabel(serviceAccount.name)}>
  36. <img
  37. className="filter-table__avatar"
  38. src={serviceAccount.avatarUrl}
  39. alt={`Avatar for user ${serviceAccount.name}`}
  40. />
  41. </a>
  42. </td>
  43. <td className="link-td max-width-10">
  44. <a
  45. className="ellipsis"
  46. href={editUrl}
  47. title={serviceAccount.name}
  48. aria-label={getServiceAccountsAriaLabel(serviceAccount.name)}
  49. >
  50. {serviceAccount.name}
  51. </a>
  52. </td>
  53. <td className="link-td max-width-10">
  54. <a
  55. className="ellipsis"
  56. href={editUrl}
  57. title={serviceAccount.login}
  58. aria-label={getServiceAccountsAriaLabel(serviceAccount.name)}
  59. >
  60. {serviceAccount.login}
  61. </a>
  62. </td>
  63. {contextSrv.licensedAccessControlEnabled() ? (
  64. <td className={cx('link-td', styles.iconRow)}>
  65. {displayRolePicker && (
  66. <UserRolePicker
  67. userId={serviceAccount.id}
  68. orgId={serviceAccount.orgId}
  69. builtInRole={serviceAccount.role}
  70. onBuiltinRoleChange={(newRole) => onRoleChange(newRole, serviceAccount)}
  71. roleOptions={roleOptions}
  72. builtInRoles={builtInRoles}
  73. disabled={!enableRolePicker}
  74. />
  75. )}
  76. </td>
  77. ) : (
  78. <td className={cx('link-td', styles.iconRow)}>
  79. <OrgRolePicker
  80. aria-label="Role"
  81. value={serviceAccount.role}
  82. disabled={!canUpdateRole}
  83. onChange={(newRole) => onRoleChange(newRole, serviceAccount)}
  84. />
  85. </td>
  86. )}
  87. <td className="link-td max-width-10">
  88. <a
  89. className="ellipsis"
  90. href={editUrl}
  91. title={getServiceAccountsEnabledStatus(serviceAccount.isDisabled)}
  92. aria-label={getServiceAccountsAriaLabel(serviceAccount.name)}
  93. >
  94. {getServiceAccountsEnabledStatus(serviceAccount.isDisabled)}
  95. </a>
  96. </td>
  97. <td className="link-td max-width-10">
  98. <a
  99. className="ellipsis"
  100. href={editUrl}
  101. title="Tokens"
  102. aria-label={getServiceAccountsAriaLabel(serviceAccount.name)}
  103. >
  104. <span>
  105. <Icon name={'key-skeleton-alt'}></Icon>
  106. </span>
  107. &nbsp;
  108. {serviceAccount.tokens}
  109. </a>
  110. </td>
  111. {contextSrv.hasPermissionInMetadata(AccessControlAction.ServiceAccountsDelete, serviceAccount) && (
  112. <td>
  113. <Button
  114. size="sm"
  115. variant="destructive"
  116. onClick={() => {
  117. onSetToRemove(serviceAccount);
  118. }}
  119. icon="times"
  120. aria-label="Delete service account"
  121. />
  122. </td>
  123. )}
  124. </tr>
  125. );
  126. }
  127. );
  128. ServiceAccountListItem.displayName = 'ServiceAccountListItem';
  129. export default ServiceAccountListItem;