mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[data view management] Fix set default data view permissions check (#124897)
* fix set default data view permissions * fix fields table * fix scripted field add button * fix jest tests * lint fixes * fix test * updte snapshot
This commit is contained in:
parent
67cd496daa
commit
ded0478ed7
14 changed files with 72 additions and 57 deletions
|
@ -70,7 +70,11 @@ export const CreateEditField = withRouter(
|
|||
if (spec) {
|
||||
return (
|
||||
<>
|
||||
<IndexHeader indexPattern={indexPattern} defaultIndex={uiSettings.get('defaultIndex')} />
|
||||
<IndexHeader
|
||||
indexPattern={indexPattern}
|
||||
defaultIndex={uiSettings.get('defaultIndex')}
|
||||
canSave={dataViews.getCanSaveSync()}
|
||||
/>
|
||||
<EuiSpacer size={'l'} />
|
||||
<FieldEditor
|
||||
indexPattern={indexPattern}
|
||||
|
|
|
@ -65,7 +65,7 @@ const securitySolution = 'security-solution';
|
|||
|
||||
export const EditIndexPattern = withRouter(
|
||||
({ indexPattern, history, location }: EditIndexPatternProps) => {
|
||||
const { application, uiSettings, overlays, chrome, dataViews } =
|
||||
const { uiSettings, overlays, chrome, dataViews } =
|
||||
useKibana<IndexPatternManagmentContext>().services;
|
||||
const [fields, setFields] = useState<DataViewField[]>(indexPattern.getNonScriptedFields());
|
||||
const [conflictedFields, setConflictedFields] = useState<DataViewField[]>(
|
||||
|
@ -143,15 +143,16 @@ export const EditIndexPattern = withRouter(
|
|||
const showTagsSection = Boolean(indexPattern.timeFieldName || (tags && tags.length > 0));
|
||||
const kibana = useKibana();
|
||||
const docsUrl = kibana.services.docLinks!.links.elasticsearch.mapping;
|
||||
const userEditPermission = !!application?.capabilities?.indexPatterns?.save;
|
||||
const userEditPermission = dataViews.getCanSaveSync();
|
||||
|
||||
return (
|
||||
<div data-test-subj="editIndexPattern" role="region" aria-label={headingAriaLabel}>
|
||||
<IndexHeader
|
||||
indexPattern={indexPattern}
|
||||
setDefault={setDefaultPattern}
|
||||
{...(userEditPermission ? { deleteIndexPatternClick: removePattern } : {})}
|
||||
deleteIndexPatternClick={removePattern}
|
||||
defaultIndex={defaultIndex}
|
||||
canSave={userEditPermission}
|
||||
>
|
||||
{showTagsSection && (
|
||||
<EuiFlexGroup wrap gutterSize="s">
|
||||
|
|
|
@ -16,6 +16,7 @@ interface IndexHeaderProps {
|
|||
defaultIndex?: string;
|
||||
setDefault?: () => void;
|
||||
deleteIndexPatternClick?: () => void;
|
||||
canSave: boolean;
|
||||
}
|
||||
|
||||
const setDefaultAriaLabel = i18n.translate('indexPatternManagement.editDataView.setDefaultAria', {
|
||||
|
@ -40,12 +41,13 @@ export const IndexHeader: React.FC<IndexHeaderProps> = ({
|
|||
setDefault,
|
||||
deleteIndexPatternClick,
|
||||
children,
|
||||
canSave,
|
||||
}) => {
|
||||
return (
|
||||
<EuiPageHeader
|
||||
pageTitle={<span data-test-subj="indexPatternTitle">{indexPattern.title}</span>}
|
||||
rightSideItems={[
|
||||
defaultIndex !== indexPattern.id && setDefault && (
|
||||
defaultIndex !== indexPattern.id && setDefault && canSave && (
|
||||
<EuiToolTip content={setDefaultTooltip}>
|
||||
<EuiButtonIcon
|
||||
color="text"
|
||||
|
@ -56,7 +58,7 @@ export const IndexHeader: React.FC<IndexHeaderProps> = ({
|
|||
/>
|
||||
</EuiToolTip>
|
||||
),
|
||||
deleteIndexPatternClick && (
|
||||
canSave && (
|
||||
<EuiToolTip content={removeTooltip}>
|
||||
<EuiButtonIcon
|
||||
color="danger"
|
||||
|
|
|
@ -161,6 +161,8 @@ exports[`IndexedFieldsTable IndexedFieldsTable with rollup index pattern should
|
|||
},
|
||||
]
|
||||
}
|
||||
openModal={[Function]}
|
||||
theme={Object {}}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
@ -196,6 +198,8 @@ exports[`IndexedFieldsTable should filter based on the query bar 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
openModal={[Function]}
|
||||
theme={Object {}}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
@ -233,6 +237,8 @@ exports[`IndexedFieldsTable should filter based on the schema filter 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
openModal={[Function]}
|
||||
theme={Object {}}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
@ -267,6 +273,8 @@ exports[`IndexedFieldsTable should filter based on the type filter 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
openModal={[Function]}
|
||||
theme={Object {}}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
@ -366,6 +374,8 @@ exports[`IndexedFieldsTable should render normally 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
openModal={[Function]}
|
||||
theme={Object {}}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -97,6 +97,12 @@ const fields = [
|
|||
},
|
||||
].map(mockFieldToIndexPatternField);
|
||||
|
||||
const mockedServices = {
|
||||
userEditPermission: false,
|
||||
openModal: () => ({ onClose: new Promise<void>(() => {}), close: async () => {} }),
|
||||
theme: {} as any,
|
||||
};
|
||||
|
||||
describe('IndexedFieldsTable', () => {
|
||||
test('should render normally', async () => {
|
||||
const component: ShallowWrapper<any, Readonly<{}>, React.Component<{}, {}, any>> = shallow(
|
||||
|
@ -110,8 +116,9 @@ describe('IndexedFieldsTable', () => {
|
|||
indexedFieldTypeFilter={[]}
|
||||
schemaFieldTypeFilter={[]}
|
||||
fieldFilter=""
|
||||
{...mockedServices}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.update();
|
||||
|
@ -131,8 +138,9 @@ describe('IndexedFieldsTable', () => {
|
|||
indexedFieldTypeFilter={[]}
|
||||
schemaFieldTypeFilter={[]}
|
||||
fieldFilter=""
|
||||
{...mockedServices}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.setProps({ fieldFilter: 'Elast' });
|
||||
|
@ -153,8 +161,9 @@ describe('IndexedFieldsTable', () => {
|
|||
indexedFieldTypeFilter={[]}
|
||||
schemaFieldTypeFilter={[]}
|
||||
fieldFilter=""
|
||||
{...mockedServices}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.setProps({ indexedFieldTypeFilter: ['date'] });
|
||||
|
@ -175,8 +184,9 @@ describe('IndexedFieldsTable', () => {
|
|||
indexedFieldTypeFilter={[]}
|
||||
schemaFieldTypeFilter={[]}
|
||||
fieldFilter=""
|
||||
{...mockedServices}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.setProps({ schemaFieldTypeFilter: ['runtime'] });
|
||||
|
@ -198,8 +208,9 @@ describe('IndexedFieldsTable', () => {
|
|||
indexedFieldTypeFilter={[]}
|
||||
schemaFieldTypeFilter={[]}
|
||||
fieldFilter=""
|
||||
{...mockedServices}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
component.update();
|
||||
|
|
|
@ -10,10 +10,8 @@ import React, { Component } from 'react';
|
|||
import { createSelector } from 'reselect';
|
||||
import { OverlayStart, ThemeServiceStart } from 'src/core/public';
|
||||
import { DataViewField, DataView } from '../../../../../../plugins/data_views/public';
|
||||
import { useKibana } from '../../../../../../plugins/kibana_react/public';
|
||||
import { Table } from './components/table';
|
||||
import { IndexedFieldItem } from './types';
|
||||
import { IndexPatternManagmentContext } from '../../../types';
|
||||
|
||||
interface IndexedFieldsTableProps {
|
||||
fields: DataViewField[];
|
||||
|
@ -36,16 +34,10 @@ interface IndexedFieldsTableState {
|
|||
fields: IndexedFieldItem[];
|
||||
}
|
||||
|
||||
const withHooks = (Comp: typeof Component) => {
|
||||
return (props: any) => {
|
||||
const { application } = useKibana<IndexPatternManagmentContext>().services;
|
||||
const userEditPermission = !!application?.capabilities?.indexPatterns?.save;
|
||||
|
||||
return <Comp userEditPermission={userEditPermission} {...props} />;
|
||||
};
|
||||
};
|
||||
|
||||
class IndexedFields extends Component<IndexedFieldsTableProps, IndexedFieldsTableState> {
|
||||
export class IndexedFieldsTable extends Component<
|
||||
IndexedFieldsTableProps,
|
||||
IndexedFieldsTableState
|
||||
> {
|
||||
constructor(props: IndexedFieldsTableProps) {
|
||||
super(props);
|
||||
|
||||
|
@ -158,5 +150,3 @@ class IndexedFields extends Component<IndexedFieldsTableProps, IndexedFieldsTabl
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const IndexedFieldsTable = withHooks(IndexedFields);
|
||||
|
|
|
@ -22,9 +22,9 @@ interface HeaderProps extends RouteComponentProps {
|
|||
}
|
||||
|
||||
export const Header = withRouter(({ indexPatternId, history }: HeaderProps) => {
|
||||
const { application, docLinks } = useKibana<IndexPatternManagmentContext>().services;
|
||||
const { dataViews, docLinks } = useKibana<IndexPatternManagmentContext>().services;
|
||||
const links = docLinks?.links;
|
||||
const userEditPermission = !!application?.capabilities?.indexPatterns?.save;
|
||||
const userEditPermission = dataViews.getCanSaveSync();
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
|
|
|
@ -68,9 +68,10 @@ describe('ScriptedFieldsTable', () => {
|
|||
helpers={helpers}
|
||||
painlessDocLink={'painlessDoc'}
|
||||
saveIndexPattern={async () => {}}
|
||||
userEditPermission={false}
|
||||
scriptedFieldLanguageFilter={[]}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
// Allow the componentWillMount code to execute
|
||||
// https://github.com/airbnb/enzyme/issues/450
|
||||
|
@ -87,9 +88,10 @@ describe('ScriptedFieldsTable', () => {
|
|||
helpers={helpers}
|
||||
painlessDocLink={'painlessDoc'}
|
||||
saveIndexPattern={async () => {}}
|
||||
userEditPermission={false}
|
||||
scriptedFieldLanguageFilter={[]}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
// Allow the componentWillMount code to execute
|
||||
// https://github.com/airbnb/enzyme/issues/450
|
||||
|
@ -119,9 +121,10 @@ describe('ScriptedFieldsTable', () => {
|
|||
painlessDocLink={'painlessDoc'}
|
||||
helpers={helpers}
|
||||
saveIndexPattern={async () => {}}
|
||||
userEditPermission={false}
|
||||
scriptedFieldLanguageFilter={[]}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
// Allow the componentWillMount code to execute
|
||||
// https://github.com/airbnb/enzyme/issues/450
|
||||
|
@ -145,9 +148,10 @@ describe('ScriptedFieldsTable', () => {
|
|||
painlessDocLink={'painlessDoc'}
|
||||
helpers={helpers}
|
||||
saveIndexPattern={async () => {}}
|
||||
userEditPermission={false}
|
||||
scriptedFieldLanguageFilter={[]}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
// Allow the componentWillMount code to execute
|
||||
// https://github.com/airbnb/enzyme/issues/450
|
||||
|
@ -166,9 +170,10 @@ describe('ScriptedFieldsTable', () => {
|
|||
helpers={helpers}
|
||||
painlessDocLink={'painlessDoc'}
|
||||
saveIndexPattern={async () => {}}
|
||||
userEditPermission={false}
|
||||
scriptedFieldLanguageFilter={[]}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await component.update(); // Fire `componentWillMount()`
|
||||
// @ts-expect-error lang is not valid
|
||||
|
@ -194,9 +199,10 @@ describe('ScriptedFieldsTable', () => {
|
|||
helpers={helpers}
|
||||
painlessDocLink={'painlessDoc'}
|
||||
saveIndexPattern={async () => {}}
|
||||
userEditPermission={false}
|
||||
scriptedFieldLanguageFilter={[]}
|
||||
/>
|
||||
).dive();
|
||||
);
|
||||
|
||||
await component.update(); // Fire `componentWillMount()`
|
||||
// @ts-expect-error
|
||||
|
|
|
@ -15,10 +15,8 @@ import {
|
|||
|
||||
import { Table, Header, CallOuts, DeleteScritpedFieldConfirmationModal } from './components';
|
||||
import { ScriptedFieldItem } from './types';
|
||||
import { IndexPatternManagmentContext } from '../../../types';
|
||||
|
||||
import { DataView, DataViewsPublicPluginStart } from '../../../../../../plugins/data_views/public';
|
||||
import { useKibana } from '../../../../../../plugins/kibana_react/public';
|
||||
|
||||
interface ScriptedFieldsTableProps {
|
||||
indexPattern: DataView;
|
||||
|
@ -41,16 +39,10 @@ interface ScriptedFieldsTableState {
|
|||
fields: ScriptedFieldItem[];
|
||||
}
|
||||
|
||||
const withHooks = (Comp: typeof Component) => {
|
||||
return (props: any) => {
|
||||
const { application } = useKibana<IndexPatternManagmentContext>().services;
|
||||
const userEditPermission = !!application?.capabilities?.indexPatterns?.save;
|
||||
|
||||
return <Comp userEditPermission={userEditPermission} {...props} />;
|
||||
};
|
||||
};
|
||||
|
||||
class ScriptedFields extends Component<ScriptedFieldsTableProps, ScriptedFieldsTableState> {
|
||||
export class ScriptedFieldsTable extends Component<
|
||||
ScriptedFieldsTableProps,
|
||||
ScriptedFieldsTableState
|
||||
> {
|
||||
constructor(props: ScriptedFieldsTableProps) {
|
||||
super(props);
|
||||
|
||||
|
@ -168,5 +160,3 @@ class ScriptedFields extends Component<ScriptedFieldsTableProps, ScriptedFieldsT
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const ScriptedFieldsTable = withHooks(ScriptedFields);
|
||||
|
|
|
@ -132,7 +132,7 @@ export function Tabs({
|
|||
location,
|
||||
refreshFields,
|
||||
}: TabsProps) {
|
||||
const { application, uiSettings, docLinks, dataViewFieldEditor, overlays, theme } =
|
||||
const { uiSettings, docLinks, dataViewFieldEditor, overlays, theme, dataViews } =
|
||||
useKibana<IndexPatternManagmentContext>().services;
|
||||
const [fieldFilter, setFieldFilter] = useState<string>('');
|
||||
const [syncingStateFunc, setSyncingStateFunc] = useState<any>({
|
||||
|
@ -241,7 +241,7 @@ export function Tabs({
|
|||
[uiSettings]
|
||||
);
|
||||
|
||||
const userEditPermission = !!application?.capabilities?.indexPatterns?.save;
|
||||
const userEditPermission = dataViews.getCanSaveSync();
|
||||
const getFilterSection = useCallback(
|
||||
(type: string) => {
|
||||
return (
|
||||
|
@ -448,7 +448,8 @@ export function Tabs({
|
|||
getFieldInfo,
|
||||
}}
|
||||
openModal={overlays.openModal}
|
||||
theme={theme}
|
||||
theme={theme!}
|
||||
userEditPermission={dataViews.getCanSaveSync()}
|
||||
/>
|
||||
)}
|
||||
</DeleteRuntimeFieldProvider>
|
||||
|
@ -472,6 +473,7 @@ export function Tabs({
|
|||
}}
|
||||
onRemoveField={refreshFilters}
|
||||
painlessDocLink={docLinks.links.scriptedFields.painless}
|
||||
userEditPermission={dataViews.getCanSaveSync()}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
|
@ -510,6 +512,7 @@ export function Tabs({
|
|||
refreshFields,
|
||||
overlays,
|
||||
theme,
|
||||
dataViews,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export async function mountManagementSection(
|
|||
params: ManagementAppMountParams
|
||||
) {
|
||||
const [
|
||||
{ chrome, application, uiSettings, notifications, overlays, http, docLinks, theme },
|
||||
{ chrome, uiSettings, notifications, overlays, http, docLinks, theme },
|
||||
{ data, dataViewFieldEditor, dataViewEditor, dataViews, fieldFormats },
|
||||
indexPatternManagementStart,
|
||||
] = await getStartServices();
|
||||
|
@ -51,7 +51,6 @@ export async function mountManagementSection(
|
|||
|
||||
const deps: IndexPatternManagmentContext = {
|
||||
chrome,
|
||||
application,
|
||||
uiSettings,
|
||||
notifications,
|
||||
overlays,
|
||||
|
|
|
@ -13,6 +13,7 @@ import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks';
|
|||
import { dataPluginMock } from '../../data/public/mocks';
|
||||
import { indexPatternFieldEditorPluginMock } from '../../data_view_field_editor/public/mocks';
|
||||
import { indexPatternEditorPluginMock } from '../../data_view_editor/public/mocks';
|
||||
import { dataViewPluginMocks } from '../../data_views/public/mocks';
|
||||
import {
|
||||
IndexPatternManagementSetup,
|
||||
IndexPatternManagementStart,
|
||||
|
@ -54,15 +55,14 @@ const docLinks = {
|
|||
const createIndexPatternManagmentContext = (): {
|
||||
[key in keyof IndexPatternManagmentContext]: any;
|
||||
} => {
|
||||
const { chrome, application, uiSettings, notifications, overlays } = coreMock.createStart();
|
||||
const { chrome, uiSettings, notifications, overlays } = coreMock.createStart();
|
||||
const { http } = coreMock.createSetup();
|
||||
const data = dataPluginMock.createStartContract();
|
||||
const dataViewFieldEditor = indexPatternFieldEditorPluginMock.createStartContract();
|
||||
const dataViews = data.indexPatterns;
|
||||
const dataViews = dataViewPluginMocks.createStartContract();
|
||||
|
||||
return {
|
||||
chrome,
|
||||
application,
|
||||
uiSettings,
|
||||
notifications,
|
||||
overlays,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
import {
|
||||
ChromeStart,
|
||||
ApplicationStart,
|
||||
IUiSettingsClient,
|
||||
OverlayStart,
|
||||
NotificationsStart,
|
||||
|
@ -26,7 +25,6 @@ import { FieldFormatsStart } from '../../field_formats/public';
|
|||
|
||||
export interface IndexPatternManagmentContext {
|
||||
chrome: ChromeStart;
|
||||
application: ApplicationStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
notifications: NotificationsStart;
|
||||
overlays: OverlayStart;
|
||||
|
|
|
@ -27,6 +27,7 @@ const createStartContract = (): Start => {
|
|||
}),
|
||||
get: jest.fn().mockReturnValue(Promise.resolve({})),
|
||||
clearCache: jest.fn(),
|
||||
getCanSaveSync: jest.fn(),
|
||||
} as unknown as jest.Mocked<DataViewsContract>;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue