Unverified Commit 1451a7ec authored by Allison Suarez Miranda's avatar Allison Suarez Miranda Committed by GitHub

feat: Make 'schema' and 'database' clickable to initiate a search (#766)

* search works, no checkbox marked
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* search for schema is working
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* added these || to set default values for missing props
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* changed the tests to kind of adjust to new testing practices, left some very much the same
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* fixed tests, all that's missing is the checkbox
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* fixed small == vs === typo
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* oops
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* prettier lint'
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* lintttt
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* filter now shows checked box
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>

* fixed prettier error
Signed-off-by: 's avatarAllison Suarez Miranda <asuarezmiranda@lyft.com>
parent 13164bf4
......@@ -2,15 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { mocked } from 'ts-jest/utils';
import { shallow } from 'enzyme';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { BrowserRouter } from 'react-router-dom';
import { ResourceType } from 'interfaces/Resources';
import {
getSourceDisplayName,
getDisplayNameByResource,
} from 'config/config-utils';
import globalState from 'fixtures/globalState';
import TableHeaderBullets, { TableHeaderBulletsProps } from '.';
const MOCK_RESOURCE_DISPLAY_NAME = 'Test';
......@@ -22,22 +25,62 @@ jest.mock('config/config-utils', () => ({
getSourceDisplayName: jest.fn(),
}));
describe('TableHeaderBullets', () => {
const setup = (propOverrides?: Partial<TableHeaderBulletsProps>) => {
const props: TableHeaderBulletsProps = {
database: 'hive',
cluster: 'main',
isView: true,
...propOverrides,
};
const wrapper = shallow(<TableHeaderBullets {...props} />);
return { props, wrapper };
let noDatabase;
let noCluster;
let noIsView;
const middlewares = [];
const mockStore = configureStore(middlewares);
const setup = (propOverrides?: Partial<TableHeaderBulletsProps>) => {
const props = {
database: 'hive',
cluster: 'main',
isView: true,
...propOverrides,
};
const testState = globalState;
const wrapper = mount<TableHeaderBulletsProps>(
<Provider store={mockStore(testState)}>
<BrowserRouter>
<TableHeaderBullets {...props} />
</BrowserRouter>
</Provider>
);
return { props, wrapper };
};
describe('TableHeaderBullets', () => {
describe('when no props passed', () => {
const { wrapper } = setup({
database: noDatabase,
cluster: noCluster,
isView: noIsView,
});
it('renders TableHeaderBullets element', () => {
const actual = wrapper.find('.header-bullets').length;
const expected = 1;
expect(actual).toEqual(expected);
});
it('renders TableHeaderBullets list with default props', () => {
const actualDatabase = wrapper.find('ul').find('li').at(0).text();
const expectedDatabase = '';
const actualCluster = wrapper.find('ul').find('li').at(1).text();
const expectedCluster = '';
const actualIsView = wrapper.find('ul').find('li').at(2).text();
const expectedIsView = '';
expect(actualDatabase).toEqual(expectedDatabase);
expect(actualCluster).toEqual(expectedCluster);
expect(actualIsView).toEqual(expectedIsView);
});
});
describe('render', () => {
let props: TableHeaderBulletsProps;
describe('when props are defined', () => {
let props;
let wrapper;
let listElement;
beforeAll(() => {
mocked(getSourceDisplayName).mockImplementation(
() => MOCK_DB_DISPLAY_NAME
......@@ -48,34 +91,37 @@ describe('TableHeaderBullets', () => {
const setupResult = setup();
props = setupResult.props;
wrapper = setupResult.wrapper;
listElement = wrapper.find('ul');
});
it('renders a list with correct class', () => {
expect(listElement.props().className).toEqual('header-bullets');
});
it('renders TableHeaderBullets element', () => {
const actual = wrapper.find('.header-bullets').length;
const expected = 1;
expect(actual).toEqual(expected);
});
it('renders a list with resource display name', () => {
console.log(wrapper.debug());
expect(getDisplayNameByResource).toHaveBeenCalledWith(ResourceType.table);
expect(listElement.find('li').at(0).text()).toEqual(
expect(wrapper.find('ul').find('li').at(0).text()).toEqual(
MOCK_RESOURCE_DISPLAY_NAME
);
});
it('renders a list with database display name', () => {
expect(getSourceDisplayName).toHaveBeenCalledWith(
props.database,
ResourceType.table
);
expect(listElement.find('li').at(1).text()).toEqual(MOCK_DB_DISPLAY_NAME);
expect(wrapper.find('ul').find('li').at(1).text()).toEqual(
MOCK_DB_DISPLAY_NAME
);
});
it('renders a list with cluster', () => {
expect(listElement.find('li').at(2).text()).toEqual(props.cluster);
expect(wrapper.find('ul').find('li').at(2).text()).toEqual(props.cluster);
});
it('renders a list with table view', () => {
expect(listElement.find('li').at(3).text()).toEqual(TABLE_VIEW_TEXT);
expect(wrapper.find('ul').find('li').at(3).text()).toEqual(
TABLE_VIEW_TEXT
);
});
});
});
// Copyright Contributors to the Amundsen project.
// Copyright Contributors to the Amundsen project. /*
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { Link } from 'react-router-dom';
import {
getDisplayNameByResource,
getSourceDisplayName,
} from 'config/config-utils';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { updateSearchState } from 'ducks/search/reducer';
import { UpdateSearchStateRequest } from 'ducks/search/types';
import { logClick } from 'ducks/utilMethods';
import { ResourceType } from 'interfaces/Resources';
import { TABLE_VIEW_TEXT } from './constants';
export interface TableHeaderBulletsProps {
export interface HeaderBulletsProps {
cluster: string;
database: string;
isView: boolean;
}
export interface DispatchFromProps {
searchDatabase: (databaseText: string) => UpdateSearchStateRequest;
}
const TableHeaderBullets: React.FC<TableHeaderBulletsProps> = ({
cluster,
database,
isView,
}: TableHeaderBulletsProps) => {
return (
<ul className="header-bullets">
<li>{getDisplayNameByResource(ResourceType.table)}</li>
<li>{getSourceDisplayName(database, ResourceType.table)}</li>
<li>{cluster}</li>
{isView && <li>{TABLE_VIEW_TEXT}</li>}
</ul>
);
};
export type TableHeaderBulletsProps = HeaderBulletsProps & DispatchFromProps;
TableHeaderBullets.defaultProps = {
cluster: '',
database: '',
isView: false,
export class TableHeaderBullets extends React.Component<
TableHeaderBulletsProps
> {
handleClick = (e) => {
const databaseText = this.props.database;
logClick(e, {
target_type: 'database',
label: databaseText,
});
this.props.searchDatabase(databaseText);
};
render() {
const isViewCheck =
this.props.isView === undefined ? false : this.props.isView;
return (
<ul className="header-bullets">
<li>{getDisplayNameByResource(ResourceType.table)}</li>
<li>
<Link to="/search" onClick={this.handleClick}>
{getSourceDisplayName(
this.props.database || '',
ResourceType.table
)}
</Link>
</li>
<li>{this.props.cluster || ''}</li>
{isViewCheck && <li>{TABLE_VIEW_TEXT}</li>}
</ul>
);
}
}
export const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators(
{
searchDatabase: (databaseText: string) =>
updateSearchState({
filters: {
[ResourceType.table]: { database: { [databaseText]: true } },
},
submitSearch: true,
}),
},
dispatch
);
};
export default TableHeaderBullets;
export default connect<null, DispatchFromProps, HeaderBulletsProps>(
null,
mapDispatchToProps
)(TableHeaderBullets);
......@@ -41,6 +41,7 @@ const setup = (
tableData: tableMetadata,
getTableData: jest.fn(),
openRequestDescriptionDialog: jest.fn(),
searchSchema: jest.fn(),
...routerProps,
...propOverrides,
};
......
......@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import * as React from 'react';
import { Link } from 'react-router-dom';
import * as DocumentTitle from 'react-document-title';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
......@@ -10,8 +11,11 @@ import { RouteComponentProps } from 'react-router';
import { GlobalState } from 'ducks/rootReducer';
import { getTableData } from 'ducks/tableMetadata/reducer';
import { openRequestDescriptionDialog } from 'ducks/notification/reducer';
import { updateSearchState } from 'ducks/search/reducer';
import { GetTableDataRequest } from 'ducks/tableMetadata/types';
import { OpenRequestAction } from 'ducks/notification/types';
import { UpdateSearchStateRequest } from 'ducks/search/types';
import { logClick } from 'ducks/utilMethods';
import {
getDescriptionSourceDisplayName,
......@@ -90,6 +94,7 @@ export interface DispatchFromProps {
requestMetadataType: RequestMetadataType,
columnName: string
) => OpenRequestAction;
searchSchema: (schemaText: string) => UpdateSearchStateRequest;
}
export interface MatchProps {
......@@ -170,6 +175,17 @@ export class TableDetail extends React.Component<
return `${params.database}://${params.cluster}.${params.schema}/${params.table}`;
}
handleClick = (e) => {
const { match } = this.props;
const { params } = match;
const schemaText = params.schema;
logClick(e, {
target_type: 'schema',
label: schemaText,
});
this.props.searchSchema(schemaText);
};
renderProgrammaticDesc = (
descriptions: ProgrammaticDescription[] | undefined
) => {
......@@ -290,7 +306,10 @@ export class TableDetail extends React.Component<
</div>
<div className="header-section header-title">
<h1 className="header-title-text truncated">
{this.getDisplayName()}
<Link to="/search" onClick={this.handleClick}>
{data.schema}
</Link>
.{data.name}
</h1>
<BookmarkIcon
bookmarkKey={data.key}
......@@ -432,7 +451,17 @@ export const mapStateToProps = (state: GlobalState) => {
export const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators(
{ getTableData, openRequestDescriptionDialog },
{
getTableData,
openRequestDescriptionDialog,
searchSchema: (schemaText: string) =>
updateSearchState({
filters: {
[ResourceType.table]: { schema: schemaText },
},
submitSearch: true,
}),
},
dispatch
);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment