Skip to content

Commit

Permalink
feat: List available badges on Home & Browse Pages #1535
Browse files Browse the repository at this point in the history
Signed-off-by: Mariusz Górski <[email protected]>
  • Loading branch information
mgorsk1 authored Oct 15, 2021
1 parent b5074ba commit 5685791
Show file tree
Hide file tree
Showing 32 changed files with 720 additions and 38 deletions.
33 changes: 30 additions & 3 deletions frontend/amundsen_application/api/metadata/v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
LAST_INDEXED_ENDPOINT = '/latest_updated_ts'
POPULAR_RESOURCES_ENDPOINT = '/popular_resources'
TAGS_ENDPOINT = '/tags/'
BADGES_ENDPOINT = '/badges/'
USER_ENDPOINT = '/user'
DASHBOARD_ENDPOINT = '/dashboard'

Expand Down Expand Up @@ -375,10 +376,8 @@ def _log_put_column_description(*, table_key: str, column_name: str, description
@metadata_blueprint.route('/tags')
def get_tags() -> Response:
"""
call the metadata service endpoint to get the list of all tags from neo4j
call the metadata service endpoint to get the list of all tags from metadata proxy
:return: a json output containing the list of all tags, as 'tags'
Schema Defined Here: https://github.com/lyft/amundsenmetadatalibrary/blob/master/metadata_service/api/tag.py
"""
try:
url = app.config['METADATASERVICE_BASE'] + TAGS_ENDPOINT
Expand All @@ -402,6 +401,34 @@ def get_tags() -> Response:
return make_response(payload, HTTPStatus.INTERNAL_SERVER_ERROR)


@metadata_blueprint.route('/badges')
def get_badges() -> Response:
"""
call the metadata service endpoint to get the list of all badges from metadata proxy
:return: a json output containing the list of all badges, as 'badges'
"""
try:
url = app.config['METADATASERVICE_BASE'] + BADGES_ENDPOINT
response = request_metadata(url=url)
status_code = response.status_code

if status_code == HTTPStatus.OK:
message = 'Success'
badges = response.json().get('badges')
else:
message = 'Encountered error: Badges Unavailable'
logging.error(message)
badges = []

payload = jsonify({'badges': badges, 'msg': message})
return make_response(payload, status_code)
except Exception as e:
message = 'Encountered exception: ' + str(e)
payload = jsonify({'badges': [], 'msg': message})
logging.exception(message)
return make_response(payload, HTTPStatus.INTERNAL_SERVER_ERROR)


def _update_metadata_tag(table_key: str, method: str, tag: str) -> int:
table_endpoint = _get_table_endpoint()
url = f'{table_endpoint}/{table_key}/tag/{tag}'
Expand Down
17 changes: 4 additions & 13 deletions frontend/amundsen_application/static/.betterer.results
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,9 @@ exports[`eslint`] = {
[33, 6, 25, "Use object destructuring.", "354229464"],
[34, 6, 29, "Use object destructuring.", "2645724888"]
],
"js/components/BadgeList/index.spec.tsx:3772320601": [
"js/components/Badges/BadgeList/index.spec.tsx:3772320601": [
[153, 14, 36, "Use array destructuring.", "898356559"]
],
"js/components/BadgeList/index.tsx:3233891211": [
[42, 2, 52, "Visible, non-interactive elements with click handlers must have at least one keyboard listener.", "2290783753"],
[42, 2, 52, "Static HTML elements with event handlers require a role.", "2290783753"],
[68, 47, 2, "Array.prototype.map() expects a value to be returned at the end of arrow function.", "5859494"],
[68, 47, -1867, "Expected to return a value at the end of arrow function.", "5381"]
],
"js/components/Bookmark/BookmarkIcon/index.tsx:2757285913": [
[44, 8, 23, "Must use destructuring props assignment", "2039607050"],
[45, 6, 25, "Must use destructuring props assignment", "2219705271"],
Expand Down Expand Up @@ -585,7 +579,7 @@ exports[`eslint`] = {
"js/ducks/tags/api/v0.ts:2781466514": [
[21, 16, -605, "Expected to return a value at the end of function \'getResourceTags\'.", "5381"]
],
"js/features/BadgeList/index.tsx:4274393553": [
"js/features/BadgeList/index.tsx:2768467336": [
[3, 12, 5, "\'React\' is defined but never used.", "229961444"]
],
"js/features/ColumnList/ColumnStats/columnStats.story.tsx:2552692472": [
Expand Down Expand Up @@ -690,9 +684,6 @@ exports[`eslint`] = {
"js/features/NavBar/index.tsx:2853766101": [
[69, 8, 19, "Must use destructuring props assignment", "1779396464"]
],
"js/pages/BrowsePage/index.tsx:4021927425": [
[12, 7, 453, "Component should be written as a pure function", "779515038"]
],
"js/pages/DashboardPage/ChartList/index.spec.tsx:876473578": [
[21, 14, 5, "\'props\' is assigned a value but never used.", "187023499"]
],
Expand Down Expand Up @@ -749,8 +740,8 @@ exports[`eslint`] = {
[33, 4, 25, "Use object destructuring.", "354229464"],
[34, 4, 29, "Use object destructuring.", "2645724888"]
],
"js/pages/HomePage/index.tsx:2510324256": [
[32, 4, 22, "Must use destructuring props assignment", "2151395318"]
"js/pages/HomePage/index.tsx:3641863187": [
[33, 4, 22, "Must use destructuring props assignment", "2151395318"]
],
"js/pages/ProfilePage/index.spec.tsx:1332520872": [
[216, 9, 5, "\'props\' is assigned a value but never used.", "187023499"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright Contributors to the Amundsen project.
// SPDX-License-Identifier: Apache-2.0

export const AVAILABLE_BADGES_TITLE = 'Available Badges';
export const BROWSE_BADGES_TITLE = 'Browse Badges';
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright Contributors to the Amundsen project.
// SPDX-License-Identifier: Apache-2.0

import * as React from 'react';
import { shallow } from 'enzyme';

import { BadgeStyle } from 'config/config-types';
import * as ConfigUtils from 'config/config-utils';
import { Badge } from 'interfaces/Badges';

import * as Analytics from 'utils/analytics';

import BadgeBrowseList, { BadgeBrowseListProps } from '.';

const badges: Badge[] = [
{
badge_name: 'beta',
category: 'table_status',
},
{
badge_name: 'Core Concepts',
category: 'coco',
},
];

const setup = (propOverrides?: Partial<BadgeBrowseListProps>) => {
const props = {
badges,
...propOverrides,
};
const wrapper = shallow<typeof BadgeBrowseList>(
<BadgeBrowseList {...props} />
).dive();
return { props, wrapper };
};

const logClickSpy = jest.spyOn(Analytics, 'logClick');
logClickSpy.mockImplementation(() => null);

describe('BadgeBrowseList', () => {
const getBadgeConfigSpy = jest.spyOn(ConfigUtils, 'getBadgeConfig');
getBadgeConfigSpy.mockImplementation((badgeName: string) => ({
displayName: badgeName + ' test name',
style: BadgeStyle.PRIMARY,
}));

describe('render', () => {
describe('when BadgeBrowseList called with shortBadgesList={false}', () => {
it('renders component with browse header', () => {
const { wrapper } = setup({ shortBadgesList: false });
const expected = 1;
const actualHeaders = wrapper.find('.header-title').length;
const actualHrs = wrapper.find('.header-hr').length;

expect(actualHeaders).toEqual(expected);
expect(actualHrs).toEqual(expected);
});
});

describe('when BadgeBrowseList called with shortBadgesList={true}', () => {
it('renders component without browse header', () => {
const { wrapper } = setup({ shortBadgesList: true });
const expected = 0;
const actualHeaders = wrapper.find('.header-title').length;
const actualHrs = wrapper.find('.header-hr').length;

expect(actualHeaders).toEqual(expected);
expect(actualHrs).toEqual(expected);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright Contributors to the Amundsen project.
// SPDX-License-Identifier: Apache-2.0

import * as React from 'react';
import { Badge } from 'interfaces/Badges';
import BadgeList from 'features/BadgeList';
import './styles.scss';
import {
AVAILABLE_BADGES_TITLE,
BROWSE_BADGES_TITLE,
} from 'components/Badges/BadgeBrowseList/constants';
import { isShowBadgesInHomeEnabled } from 'config/config-utils';

export interface BadgeBrowseListProps {
badges: Badge[];
shortBadgesList?: boolean;
}

const BadgeBrowseListShort: React.FC<BadgeBrowseListProps> = ({
badges,
}: BadgeBrowseListProps) => {
const hasBadges = badges.length > 0;
if (hasBadges && isShowBadgesInHomeEnabled()) {
return (
<article className="badges-browse-section badges-browse-section-short">
<h2 className="available-badges-header-title">
{AVAILABLE_BADGES_TITLE}
</h2>
<BadgeList badges={badges} />
</article>
);
}
// do not show component at all if there are no badges to be shown
return null;
};

const BadgeBrowseListLong: React.FC<BadgeBrowseListProps> = ({
badges,
}: BadgeBrowseListProps) => (
<article className="badges-browse-section badges-browse-section-long">
<h1 className="header-title">{BROWSE_BADGES_TITLE}</h1>
<hr className="header-hr" />
<label className="section-label">
<span className="section-title title-2">{AVAILABLE_BADGES_TITLE}</span>
</label>
<BadgeList badges={badges} />
</article>
);

const BadgeBrowseList: React.FC<BadgeBrowseListProps> = ({
badges,
shortBadgesList,
}: BadgeBrowseListProps) => {
if (shortBadgesList) {
return <BadgeBrowseListShort badges={badges} />;
}

return <BadgeBrowseListLong badges={badges} />;
};

export default BadgeBrowseList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright Contributors to the Amundsen project.
// SPDX-License-Identifier: Apache-2.0

@import 'variables';
@import 'typography';

.badges-browse-section {
margin: 32px 0;

.badge-list {
display: block;
font-weight: $font-weight-body-regular;
margin-top: $spacer-3;
margin-bottom: $spacer-2;
}
}

.badges-browse-section-short {
.available-badges-header-title {
@extend %text-title-w1;

margin-bottom: $spacer-1;
}
}


.badges-browse-section-long {
.header-hr {
border: 2px solid $brand-color-4;
}

.header-title {
@extend %text-title-w1;

margin-bottom: $spacer-2;
}

.section-label {
display: block;
font-weight: $font-weight-body-regular;
margin-top: $spacer-3;
margin-bottom: $spacer-2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ const ActionableBadge: React.FC<ActionableBadgeProps> = ({
displayName,
action,
}: ActionableBadgeProps) => (
<span className="actionable-badge" onClick={action}>
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<span className="actionable-badge" onClick={action} onKeyDown={action}>
<StaticBadge style={style} displayName={displayName} />
</span>
);
Expand Down Expand Up @@ -97,6 +98,8 @@ export default class BadgeList extends React.Component<BadgeListProps> {
/>
);
}

return null;
})}
</span>
);
Expand Down
Loading

0 comments on commit 5685791

Please sign in to comment.