Skip to content

Commit 8661bde

Browse files
[Unified Rules] Update "Go to rules" link in Saved Object import workflow (elastic#250220)
closes elastic#239614 ## Summary Make the "Go to rules" button in the Saved Object import flow redirect the user to the unified rules page (`/app/rules`) if the feature flag `xpack.trigger_actions_ui.enableExperimental.unifiedRulesPage` is enabled. Since... 1. This feature flag lives within the configuration of the `triggersActionsUi` plugin 2. The `triggersActionsUi` plugin depends on the `alerting` plugin 3. The `actionPath` is initialized in the `alerting` plugin server-side code ... we can't check if the FF is enabled directly on the `alerting` server-side code. For this reason, I've moved the logic to determine the link to the frontend code, in which we use `kibana.services.application.isAppRegistered` to check if the `rules` app is registered as an indirect way of knowing if the feature flag is enabled. Similar to the work done [here](https://github.com/elastic/kibana/pull/249750/files). Once the migration to the new unified rules page is complete we should remove/revert these changes and modify the link directly in `x-pack/platform/plugins/shared/alerting/server/saved_objects/get_import_warnings.ts` ![demoSavedObjectImport](https://github.com/user-attachments/assets/cb4d6474-0eae-41ba-94cb-02344192a6a7) ## Testing To test this change: ### Functional 1. Enable the feature flag: `xpack.trigger_actions_ui.enableExperimental: ['unifiedRulesPage']` 2. Navigate to the Import Saved Objects page (http://localhost:5601/app/management/kibana/objects) 3. Start importing a saved object with rules 4. Click on "Create new objects with random IDs" 5. Select a file to import 6. Click on "Import" 7. Verify that a warning is shown and that clicking on "Go to rules" redirects you to the new unified rules page ### Regression 1. Disable the feature flag 2. Repeat Functional steps from 2 to 6 3. Verify that a warning is shown and that clicking on "Go to rules" redirects you to the legacy Management rules page (http://localhost:5601/app/management/insightsAndAlerting/triggersActions/rules) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
1 parent 6e2d524 commit 8661bde

5 files changed

Lines changed: 121 additions & 33 deletions

File tree

src/platform/plugins/shared/saved_objects_management/moon.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dependsOn:
4343
- '@kbn/react-kibana-context-render'
4444
- '@kbn/shared-ux-table-persist'
4545
- '@kbn/css-utils'
46+
- '@kbn/content-management-plugin'
4647
tags:
4748
- plugin
4849
- prod

src/platform/plugins/shared/saved_objects_management/public/management_section/mount_section.tsx

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { EuiLoadingSpinner } from '@elastic/eui';
1616
import type { CoreSetup } from '@kbn/core/public';
1717
import type { ManagementAppMountParams } from '@kbn/management-plugin/public';
1818
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
19+
import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public';
1920
import type { SavedObjectManagementTypeInfo } from '../../common/types';
2021
import type { StartDependencies, SavedObjectsManagementPluginStart } from '../plugin';
2122
import { getAllowedTypes } from '../lib';
@@ -66,40 +67,44 @@ export const mountManagementSection = async ({
6667
return children! as React.ReactElement;
6768
};
6869

70+
const { Provider: KibanaReactContextProvider } = createKibanaReactContext(coreStart);
71+
6972
ReactDOM.render(
7073
<KibanaRenderContextProvider {...coreStart}>
71-
<Router history={history}>
72-
<Routes>
73-
<Route path={'/:type/:id'} exact={true}>
74-
<RedirectToHomeIfUnauthorized>
75-
<Suspense fallback={<EuiLoadingSpinner />}>
76-
<SavedObjectsEditionPage
77-
coreStart={coreStart}
78-
setBreadcrumbs={setBreadcrumbs}
79-
history={history}
80-
/>
81-
</Suspense>
82-
</RedirectToHomeIfUnauthorized>
83-
</Route>
84-
<Route path={'/'} exact={false}>
85-
<RedirectToHomeIfUnauthorized>
86-
<Suspense fallback={<EuiLoadingSpinner />}>
87-
<SavedObjectsTablePage
88-
coreStart={coreStart}
89-
taggingApi={savedObjectsTaggingOss?.getTaggingApi()}
90-
spacesApi={spacesApi}
91-
dataStart={data}
92-
dataViewsApi={dataViews}
93-
actionRegistry={getActionServiceStart()}
94-
columnRegistry={getColumnServiceStart()}
95-
allowedTypes={allowedObjectTypes}
96-
setBreadcrumbs={setBreadcrumbs}
97-
/>
98-
</Suspense>
99-
</RedirectToHomeIfUnauthorized>
100-
</Route>
101-
</Routes>
102-
</Router>
74+
<KibanaReactContextProvider>
75+
<Router history={history}>
76+
<Routes>
77+
<Route path={'/:type/:id'} exact={true}>
78+
<RedirectToHomeIfUnauthorized>
79+
<Suspense fallback={<EuiLoadingSpinner />}>
80+
<SavedObjectsEditionPage
81+
coreStart={coreStart}
82+
setBreadcrumbs={setBreadcrumbs}
83+
history={history}
84+
/>
85+
</Suspense>
86+
</RedirectToHomeIfUnauthorized>
87+
</Route>
88+
<Route path={'/'} exact={false}>
89+
<RedirectToHomeIfUnauthorized>
90+
<Suspense fallback={<EuiLoadingSpinner />}>
91+
<SavedObjectsTablePage
92+
coreStart={coreStart}
93+
taggingApi={savedObjectsTaggingOss?.getTaggingApi()}
94+
spacesApi={spacesApi}
95+
dataStart={data}
96+
dataViewsApi={dataViews}
97+
actionRegistry={getActionServiceStart()}
98+
columnRegistry={getColumnServiceStart()}
99+
allowedTypes={allowedObjectTypes}
100+
setBreadcrumbs={setBreadcrumbs}
101+
/>
102+
</Suspense>
103+
</RedirectToHomeIfUnauthorized>
104+
</Route>
105+
</Routes>
106+
</Router>
107+
</KibanaReactContextProvider>
103108
</KibanaRenderContextProvider>,
104109
element
105110
);

src/platform/plugins/shared/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ import React from 'react';
1111
import type { ReactWrapper } from 'enzyme';
1212
import { mountWithI18nProvider } from '@kbn/test-jest-helpers';
1313
import { httpServiceMock } from '@kbn/core/public/mocks';
14+
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
15+
import { coreMock } from '@kbn/core/public/mocks';
1416
import type { ImportSummaryProps } from './import_summary';
1517
import { ImportSummary } from './import_summary';
1618
import type { FailedImport } from '../../../lib';
1719

1820
describe('ImportSummary', () => {
1921
let basePath: ReturnType<typeof httpServiceMock.createBasePath>;
22+
type PrependType = jest.MockInstance<string, [url: string], unknown> & ((url: string) => string);
2023

2124
const getProps = (parts: Partial<ImportSummaryProps>): ImportSummaryProps => ({
2225
basePath,
@@ -175,4 +178,61 @@ describe('ImportSummary', () => {
175178

176179
expect(findWarnings(wrapper)).toHaveLength(2);
177180
});
181+
182+
it('should use /app/rules actionPath when rules app is registered', async () => {
183+
const coreStart = coreMock.createStart();
184+
coreStart.application.isAppRegistered = jest.fn().mockReturnValue(true);
185+
basePath.prepend = ((path: string) => path) as PrependType;
186+
187+
const props = getProps({
188+
successfulImports: [successNew],
189+
importWarnings: [
190+
{
191+
type: 'action_required',
192+
message: 'Rules need to be enabled',
193+
actionPath: '/app/management/insightsAndAlerting/triggersActions/rules',
194+
},
195+
],
196+
});
197+
198+
const wrapper = mountWithI18nProvider(
199+
<KibanaContextProvider services={coreStart}>
200+
<ImportSummary {...props} />
201+
</KibanaContextProvider>
202+
);
203+
204+
const button = wrapper.find('EuiButton[data-test-subj="warningActionButton"]');
205+
expect(button).toHaveLength(1);
206+
expect(button.prop('href')).toBe('/app/rules');
207+
expect(coreStart.application.isAppRegistered).toHaveBeenCalledWith('rules');
208+
});
209+
210+
it('should use original actionPath when rules app is not registered', async () => {
211+
const coreStart = coreMock.createStart();
212+
coreStart.application.isAppRegistered = jest.fn().mockReturnValue(false);
213+
basePath.prepend = ((path: string) => path) as PrependType;
214+
215+
const originalActionPath = '/app/management/insightsAndAlerting/triggersActions/rules';
216+
const props = getProps({
217+
successfulImports: [successNew],
218+
importWarnings: [
219+
{
220+
type: 'action_required',
221+
message: 'Rules need to be enabled',
222+
actionPath: originalActionPath,
223+
},
224+
],
225+
});
226+
227+
const wrapper = mountWithI18nProvider(
228+
<KibanaContextProvider services={coreStart}>
229+
<ImportSummary {...props} />
230+
</KibanaContextProvider>
231+
);
232+
233+
const button = wrapper.find('EuiButton[data-test-subj="warningActionButton"]');
234+
expect(button).toHaveLength(1);
235+
expect(button.prop('href')).toBe(originalActionPath);
236+
expect(coreStart.application.isAppRegistered).toHaveBeenCalledWith('rules');
237+
});
178238
});

src/platform/plugins/shared/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ import type {
2828
SavedObjectsImportSuccess,
2929
SavedObjectsImportWarning,
3030
IBasePath,
31+
CoreStart,
3132
} from '@kbn/core/public';
3233
import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
3334
import { css } from '@emotion/react';
35+
import { useKibana } from '@kbn/kibana-react-plugin/public';
36+
import type { StartDependencies } from '@kbn/content-management-plugin/public/types';
3437
import type { SavedObjectManagementTypeInfo } from '../../../../common/types';
3538
import type { FailedImport } from '../../../lib';
3639
import { getDefaultTitle, getSavedObjectLabel } from '../../../lib';
@@ -202,9 +205,26 @@ const ImportWarnings: FC<{ warnings: SavedObjectsImportWarning[]; basePath: IBas
202205
};
203206

204207
const ImportWarning: FC<{ warning: SavedObjectsImportWarning; basePath: IBasePath }> = ({
205-
warning,
208+
warning: providedWarning,
206209
basePath,
207210
}) => {
211+
const kibana = useKibana<CoreStart & StartDependencies>();
212+
const isUnifiedRulesPageEnabled = useMemo(
213+
() => kibana.services.application?.isAppRegistered?.('rules') ?? false,
214+
[kibana.services.application]
215+
);
216+
217+
const warning = useMemo(
218+
() =>
219+
isUnifiedRulesPageEnabled && 'actionPath' in providedWarning
220+
? {
221+
...providedWarning,
222+
actionPath: '/app/rules',
223+
}
224+
: providedWarning,
225+
[isUnifiedRulesPageEnabled, providedWarning]
226+
);
227+
208228
const warningContent = useMemo(() => {
209229
if (warning.type === 'action_required') {
210230
return (
@@ -213,6 +233,7 @@ const ImportWarning: FC<{ warning: SavedObjectsImportWarning; basePath: IBasePat
213233
<EuiButton
214234
size="s"
215235
color="warning"
236+
data-test-subj="warningActionButton"
216237
href={basePath.prepend(warning.actionPath)}
217238
target="_blank"
218239
>

src/platform/plugins/shared/saved_objects_management/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@kbn/react-kibana-context-render",
3535
"@kbn/shared-ux-table-persist",
3636
"@kbn/css-utils",
37+
"@kbn/content-management-plugin",
3738
],
3839
"exclude": [
3940
"target/**/*",

0 commit comments

Comments
 (0)