Skip to content

Conversation

@myieye
Copy link
Collaborator

@myieye myieye commented Nov 14, 2025

Resolves #2103 (https://community.software.sil.org/t/new-word-dialog-should-contain-part-of-speech/10796)
Also implements: https://community.software.sil.org/t/collect-words-by-semantic-domain/10949/1

When filtering by a semantic domain, that semantic domain is now pre-selected when creating new entries:
image

Note Semantic domains are not visible in the new entry dialog unless there's a pre-selection:
image

But if there was a pre-selection and that selection is cleared we do not suddenly hide the semantic domains:
image

Scope creep:

I just went ahead and did the same thing for part of speech:
image
It's been a requested feature to also show part of speech in the new entry dialog, so that happened along the way here. We always show it (i.e. not only when there's a pre-selected PoS).

We were incorrectly showing the Sense/Meaning history button in the dialog, because I touched that code anyway, I fixed it so that we're only showing the delete button:
Before:
image
After:
image
Note that the index/"1" is also gone now, because it was meaningless.

Final change:
The delete sense button doesn't have a confirmation dialog anymore. I don't think it's important.
A user would presumably click it, because they don't want to provide a gloss. So, the confirmation just adds extra clicks.
Also, the chance of losing something important is minimal, because the sense hasn't been created yet.
But to counter the new ease of deletion, you can now re-add the sense: (which uses the same pre-population code as the originally generated sense)
image

@github-actions github-actions bot added the 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related label Nov 14, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This PR refactors entry creation with sense management UI capabilities in the dialog, introduces ObjectHeader component for consistent header rendering, enforces readonly semantics across type signatures, and integrates part-of-speech and semantic domain filtering into the browse view components.

Changes

Cohort / File(s) Change Summary
New UI Components
frontend/viewer/src/lib/entry-editor/object-editors/AddSenseButton.svelte, frontend/viewer/src/lib/entry-editor/object-editors/ObjectHeader.svelte
Introduces AddSenseButton component for adding senses and ObjectHeader component for rendering consistent headers (sense or example types) with localization and optional actions.
Entry Dialog Refactoring
frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte
Replaces simple EntryEditor with richer composition using EntryEditorPrimitive, SenseEditorPrimitive, and ObjectHeader; adds SenseTemplate type; implements sense lifecycle management with add/remove capabilities; makes openWithValue internal and extends it to accept optional sense template parameter.
Dialog Service Integration
frontend/viewer/src/lib/services/dialogs-service.ts
Extends invokeNewEntryDialog callback and createNewEntry method to accept optional newSense (SenseTemplate) parameter; imports and threads SenseTemplate through dialog invocation chain.
Field Editor Type Updates
frontend/viewer/src/lib/entry-editor/field-editors/ComplexForms.svelte, frontend/viewer/src/lib/entry-editor/field-editors/ComplexFormComponents.svelte, frontend/viewer/src/lib/writing-system-service.svelte.ts
Enforces readonly semantics on entry types by replacing IEntry with ReadonlyDeep in component props and service method signatures; adds type-fest ReadonlyDeep import across files.
Entry Editor Refactoring
frontend/viewer/src/lib/entry-editor/object-editors/EntryEditor.svelte
Replaces inline sense/example header markup with ObjectHeader components; imports and uses new AddSenseButton and ObjectHeader components; maintains sticky header and action handling patterns.
Sense Editor Props Extension
frontend/viewer/src/lib/entry-editor/object-editors/SenseEditorPrimitive.svelte
Adds optional partOfSpeechDescription and semanticDomainsDescription Snippet props; renders description blocks after respective form fields.
Browse View Integration
frontend/viewer/src/project/browse/BrowseView.svelte, frontend/viewer/src/project/browse/EntriesList.svelte, frontend/viewer/src/project/browse/SearchFilter.svelte
Adds partOfSpeech and semanticDomain state bindings in BrowseView; extends EntriesList and SearchFilter components with public props for filtering; threads filter context through component hierarchy; updates createNewEntry calls to include semantic domain and part-of-speech template options.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • NewEntryDialog.svelte: High-complexity sense lifecycle management, template-driven state initialization, and UI composition requires careful trace-through of data flow and edge cases (sense add/remove, template binding, entry initialization).
  • Type changes across multiple files: Verify readonly enforcement doesn't break existing mutation patterns and that type-fest ReadonlyDeep is correctly applied throughout the hierarchy.
  • Component integration points: Cross-verify prop threading through BrowseView → EntriesList → EntriesList → DialogsService → NewEntryDialog, ensuring context propagates correctly.
  • AddSenseButton and ObjectHeader: Verify new component props (Snippet-based descriptions), rendering logic, and accessibility patterns align with existing patterns.
  • State binding changes in SearchFilter: Ensure $bindable() migration from internal state to props doesn't introduce reactivity issues.

