ServiceAccountCreatePage.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { connect } from 'react-redux';
  3. import { useHistory } from 'react-router-dom';
  4. import { NavModel } from '@grafana/data';
  5. import { getBackendSrv } from '@grafana/runtime';
  6. import { Form, Button, Input, Field } from '@grafana/ui';
  7. import Page from 'app/core/components/Page/Page';
  8. import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
  9. import { fetchBuiltinRoles, fetchRoleOptions, updateUserRoles } from 'app/core/components/RolePicker/api';
  10. import { contextSrv } from 'app/core/core';
  11. import { AccessControlAction, OrgRole, Role, ServiceAccountCreateApiResponse, ServiceAccountDTO } from 'app/types';
  12. import { getNavModel } from '../../core/selectors/navModel';
  13. import { StoreState } from '../../types';
  14. interface ServiceAccountCreatePageProps {
  15. navModel: NavModel;
  16. }
  17. const createServiceAccount = async (sa: ServiceAccountDTO) => getBackendSrv().post('/api/serviceaccounts/', sa);
  18. const updateServiceAccount = async (id: number, sa: ServiceAccountDTO) =>
  19. getBackendSrv().patch(`/api/serviceaccounts/${id}`, sa);
  20. const ServiceAccountCreatePage: React.FC<ServiceAccountCreatePageProps> = ({ navModel }) => {
  21. const [roleOptions, setRoleOptions] = useState<Role[]>([]);
  22. const [builtinRoles, setBuiltinRoles] = useState<{ [key: string]: Role[] }>({});
  23. const [pendingRoles, setPendingRoles] = useState<Role[]>([]);
  24. const currentOrgId = contextSrv.user.orgId;
  25. const [serviceAccount, setServiceAccount] = useState<ServiceAccountDTO>({
  26. id: 0,
  27. orgId: contextSrv.user.orgId,
  28. role: OrgRole.Viewer,
  29. tokens: 0,
  30. name: '',
  31. login: '',
  32. isDisabled: false,
  33. createdAt: '',
  34. teams: [],
  35. });
  36. useEffect(() => {
  37. async function fetchOptions() {
  38. try {
  39. if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
  40. let options = await fetchRoleOptions(currentOrgId);
  41. setRoleOptions(options);
  42. }
  43. if (contextSrv.hasPermission(AccessControlAction.ActionBuiltinRolesList)) {
  44. const builtInRoles = await fetchBuiltinRoles(currentOrgId);
  45. setBuiltinRoles(builtInRoles);
  46. }
  47. } catch (e) {
  48. console.error('Error loading options', e);
  49. }
  50. }
  51. if (contextSrv.licensedAccessControlEnabled()) {
  52. fetchOptions();
  53. }
  54. }, [currentOrgId]);
  55. const history = useHistory();
  56. const onSubmit = useCallback(
  57. async (data: ServiceAccountDTO) => {
  58. data.role = serviceAccount.role;
  59. const response = await createServiceAccount(data);
  60. try {
  61. const newAccount: ServiceAccountCreateApiResponse = {
  62. avatarUrl: response.avatarUrl,
  63. id: response.id,
  64. isDisabled: response.isDisabled,
  65. login: response.login,
  66. name: response.name,
  67. orgId: response.orgId,
  68. role: response.role,
  69. tokens: response.tokens,
  70. };
  71. await updateServiceAccount(response.id, data);
  72. await updateUserRoles(pendingRoles, newAccount.id, newAccount.orgId);
  73. } catch (e) {
  74. console.error(e);
  75. }
  76. history.push('/org/serviceaccounts/');
  77. },
  78. [history, serviceAccount.role, pendingRoles]
  79. );
  80. const onRoleChange = (role: OrgRole) => {
  81. setServiceAccount({
  82. ...serviceAccount,
  83. role: role,
  84. });
  85. };
  86. const onPendingRolesUpdate = (roles: Role[], userId: number, orgId: number | undefined) => {
  87. // keep the new role assignments for user
  88. setPendingRoles(roles);
  89. };
  90. return (
  91. <Page navModel={navModel}>
  92. <Page.Contents>
  93. <h1>Create service account</h1>
  94. <Form onSubmit={onSubmit} validateOn="onBlur">
  95. {({ register, errors }) => {
  96. return (
  97. <>
  98. <Field
  99. label="Display name"
  100. required
  101. invalid={!!errors.name}
  102. error={errors.name ? 'Display name is required' : undefined}
  103. >
  104. <Input id="display-name-input" {...register('name', { required: true })} />
  105. </Field>
  106. {contextSrv.accessControlEnabled() && (
  107. <Field label="Role">
  108. <UserRolePicker
  109. userId={serviceAccount.id || 0}
  110. orgId={serviceAccount.orgId}
  111. builtInRole={serviceAccount.role}
  112. builtInRoles={builtinRoles}
  113. onBuiltinRoleChange={(newRole) => onRoleChange(newRole)}
  114. builtinRolesDisabled={false}
  115. roleOptions={roleOptions}
  116. updateDisabled={true}
  117. onApplyRoles={onPendingRolesUpdate}
  118. pendingRoles={pendingRoles}
  119. />
  120. </Field>
  121. )}
  122. <Button type="submit">Create</Button>
  123. </>
  124. );
  125. }}
  126. </Form>
  127. </Page.Contents>
  128. </Page>
  129. );
  130. };
  131. const mapStateToProps = (state: StoreState) => ({
  132. navModel: getNavModel(state.navIndex, 'serviceaccounts'),
  133. });
  134. export default connect(mapStateToProps)(ServiceAccountCreatePage);