Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

export const LATEST_VERSION = 1;
export const DASHBOARD_API_VERSION = String(LATEST_VERSION);

export const CONTENT_ID = 'dashboard';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { DASHBOARD_APP_ID } from '../../common/constants';
import { getReferencesForControls, getReferencesForPanelId } from '../../common';
import type { DashboardState } from '../../common/types';
import { getDashboardContentManagementService } from '../services/dashboard_content_management_service';
import type { LoadDashboardReturn } from '../services/dashboard_content_management_service/types';
import {
CONTROL_GROUP_EMBEDDABLE_ID,
initializeControlGroupManager,
Expand All @@ -38,6 +37,7 @@ import { initializeUnifiedSearchManager } from './unified_search_manager';
import { initializeUnsavedChangesManager } from './unsaved_changes_manager';
import { initializeViewModeManager } from './view_mode_manager';
import { mergeControlGroupStates } from './merge_control_group_states';
import type { DashboardAPIGetOut } from '../../server/content_management';

export function getDashboardApi({
creationOptions,
Expand All @@ -49,15 +49,19 @@ export function getDashboardApi({
creationOptions?: DashboardCreationOptions;
incomingEmbeddables?: EmbeddablePackageState[] | undefined;
initialState: DashboardState;
savedObjectResult?: LoadDashboardReturn;
savedObjectResult?: DashboardAPIGetOut;
savedObjectId?: string;
}) {
const fullScreenMode$ = new BehaviorSubject(creationOptions?.fullScreenMode ?? false);
const isManaged = savedObjectResult?.managed ?? false;
const isManaged = savedObjectResult?.meta.managed ?? false;
const savedObjectId$ = new BehaviorSubject<string | undefined>(savedObjectId);
const dashboardContainerRef$ = new BehaviorSubject<HTMLElement | null>(null);

const viewModeManager = initializeViewModeManager(incomingEmbeddables, savedObjectResult);
const viewModeManager = initializeViewModeManager({
incomingEmbeddables,
isManaged,
savedObjectId,
});
const trackPanel = initializeTrackPanel(async (id: string) => {
await layoutManager.api.getChildApi(id);
}, dashboardContainerRef$);
Expand Down Expand Up @@ -108,7 +112,7 @@ export function getDashboardApi({
viewMode$: viewModeManager.api.viewMode$,
storeUnsavedChanges: creationOptions?.useSessionStorageIntegration,
controlGroupManager,
lastSavedState: savedObjectResult?.dashboardInput ?? DEFAULT_DASHBOARD_STATE,
lastSavedState: savedObjectResult?.data ?? DEFAULT_DASHBOARD_STATE,
layoutManager,
savedObjectId$,
settingsManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
*/

import { ContentInsightsClient } from '@kbn/content-management-content-insights-public';
import type { DashboardState } from '../../../common';
import { getDashboardBackupService } from '../../services/dashboard_backup_service';
import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service';
import { coreServices } from '../../services/kibana_services';
import { logger } from '../../services/logger';
import { getDashboardApi } from '../get_dashboard_api';
import { startQueryPerformanceTracking } from '../performance/query_performance_tracking';
import type { DashboardCreationOptions } from '../types';
import { transformPanels } from './transform_panels';
import { dashboardClient } from '../../dashboard_client/dashboard_client';
import { DEFAULT_DASHBOARD_STATE } from '../default_dashboard_state';

export async function loadDashboardApi({
getCreationOptions,
Expand All @@ -28,13 +28,8 @@ export async function loadDashboardApi({
const creationStartTime = performance.now();
const creationOptions = await getCreationOptions?.();
const incomingEmbeddables = creationOptions?.getIncomingEmbeddables?.();
const savedObjectResult = await getDashboardContentManagementService().loadDashboardState({
id: savedObjectId,
});
const savedObjectResult = savedObjectId ? await dashboardClient.get(savedObjectId) : undefined;

// --------------------------------------------------------------------------------------
// Run validation.
// --------------------------------------------------------------------------------------
const validationResult =
savedObjectResult && creationOptions?.validateLoadedSavedObject?.(savedObjectResult);
if (validationResult === 'invalid') {
Expand All @@ -44,25 +39,10 @@ export async function loadDashboardApi({
return;
}

// --------------------------------------------------------------------------------------
// Combine saved object state and session storage state
// --------------------------------------------------------------------------------------
const sessionStorageInput = ((): Partial<DashboardState> | undefined => {
if (!creationOptions?.useSessionStorageIntegration) return;
return getDashboardBackupService().getState(savedObjectResult.dashboardId);
})();
const unsavedChanges = creationOptions?.useSessionStorageIntegration
? getDashboardBackupService().getState(savedObjectId)
: undefined;

const combinedSessionState: DashboardState = {
...(savedObjectResult?.dashboardInput ?? {}),
...sessionStorageInput,
};
combinedSessionState.references = sessionStorageInput?.references?.length
? sessionStorageInput?.references
: savedObjectResult?.references;

// --------------------------------------------------------------------------------------
// Combine state with overrides.
// --------------------------------------------------------------------------------------
const { viewMode, ...overrideState } = creationOptions?.getInitialInput?.() ?? {};
if (overrideState.panels) {
overrideState.panels = await transformPanels(overrideState.panels, overrideState.references);
Expand All @@ -80,7 +60,9 @@ export async function loadDashboardApi({
creationOptions,
incomingEmbeddables,
initialState: {
...combinedSessionState,
...DEFAULT_DASHBOARD_STATE,
...savedObjectResult?.data,
...unsavedChanges,
...overrideState,
},
savedObjectResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import {
} from '../../services/kibana_services';
import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service';
import type { DashboardState } from '../../../common';
import { DASHBOARD_CONTENT_ID, SAVED_OBJECT_POST_TIME } from '../../utils/telemetry_constants';
import { SAVED_OBJECT_POST_TIME } from '../../utils/telemetry_constants';
import { extractTitleAndCount } from '../../utils/extract_title_and_count';
import { DashboardSaveModal } from './save_modal';
import { CONTENT_ID } from '../../../common/content_management';

/**
* @description exclusively for user directed dashboard save actions, also
Expand Down Expand Up @@ -117,7 +118,7 @@ export async function openSaveModal({
eventName: SAVED_OBJECT_POST_TIME,
duration: addDuration,
meta: {
saved_object_type: DASHBOARD_CONTENT_ID,
saved_object_type: CONTENT_ID,
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,8 @@ import type { ControlsGroupState } from '@kbn/controls-schemas';
import type { LocatorPublic } from '@kbn/share-plugin/common';
import type { BehaviorSubject, Observable, Subject } from 'rxjs';
import type { DashboardLocatorParams } from '../../common';
import type { DashboardState, GridData } from '../../server/content_management';
import type {
LoadDashboardReturn,
SaveDashboardReturn,
} from '../services/dashboard_content_management_service/types';
import type { DashboardAPIGetOut, DashboardState, GridData } from '../../server/content_management';
import type { SaveDashboardReturn } from '../services/dashboard_content_management_service/types';
import type { DashboardLayout } from './layout_manager/types';
import type { DashboardSettings } from './settings_manager';

Expand Down Expand Up @@ -87,7 +84,7 @@ export interface DashboardCreationOptions {
useUnifiedSearchIntegration?: boolean;
unifiedSearchSettings?: { kbnUrlStateStorage: IKbnUrlStateStorage };

validateLoadedSavedObject?: (result: LoadDashboardReturn) => 'valid' | 'invalid' | 'redirected';
validateLoadedSavedObject?: (result: DashboardAPIGetOut) => 'valid' | 'invalid' | 'redirected';

fullScreenMode?: boolean;
isEmbeddedExternally?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,28 @@
import type { EmbeddablePackageState } from '@kbn/embeddable-plugin/public';
import type { ViewMode } from '@kbn/presentation-publishing';
import { BehaviorSubject } from 'rxjs';
import type { LoadDashboardReturn } from '../services/dashboard_content_management_service/types';
import { getDashboardBackupService } from '../services/dashboard_backup_service';
import { getDashboardCapabilities } from '../utils/get_dashboard_capabilities';

export function initializeViewModeManager(
incomingEmbeddables?: EmbeddablePackageState[],
savedObjectResult?: LoadDashboardReturn
) {
export function initializeViewModeManager({
incomingEmbeddables,
isManaged,
savedObjectId,
}: {
incomingEmbeddables?: EmbeddablePackageState[];
isManaged: boolean;
savedObjectId?: string;
}) {
const dashboardBackupService = getDashboardBackupService();
function getInitialViewMode() {
if (savedObjectResult?.managed || !getDashboardCapabilities().showWriteControls) {
if (isManaged || !getDashboardCapabilities().showWriteControls) {
return 'view';
}

if (
incomingEmbeddables?.length ||
savedObjectResult?.newDashboardCreated ||
dashboardBackupService.dashboardHasUnsavedEdits(savedObjectResult?.dashboardId)
!Boolean(savedObjectId) ||
dashboardBackupService.dashboardHasUnsavedEdits(savedObjectId)
)
return 'edit';

Expand All @@ -38,7 +42,7 @@ export function initializeViewModeManager(

function setViewMode(viewMode: ViewMode) {
// block the Dashboard from entering edit mode if this Dashboard is managed.
if (savedObjectResult?.managed && viewMode?.toLowerCase() === 'edit') {
if (isManaged && viewMode?.toLowerCase() === 'edit') {
return;
}
viewMode$.next(viewMode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import { useCallback, useMemo, useState } from 'react';

import type { DashboardCreationOptions } from '../..';
import { createDashboardEditUrl } from '../../utils/urls';
import type { LoadDashboardReturn } from '../../services/dashboard_content_management_service/types';
import { screenshotModeService, spacesService } from '../../services/kibana_services';
import { useDashboardMountContext } from './dashboard_mount_context';
import type { DashboardAPIGetOut } from '../../../server/content_management';

export const useDashboardOutcomeValidation = () => {
const [aliasId, setAliasId] = useState<string>();
Expand All @@ -24,29 +24,19 @@ export const useDashboardOutcomeValidation = () => {
const scopedHistory = getScopedHistory?.();

const validateOutcome: DashboardCreationOptions['validateLoadedSavedObject'] = useCallback(
({ dashboardFound, resolveMeta, dashboardId }: LoadDashboardReturn) => {
if (!dashboardFound) {
return 'invalid';
}

if (resolveMeta && dashboardId) {
const { outcome: loadOutcome, aliasTargetId: alias, aliasPurpose } = resolveMeta;
/**
* Handle saved object resolve alias outcome by redirecting.
*/
if (loadOutcome === 'aliasMatch' && dashboardId && alias) {
const path = scopedHistory.location.hash.replace(dashboardId, alias);
if (screenshotModeService.isScreenshotMode()) {
scopedHistory.replace(path); // redirect without the toast when in screenshot mode.
} else {
spacesService?.ui.redirectLegacyUrl({ path, aliasPurpose });
}
return 'redirected'; // redirected. Stop loading dashboard.
(result: DashboardAPIGetOut) => {
if (result.meta.outcome === 'aliasMatch' && result.meta.aliasTargetId) {
const path = scopedHistory.location.hash.replace(result.id, result.meta.aliasTargetId);
if (screenshotModeService.isScreenshotMode()) {
scopedHistory.replace(path); // redirect without the toast when in screenshot mode.
} else {
spacesService?.ui.redirectLegacyUrl({ path, aliasPurpose: result.meta.aliasPurpose });
}
setAliasId(alias);
setOutcome(loadOutcome);
setSavedObjectId(dashboardId);
return 'redirected'; // redirected. Stop loading dashboard.
}
setAliasId(result.meta.aliasTargetId);
setOutcome(result.meta.outcome);
setSavedObjectId(result.id);
return 'valid';
},
[scopedHistory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import {
isDashboardAppInNoDataState,
} from '../no_data/dashboard_app_no_data';
import { getDashboardListItemLink } from './get_dashboard_list_item_link';
import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service';
import type { DashboardRedirect } from '../types';
import { findService } from '../../dashboard_client';

export interface DashboardListingPageProps {
kbnUrlStateStorage: IKbnUrlStateStorage;
Expand Down Expand Up @@ -74,16 +74,14 @@ export const DashboardListingPage = ({
kbnUrlStateStorage
);
if (title) {
getDashboardContentManagementService()
.findDashboards.findByTitle(title)
.then((result) => {
if (!result) return;
redirectTo({
destination: 'dashboard',
id: result.id,
useReplace: true,
});
findService.findByTitle(title).then((result) => {
if (!result) return;
redirectTo({
destination: 'dashboard',
id: result.id,
useReplace: true,
});
});
}

return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
lensService,
} from '../../services/kibana_services';
import { getDashboardBackupService } from '../../services/dashboard_backup_service';
import { getDashboardContentManagementService } from '../../services/dashboard_content_management_service';
import { dashboardClient } from '../../dashboard_client/dashboard_client';

export const DashboardAppNoDataPage = ({
onDataViewCreated,
Expand Down Expand Up @@ -153,8 +153,8 @@ export const isDashboardAppInNoDataState = async () => {
if (getDashboardBackupService().dashboardHasUnsavedEdits()) return false;

// consider has data if there is at least one dashboard
const { total } = await getDashboardContentManagementService()
.findDashboards.search({ search: '', size: 1 })
const { total } = await dashboardClient
.search({ search: '', size: 1 })
.catch(() => ({ total: 0 }));
if (total > 0) return false;

Expand Down
Loading