Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MergeDups] Enable bypassing protection of protected words and senses #3445

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Backend.Tests/Models/ProjectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public void TestClone()
DefinitionsEnabled = true,
GrammaticalInfoEnabled = true,
AutocompleteSetting = OffOnSetting.On,
ProtectedDataOverrideEnabled = OffOnSetting.Off,
SemDomWritingSystem = new("fr", "Français"),
VernacularWritingSystem = new("en", "English", "Calibri"),
AnalysisWritingSystems = new() { new("es", "Español") },
Expand Down
9 changes: 9 additions & 0 deletions Backend/Models/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public class Project
[BsonRepresentation(BsonType.String)]
public OffOnSetting AutocompleteSetting { get; set; }

[Required]
[BsonElement("protectedDataOverrideEnabled")]
[BsonRepresentation(BsonType.String)]
public OffOnSetting ProtectedDataOverrideEnabled { get; set; }

[Required]
[BsonElement("semDomWritingSystem")]
public WritingSystem SemDomWritingSystem { get; set; }
Expand Down Expand Up @@ -93,6 +98,7 @@ public Project()
DefinitionsEnabled = false;
GrammaticalInfoEnabled = false;
AutocompleteSetting = OffOnSetting.On;
ProtectedDataOverrideEnabled = OffOnSetting.Off;
SemDomWritingSystem = new();
VernacularWritingSystem = new();
AnalysisWritingSystems = new();
Expand All @@ -117,6 +123,7 @@ public Project Clone()
DefinitionsEnabled = DefinitionsEnabled,
GrammaticalInfoEnabled = GrammaticalInfoEnabled,
AutocompleteSetting = AutocompleteSetting,
ProtectedDataOverrideEnabled = ProtectedDataOverrideEnabled,
SemDomWritingSystem = SemDomWritingSystem.Clone(),
VernacularWritingSystem = VernacularWritingSystem.Clone(),
AnalysisWritingSystems = AnalysisWritingSystems.Select(ws => ws.Clone()).ToList(),
Expand All @@ -140,6 +147,7 @@ public bool ContentEquals(Project other)
other.DefinitionsEnabled == DefinitionsEnabled &&
other.GrammaticalInfoEnabled == GrammaticalInfoEnabled &&
other.AutocompleteSetting.Equals(AutocompleteSetting) &&
other.ProtectedDataOverrideEnabled.Equals(ProtectedDataOverrideEnabled) &&
other.SemDomWritingSystem.Equals(SemDomWritingSystem) &&
other.VernacularWritingSystem.Equals(VernacularWritingSystem) &&

