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,
|
||||
DataTransferJobGetResults,
|
||||
} from "../../../Utils/arm/generatedClients/dataTransferService/types";
|
||||
import ContainerCopyMessages from "../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
import {
|
||||
convertTime,
|
||||
convertToCamelCase,
|
||||
@@ -35,7 +35,7 @@ export const openCreateCopyJobPanel = (explorer: Explorer) => {
|
||||
const sidePanelState = useSidePanel.getState();
|
||||
sidePanelState.setPanelHasConsole(false);
|
||||
sidePanelState.openSidePanel(
|
||||
ContainerCopyMessages.createCopyJobPanelTitle,
|
||||
t(Keys.containerCopy.createCopyJob.panelTitle),
|
||||
<CreateCopyJobScreensProvider explorer={explorer} />,
|
||||
"650px",
|
||||
);
|
||||
@@ -45,7 +45,7 @@ export const openCopyJobDetailsPanel = (job: CopyJobType) => {
|
||||
const sidePanelState = useSidePanel.getState();
|
||||
sidePanelState.setPanelHasConsole(false);
|
||||
sidePanelState.openSidePanel(
|
||||
ContainerCopyMessages.copyJobDetailsPanelTitle(job.Name),
|
||||
job.Name || t(Keys.containerCopy.jobDetails.panelTitleDefault),
|
||||
<CopyJobDetails job={job} />,
|
||||
"650px",
|
||||
);
|
||||
@@ -193,7 +193,7 @@ export const updateCopyJobStatus = async (job: CopyJobType, action: string): Pro
|
||||
const pattern = new RegExp(`'(${statusList.join("|")})'`, "g");
|
||||
const normalizedErrorMessage = errorMessage.replace(
|
||||
pattern,
|
||||
`'${ContainerCopyMessages.MonitorJobs.Status.InProgress}'`,
|
||||
`'${t(Keys.containerCopy.monitorJobs.status.inProgress)}'`,
|
||||
);
|
||||
logError(`Error updating copy job status: ${normalizedErrorMessage}`, "CopyJob/CopyJobActions.updateCopyJobStatus");
|
||||
throw error;
|
||||
|
||||
@@ -5,10 +5,10 @@ import RefreshIcon from "../../../../images/refresh-cosmos.svg";
|
||||
import SunIcon from "../../../../images/SunIcon.svg";
|
||||
import { configContext, Platform } from "../../../ConfigContext";
|
||||
import { useThemeStore } from "../../../hooks/useTheme";
|
||||
import { Keys, t } from "Localization";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import Explorer from "../../Explorer";
|
||||
import * as Actions from "../Actions/CopyJobActions";
|
||||
import ContainerCopyMessages from "../ContainerCopyMessages";
|
||||
import { MonitorCopyJobsRefState } from "../MonitorCopyJobs/MonitorCopyJobRefState";
|
||||
import { CopyJobCommandBarBtnType } from "../Types/CopyJobTypes";
|
||||
|
||||
@@ -19,15 +19,15 @@ function getCopyJobBtns(explorer: Explorer, isDarkMode: boolean): CopyJobCommand
|
||||
{
|
||||
key: "createCopyJob",
|
||||
iconSrc: AddIcon,
|
||||
label: ContainerCopyMessages.createCopyJobButtonLabel,
|
||||
ariaLabel: ContainerCopyMessages.createCopyJobButtonAriaLabel,
|
||||
label: t(Keys.containerCopy.commandBar.createCopyJobButtonLabel),
|
||||
ariaLabel: t(Keys.containerCopy.commandBar.createCopyJobButtonAriaLabel),
|
||||
onClick: () => Actions.openCreateCopyJobPanel(explorer),
|
||||
},
|
||||
{
|
||||
key: "refresh",
|
||||
iconSrc: RefreshIcon,
|
||||
label: ContainerCopyMessages.refreshButtonLabel,
|
||||
ariaLabel: ContainerCopyMessages.refreshButtonAriaLabel,
|
||||
label: t(Keys.common.refresh),
|
||||
ariaLabel: t(Keys.containerCopy.commandBar.refreshButtonAriaLabel),
|
||||
onClick: () => monitorCopyJobsRef?.refreshJobList(),
|
||||
},
|
||||
{
|
||||
@@ -48,8 +48,8 @@ function getCopyJobBtns(explorer: Explorer, isDarkMode: boolean): CopyJobCommand
|
||||
buttons.push({
|
||||
key: "feedback",
|
||||
iconSrc: FeedbackIcon,
|
||||
label: ContainerCopyMessages.feedbackButtonLabel,
|
||||
ariaLabel: ContainerCopyMessages.feedbackButtonAriaLabel,
|
||||
label: t(Keys.containerCopy.commandBar.feedbackButtonLabel),
|
||||
ariaLabel: t(Keys.containerCopy.commandBar.feedbackButtonAriaLabel),
|
||||
onClick: () => {
|
||||
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 { DatabaseAccount } from "Contracts/DataModels";
|
||||
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { updateSystemIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import AddManagedIdentity from "./AddManagedIdentity";
|
||||
|
||||
@@ -133,16 +133,16 @@ describe("AddManagedIdentity", () => {
|
||||
it("renders all required elements", () => {
|
||||
renderWithContext();
|
||||
|
||||
expect(screen.getByText(ContainerCopyMessages.addManagedIdentity.description)).toBeInTheDocument();
|
||||
expect(screen.getByText(ContainerCopyMessages.addManagedIdentity.descriptionHrefText)).toBeInTheDocument();
|
||||
expect(screen.getByText(t(Keys.containerCopy.addManagedIdentity.description))).toBeInTheDocument();
|
||||
expect(screen.getByText(t(Keys.containerCopy.addManagedIdentity.descriptionHrefText))).toBeInTheDocument();
|
||||
expect(screen.getByRole("switch")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders description link with correct href", () => {
|
||||
renderWithContext();
|
||||
|
||||
const link = screen.getByText(ContainerCopyMessages.addManagedIdentity.descriptionHrefText);
|
||||
expect(link.closest("a")).toHaveAttribute("href", ContainerCopyMessages.addManagedIdentity.descriptionHref);
|
||||
const link = screen.getByText(t(Keys.containerCopy.addManagedIdentity.descriptionHrefText));
|
||||
expect(link.closest("a")).toHaveAttribute("href", t(Keys.containerCopy.addManagedIdentity.descriptionHref));
|
||||
expect(link.closest("a")).toHaveAttribute("target", "_blank");
|
||||
expect(link.closest("a")).toHaveAttribute("rel", "noopener noreferrer");
|
||||
});
|
||||
@@ -175,7 +175,7 @@ describe("AddManagedIdentity", () => {
|
||||
const toggle = screen.getByRole("switch");
|
||||
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", () => {
|
||||
@@ -185,7 +185,7 @@ describe("AddManagedIdentity", () => {
|
||||
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", () => {
|
||||
const expectedDescription = ContainerCopyMessages.addManagedIdentity.enablementDescription(
|
||||
mockCopyJobState.target.account.name,
|
||||
);
|
||||
expect(screen.getByText(expectedDescription)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
t(Keys.containerCopy.addManagedIdentity.enablementDescription, { accountName: "test-target-account" }),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls handleAddSystemIdentity when primary button clicked", async () => {
|
||||
@@ -220,7 +221,7 @@ describe("AddManagedIdentity", () => {
|
||||
const cancelButton = screen.getByText("Cancel");
|
||||
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");
|
||||
expect(toggle).not.toBeChecked();
|
||||
|
||||
+14
-16
@@ -1,7 +1,7 @@
|
||||
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { updateSystemIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import InfoTooltip from "../Components/InfoTooltip";
|
||||
import PopoverMessage from "../Components/PopoverContainer";
|
||||
@@ -11,14 +11,14 @@ import useToggle from "./hooks/useToggle";
|
||||
|
||||
const managedIdentityTooltip = (
|
||||
<Text>
|
||||
{ContainerCopyMessages.addManagedIdentity.tooltip.content}
|
||||
{t(Keys.containerCopy.addManagedIdentity.tooltipContent)}
|
||||
<Link
|
||||
style={{ color: "var(--colorBrandForeground1)" }}
|
||||
href={ContainerCopyMessages.addManagedIdentity.tooltip.href}
|
||||
href={t(Keys.containerCopy.addManagedIdentity.tooltipHref)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{ContainerCopyMessages.addManagedIdentity.tooltip.hrefText}
|
||||
{t(Keys.containerCopy.addManagedIdentity.tooltipHrefText)}
|
||||
</Link>
|
||||
</Text>
|
||||
);
|
||||
@@ -32,28 +32,26 @@ const AddManagedIdentity: React.FC<AddManagedIdentityProps> = () => {
|
||||
return (
|
||||
<Stack className="addManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||
<Text className="themeText">
|
||||
{ContainerCopyMessages.addManagedIdentity.description} 
|
||||
<Link href={ContainerCopyMessages.addManagedIdentity.descriptionHref} target="_blank" rel="noopener noreferrer">
|
||||
{ContainerCopyMessages.addManagedIdentity.descriptionHrefText}
|
||||
{t(Keys.containerCopy.addManagedIdentity.description)} 
|
||||
<Link href={t(Keys.containerCopy.addManagedIdentity.descriptionHref)} target="_blank" rel="noopener noreferrer">
|
||||
{t(Keys.containerCopy.addManagedIdentity.descriptionHrefText)}
|
||||
</Link>{" "}
|
||||
|
||||
<InfoTooltip content={managedIdentityTooltip} />
|
||||
</Text>
|
||||
<Toggle
|
||||
data-test="btn-toggle"
|
||||
checked={systemAssigned}
|
||||
onText={ContainerCopyMessages.toggleBtn.onText}
|
||||
offText={ContainerCopyMessages.toggleBtn.offText}
|
||||
onChange={onToggle}
|
||||
/>
|
||||
<Toggle data-test="btn-toggle" checked={systemAssigned} onText="On" offText="Off" onChange={onToggle} />
|
||||
<PopoverMessage
|
||||
isLoading={loading}
|
||||
visible={systemAssigned}
|
||||
title={ContainerCopyMessages.addManagedIdentity.enablementTitle}
|
||||
title={t(Keys.containerCopy.addManagedIdentity.enablementTitle)}
|
||||
onCancel={() => onToggle(null, false)}
|
||||
onPrimary={handleAddSystemIdentity}
|
||||
>
|
||||
{ContainerCopyMessages.addManagedIdentity.enablementDescription(copyJobState.target?.account?.name)}
|
||||
{copyJobState.target?.account?.name
|
||||
? t(Keys.containerCopy.addManagedIdentity.enablementDescription, {
|
||||
accountName: copyJobState.target?.account?.name,
|
||||
})
|
||||
: ""}
|
||||
</PopoverMessage>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { CopyJobContextProviderType } from "../../../Types/CopyJobTypes";
|
||||
import AddReadPermissionToDefaultIdentity from "./AddReadPermissionToDefaultIdentity";
|
||||
@@ -180,7 +180,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
|
||||
describe("Component Structure", () => {
|
||||
it("should display the description text", () => {
|
||||
renderComponent();
|
||||
expect(screen.getByText(ContainerCopyMessages.readPermissionAssigned.description)).toBeInTheDocument();
|
||||
expect(screen.getByText(t(Keys.containerCopy.readPermissionAssigned.description))).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should display the info tooltip", () => {
|
||||
@@ -212,10 +212,10 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
|
||||
|
||||
expect(screen.getByTestId("popover-message")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("popover-title")).toHaveTextContent(
|
||||
ContainerCopyMessages.readPermissionAssigned.popoverTitle,
|
||||
t(Keys.containerCopy.readPermissionAssigned.popoverTitle),
|
||||
);
|
||||
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 { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { logError } from "../../../../../Common/Logger";
|
||||
import { assignRole } from "../../../../../Utils/arm/RbacUtils";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
||||
import InfoTooltip from "../Components/InfoTooltip";
|
||||
@@ -12,14 +12,14 @@ import useToggle from "./hooks/useToggle";
|
||||
|
||||
const TooltipContent = (
|
||||
<Text>
|
||||
{ContainerCopyMessages.readPermissionAssigned.tooltip.content}
|
||||
{t(Keys.containerCopy.readPermissionAssigned.tooltipContent)}
|
||||
<Link
|
||||
style={{ color: "var(--colorBrandForeground1)" }}
|
||||
href={ContainerCopyMessages.readPermissionAssigned.tooltip.href}
|
||||
href={t(Keys.containerCopy.readPermissionAssigned.tooltipHref)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{ContainerCopyMessages.readPermissionAssigned.tooltip.hrefText}
|
||||
{t(Keys.containerCopy.readPermissionAssigned.tooltipHrefText)}
|
||||
</Link>
|
||||
</Text>
|
||||
);
|
||||
@@ -66,14 +66,14 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
|
||||
return (
|
||||
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||
<Text className="toggle-label">
|
||||
{ContainerCopyMessages.readPermissionAssigned.description} 
|
||||
{t(Keys.containerCopy.readPermissionAssigned.description)} 
|
||||
<InfoTooltip content={TooltipContent} />
|
||||
</Text>
|
||||
<Toggle
|
||||
data-test="btn-toggle"
|
||||
checked={readPermissionAssigned}
|
||||
onText={ContainerCopyMessages.toggleBtn.onText}
|
||||
offText={ContainerCopyMessages.toggleBtn.offText}
|
||||
onText="On"
|
||||
offText="Off"
|
||||
onChange={onToggle}
|
||||
inlineLabel
|
||||
styles={{
|
||||
@@ -84,11 +84,11 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
|
||||
<PopoverMessage
|
||||
isLoading={loading}
|
||||
visible={readPermissionAssigned}
|
||||
title={ContainerCopyMessages.readPermissionAssigned.popoverTitle}
|
||||
title={t(Keys.containerCopy.readPermissionAssigned.popoverTitle)}
|
||||
onCancel={() => onToggle(null, false)}
|
||||
onPrimary={handleAddReadPermission}
|
||||
>
|
||||
{ContainerCopyMessages.readPermissionAssigned.popoverDescription}
|
||||
{t(Keys.containerCopy.readPermissionAssigned.popoverDescription)}
|
||||
</PopoverMessage>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
+5
-3
@@ -1,7 +1,7 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { render, RenderResult } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
||||
import { CopyJobContextProviderType, CopyJobContextState } from "../../../Types/CopyJobTypes";
|
||||
@@ -154,7 +154,7 @@ describe("AssignPermissions Component", () => {
|
||||
const copyJobState = createMockCopyJobState();
|
||||
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 () => {
|
||||
@@ -179,7 +179,9 @@ describe("AssignPermissions Component", () => {
|
||||
|
||||
const { getByText } = renderWithContext(copyJobState);
|
||||
expect(
|
||||
getByText(ContainerCopyMessages.assignPermissions.intraAccountOnlineDescription("Same Account")),
|
||||
getByText(
|
||||
t(Keys.containerCopy.assignPermissions.intraAccountOnlineDescription, { accountName: "Same Account" }),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+5
-5
@@ -4,7 +4,7 @@ import React, { useEffect } from "react";
|
||||
import CheckmarkIcon from "../../../../../../images/successfulPopup.svg";
|
||||
import WarningIcon from "../../../../../../images/warning.svg";
|
||||
import ShimmerTree, { IndentLevel } from "../../../../../Common/ShimmerTree/ShimmerTree";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { isIntraAccountCopy } from "../../../CopyJobUtils";
|
||||
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
||||
@@ -107,10 +107,10 @@ const AssignPermissions = () => {
|
||||
>
|
||||
<Text variant="medium" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
{isSameAccount && copyJobState.migrationType === CopyJobMigrationType.Online
|
||||
? ContainerCopyMessages.assignPermissions.intraAccountOnlineDescription(
|
||||
copyJobState?.source?.account?.name || "",
|
||||
)
|
||||
: ContainerCopyMessages.assignPermissions.crossAccountDescription}
|
||||
? t(Keys.containerCopy.assignPermissions.intraAccountOnlineDescription, {
|
||||
accountName: copyJobState?.source?.account?.name || "",
|
||||
})
|
||||
: t(Keys.containerCopy.assignPermissions.crossAccountDescription)}
|
||||
</Text>
|
||||
|
||||
{totalSectionsCount === 0 ? (
|
||||
|
||||
+9
-9
@@ -1,8 +1,8 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { updateDefaultIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import DefaultManagedIdentity from "./DefaultManagedIdentity";
|
||||
|
||||
@@ -117,7 +117,7 @@ describe("DefaultManagedIdentity", () => {
|
||||
renderComponent();
|
||||
|
||||
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();
|
||||
});
|
||||
@@ -127,8 +127,8 @@ describe("DefaultManagedIdentity", () => {
|
||||
|
||||
const tooltip = screen.getByTestId("info-tooltip");
|
||||
expect(tooltip).toBeInTheDocument();
|
||||
expect(tooltip).toHaveTextContent("Learn more about");
|
||||
expect(tooltip).toHaveTextContent("Default Managed Identities.");
|
||||
expect(tooltip).toHaveTextContent(t(Keys.containerCopy.defaultManagedIdentity.tooltipContent));
|
||||
expect(tooltip).toHaveTextContent(t(Keys.containerCopy.defaultManagedIdentity.tooltipHrefText));
|
||||
});
|
||||
|
||||
it("should render the toggle button with correct initial state", () => {
|
||||
@@ -166,11 +166,11 @@ describe("DefaultManagedIdentity", () => {
|
||||
expect(popover).toBeInTheDocument();
|
||||
|
||||
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");
|
||||
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", () => {
|
||||
renderComponent();
|
||||
|
||||
const onText = screen.queryByText(ContainerCopyMessages.toggleBtn.onText);
|
||||
const offText = screen.queryByText(ContainerCopyMessages.toggleBtn.offText);
|
||||
const onText = screen.queryByText("On");
|
||||
const offText = screen.queryByText("Off");
|
||||
|
||||
expect(onText || offText).toBeTruthy();
|
||||
});
|
||||
@@ -348,7 +348,7 @@ describe("DefaultManagedIdentity", () => {
|
||||
it("should display correct link text in tooltip", () => {
|
||||
renderComponent();
|
||||
|
||||
const linkText = screen.getByText(ContainerCopyMessages.defaultManagedIdentity.tooltip.hrefText);
|
||||
const linkText = screen.getByText(t(Keys.containerCopy.defaultManagedIdentity.tooltipHrefText));
|
||||
expect(linkText).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+12
-9
@@ -1,7 +1,7 @@
|
||||
import { Link, Stack, Text, Toggle } from "@fluentui/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { updateDefaultIdentity } from "../../../../../Utils/arm/identityUtils";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import InfoTooltip from "../Components/InfoTooltip";
|
||||
import PopoverMessage from "../Components/PopoverContainer";
|
||||
@@ -11,14 +11,14 @@ import useToggle from "./hooks/useToggle";
|
||||
|
||||
const managedIdentityTooltip = (
|
||||
<Text>
|
||||
{ContainerCopyMessages.defaultManagedIdentity.tooltip.content}
|
||||
{t(Keys.containerCopy.defaultManagedIdentity.tooltipContent)}
|
||||
<Link
|
||||
style={{ color: "var(--colorBrandForeground1)" }}
|
||||
href={ContainerCopyMessages.defaultManagedIdentity.tooltip.href}
|
||||
href={t(Keys.containerCopy.defaultManagedIdentity.tooltipHref)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{ContainerCopyMessages.defaultManagedIdentity.tooltip.hrefText}
|
||||
{t(Keys.containerCopy.defaultManagedIdentity.tooltipHrefText)}
|
||||
</Link>
|
||||
</Text>
|
||||
);
|
||||
@@ -32,14 +32,15 @@ const DefaultManagedIdentity: React.FC<AddManagedIdentityProps> = () => {
|
||||
return (
|
||||
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||
<div className="toggle-label">
|
||||
{ContainerCopyMessages.defaultManagedIdentity.description(copyJobState?.target?.account?.name)}
|
||||
{t(Keys.containerCopy.defaultManagedIdentity.description, { accountName: copyJobState?.target?.account?.name })}{" "}
|
||||
|
||||
<InfoTooltip content={managedIdentityTooltip} />
|
||||
</div>
|
||||
<Toggle
|
||||
data-test="btn-toggle"
|
||||
checked={defaultSystemAssigned}
|
||||
onText={ContainerCopyMessages.toggleBtn.onText}
|
||||
offText={ContainerCopyMessages.toggleBtn.offText}
|
||||
onText={t(Keys.common.on)}
|
||||
offText={t(Keys.common.off)}
|
||||
onChange={onToggle}
|
||||
inlineLabel
|
||||
styles={{
|
||||
@@ -50,11 +51,13 @@ const DefaultManagedIdentity: React.FC<AddManagedIdentityProps> = () => {
|
||||
<PopoverMessage
|
||||
isLoading={loading}
|
||||
visible={defaultSystemAssigned}
|
||||
title={ContainerCopyMessages.defaultManagedIdentity.popoverTitle}
|
||||
title={t(Keys.containerCopy.defaultManagedIdentity.popoverTitle)}
|
||||
onCancel={() => onToggle(null, false)}
|
||||
onPrimary={handleAddSystemIdentity}
|
||||
>
|
||||
{ContainerCopyMessages.defaultManagedIdentity.popoverDescription(copyJobState?.target?.account?.name)}
|
||||
{t(Keys.containerCopy.defaultManagedIdentity.popoverDescription, {
|
||||
accountName: copyJobState?.target?.account?.name,
|
||||
})}
|
||||
</PopoverMessage>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
+25
-21
@@ -2,12 +2,12 @@ import "@testing-library/jest-dom";
|
||||
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { DatabaseAccount } from "Contracts/DataModels";
|
||||
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
||||
import { CapabilityNames } from "../../../../../Common/Constants";
|
||||
import { logError } from "../../../../../Common/Logger";
|
||||
import { update as updateDatabaseAccount } from "../../../../../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import OnlineCopyEnabled from "./OnlineCopyEnabled";
|
||||
|
||||
@@ -97,7 +97,9 @@ describe("OnlineCopyEnabled", () => {
|
||||
it("should render the description with account name", () => {
|
||||
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();
|
||||
});
|
||||
|
||||
@@ -105,10 +107,10 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const link = screen.getByRole("link", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.hrefText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.hrefText),
|
||||
});
|
||||
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("rel", "noopener noreferrer");
|
||||
});
|
||||
@@ -117,7 +119,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const button = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).not.toBeDisabled();
|
||||
@@ -134,7 +136,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const refreshButton = screen.queryByRole("button", {
|
||||
name: ContainerCopyMessages.refreshButtonLabel,
|
||||
name: "Refresh",
|
||||
});
|
||||
expect(refreshButton).not.toBeInTheDocument();
|
||||
});
|
||||
@@ -167,7 +169,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -222,7 +224,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -246,7 +248,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -259,7 +261,9 @@ describe("OnlineCopyEnabled", () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(ContainerCopyMessages.onlineCopyEnabled.enablingOnlineCopySpinnerLabel("test-account")),
|
||||
screen.getByText(
|
||||
t(Keys.containerCopy.onlineCopyEnabled.enablingOnlineCopySpinnerLabel, { accountName: "test-account" }),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -272,7 +276,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -306,7 +310,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -318,7 +322,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
});
|
||||
|
||||
const refreshButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.refreshButtonLabel,
|
||||
name: "Refresh",
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -349,7 +353,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -379,7 +383,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -401,7 +405,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -418,7 +422,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -436,7 +440,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -450,7 +454,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
mockFetchDatabaseAccount.mockImplementation(() => new Promise(() => {}));
|
||||
|
||||
const refreshButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.refreshButtonLabel,
|
||||
name: "Refresh",
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -536,7 +540,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent(contextWithNoCapabilities);
|
||||
|
||||
const enableButton = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
expect(enableButton).toBeInTheDocument();
|
||||
});
|
||||
@@ -547,7 +551,7 @@ describe("OnlineCopyEnabled", () => {
|
||||
renderComponent();
|
||||
|
||||
const button = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.onlineCopyEnabled.buttonText,
|
||||
name: t(Keys.containerCopy.onlineCopyEnabled.buttonText),
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
+11
-9
@@ -1,12 +1,12 @@
|
||||
import { Link, PrimaryButton, Stack } from "@fluentui/react";
|
||||
import { DatabaseAccount } from "Contracts/DataModels";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
||||
import { CapabilityNames } from "../../../../../Common/Constants";
|
||||
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
||||
import { logError } from "../../../../../Common/Logger";
|
||||
import { update as updateDatabaseAccount } from "../../../../../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
||||
import { AccountValidatorFn } from "../../../Types/CopyJobTypes";
|
||||
@@ -76,21 +76,23 @@ const OnlineCopyEnabled: React.FC = () => {
|
||||
setShowRefreshButton(false);
|
||||
|
||||
try {
|
||||
setLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel);
|
||||
setLoaderMessage(t(Keys.containerCopy.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel));
|
||||
const sourAccountBeforeUpdate = await fetchDatabaseAccount(
|
||||
sourceSubscriptionId,
|
||||
sourceResourceGroup,
|
||||
sourceAccountName,
|
||||
);
|
||||
if (!sourAccountBeforeUpdate?.properties.enableAllVersionsAndDeletesChangeFeed) {
|
||||
setLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel);
|
||||
setLoaderMessage(t(Keys.containerCopy.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel));
|
||||
await updateDatabaseAccount(sourceSubscriptionId, sourceResourceGroup, sourceAccountName, {
|
||||
properties: {
|
||||
enableAllVersionsAndDeletesChangeFeed: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
setLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.enablingOnlineCopySpinnerLabel(sourceAccountName));
|
||||
setLoaderMessage(
|
||||
t(Keys.containerCopy.onlineCopyEnabled.enablingOnlineCopySpinnerLabel, { accountName: sourceAccountName }),
|
||||
);
|
||||
await updateDatabaseAccount(sourceSubscriptionId, sourceResourceGroup, sourceAccountName, {
|
||||
properties: {
|
||||
capabilities: [...sourceAccountCapabilities, { name: CapabilityNames.EnableOnlineCopyFeature }],
|
||||
@@ -132,16 +134,16 @@ const OnlineCopyEnabled: React.FC = () => {
|
||||
<Stack className="onlineCopyContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
|
||||
<LoadingOverlay isLoading={loading} label={loaderMessage} />
|
||||
<Stack.Item className="info-message">
|
||||
{ContainerCopyMessages.onlineCopyEnabled.description(source?.account?.name || "")} 
|
||||
<Link href={ContainerCopyMessages.onlineCopyEnabled.href} target="_blank" rel="noopener noreferrer">
|
||||
{ContainerCopyMessages.onlineCopyEnabled.hrefText}
|
||||
{t(Keys.containerCopy.onlineCopyEnabled.description, { accountName: source?.account?.name || "" })} 
|
||||
<Link href={t(Keys.containerCopy.onlineCopyEnabled.href)} target="_blank" rel="noopener noreferrer">
|
||||
{t(Keys.containerCopy.onlineCopyEnabled.hrefText)}
|
||||
</Link>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
{showRefreshButton ? (
|
||||
<PrimaryButton
|
||||
className="fullWidth"
|
||||
text={ContainerCopyMessages.refreshButtonLabel}
|
||||
text={t(Keys.common.refresh)}
|
||||
iconProps={{ iconName: "Refresh" }}
|
||||
onClick={handleRefresh}
|
||||
disabled={loading}
|
||||
@@ -149,7 +151,7 @@ const OnlineCopyEnabled: React.FC = () => {
|
||||
) : (
|
||||
<PrimaryButton
|
||||
className="fullWidth"
|
||||
text={loading ? "" : ContainerCopyMessages.onlineCopyEnabled.buttonText}
|
||||
text={loading ? "" : t(Keys.containerCopy.onlineCopyEnabled.buttonText)}
|
||||
{...(loading ? { iconProps: { iconName: "SyncStatusSolid" } } : {})}
|
||||
disabled={loading}
|
||||
onClick={handleOnlineCopyEnable}
|
||||
|
||||
+8
-8
@@ -1,10 +1,10 @@
|
||||
import { Link, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||
import { DatabaseAccount } from "Contracts/DataModels";
|
||||
import { Keys, t } from "Localization";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { fetchDatabaseAccount } from "Utils/arm/databaseAccountUtils";
|
||||
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
||||
import { logError } from "../../../../../Common/Logger";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { buildResourceLink, getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
|
||||
import { AccountValidatorFn } from "../../../Types/CopyJobTypes";
|
||||
@@ -12,14 +12,14 @@ import InfoTooltip from "../Components/InfoTooltip";
|
||||
|
||||
const tooltipContent = (
|
||||
<Text>
|
||||
{ContainerCopyMessages.pointInTimeRestore.tooltip.content}
|
||||
{t(Keys.containerCopy.pointInTimeRestore.tooltipContent)}
|
||||
<Link
|
||||
style={{ color: "var(--colorBrandForeground1)" }}
|
||||
href={ContainerCopyMessages.pointInTimeRestore.tooltip.href}
|
||||
href={t(Keys.containerCopy.pointInTimeRestore.tooltipHref)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{ContainerCopyMessages.pointInTimeRestore.tooltip.hrefText}
|
||||
{t(Keys.containerCopy.pointInTimeRestore.tooltipHrefText)}
|
||||
</Link>
|
||||
</Text>
|
||||
);
|
||||
@@ -119,9 +119,9 @@ const PointInTimeRestore: React.FC = () => {
|
||||
|
||||
return (
|
||||
<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">
|
||||
{ContainerCopyMessages.pointInTimeRestore.description(source.account?.name ?? "")}
|
||||
{t(Keys.containerCopy.pointInTimeRestore.description, { accessName: source.account?.name ?? "" })}
|
||||
{tooltipContent && (
|
||||
<>
|
||||
{" "}
|
||||
@@ -134,7 +134,7 @@ const PointInTimeRestore: React.FC = () => {
|
||||
<PrimaryButton
|
||||
data-test="pointInTimeRestore:RefreshBtn"
|
||||
className="fullWidth"
|
||||
text={ContainerCopyMessages.refreshButtonLabel}
|
||||
text={t(Keys.common.refresh)}
|
||||
iconProps={{ iconName: "Refresh" }}
|
||||
onClick={handleRefresh}
|
||||
/>
|
||||
@@ -142,7 +142,7 @@ const PointInTimeRestore: React.FC = () => {
|
||||
<PrimaryButton
|
||||
data-test="pointInTimeRestore:PrimaryBtn"
|
||||
className="fullWidth"
|
||||
text={loading ? "" : ContainerCopyMessages.pointInTimeRestore.buttonText}
|
||||
text={loading ? "" : t(Keys.containerCopy.pointInTimeRestore.buttonText)}
|
||||
{...(loading ? { iconProps: { iconName: "SyncStatusSolid" } } : {})}
|
||||
disabled={loading}
|
||||
onClick={openWindowAndMonitor}
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@ exports[`AddManagedIdentity Snapshot Tests renders initial state correctly 1`] =
|
||||
<span
|
||||
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
|
||||
class="ms-Link root-111"
|
||||
@@ -95,7 +95,7 @@ exports[`AddManagedIdentity Snapshot Tests renders loading state 1`] = `
|
||||
<span
|
||||
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
|
||||
class="ms-Link root-111"
|
||||
@@ -267,7 +267,7 @@ exports[`AddManagedIdentity Snapshot Tests renders with toggle on and popover vi
|
||||
<span
|
||||
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
|
||||
class="ms-Link root-111"
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ exports[`DefaultManagedIdentity Edge Cases should handle null account 1`] = `
|
||||
<div
|
||||
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
|
||||
data-testid="info-tooltip"
|
||||
|
||||
+15
-13
@@ -1,7 +1,7 @@
|
||||
import { Keys, t } from "Localization";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { CapabilityNames } from "../../../../../../Common/Constants";
|
||||
import { fetchRoleAssignments, fetchRoleDefinitions, RoleDefinitionType } from "../../../../../../Utils/arm/RbacUtils";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { getAccountDetailsFromResourceId, getContainerIdentifiers, isIntraAccountCopy } from "../../../../CopyJobUtils";
|
||||
import {
|
||||
BackupPolicyType,
|
||||
@@ -44,7 +44,7 @@ export const SECTION_IDS = {
|
||||
const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
||||
{
|
||||
id: SECTION_IDS.addManagedIdentity,
|
||||
title: ContainerCopyMessages.addManagedIdentity.title,
|
||||
title: t(Keys.containerCopy.addManagedIdentity.title),
|
||||
Component: AddManagedIdentity,
|
||||
disabled: true,
|
||||
validate: (state: CopyJobContextState) => {
|
||||
@@ -57,7 +57,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
||||
},
|
||||
{
|
||||
id: SECTION_IDS.defaultManagedIdentity,
|
||||
title: ContainerCopyMessages.defaultManagedIdentity.title,
|
||||
title: t(Keys.containerCopy.defaultManagedIdentity.title),
|
||||
Component: DefaultManagedIdentity,
|
||||
disabled: true,
|
||||
validate: (state: CopyJobContextState) => {
|
||||
@@ -67,7 +67,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
||||
},
|
||||
{
|
||||
id: SECTION_IDS.readPermissionAssigned,
|
||||
title: ContainerCopyMessages.readPermissionAssigned.title,
|
||||
title: t(Keys.containerCopy.readPermissionAssigned.title),
|
||||
Component: AddReadPermissionToDefaultIdentity,
|
||||
disabled: true,
|
||||
validate: async (state: CopyJobContextState) => {
|
||||
@@ -95,7 +95,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
|
||||
const PERMISSION_SECTIONS_FOR_ONLINE_JOBS: PermissionSectionConfig[] = [
|
||||
{
|
||||
id: SECTION_IDS.pointInTimeRestore,
|
||||
title: ContainerCopyMessages.pointInTimeRestore.title,
|
||||
title: t(Keys.containerCopy.pointInTimeRestore.title),
|
||||
Component: PointInTimeRestore,
|
||||
disabled: true,
|
||||
validate: (state: CopyJobContextState) => {
|
||||
@@ -105,7 +105,7 @@ const PERMISSION_SECTIONS_FOR_ONLINE_JOBS: PermissionSectionConfig[] = [
|
||||
},
|
||||
{
|
||||
id: SECTION_IDS.onlineCopyEnabled,
|
||||
title: ContainerCopyMessages.onlineCopyEnabled.title,
|
||||
title: t(Keys.containerCopy.onlineCopyEnabled.title),
|
||||
Component: OnlineCopyEnabled,
|
||||
disabled: true,
|
||||
validate: (state: CopyJobContextState) => {
|
||||
@@ -194,11 +194,11 @@ const usePermissionSections = (state: CopyJobContextState): PermissionGroupConfi
|
||||
if (crossAccountSections.length > 0) {
|
||||
groups.push({
|
||||
id: "crossAccountConfigs",
|
||||
title: ContainerCopyMessages.assignPermissions.crossAccountConfiguration.title,
|
||||
description: ContainerCopyMessages.assignPermissions.crossAccountConfiguration.description(
|
||||
sourceAccountName,
|
||||
targetAccountName,
|
||||
),
|
||||
title: t(Keys.containerCopy.assignPermissions.crossAccountConfiguration.title),
|
||||
description: t(Keys.containerCopy.assignPermissions.crossAccountConfiguration.description, {
|
||||
sourceAccount: sourceAccountName,
|
||||
destinationAccount: targetAccountName,
|
||||
}),
|
||||
sections: crossAccountSections,
|
||||
});
|
||||
}
|
||||
@@ -206,8 +206,10 @@ const usePermissionSections = (state: CopyJobContextState): PermissionGroupConfi
|
||||
if (state.migrationType === CopyJobMigrationType.Online) {
|
||||
groups.push({
|
||||
id: "onlineConfigs",
|
||||
title: ContainerCopyMessages.assignPermissions.onlineConfiguration.title,
|
||||
description: ContainerCopyMessages.assignPermissions.onlineConfiguration.description(sourceAccountName),
|
||||
title: t(Keys.containerCopy.assignPermissions.onlineConfiguration.title),
|
||||
description: t(Keys.containerCopy.assignPermissions.onlineConfiguration.description, {
|
||||
accountName: sourceAccountName,
|
||||
}),
|
||||
sections: [...PERMISSION_SECTIONS_FOR_ONLINE_JOBS],
|
||||
});
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import PopoverMessage from "./PopoverContainer";
|
||||
|
||||
jest.mock("../../../../../Common/LoadingOverlay", () => {
|
||||
@@ -181,7 +181,7 @@ describe("PopoverMessage Component", () => {
|
||||
it("should use correct loading overlay label", () => {
|
||||
render(<PopoverMessage {...defaultProps} isLoading={true} />);
|
||||
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/display-name */
|
||||
import { DefaultButton, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import LoadingOverlay from "../../../../../Common/LoadingOverlay";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
|
||||
interface PopoverContainerProps {
|
||||
isLoading?: boolean;
|
||||
@@ -22,7 +22,7 @@ const PopoverContainer: React.FC<PopoverContainerProps> = React.memo(
|
||||
tokens={{ childrenGap: 20 }}
|
||||
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 }}>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
+7
-7
@@ -4,8 +4,8 @@ import { CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums"
|
||||
import { CopyJobContextProviderType } from "Explorer/ContainerCopy/Types/CopyJobTypes";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import AddCollectionPanelWrapper from "./AddCollectionPanelWrapper";
|
||||
|
||||
@@ -109,7 +109,7 @@ describe("AddCollectionPanelWrapper", () => {
|
||||
expect(container.querySelector(".addCollectionPanelWrapper")).toBeInTheDocument();
|
||||
expect(container.querySelector(".addCollectionPanelHeader")).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();
|
||||
});
|
||||
|
||||
@@ -138,7 +138,7 @@ describe("AddCollectionPanelWrapper", () => {
|
||||
it("should set header text to create container heading on mount", () => {
|
||||
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", () => {
|
||||
@@ -146,13 +146,13 @@ describe("AddCollectionPanelWrapper", () => {
|
||||
|
||||
unmount();
|
||||
|
||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createCopyJobPanelTitle);
|
||||
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.createCopyJob.panelTitle));
|
||||
});
|
||||
|
||||
it("should not change header text if already set correctly", () => {
|
||||
const modifiedSidePanelState = {
|
||||
...mockSidePanelState,
|
||||
headerText: ContainerCopyMessages.createContainerHeading,
|
||||
headerText: t(Keys.containerCopy.selectContainers.createContainerHeading),
|
||||
};
|
||||
|
||||
mockUseSidePanel.getState = jest.fn().mockReturnValue(modifiedSidePanelState);
|
||||
@@ -245,10 +245,10 @@ describe("AddCollectionPanelWrapper", () => {
|
||||
describe("Component Lifecycle", () => {
|
||||
it("should properly cleanup on unmount", () => {
|
||||
const { unmount } = render(<AddCollectionPanelWrapper />);
|
||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createContainerHeading);
|
||||
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.selectContainers.createContainerHeading));
|
||||
mockSetHeaderText.mockClear();
|
||||
unmount();
|
||||
expect(mockSetHeaderText).toHaveBeenCalledWith(ContainerCopyMessages.createCopyJobPanelTitle);
|
||||
expect(mockSetHeaderText).toHaveBeenCalledWith(t(Keys.containerCopy.createCopyJob.panelTitle));
|
||||
});
|
||||
|
||||
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 { useSidePanel } from "hooks/useSidePanel";
|
||||
import { produce } from "immer";
|
||||
import { Keys, t } from "Localization";
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import { AddCollectionPanel } from "../../../../Panes/AddCollectionPanel/AddCollectionPanel";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
|
||||
type AddCollectionPanelWrapperProps = {
|
||||
@@ -17,11 +17,11 @@ const AddCollectionPanelWrapper: React.FunctionComponent<AddCollectionPanelWrapp
|
||||
|
||||
useEffect(() => {
|
||||
const sidePanelStore = useSidePanel.getState();
|
||||
if (sidePanelStore.headerText !== ContainerCopyMessages.createContainerHeading) {
|
||||
sidePanelStore.setHeaderText(ContainerCopyMessages.createContainerHeading);
|
||||
if (sidePanelStore.headerText !== t(Keys.containerCopy.selectContainers.createContainerHeading)) {
|
||||
sidePanelStore.setHeaderText(t(Keys.containerCopy.selectContainers.createContainerHeading));
|
||||
}
|
||||
return () => {
|
||||
sidePanelStore.setHeaderText(ContainerCopyMessages.createCopyJobPanelTitle);
|
||||
sidePanelStore.setHeaderText(t(Keys.containerCopy.createCopyJob.panelTitle));
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -41,7 +41,7 @@ const AddCollectionPanelWrapper: React.FunctionComponent<AddCollectionPanelWrapp
|
||||
return (
|
||||
<Stack className="addCollectionPanelWrapper">
|
||||
<Stack.Item className="addCollectionPanelHeader">
|
||||
<Text className="themeText">{ContainerCopyMessages.createNewContainerSubHeading}</Text>
|
||||
<Text className="themeText">{t(Keys.containerCopy.selectContainers.createNewContainerSubHeading)}</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item className="addCollectionPanelBody">
|
||||
<AddCollectionPanel explorer={explorer} isCopyJobFlow={true} onSubmitSuccess={handleAddCollectionSuccess} />
|
||||
|
||||
+5
-4
@@ -1,6 +1,7 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, waitFor } from "@testing-library/react";
|
||||
import { Subscription } from "Contracts/DataModels";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { CopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums";
|
||||
@@ -350,7 +351,7 @@ describe("PreviewCopyJob", () => {
|
||||
expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function));
|
||||
});
|
||||
|
||||
it("should display proper field labels from ContainerCopyMessages", () => {
|
||||
it("should display proper field labels", () => {
|
||||
const mockContext = createMockContext();
|
||||
|
||||
const { getByText } = render(
|
||||
@@ -359,8 +360,8 @@ describe("PreviewCopyJob", () => {
|
||||
</CopyJobContext.Provider>,
|
||||
);
|
||||
|
||||
expect(getByText(/Job name/i)).toBeInTheDocument();
|
||||
expect(getByText(/Source subscription/i)).toBeInTheDocument();
|
||||
expect(getByText(/Source account/i)).toBeInTheDocument();
|
||||
expect(getByText(new RegExp(t(Keys.containerCopy.preview.jobNameLabel), "i"))).toBeInTheDocument();
|
||||
expect(getByText(new RegExp(t(Keys.containerCopy.preview.sourceSubscriptionLabel), "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 { Keys, t } from "Localization";
|
||||
import React, { useEffect } from "react";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { getDefaultJobName } from "../../../CopyJobUtils";
|
||||
import FieldRow from "../Components/FieldRow";
|
||||
@@ -32,17 +32,17 @@ const PreviewCopyJob: React.FC = () => {
|
||||
};
|
||||
return (
|
||||
<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} />
|
||||
</FieldRow>
|
||||
<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">
|
||||
{copyJobState.source?.subscription?.displayName}
|
||||
</Text>
|
||||
</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">
|
||||
{copyJobState.source?.account?.name}
|
||||
</Text>
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
import { IColumn } from "@fluentui/react";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
|
||||
const commonProps = {
|
||||
minWidth: 130,
|
||||
@@ -17,25 +17,25 @@ export const getPreviewCopyJobDetailsListColumns = (): IColumn[] => {
|
||||
return [
|
||||
{
|
||||
key: "sourcedbname",
|
||||
name: ContainerCopyMessages.sourceDatabaseLabel,
|
||||
name: t(Keys.containerCopy.preview.sourceDatabaseLabel),
|
||||
fieldName: "sourceDatabaseName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "sourcecolname",
|
||||
name: ContainerCopyMessages.sourceContainerLabel,
|
||||
name: t(Keys.containerCopy.preview.sourceContainerLabel),
|
||||
fieldName: "sourceContainerName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "targetdbname",
|
||||
name: ContainerCopyMessages.targetDatabaseLabel,
|
||||
name: t(Keys.containerCopy.preview.targetDatabaseLabel),
|
||||
fieldName: "targetDatabaseName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "targetcolname",
|
||||
name: ContainerCopyMessages.targetContainerLabel,
|
||||
name: t(Keys.containerCopy.preview.targetContainerLabel),
|
||||
fieldName: "targetContainerName",
|
||||
...commonProps,
|
||||
},
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { configContext, Platform } from "../../../../../../ConfigContext";
|
||||
import { DatabaseAccount } from "../../../../../../Contracts/DataModels";
|
||||
import * as useDatabaseAccountsHook from "../../../../../../hooks/useDatabaseAccounts";
|
||||
import { apiType, userContext } from "../../../../../../UserContext";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { CopyJobContext } from "../../../../Context/CopyJobContext";
|
||||
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
||||
import { CopyJobContextProviderType, CopyJobContextState } from "../../../../Types/CopyJobTypes";
|
||||
@@ -129,11 +129,11 @@ describe("AccountDropdown", () => {
|
||||
renderWithContext();
|
||||
|
||||
expect(
|
||||
screen.getByText(`${ContainerCopyMessages.sourceAccountDropdownLabel}:`, { exact: true }),
|
||||
screen.getByText(`${t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel)}:`, { exact: true }),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByRole("combobox")).toHaveAttribute(
|
||||
"aria-label",
|
||||
ContainerCopyMessages.sourceAccountDropdownLabel,
|
||||
t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -409,7 +409,7 @@ describe("AccountDropdown", () => {
|
||||
renderWithContext();
|
||||
|
||||
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", () => {
|
||||
|
||||
+4
-4
@@ -2,11 +2,11 @@
|
||||
/* eslint-disable react/display-name */
|
||||
import { Dropdown } from "@fluentui/react";
|
||||
import { configContext, Platform } from "ConfigContext";
|
||||
import { Keys, t } from "Localization";
|
||||
import React, { useEffect } from "react";
|
||||
import { DatabaseAccount } from "../../../../../../Contracts/DataModels";
|
||||
import { useDatabaseAccounts } from "../../../../../../hooks/useDatabaseAccounts";
|
||||
import { apiType, userContext } from "../../../../../../UserContext";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
||||
import FieldRow from "../../Components/FieldRow";
|
||||
|
||||
@@ -80,10 +80,10 @@ export const AccountDropdown: React.FC<AccountDropdownProps> = () => {
|
||||
const selectedAccountId = normalizeAccountId(copyJobState?.source?.account?.id ?? "");
|
||||
|
||||
return (
|
||||
<FieldRow label={ContainerCopyMessages.sourceAccountDropdownLabel}>
|
||||
<FieldRow label={t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel)}>
|
||||
<Dropdown
|
||||
placeholder={ContainerCopyMessages.sourceAccountDropdownPlaceholder}
|
||||
ariaLabel={ContainerCopyMessages.sourceAccountDropdownLabel}
|
||||
placeholder={t(Keys.containerCopy.selectAccount.sourceAccountDropdownPlaceholder)}
|
||||
ariaLabel={t(Keys.containerCopy.selectAccount.sourceAccountDropdownLabel)}
|
||||
options={accountOptions}
|
||||
disabled={isAccountDropdownDisabled}
|
||||
required
|
||||
|
||||
+13
-17
@@ -1,7 +1,7 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
||||
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
||||
import { MigrationType } from "./MigrationType";
|
||||
@@ -53,9 +53,9 @@ describe("MigrationType", () => {
|
||||
expect(screen.getByRole("radiogroup")).toBeInTheDocument();
|
||||
|
||||
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(onlineRadio).toBeInTheDocument();
|
||||
@@ -65,9 +65,9 @@ describe("MigrationType", () => {
|
||||
it("should render with online mode selected by default", () => {
|
||||
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", {
|
||||
name: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
||||
name: t(Keys.containerCopy.migrationType.offline.title),
|
||||
});
|
||||
|
||||
expect(onlineRadio).toBeChecked();
|
||||
@@ -86,9 +86,9 @@ describe("MigrationType", () => {
|
||||
render(<MigrationType />);
|
||||
|
||||
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(onlineRadio).not.toBeChecked();
|
||||
@@ -141,7 +141,7 @@ describe("MigrationType", () => {
|
||||
render(<MigrationType />);
|
||||
|
||||
const offlineRadio = screen.getByRole("radio", {
|
||||
name: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
||||
name: t(Keys.containerCopy.migrationType.offline.title),
|
||||
});
|
||||
fireEvent.click(offlineRadio);
|
||||
|
||||
@@ -167,7 +167,7 @@ describe("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);
|
||||
|
||||
expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function));
|
||||
@@ -198,11 +198,9 @@ describe("MigrationType", () => {
|
||||
render(<MigrationType />);
|
||||
|
||||
expect(
|
||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.offline.title }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }),
|
||||
screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.offline.title) }),
|
||||
).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(
|
||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.offline.title }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }),
|
||||
screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.offline.title) }),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByRole("radio", { name: t(Keys.containerCopy.migrationType.online.title) })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should handle null copyJobState gracefully", () => {
|
||||
|
||||
+6
-6
@@ -3,20 +3,20 @@
|
||||
import { ChoiceGroup, IChoiceGroupOption, Stack, Text } from "@fluentui/react";
|
||||
import MarkdownRender from "@nteract/markdown";
|
||||
import { useCopyJobContext } from "Explorer/ContainerCopy/Context/CopyJobContext";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums";
|
||||
|
||||
interface MigrationTypeProps {}
|
||||
const options: IChoiceGroupOption[] = [
|
||||
{
|
||||
key: CopyJobMigrationType.Offline,
|
||||
text: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
||||
text: t(Keys.containerCopy.migrationType.offline.title),
|
||||
styles: { root: { width: "33%" } },
|
||||
},
|
||||
{
|
||||
key: CopyJobMigrationType.Online,
|
||||
text: ContainerCopyMessages.migrationTypeOptions.online.title,
|
||||
text: t(Keys.containerCopy.migrationType.online.title),
|
||||
styles: { root: { width: "33%" } },
|
||||
},
|
||||
];
|
||||
@@ -47,8 +47,8 @@ export const MigrationType: React.FC<MigrationTypeProps> = React.memo(() => {
|
||||
};
|
||||
|
||||
const selectedKey = copyJobState?.migrationType ?? "";
|
||||
const selectedKeyLowercase = selectedKey.toLowerCase() as keyof typeof ContainerCopyMessages.migrationTypeOptions;
|
||||
const selectedKeyContent = ContainerCopyMessages.migrationTypeOptions[selectedKeyLowercase];
|
||||
const selectedKeyLowercase = selectedKey.toLowerCase() as keyof typeof Keys.containerCopy.migrationType;
|
||||
const selectedKeyContent = Keys.containerCopy.migrationType[selectedKeyLowercase];
|
||||
|
||||
return (
|
||||
<Stack data-test="migration-type" className="migrationTypeContainer">
|
||||
@@ -68,7 +68,7 @@ export const MigrationType: React.FC<MigrationTypeProps> = React.memo(() => {
|
||||
className="migrationTypeDescription"
|
||||
data-test={`migration-type-description-${selectedKeyLowercase}`}
|
||||
>
|
||||
<MarkdownRender source={selectedKeyContent.description} linkTarget="_blank" />
|
||||
<MarkdownRender source={t(selectedKeyContent.description)} linkTarget="_blank" />
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
)}
|
||||
|
||||
-5
@@ -8,14 +8,9 @@ import { SubscriptionDropdown } from "./SubscriptionDropdown";
|
||||
|
||||
jest.mock("../../../../../../hooks/useSubscriptions");
|
||||
jest.mock("../../../../../../UserContext");
|
||||
jest.mock("../../../../ContainerCopyMessages");
|
||||
|
||||
const mockUseSubscriptions = jest.requireMock("../../../../../../hooks/useSubscriptions").useSubscriptions;
|
||||
const mockUserContext = jest.requireMock("../../../../../../UserContext").userContext;
|
||||
const mockContainerCopyMessages = jest.requireMock("../../../../ContainerCopyMessages").default;
|
||||
|
||||
mockContainerCopyMessages.subscriptionDropdownLabel = "Subscription";
|
||||
mockContainerCopyMessages.subscriptionDropdownPlaceholder = "Select a subscription";
|
||||
|
||||
describe("SubscriptionDropdown", () => {
|
||||
let mockExplorer: Explorer;
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
/* eslint-disable react/display-name */
|
||||
import { Dropdown } from "@fluentui/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React, { useEffect } from "react";
|
||||
import { Subscription } from "../../../../../../Contracts/DataModels";
|
||||
import { useSubscriptions } from "../../../../../../hooks/useSubscriptions";
|
||||
import { userContext } from "../../../../../../UserContext";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../../Context/CopyJobContext";
|
||||
import FieldRow from "../../Components/FieldRow";
|
||||
|
||||
@@ -64,10 +64,10 @@ export const SubscriptionDropdown: React.FC<SubscriptionDropdownProps> = React.m
|
||||
const selectedSubscriptionId = copyJobState?.source?.subscription?.subscriptionId;
|
||||
|
||||
return (
|
||||
<FieldRow label={ContainerCopyMessages.subscriptionDropdownLabel}>
|
||||
<FieldRow label={t(Keys.containerCopy.selectAccount.subscriptionDropdownLabel)}>
|
||||
<Dropdown
|
||||
placeholder={ContainerCopyMessages.subscriptionDropdownPlaceholder}
|
||||
ariaLabel={ContainerCopyMessages.subscriptionDropdownLabel}
|
||||
placeholder={t(Keys.containerCopy.selectAccount.subscriptionDropdownPlaceholder)}
|
||||
ariaLabel={t(Keys.containerCopy.selectAccount.subscriptionDropdownLabel)}
|
||||
data-test="subscription-dropdown"
|
||||
options={subscriptionOptions}
|
||||
required
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Stack, Text } from "@fluentui/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { AccountDropdown } from "./Components/AccountDropdown";
|
||||
import { MigrationType } from "./Components/MigrationType";
|
||||
import { SubscriptionDropdown } from "./Components/SubscriptionDropdown";
|
||||
@@ -8,7 +8,7 @@ import { SubscriptionDropdown } from "./Components/SubscriptionDropdown";
|
||||
const SelectAccount = React.memo(() => {
|
||||
return (
|
||||
<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 />
|
||||
|
||||
|
||||
+25
-25
@@ -1,5 +1,6 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import { DatabaseModel } from "Contracts/DataModels";
|
||||
import React from "react";
|
||||
import Explorer from "../../../../../Explorer/Explorer";
|
||||
@@ -15,15 +16,6 @@ jest.mock("../../../../../hooks/useDataContainers", () => ({
|
||||
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", () => ({
|
||||
dropDownChangeHandler: jest.fn(() => () => jest.fn()),
|
||||
}));
|
||||
@@ -124,22 +116,26 @@ describe("SelectSourceAndTargetContainers", () => {
|
||||
describe("Component Rendering", () => {
|
||||
it("should render without crashing", () => {
|
||||
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", () => {
|
||||
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", () => {
|
||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render target container section", () => {
|
||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should return null when source is not available", () => {
|
||||
@@ -238,14 +234,14 @@ describe("SelectSourceAndTargetContainers", () => {
|
||||
describe("Component Props", () => {
|
||||
it("should pass showAddCollectionPanel to DatabaseContainerSection", () => {
|
||||
renderWithContext(<SelectSourceAndTargetContainers showAddCollectionPanel={mockShowAddCollectionPanel} />);
|
||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render without showAddCollectionPanel prop", () => {
|
||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||
|
||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -310,13 +306,13 @@ describe("SelectSourceAndTargetContainers", () => {
|
||||
it("should pass correct props to source DatabaseContainerSection", () => {
|
||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||
|
||||
expect(screen.getByText("Source Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Source container")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should pass correct props to target DatabaseContainerSection", () => {
|
||||
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", () => {
|
||||
@@ -329,7 +325,7 @@ describe("SelectSourceAndTargetContainers", () => {
|
||||
} as ReturnType<typeof useSourceAndTargetData>);
|
||||
|
||||
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", () => {
|
||||
@@ -342,7 +338,7 @@ describe("SelectSourceAndTargetContainers", () => {
|
||||
} as ReturnType<typeof useSourceAndTargetData>);
|
||||
|
||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||
expect(screen.getByText("Target Container")).toBeInTheDocument();
|
||||
expect(screen.getByText("Destination container")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -353,7 +349,9 @@ describe("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", () => {
|
||||
@@ -421,7 +419,9 @@ describe("SelectSourceAndTargetContainers", () => {
|
||||
it("should apply correct spacing tokens", () => {
|
||||
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", () => {
|
||||
renderWithContext(<SelectSourceAndTargetContainers />);
|
||||
|
||||
const description = screen.getByText("Select source and target containers for migration");
|
||||
const sourceSection = screen.getByText("Source Container");
|
||||
const targetSection = screen.getByText("Target Container");
|
||||
const description = screen.getByText("Please select a source container and a destination container to copy to.");
|
||||
const sourceSection = screen.getByText("Source container");
|
||||
const targetSection = screen.getByText("Destination container");
|
||||
|
||||
expect(description).toBeInTheDocument();
|
||||
expect(sourceSection).toBeInTheDocument();
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
import { Stack } from "@fluentui/react";
|
||||
import { DatabaseModel } from "Contracts/DataModels";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import { useDatabases } from "../../../../../hooks/useDatabases";
|
||||
import { useDataContainers } from "../../../../../hooks/useDataContainers";
|
||||
import ContainerCopyMessages from "../../../ContainerCopyMessages";
|
||||
import { useCopyJobContext } from "../../../Context/CopyJobContext";
|
||||
import { DatabaseContainerSection } from "./components/DatabaseContainerSection";
|
||||
import { dropDownChangeHandler } from "./Events/DropDownChangeHandler";
|
||||
@@ -52,9 +52,9 @@ const SelectSourceAndTargetContainers = ({ showAddCollectionPanel }: SelectSourc
|
||||
className="selectSourceAndTargetContainers"
|
||||
tokens={{ childrenGap: 25 }}
|
||||
>
|
||||
<span className="themeText">{ContainerCopyMessages.selectSourceAndTargetContainersDescription}</span>
|
||||
<span className="themeText">{t(Keys.containerCopy.selectContainers.description)}</span>
|
||||
<DatabaseContainerSection
|
||||
heading={ContainerCopyMessages.sourceContainerSubHeading}
|
||||
heading={t(Keys.containerCopy.selectContainers.sourceContainerSubHeading)}
|
||||
databaseOptions={sourceDatabaseOptions}
|
||||
selectedDatabase={source?.databaseId}
|
||||
databaseDisabled={false}
|
||||
@@ -66,7 +66,7 @@ const SelectSourceAndTargetContainers = ({ showAddCollectionPanel }: SelectSourc
|
||||
sectionType="source"
|
||||
/>
|
||||
<DatabaseContainerSection
|
||||
heading={ContainerCopyMessages.targetContainerSubHeading}
|
||||
heading={t(Keys.containerCopy.selectContainers.targetContainerSubHeading)}
|
||||
databaseOptions={targetDatabaseOptions}
|
||||
selectedDatabase={target?.databaseId}
|
||||
databaseDisabled={false}
|
||||
|
||||
+53
-31
@@ -1,7 +1,7 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { DatabaseContainerSectionProps, DropdownOptionType } from "../../../../Types/CopyJobTypes";
|
||||
import { DatabaseContainerSection } from "./DatabaseContainerSection";
|
||||
|
||||
@@ -60,11 +60,14 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
|
||||
expect(databaseDropdown).toBeInTheDocument();
|
||||
expect(databaseDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.databaseDropdownLabel);
|
||||
expect(databaseDropdown).toHaveAttribute(
|
||||
"aria-label",
|
||||
t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
);
|
||||
expect(databaseDropdown).not.toBeDisabled();
|
||||
});
|
||||
|
||||
@@ -72,30 +75,35 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
expect(containerDropdown).toBeInTheDocument();
|
||||
expect(containerDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.containerDropdownLabel);
|
||||
expect(containerDropdown).toHaveAttribute(
|
||||
"aria-label",
|
||||
t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
);
|
||||
expect(containerDropdown).not.toBeDisabled();
|
||||
});
|
||||
|
||||
it("renders database label correctly", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText(`${ContainerCopyMessages.databaseDropdownLabel}:`)).toBeInTheDocument();
|
||||
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}:`)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders container label correctly", () => {
|
||||
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", () => {
|
||||
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", () => {
|
||||
@@ -107,7 +115,7 @@ describe("DatabaseContainerSection", () => {
|
||||
const createButton = container.querySelector(".create-container-link-btn");
|
||||
|
||||
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} />);
|
||||
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
|
||||
expect(databaseDropdown).toHaveAttribute("aria-disabled", "true");
|
||||
@@ -136,7 +144,7 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...propsWithDisabledContainer} />);
|
||||
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
expect(containerDropdown).toHaveAttribute("aria-disabled", "true");
|
||||
@@ -152,10 +160,10 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...propsWithFalsyDisabled} />);
|
||||
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
expect(databaseDropdown).not.toHaveAttribute("aria-disabled", "true");
|
||||
@@ -167,21 +175,27 @@ describe("DatabaseContainerSection", () => {
|
||||
it("calls databaseOnChange when database dropdown selection changes", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
|
||||
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", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
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", () => {
|
||||
@@ -192,7 +206,7 @@ describe("DatabaseContainerSection", () => {
|
||||
|
||||
render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
||||
|
||||
const createButton = screen.getByText(ContainerCopyMessages.createContainerButtonLabel);
|
||||
const createButton = screen.getByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel));
|
||||
fireEvent.click(createButton);
|
||||
|
||||
expect(mockHandleOnDemandCreateContainer).toHaveBeenCalledTimes(1);
|
||||
@@ -235,10 +249,10 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...propsWithEmptyOptions} />);
|
||||
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
expect(databaseDropdown).toBeInTheDocument();
|
||||
@@ -251,24 +265,30 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
expect(databaseDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.databaseDropdownLabel);
|
||||
expect(containerDropdown).toHaveAttribute("aria-label", ContainerCopyMessages.containerDropdownLabel);
|
||||
expect(databaseDropdown).toHaveAttribute(
|
||||
"aria-label",
|
||||
t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
);
|
||||
expect(containerDropdown).toHaveAttribute(
|
||||
"aria-label",
|
||||
t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
);
|
||||
});
|
||||
|
||||
it("has proper required attributes for dropdowns", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
|
||||
const databaseDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.databaseDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.databaseDropdownLabel),
|
||||
});
|
||||
const containerDropdown = screen.getByRole("combobox", {
|
||||
name: ContainerCopyMessages.containerDropdownLabel,
|
||||
name: t(Keys.containerCopy.selectContainers.containerDropdownLabel),
|
||||
});
|
||||
|
||||
expect(databaseDropdown).toHaveAttribute("aria-required", "true");
|
||||
@@ -278,8 +298,8 @@ describe("DatabaseContainerSection", () => {
|
||||
it("maintains proper label associations", () => {
|
||||
render(<DatabaseContainerSection {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText(`${ContainerCopyMessages.databaseDropdownLabel}:`)).toBeInTheDocument();
|
||||
expect(screen.getByText(`${ContainerCopyMessages.containerDropdownLabel}:`)).toBeInTheDocument();
|
||||
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}:`)).toBeInTheDocument();
|
||||
expect(screen.getByText(`${t(Keys.containerCopy.selectContainers.containerDropdownLabel)}:`)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -299,7 +319,9 @@ describe("DatabaseContainerSection", () => {
|
||||
render(<DatabaseContainerSection {...minimalProps} />);
|
||||
|
||||
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", () => {
|
||||
@@ -366,7 +388,7 @@ describe("DatabaseContainerSection", () => {
|
||||
|
||||
const { container } = render(<DatabaseContainerSection {...propsWithCreateHandler} />);
|
||||
|
||||
const createButton = screen.getByText(ContainerCopyMessages.createContainerButtonLabel);
|
||||
const createButton = screen.getByText(t(Keys.containerCopy.selectContainers.createContainerButtonLabel));
|
||||
expect(createButton).toBeInTheDocument();
|
||||
|
||||
const containerSection = container.querySelector(".databaseContainerSection");
|
||||
@@ -381,7 +403,7 @@ describe("DatabaseContainerSection", () => {
|
||||
|
||||
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 { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../../../ContainerCopyMessages";
|
||||
import { DatabaseContainerSectionProps } from "../../../../Types/CopyJobTypes";
|
||||
import FieldRow from "../../Components/FieldRow";
|
||||
|
||||
@@ -19,10 +19,10 @@ export const DatabaseContainerSection = ({
|
||||
}: DatabaseContainerSectionProps) => (
|
||||
<Stack tokens={{ childrenGap: 15 }} className="databaseContainerSection">
|
||||
<label className="subHeading">{heading}</label>
|
||||
<FieldRow label={ContainerCopyMessages.databaseDropdownLabel}>
|
||||
<FieldRow label={t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}>
|
||||
<Dropdown
|
||||
placeholder={ContainerCopyMessages.databaseDropdownPlaceholder}
|
||||
ariaLabel={ContainerCopyMessages.databaseDropdownLabel}
|
||||
placeholder={t(Keys.containerCopy.selectContainers.databaseDropdownPlaceholder)}
|
||||
ariaLabel={t(Keys.containerCopy.selectContainers.databaseDropdownLabel)}
|
||||
options={databaseOptions}
|
||||
required
|
||||
disabled={!!databaseDisabled}
|
||||
@@ -31,11 +31,11 @@ export const DatabaseContainerSection = ({
|
||||
data-test={`${sectionType}-databaseDropdown`}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow label={ContainerCopyMessages.containerDropdownLabel}>
|
||||
<FieldRow label={t(Keys.containerCopy.selectContainers.containerDropdownLabel)}>
|
||||
<Stack>
|
||||
<Dropdown
|
||||
placeholder={ContainerCopyMessages.containerDropdownPlaceholder}
|
||||
ariaLabel={ContainerCopyMessages.containerDropdownLabel}
|
||||
placeholder={t(Keys.containerCopy.selectContainers.containerDropdownPlaceholder)}
|
||||
ariaLabel={t(Keys.containerCopy.selectContainers.containerDropdownLabel)}
|
||||
options={containerOptions}
|
||||
required
|
||||
disabled={!!containerDisabled}
|
||||
@@ -49,7 +49,7 @@ export const DatabaseContainerSection = ({
|
||||
style={{ color: "var(--colorBrandForeground1)" }}
|
||||
onClick={() => handleOnDemandCreateContainer()}
|
||||
>
|
||||
{ContainerCopyMessages.createContainerButtonLabel}
|
||||
{t(Keys.containerCopy.selectContainers.createContainerButtonLabel)}
|
||||
</ActionButton>
|
||||
)}
|
||||
</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", () => {
|
||||
const createMockJob = (overrides: Partial<CopyJobType> = {}): CopyJobType =>
|
||||
({
|
||||
@@ -301,7 +279,7 @@ describe("CopyJobActionMenu", () => {
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||
"Confirm Action",
|
||||
"",
|
||||
null,
|
||||
"Confirm",
|
||||
expect.any(Function),
|
||||
@@ -358,7 +336,7 @@ describe("CopyJobActionMenu", () => {
|
||||
fireEvent.click(completeButton);
|
||||
|
||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||
"Confirm Action",
|
||||
"",
|
||||
null,
|
||||
"Confirm",
|
||||
expect.any(Function),
|
||||
@@ -402,7 +380,7 @@ describe("CopyJobActionMenu", () => {
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||
"Confirm Action",
|
||||
"",
|
||||
null,
|
||||
"Confirm",
|
||||
expect.any(Function),
|
||||
@@ -433,7 +411,7 @@ describe("CopyJobActionMenu", () => {
|
||||
fireEvent.click(completeButton);
|
||||
|
||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||
"Confirm Action",
|
||||
"",
|
||||
null,
|
||||
"Confirm",
|
||||
expect.any(Function),
|
||||
@@ -849,7 +827,7 @@ describe("CopyJobActionMenu", () => {
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(mockShowOkCancelModalDialog).toHaveBeenCalledWith(
|
||||
"Confirm Action", // title
|
||||
"", // title
|
||||
null, // subText
|
||||
"Confirm", // confirmLabel
|
||||
expect.any(Function), // onOk
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DirectionalHint, IconButton, IContextualMenuProps, Stack } from "@fluentui/react";
|
||||
import React from "react";
|
||||
import { useDialog } from "../../../Controls/Dialog";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
import { CopyJobActions, CopyJobMigrationType, CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
||||
|
||||
@@ -49,11 +49,11 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkCancelModalDialog(
|
||||
ContainerCopyMessages.MonitorJobs.dialog.heading,
|
||||
"",
|
||||
null,
|
||||
ContainerCopyMessages.MonitorJobs.dialog.confirmButtonText,
|
||||
t(Keys.common.confirm),
|
||||
() => handleClick(job, action, setUpdatingJobAction),
|
||||
ContainerCopyMessages.MonitorJobs.dialog.cancelButtonText,
|
||||
t(Keys.common.cancel),
|
||||
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 = [
|
||||
{
|
||||
key: CopyJobActions.pause,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.pause,
|
||||
text: t(Keys.containerCopy.monitorJobs.actions.pause),
|
||||
iconProps: { iconName: "Pause" },
|
||||
onClick: () => handleClick(job, CopyJobActions.pause, setUpdatingJobAction),
|
||||
disabled: isThisJobUpdating,
|
||||
},
|
||||
{
|
||||
key: CopyJobActions.cancel,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.cancel,
|
||||
text: t(Keys.common.cancel),
|
||||
iconProps: { iconName: "Cancel" },
|
||||
onClick: () => showActionConfirmationDialog(job, CopyJobActions.cancel),
|
||||
disabled: isThisJobUpdating,
|
||||
},
|
||||
{
|
||||
key: CopyJobActions.resume,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.resume,
|
||||
text: t(Keys.containerCopy.monitorJobs.actions.resume),
|
||||
iconProps: { iconName: "Play" },
|
||||
onClick: () => handleClick(job, CopyJobActions.resume, setUpdatingJobAction),
|
||||
disabled: isThisJobUpdating,
|
||||
@@ -101,7 +101,7 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
||||
if ((job.Mode ?? "").toLowerCase() === CopyJobMigrationType.Online) {
|
||||
filteredItems.push({
|
||||
key: CopyJobActions.complete,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.complete,
|
||||
text: t(Keys.containerCopy.monitorJobs.actions.complete),
|
||||
iconProps: { iconName: "CheckMark" },
|
||||
onClick: () => showActionConfirmationDialog(job, CopyJobActions.complete),
|
||||
disabled: isThisJobUpdating,
|
||||
@@ -124,8 +124,8 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
|
||||
iconProps={{ iconName: "More", styles: { root: { fontSize: "20px", fontWeight: "bold" } } }}
|
||||
menuProps={{ items: getMenuItems(), directionalHint: DirectionalHint.leftTopEdge, directionalHintFixed: false }}
|
||||
menuIconProps={{ iconName: "", className: "hidden" }}
|
||||
ariaLabel={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
||||
title={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
||||
ariaLabel={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||
title={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { IColumn } from "@fluentui/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import { render } from "@testing-library/react";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
||||
import { getColumns } from "./CopyJobColumns";
|
||||
@@ -79,14 +79,14 @@ describe("CopyJobColumns", () => {
|
||||
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);
|
||||
|
||||
expect(columns[0].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.lastUpdatedTime);
|
||||
expect(columns[1].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.name);
|
||||
expect(columns[2].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.mode);
|
||||
expect(columns[3].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.completionPercentage);
|
||||
expect(columns[4].name).toBe(ContainerCopyMessages.MonitorJobs.Columns.status);
|
||||
expect(columns[0].name).toBe(t(Keys.containerCopy.monitorJobs.columns.lastUpdatedTime));
|
||||
expect(columns[1].name).toBe(t(Keys.containerCopy.monitorJobs.columns.name));
|
||||
expect(columns[2].name).toBe(t(Keys.containerCopy.monitorJobs.columns.mode));
|
||||
expect(columns[3].name).toBe(t(Keys.containerCopy.monitorJobs.columns.completionPercentage));
|
||||
expect(columns[4].name).toBe(t(Keys.containerCopy.monitorJobs.columns.status));
|
||||
expect(columns[5].name).toBe("");
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IColumn } from "@fluentui/react";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
import { CopyJobType, HandleJobActionClickType } from "../../Types/CopyJobTypes";
|
||||
import CopyJobActionMenu from "./CopyJobActionMenu";
|
||||
import CopyJobStatusWithIcon from "./CopyJobStatusWithIcon";
|
||||
@@ -13,7 +13,7 @@ export const getColumns = (
|
||||
): IColumn[] => [
|
||||
{
|
||||
key: "LastUpdatedTime",
|
||||
name: ContainerCopyMessages.MonitorJobs.Columns.lastUpdatedTime,
|
||||
name: t(Keys.containerCopy.monitorJobs.columns.lastUpdatedTime),
|
||||
fieldName: "LastUpdatedTime",
|
||||
minWidth: 140,
|
||||
maxWidth: 300,
|
||||
@@ -24,7 +24,7 @@ export const getColumns = (
|
||||
},
|
||||
{
|
||||
key: "Name",
|
||||
name: ContainerCopyMessages.MonitorJobs.Columns.name,
|
||||
name: t(Keys.containerCopy.monitorJobs.columns.name),
|
||||
fieldName: "Name",
|
||||
minWidth: 140,
|
||||
maxWidth: 300,
|
||||
@@ -36,7 +36,7 @@ export const getColumns = (
|
||||
},
|
||||
{
|
||||
key: "Mode",
|
||||
name: ContainerCopyMessages.MonitorJobs.Columns.mode,
|
||||
name: t(Keys.containerCopy.monitorJobs.columns.mode),
|
||||
fieldName: "Mode",
|
||||
minWidth: 90,
|
||||
maxWidth: 200,
|
||||
@@ -47,7 +47,7 @@ export const getColumns = (
|
||||
},
|
||||
{
|
||||
key: "CompletionPercentage",
|
||||
name: ContainerCopyMessages.MonitorJobs.Columns.completionPercentage,
|
||||
name: t(Keys.containerCopy.monitorJobs.columns.completionPercentage),
|
||||
fieldName: "CompletionPercentage",
|
||||
minWidth: 110,
|
||||
maxWidth: 200,
|
||||
@@ -59,7 +59,7 @@ export const getColumns = (
|
||||
},
|
||||
{
|
||||
key: "CopyJobStatus",
|
||||
name: ContainerCopyMessages.MonitorJobs.Columns.status,
|
||||
name: t(Keys.containerCopy.monitorJobs.columns.status),
|
||||
fieldName: "Status",
|
||||
minWidth: 130,
|
||||
maxWidth: 200,
|
||||
|
||||
@@ -13,22 +13,6 @@ jest.mock("./CopyJobStatusWithIcon", () => {
|
||||
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", () => {
|
||||
const mockBasicJob: CopyJobType = {
|
||||
ID: "test-job-1",
|
||||
@@ -102,7 +86,7 @@ describe("CopyJobDetails", () => {
|
||||
expect(screen.getByText("Date & time")).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("Mode")).toBeInTheDocument();
|
||||
@@ -322,7 +306,7 @@ describe("CopyJobDetails", () => {
|
||||
render(<CopyJobDetails job={mockBasicJob} />);
|
||||
|
||||
const dateTimeHeading = screen.getByText("Date & time");
|
||||
const sourceAccountHeading = screen.getByText("Source Account");
|
||||
const sourceAccountHeading = screen.getByText("Source account");
|
||||
const modeHeading = screen.getByText("Mode");
|
||||
|
||||
expect(dateTimeHeading).toHaveClass("bold");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DetailsList, DetailsListLayoutMode, IColumn, Stack, Text } from "@fluentui/react";
|
||||
import React, { memo } from "react";
|
||||
import { useThemeStore } from "../../../../hooks/useTheme";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||
import { CopyJobType } from "../../Types/CopyJobTypes";
|
||||
import CopyJobStatusWithIcon from "./CopyJobStatusWithIcon";
|
||||
@@ -31,31 +31,31 @@ const getCopyJobDetailsListColumns = (): IColumn[] => {
|
||||
return [
|
||||
{
|
||||
key: "sourcedbcol",
|
||||
name: ContainerCopyMessages.sourceDatabaseLabel,
|
||||
name: t(Keys.containerCopy.preview.sourceDatabaseLabel),
|
||||
fieldName: "sourceDatabaseName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "sourcecol",
|
||||
name: ContainerCopyMessages.sourceContainerLabel,
|
||||
name: t(Keys.containerCopy.preview.sourceContainerLabel),
|
||||
fieldName: "sourceContainerName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "targetdbcol",
|
||||
name: ContainerCopyMessages.targetDatabaseLabel,
|
||||
name: t(Keys.containerCopy.preview.targetDatabaseLabel),
|
||||
fieldName: "targetDatabaseName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "targetcol",
|
||||
name: ContainerCopyMessages.targetContainerLabel,
|
||||
name: t(Keys.containerCopy.preview.targetContainerLabel),
|
||||
fieldName: "targetContainerName",
|
||||
...commonProps,
|
||||
},
|
||||
{
|
||||
key: "statuscol",
|
||||
name: ContainerCopyMessages.MonitorJobs.Columns.status,
|
||||
name: t(Keys.containerCopy.monitorJobs.columns.status),
|
||||
fieldName: "jobStatus",
|
||||
onRender: ({ jobStatus }: { jobStatus: CopyJobStatusType }) => <CopyJobStatusWithIcon status={jobStatus} />,
|
||||
...commonProps,
|
||||
@@ -92,7 +92,7 @@ const CopyJobDetails: React.FC<CopyJobDetailsProps> = ({ job }) => {
|
||||
{job.Error ? (
|
||||
<Stack.Item data-testid="error-stack" style={sectionCss.verticalAlign}>
|
||||
<Text className="bold themeText" style={sectionCss.headingText}>
|
||||
{ContainerCopyMessages.errorTitle}
|
||||
{t(Keys.containerCopy.jobDetails.errorTitle)}
|
||||
</Text>
|
||||
<Text as="pre" style={errorMessageStyle}>
|
||||
{job.Error.message}
|
||||
@@ -102,15 +102,15 @@ const CopyJobDetails: React.FC<CopyJobDetailsProps> = ({ job }) => {
|
||||
<Stack.Item data-testid="selectedcollection-stack">
|
||||
<Stack tokens={{ childrenGap: 15 }}>
|
||||
<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>
|
||||
</Stack.Item>
|
||||
<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>
|
||||
</Stack.Item>
|
||||
<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>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FontIcon, mergeStyles, Spinner, SpinnerSize, Stack, Text } from "@fluentui/react";
|
||||
import PropTypes from "prop-types";
|
||||
import React from "react";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
import { Keys, t } from "Localization";
|
||||
import { CopyJobStatusType } from "../../Enums/CopyJobEnums";
|
||||
|
||||
const iconClass = mergeStyles({
|
||||
@@ -30,12 +30,25 @@ const statusIconColors: Partial<Record<CopyJobStatusType, string>> = {
|
||||
[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 {
|
||||
status: CopyJobStatusType;
|
||||
}
|
||||
|
||||
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 = [
|
||||
CopyJobStatusType.Running,
|
||||
|
||||
@@ -3,9 +3,9 @@ jest.mock("../../Actions/CopyJobActions");
|
||||
import "@testing-library/jest-dom";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { Keys, t } from "Localization";
|
||||
import React from "react";
|
||||
import * as Actions from "../../Actions/CopyJobActions";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
import CopyJobsNotFound from "./CopyJobs.NotFound";
|
||||
|
||||
describe("CopyJobsNotFound", () => {
|
||||
@@ -22,10 +22,10 @@ describe("CopyJobsNotFound", () => {
|
||||
const image = container.querySelector(".notFoundContainer .ms-Image");
|
||||
expect(image).toBeInTheDocument();
|
||||
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", {
|
||||
name: ContainerCopyMessages.createCopyJobButtonText,
|
||||
name: t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText),
|
||||
});
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).toHaveClass("createCopyJobButton");
|
||||
@@ -45,7 +45,7 @@ describe("CopyJobsNotFound", () => {
|
||||
render(<CopyJobsNotFound explorer={mockExplorer} />);
|
||||
|
||||
const button = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.createCopyJobButtonText,
|
||||
name: t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText),
|
||||
});
|
||||
|
||||
fireEvent.click(button);
|
||||
@@ -58,11 +58,11 @@ describe("CopyJobsNotFound", () => {
|
||||
render(<CopyJobsNotFound explorer={mockExplorer} />);
|
||||
|
||||
const button = screen.getByRole("button", {
|
||||
name: ContainerCopyMessages.createCopyJobButtonText,
|
||||
name: t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText),
|
||||
});
|
||||
|
||||
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", () => {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { ActionButton, Image } from "@fluentui/react";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import React from "react";
|
||||
import CopyJobIcon from "../../../../../images/ContainerCopy/copy-jobs.svg";
|
||||
import { Keys, t } from "Localization";
|
||||
import * as Actions from "../../Actions/CopyJobActions";
|
||||
import ContainerCopyMessages from "../../ContainerCopyMessages";
|
||||
|
||||
interface CopyJobsNotFoundProps {
|
||||
explorer: Explorer;
|
||||
@@ -12,14 +12,14 @@ interface CopyJobsNotFoundProps {
|
||||
const CopyJobsNotFound: React.FC<CopyJobsNotFoundProps> = ({ explorer }) => {
|
||||
return (
|
||||
<div className="notFoundContainer flexContainer centerContent">
|
||||
<Image src={CopyJobIcon} alt={ContainerCopyMessages.noCopyJobsTitle} width={100} height={100} />
|
||||
<h4 className="noCopyJobsMessage">{ContainerCopyMessages.noCopyJobsTitle}</h4>
|
||||
<Image src={CopyJobIcon} alt={t(Keys.containerCopy.noCopyJobs.title)} width={100} height={100} />
|
||||
<h4 className="noCopyJobsMessage">{t(Keys.containerCopy.noCopyJobs.title)}</h4>
|
||||
<ActionButton
|
||||
allowDisabledFocus
|
||||
className="createCopyJobButton"
|
||||
onClick={() => Actions.openCreateCopyJobPanel(explorer)}
|
||||
>
|
||||
{ContainerCopyMessages.createCopyJobButtonText}
|
||||
{t(Keys.containerCopy.noCopyJobs.createCopyJobButtonText)}
|
||||
</ActionButton>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
resumeDataTransferJob,
|
||||
} from "Common/dataAccess/dataTransfers";
|
||||
import { Platform, configContext } from "ConfigContext";
|
||||
import ContainerCopyMessages from "Explorer/ContainerCopy/ContainerCopyMessages";
|
||||
import { CopyJobActions, CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums";
|
||||
import { useDialog } from "Explorer/Controls/Dialog";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
@@ -174,7 +173,8 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
action === CopyJobActions.cancel ? (
|
||||
<Stack tokens={{ childrenGap: 10 }}>
|
||||
<Stack.Item>
|
||||
{/*t(Keys.controls.settings.partitionKeyEditor.confirmCancel1)*/}<br />
|
||||
{/*t(Keys.controls.settings.partitionKeyEditor.confirmCancel1)*/}
|
||||
<br />
|
||||
<b>{jobName}</b>
|
||||
</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 ? (
|
||||
<Stack tokens={{ childrenGap: 10 }}>
|
||||
<Stack.Item>
|
||||
{/*t(Keys.controls.settings.partitionKeyEditor.confirmComplete1)*/}<br />
|
||||
{/*t(Keys.controls.settings.partitionKeyEditor.confirmComplete1)*/}
|
||||
<br />
|
||||
<b>{jobName}</b>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
{/*t(Keys.controls.settings.partitionKeyEditor.confrimComplete2)*/}
|
||||
</Stack.Item>
|
||||
<Stack.Item>{/*t(Keys.controls.settings.partitionKeyEditor.confrimComplete2)*/}</Stack.Item>
|
||||
</Stack>
|
||||
) : null;
|
||||
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkCancelModalDialog(
|
||||
ContainerCopyMessages.MonitorJobs.dialog.heading,
|
||||
null,
|
||||
ContainerCopyMessages.MonitorJobs.dialog.confirmButtonText,
|
||||
onConfirm,
|
||||
ContainerCopyMessages.MonitorJobs.dialog.cancelButtonText,
|
||||
null,
|
||||
dialogBody,
|
||||
);
|
||||
.showOkCancelModalDialog("", null, t(Keys.common.confirm), onConfirm, t(Keys.common.cancel), null, dialogBody);
|
||||
};
|
||||
|
||||
const getOnlineJobMenuProps = (currentJob: DataTransferJobGetResults): IContextualMenuProps => {
|
||||
@@ -213,7 +204,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
if (!isPaused) {
|
||||
items.push({
|
||||
key: CopyJobActions.pause,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.pause,
|
||||
text: t(Keys.containerCopy.monitorJobs.actions.pause),
|
||||
iconProps: { iconName: "Pause" },
|
||||
onClick: () => {
|
||||
pauseRunningDataTransferJob(currentJob);
|
||||
@@ -224,7 +215,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
if (isPaused) {
|
||||
items.push({
|
||||
key: CopyJobActions.resume,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.resume,
|
||||
text: t(Keys.containerCopy.monitorJobs.actions.resume),
|
||||
iconProps: { iconName: "Play" },
|
||||
onClick: () => {
|
||||
resumePausedDataTransferJob(currentJob);
|
||||
@@ -234,7 +225,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
|
||||
items.push({
|
||||
key: CopyJobActions.cancel,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.cancel,
|
||||
text: t(Keys.common.cancel),
|
||||
iconProps: { iconName: "Cancel" },
|
||||
onClick: () =>
|
||||
showActionConfirmationDialog(currentJob, CopyJobActions.cancel, () => cancelRunningDataTransferJob(currentJob)),
|
||||
@@ -242,7 +233,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
|
||||
items.push({
|
||||
key: CopyJobActions.complete,
|
||||
text: ContainerCopyMessages.MonitorJobs.Actions.complete,
|
||||
text: t(Keys.containerCopy.monitorJobs.actions.complete),
|
||||
iconProps: { iconName: "CheckMark" },
|
||||
onClick: () =>
|
||||
showActionConfirmationDialog(currentJob, CopyJobActions.complete, () =>
|
||||
@@ -290,9 +281,9 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
const processedCountString =
|
||||
totalCount > 0
|
||||
? t(Keys.controls.settings.partitionKeyEditor.documentsProcessed, {
|
||||
processedCount: String(processedCount),
|
||||
totalCount: String(totalCount),
|
||||
})
|
||||
processedCount: String(processedCount),
|
||||
totalCount: String(totalCount),
|
||||
})
|
||||
: "";
|
||||
return `${portalDataTransferJob?.properties?.status} ${processedCountString}`;
|
||||
};
|
||||
@@ -418,8 +409,8 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
}}
|
||||
menuProps={getOnlineJobMenuProps(portalDataTransferJob)}
|
||||
menuIconProps={{ iconName: "", className: "hidden" }}
|
||||
ariaLabel={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
||||
title={ContainerCopyMessages.MonitorJobs.Columns.actions}
|
||||
ariaLabel={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||
title={t(Keys.containerCopy.monitorJobs.columns.actions)}
|
||||
/>
|
||||
) : (
|
||||
<DefaultButton
|
||||
|
||||
@@ -30,7 +30,6 @@ import {
|
||||
getPartitionKeySubtext,
|
||||
getPartitionKeyTooltipText,
|
||||
} from "Explorer/Controls/Settings/SettingsUtils";
|
||||
import ContainerCopyMessages from "Explorer/ContainerCopy/ContainerCopyMessages";
|
||||
import { BackupPolicyType, CopyJobMigrationType } from "Explorer/ContainerCopy/Enums/CopyJobEnums";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { RightPaneForm } from "Explorer/Panes/RightPaneForm/RightPaneForm";
|
||||
@@ -54,12 +53,12 @@ export interface ChangePartitionKeyPaneProps {
|
||||
const migrationTypeOptions: IChoiceGroupOption[] = [
|
||||
{
|
||||
key: CopyJobMigrationType.Offline,
|
||||
text: ContainerCopyMessages.migrationTypeOptions.offline.title,
|
||||
text: t(Keys.containerCopy.migrationType.offline.title),
|
||||
styles: { root: { width: "33%" } },
|
||||
},
|
||||
{
|
||||
key: CopyJobMigrationType.Online,
|
||||
text: ContainerCopyMessages.migrationTypeOptions.online.title,
|
||||
text: t(Keys.containerCopy.migrationType.online.title),
|
||||
styles: { root: { width: "33%" } },
|
||||
},
|
||||
];
|
||||
@@ -173,7 +172,7 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
const handleEnablePitr = () => {
|
||||
const featureUrl = `https://portal.azure.com/#@/resource/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/backupRestore`;
|
||||
setIsEnablingPrerequisite(true);
|
||||
setPrerequisiteLoaderMessage(ContainerCopyMessages.popoverOverlaySpinnerLabel);
|
||||
setPrerequisiteLoaderMessage(t(Keys.containerCopy.popoverOverlaySpinnerLabel));
|
||||
window.open(featureUrl, "_blank");
|
||||
startPollingForAccountUpdate();
|
||||
};
|
||||
@@ -182,12 +181,12 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
setIsEnablingPrerequisite(true);
|
||||
try {
|
||||
setPrerequisiteLoaderMessage(
|
||||
ContainerCopyMessages.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel,
|
||||
t(Keys.containerCopy.onlineCopyEnabled.validateAllVersionsAndDeletesChangeFeedSpinnerLabel),
|
||||
);
|
||||
const currentAccount = await fetchDatabaseAccount(subscriptionId, resourceGroup, accountName);
|
||||
if (!currentAccount?.properties?.enableAllVersionsAndDeletesChangeFeed) {
|
||||
setPrerequisiteLoaderMessage(
|
||||
ContainerCopyMessages.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel,
|
||||
t(Keys.containerCopy.onlineCopyEnabled.enablingAllVersionsAndDeletesChangeFeedSpinnerLabel),
|
||||
);
|
||||
await updateDatabaseAccount(subscriptionId, resourceGroup, accountName, {
|
||||
properties: {
|
||||
@@ -196,7 +195,9 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
});
|
||||
}
|
||||
const capabilities = currentAccount?.properties?.capabilities ?? [];
|
||||
setPrerequisiteLoaderMessage(ContainerCopyMessages.onlineCopyEnabled.enablingOnlineCopySpinnerLabel(accountName));
|
||||
setPrerequisiteLoaderMessage(
|
||||
t(Keys.containerCopy.onlineCopyEnabled.enablingOnlineCopySpinnerLabel, { accountName }),
|
||||
);
|
||||
await updateDatabaseAccount(subscriptionId, resourceGroup, accountName, {
|
||||
properties: {
|
||||
capabilities: [...capabilities, { name: CapabilityNames.EnableOnlineCopyFeature }],
|
||||
@@ -345,8 +346,8 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
data-test={`migration-type-description-${migrationType}`}
|
||||
>
|
||||
{migrationType === CopyJobMigrationType.Offline
|
||||
? ContainerCopyMessages.migrationTypeOptions.offline.description
|
||||
: ContainerCopyMessages.migrationTypeOptions.online.description}
|
||||
? t(Keys.containerCopy.migrationType.offline.description)
|
||||
: t(Keys.containerCopy.migrationType.online.description)}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
@@ -626,10 +627,10 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
<Stack data-test="online-prerequisites-section" tokens={{ childrenGap: 10 }}>
|
||||
<LoadingOverlay isLoading={isEnablingPrerequisite} label={prerequisiteLoaderMessage} />
|
||||
<Text className="panelTextBold" variant="small">
|
||||
{ContainerCopyMessages.assignPermissions.onlineConfiguration.title}
|
||||
{t(Keys.containerCopy.assignPermissions.onlineConfiguration.title)}
|
||||
</Text>
|
||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
{ContainerCopyMessages.assignPermissions.onlineConfiguration.description(accountName)}
|
||||
{t(Keys.containerCopy.assignPermissions.onlineConfiguration.description, { accountName })}
|
||||
</Text>
|
||||
|
||||
{/* Point In Time Restore */}
|
||||
@@ -642,17 +643,17 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
}}
|
||||
/>
|
||||
<Text variant="small" style={{ fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||
{ContainerCopyMessages.pointInTimeRestore.title}
|
||||
{t(Keys.containerCopy.pointInTimeRestore.title)}
|
||||
</Text>
|
||||
</Stack>
|
||||
{!pitrEnabled && (
|
||||
<Stack tokens={{ childrenGap: 10, padding: "0 0 0 20px" }}>
|
||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
{ContainerCopyMessages.pointInTimeRestore.description(accountName)}
|
||||
{t(Keys.containerCopy.pointInTimeRestore.description, { accessName: accountName })}
|
||||
</Text>
|
||||
<PrimaryButton
|
||||
data-test="enable-pitr-button"
|
||||
text={ContainerCopyMessages.pointInTimeRestore.buttonText}
|
||||
text={t(Keys.containerCopy.pointInTimeRestore.buttonText)}
|
||||
disabled={isEnablingPrerequisite}
|
||||
onClick={handleEnablePitr}
|
||||
styles={{ root: { width: "fit-content" } }}
|
||||
@@ -674,20 +675,20 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
}}
|
||||
/>
|
||||
<Text variant="small" style={{ fontWeight: 600, color: "var(--colorNeutralForeground1)" }}>
|
||||
{ContainerCopyMessages.onlineCopyEnabled.title}
|
||||
{t(Keys.containerCopy.onlineCopyEnabled.title)}
|
||||
</Text>
|
||||
</Stack>
|
||||
{!onlineCopyFeatureEnabled && (
|
||||
<Stack tokens={{ childrenGap: 10, padding: "0 0 0 20px" }}>
|
||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
{ContainerCopyMessages.onlineCopyEnabled.description(accountName)} 
|
||||
<Link href={ContainerCopyMessages.onlineCopyEnabled.href} target="_blank" rel="noopener noreferrer">
|
||||
{ContainerCopyMessages.onlineCopyEnabled.hrefText}
|
||||
{t(Keys.containerCopy.onlineCopyEnabled.description, { accountName })} 
|
||||
<Link href={t(Keys.containerCopy.onlineCopyEnabled.href)} target="_blank" rel="noopener noreferrer">
|
||||
{t(Keys.containerCopy.onlineCopyEnabled.hrefText)}
|
||||
</Link>
|
||||
</Text>
|
||||
<PrimaryButton
|
||||
data-test="enable-online-copy-button"
|
||||
text={ContainerCopyMessages.onlineCopyEnabled.buttonText}
|
||||
text={t(Keys.containerCopy.onlineCopyEnabled.buttonText)}
|
||||
disabled={isEnablingPrerequisite || !pitrEnabled}
|
||||
onClick={handleEnableOnlineCopy}
|
||||
styles={{ root: { width: "fit-content" } }}
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
"publish": "Publish",
|
||||
"browse": "Browse",
|
||||
"increaseValueBy1": "Increase value by 1",
|
||||
"decreaseValueBy1": "Decrease value by 1"
|
||||
"decreaseValueBy1": "Decrease value by 1",
|
||||
"on": "On",
|
||||
"off": "Off"
|
||||
},
|
||||
"splashScreen": {
|
||||
"title": {
|
||||
@@ -974,5 +976,163 @@
|
||||
"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