Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
41f3737
First-take with ChatGTP
imnasnainaec May 30, 2025
a2a3d08
Finish first draft
imnasnainaec Jun 2, 2025
c1d3d0d
Merge branch 'master' into goal-timeline
imnasnainaec Jun 2, 2025
8b830c8
Tidy
imnasnainaec Jun 2, 2025
ade9783
Add icons
imnasnainaec Jun 2, 2025
e40adcb
Clean up change summary
imnasnainaec Jun 2, 2025
b149cb9
Finish redesign
imnasnainaec Jun 3, 2025
6d37bb2
Merge branch 'master' into goal-timeline
imnasnainaec Jun 3, 2025
2871c5b
Fix test
imnasnainaec Jun 3, 2025
3c53a99
[GoalTimeline] Primarily use GoalName rather than GoalType
imnasnainaec Jun 3, 2025
504f7b3
Nicer scrollbar
imnasnainaec Jun 3, 2025
48f4402
Fix render bug
imnasnainaec Jun 3, 2025
de17b68
Tidy
imnasnainaec Jun 3, 2025
caca865
Drop the x
imnasnainaec Jun 3, 2025
6333abe
Refactor CharInvCompleted
imnasnainaec Jun 3, 2025
773fb86
Merge branch 'master' into goal-timeline
imnasnainaec Jun 4, 2025
a7d4db1
Cleanup
imnasnainaec Jun 4, 2025
66179fe
Refactor CharInv changes summary
imnasnainaec Jun 4, 2025
2a8df20
Refactor goal history
imnasnainaec Jun 4, 2025
63ea3b6
Update tests
imnasnainaec Jun 4, 2025
b77065b
Remove suggestions/recommendations
imnasnainaec Jun 5, 2025
c79e2f4
Merge branch 'master' into goal-timeline
imnasnainaec Jun 9, 2025
c6a486a
Add modified datetime to goal edit
imnasnainaec Jun 9, 2025
0e85e52
Merge branch 'master' into goal-timeline
imnasnainaec Jun 9, 2025
ed8a134
Remove debugging line
imnasnainaec Jun 9, 2025
95e89f2
Fix i18n source
imnasnainaec Jun 9, 2025
45bbd8a
Remove unnecessary mocks
imnasnainaec Jun 9, 2025
f6397c4
Merge branch 'master' into goal-timeline
imnasnainaec Jun 13, 2025
7945d3d
Update CharInv title and description
imnasnainaec Jun 13, 2025
5937095
Merge branch 'master' into goal-timeline
imnasnainaec Jun 16, 2025
a917ccd
Fix bad merge
imnasnainaec Jun 16, 2025
36a0fb6
Merge branch 'master' into goal-timeline
imnasnainaec Jun 16, 2025
6eb78de
Remove vestig
imnasnainaec Jun 16, 2025
2a2ec69
Merge branch 'master' into goal-timeline
imnasnainaec Jun 17, 2025
91e88c3
Tidy
imnasnainaec Jun 17, 2025
b4c8b6f
Revert unnecessary GoalType changes
imnasnainaec Jun 17, 2025
1f7e33a
Clean up useEffects
imnasnainaec Jun 17, 2025
2f54f72
Expand tests
imnasnainaec Jun 18, 2025
0789bea
Tidy
imnasnainaec Jun 18, 2025
7703b1b
Merge branch 'master' into goal-timeline
imnasnainaec Jun 18, 2025
f5742fd
Simplify GoalHistoryButton
imnasnainaec Jun 18, 2025
aa61cfc
Merge branch 'master' into goal-timeline
imnasnainaec Jun 23, 2025
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
5 changes: 3 additions & 2 deletions Backend.Tests/Controllers/UserEditControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ public async Task TestAddGoalToUserEdit()

await _userEditController.UpdateUserEditGoal(ProjId, userEdit.Id, newEdit);

var allUserEdits = await _userEditRepo.GetAllUserEdits(ProjId);
Assert.That(allUserEdits, Does.Contain(updatedUserEdit).UsingPropertiesComparer());
var repoUserEdit = await _userEditRepo.GetUserEdit(ProjId, userEdit.Id);
newEdit.Modified = repoUserEdit!.Edits.FirstOrDefault(e => e.Guid == newEdit.Guid)!.Modified;
Assert.That(repoUserEdit, Is.EqualTo(updatedUserEdit).UsingPropertiesComparer());
}

