From 0b9c5c410a4a0b81d24c4eff5e75b8ec4190fc2a Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Thu, 2 Apr 2020 16:29:40 -0700 Subject: [PATCH] add credential select list to launch CredentialsStep --- .../LaunchPrompt/CredentialsStep.jsx | 165 +++++++++++++++++- .../components/LaunchPrompt/InventoryStep.jsx | 2 +- 2 files changed, 162 insertions(+), 5 deletions(-) diff --git a/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.jsx b/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.jsx index 10872e311c..8d68995197 100644 --- a/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.jsx +++ b/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.jsx @@ -1,7 +1,164 @@ -import React from 'react'; +import React, { useState, useCallback, useEffect } from 'react'; +import { useHistory } from 'react-router-dom'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; +import { useField } from 'formik'; +import { ToolbarItem } from '@patternfly/react-core'; +import { CredentialsAPI, CredentialTypesAPI } from '@api'; +import AnsibleSelect from '@components/AnsibleSelect'; +import OptionsList from '@components/OptionsList'; +import ContentLoading from '@components/ContentLoading'; +import CredentialChip from '@components/CredentialChip'; +import { getQSConfig, parseQueryString } from '@util/qs'; +import useRequest from '@util/useRequest'; -function CredentialsStep() { - return
; +const QS_CONFIG = getQSConfig('inventory', { + page: 1, + page_size: 5, + order_by: 'name', +}); + +function CredentialsStep({ i18n }) { + const [field, , helpers] = useField('credentials'); + const [selectedType, setSelectedType] = useState(null); + const [selectedItems, setSelectedItems] = useState([]); + const history = useHistory(); + + const isTypeSelected = !!selectedType; + const { + result: types, + error: typesError, + isLoading: isTypesLoading, + request: fetchTypes, + } = useRequest( + useCallback(async () => { + const loadedTypes = await CredentialTypesAPI.loadAllTypes(); + if (!isTypeSelected && loadedTypes.length) { + const match = + loadedTypes.find(type => type.kind === 'ssh') || loadedTypes[0]; + setSelectedType(match); + } + return loadedTypes; + }, [isTypeSelected]), + [] + ); + + useEffect(() => { + fetchTypes(); + }, [fetchTypes]); + + const { + result: { credentials, count }, + error: credentialsError, + isLoading: isCredentialsLoading, + request: fetchCredentials, + } = useRequest( + useCallback(async () => { + const params = parseQueryString(QS_CONFIG, history.location.search); + const { data } = await CredentialsAPI.read({ + ...params, + credential_type: selectedType.id || 1, + }); + return { + credentials: data.results, + count: data.count, + }; + }, [selectedType, history.location.search]), + { credentials: [], count: 0 } + ); + + useEffect(() => { + fetchCredentials(); + }, [fetchCredentials]); + + if (isTypesLoading) { + return ; + } + + const isVault = selectedType?.kind === 'vault'; + + const renderChip = ({ item, removeItem, canDelete }) => ( + removeItem(item)} + isReadOnly={!canDelete} + credential={item} + /> + ); + + return ( + <> + {types && types.length > 0 && ( + +
+ {i18n._(t`Selected Category`)} +
+ ({ + key: type.id, + value: type.id, + label: type.name, + isDisabled: false, + }))} + value={selectedType && selectedType.id} + onChange={(e, id) => { + setSelectedType(types.find(o => o.id === parseInt(id, 10))); + }} + /> +
+ )} + { + const hasSameVaultID = val => + val?.inputs?.vault_id !== undefined && + val?.inputs?.vault_id === item?.inputs?.vault_id; + const hasSameKind = val => val.kind === item.kind; + const newItems = selectedItems.filter(i => + isVault ? !hasSameVaultID(i) : !hasSameKind(i) + ); + newItems.push(item); + setSelectedItems(newItems); + }} + deselectItem={item => { + setSelectedItems(selectedItems.filter(i => i.id !== item.id)); + }} + renderItemChip={renderChip} + /> + ) + + ); } -export default CredentialsStep; +export default withI18n()(CredentialsStep); diff --git a/awx/ui_next/src/components/LaunchPrompt/InventoryStep.jsx b/awx/ui_next/src/components/LaunchPrompt/InventoryStep.jsx index 696dc445bc..b35a9f4090 100644 --- a/awx/ui_next/src/components/LaunchPrompt/InventoryStep.jsx +++ b/awx/ui_next/src/components/LaunchPrompt/InventoryStep.jsx @@ -16,8 +16,8 @@ const QS_CONFIG = getQSConfig('inventory', { }); function InventoryStep({ i18n }) { - const history = useHistory(); const [field, , helpers] = useField('inventory'); + const history = useHistory(); const { isLoading,