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

fix(compass-connections, sidebar): move all connection related logic and state to compass-connections COMPASS-8067 #6059

Merged
merged 11 commits into from
Jul 29, 2024

Conversation

gribnoysup
Copy link
Collaborator

@gribnoysup gribnoysup commented Jul 25, 2024

The goal of this patch is to fix various inconsistencies in connection logic caused by the logic being spread across two places in the application. The issue was highlighted by the autoconnection flow just not working as expected at all, but the fix was not possible to do in a clean way without refactoring the connection store as the store shape was just not accounting for multiple connection mode at all (it's honestly mostly luck that e2e tests were still passing, mostly because even in multiple connections mode we're still testing more or less a single connection flow at a time).

The main changes to the store that this patch introduces:

  • Remove activeConnectionId, connectingConnectionId states: they don't make any sense in the multiple connection world
  • Remove state that can be derived or already provided by other hooks, like connections list or connection status / status text
  • Generally align the reducer following Redux style guide (which is only somewhat possible because React reducers work differently and doesn't allow to follow all the best practices): meaningful UI event based actions, no derived state in store, etc.
  • Remove all the "legacy" prefixed methods and logic: there is nothing in the connection flow or connection state methods that would require us to export legacy methods and not share the same ones between two modes, all the switch logic can be done in place by just checking the feature flag if needed
  • Move "Non genuine" modal and connection flow toasts to compass-connections: showing those is part of the connection flow logic and the UI is related to the connections

I want to note that it's not the final shape of this store, it's still not aligned with Compass architecture and using React reduxers here puts some restrictions on how separated the logic can be and the async nature of state updates spread around here.

For the reviewer: connections-store.tsx file is probably the main one to focus on, it changed a lot because very little of the old store was relevant and had to be adjusted for multiple connections to work, so it would probably be easier to just read through it as if it's a new file and not a diff.

I'll try to leave comments in places that I think are most notable, but if something doesn't make sense, please ask for clarifications!

@gribnoysup gribnoysup added feature flagged PRs labeled with this label will not be included in the release notes of the next release fix labels Jul 25, 2024
@gribnoysup gribnoysup force-pushed the compass-8067-consolidate-connection-store-logic branch from 8408ac4 to 41e9d44 Compare July 25, 2024 13:44
};

if (duplicate.favorite?.name) {
const copyFormat = duplicate.favorite?.name.match(/(.*)\s\(([0-9])+\)/); // title (2) -> [title (2), title, 2]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this missing anchors? Otherwise we match something like foo (2) bar as well and lose everything after the closing parenthesis

Suggested change
const copyFormat = duplicate.favorite?.name.match(/(.*)\s\(([0-9])+\)/); // title (2) -> [title (2), title, 2]
const copyFormat = duplicate.favorite?.name.match(/^(.*)\s\(([0-9])+\)$/); // title (2) -> [title (2), title, 2]

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch! I'll fix this implementation and add a test (we can also probably reduce the complexity of the algorithm there by reducing to the highest number right away instead of looping over for every number 🤔)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in ade3ada, also fixed handling multi digit numbers

error: error as Error,
// Autoconnect flow might fail before we can even load connection info
// so connectionInfo might be undefiend at this point. In
// single-conneciton mode this requires some special handling so that
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// single-conneciton mode this requires some special handling so that
// single-connection mode this requires some special handling so that

const isOIDC = isOIDCAuth(connectionInfo.connectionOptions.connectionString);
return {
title: `Connecting to ${connectionTitle}`,
description: isOIDC ? 'Go to the browser to complete authentication' : '',
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 text is now applied both to multiple and single connections flow now that we're sharing more UI code between the two

// connection info object to be passed around. For that purposes this hook will
// either return an editing connection info or will create a new one as a
// fallback if nothing is actively being edited
function useActiveConnectionInfo(
Copy link
Collaborator Author

@gribnoysup gribnoysup Jul 25, 2024

Choose a reason for hiding this comment

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

It might be something that we want to just make part of the connection-form logic, it's convenient to have a default there and then we don't need to manually create new connection info in two different places all the time

);

const onConnectClick = (connectionInfo: ConnectionInfo) => {
void connect({ ...cloneDeep(connectionInfo) }, true).catch(() => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Honestly not sure why this was shallow and deep cloning, if someone knows what's the reason for this, please tell

enableDebugUseCsfleSchemaMap,
protectConnectionStringsForNewConnections,
]
const activeConnectionInfo = useActiveConnectionInfo(editingConnectionInfo);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Active" is like this concept only applicable to single connection form: what is being edited is also what you are connecting to (not sure if it's worth a comment in the code taking into account that we're going to remove it)

export function showNonGenuineMongoDBWarningModal(
connectionInfo?: ConnectionInfo
) {
return showConfirmation({
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Button names are slightly different because of this change, but I'm not sure if it matters much tbh, I didn't try to make the names exactly the same

Comment on lines +84 to +91
const favoriteConnectionsRef = useRef(favoriteConnections);
favoriteConnectionsRef.current = favoriteConnections;

const nonFavoriteConnectionsRef = useRef(nonFavoriteConnections);
nonFavoriteConnectionsRef.current = nonFavoriteConnections;

const autoConnectInfoRef = useRef(autoConnectInfo);
autoConnectInfoRef.current = autoConnectInfo;
Copy link
Collaborator Author

@gribnoysup gribnoysup Jul 25, 2024

Choose a reason for hiding this comment

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

Drive-by: in a lot of places we need to just access the current state of those, which without changing some of the methods here required subscribing to changes to those (invalidating dependencies of a lot of other hooks) even when we don't care about it and only want to read the current value

Comment on lines -51 to -57
activeConnectionId?: string;
activeConnectionInfo: ConnectionInfo;
connectingConnectionId: string | null;
connectingStatusText: string;
connectionErrorMessage: string | null;
oidcDeviceAuthVerificationUrl: string | null;
oidcDeviceAuthUserCode: string | null;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Literally none of this state makes sense in multiple connections mode 🙃

Comment on lines +195 to +196
// In multiple connections mode we don't allow to start another edit
// when one is already in progress
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not sure if this was an intentional decision, before this was not possible mostly because of the bugs in the state. Currently it should be technically possible to "open" multiple times while editing if you get a toast with an error for a different connection, but maybe it's still a good idea not to allow resetting the form while one is already opened

duplicate.favorite.name = `${name} (${copyNumber})`;
const connectWithInflightCheck = useCallback(
async (connectionInfo: ConnectionInfo) => {
const inflightConnect = InFlightConnections.get(connectionInfo.id);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@himanshusinghs is this something that you had in mind?

Copy link
Contributor

Choose a reason for hiding this comment

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

yea something similar. I was probably thinking of having that in ConnectionsManager itself but having it here must have its own reasons. Sorry, I am yet to go through the PR (for my own understanding of the change).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My thinking is that this connect method is the main and only interface that other parts of UI should use to start a connection, so debounce should happen as high as possible. We are also planning to dissolve manager and repository in the connections redux store with the follow-up refactor, so this logic will end up in the store eventually anyway

/>
{editingConnectionInfo && (
<ConnectionFormModal
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Technically could've moved the form to compass-connections too already, but all the tests are also here and I'm trying to limit this already massive PR 😅

@gribnoysup gribnoysup marked this pull request as ready for review July 29, 2024 12:03
@gribnoysup gribnoysup merged commit d5fe7d7 into main Jul 29, 2024
34 of 35 checks passed
@gribnoysup gribnoysup deleted the compass-8067-consolidate-connection-store-logic branch July 29, 2024 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature flagged PRs labeled with this label will not be included in the release notes of the next release fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants