[Dashboard] Fix Copy To Permission & Unskip RBAC tests (#100616)

* slightly better typing for dashboard permissions. Fixed typo, unskipped functional tests
This commit is contained in:
Devon Thomson 2021-06-03 11:58:25 -04:00 committed by GitHub
parent a9a9013120
commit a0c20ac7aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 58 additions and 31 deletions

View file

@ -32,6 +32,14 @@ export interface DashboardPanelState<
panelRefName?: string;
}
export interface DashboardCapabilities {
showWriteControls: boolean;
saveQuery: boolean;
createNew: boolean;
show: boolean;
[key: string]: boolean;
}
/**
* This should always represent the latest dashboard panel shape, after all possible migrations.
*/

View file

@ -21,7 +21,7 @@ import {
switchMap,
} from 'rxjs/operators';
import { DashboardCapabilities } from './types';
import { DashboardAppCapabilities } from './types';
import { DashboardConstants } from '../dashboard_constants';
import { DashboardStateManager } from './dashboard_state_manager';
import { convertSavedDashboardPanelToPanelState } from '../../common/embeddable/embeddable_saved_object_converters';
@ -103,7 +103,7 @@ export const getDashboardContainerInput = ({
dashboardStateManager,
dashboardCapabilities,
}: {
dashboardCapabilities: DashboardCapabilities;
dashboardCapabilities: DashboardAppCapabilities;
dashboardStateManager: DashboardStateManager;
incomingEmbeddable?: EmbeddablePackageState;
lastReloadRequestTime?: number;

View file

@ -37,11 +37,11 @@ import {
} from '../../services/kibana_react';
import { PLACEHOLDER_EMBEDDABLE } from './placeholder';
import { PanelPlacementMethod, IPanelPlacementArgs } from './panel/dashboard_panel_placement';
import { DashboardCapabilities } from '../types';
import { DashboardAppCapabilities } from '../types';
import { PresentationUtilPluginStart } from '../../services/presentation_util';
export interface DashboardContainerInput extends ContainerInput {
dashboardCapabilities?: DashboardCapabilities;
dashboardCapabilities?: DashboardAppCapabilities;
refreshConfig?: RefreshInterval;
isEmbeddedExternally?: boolean;
isFullScreenMode: boolean;
@ -91,7 +91,7 @@ export interface InheritedChildInput extends IndexSignature {
export type DashboardReactContextValue = KibanaReactContextValue<DashboardContainerServices>;
export type DashboardReactContext = KibanaReactContext<DashboardContainerServices>;
const defaultCapabilities: DashboardCapabilities = {
const defaultCapabilities: DashboardAppCapabilities = {
show: false,
createNew: false,
saveQuery: false,

View file

@ -590,10 +590,12 @@ exports[`DashboardEmptyScreen renders correctly with readonly mode 1`] = `
<PseudoLocaleWrapper>
<EuiPage
className="dshStartScreen"
data-test-subj="dashboardEmptyReadOnly"
restrictWidth="500px"
>
<div
className="euiPage euiPage--paddingMedium euiPage--grow euiPage--restrictWidth-custom dshStartScreen"
data-test-subj="dashboardEmptyReadOnly"
style={
Object {
"maxWidth": "500px",
@ -935,10 +937,12 @@ exports[`DashboardEmptyScreen renders correctly with view mode 1`] = `
<PseudoLocaleWrapper>
<EuiPage
className="dshStartScreen"
data-test-subj="dashboardEmptyReadWrite"
restrictWidth="500px"
>
<div
className="euiPage euiPage--paddingMedium euiPage--grow euiPage--restrictWidth-custom dshStartScreen"
data-test-subj="dashboardEmptyReadWrite"
style={
Object {
"maxWidth": "500px",

View file

@ -70,7 +70,11 @@ export function DashboardEmptyScreen({
);
const page = (mainText: string, showAdditionalParagraph?: boolean, additionalText?: string) => {
return (
<EuiPage className="dshStartScreen" restrictWidth="500px">
<EuiPage
data-test-subj={isReadonlyMode ? 'dashboardEmptyReadOnly' : 'dashboardEmptyReadWrite'}
className="dshStartScreen"
restrictWidth="500px"
>
<EuiPageBody>
<EuiPageContent
verticalPosition="center"

View file

@ -16,7 +16,7 @@ import { createKbnUrlStateStorage, defer } from '../../../../kibana_utils/public
import { createBrowserHistory } from 'history';
import { dataPluginMock } from '../../../../data/public/mocks';
import { embeddablePluginMock } from '../../../../embeddable/public/mocks';
import { DashboardCapabilities } from '../types';
import { DashboardAppCapabilities } from '../types';
import { EmbeddableFactory } from '../../../../embeddable/public';
import { HelloWorldEmbeddable } from '../../../../embeddable/public/tests/fixtures';
import { DashboardContainer } from '../embeddable';
@ -43,7 +43,7 @@ const createDashboardState = () =>
toasts: coreMock.createStart().notifications.toasts,
});
const defaultCapabilities: DashboardCapabilities = {
const defaultCapabilities: DashboardAppCapabilities = {
show: false,
createNew: false,
saveQuery: false,

View file

@ -24,7 +24,7 @@ import { savedObjectsPluginMock } from '../../../../saved_objects/public/mocks';
import { DashboardListing, DashboardListingProps } from './dashboard_listing';
import { embeddablePluginMock } from '../../../../embeddable/public/mocks';
import { visualizationsPluginMock } from '../../../../visualizations/public/mocks';
import { DashboardAppServices, DashboardCapabilities } from '../types';
import { DashboardAppServices, DashboardAppCapabilities } from '../types';
import { dataPluginMock } from '../../../../data/public/mocks';
import { chromeServiceMock, coreMock } from '../../../../../core/public/mocks';
import { I18nProvider } from '@kbn/i18n/react';
@ -59,7 +59,7 @@ function makeDefaultServices(): DashboardAppServices {
return {
savedObjects: savedObjectsPluginMock.createStartContract(),
embeddable: embeddablePluginMock.createInstance().doStart(),
dashboardCapabilities: {} as DashboardCapabilities,
dashboardCapabilities: {} as DashboardAppCapabilities,
initializerContext: {} as PluginInitializerContext,
chrome: chromeServiceMock.createStartContract(),
navigation: {} as NavigationPublicPluginStart,

View file

@ -16,7 +16,7 @@ import { SharePluginStart } from '../../services/share';
import { dashboardUrlParams } from '../dashboard_router';
import { DashboardStateManager } from '../dashboard_state_manager';
import { shareModalStrings } from '../../dashboard_strings';
import { DashboardCapabilities } from '../types';
import { DashboardAppCapabilities } from '../types';
const showFilterBarId = 'showFilterBar';
@ -24,14 +24,14 @@ interface ShowShareModalProps {
share: SharePluginStart;
anchorElement: HTMLElement;
savedDashboard: DashboardSavedObject;
dashboardCapabilities: DashboardCapabilities;
dashboardCapabilities: DashboardAppCapabilities;
dashboardStateManager: DashboardStateManager;
}
export const showPublicUrlSwitch = (anonymousUserCapabilities: Capabilities) => {
if (!anonymousUserCapabilities.dashboard) return false;
const dashboard = (anonymousUserCapabilities.dashboard as unknown) as DashboardCapabilities;
const dashboard = (anonymousUserCapabilities.dashboard as unknown) as DashboardAppCapabilities;
return !!dashboard.show;
};

View file

@ -49,7 +49,7 @@ export interface DashboardSaveOptions {
isTitleDuplicateConfirmed: boolean;
}
export interface DashboardCapabilities {
export interface DashboardAppCapabilities {
visualizeCapabilities: { save: boolean };
mapsCapabilities: { save: boolean };
hideWriteControls: boolean;
@ -77,7 +77,7 @@ export interface DashboardAppServices {
usageCollection?: UsageCollectionSetup;
navigation: NavigationPublicPluginStart;
dashboardPanelStorage: DashboardPanelStorage;
dashboardCapabilities: DashboardCapabilities;
dashboardCapabilities: DashboardAppCapabilities;
initializerContext: PluginInitializerContext;
onAppLeave: AppMountParameters['onAppLeave'];
savedObjectsTagging?: SavedObjectsTaggingApi;

View file

@ -65,6 +65,7 @@ import {
AddToLibraryAction,
LibraryNotificationAction,
CopyToDashboardAction,
DashboardCapabilities,
} from './application';
import {
createDashboardUrlGenerator,
@ -351,6 +352,9 @@ export class DashboardPlugin
const { notifications, overlays, application } = core;
const { uiActions, data, share, presentationUtil, embeddable } = plugins;
const dashboardCapabilities: Readonly<DashboardCapabilities> = application.capabilities
.dashboard as DashboardCapabilities;
const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, core.uiSettings);
const expandPanelAction = new ExpandPanelAction();
@ -395,8 +399,8 @@ export class DashboardPlugin
overlays,
embeddable.getStateTransfer(),
{
canCreateNew: Boolean(application.capabilities.dashboard.createNew),
canEditExisting: !Boolean(application.capabilities.dashboard.hideWriteControls),
canCreateNew: Boolean(dashboardCapabilities.createNew),
canEditExisting: Boolean(dashboardCapabilities.showWriteControls),
},
presentationUtil.ContextProvider
);

View file

@ -6,7 +6,11 @@
* Side Public License, v 1.
*/
export const capabilitiesProvider = () => ({
import { DashboardCapabilities } from '../common/types';
export const capabilitiesProvider = (): {
dashboard: DashboardCapabilities;
} => ({
dashboard: {
createNew: true,
show: true,

View file

@ -31,8 +31,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const queryBar = getService('queryBar');
const savedQueryManagementComponent = getService('savedQueryManagementComponent');
// FLAKY: https://github.com/elastic/kibana/issues/86950
describe.skip('dashboard feature controls security', () => {
describe('dashboard feature controls security', () => {
before(async () => {
await esArchiver.load('dashboard/feature_controls/security');
await esArchiver.loadIfNeeded('logstash_functional');
@ -86,7 +85,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('only shows the dashboard navlink', async () => {
const navLinks = await appsMenu.readLinks();
expect(navLinks.map((link) => link.text)).to.eql(['Overview', 'Dashboard']);
expect(navLinks.map((link) => link.text)).to.eql([
'Overview',
'Dashboard',
'Stack Management',
]);
});
it(`landing page shows "Create new Dashboard" button`, async () => {
@ -108,8 +111,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await globalNav.badgeMissingOrFail();
});
// Can't figure out how to get this test to pass
it.skip(`create new dashboard shows addNew button`, async () => {
it(`create new dashboard shows addNew button`, async () => {
await PageObjects.common.navigateToActualUrl(
'dashboard',
DashboardConstants.CREATE_NEW_DASHBOARD_URL,
@ -320,8 +322,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await globalNav.badgeExistsOrFail('Read only');
});
// Has this behavior changed?
it.skip(`create new dashboard redirects to the home page`, async () => {
it(`create new dashboard shows the read only warning`, async () => {
await PageObjects.common.navigateToActualUrl(
'dashboard',
DashboardConstants.CREATE_NEW_DASHBOARD_URL,
@ -330,7 +331,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
shouldLoginIfPrompted: false,
}
);
await testSubjects.existOrFail('homeApp', { timeout: 20000 });
await testSubjects.existOrFail('dashboardEmptyReadOnly', { timeout: 20000 });
});
it(`can view existing Dashboard`, async () => {
@ -347,6 +348,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
});
});
it('does not allow copy to dashboard behaviour', async () => {
await panelActions.expectMissingPanelAction('embeddablePanelAction-copyToDashboard');
});
it(`Permalinks doesn't show create short-url button`, async () => {
await PageObjects.share.openShareMenuItem('Permalinks');
await PageObjects.share.createShortUrlMissingOrFail();
@ -438,8 +443,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await globalNav.badgeExistsOrFail('Read only');
});
// Has this behavior changed?
it.skip(`create new dashboard redirects to the home page`, async () => {
it(`create new dashboard shows the read only warning`, async () => {
await PageObjects.common.navigateToActualUrl(
'dashboard',
DashboardConstants.CREATE_NEW_DASHBOARD_URL,
@ -448,7 +452,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
shouldLoginIfPrompted: false,
}
);
await testSubjects.existOrFail('homeApp', { timeout: 20000 });
await testSubjects.existOrFail('dashboardEmptyReadOnly', { timeout: 20000 });
});
it(`can view existing Dashboard`, async () => {

View file

@ -29,8 +29,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const security = getService('security');
const find = getService('find');
// flaky https://github.com/elastic/kibana/issues/98249
describe.skip('dashboard time to visualize security', () => {
describe('dashboard time to visualize security', () => {
before(async () => {
await esArchiver.load('dashboard/feature_controls/security');
await esArchiver.loadIfNeeded('logstash_functional');