-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Embeddables as Building Blocks] Controls API (#140739)
Added control group API and renderer component
- Loading branch information
1 parent
fcea2e7
commit c8a0376
Showing
15 changed files
with
274 additions
and
54 deletions.
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
src/plugins/controls/public/control_group/control_group_renderer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import uuid from 'uuid'; | ||
import useLifecycles from 'react-use/lib/useLifecycles'; | ||
import React, { useEffect, useMemo, useRef, useState } from 'react'; | ||
|
||
import { IEmbeddable } from '@kbn/embeddable-plugin/public'; | ||
|
||
import { pluginServices } from '../services'; | ||
import { getDefaultControlGroupInput } from '../../common'; | ||
import { ControlGroupInput, ControlGroupOutput, CONTROL_GROUP_TYPE } from './types'; | ||
import { ControlGroupContainer } from './embeddable/control_group_container'; | ||
|
||
export interface ControlGroupRendererProps { | ||
input?: Partial<Pick<ControlGroupInput, 'viewMode' | 'executionContext'>>; | ||
onEmbeddableLoad: (controlGroupContainer: ControlGroupContainer) => void; | ||
} | ||
|
||
export const ControlGroupRenderer = ({ input, onEmbeddableLoad }: ControlGroupRendererProps) => { | ||
const controlsRoot = useRef(null); | ||
const [controlGroupContainer, setControlGroupContainer] = useState<ControlGroupContainer>(); | ||
|
||
const id = useMemo(() => uuid.v4(), []); | ||
|
||
/** | ||
* Use Lifecycles to load initial control group container | ||
*/ | ||
useLifecycles( | ||
() => { | ||
const { embeddable } = pluginServices.getServices(); | ||
|
||
(async () => { | ||
const container = (await embeddable | ||
.getEmbeddableFactory< | ||
ControlGroupInput, | ||
ControlGroupOutput, | ||
IEmbeddable<ControlGroupInput, ControlGroupOutput> | ||
>(CONTROL_GROUP_TYPE) | ||
?.create({ id, ...getDefaultControlGroupInput(), ...input })) as ControlGroupContainer; | ||
|
||
if (controlsRoot.current) { | ||
container.render(controlsRoot.current); | ||
} | ||
setControlGroupContainer(container); | ||
onEmbeddableLoad(container); | ||
})(); | ||
}, | ||
() => { | ||
controlGroupContainer?.destroy(); | ||
} | ||
); | ||
|
||
/** | ||
* Update embeddable input when props input changes | ||
*/ | ||
useEffect(() => { | ||
let updateCanceled = false; | ||
(async () => { | ||
// check if applying input from props would result in any changes to the embeddable input | ||
const isInputEqual = await controlGroupContainer?.getExplicitInputIsEqual({ | ||
...controlGroupContainer?.getInput(), | ||
...input, | ||
}); | ||
if (!controlGroupContainer || isInputEqual || updateCanceled) return; | ||
controlGroupContainer.updateInput({ ...input }); | ||
})(); | ||
|
||
return () => { | ||
updateCanceled = true; | ||
}; | ||
}, [controlGroupContainer, input]); | ||
|
||
return <div ref={controlsRoot} />; | ||
}; | ||
|
||
// required for dynamic import using React.lazy() | ||
// eslint-disable-next-line import/no-default-export | ||
export default ControlGroupRenderer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
src/plugins/controls/public/control_group/editor/data_control_editor_tools.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { IFieldSubTypeMulti } from '@kbn/es-query'; | ||
import { DataView } from '@kbn/data-views-plugin/common'; | ||
|
||
import { pluginServices } from '../../services'; | ||
import { DataControlFieldRegistry, IEditableControlFactory } from '../../types'; | ||
|
||
const dataControlFieldRegistryCache: { [key: string]: DataControlFieldRegistry } = {}; | ||
|
||
const doubleLinkFields = (dataView: DataView) => { | ||
// double link the parent-child relationship specifically for case-sensitivity support for options lists | ||
const fieldRegistry: DataControlFieldRegistry = {}; | ||
|
||
for (const field of dataView.fields.getAll()) { | ||
if (!fieldRegistry[field.name]) { | ||
fieldRegistry[field.name] = { field, compatibleControlTypes: [] }; | ||
} | ||
const parentFieldName = (field.subType as IFieldSubTypeMulti)?.multi?.parent; | ||
if (parentFieldName) { | ||
fieldRegistry[field.name].parentFieldName = parentFieldName; | ||
|
||
const parentField = dataView.getFieldByName(parentFieldName); | ||
if (!fieldRegistry[parentFieldName] && parentField) { | ||
fieldRegistry[parentFieldName] = { field: parentField, compatibleControlTypes: [] }; | ||
} | ||
fieldRegistry[parentFieldName].childFieldName = field.name; | ||
} | ||
} | ||
return fieldRegistry; | ||
}; | ||
|
||
export const loadFieldRegistryFromDataViewId = async ( | ||
dataViewId: string | ||
): Promise<DataControlFieldRegistry> => { | ||
if (dataControlFieldRegistryCache[dataViewId]) { | ||
return dataControlFieldRegistryCache[dataViewId]; | ||
} | ||
const { | ||
dataViews, | ||
controls: { getControlTypes, getControlFactory }, | ||
} = pluginServices.getServices(); | ||
const dataView = await dataViews.get(dataViewId); | ||
|
||
const newFieldRegistry: DataControlFieldRegistry = doubleLinkFields(dataView); | ||
|
||
const controlFactories = getControlTypes().map( | ||
(controlType) => getControlFactory(controlType) as IEditableControlFactory | ||
); | ||
dataView.fields.map((dataViewField) => { | ||
for (const factory of controlFactories) { | ||
if (factory.isFieldCompatible) { | ||
factory.isFieldCompatible(newFieldRegistry[dataViewField.name]); | ||
} | ||
} | ||
|
||
if (newFieldRegistry[dataViewField.name]?.compatibleControlTypes.length === 0) { | ||
delete newFieldRegistry[dataViewField.name]; | ||
} | ||
}); | ||
dataControlFieldRegistryCache[dataViewId] = newFieldRegistry; | ||
|
||
return newFieldRegistry; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.