Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UnifiedSearch] Allow editing ad-hoc data views without permissions #142723

Merged
merged 7 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ const IndexPatternEditorFlyoutContentComponent = ({
services: { application, http, dataViews, uiSettings, overlays },
} = useKibana<DataViewEditorContext>();

const canSave = dataViews.getCanSaveSync();

const { form } = useForm<IndexPatternConfig, FormInternal>({
// Prefill with data if editData exists
defaultValue: {
Expand Down Expand Up @@ -447,6 +449,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
isEdit={!!editData}
isPersisted={Boolean(editData && editData.isPersisted())}
allowAdHoc={allowAdHoc}
canSave={canSave}
/>
</FlyoutPanels.Item>
<FlyoutPanels.Item>
Expand Down
34 changes: 19 additions & 15 deletions src/plugins/data_view_editor/public/components/footer/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface FooterProps {
isEdit: boolean;
isPersisted: boolean;
allowAdHoc: boolean;
canSave: boolean;
}

const closeButtonLabel = i18n.translate('indexPatternEditor.editor.flyoutCloseButtonLabel', {
Expand Down Expand Up @@ -56,6 +57,7 @@ export const Footer = ({
isEdit,
allowAdHoc,
isPersisted,
canSave,
}: FooterProps) => {
const submitPersisted = () => {
onSubmit(false);
Expand Down Expand Up @@ -96,21 +98,23 @@ export const Footer = ({
</EuiFlexItem>
)}

<EuiFlexItem grow={false}>
<EuiButton
color="primary"
onClick={submitPersisted}
data-test-subj="saveIndexPatternButton"
fill
disabled={submitDisabled}
>
{isEdit
? isPersisted
? editButtonLabel
: editUnpersistedButtonLabel
: saveButtonLabel}
</EuiButton>
</EuiFlexItem>
{(canSave || (isEdit && !isPersisted)) && (
<EuiFlexItem grow={false}>
<EuiButton
color="primary"
onClick={submitPersisted}
data-test-subj="saveIndexPatternButton"
fill
disabled={submitDisabled}
>
{isEdit
? isPersisted
? editButtonLabel
: editUnpersistedButtonLabel
: saveButtonLabel}
</EuiButton>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps)
const { dataViewFieldEditor, dataViewEditor } = services;
const { availableFields$ } = props;

const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView());
const canEditDataView =
Boolean(dataViewEditor?.userPermissions.editDataView()) || !selectedDataView?.isPersisted();

useEffect(
() => {
Expand Down Expand Up @@ -241,25 +242,19 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps)
]
);

const createNewDataView = useMemo(
() =>
canEditDataView
? () => {
const ref = dataViewEditor.openEditor({
onSave: async (dataView) => {
onDataViewCreated(dataView);
},
});
if (setDataViewEditorRef) {
setDataViewEditorRef(ref);
}
if (closeFlyout) {
closeFlyout();
}
}
: undefined,
[canEditDataView, dataViewEditor, setDataViewEditorRef, closeFlyout, onDataViewCreated]
);
const createNewDataView = useCallback(() => {
const ref = dataViewEditor.openEditor({
onSave: async (dataView) => {
onDataViewCreated(dataView);
},
});
if (setDataViewEditorRef) {
setDataViewEditorRef(ref);
}
if (closeFlyout) {
closeFlyout();
}
}, [dataViewEditor, setDataViewEditorRef, closeFlyout, onDataViewCreated]);

if (!selectedDataView) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export const DiscoverTopNav = ({
const services = useDiscoverServices();
const { dataViewEditor, navigation, dataViewFieldEditor, data, uiSettings, dataViews } = services;

const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView());
const canEditDataView =
Boolean(dataViewEditor?.userPermissions.editDataView()) || !dataView.isPersisted();

const closeFieldEditor = useRef<() => void | undefined>();
const closeDataViewEditor = useRef<() => void | undefined>();
Expand Down Expand Up @@ -124,22 +125,16 @@ export const DiscoverTopNav = ({
[editField, canEditDataView]
);

const createNewDataView = useMemo(
() =>
canEditDataView
? () => {
closeDataViewEditor.current = dataViewEditor.openEditor({
onSave: async (dataViewToSave) => {
if (dataViewToSave.id) {
onChangeDataView(dataViewToSave.id);
}
},
allowAdHocDataView: true,
});
}
: undefined,
[canEditDataView, dataViewEditor, onChangeDataView]
);
const createNewDataView = useCallback(() => {
closeDataViewEditor.current = dataViewEditor.openEditor({
onSave: async (dataViewToSave) => {
if (dataViewToSave.id) {
onChangeDataView(dataViewToSave.id);
}
},
allowAdHocDataView: true,
});
}, [dataViewEditor, onChangeDataView]);

const onCreateDefaultAdHocDataView = useCallback(
async (pattern: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { mountWithIntl as mount } from '@kbn/test-jest-helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { indexPatternEditorPluginMock as dataViewEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks';
import { ChangeDataView } from './change_dataview';
import { DataViewPickerPropsExtended, TextBasedLanguages } from '.';

Expand Down Expand Up @@ -44,6 +45,8 @@ describe('DataView component', () => {
storageValue: boolean,
uiSettingValue: boolean = false
) {
const dataViewEditorMock = dataViewEditorPluginMock.createStartContract();
(dataViewEditorMock.userPermissions.editDataView as jest.Mock).mockReturnValue(true);
let dataMock = dataPluginMock.createStartContract();
dataMock = {
...dataMock,
Expand All @@ -56,6 +59,7 @@ describe('DataView component', () => {
const services = {
data: dataMock,
storage: getStorage(storageValue),
dataViewEditor: dataViewEditorMock,
uiSettings: {
get: jest.fn(() => uiSettingValue),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,31 +190,35 @@ export function ChangeDataView({
defaultMessage: 'Add a field to this data view',
})}
</EuiContextMenuItem>,
<EuiContextMenuItem
key="manage"
icon="indexSettings"
data-test-subj="indexPattern-manage-field"
onClick={async () => {
if (onEditDataView) {
const dataView = await dataViews.get(currentDataViewId!);
dataViewEditor.openEditor({
editData: dataView,
onSave: (updatedDataView) => {
onEditDataView(updatedDataView);
},
});
} else {
application.navigateToApp('management', {
path: `/kibana/indexPatterns/patterns/${currentDataViewId}`,
});
}
setPopoverIsOpen(false);
}}
>
{i18n.translate('unifiedSearch.query.queryBar.indexPattern.manageFieldButton', {
defaultMessage: 'Manage this data view',
})}
</EuiContextMenuItem>,
onEditDataView || dataViewEditor.userPermissions.editDataView() ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readabiily nit: move this outside this .push and add a separate if check

<EuiContextMenuItem
key="manage"
icon="indexSettings"
data-test-subj="indexPattern-manage-field"
onClick={async () => {
if (onEditDataView) {
const dataView = await dataViews.get(currentDataViewId!);
dataViewEditor.openEditor({
editData: dataView,
onSave: (updatedDataView) => {
onEditDataView(updatedDataView);
},
});
} else {
application.navigateToApp('management', {
path: `/kibana/indexPatterns/patterns/${currentDataViewId}`,
});
}
setPopoverIsOpen(false);
}}
>
{i18n.translate('unifiedSearch.query.queryBar.indexPattern.manageFieldButton', {
defaultMessage: 'Manage this data view',
})}
</EuiContextMenuItem>
) : (
<React.Fragment />
),
<EuiHorizontalRule margin="none" />
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React from 'react';
import SearchBar from './search_bar';

import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { indexPatternEditorPluginMock as dataViewEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks';
import { I18nProvider } from '@kbn/i18n-react';

import { coreMock } from '@kbn/core/public/mocks';
Expand Down Expand Up @@ -83,6 +84,9 @@ function wrapSearchBarInContext(testProps: any) {
intl: null as any,
};

const dataViewEditorMock = dataViewEditorPluginMock.createStartContract();
(dataViewEditorMock.userPermissions.editDataView as jest.Mock).mockReturnValue(true);

const services = {
uiSettings: startMock.uiSettings,
savedObjects: startMock.savedObjects,
Expand Down Expand Up @@ -111,6 +115,7 @@ function wrapSearchBarInContext(testProps: any) {
}),
},
},
dataViewEditor: dataViewEditorMock,
dataViews: {
getIdsWithTitle: jest.fn(() => []),
},
Expand Down
33 changes: 0 additions & 33 deletions x-pack/plugins/lens/public/app_plugin/app.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -405,39 +405,6 @@ describe('Lens App', () => {
});

describe('TopNavMenu#dataViewPickerProps', () => {
it('calls the nav component with the correct dataview picker props if no permissions are given', async () => {
const { instance, lensStore } = await mountWith({ preloadedState: {} });
const document = {
savedObjectId: defaultSavedObjectId,
state: {
query: 'fake query',
filters: [{ query: { match_phrase: { src: 'test' } } }],
},
references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }],
} as unknown as Document;

act(() => {
lensStore.dispatch(
setState({
query: 'fake query' as unknown as Query,
persistedDoc: document,
})
);
});
instance.update();
const props = instance
.find('[data-test-subj="lnsApp_topNav"]')
.prop('dataViewPickerComponentProps') as TopNavMenuData[];
expect(props).toEqual(
expect.objectContaining({
currentDataViewId: 'mockip',
onChangeDataView: expect.any(Function),
onDataViewCreated: undefined,
onAddField: undefined,
})
);
});

it('calls the nav component with the correct dataview picker props if permissions are given', async () => {
const { instance, lensStore, services } = await mountWith({ preloadedState: {} });
services.dataViewEditor.userPermissions.editDataView = () => true;
Expand Down
60 changes: 27 additions & 33 deletions x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ export const LensTopNavMenu = ({
]
);

const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView());
const canEditDataView =
Boolean(dataViewEditor?.userPermissions.editDataView()) || !currentIndexPattern?.isPersisted();
const closeFieldEditor = useRef<() => void | undefined>();
const closeDataViewEditor = useRef<() => void | undefined>();

Expand Down Expand Up @@ -756,39 +757,32 @@ export const LensTopNavMenu = ({
[editField, canEditDataView]
);

const createNewDataView = useMemo(
() =>
canEditDataView
? () => {
closeDataViewEditor.current = dataViewEditor.openEditor({
onSave: async (dataView) => {
if (dataView.id) {
if (isOnTextBasedMode) {
dispatch(
switchAndCleanDatasource({
newDatasourceId: 'indexpattern',
visualizationId: visualization?.activeId,
currentIndexPatternId: dataView?.id,
})
);
}
dispatchChangeIndexPattern(dataView);
setCurrentIndexPattern(dataView);
}
},
allowAdHocDataView: true,
});
const createNewDataView = useCallback(() => {
closeDataViewEditor.current = dataViewEditor.openEditor({
onSave: async (dataView) => {
if (dataView.id) {
if (isOnTextBasedMode) {
dispatch(
switchAndCleanDatasource({
newDatasourceId: 'indexpattern',
visualizationId: visualization?.activeId,
currentIndexPatternId: dataView?.id,
})
);
}
: undefined,
[
canEditDataView,
dataViewEditor,
dispatch,
dispatchChangeIndexPattern,
isOnTextBasedMode,
visualization?.activeId,
]
);
dispatchChangeIndexPattern(dataView);
setCurrentIndexPattern(dataView);
}
},
allowAdHocDataView: true,
});
}, [
dataViewEditor,
dispatch,
dispatchChangeIndexPattern,
isOnTextBasedMode,
visualization?.activeId,
]);

const onCreateDefaultAdHocDataView = useCallback(
async (pattern: string) => {
Expand Down
Loading