PT-4731: Show Biblica license notice on restricted texts - #2864
Open
katherinejensen00 wants to merge 6 commits into
Open
katherinejensen00 wants to merge 6 commits into
katherinejensen00 wants to merge 6 commits into
Conversation
katherinejensen00
requested review from
irahopkinson,
jolierabideau,
lyonsil,
rolfheij-sil and
tjcouch-sil
as code owners
September 25, 2026 00:24
katherinejensen00
force-pushed
the
pt-4731-biblica-texts-special-message
branch
2 times, most recently
from
September 28, 2026 14:42
91e8947 to
de1fb36
Compare
Show a dismissible licence banner on Biblica's traditionally licensed
(non-Open) texts, and keep them from being picked as a model or base text.
Detection (C#)
- BiblicaLicensing: Biblica's list of 56 DBL ids (rights holder Biblica,
not open access) is the authority; a copyright rule ("Biblica, Inc" /
"Biblica®", not "Biblica® Open", OBTT exempted by id) also counts, so an
installed Biblica text added to the DBL later is covered. A survey of all
1,819 resources in Platform.Bible's list shows the rule and the list agree.
- New read-only computed project setting platformScripture.copyrightNotice:
none | notification (PT9's "Notification:" copyright banner, e.g. ESV) |
restrictedLicense (with the years of the text's copyright statement).
- DblResourceData.IsRestrictedAsModelText for catalog rows;
ProjectSummary.IsRestrictedAsBase for Manage Books.
Banner (platform-scripture-editor)
- CopyrightNoticeBanner in Simple Column 1 and Column 3 and the Power-mode
editor: bold name, clamped to two lines with Show more (re-measured when
a hidden tab becomes visible), More info… opens Biblica's terms with a
link to biblica.com/permissions, dismissal kept per pane and per text.
- Text Collection cells get an info icon carrying the notice.
- Strings live in platform-scripture and are translated into all 33 of its
locales (AI drafts).
Pickers
- ResourcePickerDialog gains getDisabledReason; the Column 1 model text
picker and Team layout's model text picker grey out restricted texts
with a tooltip. Already-selected ones can still be deselected.
- Manage Books "Create based on" shows restricted texts but not as choices.
Also: Storybook stories for the banner and the picker's disabled rows,
rebuilt platform-bible-react/-utils dist and papi.d.ts, and
adr-biblica-license-notice-computed-setting.
Enhanced Resources is not covered: an Enhanced Resource is not a ScrText
project, so the setting cannot reach it.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Restriction - One check, BiblicaLicensing.IsRestricted(scrText), used by the notice setting and Manage Books. It applies only to resources, so a Biblica team's own editable project (or Biblica's master project, whose DBL id matches the list) is never flagged. It reads the typed, entity-decoded plain-text copyright, survives a malformed DBL id, and matches more spellings (Biblica after a non-Latin letter, Arabic and full-width commas, "Biblica Open" without ®). - The notice now carries its names (name, fullName falling back to the short name), so panes read one setting and a missing full name no longer shows "*Name Missing*". It is built through factories, and CopyrightNoticeKind has its own file. - Pickers no longer rely on a flag baked into the cached DBL catalog: a new listModelTextRestrictions call (no network needed) returns Biblica's ids and the installed restricted resources, and platform-get-resources stamps isRestrictedAsModelText on every catalog and local row it serves. This covers an old persisted cache, offline sessions, local rows and Biblica texts added to the DBL after the list was made. Banner and details - Dismissal matches Paratext 9: a pane remembers only the text whose notice was dismissed, so switching to another text and back shows it again. The banner and grid icon are keyed by project, so a switch never shows the previous text's notice. - The details dialog is modal, returns focus to its opener, has a working width and a localized Close, and announces its text. The permissions URL is a real link, opened in the browser through platform.openWindow. - role="note" instead of a live region; the dismiss button has a tooltip and a clearer label; the grid icon has a short label and its tooltip is one paragraph; "Show more" re-measures when the wording changes. - Text Collection: clicks, keys, right-clicks and Escape inside the details dialog no longer reach the verse row. - Model texts stored as project references get their notice too. - The Power/Simple editor asks every project, since a "Notification:" copyright shows its banner on any text, as in Paratext 9. Pickers - ResourcePickerDialog disabled rows: reachable like other rows, name plus reason as description, lock icon, no hover highlight, no selection by click, Enter or Space; shared row cells extracted. - ProjectSelector disabled rows keep pointer events so their reason tooltip opens, and carry the reason as their description. - The picker tooltip is a core string (%resourcePicker_restrictedModelText_tooltip%). Also: notice strings sorted in every locale; wiring tests for the web views, Team layout, Manage Books and the restriction list; stories for the grid icon, grid cells and the model text panel; the Storybook stub no longer crashes the grid stories; rebuilt platform-bible-react/-utils dist; ADR adr-biblica-license-notice-computed-setting updated to the final design. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Correct the CopyrightNotice and copyrightNotice setting TSDoc: restrictedLicense applies only to resources, notification to any project whose copyright starts with "Notification:" - Drop the ellipsis from "More info" in all locales; it opens an informational dialog - Give the ProjectSelector disabled reason the tooltip's own foreground so it meets contrast on the inverted tooltip background - Rename the disabled-reason key to %restrictedModelOrBaseText_disabledReason%, since Manage Books uses it too - Hide the bound-but-closed Open button on disabled ProjectSelector rows - Make BiblicaLicensing.IsOnRestrictedList internal - Share one helper for the notice's message format between the banner and the message utils - Move BIBLICA_PERMISSIONS_URL to the const file; name utils files .utils - Note that the details wording is Biblica's own and not to be reworded - Add a story for the Notification details dialog - Make the model-text restrictions cache free of `this`, and extract the resync decision and bounded wait-then-stamp from platform-get-resources' main.ts into tested utils - Use a sample reason in the ResourcePickerDialog disabled-rows story and logical-direction classes in its row cells Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The resource tests read the notice through the project data provider, which refuses to open a resource without a valid Paratext registration. CI machines have none, so all eight failed there while passing on registered developer machines. Ask CopyrightNotice.FromScrText directly for the resource cases; the editable-project tests still cover the provider routing the setting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CopyrightNotice.fullName already falls back to the short name on the C# side, as its type documents, so the dialog's `fullName || name` repeated that guarantee and tripped the project-name adoption sweep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased onto main after PT-4585 (#2849) moved the zoom markers inside the editor scroll boxes and reworked the resource cell's right-click menu: - Portalled right-click test and copyright stories use the new cell props (required zoomArea, menuStrings fixture, Copy-only menu) - Grid test's verse-text ids no longer match the /^cell-/ cell count - Rebuilt platform-bible-react and platform-bible-utils dist Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
katherinejensen00
force-pushed
the
pt-4731-biblica-texts-special-message
branch
from
September 29, 2026 19:01
de1fb36 to
5d0046e
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Code Review Summary
Branch: pt-4731-biblica-texts-special-message
Base: origin/main
Date: 2026-09-24
Review model: Claude Opus 5.5
Files changed: 98. About 1,800 lines are production code; the rest is tests, stories, translations, test fixtures and generated files.
Summary
What users see. Biblica licenses some texts (NIV, NVI and others) as "reference text" resources only: they may not be translated or used as the basis for a new translation. When one of these resources is open, Simple and Power mode now show a dismissible banner with Biblica's wording.
Second feature (the ticket's nice-to-have). These texts are greyed out, with a reason, in the pickers. They can't be chosen as a model text (resource picker, Team Layout) or as the base of a new book (Manage Books "Create based on"). An existing selection is kept, and its banner shows.
How it works. One C# check,
BiblicaLicensing.IsRestricted, decides what is restricted. It applies to resources only: the DBL id must be on Matt T's list of 56 texts, or the copyright must say "Biblica, Inc." without "Biblica Open". That check reaches the UI by two paths:platformScripture.copyrightNotice.listModelTextRestrictions, which platform-get-resources stamps onto rows asisRestrictedAsModelText, andProjectSummary.IsRestrictedAsBasefor Manage Books.Suggested reading order
c-sharp/Projects/DigitalBibleLibrary/BiblicaLicensing.csIsRestricted: the id list, the copyright rule and the Open-text exemptions. Tests:BiblicaLicensingTests.cs, backed by a survey of 1,819 DBL texts inTestData/.c-sharp/Projects/CopyrightNotice.cs,ParatextProjectDataProvider.csnone/notification/restrictedLicensevalue, which is read-only. The TS type isCopyrightNoticeinplatform-scripture.d.ts.extensions/src/platform-scripture-editor/src/copyright-notice/project-copyright-notice.component.tsxreads the setting and handles dismissal. It renderscopyright-notice-banner,copyright-details-dialogand, in narrow cells,copyright-notice-indicator.platform-scripture-editor.web-view.tsx,model-text-panel.*,resource-text-panel.*,scripture-text-grid/resource-cell*chapter-context-escape.utils.ts).ModelTextRestrictions.cs→platform-get-resources/src/model-text-restrictions.utils.ts→src/renderer/components/dialogs/restricted-model-text.utils.ts→resource-picker.dialog.tsx,team-layout.*ResourcePickerDialog's newgetDisabledReason.c-sharp/ManageBooks/ProjectSummary.cs→manage-books-dialog.component.tsx→ProjectSelectorIsRestrictedAsBasebecomes adisabledReason.ProjectSelectordisabled rows can now show their tooltip.Safe to skim:
lib/*/dist/,lib/papi-dts/papi.d.ts.localizedStrings.json.TestData/*.jsonfiles.adr-biblica-license-notice-computed-setting.Decisions worth a second look
How to try it
Bundled Extensions/platform-scripture-editor/CopyrightNoticeBannerhas 7 stories, including the dialog, a right-to-left name and a "Notification:" text.Full review notes: API changes, findings, interview and quality checks
API Changes
lib/platform-bible-utils(resources.model.ts):DblResourceDatagains an optionalisRestrictedAsModelText?: booleanfield.lib/platform-bible-react(experimentalResourcePickerDialog):ResourcePickerDialogPropsgains an optionalgetDisabledReason?: (resource: DblResourceData) => string | undefined. When it returns a reason for a row in the "Installed" or "Available to Download" section, that row is dimmed, shows a lock icon and a tooltip, and cannot be picked.lib/platform-bible-react(experimentalProjectSelector): no signature change. Behavior changes:tw:data-[disabled=true]:pointer-events-auto), so theirdisabledReasontooltip can open.disabledReasonis exposed to screen readers througharia-describedby.ProjectSelectorProject.disabledReasonwas updated to match.isBoundButClosedJSDoc says so.papi.d.ts(renderer/components/dialogs/dialog-definition.model, reached through the dialog types):ResourcePickerDialogOptionsgains an optionaldisableRestrictedModelTexts?: boolean. It matches the source insrc/renderer/components/dialogs/dialog-definition.model.tsand looks regenerated, not hand-edited.extensions/src/platform-scripture/src/types/platform-scripture.d.ts:CopyrightNotice, a union overkind:none,notificationandrestrictedLicense.CopyrightNoticeis added to thepapi-shared-typesimport.'platformScripture.copyrightNotice': CopyrightNoticeinProjectSettingTypes. It is computed and read-only; C# throwsInvalidOperationExceptionon a write.extensions/src/platform-get-resources/src/types/platform-get-resources.d.ts:ModelTextRestrictions({ dblIds: string[]; projectIds: string[] }).listModelTextRestrictions(): Promise<ModelTextRestrictions>onIDblResourcesProvider.getCachedResourcesandgetLocalNonDblResources: docs now say each row carriesisRestrictedAsModelText, and that a read can wait up to 2 seconds for the first restrictions fetch.%restrictedModelOrBaseText_disabledReason%(en, es).Findings
Critical — Must address before merge
None.
Important — Should address before merge
CopyrightNoticeandplatformScripture.copyrightNoticeTSDoc said a non-resource project always getsnone, but a "Notification:" copyright shows on any project, as in Paratext 9. (fixed during review: both docs now sayrestrictedLicenseapplies only to resources,notificationto any project whose copyright starts with "Notification:", and otherwisenone.)The picker tooltip, "This text is disabled from being selected because of licensing terms which prohibit its use as a model or base for a new translation.", is one 25-word sentence, longer than the Tooltips guideline allows.(Author kept it: this is Ian's wording from the ticket.)ProjectSelectordisabled-reason line usedtw:text-muted-foregroundon the tooltip's invertedbg-foreground: about 4.0:1 contrast in light theme and 2.5:1 in dark, below AA. This branch is the first to show text in that line. (fixed during review: droppedtw:text-muted-foregroundso the reason inherits the tooltip's own foreground; italics kept;pbrrebuilt.)Author response: the author fixed three of the four during the interview and kept Ian's tooltip wording on purpose.
Minor — Consider
BiblicaLicensing.IsOnRestrictedListwaspublic, and its doc described picker callers that don't exist. (fixed during review: madeinternaland reworded the doc; the tests reach it throughInternalsVisibleTo.)messageFormatOfduplicated the choice of string key per notice kind informatCopyrightNoticeMessage. (fixed during review: one exportedgetCopyrightNoticeMessageFormathelper is used by both. A deliberate break of the re-measure dependency makes its test fail.)%resourcePicker_restrictedModelText_tooltip%was also used in Manage Books, which is not a resource picker, and it is a screen-reader description as well as a tooltip. (fixed during review: renamed to%restrictedModelOrBaseText_disabledReason%in en and es and at every call site. The constant was renamed to match. A repo-wide grep for the old key is empty.)M3 (other part): the flag has three names,(Author kept them: each names the role in its own context, a resource row "as a model text" and a project "as a base". Unifying them would mean renaming across C# and TypeScript for little gain.)isRestrictedAsModelText,isRestrictedAsBaseanddisableRestrictedModelTexts.ResourcePickerDialogWithDisabledRowsstory disabled ESV and NLT, which aren't Biblica texts, with a hardcoded copy of the Biblica reason. (fixed during review: it now uses the sample reason "Not available for this translation", documented as consumer-supplied.)BIBLICA_PERMISSIONS_URLlived in the message utils rather than the folder's const file, and the folder mixed.utiland.utilsfile names. (fixed during review: moved the URL tocopyright-notice.const.ts, and renamedopen-in-browser.util.tstoopen-in-browser.utils.tswithgit mv.)ProjectRowView,hasDisabledReasonrepeated a term ofhasExtraTooltipContent. (fixed during review:hasDisabledReasonis declared first and reused.)createModelTextRestrictionsCacheusedthis, so destructuringsyncorgetWithinwould break. (fixed during review: they are now closure-local functions. A new test destructures and calls them; it failed before the change.)M8: Enhanced Resources already has its own copyright ribbon and dialog, so this is a second, parallel copyright UI.(Author: for information only. Consolidating would mean moving both intoplatform-bible-react, which is out of scope; it's a follow-up if a third surface appears.)M9: The pickers treat restricted texts differently. The resource picker shows a lock icon, the row is reachable by keyboard and the tooltip opens on focus. Manage Books' "Based on"(Author: fixing it means changing how the sharedProjectSelectorrow has no icon and a hover-only tooltip, and cmdk skips disabled items with the keyboard.ProjectSelectorhandles disabled rows for every consumer. Follow-up.)M10: The narrow-cell indicator's tooltip shows the full banner, about 50 words.(Author kept it: in a narrow Text Collection cell the tooltip is the only place the banner wording appears. The dialog shows Biblica's terms, a different text, so shortening it would drop part of the required notice.)M11: Once a pane's banner is dismissed, the only way back to it is to switch texts.(Author: deliberate Paratext 9 parity. Switching to another text and back shows the banner again. Adding a "see it again" control would invent a requirement.)ResourceRowCellsandDisabledResourceRowused physical-direction classes. (fixed during review: switched tope-*,ps-*andtext-end.)NotificationDetailsOpenstory.)main.tswiring was untested, both the "resync when a flag changed" decision and the 2-second wait-then-stamp. (fixed during review: extracted intosyncModelTextRestrictionsAfterFlagSync,applyModelTextRestrictionsWithinandapplyModelTextRestrictionsToCatalogWithininmodel-text-restrictions.utils.ts, with 7 new tests, each of which fails when its code is deliberately broken.main.tsnow just calls them.)M17:(Author kept it: the wait only happens until the first fetch lands, a local C# call that normally takes milliseconds, and 2 seconds is the ceiling. Without it, a picker opened early could offer a restricted text; making it opt-in would add API for a startup-only edge case.)getCachedResourcesandgetLocalNonDblResourcescan wait up to 2 seconds for the first restrictions fetch, even for callers that don't read the flag.ProjectSelectorrows now take pointer events, so a disabled, bound-but-closed row's "Open" button would become clickable. (fixed during review: the Open button is not rendered on a disabled row. A new test failed before the fix.)Author response: the author asked for the reviewer's recommendation on each item, accepted fixing M1–M7, M12–M16 and M18, including the key rename in M3, and chose to skip M8–M11 and M17 for the reasons given.
Template Propagation
Shared Regions Modified
None.
Extension Config Changes
extensions/src/platform-scripture/contributions/localizedStrings.json: extension-specific, no propagation neededextensions/src/platform-scripture/contributions/projectSettings.json: extension-specific, no propagation neededPositive Observations
PB_IS_PUBLISHEDexactly: a get branch, a rejected set, aProjectSettingsNamesconstant and a hiddenprojectSettings.jsoncontribution. The C# wire shape is pinned byCopyrightNotice_SerializesToTheShapeTheFrontEndReads.CopyrightNoticetells consumers to treat an unknownkindasnone, so the union can grow safely.ResizeObservercatches up when the tab is shown, as.claude/rules/cross-view-sync-hidden-views.mdrequires. A test pins it.<bdi>, and the permissions URL is forced left-to-right.dir="auto".SyncBlockedBannerand sits outside the scrolling area. It clamps to two lines, offering Show more only when the text overflows. Narrow Text Collection cells get an indicator instead.copyright-notice-strings.test.tschecks that each locale has every key with the same placeholders.ListModelTextRestrictions;IsRestrictedAsBase.resolveModelTextProjectIdis now shared by the model-text panel and its web view, andResourceRowCellsavoids duplicating the picker row markup.adr-biblica-license-notice-computed-setting, is in byte-order slug position and records the rejected alternatives.Interview Notes
Purpose (author): "Show a banner on traditionally published Biblica texts explaining the copyright information."
Design explanation (Step 3.3): The author explained that Matt T provided the list of resources that must show the Biblica notice, and that the list was backed up programmatically by checking each resource's copyright; a text on the list gets the banner. The assistant filled in the code-level detail and the author accepted it:
The copyright rule matched exactly the 55 listed texts among the 1,819 surveyed.
Scope decision, Paratext 9 parity: The author first expected the Biblica notice to show on editable projects too. After discussing it, they agreed to keep Paratext 9's behaviour:
The TSDoc was corrected to say exactly this.
Deliberate choices for the reviewer:
ProjectSummary.IsRestrictedAsBase.%restrictedModelOrBaseText_disabledReason%exists in en and es only, like the otherresourcePicker_*keys.platform.openWindow. The web views'allowPopupswas deliberately not widened.Unresolved items: none. The author could explain every finding.
In-Review Quality Check
Every check passes, and none of them needed a fix.
npm run typecheck: pass.npm run linttakes over 40 minutes locally, so it was scoped to the changed files.--check: clean on all changed files.npm test: pass.web-view.component.test.tsx,comment-list.storiesandcomment-thread.stories.dotnet test c-sharp-tests/: 2,401 passed, 0 failed.Rebased onto main (
bbd52be5ac3, 16 new commits). Nine files conflicted, and main's changes were kept in each:ProjectSelector's indicator tooltips.fullName.Two of main's tests needed updating for this branch: one
ProjectSelectortest's query, and a source-contract test that now pins the banner between the resource selector and the zoom area.After the rebase:
Suggested Review Focus
BiblicaLicensing.IsRestrictedLicense:The author explained the list at a product level; walk through the fallback rule together.
Paratext 9 parity scope. Is showing "Notification:" banners on editable projects, and the Biblica notice on resources only, the product decision we want?
Second feature: disabling restricted texts in the model and base pickers. Review its public API (
getDisabledReason,disableRestrictedModelTexts,listModelTextRestrictions,isRestrictedAsModelText), and confirm that UI-only enforcement is acceptable.ProjectSelectordisabled rows now take pointer events. This is a shared component, so check other consumers.The up-to-2-second first wait in
getCachedResourcesandgetLocalNonDblResources(M17).Follow-ups to file. The Manage Books keyboard reachability for disabled rows (M9), and a shared copyright UI in
platform-bible-react(M8).AI-assisted — Claude Code (Claude Opus 5.5)
🤖 Generated with Claude Code
This change is