Skip to content

Commit

Permalink
[DataEntryTable] Use current analysis lang with sense glosses (#3239)
Browse files Browse the repository at this point in the history
  • Loading branch information
imnasnainaec authored Jul 24, 2024
1 parent 8975e57 commit 8be0003
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function SenseList(props: SenseListProps): ReactElement {

const menuItem = (sense: Sense): ReactElement => {
const word: Word = { ...props.selectedWord, senses: [sense] };
const gloss = firstGlossText(sense);
const gloss = firstGlossText(sense, props.analysisLang);
return (
<StyledMenuItem
id={sense.guid}
Expand Down
8 changes: 5 additions & 3 deletions src/components/DataEntry/DataEntryTable/RecentEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ export function RecentEntry(props: RecentEntryProps): ReactElement {
sense.glosses.push(newGloss("", props.analysisLang.bcp47));
}
const [editing, setEditing] = useState(false);
const [gloss, setGloss] = useState(firstGlossText(sense));
const [gloss, setGloss] = useState(
firstGlossText(sense, props.analysisLang.bcp47)
);
const [vernacular, setVernacular] = useState(props.entry.vernacular);

const updateGlossField = (gloss: string): void => {
setEditing(gloss !== firstGlossText(sense));
setEditing(gloss !== firstGlossText(sense, props.analysisLang.bcp47));
setGloss(gloss);
};
const updateVernField = (vern: string): void => {
Expand All @@ -54,7 +56,7 @@ export function RecentEntry(props: RecentEntryProps): ReactElement {
};

function conditionallyUpdateGloss(): void {
if (firstGlossText(sense) !== gloss) {
if (firstGlossText(sense, props.analysisLang.bcp47) !== gloss) {
props.updateGloss(props.rowIndex, gloss);
}
}
Expand Down
52 changes: 37 additions & 15 deletions src/components/DataEntry/DataEntryTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,24 @@ export function makeSemDomCurrent(semDom: SemanticDomain): SemanticDomain {
export function updateEntryGloss(
entry: WordAccess,
def: string,
semDomId: string
semDomId: string,
analysisLang: string
): Word {
const sense = entry.word.senses.find((s) => s.guid === entry.senseGuid);
if (!sense) {
throw new Error("Word has no sense with specified guid");
}

const newSense: Sense = { ...sense };
newSense.glosses = [{ ...sense.glosses[0], def }];
let glossIndex = sense.glosses.findIndex((g) => g.language === analysisLang);
if (glossIndex === -1) {
// It there's no gloss in the current analysis language, then it's the first gloss
// that was shown in the RecentEntry that's now being updated.
glossIndex = 0;
}
newSense.glosses = sense.glosses.map((g, i) =>
i === glossIndex ? { ...g, def } : { ...g }
);
const oldSense: Sense = { ...sense };

// Move only the current semantic domain to the new sense.
Expand Down Expand Up @@ -476,7 +485,9 @@ export default function DataEntryTable(
: undefined;
return {
...prev,
newGloss: selectedSense ? firstGlossText(selectedSense) : "",
newGloss: selectedSense
? firstGlossText(selectedSense, analysisLang.bcp47)
: "",
selectedSenseGuid: guid,
};
});
Expand Down Expand Up @@ -774,14 +785,15 @@ export default function DataEntryTable(
};

/** Update the selected duplicate with the new entry.
* (Only considers the first gloss, `.glosses[0]`, of each sense.) */
* (Considers the gloss in the current analysis language.) */
const updateWordWithNewEntry = async (): Promise<void> => {
const oldWord = state.selectedDup;
if (!oldWord || !oldWord.id) {
if (!oldWord?.id) {
throw new Error("You are trying to update a nonexistent word");
}

const gloss = state.newGloss.trim();
const lang = analysisLang.bcp47;
const semDom = makeSemDomCurrent(props.semanticDomain);

// If a dup sense is selected, update it.
Expand All @@ -796,9 +808,9 @@ export default function DataEntryTable(
oldSense.glosses.push(newGloss());
}

// If selected sense already has this domain, add audio without updating first.
// If sense already has this gloss and domain, add audio without updating first.
if (
oldSense.glosses[0].def === gloss &&
oldSense.glosses.some((g) => g.def === gloss && g.language === lang) &&
oldSense.semanticDomains.some((d) => d.id === semDom.id)
) {
enqueueSnackbar(
Expand All @@ -810,11 +822,15 @@ export default function DataEntryTable(
return;
}

// Only update the selected sense if the old gloss is blank or matches the new gloss.
if (!oldSense.glosses[0].def.trim()) {
oldSense.glosses[0] = newGloss(gloss, analysisLang.bcp47);
// Only update the sense if the old gloss is missing or matches the new gloss.
let glossIndex = oldSense.glosses.findIndex((g) => g.language === lang);
if (glossIndex === -1) {
oldSense.glosses.push(newGloss(gloss, lang));
glossIndex = oldSense.glosses.length - 1;
} else if (!oldSense.glosses[glossIndex].def.trim()) {
oldSense.glosses[glossIndex].def = gloss;
}
if (oldSense.glosses[0].def === gloss) {
if (oldSense.glosses[glossIndex].def === gloss) {
await updateWordBackAndFront(
addSemanticDomainToSense(semDom, oldWord, state.selectedSenseGuid),
state.selectedSenseGuid,
Expand All @@ -826,7 +842,7 @@ export default function DataEntryTable(

// Otherwise, if new gloss matches a sense, update that sense.
for (const sense of oldWord.senses) {
if (sense.glosses?.length && sense.glosses[0].def === gloss) {
if (sense.glosses?.some((g) => g.def === gloss && g.language === lang)) {
if (sense.semanticDomains.some((d) => d.id === semDom.id)) {
// User is trying to add a sense that already exists.
enqueueSnackbar(
Expand All @@ -849,7 +865,7 @@ export default function DataEntryTable(

// The gloss is new for this word, so add a new sense.
defunctWord(oldWord.id);
const sense = newSense(gloss, analysisLang.bcp47, semDom);
const sense = newSense(gloss, lang, semDom);
const senses = [...oldWord.senses, sense];
const newWord: Word = { ...oldWord, senses };

Expand Down Expand Up @@ -922,7 +938,7 @@ export default function DataEntryTable(
// Retract and replaced with a new entry.
const word = simpleWord(
vernacular,
firstGlossText(oldSense),
firstGlossText(oldSense, analysisLang.bcp47),
analysisLang.bcp47
);
word.id = "";
Expand All @@ -945,7 +961,12 @@ export default function DataEntryTable(
const oldEntry = state.recentWords[index];
defunctWord(oldEntry.word.id);
def = def.trim();
const newWord = updateEntryGloss(oldEntry, def, props.semanticDomain.id);
const newWord = updateEntryGloss(
oldEntry,
def,
props.semanticDomain.id,
analysisLang.bcp47
);
await updateWordInBackend(newWord);

// If a sense with a new guid was added, it needs to replace the old sense in the display.
Expand All @@ -959,6 +980,7 @@ export default function DataEntryTable(
}
},
[
analysisLang.bcp47,
defunctWord,
props.semanticDomain.id,
state.recentWords,
Expand Down
39 changes: 35 additions & 4 deletions src/components/DataEntry/DataEntryTable/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ import {
newSemanticDomainTreeNode,
semDomFromTreeNode,
} from "types/semanticDomain";
import { multiSenseWord, newSense, newWord, simpleWord } from "types/word";
import {
multiSenseWord,
newGloss,
newSense,
newWord,
simpleWord,
} from "types/word";
import { Bcp47Code } from "types/writingSystem";
import { firstGlossText } from "utilities/wordUtilities";

Expand Down Expand Up @@ -240,7 +246,7 @@ describe("DataEntryTable", () => {
describe("updateEntryGloss", () => {
it("throws error when entry doesn't have sense with specified guid", () => {
const entry: WordAccess = { word: newWord(), senseGuid: "gibberish" };
expect(() => updateEntryGloss(entry, "def", "semDomId")).toThrow();
expect(() => updateEntryGloss(entry, "def", "semDomId", "en")).toThrow();
});

it("directly updates a sense with no other semantic domains", () => {
Expand All @@ -254,7 +260,30 @@ describe("DataEntryTable", () => {
const expectedWord: Word = { ...entry.word };
expectedWord.senses[senseIndex] = { ...sense, glosses: [expectedGloss] };

expect(updateEntryGloss(entry, def, mockSemDom.id)).toEqual(expectedWord);
expect(
updateEntryGloss(entry, def, mockSemDom.id, sense.glosses[0].language)
).toEqual(expectedWord);
});

it("updates gloss of specified language", () => {
const senseIndex = 1;
const sense: Sense = { ...mockMultiWord.senses[senseIndex] };
const targetGloss = newGloss("target language", "tl");
sense.glosses = [...sense.glosses, targetGloss];
sense.semanticDomains = [mockSemDom];
const entry: WordAccess = { word: mockMultiWord, senseGuid: sense.guid };
const def = "newGlossDef";

const expectedGloss: Gloss = { ...targetGloss, def };
const expectedWord: Word = { ...entry.word };
expectedWord.senses[senseIndex] = {
...sense,
glosses: [sense.glosses[0], expectedGloss],
};

expect(
updateEntryGloss(entry, def, mockSemDom.id, targetGloss.language)
).toEqual(expectedWord);
});

it("splits a sense with multiple semantic domains", () => {
Expand All @@ -272,7 +301,9 @@ describe("DataEntryTable", () => {
newSense.semanticDomains = [mockSemDom];
const expectedWord: Word = { ...word, senses: [oldSense, newSense] };

expect(updateEntryGloss(entry, def, mockSemDom.id)).toEqual(expectedWord);
expect(
updateEntryGloss(entry, def, mockSemDom.id, sense.glosses[0].language)
).toEqual(expectedWord);
});
});

Expand Down
11 changes: 11 additions & 0 deletions src/utilities/tests/wordUtilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ describe("wordUtilities", () => {
sense.glosses[0] = newGloss(text);
expect(firstGlossText(sense)).toEqual(text);
});

it("matches language, if lang specified and present", () => {
const sense = newSense();
const lang = "gg";
const defFirst = "Not this one.";
const defInLang = "This one!";
expect(firstGlossText(sense)).toEqual("");
sense.glosses.push(newGloss(defFirst, "en"), newGloss(defInLang, lang));
expect(firstGlossText(sense, lang)).toEqual(defInLang);
expect(firstGlossText(sense, "other")).toEqual(defFirst);
});
});

describe("getAnalysisLangsFromWords", () => {
Expand Down
10 changes: 7 additions & 3 deletions src/utilities/wordUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ export function compareFlags(a: Flag, b: Flag): number {
}

/**
* Returns the text of the first gloss of a sense.
* Returns the text of the first gloss of a sense, matching the lang tag if given.
* In the case that the array of glosses is empty, returns an empty string.
*/
export function firstGlossText(sense: Sense): string {
return sense.glosses[0]?.def ?? "";
export function firstGlossText(sense: Sense, lang?: string): string {
return (
sense.glosses.find((g) => g.language === lang)?.def ??
sense.glosses[0]?.def ??
""
);
}

/**
Expand Down

0 comments on commit 8be0003

Please sign in to comment.