Expand Down Expand Up @@ -191,6 +199,7 @@ public override int GetHashCode()
hash.Add(DefinitionsEnabled);
hash.Add(GrammaticalInfoEnabled);
hash.Add(AutocompleteSetting);
hash.Add(ProtectedDataOverrideEnabled);
hash.Add(SemDomWritingSystem);
hash.Add(VernacularWritingSystem);
hash.Add(AnalysisWritingSystems);
Expand Down
1 change: 1 addition & 0 deletions Backend/Repositories/ProjectRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public async Task<ResultOfUpdate> Update(string projectId, Project project)
.Set(x => x.DefinitionsEnabled, project.DefinitionsEnabled)
.Set(x => x.GrammaticalInfoEnabled, project.GrammaticalInfoEnabled)
.Set(x => x.AutocompleteSetting, project.AutocompleteSetting)
.Set(x => x.ProtectedDataOverrideEnabled, project.ProtectedDataOverrideEnabled)
.Set(x => x.SemDomWritingSystem, project.SemDomWritingSystem)
.Set(x => x.VernacularWritingSystem, project.VernacularWritingSystem)
.Set(x => x.AnalysisWritingSystems, project.AnalysisWritingSystems)
Expand Down
11 changes: 8 additions & 3 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@
"on": "On",
"hint": "In Data Entry, suggest existing Vernaculars similar to the Vernacular being typed."
},
"protectedDataOverride": {
"hint": "In Merge Duplicates, allow overriding protection of protected words and senses.",
"label": "Protected Data Override"
},
"invite": {
"inviteByEmailLabel": "Invite by Email",
"userExists": "This user is already registered.",
Expand Down Expand Up @@ -410,10 +414,11 @@
"delete": "Delete sense",
"deleteDialog": "Delete this sense?",
"protectedSense": "This sense was imported with data that The Combine doesn't handle.",
"protectedSenseInfo": "This sense cannot be deleted or dropped into another sense. You may still move it to another word or drop other senses into this one to merge them.",
"protectedSenseInfo": "This sense cannot be safely deleted or dropped into another sense. You may still move it to another word or drop other senses into this one to merge them.",
"protectedWord": "This word was imported with data that The Combine doesn't handle.",
"protectedWordInfo": "To prevent deletion, the final sense of this word cannot be removed.",
"protectedData": "Protected data: {{ val }}"
"protectedWordInfo": "To prevent deletion, the final sense of this word cannot be safely removed.",
"protectedData": "Protected data: {{ val }}",
"protectedOverrideWarning": "The following data will be lost: {{ val }}"
},
"protectReason": {
"annotations": "annotations",
Expand Down
6 changes: 6 additions & 0 deletions src/api/models/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ export interface Project {
* @memberof Project
*/
autocompleteSetting: OffOnSetting;
/**
*
* @type {OffOnSetting}
* @memberof Project
*/
protectedDataOverrideEnabled: OffOnSetting;
/**
*
* @type {WritingSystem}
Expand Down
48 changes: 48 additions & 0 deletions src/components/ProjectSettings/ProjectProtectedOverride.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { HelpOutline } from "@mui/icons-material";
import { Grid, MenuItem, Select, Tooltip } from "@mui/material";
import { type ReactElement } from "react";
import { useTranslation } from "react-i18next";

import { OffOnSetting } from "api/models";
import { type ProjectSettingProps } from "components/ProjectSettings/ProjectSettingsTypes";

export default function ProjectProtectedOverride(
props: ProjectSettingProps
): ReactElement {
const { t } = useTranslation();

const updateProtectOverrideSetting = async (
protectedDataOverrideEnabled: OffOnSetting
): Promise<void> => {
await props.setProject({ ...props.project, protectedDataOverrideEnabled });
};

return (
<Grid container>
<Grid>
<Select
variant="standard"
value={props.project.protectedDataOverrideEnabled}
onChange={(e) =>
updateProtectOverrideSetting(e.target.value as OffOnSetting)
}
>
<MenuItem value={OffOnSetting.Off}>
{t("projectSettings.autocomplete.off")}
</MenuItem>
<MenuItem value={OffOnSetting.On}>
{t("projectSettings.autocomplete.on")}
</MenuItem>
</Select>
</Grid>
<Grid>
<Tooltip
title={t("projectSettings.protectedDataOverride.hint")}
placement={document.body.dir === "rtl" ? "left" : "right"}
>
<HelpOutline fontSize="small" />
</Tooltip>
</Grid>
</Grid>
);
}
17 changes: 17 additions & 0 deletions src/components/ProjectSettings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
People,
PersonAdd,
RecordVoiceOver,
RemoveModerator,
Settings,
Sms,
} from "@mui/icons-material";
Expand Down Expand Up @@ -53,6 +54,7 @@ import ProjectLanguages, {
SemanticDomainLanguage,
} from "components/ProjectSettings/ProjectLanguages";
import ProjectName from "components/ProjectSettings/ProjectName";
import ProjectProtectedOverride from "components/ProjectSettings/ProjectProtectedOverride";
import ProjectSchedule from "components/ProjectSettings/ProjectSchedule";
import ProjectSelect from "components/ProjectSettings/ProjectSelect";
import ActiveProjectUsers from "components/ProjectUsers/ActiveProjectUsers";
Expand Down Expand Up @@ -80,6 +82,7 @@ export enum Setting {
Import = "SettingImport",
Languages = "SettingLanguages",
Name = "SettingName",
ProtectOverride = "SettingProtectOverride",
Schedule = "SettingSchedule",
Speakers = "SettingSpeakers",
UserAdd = "SettingUserAdd",
Expand Down Expand Up @@ -176,6 +179,20 @@ export default function ProjectSettingsComponent(): ReactElement {
/>
)}

{/* Protected data override toggle */}
{permissions.includes(Permission.DeleteEditSettingsAndUsers) && (
<BaseSettings
icon={<RemoveModerator data-testid={Setting.ProtectOverride} />}
title={t("projectSettings.protectedDataOverride.label")}
body={
<ProjectProtectedOverride
project={project}
setProject={updateProject}
/>
}
/>
)}

{/* Archive project */}
{permissions.includes(Permission.Archive) && (
<BaseSettings
Expand Down
2 changes: 2 additions & 0 deletions src/components/ProjectSettings/tests/SettingsTabTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const settingsByTab: Record<ProjectSettingsTab, Setting[]> = {
Setting.Archive,
Setting.Autocomplete,
Setting.Name,
Setting.ProtectOverride,
],
[ProjectSettingsTab.ImportExport]: [Setting.Export, Setting.Import],
[ProjectSettingsTab.Languages]: [Setting.Languages],
Expand All @@ -34,6 +35,7 @@ const settingsByPermission: Record<Permission, Setting[]> = {
Setting.DomainsCustom,
Setting.Languages,
Setting.Name,
Setting.ProtectOverride,
Setting.Speakers,
Setting.UserAdd,
Setting.Users,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export default function DragSense(props: DragSenseProps): ReactElement {
arraysEqual<string>
);
const dispatch = useAppDispatch();
const overrideProtection = useAppSelector(
(state: StoreState) => state.mergeDuplicateGoal.overrideProtection
);
const sidebar = useAppSelector(
(state: StoreState) => state.mergeDuplicateGoal.tree.sidebar
);
Expand Down Expand Up @@ -88,7 +91,7 @@ export default function DragSense(props: DragSenseProps): ReactElement {
key={props.senseRef.mergeSenseId}
draggableId={JSON.stringify(props.senseRef)}
index={props.index}
isDragDisabled={props.isOnlySenseInProtectedWord}
isDragDisabled={props.isOnlySenseInProtectedWord && !overrideProtection}
>
{(provided, snapshot): ReactElement => (
<Card
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export default function DropWord(props: DropWordProps): ReactElement {
senseRef={{
isSenseProtected: senses[0].protected,
mergeSenseId: id,
protectReasons: senses[0].protectReasons,
wordId: props.wordId,
}}
isOnlySenseInProtectedWord={protectedWithOneChild}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ export default function SidebarDragSense(
const ref = state.mergeDuplicateGoal.tree.sidebar.senseRef;
return JSON.stringify({ ...ref, order: props.index });
});
const overrideProtection = useAppSelector(
(state: StoreState) => state.mergeDuplicateGoal.overrideProtection
);

return (
<Draggable
key={props.mergeSense.sense.guid}
draggableId={draggableId}
index={props.index}
isDragDisabled={props.mergeSense.protected}
isDragDisabled={props.mergeSense.protected && !overrideProtection}
>
{(provided, snapshot): ReactElement => (
<div
Expand Down
Loading
Loading