Skip to content

Commit 34b59b5

Browse files
authored
[MergeDups] Show merge result when combining senses (#3324)
1 parent 0804ef9 commit 34b59b5

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { IconButtonWithTooltip, PartOfSpeechButton } from "components/Buttons";
1414
import MultilineTooltipTitle from "components/MultilineTooltipTitle";
1515
import DomainChipsGrid from "components/WordCard/DomainChipsGrid";
1616
import SenseCardText from "components/WordCard/SenseCardText";
17+
import { combineSenses } from "goals/MergeDuplicates/Redux/reducerUtilities";
1718

1819
interface SenseCardContentProps {
1920
senses: Sense[];
@@ -31,13 +32,14 @@ export default function SenseCardContent(
3132
): ReactElement {
3233
const { t } = useTranslation();
3334

34-
const gramInfo = props.senses
35-
.map((s) => s.grammaticalInfo)
36-
.find((g) => g.catGroup !== GramCatGroup.Unspecified);
37-
38-
const semDoms = props.senses
39-
.flatMap((s) => s.semanticDomains)
40-
.sort((a, b) => a.id.localeCompare(b.id));
35+
const sense = combineSenses(props.senses);
36+
const gramInfo =
37+
sense.grammaticalInfo.catGroup === GramCatGroup.Unspecified
38+
? undefined
39+
: sense.grammaticalInfo;
40+
const semDoms = sense.semanticDomains.sort((a, b) =>
41+
a.id.localeCompare(b.id)
42+
);
4143

4244
const reasonText = (reason: ProtectReason): string => {
4345
// Backend/Helper/LiftHelper.cs > GetProtectedReasons(LiftSense sense)
@@ -96,9 +98,9 @@ export default function SenseCardContent(
9698
};
9799

98100
const protectedWarning =
99-
!props.sidebar && props.senses[0].accessibility === Status.Protected;
101+
!props.sidebar && sense.accessibility === Status.Protected;
100102
const tooltipTexts = [t("mergeDups.helpText.protectedSense")];
101-
const reasons = props.senses[0]?.protectReasons;
103+
const reasons = sense.protectReasons;
102104
if (reasons?.length) {
103105
tooltipTexts.push(
104106
t("mergeDups.helpText.protectedData", {
@@ -114,7 +116,7 @@ export default function SenseCardContent(
114116
<div style={{ position: "absolute", left: 0, top: 0 }}>
115117
{gramInfo && (
116118
<PartOfSpeechButton
117-
buttonId={`sense-${props.senses[0].guid}-part-of-speech`}
119+
buttonId={`sense-${sense.guid}-part-of-speech`}
118120
gramInfo={gramInfo}
119121
onlyIcon
120122
/>
@@ -128,7 +130,7 @@ export default function SenseCardContent(
128130
side="top"
129131
size="small"
130132
text={<MultilineTooltipTitle lines={tooltipTexts} />}
131-
buttonId={`sense-${props.senses[0].guid}-protected`}
133+
buttonId={`sense-${sense.guid}-protected`}
132134
/>
133135
)}
134136
</div>
@@ -144,15 +146,15 @@ export default function SenseCardContent(
144146
{props.senses.length > 1 && (
145147
<IconButton
146148
onClick={props.toggleFunction}
147-
id={`sidebar-open-sense-${props.senses[0].guid}`}
149+
id={`sidebar-open-sense-${sense.guid}`}
148150
size="large"
149151
>
150152
<ArrowForwardIos />
151153
</IconButton>
152154
)}
153155
</div>
154156
{/* List glosses and (if any) definitions. */}
155-
<SenseCardText languages={props.languages} sense={props.senses[0]} />
157+
<SenseCardText languages={props.languages} sense={sense} />
156158
{/* List semantic domains. */}
157159
<DomainChipsGrid semDoms={semDoms} />
158160
</CardContent>

src/goals/MergeDuplicates/Redux/reducerUtilities.ts

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from "goals/MergeDuplicates/MergeDupsTreeTypes";
1313
import { newMergeWords } from "goals/MergeDuplicates/MergeDupsTypes";
1414
import { type Hash } from "types/hash";
15+
import { newGrammaticalInfo, newSense } from "types/word";
1516
import { compareFlags } from "utilities/wordUtilities";
1617

1718
// A collection of helper/utility functions only for use in the MergeDupsReducer.
@@ -112,15 +113,42 @@ export function createMergeParent(
112113
export function combineIntoFirstSense(mergeSenses: MergeTreeSense[]): void {
113114
// Set the main sense to the first sense (the top one when the sidebar was opened).
114115
const mainSense = mergeSenses[0].sense;
115-
const sep = "; ";
116+
const senses: Sense[] = [mainSense];
116117

117-
// Merge the rest as duplicates.
118+
// Mark the rest as duplicates.
118119
// These were senses dropped into another sense.
119120
mergeSenses.slice(1).forEach((mergeDupSense) => {
120-
const dupSense = mergeDupSense.sense;
121-
dupSense.accessibility = Status.Duplicate;
121+
mergeDupSense.sense.accessibility = Status.Duplicate;
122+
senses.push(mergeDupSense.sense);
123+
});
124+
125+
// Combine the sense content and update the main sense.
126+
const combinedSense = combineSenses(senses);
127+
mainSense.definitions = combinedSense.definitions;
128+
mainSense.glosses = combinedSense.glosses;
129+
mainSense.grammaticalInfo = combinedSense.grammaticalInfo;
130+
mainSense.semanticDomains = combinedSense.semanticDomains;
131+
}
132+
133+
/** Create a copy of the first sense with the following content merged from all senses:
134+
* definitions, glosses, grammaticalInfo, semanticDomains. */
135+
export function combineSenses(senses: Sense[]): Sense {
136+
if (!senses.length) {
137+
return newSense();
138+
}
122139

123-
// Merge the duplicate's definitions into the main sense.
140+
const mainSense: Sense = {
141+
...senses[0],
142+
definitions: [],
143+
glosses: [],
144+
grammaticalInfo: newGrammaticalInfo(),
145+
semanticDomains: [],
146+
};
147+
148+
const sep = "; ";
149+
150+
senses.forEach((dupSense) => {
151+
// Merge in the definitions.
124152
dupSense.definitions.forEach((def) => {
125153
const newText = def.text.trim();
126154
if (newText) {
@@ -143,7 +171,7 @@ export function combineIntoFirstSense(mergeSenses: MergeTreeSense[]): void {
143171
}
144172
});
145173

146-
// Merge the duplicate's glosses into the main sense.
174+
// Merge in the glosses.
147175
dupSense.glosses.forEach((gloss) => {
148176
const newDef = gloss.def.trim();
149177
if (newDef) {
@@ -166,7 +194,7 @@ export function combineIntoFirstSense(mergeSenses: MergeTreeSense[]): void {
166194
}
167195
});
168196

169-
// Use the duplicate's part of speech if not specified in the main sense.
197+
// Use the grammatical info if not already specified.
170198
if (mainSense.grammaticalInfo.catGroup === GramCatGroup.Unspecified) {
171199
mainSense.grammaticalInfo = { ...dupSense.grammaticalInfo };
172200
} else if (
@@ -180,11 +208,13 @@ export function combineIntoFirstSense(mergeSenses: MergeTreeSense[]): void {
180208
}
181209
}
182210

183-
// Put the duplicate's domains in the main sense if the id is new.
211+
// Merge in the semantic domains.
184212
dupSense.semanticDomains.forEach((dom) => {
185213
if (mainSense.semanticDomains.every((d) => d.id !== dom.id)) {
186214
mainSense.semanticDomains.push({ ...dom });
187215
}
188216
});
189217
});
218+
219+
return mainSense;
190220
}

0 commit comments

Comments
 (0)