[Upgrade Assistant] Improve flyout information architecture (#111713)

* Make sure longstrings inside flyout body are text-wrap

* Show resolved badge for reindex flyout and row

* Finish off rest of ES deprecation flyouts

* Refactor deprecation badge into its own component

* Add tests for kibana deprecations

* Add tests for es deprecations

* Also check that we have status=error before rendering error callout

* Check for non-complete states instead of just error

* Small refactor

* Default deprecation is not resolvable

* Add a bit more spacing between title and badge

* Address CR changes

* Use EuiSpacer instead of flexitems
This commit is contained in:
Ignacio Rivas 2021-09-15 12:31:41 +02:00 committed by GitHub
parent a49c70bdf7
commit 70f2677213
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 171 additions and 143 deletions

View file

@ -25845,7 +25845,6 @@
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "再インデックスはバックグラウンドで継続しますが、Kibana がシャットダウンまたは再起動した場合、このページに戻り再インデックスを再開させる必要があります。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "再インデックスはバックグラウンドで継続しますが、Kibana がシャットダウンまたは再起動した場合、このページに戻り再インデックスを再開させる必要があります。",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.calloutTitle": "インデックスは再インデックス中にドキュメントを投入、更新、または削除できません", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.calloutTitle": "インデックスは再インデックス中にドキュメントを投入、更新、または削除できません",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.cantStopDetail": "ドキュメントの更新を停止できない場合、または新しいクラスターに再インデックスする必要がある場合は、異なるアップグレード方法をお勧めします。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.cantStopDetail": "ドキュメントの更新を停止できない場合、または新しいクラスターに再インデックスする必要がある場合は、異なるアップグレード方法をお勧めします。",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.doneLabel": "完了!",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.reindexingLabel": "再インデックス中…", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.reindexingLabel": "再インデックス中…",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.resumeLabel": "再開", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.resumeLabel": "再開",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.runReindexLabel": "再インデックスを実行", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.runReindexLabel": "再インデックスを実行",

View file

@ -26280,7 +26280,6 @@
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "重新索引将在后台继续,但如果 Kibana 关闭或重新启动,您将需要返回此页,才能恢复重新索引。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "重新索引将在后台继续,但如果 Kibana 关闭或重新启动,您将需要返回此页,才能恢复重新索引。",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.calloutTitle": "在重新索引时,索引无法采集、更新或删除文档", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.calloutTitle": "在重新索引时,索引无法采集、更新或删除文档",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.cantStopDetail": "如果您无法停止文档更新或需要重新索引到新的集群中,请考虑使用不同的升级策略。", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.readonlyCallout.cantStopDetail": "如果您无法停止文档更新或需要重新索引到新的集群中,请考虑使用不同的升级策略。",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.doneLabel": "已完成!",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.reindexingLabel": "正在重新索引……", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.reindexingLabel": "正在重新索引……",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.resumeLabel": "恢复", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.resumeLabel": "恢复",
"xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.runReindexLabel": "运行重新索引", "xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.runReindexLabel": "运行重新索引",

View file

@ -47,12 +47,14 @@ describe('Index settings deprecation flyout', () => {
}); });
it('removes deprecated index settings', async () => { it('removes deprecated index settings', async () => {
const { find, actions } = testBed; const { find, actions, exists } = testBed;
httpRequestsMockHelpers.setUpdateIndexSettingsResponse({ httpRequestsMockHelpers.setUpdateIndexSettingsResponse({
acknowledged: true, acknowledged: true,
}); });
expect(exists('indexSettingsDetails.warningDeprecationBadge')).toBe(true);
await actions.indexSettingsDeprecationFlyout.clickDeleteSettingsButton(); await actions.indexSettingsDeprecationFlyout.clickDeleteSettingsButton();
const request = server.requests[server.requests.length - 1]; const request = server.requests[server.requests.length - 1];
@ -75,6 +77,8 @@ describe('Index settings deprecation flyout', () => {
expect(find('removeSettingsPrompt').length).toEqual(0); expect(find('removeSettingsPrompt').length).toEqual(0);
// Verify the action button no longer displays // Verify the action button no longer displays
expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0); expect(find('indexSettingsDetails.deleteSettingsButton').length).toEqual(0);
// Verify the badge got marked as resolved
expect(exists('indexSettingsDetails.resolvedDeprecationBadge')).toBe(true);
}); });
it('handles failure', async () => { it('handles failure', async () => {

View file

@ -48,7 +48,7 @@ describe('Machine learning deprecation flyout', () => {
describe('upgrade snapshots', () => { describe('upgrade snapshots', () => {
it('successfully upgrades snapshots', async () => { it('successfully upgrades snapshots', async () => {
const { find, actions } = testBed; const { find, actions, exists } = testBed;
httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({ httpRequestsMockHelpers.setUpgradeMlSnapshotResponse({
nodeId: 'my_node', nodeId: 'my_node',
@ -64,6 +64,7 @@ describe('Machine learning deprecation flyout', () => {
status: 'complete', status: 'complete',
}); });
expect(exists('mlSnapshotDetails.criticalDeprecationBadge')).toBe(true);
expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade'); expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toEqual('Upgrade');
await actions.mlDeprecationFlyout.clickUpgradeSnapshot(); await actions.mlDeprecationFlyout.clickUpgradeSnapshot();
@ -86,10 +87,11 @@ describe('Machine learning deprecation flyout', () => {
// Reopen the flyout // Reopen the flyout
await actions.table.clickDeprecationRowAt('mlSnapshot', 0); await actions.table.clickDeprecationRowAt('mlSnapshot', 0);
// Flyout actions should be disabled if deprecation was resolved // Flyout actions should be hidden if deprecation was resolved
expect(find('mlSnapshotDetails.upgradeSnapshotButton').props().disabled).toBe(true); expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false);
expect(find('mlSnapshotDetails.upgradeSnapshotButton').text()).toContain('Upgrade complete'); expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false);
expect(find('mlSnapshotDetails.deleteSnapshotButton').props().disabled).toBe(true); // Badge should be updated in flyout title
expect(exists('mlSnapshotDetails.resolvedDeprecationBadge')).toBe(true);
}); });
it('handles upgrade failure', async () => { it('handles upgrade failure', async () => {
@ -133,12 +135,13 @@ describe('Machine learning deprecation flyout', () => {
describe('delete snapshots', () => { describe('delete snapshots', () => {
it('successfully deletes snapshots', async () => { it('successfully deletes snapshots', async () => {
const { find, actions } = testBed; const { find, actions, exists } = testBed;
httpRequestsMockHelpers.setDeleteMlSnapshotResponse({ httpRequestsMockHelpers.setDeleteMlSnapshotResponse({
acknowledged: true, acknowledged: true,
}); });
expect(exists('mlSnapshotDetails.criticalDeprecationBadge')).toBe(true);
expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete'); expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toEqual('Delete');
await actions.mlDeprecationFlyout.clickDeleteSnapshot(); await actions.mlDeprecationFlyout.clickDeleteSnapshot();
@ -158,10 +161,11 @@ describe('Machine learning deprecation flyout', () => {
// Reopen the flyout // Reopen the flyout
await actions.table.clickDeprecationRowAt('mlSnapshot', 0); await actions.table.clickDeprecationRowAt('mlSnapshot', 0);
// Flyout actions should be disabled if deprecation was resolved // Flyout actions should be hidden if deprecation was resolved
expect(find('mlSnapshotDetails.deleteSnapshotButton').props().disabled).toBe(true); expect(exists('mlSnapshotDetails.upgradeSnapshotButton')).toBe(false);
expect(find('mlSnapshotDetails.deleteSnapshotButton').text()).toContain('Deletion complete'); expect(exists('mlSnapshotDetails.deleteSnapshotButton')).toBe(false);
expect(find('mlSnapshotDetails.upgradeSnapshotButton').props().disabled).toBe(true); // Badge should be updated in flyout title
expect(exists('mlSnapshotDetails.resolvedDeprecationBadge')).toBe(true);
}); });
it('handles delete failure', async () => { it('handles delete failure', async () => {

View file

@ -47,6 +47,7 @@ describe('Kibana deprecation details flyout', () => {
await actions.table.clickDeprecationAt(1); await actions.table.clickDeprecationAt(1);
expect(exists('kibanaDeprecationDetails')).toBe(true); expect(exists('kibanaDeprecationDetails')).toBe(true);
expect(exists('kibanaDeprecationDetails.warningDeprecationBadge')).toBe(true);
expect(find('kibanaDeprecationDetails.flyoutTitle').text()).toBe(manualDeprecation.title); expect(find('kibanaDeprecationDetails.flyoutTitle').text()).toBe(manualDeprecation.title);
expect(find('manualStepsList').find('li').length).toEqual( expect(find('manualStepsList').find('li').length).toEqual(
manualDeprecation.correctiveActions.manualSteps.length manualDeprecation.correctiveActions.manualSteps.length
@ -66,6 +67,7 @@ describe('Kibana deprecation details flyout', () => {
await actions.table.clickDeprecationAt(0); await actions.table.clickDeprecationAt(0);
expect(exists('kibanaDeprecationDetails')).toBe(true); expect(exists('kibanaDeprecationDetails')).toBe(true);
expect(exists('kibanaDeprecationDetails.criticalDeprecationBadge')).toBe(true);
expect(find('kibanaDeprecationDetails.flyoutTitle').text()).toBe( expect(find('kibanaDeprecationDetails.flyoutTitle').text()).toBe(
quickResolveDeprecation.title quickResolveDeprecation.title
); );
@ -87,8 +89,9 @@ describe('Kibana deprecation details flyout', () => {
// Resolve information should not display and Quick resolve button should be disabled // Resolve information should not display and Quick resolve button should be disabled
expect(exists('resolveSection')).toBe(false); expect(exists('resolveSection')).toBe(false);
expect(find('resolveButton').props().disabled).toBe(true); expect(exists('resolveButton')).toBe(false);
expect(find('resolveButton').text()).toContain('Resolved'); // Badge should be updated in flyout title
expect(exists('kibanaDeprecationDetails.resolvedDeprecationBadge')).toBe(true);
}); });
test('handles resolve failure', async () => { test('handles resolve failure', async () => {
@ -103,6 +106,7 @@ describe('Kibana deprecation details flyout', () => {
await actions.table.clickDeprecationAt(0); await actions.table.clickDeprecationAt(0);
expect(exists('kibanaDeprecationDetails')).toBe(true); expect(exists('kibanaDeprecationDetails')).toBe(true);
expect(exists('kibanaDeprecationDetails.criticalDeprecationBadge')).toBe(true);
expect(find('kibanaDeprecationDetails.flyoutTitle').text()).toBe( expect(find('kibanaDeprecationDetails.flyoutTitle').text()).toBe(
quickResolveDeprecation.title quickResolveDeprecation.title
); );
@ -123,6 +127,8 @@ describe('Kibana deprecation details flyout', () => {
expect(exists('quickResolveError')).toBe(true); expect(exists('quickResolveError')).toBe(true);
// Resolve information should display and Quick resolve button should be enabled // Resolve information should display and Quick resolve button should be enabled
expect(exists('resolveSection')).toBe(true); expect(exists('resolveSection')).toBe(true);
// Badge should remain the same
expect(exists('kibanaDeprecationDetails.criticalDeprecationBadge')).toBe(true);
expect(find('resolveButton').props().disabled).toBe(false); expect(find('resolveButton').props().disabled).toBe(false);
expect(find('resolveButton').text()).toContain('Try again'); expect(find('resolveButton').text()).toContain('Try again');
}); });

View file

@ -18,9 +18,11 @@ import {
EuiText, EuiText,
EuiTextColor, EuiTextColor,
EuiLink, EuiLink,
EuiSpacer,
} from '@elastic/eui'; } from '@elastic/eui';
import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import { DeprecationBadge } from '../../../shared';
export interface DefaultDeprecationFlyoutProps { export interface DefaultDeprecationFlyoutProps {
deprecation: EnrichedDeprecationInfo; deprecation: EnrichedDeprecationInfo;
@ -61,10 +63,10 @@ export const DefaultDeprecationFlyout = ({
return ( return (
<> <>
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.isCritical} isResolved={false} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle"> <EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="defaultDeprecationDetailsFlyoutTitle" className="eui-textBreakWord"> <h2 id="defaultDeprecationDetailsFlyoutTitle">{message}</h2>
{message}
</h2>
</EuiTitle> </EuiTitle>
{index && ( {index && (
<EuiText data-test-subj="flyoutDescription"> <EuiText data-test-subj="flyoutDescription">

View file

@ -44,6 +44,7 @@ export const DefaultTableRow: React.FunctionComponent<Props> = ({ rowFieldNames,
}, },
flyoutProps: { flyoutProps: {
onClose: closeFlyout, onClose: closeFlyout,
className: 'eui-textBreakWord',
'data-test-subj': 'defaultDeprecationDetails', 'data-test-subj': 'defaultDeprecationDetails',
'aria-labelledby': 'defaultDeprecationDetailsFlyoutTitle', 'aria-labelledby': 'defaultDeprecationDetailsFlyoutTitle',
}, },
@ -62,8 +63,8 @@ export const DefaultTableRow: React.FunctionComponent<Props> = ({ rowFieldNames,
> >
<EsDeprecationsTableCells <EsDeprecationsTableCells
fieldName={field} fieldName={field}
openFlyout={() => setShowFlyout(true)}
deprecation={deprecation} deprecation={deprecation}
openFlyout={() => setShowFlyout(true)}
/> />
</EuiTableRowCell> </EuiTableRowCell>
); );

View file

@ -26,6 +26,7 @@ import {
import { EnrichedDeprecationInfo, IndexSettingAction } from '../../../../../../common/types'; import { EnrichedDeprecationInfo, IndexSettingAction } from '../../../../../../common/types';
import type { ResponseError } from '../../../../lib/api'; import type { ResponseError } from '../../../../lib/api';
import type { Status } from '../../../types'; import type { Status } from '../../../types';
import { DeprecationBadge } from '../../../shared';
export interface RemoveIndexSettingsFlyoutProps { export interface RemoveIndexSettingsFlyoutProps {
deprecation: EnrichedDeprecationInfo; deprecation: EnrichedDeprecationInfo;
@ -109,6 +110,11 @@ export const RemoveIndexSettingsFlyout = ({
return ( return (
<> <>
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<DeprecationBadge
isCritical={deprecation.isCritical}
isResolved={statusType === 'complete'}
/>
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle"> <EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="indexSettingsDetailsFlyoutTitle">{message}</h2> <h2 id="indexSettingsDetailsFlyoutTitle">{message}</h2>
</EuiTitle> </EuiTitle>

View file

@ -75,6 +75,7 @@ export const IndexSettingsTableRow: React.FunctionComponent<Props> = ({
}, },
flyoutProps: { flyoutProps: {
onClose: closeFlyout, onClose: closeFlyout,
className: 'eui-textBreakWord',
'data-test-subj': 'indexSettingsDetails', 'data-test-subj': 'indexSettingsDetails',
'aria-labelledby': 'indexSettingsDetailsFlyoutTitle', 'aria-labelledby': 'indexSettingsDetailsFlyoutTitle',
}, },

View file

@ -24,6 +24,7 @@ import {
} from '@elastic/eui'; } from '@elastic/eui';
import { EnrichedDeprecationInfo } from '../../../../../../common/types'; import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import { DeprecationBadge } from '../../../shared';
import { MlSnapshotContext } from './context'; import { MlSnapshotContext } from './context';
import { SnapshotState } from './use_snapshot_state'; import { SnapshotState } from './use_snapshot_state';
@ -51,12 +52,6 @@ const i18nTexts = {
defaultMessage: 'Retry upgrade', defaultMessage: 'Retry upgrade',
} }
), ),
upgradeResolvedButtonLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteResolvupgradeResolvedButtonLabeledButtonLabel',
{
defaultMessage: 'Upgrade complete',
}
),
closeButtonLabel: i18n.translate( closeButtonLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.closeButtonLabel', 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.closeButtonLabel',
{ {
@ -75,12 +70,6 @@ const i18nTexts = {
defaultMessage: 'Deleting…', defaultMessage: 'Deleting…',
} }
), ),
deleteResolvedButtonLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.deleteResolvedButtonLabel',
{
defaultMessage: 'Deletion complete',
}
),
retryDeleteButtonLabel: i18n.translate( retryDeleteButtonLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryDeleteButtonLabel', 'xpack.upgradeAssistant.esDeprecations.mlSnapshots.flyout.retryDeleteButtonLabel',
{ {
@ -119,8 +108,6 @@ const getDeleteButtonLabel = (snapshotState: SnapshotState) => {
switch (snapshotState.status) { switch (snapshotState.status) {
case 'in_progress': case 'in_progress':
return i18nTexts.deletingButtonLabel; return i18nTexts.deletingButtonLabel;
case 'complete':
return i18nTexts.deleteResolvedButtonLabel;
case 'idle': case 'idle':
default: default:
return i18nTexts.deleteButtonLabel; return i18nTexts.deleteButtonLabel;
@ -138,8 +125,6 @@ const getUpgradeButtonLabel = (snapshotState: SnapshotState) => {
switch (snapshotState.status) { switch (snapshotState.status) {
case 'in_progress': case 'in_progress':
return i18nTexts.upgradingButtonLabel; return i18nTexts.upgradingButtonLabel;
case 'complete':
return i18nTexts.upgradeResolvedButtonLabel;
case 'idle': case 'idle':
default: default:
return i18nTexts.upgradeButtonLabel; return i18nTexts.upgradeButtonLabel;
@ -155,6 +140,8 @@ export const FixSnapshotsFlyout = ({
upgradeSnapshot, upgradeSnapshot,
deleteSnapshot, deleteSnapshot,
}: FixSnapshotsFlyoutProps) => { }: FixSnapshotsFlyoutProps) => {
const isResolved = snapshotState.status === 'complete';
const onUpgradeSnapshot = () => { const onUpgradeSnapshot = () => {
upgradeSnapshot(); upgradeSnapshot();
closeFlyout(); closeFlyout();
@ -168,12 +155,14 @@ export const FixSnapshotsFlyout = ({
return ( return (
<> <>
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.isCritical} isResolved={isResolved} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle"> <EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="mlSnapshotDetailsFlyoutTitle">{i18nTexts.flyoutTitle}</h2> <h2 id="mlSnapshotDetailsFlyoutTitle">{i18nTexts.flyoutTitle}</h2>
</EuiTitle> </EuiTitle>
</EuiFlyoutHeader> </EuiFlyoutHeader>
<EuiFlyoutBody> <EuiFlyoutBody>
{snapshotState.error && ( {snapshotState.error && !isResolved && (
<> <>
<EuiCallOut <EuiCallOut
title={ title={
@ -207,40 +196,38 @@ export const FixSnapshotsFlyout = ({
</EuiButtonEmpty> </EuiButtonEmpty>
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem grow={false}> {!isResolved && (
<EuiFlexGroup> <EuiFlexItem grow={false}>
<EuiFlexItem> <EuiFlexGroup>
<EuiButtonEmpty <EuiFlexItem>
data-test-subj="deleteSnapshotButton" <EuiButtonEmpty
color="danger" data-test-subj="deleteSnapshotButton"
onClick={onDeleteSnapshot} color="danger"
isLoading={ onClick={onDeleteSnapshot}
snapshotState.action === 'delete' && snapshotState.status === 'in_progress' isLoading={
} snapshotState.action === 'delete' && snapshotState.status === 'in_progress'
disabled={ }
snapshotState.status === 'in_progress' || snapshotState.status === 'complete' isDisabled={snapshotState.status === 'in_progress'}
} >
> {getDeleteButtonLabel(snapshotState)}
{getDeleteButtonLabel(snapshotState)} </EuiButtonEmpty>
</EuiButtonEmpty> </EuiFlexItem>
</EuiFlexItem> <EuiFlexItem>
<EuiFlexItem> <EuiButton
<EuiButton fill
fill onClick={onUpgradeSnapshot}
onClick={onUpgradeSnapshot} isLoading={
isLoading={ snapshotState.action === 'upgrade' && snapshotState.status === 'in_progress'
snapshotState.action === 'upgrade' && snapshotState.status === 'in_progress' }
} isDisabled={snapshotState.status === 'in_progress'}
disabled={ data-test-subj="upgradeSnapshotButton"
snapshotState.status === 'in_progress' || snapshotState.status === 'complete' >
} {getUpgradeButtonLabel(snapshotState)}
data-test-subj="upgradeSnapshotButton" </EuiButton>
> </EuiFlexItem>
{getUpgradeButtonLabel(snapshotState)} </EuiFlexGroup>
</EuiButton> </EuiFlexItem>
</EuiFlexItem> )}
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup> </EuiFlexGroup>
</EuiFlyoutFooter> </EuiFlyoutFooter>
</> </>

View file

@ -52,6 +52,7 @@ export const MlSnapshotsTableRowCells: React.FunctionComponent<TableRowProps> =
}, },
flyoutProps: { flyoutProps: {
onClose: closeFlyout, onClose: closeFlyout,
className: 'eui-textBreakWord',
'data-test-subj': 'mlSnapshotDetails', 'data-test-subj': 'mlSnapshotDetails',
'aria-labelledby': 'mlSnapshotDetailsFlyoutTitle', 'aria-labelledby': 'mlSnapshotDetailsFlyoutTitle',
}, },

View file

@ -41,13 +41,6 @@ const buttonLabel = (status?: ReindexStatus) => {
defaultMessage="Reindexing…" defaultMessage="Reindexing…"
/> />
); );
case ReindexStatus.completed:
return (
<FormattedMessage
id="xpack.upgradeAssistant.checkupTab.reindexing.flyout.checklistStep.reindexButton.doneLabel"
defaultMessage="Resolved"
/>
);
case ReindexStatus.paused: case ReindexStatus.paused:
return ( return (
<FormattedMessage <FormattedMessage
@ -143,18 +136,20 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
/> />
</EuiButtonEmpty> </EuiButtonEmpty>
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem grow={false}> {status !== ReindexStatus.completed && (
<EuiButton <EuiFlexItem grow={false}>
fill <EuiButton
color={status === ReindexStatus.paused ? 'warning' : 'primary'} fill
iconType={status === ReindexStatus.paused ? 'play' : undefined} color={status === ReindexStatus.paused ? 'warning' : 'primary'}
onClick={startReindex} iconType={status === ReindexStatus.paused ? 'play' : undefined}
isLoading={loading} onClick={startReindex}
disabled={loading || status === ReindexStatus.completed || !hasRequiredPrivileges} isLoading={loading}
> disabled={loading || !hasRequiredPrivileges}
{buttonLabel(status)} >
</EuiButton> {buttonLabel(status)}
</EuiFlexItem> </EuiButton>
</EuiFlexItem>
)}
</EuiFlexGroup> </EuiFlexGroup>
</EuiFlyoutFooter> </EuiFlyoutFooter>
</Fragment> </Fragment>

View file

@ -21,6 +21,7 @@ import { useAppContext } from '../../../../../app_context';
import type { ReindexStateContext } from '../context'; import type { ReindexStateContext } from '../context';
import { ChecklistFlyoutStep } from './checklist_step'; import { ChecklistFlyoutStep } from './checklist_step';
import { WarningsFlyoutStep } from './warnings_step'; import { WarningsFlyoutStep } from './warnings_step';
import { DeprecationBadge } from '../../../../shared';
enum ReindexFlyoutStep { enum ReindexFlyoutStep {
reindexWarnings, reindexWarnings,
@ -130,6 +131,11 @@ export const ReindexFlyout: React.FunctionComponent<ReindexFlyoutProps> = ({
return ( return (
<> <>
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<DeprecationBadge
isCritical={deprecation.isCritical}
isResolved={reindexState.status === ReindexStatus.completed}
/>
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle"> <EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="reindexDetailsFlyoutTitle"> <h2 id="reindexDetailsFlyoutTitle">
<FormattedMessage <FormattedMessage

View file

@ -56,6 +56,7 @@ const ReindexTableRowCells: React.FunctionComponent<TableRowProps> = ({
}, },
flyoutProps: { flyoutProps: {
onClose: closeFlyout, onClose: closeFlyout,
className: 'eui-textBreakWord',
'data-test-subj': 'reindexDetails', 'data-test-subj': 'reindexDetails',
'aria-labelledby': 'reindexDetailsFlyoutTitle', 'aria-labelledby': 'reindexDetailsFlyoutTitle',
}, },

View file

@ -7,10 +7,11 @@
import React from 'react'; import React from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiBadge, EuiLink, EuiText, EuiToolTip } from '@elastic/eui'; import { EuiLink, EuiText, EuiToolTip } from '@elastic/eui';
import { EnrichedDeprecationInfo } from '../../../../common/types'; import { EnrichedDeprecationInfo } from '../../../../common/types';
import { DEPRECATION_TYPE_MAP } from '../constants'; import { DEPRECATION_TYPE_MAP } from '../constants';
import { DeprecationTableColumns } from '../types'; import { DeprecationTableColumns } from '../types';
import { DeprecationBadge } from '../shared';
interface Props { interface Props {
resolutionTableCell?: React.ReactNode; resolutionTableCell?: React.ReactNode;
@ -20,18 +21,6 @@ interface Props {
} }
const i18nTexts = { const i18nTexts = {
criticalBadgeLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.criticalBadgeLabel',
{
defaultMessage: 'Critical',
}
),
warningBadgeLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.warningBadgeLabel',
{
defaultMessage: 'Warning',
}
),
manualCellLabel: i18n.translate( manualCellLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.manualCellLabel', 'xpack.upgradeAssistant.esDeprecations.defaultDeprecation.manualCellLabel',
{ {
@ -54,11 +43,7 @@ export const EsDeprecationsTableCells: React.FunctionComponent<Props> = ({
}) => { }) => {
// "Status column" // "Status column"
if (fieldName === 'isCritical') { if (fieldName === 'isCritical') {
if (deprecation.isCritical === true) { return <DeprecationBadge isCritical={deprecation.isCritical} />;
return <EuiBadge color="danger">{i18nTexts.criticalBadgeLabel}</EuiBadge>;
}
return <EuiBadge color="default">{i18nTexts.warningBadgeLabel}</EuiBadge>;
} }
// "Issue" column // "Issue" column

View file

@ -25,6 +25,7 @@ import {
} from '@elastic/eui'; } from '@elastic/eui';
import type { DeprecationResolutionState, KibanaDeprecationDetails } from './kibana_deprecations'; import type { DeprecationResolutionState, KibanaDeprecationDetails } from './kibana_deprecations';
import { DeprecationBadge } from '../shared';
import './_deprecation_details_flyout.scss'; import './_deprecation_details_flyout.scss';
@ -130,12 +131,18 @@ export const DeprecationDetailsFlyout = ({
deprecationResolutionState, deprecationResolutionState,
}: DeprecationDetailsFlyoutProps) => { }: DeprecationDetailsFlyoutProps) => {
const { documentationUrl, message, correctiveActions, title } = deprecation; const { documentationUrl, message, correctiveActions, title } = deprecation;
const isCurrent = deprecationResolutionState?.id === deprecation.id;
const isResolved = isCurrent && deprecationResolutionState?.resolveDeprecationStatus === 'ok';
return ( return (
<> <>
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.level === 'critical'} isResolved={isResolved} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle"> <EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="kibanaDeprecationDetailsFlyoutTitle">{title}</h2> <h2 id="kibanaDeprecationDetailsFlyoutTitle" className="eui-textBreakWord">
{title}
</h2>
</EuiTitle> </EuiTitle>
</EuiFlyoutHeader> </EuiFlyoutHeader>
<EuiFlyoutBody> <EuiFlyoutBody>
@ -154,7 +161,7 @@ export const DeprecationDetailsFlyout = ({
)} )}
<EuiText> <EuiText>
<p>{message}</p> <p className="eui-textBreakWord">{message}</p>
{documentationUrl && ( {documentationUrl && (
<p> <p>
@ -168,7 +175,7 @@ export const DeprecationDetailsFlyout = ({
<EuiSpacer /> <EuiSpacer />
{/* Hide resolution steps if already resolved */} {/* Hide resolution steps if already resolved */}
{deprecationResolutionState?.resolveDeprecationStatus !== 'ok' && ( {!isResolved && (
<div data-test-subj="resolveSection"> <div data-test-subj="resolveSection">
{correctiveActions.api && ( {correctiveActions.api && (
<> <>
@ -212,8 +219,8 @@ export const DeprecationDetailsFlyout = ({
</EuiButtonEmpty> </EuiButtonEmpty>
</EuiFlexItem> </EuiFlexItem>
{/* Only show the "Quick resolve" button if deprecation supports it */} {/* Only show the "Quick resolve" button if deprecation supports it and deprecation is not yet resolved */}
{correctiveActions.api && ( {correctiveActions.api && !isResolved && (
<EuiFlexItem grow={false}> <EuiFlexItem grow={false}>
<EuiButton <EuiButton
fill fill
@ -222,7 +229,6 @@ export const DeprecationDetailsFlyout = ({
isLoading={Boolean( isLoading={Boolean(
deprecationResolutionState?.resolveDeprecationStatus === 'in_progress' deprecationResolutionState?.resolveDeprecationStatus === 'in_progress'
)} )}
disabled={Boolean(deprecationResolutionState?.resolveDeprecationStatus === 'ok')}
> >
{getQuickResolveButtonLabel(deprecationResolutionState)} {getQuickResolveButtonLabel(deprecationResolutionState)}
</EuiButton> </EuiButton>

View file

@ -6,18 +6,12 @@
*/ */
import React from 'react'; import React from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { import { EuiInMemoryTable, EuiBasicTableColumn, EuiButton, EuiLink, Search } from '@elastic/eui';
EuiInMemoryTable,
EuiBasicTableColumn,
EuiButton,
EuiLink,
EuiBadge,
Search,
} from '@elastic/eui';
import { PAGINATION_CONFIG } from '../constants'; import { PAGINATION_CONFIG } from '../constants';
import type { DeprecationResolutionState, KibanaDeprecationDetails } from './kibana_deprecations'; import type { DeprecationResolutionState, KibanaDeprecationDetails } from './kibana_deprecations';
import { ResolutionTableCell } from './resolution_table_cell'; import { ResolutionTableCell } from './resolution_table_cell';
import { DeprecationBadge } from '../shared';
const i18nTexts = { const i18nTexts = {
refreshButtonLabel: i18n.translate( refreshButtonLabel: i18n.translate(
@ -80,18 +74,6 @@ const i18nTexts = {
defaultMessage: 'Critical', defaultMessage: 'Critical',
} }
), ),
criticalBadgeLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.criticalBadgeLabel',
{
defaultMessage: 'critical',
}
),
warningBadgeLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.warningBadgeLabel',
{
defaultMessage: 'warning',
}
),
searchPlaceholderLabel: i18n.translate( searchPlaceholderLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.searchPlaceholderLabel', 'xpack.upgradeAssistant.kibanaDeprecations.table.searchPlaceholderLabel',
{ {
@ -121,16 +103,7 @@ export const KibanaDeprecationsTable: React.FunctionComponent<Props> = ({
truncateText: true, truncateText: true,
sortable: true, sortable: true,
render: (level: KibanaDeprecationDetails['level']) => { render: (level: KibanaDeprecationDetails['level']) => {
switch (level) { return <DeprecationBadge isCritical={level === 'critical'} />;
case 'critical':
return <EuiBadge color="danger">{i18nTexts.criticalBadgeLabel}</EuiBadge>;
case 'warning':
return <EuiBadge color="default">{i18nTexts.warningBadgeLabel}</EuiBadge>;
default:
return <>{''}</>;
}
}, },
}, },
{ {

View file

@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { FunctionComponent } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiBadge } from '@elastic/eui';
const i18nTexts = {
criticalBadgeLabel: i18n.translate('xpack.upgradeAssistant.deprecationBadge.criticalBadgeLabel', {
defaultMessage: 'Critical',
}),
resolvedBadgeLabel: i18n.translate('xpack.upgradeAssistant.deprecationBadge.resolvedBadgeLabel', {
defaultMessage: 'Resolved',
}),
warningBadgeLabel: i18n.translate('xpack.upgradeAssistant.deprecationBadge.warningBadgeLabel', {
defaultMessage: 'Warning',
}),
};
interface Props {
isCritical: boolean;
isResolved?: boolean;
}
export const DeprecationBadge: FunctionComponent<Props> = ({ isCritical, isResolved }) => {
if (isResolved) {
return (
<EuiBadge color="success" data-test-subj="resolvedDeprecationBadge">
{i18nTexts.resolvedBadgeLabel}
</EuiBadge>
);
}
if (isCritical) {
return (
<EuiBadge color="danger" data-test-subj="criticalDeprecationBadge">
{i18nTexts.criticalBadgeLabel}
</EuiBadge>
);
}
return (
<EuiBadge color="default" data-test-subj="warningDeprecationBadge">
{i18nTexts.warningBadgeLabel}
</EuiBadge>
);
};

View file

@ -7,3 +7,4 @@
export { NoDeprecationsPrompt } from './no_deprecations'; export { NoDeprecationsPrompt } from './no_deprecations';
export { DeprecationCount } from './deprecation_count'; export { DeprecationCount } from './deprecation_count';
export { DeprecationBadge } from './deprecation_badge';