Skip to content

[Runtime field editor] Composite runtime in Kibana Data Views#110226

Merged
sebelga merged 65 commits intoelastic:index-pattern-field-editor/composite-runtime-fieldfrom
sebelga:index-pattern-field-editor/composite-runtime-in-data-views
Sep 9, 2021
Merged

[Runtime field editor] Composite runtime in Kibana Data Views#110226
sebelga merged 65 commits intoelastic:index-pattern-field-editor/composite-runtime-fieldfrom
sebelga:index-pattern-field-editor/composite-runtime-in-data-views

Conversation

@sebelga
Copy link
Contributor

@sebelga sebelga commented Aug 26, 2021

This PR adds support in Kibana Data views (former "Index pattern") for composite runtime fields.

It is the implementation of the #99462 discussion.

The problem

The new "composite" runtime fields allows a user to emit multiple values from a script. This means that when creating one runtime field of type: "composite" what the user is actually doing is creating one or multiple runtime fields behind a namespace (the name of the runtime field).

When we attach a composite runtime field to a search request:

GET my-index-000001/_search
{
  "runtime_mappings": {
    "myComposite" : {
        "type" : "composite",
        "script" : "emit('day_of_week', 'someValue'); emit('anotherField',  1234);",
        "fields" : {
            "day_of_week" : {
                "type" : "keyword"
            },
            "anotherField" : {
                "type" : "long"
            }
        }
      }
  },
  "aggs": {
    "day_of_week": {
      "terms": {
        "field": "myComposite.day_of_week"
      }
    }
  }
}

we are creating two runtime fields for the user: myComposite.day_of_week and myComposite.anotherField. The former of type keyword and the second of type long.

We need a way to store in the Kibana Data view both the composite runtime field (which is not a field but a holder of fields) and the fields themselves.

How to test

  • Navigate to Discover
  • Create a new field on the index pattern
  • Give a name (e.g. "log") and set the type to composite
  • Toggle the "Set value" and add a script
emit('field1', 'hello');
emit('field2', 'world');

Screenshot 2021-08-26 at 15 28 41

  • Save the runtime field
  • The 2 fields should appear in the list of fields (under "log.field1" and "log.field2"
  • You should be able to select them as any other field

Screenshot 2021-08-26 at 15 29 22

  • The 2 fields should be available in the Search bar

Screenshot 2021-08-26 at 15 29 01

  • You should not be able to edit or delete them (work for future PR)

Future work

This PR is going to a feature branch. Future PR will add

  • Functional tests
  • Component integration tests
  • Server CRUD routes to Get/Create/Update/Delete composite runtime in the Data view
  • UI to set the format, type, custom label and popularity to sub fields
  • UI (modals) to indicate how to delete/edit a subfield

Fixes #99177

@sebelga sebelga changed the title Index pattern field editor/composite runtime in data views [Runtime field editor] Composite runtime in Kibana Data Views Aug 26, 2021
const subField: EnhancedRuntimeField = {
// We hardcode "keyword" and "format" for now until the UI
// lets us define them for each of the sub fields
type: 'keyword' as const,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"type" and "format" will be defined in the UI in a following PR

parent === undefined ? false : options.ctx.indexPattern.getRuntimeComposite(parent) !== null;

if (doesBelongToCompositeField) {
console.log( // eslint-disable-line
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be done in a following PR

@sebelga sebelga requested a review from mattkime August 26, 2021 14:36
indexPattern.addRuntimeField(name, runtimeField);

const addedField = indexPattern.fields.getByName(name);
if (!addedField) throw new Error(`Could not create a field [name = ${name}].`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to add this validation as adding a field will either throw (in which case the error will be displayed from that throw) or succeed.


await indexPatternsService.updateSavedObject(indexPattern);

const savedField = indexPattern.fields.getByName(name);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too this validation is not necessary. We can wrap the indexPatternsService.updateSavedObject() in a try/catch but that operation should never remove the field created.

@sebelga
Copy link
Contributor Author

sebelga commented Sep 6, 2021

@stacey-gammon @mattkime The PR is ready for another round of review!
I have followed Matt's suggestion and removed the need of an intermediary compositeRuntimeMap. You will also see in the types that there is just RuntimeField (no more EnhancedRuntimeField).

Why is this returning a DataViewField type?

const fields: DataViewField[] = dv.addRuntimeField(name, runtimeField);

This is to help consumers knowing which DataViewField(s) have been created when adding the runtime field. Now with composite runtime fields it could be one or a lot more.

Here you are returning a different type, you've lost the extra fields (customLabel, etc).

const rtField: RuntimeField = dv.getRuntimeField(name);

Great point, I have updated the code and we now always get back a RuntimeField (with custom label, format and popularity information)

I'd prefer to keep addRuntimeField a simple method that only appends to the runtimeFieldMap.

@mattkime That would be too much of a change on the existing architecture. Probably worth revisiting as a separate work. For now I followed what was in place, adding a runtime field will adding it to the runtimeFieldMap + creating the DataViewField(s).

expect(response.status).to.be(404);
});

it('returns error on non-runtime field update attempt', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of this test as the lookup is in the runtimeFieldMap and not the field list, so there is no way to edit a non-runtime field through API.

);
});

it('returns error when attempting to fetch a field which is not a runtime field', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of this test as the lookup is in the runtimeFieldMap and not the field list, so there is no way to get a non-runtime field through API.

expect(response1.status).to.be(404);
});

