diff --git a/.cypress/integration/integrations_test/integrations.spec.js b/.cypress/integration/integrations_test/integrations.spec.js index f1281a795a..b386f62aa4 100644 --- a/.cypress/integration/integrations_test/integrations.spec.js +++ b/.cypress/integration/integrations_test/integrations.spec.js @@ -2,7 +2,6 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -/* eslint-disable jest/expect-expect */ /// @@ -39,6 +38,7 @@ describe('Integrations plugin', () => { moveToIntegrationsHome(); cy.get('[data-test-subj="integration_card_nginx"]').click(); cy.url().should('include', '/available/nginx'); + cy.get('[data-test-subj="eventHomePageTitle"').should('contain', 'Nginx'); }); it('Navigates to nginx page and asserts the page to be as expected', () => { diff --git a/public/components/datasources/components/__tests__/__snapshots__/installed_integrations_table.test.tsx.snap b/public/components/datasources/components/__tests__/__snapshots__/installed_integrations_table.test.tsx.snap index 97ee1a1bf1..b1ca146d2d 100644 --- a/public/components/datasources/components/__tests__/__snapshots__/installed_integrations_table.test.tsx.snap +++ b/public/components/datasources/components/__tests__/__snapshots__/installed_integrations_table.test.tsx.snap @@ -2,6 +2,7 @@ exports[`Installed Integrations Table test Renders the empty installed integrations table 1`] = ` @@ -928,6 +929,7 @@ exports[`Installed Integrations Table test Renders the installed integrations ta } } closeFlyout={[Function]} + datasourceName="test" datasourceType="S3GLUE" setAvailableIntegrations={[Function]} > @@ -1147,14 +1149,13 @@ exports[`Installed Integrations Table test Renders the installed integrations ta - sample2 - + - sample2 - + - sample2 - + - sample2 - + - sample2 - + diff --git a/public/components/datasources/components/__tests__/installed_integrations_table.test.tsx b/public/components/datasources/components/__tests__/installed_integrations_table.test.tsx index 5638f6d0e5..81ed035a3a 100644 --- a/public/components/datasources/components/__tests__/installed_integrations_table.test.tsx +++ b/public/components/datasources/components/__tests__/installed_integrations_table.test.tsx @@ -30,7 +30,9 @@ describe('Installed Integrations Table test', () => { }); it('Renders the empty installed integrations table', async () => { - const wrapper = mount(); + const wrapper = mount( + + ); expect(wrapper).toMatchSnapshot(); }); @@ -42,6 +44,7 @@ describe('Installed Integrations Table test', () => { setAvailableIntegrations={() => {}} closeFlyout={() => {}} datasourceType="S3GLUE" + datasourceName="test" /> ); diff --git a/public/components/datasources/components/manage/data_connection.tsx b/public/components/datasources/components/manage/data_connection.tsx index 8d126c490a..535a0ffdcc 100644 --- a/public/components/datasources/components/manage/data_connection.tsx +++ b/public/components/datasources/components/manage/data_connection.tsx @@ -232,6 +232,7 @@ export const DataConnection = (props: any) => { ), }, diff --git a/public/components/datasources/components/manage/integrations/installed_integrations_table.tsx b/public/components/datasources/components/manage/integrations/installed_integrations_table.tsx index 426a52a092..a04db9015d 100644 --- a/public/components/datasources/components/manage/integrations/installed_integrations_table.tsx +++ b/public/components/datasources/components/manage/integrations/installed_integrations_table.tsx @@ -20,6 +20,7 @@ import { } from '@elastic/eui'; import _ from 'lodash'; import { IntegrationHealthBadge } from '../../../../integrations/components/added_integration'; +import { SetupIntegrationForm } from '../../../../integrations/components/setup_integration'; import { coreRefs } from '../../../../../framework/core_refs'; import { basePathLink } from '../../../../../../common/utils/shared'; import { AvailableIntegrationsTable } from '../../../../integrations/components/available_integration_table'; @@ -127,11 +128,13 @@ export const InstallIntegrationFlyout = ({ setAvailableIntegrations, closeFlyout, datasourceType, + datasourceName, }: { availableIntegrations: AvailableIntegrationsList; setAvailableIntegrations: (value: AvailableIntegrationsList) => void; closeFlyout: () => void; datasourceType: DatasourceType; + datasourceName: string; }) => { useEffect(() => { if (!coreRefs.http) { @@ -148,9 +151,32 @@ export const InstallIntegrationFlyout = ({ ), }; + const [installingIntegration, setInstallingIntegration] = useState(null); + return ( - + {installingIntegration === null ? ( + + ) : ( + setInstallingIntegration(null)} + renderType="flyout" + forceConnection={ + datasourceType === 'S3GLUE' + ? { + name: datasourceName, + type: 's3', + } + : undefined + } + /> + )} ); }; @@ -158,9 +184,11 @@ export const InstallIntegrationFlyout = ({ export const InstalledIntegrationsTable = ({ integrations, datasourceType, + datasourceName, }: { integrations: IntegrationInstanceResult[]; datasourceType: DatasourceType; + datasourceName: string; }) => { const [query, setQuery] = useState(''); const filteredIntegrations = integrations @@ -215,6 +243,7 @@ export const InstalledIntegrationsTable = ({ setAvailableIntegrations={setAvailableIntegrations} closeFlyout={() => setShowAvailableFlyout(false)} datasourceType={datasourceType} + datasourceName={datasourceName} /> ) : null} diff --git a/public/components/datasources/components/new/new_datasource_card_view.tsx b/public/components/datasources/components/new/new_datasource_card_view.tsx index 46845df10c..19e4833d08 100644 --- a/public/components/datasources/components/new/new_datasource_card_view.tsx +++ b/public/components/datasources/components/new/new_datasource_card_view.tsx @@ -41,9 +41,9 @@ export function NewDatasourceCardView() { return ( <> - {datasources.map((i, v) => { + {datasources.map((i) => { return ( - + } - onClick={[Function]} + href="/app/integrations#/available/nginx" + icon={ + + } title="NginX Dashboard" titleElement="span" >
+
+ +
@@ -532,14 +560,14 @@ exports[`Available Integration Card View Test Renders nginx integration card vie className="euiTitle euiTitle--small euiCard__title" id="random_html_idTitle" > - + - - -
+ + - -
- + +
+ - -
- -

- Set Up Integration -

-
- -
- - -
- - -
-

- Integration Details -

-
-
- -
- - + +
-
+

+ Set Up Integration +

+ + +
+ + +
+ + +
+

+ Integration Details +

+
+
+ +
+ +
- - - -
-
- + Display Name + + +
+
- -
- - - - + + + + +
-
- - + + +
-
- - -
- - -
-

- Integration Connection -

-
-
- -
- - -
+ +
+ + +
+

+ Integration Connection +

+
+
+ +
+ +
- - - -
-
- + Connection Type + + +
+
- -
- - + + - - - - - -
- + + + + + + + +
+ +
-
- - - -
+ + - Select the type of connection to use for queries. -
-
+
+ Select the type of connection to use for queries. +
+ +
-
- - -
+
- - - -
-
- + Index + + +
+
-
- +
- -
- - - - -
+ + + -
-
-
-
- + +
+
+
+
+ -
- - + + + + + + + + - - - - - - - - -
-
+ +
+ +
-
- - -
- - -
+ +
+ + - Select an index to pull the data from. -
- +
+ Select an index to pull the data from. +
+ +
-
- -
- - -
- -
- - - + +
+ + +
+
+
+
+
- -
- -
- - - -
-
- -
- - - - -
-
-
-
+ +
+ + +
+ + + + + +
+
+
+
+ @@ -1049,7 +1063,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = - + @@ -1058,7 +1072,7 @@ exports[`Integration Setup Page Renders integration setup page as expected 1`] = `; exports[`Integration Setup Page Renders the S3 connector form as expected 1`] = ` - - + `; exports[`Integration Setup Page Renders the S3 connector form without workflows 1`] = ` - - + `; exports[`Integration Setup Page Renders the index form as expected 1`] = ` - - + `; diff --git a/public/components/integrations/components/__tests__/setup_integration.test.tsx b/public/components/integrations/components/__tests__/setup_integration.test.tsx index 5143b61ff7..1fb32133ec 100644 --- a/public/components/integrations/components/__tests__/setup_integration.test.tsx +++ b/public/components/integrations/components/__tests__/setup_integration.test.tsx @@ -7,7 +7,7 @@ import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { waitFor } from '@testing-library/react'; -import { SetupIntegrationPage, SetupIntegrationForm } from '../setup_integration'; +import { SetupIntegrationPage, SetupIntegrationFormInputs } from '../setup_integration'; import { TEST_INTEGRATION_CONFIG, TEST_INTEGRATION_SETUP_INPUTS, @@ -26,7 +26,7 @@ describe('Integration Setup Page', () => { it('Renders the index form as expected', async () => { const wrapper = mount( - {}} integration={TEST_INTEGRATION_CONFIG} @@ -41,7 +41,7 @@ describe('Integration Setup Page', () => { it('Renders the S3 connector form as expected', async () => { const wrapper = mount( - {}} integration={TEST_INTEGRATION_CONFIG} @@ -56,7 +56,7 @@ describe('Integration Setup Page', () => { it('Renders the S3 connector form without workflows', async () => { const wrapper = mount( - {}} integration={{ ...TEST_INTEGRATION_CONFIG, workflows: undefined }} diff --git a/public/components/integrations/components/available_integration_card_view.tsx b/public/components/integrations/components/available_integration_card_view.tsx index ffcb981eba..56d7a7ef62 100644 --- a/public/components/integrations/components/available_integration_card_view.tsx +++ b/public/components/integrations/components/available_integration_card_view.tsx @@ -20,9 +20,9 @@ import { } from './available_integration_overview_page'; import { INTEGRATIONS_BASE } from '../../../../common/constants/shared'; import { badges } from './integration_category_badge_group'; +import { basePathLink } from '../../../../common/utils/shared'; export function AvailableIntegrationsCardView(props: AvailableIntegrationsCardViewProps) { - const http = props.http; const [toggleIconIdSelected, setToggleIconIdSelected] = useState('1'); const getImage = (url?: string) => { @@ -67,7 +67,7 @@ export function AvailableIntegrationsCardView(props: AvailableIntegrationsCardVi - (window.location.hash = http.basePath.prepend( - `/app/integrations#/available/${i.name}` - )) - } + href={basePathLink(`/app/integrations#/available/${i.name}`)} footer={badges(i.labels ?? [])} /> diff --git a/public/components/integrations/components/available_integration_overview_page.tsx b/public/components/integrations/components/available_integration_overview_page.tsx index 173c21d1df..8a209fa7f5 100644 --- a/public/components/integrations/components/available_integration_overview_page.tsx +++ b/public/components/integrations/components/available_integration_overview_page.tsx @@ -21,7 +21,6 @@ import { AvailableIntegrationsTable } from './available_integration_table'; import { AvailableIntegrationsCardView } from './available_integration_card_view'; import { INTEGRATIONS_BASE } from '../../../../common/constants/shared'; import { AvailableIntegrationOverviewPageProps } from './integration_types'; -import { HttpStart } from '../../../../../../src/core/public'; type CategoryItems = Array<{ name: string; checked: boolean }>; @@ -31,6 +30,7 @@ export interface AvailableIntegrationsTableProps { isCardView: boolean; setCardView?: (input: boolean) => void; filters?: React.JSX.Element; + setInstallingIntegration?: (integration: string) => void; } export interface AvailableIntegrationsList { @@ -43,7 +43,6 @@ export interface AvailableIntegrationsCardViewProps { setCardView: (input: boolean) => void; query: string; setQuery: (input: string) => void; - http: HttpStart; filters?: React.JSX.Element; } diff --git a/public/components/integrations/components/available_integration_table.tsx b/public/components/integrations/components/available_integration_table.tsx index e935320abf..05edcf0757 100644 --- a/public/components/integrations/components/available_integration_table.tsx +++ b/public/components/integrations/components/available_integration_table.tsx @@ -22,6 +22,7 @@ import { badges } from './integration_category_badge_group'; export function AvailableIntegrationsTable(props: AvailableIntegrationsTableProps) { const integrations = props.data.hits; + const setInstallingIntegration = props.setInstallingIntegration; const toggleButtonsIcons = [ { @@ -56,14 +57,27 @@ export function AvailableIntegrationsTable(props: AvailableIntegrationsTableProp name: 'Name', sortable: true, truncateText: true, - render: (value, record) => ( - - {_.truncate(record.displayName || record.name, { length: 100 })} - - ), + render: (_value, record) => { + if (setInstallingIntegration) { + return ( + setInstallingIntegration(record.name)} + > + {_.truncate(record.displayName || record.name, { length: 100 })} + + ); + } else { + return ( + + {_.truncate(record.displayName || record.name, { length: 100 })} + + ); + } + }, }, { field: 'description', diff --git a/public/components/integrations/components/integration.tsx b/public/components/integrations/components/integration.tsx index 4a32122e16..6bccdd65ee 100644 --- a/public/components/integrations/components/integration.tsx +++ b/public/components/integrations/components/integration.tsx @@ -142,12 +142,12 @@ export function Integration(props: AvailableIntegrationProps) { - {IntegrationOverview({ - integration, - showFlyout: () => { + { window.location.hash = `#/available/${integration.name}/setup`; - }, - setUpSample: async () => { + }} + setUpSample={async () => { setLoading(true); await addIntegrationRequest( true, @@ -157,9 +157,9 @@ export function Integration(props: AvailableIntegrationProps) { setToast ); setLoading(false); - }, - loading, - })} + }} + loading={loading} + /> {IntegrationDetails({ integration })} diff --git a/public/components/integrations/components/setup_integration.tsx b/public/components/integrations/components/setup_integration.tsx index 0e30dab6c9..741a19872a 100644 --- a/public/components/integrations/components/setup_integration.tsx +++ b/public/components/integrations/components/setup_integration.tsx @@ -14,6 +14,8 @@ import { EuiFieldText, EuiFlexGroup, EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, EuiForm, EuiFormRow, EuiLoadingLogo, @@ -53,6 +55,7 @@ interface IntegrationConfigProps { updateConfig: (updates: Partial) => void; integration: IntegrationConfig; setupCallout: SetupCallout; + lockConnectionType?: boolean; } // TODO support localization @@ -216,11 +219,12 @@ export function SetupWorkflowSelector({ return cards; } -export function SetupIntegrationForm({ +export function SetupIntegrationFormInputs({ config, updateConfig, integration, setupCallout, + lockConnectionType, }: IntegrationConfigProps) { const connectionType = INTEGRATION_CONNECTION_DATA_SOURCE_TYPES.get(config.connectionType)!; @@ -313,6 +317,7 @@ export function SetupIntegrationForm({ onChange={(event) => updateConfig({ connectionType: event.target.value, connectionDataSource: '' }) } + disabled={lockConnectionType} /> @@ -339,6 +344,7 @@ export function SetupIntegrationForm({ }} customOptionText={`Select {searchValue} as your ${connectionType.lower}`} data-test-subj="data-source-name" + isDisabled={lockConnectionType} /> {config.connectionType === 's3' ? ( @@ -533,12 +539,14 @@ export function SetupBottomBar({ loading, setLoading, setSetupCallout, + unsetIntegration, }: { config: IntegrationSetupInputs; integration: IntegrationConfig; loading: boolean; setLoading: (loading: boolean) => void; setSetupCallout: (setupCallout: SetupCallout) => void; + unsetIntegration?: () => void; }) { // Drop-in replacement for setToast const setCalloutLikeToast = (title: string, color?: Color, text?: string) => @@ -550,41 +558,44 @@ export function SetupBottomBar({ }); return ( - - - - { - // TODO evil hack because props aren't set up - let hash = window.location.hash; - hash = hash.trim(); - hash = hash.substring(0, hash.lastIndexOf('/setup')); - window.location.hash = hash; - }} - disabled={loading} - > - Discard - - - - - addIntegration({ integration, config, setLoading, setCalloutLikeToast }) + + + { + // If we can unset the integration, then just unset it. + // Otherwise, remove `/setup` from the window location. + if (unsetIntegration) { + unsetIntegration(); + return; } - data-test-subj="create-instance-button" - > - Add Integration - - - - + let hash = window.location.hash; + hash = hash.trim(); + hash = hash.substring(0, hash.lastIndexOf('/setup')); + window.location.hash = hash; + }} + disabled={loading} + > + Discard + + + + + addIntegration({ integration, config, setLoading, setCalloutLikeToast }) + } + data-test-subj="create-instance-button" + > + Add Integration + + + ); } @@ -600,11 +611,24 @@ export function LoadingPage() { ); } -export function SetupIntegrationPage({ integration }: { integration: string }) { +export function SetupIntegrationForm({ + integration, + renderType = 'page', + unsetIntegration, + forceConnection, +}: { + integration: string; + renderType: 'page' | 'flyout'; + unsetIntegration?: () => void; + forceConnection?: { + name: string; + type: string; + }; +}) { const [integConfig, setConfig] = useState({ displayName: `${integration} Integration`, - connectionType: 'index', - connectionDataSource: '', + connectionType: forceConnection?.type ?? 'index', + connectionDataSource: forceConnection?.name ?? '', connectionLocation: '', checkpointLocation: '', connectionTableName: integration, @@ -635,29 +659,81 @@ export function SetupIntegrationPage({ integration }: { integration: string }) { const updateConfig = (updates: Partial) => setConfig(Object.assign({}, integConfig, updates)); - return ( - - + if (renderType === 'page') { + return ( + <> {showLoading ? ( ) : ( - )} - + + + + ); + } else if (renderType === 'flyout') { + return ( + <> + + {showLoading ? ( + + ) : ( + + )} + + + + + + ); + } +} + +export function SetupIntegrationPage({ + integration, + unsetIntegration, +}: { + integration: string; + unsetIntegration?: () => void; +}) { + return ( + + +