- Notifications
You must be signed in to change notification settings - Fork4.4k
feat: Made changes to support datasources configuration page for workspace#41324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:release
Are you sure you want to change the base?
Conversation
… without needing an entity like applications.
coderabbitaibot commentedOct 27, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
WalkthroughAdds Workspace IDE support: new IDE type, workspace-scoped routes and URL builders, workspace context in URL assembly, Redux actions/reducer and sagas to initialize a WorkspaceEditorEngine, new workspace datasources UI (pages, header, side pane, editor), permission/plugin filter adjustments, and e2e tests. Changes
Sequence Diagram(s)sequenceDiagram participant User participant Router participant WorkspacePage as WorkspaceDatasourcesPage participant Redux participant Saga as workspaceIDESaga participant Engine as WorkspaceEditorEngine participant API User->>Router: GET /workspace/:id/datasources Router->>WorkspacePage: render(workspaceId) WorkspacePage->>Redux: select isWorkspaceEditorInitialized alt not initialized WorkspacePage->>Redux: dispatch initWorkspaceIDE({workspaceId}) Redux->>Saga: middleware handles action activate Saga Saga->>Engine: new WorkspaceEditorEngine() Saga->>Engine: call loadWorkspace(workspaceId) activate Engine Engine->>API: fetch workspace environments API-->>Engine: environments Engine->>API: fetch plugins & datasources API-->>Engine: plugins & datasources Engine->>Redux: put INITIALIZE_WORKSPACE_IDE_SUCCESS deactivate Engine deactivate Saga Redux->>WorkspacePage: isWorkspaceEditorInitialized = true end WorkspacePage->>WorkspacePage: render side pane + editor routesEstimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for usingCodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
tomjose92 commentedOct 27, 2025
/build-deploy-preview skip-tests=true |
Deploying Your Preview:https://github.com/appsmithorg/appsmith/actions/runs/18841755423. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (14)
app/client/src/ce/pages/Applications/WorkspaceMenu.tsx (1)
169-181:Use RouteBuilder + add test id/a11y role.
- Prefer central URL helper to avoid hard-coded paths.
- Add data-testid and role="menuitem" for QA/a11y parity with other items.
Apply within this block:
- <CustomMenuItem- className="workspace-menu-item"+ <CustomMenuItem+ className="workspace-menu-item"+ data-testid="t--workspace-datasources"+ role="menuitem" onClick={() =>- getOnSelectAction(DropdownOnSelectActions.REDIRECT, {- path: `/workspace/${workspace.id}/datasources`,- })+ getOnSelectAction(DropdownOnSelectActions.REDIRECT, {+ path: workspaceDatasourcesURL({ workspaceId: workspace.id }),+ }) } >And add import at top:
+import { workspaceDatasourcesURL } from "ce/RouteBuilder";app/client/src/pages/workspace/index.tsx (1)
20-29:Prefer Route.render to avoid remounts and re-created component functions.
Keeps props typing simple and avoids new component identity per render.- <SentryRoute- component={({- match,- }: {- match: { params: { workspaceId: string } };- }) => (- <WorkspaceDatasourcesPage workspaceId={match.params.workspaceId} />- )}- path={`${path}/:workspaceId/datasources`}- />+ <SentryRoute+ path={`${path}/:workspaceId/datasources`}+ render={({ match }: { match: { params: { workspaceId: string } } }) => (+ <WorkspaceDatasourcesPage workspaceId={match.params.workspaceId} />+ )}+ />app/client/src/ce/RouteBuilder.ts (1)
200-206:Consider aligning with the existing URL building pattern.These functions use template literals directly, while most other URL builders in this file use
urlBuilder.build(). For consistency and to leverage any URL handling logic (encoding, normalization) thaturlBuilderprovides, consider using the established pattern.Apply this diff to align with existing patterns:
-export const workspaceDatasourcesURL = (workspaceId: string): string =>- `/workspace/${workspaceId}/datasources`;--export const workspaceDatasourceEditorURL = (- workspaceId: string,- datasourceId: string,-): string => `/workspace/${workspaceId}/datasources/${datasourceId}`;+export const workspaceDatasourcesURL = (workspaceId: string): string =>+ urlBuilder.build({+ suffix: `workspace/${workspaceId}/datasources`,+ });++export const workspaceDatasourceEditorURL = (+ workspaceId: string,+ datasourceId: string,+): string =>+ urlBuilder.build({+ suffix: `workspace/${workspaceId}/datasources/${datasourceId}`,+ });Note: Review urlBuilder.build implementation to ensure it handles absolute paths starting with "workspace" correctly, or adjust the pattern accordingly.
app/client/src/ce/sagas/workspaceIDESagas.ts (2)
24-28:Await editor reset before initialization to avoid race conditions.RESET_EDITOR_REQUEST may have async side-effects. Wait for RESET_EDITOR_SUCCESS before proceeding.
-import { all, put, call, takeLatest } from "redux-saga/effects";+import { all, put, call, take, takeLatest } from "redux-saga/effects";... yield put(resetEditorRequest());+ yield take(ReduxActionTypes.RESET_EDITOR_SUCCESS); yield call(workspaceEngine.setupEngine);
39-43:Simplify watcher.all([...]) with a single effect is unnecessary. Yield takeLatest directly.
-export default function* watchWorkspaceIDESagas() {- yield all([- takeLatest(ReduxActionTypes.INITIALIZE_WORKSPACE_IDE, startWorkspaceIDE),- ]);-}+export default function* watchWorkspaceIDESagas() {+ yield takeLatest(ReduxActionTypes.INITIALIZE_WORKSPACE_IDE, startWorkspaceIDE);+}app/client/src/ce/reducers/uiReducers/editorReducer.tsx (1)
45-62:Reset workspace IDE flag on RESET_EDITOR_REQUEST.Keeps flags consistent across editor switches.
[ReduxActionTypes.RESET_EDITOR_REQUEST]: (state: EditorReduxState) => { return { ...state,+ isWorkspaceEditorInitialized: false, currentPageId: undefined,app/client/src/ce/actions/workspaceIDEActions.ts (1)
7-10:LGTM. Consider typing the action.Optionally return ReduxAction for stricter typing.
app/client/src/pages/workspace/WorkspaceDatasourceEditor.tsx (1)
16-24:Guard selector result and avoid magic string.
- Use optional chaining to avoid reading id from undefined.
- Replace "unused_env" with a shared constant.
useEffect(() => {- if (- currentEnvironmentDetails.id &&- currentEnvironmentDetails.id !== "unused_env"- ) {- dispatch(setCurrentEditingEnvironmentID(currentEnvironmentDetails.id));- }-}, [dispatch, currentEnvironmentDetails.id]);+ const envId = currentEnvironmentDetails?.id;+ if (envId && envId !== UNUSED_ENV_ID) {+ dispatch(setCurrentEditingEnvironmentID(envId));+ }+}, [dispatch, currentEnvironmentDetails?.id]);Add/import:
const UNUSED_ENV_ID = "unused_env";(or import an existing constant).app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
95-106:Add error fallback UI.Show an error state if initialization fails (pair with reducer error flag).
-if (!isWorkspaceEditorInitialized) {+const initError = useSelector(+ (state: DefaultRootState) => state.ui.editor.workspaceEditorInitError,+);+if (initError) {+ return (+ <PageContainer>+ <CenteredWrapper style={{ height: `calc(100vh - ${IDE_HEADER_HEIGHT}px)` }}>+ <div>Failed to initialize Workspace Datasources. Please retry.</div>+ </CenteredWrapper>+ </PageContainer>+ );+}+if (!isWorkspaceEditorInitialized) { return (app/client/src/ce/entities/Engine/WorkspaceEditorEngine.ts (1)
104-108:Optional: include workspaceId in SUCCESS payload.Helps consumers correlate which workspace initialized (useful for telemetry or race-proofing).
*completeChore() { yield put({- type: ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_SUCCESS,+ type: ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_SUCCESS,+ // payload: { workspaceId }, // if you propagate it here }); }app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (4)
170-179:Add alt text to datasource icons (a11y).Provide meaningful alt; fallback to plugin or datasource name.
- startIcon: (- <DatasourceIcon- src={getAssetUrl(pluginImages[data.pluginId])}- />- ),+ startIcon: (+ <DatasourceIcon+ alt={`${data.name} icon`}+ src={getAssetUrl(pluginImages[data.pluginId])}+ />+ ),
36-40:Optional: avoid magic numbers in heights.Use a shared header height token to compute PaneBody height for consistency with IDE.
- height: calc(100vh - 120px);+ /* import { IDE_HEADER_HEIGHT } from "@appsmith/ads"; */+ height: calc(100vh - var(--ide-header-height, 120px));And set the CSS variable at a higher container if available.
70-75:useCallback deps completeness.goToDatasource depends on history. It’s stable, but include it to silence exhaustive-deps lint (if enabled).
- const goToDatasource = useCallback(+ const goToDatasource = useCallback( (id: string) => { history.push(workspaceDatasourceEditorURL(workspaceId, id)); },- [workspaceId],+ [workspaceId, history], );
124-137:Show spinner copy via i18n message key.Replace hardcoded “Loading workspace permissions...” with a messages constant for consistency.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
app/client/src/ce/IDE/Interfaces/IDETypes.ts(1 hunks)app/client/src/ce/IDE/constants/routes.ts(1 hunks)app/client/src/ce/RouteBuilder.ts(1 hunks)app/client/src/ce/actions/workspaceIDEActions.ts(1 hunks)app/client/src/ce/constants/ReduxActionConstants.tsx(2 hunks)app/client/src/ce/entities/Engine/WorkspaceEditorEngine.ts(1 hunks)app/client/src/ce/entities/URLRedirect/URLAssembly.ts(7 hunks)app/client/src/ce/pages/Applications/WorkspaceMenu.tsx(1 hunks)app/client/src/ce/reducers/uiReducers/editorReducer.tsx(3 hunks)app/client/src/ce/sagas/index.tsx(2 hunks)app/client/src/ce/sagas/workspaceIDESagas.ts(1 hunks)app/client/src/constants/routes/baseRoutes.ts(1 hunks)app/client/src/ee/actions/workspaceIDEActions.ts(1 hunks)app/client/src/ee/entities/Engine/WorkspaceEditorEngine.ts(1 hunks)app/client/src/ee/sagas/workspaceIDESagas.ts(1 hunks)app/client/src/pages/workspace/WorkspaceCreateNewDatasourceTab.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourceEditor.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx(1 hunks)app/client/src/pages/workspace/index.tsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (11)
app/client/src/ce/actions/workspaceIDEActions.ts (1)
app/client/src/ce/constants/ReduxActionConstants.tsx (1)
ReduxActionTypes(1302-1346)
app/client/src/ce/IDE/constants/routes.ts (1)
app/client/src/ce/IDE/Interfaces/IDETypes.ts (1)
IDE_TYPE(1-6)
app/client/src/ce/sagas/workspaceIDESagas.ts (4)
app/client/src/actions/ReduxActionTypes.ts (1)
ReduxAction(9-12)app/client/src/ce/actions/workspaceIDEActions.ts (1)
InitWorkspaceIDEPayload(3-5)app/client/src/ce/entities/Engine/WorkspaceEditorEngine.ts (1)
WorkspaceEditorEngine(22-109)app/client/src/actions/initActions.ts (1)
resetEditorRequest(51-53)
app/client/src/ce/reducers/uiReducers/editorReducer.tsx (1)
app/client/src/ce/constants/ReduxActionConstants.tsx (1)
ReduxActionTypes(1302-1346)
app/client/src/pages/workspace/WorkspaceDatasourceEditor.tsx (1)
app/client/src/ce/actions/environmentAction.ts (1)
setCurrentEditingEnvironmentID(7-10)
app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (6)
app/client/src/ce/selectors/entitiesSelector.ts (4)
getDatasources(86-88)getDatasourcesGroupedByPluginCategory(114-144)getPluginImages(605-623)getPlugins(90-91)app/client/src/ce/entities/FeatureFlag.ts (1)
FEATURE_FLAG(2-67)app/client/src/ce/RouteBuilder.ts (1)
workspaceDatasourceEditorURL(203-206)app/client/src/ce/utils/BusinessFeatures/permissionPageHelpers.tsx (1)
getHasCreateDatasourcePermission(56-62)app/client/src/ce/constants/messages.ts (3)
DATASOURCE_BLANK_STATE_CTA(2360-2360)DATA_PANE_TITLE(2356-2356)DATASOURCE_LIST_BLANK_DESCRIPTION(2357-2358)app/client/src/entities/Datasource/index.ts (1)
Datasource(154-162)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (5)
app/client/src/ce/selectors/entitiesSelector.ts (1)
getDatasourceUsageCountForApp(1769-1787)app/client/src/ce/IDE/Interfaces/IDETypes.ts (1)
IDE_TYPE(1-6)app/client/src/ce/actions/workspaceIDEActions.ts (1)
initWorkspaceIDE(7-10)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
WorkspaceDataSidePane(52-197)app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)
app/client/src/ce/RouteBuilder.ts (1)
app/client/cypress/support/commands.js (1)
workspaceId(396-396)
app/client/src/ce/entities/URLRedirect/URLAssembly.ts (1)
app/client/cypress/support/commands.js (1)
workspaceId(396-396)
app/client/src/ce/entities/Engine/WorkspaceEditorEngine.ts (5)
app/client/src/ce/actions/environmentAction.ts (1)
fetchingEnvironmentConfigs(13-26)app/client/src/actions/ReduxActionTypes.ts (1)
ReduxAction(9-12)app/client/src/sagas/InitSagas.ts (1)
failFastApiCalls(147-167)app/client/src/entities/Engine/index.ts (2)
PluginsNotFoundError(61-61)PluginFormConfigsNotFoundError(62-62)app/client/src/actions/pluginActions.ts (1)
fetchPluginFormConfigs(22-29)
app/client/src/pages/workspace/index.tsx (2)
app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
WorkspaceDatasourcesPage(59-145)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-lint / client-lint
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-build / client-build
🔇 Additional comments (12)
app/client/src/ce/sagas/index.tsx (1)
60-60:Saga wiring looks good.
Placement alongside workspaceSagas is reasonable. No changes needed.Also applies to: 79-79
app/client/src/ce/entities/URLRedirect/URLAssembly.ts (1)
245-252:Workspace URL resolution needs refinement, but proposed fixes require design clarification.The concerns about empty workspaceId and context-coupled suffix rewriting are valid. However, the proposed diffs have structural issues that need addressing:
Confirmed issues:
resolveEntityIdForWorkspace()returns""instead of throwing—creates/workspace//datasourcesrisk- Suffix rewrite gates on
isWorkspaceContext()only, not explicitworkspaceIdintentIssues with proposed solution:
generateBasePath()receives onlybasePageIdandmode; diffs assume it receivesbuilderParams—misaligned with actual signature- No evidence of
datasource/suffix pattern in RouteBuilder (uses"datasource","datasources","datasource/{id}")- Diff E duplicates suffix logic; unclear whether
generateBasePath()should make the workspace vs. app decisionRecommended approach:
- Fix
resolveEntityIdForWorkspace()to throw on missing ID (align withresolveEntityIdForApp())- Clarify method responsibilities: Should
generateBasePath()be refactored to receivebuilderParamsand handle the workspace/app decision, or shouldbuild()handle routing logic?- Unify suffix handling: Gate on
!!builderParams.workspaceId || isWorkspaceContext()consistently—not just in one locationRedesign the routing layer to pass explicit intent (workspaceId) through method calls rather than relying on URL parsing alone.
app/client/src/constants/routes/baseRoutes.ts (1)
31-31:LGTM!The new workspace datasources route constant follows the established naming pattern and integrates cleanly with existing workspace routes.
app/client/src/ce/IDE/constants/routes.ts (1)
45-45:LGTM!Adding the Workspace IDE type to the IDEBasePaths mapping is consistent with the existing pattern for None and UIPackage types.
app/client/src/ee/actions/workspaceIDEActions.ts (1)
1-1:LGTM!Standard EE/CE facade pattern that allows for potential future extensions while maintaining a clean architecture boundary.
app/client/src/ee/entities/Engine/WorkspaceEditorEngine.ts (1)
1-1:LGTM!The EE facade for WorkspaceEditorEngine follows the established pattern and maintains clean architectural boundaries.
app/client/src/ee/sagas/workspaceIDESagas.ts (1)
1-2:LGTM!The EE saga facade follows the established pattern and properly re-exports both named and default exports from the CE layer.
app/client/src/ce/constants/ReduxActionConstants.tsx (2)
414-415:LGTM!The new workspace IDE action constants follow the established naming convention and are consistent with existing IDE initialization patterns (e.g., INITIALIZE_EDITOR).
483-483:LGTM!The error action constant is properly placed in IDEActionErrorTypes and follows the naming pattern.
app/client/src/pages/workspace/WorkspaceCreateNewDatasourceTab.tsx (1)
4-6:No issues found. CreateNewDatasourceTab properly accesses workspace context via Redux.The component is Redux-connected through
connect(mapStateToProps), which automatically injects workspace data (viagetCurrentAppWorkspace,getCurrentPageId, and other selectors) as props. The wrapper component correctly omits props since the child component obtains all required context from Redux state.app/client/src/ce/entities/Engine/WorkspaceEditorEngine.ts (1)
40-47:No action required—empty type is intentional.The
typeproperty in thefetchingEnvironmentConfigsaction creator is intentionally left as an empty string to imitate the functionality of the enterprise edition. The action properly propagates through sagas that handle environment configuration fetching. The code at lines 40–47 is correct as written.app/client/src/pages/workspace/WorkspaceDatasourceEditor.tsx (1)
5-5:Fix empty Redux action type in setCurrentEditingEnvironmentID.The action type is confirmed empty in
app/client/src/ce/actions/environmentAction.tsline 8. Redux actions require a non-emptytypeproperty for proper routing and reducer handling. Replace the empty string with a descriptive action type constant.⛔ Skipped due to learnings
Learnt from: AmanAgarwal041PR: appsmithorg/appsmith#29266File: app/client/src/ce/actions/environmentAction.ts:15-16Timestamp: 2024-07-26T21:12:57.228ZLearning: The `type` property in the `fetchingEnvironmentConfigs` action creator is intentionally left as an empty string to imitate the functionality of the enterprise edition, as per the user's clarification.
| None:"None", | ||
| App:"App", | ||
| UIPackage:"UIPackage", | ||
| Workspace:"Workspace", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
🧩 Analysis chain
LGTM — new IDE type addition is consistent.
No concerns here. Please ensure downstream switch/route maps cover IDE_TYPE.Workspace.
Run to spot any missing cases:
🏁 Script executed:
#!/bin/bashrg -nP --type=ts'\bIDE_TYPE\.Workspace\b|:\s*IDEType\b' -C2
Length of output: 8283
---🏁 Script executed:```shell#!/bin/bash# Find switch statements handling IDE_TYPErg -nP --type=ts 'switch\s*\(\s*(type|ideType|.*IDE_TYPE)' -A 15 | head -100Length of output: 8750
🏁 Script executed:
#!/bin/bash# Find other enum-like mappings that use IDE_TYPE keysrg -nP --type=ts'\[IDE_TYPE\.' -C 1| head -150
Length of output: 498
🏁 Script executed:
#!/bin/bash# Check if there are any references to IDE_TYPE.Workspace that might be missingrg -nP --type=ts'IDE_TYPE\.Workspace' -C 3
Length of output: 386
🏁 Script executed:
#!/bin/bash# Get full getIDEFocusStrategy function to check if Workspace case is handledcat app/client/src/ce/navigation/FocusStrategy/index.ts
Length of output: 528
🏁 Script executed:
#!/bin/bash# Search for getIDETypeByUrl to see if it handles Workspacecat app/client/src/ce/entities/IDE/utils/getIDETypeByUrl.ts
Length of output: 434
🏁 Script executed:
#!/bin/bash# Search for EE FocusStrategy implementationsfd -t f'FocusStrategy' -path'*/ee/*'
Length of output: 168
🏁 Script executed:
#!/bin/bash# Check if UIPackageFocusStrategy or WorkspaceFocusStrategy existsrg -nP --type=ts'UIPackageFocusStrategy|WorkspaceFocusStrategy' -l
Length of output: 0
🏁 Script executed:
#!/bin/bash# Find AppIDEFocusStrategy to understand implementation patternrg -nP --type=ts'class AppIDEFocusStrategy|export.*AppIDEFocusStrategy' -C 3
Length of output: 784
🏁 Script executed:
#!/bin/bash# Search more broadly for strategy files in EE folderfind. -path"*/ee/*" -name"*FocusStrategy*"2>/dev/null| head -20
Length of output: 179
🏁 Script executed:
#!/bin/bash# Check if there's an EE version of the focus strategy indexfind. -path"*/ee/*" -name"index.ts"| xargs grep -l"getIDEFocusStrategy\|FocusStrategy"2>/dev/null| head -10
Length of output: 53
🏁 Script executed:
#!/bin/bash# Check the EE version of getIDEFocusStrategycat app/client/src/ee/navigation/FocusStrategy/index.ts
Length of output: 44
🏁 Script executed:
#!/bin/bash# Check if getIDEFocusStrategy is called with Workspace anywhererg -nP --type=ts'getIDEFocusStrategy' -C 3
Length of output: 2489
Add case for IDE_TYPE.Workspace in getIDEFocusStrategy or update default handler.
The switch statement inapp/client/src/ce/navigation/FocusStrategy/index.ts only handlesIDE_TYPE.None andIDE_TYPE.App, butIDE_TYPE.Workspace is now inIDEBasePaths. SinceFocusRetentionSaga callsgetIDEFocusStrategy(ideType) whereideType comes fromgetIDETypeByUrl(), this will throw an error if Workspace paths are configured.
Currently,IDE_TYPE.Workspace has an empty path array, so it won't trigger at runtime yet—but this is a latent bug waiting to happen.
🤖 Prompt for AI Agents
In app/client/src/ce/IDE/Interfaces/IDETypes.ts around line 5,IDE_TYPE.Workspace was added but getIDEFocusStrategy (inapp/client/src/ce/navigation/FocusStrategy/index.ts) only handles IDE_TYPE.Noneand IDE_TYPE.App; add a case for IDE_TYPE.Workspace to the switch ingetIDEFocusStrategy (or update the switch default to handle unknown/added IDEtypes safely) so FocusRetentionSaga won't throw when getIDETypeByUrl() returnsWorkspace; implement the Workspace case to return the appropriate focus strategy(match App behavior or a no-op strategy) and ensure the default branch logs awarning and returns a safe fallback strategy.| [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE]:(state:EditorReduxState)=>{ | ||
| return{ ...state,isWorkspaceEditorInitialized:false}; | ||
| }, | ||
| [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_SUCCESS]:( | ||
| state:EditorReduxState, | ||
| )=>{ | ||
| return{ ...state,isWorkspaceEditorInitialized:true}; | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Handle initialization error to avoid infinite spinner.
Add INITIALIZE_WORKSPACE_IDE_ERROR handler and store the error so UI can show a fallback.
[ReduxActionTypes.INITIALIZE_WORKSPACE_IDE]: (state: EditorReduxState) => { return { ...state, isWorkspaceEditorInitialized: false }; }, [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_SUCCESS]: ( state: EditorReduxState, ) => { return { ...state, isWorkspaceEditorInitialized: true }; },+ [ReduxActionErrorTypes.INITIALIZE_WORKSPACE_IDE_ERROR]: (+ state: EditorReduxState,+ action: ReduxAction<{ error: unknown }>,+ ) => {+ return {+ ...state,+ isWorkspaceEditorInitialized: false,+ workspaceEditorInitError: action.payload?.error,+ };+ },Additionally add the field to state shape and initial state:
// initialState onLoadActionExecution: false,+ workspaceEditorInitError: undefined, export interface EditorReduxState { ... onLoadActionExecution?: boolean;+ workspaceEditorInitError?: unknown;📝 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.
| [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE]:(state:EditorReduxState)=>{ | |
| return{ ...state,isWorkspaceEditorInitialized:false}; | |
| }, | |
| [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_SUCCESS]:( | |
| state:EditorReduxState, | |
| )=>{ | |
| return{ ...state,isWorkspaceEditorInitialized:true}; | |
| }, | |
| [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE]:(state:EditorReduxState)=>{ | |
| return{ ...state,isWorkspaceEditorInitialized:false}; | |
| }, | |
| [ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_SUCCESS]:( | |
| state:EditorReduxState, | |
| )=>{ | |
| return{ ...state,isWorkspaceEditorInitialized:true}; | |
| }, | |
| [ReduxActionErrorTypes.INITIALIZE_WORKSPACE_IDE_ERROR]:( | |
| state:EditorReduxState, | |
| action:ReduxAction<{error:unknown}>, | |
| )=>{ | |
| return{ | |
| ...state, | |
| isWorkspaceEditorInitialized:false, | |
| workspaceEditorInitError:action.payload?.error, | |
| }; | |
| }, |
🤖 Prompt for AI Agents
In app/client/src/ce/reducers/uiReducers/editorReducer.tsx around lines 69 to76, add a new ReduxActionTypes.INITIALIZE_WORKSPACE_IDE_ERROR case that setsisWorkspaceEditorInitialized to false and stores the error payload on state(e.g., workspaceInitError or initializeWorkspaceError) so the UI can stop thespinner and show a fallback; also add that error field to the EditorReduxStatetype/shape and initialize it in the reducer's initial state (null or undefinedby default), and ensure the SUCCESS and INITIALIZE handlers clear/reset theerror.| yieldput({ | ||
| type:ReduxActionErrorTypes.INITIALIZE_WORKSPACE_IDE_ERROR, | ||
| payload:{ | ||
| error, | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Surface error state for UI.
INITIALIZE_WORKSPACE_IDE_ERROR is dispatched, but there’s no reducer handling to unblock or show an error. Pair this with a reducer flag and UI fallback. See reducer comment for concrete diff.
🤖 Prompt for AI Agents
In app/client/src/ce/sagas/workspaceIDESagas.ts around lines 30 to 36, the sagadispatches INITIALIZE_WORKSPACE_IDE_ERROR but the app has no reducer or stateflag to surface this error to the UI; add a reducer case and state flag (e.g.,workspaceIDEInitializationError or isWorkspaceIDEInitError) to store the errorpayload and clear any "initializing" flag, update the reducer's initial stateaccordingly, and ensure components read this flag to show a fallback/error UIand stop loading spinners; also add an action handler to clear the error whenretrying or on successful init.Uh oh!
There was an error while loading.Please reload this page.
| return( | ||
| <DataSourceEditor | ||
| applicationId={workspaceApplicationId} | ||
| datasourceId={datasourceId} | ||
| isWorkspaceContext | ||
| pageId={workspacePageId} | ||
| /> | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
🧩 Analysis chain
Verify DataSourceEditor workspace mode assumptions.
We pass synthetic applicationId/pageId with isWorkspaceContext. Confirm DataSourceEditor suppresses app/page fetches in this mode.
🏁 Script executed:
#!/bin/bash# Ensure DataSourceEditor gates app/page dependent fetches behind `isWorkspaceContext`.rg -nP --type=ts --type=tsx -C3'\bfunction\s+DataSourceEditor\b|\bconst\s+DataSourceEditor\b' app/client/src \| sed -n'1,120p'rg -nP --type=ts --type=tsx -C3'isWorkspaceContext' app/client/src/pages/Editor/DataSourceEditor*
Length of output: 55
🏁 Script executed:
#!/bin/bash# Find DataSourceEditor component filesfd -e ts -e tsx'DataSourceEditor' app/client/src# Search for DataSourceEditor definition without type flagrg -n'function DataSourceEditor|const DataSourceEditor' app/client/src -A 5# Search for isWorkspaceContext usage in Editor directoryrg -n'isWorkspaceContext' app/client/src/pages/Editor -C 3
Length of output: 0
🏁 Script executed:
#!/bin/bash# Broader search for DataSource-related filesfind app/client/src -type f -name"*DataSource*"2>/dev/null| head -20# List structure of app/client/src if it existsls -la app/client/src/2>/dev/null| head -20# Search broadly for isWorkspaceContext across entire codebaserg'isWorkspaceContext' -n2>/dev/null| head -30# Search for any Editor directoryfind app/client -type d -name"Editor"2>/dev/null
Length of output: 2312
🏁 Script executed:
#!/bin/bash# Check what WorkspaceDatasourceEditor imports and usescat app/client/src/pages/workspace/WorkspaceDatasourceEditor.tsx# Search for component definitions accepting isWorkspaceContextrg'isWorkspaceContext' app/client/src/pages/Editor -B 5 -A 10# Look for Datasource related components in Editor directoriesfind app/client/src/pages/Editor -type f\( -name"*.tsx" -o -name"*.ts"\)| xargs grep -l"Datasource"2>/dev/null
Length of output: 5898
🏁 Script executed:
#!/bin/bash# View DataSourceEditor component definitioncat app/client/src/pages/Editor/DataSourceEditor/index.tsx# Search for isWorkspaceContext usage in DataSourceEditor directoryrg'isWorkspaceContext' app/client/src/pages/Editor/DataSourceEditor -B 3 -A 3# Look for useEffect and fetch patterns in the directoryrg'useEffect|fetch|applicationId|pageId' app/client/src/pages/Editor/DataSourceEditor/index.tsx -n
Length of output: 40922
DataSourceEditor must handle isWorkspaceContext to suppress app/page dependency fetches.
TheisWorkspaceContext prop passed from WorkspaceDatasourceEditor is never declared in the component'sReduxStateProps interface and never checked. The component unconditionally callsgetApplicationByIdFromWorkspaces(state, applicationId) and passes bothapplicationId andpageId to subforms without guarding based on workspace context. This means synthetic IDs intended to avoid unnecessary API calls are still processed as legitimate application/page references, potentially triggering fetches.
AddisWorkspaceContext to theReduxStateProps interface, extract it inmapStateToProps, and conditionally skip app/page lookups when true. Alternatively, prevent the synthetic IDs from reaching selectors that trigger API calls by gating the affected logic.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
tomjose92 commentedOct 27, 2025
/build-deploy-preview skip-tests=true |
Deploying Your Preview:https://github.com/appsmithorg/appsmith/actions/runs/18842120808. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (3)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (3)
71-73:Pass IDE_TYPE.Workspace for correct usage labels.The selector generates usage strings like "N queries in this app" when passed
IDE_TYPE.App. Since this is a workspace context, passIDE_TYPE.Workspaceso labels read "…in this workspace".-const dsUsageMap = useSelector((state) =>- getDatasourceUsageCountForApp(state, IDE_TYPE.App),-);+const dsUsageMap = useSelector((state) =>+ getDatasourceUsageCountForApp(state, IDE_TYPE.Workspace),+);
81-86:Initialization won't re-run when switching workspaces.The
!isWorkspaceEditorInitializedguard prevents re-initialization when navigating from one workspace to another. The flag stays true from the first workspace, so workspace B never initializes.-useEffect(() => {- if (workspaceId && !isWorkspaceEditorInitialized) {- dispatch(initWorkspaceIDE({ workspaceId }));- }-}, [dispatch, workspaceId, isWorkspaceEditorInitialized]);+useEffect(() => {+ if (workspaceId) {+ dispatch(initWorkspaceIDE({ workspaceId }));+ }+}, [dispatch, workspaceId]);
120-124:Route path case mismatch with navigation calls.This route uses "/new" (lowercase), but WorkspaceDataSidePane pushes "/NEW" (uppercase) on lines 43 and 102. Navigation will fail. Standardize on lowercase "/new" in WorkspaceDataSidePane.tsx.
🧹 Nitpick comments (2)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (2)
89-106:Consider adding error handling for failed initialization.Currently there's no feedback if workspace fetch or IDE initialization fails. Users might see an indefinite spinner. Consider adding error boundaries or timeout handling.
123-135:Inconsistent workspaceId prop.Line 123 renders
WorkspaceCreateNewDatasourceTabwithout passingworkspaceId, but line 135 passes it explicitly. If the component extracts it from route params, the explicit prop is redundant. If not, line 123 is missing it.For consistency, either remove the explicit prop on line 135:
-<WorkspaceCreateNewDatasourceTab workspaceId={workspaceId} />+<WorkspaceCreateNewDatasourceTab />Or add it to line 123:
-render={() => <WorkspaceCreateNewDatasourceTab />}+render={() => <WorkspaceCreateNewDatasourceTab workspaceId={workspaceId} />}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (5)
app/client/src/ce/selectors/entitiesSelector.ts (1)
getDatasourceUsageCountForApp(1769-1787)app/client/src/ce/IDE/Interfaces/IDETypes.ts (1)
IDE_TYPE(1-6)app/client/src/ce/actions/workspaceIDEActions.ts (1)
initWorkspaceIDE(7-10)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
WorkspaceDataSidePane(52-197)app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-lint / client-lint
- GitHub Check: client-build / client-build
…r datasource configuration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (2)
70-73:Use Workspace context for usage strings.Pass IDE_TYPE.Workspace so labels read “…in this workspace”.
- const dsUsageMap = useSelector((state) =>- getDatasourceUsageCountForApp(state, IDE_TYPE.App),- );+ const dsUsageMap = useSelector((state) =>+ getDatasourceUsageCountForApp(state, IDE_TYPE.Workspace),+ );
81-86:Re-initialize IDE on workspace change.The guard can skip init when switching workspaces. Dispatch on every workspaceId change.
-useEffect(() => {- if (workspaceId && !isWorkspaceEditorInitialized) {- dispatch(initWorkspaceIDE({ workspaceId }));- }-}, [dispatch, workspaceId, isWorkspaceEditorInitialized]);+useEffect(() => {+ if (workspaceId) {+ dispatch(initWorkspaceIDE({ workspaceId }));+ }+}, [dispatch, workspaceId]);
🧹 Nitpick comments (6)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (2)
132-135:Make the default list route exact.Prevents accidental matches if route order shifts.
- <SentryRoute- path="/workspace/:workspaceId/datasources"- render={() => <WorkspaceCreateNewDatasourceTab />}- />+ <SentryRoute+ exact+ path="/workspace/:workspaceId/datasources"+ render={() => <WorkspaceCreateNewDatasourceTab />}+ />
121-124:Avoid magic “NEW” segment.Extract to a constant or reuse a RouteBuilder helper to keep callers and routes in sync.
- path="/workspace/:workspaceId/datasources/NEW"+ path={`/workspace/:workspaceId/datasources/${NEW_SEGMENT}`}Consider adding workspaceDatasourceNewURL(workspaceId) in RouteBuilder and using it here.
app/client/src/ce/entities/URLRedirect/URLAssembly.ts (3)
254-263:Don’t infer context from window.location. Prefer explicit params.Coupling to window pathname makes URL building dependent on the current page and breaks SSR/tests. Consider treating presence of builderParams.workspaceId as the workspace context switch, falling back to location only if absent.
Minimal approach: add an optional parameter or internal flag set in build():
- Determine
const inWorkspace = !!builderParams.workspaceId || this.isWorkspaceContext();- Pass workspaceId explicitly to generateBasePathForWorkspace rather than re-parsing location.
341-349:Suffix rewrite for “datasource/” is brittle.This special-case logic is easy to miss for other workspace routes and mixes concerns. Prefer dedicated helpers or route constants for workspace URLs and keep URLBuilder generic.
- Move workspace-datasource path assembly to RouteBuilder (already added) and remove this special-case.
- If retained, also handle exact "datasource" (no trailing slash) to avoid edge cases.
30-32:Document workspaceId usage.Clarify that providing workspaceId opts into workspace routing so callers aren’t surprised.
Add JSDoc on URLBuilderParams.workspaceId explaining precedence over window location and expected consumers.
app/client/src/ce/RouteBuilder.ts (1)
200-207:Unify with route constants and add a helper for "NEW".
- Constants
WORKSPACE_URLandWORKSPACE_DATASOURCES_PAGE_URLexist in baseRoutes and should be imported to avoid drift.- Add
workspaceDatasourceNewURLhelper to consolidate the three hardcoded/datasources/NEWstrings currently in WorkspaceDatasourcesPage.tsx and WorkspaceDataSidePane.tsx.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/client/src/ce/RouteBuilder.ts(1 hunks)app/client/src/ce/entities/URLRedirect/URLAssembly.ts(6 hunks)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx(1 hunks)app/client/src/pages/workspace/index.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/client/src/pages/workspace/index.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
app/client/src/ce/RouteBuilder.ts (1)
app/client/cypress/support/commands.js (1)
workspaceId(396-396)
app/client/src/ce/entities/URLRedirect/URLAssembly.ts (1)
app/client/cypress/support/commands.js (1)
workspaceId(396-396)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (5)
app/client/src/ce/selectors/entitiesSelector.ts (1)
getDatasourceUsageCountForApp(1769-1787)app/client/src/ce/IDE/Interfaces/IDETypes.ts (1)
IDE_TYPE(1-6)app/client/src/ce/actions/workspaceIDEActions.ts (1)
initWorkspaceIDE(7-10)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
WorkspaceDataSidePane(52-197)app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-build / client-build
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-lint / client-lint
| resolveEntityIdForWorkspace(builderParams:URLBuilderParams):string{ | ||
| // Extract workspaceId from current URL if not provided | ||
| if(builderParams?.workspaceId){ | ||
| returnbuilderParams.workspaceId; | ||
| } | ||
| constcurrentUrl=window.location.pathname; | ||
| constworkspaceMatch=currentUrl.match(/^\/workspace\/([^\/]+)/); | ||
| returnworkspaceMatch ?workspaceMatch[1] :""; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Validate workspaceId; don’t fall back to empty string.
Returning "" yields “/workspace//…” URLs. Align with app path behavior and throw.
- const workspaceMatch = currentUrl.match(/^\/workspace\/([^\/]+)/);-- return workspaceMatch ? workspaceMatch[1] : "";+ const workspaceMatch = currentUrl.match(/^\/workspace\/([^\/]+)/);+ const id = workspaceMatch ? workspaceMatch[1] : "";+ if (!id) {+ throw new URIError("Missing workspaceId. Provide builderParams.workspaceId or navigate under /workspace/:workspaceId.");+ }+ return id;
🤖 Prompt for AI Agents
In app/client/src/ce/entities/URLRedirect/URLAssembly.ts around lines 312 to323, the resolver returns an empty string when no workspaceId is found whichproduces malformed paths like "/workspace//…"; change the logic to validate andrequire a workspaceId: if builderParams.workspaceId is present return it;otherwise attempt to extract from window.location.pathname and if extractionfails throw a clear Error (or assert) indicating missing workspaceId instead ofreturning ""; ensure the thrown error message includes context (e.g., "MissingworkspaceId in URL or builderParams") so callers can handle or surface it.tomjose92 commentedOct 27, 2025
/build-deploy-preview skip-tests=true |
Deploying Your Preview:https://github.com/appsmithorg/appsmith/actions/runs/18848305560. |
Deploy-Preview-URL:https://ce-41324.dp.appsmith.com |
…components. Also handled the header for WorkspaceDatasources. Also hiding REST API and GRAPHQL API from datasources list on workspaces page
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (2)
75-78:Use Workspace context for usage strings.As previously noted, passing
IDE_TYPE.Appcauses usage labels to read "in this app". Update toIDE_TYPE.Workspaceso the UI displays "in this workspace" for consistency with the workspace context.- const dsUsageMap = useSelector((state) =>- getDatasourceUsageCountForApp(state, IDE_TYPE.App),- );+ const dsUsageMap = useSelector((state) =>+ getDatasourceUsageCountForApp(state, IDE_TYPE.Workspace),+ );
86-91:Re-initialize when workspaceId changes.As previously noted, the current guard prevents re-initialization when navigating between different workspaces. The
isWorkspaceEditorInitializedflag remains true after the first workspace is loaded, so switching to a different workspace won't trigger initialization.- useEffect(() => {- if (workspaceId && !isWorkspaceEditorInitialized) {- dispatch(initWorkspaceIDE({ workspaceId }));- }- }, [dispatch, workspaceId, isWorkspaceEditorInitialized]);+ useEffect(() => {+ if (workspaceId) {+ dispatch(initWorkspaceIDE({ workspaceId }));+ }+ }, [dispatch, workspaceId]);
🧹 Nitpick comments (3)
app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx (1)
330-335:Optional: Consider removing unnecessary optional chaining.The Plugin interface (from
entities/Plugin/index.ts) showspackageNameis a required field, so the optional chainingplugin?.packageNameis unnecessary. The variable namefinalFilteredMostPopularPluginscould be more descriptive (e.g.,workspaceFilteredPlugins), though the current name is acceptable.- // Filter out REST API from most popular plugins when on workspace datasources page- const finalFilteredMostPopularPlugins = isWorkspaceDatasourcesPage- ? filteredMostPopularPlugins.filter(- (plugin: Plugin) => plugin?.packageName !== PluginPackageName.REST_API,- )- : filteredMostPopularPlugins;+ // Filter out REST API from most popular plugins when on workspace datasources page+ const workspaceFilteredPlugins = isWorkspaceDatasourcesPage+ ? filteredMostPopularPlugins.filter(+ (plugin: Plugin) => plugin.packageName !== PluginPackageName.REST_API,+ )+ : filteredMostPopularPlugins;app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx (1)
368-371:Consider using route matching utilities for robustness.The current implementation using
includes()will work for the expected paths but could theoretically match unintended URLs. For more robust path matching, consider using React Router'smatchPathor theuseLocationhook with explicit path comparison.Example refactor:
+import { useLocation, matchPath } from "react-router";+import { WORKSPACE_DATASOURCES_PAGE_URL, WORKSPACE_DATASOURCE_EDITOR_PAGE_URL } from "constants/routes";...- // Check if we're on workspace datasources page- const isWorkspaceDatasourcesPage =- window.location.pathname.includes("/workspace/") &&- window.location.pathname.includes("/datasources");+ const location = useLocation();+ const isWorkspaceDatasourcesPage = Boolean(+ matchPath(location.pathname, { path: WORKSPACE_DATASOURCES_PAGE_URL }) ||+ matchPath(location.pathname, { path: WORKSPACE_DATASOURCE_EDITOR_PAGE_URL })+ );app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
123-141:Consider using lowercase "new" for route consistency.The route uses
/NEW(uppercase), which matches the navigation inWorkspaceDataSidePane. While this works, the convention in web routing typically favors lowercase path segments. Consider standardizing on/newacross both the route definition and all navigation calls for better consistency with common web practices.- path={`${WORKSPACE_DATASOURCES_PAGE_URL}/NEW`}+ path={`${WORKSPACE_DATASOURCES_PAGE_URL}/new`}And update navigation calls in
WorkspaceDataSidePane.tsx:-history.push(`/workspace/${workspaceId}/datasources/NEW`);+history.push(`/workspace/${workspaceId}/datasources/new`);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
app/client/src/ce/pages/common/AppHeader.tsx(2 hunks)app/client/src/constants/routes/baseRoutes.ts(1 hunks)app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx(1 hunks)app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx(1 hunks)app/client/src/pages/workspace/index.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/client/src/constants/routes/baseRoutes.ts
🧰 Additional context used
🧬 Code graph analysis (6)
app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx (2)
app/client/src/pages/Editor/IntegrationEditor/util.ts (1)
filterSearch(11-20)app/client/src/ce/constants/messages.ts (1)
CREATE_NEW_DATASOURCE_REST_API(402-402)
app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx (2)
app/client/src/pages/Editor/AppsmithLink.tsx (1)
AppsmithLink(29-67)app/client/src/constants/routes/baseRoutes.ts (1)
APPLICATIONS_URL(8-8)
app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx (1)
app/client/src/entities/Plugin/index.ts (1)
Plugin(71-87)
app/client/src/pages/workspace/index.tsx (3)
app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)app/client/src/pages/common/PageWrapper.tsx (1)
PageWrapper(63-89)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
WorkspaceDatasourcesPage(64-146)
app/client/src/ce/pages/common/AppHeader.tsx (1)
app/client/src/constants/routes/baseRoutes.ts (2)
WORKSPACE_DATASOURCES_PAGE_URL(31-31)WORKSPACE_DATASOURCE_EDITOR_PAGE_URL(32-32)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (6)
app/client/src/ce/selectors/entitiesSelector.ts (1)
getDatasourceUsageCountForApp(1769-1787)app/client/src/ce/IDE/Interfaces/IDETypes.ts (1)
IDE_TYPE(1-6)app/client/src/ce/actions/workspaceIDEActions.ts (1)
initWorkspaceIDE(7-10)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
WorkspaceDataSidePane(52-197)app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)app/client/src/constants/routes/baseRoutes.ts (2)
WORKSPACE_DATASOURCES_PAGE_URL(31-31)WORKSPACE_DATASOURCE_EDITOR_PAGE_URL(32-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-lint / client-lint
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-build / client-build
🔇 Additional comments (15)
app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx (1)
338-338:LGTM!The plugin selection correctly uses the workspace-filtered plugin list when displaying most popular plugins.
app/client/src/ce/pages/common/AppHeader.tsx (2)
19-20:LGTM!The new imports for workspace datasource routes and header component are correctly placed and follow the existing import patterns.
Also applies to: 25-25
49-56:LGTM!The new workspace datasource routes are properly integrated into the Switch statement and follow the existing routing patterns.
app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx (1)
373-386:LGTM!The visibility conditions correctly hide REST and GraphQL API creation options when on workspace datasources pages. The logic is consistently applied to both API types.
app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx (3)
1-7:LGTM!All imports are correctly placed and necessary for the component implementation.
9-16:LGTM!The fixed header styling is appropriate and uses the correct CSS variables for z-index and background color.
18-38:LGTM!The header component is well-structured and correctly implements the IDEHeader pattern with appropriate conditional rendering for the workspace name.
app/client/src/pages/workspace/index.tsx (4)
6-6:LGTM!The import for WorkspaceDatasourcesPage is correctly placed.
15-22:LGTM!The Settings route maintains the existing PageWrapper pattern and is correctly structured.
23-42:LGTM!The workspace datasources routes are correctly configured. Both routes properly extract
workspaceIdfrom route parameters and pass it toWorkspaceDatasourcesPage. The component handles its own layout, so not wrapping it inPageWrapperis appropriate.
43-49:LGTM!The default workspace page route maintains the existing PageWrapper pattern and is correctly positioned as the catch-all route.
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (4)
1-24:LGTM!All imports are appropriately organized and necessary for the component implementation.
27-58:LGTM!The styled components create an appropriate two-pane IDE layout that mirrors the AppIDE structure.
80-84:LGTM!The workspace selector correctly retrieves the current workspace by ID.
93-98:LGTM!The workspace fetching logic correctly ensures workspace data is loaded when needed.
app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx (2)
34-36:Remove or clarify the empty div.The empty div in IDEHeader.Right serves no clear purpose. Either remove it if IDEHeader.Right can be empty, or add a comment if it's a placeholder for future functionality.
<IDEHeader.Right>- <div /> </IDEHeader.Right>
9-16:WorkspaceDatasourceHeader height should be explicitly set to match padding-top.The page correctly applies
padding-top: ${IDE_HEADER_HEIGHT}pxonPageContainerto offset the fixed header. However,WorkspaceDatasourceHeaderdoesn't explicitly set its own height property. For alignment consistency, addheight: ${IDE_HEADER_HEIGHT}px;toStyledWorkspaceHeaderto ensure the header and content spacing remain in sync ifIDE_HEADER_HEIGHTchanges.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx (2)
app/client/src/pages/Editor/AppsmithLink.tsx (1)
AppsmithLink(29-67)app/client/src/constants/routes/baseRoutes.ts (1)
APPLICATIONS_URL(8-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-lint / client-lint
- GitHub Check: client-build / client-build
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
🔇 Additional comments (1)
app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx (1)
1-7:LGTM!Imports are clean and all used.
Uh oh!
There was an error while loading.Please reload this page.
…age, it takes the user to the workspace on the applications page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
app/client/src/pages/AppIDE/layouts/components/Header/index.tsx (2)
165-168:Consider adding a defensive check forcurrentWorkspace.id.The code checks
currentWorkspace.nameon line 163 but directly accessescurrentWorkspace.idwithout validation. If the id is undefined, the URL becomes malformed (/applications?workspaceId=undefined).Consider either:
- Adding
currentWorkspace.idto the condition on line 163- Using optional chaining with a fallback
- <>- <Link- className="mr-1.5"- to={`${APPLICATIONS_URL}?workspaceId=${currentWorkspace.id}`}- >+ {currentWorkspace.id ? (+ <>+ <Link+ className="mr-1.5"+ to={`${APPLICATIONS_URL}?workspaceId=${currentWorkspace.id}`}+ >+ {currentWorkspace.name}+ </Link>+ {"/"}+ <EditorName+ applicationId={applicationId}+ className="t--application-name editable-application-name max-w-48"+ defaultSavingState={+ isSavingName ? SavingState.STARTED : SavingState.NOT_STARTED+ }+ defaultValue={currentApplication?.name || ""}+ editInteractionKind={EditInteractionKind.SINGLE}+ editorName="Application"+ fill+ getNavigationMenu={useNavigationMenuData}+ isError={isErroredSavingName}+ isNewEditor={+ applicationList.filter((el) => el.id === applicationId)+ .length > 0+ }+ isPopoverOpen={isPopoverOpen}+ onBlur={(value: string) =>+ updateApplicationDispatch(applicationId || "", {+ name: value,+ currentApp: true,+ })+ }+ setIsPopoverOpen={setIsPopoverOpen}+ />+ </>+ ) : null}- {currentWorkspace.name}- </Link>- {"/"}- <EditorName- applicationId={applicationId}- className="t--application-name editable-application-name max-w-48"- defaultSavingState={- isSavingName ? SavingState.STARTED : SavingState.NOT_STARTED- }- defaultValue={currentApplication?.name || ""}- editInteractionKind={EditInteractionKind.SINGLE}- editorName="Application"- fill- getNavigationMenu={useNavigationMenuData}- isError={isErroredSavingName}- isNewEditor={- applicationList.filter((el) => el.id === applicationId)- .length > 0- }- isPopoverOpen={isPopoverOpen}- onBlur={(value: string) =>- updateApplicationDispatch(applicationId || "", {- name: value,- currentApp: true,- })- }- setIsPopoverOpen={setIsPopoverOpen}- />- </>
167-167:Consider using a URL builder utility for query parameter construction.Manually constructing query parameters via template literals lacks type safety and proper URL encoding. Consider using
URLSearchParamsor a URL builder utility consistent with patterns elsewhere in the codebase (e.g.,viewerURLon line 144).Example with
URLSearchParams:constapplicationsUrl=`${APPLICATIONS_URL}?${newURLSearchParams({workspaceId:currentWorkspace.id}).toString()}`;Or define a URL builder function similar to other route builders in the codebase.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/client/src/pages/AppIDE/layouts/components/Header/index.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/client/src/pages/workspace/WorkspaceDatasourceHeader.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
app/client/src/pages/AppIDE/layouts/components/Header/index.tsx (1)
app/client/src/constants/routes/baseRoutes.ts (1)
APPLICATIONS_URL(8-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-build / client-build
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-lint / client-lint
This PR has not seen activitiy for a while. It will be closed in 7 days unless further activity is detected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
78-83:Re-initialize when workspaceId changes.The
!isWorkspaceEditorInitializedguard prevents re-initialization when navigating between different workspaces. Once initialized for workspace A, switching to workspace B will skip initialization because the flag is already true.Apply this diff to ensure initialization occurs for each workspace:
useEffect(() => {- if (workspaceId && !isWorkspaceEditorInitialized) {+ if (workspaceId) { dispatch(initWorkspaceIDE({ workspaceId })); }-}, [dispatch, workspaceId, isWorkspaceEditorInitialized]);+}, [dispatch, workspaceId]);Note: If initialization should only occur once per workspace, track the initialized workspaceId separately rather than using a boolean flag.
🧹 Nitpick comments (1)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
114-118:Consider lowercase route convention.The route uses uppercase
/NEW, which is unconventional (most routes use lowercase/new). While this is consistent with the navigation inWorkspaceDataSidePane.tsx, lowercase is the standard convention for URLs.To align with web conventions, consider refactoring to lowercase:
- path={`${WORKSPACE_DATASOURCES_PAGE_URL}/NEW`}+ path={`${WORKSPACE_DATASOURCES_PAGE_URL}/new`}And update the corresponding navigation in
WorkspaceDataSidePane.tsx:history.push(`/workspace/${workspaceId}/datasources/new`)Alternatively, extract to a shared constant to prevent future mismatches:
// In constants/routes.tsexportconstDATASOURCE_NEW_PATH='/new';// Usagepath={`${WORKSPACE_DATASOURCES_PAGE_URL}${DATASOURCE_NEW_PATH}`}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
app/client/src/ce/IDE/constants/routes.ts(1 hunks)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- app/client/src/ce/IDE/constants/routes.ts
- app/client/src/pages/workspace/WorkspaceDataSidePane.tsx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-10-08T15:32:39.374ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-07-26T21:12:57.228ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.📚 Learning: 2024-12-16T19:43:14.764Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 38171File: app/client/src/git/components/GitContextProvider/index.tsx:60-70Timestamp: 2024-12-16T19:43:14.764ZLearning: Prefer not to throw errors when dispatching actions in the `setImportWorkspaceId` function in `app/client/src/git/components/GitContextProvider/index.tsx`.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
📚 Learning: 2024-12-11T08:33:24.352Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 38088File: app/client/src/git/components/GitQuickActions/BranchButton/index.tsx:72-74Timestamp: 2024-12-11T08:33:24.352ZLearning: In the 'BranchButton' component in 'app/client/src/git/components/GitQuickActions/BranchButton/index.tsx' (TypeScript, React), the `useEffect` hook that checks for label ellipsis does not need to include `currentBranch` in its dependency array.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: ankitakingerRepo: appsmithorg/appsmith PR: 29965File: app/client/src/utils/storage.ts:129-129Timestamp: 2024-10-08T15:32:34.115ZLearning: The `migrateAppIdToEditorId` function in `app/client/src/utils/storage.ts` is intended to be called only when `appId` is present and `editorId` is not in the payload. This context should be considered in future reviews related to this function.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
📚 Learning: 2025-10-30T07:15:20.287Z
Learnt from: ashit-rathRepo: appsmithorg/appsmith PR: 41312File: app/client/src/utils/helpers.tsx:1124-1136Timestamp: 2025-10-30T07:15:20.287ZLearning: In app/client/src/utils/helpers.tsx, within the getUpdateRouteForSlugPath function, the pageSlug parameter extracted from the route includes the trailing hyphen (e.g., "home-page-" not "home-page"). Additionally, when the static slug conversion branch is executed, params.basePageId is guaranteed to be defined because the code path requires successful page data fetch from the server as a precondition.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
🧬 Code graph analysis (1)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (4)
app/client/src/ce/actions/workspaceIDEActions.ts (1)
initWorkspaceIDE(7-10)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
WorkspaceDataSidePane(50-193)app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)app/client/src/constants/routes/baseRoutes.ts (2)
WORKSPACE_DATASOURCES_PAGE_URL(31-31)WORKSPACE_DATASOURCE_EDITOR_PAGE_URL(32-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-lint / client-lint
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-build / client-build
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
🔇 Additional comments (1)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
85-103:No changes needed—code already handles undefined workspace gracefully.WorkspaceDataSidePane has its own
isFetchingCurrentWorkspaceguard (line 123) that displays a loading state while the workspace fetch completes. All workspace property accesses use safe optional chaining (currentWorkspace?.userPermissions), so rendering with undefined workspace is handled defensively. The parent'sisWorkspaceEditorInitializedgate and the child'sisFetchingCurrentWorkspacegate serve different purposes and work in tandem.
Uh oh!
There was an error while loading.Please reload this page.
…orkspace then provide false.
…spaceEditor Engine to a folder outside of ee or ce, and made it adjacent to AppEditorEngine. Using isWorkspaceContext function across APIOrSaaS and DBOrMostPopular plugins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx (1)
372-385:Add workspace context check to authApiPlugin visibility.The authenticated REST API (
authApiPlugin, lines 208-216) lacks the!isWorkspaceDatasourcesPagecheck that's applied to bothrestAPIVisibleandgraphQLAPIVisible. DBOrMostPopularPlugins.tsx also filters out REST API in workspace context (line 332), establishing a consistent pattern. Apply the same check to authApiPlugin at line 208 for consistency.
🧹 Nitpick comments (1)
app/client/src/entities/Engine/WorkspaceEditorEngine.ts (1)
58-102:LGTM with minor suggestion.The plugin and datasource loading logic is correct, with proper airgap handling and error flows. The
failFastApiCallspattern is used appropriately.Consider including
workspaceIdin error messages for easier debugging:if (!initActionCalls)- throw new PluginsNotFoundError("Unable to fetch plugins");+ throw new PluginsNotFoundError(`Unable to fetch plugins for workspace ${workspaceId}`); // ... later ... if (!pluginFormCall) throw new PluginFormConfigsNotFoundError(- "Unable to fetch plugin form configs",+ `Unable to fetch plugin form configs for workspace ${workspaceId}`, );Based on learnings, workspace IDs are obfuscated and safe to log.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/client/src/ce/sagas/workspaceIDESagas.ts(1 hunks)app/client/src/ee/sagas/workspaceIDESagas.ts(1 hunks)app/client/src/entities/Engine/WorkspaceEditorEngine.ts(1 hunks)app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx(2 hunks)app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- app/client/src/ce/sagas/workspaceIDESagas.ts
- app/client/src/pages/Editor/IntegrationEditor/DBOrMostPopularPlugins.tsx
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-10-08T15:32:39.374ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-07-26T21:12:57.228ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.📚 Learning: 2024-10-11T09:28:32.636Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 36622File: app/client/src/entities/Engine/AppEditorEngine.ts:0-0Timestamp: 2024-10-11T09:28:32.636ZLearning: In the file `app/client/src/entities/Engine/AppEditorEngine.ts`, the IDs (`currentApplication.baseId`) and branches (`currentBranch`) are obfuscated, so it's acceptable to log them for debugging purposes.Applied to files:
app/client/src/entities/Engine/WorkspaceEditorEngine.ts
🧬 Code graph analysis (3)
app/client/src/entities/Engine/WorkspaceEditorEngine.ts (5)
app/client/src/ce/actions/environmentAction.ts (1)
fetchingEnvironmentConfigs(13-26)app/client/src/actions/ReduxActionTypes.ts (1)
ReduxAction(9-12)app/client/src/sagas/InitSagas.ts (1)
failFastApiCalls(147-167)app/client/src/entities/Engine/index.ts (2)
PluginsNotFoundError(61-61)PluginFormConfigsNotFoundError(62-62)app/client/src/actions/pluginActions.ts (1)
fetchPluginFormConfigs(22-29)
app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx (2)
app/client/src/pages/Editor/IntegrationEditor/util.ts (1)
filterSearch(11-20)app/client/src/ce/constants/messages.ts (1)
CREATE_NEW_DATASOURCE_REST_API(402-402)
app/client/src/ee/sagas/workspaceIDESagas.ts (2)
app/client/src/ce/constants/ReduxActionConstants.tsx (1)
ReduxActionTypes(1302-1346)app/client/src/ce/sagas/workspaceIDESagas.ts (1)
startWorkspaceIDE(9-34)
🔇 Additional comments (7)
app/client/src/ee/sagas/workspaceIDESagas.ts (3)
1-1:LGTM! Standard EE/CE re-export pattern.The re-export statement correctly exposes CE layer functionality through the EE layer, following the established architecture pattern in the codebase.
3-5:LGTM! Import statements are correct.All imports follow the proper EE/CE conventions and reference the correct modules. The CE implementation of
startWorkspaceIDEincludes appropriate error handling with try-catch blocks.
7-11:LGTM! Saga wiring is correct.The saga properly uses
takeLatestto listen for workspace IDE initialization, which cancels stale initializations on rapid dispatches. The action typeINITIALIZE_WORKSPACE_IDEis defined in ReduxActionConstants, and the structure follows established saga patterns with proper delegation to the CE implementation.app/client/src/pages/Editor/IntegrationEditor/APIOrSaasPlugins.tsx (1)
369-370:No issues found. The implementation is correct and consistent.The
urlBuilder.isWorkspaceContext()method correctly identifies workspace context by checking if the URL pathname starts with "/workspace". This detection pattern is consistently applied across bothAPIOrSaasPlugins.tsxandDBOrMostPopularPlugins.tsx, confirming the feature is intentionally designed to hide API creation options in workspace context.app/client/src/entities/Engine/WorkspaceEditorEngine.ts (3)
53-56:LGTM!Standard engine setup pattern: starts evaluation and resets autocomplete service.
104-108:LGTM!Clean completion signal dispatching success action.
23-28:Binding generator methods is valid and correctly preserves context.The search confirms these methods are called directly via
yield call()in workspaceIDESagas.ts and InitSagas.ts, and tests validate this pattern works correctly. Binding generator functions is a legitimate defensive pattern ensuringthiscontext is always preserved, even when method references are stored or passed around. No issues found.
| *loadWorkspace(workspaceId:string){ | ||
| // Set the current workspace context | ||
| yieldput({ | ||
| type:ReduxActionTypes.SET_CURRENT_WORKSPACE_ID, | ||
| payload:{ | ||
| workspaceId, | ||
| editorId:workspaceId,// Use workspaceId as editorId for workspace context | ||
| }, | ||
| }); | ||
| // Fetch environment configs for the workspace | ||
| yieldput( | ||
| fetchingEnvironmentConfigs({ | ||
| workspaceId, | ||
| editorId:workspaceId, | ||
| fetchDatasourceMeta:true, | ||
| }), | ||
| ); | ||
| // Wait for environments to be fetched | ||
| yieldcall(waitForFetchEnvironments); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Add error handling and timeout for environment fetching.
ThewaitForFetchEnvironments call at line 50 has no error handling or timeout. If environment fetching fails or hangs, the workspace IDE initialization will block indefinitely with no user feedback or recovery path.
Consider wrapping the call in a try-catch block or using a race condition with a timeout, similar to the error handling pattern inloadPluginsAndDatasources.
// Wait for environments to be fetched- yield call(waitForFetchEnvironments);+ try {+ yield call(waitForFetchEnvironments);+ } catch (error) {+ throw new Error(`Failed to fetch workspace environments: ${error.message}`);+ }
📝 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.
| *loadWorkspace(workspaceId: string){ | |
| // Set the current workspace context | |
| yieldput({ | |
| type:ReduxActionTypes.SET_CURRENT_WORKSPACE_ID, | |
| payload:{ | |
| workspaceId, | |
| editorId:workspaceId,// Use workspaceId as editorId for workspace context | |
| }, | |
| }); | |
| // Fetch environment configs for the workspace | |
| yieldput( | |
| fetchingEnvironmentConfigs({ | |
| workspaceId, | |
| editorId:workspaceId, | |
| fetchDatasourceMeta:true, | |
| }), | |
| ); | |
| // Wait for environments to be fetched | |
| yieldcall(waitForFetchEnvironments); | |
| } | |
| *loadWorkspace(workspaceId: string){ | |
| // Set the current workspace context | |
| yieldput({ | |
| type:ReduxActionTypes.SET_CURRENT_WORKSPACE_ID, | |
| payload:{ | |
| workspaceId, | |
| editorId:workspaceId,// Use workspaceId as editorId for workspace context | |
| }, | |
| }); | |
| // Fetch environment configs for the workspace | |
| yieldput( | |
| fetchingEnvironmentConfigs({ | |
| workspaceId, | |
| editorId:workspaceId, | |
| fetchDatasourceMeta:true, | |
| }), | |
| ); | |
| // Wait for environments to be fetched | |
| try{ | |
| yieldcall(waitForFetchEnvironments); | |
| }catch(error){ | |
| thrownewError(`Failed to fetch workspace environments:${error.message}`); | |
| } | |
| } |
🤖 Prompt for AI Agents
In app/client/src/entities/Engine/WorkspaceEditorEngine.ts around lines 30 to51, the call to waitForFetchEnvironments is unguarded and can hang indefinitely;wrap the environment fetch wait in a guarded flow (use a try/catch or aredux-saga race between call(waitForFetchEnvironments) and a timeout delay,e.g., const { environments, timeout } = yield race({ environments:call(waitForFetchEnvironments), timeout: delay(ENV_FETCH_TIMEOUT_MS) }) ),handle the timeout or thrown error by dispatching a clear failure action ornotification (and logging the error), and ensure you return or abort workspaceinitialization on failure so the IDE doesn't block (also include a configurabletimeout constant and any necessary cleanup/cancel effects).…asources component.
tomjose92 commentedNov 11, 2025
/build-deploy-preview skip-tests=true |
Deploying Your Preview:https://github.com/appsmithorg/appsmith/actions/runs/19262099578. |
Deploy-Preview-URL:https://ce-41324.dp.appsmith.com |
…ge instead of component, hence preventing unmount/mount of it on every navigation. Added cypress test case for WorkspaceDatasourceSettings. And minor css change.
pedro-santos-rodrigues commentedNov 28, 2025
@tomjose92 I've had the opportunity to take a look at it and left some feedback about the experience here:https://jam.dev/c/b7f9aafe-c703-4895-a2ac-9cf60d80a169 |
tomjose92 commentedNov 28, 2025
Thanks@pedro-santos-rodrigues, regarding the comments
|
… Also deciding when to show + icon. Also added test cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 6
♻️ Duplicate comments (3)
app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
94-95:Fix route case: "NEW" → "new".Routes are case-sensitive. The route in
WorkspaceDatasourcesPage.tsxuses lowercase/NEWat line 127. Standardize to consistent casing.Also applies to: 158-160
app/client/src/ce/entities/URLRedirect/URLAssembly.ts (1)
314-324:Validate workspaceId; don't fall back to empty string.Returning
""yields/workspace//…URLs. Already flagged previously - ensure this is addressed.app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
125-129:Route path case must match callers.Route uses
/NEW(uppercase). Callers inWorkspaceDataSidePane.tsxalso push/NEW. Standardize to lowercase/newfor URL consistency.
🧹 Nitpick comments (7)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
92-92:Reconsider excessive use of{ force: true }when enabling tests.The commented tests use
{ force: true }extensively in click operations. While not explicitly prohibited, forcing clicks can mask real actionability issues like elements being covered or not properly visible. Consider removing force flags and ensuring elements are properly interactable before clicking.Example improvement:
- cy.get(".t--add-datasource-button").first().click({ force: true });+ cy.get(".t--add-datasource-button").first().should("be.visible").should("be.enabled").click();Also applies to: 97-97, 141-141, 145-145, 147-147, 175-175, 180-180
app/client/src/pages/workspace/index.tsx (2)
15-22:Avoid inline arrow functions incomponentprop.Using
component={() => <Component />}creates a new component instance on every render, causing unnecessary unmounting/remounting. Userenderprop instead for inline JSX.- <SentryRoute- component={() => (- <PageWrapper displayName="Workspace Settings">- <Settings />- </PageWrapper>- )}- path={`${path}/:workspaceId/settings`}- />+ <SentryRoute+ path={`${path}/:workspaceId/settings`}+ render={() => (+ <PageWrapper displayName="Workspace Settings">+ <Settings />+ </PageWrapper>+ )}+ />Apply the same fix to the default route (lines 35-41).
Also applies to: 35-41
23-34:Consider consolidating duplicate routes.Both
/datasourcesand/datasourceroutes render identical components. If intentional for backward compatibility, add a comment. Otherwise, consolidate.- <SentryRoute- path={`${path}/:workspaceId/datasources`}- render={({ match }: { match: { params: { workspaceId: string } } }) => (- <WorkspaceDatasourcesPage workspaceId={match.params.workspaceId} />- )}- />- <SentryRoute- path={`${path}/:workspaceId/datasource`}- render={({ match }: { match: { params: { workspaceId: string } } }) => (- <WorkspaceDatasourcesPage workspaceId={match.params.workspaceId} />- )}- />+ {/* /datasources for list view, /datasource/:id for editor - both use same page */}+ <SentryRoute+ path={[`${path}/:workspaceId/datasources`, `${path}/:workspaceId/datasource`]}+ render={({ match }: { match: { params: { workspaceId: string } } }) => (+ <WorkspaceDatasourcesPage workspaceId={match.params.workspaceId} />+ )}+ />app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (2)
122-135:Consider using Spinner for consistent loading UX.
WorkspaceDatasourcesPageuses<Spinner size="lg" />during loading. This component shows plain text. Consider aligning for consistent UX.
169-201:Short-circuit EntityGroupsList when no datasources.
EntityGroupsListrenders even whendatasources.length === 0, producing empty group containers. Short-circuit to avoid rendering empty structure.{datasources.length === 0 ? ( <EmptyState button={blankStateButtonProps} description={createMessage(DATASOURCE_LIST_BLANK_DESCRIPTION)} icon={"datasource-v3"} />- ) : null}- <EntityGroupsList+ ) : (+ <EntityGroupsListAnd close the ternary properly with
)after theEntityGroupsListblock.app/client/src/ce/entities/URLRedirect/URLAssembly.ts (2)
256-260:isWorkspaceContext()is called multiple times per build.Consider caching the result within
build()to avoid repeatedwindow.location.pathnamereads and regex matching.build(builderParams: URLBuilderParams, mode: APP_MODE = APP_MODE.EDIT) {+ const isWorkspace = this.isWorkspaceContext(); // ... use isWorkspace instead of this.isWorkspaceContext() throughout
262-264:Misleading parameter name ingenerateBasePathForWorkspace.Parameter is named
workspaceIdbut the caller passesentityId. While functionally correct in workspace context, consider renaming for clarity.- generateBasePathForWorkspace(workspaceId: string) {- return `/workspace/${workspaceId}/datasources`;+ generateBasePathForWorkspace(entityId: string) {+ // In workspace context, entityId is the workspaceId+ return `/workspace/${entityId}/datasources`; }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts(1 hunks)app/client/src/ce/entities/URLRedirect/URLAssembly.ts(6 hunks)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx(1 hunks)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx(1 hunks)app/client/src/pages/workspace/index.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/client/cypress/**/**.*
⚙️ CodeRabbit configuration file
app/client/cypress/**/**.*: Review the following e2e test code written using the Cypress test library. Ensure that:
- Follow best practices for Cypress code and e2e automation.
- Avoid using cy.wait in code.
- Avoid using cy.pause in code.
- Avoid using agHelper.sleep().
- Use locator variables for locators and do not use plain strings.
- Use data-* attributes for selectors.
- Avoid Xpaths, Attributes and CSS path.
- Avoid selectors like .btn.submit or button[type=submit].
- Perform logins via API with LoginFromAPI.
- Perform logout via API with LogOutviaAPI.
- Perform signup via API with SignupFromAPI.
- Avoid using it.only.
- Avoid using after and aftereach in test cases.
- Use multiple assertions for expect statements.
- Avoid using strings for assertions.
- Do not use duplicate filenames even with different paths.
- Avoid using agHelper.Sleep, this.Sleep in any file in code.
Files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
🧠 Learnings (16)
📚 Learning: 2024-12-16T19:43:14.764Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 38171File: app/client/src/git/components/GitContextProvider/index.tsx:60-70Timestamp: 2024-12-16T19:43:14.764ZLearning: Prefer not to throw errors when dispatching actions in the `setImportWorkspaceId` function in `app/client/src/git/components/GitContextProvider/index.tsx`.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsxapp/client/src/ce/entities/URLRedirect/URLAssembly.ts
📚 Learning: 2024-12-11T08:33:24.352Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 38088File: app/client/src/git/components/GitQuickActions/BranchButton/index.tsx:72-74Timestamp: 2024-12-11T08:33:24.352ZLearning: In the 'BranchButton' component in 'app/client/src/git/components/GitQuickActions/BranchButton/index.tsx' (TypeScript, React), the `useEffect` hook that checks for label ellipsis does not need to include `currentBranch` in its dependency array.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
📚 Learning: 2024-07-26T21:12:57.228Z
Learnt from: ankitakingerRepo: appsmithorg/appsmith PR: 29965File: app/client/src/utils/storage.ts:129-129Timestamp: 2024-07-26T21:12:57.228ZLearning: The `migrateAppIdToEditorId` function in `app/client/src/utils/storage.ts` is intended to be called only when `appId` is present and `editorId` is not in the payload. This context should be considered in future reviews related to this function.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
📚 Learning: 2025-10-30T07:15:20.287Z
Learnt from: ashit-rathRepo: appsmithorg/appsmith PR: 41312File: app/client/src/utils/helpers.tsx:1124-1136Timestamp: 2025-10-30T07:15:20.287ZLearning: In app/client/src/utils/helpers.tsx, within the getUpdateRouteForSlugPath function, the pageSlug parameter extracted from the route includes the trailing hyphen (e.g., "home-page-" not "home-page"). Additionally, when the static slug conversion branch is executed, params.basePageId is guaranteed to be defined because the code path requires successful page data fetch from the server as a precondition.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsxapp/client/src/ce/entities/URLRedirect/URLAssembly.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: alex-golovanovRepo: appsmithorg/appsmith PR: 36665File: app/client/src/IDE/Components/FileTab/styles.tsx:19-19Timestamp: 2024-10-08T15:32:34.115ZLearning: Do not suggest replacing hardcoded `padding-top: 6px;` with design variables in `app/client/src/IDE/Components/FileTab/styles.tsx`.Applied to files:
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx
📚 Learning: 2025-11-05T12:56:49.249Z
Learnt from: vsvamsi1Repo: appsmithorg/appsmith PR: 41363File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts:0-0Timestamp: 2025-11-05T12:56:49.249ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 4-6 depend on state (`page1Slug`, `page2Slug`) set in Tests 2-3. The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-10-08T15:32:34.115ZLearning: Learnt from: sagar-qa007PR: appsmithorg/appsmith#34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-07-16T06:44:55.118ZLearning: Avoid using sleep functions like `agHelper.Sleep`, `this.Sleep`, and other related sleep functions in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2025-11-05T12:58:32.486Z
Learnt from: vsvamsi1Repo: appsmithorg/appsmith PR: 41363File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts:32-225Timestamp: 2025-11-05T12:58:32.486ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 2-5 depend on state from previous tests (e.g., slug values modified in earlier tests). The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-07-24T08:29:41.208Z
Learnt from: abhishek-bandameediRepo: appsmithorg/appsmith PR: 35133File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBox2_spec.js:0-0Timestamp: 2024-07-24T08:29:41.208ZLearning: In Cypress tests for the Appsmith project, ensure the use of locator variables for selectors and include multiple assertions for comprehensive testing.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-11-13T09:07:54.931Z
Learnt from: vhemeryRepo: appsmithorg/appsmith PR: 37371File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js:44-47Timestamp: 2024-11-13T09:07:54.931ZLearning: When reviewing code in `app/client/cypress/**` paths, ensure that suggestions are appropriate for test code and not for `src` code. Avoid applying source code checks to test code unless relevant.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:39.374Z
Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-10-08T15:32:39.374ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-11-13T09:11:36.959Z
Learnt from: vhemeryRepo: appsmithorg/appsmith PR: 37371File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37Timestamp: 2024-11-13T09:11:36.959ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.114Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settingsTe_Spec.ts:33-33Timestamp: 2024-10-08T15:32:34.114ZLearning: Follow best practices for Cypress code and e2e automation:- Avoid using cy.wait in code.- Avoid using cy.pause in code.- Avoid using agHelper.sleep().- Use locator variables for locators and do not use plain strings.- Use data-* attributes for selectors.- Avoid Xpaths, Attributes, and CSS path.- Avoid selectors like .btn.submit or button[type=submit].- Perform logins via API with LoginFromAPI.- Perform logout via API with LogOutviaAPI.- Perform signup via API with SignupFromAPI.- Avoid using it.only.- Avoid using after and aftereach in test cases.- Use multiple assertions for expect statements.- Avoid using strings for assertions.- Do not use duplicate filenames even with different paths.- Avoid using agHelper.Sleep, this.Sleep in any file in code.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-12-05T10:56:13.739Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 37984File: app/client/src/git/requests/fetchSSHKeyRequest.ts:5-9Timestamp: 2024-12-05T10:56:13.739ZLearning: In `app/client/src/git/requests/fetchSSHKeyRequest.ts`, the `fetchSSHKeyRequest` function does not require explicit error handling for `baseApplicationId`; the function should throw an error naturally if `baseApplicationId` is missing or invalid.Applied to files:
app/client/src/ce/entities/URLRedirect/URLAssembly.ts
📚 Learning: 2025-01-15T20:46:05.401Z
Learnt from: brayn003Repo: appsmithorg/appsmith PR: 38681File: app/client/src/git/requests/helpers/urlArtifactType.ts:3-12Timestamp: 2025-01-15T20:46:05.401ZLearning: In URL helper functions like `urlArtifactType`, error handling in switch statements is not required as TypeScript's compile-time checks are sufficient.Applied to files:
app/client/src/ce/entities/URLRedirect/URLAssembly.ts
📚 Learning: 2025-10-28T03:30:58.299Z
Learnt from: ashit-rathRepo: appsmithorg/appsmith PR: 41312File: app/client/src/sagas/InitSagas.ts:260-271Timestamp: 2025-10-28T03:30:58.299ZLearning: In app/client/src/sagas/InitSagas.ts, when constructing consolidatedApiParams for static page URLs, the code intentionally reuses applicationId and defaultPageId fields to pass staticApplicationSlug and staticPageSlug values respectively. This is by design, even though ConsolidatedApiParams type has dedicated staticApplicationSlug and staticPageSlug fields.Applied to files:
app/client/src/ce/entities/URLRedirect/URLAssembly.ts
🧬 Code graph analysis (4)
app/client/src/pages/workspace/index.tsx (3)
app/client/src/components/SentryRoute.tsx (1)
SentryRoute(3-3)app/client/src/pages/common/PageWrapper.tsx (1)
PageWrapper(63-89)app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
WorkspaceDatasourcesPage(72-146)
app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (4)
app/client/src/ce/selectors/entitiesSelector.ts (4)
getDatasources(86-88)getDatasourcesGroupedByPluginCategory(114-144)getPluginImages(605-623)getPlugins(90-91)app/client/src/ce/entities/FeatureFlag.ts (1)
FEATURE_FLAG(2-67)app/client/src/ce/RouteBuilder.ts (1)
workspaceDatasourceEditorURL(203-206)app/client/src/entities/Datasource/index.ts (1)
Datasource(154-162)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (4)
app/client/src/ce/selectors/entitiesSelector.ts (1)
getDatasources(86-88)app/client/src/ce/actions/workspaceIDEActions.ts (1)
initWorkspaceIDE(7-10)app/client/src/pages/workspace/WorkspaceDataSidePane.tsx (1)
WorkspaceDataSidePane(50-205)app/client/src/constants/routes/baseRoutes.ts (2)
WORKSPACE_DATASOURCES_PAGE_URL(31-31)WORKSPACE_DATASOURCE_EDITOR_PAGE_URL(32-32)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
app/client/cypress/support/commands.js (2)
_(1071-1071)workspaceId(396-396)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: perform-test / rts-build / build
- GitHub Check: perform-test / client-build / client-build
- GitHub Check: perform-test / server-build / server-unit-tests
- GitHub Check: client-lint / client-lint
- GitHub Check: client-build / client-build
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-unit-tests / client-unit-tests
🔇 Additional comments (2)
app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx (1)
35-41:LGTM - Height conflict addressed.
IDEContainernow usesflex: 1without conflictingheight: 100vh. Layout should work correctly within the parent's flex context.app/client/src/ce/entities/URLRedirect/URLAssembly.ts (1)
347-351: I'll help you verify the edge case concern in the URLAssembly.ts file. Let me search the codebase to understand how this code is called and what suffix values are actually passed.
<function_calls>
#!/bin/bashFind the URLAssembly file and understand its context
find . -type f -name "URLAssembly.ts" 2>/dev/null | head -5
</function_calls>Now let me examine the file around the lines in question:
<function_calls>
#!/bin/bashRead the URLAssembly.ts file to see the function context
wc -l app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me get the broader context of the function containing these lines:
<function_calls>
#!/bin/bashGet lines around 347-351 to understand the function
sed -n '330,365p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Now let me search for callers of this function and test cases:
<function_calls>
#!/bin/bashSearch for calls to the function that contains this logic
First, let's find what function this is in
sed -n '300,355p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | grep -n "^[[:space:]][a-zA-Z].(" | head -3
</function_calls>Let me get more context to identify the function name:
<function_calls>
#!/bin/bashGet broader context to find function definition
sed -n '320,355p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Now search for callers and test cases:
<function_calls>
#!/bin/bashSearch for places where suffix with "datasource" is used
rg -n "datasource/" app/client/src/ce/entities/URLRedirect/ -C2 --type=ts
</function_calls>Let me search for test files related to URLAssembly:
<function_calls>
#!/bin/bashSearch for test files
find . -type f -name "URLAssembly" | grep -i test
find . -type f -path "/test/" -name "URL" | head -10
find . -type f -name "*.spec.ts" | xargs grep -l "URLAssembly" 2>/dev/null | head -5
</function_calls>Let me search for how suffix is used more broadly:
<function_calls>
#!/bin/bashSearch for suffix construction and usage patterns
rg -n "suffix.*datasource" --type=ts -C3
</function_calls>Let me search for any unit tests and understand the function better:
<function_calls>
#!/bin/bashGet the entire function to understand its purpose and logic
sed -n '335,360p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me try a different approach to find tests:
<function_calls>
#!/bin/bashSearch for test files in the entire repo
find . -type f ( -name ".spec.ts" -o -name ".test.ts" ) | xargs grep -l "URLAssembly|URLRedirect" 2>/dev/null | head -10
</function_calls>Let me check what paths are actually being generated with different suffix values:
<function_calls>
#!/bin/bashLook at the full context to understand the method and its return value
sed -n '310,370p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me search for any validation or handling of empty suffix paths:
<function_calls>
#!/bin/bashSearch for any validation of suffixPath or basePath
rg -n "suffixPath" app/client/src/ce/entities/URLRedirect/URLAssembly.ts -B2 -A2
</function_calls>Let me check the complete method more systematically:
<function_calls>
#!/bin/bashGet the exact lines and some context
cat -n app/client/src/ce/entities/URLRedirect/URLAssembly.ts | sed -n '340,360p'
</function_calls>Let me look for where this method is called from:
<function_calls>
#!/bin/bashSearch for callers of this method across the codebase
rg -n "isWorkspaceContext" app/client/src/ce/entities/URLRedirect/URLAssembly.ts -B5 | head -20
</function_calls>Let me search for how datasource URLs are constructed in the codebase:
<function_calls>
#!/bin/bashSearch for datasource URL patterns
rg -n "datasource" app/client/src/ce/entities/URLRedirect/ --type=ts -B2 -A2 | head -50
</function_calls>Let me search for any tests in the repo that might test this functionality:
<function_calls>
#!/bin/bashSearch for test files
find . -type f -name ".test.ts" -o -name ".spec.ts" | xargs grep -l "datasource" 2>/dev/null | head -5
</function_calls>Let me check if there's any validation after the suffixPath is set:
<function_calls>
#!/bin/bashLook at what happens after line 351
sed -n '351,375p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me search for the complete function definition more broadly:
<function_calls>
#!/bin/bashGet lines 1-365 and search for function definition around line 347
sed -n '300,365p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | cat -n
</function_calls>Let me check the actual file to better understand the structure:
<function_calls>
#!/bin/bashCheck file size first
wc -l app/client/src/ce/entities/URLRedirect/URLAssembly.ts
Then get the problematic section with more context
sed -n '325,365p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | nl -v 325
</function_calls>Now let me search for how suffix values are passed to understand if "datasource/" alone is a realistic input:
<function_calls>
#!/bin/bashSearch for where suffix parameter comes from
rg -n "suffix\s*=" app/client/src/ce/entities/URLRedirect/URLAssembly.ts -B3 -A1
</function_calls>Let me search across the codebase for how this function is called:
<function_calls>
#!/bin/bashSearch for imports and calls to URLAssembly
rg -n "from.*URLAssembly|import.*URLAssembly" --type=ts | head -10
</function_calls>Let me search for callers of the specific function:
<function_calls>
#!/bin/bashFirst, let me understand what method this is by looking at the class structure
sed -n '1,30p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me look at the method more carefully to determine its name:
<function_calls>
#!/bin/bashGet a wider context around line 347
sed -n '280,365p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | nl -v 280
</function_calls>Let me search for the actual method definition:
<function_calls>
#!/bin/bashUse ast-grep to find methods containing this pattern
ast-grep --pattern 'getWorkspaceUrl($$$) { $$$ }'
</function_calls>Let me try a more direct approach to understand the method:
<function_calls>
#!/bin/bashSearch for method declarations around this area
sed -n '250,365p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | grep -n "^\s*[a-zA-Z].*(" | tail -5
</function_calls>Let me get the raw file and analyze it properly:
<function_calls>
#!/bin/bashGet the complete context with better structure
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts', 'r') as f:
lines = f.readlines()Print lines 340-365 with context
for i in range(339, min(365, len(lines))):
print(f"{i+1:4d}: {lines[i]}", end='')Also find the method name by looking backwards
print("\n\n--- Finding method name ---")
for i in range(346, 200, -1):
if 'function ' in lines[i] or '(' in lines[i] and ')' in lines[i]:
print(f"{i+1:4d}: {lines[i]}", end='')
if 'function ' in lines[i] or (i > 0 and ')' in lines[i]):
break
EOF
</function_calls>Now let me search for test cases and how this is used:
<function_calls>
#!/bin/bashSearch for any test files related to URLAssembly
find . -type f ( -name ".test.ts" -o -name ".spec.ts" ) -exec grep -l "URLAssembly|datasource/" {} ; 2>/dev/null | head -5
</function_calls>Let me search for actual usage of the problematic suffix pattern:
<function_calls>
#!/bin/bashSearch for all references to getRedirectUrl or similar methods
rg -n "getRedirectUrl|getWorkspaceUrl" --type=ts | head -20
</function_calls>Let me check what happens with the constructed paths:
<function_calls>
#!/bin/bashSearch for where basePath + suffixPath is used
rg -n "basePath.*suffixPath|suffixPath.*basePath|${.*suffixPath" --type=ts -C2 | head -40
</function_calls>Let me look at the complete function implementation:
<function_calls>
#!/bin/bashGet context to understand the return statement
sed -n '330,390p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Now let me verify if there are any tests that exercise this code path:
<function_calls>
#!/bin/bashSearch recursively for test files that might test this
find app -type f ( -name ".spec.ts" -o -name ".test.ts" ) -exec grep -l "datasource|URLAssembly" {} ; 2>/dev/null
</function_calls>Let me check if there's a tests directory:
<function_calls>
#!/bin/bashSearch for test files
find . -type d -name "tests" -o -type d -name "tests" -o -type d -name "test" 2>/dev/null | head -10
</function_calls>Let me look for any documentation or comments about this behavior:
<function_calls>
#!/bin/bashGet the full method with comments
sed -n '300,390p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me use a more focused Python approach to analyze the code:
<function_calls>
#!/bin/bash
python3 << 'EOF'
import rewith open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts', 'r') as f:
content = f.read()
lines = content.split('\n')Find the section around line 347
print("=" * 70)
print("SECTION AROUND LINES 347-351:")
print("=" * 70)
for i in range(300, min(400, len(lines))):
marker = " >>> " if 347 <= i+1 <= 351 else " "
print(f"{marker}{i+1:4d}: {lines[i]}")Find the method this belongs to
print("\n" + "=" * 70)
print("SEARCHING FOR METHOD DEFINITION:")
print("=" * 70)
for i in range(346, 200, -1):
if re.search(r'\b(public|private|protected|async)?\s+\w+\s*(', lines[i]):
# Print a few lines around the method declaration
for j in range(max(0, i-2), min(len(lines), i+3)):
print(f"{j+1:4d}: {lines[j]}")
breakEOF
</function_calls>Now let me search for where this might be called from and test cases:
<function_calls>
#!/bin/bashSearch for references to this function
rg -n "getRedirectUrl" app/client/src/ce/entities/URLRedirect/ --type=ts
rg -n "URLAssembly" app/client/src --type=ts | head -20
</function_calls>Let me check if there's validation or handling of empty paths:
<function_calls>
#!/bin/bashLook for any URL validation or joining logic
sed -n '340,400p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | cat -n
</function_calls>Let me check what the full return statement looks like:
<function_calls>
#!/bin/bashGet lines 340-395 to see the complete logic flow
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts') as f:
lines = f.readlines()Get lines 340-395
for i in range(339, min(395, len(lines))):
print(f"{i+1:4d}: {lines[i]}", end='')
EOF
</function_calls>Let me search across the entire codebase to understand how suffix values are formed:
<function_calls>
#!/bin/bashSearch for patterns that construct "datasource/" strings
rg -n "datasource.*/" --type=ts | grep -v node_modules | head -30
</function_calls>Let me look for the actual usage pattern and what suffix contains:
<function_calls>
#!/bin/bashSearch for how the function is called - passing suffix parameter
rg -n "getRedirectUrl.*datasource" --type=ts -B2 -A2
</function_calls>Let me check what the actual return looks like:
<function_calls>
#!/bin/bashLook for the return statement in the method
sed -n '340,410p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | grep -n "return|basePath.*suffixPath"
</function_calls>Let me get the complete method implementation more carefully:
<function_calls>
#!/bin/bashGet full context
cat -n app/client/src/ce/entities/URLRedirect/URLAssembly.ts | sed -n '325,380p'
</function_calls>Now let me verify the actual concern by checking if an empty string after replace would cause issues:
<function_calls>
#!/bin/bashSimulate what happens with "datasource/" input
python3 << 'EOF'
Simulate the logic from lines 347-351
suffix = "datasource/"
if suffix and suffix.startswith("datasource/"):
# This is what the code does
result = suffix.replace("datasource/", "")
print(f"Input suffix: '{suffix}'")
print(f"After replace: '{result}'")
print(f"suffixPath would be: '/{result}'")
print(f"Result length: {len(result)}")
print(f"Is empty: {result == ''}")# This would produce a path like:print(f"\nFinal path would be: /workspace/xxx/datasource/{result}")print(f"Which is: /workspace/xxx/datasource/")print("\n---Other examples---")
suffix2 = "datasource/columns"
result2 = suffix2.replace("datasource/", "")
print(f"If suffix = '{suffix2}', result = '{result2}', path = /workspace/xxx/datasource/{result2}")EOF
</function_calls>Let me read the actual URL assembly to understand the final result:
<function_calls>
#!/bin/bashGet lines right after 351 to see how URL is assembled
sed -n '347,365p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | cat -n -v
</function_calls>Let me search for all test files in the repository:
<function_calls>
#!/bin/bashFind all test files
find . -type f ( -name ".test.ts" -o -name ".spec.ts" ) 2>/dev/null | wc -l
Find tests related to URL or datasource
find . -type f ( -name ".test.ts" -o -name ".spec.ts" ) -exec grep -l "URLAssembly|getRedirectUrl" {} ; 2>/dev/null
</function_calls>Let me check if there's any special handling or middleware that processes URLs:
<function_calls>
#!/bin/bashSearch for URL validation or sanitization
rg -n "URL|path.*validate|trailing.*slash|normaliz" app/client/src/ce/entities/URLRedirect/ --type=ts | head -20
</function_calls>Let me check the exact lines and what comes after:
<function_calls>
#!/bin/bashGet exact lines from file
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts') as f:
lines = f.readlines()Lines 345-375
for i in range(344, min(375, len(lines))):
print(f"{i+1:3d}: {lines[i]}", end='')
EOF
</function_calls>Now let me search for how these URLs are actually used downstream:
<function_calls>
#!/bin/bashSearch for any URL normalization or cleaning
rg -n "replace.*/|normalize|trailing" --type=ts app/client/src/ce/entities/URLRedirect/ -C2 | head -40
</function_calls>Let me check the actual file structure more carefully:
<function_calls>
#!/bin/bashUse grep to find the exact method and surrounding context
grep -n "isWorkspaceContext" app/client/src/ce/entities/URLRedirect/URLAssembly.ts -B10 -A15
</function_calls>Perfect! Now let me understand what getRedirectUrl does and how this is actually used:
<function_calls>
#!/bin/bashGet the complete function definition
grep -n "getRedirectUrl|getWorkspaceUrl" app/client/src/ce/entities/URLRedirect/URLAssembly.ts -B2 -A25 | head -60
</function_calls>Now let me look for where this is actually called with datasource suffix:
<function_calls>
#!/bin/bashSearch for calls to the method
rg -n "getRedirectUrl|URLAssembly" app/client/src --type=ts | grep -v "node_modules|URLAssembly.ts:" | head -20
</function_calls>Let me search for datasource-related URL patterns:
<function_calls>
#!/bin/bashSearch for how datasource paths are constructed
rg -n "datasource/|workspace.*datasource" app/client/src --type=ts | head -30
</function_calls>Let me check if there are any tests by searching more broadly:
<function_calls>
#!/bin/bashSearch for test files and mock data
find . -type f -name "*.mock.ts" -o -name "fixture" -o -name "mock" 2>/dev/null | grep -i url | head -10
</function_calls>Let me look at the actual implementation to understand what basePath + suffixPath produces:
<function_calls>
#!/bin/bashGet lines 347-370 to see the complete URL construction
sed -n '345,375p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Now let me verify if the behavior mentioned in the review is correct by searching for the complete function:
<function_calls>
#!/bin/bashGet more lines to understand the complete method
sed -n '300,400p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | head -100
</function_calls>Let me take a different approach and look for imports and usage of this function:
<function_calls>
#!/bin/bashCheck what's exported from this file
grep -n "export|import" app/client/src/ce/entities/URLRedirect/URLAssembly.ts | head -20
</function_calls>Now let me check for any callers of the functions in this file:
<function_calls>
#!/bin/bashSearch for who calls URLAssembly
rg -n "new URLAssembly|URLAssembly(|from.*URLAssembly" app/client/src --type=ts | head -15
</function_calls>Let me check if the suffix can actually be just "datasource/":
<function_calls>
#!/bin/bashSearch for where suffix parameter is set or passed
rg -n "suffix\s*[=:]|suffix)" app/client/src/ce/entities/URLRedirect/URLAssembly.ts -B2 -A1 | head -40
</function_calls>Let me look at the complete method definition one more time with better context:
<function_calls>
#!/bin/bash
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts') as f:
content = f.read()
lines = content.split('\n')Find the complete getRedirectUrl or similar method
in_method = False
method_start = 0
for i, line in enumerate(lines):
if 'isWorkspaceContext' in line and '&&' in line:
# Found the line in question, now trace back to find the method start
for j in range(i, -1, -1):
if re.search(r'\bpublic|private|protected\s+\w+\s*([^)])\s[:{]', lines[j]) or (j > 0 and ')' in lines[j] and not '{' in lines[j]):
method_start = j
break
# Now print from method start to find the end
print(f"METHOD STARTING AT LINE {method_start + 1}:")
for k in range(method_start, min(i+25, len(lines))):
marker = ">>>" if i == k else " "
print(f"{marker} {k+1:4d}: {lines[k]}")
breakimport re
EOF
</function_calls>Let me just directly read the section and analyze it:
<function_calls>
#!/bin/bashGet the exact section that concerns us
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts') as f:
lines = f.readlines()Show lines 325-375
print("COMPLETE CONTEXT (lines 325-375):")
print("=" * 80)
for i in range(324, min(375, len(lines))):
marker = ">>>" if 346 <= i < 351 else " "
print(f"{marker} {i+1:4d}: {lines[i]}", end='')
EOF
</function_calls>Now let me search for what happens after the suffixPath is set to understand the final URL:
<function_calls>
#!/bin/bashCheck what the method returns
sed -n '347,385p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Perfect! Now I have the context. Let me verify if this is actually an issue by checking if suffix can be "datasource/":
<function_calls>
#!/bin/bashSearch for all calls and suffix construction patterns
rg -n "datasource/" --type=ts app/client/src | head -40
</function_calls>Now let me search for whether there's any guard condition or validation that prevents empty suffixes:
<function_calls>
#!/bin/bashCheck if there are any guards for empty suffix
grep -n "suffix|basePath.*suffixPath|return.*basePath" app/client/src/ce/entities/URLRedirect/URLAssembly.ts | grep -A2 -B2 "347:|348:|349:|350:|351:|352:"
</function_calls>Let me get the return statement and understand the final URL:
<function_calls>
#!/bin/bashGet the complete function to see what's returned
sed -n '347,380p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | cat -n
</function_calls>Let me look for tests in the codebase:
<function_calls>
#!/bin/bashFind test files related to URL
find . -path "/node_modules" -prune -o -type f ( -name ".test.ts" -o -name "*.spec.ts" ) -print | xargs grep -l "getRedirectUrl|URLAssembly" 2>/dev/null
</function_calls>Let me check the exact return statement more carefully:
<function_calls>
#!/bin/bashGet what's returned from the method
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts') as f:
lines = f.readlines()Find the return statement after line 351
for i in range(350, min(375, len(lines))):
line = lines[i]
if 'return' in line or 'basePath' in line and 'suffixPath' in line:
# Print context
for j in range(max(0, i-2), min(len(lines), i+3)):
marker = ">>>" if i == j else " "
print(f"{marker} {j+1:4d}: {lines[j]}", end='')
print()
EOF
</function_calls>Now let me verify the complete logic by understanding what URL is constructed:
<function_calls>
#!/bin/bashGet lines 360-375 to see the return
sed -n '360,375p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Let me check the method name and see if there are any tests:
<function_calls>
#!/bin/bashFind the method name by looking at the function definition
sed -n '320,350p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | grep -n "getRedirectUrl|getWorkspaceUrl|function|^\s*[a-z].*("
</function_calls>Based on my investigation, let me now gather information on whether this is actually problematic:
<function_calls>
#!/bin/bashSearch for test cases that specifically test the datasource path
rg -n "datasource.*suffix|suffix.*datasource" --type=ts | head -20
</function_calls>Let me verify if the edge case is realistic by checking how suffix is constructed in the callers:
<function_calls>
#!/bin/bashLook for URLAssembly instantiation and method calls
rg -n ".getRedirectUrl|new URLAssembly" app/client/src --type=ts -A3 -B1 | head -50
</function_calls>Now let me check if there's documentation on what valid suffix values are:
<function_calls>
#!/bin/bashLook for JSDoc or comments explaining the parameters
sed -n '310,350p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | grep -E "^\s*//|^\s*/*|*/\s*$|@param|@returns"
</function_calls>Let me check the complete structure of the file:
<function_calls>
#!/bin/bashGet a complete picture of the method
sed -n '320,375p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts
</function_calls>Based on all my searches, let me now verify the actual concern by checking if there's any validation. Let me look for tests one more time:
<function_calls>
#!/bin/bashSearch for test files that might test URLAssembly
find . -path "/node_modules" -prune -o -type f -name ".test.ts" -o -name "*.spec.ts" | head -20 | xargs grep -l "URLAssembly|getRedirectUrl" 2>/dev/null | head -3
</function_calls>Let me understand whether the concern is valid by analyzing the code logic once more:
<function_calls>
#!/bin/bash
python3 << 'EOF'Let's trace through the logic as described in the review
The code (lines 347-351):
if (this.isWorkspaceContext() && suffix?.startsWith("datasource/")) {
basePath =
/workspace/${entityId}/datasource;suffixPath =
/${suffix.replace("datasource/", "")};}
Scenario 1: suffix = "datasource/"
suffix1 = "datasource/"
if suffix1.startswith("datasource/"):
base = "/workspace/123/datasource"
suffix_result = suffix1.replace("datasource/", "")
suffix_path = f"/{suffix_result}"
print(f"Scenario 1: suffix = '{suffix1}'")
print(f" basePath = '{base}'")
print(f" suffixPath = '{suffix_path}'")
print(f" Result = '{base}{suffix_path}'")
print()Scenario 2: suffix = "datasource/columns"
suffix2 = "datasource/columns"
if suffix2.startswith("datasource/"):
base = "/workspace/123/datasource"
suffix_result = suffix2.replace("datasource/", "")
suffix_path = f"/{suffix_result}"
print(f"Scenario 2: suffix = '{suffix2}'")
print(f" basePath = '{base}'")
print(f" suffixPath = '{suffix_path}'")
print(f" Result = '{base}{suffix_path}'")
print()The concern is that scenario 1 produces a trailing slash with nothing after it
print("CONCERN ANALYSIS:")
print("If suffix = 'datasource/', then suffixPath = '/' (empty content between slashes)")
print("This creates a URL with redundant trailing slash")EOF
</function_calls>Let me find the actual callers of this method to understand what suffix values are passed:
<function_calls>
#!/bin/bashSearch for all usages of getRedirectUrl method
rg -n "getRedirectUrl" app/client/src --type=ts -B3 -A3 | grep -v "node_modules"
</function_calls>Now let me check if there's any URL normalization logic:
<function_calls>
#!/bin/bashSearch for URL normalization or trailing slash handling
rg -n "replace.*/$|trailing|normalize.*url|//" app/client/src/ce/entities/URLRedirect/ --type=ts | head -20
</function_calls>Let me now verify this is actually part of a real method by checking the context one final time:
<function_calls>
#!/bin/bashGet complete method with all details
sed -n '310,380p' app/client/src/ce/entities/URLRedirect/URLAssembly.ts | nl -v 310
</function_calls>Now let me search for where the getRedirectUrl is actually called with what parameters:
<function_calls>
#!/bin/bashSearch for all calls to this method in the codebase
find app -name ".ts" -type f ! -path "/node_modules/*" | xargs grep -n "getRedirectUrl|URLAssembly()" 2>/dev/null | head -15
</function_calls>Based on all my research, let me now provide the final verification. The concern appears to be about a potential edge case. Let me verify if this is even a realistic scenario by checking the code flow one more time and looking for any guards:
<function_calls>
#!/bin/bashFinal check: Get the complete method and analyze edge cases
python3 << 'EOF'
with open('app/client/src/ce/entities/URLRedirect/URLAssembly.ts') as f:
lines = f.readlines()print("COMPLETE METHOD CONTEXT (lines 310-385):")
print("=" * 80)
for i in range(309, min(385, len(lines))):
marker = ">>>" if 346 <= i < 351 else " "
print(f"{marker} {i+1:4d}: {lines[i]}", end='')Analyze the logic
print("\n" + "=" * 80)
print("EDGE CASE ANALYSIS:")
print("=" * 80)
print("If suffix = 'datasource/':")
print(" - Line 348: basePath =/workspace/${entityId}/datasource")
print(" - Line 349: suffixPath =/${suffix.replace('datasource/', '')}")
print(" - suffix.replace('datasource/', '') = '' (empty string)")
print(" - suffixPath = '/' (slash + empty = just slash)")
print(" - This produces a path with trailing slash only")
EOF
</function_calls>Based on my thorough investigation of the codebase, I have gathered sufficient evidence to conclude my verification. The review comment identifies a valid edge case in the code. Let me provide the final rewritten review comment:
Edge case: If suffix is exactly "datasource/", the replace produces an empty suffixPath, resulting in a path like
/workspace/xxx/datasource/with a trailing slash and no content after it.Consider adding a guard to ensure
suffixcontains additional content beyond the "datasource/" prefix, or document whether this edge case is intentionally acceptable.if (this.isWorkspaceContext() && suffix?.startsWith("datasource/")) { // For workspace datasource URLs, use singular /datasource path basePath = `/workspace/${entityId}/datasource`; suffixPath = `/${suffix.replace("datasource/", "")}`; }
| // Open the workspace menu (triple dot) and click the Datasources option | ||
| _.homePage.OpenWorkspaceOptions(workspaceId); | ||
| agHelper.GetNClickByContains(".workspace-menu-item","Datasources"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Replace class selector with data-testid attribute.
The.workspace-menu-item class selector violates the guideline to use data-* attributes for selectors. Consider using a data-testid attribute instead.
Based on coding guidelines: "Use data-* attributes for selectors" and "Avoid CSS path."
Apply this diff:
- agHelper.GetNClickByContains(".workspace-menu-item", "Datasources");+ agHelper.GetNClickByContains("[data-testid='workspace-menu-item']", "Datasources");
📝 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.
| agHelper.GetNClickByContains(".workspace-menu-item","Datasources"); | |
| agHelper.GetNClickByContains("[data-testid='workspace-menu-item']","Datasources"); |
🤖 Prompt for AI Agents
Inapp/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.tsaround line 22, replace the CSS class selector usage with a data-testidattribute selector; update the call so it targets the element by data-testid(e.g. '[data-testid="workspace-menu-item"]') instead of ".workspace-menu-item"while keeping the same visible text "Datasources" so theagHelper.GetNClickByContains invocation continues to click the correct item.| _.homePage.CreateNewWorkspace(workspaceId); | ||
| _.homePage.OpenWorkspaceOptions(workspaceId); | ||
| agHelper.GetNClickByContains(".workspace-menu-item","Datasources"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Replace class selector with data-testid attribute.
The.workspace-menu-item class selector violates the guideline to use data-* attributes for selectors.
Based on coding guidelines: "Use data-* attributes for selectors."
Apply this diff:
- agHelper.GetNClickByContains(".workspace-menu-item", "Datasources");+ agHelper.GetNClickByContains("[data-testid='workspace-menu-item']", "Datasources");
📝 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.
| agHelper.GetNClickByContains(".workspace-menu-item","Datasources"); | |
| agHelper.GetNClickByContains("[data-testid='workspace-menu-item']","Datasources"); |
🤖 Prompt for AI Agents
Inapp/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.tsaround line 49, replace the class-based selector ".workspace-menu-item" with adata-testid attribute selector (e.g. data-testid="workspace-menu-item") whencalling agHelper.GetNClickByContains so the test uses data-* attributes forelement targeting; update the selector string accordingly and ensure the targetelement in the app has the matching data-testid attribute.| cy.contains("Configurations").should("be.visible"); | ||
| cy.contains("button", "Edit").should("be.visible"); | ||
| cy.wait(100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Remove arbitrary waits before enabling these tests.
The commented-out tests containcy.wait(100) calls, which explicitly violate the guideline: "Avoid using cy.wait in code." These arbitrary waits introduce non-deterministic behavior and should be replaced with proper waits for elements, network requests, or application state.
Based on coding guidelines and learnings: "Avoid using cy.wait in code" and "Avoid using agHelper.Sleep, this.Sleep in any file in code."
Before enabling these tests, replace the arbitrary waits with appropriate assertions or aliased route waits:
- cy.wait(100);- cy.get(".t--add-datasource-button").first().click({ force: true });+ cy.get(".t--add-datasource-button").first().should("be.visible").click({ force: true });
Also applies to: 174-174
| constdatasources=useSelector(getDatasources); | ||
| constgroupedDatasources=useSelector(getDatasourcesGroupedByPluginCategory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash# First, find the getDatasources selector definitionrg -n"export.*getDatasources|function getDatasources|const getDatasources" --type=ts --type=tsx -A 5
Repository: appsmithorg/appsmith
Length of output: 91
🏁 Script executed:
#!/bin/bash# Also check the WorkspaceDataSidePane component to understand its contextfd -t f"WorkspaceDataSidePane.tsx" --exec head -100 {}
Repository: appsmithorg/appsmith
Length of output: 3614
🏁 Script executed:
#!/bin/bash# Search for workspace-filtered datasource selectorsrg -n"workspace.*datasources|getDatasources.*workspace" --type=ts --type=tsx -C 2
Repository: appsmithorg/appsmith
Length of output: 91
🏁 Script executed:
#!/bin/bash# Search for getDatasources selector definition - broader searchrg -n"export.*getDatasources|const getDatasources" -A 5| head -50
Repository: appsmithorg/appsmith
Length of output: 2839
🏁 Script executed:
#!/bin/bash# Find the selectors filefd -t f"entitiesSelector"| head -10
Repository: appsmithorg/appsmith
Length of output: 159
🏁 Script executed:
#!/bin/bash# Search for workspace-filtered datasource patternsrg -n"workspaceId.*datasource|datasource.*workspaceId" -C 2| head -60
Repository: appsmithorg/appsmith
Length of output: 5033
🏁 Script executed:
#!/bin/bash# Check the EE version of entitiesSelector for workspace-filtered selectorscat app/client/src/ee/selectors/entitiesSelector.ts| head -150
Repository: appsmithorg/appsmith
Length of output: 110
🏁 Script executed:
#!/bin/bash# Look for workspace-filtered datasource selectors in the full codebaserg -n"workspace.*getDatasources|workspaceId.*filter.*datasource" -C 3| head -80
Repository: appsmithorg/appsmith
Length of output: 46
🏁 Script executed:
#!/bin/bash# Check the full WorkspaceDataSidePane to see how datasources are renderedsed -n'50,150p' app/client/src/pages/workspace/WorkspaceDataSidePane.tsx
Repository: appsmithorg/appsmith
Length of output: 3239
🏁 Script executed:
#!/bin/bash# Get the rest of the WorkspaceDataSidePane rendering to see how datasources are filteredsed -n'130,200p' app/client/src/pages/workspace/WorkspaceDataSidePane.tsx
Repository: appsmithorg/appsmith
Length of output: 2347
🏁 Script executed:
#!/bin/bash# Check if there's any filtering of datasources in render logicrg -n"datasources.*filter|groupedDatasources.*filter" app/client/src/pages/workspace/WorkspaceDataSidePane.tsx -C 2
Repository: appsmithorg/appsmith
Length of output: 46
🏁 Script executed:
#!/bin/bash# Check if workspaceId is used anywhere to filter data in this filerg -n"workspaceId" app/client/src/pages/workspace/WorkspaceDataSidePane.tsx -C 1
Repository: appsmithorg/appsmith
Length of output: 761
🏁 Script executed:
#!/bin/bash# Find datasource reducer/actions to understand how data is loadedfd -t f"datasource.*reducer\|datasource.*slice\|datasource.*action" --type f| grep -E"(reducer|slice|action)"| head -10
Repository: appsmithorg/appsmith
Length of output: 46
🏁 Script executed:
#!/bin/bash# Search for where getDatasources is used to understand expected behaviorrg -n"getDatasources\(" -B 2 -A 2| head -100
Repository: appsmithorg/appsmith
Length of output: 5236
🏁 Script executed:
#!/bin/bash# Check if workspace filtering happens at API/data-loading levelrg -n"workspaceId.*datasource|fetchDatasources.*workspace" -C 2| head -80
Repository: appsmithorg/appsmith
Length of output: 11998
Based on my verification, the original review comment's concern iscorrect. Here's what I found:
getDatasources selector (line 86-88 of
app/client/src/ce/selectors/entitiesSelector.ts) returnsstate.entities.datasources.list- ALL datasources in Redux state without any workspace filtering.WorkspaceDataSidePane component receives
workspaceIdas a prop but uses it only for navigation URLs, not for filtering datasources.No filtering in component render logic - The component displays
groupedDatasourcesdirectly, which derives from the unfilteredgetDatasourcesselector.Datasource model includes workspaceId - Server-side code shows datasources have a
workspaceIdfield and the backend supportsgetAllByWorkspaceIdWithStorages()for workspace-scoped queries.Unfiltered display - All datasources in Redux state are displayed, regardless of which workspace page is active.
This is a legitimate data scoping issue where the component displays all datasources instead of filtering to only those belonging to the current workspace.
Datasources are not filtered by workspace in this component.
getDatasources returns all datasources in Redux state without workspace filtering. Since the component has access toworkspaceId, it should filter to workspace-scoped datasources before display.
Consider filtering byworkspaceId:
- const datasources = useSelector(getDatasources);+ const datasources = useSelector(getDatasources).filter(+ (ds) => ds.workspaceId === workspaceId+ );
Or create a workspace-specific selector in the selectors file.
📝 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.
| constdatasources=useSelector(getDatasources); | |
| constgroupedDatasources=useSelector(getDatasourcesGroupedByPluginCategory); | |
| constdatasources=useSelector(getDatasources).filter( | |
| (ds)=>ds.workspaceId===workspaceId | |
| ); | |
| constgroupedDatasources=useSelector(getDatasourcesGroupedByPluginCategory); |
🤖 Prompt for AI Agents
In app/client/src/pages/workspace/WorkspaceDataSidePane.tsx around lines 55-56,the component uses getDatasources and getDatasourcesGroupedByPluginCategorywhich return all datasources from Redux (not workspace-scoped), so the UI showsdatasources from all workspaces; update the component to scope datasources tothe passed workspaceId by either (a) creating new selectors (e.g.,getDatasourcesByWorkspaceId andgetDatasourcesGroupedByPluginCategoryByWorkspace) that filterstate.entities.datasources.list by datasource.workspaceId, then use thoseselectors here, or (b) select the full list and apply a local filter byworkspaceId before grouping and rendering; ensure all downstream grouping/propsuse the filtered list so only datasources for the current workspace are shown.| constWorkspaceDatasourceDefaultView=()=>{ | ||
| constdatasources=useSelector(getDatasources); | ||
| if(!datasources||datasources.length===0){ | ||
| return<DatasourceBlankState/>; | ||
| } | ||
| return<CreateNewDatasourceTab/>; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Same workspace-scoping issue applies here.
WorkspaceDatasourceDefaultView usesgetDatasources which returns all datasources, not workspace-filtered. Should align with workspace context filtering.
Consider passingworkspaceId to filter or use a workspace-scoped selector.
🤖 Prompt for AI Agents
In app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx around lines 62to 70, the component uses the global getDatasources selector which returns alldatasources instead of only those for the current workspace; change it to use aworkspace-scoped datasource list (either call a selector that acceptsworkspaceId or filter the results by the current workspaceId). Retrieve thecurrent workspaceId from existing workspace context/selector (e.g., useParams orgetCurrentWorkspaceId) and then either switch to a selector likegetDatasourcesForWorkspace(workspaceId) or apply a filter on getDatasources() bycomparing datasource.workspaceId === workspaceId, and update the conditionalrendering to rely on that filtered list.| useEffect(()=>{ | ||
| if(!currentWorkspace){ | ||
| dispatch(fetchAllWorkspaces({ workspaceId,fetchEntities:true})); | ||
| } | ||
| },[currentWorkspace,dispatch,workspaceId]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Potential infinite fetch loop if workspace fetch fails.
IffetchAllWorkspaces fails,currentWorkspace remains undefined, triggering repeated fetches. Add a guard or loading state check.
+ const isFetchingWorkspaces = useSelector(+ (state: DefaultRootState) => state.ui.workspaces.isFetchingAllWorkspaces+ );+ useEffect(() => {- if (!currentWorkspace) {+ if (!currentWorkspace && !isFetchingWorkspaces) { dispatch(fetchAllWorkspaces({ workspaceId, fetchEntities: true })); }- }, [currentWorkspace, dispatch, workspaceId]);+ }, [currentWorkspace, dispatch, workspaceId, isFetchingWorkspaces]);
🤖 Prompt for AI Agents
In app/client/src/pages/workspace/WorkspaceDatasourcesPage.tsx around lines 97to 101, the useEffect will repeatedly dispatch fetchAllWorkspaces whencurrentWorkspace is undefined (e.g., after a failed fetch), causing a potentialinfinite fetch loop; modify the logic to also check a loading/fetching or errorflag (or a local ref that marks that a fetch attempt is in progress/completed)before dispatching so the effect only triggers when no fetch is active and noprior failed attempt exists, and set/update that flag on fetchstart/finish/error to prevent repeated retries unless a user action triggers aretry.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (5)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (5)
76-76:Replace class selector with data-testid attribute.The
.workspace-menu-itemclass selector violates the guideline to use data-* attributes for selectors.Based on coding guidelines: "Use data-* attributes for selectors."
Apply this diff:
- agHelper.GetNClickByContains(".workspace-menu-item", "Datasources");+ agHelper.GetNClickByContains("[data-testid='workspace-menu-item']", "Datasources");
125-125:Replace class selector with data-testid attribute.The
.workspace-menu-itemclass selector violates the guideline to use data-* attributes for selectors.Based on coding guidelines: "Use data-* attributes for selectors."
Apply this diff:
- agHelper.GetNClickByContains(".workspace-menu-item", "Datasources");+ agHelper.GetNClickByContains("[data-testid='workspace-menu-item']", "Datasources");
165-165:Replace class selector with data-testid attribute.The
.workspace-menu-itemclass selector violates the guideline to use data-* attributes for selectors.Based on coding guidelines: "Use data-* attributes for selectors."
Apply this diff:
- agHelper.GetNClickByContains(".workspace-menu-item", "Datasources");+ agHelper.GetNClickByContains("[data-testid='workspace-menu-item']", "Datasources");
174-176:Remove arbitrary wait and replace ID selector with data-testid.The
cy.wait(100)arbitrary wait combined withforce: truesuggests a synchronization issue. Additionally, the ID selector#new-integrations-wrappershould be replaced with a data-testid attribute.Based on coding guidelines: "Avoid using cy.wait in code" and "Use data-* attributes for selectors."
Apply this diff to wait for the element properly and use data-testid:
- cy.wait(100);- cy.get(".t--add-datasource-button").first().click({ force: true });- cy.get("#new-integrations-wrapper").should("be.visible");+ cy.get(".t--add-datasource-button").first().should("be.visible").click();+ cy.get("[data-testid='new-integrations-wrapper']").should("be.visible");
91-93:Remove arbitrary wait and replace ID selector with data-testid.The
cy.wait(100)arbitrary wait combined withforce: truesuggests a synchronization issue. Additionally, the ID selector#new-integrations-wrappershould be replaced with a data-testid attribute.Based on coding guidelines: "Avoid using cy.wait in code" and "Use data-* attributes for selectors."
Apply this diff to wait for the element properly and use data-testid:
- cy.wait(100);- cy.get(".t--add-datasource-button").first().click({ force: true });- cy.get("#new-integrations-wrapper").should("be.visible");+ cy.get(".t--add-datasource-button").first().should("be.visible").click();+ cy.get("[data-testid='new-integrations-wrapper']").should("be.visible");
🧹 Nitpick comments (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
193-200:Consider using data-testid attributes for header input fields.The complex attribute selectors
.t--headers-array input[name$='.key']and.t--headers-array input[name$='.value']could be more robust and maintainable with data-testid attributes.Based on coding guidelines: "Use data-* attributes for selectors."
Consider updating the header input components to include data-testid attributes:
- cy.get(".t--headers-array input[name$='.key']")+ cy.get("[data-testid='header-key-input']") .first() .clear({ force: true }) .type("Content-Type", { delay: 0 });- cy.get(".t--headers-array input[name$='.value']")+ cy.get("[data-testid='header-value-input']") .first() .clear({ force: true }) .type("application/json", { delay: 0 });
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/client/cypress/**/**.*
⚙️ CodeRabbit configuration file
app/client/cypress/**/**.*: Review the following e2e test code written using the Cypress test library. Ensure that:
- Follow best practices for Cypress code and e2e automation.
- Avoid using cy.wait in code.
- Avoid using cy.pause in code.
- Avoid using agHelper.sleep().
- Use locator variables for locators and do not use plain strings.
- Use data-* attributes for selectors.
- Avoid Xpaths, Attributes and CSS path.
- Avoid selectors like .btn.submit or button[type=submit].
- Perform logins via API with LoginFromAPI.
- Perform logout via API with LogOutviaAPI.
- Perform signup via API with SignupFromAPI.
- Avoid using it.only.
- Avoid using after and aftereach in test cases.
- Use multiple assertions for expect statements.
- Avoid using strings for assertions.
- Do not use duplicate filenames even with different paths.
- Avoid using agHelper.Sleep, this.Sleep in any file in code.
Files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
🧠 Learnings (12)
📚 Learning: 2025-11-05T12:56:49.249Z
Learnt from: vsvamsi1Repo: appsmithorg/appsmith PR: 41363File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts:0-0Timestamp: 2025-11-05T12:56:49.249ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 4-6 depend on state (`page1Slug`, `page2Slug`) set in Tests 2-3. The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-10-08T15:32:34.115ZLearning: Learnt from: sagar-qa007PR: appsmithorg/appsmith#34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-07-16T06:44:55.118ZLearning: Avoid using sleep functions like `agHelper.Sleep`, `this.Sleep`, and other related sleep functions in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2025-11-05T12:58:32.486Z
Learnt from: vsvamsi1Repo: appsmithorg/appsmith PR: 41363File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts:32-225Timestamp: 2025-11-05T12:58:32.486ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 2-5 depend on state from previous tests (e.g., slug values modified in earlier tests). The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-07-24T08:29:41.208Z
Learnt from: abhishek-bandameediRepo: appsmithorg/appsmith PR: 35133File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBox2_spec.js:0-0Timestamp: 2024-07-24T08:29:41.208ZLearning: In Cypress tests for the Appsmith project, ensure the use of locator variables for selectors and include multiple assertions for comprehensive testing.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-11-13T09:07:54.931Z
Learnt from: vhemeryRepo: appsmithorg/appsmith PR: 37371File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js:44-47Timestamp: 2024-11-13T09:07:54.931ZLearning: When reviewing code in `app/client/cypress/**` paths, ensure that suggestions are appropriate for test code and not for `src` code. Avoid applying source code checks to test code unless relevant.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-11-13T09:11:36.959Z
Learnt from: vhemeryRepo: appsmithorg/appsmith PR: 37371File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37Timestamp: 2024-11-13T09:11:36.959ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:39.374Z
Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-10-08T15:32:39.374ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.114Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settingsTe_Spec.ts:33-33Timestamp: 2024-10-08T15:32:34.114ZLearning: Follow best practices for Cypress code and e2e automation:- Avoid using cy.wait in code.- Avoid using cy.pause in code.- Avoid using agHelper.sleep().- Use locator variables for locators and do not use plain strings.- Use data-* attributes for selectors.- Avoid Xpaths, Attributes, and CSS path.- Avoid selectors like .btn.submit or button[type=submit].- Perform logins via API with LoginFromAPI.- Perform logout via API with LogOutviaAPI.- Perform signup via API with SignupFromAPI.- Avoid using it.only.- Avoid using after and aftereach in test cases.- Use multiple assertions for expect statements.- Avoid using strings for assertions.- Do not use duplicate filenames even with different paths.- Avoid using agHelper.Sleep, this.Sleep in any file in code.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:39.374Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 35412File: app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/mysql_spec.ts:99-99Timestamp: 2024-10-08T15:32:39.374ZLearning: In Cypress tests within the `app/client/cypress` directory, avoid using `agHelper.Sleep`, `this.Sleep`, and other related sleep functions to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable. Instead, use Cypress methods like `cy.get()`, `cy.contains()`, and `cy.intercept()` to wait for specific conditions.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-08-06T05:39:47.929Z
Learnt from: ApekshaBhosaleRepo: appsmithorg/appsmith PR: 35412File: app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/mysql_spec.ts:99-99Timestamp: 2024-08-06T05:39:47.929ZLearning: In Cypress tests, avoid using `agHelper.Sleep` as it can lead to flaky tests and unnecessary delays. Instead, use Cypress methods like `cy.get()`, `cy.contains()`, and `cy.intercept()` to wait for specific conditions.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-07-16T08:25:23.799Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settingsTe_Spec.ts:33-33Timestamp: 2024-07-16T08:25:23.799ZLearning: Avoid using sleep functions like `agHelper.Sleep` and `this.Sleep` in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-10-08T15:32:34.115ZLearning: Avoid using sleep functions like `agHelper.Sleep`, `this.Sleep` in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
🧬 Code graph analysis (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
app/client/cypress/support/commands.js (2)
_(1071-1071)workspaceId(396-396)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: perform-test / rts-build / build
- GitHub Check: perform-test / client-build / client-build
- GitHub Check: perform-test / server-build / server-unit-tests
- GitHub Check: client-lint / client-lint
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-prettier / prettier-check
- GitHub Check: client-build / client-build
🔇 Additional comments (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
1-11:LGTM!The imports and setup follow best practices. Using
beforeEachto initialize datasource routes ensures consistent test state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (2)
22-22:Replace.workspace-menu-itemclass selector with a data-testid selector.Using the
.workspace-menu-itemclass as a locator violates the project guideline to use data-* attributes for selectors in Cypress tests. Prefer a stabledata-testidon the menu item and target that instead, while still filtering by the “Datasources” label.- agHelper.GetNClickByContains(".workspace-menu-item", "Datasources");+ agHelper.GetNClickByContains("[data-testid='workspace-menu-item']", "Datasources");Apply the same change at both usages (Lines 22 and 49), and ensure the UI element has the corresponding
data-testid="workspace-menu-item"attribute.Also applies to: 49-49
66-115:Replace staticcy.wait(100)calls with element- or network-based waits.The hard-coded
cy.wait(100)calls introduce flakiness and violate the “Avoid using cy.wait in code” guideline; they should be replaced with waits that assert on UI or network conditions before proceeding.A concrete replacement that keeps intent but uses deterministic waits:
@@- cy.wait(100);- cy.get(".t--add-datasource-button").first().click({ force: true });+ cy.get(".t--add-datasource-button")+ .first()+ .should("be.visible")+ .click({ force: true });@@- cy.wait(100);- cy.get(".t--add-datasource-button").first().click({ force: true });+ cy.get(".t--add-datasource-button")+ .first()+ .should("be.visible")+ .click({ force: true });If there’s a specific network request that must complete before the button appears, you can also alias that request and
cy.waiton the alias instead of a fixed timeout.Also applies to: 159-218
🧹 Nitpick comments (3)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (3)
1-12:Reduce duplicate imports fromObjectsCorefor consistency.You’re importing from
ObjectsCoreboth as a namespace (_) and via named imports (agHelper,dataSources), which is slightly redundant and can confuse future edits. Consider either using only the namespace (_.agHelper,_.dataSources) or only named imports for a cleaner pattern.
13-38:Align test description with assertions or add coverage for “available plugins.”The test name mentions “available plugins,” but the assertions only cover the empty list and blank state (including the CTA text). Either add an assertion that verifies the expected plugins or plugin tiles are rendered, or adjust the description so it reflects exactly what’s being checked.
196-217:Strengthen assertions to verify headers actually persist after saving from the discard dialog.The test edits header key/value, triggers the discard modal, then chooses “save” and only checks that the datasources (“Users”, “Mock API”) are visible. To fully validate “Should keep edits,” consider re-opening the editor and asserting that the header fields contain
Content-Typeandapplication/json.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/client/cypress/**/**.*
⚙️ CodeRabbit configuration file
app/client/cypress/**/**.*: Review the following e2e test code written using the Cypress test library. Ensure that:
- Follow best practices for Cypress code and e2e automation.
- Avoid using cy.wait in code.
- Avoid using cy.pause in code.
- Avoid using agHelper.sleep().
- Use locator variables for locators and do not use plain strings.
- Use data-* attributes for selectors.
- Avoid Xpaths, Attributes and CSS path.
- Avoid selectors like .btn.submit or button[type=submit].
- Perform logins via API with LoginFromAPI.
- Perform logout via API with LogOutviaAPI.
- Perform signup via API with SignupFromAPI.
- Avoid using it.only.
- Avoid using after and aftereach in test cases.
- Use multiple assertions for expect statements.
- Avoid using strings for assertions.
- Do not use duplicate filenames even with different paths.
- Avoid using agHelper.Sleep, this.Sleep in any file in code.
Files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
🧠 Learnings (12)
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-10-08T15:32:34.115ZLearning: Learnt from: sagar-qa007PR: appsmithorg/appsmith#34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-07-16T06:44:55.118ZLearning: Avoid using sleep functions like `agHelper.Sleep`, `this.Sleep`, and other related sleep functions in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2025-11-05T12:56:49.249Z
Learnt from: vsvamsi1Repo: appsmithorg/appsmith PR: 41363File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts:0-0Timestamp: 2025-11-05T12:56:49.249ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/PagePersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 4-6 depend on state (`page1Slug`, `page2Slug`) set in Tests 2-3. The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2025-11-05T12:58:32.486Z
Learnt from: vsvamsi1Repo: appsmithorg/appsmith PR: 41363File: app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts:32-225Timestamp: 2025-11-05T12:58:32.486ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/StaticUrl/SlugPersistance_Spec.ts`, the test suite intentionally uses sequential tests where Tests 2-5 depend on state from previous tests (e.g., slug values modified in earlier tests). The author (vsvamsi1) prioritizes readability by breaking the flow into different segments over strict test isolation.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-07-24T08:29:41.208Z
Learnt from: abhishek-bandameediRepo: appsmithorg/appsmith PR: 35133File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Checkbox/CheckBox2_spec.js:0-0Timestamp: 2024-07-24T08:29:41.208ZLearning: In Cypress tests for the Appsmith project, ensure the use of locator variables for selectors and include multiple assertions for comprehensive testing.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-11-13T09:07:54.931Z
Learnt from: vhemeryRepo: appsmithorg/appsmith PR: 37371File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_spec.js:44-47Timestamp: 2024-11-13T09:07:54.931ZLearning: When reviewing code in `app/client/cypress/**` paths, ensure that suggestions are appropriate for test code and not for `src` code. Avoid applying source code checks to test code unless relevant.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-11-13T09:11:36.959Z
Learnt from: vhemeryRepo: appsmithorg/appsmith PR: 37371File: app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js:35-37Timestamp: 2024-11-13T09:11:36.959ZLearning: In the file `app/client/cypress/e2e/Regression/ClientSide/Widgets/Image/Image_base64_spec.js`, when writing Cypress end-to-end tests for the Image Widget in JavaScript, use `viewWidgetsPage.imageinner` as the selector when asserting 'src' and 'alt' attributes to maintain consistency.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:39.374Z
Learnt from: Aishwarya-U-RRepo: appsmithorg/appsmith PR: 29405File: app/client/cypress/e2e/Regression/ClientSide/Binding/TableV2_Widget_API_Pagination_spec.js:37-41Timestamp: 2024-10-08T15:32:39.374ZLearning: The pull request titled "test: Cypress | Replace static with Dynamic waits - Part 1" is part of a phased approach where only certain test specifications are targeted for static wait removal in the initial phase. Future phases will address additional specs.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.114Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settingsTe_Spec.ts:33-33Timestamp: 2024-10-08T15:32:34.114ZLearning: Follow best practices for Cypress code and e2e automation:- Avoid using cy.wait in code.- Avoid using cy.pause in code.- Avoid using agHelper.sleep().- Use locator variables for locators and do not use plain strings.- Use data-* attributes for selectors.- Avoid Xpaths, Attributes, and CSS path.- Avoid selectors like .btn.submit or button[type=submit].- Perform logins via API with LoginFromAPI.- Perform logout via API with LogOutviaAPI.- Perform signup via API with SignupFromAPI.- Avoid using it.only.- Avoid using after and aftereach in test cases.- Use multiple assertions for expect statements.- Avoid using strings for assertions.- Do not use duplicate filenames even with different paths.- Avoid using agHelper.Sleep, this.Sleep in any file in code.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:39.374Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 35412File: app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/mysql_spec.ts:99-99Timestamp: 2024-10-08T15:32:39.374ZLearning: In Cypress tests within the `app/client/cypress` directory, avoid using `agHelper.Sleep`, `this.Sleep`, and other related sleep functions to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable. Instead, use Cypress methods like `cy.get()`, `cy.contains()`, and `cy.intercept()` to wait for specific conditions.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-08-06T05:39:47.929Z
Learnt from: ApekshaBhosaleRepo: appsmithorg/appsmith PR: 35412File: app/client/cypress/e2e/Regression/ClientSide/OneClickBinding/TableWidget/mysql_spec.ts:99-99Timestamp: 2024-08-06T05:39:47.929ZLearning: In Cypress tests, avoid using `agHelper.Sleep` as it can lead to flaky tests and unnecessary delays. Instead, use Cypress methods like `cy.get()`, `cy.contains()`, and `cy.intercept()` to wait for specific conditions.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-07-16T08:25:23.799Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settingsTe_Spec.ts:33-33Timestamp: 2024-07-16T08:25:23.799ZLearning: Avoid using sleep functions like `agHelper.Sleep` and `this.Sleep` in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
📚 Learning: 2024-10-08T15:32:34.115Z
Learnt from: sagar-qa007Repo: appsmithorg/appsmith PR: 34955File: app/client/cypress/e2e/Regression/ClientSide/ActionExecution/General_settings_Spec.ts:14-56Timestamp: 2024-10-08T15:32:34.115ZLearning: Avoid using sleep functions like `agHelper.Sleep`, `this.Sleep` in Cypress tests within the `app/client/cypress` directory to prevent non-deterministic behaviors and ensure tests are more reliable and maintainable.Applied to files:
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts
🧬 Code graph analysis (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
app/client/cypress/support/commands.js (2)
_(1071-1071)workspaceId(396-396)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: client-build / client-build
- GitHub Check: client-check-cyclic-deps / check-cyclic-dependencies
- GitHub Check: client-unit-tests / client-unit-tests
- GitHub Check: client-lint / client-lint
- GitHub Check: client-prettier / prettier-check
🔇 Additional comments (1)
app/client/cypress/e2e/Regression/ClientSide/Workspace/WorkspaceDatasourceSettings_spec.ts (1)
117-157:Delete flow coverage looks solid for workspace datasource removal.This test exercises add → open editor → context menu delete → confirm → verify blank state with the CTA visible, and relies only on aliased waits, which should be stable. No issues from a Cypress best-practices perspective.
tomjose92 commentedNov 29, 2025
/build-deploy-preview skip-tests=true |
Deploying Your Preview:https://github.com/appsmithorg/appsmith/actions/runs/19780602226. |
Deploy-Preview-URL:https://ce-41324.dp.appsmith.com |
Uh oh!
There was an error while loading.Please reload this page.
Description
Made changes to show datasources settings page at a workspace level.
This allows an administrator to see all the datasources being used on the workspace from a page without the need to go to App Editor.
Datasource.config.page.mov
Fixes35669
Automation
/ok-to-test tags="@tag.All"
🔍 Cypress test results
Warning
Tests have not run on the HEAD9caf3ed yet
Sat, 29 Nov 2025 06:18:52 UTC
Communication
Should the DevRel and Marketing teams inform users about this change?
Summary by CodeRabbit
New Features
Enhancements
Tests
✏️ Tip: You can customize this high-level summary in your review settings.