[Fleet] UI changes on hosted policy detail view (#96337)

## Summary

Fixes several items from https://github.com/elastic/observability-design/issues/32

- Agent policy detail page
  - [x] Integrations tab: 1a) Show a lock icon with hover tooltip next to host policy name
  - [x] Integrations tab: 7a) hide the "Add integration" button
  - [x] Integrations tab: 7b) hide the "delete integration" action which appears in the [...] actions menu
  - [x] Settings tab: 5a) Do not show the “Delete policy” section for Hosted agent policies
  - [x] Settings tab: 5b) Disable the "name" and "description" inputs
 - Agents detail page
   - [x] 2b) remove the "actions" button in the page header (top right)

## Screenshots

<details><summary>Agent policy detail page - Integrations tab</summary>
<ul>
<li>1a) Show a lock icon with hover tooltip next to host policy name</li>
<li>7a) hide the "Add integration" button</li>
<li>7b) hide the "delete integration" action which appears in the [...] actions menu</li>
</ul>

<h3>Non-hosted policy</h3>
<img width="1186" alt="Screen Shot 2021-04-08 at 1 30 24 PM" src="https://user-images.githubusercontent.com/57655/114071393-0eade000-986f-11eb-847f-0c64c7d2aa5e.png">

<h3>Hosted policy</h3>
<img width="1184" alt="Screen Shot 2021-04-08 at 1 29 26 PM" src="https://user-images.githubusercontent.com/57655/114071389-0eade000-986f-11eb-9501-332509b0a85d.png">

</details>

<details><summary>Agent policy detail page - Settings tab</summary>

<ul>
<li>5a) Do not show the “Delete policy” section for Hosted agent policies</li>
<li>5b) Disable the "name" and "description" inputs</li>
</ul>

<h3>non-hosted policy: items available</h3>
<img width="1209" alt="Screen Shot 2021-04-07 at 1 24 39 PM" src="https://user-images.githubusercontent.com/57655/114069262-cdb4cc00-986c-11eb-84c8-926c98a75d47.png">

<h3>Hosted policy: items hidden / disabled</h3>
<img width="1228" alt="Screen Shot 2021-04-07 at 1 24 23 PM" src="https://user-images.githubusercontent.com/57655/114069259-cdb4cc00-986c-11eb-82fc-39509c6ef9fe.png">

</details>

<details><summary>Agents detail page: 2b) remove the "actions" button in the page header (top right)</summary>

<h4>shown on non-hosted policy</h4>
<img width="1408" alt="Screen Shot 2021-04-08 at 9 55 06 AM" src="https://user-images.githubusercontent.com/57655/114068747-38193c80-986c-11eb-9fb6-b8f9eb77a1d6.png">

<h4>hidden on hosted policy</h4>
<img width="1345" alt="Screen Shot 2021-04-08 at 9 55 31 AM" src="https://user-images.githubusercontent.com/57655/114068748-38b1d300-986c-11eb-9eee-ee15f8acd718.png">

</details>

### Checklist
- [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)


Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
John Schulz 2021-04-12 09:43:06 -04:00 committed by GitHub
parent 886d7e0140
commit c40121151f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 82 deletions

View file

