Files
cosmos-explorer/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.tsx
sunghyunkang1111 f723b4746d Localizations batch 5 and import update (#2422)
* Locations import update

* Fix formatting

* Fix import paths
2026-03-11 13:51:19 -05:00

154 lines
5.1 KiB
TypeScript

import { MessageBar, MessageBarType, Stack } from "@fluentui/react";
import * as monaco from "monaco-editor";
import * as React from "react";
import * as DataModels from "../../../../Contracts/DataModels";
import { Keys, t } from "Localization";
import { loadMonaco } from "../../../LazyMonaco";
import { titleAndInputStackProps, unsavedEditorWarningMessage } from "../SettingsRenderUtils";
import { isDirty as isContentDirty, isDataMaskingEnabled } from "../SettingsUtils";
export interface DataMaskingComponentProps {
shouldDiscardDataMasking: boolean;
resetShouldDiscardDataMasking: () => void;
dataMaskingContent: DataModels.DataMaskingPolicy;
dataMaskingContentBaseline: DataModels.DataMaskingPolicy;
onDataMaskingContentChange: (dataMasking: DataModels.DataMaskingPolicy) => void;
onDataMaskingDirtyChange: (isDirty: boolean) => void;
validationErrors: string[];
}
interface DataMaskingComponentState {
isDirty: boolean;
dataMaskingContentIsValid: boolean;
}
const emptyDataMaskingPolicy: DataModels.DataMaskingPolicy = {
includedPaths: [],
excludedPaths: [],
};
export class DataMaskingComponent extends React.Component<DataMaskingComponentProps, DataMaskingComponentState> {
private dataMaskingDiv = React.createRef<HTMLDivElement>();
private dataMaskingEditor: monaco.editor.IStandaloneCodeEditor;
private shouldCheckComponentIsDirty = true;
constructor(props: DataMaskingComponentProps) {
super(props);
this.state = {
isDirty: false,
dataMaskingContentIsValid: true,
};
}
public componentDidUpdate(): void {
if (this.props.shouldDiscardDataMasking) {
this.resetDataMaskingEditor();
this.props.resetShouldDiscardDataMasking();
}
this.onComponentUpdate();
}
componentDidMount(): void {
this.resetDataMaskingEditor();
this.onComponentUpdate();
}
private onComponentUpdate = (): void => {
if (!this.shouldCheckComponentIsDirty) {
this.shouldCheckComponentIsDirty = true;
return;
}
this.props.onDataMaskingDirtyChange(this.IsComponentDirty());
this.shouldCheckComponentIsDirty = false;
};
public IsComponentDirty = (): boolean => {
if (
isContentDirty(this.props.dataMaskingContent, this.props.dataMaskingContentBaseline) &&
this.state.dataMaskingContentIsValid
) {
return true;
}
return false;
};
private resetDataMaskingEditor = (): void => {
if (!this.dataMaskingEditor) {
this.createDataMaskingEditor();
} else {
const dataMaskingEditorModel = this.dataMaskingEditor.getModel();
const value: string = JSON.stringify(this.props.dataMaskingContent || emptyDataMaskingPolicy, undefined, 4);
dataMaskingEditorModel.setValue(value);
}
this.onComponentUpdate();
};
private async createDataMaskingEditor(): Promise<void> {
const value: string = JSON.stringify(this.props.dataMaskingContent || emptyDataMaskingPolicy, undefined, 4);
const monaco = await loadMonaco();
this.dataMaskingEditor = monaco.editor.create(this.dataMaskingDiv.current, {
value: value,
language: "json",
automaticLayout: true,
ariaLabel: t(Keys.controls.settings.dataMasking.ariaLabel),
fontSize: 13,
minimap: { enabled: false },
wordWrap: "off",
scrollBeyondLastLine: false,
lineNumbers: "on",
});
if (this.dataMaskingEditor) {
const dataMaskingEditorModel = this.dataMaskingEditor.getModel();
dataMaskingEditorModel.onDidChangeContent(this.onEditorContentChange.bind(this));
}
}
private onEditorContentChange = (): void => {
const dataMaskingEditorModel = this.dataMaskingEditor.getModel();
try {
const newContent = JSON.parse(dataMaskingEditorModel.getValue()) as DataModels.DataMaskingPolicy;
// Always call parent's validation - it will handle validation and store errors
this.props.onDataMaskingContentChange(newContent);
const isDirty = isContentDirty(newContent, this.props.dataMaskingContentBaseline);
this.setState(
{
dataMaskingContentIsValid: this.props.validationErrors.length === 0,
isDirty,
},
() => {
this.props.onDataMaskingDirtyChange(isDirty);
},
);
} catch (e) {
// Invalid JSON - mark as invalid without propagating
this.setState({
dataMaskingContentIsValid: false,
isDirty: false,
});
}
};
public render(): JSX.Element {
if (!isDataMaskingEnabled(this.props.dataMaskingContent)) {
return null;
}
const isDirty = this.IsComponentDirty();
return (
<Stack {...titleAndInputStackProps}>
{isDirty && (
<MessageBar messageBarType={MessageBarType.warning}>{unsavedEditorWarningMessage("dataMasking")}</MessageBar>
)}
{this.props.validationErrors.length > 0 && (
<MessageBar messageBarType={MessageBarType.error}>
{t(Keys.controls.settings.dataMasking.validationFailed)} {this.props.validationErrors.join(", ")}
</MessageBar>
)}
<div className="settingsV2Editor" tabIndex={0} ref={this.dataMaskingDiv}></div>
</Stack>
);
}
}