elastic / kibana

Your window into the Elastic Stack
https://www.elastic.co/products/kibana
Other
19.63k stars 8.22k forks source link

Kibana Globalization #6515

Closed srl295 closed 6 years ago

srl295 commented 8 years ago

Kibana Globalization

Note: These requirements were originally written up over a year ago. Take any specific implementation details with a grain of salt. Phases that were already implemented should be reevaluated to make sure they still make sense, especially in light of the new kibana platform work.

Purpose

Architecture Diagram

This was our original plan, but it might need to change dramatically for the new platform

Design

Phase 1

Note this phase was completed, but it's possible the implementation might need to change for the new platform. Most of the code lives here

Purpose

Decide Language for Translation Algorithm

I18n Class

en.json

    {
        "UI-WELCOME_MESSAGE": "Loading Kibana",
        "UI-WELCOME_ERROR": "Kibana did not load properly. Check the server output for more information."
    }

UiI18n Class

Tool for Verifying All Translations have Translatable Strings

Deliverable

Phase 2

Purpose

Translations Available Client Side

Translation Identifiers Added to Kibana UI

BEFORE (HTML)

    <div class="sidebar-list">
    …

    <div class="sidebar-list-header">
        <h5>Selected Fields</h5>
    </div>

AFTER (HTML)

    <div class="sidebar-list">
    …

    <div class="sidebar-list-header">
        <h5 translate="FIELDS_SELECTEDFIELDS"></h5>
    </div>

Tool for Verifying All Translations have Translatable Strings (Update)

Translation Plugin Generator

Deliverable

Phase 3

Purpose

Translation Identifiers Added to Kibana UI

Deliverables

Phase 4

Purpose

Handling Language Packs

Deliverables

Blockers

Open Questions/Issues

History

This section has links to prior versions of this issue text.

Authors

rashidkpc commented 8 years ago
    <div class="sidebar-list-header">
        <h5>{{ FIELDS_SELECTEDFIELDS | translate }}</h5>
    </div>

Is this expecting FIELDS_SELECTEDFIELDS to be attached to $scope of the controller? It would make more sense to implement this as an attribute directive similar to ng-bind

eg:

     <div class="sidebar-list-header">
         <h5 kbn-bind="FIELDS_SELECTEDFIELDS"></h5>
     </div>

Then kbn-bind would know how to handle FIELDS_SELECTEDFIELDS as a string, retrieve the appropriate replacement text, and fill it. In addition it would allow us to use one time binding and not suffer the performance consequences of two way binding with a filter.

rashidkpc commented 8 years ago
    {
        "FIELDS_SELECTEDFIELDS": "Selected Fields",
        "METRIC_COUNT": "Count"
    }

My initial thought is that a massive master list doesn't seem very elegant. It seems like this sort of thing would be better implemented the way we do .less files, scoped to the current app?

rashidkpc commented 8 years ago

There would also need to be a test framework around this to ensure that all of the constants that must be defined, are. Potential translation volunteers need a simple way of discovering what needs translation and a simple way of confirming that they've defined everything required

