Skip to content

Commit

Permalink
feat(compass-workspaces): introduce workspaces plugin; implement sing…
Browse files Browse the repository at this point in the history
…le top level tabs COMPASS-7354 (#5169)

* feat(compass-workspaces): introduce workspaces plugin; implement single top level tabs

* chore(compass-components): redesign workspace tabs

* chore(sidebar): add Performance item to the sidebar

* chore(workspaces): workspace type based on tab plugins

* chore: depcheck

* chore: more depcheck

* chore: lint and broken unit test fixes

* chore(workspaces): add missing event listeners

* chore(app-registry): add activate helpers

* chore(e2e): update e2e tests for the new workspace tabs

* chore(workspaces): empty state and plus button behavior

* chore(workspaces): add tabs tests

* chore(components): fix tab focus state and visible focus color

* chore(components): update tab test

* chore(app-stores): show error toast if failed to get instance info on first try

* chore(collection): remove duplicated prop from expression

* chore(sidebar): be more explicit about default value for instance props

* fix(workspaces): when opening an existing workspace, prioritize current active one when selecting

* fix(workspaces): handle empty tabs state on namespace remove
  • Loading branch information
gribnoysup authored Dec 4, 2023
1 parent f93ded3 commit 87f6468
Show file tree
Hide file tree
Showing 112 changed files with 2,570 additions and 3,158 deletions.
431 changes: 340 additions & 91 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/collection-model/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ interface Collection {
dataService: DataService;
}): Promise<CollectionMetadata>;
on(evt: string, fn: (...args: any) => void);
off(evt: string, fn: (...args: any) => void);
removeListener(evt: string, fn: (...args: any) => void);
toJSON(opts?: { derived: boolean }): this;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/compass-app-stores/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@
"xvfb-maybe": "^0.2.1"
},
"dependencies": {
"@mongodb-js/compass-components": "^1.19.0",
"@mongodb-js/compass-logging": "^1.2.6",
"hadron-app-registry": "^9.0.14",
"mongodb-data-service": "^22.15.1",
"mongodb-instance-model": "^12.15.1"
},
"peerDependencies": {
"@mongodb-js/compass-components": "^1.19.0",
"@mongodb-js/compass-logging": "^1.2.6",
"hadron-app-registry": "^9.0.14",
"mongodb-data-service": "^22.15.1",
Expand Down
55 changes: 23 additions & 32 deletions packages/compass-app-stores/src/stores/instance-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import toNS from 'mongodb-ns';
import type { DataService } from 'mongodb-data-service';
import type { AppRegistry } from 'hadron-app-registry';
import type { LoggerAndTelemetry } from '@mongodb-js/compass-logging/provider';
import { openToast } from '@mongodb-js/compass-components';

function serversArray(
serversMap: NonNullable<
Expand Down Expand Up @@ -57,6 +58,8 @@ export function createInstanceStore({
'dataService'
> = {}
) {
const isFirstRun = instance.status === 'initial';

try {
await instance.refresh({ dataService, ...refreshOptions });

Expand All @@ -71,6 +74,26 @@ export function createInstanceStore({
dataService,
errorMessage: err.message,
});

// The `instance.refresh` method is catching all expected errors: we treat
// a lot of metadata as optional so failing to fetch it shouldn't throw.
// In most cases if this failed on subsequent runs, user is probably
// already in a state that will show them a more specified error (like
// seeing some server error trying to refresh collection list in cases
// that something happened with the server after connection). However if
// we are fetching instance info for the first time (as indicated by the
// initial instance status) and we ended up here, there might be no other
// place for the user to see the error. This is a very rare case, but we
// don't want to leave the user without any indication that something went
// wrong and so we show an toast with the error message
if (isFirstRun) {
const { name, message } = err as Error;
openToast('instance-refresh-failed', {
title: 'Failed to retrieve server info',
description: `${name}: ${message}`,
variant: 'important',
});
}
}
}

Expand Down Expand Up @@ -268,13 +291,6 @@ export function createInstanceStore({

const onCollectionRenamed = voidify(
async ({ from, to }: { from: string; to: string }) => {
// we must fetch the old collection's metadata before refreshing because refreshing the
// collection metadata will remove the old collection from the model.
const metadata = await fetchCollectionMetadata(from);
appRegistry.emit('refresh-collection-tabs', {
metadata,
newNamespace: to,
});
const { database } = toNS(from);
await refreshNamespace({
ns: to,
Expand Down Expand Up @@ -315,31 +331,6 @@ export function createInstanceStore({
});
onAppRegistryEvent('collection-created', onCollectionCreated);

const onActiveCollectionDropped = (ns: string) => {
// This callback will fire after drop collection happened, we force it into
// a microtask to allow drop collections event handler to force start
// databases and collections list update before we run our check here
queueMicrotask(
voidify(async () => {
const { database } = toNS(ns);
await instance.fetchDatabases({ dataService });
const db = instance.databases.get(database);
await db?.fetchCollections({ dataService });
if (db?.collectionsLength) {
appRegistry.emit('select-database', database);
} else {
appRegistry.emit('open-instance-workspace', 'Databases');
}
})
);
};
onAppRegistryEvent('active-collection-dropped', onActiveCollectionDropped);

const onActiveDatabaseDropped = () => {
appRegistry.emit('open-instance-workspace', 'Databases');
};
onAppRegistryEvent('active-database-dropped', onActiveDatabaseDropped);

/**
* Opens collection in the current active tab. No-op if currently open tab has
* the same namespace. Additional `query` and `agrregation` props can be
Expand Down
9 changes: 5 additions & 4 deletions packages/compass-collection/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,21 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"peerDependencies": {
"@mongodb-js/compass-app-stores": "^7.6.1",
"@mongodb-js/compass-components": "^1.19.0",
"@mongodb-js/compass-logging": "^1.2.6",
"bson": "^6.2.0",
"compass-preferences-model": "^2.15.6",
"hadron-app-registry": "^9.0.14",
"mongodb-data-service": "^22.15.1",
"react": "^17.0.2"
},
"dependencies": {
"@mongodb-js/compass-app-stores": "^7.6.1",
"@mongodb-js/compass-components": "^1.19.0",
"@mongodb-js/compass-logging": "^1.2.6",
"bson": "^6.2.0",
"compass-preferences-model": "^2.15.6",
"hadron-app-registry": "^9.0.14"
"hadron-app-registry": "^9.0.14",
"mongodb-data-service": "^22.15.1"
},
"devDependencies": {
"@mongodb-js/eslint-config-compass": "^1.0.11",
Expand All @@ -90,7 +92,6 @@
"eslint": "^7.25.0",
"mocha": "^10.2.0",
"mongodb-collection-model": "^5.15.1",
"mongodb-data-service": "^22.15.1",
"mongodb-instance-model": "^12.15.1",
"mongodb-ns": "^2.4.0",
"numeral": "^2.0.6",
Expand Down
24 changes: 8 additions & 16 deletions packages/compass-collection/src/components/collection-tab.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { connect, Provider } from 'react-redux';
import { connect } from 'react-redux';
import type { CollectionTabPluginMetadata } from '../modules/collection-tab';
import {
returnToView,
Expand All @@ -14,8 +14,8 @@ import {
import { css, ErrorBoundary, TabNavBar } from '@mongodb-js/compass-components';
import CollectionHeader from './collection-header';
import { createLoggerAndTelemetry } from '@mongodb-js/compass-logging';
import type { configureStore } from '../stores/collection-tab';
import { useCollectionTabPlugins } from './collection-tab-provider';
import type { CollectionTabOptions } from '../stores/collection-tab';

const { log, mongoLogId, track } = createLoggerAndTelemetry(
'COMPASS-COLLECTION-TAB-UI'
Expand Down Expand Up @@ -59,13 +59,15 @@ const collectionModalContainerStyles = css({
zIndex: 100,
});

const CollectionTab: React.FunctionComponent<{
type CollectionTabProps = {
currentTab: string;
collectionTabPluginMetadata: CollectionTabPluginMetadata;
renderScopedModals(): React.ReactElement[];
renderTabs(): { name: string; component: React.ReactElement }[];
onTabClick(name: string): void;
}> = ({
};

const CollectionTab: React.FunctionComponent<CollectionTabProps> = ({
currentTab,
collectionTabPluginMetadata,
renderScopedModals,
Expand Down Expand Up @@ -162,16 +164,6 @@ const ConnectedCollectionTab = connect(
renderTabs: renderTabs,
onTabClick: selectTab,
}
)(CollectionTab);

const CollectionTabPlugin: React.FunctionComponent<{
store: ReturnType<typeof configureStore>;
}> = ({ store }) => {
return (
<Provider store={store}>
<ConnectedCollectionTab></ConnectedCollectionTab>
</Provider>
);
};
)(CollectionTab) as React.FunctionComponent<CollectionTabOptions>;

export default CollectionTabPlugin;
export default ConnectedCollectionTab;
2 changes: 0 additions & 2 deletions packages/compass-collection/src/components/workspace/index.ts

This file was deleted.

This file was deleted.

Loading

0 comments on commit 87f6468

Please sign in to comment.