[Test]
Expand Down
29 changes: 9 additions & 20 deletions Backend/Models/UserEdit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,15 @@ public class UserEdit
[Required]
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Id { get; set; } = "";

[Required]
[BsonElement("edits")]
public List<Edit> Edits { get; set; }
public List<Edit> Edits { get; set; } = [];

[Required]
[BsonElement("projectId")]
public string ProjectId { get; set; }

public UserEdit()
{
Id = "";
ProjectId = "";
Edits = new();
}
public string ProjectId { get; set; } = "";

/// <summary> Create a deep copy. </summary>
public UserEdit Clone()
Expand Down Expand Up @@ -66,7 +59,7 @@ public class Edit
[BsonElement("guid")]
[BsonGuidRepresentation(GuidRepresentation.CSharpLegacy)]
#pragma warning disable CA1720
public Guid Guid { get; set; }
public Guid Guid { get; set; } = Guid.NewGuid();
#pragma warning restore CA1720

/// <summary> Integer representation of enum GoalType in src/types/goals.ts </summary>
Expand All @@ -76,24 +69,20 @@ public class Edit

[Required]
[BsonElement("stepData")]
public List<string> StepData { get; set; }
public List<string> StepData { get; set; } = [];

[Required]
[BsonElement("changes")]
public string Changes { get; set; }
public string Changes { get; set; } = "{}";

public Edit()
{
Guid = Guid.NewGuid();
GoalType = 0;
StepData = new();
Changes = "{}";
}
[BsonElement("modified")]
public DateTime? Modified { get; set; }

/// <summary> Create a deep copy. </summary>
public Edit Clone()
{
var clone = (Edit)MemberwiseClone();
clone.Modified = Modified is null ? null : new DateTime(Modified.Value.Ticks);
clone.StepData = StepData.Select(sd => sd).ToList();
return clone;
}
Expand Down
4 changes: 4 additions & 0 deletions Backend/Services/UserEditService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public UserEditService(IUserEditRepository userEditRepo)
return new Tuple<bool, Guid?>(false, null);
}

edit.Modified = DateTime.UtcNow;

// Update existing Edit if guid exists, otherwise add new one at end of List.
var editIndex = userEdit.Edits.FindLastIndex(e => e.Guid == edit.Guid);
if (editIndex > -1)
Expand Down Expand Up @@ -64,6 +66,7 @@ public async Task<bool> AddStepToGoal(string projectId, string userEditId, Guid
{
return false;
}
edit.Modified = DateTime.UtcNow;
edit.StepData.Add(stepString);
return await _userEditRepo.Replace(projectId, userEditId, userEdit);
}
Expand All @@ -87,6 +90,7 @@ public async Task<bool> UpdateStepInGoal(
{
return false;
}
edit.Modified = DateTime.UtcNow;
edit.StepData[stepIndex] = stepString;
return await _userEditRepo.Replace(projectId, userEditId, userEdit);
}
Expand Down
23 changes: 16 additions & 7 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -318,25 +318,32 @@
"progressMerge": "Merge Set {{ val1 }} of {{ val2 }}"
},
"createStrWordInv": {
"title": "Create Structural Word Inventory"
"title": "Create Structural Word Inventory",
"description": "NOT IMPLEMENTED"
},
"handleFlags": {
"title": "Handle Flags"
"title": "Handle Flags",
"description": "NOT IMPLEMENTED"
},
"reviewDeferredDups": {
"title": "Review Deferred Duplicates"
"title": "Review Deferred Duplicates",
"description": "Revisit potential duplicates that were deferred during Merge Duplicates."
},
"spellCheckGloss": {
"title": "Spell Check Gloss"
"title": "Spell Check Gloss",
"description": "NOT IMPLEMENTED"
},
"validateChars": {
"title": "Validate Characters"
"title": "Validate Characters",
"description": "NOT IMPLEMENTED"
},
"validateStrWords": {
"title": "Validate Structural Words"
"title": "Validate Structural Words",
"description": "NOT IMPLEMENTED"
},
"reviewEntries": {
"title": "Review Entries",
"description": "View, sort, filter, and edit entries in the project.",
"allEntriesPerPageOption": "All",
"editSense": "Edit sense",
"discardChanges": "Discard changes?",
Expand Down Expand Up @@ -375,7 +382,8 @@
}
},
"charInventory": {
"title": "Create Character Inventory",
"title": "Check Orthography",
"description": "Review characters used in the spelling of vernacular words and check for typos.",
"characters": "characters",
"examples": "Examples",
"occurrences": "occurrences",
Expand Down Expand Up @@ -418,6 +426,7 @@
},
"mergeDups": {
"title": "Merge Duplicates",
"description": "Review potential duplicates identified by The Combine and merge or eliminate true duplicates.",
"helpText": {
"dragCard": "Drag a card here to merge",
"saveAndContinue": "Save changes and load a new set of words",
Expand Down
6 changes: 6 additions & 0 deletions src/api/models/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ export interface Edit {
* @memberof Edit
*/
changes: string;
/**
*
* @type {string}
* @memberof Edit
*/
modified?: string | null;
}
6 changes: 6 additions & 0 deletions src/api/models/user-edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,10 @@ export interface UserEdit {
* @memberof UserEdit
*/
projectId: string;
/**
*
* @type {string}
* @memberof UserEdit
*/
modified?: string | null;
}
80 changes: 80 additions & 0 deletions src/components/GoalTimeline/GoalHistoryButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Box, Button, Stack, Typography } from "@mui/material";
import { Fragment, ReactElement } from "react";
import { useTranslation } from "react-i18next";

import { CharInvChangesGoalList } from "goals/CharacterInventory/CharInvCompleted";
import { CharInvChanges } from "goals/CharacterInventory/CharacterInventoryTypes";
import { MergesCount } from "goals/MergeDuplicates/MergeDupsCompleted";
import { MergesCompleted } from "goals/MergeDuplicates/MergeDupsTypes";
import { EditsCount } from "goals/ReviewEntries/ReviewEntriesCompleted";
import { EntriesEdited } from "goals/ReviewEntries/ReviewEntriesTypes";
import { Goal, GoalName } from "types/goals";
import { goalNameToIcon } from "utilities/goalUtilities";

interface GoalHistoryButtonProps {
goal: Goal;
onClick: () => void;
}

export default function GoalHistoryButton(
props: GoalHistoryButtonProps
): ReactElement {
const { goal, onClick } = props;
const { i18n, t } = useTranslation();

const modifiedFormatted = goal.modified
? new Date(goal.modified).toLocaleString(i18n.resolvedLanguage, {
day: "numeric",
hour: "numeric",
hour12: true,
minute: "2-digit",
month: "short",
weekday: "short",
year: "numeric",
})
: null;

return (
<Button
onClick={onClick}
sx={{ alignItems: "flex-start", minWidth: "225px", textAlign: "start" }}
variant="outlined"
>
<Stack spacing={1}>
{/* Goal name */}
<Typography variant="h6">
<Box
component="span" // to be inline with the title
sx={{ marginInlineEnd: 1, verticalAlign: "middle" }}
>
{goalNameToIcon(goal.name)}
</Box>
{t(goal.name + ".title")}
</Typography>

{/* Change datetime */}
{!!goal.modified && (
<Typography variant="caption">{modifiedFormatted}</Typography>
)}

{/* Change summary */}
{!!goal.changes && <div>{getCompletedGoalInfo(goal)}</div>}
</Stack>
</Button>
);
}

function getCompletedGoalInfo(goal: Goal): ReactElement {
const { changes, name } = goal;
switch (name) {
case GoalName.CreateCharInv:
return CharInvChangesGoalList(changes as CharInvChanges);
case GoalName.MergeDups:
case GoalName.ReviewDeferredDups:
return MergesCount(changes as MergesCompleted);
case GoalName.ReviewEntries:
return EditsCount(changes as EntriesEdited);
default:
return <Fragment />;
}
}
Loading
Loading