rashidkpc commented 8 years ago
    $translate('METRIC_COUNT').then( function(count) {
        return new MetricAggType({
    title: count
    }}

This seems to imply that any functions that currently contain strings would need to be updated to return a promise. I don't see the need for the async behavior here.

rashidkpc commented 8 years ago

Given the need to translate both angular and non-angular components, why was a framework specific translation implementation chosen? And why this one specifically?

srl295 commented 8 years ago

@rashidkpc thanks. Comments on a couple of items:

DTownSMR commented 8 years ago

Rashid, maybe I should take these out of order.

shikhasriva commented 8 years ago

Rashid, regarding test framework, we suggest having that as a separate issue. And definitely agree with the need and usage of it... what do you think ?

shikhasriva commented 8 years ago

Rashid and all, DO you all agree with the phased approach we suggested ...thanks

w33ble commented 8 years ago

Given the need to translate both angular and non-angular components, why was a framework specific translation implementation chosen?

While I agree that angular-translate looks pleasant to use, and seems to be well maintained, using something that's explicitly bound to angular for something as far-reaching as i18n concerns me.

As @rashidkpc points out, we have non-angular components in our code, and that's likely to become increasingly common in the future. I'm also concerned about server-side use as we push things into the node server.

Is there something more generic that fits the bill, and also has an existing angular wrapper?

rashidkpc commented 8 years ago

I haven't looked deeply into i18n, but I'm hesitant to tie to angular-translate for the full implementation. It could be used in places, but there's plenty of places it can't be used. Like joe said, I think it would be good to investigate something lower level that could be wrapped up for the angular bits.

On the topic of the phases. I don't see any problem with those stages, but i think more discussion is needed on the approach before beginning.

I would like discussion of the testing framework to happen here. We can always split it off if needed, but it has direct influence on the approach taken.

srl295 commented 8 years ago

The translated files are just JSON and could certainly be consumed by the server side or the widgets, etc without use of the angular-specific framework. So this approach doesn't preclude using angular-translate where it makes sense, and something else (or no framework) elsewhere.

Re testing - yes, we can definitely discuss it here. We were wanting to split the test itself into a separate phase as above. (I added 1AA) One issue would be that I would recommend having a missing translation be more of a warning than a failure from a CI perspective, otherwise a feature couldn't be added in the source language (English) without all translations being done, nor could a translation be partial.

w33ble commented 8 years ago

The translated files are just JSON and could certainly be consumed by the server side or the widgets, etc without use of the angular-specific framework. So this approach doesn't preclude using angular-translate where it makes sense, and something else (or no framework) elsewhere.

That's a fair point. It does seem like the format is pretty common, and the more or less the same regardless is which library/framework you use. Getting hung up on angular-translate specifically is probably a waste of time.

Given that, I think it's worth adding something in one of the earlier phases about ensuring that whatever translation format we go with works both with and without Angular somehow, most likely by specifically targeting a part of the application that isn't in Angular. Server-side code is probably an easy candidate.

srl295 commented 8 years ago

@w33ble OK. Perhaps something like - "a simple JSON format will be specified in the documentation, and the proof of concept will use angular-translate. Non-angular portions (such as the server) would not use angular-translate, and the specific plugin technology used for translating on the client side is subject to discussion"

w33ble commented 8 years ago

I think Rashid and I just want to make sure the plan specifically takes into account using the i18n definitions outside of Angular. Adding the above sounds good to me.

srl295 commented 8 years ago

@w33ble — thanks, that makes sense. Edit I have updated the text above to address the feedback from yourself and @rashidkpc .

srl295 commented 8 years ago

@rashidkpc @w33ble — any comments on the updates?

rashidkpc commented 8 years ago

I'm happier with the new proposition.

    var uiStrings = …; // loading TBD
    return new MetricAggType({
      title: uiStrings.METRIC_COUNT,

Either webpack/import or though a Private module, which would make it easy to inject into other parts of the application.

srl295 commented 8 years ago

great. We will investigate using webpack.

It seems like the proof of concept should be able to proceed for phase 1A if there are no issues on that part.

Bargs commented 8 years ago

Can we create a new ticket specifically for Phase 1A and turn this ticket into more of a meta ticket? There's a lot of good discussion and context here so I wouldn't want it to get closed when #7247 gets merged.

Bargs commented 8 years ago

Someone was asking in chat today about currency field formatters, which brought my attention to https://github.com/elastic/kibana/issues/4392

It's probably a long way down the road if we tackle something like that, but food for thought perhaps.

srl295 commented 8 years ago

@Bargs @epixa given the updated discussion, I'm going to propose the following steps— not assigning 'Phase' numbers for now, just trying to capture a way forward.

First steps will be to have the i18n plugin, and to make use of it from CLI - not even from the front end to start.

Low level i18n plugin

Translation Plugin(s)

Translation Bundle-Serving Plugin

Angular Translation Plugin

Bargs commented 8 years ago

@srl295 at first glance this looks really great! I'll have to give a few of the points some thought, so I'll try to get you some more detailed feedback next week.

One note - I chatted with @hickeyma on IRC yesterday about using the translations from the CLI. I think that's going to be a tricky place to start because the plugins don't get loaded up until the Kibana server actually starts booting up. We talked about starting with some simple API tests instead. I'll keep trying to think of other good places to start testing the i18n plugin without involving the frontend.

srl295 commented 8 years ago

@Bargs Thanks. Yeah, lots of handwavy here, just trying to capture the general direction. I didn't actually look at the wiki yet, @hickeyma did and was going to ground this firmly in reality.

on CLI, perhaps there's a way it could be used for error messages- so at least, once booted, they are localized, even if not before hand. hm.

Thanks, let's keep discussing.

hickeyma commented 8 years ago

@srl295 Looks good! :-) Like @Bargs I will give the points some more feedback as I go along with implementing. BTW, tried loading translations in CLI from plugin, Having issues with timings as seems to be returning request and not the response back from the plugin. After chatting with @Bargs, using mocha tests instead for the moment.

shikhasriva commented 8 years ago

@srl295 @Bargs @hickeyma, I would propose to start from the Ui side as that will be more prevalent use case. We can take the cli as a later phase. Enable for Ui first and then CLI. Also, lets revisit the rendering (agular, react etc) plugins. I am thinking we need a protocol setup that can be called by react or angular or anything else.

shikhasriva commented 8 years ago

@Bargs, One point that we need to discuss is correlation between views and translation bundle. So we have an algorithm to load the right bundle.

hickeyma commented 8 years ago

@shikhasriva: This is a good point to raise! As we discussed today, I am currently PoCing with known localized string file but the plugin would need to know which file(s) to load per client/view.

srl295 commented 8 years ago

@shikhasriva that makes sense from a usage point of view. @Bargs I think “simple API tests” may suffice for a phased bringup. Our prior “Phase 1A” had the translation mechanism in the UI area, and moving it to a plugin moves it out into non-UI territory.

hickeyma commented 8 years ago

The following questions have come to mind while thinking how best to implement the "Low level i18n plugin":

  1. How will the plugin retrieve the currently-installed languages? Does this need to be a configuration setting?
  2. How will the i18n plugin decide which translation files to load for a plugin? Does it traverse all translation files (i.e. any i18n) directories in a plugin directory? What about plugins where some of its languages are in different plugins?
  3. Should we use a custom HTTP header to inform the i18n plugin which plugin resources it needs to load?
  4. Does the i18n plugin load all translations (all translation file content) for a plugin and return as a JSON object in the payload?
  5. Do we need to define the JSON structure for all translation files so that there is uniqueness between plugins and in plugins? For example: `{ { { { : } } } } ` i18n plugin could define the 'plugin' as passed in the request and 'view' as retrieved from translation files traversal.
  6. Should "accept-language" header be used instead of "content-language" header? "accept-language" header would provide all languages loaded in an user's browser.
  7. Could we use the default language from "accept-language" header as the fallback language? Do we need a server configuration as well?
Bargs commented 8 years ago

These are just some thoughts off the top of my head, so take them as guidance rather than hard requirements.

How will the plugin retrieve the currently-installed languages? Does this need to be a configuration setting?

I think the i18n plugin will keep track of which languages are available as they're registered by other plugins, similar to how vis_types are added by plugins (see the table_vis plugin as an example). That's just my initial thought though, I'm open to other ideas.

How will the i18n plugin decide which translation files to load for a plugin? Does it traverse all translation files (i.e. any i18n) directories in a plugin directory? What about plugins where some of its languages are in different plugins?

That might be one way to handle it, but it would require us to force a convention on plugin authors (not necessarily a bad thing). We could also leave it up to the individual translation plugin to register the complete bundled translations with the i18n plugin. But this would probably need to be done in such a way that the translation bundles aren't all being loaded into memory on the Kibana server. We could also lean on webpack to bundle up all the translation files, if it makes sense.

Should we use a custom HTTP header to inform the i18n plugin which plugin resources it needs to load?

Not sure what you mean here.

Does the i18n plugin load all translations (all translation file content) for a plugin and return as a JSON object in the payload?

I think the biggest determinant here will be memory usage on the Kibana server. I like the simplicity of serving the translations as JSON payloads from a REST api, but it's probably too much info to hold in memory, and if we're just streaming a flat file there might not be much advantage in wrapping it in an API vs simply serving that file directly. My intuition might also be totally off on how much memory these will consume though.

Do we need to define the JSON structure for all translation files so that there is uniqueness between plugins and in plugins?

They definitely need to be namespaced in some way. Plugin id might be the natural candidate. But how do we distinguish between which plugin provided the original version of a string, and which are just providing translations? For instance, say the table_vis plugin defines a string resource keyed by table_vis.foo.bar. Another plugin called table_vis_es might provide a Spanish translation for the string, but that doesn't mean there should be a table_vis_es.foo.bar key.

Should "accept-language" header be used instead of "content-language" header? "accept-language" header would provide all languages loaded in an user's browser.

I believe these headers are for two different purposes, accept-language is a request header whereas content-language is set by the server in its response. So for the purpose of the client telling us which language they want, we should definitely use accept-language.

Could we use the default language from "accept-language" header as the fallback language? Do we need a server configuration as well?

I imagine we need some sort of fallback if the client provides no accept-language header at all.

Bargs commented 8 years ago

I forgot, another idea @epixa mentioned is that we could use the default language string itself as the key for each string resource, rather than coming up with a separate unique namespaced key. This might also side step the question of matching resource bundles to views, as the strings would be view agnostic.

epixa commented 8 years ago

Plugins should have to explicitly register their translations rather than Kibana traversing the file system to find them. We could just lean on the hapi plugin system for this:

// synchronously
server.plugins.i18n.registerTranslation('en', {
  somekey: 'Some Value'
});

// asynchronously
import { promisify } from 'bluebird';
import { readFile } from 'fs';
const readFileAsync = promisify(readFile);
const loadTranslation = readFileAsync('mytranslations.json').then(JSON.parse);
server.plugins.i18n.registerTranslationAsync('en', loadTranslation);

The i18n core plugin in Kibana could then write registered translations to disk on startup so it's not all sitting in memory.

The "available languages" would be inferred from all of the plugin register calls at startup.

Also, we shouldn't rely on webpack for any of this. We want to get webpack out of our release builds entirely.

hickeyma commented 8 years ago

@Bargs, @epixa: Thanks for the feedback.

@epixa: You are suggesting that all plugins register their translations with the i18n core plugin? This can be 1..m files and for multiple languages supported. If different languages of a plugin are in different plugins, then maybe they need to register with the parent plugin ID?

This registration could be one off registration on first start of the server or if new language added or if new plugin added? There could also be the option to re-register.

The i18n core plugin can then store internally each plugin language translations in file as you mentioned. It can be structured to best suit how to load data as needed. Do we consider breaking translation from one bundle file into multiple bundles?

As you said, it makes sense to get available languages from registration.

It might be prudent to put a convention on plugins that all translation IDs in a plugin are unique. This removes unnecessary multi-structured JSON and less complexity from client.

When the plugin need its translations, how best to load it from the i18n core plugin? Does it do a REST call at start of plugin, to load a language translation bundle which covers all translations for the plugin into memory? Or is it best to serve the file directly?

Bargs commented 8 years ago

I can't speak for @epixa but here are my thoughts:

This registration could be one off registration on first start of the server or if new language added or if new plugin added? There could also be the option to re-register.

My initial thought was that the translations would just get dynamically registered on every server start up. But that strategy would make build time verifications difficult/impossible. Maybe registration (and the subsequent build of the translation file by the i18n plugin) should happen at plugin installation time? This is probably something we'll have to experiment with a bit.

Do we consider breaking translation from one bundle file into multiple bundles?

I was thinking we'd have one bundle per language, maybe per app? It's possible the i18n plugin's internal representation of the data, and the API it exposes to the frontend will be different. I kind of liked @srl295's idea of a separate "Bundle Serving Plugin".

It might be prudent to put a convention on plugins that all translation IDs in a plugin are unique. This removes unnecessary multi-structured JSON and less complexity from client.

The more I think about it the more I like the idea of using the text strings as the resources keys themselves. It removes the need for any namespacing and even opens up the possibility of plugins sharing translations of common strings in a pretty frictionless manner. For instance I don't see any reason why two plugins should both need to translate some common words like "Submit" or "Click for more info". There's some precedence for this approach in other libs: https://github.com/jeresig/i18n-node-2. Can you think of any downsides?

When the plugin need its translations, how best to load it from the i18n core plugin? Does it do a REST call at start of plugin, to load a language translation bundle which covers all translations for the plugin into memory? Or is it best to serve the file directly?

We can probably figure that out as we go. As long as the content is coming from an endpoint that Hapi exposes, we can always change how that content gets stored/loaded. For instance, this is how we serve the static js and css bundles: https://github.com/elastic/kibana/blob/f379074ebd9c73fa64fc999f6cb82ca548e54350/src/server/http/index.js#L17. As you can see they currently get loaded up from the filesystem by Hapi, but that's an implementation detail of the server.

The translations probably shouldn't be loaded per plugin though. We don't want the user to have to wait for translation bundles to download every time they click to a new page in the app. Unless we can show that downloading all of the translations for a given language in one big bundle at page load time is too slow, we're probably optimizing prematurely.

srl295 commented 8 years ago

Be back from two days off tomorrow, but lots of comments. Briefly • having plugins have too much code and not data means harder for toolchain to work with such plugins.

• using English text as the key is not a good idea - example, "back" could mean to return or could mean the part of your body. Such reuse is actually not a good idea. Again tooling that can see the English side can reuse content using more context. You also lose out on history and context. If the English changes from "hello, world" to "Hello, world!" the translation may need minimal/ or even no change. Only having the English as the key throws away any information and starts from scratch.

Bargs commented 8 years ago

Good points on english text keys @srl295, I knew it sounded too good to be true. @epixa you mentioned you've seen this approach before, was there any way of mitigating the issues @srl295 brought up?

epixa commented 8 years ago

Nope, I never thought of that. We just lucked out.

srl295 commented 8 years ago

Some clarifications/responses to the discussion above.

@epixa I realized something, when you said:

rather than… traversing the file system

I didn't expect that the i18n plugin would look in all possible places for translations (such as the …/i18n/en.json files in our old proposal). What I had in mind was the following:

1) a plugin which contains just the English content for (perhaps its own) plugin:

<plugin>/translations/status_page/en.json

2) a plugin which contains English contents for multiple plugins:

<plugin>/translations/status_page/en.json
<plugin>/translations/tableVis/en.json

3) a plugin which contains German contents for multiple plugins:

