-
Notifications
You must be signed in to change notification settings - Fork 94
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: lineage refactor #1212
feat: lineage refactor #1212
Conversation
window.addEventListener( | ||
"message", | ||
( | ||
event: MessageEvent<{ command: string; args: Record<string, unknown> }>, |
Check warning
Code scanning / CodeQL
Missing origin verification in `postMessage` handler Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 2 months ago
To fix the problem, we need to verify the origin of the incoming messages in the postMessage
handler. This involves checking the event.origin
property against a list of trusted origins before processing the message.
- Identify the trusted origins for your application.
- Modify the
postMessage
handler to include a check for theevent.origin
. - If the origin is trusted, proceed with the existing logic; otherwise, ignore the message or log a warning.
-
Copy modified line R93 -
Copy modified lines R99-R102
@@ -92,2 +92,3 @@ | ||
|
||
const trustedOrigins = ['https://www.example.com', 'https://another-trusted-origin.com']; | ||
window.addEventListener( | ||
@@ -97,2 +98,6 @@ | ||
) => { | ||
if (!trustedOrigins.includes(event.origin)) { | ||
panelLogger.warn(`Untrusted origin: ${event.origin}`); | ||
return; | ||
} | ||
panelLogger.log("lineage:message -> ", JSON.stringify(event.data)); |
@@ -173,14 +173,6 @@ export class LineagePanel implements WebviewViewProvider, Disposable { | |||
return; | |||
} | |||
|
|||
if (command === "openURL") { |
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.
this is handled via altimateWebviewProvider
@@ -188,17 +188,6 @@ export class QueryResultPanel extends AltimateWebviewProvider { | |||
); | |||
} | |||
|
|||
private async checkIfWebviewReady() { |
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.
moved to altimateWebviewProvider
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
Outside diff range and nitpick comments (6)
webview_panels/src/lib/altimate/altimate-components.d.ts (1)
297-298
: Remove unnecessary empty exportThe empty export statement is unnecessary as there are other exports in the file. It can be safely removed to clean up the code.
Apply this diff to remove the empty export:
declare type ViewsTypes = keyof typeof VIEWS_TYPE_COLOR; -export { }
Tools
Biome
[error] 297-298: This empty export is useless because there's another export or import.
This import makes useless the empty export.
Safe fix: Remove this useless empty export.
(lint/complexity/noUselessEmptyExport)
src/webview_provider/newLineagePanel.ts (5)
74-117
: LGTM: Class refactor improves modularity and dependency injection.The
NewLineagePanel
class has been refactored to extendAltimateWebviewProvider
and implementLineagePanelView
. This change improves the class's modularity and allows for better separation of concerns. The constructor now uses dependency injection for various services, which is a good practice for maintainability and testability.A few minor suggestions:
- Consider using TypeScript's parameter properties to reduce boilerplate in the constructor.
- The
_disposables
property is not visible in this snippet. Ensure it's properly initialized.Consider refactoring the constructor to use parameter properties:
constructor( protected readonly dbtProjectContainer: DBTProjectContainer, private readonly altimate: AltimateRequest, protected readonly telemetry: TelemetryService, private readonly terminal: DBTTerminal, private readonly eventEmitterService: SharedStateService, protected readonly queryManifestService: QueryManifestService, protected readonly usersService: UsersService, ) { super( dbtProjectContainer, altimate, telemetry, eventEmitterService, terminal, queryManifestService, usersService, ); // ... rest of the constructor code }
Line range hint
165-327
: Consider refactoringhandleCommand
for improved maintainability.The
handleCommand
method has grown quite large and handles multiple responsibilities. While it's organized by command type, its length makes it harder to maintain and understand at a glance.Suggestions for improvement:
- Consider splitting this method into smaller, more focused methods for each command type.
- Implement a command pattern or use a map of command handlers to reduce the number of if-else statements.
- Use early returns to reduce nesting and improve readability.
Here's a high-level example of how you might refactor this method:
private commandHandlers = { openProblemsTab: () => commands.executeCommand("workbench.action.problems.focus"), upstreamTables: async (args) => { const body = await this.getUpstreamTables(args.params); return { body, status: true }; }, // ... other command handlers }; async handleCommand(message: { command: string; args: any; syncRequestId?: string }): Promise<void> { const { command, args = {}, syncRequestId } = message; const { id = syncRequestId, params } = args; const handler = this.commandHandlers[command]; if (handler) { const result = await handler(args); this._panel?.webview.postMessage({ command: "response", args: { id, syncRequestId, ...result }, }); return; } this.terminal.debug("newLineagePanel:handleCommand", "Unsupported command", message); super.handleCommand(message); }This refactoring would make the
handleCommand
method more concise and easier to maintain, as each command's logic would be encapsulated in its own function.
Line range hint
541-757
: RefactorgetConnectedColumns
for improved readability and maintainability.The
getConnectedColumns
method is complex and handles multiple responsibilities. While it seems to work as intended, its length and complexity make it difficult to understand and maintain.Suggestions for improvement:
- Break down the method into smaller, more focused helper methods.
- Consider moving some of the logic (e.g., model fetching, SQL compilation) into separate services.
- Use more descriptive variable names to improve readability.
- Add more inline comments explaining the purpose of each section.
Here's a high-level example of how you might start refactoring this method:
private async getConnectedColumns(params: ConnectedColumnsParams) { const { event, project } = await this.validateAndGetEventAndProject(); if (!event || !project) return; const modelInfos = await this.prepareModelInfos(params, event, project); if (this.cancellationTokenSource?.token.isCancellationRequested) { return { column_lineage: [] }; } const request = this.buildColumnLevelLineageRequest(params, modelInfos, project); const result = await this.fetchColumnLevelLineage(request); return this.processColumnLevelLineageResult(result); } private async validateAndGetEventAndProject() { // ... implementation } private async prepareModelInfos(params: ConnectedColumnsParams, event: Event, project: Project) { // ... implementation } private buildColumnLevelLineageRequest(params: ConnectedColumnsParams, modelInfos: ModelInfo[], project: Project) { // ... implementation } private async fetchColumnLevelLineage(request: ColumnLevelLineageRequest) { // ... implementation } private processColumnLevelLineageResult(result: ColumnLevelLineageResult) { // ... implementation }This refactoring breaks down the large method into smaller, more focused methods, improving readability and maintainability.
Line range hint
981-994
: LGTM: Good approach for gradual feature rollout.The
renderWebviewView
method has been updated to support a new version of the lineage panel. This is a good approach for gradually rolling out new features while maintaining backward compatibility.A minor suggestion for improvement:
Consider extracting the version check into a separate method for better readability and reusability.Here's a suggested refactor:
private isV2Enabled = () => workspace .getConfiguration("dbt") .get<boolean>("enableLineagePanelV2", false); protected renderWebviewView(webview: Webview) { if (this.isV2Enabled()) { this.renderV2WebviewView(webview); } else { this.renderV1WebviewView(webview); } } private renderV2WebviewView(webview: Webview) { this._panel!.webview.html = super.getHtml( webview, this.dbtProjectContainer.extensionUri, ); } private renderV1WebviewView(webview: Webview) { this._panel!.webview.options = <WebviewOptions>{ enableScripts: true }; this._panel!.webview.html = getHtml( webview, this.dbtProjectContainer.extensionUri, ); }This refactoring improves readability and makes it easier to maintain different versions of the webview rendering logic.
Line range hint
1-1048
: Consider further refactoring for improved modularity and consistency.While the individual methods have been improved, the overall file structure could benefit from further refactoring:
- The file is quite large. Consider splitting it into smaller, more focused modules.
- There's a mix of async/await and Promise-based code. Standardize on async/await for consistency.
- Remove or address TODO comments and commented-out code sections.
- Consider creating separate services for some of the complex logic (e.g., lineage calculation, webview rendering).
Here are some high-level suggestions for improving the overall architecture:
- Create a
LineageService
to handle the complex lineage calculation logic.- Move webview-related code to a separate
LineageWebviewProvider
class.- Use dependency injection consistently throughout the codebase.
- Create interfaces for the main classes to improve testability and maintainability.
Example structure:
// lineageService.ts export class LineageService { // ... lineage calculation methods } // lineageWebviewProvider.ts export class LineageWebviewProvider extends AltimateWebviewProvider { // ... webview-related methods } // newLineagePanel.ts export class NewLineagePanel implements LineagePanelView { constructor( private lineageService: LineageService, private webviewProvider: LineageWebviewProvider, // ... other dependencies ) {} // ... simplified methods using the new services }This structure would improve modularity, testability, and maintainability of the codebase.
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (3)
- src/webview_provider/newLineagePanel.ts (24 hunks)
- webview_panels/src/lib/altimate/altimate-components.d.ts (1 hunks)
- webview_panels/src/lib/altimate/altimate-components.js (1 hunks)
Files skipped from review as they are similar to previous changes (1)
- webview_panels/src/lib/altimate/altimate-components.js
Additional context used
Biome
webview_panels/src/lib/altimate/altimate-components.d.ts
[error] 9-19: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
[error] 297-298: This empty export is useless because there's another export or import.
This import makes useless the empty export.
Safe fix: Remove this useless empty export.
(lint/complexity/noUselessEmptyExport)
Additional comments not posted (7)
webview_panels/src/lib/altimate/altimate-components.d.ts (6)
21-25
: LGTM: CllEvents enum declarationThe
CllEvents
enum is well-structured and follows TypeScript conventions. It appropriately defines the events related to the CLL lifecycle (CANCEL, END, START).
27-27
: LGTM: CodeBlock component props enhancementThe
CodeBlock
component has been updated with additional props (editorTheme
andclassName
) and refined type definitions. These changes improve the component's flexibility and customization options, aligning with modern React component patterns.Also applies to: 177-186
29-293
: LGTM: Comprehensive type definitions with new interfacesThe addition of numerous new interfaces (e.g., CollectColumn, Column, ColumnLineage, Columns, Confidence, Conversation, ConversationGroup, ExposureMetaData, LineageProviderProps, ModalArgs, OpNodeArgs, SelectedColumn, SqlLineage, StaticLineage, StaticLineageDetails) significantly enhances the type safety and readability of the codebase. These well-structured interfaces follow TypeScript best practices and provide clear type definitions for various data structures used in the application.
279-286
: LGTM: VIEWS_TYPE_COLOR constant declarationThe
VIEWS_TYPE_COLOR
constant provides a centralized definition for view type colors, which can improve consistency across the application. The naming convention follows TypeScript standards for constants.
306-321
: LGTM: Identifiers namespace declarationThe
Identifiers
namespace is a well-structured grouping of related constants. This approach effectively organizes and encapsulates values related to various aspects of the application, including themes, debugging, and remote URIs. It follows good TypeScript practices for constant management.
300-303
: Verify usage of custom 'selectionend' eventThe global
HTMLElementEventMap
has been extended to include a custom 'selectionend' event. This is a valid approach to declare custom events. However, it's important to ensure that this custom event is actually used and dispatched in the application.To verify the usage of this custom event, you can run the following script:
This will help confirm that the custom event is being utilized in the application.
Verification successful
To address the issue with the previous search, please run the following script to verify the usage of the custom
'selectionend'
event:
'selectionend' event usage verified
The custom
selectionend
event is actively used within the application as seen in the following file:
webview_panels/src/lib/altimate/DbtDocsRenderer.js
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for usage of 'selectionend' event in the codebase rg --type typescript --type javascript "selectionend" -C 3Length of output: 93
Script:
# Searching for 'selectionend' event usage in .ts and .js files rg -e 'selectionend' --glob '*.ts' --glob '*.js' -C 3Length of output: 1882
src/webview_provider/newLineagePanel.ts (1)
Line range hint
1-1048
: Summary: Significant improvements with opportunities for further refinement.The
NewLineagePanel
class has undergone substantial refactoring, resulting in improved modularity and functionality. Key improvements include:
- Extension of
AltimateWebviewProvider
and implementation ofLineagePanelView
.- Improved dependency injection in the constructor.
- Support for a new version of the lineage panel.
While these changes are positive, there are opportunities for further improvement:
- Further break down large methods like
handleCommand
andgetConnectedColumns
.- Standardize on async/await throughout the file.
- Consider splitting the file into smaller, more focused modules.
- Implement a more robust error handling strategy.
Overall, the changes represent a significant step forward in the codebase's evolution. Addressing the suggested improvements will further enhance the maintainability and scalability of the lineage functionality.
export declare class CLL { | ||
static isCancelled: boolean; | ||
static inProgress: boolean; | ||
static linkCount: number; | ||
static onCancel(): void; | ||
static cancel(): void; | ||
static start(): void; | ||
static end(): void; | ||
static addLinks(n: number): void; | ||
static showCllInProgressMsg(): void; | ||
} |
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.
Consider refactoring the CLL
class to a namespace or module
The CLL
class contains only static members and methods, which is generally discouraged in TypeScript. To improve maintainability and adhere to best practices, consider refactoring this into a namespace or module with exported functions and variables.
Here's a suggested refactor:
export namespace CLL {
export let isCancelled: boolean;
export let inProgress: boolean;
export let linkCount: number;
export function onCancel(): void;
export function cancel(): void;
export function start(): void;
export function end(): void;
export function addLinks(n: number): void;
export function showCllInProgressMsg(): void;
}
This approach maintains the same functionality while aligning with TypeScript best practices.
Tools
Biome
[error] 9-19: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
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: 3
🧹 Outside diff range and nitpick comments (2)
src/webview_provider/sqlLineagePanel.ts (1)
202-202
: Use Consistent Node Type StringsIn assigning the
type
property for the node mapping, ensure that the string values match expected resource types. For example,"source"
should match the resource type used elsewhere in the application to avoid inconsistencies.src/webview_provider/newLineagePanel.ts (1)
165-171
: Standardize the use of 'id' and 'syncRequestId'In the
handleCommand
method, bothid
andsyncRequestId
are being used interchangeably. This can lead to confusion and potential bugs. Consider standardizing on a single identifier for request correlation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- src/commands/index.ts (1 hunks)
- src/webview_provider/newLineagePanel.ts (23 hunks)
- src/webview_provider/sqlLineagePanel.ts (6 hunks)
🧰 Additional context used
🪛 Biome
src/webview_provider/sqlLineagePanel.ts
[error] 220-220: Unnecessary continue statement
Unsafe fix: Delete the unnecessary continue statement
(lint/correctness/noUnnecessaryContinue)
[error] 281-281: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.The declaration is defined in this switch clause:
Unsafe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 291-291: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.The declaration is defined in this switch clause:
Unsafe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 299-299: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.The declaration is defined in this switch clause:
Unsafe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (11)
src/webview_provider/sqlLineagePanel.ts (9)
38-40
: ExtendingAltimateWebviewProvider
Enhances Code ReusabilityBy extending
AltimateWebviewProvider
, theSQLLineagePanel
class now inherits shared functionalities, promoting code reuse and improving maintainability as per the PR objectives.
47-63
: Constructor Properly Injects DependenciesThe constructor correctly injects all necessary services and passes them to the superclass, ensuring that both the
SQLLineagePanel
and its superclass are properly initialized with required dependencies.
250-261
: RefactoredrenderSqlVisualizer
Method Improves ClarityThe
renderSqlVisualizer
method has been refactored for better clarity and efficiency. It streamlines the rendering process by directly posting messages to the webview after ensuring it's ready.
267-272
: Enhanced Command Handling inhandleCommand
MethodThe
handleCommand
method now uses a switch statement for cleaner and more maintainable command handling. The inclusion ofsyncRequestId
supports synchronous communication when necessary.
Line range hint
193-225
: Efficient Mapping of Nodes innodeMapping
The updates to
nodeMapping
correctly associate node IDs and types, improving the accuracy of the lineage visualization by ensuring that nodes are properly identified and rendered.🧰 Tools
🪛 Biome
[error] 220-220: Unnecessary continue statement
Unsafe fix: Delete the unnecessary continue statement
(lint/correctness/noUnnecessaryContinue)
31-31
: Updated Type Definition fordetails
The
details
property in theSQLLineage
type has been updated toSqlLineageDetails
, ensuring type correctness and better alignment with the data being handled.
15-15
: Importing Necessary Types from../altimate
The import statement now includes
SqlLineageDetails
, which is necessary for the updateddetails
type, ensuring that all required types are available.
25-27
: New Imports for Expanded FunctionalityThe added imports of
AltimateWebviewProvider
,SharedStateService
, andUsersService
indicate an expansion of functionality and integration with additional services, enhancing the capabilities of theSQLLineagePanel
.
225-225
: Consistent Use of Node Resource TypesEnsure that
currNode.resource_type
returns a string consistent with the expected values for node types. This consistency is crucial for correct rendering and interaction in the lineage visualization.src/webview_provider/newLineagePanel.ts (2)
913-915
: Good job addressing the previous null check issueYou've successfully added a null check before calling
throwDiagnosticsErrorIfAvailable()
, preventing potential runtime errors whengetProject()
returnsundefined
.
594-594
:⚠️ Potential issueEnsure 'cancellationTokenSource' is initialized before use
In
getConnectedColumns
,this.cancellationTokenSource
is used without checking if it's initialized. Ifthis.cancellationTokenSource
isundefined
, accessing itstoken
property will lead to a runtime error. Please ensure thatthis.cancellationTokenSource
is properly initialized before accessing itstoken
.Apply this diff to add a null check:
- this.cancellationTokenSource!.token, + this.cancellationTokenSource?.token || CancellationToken.None,Likely invalid or redundant comment.
@@ -700,7 +700,7 @@ export class VSCodeCommands implements Disposable { | |||
ViewColumn.Two, | |||
{ retainContextWhenHidden: true, enableScripts: true }, | |||
); | |||
this.sqlLineagePanel.resolveWebviewView(panel, lineage); | |||
this.sqlLineagePanel.renderSqlVisualizer(panel, lineage); |
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.
💡 Codebase verification
Incomplete method renaming detected.
The method resolveWebviewView
still exists in multiple files, indicating that the renaming to renderSqlVisualizer
was not fully propagated. To maintain code consistency and prevent potential issues, please ensure that all instances of resolveWebviewView
are updated accordingly.
Affected files:
src/webview_provider/lineagePanel.ts
src/webview_provider/altimateWebviewProvider.ts
src/webview_provider/sqlLineagePanel.ts
src/webview_provider/queryResultPanel.ts
src/webview_provider/newDocsGenPanel.ts
src/webview_provider/docsEditPanel.ts
src/webview_provider/modelGraphViewPanel.ts
🔗 Analysis chain
Improved method naming for better clarity.
The renaming of resolveWebviewView
to renderSqlVisualizer
enhances code readability by more accurately describing the method's purpose. This change is a step in the right direction for maintaining clear and self-documenting code.
To ensure consistency across the codebase, let's verify if this method has been renamed in all relevant files:
Correction needed for file type specification in search scripts.
The initial shell scripts failed because rg
does not recognize typescript
as a valid file type. To resolve this, we'll use the correct file type identifier ts
for TypeScript files.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any remaining instances of 'resolveWebviewView' in TypeScript files
echo "Searching for 'resolveWebviewView':"
rg --type typescript 'resolveWebviewView'
# Search for occurrences of 'renderSqlVisualizer' to ensure consistent usage
echo "Searching for 'renderSqlVisualizer':"
rg --type typescript 'renderSqlVisualizer'
Length of output: 330
Script:
#!/bin/bash
# Search for any remaining instances of 'resolveWebviewView' in TypeScript files
echo "Searching for 'resolveWebviewView':"
rg --type ts 'resolveWebviewView'
# Search for occurrences of 'renderSqlVisualizer' to ensure consistent usage
echo "Searching for 'renderSqlVisualizer':"
rg --type ts 'renderSqlVisualizer'
Length of output: 1138
protected renderWebviewView(webview: Webview) { | ||
if (this.isV2Enabled()) { | ||
this._panel!.webview.html = super.getHtml( | ||
webview, | ||
this.dbtProjectContainer.extensionUri, | ||
); | ||
return; | ||
} |
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.
🛠️ Refactor suggestion
Set 'webview.options' consistently
In the renderWebviewView
method, this._panel!.webview.options
is only set when isV2Enabled()
is false
. For consistency and to avoid potential issues, consider setting webview.options
regardless of the feature flag.
Apply this diff to set webview.options
in both cases:
protected renderWebviewView(webview: Webview) {
+ this._panel!.webview.options = { enableScripts: true };
if (this.isV2Enabled()) {
this._panel!.webview.html = super.getHtml(
webview,
this.dbtProjectContainer.extensionUri,
);
return;
}
- this._panel!.webview.options = { enableScripts: true };
this._panel!.webview.html = getHtml(
webview,
this.dbtProjectContainer.extensionUri,
);
}
📝 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.
protected renderWebviewView(webview: Webview) { | |
if (this.isV2Enabled()) { | |
this._panel!.webview.html = super.getHtml( | |
webview, | |
this.dbtProjectContainer.extensionUri, | |
); | |
return; | |
} | |
protected renderWebviewView(webview: Webview) { | |
this._panel!.webview.options = { enableScripts: true }; | |
if (this.isV2Enabled()) { | |
this._panel!.webview.html = super.getHtml( | |
webview, | |
this.dbtProjectContainer.extensionUri, | |
); | |
return; | |
} | |
this._panel!.webview.html = getHtml( | |
webview, | |
this.dbtProjectContainer.extensionUri, | |
); | |
} |
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: 2
🧹 Outside diff range and nitpick comments (2)
src/webview_provider/altimateWebviewProvider.ts (1)
641-648
: LGTM: HTML template updates look goodThe changes to the HTML template are well-implemented:
- Adding a class to the body based on
viewPath
allows for view-specific styling.- The new "modal" div can be used for modal dialogs.
- The
lineageGif
variable makes the new asset available to the webview's JavaScript.Minor suggestion: Consider using template literals for the class attribute to improve readability:
<body class="${this.viewPath.replace(/\//g, "")}">src/altimate.ts (1)
Line range hint
936-940
: LGTM! Consistent return type update.The update of the return type from
StaticLineageResponse
toSqlLineageResponse
is consistent with the earlier type renaming, maintaining type coherence throughout the file.For complete consistency, consider updating the method name from
sqlLineage
togetSqlLineage
orfetchSqlLineage
to better align with other method names in the class (e.g.,getColumnLevelLineage
,fetchArtifactUrl
).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (6)
- src/altimate.ts (3 hunks)
- src/webview_provider/altimateWebviewProvider.ts (3 hunks)
- src/webview_provider/queryResultPanel.ts (0 hunks)
- webview_panels/package.json (1 hunks)
- webview_panels/src/assets/icons/index.tsx (2 hunks)
- webview_panels/src/uiCore/theme.scss (1 hunks)
💤 Files with no reviewable changes (1)
- src/webview_provider/queryResultPanel.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- webview_panels/package.json
🧰 Additional context used
🔇 Additional comments (7)
webview_panels/src/uiCore/theme.scss (3)
178-178
: LGTM: Proper closure of CSS ruleThe addition of the closing brace for the
.offcanvas
class is a good fix. It ensures that the CSS rule is properly structured and closed.
178-182
: Summary: Minor styling updatesThe changes in this file include properly closing the
.offcanvas
rule and adding a new.modal-content
class. While these changes are consistent with good coding practices and the existing style, it would be helpful to understand how they specifically relate to the lineage refactoring mentioned in the PR objectives.Could you provide more context on how these styling changes contribute to the overall goal of enhancing the maintainability of the lineage component?
180-182
: LGTM: New modal content stylingThe addition of the
.modal-content
class with a background color is consistent with the existing code style and use of CSS variables. This change aligns with the modifications mentioned in the AI-generated summary.Could you please clarify the specific use case for this new modal content styling? It would be helpful to understand how it relates to the lineage refactoring mentioned in the PR objectives.
✅ Verification successful
To verify the connection between the new modal content styling and the lineage components mentioned in the PR objectives, we need to examine the contents of some key files. Let's run the following scripts to gather more information:
To further verify the connection between the new modal content styling and the lineage components, let's examine a few more files:
LGTM: Modal styling consistent with lineage components
The new
.modal-content
class, while not directly visible in the custom components, is likely part of the reactstrap library used in the Modals.tsx file. The modal components (Modal, SidebarModal, LineageModal) are being used in the context of lineage functionality, as seen in the Lineage.tsx file. This confirms that the new modal content styling is related to the lineage refactoring mentioned in the PR objectives.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Search for modal-related changes in other files # Test: Look for modal-related changes in HTML templates rg -i 'modal' --type html # Test: Look for modal-related changes in TypeScript/JavaScript files rg -i 'modal' --type ts --type jsLength of output: 257594
Script:
#!/bin/bash # View contents of main.tsx cat new_lineage_panel/src/main.tsx # View contents of Modals.tsx cat new_lineage_panel/src/Modals.tsx # View contents of PageModal.tsx cat new_lineage_panel/src/components/Modal/PageModal.tsxLength of output: 5866
Script:
#!/bin/bash # Check contents of PageModal.css cat new_lineage_panel/src/components/Modal/PageModal.css # Examine Lineage.tsx cat new_lineage_panel/src/Lineage.tsx # Search for other CSS files containing .modal-content grep -r "\.modal-content" new_lineage_panel/src --include="*.css" --include="*.scss"Length of output: 15878
webview_panels/src/assets/icons/index.tsx (1)
31-31
: LGTM: New import statement for LineageGif.The import statement for
LineageGif
is correctly placed and follows the existing pattern in the file.src/webview_provider/altimateWebviewProvider.ts (1)
601-611
: LGTM: New asset added correctlyThe addition of the
LineageGif
constant follows the existing pattern for other assets and is implemented correctly.src/altimate.ts (2)
Line range hint
82-93
: LGTM! Improved type naming for better clarity.The renaming of
Details
toSqlLineageDetails
enhances code readability by making the type name more specific and descriptive of its purpose in the context of SQL lineage.
93-97
: LGTM! Consistent type renaming and usage.The renaming of
StaticLineageResponse
toSqlLineageResponse
and the update of thedetails
property to useSqlLineageDetails
maintain consistency with the previous change. This improves the overall clarity and coherence of the type system related to SQL lineage.
export const LineageDemo = (): JSX.Element => ( | ||
<img | ||
// @ts-expect-error added in altimateWebViewProvider | ||
src={(window.lineageGif as string) ?? LineageGif} | ||
alt="Lineage demo" | ||
/> | ||
); |
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.
🛠️ Refactor suggestion
Review the LineageDemo component implementation.
The LineageDemo
component is well-structured and consistent with other components in the file. However, there are a couple of points that need attention:
- The TypeScript error suppression comment (
@ts-expect-error
) might hide underlying type issues. Consider addressing the root cause instead of suppressing the error. - The use of
window.lineageGif
assumes it's defined somewhere else, which could lead to runtime errors if not properly managed. Ensure that this global variable is consistently set where needed.
To address these issues, consider refactoring the component as follows:
export const LineageDemo = (): JSX.Element => {
const gifSrc = typeof window !== 'undefined' && 'lineageGif' in window
? (window as any).lineageGif as string
: LineageGif;
return <img src={gifSrc} alt="Lineage demo" />;
};
This approach type-checks the window
object and uses a type assertion only when necessary, reducing the risk of runtime errors.
Note: While a similar comment was made in a previous review, this new comment is necessary as the issues haven't been fully addressed in the current implementation.
protected async checkIfWebviewReady() { | ||
return new Promise<void>((resolve) => { | ||
const interval = setInterval(() => { | ||
if (this.isWebviewReady) { | ||
clearInterval(interval); | ||
resolve(); | ||
} | ||
}, 500); | ||
}); | ||
} |
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.
🛠️ Refactor suggestion
Consider optimizing the webview ready check
The checkIfWebviewReady
method provides a way to asynchronously wait for the webview to be ready, which is good. However, there are a few potential improvements:
- Instead of using
setInterval
, consider usingsetTimeout
with a recursive approach. This would be more efficient, especially if the webview takes a while to be ready. - Add a timeout mechanism to prevent an infinite loop if
isWebviewReady
never becomes true.
Here's a suggested implementation:
protected async checkIfWebviewReady(timeout = 30000): Promise<void> {
return new Promise<void>((resolve, reject) => {
const startTime = Date.now();
const check = () => {
if (this.isWebviewReady) {
resolve();
} else if (Date.now() - startTime > timeout) {
reject(new Error('Timeout waiting for webview to be ready'));
} else {
setTimeout(check, 500);
}
};
check();
});
}
This implementation will reject the promise if the webview isn't ready within the specified timeout (default 30 seconds).
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- webview_panels/src/modules/lineage/components/demo/DemoButton.tsx (1 hunks)
🧰 Additional context used
🔇 Additional comments (5)
webview_panels/src/modules/lineage/components/demo/DemoButton.tsx (5)
1-5
: LGTM: Import statements are well-organized and necessary.The import statements are logically ordered and include all the necessary dependencies for the component's functionality.
7-46
: LGTM: Component structure follows React best practices.The
DemoButton
component is well-structured as a functional component. It effectively uses React hooks for state management and implements conditional rendering correctly.
11-16
: Implement the suggested timeout cleanup to prevent memory leaks.As mentioned in a previous review comment, it's important to clear the timeout when the component unmounts to prevent potential memory leaks. Please implement the suggested change:
useEffect(() => { // hide demo button after 10s const timer = setTimeout(() => { setShowDemoButton(false); }, 10000); // Clear the timeout when the component unmounts return () => clearTimeout(timer); }, []);This ensures proper cleanup if the component unmounts before the 10-second delay elapses.
31-43
: LGTM: Button implementation is correct and follows good practices.The conditional rendering of the Button component is well-implemented. The use of
stopPropagation()
in the onClick handler is appropriate to prevent event bubbling. The button's content and styling are clear and consistent with the component's purpose.
1-48
: Overall, well-implemented component with minor suggestions for improvement.The
DemoButton
component is well-structured and follows React best practices. The suggested improvements (timeout cleanup and close button accessibility) are minor and once addressed, will further enhance the component's quality and robustness.
<Modal | ||
isOpen={showDemoModal} | ||
close={() => setShowDemoModal(false)} | ||
fullscreen | ||
className={styles.demoModal} | ||
> | ||
<Demo /> | ||
<div className="close-btn" onClick={() => setShowDemoModal(false)}> | ||
<CloseIcon /> | ||
</div> | ||
</Modal> |
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.
🛠️ Refactor suggestion
Enhance accessibility of the close button in the Modal.
While the Modal implementation is generally correct, the close button could be improved for better accessibility. Consider replacing the div with a proper button element:
<button
className="close-btn"
onClick={() => setShowDemoModal(false)}
aria-label="Close demo modal"
>
<CloseIcon />
</button>
This change improves keyboard accessibility and provides better semantic meaning to screen readers.
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
🧹 Outside diff range and nitpick comments (2)
src/webview_provider/newLineagePanel.ts (2)
594-596
: Proper error handling for cancellationThe code now checks for cancellation using
this.cancellationTokenSource!.token
, which is a good practice. However, the use of the non-null assertion operator (!
) might be risky ifcancellationTokenSource
could be undefined.Consider adding a null check before using
cancellationTokenSource
to avoid potential runtime errors:if (this.cancellationTokenSource?.token) { // Use the token } else { // Handle the case where cancellationTokenSource is undefined }
913-915
: Improved error handling in getMissingLineageMessageThe code now uses optional chaining (
?.
) when callingthrowDiagnosticsErrorIfAvailable()
, which is safer than the previous implementation. However, there's still room for improvement.Consider using nullish coalescing to provide a default error message:
try { this.queryManifestService.getProject()?.throwDiagnosticsErrorIfAvailable(); } catch (err) { return { message: (err as Error).message ?? "Unknown error occurred", type: "error" }; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- src/webview_provider/newLineagePanel.ts (24 hunks)
🧰 Additional context used
🔇 Additional comments (9)
src/webview_provider/newLineagePanel.ts (9)
74-117
: Improved class structure and dependency injectionThe
NewLineagePanel
class has been refactored to extendAltimateWebviewProvider
and implementLineagePanelView
. The constructor now accepts more dependencies, improving modularity and testability. The addition of a configuration change listener is a good practice for keeping the panel up-to-date with user settings.
165-171
: Enhanced command handling with sync request supportThe
handleCommand
method signature has been updated to include an optionalsyncRequestId
. This allows for better tracking and correlation of asynchronous operations, improving the overall reliability of the command handling system.
181-181
: Consistent use of syncRequestId in response messagesThe
syncRequestId
is now consistently included in the response messages sent back to the webview. This improvement ensures that the frontend can accurately match responses to their corresponding requests, enhancing the reliability of the communication between the extension and the webview.Also applies to: 190-190, 199-199, 208-208, 218-218, 247-247, 252-252
327-327
: Proper delegation to parent classThe
handleCommand
method now correctly delegates to the parent class implementation usingsuper.handleCommand(message)
for unsupported commands. This ensures that any common command handling logic in the parent class is not bypassed.
576-579
: Improved usage of event objectThe code now correctly uses
event.event
when callingDBTProject.getNonEphemeralParents
, ensuring that the correct data is passed to the method. This change aligns with the updated structure of theevent
object.Also applies to: 582-583
619-621
: Efficient bulk compilation of SQLThe code now uses
project.getBulkCompiledSql
to compile multiple SQL models at once, which is likely more efficient than compiling them individually. This is a good optimization for performance.
786-788
: Improved null handling in createTable methodThe code now properly checks if
_node
is undefined before attempting to use it, preventing potential runtime errors. This is a good defensive programming practice.
975-978
: New method for checking if V2 is enabledThe addition of the
isV2Enabled
method is a good practice for encapsulating the configuration check. This makes it easier to update the condition in the future if needed.
Line range hint
980-992
: Improved renderWebviewView methodThe
renderWebviewView
method now checks if V2 is enabled and renders the appropriate HTML. This is a good way to handle feature flags and gradually roll out new features.To ensure that the V2 rendering is working as expected, we should verify that the configuration is being read correctly. Run the following script to check the 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
🧹 Outside diff range and nitpick comments (2)
src/webview_provider/newLineagePanel.ts (2)
Line range hint
149-311
: Improved command handling with suggestion for further refactoringThe updates to the
handleCommand
method, including the addition ofsyncRequestId
for better response tracking, are good improvements. However, the method is handling many different commands, which could make it harder to maintain as the number of commands grows.Consider refactoring this method to use a command pattern or a map of command handlers to improve maintainability and make it easier to add new commands in the future.
Line range hint
524-740
: Consider refactoringgetConnectedColumns
for improved maintainabilityThe
getConnectedColumns
method is quite long and complex, handling multiple responsibilities. Consider breaking it down into smaller, more focused methods to improve readability and maintainability. This would make the code easier to understand, test, and modify in the future.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- src/webview_provider/newLineagePanel.ts (23 hunks)
🧰 Additional context used
🔇 Additional comments (2)
src/webview_provider/newLineagePanel.ts (2)
73-101
: Improved class structure and dependency injectionThe refactoring of
NewLineagePanel
to extendAltimateWebviewProvider
and the addition of new dependencies in the constructor enhance the modularity and maintainability of the code. This change aligns with best practices for dependency injection and separation of concerns.
959-963
: Simplified webview renderingThe new
renderWebviewView
method effectively leverages the superclass implementation, promoting code reuse and maintaining a clear separation of concerns. This change simplifies the rendering process and makes the code more maintainable.
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: 2
🧹 Outside diff range and nitpick comments (3)
src/webview_provider/newLineagePanel.ts (3)
84-101
: LGTM! Improved dependency injection. Consider using parameter properties for conciseness.The updated constructor properly injects the required services, which is excellent for managing dependencies and improving testability.
For improved readability and conciseness, consider using TypeScript's parameter properties. This can reduce boilerplate code. For example:
constructor( protected readonly dbtProjectContainer: DBTProjectContainer, private readonly altimate: AltimateRequest, protected readonly telemetry: TelemetryService, private readonly terminal: DBTTerminal, protected readonly eventEmitterService: SharedStateService, protected readonly queryManifestService: QueryManifestService, protected readonly usersService: UsersService ) { super( dbtProjectContainer, altimate, telemetry, eventEmitterService, terminal, queryManifestService, usersService ); }This change would eliminate the need for separate property declarations.
149-155
: LGTM! Improved command handling with sync request tracking. Consider adding a default error handler.The changes to the
handleCommand
method are good:
- The addition of
syncRequestId
improves request-response tracking.- The call to
super.handleCommand(message)
ensures proper inheritance behavior.Consider adding a default error handler for unhandled commands before calling the super method. This could improve error reporting and debugging. For example:
if (!handled) { console.warn(`Unhandled command: ${command}`); // Optionally, send an error response to the webview this._panel?.webview.postMessage({ command: "response", args: { id, syncRequestId, error: "Unhandled command", status: false }, }); } super.handleCommand(message);This addition would help catch and report any commands that aren't explicitly handled in this class or its superclass.
Also applies to: 165-165, 174-174, 183-183, 192-192, 202-202, 231-231, 236-236, 277-277, 298-298, 311-311
897-899
: LGTM! Improved null safety. Consider enhancing error handling.The changes in
getMissingLineageMessage
are good:
- The use of
queryManifestService
is consistent with the overall refactoring.- The null-safe call operator
?.
prevents potential null reference errors.Consider enhancing the error handling to provide more specific error messages. For example:
try { const project = this.queryManifestService.getProject(); if (!project) { return { message: "No active dbt project found", type: "error" }; } project.throwDiagnosticsErrorIfAvailable(); } catch (err) { return { message: `Error in dbt project: ${(err as Error).message}`, type: "error" }; }This change would provide more context in the error message, making it easier for users to understand and troubleshoot issues.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- src/webview_provider/newLineagePanel.ts (24 hunks)
🧰 Additional context used
🔇 Additional comments (3)
src/webview_provider/newLineagePanel.ts (3)
32-35
: LGTM! Improved modularity and service-oriented architecture.The changes to the import statements and class declaration show a shift towards a more modular and service-oriented architecture. This is a positive change as it:
- Improves maintainability by separating concerns.
- Enhances testability by allowing easier mocking of dependencies.
- Promotes code reuse through the use of shared services.
Also applies to: 73-76
Line range hint
1-963
: Overall, great improvements to modularity and maintainability!The refactoring of
NewLineagePanel
represents a significant improvement to the codebase:
- The shift towards a service-oriented architecture enhances modularity and testability.
- Improved error handling and null checks increase robustness.
- Consistent use of
queryManifestService
centralizes data retrieval logic.While there are some areas for potential further improvement (as noted in previous comments), these changes lay a solid foundation for easier maintenance and future enhancements.
959-963
: LGTM! Simplified rendering. Verify webview script execution.The simplification of
renderWebviewView
is good:
- It reduces code duplication by using the superclass's
getHtml
method.- It makes the code more maintainable and consistent with the base class implementation.
Please verify that removing the
webview.options = { enableScripts: true }
setting doesn't affect the functionality of the webview. If scripts are required in the webview, ensure that this setting is properly handled in the superclass or add it back if necessary.Run the following script to check if
enableScripts
is set in the superclass:If the script doesn't find any results, consider adding the
enableScripts
option back to this method.✅ Verification successful
Verified:
enableScripts
is enabled in the superclass.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if enableScripts is set in AltimateWebviewProvider # Test: Search for enableScripts in AltimateWebviewProvider rg -A 5 'enableScripts' src/webview_provider/altimateWebviewProvider.tsLength of output: 253
const event = this.queryManifestService.getEventByCurrentProject(); | ||
if (!event?.event) { |
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.
🛠️ Refactor suggestion
Consider abstracting repeated null checks into a helper method.
The use of queryManifestService
to retrieve project and event data is a good practice. However, the repeated null checks for event
and project
in multiple methods introduce code duplication.
Consider creating a helper method to perform these checks, which would reduce code duplication and improve maintainability. For example:
private getEventAndProject(): { event: ManifestCacheProjectAddedEvent['event'], project: DBTProject } | undefined {
const event = this.queryManifestService.getEventByCurrentProject();
if (!event?.event) {
return undefined;
}
const project = this.queryManifestService.getProject();
if (!project) {
return undefined;
}
return { event: event.event, project };
}
You can then use this helper method in place of the repeated checks throughout the class:
const eventAndProject = this.getEventAndProject();
if (!eventAndProject) {
return;
}
const { event, project } = eventAndProject;
This refactoring would make the code more DRY and easier to maintain.
Also applies to: 382-382, 412-413, 416-416, 541-542, 545-545
const event = this.queryManifestService.getEventByCurrentProject(); | ||
if (!event?.event) { |
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.
🛠️ Refactor suggestion
Consider further simplification of table-related methods.
The changes to use queryManifestService
in getConnectedTables
and createTable
are consistent with the overall refactoring. However, these methods still contain complex logic that could potentially be simplified.
Consider the following improvements:
-
Extract the logic for creating different types of tables (source, metric, exposure, etc.) into separate methods or a factory class. This would make the
createTable
method more readable and easier to maintain. -
Use early returns in
getConnectedTables
to reduce nesting and improve readability. For example:
private getConnectedTables(key: keyof GraphMetaMap, table: string): Table[] | undefined {
const event = this.queryManifestService.getEventByCurrentProject();
if (!event?.event) return;
const { graphMetaMap } = event.event;
const dependencyNodes = graphMetaMap[key];
const node = dependencyNodes.get(table);
if (!node) return;
const tables = new Map<string, Table>();
node.nodes.forEach(({ url, key }) => {
const _node = this.createTable(event.event!, url, key);
if (_node && !tables.has(_node.table)) {
tables.set(_node.table, _node);
}
});
return Array.from(tables.values()).sort((a, b) => a.table.localeCompare(b.table));
}
These changes would improve the overall structure and readability of the code.
Also applies to: 762-762, 770-772
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: 4
🧹 Outside diff range and nitpick comments (1)
webview_panels/src/modules/lineage/LineageView.tsx (1)
38-38
: Remove debugging log statementsThere are log statements with the message "thisisiit" that appear to be left over from debugging. To maintain clean and readable code, consider removing or updating these log statements.
Apply this diff to clean up the log statements:
- panelLogger.log("thisisiit", "render"); - panelLogger.log("thisisiit", "ApiHelper.get", url, data); - panelLogger.log("thisisiit", renderNode);Also applies to: 48-48, 122-122
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- webview_panels/src/modules/lineage/LineageView.tsx (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
webview_panels/src/modules/lineage/LineageView.tsx
[warning] 98-98: Missing origin verification in
postMessage
handler
Postmessage handler has no origin check.
} | ||
|
||
// const lineageType = renderNode.details ? "sql" : "dynamic"; | ||
const lineageType = "dynamic" as "dynamic" | "sql"; |
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.
Determine lineage type dynamically instead of hardcoding
Currently, lineageType
is hardcoded to "dynamic"
. To ensure the component behaves correctly in all scenarios, determine the lineage type based on the available data.
Apply this diff to set lineageType
dynamically:
- const lineageType = "dynamic" as "dynamic" | "sql";
+ const lineageType = renderNode.details ? "sql" : "dynamic";
This change uses the presence of renderNode.details
to decide the lineage type.
Committable suggestion was skipped due to low confidence.
if (!event.origin.startsWith("vscode-webview://")) { | ||
panelLogger.debug("invalid message ", event); | ||
return; | ||
} |
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.
🛠️ Refactor suggestion
Improve origin verification in message event handler
The current origin check using event.origin.startsWith("vscode-webview://")
may not be reliable, as event.origin
can be an empty string in VSCode webviews. Consider verifying the message source by checking event.source
or implementing a more robust message validation mechanism.
Apply this diff to enhance security:
- if (!event.origin.startsWith("vscode-webview://")) {
+ if (event.source !== window.parent) {
panelLogger.debug("invalid message ", event);
return;
}
Ensure that event.source
correctly identifies messages from the expected source.
📝 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.
if (!event.origin.startsWith("vscode-webview://")) { | |
panelLogger.debug("invalid message ", event); | |
return; | |
} | |
if (event.source !== window.parent) { | |
panelLogger.debug("invalid message ", event); | |
return; | |
} |
// @ts-expect-error TODO: add type generic for executeRequestInSync | ||
ApiHelper.get = async (url: string, data?: Record<string, unknown>) => { | ||
panelLogger.log("thisisiit", "ApiHelper.get", url, data); | ||
switch (url) { | ||
case "init": { | ||
const event = new CustomEvent("renderStartNode", { | ||
detail: _data, | ||
}); | ||
document.dispatchEvent(event); | ||
return; | ||
} | ||
case "upstreamTables": | ||
case "downstreamTables": | ||
case "getExposureDetails": | ||
case "getColumns": | ||
case "getConnectedColumns": | ||
case "sendFeedback": | ||
case "getLineageSettings": | ||
case "persistLineageSettings": | ||
case "openFile": | ||
case "openChat": | ||
case "showInfoNotification": | ||
case "previewFeature": | ||
case "telemetryEvents": | ||
return executeRequestInSync(url, { args: { params: data ?? {} } }); | ||
case "columnLineage": | ||
return executeRequestInSync(url, { args: data }); | ||
|
||
default: | ||
break; | ||
} | ||
}; |
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.
Avoid overwriting imported module methods directly
Overwriting ApiHelper.get
directly can lead to unexpected behavior and makes the code harder to maintain and test. Consider using dependency injection or a wrapper function to achieve the desired behavior without modifying the imported module.
Apply this diff to refactor the code:
- // @ts-expect-error TODO: add type generic for executeRequestInSync
- ApiHelper.get = async (url: string, data?: Record<string, unknown>) => {
- // Implementation
- };
+ // Consider creating a custom API helper or passing necessary functions as props
Committable suggestion was skipped due to low confidence.
useEffect(() => { | ||
const commandMap = { | ||
render, | ||
columnLineage: (data: { event: CllEvents }) => { | ||
columnLineage(data); | ||
}, | ||
}; | ||
|
||
window.addEventListener( | ||
"message", | ||
( | ||
event: MessageEvent<{ command: string; args: Record<string, unknown> }>, | ||
) => { | ||
if (!event.origin.startsWith("vscode-webview://")) { | ||
panelLogger.debug("invalid message ", event); | ||
return; | ||
} | ||
|
||
panelLogger.log("lineage:message -> ", JSON.stringify(event.data)); | ||
const { command, args } = event.data; | ||
|
||
if (command in commandMap) { | ||
( | ||
commandMap[command as keyof typeof commandMap] as ( | ||
args: Record<string, unknown>, | ||
) => void | ||
)(args); | ||
} | ||
}, | ||
); | ||
|
||
panelLogger.info("lineage:onload"); | ||
document.documentElement.classList.add(styles.lineageBody); | ||
executeRequestInAsync("init", {}); | ||
}, []); |
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 cleanup for event listeners in useEffect
The useEffect
hook adds an event listener to the window but does not remove it upon component unmounting, which can lead to memory leaks or unwanted behavior. Return a cleanup function to remove the event listener when the component unmounts.
Apply this diff to ensure proper cleanup:
useEffect(() => {
const commandMap = {
render,
columnLineage: (data: { event: CllEvents }) => {
columnLineage(data);
},
};
+ const messageHandler = (
+ event: MessageEvent<{ command: string; args: Record<string, unknown> }>,
+ ) => {
+ // Existing event handler code
+ };
+
- window.addEventListener(
- "message",
- (
- event: MessageEvent<{ command: string; args: Record<string, unknown> }>,
- ) => {
- // Existing event handler code
- },
- );
+ window.addEventListener("message", messageHandler);
panelLogger.info("lineage:onload");
document.documentElement.classList.add(styles.lineageBody);
executeRequestInAsync("init", {});
+ return () => {
+ window.removeEventListener("message", messageHandler);
+ };
}, []);
📝 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.
useEffect(() => { | |
const commandMap = { | |
render, | |
columnLineage: (data: { event: CllEvents }) => { | |
columnLineage(data); | |
}, | |
}; | |
window.addEventListener( | |
"message", | |
( | |
event: MessageEvent<{ command: string; args: Record<string, unknown> }>, | |
) => { | |
if (!event.origin.startsWith("vscode-webview://")) { | |
panelLogger.debug("invalid message ", event); | |
return; | |
} | |
panelLogger.log("lineage:message -> ", JSON.stringify(event.data)); | |
const { command, args } = event.data; | |
if (command in commandMap) { | |
( | |
commandMap[command as keyof typeof commandMap] as ( | |
args: Record<string, unknown>, | |
) => void | |
)(args); | |
} | |
}, | |
); | |
panelLogger.info("lineage:onload"); | |
document.documentElement.classList.add(styles.lineageBody); | |
executeRequestInAsync("init", {}); | |
}, []); | |
useEffect(() => { | |
const commandMap = { | |
render, | |
columnLineage: (data: { event: CllEvents }) => { | |
columnLineage(data); | |
}, | |
}; | |
const messageHandler = ( | |
event: MessageEvent<{ command: string; args: Record<string, unknown> }>, | |
) => { | |
if (!event.origin.startsWith("vscode-webview://")) { | |
panelLogger.debug("invalid message ", event); | |
return; | |
} | |
panelLogger.log("lineage:message -> ", JSON.stringify(event.data)); | |
const { command, args } = event.data; | |
if (command in commandMap) { | |
( | |
commandMap[command as keyof typeof commandMap] as ( | |
args: Record<string, unknown>, | |
) => void | |
)(args); | |
} | |
}; | |
window.addEventListener("message", messageHandler); | |
panelLogger.info("lineage:onload"); | |
document.documentElement.classList.add(styles.lineageBody); | |
executeRequestInAsync("init", {}); | |
return () => { | |
window.removeEventListener("message", messageHandler); | |
}; | |
}, []); |
🧰 Tools
🪛 GitHub Check: CodeQL
[warning] 98-98: Missing origin verification in
postMessage
handler
Postmessage handler has no origin check.
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: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- webview_panels/src/modules/lineage/LineageView.tsx (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeQL
webview_panels/src/modules/lineage/LineageView.tsx
[warning] 96-96: Missing origin verification in
postMessage
handler
Postmessage handler has no origin check.
// @ts-expect-error TODO: add type generic for executeRequestInSync | ||
ApiHelper.get = async (url: string, data?: Record<string, unknown>) => { |
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.
Resolve TypeScript errors instead of suppressing them
The @ts-expect-error
directive suppresses a TypeScript error. It's better to properly type executeRequestInSync
to ensure type safety and prevent potential runtime issues.
Update the type definitions to include generic types for executeRequestInSync
, eliminating the need for the @ts-expect-error
comment.
( | ||
event: MessageEvent<{ command: string; args: Record<string, unknown> }>, | ||
) => { | ||
panelLogger.log("lineage:message -> ", JSON.stringify(event.data)); |
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.
Sanitize user-provided data before logging
Logging user-provided data directly can introduce security risks like log injection. Consider sanitizing or validating event.data
before logging.
Update the logging statement to ensure safe logging practices:
- panelLogger.log("lineage:message -> ", JSON.stringify(event.data));
+ const sanitizedData = sanitizeEventData(event.data);
+ panelLogger.log("lineage:message -> ", JSON.stringify(sanitizedData));
Implement sanitizeEventData
to properly sanitize the data before logging.
Committable suggestion was skipped due to low confidence.
// @ts-expect-error TODO: add type generic for executeRequestInSync | ||
ApiHelper.get = async (url: string, data?: Record<string, unknown>) => { | ||
switch (url) { | ||
case "upstreamTables": | ||
case "downstreamTables": | ||
case "getExposureDetails": | ||
case "getColumns": | ||
case "getConnectedColumns": | ||
case "sendFeedback": | ||
case "getLineageSettings": | ||
case "persistLineageSettings": | ||
case "init": | ||
case "openFile": | ||
case "openChat": | ||
case "showInfoNotification": | ||
case "previewFeature": | ||
case "telemetryEvents": | ||
return executeRequestInSync(url, { args: { params: data ?? {} } }); | ||
case "columnLineage": | ||
return executeRequestInSync(url, { args: data }); | ||
|
||
default: | ||
break; | ||
} | ||
}; |
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.
🛠️ Refactor suggestion
Avoid overwriting imported module methods directly
Overwriting ApiHelper.get
can lead to unexpected behavior and make the code harder to maintain and test. Consider using a custom API helper or dependency injection instead of modifying the imported module.
Create a custom API helper instance:
- // @ts-expect-error TODO: add type generic for executeRequestInSync
- ApiHelper.get = async (url: string, data?: Record<string, unknown>) => {
- // Implementation
- };
+ const customApiHelper = {
+ get: async (url: string, data?: Record<string, unknown>) => {
+ // Implementation
+ },
+ };
Then use customApiHelper.get
instead of ApiHelper.get
in your component.
📝 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.
// @ts-expect-error TODO: add type generic for executeRequestInSync | |
ApiHelper.get = async (url: string, data?: Record<string, unknown>) => { | |
switch (url) { | |
case "upstreamTables": | |
case "downstreamTables": | |
case "getExposureDetails": | |
case "getColumns": | |
case "getConnectedColumns": | |
case "sendFeedback": | |
case "getLineageSettings": | |
case "persistLineageSettings": | |
case "init": | |
case "openFile": | |
case "openChat": | |
case "showInfoNotification": | |
case "previewFeature": | |
case "telemetryEvents": | |
return executeRequestInSync(url, { args: { params: data ?? {} } }); | |
case "columnLineage": | |
return executeRequestInSync(url, { args: data }); | |
default: | |
break; | |
} | |
}; | |
const customApiHelper = { | |
get: async (url: string, data?: Record<string, unknown>) => { | |
switch (url) { | |
case "upstreamTables": | |
case "downstreamTables": | |
case "getExposureDetails": | |
case "getColumns": | |
case "getConnectedColumns": | |
case "sendFeedback": | |
case "getLineageSettings": | |
case "persistLineageSettings": | |
case "init": | |
case "openFile": | |
case "openChat": | |
case "showInfoNotification": | |
case "previewFeature": | |
case "telemetryEvents": | |
return executeRequestInSync(url, { args: { params: data ?? {} } }); | |
case "columnLineage": | |
return executeRequestInSync(url, { args: data }); | |
default: | |
break; | |
} | |
}, | |
}; |
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
🧹 Outside diff range and nitpick comments (3)
src/webview_provider/altimateWebviewProvider.ts (3)
640-640
: Add validation for viewPathWhile the implementation works, it would be safer to validate the viewPath format before using it as a class name.
Consider sanitizing the viewPath:
-<body class="${this.viewPath.replace(/\//g, "")}"> +<body class="${this.viewPath.replace(/[^a-zA-Z0-9-_]/g, "")}">This ensures only alphanumeric characters, hyphens, and underscores are used in class names, preventing potential CSS injection or invalid class names.
643-643
: Enhance modal accessibilityThe modal div should include ARIA attributes for better accessibility.
Consider adding ARIA attributes:
-<div id="modal"></div> +<div id="modal" role="dialog" aria-modal="true"></div>
647-647
: Improve type safety for window object extensionThe lineageGif variable is added to the window object without proper TypeScript type definitions.
Consider adding type definitions:
// Add to a separate .d.ts file or at the top of this file declare global { interface Window { viewPath: string; spinnerUrl: string; lineageGif: string; } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- src/webview_provider/altimateWebviewProvider.ts (3 hunks)
🔇 Additional comments (1)
src/webview_provider/altimateWebviewProvider.ts (1)
526-535
: Optimize webview ready check implementationThe current implementation has potential issues:
- Uses
setInterval
which is less efficient than a recursivesetTimeout
approach- No timeout mechanism to prevent infinite polling
The previous review comment suggesting improvements to this implementation is still valid. Please refer to the existing comment for the recommended implementation using
setTimeout
with a timeout mechanism.
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
🧹 Outside diff range and nitpick comments (3)
webview_panels/src/lib/altimate/altimate-components.js (2)
1-1
: Consider improving import naming for better maintainability.The extensive use of single-letter aliases (
o
,t
,n
, etc.) in imports makes the code harder to maintain and understand. Consider using more descriptive names that reflect the actual component or utility being imported.Example of a more maintainable import:
- import { A as o, B as t, m as n, p as i, o as r, n as m, r as C, t as T, C as l, E as c, k as p, i as g, h as v, D as L, I as u, x as h, l as B, L as M, P as d, F as A, J as b, H as k, q as y, y as F, z as P, w as x, T as D, G as I, v as S } from "./main.js"; + import { + ApiHelperComponent as ApiHelper, + BadgeComponent as Badge, + CLLComponent as CLL, + // ... other imports with meaningful names + } from "./main.js";
1-32
: Update README.md with component changes.As mentioned in the PR checklist, the README.md hasn't been updated. Given the significant component renaming and restructuring, documentation should be updated to reflect these changes.
Would you like me to help create a documentation section that covers:
- The new component naming scheme
- Any breaking changes in the exports
- Migration guide for existing code
webview_panels/src/lib/altimate/altimate-components.d.ts (1)
353-356
: Consider documenting the status types for onStatusUpdateThe Props_9 interface changes look good, adding proper type safety for status updates and follow-up requests. Consider documenting the possible values for the status
type
string to help implementers.Add JSDoc comments to document the possible status types:
/** Props for the Chatbot component */ interface Props_9 extends ProChatProps<any> { /** Callback for handling chat requests * @param messages The chat messages to process * @param sessionId The current session identifier * @param onStatusUpdate Callback for status updates * @param onStatusUpdate.type The type of status update (e.g., 'processing', 'error', 'complete') * @param onStatusUpdate.message A human-readable status message */ onRequest: (messages: ChatMessage[], sessionId: string, onStatusUpdate: (info: { type: string; message: string; }) => void) => any; /** Optional callback for handling follow-up requests * @param sessionId The current session identifier * @returns Promise resolving to an array of follow-up suggestions or undefined */ onFollowupRequest?: (sessionId: string) => Promise<string[] | undefined>; }Also applies to: 358-358
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
- webview_panels/src/lib/altimate/altimate-components.d.ts (2 hunks)
- webview_panels/src/lib/altimate/altimate-components.js (1 hunks)
🔇 Additional comments (3)
webview_panels/src/lib/altimate/altimate-components.js (1)
3-32
: Verify the impact of renamed exports on dependent code.The extensive renaming of exports (e.g.,
Chatbot
toChatTriggerLink
,CllEvents
toChatbot
) could potentially break existing code that imports these components.Let's verify the usage of these renamed exports:
webview_panels/src/lib/altimate/altimate-components.d.ts (2)
22-22
: LGTM: Well-structured Chatbot component declarationThe updated Chatbot component declaration with the optional
onFollowupRequest
parameter follows TypeScript best practices.
24-26
: Verify the integration of ChatTriggerLink with lineage componentsThe ChatTriggerLink component declaration looks good. Since this is part of the lineage refactoring, let's verify its integration.
import { A as o, B as t, m as n, p as i, o as r, n as m, r as C, t as T, C as l, E as c, k as p, i as g, h as v, D as L, I as u, x as h, l as B, L as M, P as d, F as A, J as b, H as k, q as y, y as F, z as P, w as x, T as D, G as I, v as S } from "./main.js"; | ||
import "reactstrap"; | ||
export { | ||
o as ApiHelper, | ||
t as Badge, | ||
n as CLL, | ||
i as Chatbot, | ||
r as CllEvents, | ||
m as CoachForm, | ||
C as CoachFormButton, | ||
i as ChatTriggerLink, | ||
r as Chatbot, | ||
m as CllEvents, | ||
C as CoachForm, | ||
T as CoachFormButton, | ||
l as CodeBlock, | ||
T as ContentCategory, | ||
c as ConversationGroupProvider, | ||
p as ConversationInputForm, | ||
c as ContentCategory, | ||
p as ConversationGroupProvider, | ||
g as ConversationInputForm, | ||
v as ConversationSources, | ||
g as DbtDocs, | ||
L as DbtDocs, | ||
u as IconButton, | ||
L as Learnings, | ||
h as Learnings, | ||
B as Lineage, | ||
M as LoadingButton, | ||
d as PersonalizationScope, | ||
h as TaskLabels, | ||
A as TeamMateActionType, | ||
b as TeamMateAvailability, | ||
A as TaskLabels, | ||
b as TeamMateActionType, | ||
k as TeamMateAvailability, | ||
y as TeamMateProvider, | ||
F as TeamMates, | ||
P as TeamMatesConfig, | ||
k as TeammateActions, | ||
x as Tooltip, | ||
D as learningSchema, | ||
I as useTeamMateContext | ||
x as TeammateActions, | ||
D as Tooltip, | ||
I as learningSchema, | ||
S as useTeamMateContext |
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.
🛠️ Refactor suggestion
Consider grouping related exports for better organization.
The exports appear to be alphabetically ordered but could benefit from logical grouping based on functionality (e.g., Chat-related, Team-related, UI components).
Example organization:
// Chat & Communication
export { ChatTriggerLink, Chatbot, CllEvents };
// Coaching & Learning
export { CoachForm, CoachFormButton, DbtDocs, Learnings, learningSchema };
// Team Management
export {
TeamMateActionType,
TeamMateAvailability,
TeamMateProvider,
TeamMates,
TeamMatesConfig,
TeammateActions,
useTeamMateContext
};
// UI Components
export { Badge, CodeBlock, IconButton, LoadingButton, Tooltip };
// Utilities
export { ApiHelper, ConversationGroupProvider };
Overview
Problem
Extract lineage component for better maintainability
Solution
Screenshot/Demo
A picture is worth a thousand words. Please highlight the changes if applicable.
How to test
dbt.enableLineageV2
as true in settings.jsonChecklist
README.md
updated and added information about my changeSummary by CodeRabbit
Release Notes
New Features
LineageDemo
component for rendering a GIF in the icon set..modal-content
CSS class for improved styling in the webview.DemoButton
component for displaying a demo modal with a close button.LineageView
component for managing lineage data display and interactions.Improvements
NewLineagePanel
andSQLLineagePanel
.QueryResultPanel
during query execution.Chatbot
component for better follow-up request handling.Refactor
NewLineagePanel
andSQLLineagePanel
classes for better modularity and service integration.Bug Fixes