@@ -129,13 +130,6 @@ exports[`Added Integration Table View Test Renders added integration table view
"sortable": true,
"truncateText": true,
},
- Object {
- "field": "actions",
- "name": "Actions",
- "render": [Function],
- "sortable": true,
- "truncateText": true,
- },
]
}
isSelectable={true}
@@ -189,6 +183,12 @@ exports[`Added Integration Table View Test Renders added integration table view
"type": "field_value_selection",
},
],
+ "toolsLeft": false,
+ }
+ }
+ selection={
+ Object {
+ "onSelectionChange": [Function],
}
}
tableLayout="auto"
@@ -220,6 +220,7 @@ exports[`Added Integration Table View Test Renders added integration table view
]
}
onChange={[Function]}
+ toolsLeft={false}
>
+ >
+
+
+
+
+
+
+ Select all rows
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- Actions
-
-
-
-
-
-
-
@@ -888,6 +933,54 @@ exports[`Added Integration Table View Test Renders added integration table view
+
+
+
+
+
-
-
-
- Actions
-
-
-
-
@@ -1607,15 +1636,16 @@ exports[`Added Integration Table View Test Renders added integration table view
>
@@ -1644,13 +1674,6 @@ exports[`Added Integration Table View Test Renders added integration table view
"sortable": true,
"truncateText": true,
},
- Object {
- "field": "actions",
- "name": "Actions",
- "render": [Function],
- "sortable": true,
- "truncateText": true,
- },
]
}
isSelectable={true}
@@ -1704,6 +1727,12 @@ exports[`Added Integration Table View Test Renders added integration table view
"type": "field_value_selection",
},
],
+ "toolsLeft": false,
+ }
+ }
+ selection={
+ Object {
+ "onSelectionChange": [Function],
}
}
tableLayout="auto"
@@ -1735,6 +1764,7 @@ exports[`Added Integration Table View Test Renders added integration table view
]
}
onChange={[Function]}
+ toolsLeft={false}
>
+ >
+
+
+
+
+
+
+ Select all rows
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- Actions
-
-
-
-
-
-
-
@@ -2404,6 +2478,54 @@ exports[`Added Integration Table View Test Renders added integration table view
+
+
+
+
+
-
-
-
- Actions
-
-
-
-
diff --git a/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap
index c6158f6f53..7610f0880a 100644
--- a/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap
+++ b/public/components/integrations/components/__tests__/__snapshots__/available_integration_card_view.test.tsx.snap
@@ -512,12 +512,6 @@ exports[`Available Integration Card View Test Renders nginx integration card vie
alt=""
className="synopsisIcon"
src="/api/integrations/repository/nginx/static/logo.svg"
- style={
- Object {
- "height": 100,
- "width": 100,
- }
- }
/>
}
title="NginX Dashboard"
@@ -542,12 +536,6 @@ exports[`Available Integration Card View Test Renders nginx integration card vie
alt=""
className="synopsisIcon euiCard__icon"
src="/api/integrations/repository/nginx/static/logo.svg"
- style={
- Object {
- "height": 100,
- "width": 100,
- }
- }
/>
-
-
- Details
-
-
@@ -30,7 +23,9 @@ exports[`Available Integration Table View Test Renders nginx integration table v
-
+
@@ -40,10 +35,13 @@ exports[`Available Integration Table View Test Renders nginx integration table v
-
+
+ className="euiFlexItem euiFlexItem--flexGrowZero"
+ >
+
+
+
+
@@ -120,7 +95,9 @@ exports[`Available Integration Table View Test Renders nginx integration table v
-
+
@@ -140,12 +117,14 @@ exports[`Available Integration Table View Test Renders nginx integration table v
-
+
- Contributer
+ Contributor
@@ -209,7 +188,9 @@ exports[`Available Integration Table View Test Renders nginx integration table v
-
+
@@ -235,7 +216,9 @@ exports[`Available Integration Table View Test Renders nginx integration table v
-
+
diff --git a/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap b/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap
index 5c210c6a01..61fe5d741e 100644
--- a/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap
+++ b/public/components/integrations/components/__tests__/__snapshots__/integration_fields.test.tsx.snap
@@ -8,12 +8,14 @@ exports[`Available Integration Table View Test Renders nginx integration table v
className="euiPanel euiPanel--paddingMedium euiPanel--borderRadiusMedium euiPanel--plain euiPanel--hasShadow"
data-test-subj="nginx-fields"
>
-
-
+
Fields
-
+
-
-
+
@@ -233,11 +233,11 @@ exports[`Integration Header Test Renders integration header as expected 1`] = `
/>
();
- const activateDeleteModal = (integrationName?: string) => {
+ const activateDeleteModal = () => {
setModalLayout(
{
@@ -101,7 +103,6 @@ export function AddedIntegration(props: AddedIntegrationProps) {
}}
title={`Delete Integration`}
message={`Are you sure you want to delete the selected Integration?`}
- prompt={integrationName}
/>
);
setIsModalVisible(true);
@@ -134,15 +135,25 @@ export function AddedIntegration(props: AddedIntegrationProps) {
const badgeContent = ;
const deleteButton = (
- {
- activateDeleteModal(data?.name);
- }}
- data-test-subj="deleteInstanceButton"
- />
+
+ }
+ >
+ {
+ activateDeleteModal(data?.name);
+ }}
+ data-test-subj="deleteInstanceButton"
+ />
+
);
const headerContent = (
@@ -166,13 +177,13 @@ export function AddedIntegration(props: AddedIntegrationProps) {
const additionalInfo = (
-
+
Template
{data?.templateName}
-
+
Date Added
{data?.creationDate?.split('T')[0]}
@@ -206,7 +217,7 @@ export function AddedIntegration(props: AddedIntegrationProps) {
deleteButton,
]}
/>
- {additionalInfo}
+ {additionalInfo}
>
) : (
<>
@@ -231,7 +242,7 @@ export function AddedIntegration(props: AddedIntegrationProps) {
{headerContent}
- {additionalInfo}
+ {additionalInfo}
>
);
}
@@ -356,8 +367,10 @@ export function AddedIntegration(props: AddedIntegrationProps) {
return (
-
-
+
+ Assets List
+
+
);
+ const [selectedIntegrations, setSelectedIntegrations] = useState([]);
const tableColumns = [
{
@@ -70,20 +68,6 @@ export function AddedIntegrationsTable(props: AddedIntegrationsTableProps) {
),
},
- {
- field: 'actions',
- name: 'Actions',
- sortable: true,
- truncateText: true,
- render: (value, record) => (
- {
- activateDeleteModal(record.id, record.name);
- }}
- />
- ),
- },
] as Array>;
if (dataSourceEnabled) {
@@ -100,36 +84,38 @@ export function AddedIntegrationsTable(props: AddedIntegrationsTableProps) {
});
}
- async function deleteAddedIntegration(integrationInstance: string, name: string) {
- http
- .delete(`${INTEGRATIONS_BASE}/store/${integrationInstance}`)
- .then(() => {
- setToast(`${name} integration successfully deleted!`, 'success');
- props.setData({
- hits: props.data.hits.filter((i) => i.id !== integrationInstance),
- });
- })
- .catch((_err) => {
- setToast(`Error deleting ${name} or its assets`, 'danger');
- })
- .finally(() => {
- window.location.hash = '#/installed';
- });
+ async function deleteAddedIntegrations(selectedItems: any[]) {
+ const deletePromises = selectedItems.map(async (item) => {
+ try {
+ await http.delete(`${INTEGRATIONS_BASE}/store/${item.id}`);
+ setToast(`${item.name} integration successfully deleted!`, 'success');
+ } catch (error) {
+ setToast(`Error deleting ${item.name} or its assets`, 'danger');
+ }
+ });
+
+ Promise.all(deletePromises);
+
+ props.setData({
+ hits: props.data.hits.filter(
+ (item) => !selectedItems.some((selected) => selected.id === item.id)
+ ),
+ });
+
+ window.location.hash = '#/installed';
}
- const activateDeleteModal = (integrationInstanceId: string, name: string) => {
+ const activateDeleteModal = () => {
+ const integrationNames = selectedIntegrations.map((item) => item.name).join(', ');
setModalLayout(
{
+ onConfirm={async () => {
setIsModalVisible(false);
- deleteAddedIntegration(integrationInstanceId, name);
+ await deleteAddedIntegrations(selectedIntegrations);
}}
- onCancel={() => {
- setIsModalVisible(false);
- }}
- title={`Delete Integration`}
- message={`Are you sure you want to delete the selected integration?`}
- prompt={name}
+ onCancel={() => setIsModalVisible(false)}
+ title={`Delete Integrations`}
+ message={`Are you sure you want to delete the selected integrations: ${integrationNames}?`}
/>
);
setIsModalVisible(true);
@@ -147,6 +133,17 @@ export function AddedIntegrationsTable(props: AddedIntegrationsTableProps) {
}
const search = {
+ toolsLeft: selectedIntegrations.length > 0 && (
+
+ Delete {selectedIntegrations.length} integration
+ {selectedIntegrations.length > 1 ? 's' : ''}
+
+ ),
box: {
incremental: true,
compressed: true,
@@ -203,7 +200,7 @@ export function AddedIntegrationsTable(props: AddedIntegrationsTableProps) {
});
return (
-
+
{entries && entries.length > 0 ? (
setSelectedIntegrations(items),
+ }}
/>
) : (
- <>
-
-
-
-
-
-
-
-
- There are currently no added integrations. Add them{' '}
- here to start using pre-canned assets!
-
-
-
- >
+ No installed integrations}
+ body={
+
+ There are currently no added integrations in this table. Add integrations from the{' '}
+ available list .
+
+ }
+ />
)}
{isModalVisible && modalLayout}
diff --git a/public/components/integrations/components/available_integration_card_view.tsx b/public/components/integrations/components/available_integration_card_view.tsx
index 621d5310fc..0ec0ef1cf4 100644
--- a/public/components/integrations/components/available_integration_card_view.tsx
+++ b/public/components/integrations/components/available_integration_card_view.tsx
@@ -24,9 +24,7 @@ export function AvailableIntegrationsCardView(props: AvailableIntegrationsCardVi
const getImage = (url?: string) => {
let optionalImg;
if (url) {
- optionalImg = (
-
- );
+ optionalImg = ;
}
return optionalImg;
};
diff --git a/public/components/integrations/components/integration.tsx b/public/components/integrations/components/integration.tsx
index 07f831603b..9d14608e25 100644
--- a/public/components/integrations/components/integration.tsx
+++ b/public/components/integrations/components/integration.tsx
@@ -256,7 +256,7 @@ export function Integration(props: AvailableIntegrationProps) {
{IntegrationScreenshots({ integration, http })}
-
+
{renderTabs()}
diff --git a/public/components/integrations/components/integration_assets_panel.tsx b/public/components/integrations/components/integration_assets_panel.tsx
index e1baae54ca..57974aa7c5 100644
--- a/public/components/integrations/components/integration_assets_panel.tsx
+++ b/public/components/integrations/components/integration_assets_panel.tsx
@@ -85,8 +85,8 @@ export function IntegrationAssets(props: {
return (
-
- Assets
+
+ Assets
-
- Details
-
-
+
Version
- {/*
- For the link, we have the slightly odd constraint to have it go to the end of the version
- space while being horizontally next to the version (i.e. no direct EuiText). It should be
- smaller, while aligning to the bottom of the line, but not the bottom of the entire flex
- area, for a nice subscript effect.
-
- The end result is a bit of flex magic: make two vertical boxes with the second one empty
- and growing, then in the top one put two horizontal boxes with space-between, aligning to
- the bottom.
- */}
-
+
+
+ {config.version}
+
-
-
- {config.version}
-
-
-
- Check for new versions
-
-
-
+
+ Check for new versions
+
-
-
+
Category
@@ -68,8 +49,8 @@ export function IntegrationDetails(props: { integration: IntegrationConfig }) {
-
- Contributer
+
+ Contributor
@@ -78,14 +59,14 @@ export function IntegrationDetails(props: { integration: IntegrationConfig }) {
-
+
License
{config.license}
-
+
Description
{config.description}
diff --git a/public/components/integrations/components/integration_fields_panel.tsx b/public/components/integrations/components/integration_fields_panel.tsx
index 1b342ea333..4bbf845aa4 100644
--- a/public/components/integrations/components/integration_fields_panel.tsx
+++ b/public/components/integrations/components/integration_fields_panel.tsx
@@ -94,8 +94,8 @@ export function IntegrationFields(props: any) {
return (
-
- Fields
+
+ Fields
void }) => {
+export const IntegrationHeaderActions = ({
+ onShowUpload,
+}: {
+ onShowUpload: () => void;
+}): Array => {
+ return [
+ {
+ label: 'View Catalog',
+ href: OPENSEARCH_CATALOG_URL,
+ target: '_blank',
+ controlType: 'link',
+ } as TopNavControlLinkData,
+ {
+ label: 'Upload Integration',
+ run: onShowUpload,
+ fill: true,
+ controlType: 'button',
+ } as TopNavControlButtonData,
+ ];
+};
+
+export const IntegrationHeaderActionsOldNav = ({ onShowUpload }: { onShowUpload: () => void }) => {
return (
@@ -86,15 +111,12 @@ export const IntegrationHeader = () => {
{newNavigation ? (
- View integrations with preconfigured assets immediately within your OpenSearch setup.{' '}
-
- Learn more
-
- >
- }
- components={[ setShowUploadFlyout(true)} />]}
+ description={{
+ text:
+ 'View integrations with preconfigured assets immediately within your OpenSearch setup.',
+ url: OPENSEARCH_DOCUMENTATION_URL,
+ }}
+ components={IntegrationHeaderActions({ onShowUpload: () => setShowUploadFlyout(true) })}
/>
) : (
<>
@@ -105,7 +127,7 @@ export const IntegrationHeader = () => {
- setShowUploadFlyout(true)} />
+ setShowUploadFlyout(true)} />
@@ -117,7 +139,7 @@ export const IntegrationHeader = () => {
>
)}
{!newNavigation && }
-
+
{renderTabs()}
diff --git a/public/components/integrations/components/integration_screenshots_panel.tsx b/public/components/integrations/components/integration_screenshots_panel.tsx
index b346df4ea9..0d5d9a3219 100644
--- a/public/components/integrations/components/integration_screenshots_panel.tsx
+++ b/public/components/integrations/components/integration_screenshots_panel.tsx
@@ -17,8 +17,8 @@ export function IntegrationScreenshots(props: any) {
return (
-
- Screenshots
+
+ Screenshots
diff --git a/public/components/notebooks/components/note_table.tsx b/public/components/notebooks/components/note_table.tsx
index 6cdbcd5074..05e4cd463f 100644
--- a/public/components/notebooks/components/note_table.tsx
+++ b/public/components/notebooks/components/note_table.tsx
@@ -241,17 +241,12 @@ export function NoteTable({
{newNavigation ? (
- Use Notebooks to interactively and collaboratively develop rich reports backed
- by live data. Common use cases for notebooks include creating postmortem
- reports, designing run books, building live infrastructure reports, or even
- documentation.{' '}
-
- Learn more
-
- >
- }
+ description={{
+ text:
+ 'Use Notebooks to interactively and collaboratively develop rich reports backed by live data. Common use cases for notebooks include creating postmortem reports, designing run books, building live infrastructure reports, or even documentation.',
+ url: NOTEBOOKS_DOCUMENTATION_URL,
+ urlTitle: 'Learn more',
+ }}
components={[
diff --git a/public/index.scss b/public/index.scss
index 9fc9885019..0429af773e 100644
--- a/public/index.scss
+++ b/public/index.scss
@@ -11,3 +11,8 @@
// event analytics
@import 'components/event_analytics/index';
+
+.synopsisIcon {
+ height: 40px;
+ width: 40px;
+ }
\ No newline at end of file
diff --git a/public/plugin_helpers/plugin_headerControl.tsx b/public/plugin_helpers/plugin_headerControl.tsx
index 57bddd8730..ada8dc6575 100644
--- a/public/plugin_helpers/plugin_headerControl.tsx
+++ b/public/plugin_helpers/plugin_headerControl.tsx
@@ -4,15 +4,60 @@
*/
import React from 'react';
-import { EuiText } from '@elastic/eui';
import { coreRefs } from '../framework/core_refs';
+import {
+ TopNavControlLinkData,
+ TopNavControlButtonData,
+} from '../../../../src/plugins/navigation/public';
+
+interface DescriptionWithOptionalLink {
+ text: string;
+ url?: string;
+ urlTitle?: string;
+}
interface HeaderControlledComponentsWrapperProps {
- components?: React.ReactElement[];
+ components?: Array;
badgeContent?: React.ReactElement | string | number;
- description?: React.ReactNode;
+ description?: string | DescriptionWithOptionalLink;
}
+const renderHeaderComponent = (
+ component: TopNavControlButtonData | TopNavControlLinkData | React.ReactElement
+) => {
+ if (React.isValidElement(component)) {
+ return {
+ renderComponent: component,
+ };
+ }
+
+ switch ((component as TopNavControlButtonData | TopNavControlLinkData).controlType) {
+ case 'button': {
+ const buttonData = component as TopNavControlButtonData;
+ return {
+ label: buttonData.label,
+ run: buttonData.run,
+ fill: buttonData.fill,
+ color: buttonData.color,
+ iconType: buttonData.iconType,
+ iconSide: buttonData.iconSide,
+ controlType: 'button',
+ };
+ }
+ case 'link': {
+ const linkData = component as TopNavControlLinkData;
+ return {
+ label: linkData.label,
+ href: linkData.href,
+ target: linkData.target,
+ controlType: 'link',
+ };
+ }
+ default:
+ return {};
+ }
+};
+
export const HeaderControlledComponentsWrapper = ({
components = [],
badgeContent,
@@ -23,48 +68,79 @@ export const HeaderControlledComponentsWrapper = ({
const isBadgeReactElement = React.isValidElement(badgeContent);
- if (showActionsInHeader && HeaderControl) {
- return (
- <>
- {badgeContent && (
- {badgeContent}
- ) : (
- {`(${badgeContent})`}
- ), // Render based on type
- },
- ]}
- />
- )}
- {description && (
- {description} ,
- },
- ]}
- />
- )}
- {components.length > 0 && (
- ({
- key: `header-control-${index}`,
- renderComponent: component,
- }))}
- />
- )}
- >
- );
- }
+ return (
+ <>
+ {badgeContent && (
+ <>
+ {showActionsInHeader && HeaderControl ? (
+ {badgeContent}
+ ) : (
+ {`(${badgeContent})`}
+ ),
+ },
+ ]}
+ />
+ ) : (
+ {isBadgeReactElement ? badgeContent : `(${badgeContent})`}
+ )}
+ >
+ )}
- // Only render the components if the nav group is disabled
- return <>{components}>;
+ {description && (
+ <>
+ {showActionsInHeader && HeaderControl ? (
+
+ ) : (
+ {typeof description === 'string' ? description : description.text}
+ )}
+ >
+ )}
+
+ {components.length > 0 && (
+ <>
+ {showActionsInHeader && HeaderControl ? (
+ renderHeaderComponent(component))}
+ />
+ ) : (
+
+ {components.map((component) =>
+ React.isValidElement(component) ? (
+ {component}
+ ) : (
+ {(component as TopNavControlButtonData).label}
+ )
+ )}
+
+ )}
+ >
+ )}
+ >
+ );
};