<plugin>/translations/status_page/de.json
<plugin>/translations/tableVis/de.json
{
   "create.CONFIGURE_INDEX_PATTERN": "Configure an index pattern", 
   "create.MUST_CONFIGURE_INDEX_PATTERN":"In order to use Kibana you must configure at least one index pattern. Index patterns are used to identify the Elasticsearch index to run search and analytics against. They are also used to configure fields.",
   …
   "edit.DESCRIPTION": "This page lists every field in the <strong>{{indexPatternId}}</strong> index and the field's associated core type as recorded by Elasticsearch. While this list allows you to view the core type of each field, changing field types must be done using Elasticsearch's",
   "edit.TIME_BASED_INDEX_ALERT":"This index uses a <strong>Time-based index pattern</strong> which repeats"
}

Limiting the contents to a simple map makes it easier for tools to work with. In this example the UI uses the view name (create or edit) followed by a dot and then a local suffix.

(This from discussion hashing things out with @hickeyma … any errors or omissions are mine of course…)

hickeyma commented 8 years ago

@Bargs @epixa following on from our discussions and investigations, we are going to propose the following for Kibana Globalization. Any errors or omissions are mine!

Archiving the proposal as now added to the main document above https://github.com/elastic/kibana/issues/6515:

Bargs commented 8 years ago

