Skip to content

Commit

Permalink
merge with main
Browse files Browse the repository at this point in the history
  • Loading branch information
nreese committed May 17, 2024
2 parents de91f6e + 82044e1 commit ca267e0
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@ import {
isErrorEmbeddable,
ReactEmbeddableRenderer,
} from '@kbn/embeddable-plugin/public';
import { PresentationContainer } from '@kbn/presentation-containers';
import { EmbeddableAppContext } from '@kbn/presentation-publishing';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import React, { FC } from 'react';
import React, { FC, useMemo } from 'react';
import ReactDOM from 'react-dom';
import useObservable from 'react-use/lib/useObservable';
import { pluginServices } from '../../../public/services';
import { CANVAS_APP, CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib';
import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib';
import { RendererStrings } from '../../../i18n';
import {
CanvasContainerApi,
Expand All @@ -32,6 +29,7 @@ import {
import { EmbeddableExpression } from '../../expression_types/embeddable';
import { StartDeps } from '../../plugin';
import { embeddableInputToExpression } from './embeddable_input_to_expression';
import { useGetAppContext } from './use_get_app_context';

const { embeddable: strings } = RendererStrings;

Expand All @@ -55,52 +53,51 @@ const renderReactEmbeddable = ({
handlers: RendererHandlers;
core: CoreStart;
}) => {
// wrap in functional component to allow usage of hooks
const RendererWrapper: FC<{ canvasApi: CanvasContainerApi }> = ({ canvasApi }) => {
const getAppContext = useGetAppContext(core);

useMemo(() => {
canvasApi.getAppContext = getAppContext;
}, [canvasApi, getAppContext]);

return (
<ReactEmbeddableRenderer
type={type}
maybeId={uuid}
parentApi={canvasApi}
key={`${type}_${uuid}`}
state={{ rawState: input }}
onAnyStateChange={(newState) => {
const newExpression = embeddableInputToExpression(
newState.rawState as unknown as EmbeddableInput,
type,
undefined,
true
);
if (newExpression) handlers.onEmbeddableInputChange(newExpression);
}}
/>
);
};

return (
<KibanaRenderContextProvider {...core}>
<div
className={CANVAS_EMBEDDABLE_CLASSNAME}
style={{ width: '100%', height: '100%', cursor: 'auto' }}
>
<ReactEmbeddableRenderer
type={type}
maybeId={uuid}
parentApi={container as unknown as PresentationContainer}
key={`${type}_${uuid}`}
state={{ rawState: input }}
onAnyStateChange={(newState) => {
const newExpression = embeddableInputToExpression(
newState.rawState as unknown as EmbeddableInput,
type,
undefined,
true
);
if (newExpression) handlers.onEmbeddableInputChange(newExpression);
}}
/>
<RendererWrapper canvasApi={container} />
</div>
</KibanaRenderContextProvider>
);
};

const renderEmbeddableFactory = (core: CoreStart, _plugins: StartDeps) => {
const EmbeddableRenderer: FC<{ embeddable: IEmbeddable }> = ({ embeddable }) => {
const currentAppId = useObservable(core.application.currentAppId$, undefined);

if (!currentAppId) {
return null;
}

const canvasAppContext: EmbeddableAppContext = {
getCurrentPath: () => {
const urlToApp = core.application.getUrlForApp(currentAppId);
const inAppPath = window.location.pathname.replace(urlToApp, '');

return inAppPath + window.location.search + window.location.hash;
},
currentAppId: CANVAS_APP,
};
const getAppContext = useGetAppContext(core);

embeddable.getAppContext = () => canvasAppContext;
embeddable.getAppContext = getAppContext;

return <EmbeddablePanel embeddable={embeddable} />;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { useMemo } from 'react';
import type { CoreStart } from '@kbn/core/public';
import useObservable from 'react-use/lib/useObservable';
import { CANVAS_APP } from '../../../common/lib';

export function useGetAppContext(core: CoreStart) {
const currentAppId = useObservable(core.application.currentAppId$, undefined);
const getAppContext = useMemo(() => {
return () => ({
getCurrentPath: () => {
const urlToApp = core.application.getUrlForApp(currentAppId ?? CANVAS_APP);
const inAppPath = window.location.pathname.replace(urlToApp, '');

return inAppPath + window.location.search + window.location.hash;
},
currentAppId: CANVAS_APP,
});
}, [currentAppId, core.application]);
return getAppContext;
}
7 changes: 5 additions & 2 deletions x-pack/plugins/canvas/types/embeddables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import type { TimeRange } from '@kbn/es-query';
import { Filter } from '@kbn/es-query';
import { EmbeddableInput as Input } from '@kbn/embeddable-plugin/common';
import { HasType, PublishesViewMode } from '@kbn/presentation-publishing';
import { HasAppContext, HasType, PublishesViewMode } from '@kbn/presentation-publishing';
import { CanAddNewPanel } from '@kbn/presentation-containers';

export type EmbeddableInput = Input & {
Expand All @@ -17,4 +17,7 @@ export type EmbeddableInput = Input & {
savedObjectId?: string;
};

export type CanvasContainerApi = PublishesViewMode & CanAddNewPanel & HasType;
export type CanvasContainerApi = PublishesViewMode &
CanAddNewPanel &
HasType &
Partial<HasAppContext>;
Original file line number Diff line number Diff line change
Expand Up @@ -337,12 +337,13 @@ class RuleEditorFlyoutUI extends Component {

updateRuleAtIndex = (ruleIndex, editedRule) => {
const { toasts } = this.props.kibana.services.notifications;
const { mlApiServices, mlJobService } = this.props.kibana.services.mlServices;
const { job, anomaly } = this.state;

const jobId = job.job_id;
const detectorIndex = anomaly.detectorIndex;

saveJobRule(job, detectorIndex, ruleIndex, editedRule)
saveJobRule(job, detectorIndex, ruleIndex, editedRule, mlApiServices, mlJobService)
.then((resp) => {
if (resp.success) {
toasts.add({
Expand Down Expand Up @@ -391,11 +392,12 @@ class RuleEditorFlyoutUI extends Component {

deleteRuleAtIndex = (index) => {
const { toasts } = this.props.kibana.services.notifications;
const { mlApiServices, mlJobService: jobService } = this.props.kibana.services.mlServices;
const { job, anomaly } = this.state;
const jobId = job.job_id;
const detectorIndex = anomaly.detectorIndex;

deleteJobRule(job, detectorIndex, index)
deleteJobRule(job, detectorIndex, index, mlApiServices, jobService)
.then((resp) => {
if (resp.success) {
toasts.addSuccess(
Expand Down Expand Up @@ -443,7 +445,8 @@ class RuleEditorFlyoutUI extends Component {

addItemToFilterList = (item, filterId, closeFlyoutOnAdd) => {
const { toasts } = this.props.kibana.services.notifications;
addItemToFilter(item, filterId)
const { mlApiServices } = this.props.kibana.services.mlServices;
addItemToFilter(item, filterId, mlApiServices)
.then(() => {
if (closeFlyoutOnAdd === true) {
toasts.add({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import {
ML_DETECTOR_RULE_OPERATOR,
} from '@kbn/ml-anomaly-utils';

import { ml } from '../../services/ml_api_service';
import { mlJobService } from '../../services/job_service';
import { mlJobService as importedMlJobService } from '../../services/job_service';
import { processCreatedBy } from '../../../../common/util/job_utils';

export function getNewConditionDefaults() {
Expand Down Expand Up @@ -70,8 +69,16 @@ export function isValidRule(rule) {
return isValid;
}

export function saveJobRule(job, detectorIndex, ruleIndex, editedRule) {
export function saveJobRule(
job,
detectorIndex,
ruleIndex,
editedRule,
mlApiServices,
mlJobService
) {
const detector = job.analysis_config.detectors[detectorIndex];
const jobService = mlJobService || importedMlJobService;

// Filter out any scope expression where the UI=specific 'enabled'
// property is set to false.
Expand Down Expand Up @@ -103,16 +110,17 @@ export function saveJobRule(job, detectorIndex, ruleIndex, editedRule) {
}
}

return updateJobRules(job, detectorIndex, rules);
return updateJobRules(job, detectorIndex, rules, mlApiServices, jobService);
}

export function deleteJobRule(job, detectorIndex, ruleIndex) {
export function deleteJobRule(job, detectorIndex, ruleIndex, mlApiServices, mlJobService) {
const jobService = mlJobService || importedMlJobService;
const detector = job.analysis_config.detectors[detectorIndex];
let customRules = [];
if (detector.custom_rules !== undefined && ruleIndex < detector.custom_rules.length) {
customRules = cloneDeep(detector.custom_rules);
customRules.splice(ruleIndex, 1);
return updateJobRules(job, detectorIndex, customRules);
return updateJobRules(job, detectorIndex, customRules, mlApiServices, jobService);
} else {
return Promise.reject(
new Error(
Expand All @@ -128,7 +136,7 @@ export function deleteJobRule(job, detectorIndex, ruleIndex) {
}
}

export function updateJobRules(job, detectorIndex, rules) {
export function updateJobRules(job, detectorIndex, rules, mlApiServices, mlJobService) {
// Pass just the detector with the edited rule to the updateJob endpoint.
const jobId = job.job_id;
const jobData = {
Expand All @@ -146,9 +154,9 @@ export function updateJobRules(job, detectorIndex, rules) {
processCreatedBy(customSettings);
jobData.custom_settings = customSettings;
}

return new Promise((resolve, reject) => {
ml.updateJob({ jobId: jobId, job: jobData })
mlApiServices
.updateJob({ jobId: jobId, job: jobData })
.then(() => {
// Refresh the job data in the job service before resolving.
mlJobService
Expand All @@ -168,9 +176,9 @@ export function updateJobRules(job, detectorIndex, rules) {

// Updates an ML filter used in the scope part of a rule,
// adding an item to the filter with the specified ID.
export function addItemToFilter(item, filterId) {
export function addItemToFilter(item, filterId, mlApiServices) {
return new Promise((resolve, reject) => {
ml.filters
mlApiServices.filters
.updateFilter(filterId, undefined, [item], undefined)
.then((updatedFilter) => {
resolve(updatedFilter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ describe('Artifacts pages', { tags: ['@ess', '@serverless', '@skipInServerlessMK
});

for (const testData of getArtifactsListTestsData()) {
describe(`When on the ${testData.title} entries list`, () => {
// FLAKY: https://github.com/elastic/kibana/issues/183718
// FLAKY: https://github.com/elastic/kibana/issues/183719
// FLAKY: https://github.com/elastic/kibana/issues/183720
describe.skip(`When on the ${testData.title} entries list`, () => {
it(`no access - should show no privileges callout`, () => {
loginWithoutAccess(`/app/security/administration/${testData.urlPath}`);
cy.getByTestSubj('noPrivilegesPage').should('exist');
Expand Down

0 comments on commit ca267e0

Please sign in to comment.