it('returns error when attempting to delete a field which is not a runtime field', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of this test as the lookup is in the runtimeFieldMap and not the field list, so there is no way to delete a non-runtime field through API.

@mattkime
Copy link
Contributor

mattkime commented Sep 7, 2021

@mattkime That would be too much of a change on the existing architecture. Probably worth revisiting as a separate work. For now I followed what was in place, adding a runtime field will adding it to the runtimeFieldMap + creating the DataViewField(s).

Yes, the field list update change would be a chunk of work. What about keeping the existing functionality of addRuntimeField and placing the logic you've added into a new function?

@sebelga
Copy link
Contributor Author

sebelga commented Sep 7, 2021

What about keeping the existing functionality of addRuntimeField and placing the logic you've added into a new function?

I moved the logic to create a composite runtime field to a new private method, which reduced the changes to addRuntimeField. addRuntimeField() is still the only public method to add a runtime field in the DataView for the consumer.

@mattkime
Copy link
Contributor

mattkime commented Sep 8, 2021

I got through most of this today but want to take another look at it tomorrow after letting this sink in. Looks like some tests will need to be added, which makes sense considering some of the recent discussion we've had.

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

// @deprecated
// To avoid creating a breaking change in 7.16 we continue to support
// the old "field" in the response
field: dataViewFields[0].toSpec(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm tempted to remove support for this. Its only been in 7.14 and 7.15. I'll address this separately, no reason to hold up this PR.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattkime - if you want to make a breaking change in 8.0, even if it's only been in 7.14 and 7.15, please reach out. With the new Make it Minor changes, we have been asked to have all breaking changes approved at team/tech lead level. REST API breaking changes are included in that (but not plugin API changes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not only on 8.x, the breaking change would also ship in 7.16.

Copy link
Contributor

@mattkime mattkime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code looks good and works well, thanks for addressing my feedback

@timroes timroes removed the request for review from a team September 9, 2021 07:42
Copy link
Contributor

@mbondyra mbondyra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elastic/kibana-vis-editors changes LGTM, code review only.

@sebelga sebelga merged commit 18ba720 into elastic:index-pattern-field-editor/composite-runtime-field Sep 9, 2021
@sebelga
Copy link
Contributor Author

sebelga commented Sep 9, 2021

Thanks for the review @mattkime and @mbondyra !

mattkime added a commit that referenced this pull request Sep 12, 2022
* Initial commit

* [Runtime field editor] Composite runtime in Kibana Data Views (#110226)

* Apply updates from feature branch

* Fix TS issues

* Fix TS issue

* Fix TS issue

* Fix jest tests

* fix jest tests

* fix integration test

* fix delete error test

* partial progress

* partial progress

* remove mistaken change

* fix import

* remove unused translation

* partial progress

* merge

* use preview api

* cleanup

* use specific index instead of index pattern

* fix jest test

* one less any

* setting type on composite subfields is roughly working

* partial progress

* setState not working

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* partial progress

* working but a bit wonky

* merge

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* fix handing of field types, remove some console.log statements

* fix initial type for subfields

* fix subfield type updates, rename some vars

* fix breakage from bad merge

* fix types

* type fixes

* cleanup

* i18n fix

* i18n fix

* i18n fix

* comment cleanup

* remove unused var

* add code comment

* remove comments

* fix jest test

* add start of functional test

* functional test:

* composite subfield preview

* add functional test

* functional tests

* functional tests

* rendering improvements

* functional tests

* functional tests

* add jest test

* add jest test

* move to observables

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* cleanup

* better use of form lib

* type fixes

* cleanup

* add refresh button

* remove ts ignore

* improve dev docs

* internationalize text

* type fix

* delete should warn regarding subfields

* typescript fix

* redraws of FieldEditor would reset diff state. This fixes it.

* add placeholder text to code editor

* hook cleanup

* add getFieldPreviewChanges jest test

* add getFieldPreviewChanges jest test

* keep parent name in sync with preview when changed during script update

* fix test

* move subfields to observables

* fix jest tests

* fix jest tests

* fix save after field type change to composite

* previewFields to behaviorSubject

* fix test

Co-authored-by: Sébastien Loix <sabee77@gmail.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Sébastien Loix <sebastien.loix@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Project:RuntimeFields Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t//

Projects

None yet

Development

Successfully merging this pull request may close these issues.