import React, { useEffect, useCallback, useContext } from 'react'; import { connect } from 'react-redux'; import { VirtualGrid, css, spacing, useSortControls, useSortedItems, } from '@mongodb-js/compass-components'; import { fetchItems } from '../stores/aggregations-queries-items'; import type { Item } from '../stores/aggregations-queries-items'; import { openSavedItem } from '../stores/open-item'; import type { RootState } from '../stores'; import { SavedItemCard, CARD_WIDTH, CARD_HEIGHT } from './saved-item-card'; import type { Action } from './saved-item-card'; import { NoSavedItems, NoSearchResults } from './empty-list-items'; import OpenItemModal from './open-item-modal'; import EditItemModal from './edit-item-modal'; import { useGridFilters, useFilteredItems } from '../hooks/use-grid-filters'; import { editItem } from '../stores/edit-item'; import { confirmDeleteItem } from '../stores/delete-item'; import { copyToClipboard } from '../stores/copy-to-clipboard'; import { useTrackOnChange } from '@mongodb-js/compass-logging/provider'; const sortBy: { name: keyof Item; label: string }[] = [ { name: 'name', label: 'Name', }, { name: 'lastModified', label: 'Last Modified', }, ]; const headerStyles = css({ padding: spacing[3], display: 'flex', justifyContent: 'space-between', }); const rowStyles = css({ gap: spacing[2], paddingLeft: spacing[3], paddingRight: spacing[3], paddingBottom: spacing[2], }); const noSavedItemsStyles = css({ width: '100%', }); const ControlsContext = React.createContext<{ filterControls: React.ReactElement | null; sortControls: React.ReactElement | null; }>({ filterControls: null, sortControls: null, }); const GridControls = () => { const { filterControls, sortControls } = useContext(ControlsContext); return (
{filterControls}
{sortControls}
); }; export type AggregationsQueriesListProps = { loading: boolean; items: Item[]; onMount(): void; onOpenItem(id: string): void; onEditItem(id: string): void; onDeleteItem(id: string): void; onCopyToClipboard(id: string): void; }; export const AggregationsQueriesList = ({ loading, items, onMount, onOpenItem, onEditItem, onDeleteItem, onCopyToClipboard, }: AggregationsQueriesListProps) => { useEffect(() => { void onMount(); }, [onMount]); const { controls: filterControls, conditions: filters, search, } = useGridFilters(items); const filteredItems = useFilteredItems(items, filters, search) .filter((e) => e.item.type !== 'updatemany') .sort((a, b) => { return a.score - b.score; }) .map((x) => x.item); useTrackOnChange( 'COMPASS-MY-QUERIES-UI', (track) => { track('Screen', { name: 'my_queries' }); }, [] ); useTrackOnChange( 'COMPASS-MY-QUERIES-UI', (track) => { if (filters.database) { track('My Queries Filter', { type: 'database' }); } }, [filters.database] ); useTrackOnChange( 'COMPASS-MY-QUERIES-UI', (track) => { if (filters.collection) { track('My Queries Filter', { type: 'collection' }); } }, [filters.collection] ); // If a user is searching, we disable the sort as // search results are sorted by match score const [sortControls, sortState] = useSortControls(sortBy, { isDisabled: Boolean(search), }); useTrackOnChange( 'COMPASS-MY-QUERIES-UI', (track) => { track('My Queries Sort', { sort_by: sortState.name, order: sortState.order === 1 ? 'ascending' : 'descending', }); }, [sortState] ); const sortedItems = useSortedItems(filteredItems, sortState); const onAction = useCallback( (id: string, actionName: Action) => { switch (actionName) { case 'open': onOpenItem(id); return; case 'rename': onEditItem(id); return; case 'delete': void onDeleteItem(id); return; case 'copy': void onCopyToClipboard(id); return; } }, [onOpenItem, onEditItem, onDeleteItem, onCopyToClipboard] ); const renderItem: React.ComponentProps['renderItem'] = useCallback( ({ index, ...props }: Omit, 'type'> & { index: number }) => { const item = sortedItems[index]; return ( ); }, [onAction, sortedItems] ); if (loading) { return null; } if (items.length === 0) { return (
); } return ( sortedItems[index].id} renderHeader={GridControls} headerHeight={spacing[5] + 36} renderEmptyList={NoSearchResults} classNames={{ row: rowStyles }} resetActiveItemOnBlur={false} > ); }; const mapState = ({ savedItems: { items, loading } }: RootState) => ({ items, loading, }); const mapDispatch = { onMount: fetchItems, onOpenItem: openSavedItem, onEditItem: editItem, onDeleteItem: confirmDeleteItem, onCopyToClipboard: copyToClipboard, }; export default connect( mapState, mapDispatch )(AggregationsQueriesList) as React.FunctionComponent>;