mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-05-17 10:47:35 +01:00
Refactoring container copy strings so they can be locallized
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
|||||||
CreateJobRequest,
|
CreateJobRequest,
|
||||||
DataTransferJobGetResults,
|
DataTransferJobGetResults,
|
||||||
} from "../../../Utils/arm/generatedClients/dataTransferService/types";
|
} from "../../../Utils/arm/generatedClients/dataTransferService/types";
|
||||||
import ContainerCopyMessages from "../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
import {
|
import {
|
||||||
convertTime,
|
convertTime,
|
||||||
convertToCamelCase,
|
convertToCamelCase,
|
||||||
@@ -35,7 +35,7 @@ export const openCreateCopyJobPanel = (explorer: Explorer) => {
|
|||||||
const sidePanelState = useSidePanel.getState();
|
const sidePanelState = useSidePanel.getState();
|
||||||
sidePanelState.setPanelHasConsole(false);
|
sidePanelState.setPanelHasConsole(false);
|
||||||
sidePanelState.openSidePanel(
|
sidePanelState.openSidePanel(
|
||||||
ContainerCopyMessages.createCopyJobPanelTitle,
|
t(Keys.containerCopy.createCopyJob.panelTitle),
|
||||||
<CreateCopyJobScreensProvider explorer={explorer} />,
|
<CreateCopyJobScreensProvider explorer={explorer} />,
|
||||||
"650px",
|
"650px",
|
||||||
);
|
);
|
||||||
@@ -45,7 +45,7 @@ export const openCopyJobDetailsPanel = (job: CopyJobType) => {
|
|||||||
const sidePanelState = useSidePanel.getState();
|
const sidePanelState = useSidePanel.getState();
|
||||||
sidePanelState.setPanelHasConsole(false);
|
sidePanelState.setPanelHasConsole(false);
|
||||||
sidePanelState.openSidePanel(
|
sidePanelState.openSidePanel(
|
||||||
ContainerCopyMessages.copyJobDetailsPanelTitle(job.Name),
|
job.Name || t(Keys.containerCopy.jobDetails.panelTitleDefault),
|
||||||
<CopyJobDetails job={job} />,
|
<CopyJobDetails job={job} />,
|
||||||
"650px",
|
"650px",
|
||||||
);
|
);
|
||||||
@@ -193,7 +193,7 @@ export const updateCopyJobStatus = async (job: CopyJobType, action: string): Pro
|
|||||||
const pattern = new RegExp(`'(${statusList.join("|")})'`, "g");
|
const pattern = new RegExp(`'(${statusList.join("|")})'`, "g");
|
||||||
const normalizedErrorMessage = errorMessage.replace(
|
const normalizedErrorMessage = errorMessage.replace(
|
||||||
pattern,
|
pattern,
|
||||||
`'${ContainerCopyMessages.MonitorJobs.Status.InProgress}'`,
|
`'${t(Keys.containerCopy.monitorJobs.status.inProgress)}'`,
|
||||||
);
|
);
|
||||||
logError(`Error updating copy job status: ${normalizedErrorMessage}`, "CopyJob/CopyJobActions.updateCopyJobStatus");
|
logError(`Error updating copy job status: ${normalizedErrorMessage}`, "CopyJob/CopyJobActions.updateCopyJobStatus");
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import RefreshIcon from "../../../../images/refresh-cosmos.svg";
|
|||||||
import SunIcon from "../../../../images/SunIcon.svg";
|
import SunIcon from "../../../../images/SunIcon.svg";
|
||||||
import { configContext, Platform } from "../../../ConfigContext";
|
import { configContext, Platform } from "../../../ConfigContext";
|
||||||
import { useThemeStore } from "../../../hooks/useTheme";
|
import { useThemeStore } from "../../../hooks/useTheme";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import * as Actions from "../Actions/CopyJobActions";
|
import * as Actions from "../Actions/CopyJobActions";
|
||||||
import ContainerCopyMessages from "../ContainerCopyMessages";
|
|
||||||
import { MonitorCopyJobsRefState } from "../MonitorCopyJobs/MonitorCopyJobRefState";
|
import { MonitorCopyJobsRefState } from "../MonitorCopyJobs/MonitorCopyJobRefState";
|
||||||
import { CopyJobCommandBarBtnType } from "../Types/CopyJobTypes";
|
import { CopyJobCommandBarBtnType } from "../Types/CopyJobTypes";
|
||||||
|
|
||||||
@@ -19,15 +19,15 @@ function getCopyJobBtns(explorer: Explorer, isDarkMode: boolean): CopyJobCommand
|
|||||||
{
|
{
|
||||||
key: "createCopyJob",
|
key: "createCopyJob",
|
||||||
iconSrc: AddIcon,
|
iconSrc: AddIcon,
|
||||||
label: ContainerCopyMessages.createCopyJobButtonLabel,
|
label: t(Keys.containerCopy.commandBar.createCopyJobButtonLabel),
|
||||||
ariaLabel: ContainerCopyMessages.createCopyJobButtonAriaLabel,
|
ariaLabel: t(Keys.containerCopy.commandBar.createCopyJobButtonAriaLabel),
|
||||||
onClick: () => Actions.openCreateCopyJobPanel(explorer),
|
onClick: () => Actions.openCreateCopyJobPanel(explorer),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "refresh",
|
key: "refresh",
|
||||||
iconSrc: RefreshIcon,
|
iconSrc: RefreshIcon,
|
||||||
label: ContainerCopyMessages.refreshButtonLabel,
|
label: t(Keys.common.refresh),
|
||||||
ariaLabel: ContainerCopyMessages.refreshButtonAriaLabel,
|
ariaLabel: t(Keys.containerCopy.commandBar.refreshButtonAriaLabel),
|
||||||
onClick: () => monitorCopyJobsRef?.refreshJobList(),
|
onClick: () => monitorCopyJobsRef?.refreshJobList(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,8 +48,8 @@ function getCopyJobBtns(explorer: Explorer, isDarkMode: boolean): CopyJobCommand
|
|||||||
buttons.push({
|
buttons.push({
|
||||||
key: "feedback",
|
key: "feedback",
|
||||||
iconSrc: FeedbackIcon,
|
iconSrc: FeedbackIcon,
|
||||||
label: ContainerCopyMessages.feedbackButtonLabel,
|
label: t(Keys.containerCopy.commandBar.feedbackButtonLabel),
|
||||||
ariaLabel: ContainerCopyMessages.feedbackButtonAriaLabel,
|
ariaLabel: t(Keys.containerCopy.commandBar.feedbackButtonAriaLabel),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
explorer.openContainerCopyFeedbackBlade();
|
explorer.openContainerCopyFeedbackBlade();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,193 +0,0 @@
|
|||||||
export default {
|
|
||||||
// Copy Job Command Bar
|
|
||||||
feedbackButtonLabel: "Feedback",
|
|
||||||
feedbackButtonAriaLabel: "Provide feedback on copy jobs",
|
|
||||||
refreshButtonLabel: "Refresh",
|
|
||||||
refreshButtonAriaLabel: "Refresh copy jobs",
|
|
||||||
createCopyJobButtonLabel: "Create Copy Job",
|
|
||||||
createCopyJobButtonAriaLabel: "Create a new container copy job",
|
|
||||||
|
|
||||||
// No Copy Jobs Found
|
|
||||||
noCopyJobsTitle: "No copy jobs to show",
|
|
||||||
createCopyJobButtonText: "Create a container copy job",
|
|
||||||
|
|
||||||
// Copy Job Details
|
|
||||||
copyJobDetailsPanelTitle: (jobName: string) => jobName || "Job Details",
|
|
||||||
errorTitle: "Error Details",
|
|
||||||
selectedContainers: "Selected Containers",
|
|
||||||
|
|
||||||
// Create Copy Job Panel
|
|
||||||
createCopyJobPanelTitle: "Create copy job",
|
|
||||||
|
|
||||||
// Select Account Screen
|
|
||||||
selectAccountDescription: "Please select a source account from which to copy.",
|
|
||||||
subscriptionDropdownLabel: "Subscription",
|
|
||||||
subscriptionDropdownPlaceholder: "Select a subscription",
|
|
||||||
sourceAccountDropdownLabel: "Account",
|
|
||||||
sourceAccountDropdownPlaceholder: "Select an account",
|
|
||||||
migrationTypeOptions: {
|
|
||||||
offline: {
|
|
||||||
title: "Offline mode",
|
|
||||||
description:
|
|
||||||
"Offline container copy jobs let you copy data from a source container to a destination Cosmos DB container for supported APIs. To ensure data integrity between the source and destination, we recommend stopping updates on the source container before creating the copy job. Learn more about [offline copy jobs](https://learn.microsoft.com/azure/cosmos-db/how-to-container-copy?tabs=offline-copy&pivots=api-nosql).",
|
|
||||||
},
|
|
||||||
online: {
|
|
||||||
title: "Online mode",
|
|
||||||
description:
|
|
||||||
"Online container copy jobs let you copy data from a source container to a destination Cosmos DB NoSQL API container using the [All Versions and Delete](https://learn.microsoft.com/azure/cosmos-db/change-feed-modes?tabs=all-versions-and-deletes#all-versions-and-deletes-change-feed-mode-preview) change feed. This allows updates to continue on the source while data is copied. A brief downtime is required at the end to safely switch over client applications to the destination container. Learn more about [online copy jobs](https://learn.microsoft.com/azure/cosmos-db/container-copy?tabs=online-copy&pivots=api-nosql#getting-started).",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Select Source and Target Containers Screen
|
|
||||||
selectSourceAndTargetContainersDescription:
|
|
||||||
"Please select a source container and a destination container to copy to.",
|
|
||||||
sourceContainerSubHeading: "Source container",
|
|
||||||
targetContainerSubHeading: "Destination container",
|
|
||||||
databaseDropdownLabel: "Database",
|
|
||||||
databaseDropdownPlaceholder: "Select a database",
|
|
||||||
containerDropdownLabel: "Container",
|
|
||||||
containerDropdownPlaceholder: "Select a container",
|
|
||||||
createNewContainerSubHeading: "Select the properties for your container.",
|
|
||||||
createContainerButtonLabel: "Create a new container",
|
|
||||||
createContainerHeading: "Create new container",
|
|
||||||
|
|
||||||
// Preview and Create Screen
|
|
||||||
jobNameLabel: "Job name",
|
|
||||||
sourceSubscriptionLabel: "Source subscription",
|
|
||||||
sourceAccountLabel: "Source account",
|
|
||||||
sourceDatabaseLabel: "Source database",
|
|
||||||
sourceContainerLabel: "Source container",
|
|
||||||
targetDatabaseLabel: "Destination database",
|
|
||||||
targetContainerLabel: "Destination container",
|
|
||||||
|
|
||||||
// Assign Permissions Screen
|
|
||||||
assignPermissions: {
|
|
||||||
crossAccountDescription:
|
|
||||||
"To copy data from the source to the destination container, ensure that the managed identity of the destination account has read access to the source account by completing the following steps.",
|
|
||||||
intraAccountOnlineDescription: (accountName: string) =>
|
|
||||||
`Follow the steps below to enable online copy on your "${accountName}" account.`,
|
|
||||||
crossAccountConfiguration: {
|
|
||||||
title: "Cross-account container copy",
|
|
||||||
description: (sourceAccount: string, destinationAccount: string) =>
|
|
||||||
`Please follow the instruction below to grant requisite permissions to copy data from "${sourceAccount}" to "${destinationAccount}".`,
|
|
||||||
},
|
|
||||||
onlineConfiguration: {
|
|
||||||
title: "Online container copy",
|
|
||||||
description: (accountName: string) =>
|
|
||||||
`Please follow the instructions below to enable online copy on your "${accountName}" account.`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
toggleBtn: {
|
|
||||||
onText: "On",
|
|
||||||
offText: "Off",
|
|
||||||
},
|
|
||||||
popoverOverlaySpinnerLabel: "Please wait while we process your request...",
|
|
||||||
addManagedIdentity: {
|
|
||||||
title: "System-assigned managed identity enabled.",
|
|
||||||
description:
|
|
||||||
"A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don’t have to store any credentials in code.",
|
|
||||||
descriptionHrefText: "Learn more about Managed identities.",
|
|
||||||
descriptionHref: "https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview",
|
|
||||||
toggleLabel: "System assigned managed identity",
|
|
||||||
tooltip: {
|
|
||||||
content: "Learn more about",
|
|
||||||
hrefText: "Managed Identities.",
|
|
||||||
href: "https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview",
|
|
||||||
},
|
|
||||||
userAssignedIdentityTooltip: "You can select an existing user assigned identity or create a new one.",
|
|
||||||
userAssignedIdentityLabel: "You may also select a user assigned managed identity.",
|
|
||||||
createUserAssignedIdentityLink: "Create User Assigned Managed Identity",
|
|
||||||
enablementTitle: "Enable system assigned managed identity",
|
|
||||||
enablementDescription: (accountName: string) =>
|
|
||||||
accountName
|
|
||||||
? `Enable system-assigned managed identity on the ${accountName}. To confirm, click the "Yes" button.`
|
|
||||||
: "",
|
|
||||||
},
|
|
||||||
defaultManagedIdentity: {
|
|
||||||
title: "System-assigned managed identity set as default.",
|
|
||||||
description: (accountName: string) =>
|
|
||||||
`Set the system-assigned managed identity as default for "${accountName}" by switching it on.`,
|
|
||||||
tooltip: {
|
|
||||||
content: "Learn more about",
|
|
||||||
hrefText: "Default Managed Identities.",
|
|
||||||
href: "https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview",
|
|
||||||
},
|
|
||||||
popoverTitle: "System assigned managed identity set as default",
|
|
||||||
popoverDescription: (accountName: string) =>
|
|
||||||
`Assign the system-assigned managed identity as the default for "${accountName}". To confirm, click the "Yes" button. `,
|
|
||||||
},
|
|
||||||
readPermissionAssigned: {
|
|
||||||
title: "Read permissions assigned to the default identity.",
|
|
||||||
description:
|
|
||||||
"To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account.",
|
|
||||||
tooltip: {
|
|
||||||
content: "Learn more about",
|
|
||||||
hrefText: "Read permissions.",
|
|
||||||
href: "https://learn.microsoft.com/azure/cosmos-db/nosql/how-to-connect-role-based-access-control",
|
|
||||||
},
|
|
||||||
popoverTitle: "Read permissions assigned to default identity.",
|
|
||||||
popoverDescription:
|
|
||||||
"Assign read permissions of the source account to the default identity of the destination account. To confirm click the “Yes” button.",
|
|
||||||
},
|
|
||||||
pointInTimeRestore: {
|
|
||||||
title: "Point In Time Restore enabled",
|
|
||||||
description: (accessName: string) =>
|
|
||||||
`To facilitate online container copy jobs, please update your "${accessName}" backup policy from periodic to continuous backup. Enabling continuous backup is required for this functionality.`,
|
|
||||||
tooltip: {
|
|
||||||
content: "Learn more about",
|
|
||||||
hrefText: "Continuous Backup",
|
|
||||||
href: "https://learn.microsoft.com/en-us/azure/cosmos-db/continuous-backup-restore-introduction",
|
|
||||||
},
|
|
||||||
buttonText: "Enable Point In Time Restore",
|
|
||||||
},
|
|
||||||
onlineCopyEnabled: {
|
|
||||||
title: "Online copy enabled",
|
|
||||||
description: (accountName: string) =>
|
|
||||||
`Enable online container copy by clicking the button below on your "${accountName}" account.`,
|
|
||||||
hrefText: "Learn more about online copy jobs",
|
|
||||||
href: "https://learn.microsoft.com/en-us/azure/cosmos-db/container-copy?tabs=online-copy&pivots=api-nosql#enable-online-copy",
|
|
||||||
buttonText: "Enable Online Copy",
|
|
||||||
validateAllVersionsAndDeletesChangeFeedSpinnerLabel:
|
|
||||||
"Validating All versions and deletes change feed mode (preview)...",
|
|
||||||
enablingAllVersionsAndDeletesChangeFeedSpinnerLabel:
|
|
||||||
"Enabling All versions and deletes change feed mode (preview)...",
|
|
||||||
enablingOnlineCopySpinnerLabel: (accountName: string) =>
|
|
||||||
`Enabling online copy on your "${accountName}" account ...`,
|
|
||||||
},
|
|
||||||
MonitorJobs: {
|
|
||||||
Columns: {
|
|
||||||
lastUpdatedTime: "Date & time",
|
|
||||||
name: "Job name",
|
|
||||||
status: "Status",
|
|
||||||
completionPercentage: "Completion %",
|
|
||||||
duration: "Duration",
|
|
||||||
error: "Error message",
|
|
||||||
mode: "Mode",
|
|
||||||
actions: "Actions",
|
|
||||||
},
|
|
||||||
Actions: {
|
|
||||||
pause: "Pause",
|
|
||||||
resume: "Resume",
|
|
||||||
cancel: "Cancel",
|
|
||||||
complete: "Complete",
|
|
||||||
viewDetails: "View Details",
|
|
||||||
},
|
|
||||||
Status: {
|
|
||||||
Pending: "Queued",
|
|
||||||
InProgress: "Running",
|
|
||||||
Running: "Running",
|
|
||||||
Partitioning: "Running",
|
|
||||||
Paused: "Paused",
|
|
||||||
Completed: "Completed",
|
|
||||||
Failed: "Failed",
|
|
||||||
Faulted: "Failed",
|
|
||||||
Skipped: "Cancelled",
|
|
||||||
Cancelled: "Cancelled",
|
|
||||||
},
|
|
||||||
dialog: {
|
|
||||||
heading: "",
|
|
||||||
confirmButtonText: "Confirm",
|
|
||||||
cancelButtonText: "Cancel",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
+13
-12
@@ -2,9 +2,9 @@ import "@testing-library/jest-dom";
|
|||||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||||
import { DatabaseAccount } from "Contracts/DataModels";
|
import { DatabaseAccount } from "Contracts/DataModels";
|
||||||
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { updateSystemIdentity } from "../../../../../Utils/arm/identityUtils";
|
import { updateSystemIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import AddManagedIdentity from "./AddManagedIdentity";
|
import AddManagedIdentity from "./AddManagedIdentity";
|
||||||
|
|
||||||
@@ -133,16 +133,16 @@ describe("AddManagedIdentity", () => {
|
|||||||
it("renders all required elements", () => {
|
it("renders all required elements", () => {
|
||||||
renderWithContext();
|
renderWithContext();
|
||||||
|
|
||||||
expect(screen.getByText(ContainerCopyMessages.addManagedIdentity.description)).toBeInTheDocument();
|
expect(screen.getByText(t(Keys.containerCopy.addManagedIdentity.description))).toBeInTheDocument();
|
||||||
expect(screen.getByText(ContainerCopyMessages.addManagedIdentity.descriptionHrefText)).toBeInTheDocument();
|
expect(screen.getByText(t(Keys.containerCopy.addManagedIdentity.descriptionHrefText))).toBeInTheDocument();
|
||||||
expect(screen.getByRole("switch")).toBeInTheDocument();
|
expect(screen.getByRole("switch")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders description link with correct href", () => {
|
it("renders description link with correct href", () => {
|
||||||
renderWithContext();
|
renderWithContext();
|
||||||
|
|
||||||
const link = screen.getByText(ContainerCopyMessages.addManagedIdentity.descriptionHrefText);
|
const link = screen.getByText(t(Keys.containerCopy.addManagedIdentity.descriptionHrefText));
|
||||||
expect(link.closest("a")).toHaveAttribute("href", ContainerCopyMessages.addManagedIdentity.descriptionHref);
|
expect(link.closest("a")).toHaveAttribute("href", t(Keys.containerCopy.addManagedIdentity.descriptionHref));
|
||||||
expect(link.closest("a")).toHaveAttribute("target", "_blank");
|
expect(link.closest("a")).toHaveAttribute("target", "_blank");
|
||||||
expect(link.closest("a")).toHaveAttribute("rel", "noopener noreferrer");
|
expect(link.closest("a")).toHaveAttribute("rel", "noopener noreferrer");
|
||||||
});
|
});
|
||||||
@@ -175,7 +175,7 @@ describe("AddManagedIdentity", () => {
|
|||||||
const toggle = screen.getByRole("switch");
|
const toggle = screen.getByRole("switch");
|
||||||
fireEvent.click(toggle);
|
fireEvent.click(toggle);
|
||||||
|
|
||||||
expect(screen.getByText(ContainerCopyMessages.addManagedIdentity.enablementTitle)).toBeInTheDocument();
|
expect(screen.getByText(t(Keys.containerCopy.addManagedIdentity.enablementTitle))).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("hides popover when toggle is off", () => {
|
it("hides popover when toggle is off", () => {
|
||||||
@@ -185,7 +185,7 @@ describe("AddManagedIdentity", () => {
|
|||||||
fireEvent.click(toggle);
|
fireEvent.click(toggle);
|
||||||
fireEvent.click(toggle);
|
fireEvent.click(toggle);
|
||||||
|
|
||||||
expect(screen.queryByText(ContainerCopyMessages.addManagedIdentity.enablementTitle)).not.toBeInTheDocument();
|
expect(screen.queryByText(t(Keys.containerCopy.addManagedIdentity.enablementTitle))).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -197,10 +197,11 @@ describe("AddManagedIdentity", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("displays correct enablement description with account name", () => {
|
it("displays correct enablement description with account name", () => {
|
||||||
const expectedDescription = ContainerCopyMessages.addManagedIdentity.enablementDescription(
|
expect(
|
||||||
mockCopyJobState.target.account.name,
|
screen.getByText(
|
||||||
);
|
t(Keys.containerCopy.addManagedIdentity.enablementDescription, { accountName: "test-target-account" }),
|
||||||
expect(screen.getByText(expectedDescription)).toBeInTheDocument();
|
),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls handleAddSystemIdentity when primary button clicked", async () => {
|
it("calls handleAddSystemIdentity when primary button clicked", async () => {
|
||||||
@@ -220,7 +221,7 @@ describe("AddManagedIdentity", () => {
|
|||||||
const cancelButton = screen.getByText("Cancel");
|
const cancelButton = screen.getByText("Cancel");
|
||||||
fireEvent.click(cancelButton);
|
fireEvent.click(cancelButton);
|
||||||
|
|
||||||
expect(screen.queryByText(ContainerCopyMessages.addManagedIdentity.enablementTitle)).not.toBeInTheDocument();
|
expect(screen.queryByText(t(Keys.containerCopy.addManagedIdentity.enablementTitle))).not.toBeInTheDocument();
|
||||||
|
|
||||||
const toggle = screen.getByRole("switch");
|
const toggle = screen.getByRole("switch");
|
||||||
expect(toggle).not.toBeChecked();
|
expect(toggle).not.toBeChecked();
|
||||||
|
|||||||
+14
-16
@@ -1,7 +1,7 @@
|
|||||||
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { updateSystemIdentity } from "../../../../../Utils/arm/identityUtils";
|
import { updateSystemIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import InfoTooltip from "../Components/InfoTooltip";
|
import InfoTooltip from "../Components/InfoTooltip";
|
||||||
import PopoverMessage from "../Components/PopoverContainer";
|
import PopoverMessage from "../Components/PopoverContainer";
|
||||||
@@ -11,14 +11,14 @@ import useToggle from "./hooks/useToggle";
|
|||||||
|
|
||||||
const managedIdentityTooltip = (
|
const managedIdentityTooltip = (
|
||||||
<Text>
|
<Text>
|
||||||
{ContainerCopyMessages.addManagedIdentity.tooltip.content}
|
{t(Keys.containerCopy.addManagedIdentity.tooltipContent)}
|
||||||
<Link
|
<Link
|
||||||
style={{ color: "var(--colorBrandForeground1)" }}
|
style={{ color: "var(--colorBrandForeground1)" }}
|
||||||
href={ContainerCopyMessages.addManagedIdentity.tooltip.href}
|
href={t(Keys.containerCopy.addManagedIdentity.tooltipHref)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.addManagedIdentity.tooltip.hrefText}
|
{t(Keys.containerCopy.addManagedIdentity.tooltipHrefText)}
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -32,28 +32,26 @@ const AddManagedIdentity: React.FC<AddManagedIdentityProps> = () => {
|
|||||||
return (
|
return (
|
||||||
<Stack className="addManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
<Stack className="addManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||||
<Text className="themeText">
|
<Text className="themeText">
|
||||||
{ContainerCopyMessages.addManagedIdentity.description} 
|
{t(Keys.containerCopy.addManagedIdentity.description)} 
|
||||||
<Link href={ContainerCopyMessages.addManagedIdentity.descriptionHref} target="_blank" rel="noopener noreferrer">
|
<Link href={t(Keys.containerCopy.addManagedIdentity.descriptionHref)} target="_blank" rel="noopener noreferrer">
|
||||||
{ContainerCopyMessages.addManagedIdentity.descriptionHrefText}
|
{t(Keys.containerCopy.addManagedIdentity.descriptionHrefText)}
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
|
|
||||||
<InfoTooltip content={managedIdentityTooltip} />
|
<InfoTooltip content={managedIdentityTooltip} />
|
||||||
</Text>
|
</Text>
|
||||||
<Toggle
|
<Toggle data-test="btn-toggle" checked={systemAssigned} onText="On" offText="Off" onChange={onToggle} />
|
||||||
data-test="btn-toggle"
|
|
||||||
checked={systemAssigned}
|
|
||||||
onText={ContainerCopyMessages.toggleBtn.onText}
|
|
||||||
offText={ContainerCopyMessages.toggleBtn.offText}
|
|
||||||
onChange={onToggle}
|
|
||||||
/>
|
|
||||||
<PopoverMessage
|
<PopoverMessage
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
visible={systemAssigned}
|
visible={systemAssigned}
|
||||||
title={ContainerCopyMessages.addManagedIdentity.enablementTitle}
|
title={t(Keys.containerCopy.addManagedIdentity.enablementTitle)}
|
||||||
onCancel={() => onToggle(null, false)}
|
onCancel={() => onToggle(null, false)}
|
||||||
onPrimary={handleAddSystemIdentity}
|
onPrimary={handleAddSystemIdentity}
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.addManagedIdentity.enablementDescription(copyJobState.target?.account?.name)}
|
{copyJobState.target?.account?.name
|
||||||
|
? t(Keys.containerCopy.addManagedIdentity.enablementDescription, {
|
||||||
|
accountName: copyJobState.target?.account?.name,
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
</PopoverMessage>
|
</PopoverMessage>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
+4
-4
@@ -1,7 +1,7 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { CopyJobContextProviderType } from "../../../Types/CopyJobTypes";
|
import { CopyJobContextProviderType } from "../../../Types/CopyJobTypes";
|
||||||
import AddReadPermissionToDefaultIdentity from "./AddReadPermissionToDefaultIdentity";
|
import AddReadPermissionToDefaultIdentity from "./AddReadPermissionToDefaultIdentity";
|
||||||
@@ -180,7 +180,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
|
|||||||
describe("Component Structure", () => {
|
describe("Component Structure", () => {
|
||||||
it("should display the description text", () => {
|
it("should display the description text", () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
expect(screen.getByText(ContainerCopyMessages.readPermissionAssigned.description)).toBeInTheDocument();
|
expect(screen.getByText(t(Keys.containerCopy.readPermissionAssigned.description))).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should display the info tooltip", () => {
|
it("should display the info tooltip", () => {
|
||||||
@@ -212,10 +212,10 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
|
|||||||
|
|
||||||
expect(screen.getByTestId("popover-message")).toBeInTheDocument();
|
expect(screen.getByTestId("popover-message")).toBeInTheDocument();
|
||||||
expect(screen.getByTestId("popover-title")).toHaveTextContent(
|
expect(screen.getByTestId("popover-title")).toHaveTextContent(
|
||||||
ContainerCopyMessages.readPermissionAssigned.popoverTitle,
|
t(Keys.containerCopy.readPermissionAssigned.popoverTitle),
|
||||||
);
|
);
|
||||||
expect(screen.getByTestId("popover-content")).toHaveTextContent(
|
expect(screen.getByTestId("popover-content")).toHaveTextContent(
|
||||||
ContainerCopyMessages.readPermissionAssigned.popoverDescription,
|
t(Keys.containerCopy.readPermissionAssigned.popoverDescription),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -1,8 +1,8 @@
|
|||||||
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { logError } from "../../../../../Common/Logger";
|
import { logError } from "../../../../../Common/Logger";
|
||||||
import { assignRole } from "../../../../../Utils/arm/RbacUtils";
|
import { assignRole } from "../../../../../Utils/arm/RbacUtils";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
||||||
import InfoTooltip from "../Components/InfoTooltip";
|
import InfoTooltip from "../Components/InfoTooltip";
|
||||||
@@ -12,14 +12,14 @@ import useToggle from "./hooks/useToggle";
|
|||||||
|
|
||||||
const TooltipContent = (
|
const TooltipContent = (
|
||||||
<Text>
|
<Text>
|
||||||
{ContainerCopyMessages.readPermissionAssigned.tooltip.content}
|
{t(Keys.containerCopy.readPermissionAssigned.tooltipContent)}
|
||||||
<Link
|
<Link
|
||||||
style={{ color: "var(--colorBrandForeground1)" }}
|
style={{ color: "var(--colorBrandForeground1)" }}
|
||||||
href={ContainerCopyMessages.readPermissionAssigned.tooltip.href}
|
href={t(Keys.containerCopy.readPermissionAssigned.tooltipHref)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.readPermissionAssigned.tooltip.hrefText}
|
{t(Keys.containerCopy.readPermissionAssigned.tooltipHrefText)}
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -66,14 +66,14 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
|
|||||||
return (
|
return (
|
||||||
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||||
<Text className="toggle-label">
|
<Text className="toggle-label">
|
||||||
{ContainerCopyMessages.readPermissionAssigned.description} 
|
{t(Keys.containerCopy.readPermissionAssigned.description)} 
|
||||||
<InfoTooltip content={TooltipContent} />
|
<InfoTooltip content={TooltipContent} />
|
||||||
</Text>
|
</Text>
|
||||||
<Toggle
|
<Toggle
|
||||||
data-test="btn-toggle"
|
data-test="btn-toggle"
|
||||||
checked={readPermissionAssigned}
|
checked={readPermissionAssigned}
|
||||||
onText={ContainerCopyMessages.toggleBtn.onText}
|
onText="On"
|
||||||
offText={ContainerCopyMessages.toggleBtn.offText}
|
offText="Off"
|
||||||
onChange={onToggle}
|
onChange={onToggle}
|
||||||
inlineLabel
|
inlineLabel
|
||||||
styles={{
|
styles={{
|
||||||
@@ -84,11 +84,11 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
|
|||||||
<PopoverMessage
|
<PopoverMessage
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
visible={readPermissionAssigned}
|
visible={readPermissionAssigned}
|
||||||
title={ContainerCopyMessages.readPermissionAssigned.popoverTitle}
|
title={t(Keys.containerCopy.readPermissionAssigned.popoverTitle)}
|
||||||
onCancel={() => onToggle(null, false)}
|
onCancel={() => onToggle(null, false)}
|
||||||
onPrimary={handleAddReadPermission}
|
onPrimary={handleAddReadPermission}
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.readPermissionAssigned.popoverDescription}
|
{t(Keys.containerCopy.readPermissionAssigned.popoverDescription)}
|
||||||
</PopoverMessage>
|
</PopoverMessage>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
+5
-3
@@ -1,7 +1,7 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { render, RenderResult } from "@testing-library/react";
|
import { render, RenderResult } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
||||||
import { CopyJobContextProviderType, CopyJobContextState } from "../../../Types/CopyJobTypes";
|
import { CopyJobContextProviderType, CopyJobContextState } from "../../../Types/CopyJobTypes";
|
||||||
@@ -154,7 +154,7 @@ describe("AssignPermissions Component", () => {
|
|||||||
const copyJobState = createMockCopyJobState();
|
const copyJobState = createMockCopyJobState();
|
||||||
const { getByText } = renderWithContext(copyJobState);
|
const { getByText } = renderWithContext(copyJobState);
|
||||||
|
|
||||||
expect(getByText(ContainerCopyMessages.assignPermissions.crossAccountDescription)).toBeInTheDocument();
|
expect(getByText(t(Keys.containerCopy.assignPermissions.crossAccountDescription))).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should display intra account description for same accounts with online migration", async () => {
|
it("should display intra account description for same accounts with online migration", async () => {
|
||||||
@@ -179,7 +179,9 @@ describe("AssignPermissions Component", () => {
|
|||||||
|
|
||||||
const { getByText } = renderWithContext(copyJobState);
|
const { getByText } = renderWithContext(copyJobState);
|
||||||
expect(
|
expect(
|
||||||
getByText(ContainerCopyMessages.assignPermissions.intraAccountOnlineDescription("Same Account")),
|
getByText(
|
||||||
|
t(Keys.containerCopy.assignPermissions.intraAccountOnlineDescription, { accountName: "Same Account" }),
|
||||||
|
),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+5
-5
@@ -4,7 +4,7 @@ import React, { useEffect } from "react";
|
|||||||
import CheckmarkIcon from "../../../../../../images/successfulPopup.svg";
|
import CheckmarkIcon from "../../../../../../images/successfulPopup.svg";
|
||||||
import WarningIcon from "../../../../../../images/warning.svg";
|
import WarningIcon from "../../../../../../images/warning.svg";
|
||||||
import ShimmerTree, { IndentLevel } from "../../../../../Common/ShimmerTree/ShimmerTree";
|
import ShimmerTree, { IndentLevel } from "../../../../../Common/ShimmerTree/ShimmerTree";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { isIntraAccountCopy } from "../../../CopyJobUtils";
|
import { isIntraAccountCopy } from "../../../CopyJobUtils";
|
||||||
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
||||||
@@ -107,10 +107,10 @@ const AssignPermissions = () => {
|
|||||||
>
|
>
|
||||||
<Text variant="medium" style={{ color: "var(--colorNeutralForeground1)" }}>
|
<Text variant="medium" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||||
{isSameAccount && copyJobState.migrationType === CopyJobMigrationType.Online
|
{isSameAccount && copyJobState.migrationType === CopyJobMigrationType.Online
|
||||||
? ContainerCopyMessages.assignPermissions.intraAccountOnlineDescription(
|
? t(Keys.containerCopy.assignPermissions.intraAccountOnlineDescription, {
|
||||||
copyJobState?.source?.account?.name || "",
|
accountName: copyJobState?.source?.account?.name || "",
|
||||||
)
|
})
|
||||||
: ContainerCopyMessages.assignPermissions.crossAccountDescription}
|
: t(Keys.containerCopy.assignPermissions.crossAccountDescription)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{totalSectionsCount === 0 ? (
|
{totalSectionsCount === 0 ? (
|
||||||
|
|||||||
+9
-9
@@ -1,8 +1,8 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen } from "@testing-library/react";
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { updateDefaultIdentity } from "../../../../../Utils/arm/identityUtils";
|
import { updateDefaultIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import DefaultManagedIdentity from "./DefaultManagedIdentity";
|
import DefaultManagedIdentity from "./DefaultManagedIdentity";
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ describe("DefaultManagedIdentity", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const description = screen.getByText(
|
const description = screen.getByText(
|
||||||
/Set the system-assigned managed identity as default for "test-cosmos-account"/,
|
t(Keys.containerCopy.defaultManagedIdentity.description, { accountName: "test-cosmos-account" }),
|
||||||
);
|
);
|
||||||
expect(description).toBeInTheDocument();
|
expect(description).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@@ -127,8 +127,8 @@ describe("DefaultManagedIdentity", () => {
|
|||||||
|
|
||||||
const tooltip = screen.getByTestId("info-tooltip");
|
const tooltip = screen.getByTestId("info-tooltip");
|
||||||
expect(tooltip).toBeInTheDocument();
|
expect(tooltip).toBeInTheDocument();
|
||||||
expect(tooltip).toHaveTextContent("Learn more about");
|
expect(tooltip).toHaveTextContent(t(Keys.containerCopy.defaultManagedIdentity.tooltipContent));
|
||||||
expect(tooltip).toHaveTextContent("Default Managed Identities.");
|
expect(tooltip).toHaveTextContent(t(Keys.containerCopy.defaultManagedIdentity.tooltipHrefText));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the toggle button with correct initial state", () => {
|
it("should render the toggle button with correct initial state", () => {
|
||||||
@@ -166,11 +166,11 @@ describe("DefaultManagedIdentity", () => {
|
|||||||
expect(popover).toBeInTheDocument();
|
expect(popover).toBeInTheDocument();
|
||||||
|
|
||||||
const title = screen.getByTestId("popover-title");
|
const title = screen.getByTestId("popover-title");
|
||||||
expect(title).toHaveTextContent(ContainerCopyMessages.defaultManagedIdentity.popoverTitle);
|
expect(title).toHaveTextContent(t(Keys.containerCopy.defaultManagedIdentity.popoverTitle));
|
||||||
|
|
||||||
const content = screen.getByTestId("popover-content");
|
const content = screen.getByTestId("popover-content");
|
||||||
expect(content).toHaveTextContent(
|
expect(content).toHaveTextContent(
|
||||||
/Assign the system-assigned managed identity as the default for "test-cosmos-account"/,
|
t(Keys.containerCopy.defaultManagedIdentity.popoverDescription, { accountName: "test-cosmos-account" }).trim(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -339,8 +339,8 @@ describe("DefaultManagedIdentity", () => {
|
|||||||
it("should display correct toggle button text", () => {
|
it("should display correct toggle button text", () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const onText = screen.queryByText(ContainerCopyMessages.toggleBtn.onText);
|
const onText = screen.queryByText("On");
|
||||||
const offText = screen.queryByText(ContainerCopyMessages.toggleBtn.offText);
|
const offText = screen.queryByText("Off");
|
||||||
|
|
||||||
expect(onText || offText).toBeTruthy();
|
expect(onText || offText).toBeTruthy();
|
||||||
});
|
});
|
||||||
@@ -348,7 +348,7 @@ describe("DefaultManagedIdentity", () => {
|
|||||||
it("should display correct link text in tooltip", () => {
|
it("should display correct link text in tooltip", () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const linkText = screen.getByText(ContainerCopyMessages.defaultManagedIdentity.tooltip.hrefText);
|
const linkText = screen.getByText(t(Keys.containerCopy.defaultManagedIdentity.tooltipHrefText));
|
||||||
expect(linkText).toBeInTheDocument();
|
expect(linkText).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+12
-9
@@ -1,7 +1,7 @@
|
|||||||
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { updateDefaultIdentity } from "../../../../../Utils/arm/identityUtils";
|
import { updateDefaultIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import InfoTooltip from "../Components/InfoTooltip";
|
import InfoTooltip from "../Components/InfoTooltip";
|
||||||
import PopoverMessage from "../Components/PopoverContainer";
|
import PopoverMessage from "../Components/PopoverContainer";
|
||||||
@@ -11,14 +11,14 @@ import useToggle from "./hooks/useToggle";
|
|||||||
|
|
||||||
const managedIdentityTooltip = (
|
const managedIdentityTooltip = (
|
||||||
<Text>
|
<Text>
|
||||||
{ContainerCopyMessages.defaultManagedIdentity.tooltip.content}
|
{t(Keys.containerCopy.defaultManagedIdentity.tooltipContent)}
|
||||||
<Link
|
<Link
|
||||||
style={{ color: "var(--colorBrandForeground1)" }}
|
style={{ color: "var(--colorBrandForeground1)" }}
|
||||||
href={ContainerCopyMessages.defaultManagedIdentity.tooltip.href}
|
href={t(Keys.containerCopy.defaultManagedIdentity.tooltipHref)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.defaultManagedIdentity.tooltip.hrefText}
|
{t(Keys.containerCopy.defaultManagedIdentity.tooltipHrefText)}
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -32,14 +32,15 @@ const DefaultManagedIdentity: React.FC<AddManagedIdentityProps> = () => {
|
|||||||
return (
|
return (
|
||||||
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||||
<div className="toggle-label">
|
<div className="toggle-label">
|
||||||
{ContainerCopyMessages.defaultManagedIdentity.description(copyJobState?.target?.account?.name)}
|
{t(Keys.containerCopy.defaultManagedIdentity.description, { accountName: copyJobState?.target?.account?.name })}{" "}
|
||||||
|
|
||||||
<InfoTooltip content={managedIdentityTooltip} />
|
<InfoTooltip content={managedIdentityTooltip} />
|
||||||
</div>
|
</div>
|
||||||
<Toggle
|
<Toggle
|
||||||
data-test="btn-toggle"
|
data-test="btn-toggle"
|
||||||
checked={defaultSystemAssigned}
|
checked={defaultSystemAssigned}
|
||||||
onText={ContainerCopyMessages.toggleBtn.onText}
|
onText={t(Keys.common.on)}
|
||||||
offText={ContainerCopyMessages.toggleBtn.offText}
|
offText={t(Keys.common.off)}
|
||||||
onChange={onToggle}
|
onChange={onToggle}
|
||||||
inlineLabel
|
inlineLabel
|
||||||
styles={{
|
styles={{
|
||||||
@@ -50,11 +51,13 @@ const DefaultManagedIdentity: React.FC<AddManagedIdentityProps> = () => {
|
|||||||
<PopoverMessage
|
<PopoverMessage
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
visible={defaultSystemAssigned}
|
visible={defaultSystemAssigned}
|
||||||
title={ContainerCopyMessages.defaultManagedIdentity.popoverTitle}
|
title={t(Keys.containerCopy.defaultManagedIdentity.popoverTitle)}
|
||||||
onCancel={() => onToggle(null, false)}
|
onCancel={() => onToggle(null, false)}
|
||||||
onPrimary={handleAddSystemIdentity}
|
onPrimary={handleAddSystemIdentity}
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.defaultManagedIdentity.popoverDescription(copyJobState?.target?.account?.name)}
|
{t(Keys.containerCopy.defaultManagedIdentity.popoverDescription, {
|
||||||
|
accountName: copyJobState?.target?.account?.name,
|
||||||
|
})}
|
||||||
</PopoverMessage>
|
</PopoverMessage>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
+25
-21
@@ -2,12 +2,12 @@ import "@testing-library/jest-dom";
|
|||||||
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||||
import { DatabaseAccount } from "Contracts/DataModels";
|
import { DatabaseAccount } from "Contracts/DataModels";
|
||||||
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
||||||
import { CapabilityNames } from "../../../../../Common/Constants";
|
import { CapabilityNames } from "../../../../../Common/Constants";
|
||||||
import { logError } from "../../../../../Common/Logger";
|
import { logError } from "../../../../../Common/Logger";
|
||||||
import { update as updateDatabaseAccount } from "../../../../../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
import { update as updateDatabaseAccount } from "../../../../../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import OnlineCopyEnabled from "./OnlineCopyEnabled";
|
import OnlineCopyEnabled from "./OnlineCopyEnabled";
|
||||||
|
|
||||||
@@ -97,7 +97,9 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
it("should render the description with account name", () => {
|
it("should render the description with account name", () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const description = screen.getByText(ContainerCopyMessages.onlineCopyEnabled.description("test-account"));
|
const description = screen.getByText(
|
||||||
|
t(Keys.containerCopy.onlineCopyEnabled.description, { accountName: "test-account" }),
|
||||||
|
);
|
||||||
expect(description).toBeInTheDocument();
|
expect(description).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,10 +107,10 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const link = screen.getByRole("link", {
|
const link = screen.getByRole("link", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.hrefText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.hrefText),
|
||||||
});
|
});
|
||||||
expect(link).toBeInTheDocument();
|
expect(link).toBeInTheDocument();
|
||||||
expect(link).toHaveAttribute("href", ContainerCopyMessages.onlineCopyEnabled.href);
|
expect(link).toHaveAttribute("href", t(Keys.containerCopy.onlineCopyEnabled.href));
|
||||||
expect(link).toHaveAttribute("target", "_blank");
|
expect(link).toHaveAttribute("target", "_blank");
|
||||||
expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
||||||
});
|
});
|
||||||
@@ -117,7 +119,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const button = screen.getByRole("button", {
|
const button = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
expect(button).toBeInTheDocument();
|
expect(button).toBeInTheDocument();
|
||||||
expect(button).not.toBeDisabled();
|
expect(button).not.toBeDisabled();
|
||||||
@@ -134,7 +136,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const refreshButton = screen.queryByRole("button", {
|
const refreshButton = screen.queryByRole("button", {
|
||||||
name: ContainerCopyMessages.refreshButtonLabel,
|
name: "Refresh",
|
||||||
});
|
});
|
||||||
expect(refreshButton).not.toBeInTheDocument();
|
expect(refreshButton).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@@ -167,7 +169,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -222,7 +224,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -246,7 +248,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -259,7 +261,9 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(
|
expect(
|
||||||
screen.getByText(ContainerCopyMessages.onlineCopyEnabled.enablingOnlineCopySpinnerLabel("test-account")),
|
screen.getByText(
|
||||||
|
t(Keys.containerCopy.onlineCopyEnabled.enablingOnlineCopySpinnerLabel, { accountName: "test-account" }),
|
||||||
|
),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -272,7 +276,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -306,7 +310,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -318,7 +322,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const refreshButton = screen.getByRole("button", {
|
const refreshButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.refreshButtonLabel,
|
name: "Refresh",
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -349,7 +353,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -379,7 +383,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -401,7 +405,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -418,7 +422,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -436,7 +440,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -450,7 +454,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
mockFetchDatabaseAccount.mockImplementation(() => new Promise(() => {}));
|
mockFetchDatabaseAccount.mockImplementation(() => new Promise(() => {}));
|
||||||
|
|
||||||
const refreshButton = screen.getByRole("button", {
|
const refreshButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.refreshButtonLabel,
|
name: "Refresh",
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -536,7 +540,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent(contextWithNoCapabilities);
|
renderComponent(contextWithNoCapabilities);
|
||||||
|
|
||||||
const enableButton = screen.getByRole("button", {
|
const enableButton = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
expect(enableButton).toBeInTheDocument();
|
expect(enableButton).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@@ -547,7 +551,7 @@ describe("OnlineCopyEnabled", () => {
|
|||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const button = screen.getByRole("button", {
|
const button = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||||
});
|
});
|
||||||
expect(button).toBeInTheDocument();
|
expect(button).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|||||||
+11
-9
@@ -1,12 +1,12 @@
|
|||||||
import { Link, PrimaryButton, Stack } from "@fluentui/react";
|
import { Link, PrimaryButton, Stack } from "@fluentui/react";
|
||||||
import { DatabaseAccount } from "Contracts/DataModels";
|
import { DatabaseAccount } from "Contracts/DataModels";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
||||||
import { CapabilityNames } from "../../../../../Common/Constants";
|
import { CapabilityNames } from "../../../../../Common/Constants";
|
||||||
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
||||||
import { logError } from "../../../../../Common/Logger";
|
import { logError } from "../../../../../Common/Logger";
|
||||||
import { update as updateDatabaseAccount } from "../../../../../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
import { update as updateDatabaseAccount } from "../../../../../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
||||||
import { AccountValidatorFn } from "../../../Types/CopyJobTypes";
|
import { AccountValidatorFn } from "../../../Types/CopyJobTypes";
|
||||||
@@ -76,21 +76,23 @@ const OnlineCopyEnabled: React.FC = () => {
|
|||||||
setShowRefreshButton(false);
|
setShowRefreshButton(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel);
|
setLoaderMessage(t(Keys.containerCopy.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel));
|
||||||
const sourAccountBeforeUpdate = await fetchDatabaseAccount(
|
const sourAccountBeforeUpdate = await fetchDatabaseAccount(
|
||||||
sourceSubscriptionId,
|
sourceSubscriptionId,
|
||||||
sourceResourceGroup,
|
sourceResourceGroup,
|
||||||
sourceAccountName,
|
sourceAccountName,
|
||||||
);
|
);
|
||||||
if (!sourAccountBeforeUpdate?.properties.enableAllVersionsAndDeletesChangeFeed) {
|
if (!sourAccountBeforeUpdate?.properties.enableAllVersionsAndDeletesChangeFeed) {
|
||||||
setLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel);
|
setLoaderMessage(t(Keys.containerCopy.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel));
|
||||||
await updateDatabaseAccount(sourceSubscriptionId, sourceResourceGroup, sourceAccountName, {
|
await updateDatabaseAccount(sourceSubscriptionId, sourceResourceGroup, sourceAccountName, {
|
||||||
properties: {
|
properties: {
|
||||||
enableAllVersionsAndDeletesChangeFeed: true,
|
enableAllVersionsAndDeletesChangeFeed: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.enablingOnlineCopySpinnerLabel(sourceAccountName));
|
setLoaderMessage(
|
||||||
|
t(Keys.containerCopy.onlineCopyEnabled.enablingOnlineCopySpinnerLabel, { accountName: sourceAccountName }),
|
||||||
|
);
|
||||||
await updateDatabaseAccount(sourceSubscriptionId, sourceResourceGroup, sourceAccountName, {
|
await updateDatabaseAccount(sourceSubscriptionId, sourceResourceGroup, sourceAccountName, {
|
||||||
properties: {
|
properties: {
|
||||||
capabilities: [...sourceAccountCapabilities, { name: CapabilityNames.EnableOnlineCopyFeature }],
|
capabilities: [...sourceAccountCapabilities, { name: CapabilityNames.EnableOnlineCopyFeature }],
|
||||||
@@ -132,16 +134,16 @@ const OnlineCopyEnabled: React.FC = () => {
|
|||||||
<Stack className="onlineCopyContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
<Stack className="onlineCopyContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||||
<LoadingOverlay isLoading={loading} label={loaderMessage} />
|
<LoadingOverlay isLoading={loading} label={loaderMessage} />
|
||||||
<Stack.Item className="info-message">
|
<Stack.Item className="info-message">
|
||||||
{ContainerCopyMessages.onlineCopyEnabled.description(source?.account?.name || "")} 
|
{t(Keys.containerCopy.onlineCopyEnabled.description, { accountName: source?.account?.name || "" })} 
|
||||||
<Link href={ContainerCopyMessages.onlineCopyEnabled.href} target="_blank" rel="noopener noreferrer">
|
<Link href={t(Keys.containerCopy.onlineCopyEnabled.href)} target="_blank" rel="noopener noreferrer">
|
||||||
{ContainerCopyMessages.onlineCopyEnabled.hrefText}
|
{t(Keys.containerCopy.onlineCopyEnabled.hrefText)}
|
||||||
</Link>
|
</Link>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item>
|
<Stack.Item>
|
||||||
{showRefreshButton ? (
|
{showRefreshButton ? (
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
className="fullWidth"
|
className="fullWidth"
|
||||||
text={ContainerCopyMessages.refreshButtonLabel}
|
text={t(Keys.common.refresh)}
|
||||||
iconProps={{ iconName: "Refresh" }}
|
iconProps={{ iconName: "Refresh" }}
|
||||||
onClick={handleRefresh}
|
onClick={handleRefresh}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
@@ -149,7 +151,7 @@ const OnlineCopyEnabled: React.FC = () => {
|
|||||||
) : (
|
) : (
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
className="fullWidth"
|
className="fullWidth"
|
||||||
text={loading ? "" : ContainerCopyMessages.onlineCopyEnabled.buttonText}
|
text={loading ? "" : t(Keys.containerCopy.onlineCopyEnabled.buttonText)}
|
||||||
{...(loading ? { iconProps: { iconName: "SyncStatusSolid" } } : {})}
|
{...(loading ? { iconProps: { iconName: "SyncStatusSolid" } } : {})}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={handleOnlineCopyEnable}
|
onClick={handleOnlineCopyEnable}
|
||||||
|
|||||||
+8
-8
@@ -1,10 +1,10 @@
|
|||||||
import { Link, PrimaryButton, Stack, Text } from "@fluentui/react";
|
import { Link, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||||
import { DatabaseAccount } from "Contracts/DataModels";
|
import { DatabaseAccount } from "Contracts/DataModels";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
||||||
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
||||||
import { logError } from "../../../../../Common/Logger";
|
import { logError } from "../../../../../Common/Logger";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { buildResourceLink, getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
import { buildResourceLink, getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
||||||
import { AccountValidatorFn } from "../../../Types/CopyJobTypes";
|
import { AccountValidatorFn } from "../../../Types/CopyJobTypes";
|
||||||
@@ -12,14 +12,14 @@ import InfoTooltip from "../Components/InfoTooltip";
|
|||||||
|
|
||||||
const tooltipContent = (
|
const tooltipContent = (
|
||||||
<Text>
|
<Text>
|
||||||
{ContainerCopyMessages.pointInTimeRestore.tooltip.content}
|
{t(Keys.containerCopy.pointInTimeRestore.tooltipContent)}
|
||||||
<Link
|
<Link
|
||||||
style={{ color: "var(--colorBrandForeground1)" }}
|
style={{ color: "var(--colorBrandForeground1)" }}
|
||||||
href={ContainerCopyMessages.pointInTimeRestore.tooltip.href}
|
href={t(Keys.containerCopy.pointInTimeRestore.tooltipHref)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.pointInTimeRestore.tooltip.hrefText}
|
{t(Keys.containerCopy.pointInTimeRestore.tooltipHrefText)}
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
@@ -119,9 +119,9 @@ const PointInTimeRestore: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className="pointInTimeRestoreContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
<Stack className="pointInTimeRestoreContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||||
<LoadingOverlay isLoading={loading} label={ContainerCopyMessages.popoverOverlaySpinnerLabel} />
|
<LoadingOverlay isLoading={loading} label={t(Keys.containerCopy.popoverOverlaySpinnerLabel)} />
|
||||||
<Stack.Item className="toggle-label">
|
<Stack.Item className="toggle-label">
|
||||||
{ContainerCopyMessages.pointInTimeRestore.description(source.account?.name ?? "")}
|
{t(Keys.containerCopy.pointInTimeRestore.description, { accessName: source.account?.name ?? "" })}
|
||||||
{tooltipContent && (
|
{tooltipContent && (
|
||||||
<>
|
<>
|
||||||
{" "}
|
{" "}
|
||||||
@@ -134,7 +134,7 @@ const PointInTimeRestore: React.FC = () => {
|
|||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
data-test="pointInTimeRestore:RefreshBtn"
|
data-test="pointInTimeRestore:RefreshBtn"
|
||||||
className="fullWidth"
|
className="fullWidth"
|
||||||
text={ContainerCopyMessages.refreshButtonLabel}
|
text={t(Keys.common.refresh)}
|
||||||
iconProps={{ iconName: "Refresh" }}
|
iconProps={{ iconName: "Refresh" }}
|
||||||
onClick={handleRefresh}
|
onClick={handleRefresh}
|
||||||
/>
|
/>
|
||||||
@@ -142,7 +142,7 @@ const PointInTimeRestore: React.FC = () => {
|
|||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
data-test="pointInTimeRestore:PrimaryBtn"
|
data-test="pointInTimeRestore:PrimaryBtn"
|
||||||
className="fullWidth"
|
className="fullWidth"
|
||||||
text={loading ? "" : ContainerCopyMessages.pointInTimeRestore.buttonText}
|
text={loading ? "" : t(Keys.containerCopy.pointInTimeRestore.buttonText)}
|
||||||
{...(loading ? { iconProps: { iconName: "SyncStatusSolid" } } : {})}
|
{...(loading ? { iconProps: { iconName: "SyncStatusSolid" } } : {})}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={openWindowAndMonitor}
|
onClick={openWindowAndMonitor}
|
||||||
|
|||||||
+3
-3
@@ -7,7 +7,7 @@ exports[`AddManagedIdentity Snapshot Tests renders initial state correctly 1`] =
|
|||||||
<span
|
<span
|
||||||
class="themeText css-110"
|
class="themeText css-110"
|
||||||
>
|
>
|
||||||
A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don’t have to store any credentials in code.
|
A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don't have to store any credentials in code.
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="ms-Link root-111"
|
class="ms-Link root-111"
|
||||||
@@ -95,7 +95,7 @@ exports[`AddManagedIdentity Snapshot Tests renders loading state 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="themeText css-110"
|
class="themeText css-110"
|
||||||
>
|
>
|
||||||
A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don’t have to store any credentials in code.
|
A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don't have to store any credentials in code.
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="ms-Link root-111"
|
class="ms-Link root-111"
|
||||||
@@ -267,7 +267,7 @@ exports[`AddManagedIdentity Snapshot Tests renders with toggle on and popover vi
|
|||||||
<span
|
<span
|
||||||
class="themeText css-110"
|
class="themeText css-110"
|
||||||
>
|
>
|
||||||
A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don’t have to store any credentials in code.
|
A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don't have to store any credentials in code.
|
||||||
|
|
||||||
<a
|
<a
|
||||||
class="ms-Link root-111"
|
class="ms-Link root-111"
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@ exports[`DefaultManagedIdentity Edge Cases should handle null account 1`] = `
|
|||||||
<div
|
<div
|
||||||
class="toggle-label"
|
class="toggle-label"
|
||||||
>
|
>
|
||||||
Set the system-assigned managed identity as default for "undefined" by switching it on.
|
Set the system-assigned managed identity as default for "" by switching it on.
|
||||||
|
|
||||||
<div
|
<div
|
||||||
data-testid="info-tooltip"
|
data-testid="info-tooltip"
|
||||||
|
|||||||
+15
-13
@@ -1,7 +1,7 @@
|
|||||||
|
import { Keys, t } from "Localization";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { CapabilityNames } from "../../../../../../Common/Constants";
|
import { CapabilityNames } from "../../../../../../Common/Constants";
|
||||||
import { fetchRoleAssignments, fetchRoleDefinitions, RoleDefinitionType } from "../../../../../../Utils/arm/RbacUtils";
|
import { fetchRoleAssignments, fetchRoleDefinitions, RoleDefinitionType } from "../../../../../../Utils/arm/RbacUtils";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { getAccountDetailsFromResourceId, getContainerIdentifiers, isIntraAccountCopy } from "../../../../CopyJobUtils";
|
import { getAccountDetailsFromResourceId, getContainerIdentifiers, isIntraAccountCopy } from "../../../../CopyJobUtils";
|
||||||
import {
|
import {
|
||||||
BackupPolicyType,
|
BackupPolicyType,
|
||||||
@@ -44,7 +44,7 @@ export const SECTION_IDS = {
|
|||||||
const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
||||||
{
|
{
|
||||||
id: SECTION_IDS.addManagedIdentity,
|
id: SECTION_IDS.addManagedIdentity,
|
||||||
title: ContainerCopyMessages.addManagedIdentity.title,
|
title: t(Keys.containerCopy.addManagedIdentity.title),
|
||||||
Component: AddManagedIdentity,
|
Component: AddManagedIdentity,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
validate: (state: CopyJobContextState) => {
|
validate: (state: CopyJobContextState) => {
|
||||||
@@ -57,7 +57,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: SECTION_IDS.defaultManagedIdentity,
|
id: SECTION_IDS.defaultManagedIdentity,
|
||||||
title: ContainerCopyMessages.defaultManagedIdentity.title,
|
title: t(Keys.containerCopy.defaultManagedIdentity.title),
|
||||||
Component: DefaultManagedIdentity,
|
Component: DefaultManagedIdentity,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
validate: (state: CopyJobContextState) => {
|
validate: (state: CopyJobContextState) => {
|
||||||
@@ -67,7 +67,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: SECTION_IDS.readPermissionAssigned,
|
id: SECTION_IDS.readPermissionAssigned,
|
||||||
title: ContainerCopyMessages.readPermissionAssigned.title,
|
title: t(Keys.containerCopy.readPermissionAssigned.title),
|
||||||
Component: AddReadPermissionToDefaultIdentity,
|
Component: AddReadPermissionToDefaultIdentity,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
validate: async (state: CopyJobContextState) => {
|
validate: async (state: CopyJobContextState) => {
|
||||||
@@ -95,7 +95,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
|||||||
const PERMISSION_SECTIONS_FOR_ONLINE_JOBS: PermissionSectionConfig[] = [
|
const PERMISSION_SECTIONS_FOR_ONLINE_JOBS: PermissionSectionConfig[] = [
|
||||||
{
|
{
|
||||||
id: SECTION_IDS.pointInTimeRestore,
|
id: SECTION_IDS.pointInTimeRestore,
|
||||||
title: ContainerCopyMessages.pointInTimeRestore.title,
|
title: t(Keys.containerCopy.pointInTimeRestore.title),
|
||||||
Component: PointInTimeRestore,
|
Component: PointInTimeRestore,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
validate: (state: CopyJobContextState) => {
|
validate: (state: CopyJobContextState) => {
|
||||||
@@ -105,7 +105,7 @@ const PERMISSION_SECTIONS_FOR_ONLINE_JOBS: PermissionSectionConfig[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: SECTION_IDS.onlineCopyEnabled,
|
id: SECTION_IDS.onlineCopyEnabled,
|
||||||
title: ContainerCopyMessages.onlineCopyEnabled.title,
|
title: t(Keys.containerCopy.onlineCopyEnabled.title),
|
||||||
Component: OnlineCopyEnabled,
|
Component: OnlineCopyEnabled,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
validate: (state: CopyJobContextState) => {
|
validate: (state: CopyJobContextState) => {
|
||||||
@@ -194,11 +194,11 @@ const usePermissionSections = (state: CopyJobContextState): PermissionGroupConfi
|
|||||||
if (crossAccountSections.length > 0) {
|
if (crossAccountSections.length > 0) {
|
||||||
groups.push({
|
groups.push({
|
||||||
id: "crossAccountConfigs",
|
id: "crossAccountConfigs",
|
||||||
title: ContainerCopyMessages.assignPermissions.crossAccountConfiguration.title,
|
title: t(Keys.containerCopy.assignPermissions.crossAccountConfiguration.title),
|
||||||
description: ContainerCopyMessages.assignPermissions.crossAccountConfiguration.description(
|
description: t(Keys.containerCopy.assignPermissions.crossAccountConfiguration.description, {
|
||||||
sourceAccountName,
|
sourceAccount: sourceAccountName,
|
||||||
targetAccountName,
|
destinationAccount: targetAccountName,
|
||||||
),
|
}),
|
||||||
sections: crossAccountSections,
|
sections: crossAccountSections,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -206,8 +206,10 @@ const usePermissionSections = (state: CopyJobContextState): PermissionGroupConfi
|
|||||||
if (state.migrationType === CopyJobMigrationType.Online) {
|
if (state.migrationType === CopyJobMigrationType.Online) {
|
||||||
groups.push({
|
groups.push({
|
||||||
id: "onlineConfigs",
|
id: "onlineConfigs",
|
||||||
title: ContainerCopyMessages.assignPermissions.onlineConfiguration.title,
|
title: t(Keys.containerCopy.assignPermissions.onlineConfiguration.title),
|
||||||
description: ContainerCopyMessages.assignPermissions.onlineConfiguration.description(sourceAccountName),
|
description: t(Keys.containerCopy.assignPermissions.onlineConfiguration.description, {
|
||||||
|
accountName: sourceAccountName,
|
||||||
|
}),
|
||||||
sections: [...PERMISSION_SECTIONS_FOR_ONLINE_JOBS],
|
sections: [...PERMISSION_SECTIONS_FOR_ONLINE_JOBS],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen } from "@testing-library/react";
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import PopoverMessage from "./PopoverContainer";
|
import PopoverMessage from "./PopoverContainer";
|
||||||
|
|
||||||
jest.mock("../../../../../Common/LoadingOverlay", () => {
|
jest.mock("../../../../../Common/LoadingOverlay", () => {
|
||||||
@@ -181,7 +181,7 @@ describe("PopoverMessage Component", () => {
|
|||||||
it("should use correct loading overlay label", () => {
|
it("should use correct loading overlay label", () => {
|
||||||
render(<PopoverMessage {...defaultProps} isLoading={true} />);
|
render(<PopoverMessage {...defaultProps} isLoading={true} />);
|
||||||
const loadingOverlay = screen.getByTestId("loading-overlay");
|
const loadingOverlay = screen.getByTestId("loading-overlay");
|
||||||
expect(loadingOverlay).toHaveAttribute("aria-label", ContainerCopyMessages.popoverOverlaySpinnerLabel);
|
expect(loadingOverlay).toHaveAttribute("aria-label", t(Keys.containerCopy.popoverOverlaySpinnerLabel));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
import { DefaultButton, PrimaryButton, Stack, Text } from "@fluentui/react";
|
import { DefaultButton, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
|
|
||||||
interface PopoverContainerProps {
|
interface PopoverContainerProps {
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
@@ -22,7 +22,7 @@ const PopoverContainer: React.FC<PopoverContainerProps> = React.memo(
|
|||||||
tokens={{ childrenGap: 20 }}
|
tokens={{ childrenGap: 20 }}
|
||||||
style={{ maxWidth: 450 }}
|
style={{ maxWidth: 450 }}
|
||||||
>
|
>
|
||||||
<LoadingOverlay isLoading={isLoading} label={ContainerCopyMessages.popoverOverlaySpinnerLabel} />
|
<LoadingOverlay isLoading={isLoading} label={t(Keys.containerCopy.popoverOverlaySpinnerLabel)} />
|
||||||
<Text variant="mediumPlus" className="themeText" style={{ fontWeight: 600 }}>
|
<Text variant="mediumPlus" className="themeText" style={{ fontWeight: 600 }}>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
+7
-7
@@ -4,8 +4,8 @@ import { CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums"
|
|||||||
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
import { useSidePanel } from "hooks/useSidePanel";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import AddCollectionPanelWrapper from "./AddCollectionPanelWrapper";
|
import AddCollectionPanelWrapper from "./AddCollectionPanelWrapper";
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ describe("AddCollectionPanelWrapper", () => {
|
|||||||
expect(container.querySelector(".addCollectionPanelWrapper")).toBeInTheDocument();
|
expect(container.querySelector(".addCollectionPanelWrapper")).toBeInTheDocument();
|
||||||
expect(container.querySelector(".addCollectionPanelHeader")).toBeInTheDocument();
|
expect(container.querySelector(".addCollectionPanelHeader")).toBeInTheDocument();
|
||||||
expect(container.querySelector(".addCollectionPanelBody")).toBeInTheDocument();
|
expect(container.querySelector(".addCollectionPanelBody")).toBeInTheDocument();
|
||||||
expect(screen.getByText(ContainerCopyMessages.createNewContainerSubHeading)).toBeInTheDocument();
|
expect(screen.getByText(t(Keys.containerCopy.selectContainers.createNewContainerSubHeading))).toBeInTheDocument();
|
||||||
expect(screen.getByTestId("add-collection-panel")).toBeInTheDocument();
|
expect(screen.getByTestId("add-collection-panel")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ describe("AddCollectionPanelWrapper", () => {
|
|||||||
it("should set header text to create container heading on mount", () => {
|
it("should set header text to create container heading on mount", () => {
|
||||||
render(<AddCollectionPanelWrapper />);
|
render(<AddCollectionPanelWrapper />);
|
||||||
|
|
||||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createContainerHeading);
|
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.selectContainers.createContainerHeading));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should reset header text to create copy job panel title on unmount", () => {
|
it("should reset header text to create copy job panel title on unmount", () => {
|
||||||
@@ -146,13 +146,13 @@ describe("AddCollectionPanelWrapper", () => {
|
|||||||
|
|
||||||
unmount();
|
unmount();
|
||||||
|
|
||||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createCopyJobPanelTitle);
|
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.createCopyJob.panelTitle));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not change header text if already set correctly", () => {
|
it("should not change header text if already set correctly", () => {
|
||||||
const modifiedSidePanelState = {
|
const modifiedSidePanelState = {
|
||||||
...mockSidePanelState,
|
...mockSidePanelState,
|
||||||
headerText: ContainerCopyMessages.createContainerHeading,
|
headerText: t(Keys.containerCopy.selectContainers.createContainerHeading),
|
||||||
};
|
};
|
||||||
|
|
||||||
mockUseSidePanel.getState = jest.fn().mockReturnValue(modifiedSidePanelState);
|
mockUseSidePanel.getState = jest.fn().mockReturnValue(modifiedSidePanelState);
|
||||||
@@ -245,10 +245,10 @@ describe("AddCollectionPanelWrapper", () => {
|
|||||||
describe("Component Lifecycle", () => {
|
describe("Component Lifecycle", () => {
|
||||||
it("should properly cleanup on unmount", () => {
|
it("should properly cleanup on unmount", () => {
|
||||||
const { unmount } = render(<AddCollectionPanelWrapper />);
|
const { unmount } = render(<AddCollectionPanelWrapper />);
|
||||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createContainerHeading);
|
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.selectContainers.createContainerHeading));
|
||||||
mockSetHeaderText.mockClear();
|
mockSetHeaderText.mockClear();
|
||||||
unmount();
|
unmount();
|
||||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createCopyJobPanelTitle);
|
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.createCopyJob.panelTitle));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should re-render correctly when props change", () => {
|
it("should re-render correctly when props change", () => {
|
||||||
|
|||||||
+5
-5
@@ -2,9 +2,9 @@ import { Stack, Text } from "@fluentui/react";
|
|||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
import { useSidePanel } from "hooks/useSidePanel";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React, { useCallback, useEffect } from "react";
|
import React, { useCallback, useEffect } from "react";
|
||||||
import { AddCollectionPanel } from "../../../../Panes/AddCollectionPanel/AddCollectionPanel";
|
import { AddCollectionPanel } from "../../../../Panes/AddCollectionPanel/AddCollectionPanel";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
|
|
||||||
type AddCollectionPanelWrapperProps = {
|
type AddCollectionPanelWrapperProps = {
|
||||||
@@ -17,11 +17,11 @@ const AddCollectionPanelWrapper: React.FunctionComponent<AddCollectionPanelWrapp
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const sidePanelStore = useSidePanel.getState();
|
const sidePanelStore = useSidePanel.getState();
|
||||||
if (sidePanelStore.headerText !== ContainerCopyMessages.createContainerHeading) {
|
if (sidePanelStore.headerText !== t(Keys.containerCopy.selectContainers.createContainerHeading)) {
|
||||||
sidePanelStore.setHeaderText(ContainerCopyMessages.createContainerHeading);
|
sidePanelStore.setHeaderText(t(Keys.containerCopy.selectContainers.createContainerHeading));
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
sidePanelStore.setHeaderText(ContainerCopyMessages.createCopyJobPanelTitle);
|
sidePanelStore.setHeaderText(t(Keys.containerCopy.createCopyJob.panelTitle));
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ const AddCollectionPanelWrapper: React.FunctionComponent<AddCollectionPanelWrapp
|
|||||||
return (
|
return (
|
||||||
<Stack className="addCollectionPanelWrapper">
|
<Stack className="addCollectionPanelWrapper">
|
||||||
<Stack.Item className="addCollectionPanelHeader">
|
<Stack.Item className="addCollectionPanelHeader">
|
||||||
<Text className="themeText">{ContainerCopyMessages.createNewContainerSubHeading}</Text>
|
<Text className="themeText">{t(Keys.containerCopy.selectContainers.createNewContainerSubHeading)}</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item className="addCollectionPanelBody">
|
<Stack.Item className="addCollectionPanelBody">
|
||||||
<AddCollectionPanel explorer={explorer} isCopyJobFlow={true} onSubmitSuccess={handleAddCollectionSuccess} />
|
<AddCollectionPanel explorer={explorer} isCopyJobFlow={true} onSubmitSuccess={handleAddCollectionSuccess} />
|
||||||
|
|||||||
+5
-4
@@ -1,6 +1,7 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, waitFor } from "@testing-library/react";
|
import { fireEvent, render, waitFor } from "@testing-library/react";
|
||||||
import { Subscription } from "Contracts/DataModels";
|
import { Subscription } from "Contracts/DataModels";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
||||||
@@ -350,7 +351,7 @@ describe("PreviewCopyJob", () => {
|
|||||||
expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function));
|
expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should display proper field labels from ContainerCopyMessages", () => {
|
it("should display proper field labels", () => {
|
||||||
const mockContext = createMockContext();
|
const mockContext = createMockContext();
|
||||||
|
|
||||||
const { getByText } = render(
|
const { getByText } = render(
|
||||||
@@ -359,8 +360,8 @@ describe("PreviewCopyJob", () => {
|
|||||||
</CopyJobContext.Provider>,
|
</CopyJobContext.Provider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(getByText(/Job name/i)).toBeInTheDocument();
|
expect(getByText(new RegExp(t(Keys.containerCopy.preview.jobNameLabel), "i"))).toBeInTheDocument();
|
||||||
expect(getByText(/Source subscription/i)).toBeInTheDocument();
|
expect(getByText(new RegExp(t(Keys.containerCopy.preview.sourceSubscriptionLabel), "i"))).toBeInTheDocument();
|
||||||
expect(getByText(/Source account/i)).toBeInTheDocument();
|
expect(getByText(new RegExp(t(Keys.containerCopy.preview.sourceAccountLabel), "i"))).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DetailsList, DetailsListLayoutMode, Stack, Text, TextField } from "@fluentui/react";
|
import { DetailsList, DetailsListLayoutMode, Stack, Text, TextField } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { getDefaultJobName } from "../../../CopyJobUtils";
|
import { getDefaultJobName } from "../../../CopyJobUtils";
|
||||||
import FieldRow from "../Components/FieldRow";
|
import FieldRow from "../Components/FieldRow";
|
||||||
@@ -32,17 +32,17 @@ const PreviewCopyJob: React.FC = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Stack tokens={{ childrenGap: 20 }} className="previewCopyJobContainer" data-test="Panel:PreviewCopyJob">
|
<Stack tokens={{ childrenGap: 20 }} className="previewCopyJobContainer" data-test="Panel:PreviewCopyJob">
|
||||||
<FieldRow label={ContainerCopyMessages.jobNameLabel}>
|
<FieldRow label={t(Keys.containerCopy.preview.jobNameLabel)}>
|
||||||
<TextField data-test="job-name-textfield" value={jobName} onChange={onJobNameChange} />
|
<TextField data-test="job-name-textfield" value={jobName} onChange={onJobNameChange} />
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text className="bold themeText">{ContainerCopyMessages.sourceSubscriptionLabel}</Text>
|
<Text className="bold themeText">{t(Keys.containerCopy.preview.sourceSubscriptionLabel)}</Text>
|
||||||
<Text data-test="source-subscription-name" className="themeText">
|
<Text data-test="source-subscription-name" className="themeText">
|
||||||
{copyJobState.source?.subscription?.displayName}
|
{copyJobState.source?.subscription?.displayName}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text className="bold themeText">{ContainerCopyMessages.sourceAccountLabel}</Text>
|
<Text className="bold themeText">{t(Keys.containerCopy.preview.sourceAccountLabel)}</Text>
|
||||||
<Text data-test="source-account-name" className="themeText">
|
<Text data-test="source-account-name" className="themeText">
|
||||||
{copyJobState.source?.account?.name}
|
{copyJobState.source?.account?.name}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
import { IColumn } from "@fluentui/react";
|
import { IColumn } from "@fluentui/react";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
|
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
@@ -17,25 +17,25 @@ export const getPreviewCopyJobDetailsListColumns = (): IColumn[] => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "sourcedbname",
|
key: "sourcedbname",
|
||||||
name: ContainerCopyMessages.sourceDatabaseLabel,
|
name: t(Keys.containerCopy.preview.sourceDatabaseLabel),
|
||||||
fieldName: "sourceDatabaseName",
|
fieldName: "sourceDatabaseName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "sourcecolname",
|
key: "sourcecolname",
|
||||||
name: ContainerCopyMessages.sourceContainerLabel,
|
name: t(Keys.containerCopy.preview.sourceContainerLabel),
|
||||||
fieldName: "sourceContainerName",
|
fieldName: "sourceContainerName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "targetdbname",
|
key: "targetdbname",
|
||||||
name: ContainerCopyMessages.targetDatabaseLabel,
|
name: t(Keys.containerCopy.preview.targetDatabaseLabel),
|
||||||
fieldName: "targetDatabaseName",
|
fieldName: "targetDatabaseName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "targetcolname",
|
key: "targetcolname",
|
||||||
name: ContainerCopyMessages.targetContainerLabel,
|
name: t(Keys.containerCopy.preview.targetContainerLabel),
|
||||||
fieldName: "targetContainerName",
|
fieldName: "targetContainerName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
|
|||||||
+4
-4
@@ -1,11 +1,11 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { configContext, Platform } from "../../../../../../ConfigContext";
|
import { configContext, Platform } from "../../../../../../ConfigContext";
|
||||||
import { DatabaseAccount } from "../../../../../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../../../../../Contracts/DataModels";
|
||||||
import * as useDatabaseAccountsHook from "../../../../../../hooks/useDatabaseAccounts";
|
import * as useDatabaseAccountsHook from "../../../../../../hooks/useDatabaseAccounts";
|
||||||
import { apiType, userContext } from "../../../../../../UserContext";
|
import { apiType, userContext } from "../../../../../../UserContext";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobContext } from "../../../../Context/CopyJobContext";
|
import { CopyJobContext } from "../../../../Context/CopyJobContext";
|
||||||
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
||||||
import { CopyJobContextProviderType, CopyJobContextState } from "../../../../Types/CopyJobTypes";
|
import { CopyJobContextProviderType, CopyJobContextState } from "../../../../Types/CopyJobTypes";
|
||||||
@@ -129,11 +129,11 @@ describe("AccountDropdown", () => {
|
|||||||
renderWithContext();
|
renderWithContext();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByText(`${ContainerCopyMessages.sourceAccountDropdownLabel}:`, { exact: true }),
|
screen.getByText(`${t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel)}:`, { exact: true }),
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(screen.getByRole("combobox")).toHaveAttribute(
|
expect(screen.getByRole("combobox")).toHaveAttribute(
|
||||||
"aria-label",
|
"aria-label",
|
||||||
ContainerCopyMessages.sourceAccountDropdownLabel,
|
t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -409,7 +409,7 @@ describe("AccountDropdown", () => {
|
|||||||
renderWithContext();
|
renderWithContext();
|
||||||
|
|
||||||
const dropdown = screen.getByRole("combobox");
|
const dropdown = screen.getByRole("combobox");
|
||||||
expect(dropdown).toHaveAttribute("aria-label", ContainerCopyMessages.sourceAccountDropdownLabel);
|
expect(dropdown).toHaveAttribute("aria-label", t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have required attribute", () => {
|
it("should have required attribute", () => {
|
||||||
|
|||||||
+4
-4
@@ -2,11 +2,11 @@
|
|||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
import { Dropdown } from "@fluentui/react";
|
import { Dropdown } from "@fluentui/react";
|
||||||
import { configContext, Platform } from "ConfigContext";
|
import { configContext, Platform } from "ConfigContext";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { DatabaseAccount } from "../../../../../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../../../../../Contracts/DataModels";
|
||||||
import { useDatabaseAccounts } from "../../../../../../hooks/useDatabaseAccounts";
|
import { useDatabaseAccounts } from "../../../../../../hooks/useDatabaseAccounts";
|
||||||
import { apiType, userContext } from "../../../../../../UserContext";
|
import { apiType, userContext } from "../../../../../../UserContext";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
||||||
import FieldRow from "../../Components/FieldRow";
|
import FieldRow from "../../Components/FieldRow";
|
||||||
|
|
||||||
@@ -80,10 +80,10 @@ export const AccountDropdown: React.FC<AccountDropdownProps> = () => {
|
|||||||
const selectedAccountId = normalizeAccountId(copyJobState?.source?.account?.id ?? "");
|
const selectedAccountId = normalizeAccountId(copyJobState?.source?.account?.id ?? "");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldRow label={ContainerCopyMessages.sourceAccountDropdownLabel}>
|
<FieldRow label={t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel)}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placeholder={ContainerCopyMessages.sourceAccountDropdownPlaceholder}
|
placeholder={t(Keys.containerCopy.selectAccount.sourceAccountDropdownPlaceholder)}
|
||||||
ariaLabel={ContainerCopyMessages.sourceAccountDropdownLabel}
|
ariaLabel={t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel)}
|
||||||
options={accountOptions}
|
options={accountOptions}
|
||||||
disabled={isAccountDropdownDisabled}
|
disabled={isAccountDropdownDisabled}
|
||||||
required
|
required
|
||||||
|
|||||||
+13
-17
@@ -1,7 +1,7 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen } from "@testing-library/react";
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
||||||
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
||||||
import { MigrationType } from "./MigrationType";
|
import { MigrationType } from "./MigrationType";
|
||||||
@@ -53,9 +53,9 @@ describe("MigrationType", () => {
|
|||||||
expect(screen.getByRole("radiogroup")).toBeInTheDocument();
|
expect(screen.getByRole("radiogroup")).toBeInTheDocument();
|
||||||
|
|
||||||
const offlineRadio = screen.getByRole("radio", {
|
const offlineRadio = screen.getByRole("radio", {
|
||||||
name: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
name: t(Keys.containerCopy.migrationType.offline.title),
|
||||||
});
|
});
|
||||||
const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title });
|
const onlineRadio = screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) });
|
||||||
|
|
||||||
expect(offlineRadio).toBeInTheDocument();
|
expect(offlineRadio).toBeInTheDocument();
|
||||||
expect(onlineRadio).toBeInTheDocument();
|
expect(onlineRadio).toBeInTheDocument();
|
||||||
@@ -65,9 +65,9 @@ describe("MigrationType", () => {
|
|||||||
it("should render with online mode selected by default", () => {
|
it("should render with online mode selected by default", () => {
|
||||||
render(<MigrationType />);
|
render(<MigrationType />);
|
||||||
|
|
||||||
const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title });
|
const onlineRadio = screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) });
|
||||||
const offlineRadio = screen.getByRole("radio", {
|
const offlineRadio = screen.getByRole("radio", {
|
||||||
name: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
name: t(Keys.containerCopy.migrationType.offline.title),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(onlineRadio).toBeChecked();
|
expect(onlineRadio).toBeChecked();
|
||||||
@@ -86,9 +86,9 @@ describe("MigrationType", () => {
|
|||||||
render(<MigrationType />);
|
render(<MigrationType />);
|
||||||
|
|
||||||
const offlineRadio = screen.getByRole("radio", {
|
const offlineRadio = screen.getByRole("radio", {
|
||||||
name: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
name: t(Keys.containerCopy.migrationType.offline.title),
|
||||||
});
|
});
|
||||||
const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title });
|
const onlineRadio = screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) });
|
||||||
|
|
||||||
expect(offlineRadio).toBeChecked();
|
expect(offlineRadio).toBeChecked();
|
||||||
expect(onlineRadio).not.toBeChecked();
|
expect(onlineRadio).not.toBeChecked();
|
||||||
@@ -141,7 +141,7 @@ describe("MigrationType", () => {
|
|||||||
render(<MigrationType />);
|
render(<MigrationType />);
|
||||||
|
|
||||||
const offlineRadio = screen.getByRole("radio", {
|
const offlineRadio = screen.getByRole("radio", {
|
||||||
name: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
name: t(Keys.containerCopy.migrationType.offline.title),
|
||||||
});
|
});
|
||||||
fireEvent.click(offlineRadio);
|
fireEvent.click(offlineRadio);
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ describe("MigrationType", () => {
|
|||||||
|
|
||||||
render(<MigrationType />);
|
render(<MigrationType />);
|
||||||
|
|
||||||
const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title });
|
const onlineRadio = screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) });
|
||||||
fireEvent.click(onlineRadio);
|
fireEvent.click(onlineRadio);
|
||||||
|
|
||||||
expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function));
|
expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function));
|
||||||
@@ -198,11 +198,9 @@ describe("MigrationType", () => {
|
|||||||
render(<MigrationType />);
|
render(<MigrationType />);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.offline.title }),
|
screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.offline.title) }),
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }),
|
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -220,11 +218,9 @@ describe("MigrationType", () => {
|
|||||||
|
|
||||||
expect(container.querySelector("[data-test='migration-type']")).toBeInTheDocument();
|
expect(container.querySelector("[data-test='migration-type']")).toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.offline.title }),
|
screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.offline.title) }),
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }),
|
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle null copyJobState gracefully", () => {
|
it("should handle null copyJobState gracefully", () => {
|
||||||
|
|||||||
+6
-6
@@ -3,20 +3,20 @@
|
|||||||
import { ChoiceGroup, IChoiceGroupOption, Stack, Text } from "@fluentui/react";
|
import { ChoiceGroup, IChoiceGroupOption, Stack, Text } from "@fluentui/react";
|
||||||
import MarkdownRender from "@nteract/markdown";
|
import MarkdownRender from "@nteract/markdown";
|
||||||
import { useCopyJobContext } from "Explorer/ContainerCopy/Context/CopyJobContext";
|
import { useCopyJobContext } from "Explorer/ContainerCopy/Context/CopyJobContext";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
||||||
|
|
||||||
interface MigrationTypeProps {}
|
interface MigrationTypeProps {}
|
||||||
const options: IChoiceGroupOption[] = [
|
const options: IChoiceGroupOption[] = [
|
||||||
{
|
{
|
||||||
key: CopyJobMigrationType.Offline,
|
key: CopyJobMigrationType.Offline,
|
||||||
text: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
text: t(Keys.containerCopy.migrationType.offline.title),
|
||||||
styles: { root: { width: "33%" } },
|
styles: { root: { width: "33%" } },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: CopyJobMigrationType.Online,
|
key: CopyJobMigrationType.Online,
|
||||||
text: ContainerCopyMessages.migrationTypeOptions.online.title,
|
text: t(Keys.containerCopy.migrationType.online.title),
|
||||||
styles: { root: { width: "33%" } },
|
styles: { root: { width: "33%" } },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -47,8 +47,8 @@ export const MigrationType: React.FC<MigrationTypeProps> = React.memo(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selectedKey = copyJobState?.migrationType ?? "";
|
const selectedKey = copyJobState?.migrationType ?? "";
|
||||||
const selectedKeyLowercase = selectedKey.toLowerCase() as keyof typeof ContainerCopyMessages.migrationTypeOptions;
|
const selectedKeyLowercase = selectedKey.toLowerCase() as keyof typeof Keys.containerCopy.migrationType;
|
||||||
const selectedKeyContent = ContainerCopyMessages.migrationTypeOptions[selectedKeyLowercase];
|
const selectedKeyContent = Keys.containerCopy.migrationType[selectedKeyLowercase];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack data-test="migration-type" className="migrationTypeContainer">
|
<Stack data-test="migration-type" className="migrationTypeContainer">
|
||||||
@@ -68,7 +68,7 @@ export const MigrationType: React.FC<MigrationTypeProps> = React.memo(() => {
|
|||||||
className="migrationTypeDescription"
|
className="migrationTypeDescription"
|
||||||
data-test={`migration-type-description-${selectedKeyLowercase}`}
|
data-test={`migration-type-description-${selectedKeyLowercase}`}
|
||||||
>
|
>
|
||||||
<MarkdownRender source={selectedKeyContent.description} linkTarget="_blank" />
|
<MarkdownRender source={t(selectedKeyContent.description)} linkTarget="_blank" />
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
)}
|
)}
|
||||||
|
|||||||
-5
@@ -8,14 +8,9 @@ import { SubscriptionDropdown } from "./SubscriptionDropdown";
|
|||||||
|
|
||||||
jest.mock("../../../../../../hooks/useSubscriptions");
|
jest.mock("../../../../../../hooks/useSubscriptions");
|
||||||
jest.mock("../../../../../../UserContext");
|
jest.mock("../../../../../../UserContext");
|
||||||
jest.mock("../../../../ContainerCopyMessages");
|
|
||||||
|
|
||||||
const mockUseSubscriptions = jest.requireMock("../../../../../../hooks/useSubscriptions").useSubscriptions;
|
const mockUseSubscriptions = jest.requireMock("../../../../../../hooks/useSubscriptions").useSubscriptions;
|
||||||
const mockUserContext = jest.requireMock("../../../../../../UserContext").userContext;
|
const mockUserContext = jest.requireMock("../../../../../../UserContext").userContext;
|
||||||
const mockContainerCopyMessages = jest.requireMock("../../../../ContainerCopyMessages").default;
|
|
||||||
|
|
||||||
mockContainerCopyMessages.subscriptionDropdownLabel = "Subscription";
|
|
||||||
mockContainerCopyMessages.subscriptionDropdownPlaceholder = "Select a subscription";
|
|
||||||
|
|
||||||
describe("SubscriptionDropdown", () => {
|
describe("SubscriptionDropdown", () => {
|
||||||
let mockExplorer: Explorer;
|
let mockExplorer: Explorer;
|
||||||
|
|||||||
+4
-4
@@ -1,11 +1,11 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
import { Dropdown } from "@fluentui/react";
|
import { Dropdown } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Subscription } from "../../../../../../Contracts/DataModels";
|
import { Subscription } from "../../../../../../Contracts/DataModels";
|
||||||
import { useSubscriptions } from "../../../../../../hooks/useSubscriptions";
|
import { useSubscriptions } from "../../../../../../hooks/useSubscriptions";
|
||||||
import { userContext } from "../../../../../../UserContext";
|
import { userContext } from "../../../../../../UserContext";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
||||||
import FieldRow from "../../Components/FieldRow";
|
import FieldRow from "../../Components/FieldRow";
|
||||||
|
|
||||||
@@ -64,10 +64,10 @@ export const SubscriptionDropdown: React.FC<SubscriptionDropdownProps> = React.m
|
|||||||
const selectedSubscriptionId = copyJobState?.source?.subscription?.subscriptionId;
|
const selectedSubscriptionId = copyJobState?.source?.subscription?.subscriptionId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldRow label={ContainerCopyMessages.subscriptionDropdownLabel}>
|
<FieldRow label={t(Keys.containerCopy.selectAccount.subscriptionDropdownLabel)}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placeholder={ContainerCopyMessages.subscriptionDropdownPlaceholder}
|
placeholder={t(Keys.containerCopy.selectAccount.subscriptionDropdownPlaceholder)}
|
||||||
ariaLabel={ContainerCopyMessages.subscriptionDropdownLabel}
|
ariaLabel={t(Keys.containerCopy.selectAccount.subscriptionDropdownLabel)}
|
||||||
data-test="subscription-dropdown"
|
data-test="subscription-dropdown"
|
||||||
options={subscriptionOptions}
|
options={subscriptionOptions}
|
||||||
required
|
required
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Stack, Text } from "@fluentui/react";
|
import { Stack, Text } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { AccountDropdown } from "./Components/AccountDropdown";
|
import { AccountDropdown } from "./Components/AccountDropdown";
|
||||||
import { MigrationType } from "./Components/MigrationType";
|
import { MigrationType } from "./Components/MigrationType";
|
||||||
import { SubscriptionDropdown } from "./Components/SubscriptionDropdown";
|
import { SubscriptionDropdown } from "./Components/SubscriptionDropdown";
|
||||||
@@ -8,7 +8,7 @@ import { SubscriptionDropdown } from "./Components/SubscriptionDropdown";
|
|||||||
const SelectAccount = React.memo(() => {
|
const SelectAccount = React.memo(() => {
|
||||||
return (
|
return (
|
||||||
<Stack data-test="Panel:SelectAccountContainer" className="selectAccountContainer" tokens={{ childrenGap: 15 }}>
|
<Stack data-test="Panel:SelectAccountContainer" className="selectAccountContainer" tokens={{ childrenGap: 15 }}>
|
||||||
<Text className="themeText">{ContainerCopyMessages.selectAccountDescription}</Text>
|
<Text className="themeText">{t(Keys.containerCopy.selectAccount.description)}</Text>
|
||||||
|
|
||||||
<SubscriptionDropdown />
|
<SubscriptionDropdown />
|
||||||
|
|
||||||
|
|||||||
+25
-25
@@ -1,5 +1,6 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { render, screen } from "@testing-library/react";
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import { DatabaseModel } from "Contracts/DataModels";
|
import { DatabaseModel } from "Contracts/DataModels";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Explorer from "../../../../../Explorer/Explorer";
|
import Explorer from "../../../../../Explorer/Explorer";
|
||||||
@@ -15,15 +16,6 @@ jest.mock("../../../../../hooks/useDataContainers", () => ({
|
|||||||
useDataContainers: jest.fn(),
|
useDataContainers: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock("../../../ContainerCopyMessages", () => ({
|
|
||||||
__esModule: true,
|
|
||||||
default: {
|
|
||||||
selectSourceAndTargetContainersDescription: "Select source and target containers for migration",
|
|
||||||
sourceContainerSubHeading: "Source Container",
|
|
||||||
targetContainerSubHeading: "Target Container",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock("./Events/DropDownChangeHandler", () => ({
|
jest.mock("./Events/DropDownChangeHandler", () => ({
|
||||||
dropDownChangeHandler: jest.fn(() => () => jest.fn()),
|
dropDownChangeHandler: jest.fn(() => () => jest.fn()),
|
||||||
}));
|
}));
|
||||||
@@ -124,22 +116,26 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
describe("Component Rendering", () => {
|
describe("Component Rendering", () => {
|
||||||
it("should render without crashing", () => {
|
it("should render without crashing", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
expect(screen.getByText("Select source and target containers for migration")).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText("Please select a source container and a destination container to copy to."),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render description text", () => {
|
it("should render description text", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
expect(screen.getByText("Select source and target containers for migration")).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText("Please select a source container and a destination container to copy to."),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render source container section", () => {
|
it("should render source container section", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render target container section", () => {
|
it("should render target container section", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return null when source is not available", () => {
|
it("should return null when source is not available", () => {
|
||||||
@@ -238,14 +234,14 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
describe("Component Props", () => {
|
describe("Component Props", () => {
|
||||||
it("should pass showAddCollectionPanel to DatabaseContainerSection", () => {
|
it("should pass showAddCollectionPanel to DatabaseContainerSection", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers showAddCollectionPanel={mockShowAddCollectionPanel} />);
|
renderWithContext(<SelectSourceAndTargetContainers showAddCollectionPanel={mockShowAddCollectionPanel} />);
|
||||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render without showAddCollectionPanel prop", () => {
|
it("should render without showAddCollectionPanel prop", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
|
|
||||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -310,13 +306,13 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
it("should pass correct props to source DatabaseContainerSection", () => {
|
it("should pass correct props to source DatabaseContainerSection", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
|
|
||||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should pass correct props to target DatabaseContainerSection", () => {
|
it("should pass correct props to target DatabaseContainerSection", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers showAddCollectionPanel={mockShowAddCollectionPanel} />);
|
renderWithContext(<SelectSourceAndTargetContainers showAddCollectionPanel={mockShowAddCollectionPanel} />);
|
||||||
|
|
||||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should disable source container dropdown when no database is selected", () => {
|
it("should disable source container dropdown when no database is selected", () => {
|
||||||
@@ -329,7 +325,7 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
} as ReturnType<typeof useSourceAndTargetData>);
|
} as ReturnType<typeof useSourceAndTargetData>);
|
||||||
|
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should disable target container dropdown when no database is selected", () => {
|
it("should disable target container dropdown when no database is selected", () => {
|
||||||
@@ -342,7 +338,7 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
} as ReturnType<typeof useSourceAndTargetData>);
|
} as ReturnType<typeof useSourceAndTargetData>);
|
||||||
|
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -353,7 +349,9 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
|
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
|
|
||||||
expect(screen.getByText("Select source and target containers for migration")).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText("Please select a source container and a destination container to copy to."),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle hooks throwing errors gracefully", () => {
|
it("should handle hooks throwing errors gracefully", () => {
|
||||||
@@ -421,7 +419,9 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
it("should apply correct spacing tokens", () => {
|
it("should apply correct spacing tokens", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
|
|
||||||
expect(screen.getByText("Select source and target containers for migration")).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText("Please select a source container and a destination container to copy to."),
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -429,9 +429,9 @@ describe("SelectSourceAndTargetContainers", () => {
|
|||||||
it("should render description, source section, and target section in correct order", () => {
|
it("should render description, source section, and target section in correct order", () => {
|
||||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||||
|
|
||||||
const description = screen.getByText("Select source and target containers for migration");
|
const description = screen.getByText("Please select a source container and a destination container to copy to.");
|
||||||
const sourceSection = screen.getByText("Source Container");
|
const sourceSection = screen.getByText("Source container");
|
||||||
const targetSection = screen.getByText("Target Container");
|
const targetSection = screen.getByText("Destination container");
|
||||||
|
|
||||||
expect(description).toBeInTheDocument();
|
expect(description).toBeInTheDocument();
|
||||||
expect(sourceSection).toBeInTheDocument();
|
expect(sourceSection).toBeInTheDocument();
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
import { Stack } from "@fluentui/react";
|
import { Stack } from "@fluentui/react";
|
||||||
import { DatabaseModel } from "Contracts/DataModels";
|
import { DatabaseModel } from "Contracts/DataModels";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useDatabases } from "../../../../../hooks/useDatabases";
|
import { useDatabases } from "../../../../../hooks/useDatabases";
|
||||||
import { useDataContainers } from "../../../../../hooks/useDataContainers";
|
import { useDataContainers } from "../../../../../hooks/useDataContainers";
|
||||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
|
||||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||||
import { DatabaseContainerSection } from "./components/DatabaseContainerSection";
|
import { DatabaseContainerSection } from "./components/DatabaseContainerSection";
|
||||||
import { dropDownChangeHandler } from "./Events/DropDownChangeHandler";
|
import { dropDownChangeHandler } from "./Events/DropDownChangeHandler";
|
||||||
@@ -52,9 +52,9 @@ const SelectSourceAndTargetContainers = ({ showAddCollectionPanel }: SelectSourc
|
|||||||
className="selectSourceAndTargetContainers"
|
className="selectSourceAndTargetContainers"
|
||||||
tokens={{ childrenGap: 25 }}
|
tokens={{ childrenGap: 25 }}
|
||||||
>
|
>
|
||||||
<span className="themeText">{ContainerCopyMessages.selectSourceAndTargetContainersDescription}</span>
|
<span className="themeText">{t(Keys.containerCopy.selectContainers.description)}</span>
|
||||||
<DatabaseContainerSection
|
<DatabaseContainerSection
|
||||||
heading={ContainerCopyMessages.sourceContainerSubHeading}
|
heading={t(Keys.containerCopy.selectContainers.sourceContainerSubHeading)}
|
||||||
databaseOptions={sourceDatabaseOptions}
|
databaseOptions={sourceDatabaseOptions}
|
||||||
selectedDatabase={source?.databaseId}
|
selectedDatabase={source?.databaseId}
|
||||||
databaseDisabled={false}
|
databaseDisabled={false}
|
||||||
@@ -66,7 +66,7 @@ const SelectSourceAndTargetContainers = ({ showAddCollectionPanel }: SelectSourc
|
|||||||
sectionType="source"
|
sectionType="source"
|
||||||
/>
|
/>
|
||||||
<DatabaseContainerSection
|
<DatabaseContainerSection
|
||||||
heading={ContainerCopyMessages.targetContainerSubHeading}
|
heading={t(Keys.containerCopy.selectContainers.targetContainerSubHeading)}
|
||||||
databaseOptions={targetDatabaseOptions}
|
databaseOptions={targetDatabaseOptions}
|
||||||
selectedDatabase={target?.databaseId}
|
selectedDatabase={target?.databaseId}
|
||||||
databaseDisabled={false}
|
databaseDisabled={false}
|
||||||
|
|||||||
+53
-31
@@ -1,7 +1,7 @@
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen } from "@testing-library/react";
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { DatabaseContainerSectionProps, DropdownOptionType } from "../../../../Types/CopyJobTypes";
|
import { DatabaseContainerSectionProps, DropdownOptionType } from "../../../../Types/CopyJobTypes";
|
||||||
import { DatabaseContainerSection } from "./DatabaseContainerSection";
|
import { DatabaseContainerSection } from "./DatabaseContainerSection";
|
||||||
|
|
||||||
@@ -60,11 +60,14 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(databaseDropdown).toBeInTheDocument();
|
expect(databaseDropdown).toBeInTheDocument();
|
||||||
expect(databaseDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.databaseDropdownLabel);
|
expect(databaseDropdown).toHaveAttribute(
|
||||||
|
"aria-label",
|
||||||
|
t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
|
);
|
||||||
expect(databaseDropdown).not.toBeDisabled();
|
expect(databaseDropdown).not.toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,30 +75,35 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(containerDropdown).toBeInTheDocument();
|
expect(containerDropdown).toBeInTheDocument();
|
||||||
expect(containerDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.containerDropdownLabel);
|
expect(containerDropdown).toHaveAttribute(
|
||||||
|
"aria-label",
|
||||||
|
t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
|
);
|
||||||
expect(containerDropdown).not.toBeDisabled();
|
expect(containerDropdown).not.toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders database label correctly", () => {
|
it("renders database label correctly", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
expect(screen.getByText(`${ContainerCopyMessages.databaseDropdownLabel}:`)).toBeInTheDocument();
|
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}:`)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders container label correctly", () => {
|
it("renders container label correctly", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
expect(screen.getByText(`${ContainerCopyMessages.containerDropdownLabel}:`)).toBeInTheDocument();
|
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.containerDropdownLabel)}:`)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not render create container button when handleOnDemandCreateContainer is not provided", () => {
|
it("does not render create container button when handleOnDemandCreateContainer is not provided", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
expect(screen.queryByText(ContainerCopyMessages.createContainerButtonLabel)).not.toBeInTheDocument();
|
expect(
|
||||||
|
screen.queryByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel)),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders create container button when handleOnDemandCreateContainer is provided", () => {
|
it("renders create container button when handleOnDemandCreateContainer is provided", () => {
|
||||||
@@ -107,7 +115,7 @@ describe("DatabaseContainerSection", () => {
|
|||||||
const createButton = container.querySelector(".create-container-link-btn");
|
const createButton = container.querySelector(".create-container-link-btn");
|
||||||
|
|
||||||
expect(createButton).toBeInTheDocument();
|
expect(createButton).toBeInTheDocument();
|
||||||
expect(createButton).toHaveTextContent(ContainerCopyMessages.createContainerButtonLabel);
|
expect(createButton).toHaveTextContent(t(Keys.containerCopy.selectContainers.createContainerButtonLabel));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -121,7 +129,7 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...propsWithDisabledDatabase} />);
|
render(<DatabaseContainerSection {...propsWithDisabledDatabase} />);
|
||||||
|
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(databaseDropdown).toHaveAttribute("aria-disabled", "true");
|
expect(databaseDropdown).toHaveAttribute("aria-disabled", "true");
|
||||||
@@ -136,7 +144,7 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...propsWithDisabledContainer} />);
|
render(<DatabaseContainerSection {...propsWithDisabledContainer} />);
|
||||||
|
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(containerDropdown).toHaveAttribute("aria-disabled", "true");
|
expect(containerDropdown).toHaveAttribute("aria-disabled", "true");
|
||||||
@@ -152,10 +160,10 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...propsWithFalsyDisabled} />);
|
render(<DatabaseContainerSection {...propsWithFalsyDisabled} />);
|
||||||
|
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(databaseDropdown).not.toHaveAttribute("aria-disabled", "true");
|
expect(databaseDropdown).not.toHaveAttribute("aria-disabled", "true");
|
||||||
@@ -167,21 +175,27 @@ describe("DatabaseContainerSection", () => {
|
|||||||
it("calls databaseOnChange when database dropdown selection changes", () => {
|
it("calls databaseOnChange when database dropdown selection changes", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
fireEvent.click(databaseDropdown);
|
fireEvent.click(databaseDropdown);
|
||||||
expect(databaseDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.databaseDropdownLabel);
|
expect(databaseDropdown).toHaveAttribute(
|
||||||
|
"aria-label",
|
||||||
|
t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls containerOnChange when container dropdown selection changes", () => {
|
it("calls containerOnChange when container dropdown selection changes", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
fireEvent.click(containerDropdown);
|
fireEvent.click(containerDropdown);
|
||||||
expect(containerDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.containerDropdownLabel);
|
expect(containerDropdown).toHaveAttribute(
|
||||||
|
"aria-label",
|
||||||
|
t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls handleOnDemandCreateContainer when create container button is clicked", () => {
|
it("calls handleOnDemandCreateContainer when create container button is clicked", () => {
|
||||||
@@ -192,7 +206,7 @@ describe("DatabaseContainerSection", () => {
|
|||||||
|
|
||||||
render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
||||||
|
|
||||||
const createButton = screen.getByText(ContainerCopyMessages.createContainerButtonLabel);
|
const createButton = screen.getByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel));
|
||||||
fireEvent.click(createButton);
|
fireEvent.click(createButton);
|
||||||
|
|
||||||
expect(mockHandleOnDemandCreateContainer).toHaveBeenCalledTimes(1);
|
expect(mockHandleOnDemandCreateContainer).toHaveBeenCalledTimes(1);
|
||||||
@@ -235,10 +249,10 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...propsWithEmptyOptions} />);
|
render(<DatabaseContainerSection {...propsWithEmptyOptions} />);
|
||||||
|
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(databaseDropdown).toBeInTheDocument();
|
expect(databaseDropdown).toBeInTheDocument();
|
||||||
@@ -251,24 +265,30 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(databaseDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.databaseDropdownLabel);
|
expect(databaseDropdown).toHaveAttribute(
|
||||||
expect(containerDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.containerDropdownLabel);
|
"aria-label",
|
||||||
|
t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
|
);
|
||||||
|
expect(containerDropdown).toHaveAttribute(
|
||||||
|
"aria-label",
|
||||||
|
t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has proper required attributes for dropdowns", () => {
|
it("has proper required attributes for dropdowns", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
const databaseDropdown = screen.getByRole("combobox", {
|
const databaseDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||||
});
|
});
|
||||||
const containerDropdown = screen.getByRole("combobox", {
|
const containerDropdown = screen.getByRole("combobox", {
|
||||||
name: ContainerCopyMessages.containerDropdownLabel,
|
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(databaseDropdown).toHaveAttribute("aria-required", "true");
|
expect(databaseDropdown).toHaveAttribute("aria-required", "true");
|
||||||
@@ -278,8 +298,8 @@ describe("DatabaseContainerSection", () => {
|
|||||||
it("maintains proper label associations", () => {
|
it("maintains proper label associations", () => {
|
||||||
render(<DatabaseContainerSection {...defaultProps} />);
|
render(<DatabaseContainerSection {...defaultProps} />);
|
||||||
|
|
||||||
expect(screen.getByText(`${ContainerCopyMessages.databaseDropdownLabel}:`)).toBeInTheDocument();
|
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}:`)).toBeInTheDocument();
|
||||||
expect(screen.getByText(`${ContainerCopyMessages.containerDropdownLabel}:`)).toBeInTheDocument();
|
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.containerDropdownLabel)}:`)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -299,7 +319,9 @@ describe("DatabaseContainerSection", () => {
|
|||||||
render(<DatabaseContainerSection {...minimalProps} />);
|
render(<DatabaseContainerSection {...minimalProps} />);
|
||||||
|
|
||||||
expect(screen.getByText("Test Heading")).toBeInTheDocument();
|
expect(screen.getByText("Test Heading")).toBeInTheDocument();
|
||||||
expect(screen.queryByText(ContainerCopyMessages.createContainerButtonLabel)).not.toBeInTheDocument();
|
expect(
|
||||||
|
screen.queryByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel)),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("handles empty string selections", () => {
|
it("handles empty string selections", () => {
|
||||||
@@ -366,7 +388,7 @@ describe("DatabaseContainerSection", () => {
|
|||||||
|
|
||||||
const { container } = render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
const { container } = render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
||||||
|
|
||||||
const createButton = screen.getByText(ContainerCopyMessages.createContainerButtonLabel);
|
const createButton = screen.getByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel));
|
||||||
expect(createButton).toBeInTheDocument();
|
expect(createButton).toBeInTheDocument();
|
||||||
|
|
||||||
const containerSection = container.querySelector(".databaseContainerSection");
|
const containerSection = container.querySelector(".databaseContainerSection");
|
||||||
@@ -381,7 +403,7 @@ describe("DatabaseContainerSection", () => {
|
|||||||
|
|
||||||
render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
||||||
|
|
||||||
expect(screen.getByText(ContainerCopyMessages.createContainerButtonLabel)).toBeInTheDocument();
|
expect(screen.getByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel))).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -1,6 +1,6 @@
|
|||||||
import { ActionButton, Dropdown, Stack } from "@fluentui/react";
|
import { ActionButton, Dropdown, Stack } from "@fluentui/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
|
||||||
import { DatabaseContainerSectionProps } from "../../../../Types/CopyJobTypes";
|
import { DatabaseContainerSectionProps } from "../../../../Types/CopyJobTypes";
|
||||||
import FieldRow from "../../Components/FieldRow";
|
import FieldRow from "../../Components/FieldRow";
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ export const DatabaseContainerSection = ({
|
|||||||
}: DatabaseContainerSectionProps) => (
|
}: DatabaseContainerSectionProps) => (
|
||||||
<Stack tokens={{ childrenGap: 15 }} className="databaseContainerSection">
|
<Stack tokens={{ childrenGap: 15 }} className="databaseContainerSection">
|
||||||
<label className="subHeading">{heading}</label>
|
<label className="subHeading">{heading}</label>
|
||||||
<FieldRow label={ContainerCopyMessages.databaseDropdownLabel}>
|
<FieldRow label={t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placeholder={ContainerCopyMessages.databaseDropdownPlaceholder}
|
placeholder={t(Keys.containerCopy.selectContainers.databaseDropdownPlaceholder)}
|
||||||
ariaLabel={ContainerCopyMessages.databaseDropdownLabel}
|
ariaLabel={t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}
|
||||||
options={databaseOptions}
|
options={databaseOptions}
|
||||||
required
|
required
|
||||||
disabled={!!databaseDisabled}
|
disabled={!!databaseDisabled}
|
||||||
@@ -31,11 +31,11 @@ export const DatabaseContainerSection = ({
|
|||||||
data-test={`${sectionType}-databaseDropdown`}
|
data-test={`${sectionType}-databaseDropdown`}
|
||||||
/>
|
/>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
<FieldRow label={ContainerCopyMessages.containerDropdownLabel}>
|
<FieldRow label={t(Keys.containerCopy.selectContainers.containerDropdownLabel)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placeholder={ContainerCopyMessages.containerDropdownPlaceholder}
|
placeholder={t(Keys.containerCopy.selectContainers.containerDropdownPlaceholder)}
|
||||||
ariaLabel={ContainerCopyMessages.containerDropdownLabel}
|
ariaLabel={t(Keys.containerCopy.selectContainers.containerDropdownLabel)}
|
||||||
options={containerOptions}
|
options={containerOptions}
|
||||||
required
|
required
|
||||||
disabled={!!containerDisabled}
|
disabled={!!containerDisabled}
|
||||||
@@ -49,7 +49,7 @@ export const DatabaseContainerSection = ({
|
|||||||
style={{ color: "var(--colorBrandForeground1)" }}
|
style={{ color: "var(--colorBrandForeground1)" }}
|
||||||
onClick={() => handleOnDemandCreateContainer()}
|
onClick={() => handleOnDemandCreateContainer()}
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.createContainerButtonLabel}
|
{t(Keys.containerCopy.selectContainers.createContainerButtonLabel)}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -20,28 +20,6 @@ jest.mock("../../../Controls/Dialog", () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock("../../ContainerCopyMessages", () => ({
|
|
||||||
__esModule: true,
|
|
||||||
default: {
|
|
||||||
MonitorJobs: {
|
|
||||||
Columns: {
|
|
||||||
actions: "Actions",
|
|
||||||
},
|
|
||||||
Actions: {
|
|
||||||
pause: "Pause",
|
|
||||||
resume: "Resume",
|
|
||||||
cancel: "Cancel",
|
|
||||||
complete: "Complete",
|
|
||||||
},
|
|
||||||
dialog: {
|
|
||||||
heading: "Confirm Action",
|
|
||||||
confirmButtonText: "Confirm",
|
|
||||||
cancelButtonText: "Cancel",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("CopyJobActionMenu", () => {
|
describe("CopyJobActionMenu", () => {
|
||||||
const createMockJob = (overrides: Partial<CopyJobType> = {}): CopyJobType =>
|
const createMockJob = (overrides: Partial<CopyJobType> = {}): CopyJobType =>
|
||||||
({
|
({
|
||||||
@@ -301,7 +279,7 @@ describe("CopyJobActionMenu", () => {
|
|||||||
fireEvent.click(cancelButton);
|
fireEvent.click(cancelButton);
|
||||||
|
|
||||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||||
"Confirm Action",
|
"",
|
||||||
null,
|
null,
|
||||||
"Confirm",
|
"Confirm",
|
||||||
expect.any(Function),
|
expect.any(Function),
|
||||||
@@ -358,7 +336,7 @@ describe("CopyJobActionMenu", () => {
|
|||||||
fireEvent.click(completeButton);
|
fireEvent.click(completeButton);
|
||||||
|
|
||||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||||
"Confirm Action",
|
"",
|
||||||
null,
|
null,
|
||||||
"Confirm",
|
"Confirm",
|
||||||
expect.any(Function),
|
expect.any(Function),
|
||||||
@@ -402,7 +380,7 @@ describe("CopyJobActionMenu", () => {
|
|||||||
fireEvent.click(cancelButton);
|
fireEvent.click(cancelButton);
|
||||||
|
|
||||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||||
"Confirm Action",
|
"",
|
||||||
null,
|
null,
|
||||||
"Confirm",
|
"Confirm",
|
||||||
expect.any(Function),
|
expect.any(Function),
|
||||||
@@ -433,7 +411,7 @@ describe("CopyJobActionMenu", () => {
|
|||||||
fireEvent.click(completeButton);
|
fireEvent.click(completeButton);
|
||||||
|
|
||||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||||
"Confirm Action",
|
"",
|
||||||
null,
|
null,
|
||||||
"Confirm",
|
"Confirm",
|
||||||
expect.any(Function),
|
expect.any(Function),
|
||||||
@@ -849,7 +827,7 @@ describe("CopyJobActionMenu", () => {
|
|||||||
fireEvent.click(cancelButton);
|
fireEvent.click(cancelButton);
|
||||||
|
|
||||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||||
"Confirm Action", // title
|
"", // title
|
||||||
null, // subText
|
null, // subText
|
||||||
"Confirm", // confirmLabel
|
"Confirm", // confirmLabel
|
||||||
expect.any(Function), // onOk
|
expect.any(Function), // onOk
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { DirectionalHint, IconButton, IContextualMenuProps, Stack } from "@fluentui/react";
|
import { DirectionalHint, IconButton, IContextualMenuProps, Stack } from "@fluentui/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useDialog } from "../../../Controls/Dialog";
|
import { useDialog } from "../../../Controls/Dialog";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
import { CopyJobActions, CopyJobMigrationType, CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
import { CopyJobActions, CopyJobMigrationType, CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||||
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
||||||
|
|
||||||
@@ -49,11 +49,11 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
|||||||
useDialog
|
useDialog
|
||||||
.getState()
|
.getState()
|
||||||
.showOkCancelModalDialog(
|
.showOkCancelModalDialog(
|
||||||
ContainerCopyMessages.MonitorJobs.dialog.heading,
|
"",
|
||||||
null,
|
null,
|
||||||
ContainerCopyMessages.MonitorJobs.dialog.confirmButtonText,
|
t(Keys.common.confirm),
|
||||||
() => handleClick(job, action, setUpdatingJobAction),
|
() => handleClick(job, action, setUpdatingJobAction),
|
||||||
ContainerCopyMessages.MonitorJobs.dialog.cancelButtonText,
|
t(Keys.common.cancel),
|
||||||
null,
|
null,
|
||||||
action in dialogBody ? dialogBody[action as keyof typeof dialogBody](job.Name) : null,
|
action in dialogBody ? dialogBody[action as keyof typeof dialogBody](job.Name) : null,
|
||||||
);
|
);
|
||||||
@@ -65,21 +65,21 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
|||||||
const baseItems = [
|
const baseItems = [
|
||||||
{
|
{
|
||||||
key: CopyJobActions.pause,
|
key: CopyJobActions.pause,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.pause,
|
text: t(Keys.containerCopy.monitorJobs.actions.pause),
|
||||||
iconProps: { iconName: "Pause" },
|
iconProps: { iconName: "Pause" },
|
||||||
onClick: () => handleClick(job, CopyJobActions.pause, setUpdatingJobAction),
|
onClick: () => handleClick(job, CopyJobActions.pause, setUpdatingJobAction),
|
||||||
disabled: isThisJobUpdating,
|
disabled: isThisJobUpdating,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: CopyJobActions.cancel,
|
key: CopyJobActions.cancel,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.cancel,
|
text: t(Keys.common.cancel),
|
||||||
iconProps: { iconName: "Cancel" },
|
iconProps: { iconName: "Cancel" },
|
||||||
onClick: () => showActionConfirmationDialog(job, CopyJobActions.cancel),
|
onClick: () => showActionConfirmationDialog(job, CopyJobActions.cancel),
|
||||||
disabled: isThisJobUpdating,
|
disabled: isThisJobUpdating,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: CopyJobActions.resume,
|
key: CopyJobActions.resume,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.resume,
|
text: t(Keys.containerCopy.monitorJobs.actions.resume),
|
||||||
iconProps: { iconName: "Play" },
|
iconProps: { iconName: "Play" },
|
||||||
onClick: () => handleClick(job, CopyJobActions.resume, setUpdatingJobAction),
|
onClick: () => handleClick(job, CopyJobActions.resume, setUpdatingJobAction),
|
||||||
disabled: isThisJobUpdating,
|
disabled: isThisJobUpdating,
|
||||||
@@ -101,7 +101,7 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
|||||||
if ((job.Mode ?? "").toLowerCase() === CopyJobMigrationType.Online) {
|
if ((job.Mode ?? "").toLowerCase() === CopyJobMigrationType.Online) {
|
||||||
filteredItems.push({
|
filteredItems.push({
|
||||||
key: CopyJobActions.complete,
|
key: CopyJobActions.complete,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.complete,
|
text: t(Keys.containerCopy.monitorJobs.actions.complete),
|
||||||
iconProps: { iconName: "CheckMark" },
|
iconProps: { iconName: "CheckMark" },
|
||||||
onClick: () => showActionConfirmationDialog(job, CopyJobActions.complete),
|
onClick: () => showActionConfirmationDialog(job, CopyJobActions.complete),
|
||||||
disabled: isThisJobUpdating,
|
disabled: isThisJobUpdating,
|
||||||
@@ -124,8 +124,8 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
|||||||
iconProps={{ iconName: "More", styles: { root: { fontSize: "20px", fontWeight: "bold" } } }}
|
iconProps={{ iconName: "More", styles: { root: { fontSize: "20px", fontWeight: "bold" } } }}
|
||||||
menuProps={{ items: getMenuItems(), directionalHint: DirectionalHint.leftTopEdge, directionalHintFixed: false }}
|
menuProps={{ items: getMenuItems(), directionalHint: DirectionalHint.leftTopEdge, directionalHintFixed: false }}
|
||||||
menuIconProps={{ iconName: "", className: "hidden" }}
|
menuIconProps={{ iconName: "", className: "hidden" }}
|
||||||
ariaLabel={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
ariaLabel={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||||
title={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
title={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IColumn } from "@fluentui/react";
|
import { IColumn } from "@fluentui/react";
|
||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
|
||||||
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||||
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
||||||
import { getColumns } from "./CopyJobColumns";
|
import { getColumns } from "./CopyJobColumns";
|
||||||
@@ -79,14 +79,14 @@ describe("CopyJobColumns", () => {
|
|||||||
expect(actualKeys).toEqual(expectedKeys);
|
expect(actualKeys).toEqual(expectedKeys);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have correct column names from ContainerCopyMessages", () => {
|
it("should have correct column names from i18n", () => {
|
||||||
const columns = getColumns(mockHandleSort, mockHandleActionClick, undefined, false);
|
const columns = getColumns(mockHandleSort, mockHandleActionClick, undefined, false);
|
||||||
|
|
||||||
expect(columns[0].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.lastUpdatedTime);
|
expect(columns[0].name).toBe(t(Keys.containerCopy.monitorJobs.columns.lastUpdatedTime));
|
||||||
expect(columns[1].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.name);
|
expect(columns[1].name).toBe(t(Keys.containerCopy.monitorJobs.columns.name));
|
||||||
expect(columns[2].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.mode);
|
expect(columns[2].name).toBe(t(Keys.containerCopy.monitorJobs.columns.mode));
|
||||||
expect(columns[3].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.completionPercentage);
|
expect(columns[3].name).toBe(t(Keys.containerCopy.monitorJobs.columns.completionPercentage));
|
||||||
expect(columns[4].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.status);
|
expect(columns[4].name).toBe(t(Keys.containerCopy.monitorJobs.columns.status));
|
||||||
expect(columns[5].name).toBe("");
|
expect(columns[5].name).toBe("");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { IColumn } from "@fluentui/react";
|
import { IColumn } from "@fluentui/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
||||||
import CopyJobActionMenu from "./CopyJobActionMenu";
|
import CopyJobActionMenu from "./CopyJobActionMenu";
|
||||||
import CopyJobStatusWithIcon from "./CopyJobStatusWithIcon";
|
import CopyJobStatusWithIcon from "./CopyJobStatusWithIcon";
|
||||||
@@ -13,7 +13,7 @@ export const getColumns = (
|
|||||||
): IColumn[] => [
|
): IColumn[] => [
|
||||||
{
|
{
|
||||||
key: "LastUpdatedTime",
|
key: "LastUpdatedTime",
|
||||||
name: ContainerCopyMessages.MonitorJobs.Columns.lastUpdatedTime,
|
name: t(Keys.containerCopy.monitorJobs.columns.lastUpdatedTime),
|
||||||
fieldName: "LastUpdatedTime",
|
fieldName: "LastUpdatedTime",
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
maxWidth: 300,
|
maxWidth: 300,
|
||||||
@@ -24,7 +24,7 @@ export const getColumns = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "Name",
|
key: "Name",
|
||||||
name: ContainerCopyMessages.MonitorJobs.Columns.name,
|
name: t(Keys.containerCopy.monitorJobs.columns.name),
|
||||||
fieldName: "Name",
|
fieldName: "Name",
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
maxWidth: 300,
|
maxWidth: 300,
|
||||||
@@ -36,7 +36,7 @@ export const getColumns = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "Mode",
|
key: "Mode",
|
||||||
name: ContainerCopyMessages.MonitorJobs.Columns.mode,
|
name: t(Keys.containerCopy.monitorJobs.columns.mode),
|
||||||
fieldName: "Mode",
|
fieldName: "Mode",
|
||||||
minWidth: 90,
|
minWidth: 90,
|
||||||
maxWidth: 200,
|
maxWidth: 200,
|
||||||
@@ -47,7 +47,7 @@ export const getColumns = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "CompletionPercentage",
|
key: "CompletionPercentage",
|
||||||
name: ContainerCopyMessages.MonitorJobs.Columns.completionPercentage,
|
name: t(Keys.containerCopy.monitorJobs.columns.completionPercentage),
|
||||||
fieldName: "CompletionPercentage",
|
fieldName: "CompletionPercentage",
|
||||||
minWidth: 110,
|
minWidth: 110,
|
||||||
maxWidth: 200,
|
maxWidth: 200,
|
||||||
@@ -59,7 +59,7 @@ export const getColumns = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "CopyJobStatus",
|
key: "CopyJobStatus",
|
||||||
name: ContainerCopyMessages.MonitorJobs.Columns.status,
|
name: t(Keys.containerCopy.monitorJobs.columns.status),
|
||||||
fieldName: "Status",
|
fieldName: "Status",
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
maxWidth: 200,
|
maxWidth: 200,
|
||||||
|
|||||||
@@ -13,22 +13,6 @@ jest.mock("./CopyJobStatusWithIcon", () => {
|
|||||||
return MockCopyJobStatusWithIcon;
|
return MockCopyJobStatusWithIcon;
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.mock("../../ContainerCopyMessages", () => ({
|
|
||||||
errorTitle: "Error Details",
|
|
||||||
sourceDatabaseLabel: "Source Database",
|
|
||||||
sourceContainerLabel: "Source Container",
|
|
||||||
targetDatabaseLabel: "Destination Database",
|
|
||||||
targetContainerLabel: "Destination Container",
|
|
||||||
sourceAccountLabel: "Source Account",
|
|
||||||
MonitorJobs: {
|
|
||||||
Columns: {
|
|
||||||
lastUpdatedTime: "Date & time",
|
|
||||||
status: "Status",
|
|
||||||
mode: "Mode",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("CopyJobDetails", () => {
|
describe("CopyJobDetails", () => {
|
||||||
const mockBasicJob: CopyJobType = {
|
const mockBasicJob: CopyJobType = {
|
||||||
ID: "test-job-1",
|
ID: "test-job-1",
|
||||||
@@ -102,7 +86,7 @@ describe("CopyJobDetails", () => {
|
|||||||
expect(screen.getByText("Date & time")).toBeInTheDocument();
|
expect(screen.getByText("Date & time")).toBeInTheDocument();
|
||||||
expect(screen.getByText("2024-01-01T10:00:00Z")).toBeInTheDocument();
|
expect(screen.getByText("2024-01-01T10:00:00Z")).toBeInTheDocument();
|
||||||
|
|
||||||
expect(screen.getByText("Source Account")).toBeInTheDocument();
|
expect(screen.getByText("Source account")).toBeInTheDocument();
|
||||||
expect(screen.getByText("sourceAccount")).toBeInTheDocument();
|
expect(screen.getByText("sourceAccount")).toBeInTheDocument();
|
||||||
|
|
||||||
expect(screen.getByText("Mode")).toBeInTheDocument();
|
expect(screen.getByText("Mode")).toBeInTheDocument();
|
||||||
@@ -322,7 +306,7 @@ describe("CopyJobDetails", () => {
|
|||||||
render(<CopyJobDetails job={mockBasicJob} />);
|
render(<CopyJobDetails job={mockBasicJob} />);
|
||||||
|
|
||||||
const dateTimeHeading = screen.getByText("Date & time");
|
const dateTimeHeading = screen.getByText("Date & time");
|
||||||
const sourceAccountHeading = screen.getByText("Source Account");
|
const sourceAccountHeading = screen.getByText("Source account");
|
||||||
const modeHeading = screen.getByText("Mode");
|
const modeHeading = screen.getByText("Mode");
|
||||||
|
|
||||||
expect(dateTimeHeading).toHaveClass("bold");
|
expect(dateTimeHeading).toHaveClass("bold");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { DetailsList, DetailsListLayoutMode, IColumn, Stack, Text } from "@fluentui/react";
|
import { DetailsList, DetailsListLayoutMode, IColumn, Stack, Text } from "@fluentui/react";
|
||||||
import React, { memo } from "react";
|
import React, { memo } from "react";
|
||||||
import { useThemeStore } from "../../../../hooks/useTheme";
|
import { useThemeStore } from "../../../../hooks/useTheme";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||||
import { CopyJobType } from "../../Types/CopyJobTypes";
|
import { CopyJobType } from "../../Types/CopyJobTypes";
|
||||||
import CopyJobStatusWithIcon from "./CopyJobStatusWithIcon";
|
import CopyJobStatusWithIcon from "./CopyJobStatusWithIcon";
|
||||||
@@ -31,31 +31,31 @@ const getCopyJobDetailsListColumns = (): IColumn[] => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: "sourcedbcol",
|
key: "sourcedbcol",
|
||||||
name: ContainerCopyMessages.sourceDatabaseLabel,
|
name: t(Keys.containerCopy.preview.sourceDatabaseLabel),
|
||||||
fieldName: "sourceDatabaseName",
|
fieldName: "sourceDatabaseName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "sourcecol",
|
key: "sourcecol",
|
||||||
name: ContainerCopyMessages.sourceContainerLabel,
|
name: t(Keys.containerCopy.preview.sourceContainerLabel),
|
||||||
fieldName: "sourceContainerName",
|
fieldName: "sourceContainerName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "targetdbcol",
|
key: "targetdbcol",
|
||||||
name: ContainerCopyMessages.targetDatabaseLabel,
|
name: t(Keys.containerCopy.preview.targetDatabaseLabel),
|
||||||
fieldName: "targetDatabaseName",
|
fieldName: "targetDatabaseName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "targetcol",
|
key: "targetcol",
|
||||||
name: ContainerCopyMessages.targetContainerLabel,
|
name: t(Keys.containerCopy.preview.targetContainerLabel),
|
||||||
fieldName: "targetContainerName",
|
fieldName: "targetContainerName",
|
||||||
...commonProps,
|
...commonProps,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "statuscol",
|
key: "statuscol",
|
||||||
name: ContainerCopyMessages.MonitorJobs.Columns.status,
|
name: t(Keys.containerCopy.monitorJobs.columns.status),
|
||||||
fieldName: "jobStatus",
|
fieldName: "jobStatus",
|
||||||
onRender: ({ jobStatus }: { jobStatus: CopyJobStatusType }) => <CopyJobStatusWithIcon status={jobStatus} />,
|
onRender: ({ jobStatus }: { jobStatus: CopyJobStatusType }) => <CopyJobStatusWithIcon status={jobStatus} />,
|
||||||
...commonProps,
|
...commonProps,
|
||||||
@@ -92,7 +92,7 @@ const CopyJobDetails: React.FC<CopyJobDetailsProps> = ({ job }) => {
|
|||||||
{job.Error ? (
|
{job.Error ? (
|
||||||
<Stack.Item data-testid="error-stack" style={sectionCss.verticalAlign}>
|
<Stack.Item data-testid="error-stack" style={sectionCss.verticalAlign}>
|
||||||
<Text className="bold themeText" style={sectionCss.headingText}>
|
<Text className="bold themeText" style={sectionCss.headingText}>
|
||||||
{ContainerCopyMessages.errorTitle}
|
{t(Keys.containerCopy.jobDetails.errorTitle)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text as="pre" style={errorMessageStyle}>
|
<Text as="pre" style={errorMessageStyle}>
|
||||||
{job.Error.message}
|
{job.Error.message}
|
||||||
@@ -102,15 +102,15 @@ const CopyJobDetails: React.FC<CopyJobDetailsProps> = ({ job }) => {
|
|||||||
<Stack.Item data-testid="selectedcollection-stack">
|
<Stack.Item data-testid="selectedcollection-stack">
|
||||||
<Stack tokens={{ childrenGap: 15 }}>
|
<Stack tokens={{ childrenGap: 15 }}>
|
||||||
<Stack.Item style={sectionCss.verticalAlign}>
|
<Stack.Item style={sectionCss.verticalAlign}>
|
||||||
<Text className="bold themeText">{ContainerCopyMessages.MonitorJobs.Columns.lastUpdatedTime}</Text>
|
<Text className="bold themeText">{t(Keys.containerCopy.monitorJobs.columns.lastUpdatedTime)}</Text>
|
||||||
<Text className="themeText">{job.LastUpdatedTime}</Text>
|
<Text className="themeText">{job.LastUpdatedTime}</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item style={sectionCss.verticalAlign}>
|
<Stack.Item style={sectionCss.verticalAlign}>
|
||||||
<Text className="bold themeText">{ContainerCopyMessages.sourceAccountLabel}</Text>
|
<Text className="bold themeText">{t(Keys.containerCopy.preview.sourceAccountLabel)}</Text>
|
||||||
<Text className="themeText">{job.Source?.remoteAccountName}</Text>
|
<Text className="themeText">{job.Source?.remoteAccountName}</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item style={sectionCss.verticalAlign}>
|
<Stack.Item style={sectionCss.verticalAlign}>
|
||||||
<Text className="bold themeText">{ContainerCopyMessages.MonitorJobs.Columns.mode}</Text>
|
<Text className="bold themeText">{t(Keys.containerCopy.monitorJobs.columns.mode)}</Text>
|
||||||
<Text className="themeText">{job.Mode}</Text>
|
<Text className="themeText">{job.Mode}</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { FontIcon, mergeStyles, Spinner, SpinnerSize, Stack, Text } from "@fluentui/react";
|
import { FontIcon, mergeStyles, Spinner, SpinnerSize, Stack, Text } from "@fluentui/react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
import { Keys, t } from "Localization";
|
||||||
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||||
|
|
||||||
const iconClass = mergeStyles({
|
const iconClass = mergeStyles({
|
||||||
@@ -30,12 +30,25 @@ const statusIconColors: Partial<Record<CopyJobStatusType, string>> = {
|
|||||||
[CopyJobStatusType.Paused]: "var(--colorBrandForeground1)",
|
[CopyJobStatusType.Paused]: "var(--colorBrandForeground1)",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusKeyMap: Record<CopyJobStatusType, string> = {
|
||||||
|
[CopyJobStatusType.Pending]: Keys.containerCopy.monitorJobs.status.pending,
|
||||||
|
[CopyJobStatusType.InProgress]: Keys.containerCopy.monitorJobs.status.inProgress,
|
||||||
|
[CopyJobStatusType.Running]: Keys.containerCopy.monitorJobs.status.running,
|
||||||
|
[CopyJobStatusType.Partitioning]: Keys.containerCopy.monitorJobs.status.partitioning,
|
||||||
|
[CopyJobStatusType.Paused]: Keys.containerCopy.monitorJobs.status.paused,
|
||||||
|
[CopyJobStatusType.Completed]: Keys.containerCopy.monitorJobs.status.completed,
|
||||||
|
[CopyJobStatusType.Failed]: Keys.containerCopy.monitorJobs.status.failed,
|
||||||
|
[CopyJobStatusType.Faulted]: Keys.containerCopy.monitorJobs.status.faulted,
|
||||||
|
[CopyJobStatusType.Skipped]: Keys.containerCopy.monitorJobs.status.skipped,
|
||||||
|
[CopyJobStatusType.Cancelled]: Keys.containerCopy.monitorJobs.status.cancelled,
|
||||||
|
};
|
||||||
|
|
||||||
export interface CopyJobStatusWithIconProps {
|
export interface CopyJobStatusWithIconProps {
|
||||||
status: CopyJobStatusType;
|
status: CopyJobStatusType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CopyJobStatusWithIcon: React.FC<CopyJobStatusWithIconProps> = React.memo(({ status }) => {
|
const CopyJobStatusWithIcon: React.FC<CopyJobStatusWithIconProps> = React.memo(({ status }) => {
|
||||||
const statusText = ContainerCopyMessages.MonitorJobs.Status[status] || "Unknown";
|
const statusText = statusKeyMap[status] ? t(statusKeyMap[status] as Parameters<typeof t>[0]) : "Unknown";
|
||||||
|
|
||||||
const isSpinnerStatus = [
|
const isSpinnerStatus = [
|
||||||
CopyJobStatusType.Running,
|
CopyJobStatusType.Running,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ jest.mock("../../Actions/CopyJobActions");
|
|||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
import { fireEvent, render, screen } from "@testing-library/react";
|
import { fireEvent, render, screen } from "@testing-library/react";
|
||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import * as Actions from "../../Actions/CopyJobActions";
|
import * as Actions from "../../Actions/CopyJobActions";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
|
||||||
import CopyJobsNotFound from "./CopyJobs.NotFound";
|
import CopyJobsNotFound from "./CopyJobs.NotFound";
|
||||||
|
|
||||||
describe("CopyJobsNotFound", () => {
|
describe("CopyJobsNotFound", () => {
|
||||||
@@ -22,10 +22,10 @@ describe("CopyJobsNotFound", () => {
|
|||||||
const image = container.querySelector(".notFoundContainer .ms-Image");
|
const image = container.querySelector(".notFoundContainer .ms-Image");
|
||||||
expect(image).toBeInTheDocument();
|
expect(image).toBeInTheDocument();
|
||||||
expect(image).toHaveAttribute("style", "width: 100px; height: 100px;");
|
expect(image).toHaveAttribute("style", "width: 100px; height: 100px;");
|
||||||
expect(getByText(ContainerCopyMessages.noCopyJobsTitle)).toBeInTheDocument();
|
expect(getByText(t(Keys.containerCopy.noCopyJobs.title))).toBeInTheDocument();
|
||||||
|
|
||||||
const button = screen.getByRole("button", {
|
const button = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.createCopyJobButtonText,
|
name: t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText),
|
||||||
});
|
});
|
||||||
expect(button).toBeInTheDocument();
|
expect(button).toBeInTheDocument();
|
||||||
expect(button).toHaveClass("createCopyJobButton");
|
expect(button).toHaveClass("createCopyJobButton");
|
||||||
@@ -45,7 +45,7 @@ describe("CopyJobsNotFound", () => {
|
|||||||
render(<CopyJobsNotFound explorer={mockExplorer} />);
|
render(<CopyJobsNotFound explorer={mockExplorer} />);
|
||||||
|
|
||||||
const button = screen.getByRole("button", {
|
const button = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.createCopyJobButtonText,
|
name: t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
@@ -58,11 +58,11 @@ describe("CopyJobsNotFound", () => {
|
|||||||
render(<CopyJobsNotFound explorer={mockExplorer} />);
|
render(<CopyJobsNotFound explorer={mockExplorer} />);
|
||||||
|
|
||||||
const button = screen.getByRole("button", {
|
const button = screen.getByRole("button", {
|
||||||
name: ContainerCopyMessages.createCopyJobButtonText,
|
name: t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(button).toBeInTheDocument();
|
expect(button).toBeInTheDocument();
|
||||||
expect(button.textContent).toBe(ContainerCopyMessages.createCopyJobButtonText);
|
expect(button.textContent).toBe(t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should use memo to prevent unnecessary re-renders", () => {
|
it("should use memo to prevent unnecessary re-renders", () => {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { ActionButton, Image } from "@fluentui/react";
|
|||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import CopyJobIcon from "../../../../../images/ContainerCopy/copy-jobs.svg";
|
import CopyJobIcon from "../../../../../images/ContainerCopy/copy-jobs.svg";
|
||||||
|
import { Keys, t } from "Localization";
|
||||||
import * as Actions from "../../Actions/CopyJobActions";
|
import * as Actions from "../../Actions/CopyJobActions";
|
||||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
|
||||||
|
|
||||||
interface CopyJobsNotFoundProps {
|
interface CopyJobsNotFoundProps {
|
||||||
explorer: Explorer;
|
explorer: Explorer;
|
||||||
@@ -12,14 +12,14 @@ interface CopyJobsNotFoundProps {
|
|||||||
const CopyJobsNotFound: React.FC<CopyJobsNotFoundProps> = ({ explorer }) => {
|
const CopyJobsNotFound: React.FC<CopyJobsNotFoundProps> = ({ explorer }) => {
|
||||||
return (
|
return (
|
||||||
<div className="notFoundContainer flexContainer centerContent">
|
<div className="notFoundContainer flexContainer centerContent">
|
||||||
<Image src={CopyJobIcon} alt={ContainerCopyMessages.noCopyJobsTitle} width={100} height={100} />
|
<Image src={CopyJobIcon} alt={t(Keys.containerCopy.noCopyJobs.title)} width={100} height={100} />
|
||||||
<h4 className="noCopyJobsMessage">{ContainerCopyMessages.noCopyJobsTitle}</h4>
|
<h4 className="noCopyJobsMessage">{t(Keys.containerCopy.noCopyJobs.title)}</h4>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
allowDisabledFocus
|
allowDisabledFocus
|
||||||
className="createCopyJobButton"
|
className="createCopyJobButton"
|
||||||
onClick={() => Actions.openCreateCopyJobPanel(explorer)}
|
onClick={() => Actions.openCreateCopyJobPanel(explorer)}
|
||||||
>
|
>
|
||||||
{ContainerCopyMessages.createCopyJobButtonText}
|
{t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText)}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import {
|
|||||||
resumeDataTransferJob,
|
resumeDataTransferJob,
|
||||||
} from "Common/dataAccess/dataTransfers";
|
} from "Common/dataAccess/dataTransfers";
|
||||||
import { Platform, configContext } from "ConfigContext";
|
import { Platform, configContext } from "ConfigContext";
|
||||||
import ContainerCopyMessages from "Explorer/ContainerCopy/ContainerCopyMessages";
|
|
||||||
import { CopyJobActions, CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums";
|
import { CopyJobActions, CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums";
|
||||||
import { useDialog } from "Explorer/Controls/Dialog";
|
import { useDialog } from "Explorer/Controls/Dialog";
|
||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
@@ -174,7 +173,8 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
action === CopyJobActions.cancel ? (
|
action === CopyJobActions.cancel ? (
|
||||||
<Stack tokens={{ childrenGap: 10 }}>
|
<Stack tokens={{ childrenGap: 10 }}>
|
||||||
<Stack.Item>
|
<Stack.Item>
|
||||||
{/*t(Keys.controls.settings.partitionKeyEditor.confirmCancel1)*/}<br />
|
{/*t(Keys.controls.settings.partitionKeyEditor.confirmCancel1)*/}
|
||||||
|
<br />
|
||||||
<b>{jobName}</b>
|
<b>{jobName}</b>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item>{/*t(Keys.controls.settings.partitionKeyEditor.confirmCancel2)*/}</Stack.Item>
|
<Stack.Item>{/*t(Keys.controls.settings.partitionKeyEditor.confirmCancel2)*/}</Stack.Item>
|
||||||
@@ -182,26 +182,17 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
) : action === CopyJobActions.complete ? (
|
) : action === CopyJobActions.complete ? (
|
||||||
<Stack tokens={{ childrenGap: 10 }}>
|
<Stack tokens={{ childrenGap: 10 }}>
|
||||||
<Stack.Item>
|
<Stack.Item>
|
||||||
{/*t(Keys.controls.settings.partitionKeyEditor.confirmComplete1)*/}<br />
|
{/*t(Keys.controls.settings.partitionKeyEditor.confirmComplete1)*/}
|
||||||
|
<br />
|
||||||
<b>{jobName}</b>
|
<b>{jobName}</b>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item>
|
<Stack.Item>{/*t(Keys.controls.settings.partitionKeyEditor.confrimComplete2)*/}</Stack.Item>
|
||||||
{/*t(Keys.controls.settings.partitionKeyEditor.confrimComplete2)*/}
|
|
||||||
</Stack.Item>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
useDialog
|
useDialog
|
||||||
.getState()
|
.getState()
|
||||||
.showOkCancelModalDialog(
|
.showOkCancelModalDialog("", null, t(Keys.common.confirm), onConfirm, t(Keys.common.cancel), null, dialogBody);
|
||||||
ContainerCopyMessages.MonitorJobs.dialog.heading,
|
|
||||||
null,
|
|
||||||
ContainerCopyMessages.MonitorJobs.dialog.confirmButtonText,
|
|
||||||
onConfirm,
|
|
||||||
ContainerCopyMessages.MonitorJobs.dialog.cancelButtonText,
|
|
||||||
null,
|
|
||||||
dialogBody,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOnlineJobMenuProps = (currentJob: DataTransferJobGetResults): IContextualMenuProps => {
|
const getOnlineJobMenuProps = (currentJob: DataTransferJobGetResults): IContextualMenuProps => {
|
||||||
@@ -213,7 +204,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
if (!isPaused) {
|
if (!isPaused) {
|
||||||
items.push({
|
items.push({
|
||||||
key: CopyJobActions.pause,
|
key: CopyJobActions.pause,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.pause,
|
text: t(Keys.containerCopy.monitorJobs.actions.pause),
|
||||||
iconProps: { iconName: "Pause" },
|
iconProps: { iconName: "Pause" },
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
pauseRunningDataTransferJob(currentJob);
|
pauseRunningDataTransferJob(currentJob);
|
||||||
@@ -224,7 +215,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
if (isPaused) {
|
if (isPaused) {
|
||||||
items.push({
|
items.push({
|
||||||
key: CopyJobActions.resume,
|
key: CopyJobActions.resume,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.resume,
|
text: t(Keys.containerCopy.monitorJobs.actions.resume),
|
||||||
iconProps: { iconName: "Play" },
|
iconProps: { iconName: "Play" },
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
resumePausedDataTransferJob(currentJob);
|
resumePausedDataTransferJob(currentJob);
|
||||||
@@ -234,7 +225,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
key: CopyJobActions.cancel,
|
key: CopyJobActions.cancel,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.cancel,
|
text: t(Keys.common.cancel),
|
||||||
iconProps: { iconName: "Cancel" },
|
iconProps: { iconName: "Cancel" },
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
showActionConfirmationDialog(currentJob, CopyJobActions.cancel, () => cancelRunningDataTransferJob(currentJob)),
|
showActionConfirmationDialog(currentJob, CopyJobActions.cancel, () => cancelRunningDataTransferJob(currentJob)),
|
||||||
@@ -242,7 +233,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
key: CopyJobActions.complete,
|
key: CopyJobActions.complete,
|
||||||
text: ContainerCopyMessages.MonitorJobs.Actions.complete,
|
text: t(Keys.containerCopy.monitorJobs.actions.complete),
|
||||||
iconProps: { iconName: "CheckMark" },
|
iconProps: { iconName: "CheckMark" },
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
showActionConfirmationDialog(currentJob, CopyJobActions.complete, () =>
|
showActionConfirmationDialog(currentJob, CopyJobActions.complete, () =>
|
||||||
@@ -290,9 +281,9 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
const processedCountString =
|
const processedCountString =
|
||||||
totalCount > 0
|
totalCount > 0
|
||||||
? t(Keys.controls.settings.partitionKeyEditor.documentsProcessed, {
|
? t(Keys.controls.settings.partitionKeyEditor.documentsProcessed, {
|
||||||
processedCount: String(processedCount),
|
processedCount: String(processedCount),
|
||||||
totalCount: String(totalCount),
|
totalCount: String(totalCount),
|
||||||
})
|
})
|
||||||
: "";
|
: "";
|
||||||
return `${portalDataTransferJob?.properties?.status} ${processedCountString}`;
|
return `${portalDataTransferJob?.properties?.status} ${processedCountString}`;
|
||||||
};
|
};
|
||||||
@@ -418,8 +409,8 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
|||||||
}}
|
}}
|
||||||
menuProps={getOnlineJobMenuProps(portalDataTransferJob)}
|
menuProps={getOnlineJobMenuProps(portalDataTransferJob)}
|
||||||
menuIconProps={{ iconName: "", className: "hidden" }}
|
menuIconProps={{ iconName: "", className: "hidden" }}
|
||||||
ariaLabel={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
ariaLabel={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||||
title={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
title={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DefaultButton
|
<DefaultButton
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import {
|
|||||||
getPartitionKeySubtext,
|
getPartitionKeySubtext,
|
||||||
getPartitionKeyTooltipText,
|
getPartitionKeyTooltipText,
|
||||||
} from "Explorer/Controls/Settings/SettingsUtils";
|
} from "Explorer/Controls/Settings/SettingsUtils";
|
||||||
import ContainerCopyMessages from "Explorer/ContainerCopy/ContainerCopyMessages";
|
|
||||||
import { BackupPolicyType, CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums";
|
import { BackupPolicyType, CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums";
|
||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
import { RightPaneForm } from "Explorer/Panes/RightPaneForm/RightPaneForm";
|
import { RightPaneForm } from "Explorer/Panes/RightPaneForm/RightPaneForm";
|
||||||
@@ -54,12 +53,12 @@ export interface ChangePartitionKeyPaneProps {
|
|||||||
const migrationTypeOptions: IChoiceGroupOption[] = [
|
const migrationTypeOptions: IChoiceGroupOption[] = [
|
||||||
{
|
{
|
||||||
key: CopyJobMigrationType.Offline,
|
key: CopyJobMigrationType.Offline,
|
||||||
text: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
text: t(Keys.containerCopy.migrationType.offline.title),
|
||||||
styles: { root: { width: "33%" } },
|
styles: { root: { width: "33%" } },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: CopyJobMigrationType.Online,
|
key: CopyJobMigrationType.Online,
|
||||||
text: ContainerCopyMessages.migrationTypeOptions.online.title,
|
text: t(Keys.containerCopy.migrationType.online.title),
|
||||||
styles: { root: { width: "33%" } },
|
styles: { root: { width: "33%" } },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -173,7 +172,7 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
const handleEnablePitr = () => {
|
const handleEnablePitr = () => {
|
||||||
const featureUrl = `https://portal.azure.com/#@/resource/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/backupRestore`;
|
const featureUrl = `https://portal.azure.com/#@/resource/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/backupRestore`;
|
||||||
setIsEnablingPrerequisite(true);
|
setIsEnablingPrerequisite(true);
|
||||||
setPrerequisiteLoaderMessage(ContainerCopyMessages.popoverOverlaySpinnerLabel);
|
setPrerequisiteLoaderMessage(t(Keys.containerCopy.popoverOverlaySpinnerLabel));
|
||||||
window.open(featureUrl, "_blank");
|
window.open(featureUrl, "_blank");
|
||||||
startPollingForAccountUpdate();
|
startPollingForAccountUpdate();
|
||||||
};
|
};
|
||||||
@@ -182,12 +181,12 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
setIsEnablingPrerequisite(true);
|
setIsEnablingPrerequisite(true);
|
||||||
try {
|
try {
|
||||||
setPrerequisiteLoaderMessage(
|
setPrerequisiteLoaderMessage(
|
||||||
ContainerCopyMessages.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel,
|
t(Keys.containerCopy.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel),
|
||||||
);
|
);
|
||||||
const currentAccount = await fetchDatabaseAccount(subscriptionId, resourceGroup, accountName);
|
const currentAccount = await fetchDatabaseAccount(subscriptionId, resourceGroup, accountName);
|
||||||
if (!currentAccount?.properties?.enableAllVersionsAndDeletesChangeFeed) {
|
if (!currentAccount?.properties?.enableAllVersionsAndDeletesChangeFeed) {
|
||||||
setPrerequisiteLoaderMessage(
|
setPrerequisiteLoaderMessage(
|
||||||
ContainerCopyMessages.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel,
|
t(Keys.containerCopy.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel),
|
||||||
);
|
);
|
||||||
await updateDatabaseAccount(subscriptionId, resourceGroup, accountName, {
|
await updateDatabaseAccount(subscriptionId, resourceGroup, accountName, {
|
||||||
properties: {
|
properties: {
|
||||||
@@ -196,7 +195,9 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const capabilities = currentAccount?.properties?.capabilities ?? [];
|
const capabilities = currentAccount?.properties?.capabilities ?? [];
|
||||||
setPrerequisiteLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.enablingOnlineCopySpinnerLabel(accountName));
|
setPrerequisiteLoaderMessage(
|
||||||
|
t(Keys.containerCopy.onlineCopyEnabled.enablingOnlineCopySpinnerLabel, { accountName }),
|
||||||
|
);
|
||||||
await updateDatabaseAccount(subscriptionId, resourceGroup, accountName, {
|
await updateDatabaseAccount(subscriptionId, resourceGroup, accountName, {
|
||||||
properties: {
|
properties: {
|
||||||
capabilities: [...capabilities, { name: CapabilityNames.EnableOnlineCopyFeature }],
|
capabilities: [...capabilities, { name: CapabilityNames.EnableOnlineCopyFeature }],
|
||||||
@@ -345,8 +346,8 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
data-test={`migration-type-description-${migrationType}`}
|
data-test={`migration-type-description-${migrationType}`}
|
||||||
>
|
>
|
||||||
{migrationType === CopyJobMigrationType.Offline
|
{migrationType === CopyJobMigrationType.Offline
|
||||||
? ContainerCopyMessages.migrationTypeOptions.offline.description
|
? t(Keys.containerCopy.migrationType.offline.description)
|
||||||
: ContainerCopyMessages.migrationTypeOptions.online.description}
|
: t(Keys.containerCopy.migrationType.online.description)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -626,10 +627,10 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
<Stack data-test="online-prerequisites-section" tokens={{ childrenGap: 10 }}>
|
<Stack data-test="online-prerequisites-section" tokens={{ childrenGap: 10 }}>
|
||||||
<LoadingOverlay isLoading={isEnablingPrerequisite} label={prerequisiteLoaderMessage} />
|
<LoadingOverlay isLoading={isEnablingPrerequisite} label={prerequisiteLoaderMessage} />
|
||||||
<Text className="panelTextBold" variant="small">
|
<Text className="panelTextBold" variant="small">
|
||||||
{ContainerCopyMessages.assignPermissions.onlineConfiguration.title}
|
{t(Keys.containerCopy.assignPermissions.onlineConfiguration.title)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||||
{ContainerCopyMessages.assignPermissions.onlineConfiguration.description(accountName)}
|
{t(Keys.containerCopy.assignPermissions.onlineConfiguration.description, { accountName })}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* Point In Time Restore */}
|
{/* Point In Time Restore */}
|
||||||
@@ -642,17 +643,17 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Text variant="small" style={{ fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
<Text variant="small" style={{ fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||||
{ContainerCopyMessages.pointInTimeRestore.title}
|
{t(Keys.containerCopy.pointInTimeRestore.title)}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
{!pitrEnabled && (
|
{!pitrEnabled && (
|
||||||
<Stack tokens={{ childrenGap: 10, padding: "0 0 0 20px" }}>
|
<Stack tokens={{ childrenGap: 10, padding: "0 0 0 20px" }}>
|
||||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||||
{ContainerCopyMessages.pointInTimeRestore.description(accountName)}
|
{t(Keys.containerCopy.pointInTimeRestore.description, { accessName: accountName })}
|
||||||
</Text>
|
</Text>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
data-test="enable-pitr-button"
|
data-test="enable-pitr-button"
|
||||||
text={ContainerCopyMessages.pointInTimeRestore.buttonText}
|
text={t(Keys.containerCopy.pointInTimeRestore.buttonText)}
|
||||||
disabled={isEnablingPrerequisite}
|
disabled={isEnablingPrerequisite}
|
||||||
onClick={handleEnablePitr}
|
onClick={handleEnablePitr}
|
||||||
styles={{ root: { width: "fit-content" } }}
|
styles={{ root: { width: "fit-content" } }}
|
||||||
@@ -674,20 +675,20 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Text variant="small" style={{ fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
<Text variant="small" style={{ fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||||
{ContainerCopyMessages.onlineCopyEnabled.title}
|
{t(Keys.containerCopy.onlineCopyEnabled.title)}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
{!onlineCopyFeatureEnabled && (
|
{!onlineCopyFeatureEnabled && (
|
||||||
<Stack tokens={{ childrenGap: 10, padding: "0 0 0 20px" }}>
|
<Stack tokens={{ childrenGap: 10, padding: "0 0 0 20px" }}>
|
||||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||||
{ContainerCopyMessages.onlineCopyEnabled.description(accountName)} 
|
{t(Keys.containerCopy.onlineCopyEnabled.description, { accountName })} 
|
||||||
<Link href={ContainerCopyMessages.onlineCopyEnabled.href} target="_blank" rel="noopener noreferrer">
|
<Link href={t(Keys.containerCopy.onlineCopyEnabled.href)} target="_blank" rel="noopener noreferrer">
|
||||||
{ContainerCopyMessages.onlineCopyEnabled.hrefText}
|
{t(Keys.containerCopy.onlineCopyEnabled.hrefText)}
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
data-test="enable-online-copy-button"
|
data-test="enable-online-copy-button"
|
||||||
text={ContainerCopyMessages.onlineCopyEnabled.buttonText}
|
text={t(Keys.containerCopy.onlineCopyEnabled.buttonText)}
|
||||||
disabled={isEnablingPrerequisite || !pitrEnabled}
|
disabled={isEnablingPrerequisite || !pitrEnabled}
|
||||||
onClick={handleEnableOnlineCopy}
|
onClick={handleEnableOnlineCopy}
|
||||||
styles={{ root: { width: "fit-content" } }}
|
styles={{ root: { width: "fit-content" } }}
|
||||||
|
|||||||
@@ -33,7 +33,9 @@
|
|||||||
"publish": "Publish",
|
"publish": "Publish",
|
||||||
"browse": "Browse",
|
"browse": "Browse",
|
||||||
"increaseValueBy1": "Increase value by 1",
|
"increaseValueBy1": "Increase value by 1",
|
||||||
"decreaseValueBy1": "Decrease value by 1"
|
"decreaseValueBy1": "Decrease value by 1",
|
||||||
|
"on": "On",
|
||||||
|
"off": "Off"
|
||||||
},
|
},
|
||||||
"splashScreen": {
|
"splashScreen": {
|
||||||
"title": {
|
"title": {
|
||||||
@@ -974,5 +976,163 @@
|
|||||||
"bucketNotActive": "Bucket {{id}} is not active."
|
"bucketNotActive": "Bucket {{id}} is not active."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"containerCopy": {
|
||||||
|
"commandBar": {
|
||||||
|
"feedbackButtonLabel": "Feedback",
|
||||||
|
"feedbackButtonAriaLabel": "Provide feedback on copy jobs",
|
||||||
|
"refreshButtonAriaLabel": "Refresh copy jobs",
|
||||||
|
"createCopyJobButtonLabel": "Create Copy Job",
|
||||||
|
"createCopyJobButtonAriaLabel": "Create a new container copy job"
|
||||||
|
},
|
||||||
|
"noCopyJobs": {
|
||||||
|
"title": "No copy jobs to show",
|
||||||
|
"createCopyJobButtonText": "Create a container copy job"
|
||||||
|
},
|
||||||
|
"jobDetails": {
|
||||||
|
"panelTitle": "{{jobName}}",
|
||||||
|
"panelTitleDefault": "Job Details",
|
||||||
|
"errorTitle": "Error Details",
|
||||||
|
"selectedContainers": "Selected Containers"
|
||||||
|
},
|
||||||
|
"createCopyJob": {
|
||||||
|
"panelTitle": "Create copy job"
|
||||||
|
},
|
||||||
|
"selectAccount": {
|
||||||
|
"description": "Please select a source account from which to copy.",
|
||||||
|
"subscriptionDropdownLabel": "Subscription",
|
||||||
|
"subscriptionDropdownPlaceholder": "Select a subscription",
|
||||||
|
"sourceAccountDropdownLabel": "Account",
|
||||||
|
"sourceAccountDropdownPlaceholder": "Select an account"
|
||||||
|
},
|
||||||
|
"migrationType": {
|
||||||
|
"offline": {
|
||||||
|
"title": "Offline mode",
|
||||||
|
"description": "Offline container copy jobs let you copy data from a source container to a destination Cosmos DB container for supported APIs. To ensure data integrity between the source and destination, we recommend stopping updates on the source container before creating the copy job. Learn more about [offline copy jobs](https://learn.microsoft.com/azure/cosmos-db/how-to-container-copy?tabs=offline-copy&pivots=api-nosql)."
|
||||||
|
},
|
||||||
|
"online": {
|
||||||
|
"title": "Online mode",
|
||||||
|
"description": "Online container copy jobs let you copy data from a source container to a destination Cosmos DB NoSQL API container using the [All Versions and Delete](https://learn.microsoft.com/azure/cosmos-db/change-feed-modes?tabs=all-versions-and-deletes#all-versions-and-deletes-change-feed-mode-preview) change feed. This allows updates to continue on the source while data is copied. A brief downtime is required at the end to safely switch over client applications to the destination container. Learn more about [online copy jobs](https://learn.microsoft.com/azure/cosmos-db/container-copy?tabs=online-copy&pivots=api-nosql#getting-started)."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"selectContainers": {
|
||||||
|
"description": "Please select a source container and a destination container to copy to.",
|
||||||
|
"sourceContainerSubHeading": "Source container",
|
||||||
|
"targetContainerSubHeading": "Destination container",
|
||||||
|
"databaseDropdownLabel": "Database",
|
||||||
|
"databaseDropdownPlaceholder": "Select a database",
|
||||||
|
"containerDropdownLabel": "Container",
|
||||||
|
"containerDropdownPlaceholder": "Select a container",
|
||||||
|
"createNewContainerSubHeading": "Select the properties for your container.",
|
||||||
|
"createContainerButtonLabel": "Create a new container",
|
||||||
|
"createContainerHeading": "Create new container"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"jobNameLabel": "Job name",
|
||||||
|
"sourceSubscriptionLabel": "Source subscription",
|
||||||
|
"sourceAccountLabel": "Source account",
|
||||||
|
"sourceDatabaseLabel": "Source database",
|
||||||
|
"sourceContainerLabel": "Source container",
|
||||||
|
"targetDatabaseLabel": "Destination database",
|
||||||
|
"targetContainerLabel": "Destination container"
|
||||||
|
},
|
||||||
|
"assignPermissions": {
|
||||||
|
"crossAccountDescription": "To copy data from the source to the destination container, ensure that the managed identity of the destination account has read access to the source account by completing the following steps.",
|
||||||
|
"intraAccountOnlineDescription": "Follow the steps below to enable online copy on your \"{{accountName}}\" account.",
|
||||||
|
"crossAccountConfiguration": {
|
||||||
|
"title": "Cross-account container copy",
|
||||||
|
"description": "Please follow the instruction below to grant requisite permissions to copy data from \"{{sourceAccount}}\" to \"{{destinationAccount}}\"."
|
||||||
|
},
|
||||||
|
"onlineConfiguration": {
|
||||||
|
"title": "Online container copy",
|
||||||
|
"description": "Please follow the instructions below to enable online copy on your \"{{accountName}}\" account."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"popoverOverlaySpinnerLabel": "Please wait while we process your request...",
|
||||||
|
"addManagedIdentity": {
|
||||||
|
"title": "System-assigned managed identity enabled.",
|
||||||
|
"description": "A system-assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. Once enabled, you can grant permissions to the managed identity by using Azure role-based access control (Azure RBAC). The managed identity is authenticated with Microsoft Entra ID, so you don't have to store any credentials in code.",
|
||||||
|
"descriptionHrefText": "Learn more about Managed identities.",
|
||||||
|
"descriptionHref": "https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview",
|
||||||
|
"toggleLabel": "System assigned managed identity",
|
||||||
|
"tooltipContent": "Learn more about",
|
||||||
|
"tooltipHrefText": "Managed Identities.",
|
||||||
|
"tooltipHref": "https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview",
|
||||||
|
"userAssignedIdentityTooltip": "You can select an existing user assigned identity or create a new one.",
|
||||||
|
"userAssignedIdentityLabel": "You may also select a user assigned managed identity.",
|
||||||
|
"createUserAssignedIdentityLink": "Create User Assigned Managed Identity",
|
||||||
|
"enablementTitle": "Enable system assigned managed identity",
|
||||||
|
"enablementDescription": "Enable system-assigned managed identity on the {{accountName}}. To confirm, click the \"Yes\" button."
|
||||||
|
},
|
||||||
|
"defaultManagedIdentity": {
|
||||||
|
"title": "System-assigned managed identity set as default.",
|
||||||
|
"description": "Set the system-assigned managed identity as default for \"{{accountName}}\" by switching it on.",
|
||||||
|
"tooltipContent": "Learn more about",
|
||||||
|
"tooltipHrefText": "Default Managed Identities.",
|
||||||
|
"tooltipHref": "https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview",
|
||||||
|
"popoverTitle": "System assigned managed identity set as default",
|
||||||
|
"popoverDescription": "Assign the system-assigned managed identity as the default for \"{{accountName}}\". To confirm, click the \"Yes\" button. "
|
||||||
|
},
|
||||||
|
"readPermissionAssigned": {
|
||||||
|
"title": "Read permissions assigned to the default identity.",
|
||||||
|
"description": "To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account.",
|
||||||
|
"tooltipContent": "Learn more about",
|
||||||
|
"tooltipHrefText": "Read permissions.",
|
||||||
|
"tooltipHref": "https://learn.microsoft.com/azure/cosmos-db/nosql/how-to-connect-role-based-access-control",
|
||||||
|
"popoverTitle": "Read permissions assigned to default identity.",
|
||||||
|
"popoverDescription": "Assign read permissions of the source account to the default identity of the destination account. To confirm click the \u201cYes\u201d button."
|
||||||
|
},
|
||||||
|
"pointInTimeRestore": {
|
||||||
|
"title": "Point In Time Restore enabled",
|
||||||
|
"description": "To facilitate online container copy jobs, please update your \"{{accessName}}\" backup policy from periodic to continuous backup. Enabling continuous backup is required for this functionality.",
|
||||||
|
"tooltipContent": "Learn more about",
|
||||||
|
"tooltipHrefText": "Continuous Backup",
|
||||||
|
"tooltipHref": "https://learn.microsoft.com/en-us/azure/cosmos-db/continuous-backup-restore-introduction",
|
||||||
|
"buttonText": "Enable Point In Time Restore"
|
||||||
|
},
|
||||||
|
"onlineCopyEnabled": {
|
||||||
|
"title": "Online copy enabled",
|
||||||
|
"description": "Enable online container copy by clicking the button below on your \"{{accountName}}\" account.",
|
||||||
|
"hrefText": "Learn more about online copy jobs",
|
||||||
|
"href": "https://learn.microsoft.com/en-us/azure/cosmos-db/container-copy?tabs=online-copy&pivots=api-nosql#enable-online-copy",
|
||||||
|
"buttonText": "Enable Online Copy",
|
||||||
|
"validateAllVersionsAndDeletesChangeFeedSpinnerLabel": "Validating All versions and deletes change feed mode (preview)...",
|
||||||
|
"enablingAllVersionsAndDeletesChangeFeedSpinnerLabel": "Enabling All versions and deletes change feed mode (preview)...",
|
||||||
|
"enablingOnlineCopySpinnerLabel": "Enabling online copy on your \"{{accountName}}\" account ..."
|
||||||
|
},
|
||||||
|
"monitorJobs": {
|
||||||
|
"columns": {
|
||||||
|
"lastUpdatedTime": "Date & time",
|
||||||
|
"name": "Job name",
|
||||||
|
"status": "Status",
|
||||||
|
"completionPercentage": "Completion %",
|
||||||
|
"duration": "Duration",
|
||||||
|
"error": "Error message",
|
||||||
|
"mode": "Mode",
|
||||||
|
"actions": "Actions"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"pause": "Pause",
|
||||||
|
"resume": "Resume",
|
||||||
|
"complete": "Complete",
|
||||||
|
"viewDetails": "View Details"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"pending": "Queued",
|
||||||
|
"inProgress": "Running",
|
||||||
|
"running": "Running",
|
||||||
|
"partitioning": "Running",
|
||||||
|
"paused": "Paused",
|
||||||
|
"completed": "Completed",
|
||||||
|
"failed": "Failed",
|
||||||
|
"faulted": "Failed",
|
||||||
|
"skipped": "Cancelled",
|
||||||
|
"cancelled": "Cancelled"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"confirmButtonText": "Confirm",
|
||||||
|
"cancelButtonText": "Cancel"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user