Remix stack glossary/fix - #874
Conversation
There was a problem hiding this comment.
Pull request overview
This PR applies a set of server + client fixes around Remixer, Glossary import, and License Restacker behavior/UI, including new ordering/metadata-copy behavior in the Remixer job and expanded license compatibility/version handling.
Changes:
- Add Remixer improvements: page ordering via CXOne order API (including “Back Matter last”), copy thumbnail/overview on import, and allow larger Remixer save/publish payloads via streamed JSON parsing.
- Extend Glossary tooling: support importing terms from an auxiliary glossary page and broaden glossary lookups to match on ancestor cover IDs.
- Update License Restacker logic/UI: refine compatibility matrix, add per-license version options, improve conflict presentation, and add bulk “Fix All” preview/apply flow.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| server/util/Restackerutil.ts | Adds retry wrapper around license/content-license retrieval during restacker processing. |
| server/util/librariesclient.ts | Adds a reference comment for the MindTouch/CXOne page order API URL. |
| server/util/CXOne/CXOnePageAPIEndpoints.ts | Adds a new ORDER_PAGES endpoint helper for the CXOne order API. |
| server/middleware.ts | Introduces streamJsonBody to parse JSON request bodies without using Express’s global json parser. |
| server/api/validators/book.ts | Extends glossary import validator with optional auxiliary glossary page IDs. |
| server/api/services/remixer-service.ts | Adds back-matter detection + ordering, orders newly created/imported pages, and copies thumbnail/overview during import. |
| server/api/services/glossary-service.ts | Refactors glossary extraction, adds auxiliary glossary import flow, and broadens glossary matching via ancestor cover IDs. |
| server/api/restacker.ts | Updates license-compatibility/conflict logic and warning messaging, including book-wide checks. |
| server/api/books.ts | Updates glossary import route handling to support auxiliary glossary imports and return extracted term data. |
| server/api.js | Switches Remixer save/publish routes to middleware.streamJsonBody and removes debug logging middleware. |
| client/src/screens/commons/Glossary/TOCTreeView.tsx | Adds persisted expand state + per-node “import glossary” action in the TOC tree. |
| client/src/screens/commons/Glossary/index.tsx | Adds breadcrumb for project glossary view and wires auxiliary glossary import params to the mutation. |
| client/src/Conductor.jsx | Changes the Remixer route to /projects/:id/remixer. |
| client/src/components/util/LicenseOptions.js | Adds per-license version option lists and exports a helper to retrieve them. |
| client/src/components/remixer/services.ts | Adjusts formatted-path override behavior to allow empty overrides and align display logic. |
| client/src/components/remixer/RemixerDashboard.tsx | Adds breadcrumb and prevents “save with no changes” from marking nodes modified. |
| client/src/components/remixer/model.ts | Updates copy mode titles (UI text adjustments). |
| client/src/components/remixer/EditPanel.tsx | Improves focus behavior and keyboard navigation within the edit modal. |
| client/src/components/remixer/ControlPanel.tsx | Improves layout/labels/tooltips and popup positioning for save/publish actions. |
| client/src/components/remixer/CatalogBook/CatalogList.tsx | Adds a single-select checkbox column using the table’s selection column helper. |
| client/src/components/remixer/BookContent/TreeNodeContainer.tsx | Adjusts link rendering/styling and keeps status icons outside the title span. |
| client/src/components/remixer/BookContent/Dashboard.tsx | Reuses computed displayTitle and adjusts link/title rendering similarly to TreeNodeContainer. |
| client/src/components/projects/Restacker/util.ts | Updates compatibility logic to incorporate versions and expands proposed-license compliance to support book-wide checks. |
| client/src/components/projects/Restacker/LicenseWarningModal.tsx | Improves conflict display for book-wide conflicts and adds scrollable list styling. |
| client/src/components/projects/Restacker/LicenseEditor.tsx | Uses per-license version options instead of a global version list; tightens UI styling. |
| client/src/components/projects/Restacker/LicenseBadge.tsx | Improves badge sizing/layout for consistent rendering. |
| client/src/components/projects/Restacker/index.tsx | Adds “Next Conflict” navigation and “Fix All” preview/apply flow; locks structural/source-mismatch cases and adds quick-apply. |
| client/src/components/projects/Restacker/FixAllPreviewModal.tsx | New modal to preview bulk “Fix All” license changes before applying. |
| client/src/components/projects/Restacker/ComplianceDetails.tsx | Aligns compliance UI with the renamed license pair structure. |
| client/src/components/projects/ProjectLinkButtons.tsx | Updates the Remixer project link to the new /projects/:id/remixer route. |
| client/src/api.ts | Adds a fetch-based JSON sender for remixer save/publish and extends glossary import payload shape. |
Comments suppressed due to low confidence (1)
client/src/screens/commons/Glossary/TOCTreeView.tsx:122
IconDownloadis clickable but markedaria-hiddenand has no keyboard interaction. This hides the import action from assistive tech and prevents keyboard users from triggering it.
className={`opacity-0 group-hover/node:opacity-100 transition-opacity shrink-0 text-info-500 ${
importingGlossary ? "pointer-events-none opacity-40" : ""
}`}
aria-hidden
onClick={(e: React.MouseEvent) => {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * Reads the incoming request body as a Node.js readable stream — no size | ||
| * ceiling — then parses it as JSON and assigns the result to `req.body`. | ||
| * | ||
| * Use this instead of the global `bodyParser.json()` on routes that must | ||
| * accept arbitrarily large JSON payloads (e.g. remixer book-state save and | ||
| * publish). The calling route must be excluded from the global body-parser | ||
| * middleware so the stream is not consumed before this runs. | ||
| */ | ||
| const STREAM_JSON_MAX_BYTES = 5 * 1024 * 1024; // 10 MB | ||
|
|
| * Moves Back Matter to the end of its sibling list via CXOne's page order API. | ||
| * | ||
| * PUT /pages/{lastSiblingId}/order?afterid={backMatterId} | ||
| * — path is the last page on the same level; afterid is the Back Matter page. | ||
| * @returns true when an order request was issued. |
| const isTransientError = (error: unknown): boolean => | ||
| error instanceof Error && error.message.includes("Transient error"); | ||
|
|
| <IconExternalLink | ||
| size={20} | ||
| className="opacity-0 group-hover/node:opacity-100 transition-opacity shrink-0 text-info-500" | ||
| aria-hidden | ||
| onClick={(e: React.MouseEvent) => { | ||
| e.stopPropagation(); | ||
| window.open(item.url, "_blank"); | ||
| }} | ||
| /> |
| /** | ||
| * Streams a JSON payload to the server using a `ReadableStream` fetch body. | ||
| * This bypasses Express's `bodyParser.json()` size ceiling — the server reads | ||
| * the body from the raw stream with no limit. Auth is handled by the session | ||
| * cookie (`credentials: "include"` mirrors `axios.defaults.withCredentials`). | ||
| * | ||
| * Returns the parsed JSON response, or throws with a shape compatible with | ||
| * the Axios error format so callers can handle it uniformly. | ||
| */ |
| const ccKeyOrigin = toCcLicenseKey(keyOrigin); | ||
| if (!ccKeyAdption || !ccKeyOrigin) return null; | ||
|
|
||
| return CC_COMPATIBILITY_MATRIX[ccKeyA][ccKeyB]; | ||
| return CC_COMPATIBILITY_MATRIX[ccKeyAdption][ccKeyOrigin]; | ||
| } |
jakeaturner
left a comment
There was a problem hiding this comment.
Sorry I didn't realize I was pushing to your branch!
| res.status(400).json({ err: true, errMsg: "Invalid or malformed JSON body" }); | ||
| } | ||
| }); | ||
| req.on("error", () => { |
There was a problem hiding this comment.
Need to add a check against trying to send a response if headers have already flushed --ERR_HTTP_HEADERS_SENT will get thrown and there's nothing outside that will catch it, causing a server crash.
Recommend something like this:
let finished = false;
const fail = (status: number, errMsg: string) => {
if (finished) return;
finished = true;
req.pause();
res.status(status).json({ err: true, errMsg });
};
Then call fail() in each catch block and req.on("error") instead of directly calling res.status(400).json....)
… and publish - Added a `streamJson` method to the API class to handle large JSON payloads without size limitations, bypassing Express's bodyParser.json() ceiling. - Updated the remixer project save and publish methods to utilize the new streaming functionality for improved performance. - Enhanced error handling to align with Axios error format for consistent response management. - Refactored routes in the server to support streaming JSON for remixer operations, ensuring efficient data handling. - Adjusted related components and routes to reflect updated API paths and improve user navigation.
- Implemented `isBackMatterNode` to identify Back Matter pages. - Created `orderBackMatterLast` function to reorder Back Matter to the end of its siblings using CXOne's page order API. - Updated `runRemixerJob` to ensure Back Matter is ordered last during job execution. - Enhanced CXOnePageAPIEndpoints with a new `ORDER_PAGES` endpoint for ordering pages.
- Added a class for larger text size to links and spans in the TreeDnd component. - Restored color styling for the link icon to maintain visual consistency. - Adjusted styles to improve readability and user interaction experience.
- Refactored license handling in the Restacker component to improve compliance checks and user interactions. - Introduced `areLicensesCompatible` utility for better license validation. - Updated LicenseEditor to dynamically fetch license version options, enhancing user experience. - Improved styling and layout of LicenseBadge for better visual consistency. - Removed deprecated license version options and streamlined related functions for clarity and efficiency.
- Introduced new utility functions for improved license validation and compliance checks. - Added functionality to automatically suggest license corrections for structural pages. - Updated LicenseEditor and LicenseBadge components for better user interaction and visual consistency. - Enhanced table column definitions for improved layout and responsiveness. - Refactored existing functions to streamline license handling and improve code clarity.
…upport - Updated API methods to include optional parameters for auxiliary glossary IDs and parent IDs. - Modified the GlossaryManager component to handle new glossary import functionality. - Enhanced TOCTreeView to support importing glossary terms with auxiliary references. - Refactored glossary service methods to accommodate new logic for handling auxiliary glossaries. - Improved validation schema to include new parameters for glossary usage.
- Refactored LicenseWarningModal to improve display of incompatible license pairs. - Updated utility functions to change license structure from `licenseA` and `licenseB` to `licenseAdption` and `licenseOrigin`. - Adjusted compatibility matrix to reflect accurate license relationships and compliance checks. - Enhanced license version handling in utility functions for better validation.
- Updated ComplianceDetails component to reflect new license structure with `licenseAdption` and `licenseOrigin`. - Enhanced LicenseWarningModal to conditionally display page titles based on the field type. - Improved utility functions for better license version handling and compliance checks. - Adjusted API compatibility logic to ensure accurate license relationship assessments.
…e handling - Added a new method `withRetryOnTransient` to handle transient errors during license retrieval with incremental backoff. - Updated license fetching logic in `runRestacker` to utilize the new retry mechanism, improving resilience against temporary failures.
…g page import - Implemented a new method `copyPageThumbnailAndOverview` to copy the thumbnail image and overview from a source page to a target page. - Enhanced error handling to log non-fatal errors during the copying process without aborting the import. - Updated the `handleImportedPage` function to include the new thumbnail and overview copying logic.
…bling - Added `orderPageAfterPreviousSibling` function to position newly created or imported pages correctly in relation to their siblings using the MindTouch page-order API. - Integrated the new ordering logic into the `runRemixerJob` function to ensure pages are ordered appropriately during job execution. - Enhanced error handling to log warnings for non-fatal errors during the ordering process, allowing the job to continue even if the ordering fails.
- Refactored logic in `resolveInheritedFormattedPathPrefix` and `getRemixerDisplayTitle` to streamline formatted path checks and ensure proper handling of empty strings. - Updated `buildBookPaths` to improve clarity in formatted path assignment and override checks. - Enhanced code readability by reducing redundant conditions and improving null handling for formatted paths.
…d UI - Changed popup position from "bottom center" to "bottom right" for better alignment. - Added offset and popper modifiers to prevent overflow and enhance visibility within the viewport. - Ensured consistent styling and behavior for both "Save Remixing Map draft" and "Save Book to Library" popups.
…te ID handling - Refactored `getGlossaryPage` and `getGlossaryDetails` methods to utilize a new helper function `getCandidateCoverIDs` for better handling of page IDs and their ancestors. - Updated database queries to use candidate IDs for more accurate glossary retrieval. - Enhanced error handling and code readability by simplifying conditional checks and improving variable naming conventions.
…e glossary management - Updated parameter names from `augGlossaryParentID` to `auxGlossaryParentID` across multiple files for consistency. - Adjusted API methods and components to ensure proper handling of auxiliary glossary IDs and parent IDs. - Enhanced validation schema to reflect the corrected parameter naming, improving clarity and reducing potential errors.
- Introduced a maximum size limit of 5 MB for JSON request bodies in the streamJsonBody middleware. - Added logic to destroy the request and return a 413 status with an error message if the limit is exceeded. - Enhanced data handling by tracking total bytes received during the streaming process.
b421c1a to
9fa3db7
Compare
|
🎉 This PR is included in version 2.140.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Multiple fixes based on Delamr's request.