@hickeyma This is a great summary. I think phase 1 and 2 probably need to happen in tandem, in fact I should probably get phase 2 merged prior to merging phase 1 so that we'll have a working pluggable translation system once the initial i18n PR gets merged (The jade template translation should be able to come from a translation plugin, not just the baked in english version).

One language for one Kibana view/plugin

I think this is outdated, we're no longer dividing translations across view/plugin boundaries right?

Sub-directories containing translation file(s)

Let's just support a single directory of translation files, one per language for now.

Otherwise I think this is a great summary of our current thinking. @srl295 could you update the main ticket description?

Bargs commented 8 years ago

@hickeyma @srl295 I chatted with @epixa today. I think we just have a few more items to take care of before we open this up to a wider audience. Hopefully the checklist below provides a clear path.

Open questions and blocker tasks:

Documentation clean up:

Other items, thoughts, non-blockers:

hickeyma commented 8 years ago

@Bargs, @epixa Thanks for the great feedback. I will initially respond to the points here and tackle them subsequently:

Open questions and blocker tasks:

@epixa mentioned he would prefer the i18n plugin's registerTranslation method take individual file paths, rather than a directory name

What is the use case for this that is not covered by directory name?

If we add translations to the Jade template, we really need the tool for verifying the translations exist.

OK. As mentioned previously , it could possibly be some pattern which would help identify that this is a string identifier. This might be something as simple as defining that the variable used for getting the translations is a certain name (for example, 'i18nTranslation') and then could search for all instances in code files and extract the identifier from it. Then you could check the translations files. It can be JS code called by a grunt task.

