mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* Check repository plugins using callWithInternalUser instead * Add information about whether repository is managed (by Cloud) * Adjust warning copy, add warning Save button styling, and remove button tooltips * Add same tooltip to trash can icon * Fix prop
This commit is contained in:
parent
a93057262f
commit
4c72c7c93c
10 changed files with 188 additions and 35 deletions
|
@ -50,4 +50,4 @@ export const REPOSITORY_PLUGINS_MAP: { [key: string]: RepositoryType } = {
|
|||
'repository-gcs': REPOSITORY_TYPES.gcs,
|
||||
};
|
||||
|
||||
export const APP_PERMISSIONS = ['monitor', 'create_snapshot', 'cluster:admin/repository'];
|
||||
export const APP_PERMISSIONS = ['create_snapshot', 'cluster:admin/repository'];
|
||||
|
|
|
@ -15,6 +15,7 @@ import { RepositoryFormStepTwo } from './step_two';
|
|||
|
||||
interface Props {
|
||||
repository: Repository | EmptyRepository;
|
||||
isManagedRepository?: boolean;
|
||||
isEditing?: boolean;
|
||||
isSaving: boolean;
|
||||
saveError?: React.ReactNode;
|
||||
|
@ -24,6 +25,7 @@ interface Props {
|
|||
|
||||
export const RepositoryForm: React.FunctionComponent<Props> = ({
|
||||
repository: originalRepository,
|
||||
isManagedRepository,
|
||||
isEditing,
|
||||
isSaving,
|
||||
saveError,
|
||||
|
@ -101,6 +103,7 @@ export const RepositoryForm: React.FunctionComponent<Props> = ({
|
|||
const renderStepTwo = () => (
|
||||
<RepositoryFormStepTwo
|
||||
repository={repository as Repository}
|
||||
isManagedRepository={isManagedRepository}
|
||||
isEditing={isEditing}
|
||||
isSaving={isSaving}
|
||||
onSave={saveRepository}
|
||||
|
|
|
@ -25,6 +25,7 @@ import { textService } from '../../services/text';
|
|||
|
||||
interface Props {
|
||||
repository: Repository;
|
||||
isManagedRepository?: boolean;
|
||||
isEditing?: boolean;
|
||||
isSaving: boolean;
|
||||
onSave: () => void;
|
||||
|
@ -36,6 +37,7 @@ interface Props {
|
|||
|
||||
export const RepositoryFormStepTwo: React.FunctionComponent<Props> = ({
|
||||
repository,
|
||||
isManagedRepository,
|
||||
isEditing,
|
||||
isSaving,
|
||||
onSave,
|
||||
|
@ -144,10 +146,10 @@ export const RepositoryFormStepTwo: React.FunctionComponent<Props> = ({
|
|||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
color="secondary"
|
||||
color={isManagedRepository ? 'warning' : 'secondary'}
|
||||
iconType="check"
|
||||
onClick={onSave}
|
||||
fill
|
||||
fill={isManagedRepository ? false : true}
|
||||
data-test-subj="srRepositoryFormSubmitButton"
|
||||
isLoading={isSaving}
|
||||
>
|
||||
|
|
|
@ -9,6 +9,7 @@ import { RouteComponentProps, withRouter } from 'react-router-dom';
|
|||
import {
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiCallOut,
|
||||
EuiCodeEditor,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -163,7 +164,7 @@ const RepositoryDetailsUi: React.FunctionComponent<Props> = ({
|
|||
};
|
||||
|
||||
const renderRepository = () => {
|
||||
const { repository } = repositoryDetails;
|
||||
const { repository, isManagedRepository } = repositoryDetails;
|
||||
|
||||
if (!repository) {
|
||||
return null;
|
||||
|
@ -172,6 +173,22 @@ const RepositoryDetailsUi: React.FunctionComponent<Props> = ({
|
|||
const { type } = repository as Repository;
|
||||
return (
|
||||
<Fragment>
|
||||
{isManagedRepository ? (
|
||||
<Fragment>
|
||||
<EuiCallOut
|
||||
size="s"
|
||||
color="warning"
|
||||
iconType="iInCircle"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.repositoryDetails.managedRepositoryWarningTitle"
|
||||
defaultMessage="This is a managed repository used by other systems. Any changes you make might affect how these systems operate."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="l" />
|
||||
</Fragment>
|
||||
) : null}
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexStart">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
|
@ -329,6 +346,17 @@ const RepositoryDetailsUi: React.FunctionComponent<Props> = ({
|
|||
onClick={() =>
|
||||
deleteRepositoryPrompt([repositoryName], onRepositoryDeleted)
|
||||
}
|
||||
isDisabled={repositoryDetails.isManagedRepository}
|
||||
title={
|
||||
repositoryDetails.isManagedRepository
|
||||
? i18n.translate(
|
||||
'xpack.snapshotRestore.repositoryDetails.removeManagedRepositoryButtonTitle',
|
||||
{
|
||||
defaultMessage: 'You cannot delete a managed repository.',
|
||||
}
|
||||
)
|
||||
: null
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.repositoryDetails.removeButtonLabel"
|
||||
|
|
|
@ -37,7 +37,10 @@ export const RepositoryList: React.FunctionComponent<RouteComponentProps<MatchPa
|
|||
const {
|
||||
error,
|
||||
loading,
|
||||
data: { repositories } = { repositories: undefined },
|
||||
data: { repositories, managedRepository } = {
|
||||
repositories: undefined,
|
||||
managedRepository: undefined,
|
||||
},
|
||||
request: reload,
|
||||
} = loadRepositories();
|
||||
|
||||
|
@ -132,6 +135,7 @@ export const RepositoryList: React.FunctionComponent<RouteComponentProps<MatchPa
|
|||
content = (
|
||||
<RepositoryTable
|
||||
repositories={repositories || []}
|
||||
managedRepository={managedRepository}
|
||||
reload={reload}
|
||||
openRepositoryDetailsUrl={openRepositoryDetailsUrl}
|
||||
onRepositoryDeleted={onRepositoryDeleted}
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, Fragment } from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiButton,
|
||||
EuiButtonIcon,
|
||||
EuiFlexGroup,
|
||||
|
@ -27,6 +28,7 @@ import { uiMetricService } from '../../../../services/ui_metric';
|
|||
|
||||
interface Props extends RouteComponentProps {
|
||||
repositories: Repository[];
|
||||
managedRepository?: string;
|
||||
reload: () => Promise<void>;
|
||||
openRepositoryDetailsUrl: (name: Repository['name']) => string;
|
||||
onRepositoryDeleted: (repositoriesDeleted: Array<Repository['name']>) => void;
|
||||
|
@ -34,6 +36,7 @@ interface Props extends RouteComponentProps {
|
|||
|
||||
const RepositoryTableUi: React.FunctionComponent<Props> = ({
|
||||
repositories,
|
||||
managedRepository,
|
||||
reload,
|
||||
openRepositoryDetailsUrl,
|
||||
onRepositoryDeleted,
|
||||
|
@ -54,14 +57,25 @@ const RepositoryTableUi: React.FunctionComponent<Props> = ({
|
|||
}),
|
||||
truncateText: true,
|
||||
sortable: true,
|
||||
render: (name: Repository['name'], repository: Repository) => {
|
||||
render: (name: Repository['name']) => {
|
||||
return (
|
||||
<EuiLink
|
||||
onClick={() => trackUiMetric(UIM_REPOSITORY_SHOW_DETAILS_CLICK)}
|
||||
href={openRepositoryDetailsUrl(name)}
|
||||
>
|
||||
{name}
|
||||
</EuiLink>
|
||||
<Fragment>
|
||||
<EuiLink
|
||||
onClick={() => trackUiMetric(UIM_REPOSITORY_SHOW_DETAILS_CLICK)}
|
||||
href={openRepositoryDetailsUrl(name)}
|
||||
>
|
||||
{name}
|
||||
</EuiLink>
|
||||
|
||||
{managedRepository === name ? (
|
||||
<EuiBadge color="primary">
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.repositoryList.table.managedRepositoryBadgeLabel"
|
||||
defaultMessage="Managed"
|
||||
/>
|
||||
</EuiBadge>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
@ -114,10 +128,18 @@ const RepositoryTableUi: React.FunctionComponent<Props> = ({
|
|||
return (
|
||||
<RepositoryDeleteProvider>
|
||||
{deleteRepositoryPrompt => {
|
||||
const label = i18n.translate(
|
||||
'xpack.snapshotRestore.repositoryList.table.actionRemoveTooltip',
|
||||
{ defaultMessage: 'Remove' }
|
||||
);
|
||||
const label =
|
||||
name !== managedRepository
|
||||
? i18n.translate(
|
||||
'xpack.snapshotRestore.repositoryList.table.actionRemoveTooltip',
|
||||
{ defaultMessage: 'Remove' }
|
||||
)
|
||||
: i18n.translate(
|
||||
'xpack.snapshotRestore.repositoryList.table.deleteManagedRepositoryTooltip',
|
||||
{
|
||||
defaultMessage: 'You cannot delete a managed repository.',
|
||||
}
|
||||
);
|
||||
return (
|
||||
<EuiToolTip content={label} delay="long">
|
||||
<EuiButtonIcon
|
||||
|
@ -132,6 +154,7 @@ const RepositoryTableUi: React.FunctionComponent<Props> = ({
|
|||
color="danger"
|
||||
data-test-subj="srRepositoryListDeleteActionButton"
|
||||
onClick={() => deleteRepositoryPrompt([name], onRepositoryDeleted)}
|
||||
isDisabled={Boolean(name === managedRepository)}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
);
|
||||
|
@ -159,6 +182,17 @@ const RepositoryTableUi: React.FunctionComponent<Props> = ({
|
|||
|
||||
const selection = {
|
||||
onSelectionChange: (newSelectedItems: Repository[]) => setSelectedItems(newSelectedItems),
|
||||
selectable: ({ name }: Repository) => Boolean(name !== managedRepository),
|
||||
selectableMessage: (selectable: boolean) => {
|
||||
if (!selectable) {
|
||||
return i18n.translate(
|
||||
'xpack.snapshotRestore.repositoryList.table.deleteManagedRepositoryTooltip',
|
||||
{
|
||||
defaultMessage: 'You cannot delete a managed repository.',
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const search = {
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, Fragment } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import { EuiCallOut, EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import { Repository, EmptyRepository } from '../../../../common/types';
|
||||
|
||||
import { RepositoryForm, SectionError, SectionLoading } from '../../components';
|
||||
|
@ -123,7 +123,7 @@ export const RepositoryEdit: React.FunctionComponent<RouteComponentProps<MatchPa
|
|||
<SectionError
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.editRepository.avingRepositoryErrorTitle"
|
||||
id="xpack.snapshotRestore.editRepository.savingRepositoryErrorTitle"
|
||||
defaultMessage="Cannot save repository"
|
||||
/>
|
||||
}
|
||||
|
@ -144,15 +144,36 @@ export const RepositoryEdit: React.FunctionComponent<RouteComponentProps<MatchPa
|
|||
return renderError();
|
||||
}
|
||||
|
||||
const { isManagedRepository } = repositoryData;
|
||||
|
||||
return (
|
||||
<RepositoryForm
|
||||
repository={repository}
|
||||
isEditing={true}
|
||||
isSaving={isSaving}
|
||||
saveError={renderSaveError()}
|
||||
clearSaveError={clearSaveError}
|
||||
onSave={onSave}
|
||||
/>
|
||||
<Fragment>
|
||||
{isManagedRepository ? (
|
||||
<Fragment>
|
||||
<EuiCallOut
|
||||
size="m"
|
||||
color="warning"
|
||||
iconType="iInCircle"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.editRepository.managedRepositoryWarningTitle"
|
||||
defaultMessage="This is a managed repository. Changing this repository might affect other systems that use it. Proceed with caution."
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="l" />
|
||||
</Fragment>
|
||||
) : null}
|
||||
<RepositoryForm
|
||||
repository={repository}
|
||||
isManagedRepository={isManagedRepository}
|
||||
isEditing={true}
|
||||
isSaving={isSaving}
|
||||
saveError={renderSaveError()}
|
||||
clearSaveError={clearSaveError}
|
||||
onSave={onSave}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import { Request, ResponseToolkit } from 'hapi';
|
||||
import { DEFAULT_REPOSITORY_TYPES, REPOSITORY_PLUGINS_MAP } from '../../../common/constants';
|
||||
import {
|
||||
registerRepositoriesRoutes,
|
||||
createHandler,
|
||||
deleteHandler,
|
||||
getAllHandler,
|
||||
|
@ -18,6 +19,30 @@ import {
|
|||
describe('[Snapshot and Restore API Routes] Repositories', () => {
|
||||
const mockRequest = {} as Request;
|
||||
const mockResponseToolkit = {} as ResponseToolkit;
|
||||
const mockCallWithInternalUser = jest.fn().mockReturnValue({
|
||||
persistent: {
|
||||
'cluster.metadata.managed_repository': 'found-snapshots',
|
||||
},
|
||||
});
|
||||
|
||||
registerRepositoriesRoutes(
|
||||
{
|
||||
// @ts-ignore
|
||||
get: () => {},
|
||||
// @ts-ignore
|
||||
post: () => {},
|
||||
// @ts-ignore
|
||||
put: () => {},
|
||||
// @ts-ignore
|
||||
delete: () => {},
|
||||
// @ts-ignore
|
||||
patch: () => {},
|
||||
},
|
||||
{
|
||||
cloud: { config: { isCloudEnabled: false } },
|
||||
elasticsearch: { getCluster: () => ({ callWithInternalUser: mockCallWithInternalUser }) },
|
||||
}
|
||||
);
|
||||
|
||||
describe('getAllHandler()', () => {
|
||||
it('should arrify repositories returned from ES', async () => {
|
||||
|
@ -39,6 +64,7 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
settings: {},
|
||||
},
|
||||
],
|
||||
managedRepository: 'found-snapshots',
|
||||
};
|
||||
await expect(
|
||||
getAllHandler(mockRequest, callWithRequest, mockResponseToolkit)
|
||||
|
@ -50,6 +76,7 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
const callWithRequest = jest.fn().mockReturnValueOnce(mockEsResponse);
|
||||
const expectedResponse = {
|
||||
repositories: [],
|
||||
managedRepository: 'found-snapshots',
|
||||
};
|
||||
await expect(
|
||||
getAllHandler(mockRequest, callWithRequest, mockResponseToolkit)
|
||||
|
@ -82,6 +109,7 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
.mockResolvedValueOnce({});
|
||||
const expectedResponse = {
|
||||
repository: { name, ...mockEsResponse[name] },
|
||||
isManagedRepository: false,
|
||||
snapshots: { count: null },
|
||||
};
|
||||
await expect(
|
||||
|
@ -117,6 +145,7 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
.mockResolvedValueOnce(mockEsSnapshotResponse);
|
||||
const expectedResponse = {
|
||||
repository: { name, ...mockEsResponse[name] },
|
||||
isManagedRepository: false,
|
||||
snapshots: {
|
||||
count: 2,
|
||||
},
|
||||
|
@ -137,6 +166,7 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
.mockRejectedValueOnce(mockEsSnapshotError);
|
||||
const expectedResponse = {
|
||||
repository: { name, ...mockEsResponse[name] },
|
||||
isManagedRepository: false,
|
||||
snapshots: {
|
||||
count: null,
|
||||
},
|
||||
|
@ -188,7 +218,8 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
describe('getTypesHandler()', () => {
|
||||
it('should return default types if no repository plugins returned from ES', async () => {
|
||||
const mockEsResponse = {};
|
||||
const callWithRequest = jest.fn().mockReturnValue(mockEsResponse);
|
||||
const callWithRequest = jest.fn();
|
||||
mockCallWithInternalUser.mockReturnValueOnce(mockEsResponse);
|
||||
const expectedResponse = [...DEFAULT_REPOSITORY_TYPES];
|
||||
await expect(
|
||||
getTypesHandler(mockRequest, callWithRequest, mockResponseToolkit)
|
||||
|
@ -199,7 +230,8 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
const pluginNames = Object.keys(REPOSITORY_PLUGINS_MAP);
|
||||
const pluginTypes = Object.entries(REPOSITORY_PLUGINS_MAP).map(([key, value]) => value);
|
||||
const mockEsResponse = [...pluginNames.map(key => ({ component: key }))];
|
||||
const callWithRequest = jest.fn().mockReturnValue(mockEsResponse);
|
||||
const callWithRequest = jest.fn();
|
||||
mockCallWithInternalUser.mockReturnValueOnce(mockEsResponse);
|
||||
const expectedResponse = [...DEFAULT_REPOSITORY_TYPES, ...pluginTypes];
|
||||
await expect(
|
||||
getTypesHandler(mockRequest, callWithRequest, mockResponseToolkit)
|
||||
|
@ -209,7 +241,8 @@ describe('[Snapshot and Restore API Routes] Repositories', () => {
|
|||
it('should not return non-repository plugins returned from ES', async () => {
|
||||
const pluginNames = ['foo-plugin', 'bar-plugin'];
|
||||
const mockEsResponse = [...pluginNames.map(key => ({ component: key }))];
|
||||
const callWithRequest = jest.fn().mockReturnValue(mockEsResponse);
|
||||
const callWithRequest = jest.fn();
|
||||
mockCallWithInternalUser.mockReturnValueOnce(mockEsResponse);
|
||||
const expectedResponse = [...DEFAULT_REPOSITORY_TYPES];
|
||||
await expect(
|
||||
getTypesHandler(mockRequest, callWithRequest, mockResponseToolkit)
|
||||
|
|
|
@ -15,10 +15,12 @@ import { Repository, RepositoryType, RepositoryVerification } from '../../../com
|
|||
import { Plugins } from '../../../shim';
|
||||
import { deserializeRepositorySettings, serializeRepositorySettings } from '../../lib';
|
||||
|
||||
let isCloudEnabled = false;
|
||||
let isCloudEnabled: boolean = false;
|
||||
let callWithInternalUser: any;
|
||||
|
||||
export function registerRepositoriesRoutes(router: Router, plugins: Plugins) {
|
||||
isCloudEnabled = plugins.cloud.config.isCloudEnabled;
|
||||
callWithInternalUser = plugins.elasticsearch.getCluster('data').callWithInternalUser;
|
||||
router.get('repository_types', getTypesHandler);
|
||||
router.get('repositories', getAllHandler);
|
||||
router.get('repositories/{name}', getOneHandler);
|
||||
|
@ -28,12 +30,28 @@ export function registerRepositoriesRoutes(router: Router, plugins: Plugins) {
|
|||
router.delete('repositories/{names}', deleteHandler);
|
||||
}
|
||||
|
||||
export const getManagedRepositoryName = async () => {
|
||||
const { persistent, transient, defaults } = await callWithInternalUser('cluster.getSettings', {
|
||||
filterPath: '*.*managed_repository',
|
||||
flatSettings: true,
|
||||
includeDefaults: true,
|
||||
});
|
||||
const { 'cluster.metadata.managed_repository': managedRepositoryName = undefined } = {
|
||||
...defaults,
|
||||
...persistent,
|
||||
...transient,
|
||||
};
|
||||
return managedRepositoryName;
|
||||
};
|
||||
|
||||
export const getAllHandler: RouterRouteHandler = async (
|
||||
req,
|
||||
callWithRequest
|
||||
): Promise<{
|
||||
repositories: Repository[];
|
||||
managedRepository?: string;
|
||||
}> => {
|
||||
const managedRepository = await getManagedRepositoryName();
|
||||
const repositoriesByName = await callWithRequest('snapshot.getRepository', {
|
||||
repository: '_all',
|
||||
});
|
||||
|
@ -46,7 +64,7 @@ export const getAllHandler: RouterRouteHandler = async (
|
|||
settings: deserializeRepositorySettings(settings),
|
||||
};
|
||||
});
|
||||
return { repositories };
|
||||
return { repositories, managedRepository };
|
||||
};
|
||||
|
||||
export const getOneHandler: RouterRouteHandler = async (
|
||||
|
@ -54,9 +72,11 @@ export const getOneHandler: RouterRouteHandler = async (
|
|||
callWithRequest
|
||||
): Promise<{
|
||||
repository: Repository | {};
|
||||
isManagedRepository?: boolean;
|
||||
snapshots: { count: number | undefined } | {};
|
||||
}> => {
|
||||
const { name } = req.params;
|
||||
const managedRepository = await getManagedRepositoryName();
|
||||
const repositoryByName = await callWithRequest('snapshot.getRepository', { repository: name });
|
||||
const { snapshots } = await callWithRequest('snapshot.get', {
|
||||
repository: name,
|
||||
|
@ -73,6 +93,7 @@ export const getOneHandler: RouterRouteHandler = async (
|
|||
type,
|
||||
settings: deserializeRepositorySettings(settings),
|
||||
},
|
||||
isManagedRepository: managedRepository === name,
|
||||
snapshots: {
|
||||
count: snapshots ? snapshots.length : null,
|
||||
},
|
||||
|
@ -108,10 +129,15 @@ export const getVerificationHandler: RouterRouteHandler = async (
|
|||
};
|
||||
};
|
||||
|
||||
export const getTypesHandler: RouterRouteHandler = async (req, callWithRequest) => {
|
||||
export const getTypesHandler: RouterRouteHandler = async () => {
|
||||
// In ECE/ESS, do not enable the default types
|
||||
const types: RepositoryType[] = isCloudEnabled ? [] : [...DEFAULT_REPOSITORY_TYPES];
|
||||
const plugins: any[] = await callWithRequest('cat.plugins', { format: 'json' });
|
||||
|
||||
// Call with internal user so that the requesting user does not need `monitoring` cluster
|
||||
// privilege just to see list of available repository types
|
||||
const plugins: any[] = await callWithInternalUser('cat.plugins', { format: 'json' });
|
||||
|
||||
// Filter list of plugins to repository-related ones
|
||||
if (plugins && plugins.length) {
|
||||
const pluginNames: string[] = [...new Set(plugins.map(plugin => plugin.component))];
|
||||
pluginNames.forEach(pluginName => {
|
||||
|
|
|
@ -29,6 +29,7 @@ export interface Plugins {
|
|||
};
|
||||
};
|
||||
xpack_main: any;
|
||||
elasticsearch: any;
|
||||
}
|
||||
|
||||
export function createShim(
|
||||
|
@ -52,6 +53,7 @@ export function createShim(
|
|||
},
|
||||
},
|
||||
xpack_main: server.plugins.xpack_main,
|
||||
elasticsearch: server.plugins.elasticsearch,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue