Repository navigation
feat: Document artifact + rich text editor - #603
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (14)
📝 WalkthroughWalkthroughThis PR introduces document artifact support to SQLRooms by creating a new ChangesDocuments Package
CLI UI Integration
CRDT & Development
🎯 4 (Complex) | ⏱️ ~45 minutes Possibly Related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
packages/documents/src/MarkdownDocument.tsx (2)
24-29: 💤 Low valueInline arrow function creates new reference on each render.
The
onChangeprop receives a new arrow function(markdown) => setMarkdown(artifactId, markdown)on every render. While this typically doesn't cause issues with Tiptap's internal memoization, you could wrap it inuseCallbackfor consistency.♻️ Optional: Memoize onChange callback
+ const handleChange = React.useCallback( + (markdown: string) => setMarkdown(artifactId, markdown), + [artifactId, setMarkdown], + ); + return ( <MarkdownDocumentEditor value={document?.markdown ?? ''} - onChange={(markdown) => setMarkdown(artifactId, markdown)} + onChange={handleChange} /> );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/documents/src/MarkdownDocument.tsx` around lines 24 - 29, The inline arrow passed to MarkdownDocumentEditor’s onChange prop creates a new function each render; wrap the handler in React.useCallback (e.g., create a memoized handleChange that calls setMarkdown(artifactId, markdown)) and pass that callback to onChange to stabilize the prop reference; ensure artifactId and setMarkdown are included in the dependency array so the callback updates correctly.
8-16: 💤 Low valueConsider combining selectors or using shallow comparison.
Three separate
useStoreWithDocumentscalls will cause this component to re-render whenever any of these three values change. While the functions (ensureDocument,setMarkdown) are likely stable references, combining related selectors can improve clarity and potentially performance.♻️ Consider consolidating selectors
- const document = useStoreWithDocuments( - (state) => state.documents.config.artifacts[artifactId], - ); - const ensureDocument = useStoreWithDocuments( - (state) => state.documents.ensureDocument, - ); - const setMarkdown = useStoreWithDocuments( - (state) => state.documents.setMarkdown, - ); + const {document, ensureDocument, setMarkdown} = useStoreWithDocuments( + (state) => ({ + document: state.documents.config.artifacts[artifactId], + ensureDocument: state.documents.ensureDocument, + setMarkdown: state.documents.setMarkdown, + }), + );However, note that this creates a new object on each selector call, which will cause re-renders unless you use a shallow equality check. If the individual selectors are more stable, the current pattern may be preferable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/documents/src/MarkdownDocument.tsx` around lines 8 - 16, The component currently calls useStoreWithDocuments three times for document, ensureDocument, and setMarkdown causing extra re-renders; replace these with a single useStoreWithDocuments selector that returns an object like { document: state.documents.config.artifacts[artifactId], ensureDocument: state.documents.ensureDocument, setMarkdown: state.documents.setMarkdown } and pass a shallow equality comparator (e.g., zustand's shallow) as the second argument to prevent re-renders from object identity changes; update references to use the new object fields and keep original symbol names (document, ensureDocument, setMarkdown) to minimize other changes.packages/documents/src/MarkdownDocumentEditor.tsx (1)
274-285: 🏗️ Heavy liftConsider a non-blocking link prompt UI.
Line 278 uses
window.prompt(), which blocks the UI thread and can be jarring. For a better user experience, consider implementing a non-blocking dialog or inline input field for link insertion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/documents/src/MarkdownDocumentEditor.tsx` around lines 274 - 285, The current command's run handler in MarkdownDocumentEditor.tsx uses window.prompt (blocking) to get the link URL; replace it with a non-blocking UI flow: create a small LinkInputDialog/InlineLinkInput component that opens via state (or returns a Promise) when the run function is invoked, pre-fill it using editor?.getAttributes('link').href, and then on confirm call editor?.chain().focus().setLink({href}).run() or editor?.chain().focus().unsetLink().run() on empty/cancel; update the run implementation to toggle the dialog state (or await the component's promise) instead of calling window.prompt so the UI remains responsive.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/documents/__tests__/documentsCrdt.test.ts`:
- Line 11: The test imports LoroDoc from "loro-crdt" but the `@sqlrooms/documents`
package manifest is missing that dependency; add "loro-crdt" to the
`@sqlrooms/documents` package.json dependencies (or devDependencies if it's only
used in tests) with an appropriate version, then run the package manager install
so knip/CI recognizes the dependency and the import in documentsCrdt.test.ts
succeeds.
In `@packages/documents/src/crdt.ts`:
- Around line 132-134: The filter that builds nonDocumentOrder currently treats
unknown IDs as non-documents because artifactsById[id]?.type !== 'document'
returns true for undefined; change the predicate to explicitly require the
artifact exists and is not a document—e.g. use artifactsById[id] != null &&
artifactsById[id].type !== 'document' (or
Object.prototype.hasOwnProperty.call(artifactsById, id) &&
artifactsById[id].type !== 'document') in the computation of nonDocumentOrder so
deleted/unknown IDs are excluded.
- Around line 125-139: incomingArtifactOrder can contain duplicates which leads
to duplicate IDs in artifactOrder; modify the creation of incomingDocumentOrder
to both filter for IDs present in documentArtifacts and remove duplicates while
preserving original order (e.g., use a seen Set to skip repeated IDs), then
rebuild knownDocumentOrder from that deduplicated incomingDocumentOrder before
computing missingDocumentOrder and artifactOrder so the final artifactOrder
contains each document ID only once.
In `@packages/documents/src/DocumentsSliceConfig.ts`:
- Around line 10-12: The DocumentsSliceConfig schema currently allows artifact
map keys to differ from DocumentArtifact.id; update the schema definition for
artifacts (DocumentsSliceConfig) to add a schema-level refinement that iterates
each record entry and fails validation if any record key !== artifact.id (use
z.record(...).superRefine or a top-level DocumentsSliceConfig.superRefine to
check artifacts). Ensure the error identifies which key/id mismatch occurred and
keep the value schema as DocumentArtifact so downstream code relying on
artifacts[artifactId] === {id: artifactId, ...} is guaranteed.
In `@python/sqlrooms-cli/scripts/dev.mjs`:
- Around line 11-13: The default DB path is hardcoded as '/tmp/sqlrooms-cli.db'
which is Unix-only; replace that literal (the '/tmp/sqlrooms-cli.db' entry in
the args array in dev.mjs) with a platform-neutral temp path built from Node's
os.tmpdir() and path.join (import os and path at top of the module and use
path.join(os.tmpdir(), 'sqlrooms-cli.db')) so Windows and Unix devs get a valid
temp file location.
---
Nitpick comments:
In `@packages/documents/src/MarkdownDocument.tsx`:
- Around line 24-29: The inline arrow passed to MarkdownDocumentEditor’s
onChange prop creates a new function each render; wrap the handler in
React.useCallback (e.g., create a memoized handleChange that calls
setMarkdown(artifactId, markdown)) and pass that callback to onChange to
stabilize the prop reference; ensure artifactId and setMarkdown are included in
the dependency array so the callback updates correctly.
- Around line 8-16: The component currently calls useStoreWithDocuments three
times for document, ensureDocument, and setMarkdown causing extra re-renders;
replace these with a single useStoreWithDocuments selector that returns an
object like { document: state.documents.config.artifacts[artifactId],
ensureDocument: state.documents.ensureDocument, setMarkdown:
state.documents.setMarkdown } and pass a shallow equality comparator (e.g.,
zustand's shallow) as the second argument to prevent re-renders from object
identity changes; update references to use the new object fields and keep
original symbol names (document, ensureDocument, setMarkdown) to minimize other
changes.
In `@packages/documents/src/MarkdownDocumentEditor.tsx`:
- Around line 274-285: The current command's run handler in
MarkdownDocumentEditor.tsx uses window.prompt (blocking) to get the link URL;
replace it with a non-blocking UI flow: create a small
LinkInputDialog/InlineLinkInput component that opens via state (or returns a
Promise) when the run function is invoked, pre-fill it using
editor?.getAttributes('link').href, and then on confirm call
editor?.chain().focus().setLink({href}).run() or
editor?.chain().focus().unsetLink().run() on empty/cancel; update the run
implementation to toggle the dialog state (or await the component's promise)
instead of calling window.prompt so the UI remains responsive.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 16d65985-3e05-475d-96f0-b45647f9cc33
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (34)
apps/sqlrooms-cli-ui/package.jsonapps/sqlrooms-cli-ui/src/artifactTypes.tsxapps/sqlrooms-cli-ui/src/createDashboardCommands.tsapps/sqlrooms-cli-ui/src/runtimeConfig.tsapps/sqlrooms-cli-ui/src/store-types.tsapps/sqlrooms-cli-ui/src/store.tsapps/sqlrooms-cli-ui/src/workspace/DocumentArtifact.tsxapps/sqlrooms-cli-ui/vite.config.tspackages/codemirror/src/index.tspackages/crdt/src/createCrdtSlice.tspackages/crdt/src/sync/webSocketSyncConnector.tspackages/documents/README.mdpackages/documents/__tests__/DocumentsSlice.test.tspackages/documents/__tests__/documentCommands.test.tspackages/documents/__tests__/documentsCrdt.test.tspackages/documents/__tests__/knowledgeIndex.test.tspackages/documents/eslint.config.jspackages/documents/jest.config.jspackages/documents/package.jsonpackages/documents/src/DocumentsSlice.tspackages/documents/src/DocumentsSliceConfig.tspackages/documents/src/MarkdownDocument.tsxpackages/documents/src/MarkdownDocumentEditor.tsxpackages/documents/src/crdt.tspackages/documents/src/documentCommands.tspackages/documents/src/index.tspackages/documents/src/knowledgeIndex.tspackages/documents/src/useStoreWithDocuments.tspackages/documents/tsconfig.jsonpackages/documents/typedoc.jspython/sqlrooms-cli/package.jsonpython/sqlrooms-cli/scripts/dev.mjspython/sqlrooms-cli/sqlrooms/web/launcher.pyscripts/dev.mjs
| '--db-path', | ||
| '/tmp/sqlrooms-cli.db', | ||
| ]; |
There was a problem hiding this comment.
Use a platform-neutral default DB path.
Line 12 hardcodes /tmp/sqlrooms-cli.db, which is Unix-specific and can fail on Windows dev machines.
💡 Suggested fix
import {spawnSync} from 'node:child_process';
+import os from 'node:os';
+import path from 'node:path';
const defaultArgs = [
'run',
'sqlrooms',
@@
'--no-open-browser',
'--db-path',
- '/tmp/sqlrooms-cli.db',
+ path.join(os.tmpdir(), 'sqlrooms-cli.db'),
];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| '--db-path', | |
| '/tmp/sqlrooms-cli.db', | |
| ]; | |
| import {spawnSync} from 'node:child_process'; | |
| import os from 'node:os'; | |
| import path from 'node:path'; | |
| const defaultArgs = [ | |
| 'run', | |
| 'sqlrooms', | |
| '--no-open-browser', | |
| '--db-path', | |
| path.join(os.tmpdir(), 'sqlrooms-cli.db'), | |
| ]; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@python/sqlrooms-cli/scripts/dev.mjs` around lines 11 - 13, The default DB
path is hardcoded as '/tmp/sqlrooms-cli.db' which is Unix-only; replace that
literal (the '/tmp/sqlrooms-cli.db' entry in the args array in dev.mjs) with a
platform-neutral temp path built from Node's os.tmpdir() and path.join (import
os and path at top of the module and use path.join(os.tmpdir(),
'sqlrooms-cli.db')) so Windows and Unix devs get a valid temp file location.
Summary by CodeRabbit