feat: Add endpoint typeahead to API Console#3259
feat: Add endpoint typeahead to API Console#3259dblythy wants to merge 5 commits intoparse-community:alphafrom
Conversation
|
🚀 Thanks for opening this pull request! We appreciate your effort in improving the project. Please let us know once your pull request is ready for review. Note Please respond to review comments from AI agents just like you would to comments from a human reviewer. Let the reviewer resolve their own comments, unless they have reviewed and accepted your commit, or agreed with your explanation for why the feedback was incorrect. Caution Pull requests must be written using an AI agent with human supervision. Pull requests written entirely by a human will likely be rejected, because of lower code quality, higher review effort and the higher risk of introducing bugs. Please note that AI review comments on this pull request alone do not satisfy this requirement. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds endpoint typeahead to the API Console via an Autocomplete integration; changes Autocomplete Enter/click resolution and suggestion container width handling; adds paginated "Load more" logs with updated fetch semantics; refactors ParseApp.getLogs to accept an options object; updates .gitignore. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Autocomplete
participant RestConsole
participant ParseServer
User->>Autocomplete: Type endpoint input
Autocomplete->>RestConsole: buildEndpointSuggestions(input)
RestConsole-->>Autocomplete: suggestions (static + schema-derived)
Autocomplete->>User: Display suggestions
User->>Autocomplete: Select or press Enter
Autocomplete->>RestConsole: onSubmit(resolvedInput)
RestConsole->>ParseServer: Send API request to resolved endpoint
ParseServer-->>RestConsole: Return response
RestConsole->>User: Show response
sequenceDiagram
actor User
participant LogsUI as Logs Component
participant ParseApp
participant ParseServer
LogsUI->>ParseApp: fetchLogs(app, type) (initial)
ParseApp->>ParseServer: GET /logs?level=X&size=100
ParseServer-->>ParseApp: Returns logs[]
ParseApp->>LogsUI: Update logs state
User->>LogsUI: Click "Load more"
LogsUI->>ParseApp: fetchLogs(app, type, until=oldestTimestamp)
ParseApp->>ParseServer: GET /logs?level=X&until=T&size=100
ParseServer-->>ParseApp: Returns next logs[]
ParseApp->>LogsUI: Append logs to state
LogsUI->>User: Display extended logs list
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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 |
3454944 to
f243964
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/dashboard/Data/ApiConsole/RestConsole.react.js (1)
85-101: Consider deduplicating endpoint suggestions.If a schema class name overlaps with a static endpoint prefix (e.g., a custom class named
userswould generateclasses/users, whileusersis also a static endpoint), the suggestions list could contain near-duplicates that may confuse users.♻️ Optional: Deduplicate endpoints
buildEndpointSuggestions(input) { const dynamicEndpoints = this.state.classNames.flatMap(className => [ `classes/${className}`, `schemas/${className}`, `aggregate/${className}`, `purge/${className}`, ]); - const allEndpoints = [...PARSE_API_ENDPOINTS, ...dynamicEndpoints]; + const allEndpoints = [...new Set([...PARSE_API_ENDPOINTS, ...dynamicEndpoints])]; if (!input) { return allEndpoints; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/dashboard/Data/ApiConsole/RestConsole.react.js` around lines 85 - 101, The suggestions list can contain duplicate entries when dynamicEndpoints overlap with PARSE_API_ENDPOINTS; update buildEndpointSuggestions to deduplicate allEndpoints (after combining PARSE_API_ENDPOINTS and dynamicEndpoints) by using a Set (or similar) that preserves the first occurrence and compares entries in a case-insensitive manner if you want to avoid same-text differences, then continue to return either the full deduped list or the filtered deduped list from the existing filter logic; reference buildEndpointSuggestions, PARSE_API_ENDPOINTS, and this.state.classNames to locate where to perform the dedupe.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/dashboard/Data/Browser/EditRowDialog.react.js`:
- Around line 540-543: The JSX for the div in EditRowDialog.react.js is passing
an array to className (className={[styles.objectPickerContent]}); change it to a
string by using className={styles.objectPickerContent} so React receives a
proper CSS class string. Locate the div that renders {unlockBanner} and {fields}
and update the className there (reference: styles.objectPickerContent in the
EditRowDialog component).
---
Nitpick comments:
In `@src/dashboard/Data/ApiConsole/RestConsole.react.js`:
- Around line 85-101: The suggestions list can contain duplicate entries when
dynamicEndpoints overlap with PARSE_API_ENDPOINTS; update
buildEndpointSuggestions to deduplicate allEndpoints (after combining
PARSE_API_ENDPOINTS and dynamicEndpoints) by using a Set (or similar) that
preserves the first occurrence and compares entries in a case-insensitive manner
if you want to avoid same-text differences, then continue to return either the
full deduped list or the filtered deduped list from the existing filter logic;
reference buildEndpointSuggestions, PARSE_API_ENDPOINTS, and
this.state.classNames to locate where to perform the dedupe.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9ee37115-806b-4f29-a5d1-9c4eb30c78c7
📒 Files selected for processing (9)
src/components/Autocomplete/Autocomplete.react.jssrc/components/BrowserCell/BrowserCell.react.jssrc/components/BrowserCell/BrowserCell.scsssrc/components/BrowserRow/BrowserRow.react.jssrc/dashboard/Data/ApiConsole/RestConsole.react.jssrc/dashboard/Data/Browser/Browser.scsssrc/dashboard/Data/Browser/EditRowDialog.react.jssrc/lib/Constants.jssrc/lib/tests/BrowserCell.test.js
| <div className={[styles.objectPickerContent]}> | ||
| {unlockBanner} | ||
| {fields} | ||
| </div> |
There was a problem hiding this comment.
Fix JSX className to use string instead of array.
className={[styles.objectPickerContent]} creates an array, which React will coerce to a string with array notation. This should be a direct string reference.
🐛 Proposed fix
- <div className={[styles.objectPickerContent]}>
+ <div className={styles.objectPickerContent}>
{unlockBanner}
{fields}
</div>📝 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.
| <div className={[styles.objectPickerContent]}> | |
| {unlockBanner} | |
| {fields} | |
| </div> | |
| <div className={styles.objectPickerContent}> | |
| {unlockBanner} | |
| {fields} | |
| </div> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/dashboard/Data/Browser/EditRowDialog.react.js` around lines 540 - 543,
The JSX for the div in EditRowDialog.react.js is passing an array to className
(className={[styles.objectPickerContent]}); change it to a string by using
className={styles.objectPickerContent} so React receives a proper CSS class
string. Locate the div that renders {unlockBanner} and {fields} and update the
className there (reference: styles.objectPickerContent in the EditRowDialog
component).
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/dashboard/Data/ApiConsole/RestConsole.react.js (1)
74-83: Consider logging schema fetch failures for debugging.The silent
.catch(() => {})prevents UI breakage, which is good for resilience. However, completely swallowing errors can hide issues during development or when troubleshooting.♻️ Optional: Add console warning
componentDidMount() { this.context .apiRequest('GET', 'schemas', {}, { useMasterKey: true }) .then(({ results }) => { if (results) { this.setState({ classNames: results.map(s => s.className) }); } }) - .catch(() => {}); + .catch(err => { + console.warn('Failed to fetch schemas for endpoint suggestions:', err); + }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/dashboard/Data/ApiConsole/RestConsole.react.js` around lines 74 - 83, The catch block in componentDidMount that swallows errors from this.context.apiRequest('GET', 'schemas', ..., { useMasterKey: true }) should log failures so schema fetch issues are visible during debugging; update the .catch handler on that promise to log the error (e.g., console.warn or console.error) with context like "Failed to fetch schemas" and the error object while preserving the current resilience (do not rethrow), ensuring setState({ classNames: ... }) remains unchanged in the success path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/dashboard/Data/ApiConsole/RestConsole.react.js`:
- Around line 293-297: The onSubmit handler ignores the Autocomplete-provided
userInput and reads this.state.endpoint, causing Enter to submit a stale value
when selections are made via keyboard; update the onSubmit handler to accept the
userInput parameter and use it for the request (either setState({endpoint:
userInput}, () => this.makeRequest()) or invoke makeRequest(userInput) after
adjusting makeRequest to accept an endpoint), so the Autocomplete selection
passed to onSubmit is the value actually submitted; reference the onSubmit
callback, this.state.endpoint, makeRequest, and the Autocomplete component when
making the change.
---
Nitpick comments:
In `@src/dashboard/Data/ApiConsole/RestConsole.react.js`:
- Around line 74-83: The catch block in componentDidMount that swallows errors
from this.context.apiRequest('GET', 'schemas', ..., { useMasterKey: true })
should log failures so schema fetch issues are visible during debugging; update
the .catch handler on that promise to log the error (e.g., console.warn or
console.error) with context like "Failed to fetch schemas" and the error object
while preserving the current resilience (do not rethrow), ensuring setState({
classNames: ... }) remains unchanged in the success path.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ceeef171-def6-49cd-b719-4f5e797b9536
📒 Files selected for processing (2)
src/components/Autocomplete/Autocomplete.react.jssrc/dashboard/Data/ApiConsole/RestConsole.react.js
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/Autocomplete/Autocomplete.react.js`:
- Around line 252-259: The Enter key handler in Autocomplete.react.js uses const
resolvedInput = filteredSuggestions[activeSuggestion] || userInput and then
always calls this.props.onChange/onSubmit, which bypasses the component's
strict-mode validation; update the Enter handling in the Autocomplete component
(the key handler that references activeSuggestion, filteredSuggestions,
userInput) to respect this.props.strict: if strict is true only accept a
resolvedInput that comes from filteredSuggestions (i.e., non-empty and selected)
and do not fallback to raw userInput or call onChange/onSubmit when no valid
suggestion exists; if strict is false keep the existing fallback behavior.
- Around line 349-355: The current merge always overwrites
suggestionsStyle.width with the measured containerWidth; change the merge in the
Autocomplete component so the measured width (containerWidth) is used only as a
fallback when suggestionsStyle.width is not already set. Update the logic around
fieldRef/current containerWidth and mergedSuggestionsStyle to check for an
explicit width in suggestionsStyle (e.g., suggestionsStyle &&
suggestionsStyle.width) and only inject width: containerWidth + 'px' when no
explicit width exists, preserving consumer-specified widths such as those used
in ProtectedFieldsDialog.
In `@src/components/BrowserCell/BrowserCell.react.js`:
- Around line 216-220: The code currently caches this.props.isLockedOut into
this.state.classes (see the setState call and state.classes) which makes the
locked styling stale when isLockedOut changes without value changing; instead
remove pushing styles.lockedOut into state.classes and apply the lockedOut class
dynamically at render time (use this.props.isLockedOut inside
renderCellContent() or the component's render path to compute classes) so that
renderCellContent()/render() always reflects the latest isLockedOut prop rather
than a cached state value.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ec12c76c-3389-4c6a-9aa1-185907684cb8
📒 Files selected for processing (9)
src/components/Autocomplete/Autocomplete.react.jssrc/components/BrowserCell/BrowserCell.react.jssrc/components/BrowserCell/BrowserCell.scsssrc/components/BrowserRow/BrowserRow.react.jssrc/dashboard/Data/ApiConsole/RestConsole.react.jssrc/dashboard/Data/Browser/Browser.scsssrc/dashboard/Data/Browser/EditRowDialog.react.jssrc/lib/Constants.jssrc/lib/tests/BrowserCell.test.js
| if (this.props.isLockedOut) { | ||
| classes.push(styles.lockedOut); | ||
| } | ||
|
|
||
| this.setState({ ...this.state, content, classes }); |
There was a problem hiding this comment.
Don't cache isLockedOut in state.classes.
Lines 216-220 fold isLockedOut into state.classes, but renderCellContent() only reruns when value changes. src/components/BrowserRow/BrowserRow.react.js:150-186 recalculates isLockedOut from the current time on each row render, so this prop can change while the underlying date value does not; in that case the red styling stays stale.
Suggested simplification
- if (this.props.isLockedOut) {
- classes.push(styles.lockedOut);
- }
-
this.setState({ ...this.state, content, classes });
@@
const classes = [...this.state.classes];
+ if (this.props.isLockedOut) {
+ classes.push(styles.lockedOut);
+ }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/BrowserCell/BrowserCell.react.js` around lines 216 - 220, The
code currently caches this.props.isLockedOut into this.state.classes (see the
setState call and state.classes) which makes the locked styling stale when
isLockedOut changes without value changing; instead remove pushing
styles.lockedOut into state.classes and apply the lockedOut class dynamically at
render time (use this.props.isLockedOut inside renderCellContent() or the
component's render path to compute classes) so that renderCellContent()/render()
always reflects the latest isLockedOut prop rather than a cached state value.
There was a problem hiding this comment.
🧩 Analysis chain
Let me inspect the current state of the file on the PR branch to verify.
🏁 Script executed:
#!/bin/bash
# Look at the render method and renderCellContent in BrowserCell
rg -n "isLockedOut|lockedOut|renderCellContent|state\.classes" src/components/BrowserCell/BrowserCell.react.js -A2 -B2
Length of output: 590
@dblythy, you're right — my suggested diff was malformed. The bare @@ I used between the two hunks is not valid unified diff syntax. Here is a corrected version:
--- a/src/components/BrowserCell/BrowserCell.react.js
+++ b/src/components/BrowserCell/BrowserCell.react.js
@@ -210,10 +210,6 @@
if (this.props.markRequiredField && this.props.isRequired && this.props.value == null) {
classes.push(styles.required);
}
- if (this.props.isLockedOut) {
- classes.push(styles.lockedOut);
- }
-
this.setState({ ...this.state, content, classes });
@@ -683,6 +679,10 @@
const classes = [...this.state.classes];
+ if (this.props.isLockedOut) {
+ classes.push(styles.lockedOut);
+ }
+
if (current) {
classes.push(styles.current);
}The concern itself still stands: renderCellContent() only runs when value changes, so caching isLockedOut there can leave the styling stale. Moving it to render() — alongside the existing dynamic current and required class additions — ensures it always reflects the latest prop.
🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-dashboard PR: 3145
File: src/dashboard/Data/CustomDashboard/CustomDashboard.react.js:1281-1327
Timestamp: 2026-01-23T18:51:19.954Z
Learning: Avoid using disableMouseDown={true} on MenuItem components. Across the codebase, only a small minority of MenuItem instances require it, and MenuItems function correctly with the standard onClick and onMouseDown handler flow. Apply this guideline broadly to all MenuItem usages in JavaScript/JSX files; reserve disableMouseDown for explicit, well-justified edge cases only.
Learnt from: mtrezza
Repo: parse-community/parse-dashboard PR: 3185
File: package.json:51-51
Timestamp: 2026-02-07T02:18:48.037Z
Learning: In parse-dashboard code, async route handlers should wrap logic in try/catch and respond with appropriate HTTP errors (e.g., 500 with an error message). This guards against unhandled promise rejections. If a route handler returns a rejected promise and Express 5 is configured, explicit rejection forwarding may be used instead. Apply this guideline to all server routes and middleware that perform async operations.
Resolve the active suggestion before calling onSubmit and onChange in onKeyDown, so Enter submits the highlighted item instead of stale typed text. Update RestConsole onSubmit to sync the provided endpoint to state before making the request.
f8bdbd4 to
b587e68
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/dashboard/Data/Logs/Logs.react.js (1)
141-144:⚠️ Potential issue | 🟡 MinorPotential duplicate keys when
timestampis an object.Line 142 uses
key={timestamp}, but based on line 81,timestampcan be an object with anisoproperty. Whentimestampis an object, React will convert it to"[object Object]", causing duplicate keys and potential rendering issues.🛠️ Suggested fix
{this.state.logs.map(({ message, timestamp }) => ( - <LogViewEntry key={timestamp} text={message} timestamp={timestamp} /> + <LogViewEntry key={timestamp.iso || timestamp} text={message} timestamp={timestamp} /> ))}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/dashboard/Data/Logs/Logs.react.js` around lines 141 - 144, The map is using key={timestamp} which can be an object (per the timestamp.iso usage), causing keys like "[object Object]" and duplicates; update the key in the this.state.logs.map that renders LogViewEntry so it uses a stable string/id (e.g. timestamp.iso when timestamp is an object, falling back to timestamp or an index/unique id) — locate the map where LogViewEntry is rendered and replace key={timestamp} with a stable expression like timestamp?.iso || String(timestamp) || `log-${index}` to ensure unique, deterministic keys.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/dashboard/Data/Logs/Logs.react.js`:
- Around line 141-144: The map is using key={timestamp} which can be an object
(per the timestamp.iso usage), causing keys like "[object Object]" and
duplicates; update the key in the this.state.logs.map that renders LogViewEntry
so it uses a stable string/id (e.g. timestamp.iso when timestamp is an object,
falling back to timestamp or an index/unique id) — locate the map where
LogViewEntry is rendered and replace key={timestamp} with a stable expression
like timestamp?.iso || String(timestamp) || `log-${index}` to ensure unique,
deterministic keys.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f9d7ec19-2299-470e-a2e4-5a91527596aa
📒 Files selected for processing (6)
.gitignoresrc/components/Autocomplete/Autocomplete.react.jssrc/dashboard/Data/ApiConsole/RestConsole.react.jssrc/dashboard/Data/Logs/Logs.react.jssrc/dashboard/Data/Logs/Logs.scsssrc/lib/ParseApp.js
✅ Files skipped from review due to trivial changes (1)
- .gitignore
- Enter key handler now only accepts suggestion matches in strict mode, preventing raw user input from bypassing validation - Suggestions dropdown width from container measurement is now a fallback only, preserving explicit widths set via suggestionsStyle prop

Add typeahead
Closes #226
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Enhancements