From 0103ee526f624a272c572083920d88707938e523 Mon Sep 17 00:00:00 2001 From: Philippe Duval Date: Wed, 26 Sep 2018 11:16:16 -0400 Subject: [PATCH 1/5] Add default dash favicon. --- MANIFEST.in | 1 + dash/dash.py | 16 +++++++++++----- dash/favicon.ico | Bin 0 -> 15086 bytes 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 dash/favicon.ico diff --git a/MANIFEST.in b/MANIFEST.in index 04f196ac78..af967cd137 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include README.md include LICENSE +include dash/favicon.ico diff --git a/dash/dash.py b/dash/dash.py index 1fb94d83ce..7a589aa5ae 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -64,6 +64,11 @@ _re_index_scripts_id = re.compile(r'src=".*dash[-_]renderer.*"') +def _serve_default_favicon(): + return flask.Response(pkgutil.get_data('dash', 'favicon.ico'), + content_type='image/x-icon') + + # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-arguments, too-many-locals class Dash(object): @@ -216,6 +221,9 @@ def add_url(name, view_func, methods=('GET',)): '{}'.format(self.config['routes_pathname_prefix']), self.index) + add_url('{}_favicon'.format(self.config['routes_pathname_prefix']), + _serve_default_favicon) + self.server.before_first_request(self._setup_server) self._layout = None @@ -461,11 +469,9 @@ def index(self, *args, **kwargs): # pylint: disable=unused-argument config = self._generate_config_html() metas = self._generate_meta_html() title = getattr(self, 'title', 'Dash') - if self._favicon: - favicon = ''.format( - self.get_asset_url(self._favicon)) - else: - favicon = '' + favicon = ''.format( + self.get_asset_url(self._favicon) if self._favicon + else '{}_favicon'.format(self.config.requests_pathname_prefix)) index = self.interpolate_index( metas=metas, title=title, css=css, config=config, diff --git a/dash/favicon.ico b/dash/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cbdf9afdf18b1de557405e29997b9b23a81d5a9d GIT binary patch literal 15086 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 Date: Wed, 26 Sep 2018 11:28:09 -0400 Subject: [PATCH 2/5] Add cache control header to default favicon. --- dash/dash.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dash/dash.py b/dash/dash.py index 7a589aa5ae..7ebe85009f 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -64,11 +64,6 @@ _re_index_scripts_id = re.compile(r'src=".*dash[-_]renderer.*"') -def _serve_default_favicon(): - return flask.Response(pkgutil.get_data('dash', 'favicon.ico'), - content_type='image/x-icon') - - # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-arguments, too-many-locals class Dash(object): @@ -222,7 +217,7 @@ def add_url(name, view_func, methods=('GET',)): self.index) add_url('{}_favicon'.format(self.config['routes_pathname_prefix']), - _serve_default_favicon) + self._serve_default_favicon) self.server.before_first_request(self._setup_server) @@ -981,6 +976,15 @@ def add_resource(p, filepath): def _invalid_resources_handler(self, err): return err.args[0], 404 + def _serve_default_favicon(self): + headers = { + 'Cache-Control': 'public, max-age={}'.format( + self.config.components_cache_max_age) + } + return flask.Response(pkgutil.get_data('dash', 'favicon.ico'), + headers=headers, + content_type='image/x-icon') + def get_asset_url(self, path): asset = _get_asset_path( self.config.requests_pathname_prefix, From 11905d83a4edb2e3d95f364824b46ab68258a04b Mon Sep 17 00:00:00 2001 From: Philippe Duval Date: Wed, 26 Sep 2018 11:34:44 -0400 Subject: [PATCH 3/5] Fix favicon format indent. --- dash/dash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dash/dash.py b/dash/dash.py index 7ebe85009f..2bb24e92f6 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -465,8 +465,8 @@ def index(self, *args, **kwargs): # pylint: disable=unused-argument metas = self._generate_meta_html() title = getattr(self, 'title', 'Dash') favicon = ''.format( - self.get_asset_url(self._favicon) if self._favicon - else '{}_favicon'.format(self.config.requests_pathname_prefix)) + self.get_asset_url(self._favicon) if self._favicon + else '{}_favicon'.format(self.config.requests_pathname_prefix)) index = self.interpolate_index( metas=metas, title=title, css=css, config=config, From d2a2752ed3b088d6f23782ee84ec9f952349ae0d Mon Sep 17 00:00:00 2001 From: Philippe Duval Date: Wed, 26 Sep 2018 14:57:12 -0400 Subject: [PATCH 4/5] Add assets favicon cache busting, clearer favicon tag format. --- dash/dash.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/dash/dash.py b/dash/dash.py index 2bb24e92f6..d057ad977c 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -216,7 +216,7 @@ def add_url(name, view_func, methods=('GET',)): '{}'.format(self.config['routes_pathname_prefix']), self.index) - add_url('{}_favicon'.format(self.config['routes_pathname_prefix']), + add_url('{}_favicon.ico'.format(self.config['routes_pathname_prefix']), self._serve_default_favicon) self.server.before_first_request(self._setup_server) @@ -464,9 +464,22 @@ def index(self, *args, **kwargs): # pylint: disable=unused-argument config = self._generate_config_html() metas = self._generate_meta_html() title = getattr(self, 'title', 'Dash') - favicon = ''.format( - self.get_asset_url(self._favicon) if self._favicon - else '{}_favicon'.format(self.config.requests_pathname_prefix)) + + if self._favicon: + favicon_mod_time = os.path.getmtime( + os.path.join(self._assets_folder, self._favicon)) + favicon_url = self.get_asset_url(self._favicon) + '?m={}'.format( + favicon_mod_time + ) + else: + favicon_url = '{}_favicon.ico'.format( + self.config.requests_pathname_prefix) + + favicon = _format_tag('link', { + 'rel': 'icon', + 'type': 'image/x-icon', + 'href': favicon_url + }, opened=True) index = self.interpolate_index( metas=metas, title=title, css=css, config=config, From 30e8f143973376ecf3a78ddc1719cb6e362bd127 Mon Sep 17 00:00:00 2001 From: Philippe Duval Date: Wed, 26 Sep 2018 15:10:16 -0400 Subject: [PATCH 5/5] Update version and changelogs. --- CHANGELOG.md | 8 ++++++++ dash/version.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdaebbeac2..7197e7cc8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.28.0 - 2018-09-26 +## Added +- Default favicon for dash apps. [#406](https://github.com/plotly/dash/pull/406#issuecomment-424821743) +- Bust the cache of the assets favicon. + +## Fixed +- Remove the first and last blank lines from the HTML index string. [#403](https://github.com/plotly/dash/pull/403) + ## 0.27.0 - 2018-09-20 ## Added - Added support for serving dev bundles from the components suite, enable with `app.run_server(dev_tools_serve_dev_bundles=True)` [#369](https://github.com/plotly/dash/pull/369) diff --git a/dash/version.py b/dash/version.py index cf7b6d6589..1bf36757cf 100644 --- a/dash/version.py +++ b/dash/version.py @@ -1 +1 @@ -__version__ = '0.27.0' +__version__ = '0.28.0'