Skip to content

Commit

Permalink
[Lens] Show underlying data editor navigation (#125983)
Browse files Browse the repository at this point in the history
* ⚗️ First steps

* 🎉 Initial implementation for button insider editor

* ✅ fix types and tests

* ✅ Add some tests and some test placeholders

* 🐛 Fix issues on mount

* 🔥 Remove unused attr

* ✅ Add more tests for edge cases

* ♻️ First code refactor

* 🐛 Fix discover capabilities check

* 🐛 Fix various issues

* ✅ Add functional tests

* ✅ Add more tests

* ✨ Add support for terms + multiterms

* ✨ Make link open a new window with discover

* :white_check_make: Update functional tests to deal with new tab

* 🐛 Fix transposed table case: make it use fallback

* 🐛 Fix unit tests

* 👌 Address review feedback

* 🐛 Skip filtered metrics if there's at least an unfiltered one

* 🐛 Improve string escaping strategy

* 🐛 Fix functional tests and improved filters dedup checks

* ✅ Fix functional tests for formula case

* 🔧 Make close editor panel more robust

* 🔧 Try focus approach

* 👌 Rename variable

* ✅ Try to click outside

* ✅ Use the keyboard arrow approach

* 👌 Address some issues raised by review

* ✅ Fix tests and add one more for unsupported datasource

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
dej611 and kibanamachine authored Mar 9, 2022
1 parent b76370d commit 133e57f
Show file tree
Hide file tree
Showing 36 changed files with 2,511 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface TopNavMenuData {
isLoading?: boolean;
iconType?: string;
iconSide?: EuiButtonProps['iconSide'];
target?: string;
href?: string;
}

export interface RegisteredTopNavMenuData extends TopNavMenuData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,19 @@ export function TopNavMenuItem(props: TopNavMenuData) {
className: props.className,
};

// If the item specified a href, then override the suppress the onClick
// and make it become a regular link
const overrideProps =
props.target && props.href
? { onClick: undefined, href: props.href, target: props.target }
: {};

const btn = props.emphasize ? (
<EuiButton size="s" {...commonButtonProps} fill>
{getButtonContainer()}
</EuiButton>
) : (
<EuiHeaderLink size="s" color="primary" {...commonButtonProps}>
<EuiHeaderLink size="s" color="primary" {...commonButtonProps} {...overrideProps}>
{getButtonContainer()}
</EuiHeaderLink>
);
Expand Down
5 changes: 5 additions & 0 deletions test/functional/services/filter_bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ export class FilterBarService extends FtrService {
return filters.length;
}

public async getFiltersLabel(): Promise<string[]> {
const filters = await this.testSubjects.findAll('~filter');
return Promise.all(filters.map((filter) => filter.getVisibleText()));
}

/**
* Adds a filter to the filter bar.
*
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/lens/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"taskManager",
"globalSearch",
"savedObjectsTagging",
"spaces"
"spaces",
"discover"
],
"configPath": [
"xpack",
Expand Down
78 changes: 78 additions & 0 deletions x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ import {
DispatchSetState,
} from '../state_management';
import { getIndexPatternsObjects, getIndexPatternsIds, getResolvedDateRange } from '../utils';
import {
combineQueryAndFilters,
getLayerMetaInfo,
getShowUnderlyingDataLabel,
} from './show_underlying_data';

function getLensTopNavConfig(options: {
showSaveAndReturn: boolean;
enableExportToCSV: boolean;
showOpenInDiscover?: boolean;
showCancel: boolean;
isByValueMode: boolean;
allowByValue: boolean;
Expand All @@ -46,6 +52,7 @@ function getLensTopNavConfig(options: {
showCancel,
allowByValue,
enableExportToCSV,
showOpenInDiscover,
showSaveAndReturn,
savingToLibraryPermitted,
savingToDashboardPermitted,
Expand Down Expand Up @@ -90,6 +97,21 @@ function getLensTopNavConfig(options: {
});
}

if (showOpenInDiscover) {
topNavMenu.push({
label: getShowUnderlyingDataLabel(),
run: () => {},
testId: 'lnsApp_openInDiscover',
description: i18n.translate('xpack.lens.app.openInDiscoverAriaLabel', {
defaultMessage: 'Open underlying data in Discover',
}),
disableButton: Boolean(tooltips.showUnderlyingDataWarning()),
tooltip: tooltips.showUnderlyingDataWarning,
target: '_blank',
href: actions.getUnderlyingDataUrl(),
});
}

topNavMenu.push({
label: i18n.translate('xpack.lens.app.inspect', {
defaultMessage: 'Inspect',
Expand Down Expand Up @@ -183,6 +205,7 @@ export const LensTopNavMenu = ({
uiSettings,
application,
attributeService,
discover,
dashboardFeatureFlag,
} = useKibana<LensAppServices>().services;

Expand Down Expand Up @@ -290,6 +313,26 @@ export const LensTopNavMenu = ({
filters,
initialContext,
]);

const layerMetaInfo = useMemo(() => {
if (!activeDatasourceId || !discover) {
return;
}
return getLayerMetaInfo(
datasourceMap[activeDatasourceId],
datasourceStates[activeDatasourceId].state,
activeData,
application.capabilities
);
}, [
activeData,
activeDatasourceId,
datasourceMap,
datasourceStates,
discover,
application.capabilities,
]);

const topNavConfig = useMemo(() => {
const baseMenuEntries = getLensTopNavConfig({
showSaveAndReturn:
Expand All @@ -299,6 +342,7 @@ export const LensTopNavMenu = ({
(dashboardFeatureFlag.allowByValueEmbeddables || Boolean(initialInput))
) || Boolean(initialContextIsEmbedded),
enableExportToCSV: Boolean(isSaveable && activeData && Object.keys(activeData).length),
showOpenInDiscover: Boolean(layerMetaInfo?.isVisible),
isByValueMode: getIsByValueMode(),
allowByValue: dashboardFeatureFlag.allowByValueEmbeddables,
showCancel: Boolean(isLinkedToOriginatingApp),
Expand All @@ -321,6 +365,9 @@ export const LensTopNavMenu = ({
}
return undefined;
},
showUnderlyingDataWarning: () => {
return layerMetaInfo?.error;
},
},
actions: {
inspect: () => lensInspector.inspect({ title }),
Expand Down Expand Up @@ -388,6 +435,31 @@ export const LensTopNavMenu = ({
redirectToOrigin();
}
},
getUnderlyingDataUrl: () => {
if (!layerMetaInfo) {
return;
}
const { error, meta } = layerMetaInfo;
// If Discover is not available, return
// If there's no data, return
if (error || !discover || !meta) {
return;
}
const { filters: newFilters, query: newQuery } = combineQueryAndFilters(
query,
filters,
meta,
indexPatterns
);

return discover.locator!.getRedirectUrl({
indexPatternId: meta.id,
timeRange: data.query.timefilter.timefilter.getTime(),
filters: newFilters,
query: newQuery,
columns: meta.columns,
});
},
},
});
return [...(additionalMenuEntries || []), ...baseMenuEntries];
Expand All @@ -398,6 +470,7 @@ export const LensTopNavMenu = ({
initialContextIsEmbedded,
isSaveable,
activeData,
layerMetaInfo,
getIsByValueMode,
savingToLibraryPermitted,
savingToDashboardPermitted,
Expand All @@ -414,6 +487,11 @@ export const LensTopNavMenu = ({
setIsSaveModalVisible,
goBackToOriginatingApp,
redirectToOrigin,
discover,
query,
filters,
indexPatterns,
data.query.timefilter.timefilter,
]);

const onQuerySubmitWrapped = useCallback(
Expand Down
8 changes: 6 additions & 2 deletions x-pack/plugins/lens/public/app_plugin/mounter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export async function getLensServices(
usageCollection,
fieldFormats,
spaces,
discover,
} = startDependencies;

const storage = new Storage(localStorage);
Expand Down Expand Up @@ -95,6 +96,7 @@ export async function getLensServices(
// Temporarily required until the 'by value' paradigm is default.
dashboardFeatureFlag: startDependencies.dashboard.dashboardFeatureFlagConfig,
spaces,
discover,
};
}

Expand All @@ -114,8 +116,10 @@ export async function mountApp(
getPresentationUtilContext,
topNavMenuEntryGenerators,
} = mountProps;
const [coreStart, startDependencies] = await core.getStartServices();
const instance = await createEditorFrame();
const [[coreStart, startDependencies], instance] = await Promise.all([
core.getStartServices(),
createEditorFrame(),
]);
const historyLocationState = params.history.location.state as HistoryLocationState;

const lensServices = await getLensServices(coreStart, startDependencies, attributeService);
Expand Down
Loading

0 comments on commit 133e57f

Please sign in to comment.