Implement custom global header banner#87438
Conversation
pgayvallet
left a comment
There was a problem hiding this comment.
Self review (please read the technical implementation section of this issue first)
| /* stylelint-disable-next-line length-zero-no-unit -- need consistent unit to sum them */ | ||
| @mixin kibanaFullBodyHeight($additionalOffset: 0px) { |
There was a problem hiding this comment.
The linter complains about units on zero values, but AFAIK you cannot sum non consistent values in sass, so I had to disable the rule for the two mixin signatures.
There was a problem hiding this comment.
We could probably maneuver around this to avoid the need for the disable line, but then we end up with more 'stuff' for a very minimal gain. I prefer the clarity here of what is implied by the default value, as well.
| /** | ||
| * Set the banner that will appear on top of the chrome header. | ||
| * | ||
| * @remarks Using `undefined` when invoking this API will remove the banner. | ||
| */ | ||
| setHeaderBanner(headerBanner?: ChromeUserBanner): void; | ||
| } | ||
|
|
There was a problem hiding this comment.
I moved the chrome types to their own file. The only addition is ChromeStart.setHeaderBanner and InternalChromeStart.getBodyClasses$
| .kbnBody--hasHeaderBanner .header__bars { | ||
| .header__firstBar { | ||
| top: $kbnHeaderBannerHeight; | ||
| } | ||
| .header__secondBar { | ||
| top: $kbnHeaderBannerHeight + $euiHeaderHeightCompensation; | ||
| } | ||
| } |
There was a problem hiding this comment.
This overrides the .euiHeader--fixed and .euiHeader--fixed + .euiHeader--fixed styles when the banner is present
There was a problem hiding this comment.
We can also revisit this once the page layout service is available.
| <> | ||
| <LoadingIndicator loadingCount$={observables.loadingCount$} showAsBar /> | ||
| <HeaderTopBanner headerBanner$={observables.headerBanner$} /> | ||
| </> |
There was a problem hiding this comment.
We need to display the banner even when chrome is hidden. I did not override the LoadingIndicator styles in this situation, so the loader appears on the banner in chromeless pages, but I think this is alright.
src/core/public/rendering/_base.scss
Outdated
| .coreSystemRootDomElement { | ||
| @include euiHeaderAffordForFixed($kbnHeaderOffset); | ||
|
|
||
| &.kbnBody--hasHeaderBanner { | ||
| @include euiHeaderAffordForFixed($kbnHeaderOffsetWithBanner); | ||
| } | ||
| } |
There was a problem hiding this comment.
Linter forbid to use tagName based rules. .coreSystemRootDomElement is just body
| readonly: !!def.readonly, | ||
| readOnly: !!def.readonly, |
There was a problem hiding this comment.
There was an undetected typo here, as conf was not explicitly typed and as readOnly is optional.
Note that this didn't have any effect because the fields are already filtered by !readonly in an earlier stage anyway.
| @import '../../../../../core/public/mixins'; | ||
|
|
||
| .homWrapper { | ||
| @include kibanaFullBodyMinHeight(); | ||
| background-color: $euiColorEmptyShade; | ||
| display: flex; | ||
| flex-direction: column; | ||
| min-height: calc(100vh - #{$euiHeaderHeightCompensation}); | ||
| } |
There was a problem hiding this comment.
I went with explicit imports because this is imho the way to go. But if @elastic/kibana-design thinks it's better to have these mixins in src/core/public/core_app/styles/_mixins.scss instead and use implicit imports, I can change it.
There was a problem hiding this comment.
I think it's good that we exercise caution before adding to the ...public/core_app/styles/ directory since that stuff all gets built and prepended to .scss imports, but the stuff being added by this PR feels appropriate given it's global nature.
If I'm following correctly, this means we could move the _core.scss and _variables.scss files and combine the _mixins.scss files from .../public/ to .../public/core_app/styles/ and remove all the direct imports? I think the import of the header variables atop the _variables.scss file could also then be removed.
Let me know if I'm missing other pitfalls in doing this, but it seems like a cleaner way to go and I sense it will reduce the likelihood of redundant variable imports and such in the future.
There was a problem hiding this comment.
Any thoughts on my prior comment? Overall, a minor item that I wouldn't block merging on.
There was a problem hiding this comment.
Sorry, I missed that one.
If I'm following correctly, this means we could move the _core.scss and _variables.scss files and combine the _mixins.scss files from .../public/ to .../public/core_app/styles/ and remove all the direct imports?
Yea. I need to confirm the consequences of doing that regarding core internal scss imports / hierarchy, but that would be the idea.
I will take a shot at it, and if it's too complicated, I will do it during phase 2
| if (this.config.placement !== 'disabled') { | ||
| getBannerInfo(http).then( | ||
| ({ allowed, banner }) => { | ||
| if (allowed) { | ||
| chrome.setHeaderBanner({ |
There was a problem hiding this comment.
I expose placement to the client-side config to avoid performing an http call when the feature is soft-disabled (which would be 99.9% of our customers, realistically)
This may have to change with stage 2, at least when within a space, as we'll need the space-relative configuration, but that was an easy optimisation for now, and we can change that later if we need to
| return res.ok({ | ||
| body: { | ||
| allowed, | ||
| banner: config, | ||
| } as BannerInfoResponse, | ||
| }); |
There was a problem hiding this comment.
TIL: license info is now available when security is on and user is not authenticated. I need to have my own unauthenticated endpoint to return to the client the info about the license level.
To minimize info leak, I'm just returning a boolean, so I think it's ok (and we don't really have any other option anyway to display that thing on all pages).
| // Note: unused for now, will be used for v2 (see https://github.com/elastic/kibana/issues/17298) | ||
|
|
||
| export const registerSettings = (uiSettings: UiSettingsServiceSetup) => { | ||
| uiSettings.register({ | ||
| 'banner:placement': { | ||
| name: i18n.translate('xpack.banners.settings.placement.title', { |
There was a problem hiding this comment.
I kept them in the PR, even if those will not be used until stage 2. I can revert these files if we really want to.
There was a problem hiding this comment.
I'd vote for removing them for now until we need them in stage 2. since we might want to change some details anyways.
No, waiting on input here. Realistically if we want to have a chance to see this lands in (adding the option for the user to choose between regular and compact could be done later, even if tbh this is adding an extra layer of complexity in an already global-impacting niche feature)
Totally forget to implement that. There should be a markdown component already existing somewhere, so it may be trivial. EDIT: done, 094223e
I'll let him answer, but I guess it would be a yes. However I see that in fullscreen mode, the banner is overlapping on the content. I guess I need to fix that. Technically, this is because in fullscreen mode, we no longer have the
Can do that. Not sure how to display the warning though? I don't think we can do better than in the server logs at startup.
I honestly have no idea what reporting is altering when navigating with their headless. It could even be a distinct media target. This one may be hard if we want to display the banner here. |
++ on a smaller default without any config for 7.12. @ryankeairns any thoughts / suggestions?
Woah, awesome! Thanks Pierre
++ I agree that it should probably be there, thanks for fixing the overlapping content.
Yeah, server logs feel like the only option here. I wonder if it's worth it though. Maybe we just add a recommended character limit in the docs?
Yeah, let's not worry about this now and see if folks ask for this later. |
Been slow to respond, but I'm also happier with the smaller default. I just mentioned in this comment that we've been giving people a plugin with the height set to
++ nice!
Yes, agree that it should be present when in full screen mode. If LOE is high, and implementing it risks kicking this out of the next release, I'd be ok with it being marked as a known issue.
Considering much depends on the client's screen size, a general note in the docs about the wrapping behavior and implications is probably enough. ...maybe even
++ |
|
Replied about the height here: #87438 (comment) |
|
This is great, many customers will be happy! |
Looks good to me, but I'm not renowned for my aesthetic eye |
Yeah, let's make it a bit smaller. Try |
ryankeairns
left a comment
There was a problem hiding this comment.
I ran through the apps in left nav, clicked through the header, opened any flyouts I could find, etc. Everything work as expected although I don't have 100% everything enabled and am using only sample data. I feel comfortable with where things stand and only left a couple of comments.
Great work @pgayvallet !
| /* stylelint-disable-next-line length-zero-no-unit -- need consistent unit to sum them */ | ||
| @mixin kibanaFullBodyHeight($additionalOffset: 0px) { |
There was a problem hiding this comment.
We could probably maneuver around this to avoid the need for the disable line, but then we end up with more 'stuff' for a very minimal gain. I prefer the clarity here of what is implied by the default value, as well.
| .kbnBody--hasHeaderBanner .header__bars { | ||
| .header__firstBar { | ||
| top: $kbnHeaderBannerHeight; | ||
| } | ||
| .header__secondBar { | ||
| top: $kbnHeaderBannerHeight + $euiHeaderHeightCompensation; | ||
| } | ||
| } |
There was a problem hiding this comment.
We can also revisit this once the page layout service is available.
| @import '../../../../../core/public/mixins'; | ||
|
|
||
| .homWrapper { | ||
| @include kibanaFullBodyMinHeight(); | ||
| background-color: $euiColorEmptyShade; | ||
| display: flex; | ||
| flex-direction: column; | ||
| min-height: calc(100vh - #{$euiHeaderHeightCompensation}); | ||
| } |
There was a problem hiding this comment.
Any thoughts on my prior comment? Overall, a minor item that I wouldn't block merging on.
|
Dropping a note here. When we merge this we'll want to open an issue in the Cloud repo to whitelist the config. |
💚 Build SucceededMetrics [docs]Module Count
Async chunks
Page load bundle
History
To update your PR or re-run it, just comment with: |
* first draft * update plugin list * fix tsproject * update bundle limits file * remove unused start dep * adapt imports * POC of footer banner * update styles, mostly * plug banner to uiSettings * adding some unit tests * add tests on sort_fields * cleanup sums in sass mixins * some self review stuff * update generated doc * add tests for color field * update chrome header test snapshots * retrieve license info from the server * switch from uiSettings to plugin config * update plugin list description * update default colors * NIT * add markdown support * fix banner overlap in fullscreen mode * change banner height to 32px * change banner's font size to 14 * delete unused uiSettings
* master: (44 commits) [APM] Add experimental support for Data Streams (elastic#89650) [Search Session] Control "Kibana / Search Sessions" management section by privileges (elastic#90818) [Lens] Median as default function (elastic#90952) Implement custom global header banner (elastic#87438) [Fleet] Reduce permissions. (elastic#90302) Update dependency @elastic/charts to v24.5.1 (elastic#89822) [Create index pattern] Can't create single character index without wildcard (elastic#90919) [ts/build_ts_refs] add support for --clean flag (elastic#91060) Don't clean when running e2e tests (elastic#91057) Fixes track_total_hits in the body not having an effect when using search strategy (elastic#91068) [Security Solution][Detections] Adds list plugin Saved Objects to Security feature privilege (elastic#90895) Removing the code plugin entirely for 8.0 (elastic#77940) chore(NA): move the instruction to remove yarn global bazelisk package into the first place on install bazel tools (elastic#91026) [jest/ci] remove max-old-space-size override to use 4gb default (elastic#91020) [Fleet] Restrict integration changes for managed policies (elastic#90675) [CI] Fix auto-backport condditions so that it doesn't trigger for other labels (elastic#91042) [DOCS] Uses variable to refer to query profiler (elastic#90976) [App Search] Relevance Tuning logic listeners (elastic#89461) [Metrics UI] Fix saving/loading saved views from URL (elastic#90216) Limit cardinality of transaction.name (elastic#90955) ...
* first draft * update plugin list * fix tsproject * update bundle limits file * remove unused start dep * adapt imports * POC of footer banner * update styles, mostly * plug banner to uiSettings * adding some unit tests * add tests on sort_fields * cleanup sums in sass mixins * some self review stuff * update generated doc * add tests for color field * update chrome header test snapshots * retrieve license info from the server * switch from uiSettings to plugin config * update plugin list description * update default colors * NIT * add markdown support * fix banner overlap in fullscreen mode * change banner height to 32px * change banner's font size to 14 * delete unused uiSettings
|
Great to see this, looking forward to the settings being whitelisted so we can try it in staging. |



Summary
This PR Implements the phase 1 of #17298. By adding a new
bannersplugin that allows users to define a static banner appearing on all page of Kibana.Screenshots
Login
Stretch to height pages
Scrollable pages
Checklist
Technical implementation
During the discussions in #17298, we came to the agreement to use
uiSettingsas the underlying implementation of the banner's configuration.However, I missed two important facts at this time:
kibana.yml, I thought it was only the ones done via the UI), are not exposed on unauthenticated pages.kibana.yml, it will always be used. You can't do per-space overrides in that case. Meaning that a uiSettings-only implementation would not have been possible when we would be implementing stage 2.Given that, I decided to go with a more classic plugin-configuration-based approach for phase1, as we don't need any way to set the global banner configuration via the UI.
Phase 2 will use uiSettings for the per-space banner overrides, which will also allow, with some logic in the middle, to fallback to the global banner configuration, which was not possible with uiSettings.
Also,
xpack.banners.placement: 'header'is just a better end user experience thanuiSettings.overrides.banner:placement: 'header'when it comes to configuring the banner imho.Design implementation
There were 3 main tasks here:
topoffset. This is done insrc/core/public/chrome/ui/header/_banner.scsseuiHeaderAffordForFixedto add the banner's height to the body/container offset when the banner is present. Done (mostly) insrc/core/public/rendering/_base.scssheight: calc(100vh - #{$headerHeightOffset});in various scss files to use a new banner-aware mixin instead.Release Note
The new
bannersplugin allows to display a static banner at the top of every page of Kibana. The plugin can be configured via thekibana.ymlconfig fileThis is a gold+ feature, and is disabled on lower license levels.