Solidify the plan for verifying angular translations.

I will investigate this further and come up with some plan/PoC.

Documentation clean up:

Update info about translation plugin directory structure once we make a decision there.

Sure, will do.

Phase 1 and 2 really need to go together, so we should update the summary to reflect that.

Sure, will flatten into one phase.

Not sure what the "Translation Loader Plugin" is?

On second thoughts, this plugin is probably superfluous. I will remove it during update.

"REST API" and translation bundle serving plugin are one in the same in my mind at the moment. I don't think we need separate sections for them.

OK. They are in separate sections because addition of "REST API" is to the i18n plugin which the translation bundle serving plugin uses.

Update the description of this issue with the cleaned up docs.

Sure, will do.

Other items, thoughts, non-blockers:

I need to look into doing some refactoring to support the plugin install time hook. This shouldn't block gathering feedback from a wider audience, but it would be a blocker for phase 1.

OK. My only concern here is that doing this may have the potential to block phase 1 for a substantial period of time? Or is it quite doable to get it merged?

Bargs commented 8 years ago

What is the use case for this that is not covered by directory name?

@epixa's argument isn't that it will support additional use cases, but that it will be less brittle since it is more explicit. My feeling was that it would complicate things for the translator without much benefit. However, just while typing this I realized we could do the single file registrations, and still maintain a good translator experience if we just move the default file gathering behavior into the translation plugin boilerplate. What do you think?

