From c486b61345ee3411a6fa9f162180d807d5d9e8ea Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat <2025sandeepkumawat@gmail.com> Date: Thu, 15 Aug 2024 08:43:33 +0530 Subject: [PATCH] Update newHeader for Snapshot pages (#1105) * PoC for ism Signed-off-by: Sandeep Kumawat * Update newHeader for snapshot policies page Signed-off-by: Sandeep Kumawat * new page header update for index snapshot and repository pages Signed-off-by: Sandeep Kumawat * triger gh workflows Signed-off-by: Sandeep Kumawat --------- Signed-off-by: Sandeep Kumawat Co-authored-by: Sandeep Kumawat --- opensearch_dashboards.json | 2 +- .../components/ContentPanel/ContentPanel.tsx | 28 +-- .../CreateSnapshotPolicy.tsx | 58 ++++-- public/pages/Main/Main.tsx | 5 +- .../containers/Repositories/Repositories.tsx | 86 ++++++++- .../SnapshotPolicies/SnapshotPolicies.tsx | 165 +++++++++++++++-- .../SnapshotPolicyDetails.tsx | 142 ++++++++++++-- .../RestoreActivitiesPanel.tsx | 175 +++++++++++------- .../containers/Snapshots/Snapshots.tsx | 123 +++++++++++- public/pages/utils/display-utils.tsx | 15 ++ public/plugin.ts | 11 +- public/services/Services.ts | 9 + public/utils/constants.ts | 3 + 13 files changed, 673 insertions(+), 149 deletions(-) create mode 100644 public/pages/utils/display-utils.tsx diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 5493c743e..917e8c0a9 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "3.0.0.0", "opensearchDashboardsVersion": "3.0.0", "configPath": ["opensearch_index_management"], - "requiredPlugins": ["navigation", "opensearchDashboardsReact"], + "requiredPlugins": ["navigation", "opensearchDashboardsReact", "opensearchDashboardsUtils"], "optionalPlugins": ["managementOverview", "dataSource", "dataSourceManagement"], "server": true, "ui": true, diff --git a/public/components/ContentPanel/ContentPanel.tsx b/public/components/ContentPanel/ContentPanel.tsx index d3689f90c..5c205614f 100644 --- a/public/components/ContentPanel/ContentPanel.tsx +++ b/public/components/ContentPanel/ContentPanel.tsx @@ -68,19 +68,21 @@ const ContentPanel: React.SFC = ({ justifyContent="spaceBetween" alignItems="flexStart" > - - {typeof title === "string" ? ( - -

- {title} - {itemCount > 0 ? `(${itemCount})` : null} -

-
- ) : ( - title - )} - {renderSubTitleText(subTitleText)} -
+ {title ? ( + + {typeof title === "string" ? ( + +

+ {title} + {itemCount > 0 ? `(${itemCount})` : null} +

+
+ ) : ( + title + )} + {renderSubTitleText(subTitleText)} +
+ ) : null} {actions ? ( diff --git a/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx b/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx index 02c73fac8..cfb8ac0d2 100644 --- a/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx +++ b/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx @@ -55,6 +55,8 @@ import Notification from "../../components/Notification"; import { DataSourceMenuContext, DataSourceMenuProperties } from "../../../../services/DataSourceMenuContext"; import MDSEnabledComponent from "../../../../components/MDSEnabledComponent"; import { useUpdateUrlWithDataSourceProperties } from "../../../../components/MDSEnabledComponent"; +import { getApplication, getNavigationUI, getUISettings } from "../../../../services/Services"; +import { ExternalLink } from "../../../utils/display-utils"; interface CreateSMPolicyProps extends RouteComponentProps, DataSourceMenuProperties { snapshotManagementService: SnapshotManagementService; @@ -97,6 +99,7 @@ interface CreateSMPolicyState extends DataSourceMenuProperties { minCountError: string; repoError: string; timezoneError: string; + useNewUX: boolean; } export class CreateSnapshotPolicy extends MDSEnabledComponent { @@ -105,6 +108,8 @@ export class CreateSnapshotPolicy extends MDSEnabledComponent - -

{isEdit ? "Edit" : "Create"} policy

-
- {subTitleText} + const { HeaderControl } = getNavigationUI(); + const { setAppDescriptionControls } = getApplication(); - + const descriptionData = [ + { + renderComponent: ( + + Snapshot policies allow you to define an automated snapshot schedule and retention period.{" "} + + + ), + }, + ]; + const padding_style = this.state.useNewUX ? { padding: "0px 0px" } : { padding: "5px 50px" }; + return ( +
+ {this.state.useNewUX ? ( + + ) : ( + <> + +

{isEdit ? "Edit" : "Create"} policy

+
+ {subTitleText} + + + )} diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx index fc0590be7..72091dc11 100644 --- a/public/pages/Main/Main.tsx +++ b/public/pages/Main/Main.tsx @@ -71,6 +71,7 @@ import * as pluginManifest from "../../../opensearch_dashboards.json"; import { DataSourceAttributes } from "../../../../../src/plugins/data_source/common/data_sources"; import { BehaviorSubject } from "rxjs"; import { i18n } from "@osd/i18n"; +import { getUISettings } from "../../services/Services"; enum Navigation { IndexManagement = "Index Management", @@ -404,7 +405,9 @@ export default class Main extends Component { const { landingPage } = this.props; - const ROUTE_STYLE = { padding: "25px 25px" }; + const uiSettings = getUISettings(); + const showActionsInHeader = uiSettings.get("home:useNewHomePage"); + const ROUTE_STYLE = showActionsInHeader ? { padding: "0px 0px" } : { padding: "25px 25px" }; const DataSourceMenu = this.props.dataSourceManagement?.ui?.getDataSourceMenu(); const DataSourceViewer = this.props.dataSourceManagement?.ui?.getDataSourceMenu(); diff --git a/public/pages/Repositories/containers/Repositories/Repositories.tsx b/public/pages/Repositories/containers/Repositories/Repositories.tsx index bebe19e59..da96b7de3 100644 --- a/public/pages/Repositories/containers/Repositories/Repositories.tsx +++ b/public/pages/Repositories/containers/Repositories/Repositories.tsx @@ -11,6 +11,7 @@ import { EuiTableFieldDataColumnType, EuiText, EuiTextColor, + EuiButtonIcon, } from "@elastic/eui"; import { getErrorMessage } from "../../../../utils/helpers"; import React, { Component, useContext } from "react"; @@ -27,6 +28,7 @@ import { truncateSpan } from "../../../Snapshots/helper"; import { DataSourceMenuContext, DataSourceMenuProperties } from "../../../../services/DataSourceMenuContext"; import MDSEnabledComponent from "../../../../components/MDSEnabledComponent"; import { useUpdateUrlWithDataSourceProperties } from "../../../../components/MDSEnabledComponent"; +import { getApplication, getNavigationUI, getUISettings } from "../../../../services/Services"; interface RepositoriesProps extends RouteComponentProps, DataSourceMenuProperties { snapshotManagementService: SnapshotManagementService; @@ -44,6 +46,7 @@ interface RepositoriesState extends DataSourceMenuProperties { editRepo: string | null; isDeleteModalVisible: boolean; + useNewUX: boolean; } export class Repositories extends MDSEnabledComponent { @@ -53,6 +56,8 @@ export class Repositories extends MDSEnabledComponent, ]; + const renderToolsRight = () => { + return [ + , + ]; + }; + + const renderToolsLeft = () => { + return [ + + Delete + , + ]; + }; + const search = { + toolsRight: useNewUX ? renderToolsRight() : undefined, + toolsLeft: useNewUX ? renderToolsLeft() : undefined, box: { placeholder: "Search repository", + compressed: useNewUX ? true : false, + increamental: true, }, filters: [ { @@ -273,9 +318,44 @@ export class Repositories extends MDSEnabledComponent + Repositories are remote storage locations used to store snapshots. + + ), + }, + ]; + + const controlControlsData = [ + { + id: "Create repository", + label: "Create repository", + iconType: "plus", + fill: true, + run: this.onClickCreate, + testId: "createRepo", + controlType: "button", + }, + ]; + + const { HeaderControl } = getNavigationUI(); + const { setAppRightControls, setAppDescriptionControls } = getApplication(); + const useTitle = useNewUX ? undefined : "Repositories"; + const useActions = useNewUX ? undefined : actions; + const useSubTitleText = useNewUX ? undefined : subTitleText; + return ( <> - + {useNewUX ? ( + <> + + + + ) : null} + { @@ -77,6 +84,8 @@ export class SnapshotPolicies extends MDSEnabledComponentDelete , ]; + + const popoverActionItemsNew = [ + { + this.closePopover(); + this.onClickStart(); + }} + > + Enable + , + { + this.closePopover(); + this.onClickStop(); + }} + > + Disable + , + { + this.closePopover(); + this.onClickEdit(); + }} + > + Edit + , + { + this.closePopover(); + this.showDeleteModal(); + }} + > + Delete + , + ]; const actionsButton = ( Actions @@ -461,7 +518,57 @@ export class SnapshotPolicies extends MDSEnabledComponent ); - return ( + const { HeaderControl } = getNavigationUI(); + const { setAppRightControls, setAppDescriptionControls } = getApplication(); + + const descriptionData = [ + { + renderComponent: ( + + Define an automated snapshot schedule and retention period with a snapshot policy.{" "} + + + ), + }, + ]; + + const controlControlsData = [ + { + id: "Create policy", + label: "Create policy", + iconType: "plus", + fill: true, + href: `${PLUGIN_NAME}#${ROUTES.CREATE_SNAPSHOT_POLICY}`, + testId: "createButton", + controlType: "button", + }, + ]; + + const CommonTable = () => { + return ( + + ); + }; + + const CommonModal = () => { + return ( + isDeleteModalVisible && ( + + ) + ); + }; + + return !this.state.useNewUx ? ( <> - + {CommonTable()} - - {isDeleteModalVisible && ( - - )} + {CommonModal()} + + ) : ( + <> + + + + + + + + + + + + + + + + + {CommonTable()} + + {CommonModal()} ); } diff --git a/public/pages/SnapshotPolicyDetails/containers/SnapshotPolicyDetails/SnapshotPolicyDetails.tsx b/public/pages/SnapshotPolicyDetails/containers/SnapshotPolicyDetails/SnapshotPolicyDetails.tsx index 11e7701bb..9fb5c52d0 100644 --- a/public/pages/SnapshotPolicyDetails/containers/SnapshotPolicyDetails/SnapshotPolicyDetails.tsx +++ b/public/pages/SnapshotPolicyDetails/containers/SnapshotPolicyDetails/SnapshotPolicyDetails.tsx @@ -20,6 +20,7 @@ import { EuiTableFieldDataColumnType, EuiText, EuiTitle, + EuiHealth, } from "@elastic/eui"; import { NotificationService, SnapshotManagementService } from "../../../../services"; import { SMMetadata, SMPolicy } from "../../../../../models/interfaces"; @@ -39,6 +40,8 @@ import { NotificationConfig } from "../../../../../server/models/interfaces"; import { DataSourceMenuContext, DataSourceMenuProperties } from "../../../../services/DataSourceMenuContext"; import MDSEnabledComponent from "../../../../components/MDSEnabledComponent"; import { useUpdateUrlWithDataSourceProperties } from "../../../../components/MDSEnabledComponent"; +import { getApplication, getNavigationUI, getUISettings } from "../../../../services/Services"; +import { TopNavControlButtonData, TopNavControlTextData, TopNavControlIconData } from "../../../../../../../src/plugins/navigation/public"; interface SnapshotPolicyDetailsProps extends RouteComponentProps, DataSourceMenuProperties { snapshotManagementService: SnapshotManagementService; @@ -54,6 +57,7 @@ interface SnapshotPolicyDetailsState extends DataSourceMenuProperties { isDeleteModalVisible: boolean; channel: NotificationConfig | null; + useNewUX: boolean; } export class SnapshotPolicyDetails extends MDSEnabledComponent { @@ -63,6 +67,9 @@ export class SnapshotPolicyDetails extends MDSEnabledComponent { + const { snapshotManagementService } = this.props; + const policyId = this.state.policyId; + try { + const response = await snapshotManagementService.stopPolicy(policyId); + if (response.ok) { + this.context.notifications.toasts.addSuccess(`"${policyId}" successfully stopped!`); + } else { + this.context.notifications.toasts.addDanger(`Could not stop policy "${policyId}" : ${response.error}`); + } + } catch (err) { + this.context.notifications.toasts.addDanger(getErrorMessage(err, "Could not stop the policy")); + } + this.componentDidMount(); + }; + + onClickStart = async () => { + const { snapshotManagementService } = this.props; + const policyId = this.state.policyId; + try { + const response = await snapshotManagementService.startPolicy(policyId); + if (response.ok) { + this.context.notifications.toasts.addSuccess(`"${policyId}" successfully started!`); + } else { + this.context.notifications.toasts.addDanger(`Could not start policy "${policyId}" : ${response.error}`); + } + } catch (err) { + this.context.notifications.toasts.addDanger(getErrorMessage(err, "Could not start the policy")); + } + this.componentDidMount(); + }; + + onClickPolicyStatusChange = async () => { + return this.state.policy?.enabled ? this.onClickStop() : this.onClickStart(); + }; + onEdit = () => { const { policyId } = this.state; if (policyId) { @@ -319,30 +369,82 @@ export class SnapshotPolicyDetails extends MDSEnabledComponent + + {_.truncate(this.renderEnabledField(policy.enabled))} + + ), + }, + ]; + + const padding_style = this.state.useNewUX ? { padding: "0px 0px" } : { padding: "5px 50px" }; return ( -
- - - - {_.truncate(policyId)} - - - - - +
+ {this.state.useNewUX ? ( + <> + + + + + ) : ( + <> + - Edit + + {_.truncate(policyId)} + + - - Delete - + + + Edit + + + + Delete + + + - - - - + + + )} diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index c96605aa8..392eaecb6 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiInMemoryTable, EuiSpacer, EuiLink, EuiFlyout, EuiButton, EuiEmptyPrompt, EuiHealth } from "@elastic/eui"; +import { EuiInMemoryTable, EuiSpacer, EuiLink, EuiFlyout, EuiButton, EuiButtonIcon, EuiEmptyPrompt, EuiHealth } from "@elastic/eui"; import _ from "lodash"; import React, { useEffect, useContext, useState, useMemo } from "react"; import { SnapshotManagementService } from "../../../../services"; import { CoreServicesContext } from "../../../../components/core_services"; -import { getToasts } from "../../helper" -import { Toast, ModifiedStages, IndexItem } from "../../../../models/interfaces" +import { getToasts } from "../../helper"; +import { Toast, ModifiedStages, IndexItem } from "../../../../models/interfaces"; import { GetIndexRecoveryResponse } from "../../../../../server/models/interfaces"; import { BREADCRUMBS, restoreIndicesCols } from "../../../../utils/constants"; import { ContentPanel } from "../../../../components/ContentPanel"; @@ -23,49 +23,55 @@ interface RestoreActivitiesPanelProps { snapshotId: string; restoreStartRef: number; indicesToRestore: string[]; + useNewUX: boolean; } const intervalIds: ReturnType[] = []; -export const RestoreActivitiesPanel = ( - { - onOpenError, - sendError, - sendToasts, - snapshotManagementService, - snapshotId, - restoreStartRef, - indicesToRestore - }: RestoreActivitiesPanelProps) => { +export const RestoreActivitiesPanel = ({ + onOpenError, + sendError, + sendToasts, + snapshotManagementService, + snapshotId, + restoreStartRef, + indicesToRestore, + useNewUX, +}: RestoreActivitiesPanelProps) => { const context = useContext(CoreServicesContext); const [startTime, setStartTime] = useState(""); const [stopTime, setStopTime] = useState(""); const [stage, setStage] = useState(""); const [indices, setIndices] = useState([]); const [flyout, setFlyout] = useState(false); - const [statusOk, setStatusOk] = useState(true) + const [statusOk, setStatusOk] = useState(true); const restoreCount = indicesToRestore.length; useEffect(() => { - context?.chrome.setBreadcrumbs([BREADCRUMBS.SNAPSHOT_MANAGEMENT, BREADCRUMBS.SNAPSHOTS, BREADCRUMBS.SNAPSHOT_RESTORE]); + const breadCrumbs = useNewUX + ? [BREADCRUMBS.INDEX_SNAPSHOT_RESTORE] + : [BREADCRUMBS.SNAPSHOT_MANAGEMENT, BREADCRUMBS.SNAPSHOTS, BREADCRUMBS.SNAPSHOT_RESTORE]; + context?.chrome.setBreadcrumbs(breadCrumbs); if (statusOk && stage !== "Completed (100%)") { - intervalIds.push(setInterval(() => { - getRestoreStatus(); - }, 2000)) + intervalIds.push( + setInterval(() => { + getRestoreStatus(); + }, 2000) + ); return () => { intervalIds.forEach((id) => { clearInterval(id); }); - } + }; } }, [stage]); const getRestoreStatus = async () => { const percent = stage.slice(stage.indexOf("(")); - const failedStage = `Failed ${percent}` + const failedStage = `Failed ${percent}`; if (!restoreStartRef) { return; @@ -79,35 +85,25 @@ export const RestoreActivitiesPanel = ( setRestoreStatus(response); } else { - const toasts = getToasts( - "error_restore_toast", - "", - snapshotId, - onOpenError - ); + const toasts = getToasts("error_restore_toast", "", snapshotId, onOpenError); res.error = res.error.concat(`, please check your connection`); setStage(failedStage); sendError(res); - sendToasts(toasts) + sendToasts(toasts); intervalIds.forEach((id) => { clearInterval(id); }); return; } } catch (err) { - const toasts = getToasts( - "error_restore_toast", - "", - snapshotId, - onOpenError - ); + const toasts = getToasts("error_restore_toast", "", snapshotId, onOpenError); setStage(failedStage); setStatusOk(false); sendError(err); - sendToasts(toasts) + sendToasts(toasts); } }; @@ -135,11 +131,11 @@ export const RestoreActivitiesPanel = ( VERIFY_INDEX: "Verifying", TRANSLOG: "Replaying translog", FINALIZE: "Cleaning up", - DONE: "Completed" - } + DONE: "Completed", + }; const lastStage = stages.length - 1; - // Loop through indices in response, filter out kibana index, + // Loop through indices in response, filter out kibana index, // gather progress info then use it to create progress field values. for (let item in response) { const responseItem = item as keyof GetIndexRecoveryResponse; @@ -152,7 +148,7 @@ export const RestoreActivitiesPanel = ( const stage = stages.indexOf(info.stage); const time = { start_time: info.start_time_in_millis, - stop_time: info.stop_time_in_millis ? info.stop_time_in_millis : Date.now() + stop_time: info.stop_time_in_millis ? info.stop_time_in_millis : Date.now(), }; doneCount = stage === lastStage ? doneCount + 1 : doneCount; @@ -164,7 +160,7 @@ export const RestoreActivitiesPanel = ( if (info.source.index && info.source.snapshot === snapshotId) { minStartTime = minStartTime && minStartTime < time.start_time ? minStartTime : time.start_time; - indexes.push({ index: info.source.index, "restore_status": indexStatus }); + indexes.push({ index: info.source.index, restore_status: indexStatus }); } } } @@ -174,7 +170,7 @@ export const RestoreActivitiesPanel = ( for (let index of indicesToRestore) { if (indicesStarted.indexOf(index) < 0) { - updatedIndices.push({ index, restore_status: "Pending" }) + updatedIndices.push({ index, restore_status: "Pending" }); } } @@ -185,25 +181,35 @@ export const RestoreActivitiesPanel = ( setIndices(sortedUpdatedIndices); setStopTime(new Date(maxStopTime).toLocaleString().replace(",", " ")); - setStartTime(new Date(minStartTime).toLocaleString().replace(",", " ")) + setStartTime(new Date(minStartTime).toLocaleString().replace(",", " ")); if (stages[stageIndex]) { - stageIndex = (stageIndex === lastStage && doneCount < restoreCount) ? 2 : stageIndex; + stageIndex = stageIndex === lastStage && doneCount < restoreCount ? 2 : stageIndex; setStage(`${modifiedStages[stages[stageIndex] as keyof ModifiedStages]} (${percent}%)`); } - }; - const actions = useMemo(() => ( - [ - + const actions = useMemo( + () => [ + Refresh , - ] - ), []); - const currentStage = stage.slice(0, stage.indexOf(" ")) + ], + [] + ); + + const renderToolsRight = () => { + return []; + }; + + const currentStage = stage.slice(0, stage.indexOf(" ")); const color = currentStage === "Completed" ? "success" : currentStage === "Failed" ? "failure" : "warning"; - const indexText = `${restoreCount === 1 ? "1 Index" : `${restoreCount} Indices`}` + const indexText = `${restoreCount === 1 ? "1 Index" : `${restoreCount} Indices`}`; const restoreStatus = [ { @@ -230,7 +236,7 @@ export const RestoreActivitiesPanel = ( { field: "status", name: "Status", - render: (text: string) => {text} + render: (text: string) => {text}, }, { field: "indexes", @@ -239,27 +245,60 @@ export const RestoreActivitiesPanel = ( }, ]; - const message = (There are no restore activities.

} titleSize="s">
) + const search = { + toolsRight: renderToolsRight(), + box: { + placeholder: "Search", + incremental: true, + compressed: true, + }, + }; + + const oldMessage = There are no restore activities.

} titleSize="s">
; + const newMessage = ( + +

There are no restore activities

When a restore activity is in progress it will appear here.

+ + } + titleSize="s" + >
+ ); + const message = useNewUX ? newMessage : oldMessage; + const title = useNewUX ? undefined : "Restore activities in progress"; + const useActions = useNewUX ? undefined : actions; + const useSearch = useNewUX ? search : undefined; return ( <> - {flyout && - - + {flyout && ( + + - } - - - - - - + )} + + + {useNewUX ? null : ( + <> + + + + + + )} ); diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index ff98d7784..460ea9c7e 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -17,6 +17,10 @@ import { EuiTab, EuiOverlayMask, EuiGlobalToastList, + EuiPopover, + EuiContextMenuPanel, + EuiContextMenuItem, + EuiButtonIcon, } from "@elastic/eui"; import { FieldValueSelectionFilterConfigType } from "@elastic/eui/src/components/search_bar/filters/field_value_selection_filter"; import { CoreServicesContext } from "../../../../components/core_services"; @@ -39,6 +43,7 @@ import { snapshotStatusRender, truncateSpan } from "../../helper"; import { DataSourceMenuContext, DataSourceMenuProperties } from "../../../../services/DataSourceMenuContext"; import MDSEnabledComponent from "../../../../components/MDSEnabledComponent"; import { useUpdateUrlWithDataSourceProperties } from "../../../../components/MDSEnabledComponent"; +import { getApplication, getNavigationUI, getUISettings } from "../../../../services/Services"; interface SnapshotsProps extends RouteComponentProps, DataSourceMenuProperties { snapshotManagementService: SnapshotManagementService; @@ -68,6 +73,8 @@ interface SnapshotsState extends DataSourceMenuProperties { message?: React.ReactNode; isDeleteModalVisible: boolean; + isPopoverOpen: boolean; + useNewUX: boolean; } export class Snapshots extends MDSEnabledComponent { @@ -77,7 +84,8 @@ export class Snapshots extends MDSEnabledComponent { + this.setState({ isPopoverOpen: !this.state.isPopoverOpen }); + }; + + closePopover = () => { + this.setState({ isPopoverOpen: false }); + }; + render() { const { snapshots, @@ -409,13 +430,66 @@ export class Snapshots extends MDSEnabledComponent snapshot.repository))]; const status = [...new Set(snapshots.map((snapshot) => snapshot.status))]; + + const popoverActionItems = [ + { + this.closePopover(); + this.showDeleteModal(); + }} + data-test-subj="deleteButton" + > + Delete + , + { + this.closePopover(); + this.onClickRestore(); + }} + data-test-subj="restoreButton" + > + Restore + , + ]; + + const renderToolsRight = () => { + return [ + , + + + , + ]; + }; + + const actionsButton = ( + + Actions + + ); + const search = { + toolsRight: useNewUX ? renderToolsRight() : undefined, box: { placeholder: "Search snapshot", + incremental: true, + compressed: useNewUX ? true : false, }, filters: [ { @@ -468,12 +542,48 @@ export class Snapshots extends MDSEnabledComponent ); + const controlControlsData = [ + { + id: "Take snapshot", + label: "Take snapshot", + fill: true, + run: this.onClickCreate, + testId: "takeSnapshot", + controlType: "button", + }, + ]; + + const descriptionData = [ + { + renderComponent: ( + + Index snapshots are taken automatically from snapshot policies, or you can initiate manual snapshots to save to a repository.{" "} +

+ You can restore indices by selecting a snapshot. +
+ ), + }, + ]; + + const { HeaderControl } = getNavigationUI(); + const { setAppRightControls, setAppDescriptionControls } = getApplication(); + const showTitle = useNewUX ? undefined : "Snapshots"; + const SnapshotTabName = useNewUX ? "Index snapshots" : "Snapshots"; + const useActions = useNewUX ? undefined : actions; + const useSubTitle = useNewUX ? undefined : subTitleText; + return ( <> + {useNewUX ? ( + <> + + + + ) : null} - Snapshots + {SnapshotTabName} Restore activities in progress @@ -487,11 +597,12 @@ export class Snapshots extends MDSEnabledComponent )} {snapshotPanel && ( - + `${item.repository}:${item.id}`} diff --git a/public/pages/utils/display-utils.tsx b/public/pages/utils/display-utils.tsx new file mode 100644 index 000000000..1e6265e67 --- /dev/null +++ b/public/pages/utils/display-utils.tsx @@ -0,0 +1,15 @@ +import { EuiLink } from "@elastic/eui"; + +import React from "react"; + +export interface UIProps { + cssClassName: string; +} + +export function ExternalLink(props: { href: string }) { + return ( + + Learn more. + + ); +} diff --git a/public/plugin.ts b/public/plugin.ts index 178bb6b51..346781e13 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -24,6 +24,8 @@ import { ManagementOverViewPluginSetup } from "../../../src/plugins/management_o import { DataSourceManagementPluginSetup } from "../../../src/plugins/data_source_management/public"; import { dataSourceObservable } from "./pages/Main/Main"; import { BehaviorSubject } from "rxjs"; +import { NavigationPublicPluginStart } from "../../../src/plugins/navigation/public"; +import { setApplication, setNavigationUI, setUISettings } from "./services/Services"; interface IndexManagementSetupDeps { managementOverview?: ManagementOverViewPluginSetup; @@ -96,6 +98,10 @@ const ISM_FEATURE_DESCRIPTION: Record = Object.freeze({ }), }); +export interface ISMPluginStartDeps { + navigation: NavigationPublicPluginStart; +} + export class IndexManagementPlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) { // can retrieve config from initializerContext @@ -391,9 +397,12 @@ export class IndexManagementPlugin implements Plugin(null); const ServicesConsumer = ServicesContext.Consumer; export { ServicesContext, ServicesConsumer }; + +export const [getUISettings, setUISettings] = createGetterSetter("UISettings"); + +export const [getNavigationUI, setNavigationUI] = createGetterSetter("navigation"); + +export const [getApplication, setApplication] = createGetterSetter("application"); diff --git a/public/utils/constants.ts b/public/utils/constants.ts index a924b2bc9..1e97f57ae 100644 --- a/public/utils/constants.ts +++ b/public/utils/constants.ts @@ -96,11 +96,14 @@ export const BREADCRUMBS = Object.freeze({ EDIT_SNAPSHOT_POLICY: { text: "Edit snapshot policy" }, SNAPSHOTS: { text: "Snapshots", href: `#${ROUTES.SNAPSHOTS}` }, + INDEX_SNAPSHOTS: { text: "Index snapshots", href: `#${ROUTES.SNAPSHOTS}` }, SNAPSHOT_RESTORE: { text: "Restore activities in progress" }, + INDEX_SNAPSHOT_RESTORE: { text: "Index snapshots" }, CREATE_SNAPSHOT: { text: "Create repository", href: `#${ROUTES.CREATE_REPOSITORY}` }, EDIT_SNAPSHOT: { text: "Edit repository", href: `#${ROUTES.EDIT_REPOSITORY}` }, REPOSITORIES: { text: "Repositories", href: `#${ROUTES.REPOSITORIES}` }, + SNAPSHOT_REPOSITORIES: { text: "Snapshot repositories", href: `#${ROUTES.REPOSITORIES}` }, CREATE_REPOSITORY: { text: "Create repository", href: `#${ROUTES.CREATE_REPOSITORY}` }, EDIT_REPOSITORY: { text: "Edit repository", href: `#${ROUTES.EDIT_REPOSITORY}` }, CREATE_INDEX: { text: "Create Index", href: `#${ROUTES.CREATE_INDEX}` },