Unverified Commit a47078c2 authored by Marcos Iglesias's avatar Marcos Iglesias Committed by GitHub

Fixes DataSource or Dashboard Icons not rendering on Firefox (#443)

* Updates resource icons with background image approach

* Adds a main landmark to the application

* Adds labels to filter inputs

* Adds language to the html tag and some other missing meta tags (to complete)

* Update styling on Dashboard and Data Store detail pages

* De-duplicates main landmark tag

* DRYs up the creation of icon classes by using Sass maps and @each

* Updating Table Detail landmark tag
parent a14c4dde
@import 'variables';
@import "variables";
$icon-size: 24px;
$icon-small-size: 16px;
// Map of Database names and icon paths
$data-stores: (
database: "/static/images/icons/Database.svg", // Default
hive: "/static/images/icons/logo-hive.svg",
bigquery: "/static/images/icons/logo-bigquery.svg",
druid: "/static/images/icons/logo-druid.svg",
presto: "/static/images/icons/logo-presto.svg",
postgres: "/static/images/icons/logo-postgres.svg",
redshift: "/static/images/icons/logo-redshift.svg"
);
// Map of Dashboard names and icon paths
$dashboards: (
dashboard: "/static/images/icons/dashboard.svg", //Default
mode: "/static/images/icons/logo-mode.svg"
);
// Given a Map of key/value pairs, generates a new class
@mixin iconBackgrounds($map){
@each $name, $url in $map {
&.icon-#{$name} {
background: transparent url($url) center center / contain no-repeat;
}
}
}
span.icon {
background-color: $icon-bg;
border: none;
height: $icon-size;
margin: auto 16px auto 0;
min-width: $icon-size;
width: $icon-size;
display: inline-block;
vertical-align: middle;
// Generate Icons
@include iconBackgrounds($data-stores);
@include iconBackgrounds($dashboards);
}
img.icon {
background-color: $icon-bg;
border: none;
height: 24px;
margin: -3px 4px -3px 0px;
height: $icon-size;
margin: -3px 4px -3px 0;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
min-width: 24px;
width: 24px;
min-width: $icon-size;
width: $icon-size;
-webkit-mask-size: contain;
mask-size: contain;
&.icon-small {
height: 16px;
width: 16px;
min-width: 16px;
-webkit-mask-size: 16px 16px;
mask-size: 16px 16px;
height: $icon-small-size;
width: $icon-small-size;
min-width: $icon-small-size;
-webkit-mask-size: $icon-small-size $icon-small-size;
mask-size: $icon-small-size $icon-small-size;
}
&.icon-color {
......@@ -29,163 +73,118 @@ img.icon {
}
&.icon-alert {
-webkit-mask-image: url('/static/images/icons/Alert-Triangle.svg');
mask-image: url('/static/images/icons/Alert-Triangle.svg');
}
&.icon-bigquery {
content: url('/static/images/icons/logo-bigquery.svg');
background-color: transparent;
-webkit-mask-image: url("/static/images/icons/Alert-Triangle.svg");
mask-image: url("/static/images/icons/Alert-Triangle.svg");
}
&.icon-bookmark {
-webkit-mask-image: url('/static/images/icons/Favorite.svg');
mask-image: url('/static/images/icons/Favorite.svg');
-webkit-mask-image: url("/static/images/icons/Favorite.svg");
mask-image: url("/static/images/icons/Favorite.svg");
}
&.icon-bookmark-filled {
-webkit-mask-image: url('/static/images/icons/Favorite-Filled.svg');
mask-image: url('/static/images/icons/Favorite-Filled.svg');
-webkit-mask-image: url("/static/images/icons/Favorite-Filled.svg");
mask-image: url("/static/images/icons/Favorite-Filled.svg");
}
&.icon-delete {
-webkit-mask-image: url('/static/images/icons/Trash.svg');
mask-image: url('/static/images/icons/Trash.svg');
}
&.icon-database {
-webkit-mask-image: url('/static/images/icons/Database.svg');
mask-image: url('/static/images/icons/Database.svg');
-webkit-mask-image: url("/static/images/icons/Trash.svg");
mask-image: url("/static/images/icons/Trash.svg");
}
&.icon-red-triangle-warning {
-webkit-mask-image: url('/static/images/icons/DataQualityWarning.svg');
mask-image: url('/static/images/icons/DataQualityWarning.svg');
}
&.icon-dashboard {
-webkit-mask-image: url('/static/images/icons/dashboard.svg');
mask-image: url('/static/images/icons/dashboard.svg');
-webkit-mask-image: url("/static/images/icons/DataQualityWarning.svg");
mask-image: url("/static/images/icons/DataQualityWarning.svg");
}
&.icon-down {
-webkit-mask-image: url('/static/images/icons/Down.svg');
mask-image: url('/static/images/icons/Down.svg');
-webkit-mask-image: url("/static/images/icons/Down.svg");
mask-image: url("/static/images/icons/Down.svg");
}
&.icon-edit {
-webkit-mask-image: url('/static/images/icons/Edit.svg');
mask-image: url('/static/images/icons/Edit.svg');
-webkit-mask-image: url("/static/images/icons/Edit.svg");
mask-image: url("/static/images/icons/Edit.svg");
}
&.icon-help {
-webkit-mask-image: url('/static/images/icons/Help-Circle.svg');
mask-image: url('/static/images/icons/Help-Circle.svg');
}
&.icon-hive {
content: url('/static/images/icons/logo-hive.svg');
background-color: transparent;
}
&.icon-druid {
content: url('/static/images/icons/logo-druid.svg');
background-color: transparent;
-webkit-mask-image: url("/static/images/icons/Help-Circle.svg");
mask-image: url("/static/images/icons/Help-Circle.svg");
}
&.icon-github {
-webkit-mask-image: url('/static/images/icons/github.svg');
mask-image: url('/static/images/icons/github.svg');
-webkit-mask-image: url("/static/images/icons/github.svg");
mask-image: url("/static/images/icons/github.svg");
}
&.icon-left {
-webkit-mask-image: url('/static/images/icons/Left.svg');
mask-image: url('/static/images/icons/Left.svg');
-webkit-mask-image: url("/static/images/icons/Left.svg");
mask-image: url("/static/images/icons/Left.svg");
}
&.icon-loading {
-webkit-mask-image: url('/static/images/icons/Loader.svg');
mask-image: url('/static/images/icons/Loader.svg');
-webkit-mask-image: url("/static/images/icons/Loader.svg");
mask-image: url("/static/images/icons/Loader.svg");
}
&.icon-mail {
-webkit-mask-image: url('/static/images/icons/mail.svg');
mask-image: url('/static/images/icons/mail.svg');
}
&.icon-mode {
content: url('/static/images/icons/logo-mode.svg');
background-color: transparent;
-webkit-mask-image: url("/static/images/icons/mail.svg");
mask-image: url("/static/images/icons/mail.svg");
}
&.icon-plus {
-webkit-mask-image: url('/static/images/icons/plus.svg');
mask-image: url('/static/images/icons/plus.svg');
-webkit-mask-image: url("/static/images/icons/plus.svg");
mask-image: url("/static/images/icons/plus.svg");
}
&.icon-plus-circle {
-webkit-mask-image: url('/static/images/icons/Plus-Circle.svg');
mask-image: url('/static/images/icons/Plus-Circle.svg');
}
&.icon-postgres {
content: url('/static/images/icons/logo-postgres.svg');
background-color: transparent;
}
&.icon-presto {
content: url('/static/images/icons/logo-presto.svg');
background-color: transparent;
-webkit-mask-image: url("/static/images/icons/Plus-Circle.svg");
mask-image: url("/static/images/icons/Plus-Circle.svg");
}
&.icon-preview {
-webkit-mask-image: url('/static/images/icons/Preview.svg');
mask-image: url('/static/images/icons/Preview.svg');
}
&.icon-redshift {
content: url('/static/images/icons/logo-redshift.svg');
background-color: transparent;
-webkit-mask-image: url("/static/images/icons/Preview.svg");
mask-image: url("/static/images/icons/Preview.svg");
}
&.icon-refresh {
-webkit-mask-image: url('/static/images/icons/Refresh-cw.svg');
mask-image: url('/static/images/icons/Refresh-cw.svg');
-webkit-mask-image: url("/static/images/icons/Refresh-cw.svg");
mask-image: url("/static/images/icons/Refresh-cw.svg");
}
&.icon-right {
-webkit-mask-image: url('/static/images/icons/Right.svg');
mask-image: url('/static/images/icons/Right.svg');
-webkit-mask-image: url("/static/images/icons/Right.svg");
mask-image: url("/static/images/icons/Right.svg");
}
&.icon-search {
-webkit-mask-image: url('/static/images/icons/Search.svg');
mask-image: url('/static/images/icons/Search.svg');
-webkit-mask-image: url("/static/images/icons/Search.svg");
mask-image: url("/static/images/icons/Search.svg");
}
&.icon-send {
-webkit-mask-image: url('/static/images/icons/Send.svg');
mask-image: url('/static/images/icons/Send.svg');
-webkit-mask-image: url("/static/images/icons/Send.svg");
mask-image: url("/static/images/icons/Send.svg");
}
&.icon-slack {
-webkit-mask-image: url('/static/images/icons/slack.svg');
mask-image: url('/static/images/icons/slack.svg');
-webkit-mask-image: url("/static/images/icons/slack.svg");
mask-image: url("/static/images/icons/slack.svg");
}
&.icon-up {
-webkit-mask-image: url('/static/images/icons/Up.svg');
mask-image: url('/static/images/icons/Up.svg');
-webkit-mask-image: url("/static/images/icons/Up.svg");
mask-image: url("/static/images/icons/Up.svg");
}
&.icon-users {
-webkit-mask-image: url('/static/images/icons/users.svg');
mask-image: url('/static/images/icons/users.svg');
-webkit-mask-image: url("/static/images/icons/users.svg");
mask-image: url("/static/images/icons/users.svg");
}
&.icon-more {
-webkit-mask-image: url('/static/images/icons/More.svg');
mask-image: url('/static/images/icons/More.svg');
-webkit-mask-image: url("/static/images/icons/More.svg");
mask-image: url("/static/images/icons/More.svg");
}
}
......
......@@ -145,7 +145,7 @@ export class DashboardPage extends React.Component<DashboardPageProps, Dashboard
<header className="resource-header">
<div className="header-section">
<Breadcrumb />
<img className={`icon icon-header ${getSourceIconClass(dashboard.product, ResourceType.dashboard)}`}/>
<span className={`icon icon-header ${getSourceIconClass(dashboard.product, ResourceType.dashboard)}`}/>
</div>
<div className="header-section header-title">
<h3 className="header-title-text truncated">
......@@ -171,7 +171,7 @@ export class DashboardPage extends React.Component<DashboardPageProps, Dashboard
className="btn btn-default btn-lg">Open Dashboard</a>
</div>
</header>
<main className="column-layout-1">
<article className="column-layout-1">
<section className="left-panel">
<div className="section-title title-3">Description</div>
{
......@@ -256,7 +256,7 @@ export class DashboardPage extends React.Component<DashboardPageProps, Dashboard
<section className="right-panel">
{ this.renderTabs() }
</section>
</main>
</article>
</div>
);
}
......
......@@ -44,6 +44,7 @@ export class FilterSection extends React.Component<FilterSectionProps> {
renderFilterComponent = () => {
const { categoryId, options, type } = this.props;
if (type === FilterType.INPUT_SELECT) {
return (
<InputFilter
......@@ -63,11 +64,12 @@ export class FilterSection extends React.Component<FilterSectionProps> {
render = () => {
const { categoryId, hasValue, helpText, title } = this.props;
return (
<div className="search-filter-section">
<div className="search-filter-section-header">
<div className="search-filter-section-title">
<div className="title-2">{ title }</div>
<label className="title-2" htmlFor={categoryId}>{ title }</label>
{
helpText &&
<InfoButton
......
......@@ -64,6 +64,7 @@ export class InputFilter extends React.Component<InputFilterProps, InputFilterSt
type="text"
className="form-control"
name={ categoryId }
id={ categoryId }
onChange={ this.onInputChange }
value={ this.state.value }
/>
......
......@@ -125,7 +125,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
<header className="resource-header">
<div className="header-section">
<Breadcrumb />
<img className={"icon icon-header " + getSourceIconClass(data.database, ResourceType.table)} />
<span className={"icon icon-header " + getSourceIconClass(data.database, ResourceType.table)} />
</div>
<div className="header-section header-title">
<h3 className="header-title-text truncated">
......@@ -157,7 +157,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
<ExploreButton tableData={ data }/>
</div>
</header>
<main className="column-layout-1">
<article className="column-layout-1">
<section className="left-panel">
{}
<EditableSection title="Description">
......@@ -228,7 +228,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
<section className="right-panel">
<ColumnList columns={ data.columns }/>
</section>
</main>
</article>
</div>
);
}
......
......@@ -71,7 +71,8 @@ describe('DashboardListItem', () => {
});
it('renders start correct icon', () => {
const startIcon = resourceInfo.find('img');
const startIcon = resourceInfo.find('.resource-icon');
expect(startIcon.exists()).toBe(true);
expect(startIcon.props().className).toEqual(`icon resource-icon ${MOCK_ICON_CLASS}`);
expect(ConfigUtils.getSourceIconClass).toHaveBeenCalledWith(props.dashboard.product, props.dashboard.type);
......
......@@ -8,7 +8,7 @@ import BookmarkIcon from 'components/common/Bookmark/BookmarkIcon';
import { getSourceDisplayName, getSourceIconClass } from 'config/config-utils';
import { DashboardResource } from 'interfaces';
import { ResourceType, DashboardResource } from 'interfaces';
import { formatDate } from 'utils/dateUtils';
......@@ -29,13 +29,17 @@ class DashboardListItem extends React.Component<DashboardListItemProps, {}> {
return `/dashboard?uri=${dashboard.uri}&index=${logging.index}&source=${logging.source}`;
};
generateResourceIconClass = (dashboardId: string, dashboardType: ResourceType): string => {
return `icon resource-icon ${getSourceIconClass(dashboardId, dashboardType)}`;
};
render() {
const { dashboard } = this.props;
return (
<li className="list-group-item clickable">
<Link className="resource-list-item table-list-item" to={ this.getLink() }>
<div className="resource-info">
<img className={`icon resource-icon ${getSourceIconClass(dashboard.product, dashboard.type)}`} />
<span className={this.generateResourceIconClass(dashboard.product, dashboard.type)} />
<div className="resource-info-text my-auto">
<div className="resource-name title-2">
<div className="dashboard-group">
......
......@@ -38,7 +38,7 @@ class TableListItem extends React.Component<TableListItemProps, {}> {
<li className="list-group-item clickable">
<Link className="resource-list-item table-list-item" to={ this.getLink() }>
<div className="resource-info">
<img className={this.generateResourceIconClass(table.database, table.type)} />
<span className={this.generateResourceIconClass(table.database, table.type)} />
<div className="resource-info-text my-auto">
<div className="resource-name title-2">
<div className="truncated">
......
......@@ -60,11 +60,13 @@ describe('TableListItem', () => {
const testValue = 'noEffectOnTest';
const givenResource = ResourceType.table;
const iconClass = wrapper.instance().generateResourceIconClass(testValue, givenResource);
expect(getDBIconClassSpy).toHaveBeenCalledWith(testValue, givenResource);
});
it('returns the default classes with the correct icon class appended', () => {
const iconClass = wrapper.instance().generateResourceIconClass('noEffectOnTest');
expect(iconClass).toEqual(`icon resource-icon test-class`);
});
});
......@@ -78,6 +80,7 @@ describe('TableListItem', () => {
props = setupResult.props;
wrapper = setupResult.wrapper;
});
it('renders item as Link', () => {
expect(wrapper.find(Link).exists()).toBeTruthy();
});
......@@ -89,7 +92,8 @@ describe('TableListItem', () => {
});
it('renders start correct icon', () => {
const startIcon = resourceInfo.find('img');
const startIcon = resourceInfo.find('.resource-icon');
expect(startIcon.exists()).toBe(true);
expect(startIcon.props().className).toEqual(wrapper.instance().generateResourceIconClass(props.table.database));
});
......
......@@ -35,7 +35,7 @@ ReactDOM.render(
<DocumentTitle title="Amundsen - Data Discovery Portal">
<Provider store={store}>
<Router history={BrowserHistory}>
<div id="main">
<main id="main">
<Preloader/>
<Route component={NavBar} />
<Switch>
......@@ -49,7 +49,7 @@ ReactDOM.render(
<Route path="/" component={HomePage} />
</Switch>
<Footer />
</div>
</main>
</Router>
</Provider>
</DocumentTitle>
......
<html>
<!doctype html>
<html lang="en-US">
<head>
{% if <%= htmlWebpackPlugin.options.config.google.enabled%> %}
{% include 'fragments/google-analytics-loader.html' %}
{% endif %}
<meta charset="utf-8">
<title>Amundsen - Data Discovery Portal</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/static/images/favicon.png">
<link href="/static/dist/main.css" type="text/css" rel="stylesheet"/>
<title>Amundsen - Data Discovery Portal</title>
<meta name="theme-color" content="#2B1B81">
</head>
<body>
<div id="content"/>
......
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