From f386d1b5d86a38834b7bd852a877d3f7d10531e7 Mon Sep 17 00:00:00 2001 From: Anemy Date: Mon, 21 Jun 2021 15:12:43 -0400 Subject: [PATCH 1/9] leafy-green buttons in documents view --- .../compass-crud/electron/renderer/index.js | 3 +- packages/compass-crud/package.json | 2 + .../src/components/document-actions.jsx | 135 +++++++++++++----- .../src/components/document-list-view.jsx | 5 +- .../src/components/document-list.jsx | 1 + .../compass-crud/src/components/document.jsx | 16 ++- .../src/components/expansion-bar.jsx | 28 ++-- .../src/components/readonly-document.jsx | 7 + .../compass-crud/src/stores/crud-store.js | 25 ++++ 9 files changed, 170 insertions(+), 52 deletions(-) diff --git a/packages/compass-crud/electron/renderer/index.js b/packages/compass-crud/electron/renderer/index.js index 98b46567510..6fbc5f4bc93 100644 --- a/packages/compass-crud/electron/renderer/index.js +++ b/packages/compass-crud/electron/renderer/index.js @@ -64,7 +64,8 @@ const store = configureStore({ localAppRegistry: localAppRegistry, globalAppRegistry: appRegistry, namespace: `${DB}.${COLL}`, - isReadonly: false + isReadonly: false, + isTimeSeries: false }); // Create a HMR enabled render function diff --git a/packages/compass-crud/package.json b/packages/compass-crud/package.json index 03000b88bda..61909c583c5 100644 --- a/packages/compass-crud/package.json +++ b/packages/compass-crud/package.json @@ -137,6 +137,8 @@ "xvfb-maybe": "^0.2.1" }, "dependencies": { + "@leafygreen-ui/icon": "^11.2.0", + "@leafygreen-ui/icon-button": "^9.1.5", "ag-grid-community": "20.2.0", "ag-grid-react": "20.2.0", "brace": "^0.11.1", diff --git a/packages/compass-crud/src/components/document-actions.jsx b/packages/compass-crud/src/components/document-actions.jsx index a2ed23e0777..b6d92037061 100644 --- a/packages/compass-crud/src/components/document-actions.jsx +++ b/packages/compass-crud/src/components/document-actions.jsx @@ -1,6 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { IconButton } from 'hadron-react-buttons'; +// import { IconButton } from 'hadron-react-buttons'; +import IconButton, { Size as IconButtonSizes } from '@leafygreen-ui/icon-button'; +import Icon from '@leafygreen-ui/icon'; + import UpdatableIconButton from './updatable-icon-button'; /** @@ -14,18 +17,6 @@ class DocumentActions extends React.Component { */ constructor(props) { super(props); - this.state = { allExpanded: props.allExpanded }; - } - - /** - * Set the state when new props are received. - * - * @param {Object} nextProps - The new props. - */ - componentWillReceiveProps(nextProps) { - if (nextProps.allExpanded !== this.state.allExpanded) { - this.setState({ allExpanded: nextProps.allExpanded }); - } } /** @@ -34,20 +25,32 @@ class DocumentActions extends React.Component { * @returns {React.Component} The expand all button. */ renderExpandAll() { - if (this.props.expandAll) { - const title = this.state.allExpanded ? 'Collapse All' : 'Expand All'; - const iconClass = this.state.allExpanded ? 'fa-angle-down' : 'fa-angle-right'; - return ( -
- + + -
- ); - } + /> + + {/* */} + + ); } /** @@ -58,32 +61,93 @@ class DocumentActions extends React.Component { render() { return (
- {this.renderExpandAll()} + {this.props.expandAll && this.renderExpandAll()}
- - } + {this.props.copy && - } + {this.props.clone && - } + {this.props.remove && + clickHandler={this.props.remove} + />} */} + {this.props.edit && + + } + {this.props.copy && + + } + {this.props.clone && + {/* */} + + } + {this.props.remove && + + }
); @@ -94,7 +158,6 @@ DocumentActions.displayName = 'DocumentActions'; DocumentActions.propTypes = { edit: PropTypes.func.isRequired, - copy: PropTypes.func.isRequired, remove: PropTypes.func.isRequired, clone: PropTypes.func.isRequired, allExpanded: PropTypes.bool, diff --git a/packages/compass-crud/src/components/document-list-view.jsx b/packages/compass-crud/src/components/document-list-view.jsx index 24e1a5d8c80..ccad7a05af1 100644 --- a/packages/compass-crud/src/components/document-list-view.jsx +++ b/packages/compass-crud/src/components/document-list-view.jsx @@ -37,13 +37,15 @@ class DocumentListView extends React.Component { tz={this.props.tz} key={i} editable={this.props.isEditable} + isTimeSeries={this.props.isTimeSeries} version={this.props.version} copyToClipboard={this.props.copyToClipboard} removeDocument={this.props.removeDocument} replaceDocument={this.props.replaceDocument} updateDocument={this.props.updateDocument} openImportFileDialog={this.props.openImportFileDialog} - openInsertDocumentDialog={this.props.openInsertDocumentDialog} /> + openInsertDocumentDialog={this.props.openInsertDocumentDialog} + /> ); }); @@ -66,6 +68,7 @@ class DocumentListView extends React.Component { DocumentListView.propTypes = { docs: PropTypes.array.isRequired, isEditable: PropTypes.bool.isRequired, + isTimeSeries: PropTypes.bool, copyToClipboard: PropTypes.func, removeDocument: PropTypes.func, replaceDocument: PropTypes.func, diff --git a/packages/compass-crud/src/components/document-list.jsx b/packages/compass-crud/src/components/document-list.jsx index 1141e8511b7..2a108f7837f 100644 --- a/packages/compass-crud/src/components/document-list.jsx +++ b/packages/compass-crud/src/components/document-list.jsx @@ -231,6 +231,7 @@ DocumentList.propTypes = { insertMany: PropTypes.func, isEditable: PropTypes.bool.isRequired, isExportable: PropTypes.bool.isRequired, + isTimeSeries: PropTypes.bool, store: PropTypes.object.isRequired, openInsertDocumentDialog: PropTypes.func, openImportFileDialog: PropTypes.func, diff --git a/packages/compass-crud/src/components/document.jsx b/packages/compass-crud/src/components/document.jsx index ddc23cfbb7d..8ba3bc476d0 100644 --- a/packages/compass-crud/src/components/document.jsx +++ b/packages/compass-crud/src/components/document.jsx @@ -13,14 +13,26 @@ class Document extends React.Component { * @returns {React.Component} The component. */ render() { + if (this.props.editable && this.props.isTimeSeries) { + return ( + + ); + } if (this.props.editable) { return (); } return ( + expandAll={this.props.expandAll} + /> ); } } @@ -30,8 +42,10 @@ Document.displayName = 'Document'; Document.propTypes = { doc: PropTypes.object.isRequired, tz: PropTypes.string, + copyToClipboard: PropTypes.func, editable: PropTypes.bool, expandAll: PropTypes.bool, + isTimeSeries: PropTypes.bool, removeDocument: PropTypes.func, replaceDocument: PropTypes.func, updateDocument: PropTypes.func, diff --git a/packages/compass-crud/src/components/expansion-bar.jsx b/packages/compass-crud/src/components/expansion-bar.jsx index d2a10dfac1e..557164efdb8 100644 --- a/packages/compass-crud/src/components/expansion-bar.jsx +++ b/packages/compass-crud/src/components/expansion-bar.jsx @@ -88,20 +88,22 @@ class ExpansionBar extends React.PureComponent { * @returns {React.Component} The expander bar. */ render() { - const components = []; const total = this.props.totalSize; - if (total > this.props.initialSize) { - const showMoreFields = Math.min( - total - this.props.renderSize, - this.props.perClickSize - ); - const hideFields = this.props.renderSize - this.props.initialSize; - if (this.props.renderSize < total) { - components.push(this.renderShowMoreFieldsButton(showMoreFields)); - } - if (this.props.renderSize > this.props.initialSize && !this.props.disableHideButton) { - components.push(this.renderHideFieldsButton(hideFields)); - } + if (total <= this.props.initialSize) { + return null; + } + + const showMoreFields = Math.min( + total - this.props.renderSize, + this.props.perClickSize + ); + const hideFields = this.props.renderSize - this.props.initialSize; + const components = []; + if (this.props.renderSize < total) { + components.push(this.renderShowMoreFieldsButton(showMoreFields)); + } + if (this.props.renderSize > this.props.initialSize && !this.props.disableHideButton) { + components.push(this.renderHideFieldsButton(hideFields)); } return (
diff --git a/packages/compass-crud/src/components/readonly-document.jsx b/packages/compass-crud/src/components/readonly-document.jsx index 9fc5e2e470f..f9d2c7a1e76 100644 --- a/packages/compass-crud/src/components/readonly-document.jsx +++ b/packages/compass-crud/src/components/readonly-document.jsx @@ -97,6 +97,10 @@ class ReadonlyDocument extends React.Component { ); } + renderActions() { + // this.props.openInsertDocumentDialog && + } + /** * Render a single document list item. * @@ -110,6 +114,7 @@ class ReadonlyDocument extends React.Component { {this.renderElements()} {this.renderExpansion()} + {this.renderActions()}
); @@ -119,8 +124,10 @@ class ReadonlyDocument extends React.Component { ReadonlyDocument.displayName = 'ReadonlyDocument'; ReadonlyDocument.propTypes = { + copyToClipboard: PropTypes.func, doc: PropTypes.object.isRequired, expandAll: PropTypes.bool, + openInsertDocumentDialog: PropTypes.func, tz: PropTypes.string }; diff --git a/packages/compass-crud/src/stores/crud-store.js b/packages/compass-crud/src/stores/crud-store.js index bf8f32fe36c..52f7803c1b9 100644 --- a/packages/compass-crud/src/stores/crud-store.js +++ b/packages/compass-crud/src/stores/crud-store.js @@ -104,6 +104,17 @@ export const setIsReadonly = (store, isReadonly) => { store.onReadonlyChanged(isReadonly); }; + +/** + * Set the isTimeSeries flag in the store. + * + * @param {Store} store - The store. + * @param {Boolean} isTimeSeries - If the collection is readonly. + */ + export const setIsTimeSeries = (store, isTimeSeries) => { + store.onTimeSeriesChanged(isTimeSeries); +}; + /** * Set the namespace in the store. * @@ -172,6 +183,7 @@ const configureStore = (options = {}) => { query: this.getInitialQueryState(), isDataLake: false, isReadonly: false, + isTimeSeries: false, status: 'fetching', outdated: false, shardKeys: null @@ -252,6 +264,15 @@ const configureStore = (options = {}) => { this.setState({ isReadonly: isReadonly }); }, + /** + * Set if the collection is a time-series collection. + * + * @param {Boolean} isTimeSeries - If the collection is time-series. + */ + onTimeSeriesChanged(isTimeSeries) { + this.setState({ isTimeSeries: isTimeSeries }); + }, + /** * Plugin lifecycle method that is called when the namespace changes in * Compass. Trigger with new namespace and cleared path/types. @@ -1023,6 +1044,10 @@ const configureStore = (options = {}) => { setNamespace(store, options.namespace); } + if (options.isTimeSeries) { + setIsTimeSeries(store, options.isTimeSeries); + } + if (options.dataProvider) { setDataProvider( store, From e8d1d652fdf82dcfe10e91df55800d1fcd2a0dba Mon Sep 17 00:00:00 2001 From: Anemy Date: Tue, 22 Jun 2021 11:01:38 -0400 Subject: [PATCH 2/9] Add copy button to view documents and explain plan raw json --- .../collection-header/collection-header.jsx | 38 ++-- .../src/components/collection/collection.jsx | 2 + .../components/collection/collection.spec.js | 1 + .../src/components/workspace/workspace.jsx | 1 + .../compass-collection/src/modules/context.js | 159 +++++++++------- .../compass-collection/src/modules/tabs.js | 174 +++++++++++++----- .../src/modules/tabs.spec.js | 21 ++- .../compass-collection/src/stores/store.js | 40 ++-- .../test/stores/store.spec.js | 16 ++ packages/compass-crud/package.json | 2 - .../src/components/document-actions.jsx | 102 +--------- .../compass-crud/src/components/document.jsx | 1 + .../src/components/readonly-document.jsx | 13 +- .../components/explain-json/explain-json.jsx | 11 +- .../components/explain-json/explain-json.less | 3 +- .../sidebar-collection/sidebar-collection.jsx | 6 +- .../sidebar-database/sidebar-database.jsx | 2 + .../compass-sidebar/src/modules/collection.js | 3 + .../src/modules/collection.spec.js | 9 +- .../src/modules/show-collection.js | 3 + 20 files changed, 357 insertions(+), 250 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header/collection-header.jsx b/packages/compass-collection/src/components/collection-header/collection-header.jsx index 7b19ed94e52..e3ddfddaa6a 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.jsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.jsx @@ -24,27 +24,29 @@ class CollectionHeader extends Component { }; modifySource = () => { - this.props.selectOrCreateTab( - this.props.sourceName, - this.props.sourceReadonly, - this.props.sourceViewOn, - this.props.namespace, - false, - null, - this.props.pipeline - ); + this.props.selectOrCreateTab({ + namespace: this.props.sourceName, + isReadonly: this.props.sourceReadonly, + isTimeSeries: this.props.isTimeSeries, + sourceName: this.props.sourceViewOn, + editViewName: this.props.namespace, + sourceReadonly: false, + sourceViewOn: null, + sourcePipeline: this.props.pipeline + }); } returnToView = () => { - this.props.selectOrCreateTab( - this.props.editViewName, - true, - this.props.namespace, - null, - this.props.isReadonly, - this.props.sourceName, - this.props.pipeline - ); + this.props.selectOrCreateTab({ + namespace: this.props.editViewName, + isReadonly: true, + isTimeSeries: this.props.isTimeSeries, + sourceName: this.props.namespace, + editViewName: null, + sourceReadonly: this.props.isReadonly, + sourceViewOn: this.props.sourceName, + sourcePipeline: this.props.pipeline + }); } handleDBClick = (db) => { diff --git a/packages/compass-collection/src/components/collection/collection.jsx b/packages/compass-collection/src/components/collection/collection.jsx index 0e4a4fa7f1d..84481800958 100644 --- a/packages/compass-collection/src/components/collection/collection.jsx +++ b/packages/compass-collection/src/components/collection/collection.jsx @@ -11,6 +11,7 @@ class Collection extends Component { static propTypes = { namespace: PropTypes.string.isRequired, + isTimeSeries: PropTypes.bool, isReadonly: PropTypes.bool.isRequired, tabs: PropTypes.array.isRequired, views: PropTypes.array.isRequired, @@ -69,6 +70,7 @@ class Collection extends Component { globalAppRegistry={this.props.globalAppRegistry} namespace={this.props.namespace} isReadonly={this.props.isReadonly} + isTimeSeries={this.props.isTimeSeries} statsPlugin={this.props.statsPlugin} statsStore={this.props.statsStore} editViewName={this.props.editViewName} diff --git a/packages/compass-collection/src/components/collection/collection.spec.js b/packages/compass-collection/src/components/collection/collection.spec.js index edd485b941a..c9b4e82a86e 100644 --- a/packages/compass-collection/src/components/collection/collection.spec.js +++ b/packages/compass-collection/src/components/collection/collection.spec.js @@ -19,6 +19,7 @@ describe('Collection [Component]', () => { component = mount( { /** * Setup a scoped store to the collection. * - * @param {Object} role - The role. - * @param {Object} globalAppRegistry - The global app registry. - * @param {Object} localAppRegistry - The scoped app registry to the collection. - * @param {Object} dataService - The data service. - * @param {String} namespace - The namespace. - * @param {String} serverVersion - The server version. - * @param {Boolean} isReadonly - If the collection is a readonly view. - * @param {Object} actions - The actions for the store. - * @param {Boolean} allowWrites - If writes are allowed. - * @param {String} sourceName - The source namespace for the view. - * @param {String} editViewName - The name of the view we are editing. + * @param {Object} options - The plugin store options. + * @param {Object} options.role - The role. + * @param {Object} options.globalAppRegistry - The global app registry. + * @param {Object} options.localAppRegistry - The scoped app registry to the collection. + * @param {Object} options.dataService - The data service. + * @param {String} options.namespace - The namespace. + * @param {String} options.serverVersion - The server version. + * @param {Boolean} options.isReadonly - If the collection is a readonly view. + * @param {Object} options.actions - The actions for the store. + * @param {Boolean} options.allowWrites - If writes are allowed. + * @param {String} options.sourceName - The source namespace for the view. + * @param {String} options.editViewName - The name of the view we are editing. * * @returns {Object} The configured store. */ -const setupStore = ( +const setupStore = ({ role, globalAppRegistry, localAppRegistry, @@ -42,11 +43,13 @@ const setupStore = ( namespace, serverVersion, isReadonly, + isTimeSeries, actions, allowWrites, sourceName, editViewName, - sourcePipeline) => { + sourcePipeline +}) => { const store = role.configureStore({ localAppRegistry: localAppRegistry, globalAppRegistry: globalAppRegistry, @@ -57,6 +60,7 @@ const setupStore = ( namespace: namespace, serverVersion: serverVersion, isReadonly: isReadonly, + isTimeSeries, actions: actions, allowWrites: allowWrites, sourceName: sourceName, @@ -71,19 +75,21 @@ const setupStore = ( /** * Setup a scoped plugin to the tab. * - * @param {Object} role - The role. - * @param {Object} globalAppRegistry - The global app registry. - * @param {Object} localAppRegistry - The scoped app registry to the collection. - * @param {Object} dataService - The data service. - * @param {String} namespace - The namespace. - * @param {String} serverVersion - The server version. - * @param {Boolean} isReadonly - If the collection is a readonly view. - * @param {Boolean} allowWrites - If writes are allowed. - * @param {String} key - The plugin key. + * @param options - The plugin options. + * @param {Object} options.role - The role. + * @property {Object} options.globalAppRegistry - The global app registry. + * @property {Object} options.localAppRegistry - The scoped app registry to the collection. + * @property {Object} options.dataService - The data service. + * @property {String} options.namespace - The namespace. + * @property {String} options.serverVersion - The server version. + * @property {Boolean} options.isReadonly - If the collection is a readonly view. + * @property {Boolean} options.isTimeSeries - If the collection is a time-series collection. + * @property {Boolean} options.allowWrites - If writes are allowed. + * @property {String} options.key - The plugin key. * * @returns {Component} The plugin. */ -const setupPlugin = ( +const setupPlugin = ({ role, globalAppRegistry, localAppRegistry, @@ -91,10 +97,12 @@ const setupPlugin = ( namespace, serverVersion, isReadonly, + isTimeSeries, allowWrites, - key) => { + key +}) => { const actions = role.configureActions(); - const store = setupStore( + const store = setupStore({ role, globalAppRegistry, localAppRegistry, @@ -102,9 +110,10 @@ const setupPlugin = ( namespace, serverVersion, isReadonly, + isTimeSeries, actions, allowWrites - ); + }); const plugin = role.component; return { component: plugin, @@ -117,28 +126,32 @@ const setupPlugin = ( /** * Setup every scoped modal role. * - * @param {Object} globalAppRegistry - The global app registry. - * @param {Object} localAppRegistry - The scoped app registry to the collection. - * @param {Object} dataService - The data service. - * @param {String} namespace - The namespace. - * @param {String} serverVersion - The server version. - * @param {Boolean} isReadonly - If the collection is a readonly view. - * @param {Boolean} allowWrites - If we allow writes. + * @param options - The scope modal plugin options. + * @property {Object} options.globalAppRegistry - The global app registry. + * @property {Object} options.localAppRegistry - The scoped app registry to the collection. + * @property {Object} options.dataService - The data service. + * @property {String} options.namespace - The namespace. + * @property {String} options.serverVersion - The server version. + * @property {Boolean} options.isReadonly - If the collection is a readonly view. + * @property {Boolean} options.isTimeSeries - If the collection is a time-series. + * @property {Boolean} options.allowWrites - If we allow writes. * * @returns {Array} The components. */ -const setupScopedModals = ( +const setupScopedModals = ({ globalAppRegistry, localAppRegistry, dataService, namespace, serverVersion, isReadonly, - allowWrites) => { + isTimeSeries, + allowWrites +}) => { const roles = globalAppRegistry.getRole('Collection.ScopedModal'); if (roles) { return roles.map((role, i) => { - return setupPlugin( + return setupPlugin({ role, globalAppRegistry, localAppRegistry, @@ -146,9 +159,10 @@ const setupScopedModals = ( namespace, serverVersion, isReadonly, + isTimeSeries, allowWrites, - i - ); + key: i + }); }); } return []; @@ -157,16 +171,27 @@ const setupScopedModals = ( /** * Create the context in which a tab is created. * - * @param {Object} state - The store state. - * @param {String} namespace - The namespace. - * @param {Boolean} isReadonly - Is the namespace readonly. - * @param {Boolean} isDataLake - If we are hitting the data lake. - * @param {String} sourceName - The name of the view source. - * @param {String} editViewName - The name of the view we are editing. + * @param {Object} options - The options for creating the context. + * @property {Object} options.state - The store state. + * @property {String} options.namespace - The namespace. + * @property {Boolean} options.isReadonly - Is the namespace readonly. + * @property {Boolean} options.isDataLake - If we are hitting the data lake. + * @property {String} options.sourceName - The name of the view source. + * @property {String} options.editViewName - The name of the view we are editing. + * @property {String} options.sourcePipeline * * @returns {Object} The tab context. */ -const createContext = (state, namespace, isReadonly, isDataLake, sourceName, editViewName, sourcePipeline) => { +const createContext = ({ + state, + namespace, + isReadonly, + isTimeSeries, + isDataLake, + sourceName, + editViewName, + sourcePipeline +}) => { const serverVersion = state.serverVersion; const localAppRegistry = new AppRegistry(); const globalAppRegistry = state.appRegistry; @@ -192,37 +217,39 @@ const createContext = (state, namespace, isReadonly, isDataLake, sourceName, edi const queryBarRole = globalAppRegistry.getRole('Query.QueryBar')[0]; localAppRegistry.registerRole('Query.QueryBar', queryBarRole); const queryBarActions = setupActions(queryBarRole, localAppRegistry); - setupStore( - queryBarRole, + setupStore({ + role: queryBarRole, globalAppRegistry, localAppRegistry, - state.dataService, + dataService: state.dataService, namespace, serverVersion, isReadonly, - queryBarActions, - !isDataLake - ); + isTimeSeries, + actions: queryBarActions, + allowWrites: !isDataLake + }); // Setup each of the tabs inside the collection tab. They will all get // passed the same information and can determine whether they want to // use it or not. filteredRoles.forEach((role, i) => { const actions = setupActions(role, localAppRegistry); - const store = setupStore( + const store = setupStore({ role, globalAppRegistry, localAppRegistry, - state.dataService, + dataService: state.dataService, namespace, serverVersion, isReadonly, + isTimeSeries, actions, - !isDataLake, + allowWrite: !isDataLake, sourceName, editViewName, sourcePipeline - ); + }); // Add the tab. tabs.push(role.name); @@ -239,28 +266,30 @@ const createContext = (state, namespace, isReadonly, isDataLake, sourceName, edi // Setup the stats in the collection HUD const statsRole = globalAppRegistry.getRole('Collection.HUD')[0]; const statsPlugin = statsRole.component; - const statsStore = setupStore( - statsRole, + const statsStore = setupStore({ + role: statsRole, globalAppRegistry, localAppRegistry, - state.dataService, + dataService: state.dataService, namespace, serverVersion, isReadonly, - {}, - !isDataLake - ); + isTimeSeries, + actions: {}, + allowWrites: !isDataLake + }); // Setup the scoped modals - const scopedModals = setupScopedModals( + const scopedModals = setupScopedModals({ globalAppRegistry, localAppRegistry, - state.dataService, + dataService: state.dataService, namespace, serverVersion, isReadonly, - !isDataLake - ); + isTimeSeries, + allowWrites: !isDataLake + }); const configureFieldStore = globalAppRegistry.getStore('Field.Store'); configureFieldStore({ diff --git a/packages/compass-collection/src/modules/tabs.js b/packages/compass-collection/src/modules/tabs.js index 71b8767c8d4..dc3a4a463f0 100644 --- a/packages/compass-collection/src/modules/tabs.js +++ b/packages/compass-collection/src/modules/tabs.js @@ -66,6 +66,19 @@ const doClearTabs = () => { return INITIAL_STATE; }; +/** + * Tab options. + * @typedef {Object} CollectionTabOptions + * @property {String} namespace - The namespace to select. + * @property {Boolean} isReadonly - If the ns is readonly. + * @property {Boolean} isTimeSeries - If the ns is a time-series collection. + * @property {String} sourceName - The ns of the resonly view source. + * @property {String} editViewName - The name of the view we are editing. + * @property {String} sourceReadonly + * @property {String} sourceViewOn + * @property {String} sourcePipeline + */ + /** * Handles namespace selected actions. * @@ -85,6 +98,7 @@ const doSelectNamespace = (state, action) => { activeSubTab: subTabIndex, activeSubTabName: action.context.tabs[subTabIndex], isReadonly: action.isReadonly, + isTimeSeries: action.isTimeSeries, tabs: action.context.tabs, views: action.context.views, subtab: action.context.subtab, @@ -126,6 +140,7 @@ const doCreateTab = (state, action) => { activeSubTab: subTabIndex, activeSubTabName: action.context.tabs[subTabIndex], isReadonly: action.isReadonly, + isTimeSeries: action.isTimeSeries, tabs: action.context.tabs, views: action.context.views, subtab: action.context.subtab, @@ -308,20 +323,34 @@ export default function reducer(state = INITIAL_STATE, action) { /** * Action creator for create tab. * - * @param {String} id - The tab id. - * @param {String} namespace - The namespace. - * @param {Boolean} isReadonly - Is the collection readonly? - * @param {String} sourceName - The source namespace. - * @param {String} editViewName - The name of the view we are editing. - * @param {Object} context - The tab context. - * + * @parma {Object} options + * @property {String} options.id - The tab id. + * @property {String} options.namespace - The namespace. + * @property {Boolean} options.isReadonly - Is the collection readonly? + * @property {String} options.sourceName - The source namespace. + * @property {String} options.editViewName - The name of the view we are editing. + * @property {Object} options.context - The tab context. + * @property {Boolean} sourceReadonly + * @property {String} sourceViewOn + * * @returns {Object} The create tab action. */ -export const createTab = (id, namespace, isReadonly, sourceName, editViewName, context, sourceReadonly, sourceViewOn) => ({ +export const createTab = ({ + id, + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + context, + sourceReadonly, + sourceViewOn +}) => ({ type: CREATE_TAB, id: id, namespace: namespace, isReadonly: isReadonly || false, + isTimeSeries: isTimeSeries || false, sourceName: sourceName, editViewName: editViewName, context: context, @@ -335,17 +364,31 @@ export const createTab = (id, namespace, isReadonly, sourceName, editViewName, c * @param {String} id - The tab id. * @param {String} namespace - The namespace. * @param {Boolean} isReadonly - Is the collection readonly? + * @param {Boolean} isTimeSeries - Is the collection time-series? * @param {String} sourceName - The source namespace. * @param {String} editViewName - The name of the view we are editing. * @param {Object} context - The tab context. + * @param {Object} sourceReadonly + * @param {Object} sourceViewOn * * @returns {Object} The namespace selected action. */ -export const selectNamespace = (id, namespace, isReadonly, sourceName, editViewName, context, sourceReadonly, sourceViewOn) => ({ +export const selectNamespace = ({ + id, + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + context, + sourceReadonly, + sourceViewOn +}) => ({ type: SELECT_NAMESPACE, id: id, namespace: namespace, - isReadonly: ((isReadonly === undefined) ? false : isReadonly), + isReadonly: isReadonly || false, + isTimeSeries, sourceName: sourceName, editViewName: editViewName, context: context, @@ -446,16 +489,31 @@ export const changeActiveSubTab = (activeSubTab, id) => ({ * Checks if we need to select a namespace or actually create a new * tab, then dispatches the correct events. * - * @param {String} namespace - The namespace to select. - * @param {Boolean} isReadonly - If the ns is readonly. - * @param {String} sourceName - The ns of the resonly view source. - * @param {String} editViewName - The name of the view we are editing. - */ -export const selectOrCreateTab = (namespace, isReadonly, sourceName, editViewName, sourceReadonly, sourceViewOn, sourcePipeline) => { + * @param {CollectionTabOptions} options +*/ +export const selectOrCreateTab = ({ + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + sourceReadonly, + sourceViewOn, + sourcePipeline +}) => { return (dispatch, getState) => { const state = getState(); if (state.tabs.length === 0) { - dispatch(createNewTab(namespace, isReadonly, sourceName, editViewName, sourceReadonly, sourceViewOn, sourcePipeline)); + dispatch(createNewTab({ + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + sourceReadonly, + sourceViewOn, + sourcePipeline + })); } else { // If the namespace is equal to the active tab's namespace, then // there is no need to do anything. @@ -463,7 +521,16 @@ export const selectOrCreateTab = (namespace, isReadonly, sourceName, editViewNam const activeNamespace = state.tabs[activeIndex].namespace; if (namespace !== activeNamespace) { dispatch( - replaceTabContent(namespace, isReadonly, sourceName, editViewName, sourceReadonly, sourceViewOn, sourcePipeline) + replaceTabContent({ + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + sourceReadonly, + sourceViewOn, + sourcePipeline + }) ); } } @@ -474,34 +541,42 @@ export const selectOrCreateTab = (namespace, isReadonly, sourceName, editViewNam * Handles all the setup of tab creation by creating the stores for each * of the roles in the global app registry. * - * @param {String} namespace - The namespace. - * @param {Boolean} isReadonly - If the namespace is readonly. - * @param {String} sourceName - The view source namespace. - * @param {String} editViewName - The name of the view we are editing. - */ -export const createNewTab = (namespace, isReadonly, sourceName, editViewName, sourceReadonly, sourceViewOn, sourcePipeline) => { + * @param {CollectionTabOptions} options + */ +export const createNewTab = ({ + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + sourceReadonly, + sourceViewOn, + sourcePipeline +}) => { return (dispatch, getState) => { const state = getState(); - const context = createContext( + const context = createContext({ state, namespace, isReadonly, - state.isDataLake, + isDataLake: state.isDataLake, + isTimeSeries, sourceName, editViewName, sourcePipeline - ); + }); dispatch( - createTab( - new ObjectId().toHexString(), + createTab({ + id: new ObjectId().toHexString(), namespace, isReadonly, + isTimeSeries, sourceName, editViewName, context, - !!sourceReadonly, + sourceReadonly: !!sourceReadonly, sourceViewOn - ) + }) ); }; }; @@ -510,34 +585,43 @@ export const createNewTab = (namespace, isReadonly, sourceName, editViewName, so * Handles all the setup of replacing tab content by creating the stores for each * of the roles in the global app registry. * - * @param {String} namespace - The namespace. - * @param {Boolean} isReadonly - If the namespace is readonly. - * @param {String} sourceName - The view source namespace. - * @param {String} editViewName - The name of the view we are editing. - */ -export const replaceTabContent = (namespace, isReadonly, sourceName, editViewName, sourceReadonly, sourceViewOn, sourcePipeline) => { - return (dispatch, getState) => { + * @param {CollectionTabOptions} options + */ +export const replaceTabContent = ({ + namespace, + isReadonly, + isTimeSeries, + sourceName, + editViewName, + sourceReadonly, + sourceViewOn, + sourcePipeline +}) => { + return (dispatch, + getState) => { const state = getState(); - const context = createContext( + const context = createContext({ state, namespace, isReadonly, - state.isDataLake, + isDataLake: state.isDataLake, + isTimeSeries, sourceName, editViewName, sourcePipeline - ); + }); dispatch( - selectNamespace( - new ObjectId().toHexString(), + selectNamespace({ + id: new ObjectId().toHexString(), namespace, isReadonly, + isTimeSeries, sourceName, editViewName, context, - !!sourceReadonly, + sourceReadonly: !!sourceReadonly, sourceViewOn - ) + }) ); }; }; diff --git a/packages/compass-collection/src/modules/tabs.spec.js b/packages/compass-collection/src/modules/tabs.spec.js index d17806bef89..f0df89e6e3c 100644 --- a/packages/compass-collection/src/modules/tabs.spec.js +++ b/packages/compass-collection/src/modules/tabs.spec.js @@ -18,11 +18,20 @@ import reducer, { describe('tabs module', () => { describe('#selectNamespace', () => { it('returns the SELECT_NAMESPACE action', () => { - expect(selectNamespace('t', 'db.coll', true, 'db.test', 'db.view', {})).to.deep.equal({ + expect(selectNamespace({ + id: 't', + namespace: 'db.coll', + isReadonly: true, + isTimeSeries: false, + sourceName: 'db.test', + editViewName: 'db.view', + context: {} + })).to.deep.equal({ type: SELECT_NAMESPACE, id: 't', namespace: 'db.coll', isReadonly: true, + isTimeSeries: false, sourceName: 'db.test', editViewName: 'db.view', sourceReadonly: undefined, @@ -35,12 +44,20 @@ describe('tabs module', () => { describe('#createTab', () => { it('returns the CREATE_TAB action', () => { expect( - createTab('id', 'db.coll', true, 'db.test', 'db.view', {}) + createTab({ + id: 'id', + namespace: 'db.coll', + isReadonly: true, + sourceName: 'db.test', + editViewName: 'db.view', + context: {} + }) ).to.deep.equal({ id: 'id', type: CREATE_TAB, namespace: 'db.coll', isReadonly: true, + isTimeSeries: false, sourceName: 'db.test', editViewName: 'db.view', sourceReadonly: undefined, diff --git a/packages/compass-collection/src/stores/store.js b/packages/compass-collection/src/stores/store.js index b09b667715f..6dc180a9767 100644 --- a/packages/compass-collection/src/stores/store.js +++ b/packages/compass-collection/src/stores/store.js @@ -26,22 +26,23 @@ store.onActivated = (appRegistry) => { /** * When a collection namespace is selected in the sidebar. * - * @param {Object} metatada - The metadata. + * @param {Object} metadata - The metadata. */ appRegistry.on('open-namespace-in-new-tab', (metadata) => { if (metadata.namespace) { const namespace = toNS(metadata.namespace); if (namespace.collection !== '') { store.dispatch( - createNewTab( - metadata.namespace, - metadata.isReadonly, - metadata.sourceName, - metadata.editViewName, - metadata.isSourceReadonly, - metadata.sourceViewOn, - metadata.sourcePipeline - ) + createNewTab({ + namespace: metadata.namespace, + isReadonly: metadata.isReadonly, + sourceName: metadata.sourceName, + editViewName: metadata.editViewName, + isSourceReadonly: metadata.isSourceReadonly, + isTimeSeries: !!metadata.isTimeSeries, + sourceViewOn: metadata.sourceViewOn, + sourcePipeline: metadata.sourcePipeline + }) ); } } @@ -57,15 +58,16 @@ store.onActivated = (appRegistry) => { const namespace = toNS(metadata.namespace); if (namespace.collection !== '') { store.dispatch( - selectOrCreateTab( - metadata.namespace, - metadata.isReadonly, - metadata.sourceName, - metadata.editViewName, - metadata.isSourceReadonly, - metadata.sourceViewOn, - metadata.sourcePipeline - ) + selectOrCreateTab({ + namespace: metadata.namespace, + isReadonly: metadata.isReadonly, + isTimeSeries: metadata.isTimeSeries, + sourceName: metadata.sourceName, + editViewName: metadata.editViewName, + isSourceReadonly: metadata.isSourceReadonly, + sourceViewOn: metadata.sourceViewOn, + sourcePipeline: metadata.sourcePipeline + }) ); } } diff --git a/packages/compass-collection/test/stores/store.spec.js b/packages/compass-collection/test/stores/store.spec.js index 95e85661654..28777a46f24 100644 --- a/packages/compass-collection/test/stores/store.spec.js +++ b/packages/compass-collection/test/stores/store.spec.js @@ -144,6 +144,22 @@ describe('Collection Store', () => { expect(store.getState().tabs).to.have.length(0); }); }); + + context.skip('when the colletion is a time-series collection', () => { + beforeEach(() => { + appRegistry.emit( + 'open-namespace-in-new-tab', + { + namespace: 'db.coll', + isTimeSeries: true + } + ); + }); + + it('creates a tab in the store that has isTimeSeries set', () => { + expect(store.getState().tabs[0].isTimeSeries).to.equal(true); + }); + }); }); }); }); diff --git a/packages/compass-crud/package.json b/packages/compass-crud/package.json index 61909c583c5..03000b88bda 100644 --- a/packages/compass-crud/package.json +++ b/packages/compass-crud/package.json @@ -137,8 +137,6 @@ "xvfb-maybe": "^0.2.1" }, "dependencies": { - "@leafygreen-ui/icon": "^11.2.0", - "@leafygreen-ui/icon-button": "^9.1.5", "ag-grid-community": "20.2.0", "ag-grid-react": "20.2.0", "brace": "^0.11.1", diff --git a/packages/compass-crud/src/components/document-actions.jsx b/packages/compass-crud/src/components/document-actions.jsx index b6d92037061..09d019c501b 100644 --- a/packages/compass-crud/src/components/document-actions.jsx +++ b/packages/compass-crud/src/components/document-actions.jsx @@ -1,24 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -// import { IconButton } from 'hadron-react-buttons'; -import IconButton, { Size as IconButtonSizes } from '@leafygreen-ui/icon-button'; -import Icon from '@leafygreen-ui/icon'; - +import { IconButton } from 'hadron-react-buttons'; import UpdatableIconButton from './updatable-icon-button'; /** * Component for actions on the document. */ class DocumentActions extends React.Component { - /** - * Instantiate the actions. - * - * @param {Object} props - The properties. - */ - constructor(props) { - super(props); - } - /** * Render the expand all button. * @@ -26,29 +14,16 @@ class DocumentActions extends React.Component { */ renderExpandAll() { const title = this.props.allExpanded ? 'Collapse All' : 'Expand All'; - // const iconClass = this.props.allExpanded ? 'fa-angle-down' : 'fa-angle-right'; + const iconClass = this.props.allExpanded ? 'fa-angle-down' : 'fa-angle-right'; return (
- - - - {/* */} + dataTestId="expand-all-button" + />
); } @@ -63,7 +38,7 @@ class DocumentActions extends React.Component {
{this.props.expandAll && this.renderExpandAll()}
- {/* {this.props.edit && } */} - {this.props.edit && - - } - {this.props.copy && - - } - {this.props.clone && - {/* */} - - } - {this.props.remove && - - } + />}
); @@ -157,9 +75,9 @@ class DocumentActions extends React.Component { DocumentActions.displayName = 'DocumentActions'; DocumentActions.propTypes = { - edit: PropTypes.func.isRequired, - remove: PropTypes.func.isRequired, - clone: PropTypes.func.isRequired, + edit: PropTypes.func, + remove: PropTypes.func, + clone: PropTypes.func, allExpanded: PropTypes.bool, expandAll: PropTypes.func }; diff --git a/packages/compass-crud/src/components/document.jsx b/packages/compass-crud/src/components/document.jsx index 8ba3bc476d0..be28d3eba78 100644 --- a/packages/compass-crud/src/components/document.jsx +++ b/packages/compass-crud/src/components/document.jsx @@ -16,6 +16,7 @@ class Document extends React.Component { if (this.props.editable && this.props.isTimeSeries) { return ( { + this.props.openInsertDocumentDialog(this.props.doc.generateObject(), true); + } + setRenderSize(newLimit) { this.setState({ renderSize: newLimit }); } @@ -98,7 +104,12 @@ class ReadonlyDocument extends React.Component { } renderActions() { - // this.props.openInsertDocumentDialog && + return ( + + ) } /** diff --git a/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx b/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx index 187d3365ad0..ff0a27ecdbe 100644 --- a/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx +++ b/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import HadronDocument from 'hadron-document'; import { Document } from '@mongodb-js/compass-crud'; +import { clipboard } from 'electron'; import styles from './explain-json.less'; @@ -15,6 +16,10 @@ class ExplainJSON extends Component { rawExplainObject: PropTypes.object.isRequired } + copyToClipboard = () => { + clipboard.writeText(this.props.doc); + } + /** * Renders ExplainJSON component. * @@ -28,7 +33,11 @@ class ExplainJSON extends Component {
    - +
diff --git a/packages/compass-explain-plan/src/components/explain-json/explain-json.less b/packages/compass-explain-plan/src/components/explain-json/explain-json.less index a11e4ec8347..8048668d53e 100644 --- a/packages/compass-explain-plan/src/components/explain-json/explain-json.less +++ b/packages/compass-explain-plan/src/components/explain-json/explain-json.less @@ -7,7 +7,8 @@ padding: 0; .document-list { - padding-left: 15px; + padding: 0; + position: relative; } // Hacks for json view on explain tab diff --git a/packages/compass-sidebar/src/components/sidebar-collection/sidebar-collection.jsx b/packages/compass-sidebar/src/components/sidebar-collection/sidebar-collection.jsx index 3a0b6487ea1..01107e65393 100644 --- a/packages/compass-sidebar/src/components/sidebar-collection/sidebar-collection.jsx +++ b/packages/compass-sidebar/src/components/sidebar-collection/sidebar-collection.jsx @@ -5,12 +5,11 @@ import { DropdownButton, MenuItem } from 'react-bootstrap'; import toNS from 'mongodb-ns'; import Icon from '@leafygreen-ui/icon'; -import { collectionMetadata, getSource } from '../../modules/collection'; +import { collectionMetadata, getSource, TIME_SERIES_COLLECTION_TYPE } from '../../modules/collection'; import styles from './sidebar-collection.less'; const DEFAULT_COLLECTION_TYPE = 'collection'; -const TIME_SERIES_COLLECTION_TYPE = 'timeseries'; class SidebarCollection extends PureComponent { static displayName = 'SidebarCollection'; @@ -29,7 +28,8 @@ class SidebarCollection extends PureComponent { pipeline: PropTypes.any, // undefined or array if view collections: PropTypes.array.isRequired, type: PropTypes.string, - isDataLake: PropTypes.bool.isRequired + isDataLake: PropTypes.bool.isRequired, + isTimeSeries: PropTypes.bool }; /** diff --git a/packages/compass-sidebar/src/components/sidebar-database/sidebar-database.jsx b/packages/compass-sidebar/src/components/sidebar-database/sidebar-database.jsx index ab3f97993f2..edd7d40cabf 100644 --- a/packages/compass-sidebar/src/components/sidebar-database/sidebar-database.jsx +++ b/packages/compass-sidebar/src/components/sidebar-database/sidebar-database.jsx @@ -6,6 +6,7 @@ import styles from './sidebar-database.less'; import { TOOLTIP_IDS } from '../../constants/sidebar-constants'; import SidebarCollection from '../sidebar-collection'; +import { TIME_SERIES_COLLECTION_TYPE } from '../../modules/collection'; class SidebarDatabase extends PureComponent { static displayName = 'SidebarDatabase'; @@ -40,6 +41,7 @@ class SidebarDatabase extends PureComponent { isWritable: this.props.isWritable, description: this.props.description, isDataLake: this.props.isDataLake, + isTimeSeries: c.type === TIME_SERIES_COLLECTION_TYPE, collections: this.props.collections }; return ( diff --git a/packages/compass-sidebar/src/modules/collection.js b/packages/compass-sidebar/src/modules/collection.js index 6e3ef760629..00ea09bd60b 100644 --- a/packages/compass-sidebar/src/modules/collection.js +++ b/packages/compass-sidebar/src/modules/collection.js @@ -45,6 +45,8 @@ export const getSourceViewOn = (database, source) => { return null; }; +export const TIME_SERIES_COLLECTION_TYPE = 'timeseries'; + /** * Get the collection metadata to pass to the collection plugin. * @@ -60,6 +62,7 @@ export const collectionMetadata = (collection, collections, database, editViewNa return { namespace: collection._id, isReadonly: collection.readonly, + isTimeSeries: collection.type === TIME_SERIES_COLLECTION_TYPE, sourceName: getSourceName(collection.readonly, database, collection.view_on), isSourceReadonly: source ? source.readonly : false, sourceViewOn: getSourceViewOn(database, source), diff --git a/packages/compass-sidebar/src/modules/collection.spec.js b/packages/compass-sidebar/src/modules/collection.spec.js index cf7f377d956..f4722cdef5f 100644 --- a/packages/compass-sidebar/src/modules/collection.spec.js +++ b/packages/compass-sidebar/src/modules/collection.spec.js @@ -24,7 +24,13 @@ const VIEW_ON_VIEW = { pipeline: [] }; -const COLLECTIONS = [ COLL, VIEW, VIEW_ON_VIEW ]; +const TIME_SERIES = { + _id: 'db.testTimeSeries', + type: 'timeSeries', + readonly: false +}; + +const COLLECTIONS = [ COLL, VIEW, VIEW_ON_VIEW, TIME_SERIES ]; describe('collection module', () => { describe('#getSource', () => { @@ -80,6 +86,7 @@ describe('collection module', () => { expect(collectionMetadata(VIEW_ON_VIEW, COLLECTIONS, 'db', 'db.testView')).to.deep.equal({ namespace: 'db.testViewOnView', isReadonly: true, + isTimeSeries: false, sourceName: 'db.testView', isSourceReadonly: true, sourceViewOn: 'db.test', diff --git a/packages/databases-collections/src/modules/show-collection.js b/packages/databases-collections/src/modules/show-collection.js index 09cbf4b88e1..573f63c3d9b 100644 --- a/packages/databases-collections/src/modules/show-collection.js +++ b/packages/databases-collections/src/modules/show-collection.js @@ -1,5 +1,7 @@ import find from 'lodash.find'; import toNS from 'mongodb-ns'; + +import { TIME_SERIES_COLLECTION_TYPE } from '../../../compass-sidebar/src/modules/collection'; import { appRegistryEmit } from './app-registry'; /** @@ -39,6 +41,7 @@ export const showCollection = (name) => { { namespace: collection._id, isReadonly: collection.readonly, + isTimeSeries: collection.type === TIME_SERIES_COLLECTION_TYPE, sourceName: collection.view_on ? `${state.databaseName}.${collection.view_on}` : null, editViewName: null, isSourceReadonly: source ? source.readonly : false, From c14eab9d7612e0eac059e759cc3e706fd6081c77 Mon Sep 17 00:00:00 2001 From: Anemy Date: Tue, 22 Jun 2021 11:08:36 -0400 Subject: [PATCH 3/9] Update comments --- .../compass-collection/src/modules/context.js | 24 ++++++++-------- .../compass-collection/src/modules/tabs.js | 4 +-- .../src/components/expansion-bar.jsx | 28 +++++++++---------- .../compass-crud/src/stores/crud-store.js | 2 +- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/compass-collection/src/modules/context.js b/packages/compass-collection/src/modules/context.js index 8fd02ba3916..5f33cad90a0 100644 --- a/packages/compass-collection/src/modules/context.js +++ b/packages/compass-collection/src/modules/context.js @@ -21,17 +21,17 @@ const setupActions = (role, localAppRegistry) => { * Setup a scoped store to the collection. * * @param {Object} options - The plugin store options. - * @param {Object} options.role - The role. - * @param {Object} options.globalAppRegistry - The global app registry. - * @param {Object} options.localAppRegistry - The scoped app registry to the collection. - * @param {Object} options.dataService - The data service. - * @param {String} options.namespace - The namespace. - * @param {String} options.serverVersion - The server version. - * @param {Boolean} options.isReadonly - If the collection is a readonly view. - * @param {Object} options.actions - The actions for the store. - * @param {Boolean} options.allowWrites - If writes are allowed. - * @param {String} options.sourceName - The source namespace for the view. - * @param {String} options.editViewName - The name of the view we are editing. + * @property {Object} options.role - The role. + * @property {Object} options.globalAppRegistry - The global app registry. + * @property {Object} options.localAppRegistry - The scoped app registry to the collection. + * @property {Object} options.dataService - The data service. + * @property {String} options.namespace - The namespace. + * @property {String} options.serverVersion - The server version. + * @property {Boolean} options.isReadonly - If the collection is a readonly view. + * @property {Object} options.actions - The actions for the store. + * @property {Boolean} options.allowWrites - If writes are allowed. + * @property {String} options.sourceName - The source namespace for the view. + * @property {String} options.editViewName - The name of the view we are editing. * * @returns {Object} The configured store. */ @@ -76,7 +76,7 @@ const setupStore = ({ * Setup a scoped plugin to the tab. * * @param options - The plugin options. - * @param {Object} options.role - The role. + * @property {Object} options.role - The role. * @property {Object} options.globalAppRegistry - The global app registry. * @property {Object} options.localAppRegistry - The scoped app registry to the collection. * @property {Object} options.dataService - The data service. diff --git a/packages/compass-collection/src/modules/tabs.js b/packages/compass-collection/src/modules/tabs.js index dc3a4a463f0..d411e679287 100644 --- a/packages/compass-collection/src/modules/tabs.js +++ b/packages/compass-collection/src/modules/tabs.js @@ -330,8 +330,8 @@ export default function reducer(state = INITIAL_STATE, action) { * @property {String} options.sourceName - The source namespace. * @property {String} options.editViewName - The name of the view we are editing. * @property {Object} options.context - The tab context. - * @property {Boolean} sourceReadonly - * @property {String} sourceViewOn + * @property {Boolean} options.sourceReadonly + * @property {String} options.sourceViewOn * * @returns {Object} The create tab action. */ diff --git a/packages/compass-crud/src/components/expansion-bar.jsx b/packages/compass-crud/src/components/expansion-bar.jsx index 557164efdb8..d2a10dfac1e 100644 --- a/packages/compass-crud/src/components/expansion-bar.jsx +++ b/packages/compass-crud/src/components/expansion-bar.jsx @@ -88,22 +88,20 @@ class ExpansionBar extends React.PureComponent { * @returns {React.Component} The expander bar. */ render() { - const total = this.props.totalSize; - if (total <= this.props.initialSize) { - return null; - } - - const showMoreFields = Math.min( - total - this.props.renderSize, - this.props.perClickSize - ); - const hideFields = this.props.renderSize - this.props.initialSize; const components = []; - if (this.props.renderSize < total) { - components.push(this.renderShowMoreFieldsButton(showMoreFields)); - } - if (this.props.renderSize > this.props.initialSize && !this.props.disableHideButton) { - components.push(this.renderHideFieldsButton(hideFields)); + const total = this.props.totalSize; + if (total > this.props.initialSize) { + const showMoreFields = Math.min( + total - this.props.renderSize, + this.props.perClickSize + ); + const hideFields = this.props.renderSize - this.props.initialSize; + if (this.props.renderSize < total) { + components.push(this.renderShowMoreFieldsButton(showMoreFields)); + } + if (this.props.renderSize > this.props.initialSize && !this.props.disableHideButton) { + components.push(this.renderHideFieldsButton(hideFields)); + } } return (
diff --git a/packages/compass-crud/src/stores/crud-store.js b/packages/compass-crud/src/stores/crud-store.js index 52f7803c1b9..c96f085a810 100644 --- a/packages/compass-crud/src/stores/crud-store.js +++ b/packages/compass-crud/src/stores/crud-store.js @@ -109,7 +109,7 @@ export const setIsReadonly = (store, isReadonly) => { * Set the isTimeSeries flag in the store. * * @param {Store} store - The store. - * @param {Boolean} isTimeSeries - If the collection is readonly. + * @param {Boolean} isTimeSeries - If the collection is a time-series collection. */ export const setIsTimeSeries = (store, isTimeSeries) => { store.onTimeSeriesChanged(isTimeSeries); From a5e51c94599be5f8c095cd64a237d427e6919a26 Mon Sep 17 00:00:00 2001 From: Anemy Date: Tue, 22 Jun 2021 13:06:47 -0400 Subject: [PATCH 4/9] make copy work on explain plan json --- .../compass-crud/src/components/readonly-document.jsx | 9 ++++++++- .../src/components/explain-json/explain-json.jsx | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/compass-crud/src/components/readonly-document.jsx b/packages/compass-crud/src/components/readonly-document.jsx index b62d14a3c58..4ce9d95d5e9 100644 --- a/packages/compass-crud/src/components/readonly-document.jsx +++ b/packages/compass-crud/src/components/readonly-document.jsx @@ -57,6 +57,13 @@ class ReadonlyDocument extends React.Component { this.props.openInsertDocumentDialog(this.props.doc.generateObject(), true); } + /** + * Handle copying JSON to clipboard of the document. + */ + handleCopy = () => { + this.props.copyToClipboard(this.props.doc); + } + setRenderSize(newLimit) { this.setState({ renderSize: newLimit }); } @@ -106,7 +113,7 @@ class ReadonlyDocument extends React.Component { renderActions() { return ( ) diff --git a/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx b/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx index ff0a27ecdbe..a79a4bdc733 100644 --- a/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx +++ b/packages/compass-explain-plan/src/components/explain-json/explain-json.jsx @@ -17,7 +17,7 @@ class ExplainJSON extends Component { } copyToClipboard = () => { - clipboard.writeText(this.props.doc); + clipboard.writeText(JSON.stringify(this.props.rawExplainObject.originalData)); } /** From 2efa89d6aaa8dad01f75590085289c65641333bb Mon Sep 17 00:00:00 2001 From: Anemy Date: Tue, 22 Jun 2021 13:36:13 -0400 Subject: [PATCH 5/9] create new tab format --- .../src/components/create-tab/create-tab.jsx | 10 +++++----- .../src/components/create-tab/create-tab.spec.js | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/compass-collection/src/components/create-tab/create-tab.jsx b/packages/compass-collection/src/components/create-tab/create-tab.jsx index 9c7bdc59516..ba7b85fa72d 100644 --- a/packages/compass-collection/src/components/create-tab/create-tab.jsx +++ b/packages/compass-collection/src/components/create-tab/create-tab.jsx @@ -17,11 +17,11 @@ class CreateTab extends PureComponent { * Create a new tab with the same namespace as the last one. */ createTab = () => { - this.props.createNewTab( - this.props.activeNamespace, - this.props.activeIsReadonly, - this.props.activeSourceName - ); + this.props.createNewTab({ + namespace: this.props.activeNamespace, + isReadonly: this.props.activeIsReadonly, + sourceName: this.props.activeSourceName + }); } /** diff --git a/packages/compass-collection/src/components/create-tab/create-tab.spec.js b/packages/compass-collection/src/components/create-tab/create-tab.spec.js index 2e29e5eecd1..06c04f7a615 100644 --- a/packages/compass-collection/src/components/create-tab/create-tab.spec.js +++ b/packages/compass-collection/src/components/create-tab/create-tab.spec.js @@ -32,7 +32,11 @@ describe('CreateTab [Component]', () => { context('when clicking the create button', () => { it('calls the action', () => { component.find(`.${styles['create-tab']}`).simulate('click'); - expect(createNewTabSpy.calledWith('db.coll')).to.equal(true); + expect(createNewTabSpy.firstCall.args[0]).to.deep.equal({ + namespace: 'db.coll', + isReadonly: false, + sourceName: '' + }); }); }); }); From 70e1987de27db0be6ef26b3d20179c655677c4ba Mon Sep 17 00:00:00 2001 From: Anemy Date: Tue, 22 Jun 2021 18:42:23 -0400 Subject: [PATCH 6/9] lint fixes --- .../components/collection-header/collection-header.jsx | 1 + packages/compass-collection/src/modules/tabs.js | 2 +- .../compass-crud/src/components/document-actions.jsx | 1 + .../compass-crud/src/components/readonly-document.jsx | 10 +++++----- packages/compass-crud/src/stores/crud-store.js | 4 ++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header/collection-header.jsx b/packages/compass-collection/src/components/collection-header/collection-header.jsx index e3ddfddaa6a..aeec2b875fe 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.jsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.jsx @@ -13,6 +13,7 @@ class CollectionHeader extends Component { globalAppRegistry: PropTypes.func.isRequired, namespace: PropTypes.string.isRequired, isReadonly: PropTypes.bool.isRequired, + isTimeSeries: PropTypes.bool.isRequired, statsPlugin: PropTypes.func.isRequired, selectOrCreateTab: PropTypes.func.isRequired, statsStore: PropTypes.object.isRequired, diff --git a/packages/compass-collection/src/modules/tabs.js b/packages/compass-collection/src/modules/tabs.js index d411e679287..1ed553eb176 100644 --- a/packages/compass-collection/src/modules/tabs.js +++ b/packages/compass-collection/src/modules/tabs.js @@ -332,7 +332,7 @@ export default function reducer(state = INITIAL_STATE, action) { * @property {Object} options.context - The tab context. * @property {Boolean} options.sourceReadonly * @property {String} options.sourceViewOn - * + * * @returns {Object} The create tab action. */ export const createTab = ({ diff --git a/packages/compass-crud/src/components/document-actions.jsx b/packages/compass-crud/src/components/document-actions.jsx index 09d019c501b..cd50fe9e6fe 100644 --- a/packages/compass-crud/src/components/document-actions.jsx +++ b/packages/compass-crud/src/components/document-actions.jsx @@ -75,6 +75,7 @@ class DocumentActions extends React.Component { DocumentActions.displayName = 'DocumentActions'; DocumentActions.propTypes = { + copy: PropTypes.func, edit: PropTypes.func, remove: PropTypes.func, clone: PropTypes.func, diff --git a/packages/compass-crud/src/components/readonly-document.jsx b/packages/compass-crud/src/components/readonly-document.jsx index 4ce9d95d5e9..68beccca654 100644 --- a/packages/compass-crud/src/components/readonly-document.jsx +++ b/packages/compass-crud/src/components/readonly-document.jsx @@ -53,6 +53,10 @@ class ReadonlyDocument extends React.Component { } } + setRenderSize(newLimit) { + this.setState({ renderSize: newLimit }); + } + handleClone = () => { this.props.openInsertDocumentDialog(this.props.doc.generateObject(), true); } @@ -64,10 +68,6 @@ class ReadonlyDocument extends React.Component { this.props.copyToClipboard(this.props.doc); } - setRenderSize(newLimit) { - this.setState({ renderSize: newLimit }); - } - /** * Get the elements for the document. * @@ -116,7 +116,7 @@ class ReadonlyDocument extends React.Component { copy={this.props.copyToClipboard ? this.handleCopy : undefined} clone={this.props.openInsertDocumentDialog ? this.handleClone : undefined} /> - ) + ); } /** diff --git a/packages/compass-crud/src/stores/crud-store.js b/packages/compass-crud/src/stores/crud-store.js index c96f085a810..34102360313 100644 --- a/packages/compass-crud/src/stores/crud-store.js +++ b/packages/compass-crud/src/stores/crud-store.js @@ -111,7 +111,7 @@ export const setIsReadonly = (store, isReadonly) => { * @param {Store} store - The store. * @param {Boolean} isTimeSeries - If the collection is a time-series collection. */ - export const setIsTimeSeries = (store, isTimeSeries) => { +export const setIsTimeSeries = (store, isTimeSeries) => { store.onTimeSeriesChanged(isTimeSeries); }; @@ -269,7 +269,7 @@ const configureStore = (options = {}) => { * * @param {Boolean} isTimeSeries - If the collection is time-series. */ - onTimeSeriesChanged(isTimeSeries) { + onTimeSeriesChanged(isTimeSeries) { this.setState({ isTimeSeries: isTimeSeries }); }, From de2cd0e0192780c852a4cfc2ab1e399f107daf9e Mon Sep 17 00:00:00 2001 From: Anemy Date: Wed, 23 Jun 2021 03:01:06 -0400 Subject: [PATCH 7/9] use all tab attributes to create new tab --- .../src/components/create-tab/create-tab.jsx | 21 +++-------- .../src/components/workspace/workspace.jsx | 36 +++++++------------ 2 files changed, 17 insertions(+), 40 deletions(-) diff --git a/packages/compass-collection/src/components/create-tab/create-tab.jsx b/packages/compass-collection/src/components/create-tab/create-tab.jsx index ba7b85fa72d..a070a0f8d2f 100644 --- a/packages/compass-collection/src/components/create-tab/create-tab.jsx +++ b/packages/compass-collection/src/components/create-tab/create-tab.jsx @@ -7,23 +7,9 @@ class CreateTab extends PureComponent { static displayName = 'CreateTabComponent'; static propTypes = { - createNewTab: PropTypes.func.isRequired, - activeNamespace: PropTypes.string.isRequired, - activeIsReadonly: PropTypes.bool.isRequired, - activeSourceName: PropTypes.string + createNewTab: PropTypes.func.isRequired }; - /** - * Create a new tab with the same namespace as the last one. - */ - createTab = () => { - this.props.createNewTab({ - namespace: this.props.activeNamespace, - isReadonly: this.props.activeIsReadonly, - sourceName: this.props.activeSourceName - }); - } - /** * Render the Create Tab component. * @@ -31,7 +17,10 @@ class CreateTab extends PureComponent { */ render() { return ( -
+
this.props.createNewTab()} + > +
); diff --git a/packages/compass-collection/src/components/workspace/workspace.jsx b/packages/compass-collection/src/components/workspace/workspace.jsx index f1eed817f0f..fe8343052c7 100644 --- a/packages/compass-collection/src/components/workspace/workspace.jsx +++ b/packages/compass-collection/src/components/workspace/workspace.jsx @@ -41,6 +41,12 @@ const KEY_CLOSE_BRKT = 221; */ const KEY_OPEN_BRKT = 219; +const DEFAULT_NEW_TAB = { + namespace: '', + isReadonly: false, + sourceName: '' +}; + /** * The collection workspace contains tabs of multiple collections. */ @@ -95,7 +101,7 @@ class Workspace extends PureComponent { * * @param {Event} evt - The event. */ - handleKeypress(evt) { + handleKeypress = (evt) => { if (evt.ctrlKey || evt.metaKey) { if (evt.shiftKey) { if (evt.keyCode === KEY_CLOSE_BRKT) { @@ -109,7 +115,7 @@ class Workspace extends PureComponent { evt.preventDefault(); } } else if (evt.keyCode === KEY_T) { - this.props.createNewTab(this.activeNamespace()); + this.onCreateNewTab(); } } } @@ -118,24 +124,8 @@ class Workspace extends PureComponent { return this.props.tabs.find(tab => tab.isActive); } - /** - * Get the active namespace in the list. - * - * @returns {String} The active namespace in the list. - */ - activeNamespace() { - const activeTab = this.activeTab(); - return activeTab ? activeTab.namespace : ''; - } - - activeIsReadonly() { - const activeTab = this.activeTab(); - return activeTab ? activeTab.isReadonly : false; - } - - activeSourceName() { - const activeTab = this.activeTab(); - return activeTab ? activeTab.sourceName : undefined; + onCreateNewTab = () => { + this.props.createNewTab(this.activeTab() || DEFAULT_NEW_TAB); } renderTab = (tab, i) => { @@ -237,10 +227,8 @@ class Workspace extends PureComponent {
{this.renderTabs()} + createNewTab={this.onCreateNewTab} + />
From 9d13024d3b90fa2bdd608177d6de6f3f51fa9022 Mon Sep 17 00:00:00 2001 From: Anemy Date: Wed, 23 Jun 2021 03:13:10 -0400 Subject: [PATCH 8/9] lint and fix test --- .../src/components/create-tab/create-tab.spec.js | 12 +++--------- .../src/components/workspace/workspace.jsx | 8 ++++---- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/compass-collection/src/components/create-tab/create-tab.spec.js b/packages/compass-collection/src/components/create-tab/create-tab.spec.js index 06c04f7a615..d49c40852db 100644 --- a/packages/compass-collection/src/components/create-tab/create-tab.spec.js +++ b/packages/compass-collection/src/components/create-tab/create-tab.spec.js @@ -13,10 +13,8 @@ describe('CreateTab [Component]', () => { component = mount( + createNewTab={createNewTabSpy} + /> ); }); @@ -32,11 +30,7 @@ describe('CreateTab [Component]', () => { context('when clicking the create button', () => { it('calls the action', () => { component.find(`.${styles['create-tab']}`).simulate('click'); - expect(createNewTabSpy.firstCall.args[0]).to.deep.equal({ - namespace: 'db.coll', - isReadonly: false, - sourceName: '' - }); + expect(createNewTabSpy.called).to.equal(true); }); }); }); diff --git a/packages/compass-collection/src/components/workspace/workspace.jsx b/packages/compass-collection/src/components/workspace/workspace.jsx index fe8343052c7..05efd95861c 100644 --- a/packages/compass-collection/src/components/workspace/workspace.jsx +++ b/packages/compass-collection/src/components/workspace/workspace.jsx @@ -94,6 +94,10 @@ class Workspace extends PureComponent { this.props.moveTab(oldIndex, newIndex); } + onCreateNewTab = () => { + this.props.createNewTab(this.activeTab() || DEFAULT_NEW_TAB); + } + /** * Handle key press. This listens for CTRL/CMD+T and CTRL/CMD+W to control * natural opening and closing of collection tabs. CTRL/CMD+SHIFT+] and @@ -124,10 +128,6 @@ class Workspace extends PureComponent { return this.props.tabs.find(tab => tab.isActive); } - onCreateNewTab = () => { - this.props.createNewTab(this.activeTab() || DEFAULT_NEW_TAB); - } - renderTab = (tab, i) => { return ( Date: Wed, 23 Jun 2021 12:25:37 -0400 Subject: [PATCH 9/9] Use only one variable name for the source readonly boolean --- .../src/modules/create-view/index.js | 2 +- .../src/modules/update-view.js | 2 +- .../compass-collection/electron/renderer/index.js | 6 +++--- .../src/components/workspace/workspace.jsx | 15 ++++++++++++++- packages/compass-collection/src/stores/store.js | 4 ++-- .../compass-sidebar/src/modules/collection.js | 2 +- .../src/modules/collection.spec.js | 2 +- .../src/modules/show-collection.js | 2 +- 8 files changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/compass-aggregations/src/modules/create-view/index.js b/packages/compass-aggregations/src/modules/create-view/index.js index 934db767eed..a1b9d9423f1 100644 --- a/packages/compass-aggregations/src/modules/create-view/index.js +++ b/packages/compass-aggregations/src/modules/create-view/index.js @@ -171,7 +171,7 @@ export const createView = () => { isReadonly: true, sourceName: viewSource, editViewName: null, - isSourceReadonly: state.isReadonly, + sourceReadonly: state.isReadonly, sourceViewOn: state.sourceName, sourcePipeline: viewPipeline } diff --git a/packages/compass-aggregations/src/modules/update-view.js b/packages/compass-aggregations/src/modules/update-view.js index fb03d12dabd..3e633308c7f 100644 --- a/packages/compass-aggregations/src/modules/update-view.js +++ b/packages/compass-aggregations/src/modules/update-view.js @@ -87,7 +87,7 @@ export const updateView = () => { isReadonly: true, sourceName: state.namespace, editViewName: null, - isSourceReadonly: state.isReadonly, + sourceReadonly: state.isReadonly, sourceViewOn: state.sourceName, sourcePipeline: viewPipeline }; diff --git a/packages/compass-collection/electron/renderer/index.js b/packages/compass-collection/electron/renderer/index.js index 9a70b190fa0..df78e210419 100644 --- a/packages/compass-collection/electron/renderer/index.js +++ b/packages/compass-collection/electron/renderer/index.js @@ -102,7 +102,7 @@ dataService.connect((error, ds) => { isReadonly: false, sourceName: null, editViewName: null, - isSourceReadonly: false, + sourceReadonly: false, sourceViewOn: null } ); @@ -113,7 +113,7 @@ dataService.connect((error, ds) => { isReadonly: true, sourceName: 'citibike.trips', editViewName: null, - isSourceReadonly: false, + sourceReadonly: false, sourceViewOn: null, sourcePipeline: [{ '$match': { name: 'testing' }}] } @@ -125,7 +125,7 @@ dataService.connect((error, ds) => { isReadonly: true, sourceName: 'citibike.tripsOfShortDuration', editViewName: null, - isSourceReadonly: true, + sourceReadonly: true, sourceViewOn: 'citibike.trips', sourcePipeline: [{ '$match': { gender: 0 }}] } diff --git a/packages/compass-collection/src/components/workspace/workspace.jsx b/packages/compass-collection/src/components/workspace/workspace.jsx index 05efd95861c..58546d9ba29 100644 --- a/packages/compass-collection/src/components/workspace/workspace.jsx +++ b/packages/compass-collection/src/components/workspace/workspace.jsx @@ -95,7 +95,20 @@ class Workspace extends PureComponent { } onCreateNewTab = () => { - this.props.createNewTab(this.activeTab() || DEFAULT_NEW_TAB); + const activeTab = this.activeTab(); + const newTabProps = activeTab + ? { + namespace: activeTab.namespace, + isReadonly: activeTab.isReadonly, + isTimeSeries: activeTab.isTimeSeries, + sourceName: activeTab.sourceName, + editViewName: activeTab.editViewName, + sourceReadonly: activeTab.sourceReadonly, + sourceViewOn: activeTab.sourceViewOn, + sourcePipeline: activeTab.pipeline + } + : DEFAULT_NEW_TAB; + this.props.createNewTab(newTabProps); } /** diff --git a/packages/compass-collection/src/stores/store.js b/packages/compass-collection/src/stores/store.js index 6dc180a9767..bbc5ec495d4 100644 --- a/packages/compass-collection/src/stores/store.js +++ b/packages/compass-collection/src/stores/store.js @@ -38,7 +38,7 @@ store.onActivated = (appRegistry) => { isReadonly: metadata.isReadonly, sourceName: metadata.sourceName, editViewName: metadata.editViewName, - isSourceReadonly: metadata.isSourceReadonly, + sourceReadonly: metadata.sourceReadonly, isTimeSeries: !!metadata.isTimeSeries, sourceViewOn: metadata.sourceViewOn, sourcePipeline: metadata.sourcePipeline @@ -64,7 +64,7 @@ store.onActivated = (appRegistry) => { isTimeSeries: metadata.isTimeSeries, sourceName: metadata.sourceName, editViewName: metadata.editViewName, - isSourceReadonly: metadata.isSourceReadonly, + sourceReadonly: metadata.sourceReadonly, sourceViewOn: metadata.sourceViewOn, sourcePipeline: metadata.sourcePipeline }) diff --git a/packages/compass-sidebar/src/modules/collection.js b/packages/compass-sidebar/src/modules/collection.js index 00ea09bd60b..25de42a8be4 100644 --- a/packages/compass-sidebar/src/modules/collection.js +++ b/packages/compass-sidebar/src/modules/collection.js @@ -64,7 +64,7 @@ export const collectionMetadata = (collection, collections, database, editViewNa isReadonly: collection.readonly, isTimeSeries: collection.type === TIME_SERIES_COLLECTION_TYPE, sourceName: getSourceName(collection.readonly, database, collection.view_on), - isSourceReadonly: source ? source.readonly : false, + sourceReadonly: source ? source.readonly : false, sourceViewOn: getSourceViewOn(database, source), sourcePipeline: collection.pipeline, editViewName: editViewName diff --git a/packages/compass-sidebar/src/modules/collection.spec.js b/packages/compass-sidebar/src/modules/collection.spec.js index f4722cdef5f..ae7b776736c 100644 --- a/packages/compass-sidebar/src/modules/collection.spec.js +++ b/packages/compass-sidebar/src/modules/collection.spec.js @@ -88,7 +88,7 @@ describe('collection module', () => { isReadonly: true, isTimeSeries: false, sourceName: 'db.testView', - isSourceReadonly: true, + sourceReadonly: true, sourceViewOn: 'db.test', sourcePipeline: [], editViewName: 'db.testView' diff --git a/packages/databases-collections/src/modules/show-collection.js b/packages/databases-collections/src/modules/show-collection.js index 573f63c3d9b..ce3a1f7f526 100644 --- a/packages/databases-collections/src/modules/show-collection.js +++ b/packages/databases-collections/src/modules/show-collection.js @@ -44,7 +44,7 @@ export const showCollection = (name) => { isTimeSeries: collection.type === TIME_SERIES_COLLECTION_TYPE, sourceName: collection.view_on ? `${state.databaseName}.${collection.view_on}` : null, editViewName: null, - isSourceReadonly: source ? source.readonly : false, + sourceReadonly: source ? source.readonly : false, sourceViewOn: source ? `${state.databaseName}.${source.view_on}` : null, sourcePipeline: collection.pipeline || null }