From 3f634e75398df9af6fe2403bb98f0397ac1ebd34 Mon Sep 17 00:00:00 2001 From: Sandeep Kumawat Date: Wed, 14 Aug 2024 10:03:22 +0530 Subject: [PATCH] new page header update for index snapshot and repository pages Signed-off-by: Sandeep Kumawat --- .../CreateSnapshotPolicy.tsx | 3 +- .../containers/Repositories/Repositories.tsx | 86 ++++++++- .../SnapshotPolicyDetails.tsx | 3 +- .../RestoreActivitiesPanel.tsx | 175 +++++++++++------- .../containers/Snapshots/Snapshots.tsx | 123 +++++++++++- public/utils/constants.ts | 3 + 6 files changed, 312 insertions(+), 81 deletions(-) diff --git a/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx b/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx index 894557ffe..cfb8ac0d2 100644 --- a/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx +++ b/public/pages/CreateSnapshotPolicy/containers/CreateSnapshotPolicy/CreateSnapshotPolicy.tsx @@ -578,11 +578,10 @@ export class CreateSnapshotPolicy extends MDSEnabledComponent{isEdit ? "Edit" : "Create"} policy {subTitleText} + )} - - 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} + + )} - - {policySettingItems.map((item) => ( 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/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}` },