it could possibly be some pattern which would help identify that this is a string identifier. This might be something as simple as defining that the variable used for getting the translations is a certain name

It would be nice if we could enforce the pattern somehow, rather than relying on all devs using the same variable name. Maybe we could expose a translate('<key>') function in the Jade template instead of a variable. That makes the strategy for accessing translations pretty explicit.

They are in separate sections because addition of "REST API" is to the i18n plugin which the translation bundle serving plugin uses.

I'm not sure what you mean by this. What does the bundle serving plugin do?

OK. My only concern here is that doing this may have the potential to block phase 1 for a substantial period of time? Or is it quite doable to get it merged?

It's possible, I'll need to spend some more time with the existing code to know for sure. If it looks like it will be a huge effort, maybe we can consider a phase 1 without the install hook. Here's another question that just occurred to me: how do core plugins register their translations, since they don't get "installed"? I'll add this to my list above.

hickeyma commented 8 years ago

@Bargs I have updated the description in https://github.com/elastic/kibana/issues/6515#issuecomment-231400097 accordingly following our discussions.

@epixa's argument isn't that it will support additional use cases, but that it will be less brittle since it is more explicit.

OK. registerTranslations updated to take absolute path to file instead of directory argument.

It would be nice if we could enforce the pattern somehow, rather than relying on all devs using the same variable name. Maybe we could expose a translate(<key>) function in the Jade template instead of a variable. That makes the strategy for accessing translations pretty explicit.

Sure, agreed.

What does the bundle serving plugin do?

Again, in retrospect this is now unnecessary. Removed.

How do core plugins register their translations, since they don't get "installed"?

Added "Tool for Registering Translations" section above to phase 1. By adding this section, it now seems to decouple phase 1 and phase 2 dependencies as you will now have workable translations for the welcome message.

srl295 commented 8 years ago

@Bargs I've updated the heading of this issue w/ @hickeyma 's latest… also added a History section with links to gists of prior versions of the issue heading.

shikhasriva commented 8 years ago

Thanks, Looks good. @Bargs, lets us know if you think of any open Qs or comments

Bargs commented 8 years ago

@hickeyma I think the "Tool for registering translations" section might give the wrong impression, it sounds like this is an external tool we'll create. I think the more important questions to answer are:

hickeyma commented 8 years ago

@Bargs: Sure, probably need an integrated means in the Kibana infrastructure to register the core plugin translations. I will investigate this further and in the meantime I will add a reference in the design doc and flesh it out once we have an approach unearthed.

hickeyma commented 8 years ago

I have updated the design doc kibana-proposal-update

@Bargs This should hopefully tick off some more items in your checklist! :-)

@Bargs, @srl295 could you update the main ticket description?