Skip to content

Commit

Permalink
Disable create/destroy CTAs if no write capability
Browse files Browse the repository at this point in the history
Use `core.application.capabilities.ingestManager.write` to test user permissions
  • Loading branch information
John Schulz committed Mar 11, 2020
1 parent ab43d14 commit 518ae4e
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
} from '@elastic/eui';
import { Error } from '../../../components';
import { AGENT_CONFIG_PATH } from '../../../constants';
import { useLink } from '../../../hooks';
import { useCore, useLink } from '../../../hooks';
import { AgentConfig, PackageInfo, GetAgentConfigsResponseItem } from '../../../types';
import { useGetPackageInfoByKey, useGetAgentConfigs, sendGetOneAgentConfig } from '../../../hooks';

Expand All @@ -30,6 +30,7 @@ export const StepSelectConfig: React.FunctionComponent<{
cancelUrl: string;
onNext: () => void;
}> = ({ pkgkey, updatePackageInfo, agentConfig, updateAgentConfig, cancelUrl, onNext }) => {
const core = useCore();
// Selected config state
const [selectedConfigId, setSelectedConfigId] = useState<string | undefined>(
agentConfig ? agentConfig.id : undefined
Expand Down Expand Up @@ -134,7 +135,12 @@ export const StepSelectConfig: React.FunctionComponent<{
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="plusInCircle" href={CREATE_NEW_CONFIG_URI} size="s">
<EuiButtonEmpty
isDisabled={!core.application.capabilities.ingestManager.write}
iconType="plusInCircle"
href={CREATE_NEW_CONFIG_URI}
size="s"
>
<FormattedMessage
id="xpack.ingestManager.createDatasource.StepSelectConfig.createNewConfigButtonText"
defaultMessage="Create new configuration"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '@elastic/eui';
import { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab';
import styled from 'styled-components';
import { useGetOneAgentConfig } from '../../../hooks';
import { useCore, useGetOneAgentConfig } from '../../../hooks';
import { Datasource } from '../../../types';
import { Loading } from '../../../components';
import { WithHeaderLayout } from '../../../layouts';
Expand Down Expand Up @@ -57,6 +57,7 @@ export const AgentConfigDetailsLayout: React.FunctionComponent = () => {
const {
params: { configId, tabId = '' },
} = useRouteMatch<{ configId: string; tabId?: string }>();
const core = useCore();
const agentConfigRequest = useGetOneAgentConfig(configId);
const agentConfig = agentConfigRequest.data ? agentConfigRequest.data.item : null;
const { isLoading, error, sendRequest: refreshAgentConfig } = agentConfigRequest;
Expand Down Expand Up @@ -318,7 +319,12 @@ export const AgentConfigDetailsLayout: React.FunctionComponent = () => {
</h2>
}
actions={
<EuiButton fill iconType="plusInCircle" href={URI.ADD_DATASOURCE}>
<EuiButton
isDisabled={!core.application.capabilities.ingestManager.write}
fill
iconType="plusInCircle"
href={URI.ADD_DATASOURCE}
>
<FormattedMessage
id="xpack.ingestManager.configDetails.addDatasourceButtonText"
defaultMessage="Create data source"
Expand All @@ -330,7 +336,11 @@ export const AgentConfigDetailsLayout: React.FunctionComponent = () => {
}
search={{
toolsRight: [
<EuiButton iconType="plusInCircle" href={URI.ADD_DATASOURCE}>
<EuiButton
isDisabled={!core.application.capabilities.ingestManager.write}
iconType="plusInCircle"
href={URI.ADD_DATASOURCE}
>
<FormattedMessage
id="xpack.ingestManager.configDetails.addDatasourceButtonText"
defaultMessage="Create data source"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface Props {
}

export const CreateAgentConfigFlyout: React.FunctionComponent<Props> = ({ onClose }) => {
const { notifications } = useCore();
const { application, notifications } = useCore();

const [agentConfig, setAgentConfig] = useState<NewAgentConfig>({
name: '',
Expand Down Expand Up @@ -93,7 +93,11 @@ export const CreateAgentConfigFlyout: React.FunctionComponent<Props> = ({ onClos
<EuiButton
fill
isLoading={isLoading}
disabled={isLoading || Object.keys(validation).length > 0}
isDisabled={
!application.capabilities.ingestManager.write ||
isLoading ||
Object.keys(validation).length > 0
}
onClick={async () => {
setIsLoading(true);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from '../../../constants';
import { WithHeaderLayout } from '../../../layouts';
import {
useCore,
useGetAgentConfigs,
usePagination,
useLink,
Expand Down Expand Up @@ -87,6 +88,7 @@ const DangerEuiContextMenuItem = styled(EuiContextMenuItem)`

const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
({ config, onDelete }) => {
const core = useCore();
const DETAILS_URI = useLink(`${AGENT_CONFIG_DETAILS_PATH}${config.id}`);
const ADD_DATASOURCE_URI = `${DETAILS_URI}/add-datasource`;

Expand Down Expand Up @@ -120,6 +122,7 @@ const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
</EuiContextMenuItem>,

<EuiContextMenuItem
disabled={!core.application.capabilities.ingestManager.write}
icon="plusInCircle"
href={ADD_DATASOURCE_URI}
key="createDataSource"
Expand All @@ -130,7 +133,7 @@ const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(
/>
</EuiContextMenuItem>,

<EuiContextMenuItem icon="copy" disabled={true} key="copyConfig">
<EuiContextMenuItem icon="copy" key="copyConfig">
<FormattedMessage
id="xpack.ingestManager.agentConfigList.copyConfigActionText"
defaultMessage="Copy configuration"
Expand Down Expand Up @@ -162,6 +165,7 @@ const RowActions = React.memo<{ config: AgentConfig; onDelete: () => void }>(

export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
// Config information
const core = useCore();
const {
fleet: { enabled: isFleetEnabled },
} = useConfig();
Expand Down Expand Up @@ -309,6 +313,7 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
<EuiButton
fill
iconType="plusInCircle"
isDisabled={!core.application.capabilities.ingestManager.write}
onClick={() => setIsCreateAgentConfigFlyoutOpen(true)}
>
<FormattedMessage
Expand All @@ -317,7 +322,7 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
/>
</EuiButton>
),
[setIsCreateAgentConfigFlyoutOpen]
[core.application.capabilities.ingestManager.write, setIsCreateAgentConfigFlyoutOpen]
);

const emptyPrompt = useMemo(
Expand All @@ -331,7 +336,7 @@ export const AgentConfigListPage: React.FunctionComponent<{}> = () => {
/>
</h2>
}
actions={createAgentConfigButton}
actions={false ?? createAgentConfigButton}
/>
),
[createAgentConfigButton]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { EuiFlexGroup, EuiFlexItem, EuiPage, EuiTitle, IconType, EuiButton } from '@elastic/eui';
import { PackageInfo } from '../../../../types';
import { EPM_PATH } from '../../../../constants';
import { useLink } from '../../../../hooks';
import { useCore, useLink } from '../../../../hooks';
import { IconPanel } from '../../components/icon_panel';
import { NavButtonBack } from '../../components/nav_button_back';
import { Version } from '../../components/version';
Expand All @@ -34,6 +34,7 @@ type HeaderProps = PackageInfo & { iconType?: IconType };

export function Header(props: HeaderProps) {
const { iconType, name, title, version } = props;
const core = useCore();
const { toListView } = useLinks();
// useBreadcrumbs([{ text: PLUGIN.TITLE, href: toListView() }, { text: title }]);

Expand Down Expand Up @@ -61,7 +62,11 @@ export function Header(props: HeaderProps) {
<RightColumn>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton iconType="plusInCircle" href={ADD_DATASOURCE_URI}>
<EuiButton
isDisabled={!core.application.capabilities.ingestManager.write}
iconType="plusInCircle"
href={ADD_DATASOURCE_URI}
>
<FormattedMessage
id="xpack.ingestManager.epm.addDatasourceButtonText"
defaultMessage="Create data source"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { EuiButton } from '@elastic/eui';
import React, { Fragment, useCallback, useMemo, useState } from 'react';
import { PackageInfo, InstallStatus } from '../../../../types';
import { useCore } from '../../../../hooks';
import { useDeletePackage, useGetPackageInstallStatus, useInstallPackage } from '../../hooks';
import { ConfirmPackageDelete } from './confirm_package_delete';
import { ConfirmPackageInstall } from './confirm_package_install';
Expand All @@ -16,6 +17,7 @@ interface InstallationButtonProps {

export function InstallationButton(props: InstallationButtonProps) {
const { assets, name, title, version } = props.package;
const core = useCore();
const installPackage = useInstallPackage();
const deletePackage = useDeletePackage();
const getPackageInstallStatus = useGetPackageInstallStatus();
Expand Down Expand Up @@ -86,10 +88,10 @@ export function InstallationButton(props: InstallationButtonProps) {
/>
);

return (
return core.application.capabilities.ingestManager.write ? (
<Fragment>
{isInstalled ? installedButton : installButton}
{isModalVisible && (isInstalled ? deletionModal : installationModal)}
</Fragment>
);
) : null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { useAgentRefresh } from '../hooks';
import { AgentMetadataFlyout } from './metadata_flyout';
import { Agent } from '../../../../types';
import { AgentHealth } from '../../components/agent_health';
import { useGetOneAgentConfig } from '../../../../hooks';
import { useCore, useGetOneAgentConfig } from '../../../../hooks';
import { Loading } from '../../../../components';
import { ConnectedLink } from '../../components';
import { AgentUnenrollProvider } from '../../components/agent_unenroll_provider';
Expand Down Expand Up @@ -53,6 +53,7 @@ interface Props {
agent: Agent;
}
export const AgentDetailSection: React.FunctionComponent<Props> = ({ agent }) => {
const core = useCore();
const metadataFlyout = useFlyout();
const refreshAgent = useAgentRefresh();

Expand Down Expand Up @@ -125,7 +126,7 @@ export const AgentDetailSection: React.FunctionComponent<Props> = ({ agent }) =>
<AgentUnenrollProvider>
{unenrollAgentsPrompt => (
<EuiButton
disabled={!agent.active}
disabled={!core.application.capabilities.ingestManager.write || !agent.active}
onClick={() => {
unenrollAgentsPrompt([agent.id], 1, refreshAgent);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useEnrollmentApiKeys, useEnrollmentApiKey } from './hooks';
import { ConfirmDeleteModal } from './confirm_delete_modal';
import { CreateApiKeyForm } from './create_api_key_form';
import { EnrollmentAPIKey } from '../../../../../types';
import { useCore } from '../../../../../hooks';
import { enrollmentAPIKeyRouteService } from '../../../../../services';
export { useEnrollmentApiKeys, useEnrollmentApiKey } from './hooks';

Expand Down Expand Up @@ -98,13 +99,18 @@ export const EnrollmentApiKeysTable: React.FunctionComponent<{
export const CreateApiKeyButton: React.FunctionComponent<{ onChange: () => void }> = ({
onChange,
}) => {
const core = useCore();
const [isOpen, setIsOpen] = React.useState(false);

return (
<EuiPopover
ownFocus
button={
<EuiLink onClick={() => setIsOpen(true)} color="primary">
<EuiLink
disabled={!core.application.capabilities.ingestManager.write}
onClick={() => setIsOpen(true)}
color="primary"
>
<FormattedMessage
id="xpack.ingestManager.enrollmentApiKeyList.createNewButton"
defaultMessage="Create a new key"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const statusFilters = [
] as Array<{ label: string; status: string }>;

const RowActions = React.memo<{ agent: Agent; refresh: () => void }>(({ agent, refresh }) => {
const core = useCore();
const DETAILS_URI = useLink(FLEET_AGENT_DETAIL_PATH);
const [isOpen, setIsOpen] = useState(false);
const handleCloseMenu = useCallback(() => setIsOpen(false), [setIsOpen]);
Expand Down Expand Up @@ -118,6 +119,7 @@ const RowActions = React.memo<{ agent: Agent; refresh: () => void }>(({ agent, r
<AgentUnenrollProvider>
{unenrollAgentsPrompt => (
<EuiContextMenuItem
disabled={!core.application.capabilities.ingestManager.write}
icon="cross"
onClick={() => {
unenrollAgentsPrompt([agent.id], 1, () => {
Expand Down
12 changes: 12 additions & 0 deletions x-pack/plugins/ingest_manager/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import { SecurityPluginSetup } from '../../security/server';
import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server';
import {
PLUGIN_ID,
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
DATASOURCE_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
Expand Down Expand Up @@ -76,6 +80,10 @@ export class IngestManagerPlugin implements Plugin {
api: [PLUGIN_ID],
savedObject: {
all: [
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
DATASOURCE_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
Expand All @@ -89,6 +97,10 @@ export class IngestManagerPlugin implements Plugin {
savedObject: {
all: [],
read: [
OUTPUT_SAVED_OBJECT_TYPE,
AGENT_CONFIG_SAVED_OBJECT_TYPE,
DATASOURCE_SAVED_OBJECT_TYPE,
PACKAGES_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
Expand Down

0 comments on commit 518ae4e

Please sign in to comment.