Skip to content

Commit 319b5a2

Browse files
authored
[Feature Anywhere] Add view events flyout (#3415)
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent 66070aa commit 319b5a2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2324
-197
lines changed

src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ interface Props {
8383
SavedObjectFinder: React.ComponentType<any>;
8484
stateTransfer?: EmbeddableStateTransfer;
8585
hideHeader?: boolean;
86+
hasBorder?: boolean;
87+
hasShadow?: boolean;
8688
}
8789

8890
interface State {
@@ -234,6 +236,8 @@ export class EmbeddablePanel extends React.Component<Props, State> {
234236
paddingSize="none"
235237
role="figure"
236238
aria-labelledby={headerId}
239+
hasBorder={this.props.hasBorder}
240+
hasShadow={this.props.hasShadow}
237241
>
238242
{!this.props.hideHeader && (
239243
<PanelHeader

src/plugins/embeddable/public/plugin.tsx

+12-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,12 @@ export interface EmbeddableStart extends PersistableState<EmbeddableInput> {
107107
getStateTransfer: (history?: ScopedHistory) => EmbeddableStateTransfer;
108108
}
109109

110-
export type EmbeddablePanelHOC = React.FC<{ embeddable: IEmbeddable; hideHeader?: boolean }>;
110+
export type EmbeddablePanelHOC = React.FC<{
111+
embeddable: IEmbeddable;
112+
hideHeader?: boolean;
113+
hasBorder?: boolean;
114+
hasShadow?: boolean;
115+
}>;
111116

112117
export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, EmbeddableStart> {
113118
private readonly embeddableFactoryDefinitions: Map<
@@ -168,12 +173,18 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
168173
const getEmbeddablePanelHoc = (stateTransfer?: EmbeddableStateTransfer) => ({
169174
embeddable,
170175
hideHeader,
176+
hasBorder,
177+
hasShadow,
171178
}: {
172179
embeddable: IEmbeddable;
173180
hideHeader?: boolean;
181+
hasBorder?: boolean;
182+
hasShadow?: boolean;
174183
}) => (
175184
<EmbeddablePanel
176185
hideHeader={hideHeader}
186+
hasBorder={hasBorder}
187+
hasShadow={hasShadow}
177188
embeddable={embeddable}
178189
stateTransfer={stateTransfer ? stateTransfer : this.outgoingOnlyStateTransfer}
179190
getActions={uiActions.getTriggerCompatibleActions}

src/plugins/vis_augmenter/opensearch_dashboards.json

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,14 @@
33
"version": "opensearchDashboards",
44
"server": true,
55
"ui": true,
6-
"requiredPlugins": ["data", "savedObjects", "opensearchDashboardsUtils", "expressions"]
6+
"requiredPlugins": [
7+
"data",
8+
"savedObjects",
9+
"opensearchDashboardsUtils",
10+
"expressions",
11+
"visualizations",
12+
"uiActions",
13+
"embeddable"
14+
],
15+
"requiredBundles": ["opensearchDashboardsReact"]
716
}

src/plugins/vis_augmenter/public/constants.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
*/
55

66
export const VIS_LAYER_COLUMN_TYPE = 'vis_layer';
7-
// TODO: replace with a value imported from OUI
87
export const EVENT_COLOR = 'red';
98
export const HOVER_PARAM = 'HOVER';
10-
export const EVENT_MARK_SIZE = 100;
11-
export const EVENT_MARK_SIZE_ENLARGED = 140;
9+
export const EVENT_MARK_SIZE = 40;
10+
export const EVENT_MARK_SIZE_ENLARGED = 80;
1211
export const EVENT_MARK_SHAPE = 'triangle-up';
1312
export const EVENT_TIMELINE_HEIGHT = 25;
1413
export const EVENT_TOOLTIP_CENTER_ON_MARK = 5;

src/plugins/vis_augmenter/public/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ export {
2222
PointInTimeEventsVisLayer,
2323
isPointInTimeEventsVisLayer,
2424
isVisLayerWithError,
25+
VisAugmenterEmbeddableConfig,
26+
VisFlyoutContext,
2527
} from './types';
2628

29+
export { AugmentVisContext } from './ui_actions_bootstrap';
30+
2731
export * from './expressions';
2832
export * from './utils';
2933
export * from './constants';
+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { get } from 'lodash';
7+
import { VisualizeEmbeddable, Vis } from '../../visualizations/public';
8+
import { ErrorEmbeddable } from '../../embeddable/public';
9+
// eslint-disable-next-line @osd/eslint/no-restricted-paths
10+
import { timefilterServiceMock } from '../../data/public/query/timefilter/timefilter_service.mock';
11+
import { EventVisEmbeddableItem } from './view_events_flyout';
12+
import {
13+
VisLayer,
14+
VisLayerTypes,
15+
VisLayerErrorTypes,
16+
PointInTimeEventsVisLayer,
17+
PluginResource,
18+
PointInTimeEvent,
19+
} from './types';
20+
import { AggConfigs, AggTypesRegistryStart, IndexPattern } from '../../data/common';
21+
import { mockAggTypesRegistry } from '../../data/common/search/aggs/test_helpers';
22+
23+
export const VALID_CONFIG_STATES = [
24+
{
25+
enabled: true,
26+
type: 'max',
27+
params: {},
28+
schema: 'metric',
29+
},
30+
{
31+
enabled: true,
32+
type: 'date_histogram',
33+
params: {},
34+
schema: 'segment',
35+
},
36+
];
37+
38+
export const STUB_INDEX_PATTERN_WITH_FIELDS = {
39+
id: '1234',
40+
title: 'logstash-*',
41+
fields: [
42+
{
43+
name: 'response',
44+
type: 'number',
45+
esTypes: ['integer'],
46+
aggregatable: true,
47+
filterable: true,
48+
searchable: true,
49+
},
50+
],
51+
} as IndexPattern;
52+
53+
export const TYPES_REGISTRY: AggTypesRegistryStart = mockAggTypesRegistry();
54+
55+
export const VALID_AGGS = new AggConfigs(STUB_INDEX_PATTERN_WITH_FIELDS, VALID_CONFIG_STATES, {
56+
typesRegistry: TYPES_REGISTRY,
57+
});
58+
59+
export const VALID_VIS = ({
60+
type: {},
61+
uiState: {
62+
on: jest.fn(),
63+
},
64+
params: {
65+
type: 'line',
66+
seriesParams: [
67+
{
68+
type: 'line',
69+
},
70+
],
71+
categoryAxes: [
72+
{
73+
position: 'bottom',
74+
},
75+
],
76+
},
77+
data: {
78+
aggs: VALID_AGGS,
79+
},
80+
} as unknown) as Vis;
81+
82+
const SAVED_OBJ_ID = 'test-saved-obj-id';
83+
const VIS_TITLE = 'test-vis-title';
84+
const ORIGIN_PLUGIN = 'test-plugin';
85+
const PLUGIN_RESOURCE = {
86+
type: 'test-type',
87+
id: 'test-resource-id',
88+
name: 'test-resource-name',
89+
urlPath: 'test-url-path',
90+
} as PluginResource;
91+
const EVENT_COUNT = 3;
92+
const ERROR_MESSAGE = 'test-error-message';
93+
94+
export const createPluginResource = (
95+
type: string = PLUGIN_RESOURCE.type,
96+
id: string = PLUGIN_RESOURCE.id,
97+
name: string = PLUGIN_RESOURCE.name,
98+
urlPath: string = PLUGIN_RESOURCE.urlPath
99+
): PluginResource => {
100+
return {
101+
type,
102+
id,
103+
name,
104+
urlPath,
105+
};
106+
};
107+
108+
export const createMockErrorEmbeddable = (): ErrorEmbeddable => {
109+
return new ErrorEmbeddable('Oh no something has gone wrong', { id: ' 404' });
110+
};
111+
112+
export const createMockVisEmbeddable = (
113+
savedObjectId: string = SAVED_OBJ_ID,
114+
title: string = VIS_TITLE,
115+
validVis: boolean = true
116+
): VisualizeEmbeddable => {
117+
const mockTimeFilterService = timefilterServiceMock.createStartContract();
118+
const mockTimeFilter = mockTimeFilterService.timefilter;
119+
const mockVis = validVis
120+
? VALID_VIS
121+
: (({
122+
type: {},
123+
data: {},
124+
uiState: {
125+
on: jest.fn(),
126+
},
127+
params: {
128+
type: 'line',
129+
seriesParams: [],
130+
},
131+
} as unknown) as Vis);
132+
const mockDeps = {
133+
start: jest.fn(),
134+
};
135+
const mockConfiguration = {
136+
vis: mockVis,
137+
editPath: 'test-edit-path',
138+
editUrl: 'test-edit-url',
139+
editable: true,
140+
deps: mockDeps,
141+
};
142+
const mockVisualizeInput = { id: 'test-id', savedObjectId };
143+
144+
const mockVisEmbeddable = new VisualizeEmbeddable(
145+
mockTimeFilter,
146+
mockConfiguration,
147+
mockVisualizeInput
148+
);
149+
mockVisEmbeddable.getTitle = () => title;
150+
return mockVisEmbeddable;
151+
};
152+
153+
export const createPointInTimeEventsVisLayer = (
154+
originPlugin: string = ORIGIN_PLUGIN,
155+
pluginResource: PluginResource = PLUGIN_RESOURCE,
156+
eventCount: number = EVENT_COUNT,
157+
error: boolean = false,
158+
errorMessage: string = ERROR_MESSAGE
159+
): PointInTimeEventsVisLayer => {
160+
const events = [] as PointInTimeEvent[];
161+
for (let i = 0; i < eventCount; i++) {
162+
events.push({
163+
timestamp: i,
164+
metadata: {
165+
pluginResourceId: pluginResource.id,
166+
},
167+
} as PointInTimeEvent);
168+
}
169+
return {
170+
originPlugin,
171+
type: VisLayerTypes.PointInTimeEvents,
172+
pluginResource,
173+
events,
174+
error: error
175+
? {
176+
type: VisLayerErrorTypes.FETCH_FAILURE,
177+
message: errorMessage,
178+
}
179+
: undefined,
180+
};
181+
};
182+
183+
export const createMockEventVisEmbeddableItem = (
184+
savedObjectId: string = SAVED_OBJ_ID,
185+
title: string = VIS_TITLE,
186+
originPlugin: string = ORIGIN_PLUGIN,
187+
pluginResource: PluginResource = PLUGIN_RESOURCE,
188+
eventCount: number = EVENT_COUNT
189+
): EventVisEmbeddableItem => {
190+
const visLayer = createPointInTimeEventsVisLayer(originPlugin, pluginResource, eventCount);
191+
const embeddable = createMockVisEmbeddable(savedObjectId, title);
192+
return {
193+
visLayer,
194+
embeddable,
195+
};
196+
};
197+
198+
export const createVisLayer = (
199+
type: any,
200+
error: boolean = false,
201+
errorMessage: string = 'some-error-message',
202+
resource?: {
203+
type?: string;
204+
id?: string;
205+
name?: string;
206+
urlPath?: string;
207+
}
208+
): VisLayer => {
209+
return {
210+
type,
211+
originPlugin: 'test-plugin',
212+
pluginResource: {
213+
type: get(resource, 'type', 'test-resource-type'),
214+
id: get(resource, 'id', 'test-resource-id'),
215+
name: get(resource, 'name', 'test-resource-name'),
216+
urlPath: get(resource, 'urlPath', 'test-resource-url-path'),
217+
},
218+
error: error
219+
? {
220+
type: VisLayerErrorTypes.FETCH_FAILURE,
221+
message: errorMessage,
222+
}
223+
: undefined,
224+
};
225+
};

src/plugins/vis_augmenter/public/plugin.ts

+31-5
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,22 @@
55

66
import { ExpressionsSetup } from '../../expressions/public';
77
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public';
8-
import { DataPublicPluginSetup, DataPublicPluginStart } from '../../data/public';
98
import { visLayers } from './expressions';
109
import { setSavedAugmentVisLoader, setUISettings } from './services';
1110
import { createSavedAugmentVisLoader, SavedAugmentVisLoader } from './saved_augment_vis';
11+
import { registerTriggersAndActions } from './ui_actions_bootstrap';
12+
import { UiActionsStart } from '../../ui_actions/public';
13+
import {
14+
setUiActions,
15+
setEmbeddable,
16+
setQueryService,
17+
setVisualizations,
18+
setCore,
19+
} from './services';
20+
import { EmbeddableStart } from '../../embeddable/public';
21+
import { DataPublicPluginStart } from '../../data/public';
22+
import { VisualizationsStart } from '../../visualizations/public';
23+
import { VIEW_EVENTS_FLYOUT_STATE, setFlyoutState } from './view_events_flyout';
1224

1325
// eslint-disable-next-line @typescript-eslint/no-empty-interface
1426
export interface VisAugmenterSetup {}
@@ -18,12 +30,14 @@ export interface VisAugmenterStart {
1830
}
1931

2032
export interface VisAugmenterSetupDeps {
21-
data: DataPublicPluginSetup;
2233
expressions: ExpressionsSetup;
2334
}
2435

2536
export interface VisAugmenterStartDeps {
37+
uiActions: UiActionsStart;
38+
embeddable: EmbeddableStart;
2639
data: DataPublicPluginStart;
40+
visualizations: VisualizationsStart;
2741
}
2842

2943
export class VisAugmenterPlugin
@@ -33,14 +47,26 @@ export class VisAugmenterPlugin
3347

3448
public setup(
3549
core: CoreSetup<VisAugmenterStartDeps, VisAugmenterStart>,
36-
{ data, expressions }: VisAugmenterSetupDeps
50+
{ expressions }: VisAugmenterSetupDeps
3751
): VisAugmenterSetup {
3852
expressions.registerType(visLayers);
53+
setUISettings(core.uiSettings);
3954
return {};
4055
}
4156

42-
public start(core: CoreStart, { data }: VisAugmenterStartDeps): VisAugmenterStart {
43-
setUISettings(core.uiSettings);
57+
public start(
58+
core: CoreStart,
59+
{ uiActions, embeddable, data, visualizations }: VisAugmenterStartDeps
60+
): VisAugmenterStart {
61+
setUiActions(uiActions);
62+
setEmbeddable(embeddable);
63+
setQueryService(data.query);
64+
setVisualizations(visualizations);
65+
setCore(core);
66+
setFlyoutState(VIEW_EVENTS_FLYOUT_STATE.CLOSED);
67+
68+
registerTriggersAndActions(core);
69+
4470
const savedAugmentVisLoader = createSavedAugmentVisLoader({
4571
savedObjectsClient: core.savedObjects.client,
4672
indexPatterns: data.indexPatterns,

0 commit comments

Comments
 (0)