Skip to content

Commit

Permalink
[Logs UI] Make URL syncing optional in the Log View state machine (#1…
Browse files Browse the repository at this point in the history
…54061)

## Summary

This fixes #154030 (and other
uses of the Log Stream embeddable component).

The embeddable component calls `useLogView()` directly, and this causes
issues with context dependencies for URL syncing from the consumers.

This PR makes the URL actions / services optional within the machine. 

Uses:

- `<LogViewProvider />` used for all main Logs pages (stream, anomalies,
categories) has full URL syncing ✅
- `<LogViewProvider />` used within our Logs alert editor does not have
URL syncing (not needed) ❌
- `useLogView()` as used by the embeddable component does not have URL
syncing ❌
- `useLogView()` as used by `RedirectToNodeLogs` does not have URL
syncing (not needed, URL syncing kicks in after redirect) ❌

The default / pure implementation of `initializeFromUrl` just does a
`send({ type: 'INITIALIZED_FROM_URL', logViewReference: null })` as the
state machine needs to transition to it's `initialized` state and is
already set up to use the initial context reference if there's no
reference obtained from the URL.

Examples:

![Screenshot 2023-03-30 at 15 23
48](https://user-images.githubusercontent.com/471693/228867868-b526c4b2-bec8-47cb-8e7c-c3da2dd6c803.png)

![Screenshot 2023-03-30 at 15 24
39](https://user-images.githubusercontent.com/471693/228867889-c7451f84-415c-45f9-ae96-e6908d60409c.png)
  • Loading branch information
Kerry350 authored Mar 31, 2023
1 parent a77ece2 commit 6842039
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 27 deletions.
26 changes: 14 additions & 12 deletions x-pack/plugins/infra/public/hooks/use_log_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,34 @@ import createContainer from 'constate';
import { useCallback, useState } from 'react';
import { waitFor } from 'xstate/lib/waitFor';
import { LogViewAttributes, LogViewReference } from '../../common/log_views';
import {
InitializeFromUrl,
UpdateContextInUrl,
ListenForUrlChanges,
} from '../observability_logs/log_view_state/src/url_state_storage_service';
import {
createLogViewNotificationChannel,
createLogViewStateMachine,
DEFAULT_LOG_VIEW,
} from '../observability_logs/log_view_state';
import type { ILogViewsClient } from '../services/log_views';
import { isDevMode } from '../utils/dev_mode';
import { useKbnUrlStateStorageFromRouterContext } from '../utils/kbn_url_state_context';
import { useKibanaContextForPlugin } from './use_kibana';

export const useLogView = ({
initialLogViewReference,
logViews,
useDevTools = isDevMode(),
initializeFromUrl,
updateContextInUrl,
listenForUrlChanges,
}: {
initialLogViewReference?: LogViewReference;
logViews: ILogViewsClient;
useDevTools?: boolean;
initializeFromUrl?: InitializeFromUrl;
updateContextInUrl?: UpdateContextInUrl;
listenForUrlChanges?: ListenForUrlChanges;
}) => {
const {
services: {
notifications: { toasts: toastsService },
},
} = useKibanaContextForPlugin();

const urlStateStorage = useKbnUrlStateStorageFromRouterContext();

const [logViewStateNotifications] = useState(() => createLogViewNotificationChannel());

const logViewStateService = useInterpret(
Expand All @@ -47,8 +48,9 @@ export const useLogView = ({
},
logViews,
notificationChannel: logViewStateNotifications,
toastsService,
urlStateStorage,
initializeFromUrl,
updateContextInUrl,
listenForUrlChanges,
}),
{
devTools: useDevTools,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
* 2.0.
*/

import { IToasts } from '@kbn/core/public';
import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public';
import { catchError, from, map, of, throwError } from 'rxjs';
import { createMachine, actions, assign } from 'xstate';
import { ILogViewsClient } from '../../../services/log_views';
Expand All @@ -23,9 +21,9 @@ import {
LogViewTypestate,
} from './types';
import {
initializeFromUrl,
updateContextInUrl,
listenForUrlChanges,
InitializeFromUrl,
UpdateContextInUrl,
ListenForUrlChanges,
} from './url_state_storage_service';

export const createPureLogViewStateMachine = (initialContext: LogViewContextWithReference) =>
Expand Down Expand Up @@ -223,6 +221,7 @@ export const createPureLogViewStateMachine = (initialContext: LogViewContextWith
notifyLoadingStarted: actions.pure(() => undefined),
notifyLoadingSucceeded: actions.pure(() => undefined),
notifyLoadingFailed: actions.pure(() => undefined),
updateContextInUrl: actions.pure(() => undefined),
storeLogViewReference: assign((context, event) =>
'logViewReference' in event && event.logViewReference !== null
? ({
Expand Down Expand Up @@ -282,6 +281,11 @@ export const createPureLogViewStateMachine = (initialContext: LogViewContextWith
: {}
),
},
services: {
initializeFromUrl: (_context, _event) => (send) =>
send({ type: 'INITIALIZED_FROM_URL', logViewReference: null }),
listenForUrlChanges: (_context, _event) => (send) => {},
},
guards: {
isPersistedLogView: (context, event) =>
context.logViewReference.type === 'log-view-reference',
Expand All @@ -293,16 +297,18 @@ export interface LogViewStateMachineDependencies {
initialContext: LogViewContextWithReference;
logViews: ILogViewsClient;
notificationChannel?: NotificationChannel<LogViewContext, LogViewEvent, LogViewNotificationEvent>;
toastsService: IToasts;
urlStateStorage: IKbnUrlStateStorage;
initializeFromUrl?: InitializeFromUrl;
updateContextInUrl?: UpdateContextInUrl;
listenForUrlChanges?: ListenForUrlChanges;
}

export const createLogViewStateMachine = ({
initialContext,
logViews,
notificationChannel,
toastsService,
urlStateStorage,
initializeFromUrl,
updateContextInUrl,
listenForUrlChanges,
}: LogViewStateMachineDependencies) =>
createPureLogViewStateMachine(initialContext).withConfig({
actions: {
Expand All @@ -319,11 +325,11 @@ export const createLogViewStateMachine = ({
),
}
: {}),
updateContextInUrl: updateContextInUrl({ toastsService, urlStateStorage }),
...(updateContextInUrl ? { updateContextInUrl } : {}),
},
services: {
initializeFromUrl: initializeFromUrl({ toastsService, urlStateStorage }),
listenForUrlChanges: listenForUrlChanges({ urlStateStorage }),
...(initializeFromUrl ? { initializeFromUrl } : {}),
...(listenForUrlChanges ? { listenForUrlChanges } : {}),
loadLogView: (context) =>
from(
'logViewReference' in context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,7 @@ const convertSourceIdToReference = (sourceId: string): PersistedLogViewReference
// NOTE: Used by link-to components
export const replaceLogViewInQueryString = (logViewReference: LogViewReference) =>
replaceStateKeyInQueryString(defaultLogViewKey, logViewReference);

export type InitializeFromUrl = ReturnType<typeof initializeFromUrl>;
export type UpdateContextInUrl = ReturnType<typeof updateContextInUrl>;
export type ListenForUrlChanges = ReturnType<typeof listenForUrlChanges>;
34 changes: 31 additions & 3 deletions x-pack/plugins/infra/public/pages/logs/page_providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,44 @@
* 2.0.
*/

import React from 'react';
import React, { useState } from 'react';
import { LogAnalysisCapabilitiesProvider } from '../../containers/logs/log_analysis';
import { useKibanaContextForPlugin } from '../../hooks/use_kibana';
import { LogViewProvider } from '../../hooks/use_log_view';
import {
initializeFromUrl as createInitializeFromUrl,
updateContextInUrl as createUpdateContextInUrl,
listenForUrlChanges as createListenForUrlChanges,
} from '../../observability_logs/log_view_state/src/url_state_storage_service';
import { useKbnUrlStateStorageFromRouterContext } from '../../utils/kbn_url_state_context';

export const LogsPageProviders: React.FunctionComponent = ({ children }) => {
const { services } = useKibanaContextForPlugin();
const {
services: {
notifications: { toasts: toastsService },
logViews: { client },
},
} = useKibanaContextForPlugin();

const urlStateStorage = useKbnUrlStateStorageFromRouterContext();

const [initializeFromUrl] = useState(() => {
return createInitializeFromUrl({ toastsService, urlStateStorage });
});
const [updateContextInUrl] = useState(() => {
return createUpdateContextInUrl({ toastsService, urlStateStorage });
});
const [listenForUrlChanges] = useState(() => {
return createListenForUrlChanges({ urlStateStorage });
});

return (
<LogViewProvider logViews={services.logViews.client}>
<LogViewProvider
logViews={client}
initializeFromUrl={initializeFromUrl}
updateContextInUrl={updateContextInUrl}
listenForUrlChanges={listenForUrlChanges}
>
<LogAnalysisCapabilitiesProvider>{children}</LogAnalysisCapabilitiesProvider>
</LogViewProvider>
);
Expand Down

0 comments on commit 6842039

Please sign in to comment.