Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: lineage refactor #1212

Merged
merged 55 commits into from
Oct 28, 2024
Merged

feat: lineage refactor #1212

merged 55 commits into from
Oct 28, 2024

Conversation

saravmajestic
Copy link
Collaborator

@saravmajestic saravmajestic commented Jun 13, 2024

Overview

Problem

Extract lineage component for better maintainability

Solution

  • Created separate components for lineage

Screenshot/Demo

A picture is worth a thousand words. Please highlight the changes if applicable.

How to test

  • enable feature flag: dbt.enableLineageV2 as true in settings.json
  • verify lineage panel, sql visualizer
  • all functionalities should as existing

Checklist

  • I have run this code and it appears to resolve the stated issue
  • README.md updated and added information about my change

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced new LineageDemo component for rendering a GIF in the icon set.
    • Added a new .modal-content CSS class for improved styling in the webview.
    • New DemoButton component for displaying a demo modal with a close button.
    • Added LineageView component for managing lineage data display and interactions.
  • Improvements

    • Enhanced webview readiness checks and streamlined rendering processes in the NewLineagePanel and SQLLineagePanel.
    • Improved error handling in the QueryResultPanel during query execution.
    • Enhanced Chatbot component for better follow-up request handling.
  • Refactor

    • Refactored NewLineagePanel and SQLLineagePanel classes for better modularity and service integration.
    • Updated handling of SQL lineage details for clarity and consistency.
  • Bug Fixes

    • Fixed issues with command handling and response tracking in the webview components.

@saravmajestic saravmajestic self-assigned this Jun 13, 2024
window.addEventListener(
"message",
(
event: MessageEvent<{ command: string; args: Record<string, unknown> }>,

Check warning

Code scanning / CodeQL

Missing origin verification in `postMessage` handler Medium

Postmessage handler has no origin check.

Copilot Autofix AI 5 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.

  1. Identify the trusted origins for your application.
  2. Modify the postMessage handler to include a check for the event.origin.
  3. If the origin is trusted, proceed with the existing logic; otherwise, ignore the message or log a warning.
Suggested changeset 1
webview_panels/src/modules/lineage/LineageView.tsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/webview_panels/src/modules/lineage/LineageView.tsx b/webview_panels/src/modules/lineage/LineageView.tsx
--- a/webview_panels/src/modules/lineage/LineageView.tsx
+++ b/webview_panels/src/modules/lineage/LineageView.tsx
@@ -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));
EOF
@@ -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));
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
@@ -173,14 +173,6 @@ export class LineagePanel implements WebviewViewProvider, Disposable {
return;
}

if (command === "openURL") {
Copy link
Collaborator Author

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() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to altimateWebviewProvider

@saravmajestic saravmajestic marked this pull request as ready for review July 9, 2024 07:55
@saravmajestic saravmajestic changed the title feat: lineage v2 feat: lineage refactor Jul 9, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 cancellation

The 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 if cancellationTokenSource 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 getMissingLineageMessage

The code now uses optional chaining (?.) when calling throwDiagnosticsErrorIfAvailable(), 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

📥 Commits

Files that changed from the base of the PR and between f2cdd96 and a28d423.

📒 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 injection

The NewLineagePanel class has been refactored to extend AltimateWebviewProvider and implement LineagePanelView. 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 support

The handleCommand method signature has been updated to include an optional syncRequestId. 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 messages

The 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 class

The handleCommand method now correctly delegates to the parent class implementation using super.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 object

The code now correctly uses event.event when calling DBTProject.getNonEphemeralParents, ensuring that the correct data is passed to the method. This change aligns with the updated structure of the event object.

Also applies to: 582-583


619-621: Efficient bulk compilation of SQL

The 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 method

The 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 enabled

The 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 method

The 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:

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 refactoring

The updates to the handleCommand method, including the addition of syncRequestId 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 refactoring getConnectedColumns for improved maintainability

The 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

📥 Commits

Files that changed from the base of the PR and between a28d423 and bbd65e4.

📒 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 injection

The refactoring of NewLineagePanel to extend AltimateWebviewProvider 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 rendering

The 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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:

  1. The addition of syncRequestId improves request-response tracking.
  2. 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:

  1. The use of queryManifestService is consistent with the overall refactoring.
  2. 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

📥 Commits

Files that changed from the base of the PR and between bbd65e4 and 3bcb5ae.

📒 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:

  1. Improves maintainability by separating concerns.
  2. Enhances testability by allowing easier mocking of dependencies.
  3. 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:

  1. The shift towards a service-oriented architecture enhances modularity and testability.
  2. Improved error handling and null checks increase robustness.
  3. 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:

  1. It reduces code duplication by using the superclass's getHtml method.
  2. 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.ts

Length of output: 253

Comment on lines +378 to +379
const event = this.queryManifestService.getEventByCurrentProject();
if (!event?.event) {
Copy link
Contributor

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

Comment on lines +758 to +759
const event = this.queryManifestService.getEventByCurrentProject();
if (!event?.event) {
Copy link
Contributor

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:

  1. 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.

  2. 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

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 statements

There 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

📥 Commits

Files that changed from the base of the PR and between 3bcb5ae and f182728.

📒 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";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Comment on lines 100 to 103
if (!event.origin.startsWith("vscode-webview://")) {
panelLogger.debug("invalid message ", event);
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

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.

Suggested change
if (!event.origin.startsWith("vscode-webview://")) {
panelLogger.debug("invalid message ", event);
return;
}
if (event.source !== window.parent) {
panelLogger.debug("invalid message ", event);
return;
}

Comment on lines 46 to 77
// @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;
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Comment on lines 87 to 121
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", {});
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Files that changed from the base of the PR and between f182728 and 8519f62.

📒 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.

Comment on lines +36 to +37
// @ts-expect-error TODO: add type generic for executeRequestInSync
ApiHelper.get = async (url: string, data?: Record<string, unknown>) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Comment on lines +36 to +60
// @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;
}
};
Copy link
Contributor

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.

Suggested change
// @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;
}
},
};

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 viewPath

While 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 accessibility

The 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 extension

The 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

📥 Commits

Files that changed from the base of the PR and between 8519f62 and ebdafe9.

📒 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 implementation

The current implementation has potential issues:

  1. Uses setInterval which is less efficient than a recursive setTimeout approach
  2. 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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:

  1. The new component naming scheme
  2. Any breaking changes in the exports
  3. Migration guide for existing code
webview_panels/src/lib/altimate/altimate-components.d.ts (1)

353-356: Consider documenting the status types for onStatusUpdate

The 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

📥 Commits

Files that changed from the base of the PR and between ebdafe9 and c1c03fe.

📒 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 to ChatTriggerLink, CllEvents to Chatbot) 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 declaration

The updated Chatbot component declaration with the optional onFollowupRequest parameter follows TypeScript best practices.


24-26: Verify the integration of ChatTriggerLink with lineage components

The ChatTriggerLink component declaration looks good. Since this is part of the lineage refactoring, let's verify its integration.

Comment on lines +1 to +32
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
Copy link
Contributor

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 };

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants