Skip to content
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(connections-navigation): connect in new window via connect split-button COMPASS-8473 #6577

Merged
merged 20 commits into from
Feb 14, 2025

Conversation

kraenhansen
Copy link
Contributor

@kraenhansen kraenhansen commented Dec 19, 2024

Description

Merging this PR will:

  • Adjust the "connect button" in the sidebar to display a SplitButton with a dropdown menu, containing options to "Connect Here" and "Connect in a New Window".
  • Adding the concept of the ItemActionControls being "hideable" (through the setHideable callback) allowing children (the ConnectButton in particular) to prevent the controls from being hidden once the cursor leaves the connection row. I use this to prevent controls (hence SplitButton and it's Menu) to be removed from the tree as the cursor is moved out of the ConnectButton, across and into the menu: If the menu is opened, the controls stay visible.
  • Propagate events through "connection actions" → "connections Redux store" → "globalAppRegistry" → Main IPC → Window Manager to finally create a new window and ultimately storing a "connection id" in main-process state associated with this window.
  • Auto-connect the newly created window from the associated state.
  • For consistency, I added auto-connect when invoked as a CLI and a connection ID is passed.
compass-connect-in-new-window.mov

TODOs

Checklist

  • New tests and/or benchmarks are included
  • Documentation is changed or added

Motivation and Context

  • Bugfix
  • New feature
  • Dependency update
  • Misc

Open Questions

  • I did add support for passing a connection id as positional argument when invoked via the CLI, but is this desirable?

Dependents

Types of changes

  • Backport Needed
  • Patch (non-breaking change which fixes an issue)
  • Minor (non-breaking change which adds functionality)
  • Major (fix or feature that would cause existing functionality to change)

@kraenhansen kraenhansen self-assigned this Dec 19, 2024
@github-actions github-actions bot added the feat label Dec 19, 2024
@kraenhansen kraenhansen force-pushed the kh/connect-in-new-window branch from 9bbdf1c to 1dcbbfb Compare December 19, 2024 23:04
@@ -39,7 +33,7 @@ export type ItemActionControlsProps<Action extends string> = {
'data-testid'?: string;
};

export function ItemActionControls<Action extends string>({
export function ItemActionControls<Action extends string = string>({
Copy link
Contributor

Choose a reason for hiding this comment

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

TIL that you can have a default

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah – it usually just reduces type safety, though, because then consumers are likely to omit the type (and the default is typically the most generic type available).

This also seems to be one of those cases where type safety goes away – I don't seen an obvious reason for that in the rest of the code, though, so maybe in this particular case we could reconsider?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🙂 TBH, it's likely not strictly needed here, since we'll always be using this in a way that can infer the type of this type parameter from the props.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That being said - those changes are actually a part of #6560 (which needs to be reviewed and merged first).

@kraenhansen kraenhansen force-pushed the kh/connect-in-new-window branch 3 times, most recently from cffbfbb to ddc2f45 Compare December 20, 2024 20:26
Copy link
Collaborator

@gribnoysup gribnoysup left a comment

Choose a reason for hiding this comment

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

Overall looks good, would be nice to try to run this locally after leafygreen patch is released

@@ -282,6 +282,8 @@ export const Single = {
export const Multiple = {
ConnectionsTitle: '[data-testid="connections-header"]',
ConnectButton: '[data-action="connection-connect"]',
ConnectInNewWindowButton: '[data-action="connection-connect-in-new-window"]',
ConnectDropdownButton: '[aria-label="see more connection options"]',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Doesn't look like a great selector, anything better we can target here?

Copy link
Contributor Author

@kraenhansen kraenhansen Jan 6, 2025

Choose a reason for hiding this comment

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

What in particular don't you like about this? That it will break if the button label gets updated?

This is targeting a "trigger" button within the SplitButton, but most props are forwarded to the "left most" button: https://github.com/mongodb/leafygreen-ui/blob/main/packages/split-button/src/SplitButton/SplitButton.tsx#L88

This is the trigger I'm targeting 🤔

<button
  data-lgid="lg-button"
  type="button"
  class="lg-ui-button-0000 leafygreen-ui-lt73jo"
  aria-disabled="false"
  aria-label="see more connection options"
  aria-controls="lg-split-button-menu-56"
  aria-expanded="true"
  aria-haspopup="true">
  ...
</button>

Alternatively I can select this relative to its sibling:

[data-testid="sidebar-navigation-item-actions-connection-connect-action"] + button

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't like a brittle selector that targets specifically an aria-label attribute, if leafygreen team changes how they apply a label (for example switching to visually hidden element or using labelledby instead of label directly) this will break. If you want to select by inferred button label, you should use selectors designed for that, either a button=<text> or aria/<text> selectors. You can learn more about wdio selectors in the documentation

Copy link
Collaborator

Choose a reason for hiding this comment

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

We also usually use testid selectors in e2e tests, which are also mentioned as recommented by the documentation, so if we can pass a testid here, that's also an option and consistent with most of the other selectors. If we can't, it might be worth asking leafygreen team to add the option to pass it

Copy link
Contributor Author

@kraenhansen kraenhansen Jan 7, 2025

Choose a reason for hiding this comment

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

I've made a PR for LG adding a constant data-testid attribute to the trigger element: mongodb/leafygreen-ui#2621

Related, I noticed that LG was also selecting the trigger in their test, relative to the other button: https://github.com/mongodb/leafygreen-ui/blob/f5d842764faf5b498f799d1710288ca964a93141/packages/split-button/src/SplitButton/SplitButton.spec.tsx#L52

@kraenhansen kraenhansen force-pushed the kh/connect-in-new-window branch from ce961a6 to 77c4fa7 Compare February 11, 2025 22:19
@kraenhansen kraenhansen force-pushed the kh/connect-in-new-window branch 3 times, most recently from 35118a6 to 9959e8d Compare February 12, 2025 23:18
glyph="OpenNewTab"
onClick={onClick}
>
Connect in a New Window
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this simply "In New Window"

glyph="Connect"
onClick={onClick}
>
Connect Here
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we simplify this to just "Here"

@@ -46,7 +46,7 @@
"@leafygreen-ui/guide-cue": "^7.0.2",
"@leafygreen-ui/hooks": "^8.3.4",
"@leafygreen-ui/icon": "^13.1.2",
"@leafygreen-ui/icon-button": "^16.0.2",
"@leafygreen-ui/icon-button": "16.0.2",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any reason this is pinned now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep. I meant to capture an issue on upgrading this as well, the v16.0.3 release is updating the types of the component, heres a comment on the original LG PR introducing the breaking change: mongodb/leafygreen-ui#2703 (comment)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we have a ticket to follow up with a fix for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we have a ticket to follow up with a fix for that?

Not yet. I'll create that as part of merging this PR - this is what I meant by:

I meant to capture an issue on upgrading this as well

Copy link
Contributor Author

@kraenhansen kraenhansen Feb 14, 2025

Choose a reason for hiding this comment

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

I've created COMPASS-8973 now.

@@ -180,6 +180,7 @@
},
"dependencies": {
"@mongosh/node-runtime-worker-thread": "^3.0.2",
"bson": "^6.10.1",
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a dev dependency

Copy link
Contributor Author

@kraenhansen kraenhansen Feb 13, 2025

Choose a reason for hiding this comment

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

How is that? It's being used at runtime here:

import { UUID } from 'bson';

Is this because you expect this to be included in the Webpack bundle?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This code is bundled with webpack before being packaged, bson ends up bundled within the distribution, this dependency that will be installed with node_modules in "production" will never be required, you're basically just adding some dead code to the packaged application. Only dependencies that are externalized out of the bundle are part of the dependencies list here. This is why most of the dependencies are dev here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. I've moved it to devDependencies

Comment on lines +371 to +374
// Propagate events from global app registry to the main process
globalAppRegistry.on('connect-in-new-window', (connectionId: string) => {
void ipcRenderer?.call('app:connect-in-new-window', connectionId);
});
Copy link
Collaborator

@gribnoysup gribnoysup Feb 13, 2025

Choose a reason for hiding this comment

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

FWIW adding support for web is literally just adding same three lines that call window.open instead of ipcRenderer in compass-web entrypoint and if we want to be extra minimal in the amount of required changes it's just propagating the callback as an interface on compass-web component and dealing with it on mms side

Copy link
Contributor Author

Choose a reason for hiding this comment

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

three lines that call window.open

Ideally, I don't want the compass codebase to make assumptions on what URL it is being rendered at, which is why I wanted to delegate the opening of a separate browser tab to MMS.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Awesome, as I said, even simpler, you can expose the callback as part of the CompassWeb interface and let mms deal with that, we already do this with onActiveWorkspaceTabChange

Copy link
Contributor Author

@kraenhansen kraenhansen Feb 13, 2025

Choose a reason for hiding this comment

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

Makes sense. I've linked to this thread from the COMPASS-8970 ticket.

Copy link
Collaborator

Choose a reason for hiding this comment

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

For next time, please let's discuss excluding features like that before jumping on implementation, not only this is technically and product-wise against the goals of compass-web, we also just added more extra work than the actual implementation would require to ourselves

Copy link
Contributor Author

@kraenhansen kraenhansen Feb 14, 2025

Choose a reason for hiding this comment

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

let's discuss excluding features like that before jumping on implementation

I definitely don't share your sentiment that I've been "jumping on implementation". I have had extensive discussions with @bsradcliffe in Figma on the design and I've implemented this against the design detailed in COMPASS-8381, which has clearly stated the dropdown on "compass-web" as a non-goal:

A few clarifications on the design, since it doesn't have all the details flushed out:

  • Clicking the primary trigger surface connects you immediately in the same window.
  • Button appears on hover of a connection node.
  • Definitely disable dropdown for Compass Web.

this is technically and product-wise against the goals of compass-web

I suppose I've been trusting the goals of our product was incorporated into the design,
but I'll make sure to keep that in mind going forward 👍

we also just added more extra work than the actual implementation would require to ourselves

Please clarify that statement. What extra work? To whom? And compared to what?

Copy link
Contributor Author

@kraenhansen kraenhansen Feb 14, 2025

Choose a reason for hiding this comment

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

We had a zoom call to talk through this ☝️

@kraenhansen kraenhansen force-pushed the kh/connect-in-new-window branch from 9959e8d to 806e5e6 Compare February 13, 2025 12:42
@kraenhansen
Copy link
Contributor Author

kraenhansen commented Feb 13, 2025

@betsybutton this is what it looks like now 👍

Screenshot 2025-02-13 at 11 32 51

@kraenhansen kraenhansen force-pushed the kh/connect-in-new-window branch from 806e5e6 to 37815b1 Compare February 13, 2025 14:12
@kraenhansen kraenhansen marked this pull request as ready for review February 14, 2025 05:09
Copy link
Collaborator

@gribnoysup gribnoysup left a comment

Choose a reason for hiding this comment

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

Hmmm, when running this locally, I'm getting an error in the main console every time I open a connection in the new window:

Error sending from webFrameMain:  Error: Failed to serialize arguments
    at s.send (node:electron/js2c/browser_init:2:91812)
    at _.send (node:electron/js2c/browser_init:2:75243)
    at resolve (webpack://mongodb-compass/../hadron-ipc/src/main.ts?:95:20)
    at IpcMainImpl.eval (webpack://mongodb-compass/../hadron-ipc/src/main.ts?:111:7)
    at IpcMainImpl.emit (node:events:518:28)
    at WebContents.<anonymous> (node:electron/js2c/browser_init:2:85784)
    at WebContents.emit (node:events:518:28)
Error sending from webFrameMain:  Error: Failed to serialize arguments
    at s.send (node:electron/js2c/browser_init:2:91812)
    at _.send (node:electron/js2c/browser_init:2:75243)
    at resolve (webpack://mongodb-compass/../hadron-ipc/src/main.ts?:95:20)
    at IpcMainImpl.eval (webpack://mongodb-compass/../hadron-ipc/src/main.ts?:111:7)
    at IpcMainImpl.emit (node:events:518:28)
    at WebContents.<anonymous> (node:electron/js2c/browser_init:2:85784)
    at WebContents.emit (node:events:518:28)

Have you seen that?

});

it('can connect in new window', async function (this) {
skipForWeb(this, 'connecting in new window is not supported on web');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Leave a TODO here with a ticket numer so that it's easier to find?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a todo 👍

/**
* Enables a dropdown in the connections sidebar to connect in a new window.
*/
enableConnectInNewWindow: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ditto about TODO

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a todo here as well 👍

@gribnoysup
Copy link
Collaborator

Added some logging, a whole browser window is getting passed to the resolve there at some point:

BrowserWindow {
  setBounds: [Function (anonymous)],
  _events: [Object: null prototype] {
    blur: [Function (anonymous)],
    focus: [ [Function (anonymous)], [Function: onFocus] ],
    show: [Function: visibilityChanged],
    hide: [Function: visibilityChanged],
    minimize: [Function: visibilityChanged],
    maximize: [Function: visibilityChanged],
    restore: [Function: visibilityChanged],
    closed: [ [Function (anonymous)], [Function], [Function] ],
    'ready-to-show': [Function: bound onceWrapper] { listener: [Function: resolver] },
    error: [Function: bound onceWrapper] {
      listener: [Function: errorListener]
    }
  },
  _eventsCount: 10,
  _browserViews: [],
  devToolsWebContents: [Getter]
}
Error sending from webFrameMain:  Error: Failed to serialize arguments

Copy link
Collaborator

@gribnoysup gribnoysup left a comment

Choose a reason for hiding this comment

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

Awesome work! Happy to see this landing in main!

@kraenhansen kraenhansen merged commit a203c74 into main Feb 14, 2025
35 checks passed
@kraenhansen kraenhansen deleted the kh/connect-in-new-window branch February 14, 2025 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants