* Aligned Lens & Visualize Breadcrumbs
This commit is contained in:
parent
54a37115ba
commit
530095ea00
|
@ -45,7 +45,7 @@ export const VisualizeByValueEditor = ({ onAppLeave }: VisualizeAppProps) => {
|
|||
|
||||
useEffect(() => {
|
||||
const { originatingApp: value, embeddableId: embeddableIdValue, valueInput: valueInputValue } =
|
||||
services.embeddable.getStateTransfer().getIncomingEditorState() || {};
|
||||
services.stateTransferService.getIncomingEditorState() || {};
|
||||
setOriginatingApp(value);
|
||||
setValueInput(valueInputValue);
|
||||
setEmbeddableId(embeddableIdValue);
|
||||
|
|
|
@ -46,6 +46,7 @@ export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => {
|
|||
services,
|
||||
eventEmitter,
|
||||
isChromeVisible,
|
||||
originatingApp,
|
||||
visualizationIdFromUrl
|
||||
);
|
||||
const { appState, hasUnappliedChanges } = useVisualizeAppState(
|
||||
|
@ -64,8 +65,7 @@ export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => {
|
|||
useLinkedSearchUpdates(services, eventEmitter, appState, savedVisInstance);
|
||||
|
||||
useEffect(() => {
|
||||
const { originatingApp: value } =
|
||||
services.embeddable.getStateTransfer().getIncomingEditorState() || {};
|
||||
const { originatingApp: value } = services.stateTransferService.getIncomingEditorState() || {};
|
||||
setOriginatingApp(value);
|
||||
}, [services]);
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ export const VisualizeListing = () => {
|
|||
savedVisualizations,
|
||||
toastNotifications,
|
||||
visualizations,
|
||||
embeddable,
|
||||
stateTransferService,
|
||||
savedObjects,
|
||||
savedObjectsPublic,
|
||||
savedObjectsTagging,
|
||||
|
@ -74,7 +74,7 @@ export const VisualizeListing = () => {
|
|||
|
||||
useMount(() => {
|
||||
// Reset editor state if the visualize listing page is loaded.
|
||||
embeddable.getStateTransfer().clearEditorState();
|
||||
stateTransferService.clearEditorState();
|
||||
chrome.setBreadcrumbs([
|
||||
{
|
||||
text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', {
|
||||
|
|
|
@ -80,7 +80,6 @@ const TopNav = ({
|
|||
},
|
||||
[visInstance.embeddableHandler]
|
||||
);
|
||||
const stateTransfer = services.embeddable.getStateTransfer();
|
||||
const savedObjectsClient = services.savedObjects.client;
|
||||
|
||||
const config = useMemo(() => {
|
||||
|
@ -96,7 +95,7 @@ const TopNav = ({
|
|||
visInstance,
|
||||
stateContainer,
|
||||
visualizationIdFromUrl,
|
||||
stateTransfer,
|
||||
stateTransfer: services.stateTransferService,
|
||||
savedObjectsClient,
|
||||
embeddableId,
|
||||
onAppLeave,
|
||||
|
@ -117,7 +116,6 @@ const TopNav = ({
|
|||
visualizationIdFromUrl,
|
||||
services,
|
||||
embeddableId,
|
||||
stateTransfer,
|
||||
savedObjectsClient,
|
||||
onAppLeave,
|
||||
]);
|
||||
|
|
|
@ -43,7 +43,7 @@ import {
|
|||
} from 'src/plugins/kibana_utils/public';
|
||||
import { SharePluginStart } from 'src/plugins/share/public';
|
||||
import { SavedObjectsStart, SavedObject } from 'src/plugins/saved_objects/public';
|
||||
import { EmbeddableStart } from 'src/plugins/embeddable/public';
|
||||
import { EmbeddableStart, EmbeddableStateTransfer } from 'src/plugins/embeddable/public';
|
||||
import { UrlForwardingStart } from 'src/plugins/url_forwarding/public';
|
||||
import { EventEmitter } from 'events';
|
||||
import { DashboardStart } from '../../../dashboard/public';
|
||||
|
@ -95,6 +95,7 @@ export interface EditorRenderProps {
|
|||
}
|
||||
|
||||
export interface VisualizeServices extends CoreStart {
|
||||
stateTransferService: EmbeddableStateTransfer;
|
||||
embeddable: EmbeddableStart;
|
||||
history: History;
|
||||
kbnUrlStateStorage: IKbnUrlStateStorage;
|
||||
|
|
|
@ -21,16 +21,8 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { VisualizeConstants } from '../visualize_constants';
|
||||
|
||||
const appPrefixes: Record<string, any> = {
|
||||
dashboards: {
|
||||
text: i18n.translate('visualize.dashboard.prefix.breadcrumb', {
|
||||
defaultMessage: 'Dashboard',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const defaultEditText = i18n.translate('visualize.editor.defaultEditBreadcrumbText', {
|
||||
defaultMessage: 'Edit',
|
||||
defaultMessage: 'Edit visualization',
|
||||
});
|
||||
|
||||
export function getLandingBreadcrumbs() {
|
||||
|
@ -44,9 +36,18 @@ export function getLandingBreadcrumbs() {
|
|||
];
|
||||
}
|
||||
|
||||
export function getCreateBreadcrumbs() {
|
||||
export function getCreateBreadcrumbs({
|
||||
byValue,
|
||||
originatingAppName,
|
||||
redirectToOrigin,
|
||||
}: {
|
||||
byValue?: boolean;
|
||||
originatingAppName?: string;
|
||||
redirectToOrigin?: () => void;
|
||||
}) {
|
||||
return [
|
||||
...getLandingBreadcrumbs(),
|
||||
...(originatingAppName ? [{ text: originatingAppName, onClick: redirectToOrigin }] : []),
|
||||
...(!byValue ? getLandingBreadcrumbs() : []),
|
||||
{
|
||||
text: i18n.translate('visualize.editor.createBreadcrumb', {
|
||||
defaultMessage: 'Create',
|
||||
|
@ -55,16 +56,23 @@ export function getCreateBreadcrumbs() {
|
|||
];
|
||||
}
|
||||
|
||||
export function getBreadcrumbsPrefixedWithApp(originatingApp: string) {
|
||||
const originatingAppBreadcrumb = appPrefixes[originatingApp];
|
||||
return [originatingAppBreadcrumb, ...getLandingBreadcrumbs(), { text: defaultEditText }];
|
||||
}
|
||||
|
||||
export function getEditBreadcrumbs(text: string = defaultEditText) {
|
||||
export function getEditBreadcrumbs(
|
||||
{
|
||||
byValue,
|
||||
originatingAppName,
|
||||
redirectToOrigin,
|
||||
}: {
|
||||
byValue?: boolean;
|
||||
originatingAppName?: string;
|
||||
redirectToOrigin?: () => void;
|
||||
},
|
||||
title: string = defaultEditText
|
||||
) {
|
||||
return [
|
||||
...getLandingBreadcrumbs(),
|
||||
...(originatingAppName ? [{ text: originatingAppName, onClick: redirectToOrigin }] : []),
|
||||
...(!byValue ? getLandingBreadcrumbs() : []),
|
||||
{
|
||||
text,
|
||||
text: title,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ export const getTopNavConfig = (
|
|||
stateTransfer.clearEditorState();
|
||||
}
|
||||
chrome.docTitle.change(savedVis.lastSavedTitle);
|
||||
chrome.setBreadcrumbs(getEditBreadcrumbs(savedVis.lastSavedTitle));
|
||||
chrome.setBreadcrumbs(getEditBreadcrumbs({}, savedVis.lastSavedTitle));
|
||||
|
||||
if (id !== visualizationIdFromUrl) {
|
||||
history.replace({
|
||||
|
|
|
@ -27,6 +27,7 @@ import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
|
|||
import { VisualizeServices } from '../../types';
|
||||
import { VisualizeConstants } from '../../visualize_constants';
|
||||
import { setDefaultEditor } from '../../../services';
|
||||
import { createEmbeddableStateTransferMock } from '../../../../../embeddable/public/mocks';
|
||||
|
||||
const mockDefaultEditorControllerDestroy = jest.fn();
|
||||
const mockEmbeddableHandlerDestroy = jest.fn();
|
||||
|
@ -52,7 +53,7 @@ jest.mock('../get_visualization_instance', () => ({
|
|||
getVisualizationInstance: jest.fn(() => mockSavedVisInstance),
|
||||
}));
|
||||
jest.mock('../breadcrumbs', () => ({
|
||||
getEditBreadcrumbs: jest.fn((text) => text),
|
||||
getEditBreadcrumbs: jest.fn((args, title) => title),
|
||||
getCreateBreadcrumbs: jest.fn((text) => text),
|
||||
}));
|
||||
|
||||
|
@ -81,12 +82,15 @@ describe('useSavedVisInstance', () => {
|
|||
mockServices = ({
|
||||
...coreStartMock,
|
||||
toastNotifications,
|
||||
stateTransferService: createEmbeddableStateTransferMock(),
|
||||
chrome: { setBreadcrumbs: jest.fn(), docTitle: { change: jest.fn() } },
|
||||
history: {
|
||||
location: {
|
||||
pathname: VisualizeConstants.EDIT_PATH,
|
||||
},
|
||||
replace: () => {},
|
||||
},
|
||||
dashboard: { dashboardFeatureFlagConfig: { allowByValueEmbeddables: false } },
|
||||
visualizations: {
|
||||
all: jest.fn(() => [
|
||||
{
|
||||
|
@ -111,7 +115,7 @@ describe('useSavedVisInstance', () => {
|
|||
|
||||
test('should not load instance until chrome is defined', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useSavedVisInstance(mockServices, eventEmitter, undefined, undefined)
|
||||
useSavedVisInstance(mockServices, eventEmitter, undefined, undefined, undefined)
|
||||
);
|
||||
expect(mockGetVisualizationInstance).not.toHaveBeenCalled();
|
||||
expect(result.current.visEditorController).toBeUndefined();
|
||||
|
@ -122,7 +126,7 @@ describe('useSavedVisInstance', () => {
|
|||
describe('edit saved visualization route', () => {
|
||||
test('should load instance and initiate an editor if chrome is set up', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useSavedVisInstance(mockServices, eventEmitter, true, savedVisId)
|
||||
useSavedVisInstance(mockServices, eventEmitter, true, undefined, savedVisId)
|
||||
);
|
||||
|
||||
result.current.visEditorRef.current = document.createElement('div');
|
||||
|
@ -131,7 +135,11 @@ describe('useSavedVisInstance', () => {
|
|||
|
||||
await waitForNextUpdate();
|
||||
expect(mockServices.chrome.setBreadcrumbs).toHaveBeenCalledWith('Test Vis');
|
||||
expect(getEditBreadcrumbs).toHaveBeenCalledWith('Test Vis');
|
||||
expect(mockServices.chrome.docTitle.change).toHaveBeenCalledWith('Test Vis');
|
||||
expect(getEditBreadcrumbs).toHaveBeenCalledWith(
|
||||
{ originatingAppName: undefined, redirectToOrigin: undefined },
|
||||
'Test Vis'
|
||||
);
|
||||
expect(getCreateBreadcrumbs).not.toHaveBeenCalled();
|
||||
expect(mockEmbeddableHandlerRender).not.toHaveBeenCalled();
|
||||
expect(result.current.visEditorController).toBeDefined();
|
||||
|
@ -140,7 +148,7 @@ describe('useSavedVisInstance', () => {
|
|||
|
||||
test('should destroy the editor and the savedVis on unmount if chrome exists', async () => {
|
||||
const { result, unmount, waitForNextUpdate } = renderHook(() =>
|
||||
useSavedVisInstance(mockServices, eventEmitter, true, savedVisId)
|
||||
useSavedVisInstance(mockServices, eventEmitter, true, undefined, savedVisId)
|
||||
);
|
||||
|
||||
result.current.visEditorRef.current = document.createElement('div');
|
||||
|
@ -167,7 +175,7 @@ describe('useSavedVisInstance', () => {
|
|||
|
||||
test('should create new visualization based on search params', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useSavedVisInstance(mockServices, eventEmitter, true, undefined)
|
||||
useSavedVisInstance(mockServices, eventEmitter, true, undefined, undefined)
|
||||
);
|
||||
|
||||
result.current.visEditorRef.current = document.createElement('div');
|
||||
|
@ -191,7 +199,7 @@ describe('useSavedVisInstance', () => {
|
|||
search: '?type=myVisType&indexPattern=1a2b3c4d',
|
||||
};
|
||||
|
||||
renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined));
|
||||
renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined, undefined));
|
||||
|
||||
expect(mockGetVisualizationInstance).not.toHaveBeenCalled();
|
||||
expect(redirectWhenMissing).toHaveBeenCalled();
|
||||
|
@ -204,7 +212,7 @@ describe('useSavedVisInstance', () => {
|
|||
search: '?type=area',
|
||||
};
|
||||
|
||||
renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined));
|
||||
renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined, undefined));
|
||||
|
||||
expect(mockGetVisualizationInstance).not.toHaveBeenCalled();
|
||||
expect(redirectWhenMissing).toHaveBeenCalled();
|
||||
|
@ -215,7 +223,7 @@ describe('useSavedVisInstance', () => {
|
|||
describe('embeded mode', () => {
|
||||
test('should create new visualization based on search params', async () => {
|
||||
const { result, unmount, waitForNextUpdate } = renderHook(() =>
|
||||
useSavedVisInstance(mockServices, eventEmitter, false, savedVisId)
|
||||
useSavedVisInstance(mockServices, eventEmitter, false, undefined, savedVisId)
|
||||
);
|
||||
|
||||
// mock editor ref
|
||||
|
|
|
@ -38,6 +38,7 @@ export const useSavedVisInstance = (
|
|||
services: VisualizeServices,
|
||||
eventEmitter: EventEmitter,
|
||||
isChromeVisible: boolean | undefined,
|
||||
originatingApp: string | undefined,
|
||||
visualizationIdFromUrl: string | undefined
|
||||
) => {
|
||||
const [state, setState] = useState<{
|
||||
|
@ -49,12 +50,14 @@ export const useSavedVisInstance = (
|
|||
|
||||
useEffect(() => {
|
||||
const {
|
||||
application: { navigateToApp },
|
||||
chrome,
|
||||
history,
|
||||
http: { basePath },
|
||||
dashboard,
|
||||
setActiveUrl,
|
||||
toastNotifications,
|
||||
http: { basePath },
|
||||
stateTransferService,
|
||||
application: { navigateToApp },
|
||||
} = services;
|
||||
const getSavedVisInstance = async () => {
|
||||
try {
|
||||
|
@ -93,11 +96,25 @@ export const useSavedVisInstance = (
|
|||
|
||||
const { embeddableHandler, savedVis, vis } = savedVisInstance;
|
||||
|
||||
const originatingAppName = originatingApp
|
||||
? stateTransferService.getAppNameFromId(originatingApp)
|
||||
: undefined;
|
||||
const redirectToOrigin = originatingApp ? () => navigateToApp(originatingApp) : undefined;
|
||||
const byValueCreateMode = dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables;
|
||||
|
||||
if (savedVis.id) {
|
||||
chrome.setBreadcrumbs(getEditBreadcrumbs(savedVis.title));
|
||||
chrome.setBreadcrumbs(
|
||||
getEditBreadcrumbs({ originatingAppName, redirectToOrigin }, savedVis.title)
|
||||
);
|
||||
chrome.docTitle.change(savedVis.title);
|
||||
} else {
|
||||
chrome.setBreadcrumbs(getCreateBreadcrumbs());
|
||||
chrome.setBreadcrumbs(
|
||||
getCreateBreadcrumbs({
|
||||
byValue: byValueCreateMode,
|
||||
originatingAppName,
|
||||
redirectToOrigin,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
let visEditorController;
|
||||
|
@ -174,6 +191,7 @@ export const useSavedVisInstance = (
|
|||
}, [
|
||||
eventEmitter,
|
||||
isChromeVisible,
|
||||
originatingApp,
|
||||
services,
|
||||
state.savedVisInstance,
|
||||
state.visEditorController,
|
||||
|
|
|
@ -22,7 +22,7 @@ import { useEffect, useRef, useState } from 'react';
|
|||
import { VisualizeInput } from 'src/plugins/visualizations/public';
|
||||
import { ByValueVisInstance, IEditorController, VisualizeServices } from '../../types';
|
||||
import { getVisualizationInstanceFromInput } from '../get_visualization_instance';
|
||||
import { getBreadcrumbsPrefixedWithApp, getEditBreadcrumbs } from '../breadcrumbs';
|
||||
import { getEditBreadcrumbs } from '../breadcrumbs';
|
||||
import { getDefaultEditor } from '../../../services';
|
||||
|
||||
export const useVisByValue = (
|
||||
|
@ -39,7 +39,11 @@ export const useVisByValue = (
|
|||
const visEditorRef = useRef<HTMLDivElement>(null);
|
||||
const loaded = useRef(false);
|
||||
useEffect(() => {
|
||||
const { chrome } = services;
|
||||
const {
|
||||
chrome,
|
||||
application: { navigateToApp },
|
||||
stateTransferService,
|
||||
} = services;
|
||||
const getVisInstance = async () => {
|
||||
if (!valueInput || loaded.current || !visEditorRef.current) {
|
||||
return;
|
||||
|
@ -55,11 +59,13 @@ export const useVisByValue = (
|
|||
embeddableHandler
|
||||
);
|
||||
|
||||
if (chrome && originatingApp) {
|
||||
chrome.setBreadcrumbs(getBreadcrumbsPrefixedWithApp(originatingApp));
|
||||
} else if (chrome) {
|
||||
chrome.setBreadcrumbs(getEditBreadcrumbs());
|
||||
}
|
||||
const originatingAppName = originatingApp
|
||||
? stateTransferService.getAppNameFromId(originatingApp)
|
||||
: undefined;
|
||||
const redirectToOrigin = originatingApp ? () => navigateToApp(originatingApp) : undefined;
|
||||
chrome?.setBreadcrumbs(
|
||||
getEditBreadcrumbs({ byValue: true, originatingAppName, redirectToOrigin })
|
||||
);
|
||||
|
||||
loaded.current = true;
|
||||
setState({
|
||||
|
|
|
@ -202,6 +202,7 @@ export class VisualizePlugin
|
|||
visualizeCapabilities: coreStart.application.capabilities.visualize,
|
||||
visualizations: pluginsStart.visualizations,
|
||||
embeddable: pluginsStart.embeddable,
|
||||
stateTransferService: pluginsStart.embeddable.getStateTransfer(),
|
||||
setActiveUrl,
|
||||
createVisEmbeddableFromObject:
|
||||
pluginsStart.visualizations.__LEGACY.createVisEmbeddableFromObject,
|
||||
|
|
|
@ -25,7 +25,6 @@ export function HeaderPageProvider({ getService, getPageObjects }: FtrProviderCo
|
|||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const globalNav = getService('globalNav');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
|
||||
const defaultFindTimeout = config.get('timeouts.find');
|
||||
|
@ -42,14 +41,9 @@ export function HeaderPageProvider({ getService, getPageObjects }: FtrProviderCo
|
|||
await appsMenu.clickLink('Visualize', { category: 'kibana' });
|
||||
await this.onAppLeaveWarning(ignoreAppLeaveWarning);
|
||||
await this.awaitGlobalLoadingIndicatorHidden();
|
||||
await retry.waitFor('first breadcrumb to be "Visualize"', async () => {
|
||||
const firstBreadcrumb = await globalNav.getFirstBreadcrumb();
|
||||
if (firstBreadcrumb !== 'Visualize') {
|
||||
log.debug('-- first breadcrumb =', firstBreadcrumb);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
await retry.waitFor('Visualize app to be loaded', async () => {
|
||||
const isNavVisible = await testSubjects.exists('top-nav');
|
||||
return isNavVisible;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4518,7 +4518,6 @@
|
|||
"visualize.createVisualization.failedToLoadErrorMessage": "ビジュアライゼーションを読み込めませんでした",
|
||||
"visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "indexPatternまたはsavedSearchIdが必要です",
|
||||
"visualize.createVisualization.noVisTypeErrorMessage": "有効なビジュアライゼーションタイプを指定してください",
|
||||
"visualize.dashboard.prefix.breadcrumb": "ダッシュボード",
|
||||
"visualize.discover.visualizeFieldLabel": "Visualizeフィールド",
|
||||
"visualize.editor.createBreadcrumb": "作成",
|
||||
"visualize.editor.defaultEditBreadcrumbText": "編集",
|
||||
|
|
|
@ -4520,7 +4520,6 @@
|
|||
"visualize.createVisualization.failedToLoadErrorMessage": "无法加载可视化",
|
||||
"visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "必须提供 indexPattern 或 savedSearchId",
|
||||
"visualize.createVisualization.noVisTypeErrorMessage": "必须提供有效的可视化类型",
|
||||
"visualize.dashboard.prefix.breadcrumb": "仪表板",
|
||||
"visualize.discover.visualizeFieldLabel": "可视化字段",
|
||||
"visualize.editor.createBreadcrumb": "创建",
|
||||
"visualize.editor.defaultEditBreadcrumbText": "编辑",
|
||||
|
|
Loading…
Reference in a new issue