All files / modules/10-common/components/UserGroupsReference UserGroupsReference.tsx

92.5% Statements 37/40
70.45% Branches 31/44
90.91% Functions 10/11
92.31% Lines 36/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152              125x 125x 125x 125x 125x 125x         125x   125x 125x 125x                                       125x                 4x                 2x 2x 2x 2x         9x 9x 9x 1x 76x 8x       9x           2x                       125x 8x             7x 7x 7x   7x       2x           4x               18x 52x   18x                                             125x  
/*
 * Copyright 2021 Harness Inc. All rights reserved.
 * Use of this source code is governed by the PolyForm Shield 1.0.0 license
 * that can be found in the licenses directory at the root of this repository, also available at
 * https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt.
 */
 
import React, { ReactNode } from 'react'
import { useParams } from 'react-router-dom'
import { Text, Container, Layout, AvatarGroup } from '@wings-software/uicore'
import { Color } from '@harness/design-system'
import { UserGroupDTO, getUserGroupAggregateListPromise, UserMetadataDTO } from 'services/cd-ng'
import { MultiSelectEntityReference, useToaster } from '@common/exports'
import type {
  ScopeAndIdentifier,
  ScopeUpdatedWithPreviousData
} from '@common/components/MultiSelectEntityReference/MultiSelectEntityReference'
import { Scope } from '@common/interfaces/SecretsInterface'
import type { ProjectPathProps } from '@common/interfaces/RouteInterfaces'
import { useStrings } from 'framework/strings'
import { EntityReferenceResponse, getScopeFromDTO } from '@common/components/EntityReference/EntityReference'
import css from './UserGroupsReference.module.scss'
 
export interface UserGroupsRef extends Omit<UserGroupDTO, 'users'> {
  users: UserMetadataDTO[]
}
export interface UserGroupSelectDTO {
  userGroups: UserGroupDTO[]
  previousSelectedItemsUuidAndScope: ScopeAndIdentifier[] | undefined
  scopesUpdatedWithPreviousData: ScopeUpdatedWithPreviousData
}
 
export interface UserGroupsReferenceProps {
  onSelect: (data: ScopeAndIdentifier[]) => void
  userGroupsScopeAndUuid?: ScopeAndIdentifier[]
  scope?: Scope
  mock?: UserGroupDTO[]
  onlyCurrentScope?: boolean
  disablePreSelectedItems?: boolean
}
 
const fetchRecords = (
  scope: Scope,
  search: string | undefined,
  done: (records: EntityReferenceResponse<UserGroupsRef>[]) => void,
  accountIdentifier: string,
  showError: (message: string | ReactNode, timeout?: number, key?: string) => void,
  projectIdentifier?: string,
  orgIdentifier?: string
): void => {
  getUserGroupAggregateListPromise({
    queryParams: {
      accountIdentifier,
      projectIdentifier: scope === Scope.PROJECT ? projectIdentifier : undefined,
      orgIdentifier: scope === Scope.PROJECT || scope === Scope.ORG ? orgIdentifier : undefined,
      searchTerm: search?.trim()
    }
  }).then(
    responseData => {
      Eif (responseData?.data?.content) {
        const userGroupsAggregate = responseData.data.content
        const response: EntityReferenceResponse<UserGroupsRef>[] = []
        userGroupsAggregate.forEach(aggregate => {
          /* UserMetadataDTO always returns 6 latest added users,
           * so we need to check if the users in UserGroupDTO and UserMetadataDTO lengths don't match,
           * and add the missing ones, just for count sake, if so
           */
          const usersMeta = [...((aggregate.users as UserMetadataDTO[]) || [])]
          const userUuids = [...((aggregate.userGroupDTO.users as string[]) || [])]
          if (usersMeta.length !== userUuids.length) {
            userUuids.forEach(el => {
              Eif (usersMeta.findIndex(_el => _el.uuid === el) === -1) {
                usersMeta.push({ name: el, email: el, uuid: el })
              }
            })
          }
          response.push({
            name: aggregate.userGroupDTO.name || '',
            identifier: aggregate.userGroupDTO.identifier || '',
            record: { ...aggregate.userGroupDTO, users: usersMeta }
          })
        })
        done(response)
      } else {
        done([])
      }
    },
    error => {
      showError(error)
      done([])
    }
  )
}
 
const UserGroupsReference: React.FC<UserGroupsReferenceProps> = props => {
  const { accountId: accountIdentifier, projectIdentifier, orgIdentifier } = useParams<ProjectPathProps>()
  const {
    onSelect,
    userGroupsScopeAndUuid,
    onlyCurrentScope,
    disablePreSelectedItems,
    scope = onlyCurrentScope ? getScopeFromDTO({ accountIdentifier, projectIdentifier, orgIdentifier }) : Scope.ACCOUNT
  } = props
  const { getString } = useStrings()
  const { showError } = useToaster()
 
  return (
    <MultiSelectEntityReference<UserGroupsRef>
      className={css.main}
      onMultiSelect={(selectedData: ScopeAndIdentifier[]) => {
        onSelect(selectedData)
      }}
      onlyCurrentScope={onlyCurrentScope}
      disablePreSelectedItems={disablePreSelectedItems}
      defaultScope={scope}
      fetchRecords={(fetchScope, search = '', done) => {
        fetchRecords(fetchScope, search, done, accountIdentifier, showError, projectIdentifier, orgIdentifier)
      }}
      projectIdentifier={projectIdentifier}
      orgIdentifier={orgIdentifier}
      noRecordsText={getString('noData')}
      selectedItemsUuidAndScope={userGroupsScopeAndUuid}
      recordRender={({ item, selected }) => {
        const avatars =
          item.record.users?.map(user => {
            return { email: user.email, name: user.name }
          }) || []
        return (
          <Container flex={{ justifyContent: 'space-between' }} width={'100%'}>
            <Layout.Vertical>
              <Text
                width={160}
                lineClamp={1}
                font={{ weight: 'semi-bold' }}
                color={selected ? Color.PRIMARY_7 : Color.BLACK}
              >
                {item.name}
              </Text>
              <Text width={160} lineClamp={1} font={{ size: 'small' }}>
                {item.record.identifier}
              </Text>
            </Layout.Vertical>
            <AvatarGroup avatars={avatars} restrictLengthTo={6} />
          </Container>
        )
      }}
    />
  )
}
 
export default UserGroupsReference