Possibly related PRs

  • #2041 — Adds semantic domain filtering to SearchFilter and browse flow, directly consumed by the new partOfSpeech/semanticDomain filtering integration.
  • #2079 — Introduces part-of-speech filtering support, complementary to the partOfSpeech prop integration in BrowseView and SearchFilter.
  • #2097 — Modifies entry-editor components (NewEntryDialog, EntryEditor, SenseEditorPrimitive) with overlapping UI and composition changes.

Suggested labels

💻 FW Lite

Suggested reviewers

  • hahn-kev
  • imnasnainaec

Poem

🐰✨ A Sense of Order, Bouncing Through

Hop along as dialogs bloom with senses new,
ObjectHeaders frame each meaning true,
Templates guide the fuzzy path we pursue,
Readonly guards keep mutations at bay—
Browse with confidence, filters all the way! 🌱

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Basic word collection by semantic domain (with scope creep)' clearly relates to the main changes: enabling semantic domain filtering for new entries and adding part-of-speech support.
Description check ✅ Passed The description is comprehensively related to the changeset, detailing pre-selection of semantic domains and part-of-speech fields, UI fixes for sense actions, and confirmation dialog removal.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Nov 14, 2025

UI unit Tests

  1 files  ±0   45 suites  ±0   19s ⏱️ ±0s
111 tests ±0  111 ✅ ±0  0 💤 ±0  0 ❌ ±0 
160 runs  ±0  160 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit f38c22a. ± Comparison against base commit 0aeeae9.

♻️ This comment has been updated with latest results.

@argos-ci
Copy link

argos-ci bot commented Nov 14, 2025

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Nov 18, 2025, 10:39 AM

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
frontend/viewer/src/project/browse/EntriesList.svelte (1)

155-158: Consider consistency in handling undefined semantic domain.

The code converts an undefined semanticDomain to an empty array [], while BrowseView.svelte (line 35) passes undefined in the same scenario. For consistency and clearer intent (distinguishing "not specified" from "empty list"), consider using undefined here as well.

Apply this diff if you prefer consistency:

-    const entry = await dialogsService.createNewEntry(undefined, {
-      semanticDomains: semanticDomain ? [semanticDomain] : [],
-      partOfSpeech: partOfSpeech,
-    });
+    const entry = await dialogsService.createNewEntry(undefined, {
+      semanticDomains: semanticDomain ? [semanticDomain] : undefined,
+      partOfSpeech,
+    });
frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte (4)

32-35: sense initialization is unused before first openWithValue

let sense = $state<ISense | undefined>(defaultSense(entry.id)); creates an initial sense tied to the initial entry, but both entry and sense are overwritten in openWithValue before the dialog is ever opened, so this initializer is effectively dead.

You can simplify by initializing with undefined to make the lifecycle clearer:

-  // svelte-ignore state_referenced_locally
-  let sense = $state<ISense | undefined>(defaultSense(entry.id));
+  // svelte-ignore state_referenced_locally
+  let sense = $state<ISense | undefined>(undefined);

70-79: Validation relies on entry.senses being in sync with sense

validateEntry checks entry.senses[0] rather than the standalone sense state. Right now this works because:

  • addSense() always sets entry.senses = [sense].
  • createEntry() overwrites entry.senses from sense before calling validateEntry.

However, when deleting a sense you only set sense = undefined and leave entry.senses untouched until createEntry() runs. It’s safe but a bit fragile.

Consider eagerly syncing entry.senses when clearing sense to keep the data model obviously consistent:

-                  <Button onclick={() => sense = undefined} size="icon" variant="secondary" icon="i-mdi-trash-can" />
+                  <Button
+                    onclick={() => {
+                      sense = undefined;
+                      entry.senses = [];
+                    }}
+                    size="icon"
+                    variant="secondary"
+                    icon="i-mdi-trash-can"
+                  />

or centralize this in a small helper.


81-83: Clarify types of template flags for undefined usage

partOfSpeechIsFromTemplate / semanticDomainIsFromTemplate are deliberately set to undefined in addSense(), but their declarations use $state<boolean>(). Depending on how $state is typed, this may or may not explicitly include undefined in the variable type.

