Skip to content

[PB Extension] Create FW project - #2394

Draft
imnasnainaec wants to merge 20 commits into
developfrom
pb-extension/create-project-api
Draft

[PB Extension] Create FW project#2394
imnasnainaec wants to merge 20 commits into
developfrom
pb-extension/create-project-api

Conversation

@imnasnainaec

@imnasnainaec imnasnainaec commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Lets users create a brand-new FW Lite lexicon directly from the lexicon selector in Platform.Bible instead of only picking an existing one. This wires up the backend create endpoint and the project-type-aware URL routing the flow needs, and fixes a few adjacent bugs (empty-response parsing, language-tag filtering, lexicon-code validation) surfaced along the way.

Summary

  • Adds FwLiteApi.createProject(name, code, vernacularWs, analysisWs?) to the Platform.Bible extension's HTTP client, wrapping the POST /api/project/create endpoint added in Wire up template-based project creation via JSON snapshot import #2281.
  • Fixes a latent bug in fetchUrl: it previously called response.json() unconditionally, which throws a SyntaxError on empty-body responses (HTTP 200 with no content). The fix reads the body as text first and only parses JSON when the body is non-empty. On error responses it now throws with the response body, so backend validation messages survive. This also silently affected deleteEntry.
  • Adds a Create new lexicon flow to the SelectLexicon WebView: a form with name, auto-derived code, and vernacular language tag (pre-filled from the Paratext project's language but editable), plus an optional analysis language tag. The code is validated client-side against the backend's format rule and against existing lexicon codes, so a duplicate is (usually) caught before submitting. On success the new lexicon is auto-selected and the dialog shows the standard "Lexicon selection saved" confirmation; on failure the form shows the backend's reason (e.g. "not a valid IETF language tag").
  • Tracks each local project's type (FwData vs Harmony/CRDT) so lexicon and browse URLs route to the correct backend endpoints. The lookup is self-healing: because the cache is in-memory only, on a miss (e.g. after an extension restart) it reloads the project list from the backend before falling back to FwData, so a previously created CRDT lexicon stays reachable without the user reopening the selector.
  • Hardens the pre-existing lexicon.lexiconCode project-settings validator, which accepted any resolvable code because it tested an always-truthy array (.analysis); it now requires at least one vernacular writing system (analysis writing systems remain optional and are handled by selectLexicon).

Changes

  • platform.bible-extension/src/utils/fw-lite-api.ts
    • fetchUrl: results.json()results.text() + conditional JSON.parse; throws the response body on error responses
    • FwLiteApi.createProject: new public method using URLSearchParams for the create endpoint
    • projectTypeByCode cache + resolveProjectType: checkLexiconCode and getBrowseUrl (now async) resolve a project's type, repopulating from the backend on a cache miss
    • doesProjectMatchLangTag: reads each vernacular writing system's wsId instead of Object.keys on the array (which returned index strings), so getProjectsMatchingLanguage actually filters — a path the select-lexicon flow newly exercises by passing projectId to lexicon.lexicons
  • platform.bible-extension/src/main.ts — registers the lexicon.createLexicon command (returns the backend error message on failure); validateLexiconCode now checks for a vernacular writing system instead of the always-truthy .analysis array
  • platform.bible-extension/src/types/lexicon.d.ts'lexicon.createLexicon' command handler type; optional error on SuccessHolder
  • platform.bible-extension/src/types/localized-string-keys.ts + contributions/localizedStrings.json — 9 new %lexicon_createLexicon_*% strings
  • platform.bible-extension/src/components/create-lexicon.tsx — new form component; pre-checks the entered code against existing lexicons and surfaces backend error messages
  • platform.bible-extension/src/components/lexicon-combo-box.tsx — optional onCreateNew prop adds the "Create new lexicon" button
  • platform.bible-extension/src/utils/project-manager.ts — passes the project's vernacular language tag when opening the SelectLexicon WebView
  • platform.bible-extension/src/web-views/select-lexicon.web-view.tsx — wires up the create flow with auto-selection on success, passing existing codes for the duplicate pre-check
  • platform.bible-extension/src/web-views/index.tsx — types the SelectLexicon provider as LexiconWebViewOptions so vernacularLanguage is part of the declared contract

Implemented by Claude Sonnet 4.6 & Opus 4.8.

Devin review: https://app.devin.ai/review/sillsdev/languageforge-lexbox/pull/2394

Closes #2061

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d365a689-f5e0-4f6c-9af1-122448963dd7

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a lexicon creation form, localized UI strings, a creation command, MiniLCM project creation integration, project-type URL routing, and selection web-view states for creating and selecting lexicons.

Changes

Lexicon creation

Layer / File(s) Summary
Creation contracts and API routing
platform.bible-extension/src/types/lexicon.d.ts, platform.bible-extension/src/utils/fw-lite-api.ts, platform.bible-extension/src/main.ts
Adds the lexicon.createLexicon command, project-type caching, asynchronous lexicon-code resolution, project creation, and project-specific browse URLs.
Creation form and localized controls
platform.bible-extension/src/components/create-lexicon.tsx, platform.bible-extension/src/components/lexicon-combo-box.tsx, platform.bible-extension/src/types/localized-string-keys.ts, platform.bible-extension/contributions/localizedStrings.json
Adds validated name, code, and language-tag inputs, localized labels and errors, creation state handling, and a button to enter the creation flow.
Selection web-view integration
platform.bible-extension/src/web-views/select-lexicon.web-view.tsx, platform.bible-extension/src/web-views/index.tsx, platform.bible-extension/src/utils/project-manager.ts
Passes vernacular language options into the web view and coordinates lexicon loading, creation, selection, refresh, cancellation, and saved-state rendering.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: 🟨Medium

Suggested reviewers: jasonleenaylor, hahn-kev, rmunn

Poem

I’m a rabbit with a lexicon bright,
Creating new words by moonlight.
Codes hop into place,
Tags spring with grace,
And saved little projects take flight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fulfills #2061 by adding MiniLCM project creation support and wiring it into the Platform.Bible lexicon flow.
Out of Scope Changes check ✅ Passed The extra API and validation fixes are supporting changes for the creation flow, not unrelated scope creep.
Title check ✅ Passed The title reflects the main change: adding FW project creation support in the Platform.Bible extension.
Description check ✅ Passed The description matches the changeset and summarizes the new create-lexicon flow and backend/API updates.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pb-extension/create-project-api

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.

@imnasnainaec imnasnainaec self-assigned this Jun 30, 2026
@imnasnainaec imnasnainaec changed the title Add FwLiteApi.createProject (closes #2061) [PB Extension] Create FW project Jun 30, 2026

@myieye myieye left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Generally looks fine to me. 👍


function isValidLangTag(tag: string): boolean {
try {
return Intl.getCanonicalLocales(tag).length === 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What's the === 1 about? I'd expect >= 1.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Intl.getCanonicalLocales called on a string (instead of on an array) returns an array of length at most 1. The length check would need to be changed if we refactored the param from tag: string to tags: string[].

Comment thread platform.bible-extension/src/components/create-lexicon.tsx
async getProjects(): Promise<IProjectModel[]> {
return (await this.fetchPath('localProjects')) as IProjectModel[];
const projects = (await this.fetchPath('localProjects')) as IProjectModel[];
projects.forEach((p) => FwLiteApi.projectTypeByCode.set(p.code, p.crdt ? 'Harmony' : 'FwData'));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If I'm not mistaken, these projects are sometimes flagged as both crdt and fwdata.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Correct, and if the project has both flags, don't we want to default to Harmony interaction?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not entirely sure, but I think it makes sense to surface both project types. 😕

Paratext users are probably more on the power-user side of things, which means some would likely benefit from using their fwdata/FLEx project directly.

That probably needs a bit of thought, because it sort of means
Perhaps the project-type needs to be considered part of a lexicon's identifier?

In FWL we display all projects with the harmony and fwdata ones in separate lists (which means some are in both lists). Then when a project is open the URL tells us if we're working on the harmony or fwdata copy.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Possible follow-up issue: #2394 (comment)

@imnasnainaec
imnasnainaec force-pushed the pb-extension/create-project-api branch from 26cae9e to 77b6250 Compare July 2, 2026 20:52
imnasnainaec added a commit that referenced this pull request Jul 10, 2026
Address review feedback on #2394:
- validateLexiconCode checked `.analysis` truthiness, but writing-system
  fields are arrays, so an empty array always passed. Require a vernacular
  writing system instead (analysis is optional; selectLexicon handles its
  absence).
- The create-lexicon form now blocks codes that already exist before the
  create round-trips, showing a localized message instead of a raw 400.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imnasnainaec
imnasnainaec force-pushed the pb-extension/create-project-api branch from ee4770c to 07ce2d1 Compare July 10, 2026 13:20
imnasnainaec added a commit that referenced this pull request Jul 10, 2026
Address review feedback on #2394:
- validateLexiconCode checked `.analysis` truthiness, but writing-system
  fields are arrays, so an empty array always passed. Require a vernacular
  writing system instead (analysis is optional; selectLexicon handles its
  absence).
- The create-lexicon form now blocks codes that already exist before the
  create round-trips, showing a localized message instead of a raw 400.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imnasnainaec
imnasnainaec marked this pull request as ready for review July 10, 2026 19:01
coderabbitai[bot]

This comment was marked as resolved.

@imnasnainaec
imnasnainaec requested a review from myieye July 13, 2026 19:28
@imnasnainaec

Copy link
Copy Markdown
Collaborator Author

@myieye Thanks for your previous review and approval! I've made enough changes, I think additional review is warranted.

@alex-rawlings-yyc

alex-rawlings-yyc commented Jul 16, 2026

Copy link
Copy Markdown

@imnasnainaec here are my notes. I found one major bug, one that results from it, and a couple nits:

  1. If I delete the project's lexicon in FW Lite, clicking Browse Lexicon from Scripture Editor causes the FW Lite tab to appear and show an error since the lexicon linked with the project is now missing. It also seems like you can't create a new lexicon with the same code to try and mend the gap.
  2. When there is no lexicon, Add, Search, and Find hang on "Adding entry to lexicon...", "Loading", and "Loading" when you trigger their main function. This likely won't matter if the lexicon cannot be decoupled from the project without something that lets the extension know that the project no longer has a lexicon.
  3. There's no way to access the Select Lexicon popup as far as I can tell. This is probably good since I doubt people will want more than one lexicon per project, but I just want to make sure this was intentional.
  4. Clicking Lexicon menu items from Scripture Editor when no project is loaded no-ops. Maybe have a message explaining why the no-op or have it open project selector? I just realized that this is addressed in the other PR you requested my review on

Comment thread platform.bible-extension/src/components/create-lexicon.tsx
Comment thread platform.bible-extension/src/components/create-lexicon.tsx
async getProjects(): Promise<IProjectModel[]> {
return (await this.fetchPath('localProjects')) as IProjectModel[];
const projects = (await this.fetchPath('localProjects')) as IProjectModel[];
projects.forEach((p) => FwLiteApi.projectTypeByCode.set(p.code, p.crdt ? 'Harmony' : 'FwData'));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not entirely sure, but I think it makes sense to surface both project types. 😕

Paratext users are probably more on the power-user side of things, which means some would likely benefit from using their fwdata/FLEx project directly.

That probably needs a bit of thought, because it sort of means
Perhaps the project-type needs to be considered part of a lexicon's identifier?

In FWL we display all projects with the harmony and fwdata ones in separate lists (which means some are in both lists). Then when a project is open the URL tells us if we're working on the harmony or fwdata copy.

'lexicon.createLexicon',
async (name: string, code: string, vernacularWs: string, analysisWs?: string) => {
try {
await fwLiteApi.createProject(name, code, vernacularWs, analysisWs);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

At least we know that this creates a harmony project.
Although...it would probably be pretty easy to extend the api for whipping up an fwdata project instead 😆.

imnasnainaec added a commit that referenced this pull request Jul 20, 2026
Address review feedback on #2394:
- validateLexiconCode checked `.analysis` truthiness, but writing-system
  fields are arrays, so an empty array always passed. Require a vernacular
  writing system instead (analysis is optional; selectLexicon handles its
  absence).
- The create-lexicon form now blocks codes that already exist before the
  create round-trips, showing a localized message instead of a raw 400.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imnasnainaec
imnasnainaec force-pushed the pb-extension/create-project-api branch from e692e79 to 7b2c404 Compare July 20, 2026 21:02
@imnasnainaec
imnasnainaec marked this pull request as draft July 20, 2026 21:08
@imnasnainaec

Copy link
Copy Markdown
Collaborator Author

Note

Claude-drafted — potential follow-up issue, not filed. Captures @myieye's review thread on fw-lite-api.ts / main.ts (the getProjects project-type collapse). Posting here for discussion; @imnasnainaec feel free to file it as-is, edit, or fold into #2461.


[P.B ext] Distinguish FwData vs Harmony copies of the same lexicon

Follow-up to review discussion on this PR (thread by @myieye).

Problem

The extension keys a project's API type by lexicon code alone. In getProjects (platform.bible-extension/src/utils/fw-lite-api.ts) the type is collapsed with p.crdt ? 'Harmony' : 'FwData' and cached in projectTypeByCode (a Map<string, 'FwData' | 'Harmony'>). But a single project can be flagged both crdt and fwdata. When that happens:

  • it resolves only to Harmony, so the FwData/FLEx copy is unreachable;
  • code is not a sufficient identifier — the same code denotes two different lexicons.

Why it matters

Paratext users skew power-user; some would legitimately want to work against their existing fwdata/FLEx project rather than a CRDT copy. FW Lite itself surfaces Harmony and FwData projects in separate lists (a dual-flagged project appears in both), and disambiguates via the open URL (/paratext/project/… vs /paratext/fwdata/…). The extension currently can't express that choice.

Proposed direction

  • Treat the lexicon identifier as (code, type) rather than code alone.
  • Surface both types in the Select Lexicon list when a project is dual-flagged (mirroring FW Lite).
  • Persist the chosen type alongside lexicon.lexiconCode in project settings, and route getBrowseUrl / checkLexiconCode by the stored type instead of the collapsed cache value.

Out of scope

Lexicon creation always produces a Harmony project (this PR), so createProject setting the cache to Harmony is correct and unaffected.

Relationship to #2461

#2461 (remote project selection) adds a location axis (local vs. remote/Lexbox); this adds a type axis (FwData vs. Harmony). Both break the same assumption that code uniquely identifies a lexicon — a lexicon's real identity is closer to { location } × { type } × code. They're siblings, not duplicates: whatever qualified identifier #2461 introduces to distinguish a local foo from a remote foo should be the same scheme that distinguishes a FwData foo from a Harmony foo. Suggest settling the identifier model here first (this piece is smaller and needs no auth/networking), then building #2461 on top — or folding this in as a sub-task of #2461.

imnasnainaec added a commit that referenced this pull request Jul 21, 2026
Addresses later review feedback on #2394:

- Show a validation message for an invalid vernacular or analysis language
  tag in the create-lexicon form; previously the Create button was disabled
  with no explanation (per myieye).
- Re-check a project's stored lexicon code before acting on it; if it no
  longer resolves (e.g. deleted in FW Lite) clear it and reopen the selector
  instead of routing Browse/Add/Find to a dead endpoint (per alex-rawlings-yyc).
- Add a DEV-ONLY lexicon switcher (lexicon.changeLexicon menu command) so the
  selector is reachable after a lexicon is chosen; marked for removal before
  release. Canonical switch remains clearing lexicon.lexiconCode in project
  settings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
imnasnainaec added a commit that referenced this pull request Jul 24, 2026
Address review feedback on #2394:
- validateLexiconCode checked `.analysis` truthiness, but writing-system
  fields are arrays, so an empty array always passed. Require a vernacular
  writing system instead (analysis is optional; selectLexicon handles its
  absence).
- The create-lexicon form now blocks codes that already exist before the
  create round-trips, showing a localized message instead of a raw 400.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
imnasnainaec added a commit that referenced this pull request Jul 24, 2026
Addresses later review feedback on #2394:

- Show a validation message for an invalid vernacular or analysis language
  tag in the create-lexicon form; previously the Create button was disabled
  with no explanation (per myieye).
- Re-check a project's stored lexicon code before acting on it; if it no
  longer resolves (e.g. deleted in FW Lite) clear it and reopen the selector
  instead of routing Browse/Add/Find to a dead endpoint (per alex-rawlings-yyc).
- Add a DEV-ONLY lexicon switcher (lexicon.changeLexicon menu command) so the
  selector is reachable after a lexicon is chosen; marked for removal before
  release. Canonical switch remains clearing lexicon.lexiconCode in project
  settings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imnasnainaec
imnasnainaec force-pushed the pb-extension/create-project-api branch from 18b33f9 to 036841a Compare July 24, 2026 13:20
@imnasnainaec
imnasnainaec marked this pull request as ready for review July 25, 2026 01:26
@imnasnainaec
imnasnainaec marked this pull request as draft July 25, 2026 01:27
imnasnainaec and others added 3 commits July 27, 2026 11:03
`fetchUrl` now reads the response as text before conditionally parsing
JSON, so endpoints that return an empty 200 (like DELETE entry and the
new project/create route) no longer throw a SyntaxError.

`FwLiteApi.createProject` wraps `POST /api/project/create`, which was
added in #2281 to resolve #1920. Closes #2061.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an end-to-end flow for creating a new FW Lite CRDT project from
within the SelectLexicon dialog:
- New `lexicon.createLexicon` PAPI command wrapping FwLiteApi.createProject
- New CreateLexicon form component (name, auto-derived code, vernacular
  WS pre-filled from the Paratext project language, optional analysis WS)
- "Create new lexicon" button in LexiconComboBox opens the form
- On successful creation the new lexicon is auto-selected and the dialog
  shows the standard "Lexicon selection saved" confirmation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…key order

- fw-lite-api: add static projectTypeByCode cache (shared across FwLiteApi
  instances including EntryService) so CRDT projects created via createProject
  route through mini-lcm/Harmony/... instead of mini-lcm/FwData/...
  getProjects() populates the cache; createProject() seeds 'Harmony' immediately
  so the writingSystems call in selectLexicon succeeds without a re-fetch
- fw-lite-api: include response body text in error messages so backend
  validation failures (duplicate code, invalid lang tag, etc.) reach the logger
- create-lexicon: validate vernacular and analysis language tags with
  Intl.getCanonicalLocales() before enabling the submit button
- localized-string-keys / localizedStrings.json: restore alphabetical ordering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
imnasnainaec and others added 17 commits July 27, 2026 11:03
- deriveCode now replaces invalid characters with '-' instead of removing
  them, matching the backend SanitizeProjectCode behavior
- WebView onCreated catches selectLexicon failure: logs the error, refreshes
  the lexicon list, and falls back to the combo box so the user can manually
  select the project that was created on disk

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Svelte frontend routes FwData projects via /paratext/fwdata/{code}
and CRDT/Harmony projects via /paratext/project/{code}. The standalone
getBrowseUrl always used 'fwdata', producing a broken URL for any
Harmony lexicon.

Move getBrowseUrl into FwLiteApi as a method so it can consult the
projectTypeByCode cache and emit 'project' vs 'fwdata' accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hints the default analysis writing system on the Create new lexicon form,
per review feedback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Display the backend error message (e.g. duplicate code, invalid language
tag) instead of only logging it, per review feedback. Also drop the now-
pointless useCallback around handleSubmit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ping

- createLexicon now returns the backend validation message (e.g. "Project
  already exists", "not a valid IETF language tag") instead of a generic
  failure, so the create-lexicon form shows the actual reason. Also logs the
  real message rather than JSON.stringify(e), which rendered Errors as {}.
- Type the SelectLexicon WebView provider and its caller as
  LexiconWebViewOptions so vernacularLanguage is part of the declared contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cons

The in-memory projectTypeByCode map is empty after an extension restart, so a
previously created Harmony/CRDT lexicon was misrouted to the FwData endpoints
(browse, search, and entry operations all failed) until the user reopened the
lexicon selector. checkLexiconCode and getBrowseUrl now resolve the type via a
new resolveProjectType helper, which reloads the project list from the backend
on a cache miss before falling back to FwData.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
selectLexicon awaited the command but ignored its result, so onCreated and
LexiconComboBox.saveSetting showed a "saved" confirmation even if the command
returned { success: false }. Throw on a non-success result so the create flow
falls back to the combo box and the combo box surfaces its save error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review feedback on #2394:
- validateLexiconCode checked `.analysis` truthiness, but writing-system
  fields are arrays, so an empty array always passed. Require a vernacular
  writing system instead (analysis is optional; selectLexicon handles its
  absence).
- The create-lexicon form now blocks codes that already exist before the
  create round-trips, showing a localized message instead of a raw 400.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
doesProjectMatchLangTag used Object.keys on the vernacular IWritingSystem[],
which yields index strings ('0', '1', ...) rather than language tags, so
getProjectsMatchingLanguage never matched and always fell back to all
projects. Map over the array and read each writing system's wsId instead.

Also drops a redundant comment on the lexicon-code validator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously an invalid code (uppercase, spaces, symbols) silently
disabled Submit with no feedback, unlike the codeExists case which
already had a visible error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auto-lowercase the code as typed (matching Lexbox's create-project
zod schema) instead of erroring on uppercase, and add Lexbox's
4-character minimum length with its own message.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Addresses later review feedback on #2394:

- Show a validation message for an invalid vernacular or analysis language
  tag in the create-lexicon form; previously the Create button was disabled
  with no explanation (per myieye).
- Re-check a project's stored lexicon code before acting on it; if it no
  longer resolves (e.g. deleted in FW Lite) clear it and reopen the selector
  instead of routing Browse/Add/Find to a dead endpoint (per alex-rawlings-yyc).
- Add a DEV-ONLY lexicon switcher (lexicon.changeLexicon menu command) so the
  selector is reachable after a lexicon is chosen; marked for removal before
  release. Canonical switch remains clearing lexicon.lexiconCode in project
  settings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
isLexiconCodeValid and resolveProjectType previously collapsed every
error into "the lexicon is gone" / "default to FwData", so FW Lite
still starting up (or any other transient failure) could silently
clear a project's stored lexicon choice or misroute a Harmony project.

Add HttpStatusError to distinguish a real backend response from a
request that never reached it at all, and only treat the former as
confirmed-invalid. resolveProjectType now propagates a getProjects
failure instead of guessing, since that endpoint has no per-code
failure mode to misinterpret.

Full correctness (narrowing to a 404-specific check) is blocked on
#2487, which tracks the backend
currently returning 500 for "not found" too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ge filtering

Backend error responses are JSON either way (a bare string from
Results.BadRequest/NotFound, or a ProblemDetails object from
Results.Problem), but fetchUrl surfaced the raw response text
verbatim, so create-lexicon validation errors reached the user still
wrapped in JSON-string quotes. extractErrorMessage unwraps either
shape.

getProjectsMatchingLanguage used Promise.all, so one project's failed
writingSystems lookup (e.g. a broken/deleted project) rejected the
whole batch and silently fell back to the unfiltered project list.
Switch to Promise.allSettled so a single failure just drops that
project instead of discarding every other project's match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
saveSetting caught a failed selectLexicon call, logged it, and cleared
settingSaving without any visible sign of failure — the UI just
silently returned to the combo box. Add a saveError state and render
it next to the combo box, reusing the existing (previously log-only)
%lexicon_selectLexicon_saveError% string's intent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@imnasnainaec
imnasnainaec force-pushed the pb-extension/create-project-api branch from 080a42f to 91c442b Compare July 27, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a new project via the MiniLCM API

3 participants