@ -144,6 +144,7 @@ export const AgentPolicyForm: React.FunctionComponent<Props> = ({
isInvalid={Boolean(touchedFields[name] && validation[name])}
>
<EuiFieldText
disabled={agentPolicy.is_managed === true}
fullWidth
value={agentPolicy[name]}
onChange={(e) => updateAgentPolicy({ [name]: e.target.value })}
@ -283,7 +284,7 @@ export const AgentPolicyForm: React.FunctionComponent<Props> = ({
}}
/>
</EuiDescribedFormGroup>
{isEditing && 'id' in agentPolicy ? (
{isEditing && 'id' in agentPolicy && agentPolicy.is_managed !== true ? (
<EuiDescribedFormGroup
title={
<h4>

View file

@ -167,42 +167,45 @@ export const PackagePoliciesTable: React.FunctionComponent<Props> = ({
}),
actions: [
{
render: (packagePolicy: InMemoryPackagePolicy) => (
<ContextMenuActions
items={[
// FIXME: implement View package policy action
// <EuiContextMenuItem
// disabled
// icon="inspect"
// onClick={() => {}}
// key="packagePolicyView"
// >
// <FormattedMessage
// id="xpack.fleet.policyDetails.packagePoliciesTable.viewActionTitle"
// defaultMessage="View integration"
// />
// </EuiContextMenuItem>,
<EuiContextMenuItem
disabled={!hasWriteCapabilities}
icon="pencil"
href={getHref('edit_integration', {
policyId: agentPolicy.id,
packagePolicyId: packagePolicy.id,
})}
key="packagePolicyEdit"
>
<FormattedMessage
id="xpack.fleet.policyDetails.packagePoliciesTable.editActionTitle"
defaultMessage="Edit integration"
/>
</EuiContextMenuItem>,
// FIXME: implement Copy package policy action
// <EuiContextMenuItem disabled icon="copy" onClick={() => {}} key="packagePolicyCopy">
// <FormattedMessage
// id="xpack.fleet.policyDetails.packagePoliciesTable.copyActionTitle"
// defaultMessage="Copy integration"
// />
// </EuiContextMenuItem>,
render: (packagePolicy: InMemoryPackagePolicy) => {
const menuItems = [
// FIXME: implement View package policy action
// <EuiContextMenuItem
// disabled
// icon="inspect"
// onClick={() => {}}
// key="packagePolicyView"
// >
// <FormattedMessage
// id="xpack.fleet.policyDetails.packagePoliciesTable.viewActionTitle"
// defaultMessage="View integration"
// />
// </EuiContextMenuItem>,
<EuiContextMenuItem
disabled={!hasWriteCapabilities}
icon="pencil"
href={getHref('edit_integration', {
policyId: agentPolicy.id,
packagePolicyId: packagePolicy.id,
})}
key="packagePolicyEdit"
>
<FormattedMessage
id="xpack.fleet.policyDetails.packagePoliciesTable.editActionTitle"
defaultMessage="Edit integration"
/>
</EuiContextMenuItem>,
// FIXME: implement Copy package policy action
// <EuiContextMenuItem disabled icon="copy" onClick={() => {}} key="packagePolicyCopy">
// <FormattedMessage
// id="xpack.fleet.policyDetails.packagePoliciesTable.copyActionTitle"
// defaultMessage="Copy integration"
// />
// </EuiContextMenuItem>,
];
if (!agentPolicy.is_managed) {
menuItems.push(
<PackagePolicyDeleteProvider agentPolicy={agentPolicy} key="packagePolicyDelete">
{(deletePackagePoliciesPrompt) => {
return (
@ -220,10 +223,11 @@ export const PackagePoliciesTable: React.FunctionComponent<Props> = ({
</DangerEuiContextMenuItem>
);
}}
</PackagePolicyDeleteProvider>,
]}
/>
),
</PackagePolicyDeleteProvider>
);
}
return <ContextMenuActions items={menuItems} />;
},
},
],
},
@ -244,19 +248,21 @@ export const PackagePoliciesTable: React.FunctionComponent<Props> = ({
}}
{...rest}
search={{
toolsRight: [
<EuiButton
key="addPackagePolicyButton"
isDisabled={!hasWriteCapabilities}
iconType="plusInCircle"
href={getHref('add_integration_from_policy', { policyId: agentPolicy.id })}
>
<FormattedMessage
id="xpack.fleet.policyDetails.addPackagePolicyButtonText"
defaultMessage="Add integration"
/>
</EuiButton>,
],
toolsRight: agentPolicy.is_managed
? []
: [
<EuiButton
key="addPackagePolicyButton"
isDisabled={!hasWriteCapabilities}
iconType="plusInCircle"
href={getHref('add_integration_from_policy', { policyId: agentPolicy.id })}
>
<FormattedMessage
id="xpack.fleet.policyDetails.addPackagePolicyButtonText"
defaultMessage="Add integration"
/>
</EuiButton>,
],
box: {
incremental: true,
schema: true,

View file

@ -12,6 +12,8 @@ import { FormattedMessage, FormattedDate } from '@kbn/i18n/react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiIconTip,
EuiTitle,
EuiText,
EuiSpacer,
EuiButtonEmpty,
@ -84,23 +86,42 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => {
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem>
<EuiText className="eui-textBreakWord">
<h1>
{isLoading ? (
<Loading />
) : (
(agentPolicy && agentPolicy.name) || (
<FormattedMessage
id="xpack.fleet.policyDetails.policyDetailsTitle"
defaultMessage="Policy '{id}'"
values={{
id: policyId,
}}
{isLoading ? (
<Loading />
) : (
<EuiFlexGroup alignItems="center" wrap responsive={false} gutterSize="s">
<EuiFlexItem>
<EuiTitle>
<h1>
{(agentPolicy && agentPolicy.name) || (
<FormattedMessage
id="xpack.fleet.policyDetails.policyDetailsTitle"
defaultMessage="Policy '{id}'"
values={{ id: policyId }}
/>
)}
</h1>
</EuiTitle>
</EuiFlexItem>
{agentPolicy?.is_managed && (
<EuiFlexItem grow={false}>
<EuiIconTip
title="Managed agent policy"
content={i18n.translate(
'xpack.fleet.policyDetails.policyDetailsManagedPolicyTooltip',
{
defaultMessage:
'This policy is managed outside of Fleet. Most actions related to this policy are unavailable.',
}
)}
type="lock"
size="l"
color="subdued"
/>
)
</EuiFlexItem>
)}
</h1>
</EuiText>
</EuiFlexGroup>
)}
</EuiFlexItem>
{agentPolicy && agentPolicy.description ? (

View file

@ -194,17 +194,18 @@ export const AgentDetailsPage: React.FunctionComponent = () => {
),
},
{
content: (
<AgentDetailsActionMenu
agent={agentData.item}
assignFlyoutOpenByDefault={openReassignFlyoutOpenByDefault}
onCancelReassign={
routeState && routeState.onDoneNavigateTo
? reassignCancelClickHandler
: undefined
}
/>
),
content:
isAgentPolicyLoading || agentPolicyData?.item?.is_managed ? undefined : (
<AgentDetailsActionMenu
agent={agentData.item}
assignFlyoutOpenByDefault={openReassignFlyoutOpenByDefault}
onCancelReassign={
routeState && routeState.onDoneNavigateTo
? reassignCancelClickHandler
: undefined
}
/>
),
},
].map((item, index) => (
<EuiFlexItem grow={false} key={index}>

View file

@ -341,9 +341,10 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
const isAgentSelectable = (agent: Agent) => {
if (!agent.active) return false;
if (!agent.policy_id) return true;
const agentPolicy = agentPolicies.find((p) => p.id === agent.policy_id);
const isManaged = agent.policy_id && agentPolicy?.is_managed === true;
const agentPolicy = agentPoliciesIndexedById[agent.policy_id];
const isManaged = agentPolicy?.is_managed === true;
return !isManaged;
};