To make the intent obvious to TypeScript and future readers, consider widening the type:

-  let partOfSpeechIsFromTemplate = $state<boolean>();
+  let partOfSpeechIsFromTemplate = $state<boolean | undefined>();
...
-  let semanticDomainIsFromTemplate = $state<boolean>();
+  let semanticDomainIsFromTemplate = $state<boolean | undefined>();

96-119: Unify SenseTemplate alias with newSense / senseTemplate types

You export SenseTemplate as:

export type SenseTemplate = Partial<Pick<ISense, 'partOfSpeech' | 'semanticDomains'>>;

but both senseTemplate state and the newSense parameter use Partial<Omit<ISense, 'partOfSpeechId'>>, which is broader and doesn’t reference SenseTemplate at all.

For clarity and to reduce type drift, consider using the exported alias consistently:

-  let senseTemplate = $state<Partial<Omit<ISense, 'partOfSpeechId'>>>();
+  let senseTemplate = $state<SenseTemplate>();
...
-  function openWithValue(newEntry: Partial<IEntry>, newSense?: Partial<Omit<ISense, 'partOfSpeechId'>>): Promise<IEntry | undefined> {
+  function openWithValue(newEntry: Partial<IEntry>, newSense?: SenseTemplate): Promise<IEntry | undefined> {

If you intentionally want to allow more fields (e.g. for future pre-population reuse), then it might be better to adjust SenseTemplate itself to match that, so external callers don’t see a stricter type than the implementation actually supports.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 846d917 and ee93625.

📒 Files selected for processing (12)
  • frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte (4 hunks)
  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexFormComponents.svelte (1 hunks)
  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexForms.svelte (1 hunks)
  • frontend/viewer/src/lib/entry-editor/object-editors/AddSenseButton.svelte (1 hunks)
  • frontend/viewer/src/lib/entry-editor/object-editors/EntryEditor.svelte (4 hunks)
  • frontend/viewer/src/lib/entry-editor/object-editors/ObjectHeader.svelte (1 hunks)
  • frontend/viewer/src/lib/entry-editor/object-editors/SenseEditorPrimitive.svelte (3 hunks)
  • frontend/viewer/src/lib/services/dialogs-service.ts (2 hunks)
  • frontend/viewer/src/lib/writing-system-service.svelte.ts (3 hunks)
  • frontend/viewer/src/project/browse/BrowseView.svelte (4 hunks)
  • frontend/viewer/src/project/browse/EntriesList.svelte (4 hunks)
  • frontend/viewer/src/project/browse/SearchFilter.svelte (3 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-05-27T06:18:33.852Z
Learnt from: hahn-kev
Repo: sillsdev/languageforge-lexbox PR: 1710
File: frontend/viewer/src/project/browse/BrowseView.svelte:17-19
Timestamp: 2025-05-27T06:18:33.852Z
Learning: The NewEntryButton component in frontend/viewer/src/project/NewEntryButton.svelte already internally checks features.write permission and conditionally renders based on write access, so external disabled props are not needed.

Applied to files:

  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexFormComponents.svelte
  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexForms.svelte
  • frontend/viewer/src/lib/entry-editor/object-editors/AddSenseButton.svelte
📚 Learning: 2025-07-30T04:53:41.702Z
Learnt from: rmunn
Repo: sillsdev/languageforge-lexbox PR: 1844
File: frontend/viewer/src/lib/entry-editor/ItemListItem.svelte:26-37
Timestamp: 2025-07-30T04:53:41.702Z
Learning: In frontend/viewer/src/lib/entry-editor/ItemListItem.svelte, the TODO comments for unused props `index` and `actions` are intentional reminders for future work to be completed in a separate PR, not issues to be resolved immediately. These represent planned functionality that will be implemented later.

Applied to files:

  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexFormComponents.svelte
  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexForms.svelte
  • frontend/viewer/src/project/browse/EntriesList.svelte
  • frontend/viewer/src/lib/entry-editor/object-editors/EntryEditor.svelte
  • frontend/viewer/src/lib/entry-editor/object-editors/AddSenseButton.svelte
  • frontend/viewer/src/lib/entry-editor/object-editors/SenseEditorPrimitive.svelte
  • frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte
  • frontend/viewer/src/project/browse/SearchFilter.svelte
  • frontend/viewer/src/project/browse/BrowseView.svelte
📚 Learning: 2025-06-18T05:13:00.591Z
Learnt from: hahn-kev
Repo: sillsdev/languageforge-lexbox PR: 1757
File: frontend/viewer/src/lib/components/field-editors/multi-select.svelte:130-136
Timestamp: 2025-06-18T05:13:00.591Z
Learning: In frontend/viewer/src/lib/components/field-editors/multi-select.svelte, the computeCommandScore function from 'bits-ui' handles empty filter strings appropriately and does not hide all options when the filter is empty, contrary to initial analysis assumptions.

Applied to files:

  • frontend/viewer/src/lib/entry-editor/field-editors/ComplexForms.svelte
  • frontend/viewer/src/lib/entry-editor/object-editors/SenseEditorPrimitive.svelte
  • frontend/viewer/src/project/browse/SearchFilter.svelte
  • frontend/viewer/src/project/browse/BrowseView.svelte
📚 Learning: 2025-07-22T09:19:37.386Z
Learnt from: rmunn
Repo: sillsdev/languageforge-lexbox PR: 1836
File: frontend/viewer/src/lib/components/audio/AudioDialog.svelte:25-25
Timestamp: 2025-07-22T09:19:37.386Z
Learning: In the sillsdev/languageforge-lexbox project, when file size limits or other constants need to be shared between C# backend and TypeScript frontend code, prefer exposing them through Reinforced.Typings type generation rather than hardcoding the values separately. This ensures consistency and prevents discrepancies when values change.

Applied to files:

  • frontend/viewer/src/project/browse/EntriesList.svelte
  • frontend/viewer/src/lib/writing-system-service.svelte.ts
📚 Learning: 2025-07-31T16:00:49.635Z
Learnt from: imnasnainaec
Repo: sillsdev/languageforge-lexbox PR: 1867
File: platform.bible-extension/src/types/fw-lite-extension.d.ts:4-22
Timestamp: 2025-07-31T16:00:49.635Z
Learning: In the sillsdev/languageforge-lexbox repository, the platform.bible-extension is intentionally tightly coupled with the frontend's dotnet-types. The relative imports from `../../../frontend/viewer/src/lib/dotnet-types/index.js` in the extension's type declarations are by design, not a maintainability issue that needs to be addressed.

Applied to files:

  • frontend/viewer/src/project/browse/EntriesList.svelte
  • frontend/viewer/src/project/browse/BrowseView.svelte
📚 Learning: 2025-08-14T12:54:04.004Z
Learnt from: myieye
Repo: sillsdev/languageforge-lexbox PR: 1906
File: frontend/viewer/src/lib/components/ui/alert-dialog/alert-dialog-root.svelte:11-13
Timestamp: 2025-08-14T12:54:04.004Z
Learning: In Svelte 5, children are rendered using snippets with {render children?.()} syntax instead of the legacy <slot /> approach used in earlier Svelte versions. Components should destructure children from props and use {render children?.()} to render child content.

Applied to files:

  • frontend/viewer/src/lib/entry-editor/object-editors/ObjectHeader.svelte
📚 Learning: 2025-08-14T12:50:25.135Z
Learnt from: myieye
Repo: sillsdev/languageforge-lexbox PR: 1906
File: frontend/viewer/src/lib/components/ui/dialog-shared/dialog-shared-root.svelte:3-3
Timestamp: 2025-08-14T12:50:25.135Z
Learning: In the dialog-shared-root.svelte component, the module-level `openDialogs` state is intentionally shared across all component instances to coordinate dialog stacking and overlay behavior across the entire application. This enables proper z-index management where newer dialogs appear on top and only the bottom dialog shows its overlay.

Applied to files:

  • frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte
  • frontend/viewer/src/project/browse/SearchFilter.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build UI / publish-ui
  • GitHub Check: Build API / publish-api
  • GitHub Check: check-and-lint
  • GitHub Check: Build FW Lite and run tests
  • GitHub Check: frontend-component-unit-tests
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (29)
frontend/viewer/src/lib/entry-editor/field-editors/ComplexFormComponents.svelte (1)

11-11: LGTM! Type safety improvement.

The introduction of ReadonlyDeep<IEntry> for the entry prop appropriately enforces immutability, as the component only reads from the entry object and never mutates it.

Also applies to: 16-16

frontend/viewer/src/lib/writing-system-service.svelte.ts (1)

15-15: LGTM! Consistent type safety enhancement.

The ReadonlyDeep<IEntry> parameter type for both the class method and standalone headword function correctly enforces immutability, as both implementations only read from the entry's citationForm and lexemeForm properties.

Also applies to: 123-123, 210-210

frontend/viewer/src/lib/entry-editor/field-editors/ComplexForms.svelte (3)

2-5: LGTM: Inline type import is good practice.

The inline type import for EntrySenseSelection on line 2 correctly distinguishes type-only imports, which is a TypeScript best practice.


16-16: LGTM: Readonly entry type improves immutability.

Changing the entry prop to ReadonlyDeep<IEntry> correctly enforces immutability. All usages of entry within this component (lines 35, 36, 43-45) are read-only operations, making this change safe and beneficial for type safety.


11-11: No issues found with the ReadonlyDeep import.

The latest stable version of type-fest is 5.2.0, while the codebase uses 4.41.0. However, verification confirms that ReadonlyDeep is available and unchanged between versions, with no known issues at the version being used. The import is correct and functional as written.

frontend/viewer/src/lib/entry-editor/object-editors/AddSenseButton.svelte (1)

1-14: LGTM!

The component is well-structured and correctly implements view-aware translations for the Add Sense/Meaning button. The use of pt() for both the title and label ensures consistent terminology across different views.

frontend/viewer/src/lib/entry-editor/object-editors/SenseEditorPrimitive.svelte (2)

22-31: LGTM! Optional snippet props for field descriptions.

The addition of partOfSpeechDescription and semanticDomainsDescription snippets provides a clean extension point for injecting custom UI adjacent to these fields. The implementation correctly uses optional types and chaining.


81-81: LGTM! Snippet rendering is correctly implemented.

The snippet rendering uses correct Svelte 5 syntax with {@render ...?.()}, and the optional chaining ensures safe rendering when descriptions are not provided.

Also applies to: 96-96

frontend/viewer/src/project/browse/SearchFilter.svelte (2)

31-41: LGTM! Props correctly refactored to bindable state.

The conversion of semanticDomain and partOfSpeech from internal state to bindable props enables parent components to control and react to these filter values. The type annotations are correct.


77-83: LGTM! Filter construction logic is correct.

The gridify filter construction properly handles semantic domain filtering with subdomain inclusion support and part-of-speech filtering. The operators used (^ for prefix match, = for exact match) align with the gridify filter syntax mentioned in the codebase.

frontend/viewer/src/project/browse/BrowseView.svelte (3)

28-29: LGTM! Filter state properly initialized.

The new state variables for semantic domain and part-of-speech filtering are correctly typed and initialized.


33-40: LGTM! Pre-selection context passed to new entry dialog.

The newEntry function correctly passes the current semantic domain and part-of-speech filter values to the entry creation dialog, enabling the pre-selection behavior described in the PR objectives. The conversion of semanticDomain to an array is appropriate for the API.


63-63: LGTM! Filter values correctly bound and passed through component hierarchy.

The two-way bindings to SearchFilter and one-way props to EntriesList establish the proper data flow for the filtering feature.

Also applies to: 74-75

frontend/viewer/src/project/browse/EntriesList.svelte (1)

45-46: LGTM! Props correctly added for filter context.

The new props enable EntriesList to receive the current filter context and pass it to the entry creation dialog.

Also applies to: 56-57

frontend/viewer/src/lib/entry-editor/object-editors/EntryEditor.svelte (4)

34-35: LGTM! New components imported for header refactoring.

The imports support the consolidation of header rendering logic into dedicated components.


170-178: LGTM! Sense header refactored to use ObjectHeader component.

The refactoring correctly extracts sense header rendering to the ObjectHeader component while preserving sticky positioning behavior and action buttons. The conditional sticky class application based on modalMode is appropriate.


187-194: LGTM! Example header refactored to use ObjectHeader component.

The example header correctly uses ObjectHeader with type="example". Example headers don't need sticky positioning since they're nested within sense sections, which is the appropriate behavior.


224-224: LGTM! AddSense button refactored to use AddSenseButton component.

The extracted button component promotes reusability and consistent styling.

frontend/viewer/src/lib/entry-editor/object-editors/ObjectHeader.svelte (1)

1-38: LGTM! Well-structured header component for sense and example sections.

The ObjectHeader component provides a clean abstraction for rendering section headers with consistent styling and structure. The implementation correctly:

  • Uses view-aware translations for "Sense"/"Meaning" terminology
  • Supports optional numbering via the index prop
  • Renders optional action buttons via the children snippet
  • Spreads HTMLAttributes for flexibility (e.g., custom classes)
frontend/viewer/src/lib/services/dialogs-service.ts (3)

5-5: LGTM! SenseTemplate type imported for new-entry dialog integration.

The import enables the dialog service to accept and pass sense template data for pre-population.


23-26: LGTM! Dialog invoker signature updated consistently.

Both the private field type and setter correctly include the optional newSense parameter, maintaining type safety.


28-37: LGTM! createNewEntry correctly extended with sense template support.

The method signature and implementation correctly thread the optional newSense parameter through to the dialog invocation, enabling the pre-selection feature described in the PR objectives.

frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte (7)

53-59: Sense assignment in createEntry aligns with “no-sense” behavior

Setting entry.senses = sense ? [sense] : []; right before validation and save correctly ensures:

  • Entries with no sense (after deleting the sense and not re-adding) are created with an empty senses array.
  • Validation only requires definition/gloss when a sense is actually present.

This is consistent with the intended UX around deleting a sense and optionally re‑adding it.


81-94: Template-origin flags logic looks correct and matches UX intent

The runes-based effects for partOfSpeechIsFromTemplate and semanticDomainIsFromTemplate correctly:

  • Start as undefined.
  • Compute whether the current sense matches the template values.
  • Stop updating once they flip to false, so the “From active filter” label disappears permanently after the user diverges from the template.
  • Are reset to undefined in addSense(), so a new sense can again show the label if it matches the template.

This neatly matches the intended badge semantics without extra bookkeeping.


112-119: addSense matches pre-pop & re-add semantics

addSense() correctly:

  • Resets template-origin flags.
  • Creates a fresh sense tied to entry.id.
  • Clones senseTemplate.semanticDomains into a new array to avoid aliasing.
  • Merges senseTemplate over tmpSense, then overrides id and entryId to ensure they stay coherent.
  • Updates entry.senses = [sense].

This gives the expected behavior:

  • Initial sense is pre-populated from the active filter.
  • After deleting, re-adding uses the same pre-pop logic as the original.

136-148: Field visibility logic matches the PR requirements

The OverrideFields shownFields configuration meets the described UX:

  • Always shows:
    • lexemeForm, citationForm, gloss, definition, partOfSpeechId — giving consistent PoS visibility.
  • Only shows semanticDomains when the template provided domains:
...(senseTemplate?.semanticDomains?.length ? ['semanticDomains'] as const : [])

Because this depends on senseTemplate (not the mutable sense), the semantic domain UI remains visible even if the user clears the pre-selected domains, which is exactly the requested behavior.


152-180: Sense header & delete/add behavior align with new UX

  • ObjectHeader type="sense" with just a trash button removes the history button and index, matching the simplified Sense/Meaning actions.
  • The delete button sets sense = undefined with no confirmation dialog, and the {:else} branch exposes an AddSenseButton hooked to addSense(), which reuses the template-based pre-population.

Aside from the optional suggestion to also clear entry.senses when deleting (see earlier comment), this flow looks solid and consistent with the PR description.


157-174: Template-derived descriptions are correctly wired into SenseEditorPrimitive

The partOfSpeechDescription and semanticDomainsDescription snippets display the “From active filter” label only when the corresponding *IsFromTemplate flags are truthy, and include a filter icon for clarity.

This is a clean way to surface template provenance inside the sense editor without coupling SenseEditorPrimitive to filter state.


96-110: No breaking changes—refactoring is properly encapsulated.

The search confirms that openWithValue appears only within NewEntryDialog.svelte (its definition at line 96 and assignment to dialogsService.invokeNewEntryDialog at line 39). There are no direct imports or external usages of this function anywhere in the codebase. The only cross-file reference to NewEntryDialog.svelte is a type-only import in dialogs-service.ts, which remains unaffected. All dialog invocations now correctly flow through dialogsService, as intended.

@github-actions
Copy link

github-actions bot commented Nov 14, 2025

C# Unit Tests

130 tests  ±0   130 ✅ ±0   19s ⏱️ ±0s
 20 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit f38c22a. ± Comparison against base commit 0aeeae9.

♻️ This comment has been updated with latest results.

@myieye myieye merged commit c0957ed into develop Nov 21, 2025
27 checks passed
@myieye myieye deleted the 2103-rudimentary-collect-words-by-semantic-domain-feature branch November 21, 2025 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rudimentary collect words by semantic domain feature

2 participants