[UA] Forwardport 8.x UA commits into main (#218957)

This commit is contained in:
Ignacio Rivas 2025-05-05 12:55:47 +02:00 committed by GitHub
parent 8a05701cc4
commit 3e4a44d409
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
135 changed files with 5130 additions and 1659 deletions

View file

@ -316,6 +316,9 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
remoteReindex: `${ELASTICSEARCH_DOCS}docs-reindex.html#reindex-from-remote`,
unfreezeApi: `https://www.elastic.co/guide/en/elastic-stack/9.0/release-notes-elasticsearch-9.0.0.html#remove_unfreeze_rest_endpoint`,
reindexWithPipeline: `${ELASTICSEARCH_DOCS}docs-reindex.html#reindex-with-an-ingest-pipeline`,
logsDatastream: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/logs-data-stream.html`,
usingLogsDbIndexModeWithESSecurity: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/detections-logsdb-index-mode-impact.html`,
dataStreamReindex: `${ELASTICSEARCH_DOCS}data-stream-reindex-api.html#reindex-data-stream-api-settings`,
},
rollupJobs: `${KIBANA_DOCS}data-rollups.html`,
elasticsearch: {

View file

@ -266,6 +266,9 @@ export interface DocLinks {
readonly remoteReindex: string;
readonly unfreezeApi: string;
readonly reindexWithPipeline: string;
readonly logsDatastream: string;
readonly usingLogsDbIndexModeWithESSecurity: string;
readonly dataStreamReindex: string;
};
readonly rollupJobs: string;
readonly elasticsearch: Record<string, string>;

View file

@ -13,13 +13,13 @@ const meta: Meta<typeof DeprecationBadge> = {
component: DeprecationBadge,
title: 'Upgrade Assistant/Deprecation Badge',
argTypes: {
isCritical: {
level: {
name: 'Deprecation is critical?',
control: { type: 'boolean' },
},
isResolved: {
name: 'Deprecation is resolved?',
control: { type: 'boolean' },
control: { type: 'select', options: ['none', 'info', 'warning', 'critical', 'fetch_error'] },
},
},
};
@ -29,7 +29,7 @@ type Story = StoryObj<typeof DeprecationBadge>;
export const Primary: Story = {
args: {
isCritical: false,
level: 'info',
isResolved: false,
},
};

View file

@ -22,11 +22,11 @@ const i18nTexts = {
};
interface Props {
isCritical: boolean;
level: 'none' | 'info' | 'warning' | 'critical' | 'fetch_error';
isResolved?: boolean;
}
export const DeprecationBadge: FunctionComponent<Props> = ({ isCritical, isResolved }) => {
export const DeprecationBadge: FunctionComponent<Props> = ({ level, isResolved }) => {
if (isResolved) {
return (
<EuiBadge color="success" data-test-subj="resolvedDeprecationBadge">
@ -35,7 +35,7 @@ export const DeprecationBadge: FunctionComponent<Props> = ({ isCritical, isResol
);
}
if (isCritical) {
if (level === 'critical') {
return (
<EuiBadge color="danger" data-test-subj="criticalDeprecationBadge">
{i18nTexts.criticalBadgeLabel}

View file

@ -47334,10 +47334,74 @@
"xpack.upgradeAssistant.app.deniedPrivilegeDescription": "Afin d'utiliser l'assistant de mise à niveau et de résoudre les problèmes de déclassement, vous devez disposer d'un accès permettant de gérer tous les espaces Kibana.",
"xpack.upgradeAssistant.app.deniedPrivilegeTitle": "Rôle d'administrateur Kibana requis",
"xpack.upgradeAssistant.appTitle": "Assistant de mise à niveau",
"xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel": "Logs de déclassements Elasticsearch",
"xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel": "Problèmes de déclassement Elasticsearch",
"xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Problèmes de déclassement Kibana",
"xpack.upgradeAssistant.breadcrumb.overviewLabel": "Assistant de mise à niveau",
"xpack.upgradeAssistant.dataStream.flyout.container.indicesDocsCount": "Compte du document",
"xpack.upgradeAssistant.dataStream.flyout.container.indicesDocsSize": "Taille",
"xpack.upgradeAssistant.dataStream.flyout.errorLoadingDataStreamInfo": "Erreur lors du chargement des informations sur le flux de données",
"xpack.upgradeAssistant.dataStream.flyout.unknownMessage": "Inconnu",
"xpack.upgradeAssistant.dataStream.flyout.warningsStep.readonly.acceptChangesTitle": "{count, plural, other {# index de sauvegarde}}, y compris l'index d'écriture actuel, seront marqués en lecture seule.",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.backButtonLabel": "Retour",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.cancelMigrationButtonLabel": "Annuler {resolutionType, select, reindex {la réindexation} readonly {le marquage en lecture seule} other {la migration}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.closeButtonLabel": "Fermer",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.fetchFailedCalloutTitle": "Statut de la migration indisponible",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.fetchingStatus": "Récupération du statut…",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.insufficientPrivilegeCallout.calloutTitle": "Vous ne disposez pas des privilèges requis pour migrer ce flux de données",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceCalloutDescription": "L'utilisation du disque a dépassé le niveau inférieur, ce qui peut empêcher la migration. Les nœuds suivants sont affectés :",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceCalloutTitle": "Nœuds avec espace disque faible",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceUsedText": "{nodeName} ({available} disponible)",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.migrationFailedCalloutTitle": "Erreur lors {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {de la migration}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.completeTitle": "Succès {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {de la migration}} de {count, plural, other {# index}}.",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.failedTitle": "Échec {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {de la migration}} de {count, plural, other {# index}}.",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.inProgressTitle": "{resolutionType, select, reindex {Réindexation} readonly {Marquage en lecture seule} other {Migration}} de {count, plural, other {# index}} en cours.",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.pendingTitle": "{count, plural, other {# Index}} en attente de démarrage.",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "La réindexation s'effectue en arrière-plan. Vous pouvez retourner à l'assistant de mise à niveau pour examiner la progression.",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.cancelledLabel": "Annulé",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.cancellingLabel": "Annulation…",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.errorLabel": "Échec de l'annulation {resolutionType, select, reindex {de la réindexation} readonly {de la mise en lecture seule} other {}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelled.reindexingDocumentsStepTitle": "Annulation {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.completed.reindexingDocumentsStepTitle": "Complétion {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.failed.reindexingDocumentsStepTitle": "Échec {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.fetchFailed.reindexingDocumentsStepTitle": "Échec de la récupération de l'état",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.inProgress.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {Réindexer le flux de données} readonly {Marquer le flux de données en lecture seule} other {Action inconnue}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklistTitle": "{resolutionType, select, reindex {Réindexer le flux de données} readonly {Marquer le flux de données en lecture seule} other {Migrer le flux de données}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingInProgressTitle": "Démarré à : {startTimeFromNow}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.startActionButtonLabel": "Tout marquer en lecture seule",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.closeButtonLabel": "Fermer",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.fetchFailedCalloutTitle": "Statut de la migration du flux de données indisponible",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.indexMgmtLink": "Accéder à la gestion des index",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.insufficientPrivilegeCallout.calloutTitle": "Vous ne disposez pas des privilèges requis pour migrer ce flux de données.",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceCalloutDescription": "L'utilisation du disque a dépassé le niveau inférieur, ce qui peut empêcher la migration. Les nœuds suivants sont affectés :",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceCalloutTitle": "Nœuds avec espace disque faible",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceUsedText": "{nodeName} ({available} disponible)",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.migrationDescription": "Si vous n'avez plus besoin de ces données, vous pouvez continuer en supprimant ces index. {indexManagementLinkHtml}",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.migrationFailedCalloutTitle": "Erreur de migration du flux de données",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.notCompatibleIndicesText": "Vous disposez de {backingIndicesCount} index de sauvegarde sur ce flux de données créés dans ES 7.X, qui ne seront pas compatibles avec la version suivante.",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.readOnlyText": "Si vous n'avez pas besoin de mettre à jour les données historiques, marquez cela en lecture seule. Vous pouvez effectuer une réindexation après la mise à jour si nécessaire.",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOption.additionalIndices": "Les index de sauvegarde supplémentaires seront réindexés et resteront modifiables.",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOption.rolledOverIndex": "L'index d'écriture actuel sera transféré et réindexé.",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOptionListTitle": "Réindexer",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.requiredUpgradeText": "{allBackingIndices} index de sauvegarde totaux, et {backingIndicesRequireingUpgrade} nécessitent une mise à niveau.",
"xpack.upgradeAssistant.dataStream.migration.flyout.initializingStep.errorLoadingDataStreamInfo": "Erreur lors du chargement des informations sur le flux de données",
"xpack.upgradeAssistant.dataStream.migration.flyout.initializingStep.loadingDataStreamInfo": "Chargement des informations du flux de données",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.reindexingLabel": "{resolutionType, select, reindex {Réindexation} readonly {Marquage en lecture seule} other {Migration}} en cours…",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.restartLabel": "Relancer {resolutionType, select, reindex {la réindexation} readonly {le marquage en lecture seule} other {la migration}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.runReindexLabel": "Lancer {resolutionType, select, reindex {la réindexation} readonly {le marquage en lecture seule} other {la migration}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.tryAgainLabel": "Réessayer",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.acceptChangesTitle": "Succès {resolutionType, select, reindex {de la réindexation} readonly {du marquage en lecture seule} other {de la migration}} de {count, plural, other {# index de sauvegarde}}.",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.affectExistingSetupsWarningTitle": "Marquer en lecture seule les données incompatibles avec ce flux de données",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.documentationLinkLabel": "Documentation",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.incompatibleDataWarningTitle": "Réindexer toutes les données incompatibles avec ce flux de données",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.indicesNeedReindexing": "Les index créés à la date du {formattedDate} ou avant doivent être réindexés vers un format compatible, ou marqués en lecture seule.",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.learnMoreLink": "En savoir plus",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.readonly.calloutDetail": "Assurez-vous d'avoir enregistré vos données, etc. Vous pourrez toujours réindexer ces données plus tard pour les rendre modifiables.",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.readonly.calloutTitle": "Marquer ces données en lecture seule pourrait affecter des configurations existantes",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.reindex.calloutDetail": "Assurez-vous que vos données sont sauvegardées avant de continuer. Veuillez confirmer que vous souhaitez continuer la réindexation de ces données.",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.reindex.calloutTitle": "Cette opération requiert des modifications destructives qui ne peuvent pas être annulées",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.suggestReadOnly": "En fonction de la taille et des ressources, la réindexation peut prendre beaucoup de temps, et vos données seront en lecture seule jusqu'à la fin de la tâche. {learnMoreHtml}",
"xpack.upgradeAssistant.datastream.readonlyPrivilegesErrorBatch": "Vous ne disposez pas des privilèges nécessaires pour marquer les index dans le flux de données en lecture seule \"{dataStreamName}\".",
"xpack.upgradeAssistant.datastream.reindexPrivilegesErrorBatch": "Vous ne disposez pas des privilèges nécessaires pour annuler la réindexation de \"{dataStreamName}\".",
"xpack.upgradeAssistant.deprecationBadge.criticalBadgeLabel": "Critique",
"xpack.upgradeAssistant.deprecationBadge.resolvedBadgeLabel": "Résolu",
"xpack.upgradeAssistant.deprecationBadge.warningBadgeLabel": "Avertissement",
@ -47345,15 +47409,11 @@
"xpack.upgradeAssistant.deprecationCount.warningStatusLabel": "Avertissement : {count}",
"xpack.upgradeAssistant.deprecationFlyout.learnMoreLinkLabel": "En savoir plus",
"xpack.upgradeAssistant.deprecationsPageLoadingError.title": "Impossible de récupérer les problèmes de déclassement de {deprecationSource}",
"xpack.upgradeAssistant.deprecationStats.criticalDeprecationsTitle": "Critique",
"xpack.upgradeAssistant.deprecationStats.loadingErrorMessage": "Impossible de récupérer les problèmes de déclassement Kibana.",
"xpack.upgradeAssistant.deprecationStats.warningDeprecationsTitle": "Avertissement",
"xpack.upgradeAssistant.esDeprecationErrors.loadingErrorMessage": "Impossible de récupérer les problèmes de déclassement Elasticsearch.",
"xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Mettez à niveau Kibana vers la même version que votre cluster Elasticsearch. Un ou plusieurs nœuds du cluster exécutent une version différente de celle de Kibana.",
"xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Vous n'êtes pas autorisé à afficher les problèmes de déclassement Elasticsearch.",
"xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "Tous les nœuds Elasticsearch ont été mis à niveau.",
"xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText": "Documentation",
"xpack.upgradeAssistant.esDeprecationLogs.pageDescription": "Consultez les logs de déclassement pour déterminer si vos applications utilisent des API déclassées. Mettez à jour vos applications pour empêcher des erreurs ou des changements de comportement après votre mise à niveau.",
"xpack.upgradeAssistant.esDeprecationLogs.pageTitle": "Logs de déclassements Elasticsearch",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsLink": "API de réindexation par lots",
"xpack.upgradeAssistant.esDeprecations.clusterDeprecationTypeLabel": "Cluster",
@ -47378,6 +47438,102 @@
"xpack.upgradeAssistant.esDeprecations.indexSettings.deletingButtonLabel": "Retrait des paramètres en cours…",
"xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionText": "Retirer les paramètres",
"xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionTooltipLabel": "Corrigez ce problème en retirant les paramètres de cet index. La correction peut s'effectuer automatiquement.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.backButtonLabel": "Retour",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.closeButtonLabel": "Fermer",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.frozenIndexText": "Cet index est gelé. Les index gelés ne seront plus pris en charge après la mise à niveau. Faites votre choix parmi les options suivantes :",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.indexMgmtLink": "Gestion des index",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.insufficientPrivilegeCallout.calloutTitle": "Vous ne disposez pas de privilèges suffisants pour réindexer cet index.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceCalloutDescription": "L'utilisation du disque a dépassé le niveau inférieur, ce qui peut empêcher la réindexation. Les nœuds suivants sont affectés :",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceCalloutTitle": "Nœuds avec espace disque faible",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceUsedText": "{nodeName} ({available} disponible)",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleIndexText": "Cet index a été créé dans la version ES 7.X et n'est pas compatible avec la version majeure suivante. Faites votre choix parmi les options suivantes :",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.readonlyCompatibleIndexText": "Cet index a été créé dans la version ES 7.X. Il est marqué en lecture seule, ce qui permet la compatibilité avec la version majeure suivante.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.description": "L'opération de réindexation permet de transformer un index en index compatible. Elle copiera tous les documents existants dans un nouvel index, et supprimera l'ancien index. En fonction de la taille et des ressources, la réindexation peut prendre beaucoup de temps, et vos données seront en lecture seule jusqu'à la fin de la tâche.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option2.description": "Les anciens index ne peuvent rester compatibles avec la prochaine version majeure que s'ils sont en mode lecture seule. Si vous n'avez plus besoin de mettre à jour les documents de cet index (ou d'en ajouter d'autres), vous voudrez peut-être le convertir en index en lecture seule. {docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option3.description": "Si vous n'en avez plus besoin, vous pouvez également supprimer l'index de {indexManagementLinkHtml}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.reindexingLabel": "Réindexation…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.restartLabel": "Redémarrer la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.runReindexLabel": "Démarrer la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.tryAgainLabel": "Réessayer",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexText": "L'opération de réindexation permet de transformer un index en index compatible. Elle copiera tous les documents existants dans un nouvel index, et supprimera l'ancien index. En fonction de la taille et des ressources, la réindexation peut prendre beaucoup de temps, et vos données seront en lecture seule jusqu'à la fin de la tâche.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton": "Marquer en lecture seule",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.alternativeOption.description": "Si vous n'en avez plus besoin, vous pouvez également supprimer l'index de {indexManagementLinkHtml}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.alternativeOption.title": "Alternative: Supprimer l'index",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option1.description": "Dégelez cet index et marquez-le en lecture seule. Cela vous assurera que cet index restera compatible avec la version majeure suivante.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option1.title": "Option 1 : Dégeler l'index",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option2.description": "Vous pouvez également réindexer les données sous un index compatible. Tous les documents existants seront copiés vers le nouvel index, et l'ancien index sera supprimé. En fonction de la taille de l'index et des ressources disponibles, l'opération de réindexation peut prendre un certain temps. Vos données seront en lecture seule jusqu'à la fin de la réindexation.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option2.title": "Option 2 : Réindexer les données",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreezeIndexButton": "Dégeler",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.flyoutHeader": "Mettre à jour {index}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.frozenCallout.reindexFrozenIndex": "Les index gelés ne seront plus compatibles après la mise à niveau. Ainsi, cet index sera transformé en index non gelé lors de l'opération de mise à jour. {docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.frozenCallout.reindexFrozenIndexTitle": "Cet index est gelé",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.learnMoreLinkLabel": "En savoir plus",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.fetchFailedCalloutTitle": "Statut de réindexation non disponible",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.insufficientPrivilegeCallout.calloutTitle": "Vous ne disposez pas de privilèges suffisants pour réindexer cet index",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceCalloutDescription": "L'utilisation du disque a dépassé le niveau inférieur, ce qui peut empêcher la réindexation. Les nœuds suivants sont affectés :",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceCalloutTitle": "Nœuds avec espace disque faible",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceUsedText": "{nodeName} ({available} disponible)",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.readonlyCallout.backgroundResumeDetail": "La réindexation s'effectue en arrière-plan. Vous pouvez revenir à l'assistant de mise à niveau pour visualiser la progression ou reprendre la réindexation après redémarrage de Kibana.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.reindexingLabel": "Réindexation…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.restartLabel": "Redémarrer la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.resumeLabel": "Reprendre la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel": "Démarrer la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.tryAgainLabel": "Réessayer",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexDescription": "L'index sera en lecture seule pendant la réindexation. Vous ne pourrez pas ajouter, mettre à jour ni supprimer des documents avant la fin de la réindexation. Si vous avez besoin d'effectuer une réindexation dans un nouveau cluster, utilisez l'API de réindexation. {docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.aliasCreatedStepTitle": "Créez l'alias {indexName} pour l'index {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.aliasesUpdatedStepTitle": "Mettez à jour les alias {existingAliases} afin qu'ils pointent vers l'index {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancelLabel": "Annuler",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancelledLabel": "Annulé",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancellingLabel": "Annulation…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.errorLabel": "Annulation impossible",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelledTitle": "Réindexation annulée.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.createIndexStepTitle": "Créez l'index {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.indexSettingsRestoredStepTitle": "Copiez les paramètres d'index d'origine de {indexName} vers {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.aliasCreatedStepTitle": "Création de l'alias {indexName} pour l'index {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.aliasesUpdatedStepTitle": "Mise à jour des alias {existingAliases} afin qu'ils pointent vers l'index {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.createIndexStepTitle": "Création de l'index {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.indexSettingsRestoredStepTitle": "Copie des paramètres d'index d'origine de {indexName} vers {reindexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.originalIndexDeletedStepTitle": "Suppression de l'index d'origine {indexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.readonlyStepTitle": "Définition de l'index {indexName} sur lecture seule.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.reindexingDocumentsStepTitle": "Réindexation des documents.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.originalIndexDeletedStepTitle": "Supprimez l'index d'origine {indexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.readonlyStepTitle": "Définissez l'index {indexName} sur lecture seule.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.reindexingDocumentsStepTitle": "Réindexez les documents.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklistTitle": "Processus de réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingFailedCalloutTitle": "Erreur de réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingInProgressTitle": "Réindexation en cours… {percents}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.step.readonlyStepText": "Définition de l'index {indexName} sur lecture seule.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.step.unfreezeStepText": "Dégel de l'index {indexName}.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateCompleteText": "Opération terminée",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateFailedText": "Échec de l'opération",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateInProgressText": "Mise à niveau en cours…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.retryButtonLabel": "Réessayer",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.acceptChangesTitle": "Accepter les modifications",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.deprecatedIndexSettingsWarningTitle": "Retirer les paramètres d'index déclassés",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.documentationLinkLabel": "Documentation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningDetail": "Vous pouvez continuer à rechercher et récupérer des documents de {indexName}. Vous ne pourrez pas insérer de nouveaux documents ou modifier des documents existants.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningTitle": "Définissez l'index {indexName} sur le mode lecture seule",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.calloutDetail": "Vous pouvez activer la compatibilité avec la version suivante en marquant l'index en lecture seule. Notez bien que toutes les tentatives d'insérer de nouveaux documents ou de mettre à jour les documents existants échouera. Vous pouvez choisir d'effectuer une réindexation après la mise à niveau si besoin, pour convertir l'index à un format modifiable.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.calloutTitle": "Permettez la compatibilité en marquant cet index en lecture seule",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.continueButtonLabel": "Marquer en lecture seule",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.calloutDetail": "Sauvegardez l'index avant de continuer. Pour poursuivre avec la réindexation, acceptez chaque modification.",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.calloutTitle": "Cet index requiert des modifications destructives qui ne pourront pas être annulées",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.continueButtonLabel": "Continuer la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningDetail": "Vous pourrez effectuer des recherches dans {indexName} comme avant. Pour supprimer les données, vous devrez supprimer {reindexName}",
"xpack.upgradeAssistant.esDeprecations.indices.reindexCanceledText": "Réindexation annulée",
"xpack.upgradeAssistant.esDeprecations.indices.reindexCompleteText": "Réindexation terminée",
"xpack.upgradeAssistant.esDeprecations.indices.reindexFailedText": "Échec de la réindexation",
"xpack.upgradeAssistant.esDeprecations.indices.reindexFetchFailedText": "Statut de réindexation non disponible",
"xpack.upgradeAssistant.esDeprecations.indices.reindexInProgressText": "Réindexation en cours…",
"xpack.upgradeAssistant.esDeprecations.indices.reindexLabel": "Réindexer",
"xpack.upgradeAssistant.esDeprecations.indices.reindexLoadingStatusText": "Chargement du statut…",
"xpack.upgradeAssistant.esDeprecations.indices.reindexPausedText": "Réindexation suspendue",
"xpack.upgradeAssistant.esDeprecations.indices.reindexTooltipLabel": "Corrigez ce problème avec une réindexation en index compatible.",
"xpack.upgradeAssistant.esDeprecations.indices.unfreezeLabel": "Dégeler",
"xpack.upgradeAssistant.esDeprecations.indices.unfreezeTooltipLabel": "Corrigez ce problème en dégelant cet index.",
"xpack.upgradeAssistant.esDeprecations.indices.updateCompleteText": "Mise à jour terminée",
"xpack.upgradeAssistant.esDeprecations.indices.updateLabel": "Mettre à jour",
"xpack.upgradeAssistant.esDeprecations.indices.updateTooltipLabel": "Corrigez ce problème en mettant cet index à jour. Ce problème peut être corrigé automatiquement en marquant l'index en lecture seule (recommandé pour les grands index) ou en le réindexant en index compatible.",
"xpack.upgradeAssistant.esDeprecations.loadingText": "Chargement des problèmes de déclassement…",
"xpack.upgradeAssistant.esDeprecations.mlDeprecationTypeLabel": "Machine Learning",
"xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteCompleteText": "Suppression terminée",
@ -47420,7 +47576,6 @@
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.resolvedButtonLabel": "Résolu",
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.retryRemoveButtonLabel": "Réessayer de retirer les paramètres déclassés",
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.secondaryDescription": "Index : {indexName}",
"xpack.upgradeAssistant.esDeprecations.table.criticalFilterLabel": "Critique",
"xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle": "Problème",
"xpack.upgradeAssistant.esDeprecations.table.nameColumnTitle": "Nom",
"xpack.upgradeAssistant.esDeprecations.table.noDeprecationsMessage": "Aucun problème de déclassement Elasticsearch trouvé",
@ -47481,7 +47636,6 @@
"xpack.upgradeAssistant.noDeprecationsPrompt.description": "Votre configuration {deprecationType} est à jour",
"xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "Vérifiez la {overviewButton} pour rechercher les autres déclassements de la Suite Elastic.",
"xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "Page d'aperçu",
"xpack.upgradeAssistant.noPartialDeprecationsMessage": "Aucun",
"xpack.upgradeAssistant.overview.analyzeTitle": "Analyser les logs de déclassement",
"xpack.upgradeAssistant.overview.apiCompatibilityNoteBody": "Nous vous recommandons de résoudre tous les problèmes de déclassement avant la mise à niveau. Si besoin, vous pouvez appliquer des en-têtes de compatibilité d'API aux requêtes utilisant des fonctionnalités déclassées. {learnMoreLink}.",
"xpack.upgradeAssistant.overview.apiCompatibilityNoteLink": "En savoir plus",
@ -47505,8 +47659,6 @@
"xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "Impossible de récupérer les informations de logging.",
"xpack.upgradeAssistant.overview.deprecationLogs.reloadButtonLabel": "Réessayer",
"xpack.upgradeAssistant.overview.deprecationLogs.updateErrorMessage": "Impossible de mettre à jour l'état de logging.",
"xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "Résoudre les problèmes de déclassement et vérifier vos modifications",
"xpack.upgradeAssistant.overview.documentationLinkText": "Documentation",
"xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "Une erreur s'est produite lors de la récupération du statut de mise à niveau",
"xpack.upgradeAssistant.overview.fixIssuesStepDescription": "Vous devez résoudre tous les problèmes critiques de configuration Elasticsearch et Kibana avant d'effectuer la mise à niveau vers la version suivante de la Suite Elastic. Si vous ignorez les avertissements, des différences de comportement pourront apparaître après votre mise à niveau.",
"xpack.upgradeAssistant.overview.fixIssuesStepTitle": "Passer en revue les paramètres déclassés et résoudre les problèmes",
@ -47523,10 +47675,7 @@
"xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle": "Vous avez besoin de privilèges d'index pour analyser les logs de déclassement",
"xpack.upgradeAssistant.overview.logsStep.retryButton": "Réessayer",
"xpack.upgradeAssistant.overview.logsStep.title": "Traiter les déclassements d'API",
"xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel": "Afficher les logs",
"xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes": "points forts de la toute dernière version",
"xpack.upgradeAssistant.overview.observe.discoveryDescription": "Recherchez et filtrez les logs de déclassement pour comprendre les types de modifications que vous devez effectuer.",
"xpack.upgradeAssistant.overview.pageDescription": "Préparez-vous pour la prochaine version de la Suite Elastic !",
"xpack.upgradeAssistant.overview.pageTitle": "Assistant de mise à niveau",
"xpack.upgradeAssistant.overview.snapshotRestoreLink": "Créer un snapshot",
"xpack.upgradeAssistant.overview.systemIndices.body": "Préparez les index système qui stockent des informations internes pour la mise à niveau. Cette préparation est requise uniquement lors des mises à jour des versions majeures. Tous les {hiddenIndicesLink} devant être réindexés seront affichés à l'étape suivante.",
@ -47544,7 +47693,6 @@
"xpack.upgradeAssistant.overview.systemIndices.loadingError": "Impossible de récupérer le statut des index système",
"xpack.upgradeAssistant.overview.systemIndices.migratingLabel": "Migration en cours",
"xpack.upgradeAssistant.overview.systemIndices.migrationCompleteLabel": "Migration terminée",
"xpack.upgradeAssistant.overview.systemIndices.migrationFailedBody": "Une erreur s'est produite lors de la migration des index système pour {feature} : {failureCause}",
"xpack.upgradeAssistant.overview.systemIndices.migrationFailedTitle": "Échec de la migration des index système",
"xpack.upgradeAssistant.overview.systemIndices.needsMigrationLabel": "Migration requise",
"xpack.upgradeAssistant.overview.systemIndices.noMigrationNeeded": "Migration des index système non nécessaire.",
@ -47559,7 +47707,6 @@
"xpack.upgradeAssistant.overview.upgradeStepDescription": "Une fois que vous avez résolu tous les problèmes critiques et vérifié que vos applications sont prêtes, vous pouvez effectuer la mise à niveau vers la version suivante de la Suite Elastic. Veillez à sauvegarder à nouveau vos données avant d'effectuer la mise à niveau.",
"xpack.upgradeAssistant.overview.upgradeStepDescriptionForCloud": "Une fois que vous avez résolu tous les problèmes critiques et vérifié que vos applications sont prêtes, vous pouvez effectuer la mise à niveau vers la version suivante de la Suite Elastic. Veillez à sauvegarder à nouveau vos données avant d'effectuer la mise à niveau. Mettez à niveau votre déploiement sur Elastic Cloud.",
"xpack.upgradeAssistant.overview.upgradeStepTitle": "Mise à niveau de la Suite Elastic",
"xpack.upgradeAssistant.overview.upgradeToLatestMinorBeforeMajorMessage": "Vérifiez le {link} Avant la mise à niveau vers une nouvelle version majeure, vous devez d'abord effectuer une mise à niveau vers la dernière version mineure de cette version majeure.",
"xpack.upgradeAssistant.overview.verifyChanges.calloutBody": "Après avoir effectué des modifications, réinitialisez le compteur et poursuivez le monitoring pour vérifier que vous n'utilisez plus de fonctionnalités déclassées.",
"xpack.upgradeAssistant.overview.verifyChanges.calloutTitle": "{warningsCount, plural, =0 {Aucun} other {{warningsCount}}} {warningsCount, plural, one {problème} other {problèmes}} de déclassement depuis {previousCheck}",
"xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle": "Impossible de supprimer le cache des logs de déclassement",

View file

@ -47296,10 +47296,73 @@
"xpack.upgradeAssistant.app.deniedPrivilegeDescription": "アップグレードアシスタントを使用して、廃止予定の問題を解決するには、すべてのKibanaスペースを管理するためのアクセス権が必要です。",
"xpack.upgradeAssistant.app.deniedPrivilegeTitle": "Kibana管理者ロールが必要です",
"xpack.upgradeAssistant.appTitle": "アップグレードアシスタント",
"xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel": "Elasticsearchの廃止予定ログ",
"xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel": "Elasticsearchの廃止予定の問題",
"xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibanaの廃止予定の問題",
"xpack.upgradeAssistant.breadcrumb.overviewLabel": "アップグレードアシスタント",
"xpack.upgradeAssistant.dataStream.flyout.container.indicesDocsCount": "ドキュメントカウント",
"xpack.upgradeAssistant.dataStream.flyout.container.indicesDocsSize": "サイズ",
"xpack.upgradeAssistant.dataStream.flyout.errorLoadingDataStreamInfo": "データストリームの読み込みエラー",
"xpack.upgradeAssistant.dataStream.flyout.unknownMessage": "不明",
"xpack.upgradeAssistant.dataStream.flyout.warningsStep.readonly.acceptChangesTitle": "現在の書き込みインデックスを含む{count, plural, other {#個のバッキングインデックス}}が読み取り専用に設定されます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.backButtonLabel": "戻る",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.cancelMigrationButtonLabel": "{resolutionType, select, reindex {再インデックス} readonly {読み取り専用の設定} other {移行}}をキャンセル",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.closeButtonLabel": "閉じる",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.fetchFailedCalloutTitle": "移行ステータスがありません",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.fetchingStatus": "ステータスを取得しています...",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.insufficientPrivilegeCallout.calloutTitle": "このデータストリームを移行するための十分な権限がありません。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceCalloutDescription": "ディスク使用量が低レベルを超えました。移行が防止される場合があります。次のノードが影響を受けます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceCalloutTitle": "ディスク容量が低下しているノード",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceUsedText": "{nodeName}{available}空き)",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.migrationFailedCalloutTitle": "{resolutionType, select, reindex {再インデックス} readonly {読み取り専用の設定} other {移行}}エラー",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.completeTitle": "{count, plural, other {#個のインデックス}}が正常に{resolutionType, select, reindex {再インデックス} readonly {読み取り専用に設定} other {移行}}されました。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.failedTitle": "{count, plural, other {#個のインデックス}}が{resolutionType, select, reindex {再インデックス} readonly {読み取り専用に設定} other {移行}}されませんでした。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.inProgressTitle": "{count, plural, other {#個のインデックス}}が{resolutionType, select, reindex {再インデックス} readonly {読み取り専用に設定} other {移行}}中です。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.pendingTitle": "{count, plural, other {#個のインデックス}}が開始を待機しています。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "再インデックスはバックグラウンドで実行されます。アップグレードアシスタントに戻って進行状況を確認できます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.cancelledLabel": "キャンセル済み",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.cancellingLabel": "キャンセル中…",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelled.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {再インデックス} readonly {読み取り専用の設定} other {}}がキャンセルされました",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.completed.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {再インデックス} readonly {読み取り専用の設定} other {}}が完了しました",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.failed.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {再インデックス} readonly {読み取り専用の設定} other {}}に失敗しました",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.fetchFailed.reindexingDocumentsStepTitle": "ステータスの取得が失敗しました",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.inProgress.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {データストリームを再インデックス} readonly {データストリームを読み取り専用に設定} other {不明なアクション}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklistTitle": "{resolutionType, select, reindex {データストリームを再インデックス} readonly {データストリームを読み取り専用に設定} other {データストリームを移行}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingInProgressTitle": "{startTimeFromNow}を開始しました",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.startActionButtonLabel": "すべて読み取り専用に設定",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.closeButtonLabel": "閉じる",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.fetchFailedCalloutTitle": "データストリーム移行ステータスがありません",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.indexMgmtLink": "インデックス管理に移動",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.insufficientPrivilegeCallout.calloutTitle": "このデータストリームを移行するための十分な権限がありません。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceCalloutDescription": "ディスク使用量が低レベルを超えました。移行が防止される場合があります。次のノードが影響を受けます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceCalloutTitle": "ディスク容量が低下しているノード",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceUsedText": "{nodeName}{available}空き)",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.migrationDescription": "このデータが不要になった場合は、これらのインデックスを削除して続行することもできます。{indexManagementLinkHtml}",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.migrationFailedCalloutTitle": "データストリーム移行エラー",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.notCompatibleIndicesText": "このデータストリームには、ES 7.xで作成され、次のバージョンと互換性のないバッキングインデックスが{backingIndicesCount}個あります。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.readOnlyText": "履歴データの更新が必要ない場合は、読み取り専用に設定してください。更新が必要な場合は、アップグレード後に再インデックス化できます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOption.additionalIndices": "追加のバックアップインデックスは再インデックス化され、編集可能な状態になります。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOption.rolledOverIndex": "現在の書き込みインデックスが最初にロールオーバーされ、再インデックス化されます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOptionListTitle": "再インデックス",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.requiredUpgradeText": "{allBackingIndices}合計バッキングインデックスと{backingIndicesRequireingUpgrade}のアップグレードが必要です。",
"xpack.upgradeAssistant.dataStream.migration.flyout.initializingStep.errorLoadingDataStreamInfo": "データストリームの読み込みエラー",
"xpack.upgradeAssistant.dataStream.migration.flyout.initializingStep.loadingDataStreamInfo": "データストリーム情報を読み込んでいます",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.reindexingLabel": "{resolutionType, select, reindex {再インデックス化中} readonly {読み取り専用の設定中} other {移行中}}…",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.restartLabel": "{resolutionType, select, reindex {再インデックスを再開} readonly {読み取り専用の設定を再開} other {移行を再開}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.runReindexLabel": "{resolutionType, select, reindex {再インデックスを開始} readonly {読み取り専用の設定を開始} other {移行を開始}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.tryAgainLabel": "再試行",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.acceptChangesTitle": "成功しました!{count, plural, other {#個のバッキングインデックス}}が正常に{resolutionType, select, reindex {再インデックス} readonly {読み取り専用に設定} other {移行}}されました。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.affectExistingSetupsWarningTitle": "このデータストリームの互換性のないデータをすべて読み取り専用に設定",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.documentationLinkLabel": "ドキュメント",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.incompatibleDataWarningTitle": "このデータストリームの互換性のないデータをすべて再インデックス",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.indicesNeedReindexing": "{formattedDate}以前に作成されたインデックスは、互換性のある形式に再インデックス化するか、読み取り専用として設定する必要があります。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.learnMoreLink": "詳細",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.readonly.calloutDetail": "データのバックアップなどを作成していることを確認してください。後からいつでもこのデータを再インデックス化して編集可能にすることができます。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.readonly.calloutTitle": "このデータを読み取り専用に設定すると、既存の設定の一部に影響する可能性があります",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.reindex.calloutDetail": "続行する前に、データがバックアップされていることを確認してください。このデータの再インデックス化を続行するには、以下の点を確認してください。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.reindex.calloutTitle": "この処理には元に戻すことのできない破壊的な変更が含まれています",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.suggestReadOnly": "サイズとリソースによっては、再インデックス化に時間がかかることがあり、ジョブが完了するまではデータが読み取り専用状態になります。{learnMoreHtml}",
"xpack.upgradeAssistant.datastream.readonlyPrivilegesErrorBatch": "データストリーム内のインデックスを読み取り専用\"{dataStreamName}\"として設定する権限がありません。",
"xpack.upgradeAssistant.datastream.reindexPrivilegesErrorBatch": "\"{dataStreamName}\"の再インデックスをキャンセルする権限がありません。",
"xpack.upgradeAssistant.deprecationBadge.criticalBadgeLabel": "重大",
"xpack.upgradeAssistant.deprecationBadge.resolvedBadgeLabel": "解決済み",
"xpack.upgradeAssistant.deprecationBadge.warningBadgeLabel": "警告",
@ -47307,15 +47370,11 @@
"xpack.upgradeAssistant.deprecationCount.warningStatusLabel": "警告:{count}",
"xpack.upgradeAssistant.deprecationFlyout.learnMoreLinkLabel": "詳細",
"xpack.upgradeAssistant.deprecationsPageLoadingError.title": "{deprecationSource}廃止予定の問題を取得できませんでした",
"xpack.upgradeAssistant.deprecationStats.criticalDeprecationsTitle": "重大",
"xpack.upgradeAssistant.deprecationStats.loadingErrorMessage": "Kibana廃止予定の問題を取得できませんでした。",
"xpack.upgradeAssistant.deprecationStats.warningDeprecationsTitle": "警告",
"xpack.upgradeAssistant.esDeprecationErrors.loadingErrorMessage": "Elasticsearchの廃止予定の問題を取得できませんでした。",
"xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "Kibanaをご使用のElasticsearchクラスターと同じバージョンにアップグレードしてください。クラスターの1つ以上のードがKibanaとは異なるバージョンを実行しています。",
"xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "Elasticsearchの廃止予定の問題を表示する権限がありません。",
"xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "すべての Elasticsearch ノードがアップグレードされました。",
"xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText": "ドキュメント",
"xpack.upgradeAssistant.esDeprecationLogs.pageDescription": "廃止予定ログを確認し、アプリケーションが廃止予定のAPIを使用しているかどうかを判断してください。アップグレード後に、エラーまたは動作の変更を防止するには、アプリケーションを更新します。",
"xpack.upgradeAssistant.esDeprecationLogs.pageTitle": "Elasticsearchの廃止予定ログ",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsDescription": "1つの要求で複数のインデックスのアップグレードを開始するには、Kibana {docsLink}を使用します。注このAPIはデータストリームをサポートしていません。",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsLink": "バッチ再インデックスAPI",
@ -47341,6 +47400,102 @@
"xpack.upgradeAssistant.esDeprecations.indexSettings.deletingButtonLabel": "設定を削除中…",
"xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionText": "設定の削除",
"xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionTooltipLabel": "このインデックスから設定を削除して、この問題を解決します。この問題は自動的に解決できます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.backButtonLabel": "戻る",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.closeButtonLabel": "閉じる",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.frozenIndexText": "このインデックスはフローズンです。アップグレード後は、フローズンインデックスはサポートされなくなります。次のオプションのいずれかから選択:",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.indexMgmtLink": "インデックス管理",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.insufficientPrivilegeCallout.calloutTitle": "このインデックスを再インデックス化するための権限がありません。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceCalloutDescription": "ディスク使用量が低レベルを超えました。再インデックスが防止される場合があります。次のノードが影響を受けます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceCalloutTitle": "ディスク容量が低下しているノード",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceUsedText": "{nodeName}{available}空き)",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleIndexText": "このインデックスはES 7.xで作成されており、次のメジャーバージョンとは互換性がありません。次のオプションのいずれかから選択",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.readonlyCompatibleIndexText": "このインデックスはES 7.xで作成されました。これは読み取り専用に設定され、次のメジャーバージョンとの互換性があります。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.description": "再インデックス処理により、インデックスを互換性のある新しいインデックスに変換できます。この処理では、既存のすべてのドキュメントを新しいインデックスにコピーし、古いインデックスを削除します。サイズとリソースによっては、再インデックス化に時間がかかることがあり、ジョブが完了するまではデータが読み取り専用状態になります。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option2.description": "読み取り専用モードに変更された場合、古いインデックスは次のメジャーバージョンとの互換性を維持できます。このインデックス内のドキュメントを更新する必要がなくなった(または、新しいドキュメントを追加する必要がなくなった)場合は、読み取り専用インデックスに変換することをお勧めします。{docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option3.description": "不要になった場合は、{indexManagementLinkHtml}からインデックスを削除することもできます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.reindexingLabel": "再インデックス中…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.restartLabel": "再インデックスの再起動",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.runReindexLabel": "再インデックスの開始",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.tryAgainLabel": "再試行",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexText": "再インデックス処理により、インデックスを互換性のある新しいインデックスに変換できます。この処理では、既存のすべてのドキュメントを新しいインデックスにコピーし、古いインデックスを削除します。サイズとリソースによっては、再インデックス化に時間がかかることがあり、ジョブが完了するまではデータが読み取り専用状態になります。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton": "読み込み専用に設定",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.alternativeOption.description": "不要になった場合は、{indexManagementLinkHtml}からインデックスを削除することもできます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.alternativeOption.title": "代替:インデックスの削除",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option1.description": "このインデックスの状態をフローズンから変更し、読み取り専用にします。これにより、インデックスは次のメジャーバージョンでも互換性が保証されます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option1.title": "オプション 1インデックスのフローズン状態を解除",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option2.description": "あるいは、新しい互換性のあるインデックスにデータを再インデックス化することもできます。既存のすべてのドキュメントは新しいインデックスにコピーされ、古いインデックスは削除されます。インデックスの規模と利用可能なリソースによっては、再インデックス処理に時間がかかる場合があります。再インデックス処理が完了するまで、データは読み取り専用モードになります。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option2.title": "オプション 2データを再インデックス化",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreezeIndexButton": "フローズン状態を解除",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.flyoutHeader": "{index}を更新",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.frozenCallout.reindexFrozenIndex": "アップグレード後は、フローズンインデックスはサポートされなくなります。その結果、このインデックスは更新処理中に非フローズンインデックスに変換されます。{docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.frozenCallout.reindexFrozenIndexTitle": "このインデックスはフローズンです",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.learnMoreLinkLabel": "詳細",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.fetchFailedCalloutTitle": "再インデックスステータスがありません",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.insufficientPrivilegeCallout.calloutTitle": "このインデックスを再インデックスするための権限がありません",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceCalloutDescription": "ディスク使用量が低レベルを超えました。再インデックスが防止される場合があります。次のノードが影響を受けます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceCalloutTitle": "ディスク容量が低下しているノード",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceUsedText": "{nodeName}{available}空き)",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.readonlyCallout.backgroundResumeDetail": "再インデックスはバックグラウンドで実行されます。アップグレードアシスタントに戻って進捗状況を表示するか、Kibanaの再起動後に再インデックスを再開できます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.reindexingLabel": "再インデックス中…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.restartLabel": "再インデックスの再起動",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.resumeLabel": "再インデックスの再開",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel": "再インデックスの開始",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.tryAgainLabel": "再試行",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexDescription": "再インデックス中はインデックスが読み取り専用です。再インデックスが完了するまでは、ドキュメントの追加、更新、削除ができません。新しいクラスターを再インデックスする必要がある場合は、再インデックスAPIを使用します。{docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.aliasCreatedStepTitle": "{reindexName}インデックスの{indexName}エイリアスを作成します。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.aliasesUpdatedStepTitle": "{reindexName}インデックスを参照する{existingAliases}エイリアスを更新します。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancelLabel": "キャンセル",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancelledLabel": "キャンセル済み",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancellingLabel": "キャンセル中…",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.errorLabel": "キャンセルできませんでした",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelledTitle": "再インデックスはキャンセルされました。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.createIndexStepTitle": "{reindexName}インデックスを作成します。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.indexSettingsRestoredStepTitle": "元のインデックス設定を{indexName}から{reindexName}にコピーします。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.aliasCreatedStepTitle": "{reindexName}インデックスの{indexName}エイリアスを作成しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.aliasesUpdatedStepTitle": "{reindexName}インデックスを参照する{existingAliases}エイリアスを更新しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.createIndexStepTitle": "{reindexName}インデックスを作成しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.indexSettingsRestoredStepTitle": "元のインデックス設定を{indexName}から{reindexName}にコピーしています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.originalIndexDeletedStepTitle": "元の{indexName}インデックスを削除しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.readonlyStepTitle": "{indexName}インデックスを読み取り専用に設定しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.reindexingDocumentsStepTitle": "ドキュメントを再インデックスしています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.originalIndexDeletedStepTitle": "元の{indexName}インデックスを削除します。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.readonlyStepTitle": "{indexName}インデックスを読み取り専用に設定します。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.reindexingDocumentsStepTitle": "ドキュメントのインデックスを作成します。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklistTitle": "プロセスを再インデックス中",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingFailedCalloutTitle": "再インデックスエラー",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingInProgressTitle": "再インデックス中です...{percents}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.step.readonlyStepText": "{indexName}インデックスを読み取り専用に設定しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.step.unfreezeStepText": "{indexName}インデックスを凍結解除しています。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateCompleteText": "処理が完了しました",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateFailedText": "処理失敗",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateInProgressText": "アップグレード中...",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.retryButtonLabel": "再試行",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.acceptChangesTitle": "変更を承諾",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.deprecatedIndexSettingsWarningTitle": "廃止予定のインデックス設定を削除",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.documentationLinkLabel": "ドキュメント",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningDetail": "引き続き、{indexName}からドキュメントを検索し、取得できます。新しいドキュメントを挿入したり、既存のドキュメントを修正したりすることはできません。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningTitle": "{indexName}インデックスを読み取り専用に設定",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.calloutDetail": "インデックスを読み取り専用に設定することで、次のバージョンとの互換性を確保できます。新しいドキュメントを挿入しようとしたり、既存のドキュメントを更新しようとしたりしても、失敗します。必要に応じて、アップグレード後に再インデックスを選択し、インデックスを書き込み可能な状態に変換できます。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.calloutTitle": "このインデックスを読み取り専用に設定して互換性を確保",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.continueButtonLabel": "読み込み専用に設定",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.calloutDetail": "続行する前に、インデックスをバックアップしてください。再インデックスを続行するには、各変更を承諾してください。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.calloutTitle": "このインデックスには元に戻すことのできない破壊的な変更が含まれています",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.continueButtonLabel": "再インデックスを続行",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningDetail": "以前のように{indexName}を検索できます。データを削除するには、{reindexName}を削除する必要があります",
"xpack.upgradeAssistant.esDeprecations.indices.reindexCanceledText": "再インデックスはキャンセルされました",
"xpack.upgradeAssistant.esDeprecations.indices.reindexCompleteText": "再インデックス完了",
"xpack.upgradeAssistant.esDeprecations.indices.reindexFailedText": "再インデックス失敗",
"xpack.upgradeAssistant.esDeprecations.indices.reindexFetchFailedText": "再インデックスステータスがありません",
"xpack.upgradeAssistant.esDeprecations.indices.reindexInProgressText": "再インデックス中...",
"xpack.upgradeAssistant.esDeprecations.indices.reindexLabel": "再インデックス",
"xpack.upgradeAssistant.esDeprecations.indices.reindexLoadingStatusText": "ステータスを読み込んでいます...",
"xpack.upgradeAssistant.esDeprecations.indices.reindexPausedText": "再インデックスは一時停止されました",
"xpack.upgradeAssistant.esDeprecations.indices.reindexTooltipLabel": "新しい互換性のあるインデックスに再インデックス化することで、この問題を解決します。",
"xpack.upgradeAssistant.esDeprecations.indices.unfreezeLabel": "フローズン状態を解除",
"xpack.upgradeAssistant.esDeprecations.indices.unfreezeTooltipLabel": "このインデックスの状態をフローズンから変更して、この問題を解決します。",
"xpack.upgradeAssistant.esDeprecations.indices.updateCompleteText": "更新完了",
"xpack.upgradeAssistant.esDeprecations.indices.updateLabel": "更新",
"xpack.upgradeAssistant.esDeprecations.indices.updateTooltipLabel": "このインデックスを更新して、この問題を解決します。この問題は、インデックスを読み取り専用に設定する(大きなインデックスの場合に推奨)か、新しい互換性のあるインデックスに再インデックス化することで、自動的に解決できます。",
"xpack.upgradeAssistant.esDeprecations.loadingText": "廃止予定の問題を読み込んでいます...",
"xpack.upgradeAssistant.esDeprecations.mlDeprecationTypeLabel": "機械学習",
"xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteCompleteText": "削除完了",
@ -47383,7 +47538,6 @@
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.resolvedButtonLabel": "解決済み",
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.retryRemoveButtonLabel": "廃止予定の設定の削除を再試行",
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.secondaryDescription": "インデックス:{indexName}",
"xpack.upgradeAssistant.esDeprecations.table.criticalFilterLabel": "重大",
"xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle": "問題",
"xpack.upgradeAssistant.esDeprecations.table.nameColumnTitle": "名前",
"xpack.upgradeAssistant.esDeprecations.table.noDeprecationsMessage": "Elasticsearchの廃止予定の問題が見つかりません",
@ -47444,7 +47598,6 @@
"xpack.upgradeAssistant.noDeprecationsPrompt.description": "{deprecationType}構成は最新です",
"xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "他のスタック廃止予定については、{overviewButton}を確認してください。",
"xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "概要ページ",
"xpack.upgradeAssistant.noPartialDeprecationsMessage": "なし",
"xpack.upgradeAssistant.overview.analyzeTitle": "廃止予定ログを分析",
"xpack.upgradeAssistant.overview.apiCompatibilityNoteBody": "アップグレード前にすべての廃止予定の問題を解決することをお勧めします。必要に応じて、廃止予定の機能を使用する要求にAPI互換性ヘッダーを適用できます。{learnMoreLink}。",
"xpack.upgradeAssistant.overview.apiCompatibilityNoteLink": "詳細",
@ -47468,8 +47621,6 @@
"xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "ログ情報を取得できませんでした。",
"xpack.upgradeAssistant.overview.deprecationLogs.reloadButtonLabel": "再試行",
"xpack.upgradeAssistant.overview.deprecationLogs.updateErrorMessage": "ログ状態を更新できませんでした。",
"xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "廃止予定の問題を解決して変更を検証",
"xpack.upgradeAssistant.overview.documentationLinkText": "ドキュメント",
"xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "アップグレードステータスの取得中にエラーが発生しました",
"xpack.upgradeAssistant.overview.fixIssuesStepDescription": "次のバージョンのElastic Stackにアップグレードする前に、重大なElasticsearchおよびKibana構成の問題を解決する必要があります。警告を無視すると、アップグレード後に動作が変更される場合があります。",
"xpack.upgradeAssistant.overview.fixIssuesStepTitle": "廃止予定設定を確認し、問題を解決",
@ -47486,10 +47637,7 @@
"xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle": "廃止予定ログを分析するには、インデックス権限が必要です",
"xpack.upgradeAssistant.overview.logsStep.retryButton": "再試行",
"xpack.upgradeAssistant.overview.logsStep.title": "API廃止予定に対処",
"xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel": "ログを表示",
"xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes": "最新リリースのハイライト",
"xpack.upgradeAssistant.overview.observe.discoveryDescription": "廃止予定ログを検索およびフィルターし、必要な変更のタイプを把握します。",
"xpack.upgradeAssistant.overview.pageDescription": "次のバージョンのElastic Stackをお待ちください。",
"xpack.upgradeAssistant.overview.pageTitle": "アップグレードアシスタント",
"xpack.upgradeAssistant.overview.snapshotRestoreLink": "スナップショットの作成",
"xpack.upgradeAssistant.overview.systemIndices.body": "アップグレードの内部情報を格納するシステムインデックスを準備します。これはメジャーバージョンアップグレード中にのみ必要です。インデックスを再作成する必要があるすべての{hiddenIndicesLink}は次のステップで表示されます。",
@ -47507,7 +47655,6 @@
"xpack.upgradeAssistant.overview.systemIndices.loadingError": "システムインデックスステータスを取得できませんでした",
"xpack.upgradeAssistant.overview.systemIndices.migratingLabel": "移行中",
"xpack.upgradeAssistant.overview.systemIndices.migrationCompleteLabel": "移行完了",
"xpack.upgradeAssistant.overview.systemIndices.migrationFailedBody": "{feature}のシステムインデックスの移行中にエラーが発生しました:{failureCause}",
"xpack.upgradeAssistant.overview.systemIndices.migrationFailedTitle": "システムインデックスの移行が失敗しました",
"xpack.upgradeAssistant.overview.systemIndices.needsMigrationLabel": "移行が必要",
"xpack.upgradeAssistant.overview.systemIndices.noMigrationNeeded": "システムインデックスの移行は不要です。",
@ -47522,7 +47669,6 @@
"xpack.upgradeAssistant.overview.upgradeStepDescription": "重要な問題をすべて解決し、アプリケーションの準備を確認した後に、次のバージョンのElastic Stackにアップグレードできます。アップグレードする前に、必ずもう一度データをバックアップしたことを確認してください。",
"xpack.upgradeAssistant.overview.upgradeStepDescriptionForCloud": "重要な問題をすべて解決し、アプリケーションの準備を確認した後に、次のバージョンのElastic Stackにアップグレードできます。アップグレードする前に、必ずもう一度データをバックアップしたことを確認してください。Elastic Cloudでデプロイをアップグレードします。",
"xpack.upgradeAssistant.overview.upgradeStepTitle": "Elastic Stackをアップグレード",
"xpack.upgradeAssistant.overview.upgradeToLatestMinorBeforeMajorMessage": "{link}を確認してください。新しいメジャーバージョンにアップグレードする前に、まずこのメジャーバージョンの最新マイナーバージョンにアップグレードする必要があります。",
"xpack.upgradeAssistant.overview.verifyChanges.calloutBody": "変更した後、カウンターをリセットして監視を続け、廃止予定の機能を使用していないことを確認します。",
"xpack.upgradeAssistant.overview.verifyChanges.calloutTitle": "{previousCheck}以降{warningsCount, plural, =0 {0} other {{warningsCount}}}件の廃止予定{warningsCount, plural , other {件の問題}}",
"xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle": "廃止予定ログキャッシュを削除できませんでした",

View file

@ -47370,10 +47370,74 @@
"xpack.upgradeAssistant.app.deniedPrivilegeDescription": "要使用升级助手并解决弃用问题,必须具有管理所有 Kibana 工作区的访问权限。",
"xpack.upgradeAssistant.app.deniedPrivilegeTitle": "需要 Kibana 管理员角色",
"xpack.upgradeAssistant.appTitle": "升级助手",
"xpack.upgradeAssistant.breadcrumb.esDeprecationLogsLabel": "Elasticsearch 弃用日志",
"xpack.upgradeAssistant.breadcrumb.esDeprecationsLabel": "Elasticsearch 弃用问题",
"xpack.upgradeAssistant.breadcrumb.kibanaDeprecationsLabel": "Kibana 弃用问题",
"xpack.upgradeAssistant.breadcrumb.overviewLabel": "升级助手",
"xpack.upgradeAssistant.dataStream.flyout.container.indicesDocsCount": "文档计数",
"xpack.upgradeAssistant.dataStream.flyout.container.indicesDocsSize": "大小",
"xpack.upgradeAssistant.dataStream.flyout.errorLoadingDataStreamInfo": "加载数据流信息时出错",
"xpack.upgradeAssistant.dataStream.flyout.unknownMessage": "未知",
"xpack.upgradeAssistant.dataStream.flyout.warningsStep.readonly.acceptChangesTitle": "{count, plural, other {# 个后备索引}}(包括当前写入索引)将标记为只读。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.backButtonLabel": "返回",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.cancelMigrationButtonLabel": "取消{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {迁移}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.closeButtonLabel": "关闭",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.fetchFailedCalloutTitle": "迁移状态不可用",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.fetchingStatus": "正在提取状态……",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.insufficientPrivilegeCallout.calloutTitle": "您的权限不足,无法迁移此数据流",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceCalloutDescription": "磁盘使用已超出低水位线,这可能会阻止迁移。以下节点会受到影响:",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceCalloutTitle": "磁盘空间不足的节点",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.lowDiskSpaceUsedText": "{nodeName}{available} 可用)",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.migrationFailedCalloutTitle": "{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {迁移}}错误",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.completeTitle": "{count, plural, other {# 个索引}}已成功{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {迁移}}。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.failedTitle": "{count, plural, other {# 个索引}}未能{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {迁移}}。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.inProgressTitle": "{count, plural, other {# 个索引}}当前正在{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {迁移}}。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.progressStep.pendingTitle": "{count, plural, other {# 个索引}}正等待启动。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.readonlyCallout.backgroundResumeDetail": "将在后台执行重新索引。您可以返回到升级助手以查看进度。",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.cancelledLabel": "已取消",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.cancellingLabel": "正在取消……",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelButton.errorLabel": "未能取消{resolutionType, select, reindex {重新索引} readonly {只读} other {}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.cancelled.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {}}已取消",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.completed.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {}}已完成",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.failed.reindexingDocumentsStepTitle": "未能{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.fetchFailed.reindexingDocumentsStepTitle": "提取状态失败",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklist.inProgress.reindexingDocumentsStepTitle": "{resolutionType, select, reindex {重新索引数据流} readonly {将数据流标记为只读} other {未知操作}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingChecklistTitle": "{resolutionType, select, reindex {重新索引数据流} readonly {将数据流标记为只读} other {迁移数据流}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.reindexingInProgressTitle": "已启动 {startTimeFromNow}",
"xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.startActionButtonLabel": "将所有项标记为只读",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.closeButtonLabel": "关闭",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.fetchFailedCalloutTitle": "数据流迁移状态不可用",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.indexMgmtLink": "前往索引管理",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.insufficientPrivilegeCallout.calloutTitle": "您的权限不足,无法迁移此数据流。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceCalloutDescription": "磁盘使用已超出低水位线,这可能会阻止迁移。以下节点会受到影响:",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceCalloutTitle": "磁盘空间不足的节点",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.lowDiskSpaceUsedText": "{nodeName}{available} 可用)",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.migrationDescription": "如果不再需要此数据,也可以继续删除这些索引。{indexManagementLinkHtml}",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.migrationFailedCalloutTitle": "数据流迁移错误",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.notCompatibleIndicesText": "您在此数据流上具有 {backingIndicesCount} 个在 ES 7.x 中创建的后备索引,它们将不兼容后续版本。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.readOnlyText": "如果不需要更新历史数据,请标记为只读。如果需要更新,可以在升级后重新索引。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOption.additionalIndices": "其他后备索引将进行重新索引,并保持可编辑状态。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOption.rolledOverIndex": "当前写入索引将进行滚动更新并重新索引。",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.reindexOptionListTitle": "重新索引",
"xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.requiredUpgradeText": "共有 {allBackingIndices} 个后备索引,{backingIndicesRequireingUpgrade} 个需要升级。",
"xpack.upgradeAssistant.dataStream.migration.flyout.initializingStep.errorLoadingDataStreamInfo": "加载数据流信息时出错",
"xpack.upgradeAssistant.dataStream.migration.flyout.initializingStep.loadingDataStreamInfo": "正在加载数据流信息",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.reindexingLabel": "{resolutionType, select, reindex {正在重新索引} readonly {正在标记为只读} other {正在迁移}}……",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.restartLabel": "{resolutionType, select, reindex {重新开始重新索引} readonly {重新开始标记为只读} other {重新开始迁移}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.runReindexLabel": "{resolutionType, select, reindex {开始重新索引} readonly {开始标记为只读} other {开始迁移}}",
"xpack.upgradeAssistant.dataStream.migration.flyout.reindexButton.tryAgainLabel": "重试",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.acceptChangesTitle": "成功!{count, plural, other {# 个后备索引}}已成功{resolutionType, select, reindex {重新索引} readonly {标记为只读} other {迁移}}。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.affectExistingSetupsWarningTitle": "将此数据流的所有不兼容数据标记为只读",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.documentationLinkLabel": "文档",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.incompatibleDataWarningTitle": "重新索引此数据流的所有不兼容数据",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.indicesNeedReindexing": "于 {formattedDate}或之前创建的索引需要重新索引为兼容的格式,或标记为只读。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.learnMoreLink": "了解详情",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.readonly.calloutDetail": "确保已备份您的数据,等等。您始终可以稍后重新索引此数据,以将其设为可编辑。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.readonly.calloutTitle": "将此数据标记为只读可能会影响某些现有设置",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.reindex.calloutDetail": "确保已备份数据,然后继续。要继续重新索引此数据,请在下面确认。",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.reindex.calloutTitle": "此操作需要做出无法恢复的破坏性更改",
"xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.suggestReadOnly": "根据大小和资源限制,重新索引可能需要很长时间,您的数据将处于只读状态,直到作业完成。{learnMoreHtml}",
"xpack.upgradeAssistant.datastream.readonlyPrivilegesErrorBatch": "您的权限不足,无法将数据流“{dataStreamName}”中的索引标记为只读。",
"xpack.upgradeAssistant.datastream.reindexPrivilegesErrorBatch": "您的权限不足,无法取消重新索引“{dataStreamName}”。",
"xpack.upgradeAssistant.deprecationBadge.criticalBadgeLabel": "紧急",
"xpack.upgradeAssistant.deprecationBadge.resolvedBadgeLabel": "已解决",
"xpack.upgradeAssistant.deprecationBadge.warningBadgeLabel": "警告",
@ -47381,15 +47445,11 @@
"xpack.upgradeAssistant.deprecationCount.warningStatusLabel": "警告:{count}",
"xpack.upgradeAssistant.deprecationFlyout.learnMoreLinkLabel": "了解详情",
"xpack.upgradeAssistant.deprecationsPageLoadingError.title": "无法检索 {deprecationSource} 弃用问题",
"xpack.upgradeAssistant.deprecationStats.criticalDeprecationsTitle": "紧急",
"xpack.upgradeAssistant.deprecationStats.loadingErrorMessage": "无法检索 Kibana 弃用问题。",
"xpack.upgradeAssistant.deprecationStats.warningDeprecationsTitle": "警告",
"xpack.upgradeAssistant.esDeprecationErrors.loadingErrorMessage": "无法检索 Elasticsearch 弃用问题。",
"xpack.upgradeAssistant.esDeprecationErrors.partiallyUpgradedWarningMessage": "将 Kibana 升级到与您的 Elasticsearch 集群相同的版本。集群中的一个或多个节点正在运行与 Kibana 不同的版本。",
"xpack.upgradeAssistant.esDeprecationErrors.permissionsErrorMessage": "您无权查看 Elasticsearch 弃用问题。",
"xpack.upgradeAssistant.esDeprecationErrors.upgradedWarningMessage": "所有 Elasticsearch 节点已升级。",
"xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText": "文档",
"xpack.upgradeAssistant.esDeprecationLogs.pageDescription": "请复查弃用日志以确定您的应用程序是否正使用任何已弃用的 API。在升级后请更新应用程序以防止错误或行为更改。",
"xpack.upgradeAssistant.esDeprecationLogs.pageTitle": "Elasticsearch 弃用日志",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsDescription": "要在单一请求中开始升级多个索引,请使用 Kibana {docsLink}。注意:此 API 不支持数据流。",
"xpack.upgradeAssistant.esDeprecations.batchReindexingDocsLink": "批量重新索引 API",
@ -47415,6 +47475,102 @@
"xpack.upgradeAssistant.esDeprecations.indexSettings.deletingButtonLabel": "设置移除进行中……",
"xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionText": "移除设置",
"xpack.upgradeAssistant.esDeprecations.indexSettings.resolutionTooltipLabel": "通过从此索引中移除设置来解决该问题。此问题会自动解决。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.backButtonLabel": "返回",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.closeButtonLabel": "关闭",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.frozenIndexText": "此索引已冻结。升级后将不再支持已冻结索引。选择以下选项之一:",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.indexMgmtLink": "索引管理",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.insufficientPrivilegeCallout.calloutTitle": "您的权限不足,无法重新索引此索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceCalloutDescription": "磁盘使用已超出低水位线,这可能会阻止重新索引。以下节点会受到影响:",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceCalloutTitle": "磁盘空间不足的节点",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.lowDiskSpaceUsedText": "{nodeName}{available} 可用)",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleIndexText": "此索引在 ES 7.x 中创建,与下一主要版本不兼容。选择以下选项之一:",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.readonlyCompatibleIndexText": "此索引在 ES 7.x 中创建。它已被标记为只读,这有助于兼容下一主要版本。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.description": "借助重新索引操作,可以将索引转换为新的兼容索引。这会将所有现有文档复制到新索引中,然后删除旧版索引。根据大小和资源限制,重新索引可能需要很长时间,您的数据将处于只读状态,直到作业完成。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option2.description": "如果转换为只读模式,旧版索引可保持兼容下一主要版本。如果不再需要在此索引中更新文档(或添加新文档),您可能希望将其转换为只读索引。{docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option3.description": "如果不再需要该索引,还可以将其从 {indexManagementLinkHtml} 中删除。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.reindexingLabel": "正在重新索引……",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.restartLabel": "重新启动重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.runReindexLabel": "启动重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.tryAgainLabel": "重试",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexText": "借助重新索引操作,可以将索引转换为新的兼容索引。这会将所有现有文档复制到新索引中,然后删除旧版索引。根据大小和资源限制,重新索引可能需要很长时间,您的数据将处于只读状态,直到作业完成。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton": "标记为只读",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.alternativeOption.description": "如果不再需要该索引,还可以将其从 {indexManagementLinkHtml} 中删除。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.alternativeOption.title": "选择:删除索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option1.description": "取消冻结此索引并将其标记为只读。这将确保该索引仍然兼容下一主要版本。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option1.title": "选项 1取消冻结索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option2.description": "或者,您可以将数据重新索引到新的兼容索引中。所有现有文档将复制到新索引中,并会删除旧版索引。根据索引大小和可用资源,重新索引操作可能需要一些时间。您的数据将处于只读模式,直到重新索引完成。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreeze.option2.title": "选项 2为数据重建索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.unfreezeIndexButton": "取消冻结",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.flyoutHeader": "更新 {index}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.frozenCallout.reindexFrozenIndex": "升级后将不再支持已冻结索引。因此,会在更新操作期间将此索引转换为非冻结索引。{docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.frozenCallout.reindexFrozenIndexTitle": "此索引已冻结",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.learnMoreLinkLabel": "了解详情",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.fetchFailedCalloutTitle": "重新索引状态不可用",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.insufficientPrivilegeCallout.calloutTitle": "您没有足够的权限来重新索引此索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceCalloutDescription": "磁盘使用已超出低水位线,这可能会阻止重新索引。以下节点会受到影响:",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceCalloutTitle": "磁盘空间不足的节点",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.lowDiskSpaceUsedText": "{nodeName}{available} 可用)",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.readonlyCallout.backgroundResumeDetail": "将在后台执行重新索引。可以返回到升级助手,查看在 Kibana 重新启动之后恢复重新索引的进度。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.reindexingLabel": "正在重新索引……",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.restartLabel": "重新启动重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.resumeLabel": "恢复重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel": "启动重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.tryAgainLabel": "重试",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexDescription": "重新索引期间,索引将处于只读状态。在重新索引完成之前,您无法添加、更新或删除文档。如果需要重新索引到新集群,请使用重新索引 API。{docsLink}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.aliasCreatedStepTitle": "创建 {reindexName} 索引的 {indexName} 别名。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.aliasesUpdatedStepTitle": "更新 {existingAliases} 别名以指向 {reindexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancelLabel": "取消",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancelledLabel": "已取消",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.cancellingLabel": "正在取消……",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelButton.errorLabel": "无法取消",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.cancelledTitle": "重新索引已取消。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.createIndexStepTitle": "创建 {reindexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.indexSettingsRestoredStepTitle": "将原始索引设置从 {indexName} 复制到 {reindexName}。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.aliasCreatedStepTitle": "正在创建 {reindexName} 索引的 {indexName} 别名。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.aliasesUpdatedStepTitle": "正在更新 {existingAliases} 别名以指向 {reindexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.createIndexStepTitle": "正在创建 {reindexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.indexSettingsRestoredStepTitle": "正将原始索引设置从 {indexName} 复制到 {reindexName}。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.originalIndexDeletedStepTitle": "正在删除原始 {indexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.readonlyStepTitle": "正在将 {indexName} 索引设置为只读。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.inProgress.reindexingDocumentsStepTitle": "正在重新索引文档。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.originalIndexDeletedStepTitle": "删除原始 {indexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.readonlyStepTitle": "将 {indexName} 索引设置为只读。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklist.reindexingDocumentsStepTitle": "索引文档。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingChecklistTitle": "重新索引过程",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingFailedCalloutTitle": "重新索引错误",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexingInProgressTitle": "重新索引正在进行中……{percents}",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.step.readonlyStepText": "正在将 {indexName} 索引设置为只读。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.step.unfreezeStepText": "正在取消冻结 {indexName} 索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateCompleteText": "操作已完成",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateFailedText": "操作失败",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.checklist.title.updateInProgressText": "升级进行中……",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.updateStep.retryButtonLabel": "重试",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.acceptChangesTitle": "接受更改",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.deprecatedIndexSettingsWarningTitle": "移除弃用的索引设置",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.documentationLinkLabel": "文档",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningDetail": "您可以继续从 {indexName} 中搜索和检索文档。您将无法插入新文档,也无法修改现有文档。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningTitle": "将 {indexName} 索引标记为只读",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.calloutDetail": "您可以通过将此索引标记为只读来兼容下一版本。请注意,插入新文档或更新现有文档的任何尝试都将失败。如果需要,您可以选择在升级后进行重新索引,以将该索引转换为可写索引。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.calloutTitle": "通过将此索引标记为只读来实现兼容性",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.readonly.continueButtonLabel": "标记为只读",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.calloutDetail": "继续前备份索引。要继续重新索引,请接受每个更改。",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.calloutTitle": "此索引需要无法恢复的破坏性更改",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.reindex.continueButtonLabel": "继续重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningDetail": "您可以像以前一样搜索 {indexName}。要删除数据,必须删除 {reindexName}",
"xpack.upgradeAssistant.esDeprecations.indices.reindexCanceledText": "已取消重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.reindexCompleteText": "重新索引完成",
"xpack.upgradeAssistant.esDeprecations.indices.reindexFailedText": "重新索引失败",
"xpack.upgradeAssistant.esDeprecations.indices.reindexFetchFailedText": "重新索引状态不可用",
"xpack.upgradeAssistant.esDeprecations.indices.reindexInProgressText": "重新索引正在进行中……",
"xpack.upgradeAssistant.esDeprecations.indices.reindexLabel": "重新索引",
"xpack.upgradeAssistant.esDeprecations.indices.reindexLoadingStatusText": "正在加载状态……",
"xpack.upgradeAssistant.esDeprecations.indices.reindexPausedText": "重新索引已暂停",
"xpack.upgradeAssistant.esDeprecations.indices.reindexTooltipLabel": "通过重新索引到新的兼容索引来解决此问题。",
"xpack.upgradeAssistant.esDeprecations.indices.unfreezeLabel": "取消冻结",
"xpack.upgradeAssistant.esDeprecations.indices.unfreezeTooltipLabel": "通过取消冻结该索引来解决此问题。",
"xpack.upgradeAssistant.esDeprecations.indices.updateCompleteText": "更新完成",
"xpack.upgradeAssistant.esDeprecations.indices.updateLabel": "更新",
"xpack.upgradeAssistant.esDeprecations.indices.updateTooltipLabel": "通过更新该索引来解决此问题。可以通过将该索引标记为只读(建议用于大型索引)或重新索引到新的兼容索引来解决此问题。",
"xpack.upgradeAssistant.esDeprecations.loadingText": "正在加载弃用问题……",
"xpack.upgradeAssistant.esDeprecations.mlDeprecationTypeLabel": "Machine Learning",
"xpack.upgradeAssistant.esDeprecations.mlSnapshots.deleteCompleteText": "删除完成",
@ -47457,7 +47613,6 @@
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.resolvedButtonLabel": "已解决",
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.retryRemoveButtonLabel": "重试移除过时设置",
"xpack.upgradeAssistant.esDeprecations.removeSettingsFlyout.secondaryDescription": "索引:{indexName}",
"xpack.upgradeAssistant.esDeprecations.table.criticalFilterLabel": "紧急",
"xpack.upgradeAssistant.esDeprecations.table.issueColumnTitle": "问题",
"xpack.upgradeAssistant.esDeprecations.table.nameColumnTitle": "名称",
"xpack.upgradeAssistant.esDeprecations.table.noDeprecationsMessage": "未找到 Elasticsearch 弃用问题",
@ -47518,7 +47673,6 @@
"xpack.upgradeAssistant.noDeprecationsPrompt.description": "您的 {deprecationType} 配置是最新的",
"xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "查看{overviewButton}以了解其他 Stack 弃用。",
"xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "“概览”页面",
"xpack.upgradeAssistant.noPartialDeprecationsMessage": "无",
"xpack.upgradeAssistant.overview.analyzeTitle": "分析弃用日志",
"xpack.upgradeAssistant.overview.apiCompatibilityNoteBody": "建议您在升级之前解决所有弃用问题。如果需要,您可以将 API 兼容性标头应用于使用过时功能的请求。{learnMoreLink}。",
"xpack.upgradeAssistant.overview.apiCompatibilityNoteLink": "了解详情",
@ -47542,8 +47696,6 @@
"xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage": "无法检索日志记录信息。",
"xpack.upgradeAssistant.overview.deprecationLogs.reloadButtonLabel": "重试",
"xpack.upgradeAssistant.overview.deprecationLogs.updateErrorMessage": "无法更新日志记录状态。",
"xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "解决弃用问题并验证您的更改",
"xpack.upgradeAssistant.overview.documentationLinkText": "文档",
"xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "检索升级状态时出错",
"xpack.upgradeAssistant.overview.fixIssuesStepDescription": "在升级到下一版本的 Elastic Stack 之前,必须解决任何严重的 Elasticsearch 和 Kibana 配置问题。在您升级后,忽略警告可能会导致行为差异。",
"xpack.upgradeAssistant.overview.fixIssuesStepTitle": "复查已弃用设置并解决问题",
@ -47560,10 +47712,7 @@
"xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle": "您需要索引权限才能分析弃用日志",
"xpack.upgradeAssistant.overview.logsStep.retryButton": "重试",
"xpack.upgradeAssistant.overview.logsStep.title": "解决 API 弃用",
"xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel": "查看日志",
"xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes": "最新发布亮点",
"xpack.upgradeAssistant.overview.observe.discoveryDescription": "搜索并筛选弃用日志以了解需要进行的更改类型。",
"xpack.upgradeAssistant.overview.pageDescription": "准备使用下一版 Elastic Stack",
"xpack.upgradeAssistant.overview.pageTitle": "升级助手",
"xpack.upgradeAssistant.overview.snapshotRestoreLink": "创建快照",
"xpack.upgradeAssistant.overview.systemIndices.body": "为升级准备存储内部信息的系统索引。仅在主要版本升级期间需要此项。将在下一步中显示任何需要重新索引的{hiddenIndicesLink}。",
@ -47581,7 +47730,6 @@
"xpack.upgradeAssistant.overview.systemIndices.loadingError": "无法检索系统索引状态",
"xpack.upgradeAssistant.overview.systemIndices.migratingLabel": "正在进行迁移",
"xpack.upgradeAssistant.overview.systemIndices.migrationCompleteLabel": "迁移完成",
"xpack.upgradeAssistant.overview.systemIndices.migrationFailedBody": "迁移 {feature} 的系统索引时出错:{failureCause}",
"xpack.upgradeAssistant.overview.systemIndices.migrationFailedTitle": "系统索引迁移失败",
"xpack.upgradeAssistant.overview.systemIndices.needsMigrationLabel": "需要迁移",
"xpack.upgradeAssistant.overview.systemIndices.noMigrationNeeded": "不需要进行系统索引迁移。",
@ -47596,7 +47744,6 @@
"xpack.upgradeAssistant.overview.upgradeStepDescription": "解决所有关键问题并确认您的应用程序就绪后,便可以升级到下一版本的 Elastic Stack。在升级之前请确保再次备份您的数据。",
"xpack.upgradeAssistant.overview.upgradeStepDescriptionForCloud": "解决所有关键问题并确认您的应用程序就绪后,便可以升级到下一版本的 Elastic Stack。在升级之前请确保再次备份您的数据。在 Elastic Cloud 上升级您的部署。",
"xpack.upgradeAssistant.overview.upgradeStepTitle": "升级 Elastic Stack",
"xpack.upgradeAssistant.overview.upgradeToLatestMinorBeforeMajorMessage": "请参阅 {link}。升级到新的主要版本之前,必须先升级到此主要版本的最新次要版本。",
"xpack.upgradeAssistant.overview.verifyChanges.calloutBody": "做出更改后,请重置计数器并继续监测,以确认您不再使用过时功能。",
"xpack.upgradeAssistant.overview.verifyChanges.calloutTitle": "自 {previousCheck} 以来出现 {warningsCount, plural, other {{warningsCount}}} 个弃用{warningsCount, plural, other {问题}} ",
"xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle": "无法删除弃用日志缓存",

View file

@ -8,13 +8,13 @@
import { act } from 'react-dom/test-utils';
import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers';
import { HttpSetup } from '@kbn/core/public';
import { EsDeprecationLogs } from '../../../public/application/components';
import { Overview } from '../../../public/application/components';
import { WithAppDependencies } from '../helpers';
const testBedConfig: AsyncTestBedConfig = {
memoryRouter: {
initialEntries: ['/es_deprecation_logs'],
componentRoutePath: '/es_deprecation_logs',
initialEntries: [`/overview`],
componentRoutePath: '/overview',
},
doMountAsync: true,
};
@ -28,21 +28,30 @@ const createActions = (testBed: TestBed) => {
* User Actions
*/
const clickDeprecationToggle = async () => {
const clickOpenFlyoutLoggingEnabled = async () => {
const { find, component } = testBed;
await act(async () => {
find('deprecationLoggingToggle').simulate('click');
find('viewDetailsLink').simulate('click');
});
component.update();
};
const clickOpenFlyoutLoggingDisabled = async () => {
const { find, component } = testBed;
await act(async () => {
find('enableLogsLink').simulate('click');
});
component.update();
};
const clickRetryButton = async () => {
const clickDeprecationToggle = async () => {
const { find, component } = testBed;
await act(async () => {
find('retryButton').simulate('click');
find('deprecationLoggingToggle').simulate('click');
});
component.update();
@ -57,11 +66,22 @@ const createActions = (testBed: TestBed) => {
component.update();
};
const clickCloseFlyout = async () => {
const { find, component } = testBed;
await act(async () => {
find('closeEsDeprecationLogs').simulate('click');
});
component.update();
};
return {
clickOpenFlyoutLoggingEnabled,
clickOpenFlyoutLoggingDisabled,
clickDeprecationToggle,
clickRetryButton,
clickResetButton,
clickCloseFlyout,
};
};
@ -70,7 +90,7 @@ export const setupESDeprecationLogsPage = async (
overrides?: Record<string, unknown>
): Promise<EsDeprecationLogsTestBed> => {
const initTestBed = registerTestBed(
WithAppDependencies(EsDeprecationLogs, httpSetup, overrides),
WithAppDependencies(Overview, httpSetup, overrides),
testBedConfig
);
const testBed = await initTestBed();

View file

@ -10,15 +10,14 @@ import {
EsDeprecationLogsTestBed,
setupESDeprecationLogsPage,
} from './es_deprecation_logs.helpers';
import { setupEnvironment, advanceTime } from '../helpers';
import { setupEnvironment } from '../helpers';
import { DeprecationLoggingStatus } from '../../../common/types';
import {
DEPRECATION_LOGS_INDEX,
DEPRECATION_LOGS_COUNT_POLL_INTERVAL_MS,
APPS_WITH_DEPRECATION_LOGS,
DEPRECATION_LOGS_ORIGIN_FIELD,
DEPRECATION_LOGS_COUNT_POLL_INTERVAL_MS,
} from '../../../common/constants';
import { advanceTime } from '../helpers';
// Once the logs team register the kibana locators in their app, we should be able
// to remove this mock and follow a similar approach to how discover link is tested.
// See: https://github.com/elastic/kibana/issues/104855
@ -37,7 +36,7 @@ const getLoggingResponse = (toggle: boolean): DeprecationLoggingStatus => ({
isDeprecationLoggingEnabled: toggle,
});
describe('ES deprecation logs', () => {
describe('ES deprecation logs flyout', () => {
let testBed: EsDeprecationLogsTestBed;
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
@ -47,23 +46,89 @@ describe('ES deprecation logs', () => {
httpSetup = mockEnvironment.httpSetup;
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(true));
testBed = await setupESDeprecationLogsPage(httpSetup);
testBed.component.update();
});
test('opens flyout with logging enabled', async () => {
const { exists, actions, find } = testBed;
describe('Documentation link', () => {
test('Has a link for migration info api docs in page header', () => {
const { exists } = testBed;
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('documentationLink')).toBe(true);
expect(exists('flyoutTitle')).toBe(true);
expect(find('flyoutTitle').text()).toContain('Elasticsearch deprecation logs');
expect(exists('noWarningsCallout')).toBe(true);
expect(exists('closeEsDeprecationLogs')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(true);
expect(exists('deprecationLogsDescription')).toBe(true);
expect(exists('deprecationLoggingToggle')).toBe(true);
expect(exists('viewDiscoverLogs')).toBe(true);
expect(exists('apiCompatibilityNoteTitle')).toBe(true);
await actions.clickCloseFlyout();
expect(exists('flyoutTitle')).toBe(false);
});
test('opens flyout with logging disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(false));
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component, actions, find } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingDisabled();
expect(exists('flyoutTitle')).toBe(true);
expect(find('flyoutTitle').text()).toContain('Elasticsearch deprecation logs');
expect(exists('noWarningsCallout')).toBe(false);
expect(exists('hasWarningsCallout')).toBe(false);
expect(exists('deprecationLogsDescription')).toBe(true);
expect(exists('deprecationLoggingToggle')).toBe(true);
expect(exists('viewDiscoverLogs')).toBe(false);
expect(exists('apiCompatibilityNoteTitle')).toBe(false);
expect(exists('closeEsDeprecationLogs')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(false);
await actions.clickCloseFlyout();
expect(exists('flyoutTitle')).toBe(false);
});
describe('banner', () => {
test('shows success callout if no warnings', async () => {
const { exists, actions, find } = testBed;
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('noWarningsCallout')).toBe(true);
expect(find('noWarningsCallout').text()).toContain('No deprecation issues');
});
test('shows callout with the number of warnings', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component, actions, find } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('hasWarningsCallout')).toBe(true);
expect(find('hasWarningsCallout').text()).toContain('10');
});
});
describe('Step 1 - Toggle log writing and collecting', () => {
describe('Flyout - Toggle log writing and collecting', () => {
test('toggles deprecation logging', async () => {
const { find, actions } = testBed;
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(getLoggingResponse(false));
await actions.clickOpenFlyoutLoggingEnabled();
expect(find('deprecationLoggingToggle').props()['aria-checked']).toBe(true);
@ -73,25 +138,6 @@ describe('ES deprecation logs', () => {
`/api/upgrade_assistant/deprecation_logging`,
expect.objectContaining({ body: JSON.stringify({ isEnabled: false }) })
);
expect(find('deprecationLoggingToggle').props()['aria-checked']).toBe(false);
});
test('shows callout when only loggerDeprecation is enabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: false,
isDeprecationLoggingEnabled: true,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component } = testBed;
component.update();
expect(exists('deprecationWarningCallout')).toBe(true);
});
test('handles network error when updating logging state', async () => {
@ -100,69 +146,44 @@ describe('ES deprecation logs', () => {
error: 'Internal server error',
message: 'Internal server error',
};
const { actions, exists } = testBed;
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(false));
httpRequestsMockHelpers.setUpdateDeprecationLoggingResponse(undefined, error);
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, actions, component } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingDisabled();
await actions.clickDeprecationToggle();
expect(exists('updateLoggingError')).toBe(true);
});
test('handles network error when fetching logging state', async () => {
const error = {
statusCode: 500,
error: 'Internal server error',
message: 'Internal server error',
};
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(undefined, error);
test('does not show external links and deprecations count when toggle is disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(false));
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { component, exists } = testBed;
component.update();
expect(exists('fetchLoggingError')).toBe(true);
});
test('It doesnt show external links and deprecations count when toggle is disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: false,
isDeprecationLoggingEnabled: false,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component } = testBed;
const { exists, actions, component } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingDisabled();
expect(exists('externalLinksTitle')).toBe(false);
expect(exists('deprecationsCountTitle')).toBe(false);
expect(exists('apiCompatibilityNoteTitle')).toBe(false);
});
});
describe('Step 2 - Analyze logs', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
});
describe('analyze logs', () => {
test('has a link to see logs in discover app', async () => {
const { exists, find, actions } = testBed;
test('Has a link to see logs in discover app', async () => {
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component, find } = testBed;
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('viewDiscoverLogs')).toBe(true);
@ -184,74 +205,11 @@ describe('ES deprecation logs', () => {
});
});
describe('Step 3 - Resolve log issues', () => {
describe('reset counter', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
httpRequestsMockHelpers.setDeleteLogsCacheResponse('ok');
});
test('With deprecation warnings', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { find, exists, component } = testBed;
component.update();
expect(exists('hasWarningsCallout')).toBe(true);
expect(find('hasWarningsCallout').text()).toContain('10');
});
test('No deprecation issues', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { find, exists, component } = testBed;
component.update();
expect(exists('noWarningsCallout')).toBe(true);
expect(find('noWarningsCallout').text()).toContain('No deprecation issues');
});
test('Handles errors and can retry', async () => {
const error = {
statusCode: 500,
error: 'Internal server error',
message: 'Internal server error',
};
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse(undefined, error);
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, actions, component } = testBed;
component.update();
expect(exists('errorCallout')).toBe(true);
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});
await actions.clickRetryButton();
expect(exists('noWarningsCallout')).toBe(true);
});
test('Allows user to reset last stored date', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
@ -265,6 +223,7 @@ describe('ES deprecation logs', () => {
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('hasWarningsCallout')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(true);
@ -307,6 +266,7 @@ describe('ES deprecation logs', () => {
component.update();
await actions.clickOpenFlyoutLoggingEnabled();
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ count: 0 });
await actions.clickResetButton();
@ -336,8 +296,9 @@ describe('ES deprecation logs', () => {
});
test('success state is followed by an error state', async () => {
const { exists } = testBed;
const { exists, actions } = testBed;
await actions.clickOpenFlyoutLoggingEnabled();
expect(exists('resetLastStoredDate')).toBe(true);
// second request will error
@ -356,57 +317,4 @@ describe('ES deprecation logs', () => {
});
});
});
describe('Step 4 - API compatibility header', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
});
test('It shows copy with compatibility api header advice', async () => {
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup);
});
const { exists, component } = testBed;
component.update();
expect(exists('apiCompatibilityNoteTitle')).toBe(true);
});
});
describe('Privileges check', () => {
test(`permissions warning callout is hidden if user has the right privileges`, async () => {
const { exists } = testBed;
// Index privileges warning callout should not be shown
expect(exists('noIndexPermissionsCallout')).toBe(false);
// Analyze logs and Resolve logs sections should be shown
expect(exists('externalLinksTitle')).toBe(true);
expect(exists('deprecationsCountTitle')).toBe(true);
});
test(`doesn't show analyze and resolve logs if it doesn't have the right privileges`, async () => {
await act(async () => {
testBed = await setupESDeprecationLogsPage(httpSetup, {
privileges: {
hasAllPrivileges: false,
missingPrivileges: {
index: [DEPRECATION_LOGS_INDEX],
},
},
});
});
const { exists, component } = testBed;
component.update();
// No index privileges warning callout should be shown
expect(exists('noIndexPermissionsCallout')).toBe(true);
// Analyze logs and Resolve logs sections should be hidden
expect(exists('externalLinksTitle')).toBe(false);
expect(exists('deprecationsCountTitle')).toBe(false);
});
});
});

View file

@ -0,0 +1,825 @@
/*
* 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 { act } from 'react-dom/test-utils';
import moment from 'moment';
import numeral from '@elastic/numeral';
import { setupEnvironment } from '../helpers';
import { ElasticsearchTestBed, setupElasticsearchPage } from './es_deprecations.helpers';
import {
esDeprecationsMockResponse,
MOCK_DS_DEPRECATION,
MOCK_REINDEX_DEPRECATION,
MOCK_DS_DEPRECATION_REINDEX,
MOCK_DS_DEPRECATION_READ_ONLY,
} from './mocked_responses';
import { DataStreamMigrationStatus } from '../../../common/data_stream_types';
const DATE_FORMAT = 'dddd, MMMM Do YYYY, h:mm:ss a';
const FILE_SIZE_DISPLAY_FORMAT = '0,0.[0] b';
const defaultMetaResponse = {
dataStreamName: MOCK_DS_DEPRECATION.index!,
documentationUrl: MOCK_DS_DEPRECATION.url,
lastIndexRequiringUpgradeCreationDate: 1483228800000,
allIndices: ['ds_index'],
allIndicesCount: 1,
indicesRequiringUpgradeCount: 1,
indicesRequiringUpgrade: ['ds_index'],
indicesRequiringUpgradeDocsSize: 51200,
indicesRequiringUpgradeDocsCount: 12,
};
const defaultMigrationResponse = {
hasRequiredPrivileges: true,
migrationOp: { status: DataStreamMigrationStatus.notStarted },
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
{
warningType: 'incompatibleDataStream',
resolutionType: 'readonly',
},
],
};
describe('Data streams deprecation flyout', () => {
let testBed: ElasticsearchTestBed;
beforeAll(() => {
jest.useFakeTimers({ legacyFakeTimers: true });
});
afterAll(() => {
jest.useRealTimers();
});
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
beforeEach(async () => {
const mockEnvironment = setupEnvironment();
httpRequestsMockHelpers = mockEnvironment.httpRequestsMockHelpers;
httpSetup = mockEnvironment.httpSetup;
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse);
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION.index!,
defaultMigrationResponse
);
httpRequestsMockHelpers.setDataStreamMetadataResponse(
MOCK_DS_DEPRECATION.index!,
defaultMetaResponse
);
httpRequestsMockHelpers.setReindexStatusResponse(MOCK_REINDEX_DEPRECATION.index!, {
reindexOp: null,
warnings: [],
hasRequiredPrivileges: true,
meta: {
indexName: 'foo',
reindexName: 'reindexed-foo',
aliases: [],
},
});
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
});
it('opens a flyout when clicking on a data stream row', async () => {
const { actions, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 0);
expect(exists('reindexDataStreamDetails')).toBe(true);
await actions.dataStreamDeprecationFlyout.closeFlyout();
expect(exists('reindexDataStreamDetails')).toBe(false);
});
it('renders a flyout with data stream details for both reindex and read-only', async () => {
const dataStreamDeprecation = esDeprecationsMockResponse.migrationsDeprecations[5];
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 0);
expect(exists('reindexDataStreamDetails')).toBe(true);
expect(find('reindexDataStreamDetails.flyoutTitle').text()).toBe(
`${dataStreamDeprecation.index}`
);
expect(exists('dataStreamLastIndexCreationDate')).toBe(true);
expect(find('dataStreamLastIndexCreationDate').text()).toBe(
`Migration required for indices created on or before${moment(
defaultMetaResponse.lastIndexRequiringUpgradeCreationDate
).format(DATE_FORMAT)}`
);
expect(exists('dataStreamSize')).toBe(true);
expect(find('dataStreamSize').text()).toBe(
`Size${numeral(defaultMetaResponse.indicesRequiringUpgradeDocsSize).format(
FILE_SIZE_DISPLAY_FORMAT
)}`
);
expect(exists('dataStreamDocumentCount')).toBe(true);
expect(find('dataStreamDocumentCount').text()).toBe(
`Document Count${defaultMetaResponse.indicesRequiringUpgradeDocsCount}`
);
expect(exists('dataStreamMigrationWarningsCallout')).toBe(true);
expect(find('dataStreamMigrationWarningsCallout').text()).toContain(
`Indices created on or before ${moment(
defaultMetaResponse.lastIndexRequiringUpgradeCreationDate
).format(DATE_FORMAT)} need to be reindexed to a compatible format or marked as read-only.`
);
expect(exists('dataStreamDetailsText')).toBe(true);
expect(find('dataStreamDetailsText').text()).toContain(
`You have ${defaultMetaResponse.indicesRequiringUpgradeCount} backing indices on this data stream that were created in ES 7.x and will not be compatible with next version.`
);
expect(find('dataStreamDetailsText').text()).toContain(
`${defaultMetaResponse.allIndicesCount} total backing indices, and ${defaultMetaResponse.indicesRequiringUpgradeCount} requires upgrade.`
);
expect(find('dataStreamDetailsText').text()).toContain(
`If you do not need to update historical data, mark as read-only. You can reindex post-upgrade if updates are needed.`
);
expect(find('dataStreamDetailsText').text()).toContain('Reindex');
expect(find('dataStreamDetailsText').text()).toContain(
`If you no longer need this data, you can also proceed by deleting these indices.`
);
expect(exists('closeDataStreamReindexingButton')).toBe(true);
expect(exists('startDataStreamReindexingButton')).toBe(true);
expect(exists('startDataStreamReadonlyButton')).toBe(true);
});
it('renders a callout if user has not the required privileges', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(MOCK_DS_DEPRECATION.index!, {
hasRequiredPrivileges: false,
migrationOp: { status: 0 },
warnings: [],
});
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
const { actions, exists, component } = testBed;
component.update();
await actions.table.clickDeprecationRowAt('dataStream', 0);
expect(exists('dsInsufficientPrivilegesCallout')).toBe(true);
});
it('renders a warning callout if nodes detected with low disk space', async () => {
httpRequestsMockHelpers.setLoadNodeDiskSpaceResponse([
{
nodeId: '9OFkjpAKS_aPzJAuEOSg7w',
nodeName: 'MacBook-Pro.local',
available: '25%',
lowDiskWatermarkSetting: '50%',
},
]);
const { actions, find } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 0);
expect(find('lowDiskSpaceCallout').text()).toContain('Nodes with low disk space');
expect(find('impactedNodeListItem').length).toEqual(1);
expect(find('impactedNodeListItem').at(0).text()).toContain(
'MacBook-Pro.local (25% available)'
);
});
describe('reindexing', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
defaultMigrationResponse
);
httpRequestsMockHelpers.setDataStreamMetadataResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
defaultMetaResponse
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
});
it('renders a flyout with data stream details for reindex', async () => {
const { actions, find, exists } = testBed;
const dataStreamDeprecation = esDeprecationsMockResponse.migrationsDeprecations[6];
await actions.table.clickDeprecationRowAt('dataStream', 1);
expect(exists('reindexDataStreamDetails')).toBe(true);
expect(find('reindexDataStreamDetails.flyoutTitle').text()).toBe(
`${dataStreamDeprecation.index}`
);
expect(exists('dataStreamDetailsText')).toBe(true);
expect(find('dataStreamDetailsText').text()).not.toContain(
`If you do not need to update historical data, mark as read-only. You can reindex post-upgrade if updates are needed.`
);
expect(find('dataStreamDetailsText').text()).toContain('Reindex');
expect(find('dataStreamDetailsText').text()).toContain(
`If you no longer need this data, you can also proceed by deleting these indices.`
);
expect(exists('closeDataStreamReindexingButton')).toBe(true);
expect(exists('startDataStreamReindexingButton')).toBe(true);
expect(exists('startDataStreamReadonlyButton')).toBe(false);
});
it('renders a flyout with data stream confirm step for reindex', async () => {
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 1);
await actions.dataStreamDeprecationFlyout.clickReindexButton(); // details step
expect(exists('reindexDsWarningCallout')).toBe(true);
expect(find('reindexDsWarningCallout').text()).toContain(
`This operation requires destructive changes that cannot be reversed`
);
expect(exists('migrationWarningCheckbox')).toBe(true);
expect(find('migrationWarningCheckbox').length).toBe(1);
expect(find('migrationWarningCheckbox').text()).toBe(
'Reindex all incompatible data for this data stream'
);
expect(exists('startActionButton')).toBe(true);
expect(find('startActionButton').text()).toBe('Start reindexing');
expect(find('startActionButton').props().disabled).toBe(true);
expect(exists('backButton')).toBe(true);
await actions.dataStreamDeprecationFlyout.checkMigrationWarningCheckbox();
expect(find('startActionButton').props().disabled).toBe(false);
});
describe('reindexing progress', () => {
it('reindexing pending', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'reindex',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000, // now - 10 seconds
successCount: 0,
pendingCount: 1,
inProgressCount: 0,
errorsCount: 0,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 1);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'Reindexing in progress…'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices successfully reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices currently getting reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
});
it('reindexing in progress', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'reindex',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000, // now - 10 seconds
successCount: 0,
pendingCount: 0,
inProgressCount: 1,
errorsCount: 0,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 1);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices successfully reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index currently getting reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
expect(exists('startDataStreamReadonlyButton')).toBe(false);
});
it('reindexing success', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'reindex',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000, // now - 10 seconds
successCount: 1,
pendingCount: 0,
inProgressCount: 0,
errorsCount: 0,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 1);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index successfully reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices currently getting reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
expect(exists('startDataStreamReadonlyButton')).toBe(false);
});
it('reindexing error', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'reindex',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000, // now - 10 seconds
successCount: 0,
pendingCount: 0,
inProgressCount: 0,
errorsCount: 1,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 1);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index failed to get reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices successfully reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices currently getting reindexed.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
expect(exists('startDataStreamReadonlyButton')).toBe(false);
});
describe('reindexing failed', () => {
it('offers read-only if reindexing fails and if read-only is not excluded', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(MOCK_DS_DEPRECATION.index!, {
hasRequiredPrivileges: true,
migrationOp: { resolutionType: 'reindex', status: DataStreamMigrationStatus.failed },
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
],
});
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 0);
await actions.dataStreamDeprecationFlyout.clickReindexButton();
expect(exists('dataStreamMigrationFailedCallout')).toBe(true);
expect(find('dataStreamMigrationFailedCallout').text()).toBe('Reindexing error');
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(false);
expect(find('startDataStreamMigrationButton').text()).toBe('Try again');
expect(exists('startDataStreamReadonlyButton')).toBe(true);
expect(find('startDataStreamReadonlyButton').text()).toBe('Mark as read-only');
});
it('does not offers read-only if reindexing fails and read-only is excluded', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_REINDEX.index!,
{
hasRequiredPrivileges: true,
migrationOp: { resolutionType: 'reindex', status: DataStreamMigrationStatus.failed },
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'reindex',
},
],
}
);
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 1);
await actions.dataStreamDeprecationFlyout.clickReindexButton();
expect(exists('dataStreamMigrationFailedCallout')).toBe(true);
expect(find('dataStreamMigrationFailedCallout').text()).toBe('Reindexing error');
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(false);
expect(find('startDataStreamMigrationButton').text()).toBe('Try again');
expect(exists('startDataStreamReadonlyButton')).toBe(false);
});
});
});
});
describe('read-only', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_READ_ONLY.index!,
defaultMigrationResponse
);
httpRequestsMockHelpers.setDataStreamMetadataResponse(
MOCK_DS_DEPRECATION_READ_ONLY.index!,
defaultMetaResponse
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
});
it('renders a flyout with data stream details for read-only', async () => {
const { actions, find, exists } = testBed;
const dataStreamDeprecation = esDeprecationsMockResponse.migrationsDeprecations[7];
await actions.table.clickDeprecationRowAt('dataStream', 2);
expect(exists('reindexDataStreamDetails')).toBe(true);
expect(find('reindexDataStreamDetails.flyoutTitle').text()).toBe(
`${dataStreamDeprecation.index}`
);
expect(exists('dataStreamDetailsText')).toBe(true);
expect(find('dataStreamDetailsText').text()).toContain(
`If you do not need to update historical data, mark as read-only. You can reindex post-upgrade if updates are needed.`
);
expect(find('dataStreamDetailsText').text()).not.toContain('Reindex');
expect(exists('closeDataStreamReindexingButton')).toBe(true);
expect(exists('startDataStreamReindexingButton')).toBe(false);
expect(exists('startDataStreamReadonlyButton')).toBe(true);
});
it('renders a flyout with data stream confirm step for read-only', async () => {
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 2);
await actions.dataStreamDeprecationFlyout.clickReadOnlyButton(); // details step
expect(exists('readOnlyDsWarningCallout')).toBe(true);
expect(find('readOnlyDsWarningCallout').text()).toContain(
'Marking this data read-only could affect some of the existing setups'
);
expect(exists('migrationWarningCheckbox')).toBe(true);
expect(find('migrationWarningCheckbox').length).toBe(1);
expect(find('migrationWarningCheckbox').text()).toBe(
'Reindex all incompatible data for this data stream'
);
expect(exists('startActionButton')).toBe(true);
expect(find('startActionButton').text()).toBe('Mark all read-only');
expect(find('startActionButton').props().disabled).toBe(true);
expect(exists('backButton')).toBe(true);
await actions.dataStreamDeprecationFlyout.checkMigrationWarningCheckbox();
expect(find('startActionButton').props().disabled).toBe(false);
});
describe('read-only progress', () => {
it('pending', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_READ_ONLY.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'readonly',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000,
successCount: 0,
pendingCount: 1,
inProgressCount: 0,
errorsCount: 0,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'readonly',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 2);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'Marking as read-only in progress…'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices successfully marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices currently getting marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
});
it('read-only in progress', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_READ_ONLY.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'readonly',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000, // now - 10 seconds
successCount: 0,
pendingCount: 0,
inProgressCount: 1,
errorsCount: 0,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'readonly',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 2);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices successfully marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index currently getting marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
});
it('read-only success', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_READ_ONLY.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'readonly',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000, // now - 10 seconds
successCount: 1,
pendingCount: 0,
inProgressCount: 0,
errorsCount: 0,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'readonly',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 2);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index successfully marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices currently getting marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
});
it('reindexing error', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(
MOCK_DS_DEPRECATION_READ_ONLY.index!,
{
hasRequiredPrivileges: true,
migrationOp: {
resolutionType: 'readonly',
status: DataStreamMigrationStatus.inProgress,
taskPercComplete: 1,
progressDetails: {
startTimeMs: Date.now() - 10000,
successCount: 0,
pendingCount: 0,
inProgressCount: 0,
errorsCount: 1,
},
},
warnings: [
{
warningType: 'incompatibleDataStream',
resolutionType: 'readonly',
},
],
}
);
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, find, exists } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 2);
expect(exists('dataStreamMigrationChecklistFlyout')).toBe(true);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'1 Index failed to get marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices successfully marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices currently getting marked as read-only.'
);
expect(find('dataStreamMigrationChecklistFlyout').text()).toContain(
'0 Indices waiting to start.'
);
expect(exists('startDataStreamMigrationButton')).toBe(true);
expect(find('startDataStreamMigrationButton').props().disabled).toBe(true);
expect(exists('cancelDataStreamMigrationButton')).toBe(true);
});
});
});
it('renders a callout if fetch fails', async () => {
httpRequestsMockHelpers.setDataStreamMigrationStatusResponse(MOCK_DS_DEPRECATION.index!, {
hasRequiredPrivileges: true,
migrationOp: { resolutionType: 'reindex', status: DataStreamMigrationStatus.fetchFailed },
warnings: [],
});
const { actions, exists, find } = testBed;
await actions.table.clickDeprecationRowAt('dataStream', 0);
await actions.dataStreamDeprecationFlyout.clickReindexButton();
expect(exists('fetchFailedCallout')).toBe(true);
expect(find('fetchFailedCallout').text()).toBe('Migration status not available');
});
});

View file

@ -97,10 +97,10 @@ describe('ES deprecations table', () => {
it('shows critical and warning deprecations count', () => {
const { find } = testBed;
const criticalDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical
(deprecation) => deprecation.level === 'critical'
);
const warningDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical === false
(deprecation) => deprecation.level !== 'critical'
);
expect(find('criticalDeprecationsCount').text()).toContain(String(criticalDeprecations.length));
@ -128,18 +128,20 @@ describe('ES deprecations table', () => {
});
describe('search bar', () => {
it('filters results by "critical" status', async () => {
it('filters results by status', async () => {
const { find, actions } = testBed;
await actions.searchBar.clickCriticalFilterButton();
await actions.searchBar.clickStatusFilterDropdown();
await actions.searchBar.clickFilterByTitle('Critical');
const criticalDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical
(deprecation) => deprecation.level === 'critical'
);
expect(find('deprecationTableRow').length).toEqual(criticalDeprecations.length);
await actions.searchBar.clickCriticalFilterButton();
await actions.searchBar.clickStatusFilterDropdown();
await actions.searchBar.clickFilterByTitle('Critical'); // Reset filter
expect(find('deprecationTableRow').length).toEqual(
esDeprecationsMockResponse.migrationsDeprecations.length
@ -147,23 +149,11 @@ describe('ES deprecations table', () => {
});
it('filters results by type', async () => {
const { component, find, actions } = testBed;
const { find, actions } = testBed;
await actions.searchBar.clickTypeFilterDropdownAt(0);
await actions.searchBar.clickTypeFilterDropdown();
// We need to read the document "body" as the filter dropdown (an EuiSelectable)
// is added in a portalled popover and not inside the component DOM tree.
const clusterTypeFilterButton: HTMLButtonElement | null = document.body.querySelector(
'.euiSelectableList .euiSelectableListItem'
);
expect(clusterTypeFilterButton).not.toBeNull();
await act(async () => {
clusterTypeFilterButton!.click();
});
component.update();
await actions.searchBar.clickFilterByTitle('Cluster');
const clusterDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.type === 'cluster_settings'
@ -269,10 +259,11 @@ describe('ES deprecations table', () => {
const { actions, find } = testBed;
const criticalDeprecations = migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical
(deprecation) => deprecation.level === 'critical'
);
await actions.searchBar.clickCriticalFilterButton();
await actions.searchBar.clickStatusFilterDropdown();
await actions.searchBar.clickFilterByTitle('Critical');
// Only 40 critical deprecations, so only one page should show
expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(1);

View file

@ -8,6 +8,7 @@ import { act } from 'react-dom/test-utils';
import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers';
import { HttpSetup } from '@kbn/core/public';
import { waitFor } from '@testing-library/dom';
import { EsDeprecations } from '../../../public/application/components';
import { WithAppDependencies } from '../helpers';
@ -39,7 +40,13 @@ const createActions = (testBed: TestBed) => {
component.update();
},
clickDeprecationRowAt: async (
deprecationType: 'mlSnapshot' | 'indexSetting' | 'reindex' | 'default' | 'clusterSetting',
deprecationType:
| 'mlSnapshot'
| 'indexSetting'
| 'reindex'
| 'default'
| 'clusterSetting'
| 'dataStream',
index: number
) => {
await act(async () => {
@ -48,21 +55,41 @@ const createActions = (testBed: TestBed) => {
component.update();
},
};
const searchBar = {
clickTypeFilterDropdownAt: async (index: number) => {
clickReindexColumnAt: async (
columnType: 'level' | 'message' | 'type' | 'index' | 'correctiveAction',
index: number
) => {
await act(async () => {
// EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector
find('searchBarContainer')
.find('.euiPopover')
.find('button.euiFilterButton')
.at(index)
.simulate('click');
find(`reindexTableCell-${columnType}`).at(index).simulate('click');
});
component.update();
},
};
const clickFilterByIndex = async (index: number) => {
await act(async () => {
// EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector
find('searchBarContainer')
.find('.euiPopover')
.find('button.euiFilterButton')
.at(index)
.simulate('click');
});
component.update();
// Wait for the filter dropdown to be displayed
await new Promise(requestAnimationFrame);
};
const searchBar = {
clickTypeFilterDropdown: async () => {
await clickFilterByIndex(1); // Type filter is the second filter button
},
clickStatusFilterDropdown: async () => {
await clickFilterByIndex(0); // Status filter is the first filter button
},
setSearchInputValue: async (searchValue: string) => {
await act(async () => {
find('searchBarContainer')
@ -72,10 +99,15 @@ const createActions = (testBed: TestBed) => {
component.update();
},
clickCriticalFilterButton: async () => {
await act(async () => {
// EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector
find('searchBarContainer').find('button.euiFilterButton').at(0).simulate('click');
clickFilterByTitle: async (title: string) => {
// We need to read the document "body" as the filter dropdown (an EuiSelectable)
// is added in a portalled popover and not inside the component DOM tree.
await waitFor(() => {
const filterButton: HTMLButtonElement | null = document.body.querySelector(
`.euiSelectableListItem[title=${title}]`
);
expect(filterButton).not.toBeNull();
filterButton!.click();
});
component.update();
@ -144,6 +176,71 @@ const createActions = (testBed: TestBed) => {
component.update();
},
closeFlyout: async () => {
await act(async () => {
find('closeReindexButton').simulate('click');
});
component.update();
},
clickReadOnlyButton: async () => {
await act(async () => {
find('startIndexReadonlyButton').simulate('click');
});
component.update();
},
checkMigrationWarningCheckbox: async () => {
await act(async () => {
find('warninStepCheckbox')
.find('input.euiCheckbox__input')
.simulate('change', {
target: {
checked: true,
},
});
});
component.update();
},
};
const dataStreamDeprecationFlyout = {
clickReindexButton: async () => {
await act(async () => {
find('startDataStreamReindexingButton').simulate('click');
});
component.update();
},
clickReadOnlyButton: async () => {
await act(async () => {
find('startDataStreamReadonlyButton').simulate('click');
});
component.update();
},
closeFlyout: async () => {
await act(async () => {
find('closeDataStreamReindexingButton').simulate('click');
});
component.update();
},
checkMigrationWarningCheckbox: async () => {
await act(async () => {
find('migrationWarningCheckbox')
.find('input.euiCheckbox__input')
.simulate('change', {
target: {
checked: true,
},
});
});
component.update();
},
clickStartActionButton: async () => {
await act(async () => {
find('startActionButton').simulate('click');
});
component.update();
},
};
return {
@ -154,6 +251,7 @@ const createActions = (testBed: TestBed) => {
reindexDeprecationFlyout,
indexSettingsDeprecationFlyout,
clusterSettingsDeprecationFlyout,
dataStreamDeprecationFlyout,
};
};

View file

@ -11,7 +11,7 @@ export const MOCK_SNAPSHOT_ID = '1';
export const MOCK_JOB_ID = 'deprecation_check_job';
export const MOCK_ML_DEPRECATION: EnrichedDeprecationInfo = {
isCritical: true,
level: 'critical',
resolveDuringUpgrade: false,
type: 'ml_settings',
message: 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded',
@ -26,7 +26,7 @@ export const MOCK_ML_DEPRECATION: EnrichedDeprecationInfo = {
};
export const MOCK_REINDEX_DEPRECATION: EnrichedDeprecationInfo = {
isCritical: true,
level: 'critical',
resolveDuringUpgrade: false,
type: 'index_settings',
message: 'Index created before 7.0',
@ -44,7 +44,7 @@ export const MOCK_REINDEX_DEPRECATION: EnrichedDeprecationInfo = {
};
const MOCK_INDEX_SETTING_DEPRECATION: EnrichedDeprecationInfo = {
isCritical: false,
level: 'warning',
resolveDuringUpgrade: false,
type: 'index_settings',
message: 'Setting [index.routing.allocation.include._tier] is deprecated',
@ -58,7 +58,7 @@ const MOCK_INDEX_SETTING_DEPRECATION: EnrichedDeprecationInfo = {
};
const MOCK_CLUSTER_SETTING_DEPRECATION: EnrichedDeprecationInfo = {
isCritical: false,
level: 'warning',
resolveDuringUpgrade: false,
type: 'cluster_settings',
message: 'Setting [cluster.routing.allocation.require._tier] is deprecated',
@ -71,7 +71,7 @@ const MOCK_CLUSTER_SETTING_DEPRECATION: EnrichedDeprecationInfo = {
};
const MOCK_DEFAULT_DEPRECATION: EnrichedDeprecationInfo = {
isCritical: false,
level: 'warning',
resolveDuringUpgrade: false,
type: 'index_settings',
message: 'multi-fields within multi-fields',
@ -80,6 +80,72 @@ const MOCK_DEFAULT_DEPRECATION: EnrichedDeprecationInfo = {
index: 'nested_multi-fields',
};
export const MOCK_DS_DEPRECATION: EnrichedDeprecationInfo = {
index: 'reindex_or_readonly_ds',
type: 'data_streams',
details: 'Data stream deprecation details',
message: 'Outdated data stream',
url: 'doc_url',
level: 'critical',
resolveDuringUpgrade: false,
correctiveAction: {
type: 'dataStream',
metadata: {
excludedActions: [],
reindexRequired: true,
totalBackingIndices: 1,
indicesRequiringUpgradeCount: 1,
indicesRequiringUpgrade: ['ds_index'],
ignoredIndicesRequiringUpgrade: [],
ignoredIndicesRequiringUpgradeCount: 0,
},
},
};
export const MOCK_DS_DEPRECATION_REINDEX: EnrichedDeprecationInfo = {
index: 'reindex_ds',
type: 'data_streams',
details: 'Data stream deprecation details',
message: 'Outdated data stream',
url: 'doc_url',
level: 'critical',
resolveDuringUpgrade: false,
correctiveAction: {
type: 'dataStream',
metadata: {
excludedActions: ['readOnly'],
reindexRequired: true,
totalBackingIndices: 1,
indicesRequiringUpgradeCount: 1,
indicesRequiringUpgrade: ['ds_index'],
ignoredIndicesRequiringUpgrade: [],
ignoredIndicesRequiringUpgradeCount: 0,
},
},
};
export const MOCK_DS_DEPRECATION_READ_ONLY: EnrichedDeprecationInfo = {
index: 'readonly_ds',
type: 'data_streams',
details: 'Data stream deprecation details',
message: 'Outdated data stream',
url: 'doc_url',
level: 'critical',
resolveDuringUpgrade: false,
correctiveAction: {
type: 'dataStream',
metadata: {
excludedActions: ['reindex'],
reindexRequired: true,
totalBackingIndices: 1,
indicesRequiringUpgradeCount: 1,
indicesRequiringUpgrade: ['ds_index'],
ignoredIndicesRequiringUpgrade: [],
ignoredIndicesRequiringUpgradeCount: 0,
},
},
};
export const esDeprecationsMockResponse: ESUpgradeStatus = {
totalCriticalDeprecations: 2,
migrationsDeprecations: [
@ -88,6 +154,9 @@ export const esDeprecationsMockResponse: ESUpgradeStatus = {
MOCK_DEFAULT_DEPRECATION,
MOCK_REINDEX_DEPRECATION,
MOCK_CLUSTER_SETTING_DEPRECATION,
MOCK_DS_DEPRECATION,
MOCK_DS_DEPRECATION_REINDEX,
MOCK_DS_DEPRECATION_READ_ONLY,
],
totalCriticalHealthIssues: 0,
enrichedHealthIndicators: [],

View file

@ -24,6 +24,7 @@ const defaultReindexStatusMeta: ReindexStatusResponse['meta'] = {
isFrozen: false,
isReadonly: false,
isInDataStream: false,
isFollowerIndex: false,
};
describe('Reindex deprecation flyout', () => {
@ -70,6 +71,35 @@ describe('Reindex deprecation flyout', () => {
testBed.component.update();
});
it('opens a flyout when clicking in any part of the row', async () => {
const { actions, exists } = testBed;
await actions.table.clickReindexColumnAt('level', 0);
expect(exists('reindexDetails')).toBe(true);
await actions.reindexDeprecationFlyout.closeFlyout();
expect(exists('reindexDetails')).toBe(false);
await actions.table.clickReindexColumnAt('message', 0);
expect(exists('reindexDetails')).toBe(true);
await actions.reindexDeprecationFlyout.closeFlyout();
expect(exists('reindexDetails')).toBe(false);
await actions.table.clickReindexColumnAt('type', 0);
expect(exists('reindexDetails')).toBe(true);
await actions.reindexDeprecationFlyout.closeFlyout();
expect(exists('reindexDetails')).toBe(false);
await actions.table.clickReindexColumnAt('index', 0);
expect(exists('reindexDetails')).toBe(true);
await actions.reindexDeprecationFlyout.closeFlyout();
expect(exists('reindexDetails')).toBe(false);
await actions.table.clickReindexColumnAt('correctiveAction', 0);
expect(exists('reindexDetails')).toBe(true);
await actions.reindexDeprecationFlyout.closeFlyout();
expect(exists('reindexDetails')).toBe(false);
});
it('renders a flyout with reindexing details', async () => {
const reindexDeprecation = esDeprecationsMockResponse.migrationsDeprecations[3];
const { actions, find, exists } = testBed;
@ -236,4 +266,58 @@ describe('Reindex deprecation flyout', () => {
);
});
});
describe('follower index', () => {
it('displays follower index callout and only shows mark as read-only button when index is a follower index', async () => {
httpRequestsMockHelpers.setReindexStatusResponse(MOCK_REINDEX_DEPRECATION.index!, {
reindexOp: null,
warnings: [],
hasRequiredPrivileges: true,
meta: {
...defaultReindexStatusMeta,
isFollowerIndex: true,
},
});
await act(async () => {
testBed = await setupElasticsearchPage(httpSetup);
});
testBed.component.update();
const { actions, exists } = testBed;
await actions.table.clickDeprecationRowAt('reindex', 0);
// Verify follower index callout is displayed
expect(exists('followerIndexCallout')).toBe(true);
// Verify only mark as read-only button is available (no reindex button)
expect(exists('startIndexReadonlyButton')).toBe(true);
expect(exists('startReindexingButton')).toBe(false);
});
it('shows both mark as read-only and reindex buttons for regular (non-follower) indices', async () => {
httpRequestsMockHelpers.setReindexStatusResponse(MOCK_REINDEX_DEPRECATION.index!, {
reindexOp: null,
warnings: [],
hasRequiredPrivileges: true,
meta: {
...defaultReindexStatusMeta,
isFollowerIndex: false,
},
});
const { actions, exists } = testBed;
await actions.table.clickDeprecationRowAt('reindex', 0);
// Verify follower index callout is not displayed
expect(exists('followerIndexCallout')).toBe(false);
// Verify both buttons are available for regular indices
expect(exists('startIndexReadonlyButton')).toBe(true);
expect(exists('startReindexingButton')).toBe(true);
});
});
});

View file

@ -150,6 +150,25 @@ const registerHttpRequestMockHelpers = (
mockResponse('POST', `${API_BASE_PATH}/cluster_settings`, response, error);
};
const setDataStreamMigrationStatusResponse = (
dataStreamName: string,
response?: object,
error?: ResponseError
) =>
mockResponse('GET', `${API_BASE_PATH}/migrate_data_stream/${dataStreamName}`, response, error);
const setDataStreamMetadataResponse = (
dataStreamName: string,
response?: object,
error?: ResponseError
) =>
mockResponse(
'GET',
`${API_BASE_PATH}/migrate_data_stream/${dataStreamName}/metadata`,
response,
error
);
return {
setLoadCloudBackupStatusResponse,
setLoadEsDeprecationsResponse,
@ -170,6 +189,8 @@ const registerHttpRequestMockHelpers = (
setLoadRemoteClustersResponse,
setLoadNodeDiskSpaceResponse,
setClusterSettingsResponse,
setDataStreamMigrationStatusResponse,
setDataStreamMetadataResponse,
};
};

View file

@ -81,12 +81,14 @@ describe('Kibana deprecations - Deprecations table', () => {
const { actions, table } = testBed;
// Show only critical deprecations
await actions.searchBar.clickCriticalFilterButton();
await actions.searchBar.openStatusFilterDropdown();
await actions.searchBar.filterByTitle('Critical');
const { rows: criticalRows } = table.getMetaData('kibanaDeprecationsTable');
expect(criticalRows.length).toEqual(mockedCriticalKibanaDeprecations.length);
// Show all deprecations
await actions.searchBar.clickCriticalFilterButton();
await actions.searchBar.openStatusFilterDropdown();
await actions.searchBar.filterByTitle('Critical');
const { rows: allRows } = table.getMetaData('kibanaDeprecationsTable');
expect(allRows.length).toEqual(mockedKibanaDeprecations.length);
});
@ -95,7 +97,7 @@ describe('Kibana deprecations - Deprecations table', () => {
const { table, actions } = testBed;
await actions.searchBar.openTypeFilterDropdown();
await actions.searchBar.filterByConfigType();
await actions.searchBar.filterByTitle('Config');
const { rows: configRows } = table.getMetaData('kibanaDeprecationsTable');

View file

@ -57,44 +57,43 @@ const createActions = (testBed: TestBed) => {
},
};
const openFilterByIndex = async (index: number) => {
await act(async () => {
// EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector
find('kibanaDeprecations')
.find('.euiSearchBar__filtersHolder')
.find('.euiPopover')
.find('button.euiFilterButton')
.at(index)
.simulate('click');
});
component.update();
// Wait for the filter dropdown to be displayed
await new Promise(requestAnimationFrame);
};
const searchBarActions = {
openTypeFilterDropdown: async () => {
await act(async () => {
// EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector
find('kibanaDeprecations')
.find('.euiSearchBar__filtersHolder')
.find('.euiPopover')
.find('button.euiFilterButton')
.at(0)
.simulate('click');
});
component.update();
await openFilterByIndex(1);
},
clickCriticalFilterButton: async () => {
await act(async () => {
// EUI doesn't support data-test-subj's on the filter buttons, so we must access via CSS selector
find('kibanaDeprecations')
.find('.euiSearchBar__filtersHolder')
.find('button.euiFilterButton')
.at(0)
.simulate('click');
});
component.update();
openStatusFilterDropdown: async () => {
await openFilterByIndex(0);
},
filterByConfigType: async () => {
filterByTitle: async (title: string) => {
// We need to read the document "body" as the filter dropdown (an EuiSelectable)
// is added in a portalled popover and not inside the component DOM tree.
// The "Config" option is expected to be the first item.
const configTypeFilterButton: HTMLButtonElement | null = document.body.querySelector(
'.euiSelectableList .euiSelectableListItem'
const filterButton: HTMLButtonElement | null = document.body.querySelector(
`.euiSelectableListItem[title=${title}]`
);
expect(filterButton).not.toBeNull();
await act(async () => {
configTypeFilterButton!.click();
filterButton!.click();
});
component.update();

View file

@ -73,11 +73,11 @@ describe('Overview - Fix deprecation issues step - Elasticsearch deprecations',
await setup();
});
test('renders a count for critical issues and success state for warning issues', () => {
test('renders a count for critical issues', () => {
const { exists, find } = testBed;
expect(exists('esStatsPanel')).toBe(true);
expect(find('esStatsPanel.criticalDeprecations').text()).toContain('1');
expect(exists('esStatsPanel.noWarningDeprecationIssues')).toBe(true);
expect(exists('esStatsPanel.warningDeprecations')).toBe(false);
});
test('panel links to ES deprecations page', () => {
@ -93,7 +93,7 @@ describe('Overview - Fix deprecation issues step - Elasticsearch deprecations',
await setup();
});
test('renders a count for critical issues and success state for warning issues', () => {
test('renders a success state', () => {
const { exists } = testBed;
expect(exists('esStatsPanel')).toBe(true);
expect(exists('esStatsPanel.noDeprecationIssues')).toBe(true);

View file

@ -73,12 +73,12 @@ describe('Overview - Fix deprecation issues step - Kibana deprecations', () => {
await setup(mockedCriticalKibanaDeprecations);
});
test('renders a count for critical issues and success state for warning issues', () => {
test('renders a count for critical issues', () => {
const { exists, find } = testBed;
expect(exists('kibanaStatsPanel')).toBe(true);
expect(find('kibanaStatsPanel.criticalDeprecations').text()).toContain('1');
expect(exists('kibanaStatsPanel.noWarningDeprecationIssues')).toBe(true);
expect(exists('kibanaStatsPanel.warningDeprecations')).toBe(false);
});
test('panel links to Kibana deprecations page', () => {

View file

@ -11,7 +11,7 @@ export const esCriticalAndWarningDeprecations: ESUpgradeStatus = {
totalCriticalDeprecations: 1,
migrationsDeprecations: [
{
isCritical: true,
level: 'critical',
type: 'cluster_settings',
resolveDuringUpgrade: false,
message: 'Index Lifecycle Management poll interval is set too low',
@ -20,7 +20,7 @@ export const esCriticalAndWarningDeprecations: ESUpgradeStatus = {
'The Index Lifecycle Management poll interval setting [indices.lifecycle.poll_interval] is currently set to [500ms], but must be 1s or greater',
},
{
isCritical: false,
level: 'warning',
type: 'index_settings',
resolveDuringUpgrade: false,
message: 'Setting [index.routing.allocation.include._tier] is deprecated',
@ -42,7 +42,7 @@ export const esCriticalOnlyDeprecations: ESUpgradeStatus = {
totalCriticalDeprecations: 1,
migrationsDeprecations: [
{
isCritical: true,
level: 'critical',
type: 'cluster_settings',
resolveDuringUpgrade: false,
message: 'Index Lifecycle Management poll interval is set too low',

View file

@ -9,6 +9,8 @@ import { act } from 'react-dom/test-utils';
import {
DEPRECATION_LOGS_INDEX,
APP_LOGS_COUNT_CLUSTER_PRIVILEGES,
DEPRECATION_LOGS_ORIGIN_FIELD,
APPS_WITH_DEPRECATION_LOGS,
} from '../../../../common/constants';
import { setupEnvironment } from '../../helpers';
import { OverviewTestBed, setupOverviewPage } from '../overview.helpers';
@ -32,6 +34,10 @@ describe('Overview - Logs Step', () => {
};
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse(undefined, error);
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: true,
isDeprecationLoggingEnabled: true,
});
await act(async () => {
testBed = await setupOverviewPage(httpSetup);
@ -40,10 +46,27 @@ describe('Overview - Logs Step', () => {
testBed.component.update();
});
test('is rendered', () => {
const { exists } = testBed;
test('is rendered and allows retry', async () => {
const { exists, actions } = testBed;
expect(exists('deprecationLogsErrorCallout')).toBe(true);
expect(exists('deprecationLogsRetryButton')).toBe(true);
expect(exists('logsCountDescription')).toBe(false);
expect(exists('viewDiscoverLogsButton')).toBe(false);
expect(exists('viewDetailsLink')).toBe(false);
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});
await actions.clickRetryLogsButton();
expect(exists('logsCountDescription')).toBe(true);
expect(exists('viewDiscoverLogsButton')).toBe(true);
expect(exists('viewDetailsLink')).toBe(true);
expect(exists('deprecationLogsErrorCallout')).toBe(false);
expect(exists('deprecationLogsRetryButton')).toBe(false);
});
});
@ -102,7 +125,37 @@ describe('Overview - Logs Step', () => {
component.update();
expect(find('logsCountDescription').text()).toContain('You have 10 deprecation issues');
expect(find('viewLogsLink').text()).toContain('View logs');
});
test('displays discover and verify changes buttons', async () => {
const { exists, find } = testBed;
expect(exists('viewDiscoverLogsButton')).toBe(true);
expect(exists('viewDetailsLink')).toBe(true);
expect(find('viewDiscoverLogsButton').text()).toContain('Analyze logs in Discover');
expect(find('viewDetailsLink').text()).toContain('View details');
expect(exists('enableLogsLink')).toBe(false);
});
test('has a link to see logs in discover app', async () => {
const { exists, find } = testBed;
expect(exists('viewDiscoverLogsButton')).toBe(true);
const decodedUrl = decodeURIComponent(find('viewDiscoverLogsButton').props().href);
expect(decodedUrl).toContain('discoverUrl');
[
'"language":"kuery"',
'"query":"@timestamp+>',
'filters=',
DEPRECATION_LOGS_ORIGIN_FIELD,
...APPS_WITH_DEPRECATION_LOGS,
].forEach((param) => {
try {
expect(decodedUrl).toContain(param);
} catch (e) {
throw new Error(`Expected [${param}] not found in ${decodedUrl}`);
}
});
});
});
@ -127,6 +180,8 @@ describe('Overview - Logs Step', () => {
expect(exists('logsCountDescription')).toBe(false);
expect(find('enableLogsLink').text()).toContain('Enable logging');
expect(exists('viewDiscoverLogsButton')).toBe(false);
expect(exists('viewDetailsLink')).toBe(false);
});
});
});

View file

@ -5,18 +5,22 @@ Array [
Array [
"Security",
"Migration failed",
"",
],
Array [
"Machine Learning",
"Migration in progress",
"",
],
Array [
"Kibana",
"Migration required",
"",
],
Array [
"Logstash",
"Migration complete",
"",
],
]
`;

View file

@ -9,7 +9,7 @@ import { act } from 'react-dom/test-utils';
import { OverviewTestBed, setupOverviewPage } from '../overview.helpers';
import { setupEnvironment } from '../../helpers';
import { systemIndicesMigrationStatus } from './mocks';
import { systemIndicesMigrationStatus, systemIndicesMigrationErrorStatus } from './mocks';
describe('Overview - Migrate system indices - Flyout', () => {
let testBed: OverviewTestBed;
@ -39,4 +39,90 @@ describe('Overview - Migrate system indices - Flyout', () => {
expect(tableCellsValues.length).toBe(systemIndicesMigrationStatus.features.length);
expect(tableCellsValues).toMatchSnapshot();
});
test('can trigger the migration', async () => {
const { exists, find, component } = testBed;
// Expect the migration button to be present
expect(exists('startSystemIndicesMigrationButton')).toBe(true);
await act(async () => {
find('startSystemIndicesMigrationButton').simulate('click');
});
component.update();
expect(exists('migrationConfirmModal')).toBe(true);
const modal = document.body.querySelector('[data-test-subj="migrationConfirmModal"]');
const confirmButton: HTMLButtonElement | null = modal!.querySelector(
'[data-test-subj="confirmModalConfirmButton"]'
);
await act(async () => {
confirmButton!.click();
});
component.update();
expect(exists('migrationConfirmModal')).toBe(false);
});
test('disables migrate button when migrating', async () => {
httpRequestsMockHelpers.setLoadSystemIndicesMigrationStatus({
migration_status: 'IN_PROGRESS',
});
testBed = await setupOverviewPage(httpSetup);
const { find, component } = testBed;
component.update();
expect(find('startSystemIndicesMigrationButton').props().disabled).toBe(true);
});
test('hides the start migration button when finished', async () => {
httpRequestsMockHelpers.setLoadSystemIndicesMigrationStatus({
migration_status: 'NO_MIGRATION_NEEDED',
});
testBed = await setupOverviewPage(httpSetup);
const { exists, component } = testBed;
component.update();
expect(exists('startSystemIndicesMigrationButton')).toBe(false);
});
test('shows migration errors inline within the table row', async () => {
httpRequestsMockHelpers.setLoadSystemIndicesMigrationStatus(systemIndicesMigrationErrorStatus);
await act(async () => {
testBed = await setupOverviewPage(httpSetup);
});
const { component, actions, table } = testBed;
component.update();
await actions.clickViewSystemIndicesState();
const { rows } = table.getMetaData('flyoutDetails');
expect(rows[0].columns[1].value).toBe('Migration failed');
await act(async () => {
rows[0].reactWrapper.find('button').simulate('click');
});
component.update();
const { rows: resultRows } = table.getMetaData('flyoutDetails');
// Should contain two errors about the migration
// We expect results to be on the second row, given that the first row is used as an expander
// and the second holds the collapsible content
expect(resultRows[1].reactWrapper.text()).toContain('.kibanamapper_parsing_exception');
expect(resultRows[1].reactWrapper.text()).toContain('.logsmapper_parsing_exception');
});
});

View file

@ -9,6 +9,7 @@ import { act } from 'react-dom/test-utils';
import { setupEnvironment } from '../../helpers';
import { OverviewTestBed, setupOverviewPage } from '../overview.helpers';
import { systemIndicesMigrationErrorStatus } from './mocks';
describe('Overview - Migrate system indices', () => {
let testBed: OverviewTestBed;
@ -175,33 +176,23 @@ describe('Overview - Migrate system indices', () => {
expect(find('startSystemIndicesMigrationButton').props().disabled).toBe(false);
});
test('Handles errors from migration', async () => {
httpRequestsMockHelpers.setLoadSystemIndicesMigrationStatus({
migration_status: 'ERROR',
features: [
{
feature_name: 'kibana',
indices: [
{
index: '.kibana',
migration_status: 'ERROR',
failure_cause: {
error: {
type: 'mapper_parsing_exception',
},
},
},
],
},
],
});
test('Shows migration error with details', async () => {
httpRequestsMockHelpers.setLoadSystemIndicesMigrationStatus(
systemIndicesMigrationErrorStatus
);
testBed = await setupOverviewPage(httpSetup);
const { exists } = testBed;
const { component, exists, find } = testBed;
component.update();
// Error is displayed
expect(exists('migrationFailedCallout')).toBe(true);
expect(find('migrationFailedCallout').text()).toContain(
'Errors occurred while migrating system indices:kibana: mapper_parsing_exception'
);
// CTA is enabled
expect(exists('startSystemIndicesMigrationButton')).toBe(true);
});

View file

@ -56,3 +56,36 @@ export const systemIndicesMigrationStatus: SystemIndicesMigrationStatus = {
},
],
};
export const systemIndicesMigrationErrorStatus: SystemIndicesMigrationStatus = {
migration_status: 'ERROR',
features: [
{
feature_name: 'kibana',
minimum_index_version: '7.1.1',
migration_status: 'ERROR',
indices: [
{
index: '.kibana',
migration_status: 'ERROR',
failure_cause: {
error: {
type: 'mapper_parsing_exception',
reason: 'something failed',
},
},
},
{
index: '.logs',
migration_status: 'ERROR',
failure_cause: {
error: {
type: 'mapper_parsing_exception',
reason: 'something failed',
},
},
},
],
},
],
};

View file

@ -48,9 +48,20 @@ const createActions = (testBed: TestBed) => {
component.update();
};
const clickRetryLogsButton = async () => {
const { find, component } = testBed;
await act(async () => {
find('deprecationLogsRetryButton').simulate('click');
});
component.update();
};
return {
clickViewSystemIndicesState,
clickRetrySystemIndicesButton,
clickRetryLogsButton,
};
};

View file

@ -5,9 +5,16 @@
* 2.0.
*/
import { act } from 'react-dom/test-utils';
import { waitFor } from '@testing-library/react';
import SemVer from 'semver/classes/semver';
import { LATEST_VERSION, MIN_VERSION_TO_UPGRADE_TO_LATEST } from '../../../common/constants';
import { setupEnvironment } from '../helpers';
import { OverviewTestBed, setupOverviewPage } from './overview.helpers';
const currentMinVersion = new SemVer(MIN_VERSION_TO_UPGRADE_TO_LATEST);
describe('Overview Page', () => {
let testBed: OverviewTestBed;
beforeEach(async () => {
@ -20,13 +27,76 @@ describe('Overview Page', () => {
const { exists, find } = testBed;
expect(exists('whatsNewLink')).toBe(true);
expect(find('whatsNewLink').text()).toContain('latest release');
expect(find('whatsNewLink').text()).toContain("What's new in version");
});
test('Has a link for upgrade assistant in page header', () => {
const { exists } = testBed;
describe('current version can be upgrated to last one', () => {
beforeEach(async () => {
const versionMock = {
currentMajor: currentMinVersion.major,
currentMinor: currentMinVersion.minor,
currentPatch: currentMinVersion.patch,
};
expect(exists('documentationLink')).toBe(true);
await act(async () => {
testBed = await setupOverviewPage(setupEnvironment().httpSetup, {
kibanaVersionInfo: versionMock,
});
});
testBed.component.update();
});
test('Has the current version and the lastest avaiblable version', () => {
const { find } = testBed;
expect(find('overviewPageHeader').text()).toContain(
`Current version: ${currentMinVersion.version} | Latest available version: ${LATEST_VERSION}`
);
});
test('Has not a tooltip when current version is major than min version to upgrade', () => {
const { find } = testBed;
expect(find('overviewPageHeader').find('.euiToolTipAnchor').exists()).toBe(false);
});
});
describe('current version can not be upgrated to last one', () => {
const outdatedMajor = currentMinVersion.major - 1;
beforeEach(async () => {
const versionMock = {
currentMajor: outdatedMajor,
currentMinor: 0,
currentPatch: 0,
};
await act(async () => {
testBed = await setupOverviewPage(setupEnvironment().httpSetup, {
kibanaVersionInfo: versionMock,
});
});
testBed.component.update();
});
test('Has the current version and the lastest avaiblable version', () => {
const { find } = testBed;
expect(find('overviewPageHeader').text()).toContain(
`Current version: ${outdatedMajor}.0.0 | Latest available version: ${LATEST_VERSION}`
);
});
test('Has a tooltip when current version is minor than minor version to upgrade', async () => {
const { find } = testBed;
await waitFor(() => {
find('overviewPageHeader').find('.euiToolTipAnchor').first().simulate('mouseOver');
const toolTipText = document.querySelector('.euiToolTipPopover')?.textContent;
expect(toolTipText).toBe(
`Upgrading to v${LATEST_VERSION} requires v${MIN_VERSION_TO_UPGRADE_TO_LATEST}.`
);
});
});
});
});
});

View file

@ -44,3 +44,11 @@ export const DEPRECATION_LOGS_ORIGIN_FIELD = 'elasticsearch.elastic_product_orig
export const APP_LOGS_COUNT_INDEX_PRIVILEGES = ['read', 'view_index_metadata'];
export const APP_LOGS_COUNT_CLUSTER_PRIVILEGES = ['manage_security'];
/**
* Duration for the "recent" time period (24 hours in milliseconds)
*/
export const RECENT_DURATION_MS = 24 * 60 * 60 * 1000;
export const LATEST_VERSION = '9.1.0';
export const MIN_VERSION_TO_UPGRADE_TO_LATEST = '8.19.0';

View file

@ -33,6 +33,7 @@ export interface DataStreamMetadata {
indicesRequiringUpgradeDocsSize: number;
indicesRequiringUpgradeDocsCount: number;
oldestIncompatibleDocTimestamp?: number;
}
export interface DataStreamReindexStatusResponse {

View file

@ -57,6 +57,7 @@ export interface ReindexStatusResponse {
isReadonly: boolean;
isFrozen: boolean;
isInDataStream: boolean;
isFollowerIndex: boolean;
};
warnings?: IndexWarning[];
reindexOp?: ReindexOperation;
@ -221,6 +222,11 @@ export interface ReindexAction extends IndexAction {
* The actions that should be excluded from the reindex corrective action.
*/
excludedActions?: string[];
/**
* The size of the index in bytes
*/
indexSizeInBytes?: number;
}
export interface UnfreezeAction extends IndexAction {
@ -270,7 +276,7 @@ export interface EnrichedDeprecationInfo
| 'health_indicator'
| 'ilm_policies'
| 'templates';
isCritical: boolean;
level: MIGRATION_DEPRECATION_LEVEL;
status?: estypes.HealthReportIndicatorHealthStatus;
index?: string;
correctiveAction?: CorrectiveAction;
@ -317,6 +323,23 @@ export interface DeprecationLoggingStatus {
isDeprecationLoggingEnabled: boolean;
}
export interface EsDeprecationLog {
// Define expected properties from the logs
'@timestamp'?: string;
message?: string;
[key: string]: any; // Allow for any additional ES log properties
}
export interface StatusResponseBody {
readyForUpgrade: boolean;
details: string;
recentEsDeprecationLogs?: {
count: number;
logs: EsDeprecationLog[];
};
kibanaApiDeprecations?: any[]; // Uses DomainDeprecationDetails type from Kibana core
}
export type MIGRATION_STATUS = 'MIGRATION_NEEDED' | 'NO_MIGRATION_NEEDED' | 'IN_PROGRESS' | 'ERROR';
export interface SystemIndicesMigrationFeature {
id?: string;
@ -325,7 +348,8 @@ export interface SystemIndicesMigrationFeature {
migration_status: MIGRATION_STATUS;
indices: Array<{
index: string;
version: string;
version?: string;
migration_status?: MIGRATION_STATUS;
failure_cause?: {
error: {
type: string;

View file

@ -26,7 +26,7 @@ import {
} from '../shared_imports';
import { AppDependencies } from '../types';
import { AppContextProvider, useAppContext } from './app_context';
import { EsDeprecations, EsDeprecationLogs, KibanaDeprecations, Overview } from './components';
import { EsDeprecations, KibanaDeprecations, Overview } from './components';
const { GlobalFlyoutProvider } = GlobalFlyout;
@ -121,7 +121,6 @@ const AppHandlingClusterUpgradeState: React.FunctionComponent = () => {
<Routes>
<Route exact path="/overview" component={Overview} />
<Route exact path="/es_deprecations" component={EsDeprecations} />
<Route exact path="/es_deprecation_logs" component={EsDeprecationLogs} />
<Route exact path="/kibana_deprecations" component={KibanaDeprecations} />
<Redirect from="/" to="/overview" />
</Routes>

View file

@ -1,74 +0,0 @@
/*
* 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, useEffect } from 'react';
import {
EuiPageHeader,
EuiButtonEmpty,
EuiSpacer,
EuiPageBody,
EuiPageSection,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import { FormattedMessage } from '@kbn/i18n-react';
import { useAppContext } from '../../app_context';
import { uiMetricService, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD } from '../../lib/ui_metric';
import { FixDeprecationLogs } from './fix_deprecation_logs';
export const EsDeprecationLogs: FunctionComponent = () => {
const {
services: {
breadcrumbs,
core: { docLinks },
},
} = useAppContext();
useEffect(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD);
}, []);
useEffect(() => {
breadcrumbs.setBreadcrumbs('esDeprecationLogs');
}, [breadcrumbs]);
return (
<EuiPageBody restrictWidth={true} data-test-subj="esDeprecationLogs">
<EuiPageSection color="transparent" paddingSize="none">
<EuiPageHeader
bottomBorder
pageTitle={i18n.translate('xpack.upgradeAssistant.esDeprecationLogs.pageTitle', {
defaultMessage: 'Elasticsearch deprecation logs',
})}
description={i18n.translate('xpack.upgradeAssistant.esDeprecationLogs.pageDescription', {
defaultMessage:
'Review the deprecation logs to determine if your applications are using any deprecated APIs. Update your applications to prevent errors or changes in behavior after you upgrade.',
})}
rightSideItems={[
<EuiButtonEmpty
href={docLinks.links.elasticsearch.migrationApiDeprecation}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.documentationLinkText"
defaultMessage="Documentation"
/>
</EuiButtonEmpty>,
]}
/>
<EuiSpacer size="l" />
<FixDeprecationLogs />
</EuiPageSection>
</EuiPageBody>
);
};

View file

@ -1,7 +0,0 @@
// When you have a flex item with an EuiSwitch and replace it with
// an EuiLoadingSpinner you end up with a slight 2px difference between
// them. With this selector we offset the difference so that the content
// of the page doesnt jump when toggling between states.
.upgToggleLoading > .upgLoadingItem {
margin: calc($euiSizeM / 2);
}

View file

@ -7,6 +7,8 @@
import React, { useState, FunctionComponent } from 'react';
import { css } from '@emotion/react';
import {
EuiSwitch,
EuiFlexItem,
@ -17,14 +19,13 @@ import {
EuiTextColor,
EuiButtonEmpty,
EuiLoadingSpinner,
useEuiTheme,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ResponseError } from '../../../../../../common/types';
import { DeprecationLoggingPreviewProps } from '../../../types';
import './_deprecation_logging_toggle.scss';
const i18nTexts = {
fetchErrorMessage: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.fetchErrorMessage',
@ -99,11 +100,17 @@ export const DeprecationLoggingToggle: FunctionComponent<Props> = ({
resendRequest,
toggleLogging,
}) => {
const { euiTheme } = useEuiTheme();
if (isLoading) {
return (
<EuiFlexGroup gutterSize="s" alignItems="center" className="upgToggleLoading">
<EuiFlexItem grow={false} className="upgLoadingItem">
<EuiLoadingSpinner size="m" />
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiLoadingSpinner
size="m"
css={css`
margin: calc(${euiTheme.size.m} / 2);
`}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>{i18nTexts.loadingLogsLabel}</EuiFlexItem>
</EuiFlexGroup>
@ -137,7 +144,7 @@ export const DeprecationLoggingToggle: FunctionComponent<Props> = ({
<EuiFlexItem grow={false}>
<EuiSwitch
data-test-subj="deprecationLoggingToggle"
label={i18nTexts.buttonLabel}
label={<EuiText>{i18nTexts.buttonLabel}</EuiText>}
checked={!!isDeprecationLogIndexingEnabled}
onChange={toggleLogging}
disabled={Boolean(fetchError) || isUpdating}

View file

@ -5,15 +5,12 @@
* 2.0.
*/
import React, { FunctionComponent, useState } from 'react';
import moment from 'moment-timezone';
import React, { FunctionComponent } from 'react';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n-react';
import { METRIC_TYPE } from '@kbn/analytics';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiButton, EuiSkeletonText } from '@elastic/eui';
import { EuiCallOut, EuiSkeletonText, EuiButton } from '@elastic/eui';
import { useAppContext } from '../../../../app_context';
import { uiMetricService, UIM_RESET_LOGS_COUNTER_CLICK } from '../../../../lib/ui_metric';
const i18nTexts = {
calloutTitle: (warningsCount: number, previousCheck: string) => (
@ -40,34 +37,17 @@ const i18nTexts = {
retryButton: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.retryButton', {
defaultMessage: 'Try again',
}),
resetCounterButton: i18n.translate(
'xpack.upgradeAssistant.overview.verifyChanges.resetCounterButton',
{
defaultMessage: 'Reset counter',
}
),
errorToastTitle: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle', {
defaultMessage: 'Could not delete deprecation logs cache',
}),
};
interface Props {
checkpoint: string;
setCheckpoint: (value: string) => void;
}
export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
checkpoint,
setCheckpoint,
}) => {
const [isDeletingCache, setIsDeletingCache] = useState(false);
export const DeprecationsCountCallout: FunctionComponent<Props> = ({ checkpoint }) => {
const {
services: {
api,
core: { notifications },
},
services: { api },
} = useAppContext();
const { data, error, isLoading, resendRequest, isInitialRequest } =
const { data, error, isLoading, isInitialRequest, resendRequest } =
api.getDeprecationLogsCount(checkpoint);
const logsCount = data?.count || 0;
@ -76,24 +56,6 @@ export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
const calloutIcon = hasLogs ? 'warning' : 'check';
const calloutTestId = hasLogs ? 'hasWarningsCallout' : 'noWarningsCallout';
const onResetClick = async () => {
setIsDeletingCache(true);
const { error: deleteLogsCacheError } = await api.deleteDeprecationLogsCache();
setIsDeletingCache(false);
if (deleteLogsCacheError) {
notifications.toasts.addDanger({
title: i18nTexts.errorToastTitle,
text: deleteLogsCacheError.message.toString(),
});
return;
}
const now = moment().toISOString();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_RESET_LOGS_COUNTER_CLICK);
setCheckpoint(now);
};
if (isInitialRequest && isLoading) {
return <EuiSkeletonText lines={6} />;
}
@ -122,16 +84,6 @@ export const DeprecationsCountCheckpoint: FunctionComponent<Props> = ({
color={calloutTint}
iconType={calloutIcon}
data-test-subj={calloutTestId}
>
<p>{i18nTexts.calloutBody}</p>
<EuiButton
color={calloutTint}
onClick={onResetClick}
isLoading={isDeletingCache || isLoading}
data-test-subj="resetLastStoredDate"
>
{i18nTexts.resetCounterButton}
</EuiButton>
</EuiCallOut>
/>
);
};

View file

@ -0,0 +1,71 @@
/*
* 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, useState } from 'react';
import moment from 'moment-timezone';
import { METRIC_TYPE } from '@kbn/analytics';
import { i18n } from '@kbn/i18n';
import { EuiButton } from '@elastic/eui';
import { useAppContext } from '../../../../app_context';
import { uiMetricService, UIM_RESET_LOGS_COUNTER_CLICK } from '../../../../lib/ui_metric';
const i18nTexts = {
resetCounterButton: i18n.translate(
'xpack.upgradeAssistant.overview.verifyChanges.resetCounterButton',
{
defaultMessage: 'Reset counter',
}
),
errorToastTitle: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.errorToastTitle', {
defaultMessage: 'Could not delete deprecation logs cache',
}),
};
interface Props {
setCheckpoint: (value: string) => void;
}
export const ResetCounterButton: FunctionComponent<Props> = ({ setCheckpoint }) => {
const [isDeletingCache, setIsDeletingCache] = useState(false);
const {
services: {
api,
core: { notifications },
},
} = useAppContext();
const onResetClick = async () => {
setIsDeletingCache(true);
const { error: deleteLogsCacheError } = await api.deleteDeprecationLogsCache();
setIsDeletingCache(false);
if (deleteLogsCacheError) {
notifications.toasts.addDanger({
title: i18nTexts.errorToastTitle,
text: deleteLogsCacheError.message.toString(),
});
return;
}
const now = moment().toISOString();
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_RESET_LOGS_COUNTER_CLICK);
setCheckpoint(now);
};
return (
<EuiButton
color="primary"
fill
onClick={onResetClick}
isLoading={isDeletingCache}
data-test-subj="resetLastStoredDate"
>
{i18nTexts.resetCounterButton}
</EuiButton>
);
};

View file

@ -5,4 +5,5 @@
* 2.0.
*/
export { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint';
export { ResetCounterButton } from './deprecations_count_reset_button';
export { DeprecationsCountCallout } from './deprecations_count_callout';

View file

@ -0,0 +1,295 @@
/*
* 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, { useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiText,
EuiSpacer,
EuiLink,
EuiCallOut,
EuiCode,
EuiFlyoutHeader,
EuiTitle,
EuiButtonEmpty,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import { useAppContext } from '../../../app_context';
import { DiscoverExternalLinks } from './external_links';
import { DeprecationsCountCallout, ResetCounterButton } from './deprecations_count_checkpoint';
import { useDeprecationLogging } from './use_deprecation_logging';
import { DeprecationLoggingToggle } from './deprecation_logging_toggle';
import { loadLogsCheckpoint, saveLogsCheckpoint } from '../../../lib/logs_checkpoint';
import { DEPRECATION_LOGS_INDEX } from '../../../../../common/constants';
import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports';
import { uiMetricService, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD } from '../../../lib/ui_metric';
const i18nTexts = {
analyzeTitle: i18n.translate('xpack.upgradeAssistant.overview.analyzeTitle', {
defaultMessage: 'Analyze deprecation logs',
}),
apiCompatibilityNoteTitle: i18n.translate(
'xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle',
{
defaultMessage: 'Apply API compatibility headers (optional)',
}
),
apiCompatibilityNoteBody: (docLink: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteBody"
defaultMessage="We recommend you resolve all deprecation issues before upgrading. If needed, you can apply API compatibility headers to requests that use deprecated features. {learnMoreLink}."
values={{
learnMoreLink: (
<EuiLink href={docLink} target="_blank">
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
),
onlyLogWritingEnabledTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningTitle',
{
defaultMessage: 'Your logs are being written to the logs directory',
}
),
onlyLogWritingEnabledBody: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningBody',
{
defaultMessage:
'Go to your logs directory to view the deprecation logs or enable deprecation log collection to see them in Kibana.',
}
),
deniedPrivilegeTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeTitle',
{
defaultMessage: 'You need index privileges to analyze the deprecation logs',
}
),
deniedPrivilegeDescription: (privilegesMissing: MissingPrivileges) => (
// NOTE: hardcoding the missing privilege because the WithPrivileges HOC
// doesnt provide a way to retrieve which specific privileges an index
// is missing.
<FormattedMessage
id="xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeDescription"
defaultMessage="The deprecation logs will continue to be indexed, but you won't be able to analyze them until you have the read index {privilegesCount, plural, one {privilege} other {privileges}} for: {missingPrivileges}"
values={{
missingPrivileges: (
<EuiCode transparentBackground={true}>{privilegesMissing?.index?.join(', ')}</EuiCode>
),
privilegesCount: privilegesMissing?.index?.length,
}}
/>
),
reviewDeprecationLogsInfo: (docLink: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.reviewDeprecationLogsInfo"
defaultMessage="Review the deprecation logs to determine if your applications are using any deprecated APIs. Update your applications to prevent errors or changes in behavior after you upgrade. {learnMoreLink}."
values={{
learnMoreLink: (
<EuiLink href={docLink} target="_blank" data-test-subj="documentationLink">
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
),
};
const callOut = (
hasPrivileges: boolean,
privilegesMissing: MissingPrivileges,
onlyDeprecationLogWritingEnabled: boolean,
isDeprecationLogIndexingEnabled: boolean,
checkpoint: string
) => {
if (onlyDeprecationLogWritingEnabled) {
return (
<EuiCallOut
title={i18nTexts.onlyLogWritingEnabledTitle}
color="warning"
iconType="help"
data-test-subj="deprecationWarningCallout"
>
<p>{i18nTexts.onlyLogWritingEnabledBody}</p>
</EuiCallOut>
);
}
if (!hasPrivileges && isDeprecationLogIndexingEnabled) {
return (
<EuiCallOut
iconType="help"
color="warning"
title={i18nTexts.deniedPrivilegeTitle}
data-test-subj="noIndexPermissionsCallout"
>
<p>{i18nTexts.deniedPrivilegeDescription(privilegesMissing)}</p>
</EuiCallOut>
);
}
if (hasPrivileges && isDeprecationLogIndexingEnabled) {
return <DeprecationsCountCallout checkpoint={checkpoint} />;
}
};
export interface EsDeprecationLogsFlyoutProps {
closeFlyout: () => void;
handleToggleChange: () => void;
}
export const EsDeprecationLogsFlyout = ({
closeFlyout,
handleToggleChange,
}: EsDeprecationLogsFlyoutProps) => {
const {
services: {
core: { docLinks },
},
} = useAppContext();
const {
isDeprecationLogIndexingEnabled,
onlyDeprecationLogWritingEnabled,
isLoading,
isUpdating,
fetchError,
updateError,
resendRequest,
toggleLogging,
} = useDeprecationLogging();
const [checkpoint, setCheckpoint] = useState(loadLogsCheckpoint());
useEffect(() => {
handleToggleChange();
}, [handleToggleChange, toggleLogging]);
useEffect(() => {
saveLogsCheckpoint(checkpoint);
}, [checkpoint]);
useEffect(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_ES_DEPRECATION_LOGS_PAGE_LOAD);
}, []);
return (
<>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="esDeprecationLogsFlyoutTitle">
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.pageTitle"
defaultMessage="Elasticsearch deprecation logs"
/>
</h2>
</EuiTitle>
<EuiSpacer size="m" />
</EuiFlyoutHeader>
<WithPrivileges privileges={`index.${DEPRECATION_LOGS_INDEX}`}>
{({ hasPrivileges, privilegesMissing }) => (
<EuiFlyoutBody
banner={callOut(
hasPrivileges,
privilegesMissing,
onlyDeprecationLogWritingEnabled,
isDeprecationLogIndexingEnabled,
checkpoint
)}
>
<EuiText>
<p data-test-subj="deprecationLogsDescription">
{i18nTexts.reviewDeprecationLogsInfo(
docLinks.links.elasticsearch.migrationApiDeprecation
)}
</p>
</EuiText>
<EuiSpacer size="xl" />
<DeprecationLoggingToggle
isDeprecationLogIndexingEnabled={isDeprecationLogIndexingEnabled}
isLoading={isLoading}
isUpdating={isUpdating}
fetchError={fetchError}
updateError={updateError}
resendRequest={resendRequest}
toggleLogging={toggleLogging}
/>
{hasPrivileges && isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="xl" />
<EuiText data-test-subj="externalLinksTitle">
<h4>{i18nTexts.analyzeTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<DiscoverExternalLinks
checkpoint={checkpoint}
showInfoParagraph={true}
isButtonFormat={false}
/>
<EuiSpacer size="xl" />
<EuiText data-test-subj="apiCompatibilityNoteTitle">
<h4>{i18nTexts.apiCompatibilityNoteTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<EuiText>
<p>
{i18nTexts.apiCompatibilityNoteBody(
docLinks.links.elasticsearch.apiCompatibilityHeader
)}
</p>
</EuiText>
</>
)}
</EuiFlyoutBody>
)}
</WithPrivileges>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={closeFlyout}
flush="left"
data-test-subj="closeEsDeprecationLogs"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecationLogs.closeFlyout"
defaultMessage="Close"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<WithPrivileges privileges={`index.${DEPRECATION_LOGS_INDEX}`}>
{({ hasPrivileges }) => (
<>
{hasPrivileges && isDeprecationLogIndexingEnabled && (
<ResetCounterButton setCheckpoint={setCheckpoint} />
)}
</>
)}
</WithPrivileges>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</>
);
};

View file

@ -10,8 +10,8 @@ import { buildPhrasesFilter, PhrasesFilter } from '@kbn/es-query';
import { FormattedMessage } from '@kbn/i18n-react';
import { METRIC_TYPE } from '@kbn/analytics';
import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
import type { DataView } from '@kbn/data-views-plugin/common';
import { EuiLink, EuiSpacer, EuiText, EuiButton } from '@elastic/eui';
import { DataView } from '@kbn/data-views-plugin/common';
import {
APPS_WITH_DEPRECATION_LOGS,
DEPRECATION_LOGS_ORIGIN_FIELD,
@ -25,6 +25,8 @@ import { DEPRECATION_LOGS_INDEX_PATTERN } from '../../../../../common/constants'
interface Props {
checkpoint: string;
deprecationDataView: DataView;
isButtonFormat: boolean;
showInfoParagraph: boolean;
}
export const getDeprecationDataView = async (dataService: DataPublicPluginStart) => {
@ -56,7 +58,11 @@ export const getDeprecationDataView = async (dataService: DataPublicPluginStart)
}
};
const DiscoverAppLink: FunctionComponent<Props> = ({ checkpoint, deprecationDataView }) => {
const DiscoverAppLink: FunctionComponent<Omit<Props, 'showInfoParagraph'>> = ({
checkpoint,
deprecationDataView,
isButtonFormat,
}) => {
const {
services: { data: dataService },
plugins: { share },
@ -104,25 +110,39 @@ const DiscoverAppLink: FunctionComponent<Props> = ({ checkpoint, deprecationData
return null;
}
return (
const handleClick = () => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_DISCOVER_CLICK);
};
const content = (
<FormattedMessage
id="xpack.upgradeAssistant.overview.viewDiscoverResultsAction"
defaultMessage="Analyze logs in Discover"
/>
);
return isButtonFormat ? (
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink
<EuiButton
href={discoveryUrl}
onClick={() => {
uiMetricService.trackUiMetric(METRIC_TYPE.CLICK, UIM_DISCOVER_CLICK);
}}
data-test-subj="viewDiscoverLogs"
onClick={handleClick}
data-test-subj="viewDiscoverLogsButton"
fill
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.viewDiscoverResultsAction"
defaultMessage="Analyze logs in Discover"
/>
{content}
</EuiButton>
) : (
// eslint-disable-next-line @elastic/eui/href-or-on-click
<EuiLink href={discoveryUrl} onClick={handleClick} data-test-subj="viewDiscoverLogs">
<EuiText> {content}</EuiText>
</EuiLink>
);
};
export const ExternalLinks: FunctionComponent<Omit<Props, 'deprecationDataView'>> = ({
export const DiscoverExternalLinks: FunctionComponent<Omit<Props, 'deprecationDataView'>> = ({
checkpoint,
showInfoParagraph,
isButtonFormat,
}) => {
const {
services: { data: dataService },
@ -140,19 +160,27 @@ export const ExternalLinks: FunctionComponent<Omit<Props, 'deprecationDataView'>
}, [dataService, checkpoint, share.url.locators]);
return (
<>
<EuiText size="s">
<p>
<FormattedMessage
id="xpack.upgradeAssistant.overview.observe.discoveryDescription"
defaultMessage="Search and filter the deprecation logs to understand the types of changes you need to make."
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<React.Fragment>
{showInfoParagraph && (
<>
<EuiText>
<p>
<FormattedMessage
id="xpack.upgradeAssistant.overview.observe.discoveryDescription"
defaultMessage="Search and filter the deprecation logs to understand the types of changes you need to make."
/>
</p>
</EuiText>
<EuiSpacer size="m" />
</>
)}
{deprecationDataView ? (
<DiscoverAppLink checkpoint={checkpoint} deprecationDataView={deprecationDataView} />
<DiscoverAppLink
checkpoint={checkpoint}
deprecationDataView={deprecationDataView}
isButtonFormat={isButtonFormat}
/>
) : null}
</>
</React.Fragment>
);
};

View file

@ -1,204 +0,0 @@
/*
* 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, useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiText, EuiSpacer, EuiLink, EuiCallOut, EuiCode } from '@elastic/eui';
import { useAppContext } from '../../../app_context';
import { ExternalLinks } from './external_links';
import { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint';
import { useDeprecationLogging } from './use_deprecation_logging';
import { DeprecationLoggingToggle } from './deprecation_logging_toggle';
import { loadLogsCheckpoint, saveLogsCheckpoint } from '../../../lib/logs_checkpoint';
import { DEPRECATION_LOGS_INDEX } from '../../../../../common/constants';
import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports';
const i18nTexts = {
analyzeTitle: i18n.translate('xpack.upgradeAssistant.overview.analyzeTitle', {
defaultMessage: 'Analyze deprecation logs',
}),
deprecationsCountCheckpointTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle',
{
defaultMessage: 'Resolve deprecation issues and verify your changes',
}
),
apiCompatibilityNoteTitle: i18n.translate(
'xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle',
{
defaultMessage: 'Apply API compatibility headers (optional)',
}
),
apiCompatibilityNoteBody: (docLink: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteBody"
defaultMessage="We recommend you resolve all deprecation issues before upgrading. If needed, you can apply API compatibility headers to requests that use deprecated features. {learnMoreLink}."
values={{
learnMoreLink: (
<EuiLink href={docLink} target="_blank">
<FormattedMessage
id="xpack.upgradeAssistant.overview.apiCompatibilityNoteLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
),
onlyLogWritingEnabledTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningTitle',
{
defaultMessage: 'Your logs are being written to the logs directory',
}
),
onlyLogWritingEnabledBody: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningBody',
{
defaultMessage:
'Go to your logs directory to view the deprecation logs or enable deprecation log collection to see them in Kibana.',
}
),
deniedPrivilegeTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeTitle',
{
defaultMessage: 'You require index privileges to analyze the deprecation logs',
}
),
deniedPrivilegeDescription: (privilegesMissing: MissingPrivileges) => (
// NOTE: hardcoding the missing privilege because the WithPrivileges HOC
// doesnt provide a way to retrieve which specific privileges an index
// is missing.
<FormattedMessage
id="xpack.upgradeAssistant.overview.deprecationLogs.deniedPrivilegeDescription"
defaultMessage="The deprecation logs will continue to be indexed, but you won't be able to analyze them until you have the read index {privilegesCount, plural, one {privilege} other {privileges}} for: {missingPrivileges}"
values={{
missingPrivileges: (
<EuiCode transparentBackground={true}>{privilegesMissing?.index?.join(', ')}</EuiCode>
),
privilegesCount: privilegesMissing?.index?.length,
}}
/>
),
};
interface Props {
hasPrivileges: boolean;
privilegesMissing: MissingPrivileges;
}
const FixDeprecationLogsUI: FunctionComponent<Props> = ({ hasPrivileges, privilegesMissing }) => {
const {
services: {
core: { docLinks },
},
} = useAppContext();
const {
isDeprecationLogIndexingEnabled,
onlyDeprecationLogWritingEnabled,
isLoading,
isUpdating,
fetchError,
updateError,
resendRequest,
toggleLogging,
} = useDeprecationLogging();
const [checkpoint, setCheckpoint] = useState(loadLogsCheckpoint());
useEffect(() => {
saveLogsCheckpoint(checkpoint);
}, [checkpoint]);
return (
<>
<DeprecationLoggingToggle
isDeprecationLogIndexingEnabled={isDeprecationLogIndexingEnabled}
isLoading={isLoading}
isUpdating={isUpdating}
fetchError={fetchError}
updateError={updateError}
resendRequest={resendRequest}
toggleLogging={toggleLogging}
/>
{onlyDeprecationLogWritingEnabled && (
<>
<EuiSpacer size="m" />
<EuiCallOut
title={i18nTexts.onlyLogWritingEnabledTitle}
color="warning"
iconType="help"
data-test-subj="deprecationWarningCallout"
>
<p>{i18nTexts.onlyLogWritingEnabledBody}</p>
</EuiCallOut>
</>
)}
{!hasPrivileges && isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="m" />
<EuiCallOut
iconType="help"
color="warning"
title={i18nTexts.deniedPrivilegeTitle}
data-test-subj="noIndexPermissionsCallout"
>
<p>{i18nTexts.deniedPrivilegeDescription(privilegesMissing)}</p>
</EuiCallOut>
</>
)}
{hasPrivileges && isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="xl" />
<EuiText data-test-subj="externalLinksTitle">
<h4>{i18nTexts.analyzeTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<ExternalLinks checkpoint={checkpoint} />
<EuiSpacer size="xl" />
<EuiText data-test-subj="deprecationsCountTitle">
<h4>{i18nTexts.deprecationsCountCheckpointTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<DeprecationsCountCheckpoint checkpoint={checkpoint} setCheckpoint={setCheckpoint} />
<EuiSpacer size="xl" />
<EuiText data-test-subj="apiCompatibilityNoteTitle">
<h4>{i18nTexts.apiCompatibilityNoteTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<EuiText>
<p>
{i18nTexts.apiCompatibilityNoteBody(
docLinks.links.elasticsearch.apiCompatibilityHeader
)}
</p>
</EuiText>
</>
)}
</>
);
};
export const FixDeprecationLogs = () => {
return (
<WithPrivileges privileges={`index.${DEPRECATION_LOGS_INDEX}`}>
{({ hasPrivileges, privilegesMissing, isLoading }) => (
<FixDeprecationLogsUI
hasPrivileges={!isLoading && hasPrivileges}
privilegesMissing={privilegesMissing}
/>
)}
</WithPrivileges>
);
};

View file

@ -4,6 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { FixDeprecationLogs } from './fix_deprecation_logs';
export { EsDeprecationLogsFlyout as FixDeprecationLogsFlyout } from './es_deprecation_logs_flyout';
export type { EsDeprecationLogsFlyoutProps as FixDeprecationLogsFlyoutProps } from './es_deprecation_logs_flyout';
export { useDeprecationLogging } from './use_deprecation_logging';

View file

@ -5,5 +5,4 @@
* 2.0.
*/
export { EsDeprecationLogs } from './es_deprecation_logs';
export { useDeprecationLogging } from './fix_deprecation_logs';

View file

@ -1,44 +0,0 @@
.upgStepProgress__step {
display: flex;
align-items: center;
margin-top: $euiSize;
margin-bottom: $euiSizeS;
line-height: $euiSize;
}
.upgStepProgress__status {
@include size($euiSize);
margin-right: $euiSizeM;
}
$stepStatusToCallOutColor: (
failed: $euiColorDanger,
complete: $euiColorSuccess,
paused: $euiColorWarning,
cancelled: $euiColorWarning,
);
.upgStepProgress__status--circle {
text-align: center;
border-radius: $euiSizeM;
line-height: $euiSize - 2px;
@each $status, $callOutColor in $stepStatusToCallOutColor {
&-#{$status} {
$statusBg: tintOrShade($callOutColor, 90%, 70%);
color: shadeOrTint(makeHighContrastColor($callOutColor, $statusBg), 0, 20%);
background-color: $statusBg;
}
}
}
.upgStepProgress__title {
&--currentStep {
font-weight: $euiFontWeightBold;
}
}
.upgStepProgress__content {
display: block;
margin-left: $euiSize + $euiSizeM;
}

View file

@ -5,47 +5,92 @@
* 2.0.
*/
import classNames from 'classnames';
import React, { Fragment, ReactNode } from 'react';
import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui';
import { css } from '@emotion/react';
import './_step_progress.scss';
import {
EuiIcon,
EuiLoadingSpinner,
useEuiTheme,
shadeOrTint,
makeHighContrastColor,
tintOrShade,
EuiThemeColorModeStandard,
EuiThemeComputed,
} from '@elastic/eui';
type STATUS = 'incomplete' | 'inProgress' | 'complete' | 'failed' | 'paused' | 'cancelled';
const getStatusStyles = (euiTheme: EuiThemeComputed, colorMode: EuiThemeColorModeStandard) => {
const { colors, size } = euiTheme;
const baseStyle = css`
width: ${size.base};
height: ${size.base};
margin-right: ${size.m};
`;
const getBackgroundColor = (color: string) => tintOrShade(color, 0.9, colorMode);
const getCircleStyle = (color: string) => css`
text-align: center;
border-radius: ${size.m};
line-height: calc(${size.base} - 2px);
color: ${shadeOrTint(makeHighContrastColor(color)(getBackgroundColor(color)), 0, colorMode)};
background-color: ${getBackgroundColor(color)};
`;
return {
info: baseStyle,
success: css`
${baseStyle};
${getCircleStyle(colors.success)};
`,
warning: css`
${baseStyle};
${getCircleStyle(colors.warning)};
`,
danger: css`
${baseStyle};
${getCircleStyle(colors.danger)};
`,
};
};
const StepStatus: React.FunctionComponent<{ status: STATUS; idx: number }> = ({ status, idx }) => {
if (status === 'incomplete') {
return <span className="upgStepProgress__status">{idx + 1}.</span>;
} else if (status === 'inProgress') {
return <EuiLoadingSpinner size="m" className="upgStepProgress__status" />;
} else if (status === 'complete') {
return (
<span className="upgStepProgress__status upgStepProgress__status--circle upgStepProgress__status--circle-complete">
const { euiTheme, colorMode } = useEuiTheme();
const statusStyles = getStatusStyles(euiTheme, colorMode);
const statusComponents = {
incomplete: <span css={statusStyles.info}>{idx + 1}.</span>,
inProgress: <EuiLoadingSpinner size="m" css={statusStyles.info} />,
complete: (
<span css={statusStyles.success}>
<EuiIcon type="check" size="s" />
</span>
);
} else if (status === 'paused') {
return (
<span className="upgStepProgress__status upgStepProgress__status--circle upgStepProgress__status--circle-paused">
),
paused: (
<span css={statusStyles.warning}>
<EuiIcon type="pause" size="s" />
</span>
);
} else if (status === 'cancelled') {
return (
<span className="upgStepProgress__status upgStepProgress__status--circle upgStepProgress__status--circle-cancelled">
),
cancelled: (
<span css={statusStyles.warning}>
<EuiIcon type="cross" size="s" />
</span>
);
} else if (status === 'failed') {
return (
<span className="upgStepProgress__status upgStepProgress__status--circle upgStepProgress__status--circle-failed">
),
failed: (
<span css={statusStyles.danger}>
<EuiIcon type="cross" size="s" />
</span>
);
),
};
if (!statusComponents[status]) {
throw new Error(`Unsupported status: ${status}`);
}
throw new Error(`Unsupported status: ${status}`);
return statusComponents[status];
};
const Step: React.FunctionComponent<StepProgressStep & { idx: number }> = ({
@ -54,17 +99,38 @@ const Step: React.FunctionComponent<StepProgressStep & { idx: number }> = ({
children,
idx,
}) => {
const titleClassName = classNames('upgStepProgress__title', {
'upgStepProgress__title--currentStep': status === 'inProgress',
});
const { euiTheme } = useEuiTheme();
const { size, font } = euiTheme;
const titleStyle = css`
line-height: ${size.l};
font-weight: ${status === 'inProgress' ? font.weight.bold : 'normal'};
`;
const contentStyle = css`
display: block;
margin-left: calc(${size.base} + ${size.m});
`;
const stepProgressStyle = css`
display: flex;
align-items: center;
margin-top: ${size.s};
margin-bottom: ${size.s};
line-height: ${size.base};
&:first-child {
margin-top: ${size.base};
}
`;
return (
<Fragment>
<div className="upgStepProgress__step">
<div css={stepProgressStyle} data-test-subj="stepProgressStep">
<StepStatus status={status} idx={idx} />
<div className={titleClassName}>{title}</div>
<div css={titleStyle}>{title}</div>
</div>
{children && <div className="upgStepProgress__content">{children}</div>}
{children && <div css={contentStyle}>{children}</div>}
</Fragment>
);
};
@ -82,7 +148,7 @@ export const StepProgress: React.FunctionComponent<{
steps: StepProgressStep[];
}> = ({ steps }) => {
return (
<div className="upgStepProgress__container">
<div>
{/* Use the index as the key only works here because these values do not change order after mounting. */}
{steps.map((step, idx) => (
<Step key={idx} {...step} idx={idx} />

View file

@ -106,10 +106,7 @@ export const RemoveClusterSettingsFlyout = ({
return (
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge
isCritical={deprecation.isCritical}
isResolved={statusType === 'complete'}
/>
<DeprecationBadge level={deprecation.level} isResolved={statusType === 'complete'} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="removeClusterSettingsDetailsFlyoutTitle">{message}</h2>

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRowCell, EuiTableRow } from '@elastic/eui';
import { EnrichedDeprecationInfo, ResponseError } from '../../../../../../common/types';
import { GlobalFlyout } from '../../../../../shared_imports';
import { useAppContext } from '../../../../app_context';
@ -20,11 +20,13 @@ const { useGlobalFlyout } = GlobalFlyout;
interface Props {
deprecation: EnrichedDeprecationInfo;
rowFieldNames: DeprecationTableColumns[];
index: number;
}
export const ClusterSettingsTableRow: React.FunctionComponent<Props> = ({
rowFieldNames,
deprecation,
index,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const [status, setStatus] = useState<{
@ -88,7 +90,11 @@ export const ClusterSettingsTableRow: React.FunctionComponent<Props> = ({
]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${index}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field: DeprecationTableColumns) => {
return (
<EuiTableRowCell
@ -98,13 +104,12 @@ export const ClusterSettingsTableRow: React.FunctionComponent<Props> = ({
>
<EsDeprecationsTableCells
fieldName={field}
openFlyout={() => setShowFlyout(true)}
deprecation={deprecation}
resolutionTableCell={<ClusterSettingsResolutionCell status={status} />}
/>
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -118,31 +118,40 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
await cancelReadonly();
}, [cancelReadonly]);
const { docsSizeFormatted, indicesRequiringUpgradeDocsCount, lastIndexCreationDateFormatted } =
useMemo(() => {
if (!meta) {
return {
indicesRequiringUpgradeDocsCount: containerMessages.unknownMessage,
docsSizeFormatted: containerMessages.unknownMessage,
lastIndexCreationDateFormatted: containerMessages.unknownMessage,
};
}
const {
docsSizeFormatted,
indicesRequiringUpgradeDocsCount,
lastIndexCreationDateFormatted,
oldestIncompatibleDocFormatted,
} = useMemo(() => {
if (!meta) {
return {
indicesRequiringUpgradeDocsCount:
typeof meta.indicesRequiringUpgradeDocsCount === 'number'
? `${meta.indicesRequiringUpgradeDocsCount}`
: 'Unknown',
docsSizeFormatted:
typeof meta.indicesRequiringUpgradeDocsSize === 'number'
? numeral(meta.indicesRequiringUpgradeDocsSize).format(FILE_SIZE_DISPLAY_FORMAT)
: 'Unknown',
lastIndexCreationDateFormatted:
typeof meta.lastIndexRequiringUpgradeCreationDate === 'number'
? `${moment(meta.lastIndexRequiringUpgradeCreationDate).format(DATE_FORMAT)}`
: 'Unknown',
indicesRequiringUpgradeDocsCount: containerMessages.unknownMessage,
docsSizeFormatted: containerMessages.unknownMessage,
lastIndexCreationDateFormatted: containerMessages.unknownMessage,
oldestIncompatibleDocFormatted: undefined,
};
}, [meta]);
}
return {
indicesRequiringUpgradeDocsCount:
typeof meta.indicesRequiringUpgradeDocsCount === 'number'
? `${meta.indicesRequiringUpgradeDocsCount}`
: 'Unknown',
docsSizeFormatted:
typeof meta.indicesRequiringUpgradeDocsSize === 'number'
? numeral(meta.indicesRequiringUpgradeDocsSize).format(FILE_SIZE_DISPLAY_FORMAT)
: 'Unknown',
lastIndexCreationDateFormatted:
typeof meta.lastIndexRequiringUpgradeCreationDate === 'number'
? `${moment(meta.lastIndexRequiringUpgradeCreationDate).format(DATE_FORMAT)}`
: 'Unknown',
oldestIncompatibleDocFormatted:
typeof meta.oldestIncompatibleDocTimestamp === 'number'
? `${moment(meta.oldestIncompatibleDocTimestamp).format(DATE_FORMAT)}`
: undefined,
};
}, [meta]);
const flyoutContents = useMemo(() => {
switch (flyoutStep) {
@ -224,11 +233,26 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
onStopReindex();
}
}}
startReadonly={startReadonly}
correctiveAction={correctiveAction as DataStreamsAction}
/>
);
}
case 'completed': {
return <MigrationCompletedFlyoutStep meta={meta} resolutionType={resolutionType} />;
if (!meta || !resolutionType) {
return (
<InitializingFlyoutStep
errorMessage={errorMessage || containerMessages.errorLoadingDataStreamInfo}
/>
);
}
return (
<MigrationCompletedFlyoutStep
meta={meta}
resolutionType={resolutionType}
closeFlyout={closeFlyout}
/>
);
}
}
}, [
@ -246,6 +270,7 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
resolutionType,
initMigration,
correctiveAction,
startReadonly,
]);
return (
@ -253,7 +278,7 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
{flyoutStep !== 'initializing' && (
<EuiFlyoutHeader hasBorder>
<DeprecationBadge
isCritical={deprecation.isCritical}
level={deprecation.level}
isResolved={status === DataStreamMigrationStatus.completed}
/>
<EuiSpacer size="s" />
@ -267,17 +292,34 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
<EuiFlexItem>
<EuiDescriptionList
textStyle="reverse"
listItems={[
{
title: i18n.translate(
'xpack.upgradeAssistant.dataStream.flyout.container.affectedIndicesCreatedOnOrBefore',
{
defaultMessage: 'Migration required for indices created on or before',
}
),
description: lastIndexCreationDateFormatted,
},
]}
data-test-subj="dataStreamLastIndexCreationDate"
listItems={
oldestIncompatibleDocFormatted
? [
{
title: i18n.translate(
'xpack.upgradeAssistant.dataStream.flyout.container.oldestIncompatibleDoc',
{
defaultMessage:
'Migration required for data indexed on or before',
}
),
description: oldestIncompatibleDocFormatted,
},
]
: [
{
title: i18n.translate(
'xpack.upgradeAssistant.dataStream.flyout.container.affectedIndicesCreatedOnOrBefore',
{
defaultMessage:
'Migration required for indices created on or before',
}
),
description: lastIndexCreationDateFormatted,
},
]
}
/>
</EuiFlexItem>
<EuiFlexGroup>
@ -295,6 +337,7 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
description: docsSizeFormatted,
},
]}
data-test-subj="dataStreamSize"
/>
</EuiFlexItem>
<EuiFlexItem>
@ -311,6 +354,7 @@ export const DataStreamReindexFlyout: React.FunctionComponent<Props> = ({
description: indicesRequiringUpgradeDocsCount,
},
]}
data-test-subj="dataStreamDocumentCount"
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -23,6 +23,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import {
DataStreamMigrationStatus,
DataStreamResolutionType,
DataStreamsAction,
} from '../../../../../../../../../common/types';
import { LoadingState } from '../../../../../../types';
import type { MigrationState } from '../../../use_migration_state';
@ -39,7 +40,17 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
resolutionType: DataStreamResolutionType;
executeAction: () => void;
cancelAction: () => void;
}> = ({ closeFlyout, migrationState, resolutionType, executeAction, cancelAction }) => {
startReadonly: () => void;
correctiveAction: DataStreamsAction;
}> = ({
closeFlyout,
migrationState,
resolutionType,
executeAction,
cancelAction,
startReadonly,
correctiveAction,
}) => {
const {
services: { api },
} = useAppContext();
@ -55,10 +66,13 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
const showMainButton = !hasFetchFailed && !isCompleted && hasRequiredPrivileges;
const shouldShowCancelButton = showMainButton && status === DataStreamMigrationStatus.inProgress;
const readOnlyExcluded = correctiveAction.metadata.excludedActions?.includes('readOnly');
const shouldShowReadOnlyButton =
!readOnlyExcluded && !loading && status === DataStreamMigrationStatus.failed;
return (
<Fragment>
<EuiFlyoutBody>
<EuiFlyoutBody data-test-subj="dataStreamMigrationChecklistFlyout">
{hasRequiredPrivileges === false && (
<Fragment>
<EuiSpacer />
@ -71,6 +85,7 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
}
color="danger"
iconType="warning"
data-test-subj="dsInsufficientPrivilegesCallout"
/>
</Fragment>
)}
@ -159,7 +174,12 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
<EuiButtonEmpty
iconType="cross"
onClick={closeFlyout}
flush="left"
data-test-subj="closeDataStreamReindexingButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.closeButtonLabel"
defaultMessage="Close"
@ -186,12 +206,26 @@ export const ChecklistFlyoutStep: React.FunctionComponent<{
</EuiButton>
</EuiFlexItem>
)}
{shouldShowReadOnlyButton && (
<EuiFlexItem grow={false}>
<EuiButton
color={'primary'}
onClick={startReadonly}
data-test-subj="startDataStreamReadonlyButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.initMarkAsReadOnlyButtonLabel"
defaultMessage="Mark as read-only"
/>
</EuiButton>
</EuiFlexItem>
)}
{showMainButton && (
<EuiFlexItem grow={false}>
<EuiButton
fill
color={status === DataStreamMigrationStatus.inProgress ? 'primary' : 'warning'}
color={'primary'}
iconType={
status === DataStreamMigrationStatus.inProgress ? undefined : 'refresh'
}

View file

@ -7,7 +7,15 @@
import React from 'react';
import { EuiFlyoutBody, EuiSpacer, EuiTitle } from '@elastic/eui';
import {
EuiFlyoutBody,
EuiSpacer,
EuiTitle,
EuiFlyoutFooter,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import type {
DataStreamMetadata,
@ -17,17 +25,19 @@ import type {
interface Props {
meta?: DataStreamMetadata | null;
resolutionType?: DataStreamResolutionType;
closeFlyout: () => void;
}
export const MigrationCompletedFlyoutStep: React.FunctionComponent<Props> = ({
meta,
resolutionType,
closeFlyout,
}: Props) => {
return (
<>
<EuiFlyoutBody>
<EuiTitle size="s">
<h3>
<h3 data-test-subj="dataStreamMigrationCompletedTitle">
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.acceptChangesTitle"
defaultMessage="Data Stream Migration Complete"
@ -35,7 +45,7 @@ export const MigrationCompletedFlyoutStep: React.FunctionComponent<Props> = ({
</h3>
</EuiTitle>
<EuiSpacer size="m" />
<p>
<p data-test-subj="dataStreamMigrationCompletedDescription">
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.acceptChangesTitle"
defaultMessage="Success! {count, plural, =0 {backing indices} =1 {# backing index} other {# backing indices}} successfully {resolutionType, select, reindex {reindexed} readonly {marked as read-only} other {migrated}}."
@ -43,6 +53,23 @@ export const MigrationCompletedFlyoutStep: React.FunctionComponent<Props> = ({
/>
</p>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
iconType="cross"
onClick={closeFlyout}
flush="left"
data-test-subj="closeDataStreamReindexingButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.completedStep.closeButtonLabel"
defaultMessage="Close"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</>
);
};

View file

@ -20,6 +20,7 @@ export const ReindexWarningCallout: React.FunctionComponent<{}> = () => {
}
color="warning"
iconType="warning"
data-test-subj="reindexDsWarningCallout"
>
<p>
<FormattedMessage
@ -42,6 +43,7 @@ export const ReadonlyWarningCallout: React.FunctionComponent<{}> = () => {
}
color="warning"
iconType="warning"
data-test-subj="readOnlyDsWarningCallout"
>
<p>
<FormattedMessage

View file

@ -119,10 +119,7 @@ export const ConfirmMigrationFlyoutStep: React.FunctionComponent<{
defaultMessage="You can increase the speed of reindexing by changing throttling configuration on ES. Where changing throttling configuration allows you to utilize more resources to speed up the reindexing process. {learnMoreHtml}"
values={{
learnMoreHtml: (
<EuiLink
href={`${links.elasticsearch.docsBase}data-stream-reindex-api.html#reindex-data-stream-api-settings`}
target="_blank"
>
<EuiLink href={links.upgradeAssistant.dataStreamReindex} target="_blank">
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.learnMoreLink"
defaultMessage="Learn more"
@ -175,7 +172,12 @@ export const ConfirmMigrationFlyoutStep: React.FunctionComponent<{
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="arrowLeft" onClick={hideWarningsStep} flush="left">
<EuiButtonEmpty
iconType="arrowLeft"
onClick={hideWarningsStep}
flush="left"
data-test-subj="backButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.checklistStep.backButtonLabel"
defaultMessage="Back"
@ -183,7 +185,13 @@ export const ConfirmMigrationFlyoutStep: React.FunctionComponent<{
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill color="primary" onClick={startAction} disabled={blockAdvance}>
<EuiButton
fill
color="primary"
onClick={startAction}
disabled={blockAdvance}
data-test-subj="startActionButton"
>
{startActionButtonLabel}
</EuiButton>
</EuiFlexItem>

View file

@ -30,7 +30,7 @@ export const WarningCheckbox: React.FunctionComponent<{
<>
<EuiText>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiFlexItem grow={false} data-test-subj="migrationWarningCheckbox">
<EuiCheckbox
id={warningId}
label={<strong>{label}</strong>}
@ -70,4 +70,7 @@ export interface WarningCheckboxProps {
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
docLinks: DocLinksStart['links'];
id: string;
meta?: {
oldestIncompatibleDocTimestamp?: number;
};
}

View file

@ -91,6 +91,7 @@ export const DataStreamDetailsFlyoutStep: React.FunctionComponent<{
}
color="danger"
iconType="warning"
data-test-subj="dsInsufficientPrivilegesCallout"
/>
</Fragment>
)}
@ -162,7 +163,7 @@ export const DataStreamDetailsFlyoutStep: React.FunctionComponent<{
</>
)}
<EuiText>
<EuiText data-test-subj="dataStreamDetailsText">
<p>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.notCompatibleIndicesText"
@ -238,7 +239,12 @@ export const DataStreamDetailsFlyoutStep: React.FunctionComponent<{
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
<EuiButtonEmpty
iconType="cross"
onClick={closeFlyout}
flush="left"
data-test-subj="closeDataStreamReindexingButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.detailsStep.closeButtonLabel"
defaultMessage="Close"
@ -250,13 +256,7 @@ export const DataStreamDetailsFlyoutStep: React.FunctionComponent<{
{!hasFetchFailed && !isCompleted && hasRequiredPrivileges && !reindexExcluded && (
<EuiFlexItem grow={false}>
<EuiButton
color={
status === DataStreamMigrationStatus.cancelled
? 'warning'
: readOnlyExcluded
? 'primary'
: 'accent'
}
color={status === DataStreamMigrationStatus.cancelled ? 'warning' : 'primary'}
iconType={status === DataStreamMigrationStatus.cancelled ? 'play' : undefined}
onClick={() => initAction('reindex')}
isLoading={loading}

View file

@ -19,7 +19,7 @@ export const DurationClarificationCallOut: React.FunctionComponent<Props> = ({
learnMoreUrl,
}) => {
return (
<EuiCallOut color="primary">
<EuiCallOut color="primary" data-test-subj="dataStreamMigrationWarningsCallout">
<p>
<FormattedMessage
id="xpack.upgradeAssistant.dataStream.migration.flyout.warningsStep.indicesNeedReindexing"

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRowCell, EuiTableRow } from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import { DataStreamsAction, EnrichedDeprecationInfo } from '../../../../../../common/types';
import { GlobalFlyout } from '../../../../../shared_imports';
@ -27,11 +27,13 @@ const { useGlobalFlyout } = GlobalFlyout;
interface TableRowProps {
deprecation: EnrichedDeprecationInfo;
rowFieldNames: DeprecationTableColumns[];
index: number;
}
const DataStreamTableRowCells: React.FunctionComponent<TableRowProps> = ({
rowFieldNames,
deprecation,
index,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const dataStreamContext = useDataStreamMigrationContext();
@ -57,8 +59,8 @@ const DataStreamTableRowCells: React.FunctionComponent<TableRowProps> = ({
flyoutProps: {
onClose: closeFlyout,
className: 'eui-textBreakWord',
'data-test-subj': 'reindexDetails',
'aria-labelledby': 'reindexDetailsFlyoutTitle',
'data-test-subj': 'reindexDataStreamDetails',
'aria-labelledby': 'reindexDataStreamDetailsFlyoutTitle',
},
});
}
@ -71,7 +73,11 @@ const DataStreamTableRowCells: React.FunctionComponent<TableRowProps> = ({
}, [showFlyout]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${index}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field: DeprecationTableColumns) => {
return (
<EuiTableRowCell
@ -81,7 +87,6 @@ const DataStreamTableRowCells: React.FunctionComponent<TableRowProps> = ({
>
<EsDeprecationsTableCells
fieldName={field}
openFlyout={() => setShowFlyout(true)}
deprecation={deprecation}
resolutionTableCell={
<DataStreamReindexResolutionCell
@ -92,7 +97,7 @@ const DataStreamTableRowCells: React.FunctionComponent<TableRowProps> = ({
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -20,7 +20,7 @@ import { CancelLoadingState, LoadingState } from '../../../types';
import { ApiService } from '../../../../lib/api';
import { readOnlyExecute } from './readonly_state';
const POLL_INTERVAL = 1000;
const POLL_INTERVAL = 3000;
export interface MigrationState {
loadingState: LoadingState;

View file

@ -59,7 +59,7 @@ export const DefaultDeprecationFlyout = ({
return (
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.isCritical} isResolved={false} />
<DeprecationBadge level={deprecation.level} isResolved={false} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="defaultDeprecationDetailsFlyoutTitle">{message}</h2>

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRowCell, EuiTableRow } from '@elastic/eui';
import { GlobalFlyout } from '../../../../../shared_imports';
import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import { DeprecationTableColumns } from '../../../types';
@ -18,9 +18,14 @@ const { useGlobalFlyout } = GlobalFlyout;
interface Props {
rowFieldNames: DeprecationTableColumns[];
deprecation: EnrichedDeprecationInfo;
index: number;
}
export const DefaultTableRow: React.FunctionComponent<Props> = ({ rowFieldNames, deprecation }) => {
export const DefaultTableRow: React.FunctionComponent<Props> = ({
rowFieldNames,
deprecation,
index,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const { addContent: addContentToGlobalFlyout, removeContent: removeContentFromGlobalFlyout } =
@ -51,7 +56,11 @@ export const DefaultTableRow: React.FunctionComponent<Props> = ({ rowFieldNames,
}, [addContentToGlobalFlyout, closeFlyout, deprecation, showFlyout]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${index}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field) => {
return (
<EuiTableRowCell
@ -59,14 +68,10 @@ export const DefaultTableRow: React.FunctionComponent<Props> = ({ rowFieldNames,
truncateText={false}
data-test-subj={`defaultTableCell-${field}`}
>
<EsDeprecationsTableCells
fieldName={field}
deprecation={deprecation}
openFlyout={() => setShowFlyout(true)}
/>
<EsDeprecationsTableCells fieldName={field} deprecation={deprecation} />
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -61,7 +61,7 @@ export const HealthIndicatorFlyout = ({ deprecation, closeFlyout }: HealthIndica
return (
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.isCritical} isResolved={false} />
<DeprecationBadge level={deprecation.level} isResolved={false} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="defaultDeprecationDetailsFlyoutTitle">{message}</h2>

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRowCell, EuiTableRow } from '@elastic/eui';
import { GlobalFlyout } from '../../../../../shared_imports';
import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import { DeprecationTableColumns } from '../../../types';
@ -18,11 +18,13 @@ const { useGlobalFlyout } = GlobalFlyout;
interface Props {
rowFieldNames: DeprecationTableColumns[];
deprecation: EnrichedDeprecationInfo;
index: number;
}
export const HealthIndicatorTableRow: React.FunctionComponent<Props> = ({
rowFieldNames,
deprecation,
index,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
@ -54,7 +56,11 @@ export const HealthIndicatorTableRow: React.FunctionComponent<Props> = ({
}, [addContentToGlobalFlyout, closeFlyout, deprecation, showFlyout]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${index}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field) => {
return (
<EuiTableRowCell
@ -62,14 +68,10 @@ export const HealthIndicatorTableRow: React.FunctionComponent<Props> = ({
truncateText={false}
data-test-subj={`healthIndicatorTableCell-${field}`}
>
<EsDeprecationsTableCells
fieldName={field}
deprecation={deprecation}
openFlyout={() => setShowFlyout(true)}
/>
<EsDeprecationsTableCells fieldName={field} deprecation={deprecation} />
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -114,10 +114,7 @@ export const RemoveIndexSettingsFlyout = ({
return (
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge
isCritical={deprecation.isCritical}
isResolved={statusType === 'complete'}
/>
<DeprecationBadge level={deprecation.level} isResolved={statusType === 'complete'} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="indexSettingsDetailsFlyoutTitle">{message}</h2>

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRowCell, EuiTableRow } from '@elastic/eui';
import { EnrichedDeprecationInfo, ResponseError } from '../../../../../../common/types';
import { GlobalFlyout } from '../../../../../shared_imports';
import { useAppContext } from '../../../../app_context';
@ -20,11 +20,13 @@ const { useGlobalFlyout } = GlobalFlyout;
interface Props {
deprecation: EnrichedDeprecationInfo;
rowFieldNames: DeprecationTableColumns[];
index: number;
}
export const IndexSettingsTableRow: React.FunctionComponent<Props> = ({
rowFieldNames,
deprecation,
index: rowIndex,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const [status, setStatus] = useState<{
@ -81,7 +83,11 @@ export const IndexSettingsTableRow: React.FunctionComponent<Props> = ({
}, [addContentToGlobalFlyout, deprecation, removeIndexSettings, showFlyout, closeFlyout, status]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${rowIndex}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field: DeprecationTableColumns) => {
return (
<EuiTableRowCell
@ -91,13 +97,12 @@ export const IndexSettingsTableRow: React.FunctionComponent<Props> = ({
>
<EsDeprecationsTableCells
fieldName={field}
openFlyout={() => setShowFlyout(true)}
deprecation={deprecation}
resolutionTableCell={<IndexSettingsResolutionCell status={status} />}
/>
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -54,7 +54,12 @@ export const IndexFlyout: React.FunctionComponent<IndexFlyoutProps> = ({
useEffect(() => {
switch (reindexStatus) {
case ReindexStatus.failed:
case ReindexStatus.failed: {
if (updateIndexStatus === 'complete' || updateIndexStatus === 'inProgress') {
setFlyoutStep(correctiveAction?.type === 'unfreeze' ? 'unfreeze' : 'makeReadonly');
break;
}
}
case ReindexStatus.fetchFailed:
case ReindexStatus.cancelled:
case ReindexStatus.inProgress:
@ -182,6 +187,10 @@ export const IndexFlyout: React.FunctionComponent<IndexFlyoutProps> = ({
startReindex={startReindexWithWarnings}
reindexState={reindexState}
cancelReindex={onStopReindex}
startReadonly={() => {
setFlyoutStep('confirmReadonly');
}}
deprecation={deprecation}
/>
);
case 'unfreeze':
@ -225,7 +234,7 @@ export const IndexFlyout: React.FunctionComponent<IndexFlyoutProps> = ({
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge
isCritical={deprecation.isCritical}
level={deprecation.level}
isResolved={reindexStatus === ReindexStatus.completed || updateIndexStatus === 'complete'}
/>
<EuiSpacer size="s" />

View file

@ -7,8 +7,7 @@
import React, { Fragment } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiLink, EuiSpacer } from '@elastic/eui';
import { EuiText } from '@elastic/eui';
import { EuiText, EuiLink, EuiSpacer, EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ReindexStatus } from '../../../../../../../../../common/types';
import { IndexClosedParagraph } from '../index_closed_paragraph';
@ -47,28 +46,48 @@ export const getReindexButtonLabel = (status?: ReindexStatus) => {
}
};
const RecommendedOptionBadge = () => (
<EuiBadge color="hollow">
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.recommendedOption"
defaultMessage="Recommended"
/>
</EuiBadge>
);
export const getDefaultGuideanceText = ({
isClosedIndex,
readOnlyExcluded,
reindexExcluded,
indexBlockUrl,
indexManagementUrl,
isLargeIndex,
}: {
isClosedIndex: boolean;
readOnlyExcluded: boolean;
reindexExcluded: boolean;
indexBlockUrl: string;
indexManagementUrl: string;
isLargeIndex?: boolean;
}) => {
const guideanceListItems = [];
if (!reindexExcluded) {
guideanceListItems.push({
title: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.title',
{
defaultMessage: 'Option {optionCount}: Reindex data',
values: { optionCount: guideanceListItems.length + 1 },
}
title: (
<EuiFlexGroup alignItems="center" justifyContent="flexStart" gutterSize="s">
<EuiFlexItem grow={false}>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.title"
defaultMessage="Option {optionCount}: Reindex data"
values={{ optionCount: guideanceListItems.length + 1 }}
/>
</EuiFlexItem>
{!isLargeIndex && !readOnlyExcluded && (
<EuiFlexItem grow={false}>
<RecommendedOptionBadge />
</EuiFlexItem>
)}
</EuiFlexGroup>
),
description: (
<EuiText size="m">
@ -89,12 +108,21 @@ export const getDefaultGuideanceText = ({
if (!readOnlyExcluded) {
guideanceListItems.push({
title: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option2.title',
{
defaultMessage: 'Option {optionCount}: Mark as read-only',
values: { optionCount: guideanceListItems.length + 1 },
}
title: (
<EuiFlexGroup alignItems="center" justifyContent="flexStart" gutterSize="s">
<EuiFlexItem grow={false}>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option2.title"
defaultMessage="Option {optionCount}: Mark as read-only"
values={{ optionCount: guideanceListItems.length + 1 }}
/>
</EuiFlexItem>
{(isLargeIndex || reindexExcluded) && (
<EuiFlexItem grow={false}>
<RecommendedOptionBadge />
</EuiFlexItem>
)}
</EuiFlexGroup>
),
description: (
<EuiText size="m">

View file

@ -39,7 +39,7 @@ jest.mock('../../../../../../../app_context', () => {
describe('ReindexDetailsFlyoutStep', () => {
const defaultDeprecation: () => EnrichedDeprecationInfo = () => ({
isCritical: true,
level: 'critical',
message: 'foo',
resolveDuringUpgrade: false,
type: 'index_settings',
@ -55,6 +55,7 @@ describe('ReindexDetailsFlyoutStep', () => {
isFrozen: false,
isReadonly: false,
isClosedIndex: false,
isFollowerIndex: false,
},
hasRequiredPrivileges: true,
reindexTaskPercComplete: null,
@ -100,7 +101,30 @@ describe('ReindexDetailsFlyoutStep', () => {
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.description"
/>
</EuiText>,
"title": "Option 1: Reindex data",
"title": <EuiFlexGroup
alignItems="center"
gutterSize="s"
justifyContent="flexStart"
>
<EuiFlexItem
grow={false}
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Option {optionCount}: Reindex data"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option1.title"
values={
Object {
"optionCount": 1,
}
}
/>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<RecommendedOptionBadge />
</EuiFlexItem>
</EuiFlexGroup>,
},
Object {
"description": <EuiText
@ -121,7 +145,25 @@ describe('ReindexDetailsFlyoutStep', () => {
}
/>
</EuiText>,
"title": "Option 2: Mark as read-only",
"title": <EuiFlexGroup
alignItems="center"
gutterSize="s"
justifyContent="flexStart"
>
<EuiFlexItem
grow={false}
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Option {optionCount}: Mark as read-only"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindex.option2.title"
values={
Object {
"optionCount": 2,
}
}
/>
</EuiFlexItem>
</EuiFlexGroup>,
},
Object {
"description": <EuiText
@ -161,6 +203,7 @@ describe('ReindexDetailsFlyoutStep', () => {
grow={false}
>
<EuiButtonEmpty
data-test-subj="closeReindexButton"
flush="left"
iconType="cross"
onClick={[MockFunction]}
@ -181,7 +224,7 @@ describe('ReindexDetailsFlyoutStep', () => {
grow={false}
>
<EuiButton
color="accent"
color="primary"
data-test-subj="startIndexReadonlyButton"
disabled={false}
fill={false}
@ -259,7 +302,7 @@ describe('ReindexDetailsFlyoutStep', () => {
],
"type": "reindex",
},
"isCritical": true,
"level": "critical",
"message": "foo",
"resolveDuringUpgrade": false,
"type": "index_settings",
@ -278,6 +321,7 @@ describe('ReindexDetailsFlyoutStep', () => {
grow={false}
>
<EuiButtonEmpty
data-test-subj="closeReindexButton"
flush="left"
iconType="cross"
onClick={[MockFunction]}
@ -294,6 +338,22 @@ describe('ReindexDetailsFlyoutStep', () => {
<EuiFlexGroup
gutterSize="s"
>
<EuiFlexItem
grow={false}
>
<EuiButton
color="primary"
data-test-subj="startIndexReadonlyButton"
disabled={false}
fill={false}
onClick={[MockFunction]}
>
<MemoizedFormattedMessage
defaultMessage="Mark as read-only"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton"
/>
</EuiButton>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
@ -361,6 +421,7 @@ describe('ReindexDetailsFlyoutStep', () => {
grow={false}
>
<EuiButtonEmpty
data-test-subj="closeReindexButton"
flush="left"
iconType="cross"
onClick={[MockFunction]}
@ -434,6 +495,7 @@ describe('ReindexDetailsFlyoutStep', () => {
grow={false}
>
<EuiButtonEmpty
data-test-subj="closeReindexButton"
flush="left"
iconType="cross"
onClick={[MockFunction]}
@ -454,7 +516,7 @@ describe('ReindexDetailsFlyoutStep', () => {
grow={false}
>
<EuiButton
color="accent"
color="primary"
data-test-subj="startIndexReadonlyButton"
disabled={false}
fill={false}

View file

@ -40,6 +40,30 @@ import { IndexClosedParagraph } from '../index_closed_paragraph';
const ML_ANOMALIES_PREFIX = '.ml-anomalies-';
const FollowerIndexCallout = () => (
<>
<EuiCallOut
title={
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.followerIndexTitle"
defaultMessage="Termination of replication is recommended"
/>
}
color="primary"
iconType="iInCircle"
data-test-subj="followerIndexCallout"
>
<p>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.followerIndexText"
defaultMessage="This index is a cross-cluster replication follower index, which should not be reindexed. You can mark it as read-only or terminate the replication and convert it to a standard index."
/>
</p>
</EuiCallOut>
<EuiSpacer size="m" />
</>
);
/**
* Displays a flyout that shows the details / corrective action for a "reindex" deprecation for a given index.
*/
@ -67,7 +91,7 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
const { loadingState, status: reindexStatus, hasRequiredPrivileges, meta } = reindexState;
const { status: updateIndexStatus } = updateIndexState;
const { indexName, isFrozen, isClosedIndex, isReadonly } = meta;
const { indexName, isFrozen, isClosedIndex, isReadonly, isFollowerIndex } = meta;
const loading = loadingState === LoadingState.Loading;
const isCompleted = reindexStatus === ReindexStatus.completed || updateIndexStatus === 'complete';
const hasFetchFailed = reindexStatus === ReindexStatus.fetchFailed;
@ -75,9 +99,10 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
const correctiveAction = deprecation.correctiveAction as ReindexAction | undefined;
const isESTransformTarget = !!correctiveAction?.transformIds?.length;
const isMLAnomalyIndex = Boolean(indexName?.startsWith(ML_ANOMALIES_PREFIX));
const { excludedActions = [] } = (deprecation.correctiveAction as ReindexAction) || {};
const { excludedActions = [], indexSizeInBytes = 0 } =
(deprecation.correctiveAction as ReindexAction) || {};
const readOnlyExcluded = excludedActions.includes('readOnly');
const reindexExcluded = excludedActions.includes('reindex');
const reindexExcluded = excludedActions.includes('reindex') || isFollowerIndex;
const { data: nodes } = api.useLoadNodeDiskSpace();
@ -96,6 +121,13 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
showDefaultGuidance = true;
}
// Determine if the index is larger than 1GB
const isLargeIndex = indexSizeInBytes > 1073741824;
const canShowActionButtons = !isCompleted && !hasFetchFailed && hasRequiredPrivileges;
const canShowReindexButton = canShowActionButtons && !reindexExcluded;
const canShowReadonlyButton = canShowActionButtons && !readOnlyExcluded && !isReadonly;
return (
<Fragment>
<EuiFlyoutBody>
@ -169,18 +201,21 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
{showMlAnomalyReindexingGuidance && <MlAnomalyGuidance />}
{showReadOnlyGuidance && (
<Fragment>
{isFollowerIndex && <FollowerIndexCallout />}
<p>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.readonlyCompatibleIndexText"
defaultMessage="This index was created in ES 7.x. It has been marked as read-only, which enables compatibility with the next major version."
/>
</p>
<p>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexText"
defaultMessage="The reindex operation allows transforming an index into a new, compatible one. It will copy all of the existing documents into a new index and remove the old one. Depending on size and resources, reindexing may take extended time and your data will be in a read-only state until the job has completed."
/>
</p>
{!isFollowerIndex && (
<p>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexText"
defaultMessage="The reindex operation allows transforming an index into a new, compatible one. It will copy all of the existing documents into a new index and remove the old one. Depending on size and resources, reindexing may take extended time and your data will be in a read-only state until the job has completed."
/>
</p>
)}
{isClosedIndex && (
<p>
<IndexClosedParagraph />
@ -190,6 +225,7 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
)}
{showDefaultGuidance && (
<Fragment>
{isFollowerIndex && <FollowerIndexCallout />}
<p>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleIndexText"
@ -206,6 +242,7 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
`/app/management/data/index_management/indices/index_details?indexName=${indexName}`
)}`,
indexBlockUrl: docLinks.links.upgradeAssistant.indexBlocks,
isLargeIndex,
})}
/>
</Fragment>
@ -216,7 +253,12 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
<EuiButtonEmpty
iconType="cross"
onClick={closeFlyout}
flush="left"
data-test-subj="closeReindexButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.closeButtonLabel"
defaultMessage="Close"
@ -225,31 +267,26 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="s">
{!isReadonly &&
!hasFetchFailed &&
!isCompleted &&
hasRequiredPrivileges &&
!isESTransformTarget &&
!readOnlyExcluded && (
<EuiFlexItem grow={false}>
<EuiButton
onClick={startReadonly}
disabled={loading}
color={reindexExcluded ? 'primary' : 'accent'}
fill={reindexExcluded}
data-test-subj="startIndexReadonlyButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton"
defaultMessage="Mark as read-only"
/>
</EuiButton>
</EuiFlexItem>
)}
{!hasFetchFailed && !isCompleted && hasRequiredPrivileges && !reindexExcluded && (
{canShowReadonlyButton && (
<EuiFlexItem grow={false}>
<EuiButton
fill
onClick={startReadonly}
disabled={loading}
color={'primary'}
fill={isLargeIndex || reindexExcluded}
data-test-subj="startIndexReadonlyButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton"
defaultMessage="Mark as read-only"
/>
</EuiButton>
</EuiFlexItem>
)}
{canShowReindexButton && (
<EuiFlexItem grow={false}>
<EuiButton
fill={!isLargeIndex || readOnlyExcluded}
color={reindexStatus === ReindexStatus.cancelled ? 'warning' : 'primary'}
iconType={reindexStatus === ReindexStatus.cancelled ? 'play' : undefined}
onClick={startReindex}

View file

@ -47,6 +47,7 @@ describe('UnfreezeDetailsFlyoutStep', () => {
isInDataStream: false,
isClosedIndex: false,
reindexName: 'some_index-reindexed-for-9',
isFollowerIndex: false,
},
hasRequiredPrivileges: true,
reindexTaskPercComplete: null,

View file

@ -40,6 +40,7 @@ exports[`ReindexStep renders 1`] = `
"aliases": Array [],
"indexName": "myIndex",
"isClosedIndex": false,
"isFollowerIndex": false,
"isFrozen": false,
"isInDataStream": false,
"isReadonly": false,
@ -70,23 +71,28 @@ exports[`ReindexStep renders 1`] = `
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
grow={false}
<EuiFlexGroup
gutterSize="s"
justifyContent="flexEnd"
>
<EuiButton
color="primary"
data-test-subj="startReindexingButton"
disabled={false}
fill={true}
isLoading={false}
onClick={[MockFunction]}
<EuiFlexItem
grow={false}
>
<MemoizedFormattedMessage
defaultMessage="Start reindexing"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel"
/>
</EuiButton>
</EuiFlexItem>
<EuiButton
color="primary"
data-test-subj="startReindexingButton"
disabled={false}
fill={true}
isLoading={false}
onClick={[MockFunction]}
>
<MemoizedFormattedMessage
defaultMessage="Start reindexing"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
</EuiFlyoutFooter>
</Fragment>
@ -133,6 +139,7 @@ exports[`ReindexStep renders for frozen indices 1`] = `
"aliases": Array [],
"indexName": "myIndex",
"isClosedIndex": false,
"isFollowerIndex": false,
"isFrozen": true,
"isInDataStream": false,
"isReadonly": false,
@ -163,23 +170,28 @@ exports[`ReindexStep renders for frozen indices 1`] = `
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
grow={false}
<EuiFlexGroup
gutterSize="s"
justifyContent="flexEnd"
>
<EuiButton
color="primary"
data-test-subj="startReindexingButton"
disabled={false}
fill={true}
isLoading={false}
onClick={[MockFunction]}
<EuiFlexItem
grow={false}
>
<MemoizedFormattedMessage
defaultMessage="Start reindexing"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel"
/>
</EuiButton>
</EuiFlexItem>
<EuiButton
color="primary"
data-test-subj="startReindexingButton"
disabled={false}
fill={true}
isLoading={false}
onClick={[MockFunction]}
>
<MemoizedFormattedMessage
defaultMessage="Start reindexing"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.reindexButton.runReindexLabel"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
</EuiFlyoutFooter>
</Fragment>

View file

@ -32,6 +32,7 @@ describe('ReindexProgress', () => {
isReadonly: false,
isInDataStream: false,
isClosedIndex: false,
isFollowerIndex: false,
},
} as ReindexState
}
@ -101,6 +102,7 @@ describe('ReindexProgress', () => {
"aliases": Array [],
"indexName": "foo",
"isClosedIndex": false,
"isFollowerIndex": false,
"isFrozen": false,
"isInDataStream": false,
"isReadonly": false,
@ -185,6 +187,7 @@ describe('ReindexProgress', () => {
isReadonly: false,
isInDataStream: false,
isClosedIndex: false,
isFollowerIndex: false,
},
} as ReindexState
}

View file

@ -9,7 +9,11 @@ import { shallow } from 'enzyme';
import { cloneDeep } from 'lodash';
import React from 'react';
import { ReindexStatus } from '../../../../../../../../../common/types';
import {
EnrichedDeprecationInfo,
ReindexAction,
ReindexStatus,
} from '../../../../../../../../../common/types';
import { LoadingState } from '../../../../../../types';
import type { ReindexState } from '../../../use_reindex';
import { ReindexFlyoutStep } from './reindex_step';
@ -41,6 +45,7 @@ describe('ReindexStep', () => {
onConfirmInputChange: jest.fn(),
startReindex: jest.fn(),
cancelReindex: jest.fn(),
startReadonly: jest.fn(),
http: {
basePath: {
prepend: jest.fn(),
@ -63,8 +68,21 @@ describe('ReindexStep', () => {
isFrozen: false,
isInDataStream: false,
isClosedIndex: false,
isFollowerIndex: false,
},
} as ReindexState,
deprecation: {
level: 'critical',
resolveDuringUpgrade: false,
type: 'index_settings',
message: 'Index created before 7.0',
details: 'deprecation details',
url: 'doc_url',
index: 'myIndex',
correctiveAction: {
type: 'reindex',
},
} as EnrichedDeprecationInfo,
};
it('renders', () => {
@ -135,4 +153,58 @@ describe('ReindexStep', () => {
wrapper.find('EuiButton').simulate('click');
expect(props.startReindex).toHaveBeenCalled();
});
it('shows read-only button when reindexing fails', () => {
const props = cloneDeep(defaultProps);
props.reindexState.status = ReindexStatus.failed;
props.reindexState.errorMessage = 'Reindex failed';
const wrapper = shallow(<ReindexFlyoutStep {...props} />);
expect(wrapper.find('[data-test-subj="startIndexReadonlyButton"]').exists()).toBe(true);
});
it('only shows read-only button when status is failed', () => {
const statuses = [
ReindexStatus.cancelled,
ReindexStatus.completed,
ReindexStatus.fetchFailed,
ReindexStatus.inProgress,
ReindexStatus.paused,
];
statuses.forEach((status) => {
const props = cloneDeep(defaultProps);
props.reindexState.status = status;
const wrapper = shallow(<ReindexFlyoutStep {...props} />);
expect(wrapper.find('[data-test-subj="startIndexReadonlyButton"]').exists()).toBe(false);
});
});
it('does not show read-only button when the index is already read-only', () => {
const props = cloneDeep(defaultProps);
props.reindexState.status = ReindexStatus.failed;
props.reindexState.errorMessage = 'Reindex failed';
props.reindexState.meta.isReadonly = true;
const wrapper = shallow(<ReindexFlyoutStep {...props} />);
expect(wrapper.find('[data-test-subj="startIndexReadonlyButton"]').exists()).toBe(false);
});
it('does not show read-only button when read-only is excluded', () => {
const props = {
...defaultProps,
reindexState: {
...defaultProps.reindexState,
status: ReindexStatus.failed,
errorMessage: 'Reindex failed',
},
deprecation: {
...defaultProps.deprecation,
correctiveAction: {
...defaultProps.deprecation.correctiveAction,
excludedActions: ['readOnly'],
} as ReindexAction,
},
};
const wrapper = shallow(<ReindexFlyoutStep {...props} />);
expect(wrapper.find('[data-test-subj="startIndexReadonlyButton"]').exists()).toBe(false);
});
});

View file

@ -22,7 +22,11 @@ import {
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { ReindexStatus } from '../../../../../../../../../common/types';
import {
EnrichedDeprecationInfo,
ReindexAction,
ReindexStatus,
} from '../../../../../../../../../common/types';
import { LoadingState } from '../../../../../../types';
import type { ReindexState } from '../../../use_reindex';
import { ReindexProgress } from './progress';
@ -79,7 +83,9 @@ export const ReindexFlyoutStep: React.FunctionComponent<{
reindexState: ReindexState;
startReindex: () => void;
cancelReindex: () => void;
}> = ({ closeFlyout, reindexState, startReindex, cancelReindex }) => {
startReadonly: () => void;
deprecation: EnrichedDeprecationInfo;
}> = ({ closeFlyout, reindexState, startReindex, cancelReindex, startReadonly, deprecation }) => {
const {
services: {
api,
@ -87,7 +93,7 @@ export const ReindexFlyoutStep: React.FunctionComponent<{
},
} = useAppContext();
const { loadingState, status, hasRequiredPrivileges } = reindexState;
const { loadingState, status, hasRequiredPrivileges, meta } = reindexState;
const loading = loadingState === LoadingState.Loading || status === ReindexStatus.inProgress;
const isCompleted = status === ReindexStatus.completed;
const hasFetchFailed = status === ReindexStatus.fetchFailed;
@ -95,6 +101,16 @@ export const ReindexFlyoutStep: React.FunctionComponent<{
const { data: nodes } = api.useLoadNodeDiskSpace();
const { excludedActions = [] } = (deprecation.correctiveAction as ReindexAction) || {};
const readOnlyExcluded = excludedActions.includes('readOnly');
const canShowReadonlyButton =
!readOnlyExcluded &&
!loading &&
!meta.isReadonly &&
reindexState.status === ReindexStatus.failed;
return (
<Fragment>
<EuiFlyoutBody>
@ -197,21 +213,38 @@ export const ReindexFlyoutStep: React.FunctionComponent<{
/>
</EuiButtonEmpty>
</EuiFlexItem>
{!hasFetchFailed && !isCompleted && hasRequiredPrivileges && (
<EuiFlexItem grow={false}>
<EuiButton
fill
color={status === ReindexStatus.paused ? 'warning' : 'primary'}
iconType={status === ReindexStatus.paused ? 'play' : undefined}
onClick={startReindex}
isLoading={loading}
disabled={loading || !hasRequiredPrivileges}
data-test-subj="startReindexingButton"
>
{buttonLabel(status)}
</EuiButton>
</EuiFlexItem>
)}
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
{canShowReadonlyButton && (
<EuiFlexItem grow={false}>
<EuiButton
onClick={startReadonly}
disabled={!hasRequiredPrivileges}
color={'primary'}
data-test-subj="startIndexReadonlyButton"
>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.reindexStep.startIndexReadonlyButton"
defaultMessage="Mark as read-only"
/>
</EuiButton>
</EuiFlexItem>
)}
{!hasFetchFailed && !isCompleted && hasRequiredPrivileges && (
<EuiFlexItem grow={false}>
<EuiButton
fill
color={status === ReindexStatus.paused ? 'warning' : 'primary'}
iconType={status === ReindexStatus.paused ? 'play' : undefined}
onClick={startReindex}
isLoading={loading}
disabled={loading || !hasRequiredPrivileges}
data-test-subj="startReindexingButton"
>
{buttonLabel(status)}
</EuiButton>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexGroup>
</EuiFlyoutFooter>
</Fragment>

View file

@ -20,6 +20,7 @@ describe('UpdateIndexFlyoutStep', () => {
isReadonly: false,
isClosedIndex: false,
reindexName: 'some_index-reindexed-for-9',
isFollowerIndex: false,
};
const defaultUpdateIndexState: UpdateIndexState = {
@ -42,6 +43,7 @@ describe('UpdateIndexFlyoutStep', () => {
<Fragment>
<EuiFlyoutBody>
<EuiTitle
data-test-subj="updateIndexFlyoutTitle"
size="xs"
>
<h3>
@ -112,6 +114,7 @@ describe('UpdateIndexFlyoutStep', () => {
<Fragment>
<EuiFlyoutBody>
<EuiTitle
data-test-subj="updateIndexFlyoutTitle"
size="xs"
>
<h3>

View file

@ -85,7 +85,7 @@ export const UpdateIndexFlyoutStep: React.FunctionComponent<UpdateIndexFlyoutSte
<Fragment>
<EuiFlyoutBody>
{isFrozen && <FrozenCallOut />}
<EuiTitle size="xs">
<EuiTitle size="xs" data-test-subj="updateIndexFlyoutTitle">
<h3>
{(status === 'inProgress' || status === 'incomplete') && (
<FormattedMessage

View file

@ -44,6 +44,7 @@ describe('WarningFlyoutStep', () => {
isFrozen: false,
isReadonly: false,
isInDataStream: false,
isFollowerIndex: false,
},
};

View file

@ -5,18 +5,22 @@
* 2.0.
*/
import React from 'react';
import React, { useState, ReactNode } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiCheckbox,
EuiCode,
EuiLink,
EuiSpacer,
EuiText,
EuiFlexGroup,
EuiFlexItem,
EuiIconTip,
EuiCheckableCard,
useEuiTheme,
EuiPopover,
EuiButtonIcon,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
import { DocLinksStart } from '@kbn/core/public';
import { IndexWarning, IndexWarningType } from '../../../../../../../../../common/types';
@ -28,52 +32,6 @@ export const hasIndexWarning = (
return Boolean(warnings.find((warning) => warning.warningType === warningType));
};
const WarningCheckbox: React.FunctionComponent<{
isChecked: boolean;
warningId: string;
label: React.ReactNode;
description: React.ReactNode;
documentationUrl?: string;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}> = ({ isChecked, warningId, label, onChange, description, documentationUrl }) => (
<>
<EuiText>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiCheckbox
id={warningId}
label={<strong>{label}</strong>}
checked={isChecked}
onChange={onChange}
/>
</EuiFlexItem>
{documentationUrl !== undefined && (
<EuiFlexItem grow={false}>
<EuiLink href={documentationUrl} target="_blank" external={false}>
<EuiIconTip
content={
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.documentationLinkLabel"
defaultMessage="Documentation"
/>
}
position="right"
type="help"
/>
</EuiLink>
</EuiFlexItem>
)}
</EuiFlexGroup>
<EuiSpacer size="xs" />
{description}
</EuiText>
<EuiSpacer />
</>
);
export interface WarningCheckboxProps {
isChecked: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
@ -82,6 +40,61 @@ export interface WarningCheckboxProps {
meta?: IndexWarning['meta'];
}
// Base component for all warning checkboxes
const BaseWarningCheckbox: React.FunctionComponent<{
id: string;
isChecked: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
children: ReactNode;
}> = ({ id, isChecked, onChange, children }) => {
return (
<>
<EuiCheckableCard
id={id}
checkableType="checkbox"
checked={isChecked}
onChange={onChange}
label={children}
/>
<EuiSpacer size="m" />
</>
);
};
// Reusable popover component with info button
const InfoPopover: React.FunctionComponent<{
children: ReactNode;
}> = ({ children }) => {
const { euiTheme } = useEuiTheme();
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const onTogglePopover = () => setIsPopoverOpen((isOpen) => !isOpen);
const popoverStyles = css`
margin-top: -${euiTheme.size.xs};
`;
return (
<EuiPopover
button={
<EuiButtonIcon
display="empty"
iconType="iInCircle"
onClick={onTogglePopover}
css={popoverStyles}
/>
}
isOpen={isPopoverOpen}
closePopover={() => setIsPopoverOpen(false)}
anchorPosition="leftCenter"
>
<EuiText size="s" style={{ width: 300 }}>
{children}
</EuiText>
</EuiPopover>
);
};
export const DeprecatedSettingWarningCheckbox: React.FunctionComponent<WarningCheckboxProps> = ({
isChecked,
onChange,
@ -90,70 +103,112 @@ export const DeprecatedSettingWarningCheckbox: React.FunctionComponent<WarningCh
meta,
}) => {
return (
<WarningCheckbox
isChecked={isChecked}
onChange={onChange}
warningId={id}
label={
<BaseWarningCheckbox id={id} isChecked={isChecked} onChange={onChange}>
<FormattedMessage
tagName="b"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.deprecatedIndexSettingsWarningTitle"
defaultMessage="Remove deprecated index settings"
/>
<EuiSpacer size="m" />
<EuiText size="s">
<ul>
{(meta!.deprecatedSettings as string[]).map((setting, index) => {
return (
<li key={`${setting}-${index}`}>
<EuiCode>{setting}</EuiCode>
</li>
);
})}
</ul>
</EuiText>
<EuiSpacer size="m" />
<EuiLink href={docLinks.elasticsearch.indexModules} target="_blank" external>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.deprecatedIndexSettingsWarningTitle"
defaultMessage="Remove deprecated index settings"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.documentationLinkLabel"
defaultMessage="Learn more"
/>
}
description={
<>
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.deprecatedIndexSettingsWarningDetail"
defaultMessage="The following deprecated index settings were detected:"
/>
<EuiSpacer size="xs" />
<ul>
{(meta!.deprecatedSettings as string[]).map((setting, index) => {
return (
<li key={`${setting}-${index}`}>
<EuiCode>{setting}</EuiCode>
</li>
);
})}
</ul>
</>
}
documentationUrl={docLinks.elasticsearch.indexModules}
/>
</EuiLink>
</BaseWarningCheckbox>
);
};
const i18nStrings = {
index: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.indexLabel',
{
defaultMessage: 'Index',
}
),
newIndex: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.newIndexLabel',
{
defaultMessage: 'New index',
}
),
alias: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.aliasLabel',
{
defaultMessage: 'Alias',
}
),
};
export const ReplaceIndexWithAliasWarningCheckbox: React.FunctionComponent<
WarningCheckboxProps
> = ({ isChecked, onChange, docLinks, id, meta }) => {
> = ({ isChecked, onChange, id, meta }) => {
const { euiTheme } = useEuiTheme();
const textStyles = css`
p {
word-break: break-all;
margin-bottom: ${euiTheme.size.s};
&:last-of-type {
margin-bottom: 0;
}
}
`;
return (
<WarningCheckbox
isChecked={isChecked}
onChange={onChange}
warningId={id}
label={
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningTitle"
defaultMessage="Replace {indexName} index with {reindexName} index and create {indexName} index alias"
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
reindexName: <EuiCode>{meta?.reindexName}</EuiCode>,
}}
/>
}
description={
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningDetail"
defaultMessage="You can search {indexName} as before. To delete the data you'll have to delete {reindexName}"
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
reindexName: <EuiCode>{meta?.reindexName}</EuiCode>,
}}
/>
}
/>
<BaseWarningCheckbox id={id} isChecked={isChecked} onChange={onChange}>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<FormattedMessage
tagName="b"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningTitle"
defaultMessage="Replace index and create alias"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<InfoPopover>
<FormattedMessage
tagName="p"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.replaceIndexWithAliasWarningDetail"
defaultMessage="You can search {indexName} as before. To delete the data you'll have to delete {reindexName}"
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
reindexName: <EuiCode>{meta?.reindexName}</EuiCode>,
}}
/>
</InfoPopover>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<EuiText grow={false} size="s" css={textStyles}>
<p>
{i18nStrings.index}: <EuiCode>{meta?.indexName}</EuiCode>
</p>
<p>
{i18nStrings.newIndex}: <EuiCode>{meta?.reindexName}</EuiCode>
</p>
<p>
{i18nStrings.alias}: <EuiCode>{meta?.indexName}</EuiCode>
</p>
</EuiText>
</BaseWarningCheckbox>
);
};
@ -164,28 +219,32 @@ export const MakeIndexReadonlyWarningCheckbox: React.FunctionComponent<WarningCh
meta,
}) => {
return (
<WarningCheckbox
isChecked={isChecked}
onChange={onChange}
warningId={id}
label={
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningTitle"
defaultMessage="Flag {indexName} index as read-only"
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
}}
/>
}
description={
<FormattedMessage
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningDetail"
defaultMessage="You can continue to search and retrieve documents from {indexName}. You will not be able to insert new documents or modify existing ones."
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
}}
/>
}
/>
<BaseWarningCheckbox id={id} isChecked={isChecked} onChange={onChange}>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<FormattedMessage
tagName="b"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningTitle"
defaultMessage="Flag {indexName} index as read-only"
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<InfoPopover>
<FormattedMessage
tagName="p"
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.warningsStep.makeIndexReadonlyWarningDetail"
defaultMessage="You can continue to search and retrieve documents from {indexName}. You will not be able to insert new documents or modify existing ones."
values={{
indexName: <EuiCode>{meta?.indexName}</EuiCode>,
}}
/>
</InfoPopover>
</EuiFlexItem>
</EuiFlexGroup>
</BaseWarningCheckbox>
);
};

View file

@ -67,12 +67,24 @@ const i18nTexts = {
reindexText: i18n.translate('xpack.upgradeAssistant.esDeprecations.indices.reindexLabel', {
defaultMessage: 'Reindex',
}),
reindexFollowerIndexText: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.reindexFollowerIndexLabel',
{
defaultMessage: 'Unfollow leader index',
}
),
reindexTooltipLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.reindexTooltipLabel',
{
defaultMessage: 'Resolve this issue by reindexing into a new, compatible index.',
}
),
reindexFollowerIndexTooltipLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.indices.reindexFollowerIndexTooltipLabel',
{
defaultMessage: 'Resolve this issue by terminating replication.',
}
),
updateText: i18n.translate('xpack.upgradeAssistant.esDeprecations.indices.updateLabel', {
defaultMessage: 'Update',
}),
@ -148,16 +160,19 @@ export const ReindexResolutionCell: React.FunctionComponent = () => {
</EuiFlexGroup>
);
case ReindexStatus.failed:
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type="warning" color="danger" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">{i18nTexts.reindexFailedText}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
);
if (updateIndexState.status !== 'complete') {
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type="warning" color="danger" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">{i18nTexts.reindexFailedText}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
);
}
break;
case ReindexStatus.fetchFailed:
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
@ -209,16 +224,31 @@ export const ReindexResolutionCell: React.FunctionComponent = () => {
</EuiFlexGroup>
</EuiToolTip>
) : reindexState.meta.isReadonly ? (
<EuiToolTip position="top" content={i18nTexts.reindexTooltipLabel}>
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type="indexSettings" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">{i18nTexts.reindexText}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiToolTip>
<>
{reindexState.meta.isFollowerIndex ? (
<EuiToolTip position="top" content={i18nTexts.reindexFollowerIndexTooltipLabel}>
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type="indexSettings" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">{i18nTexts.reindexFollowerIndexText}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiToolTip>
) : (
<EuiToolTip position="top" content={i18nTexts.reindexTooltipLabel}>
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type="indexSettings" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">{i18nTexts.reindexText}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiToolTip>
)}
</>
) : (
<EuiToolTip position="top" content={i18nTexts.updateTooltipLabel}>
<EuiFlexGroup gutterSize="s" alignItems="center">

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRowCell, EuiTableRow } from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import { EnrichedDeprecationInfo } from '../../../../../../common/types';
import { GlobalFlyout } from '../../../../../shared_imports';
@ -27,11 +27,13 @@ const { useGlobalFlyout } = GlobalFlyout;
interface TableRowProps {
deprecation: EnrichedDeprecationInfo;
rowFieldNames: DeprecationTableColumns[];
index: number;
}
const IndexTableRowCells: React.FunctionComponent<TableRowProps> = ({
rowFieldNames,
deprecation,
index,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const indexContext = useIndexContext();
@ -71,7 +73,11 @@ const IndexTableRowCells: React.FunctionComponent<TableRowProps> = ({
}, [showFlyout]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${index}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field: DeprecationTableColumns) => {
return (
<EuiTableRowCell
@ -81,14 +87,13 @@ const IndexTableRowCells: React.FunctionComponent<TableRowProps> = ({
>
<EsDeprecationsTableCells
fieldName={field}
openFlyout={() => setShowFlyout(true)}
deprecation={deprecation}
resolutionTableCell={<ReindexResolutionCell />}
/>
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -16,7 +16,7 @@ import {
import { CancelLoadingState, LoadingState } from '../../../types';
import { ApiService } from '../../../../lib/api';
const POLL_INTERVAL = 1000;
const POLL_INTERVAL = 3000;
export interface ReindexState {
loadingState: LoadingState;
@ -35,6 +35,7 @@ export interface ReindexState {
isReadonly: boolean;
isInDataStream: boolean;
isClosedIndex: boolean;
isFollowerIndex: boolean;
};
}
@ -136,6 +137,7 @@ export const useReindex = ({
isInDataStream,
isClosedIndex,
isReadonly: false, // we don't have this information in the deprecation list
isFollowerIndex: false, // will be updated after fetching the reindexStatus
},
});

View file

@ -187,7 +187,7 @@ export const FixSnapshotsFlyout = ({
return (
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.isCritical} isResolved={isResolved} />
<DeprecationBadge level={deprecation.level} isResolved={isResolved} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="mlSnapshotDetailsFlyoutTitle">{i18nTexts.flyoutTitle}</h2>

View file

@ -6,7 +6,7 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import { EuiTableRowCell } from '@elastic/eui';
import { EuiTableRow, EuiTableRowCell } from '@elastic/eui';
import { EnrichedDeprecationInfo, MlAction } from '../../../../../../common/types';
import { GlobalFlyout } from '../../../../../shared_imports';
import { useAppContext } from '../../../../app_context';
@ -22,11 +22,13 @@ interface TableRowProps {
deprecation: EnrichedDeprecationInfo;
rowFieldNames: DeprecationTableColumns[];
mlUpgradeModeEnabled: boolean;
index: number;
}
export const MlSnapshotsTableRowCells: React.FunctionComponent<TableRowProps> = ({
rowFieldNames,
deprecation,
index,
}) => {
const [showFlyout, setShowFlyout] = useState(false);
const snapshotState = useMlSnapshotContext();
@ -60,20 +62,23 @@ export const MlSnapshotsTableRowCells: React.FunctionComponent<TableRowProps> =
}, [snapshotState, addContentToGlobalFlyout, showFlyout, deprecation, closeFlyout]);
return (
<>
<EuiTableRow
data-test-subj="deprecationTableRow"
key={`deprecation-row-${index}`}
onClick={() => setShowFlyout(true)}
>
{rowFieldNames.map((field: DeprecationTableColumns) => {
return (
<EuiTableRowCell key={field} truncateText={false} data-test-subj={`mlTableCell-${field}`}>
<EsDeprecationsTableCells
fieldName={field}
openFlyout={() => setShowFlyout(true)}
deprecation={deprecation}
resolutionTableCell={<MlSnapshotsResolutionCell />}
/>
</EuiTableRowCell>
);
})}
</>
</EuiTableRow>
);
};

View file

@ -27,7 +27,7 @@ const getDeprecationCountByLevel = (deprecations: EnrichedDeprecationInfo[]) =>
const warningDeprecations: EnrichedDeprecationInfo[] = [];
deprecations.forEach((deprecation) => {
if (deprecation.isCritical) {
if (deprecation.level === 'critical') {
criticalDeprecations.push(deprecation);
return;
}

View file

@ -55,10 +55,10 @@ const i18nTexts = {
typeFilterLabel: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.typeFilterLabel', {
defaultMessage: 'Type',
}),
criticalFilterLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.table.criticalFilterLabel',
statusFilterLabel: i18n.translate(
'xpack.upgradeAssistant.esDeprecations.table.statusFilterLabel',
{
defaultMessage: 'Critical',
defaultMessage: 'Status',
}
),
searchPlaceholderLabel: i18n.translate(
@ -70,7 +70,7 @@ const i18nTexts = {
};
const cellToLabelMap = {
isCritical: {
level: {
label: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.statusColumnTitle', {
defaultMessage: 'Status',
}),
@ -105,9 +105,10 @@ const cellToLabelMap = {
const cellTypes = Object.keys(cellToLabelMap) as DeprecationTableColumns[];
const pageSizeOptions = PAGINATION_CONFIG.pageSizeOptions;
const renderTableRowCells = (
const renderTableRow = (
deprecation: EnrichedDeprecationInfo,
mlUpgradeModeEnabled: boolean
mlUpgradeModeEnabled: boolean,
index: number
) => {
switch (deprecation.correctiveAction?.type) {
case 'mlSnapshot':
@ -116,27 +117,44 @@ const renderTableRowCells = (
deprecation={deprecation}
rowFieldNames={cellTypes}
mlUpgradeModeEnabled={mlUpgradeModeEnabled}
index={index}
/>
);
case 'indexSetting':
return <IndexSettingsTableRow deprecation={deprecation} rowFieldNames={cellTypes} />;
return (
<IndexSettingsTableRow deprecation={deprecation} rowFieldNames={cellTypes} index={index} />
);
case 'clusterSetting':
return <ClusterSettingsTableRow deprecation={deprecation} rowFieldNames={cellTypes} />;
return (
<ClusterSettingsTableRow
deprecation={deprecation}
rowFieldNames={cellTypes}
index={index}
/>
);
case 'reindex':
case 'unfreeze':
return <IndexTableRow deprecation={deprecation} rowFieldNames={cellTypes} />;
return <IndexTableRow deprecation={deprecation} rowFieldNames={cellTypes} index={index} />;
case 'healthIndicator':
return <HealthIndicatorTableRow deprecation={deprecation} rowFieldNames={cellTypes} />;
return (
<HealthIndicatorTableRow
deprecation={deprecation}
rowFieldNames={cellTypes}
index={index}
/>
);
case 'dataStream':
return <DataStreamTableRow deprecation={deprecation} rowFieldNames={cellTypes} />;
return (
<DataStreamTableRow deprecation={deprecation} rowFieldNames={cellTypes} index={index} />
);
default:
return <DefaultTableRow deprecation={deprecation} rowFieldNames={cellTypes} />;
return <DefaultTableRow deprecation={deprecation} rowFieldNames={cellTypes} index={index} />;
}
};
@ -154,9 +172,9 @@ const getSortedItems = (deprecations: EnrichedDeprecationInfo[], sortConfig: Sor
const { isSortAscending, sortField } = sortConfig;
const sorted = sortBy(deprecations, [
(deprecation) => {
if (sortField === 'isCritical') {
// Critical deprecations should take precendence in ascending order
return deprecation.isCritical !== true;
if (sortField === 'level') {
// Critical deprecations should take precedence in ascending order
return deprecation.level === 'critical' ? 0 : 1;
}
return deprecation[sortField];
},
@ -165,6 +183,21 @@ const getSortedItems = (deprecations: EnrichedDeprecationInfo[], sortConfig: Sor
return isSortAscending ? sorted : sorted.reverse();
};
const statusFilterOptions = [
{
value: 'critical',
name: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.filter.critical', {
defaultMessage: 'Critical',
}),
},
{
value: 'warning',
name: i18n.translate('xpack.upgradeAssistant.esDeprecations.table.filter.warning', {
defaultMessage: 'Warning',
}),
},
];
export const EsDeprecationsTable: React.FunctionComponent<Props> = ({
deprecations = [],
reload,
@ -177,7 +210,7 @@ export const EsDeprecationsTable: React.FunctionComponent<Props> = ({
const [sortConfig, setSortConfig] = useState<SortConfig>({
isSortAscending: true,
sortField: 'isCritical',
sortField: 'level',
});
const [itemsPerPage, setItemsPerPage] = useState(PAGINATION_CONFIG.initialPageSize);
@ -244,9 +277,11 @@ export const EsDeprecationsTable: React.FunctionComponent<Props> = ({
}}
filters={[
{
type: 'is',
field: 'isCritical',
name: i18nTexts.criticalFilterLabel,
type: 'field_value_selection',
field: 'level',
name: i18nTexts.statusFilterLabel,
multiSelect: false,
options: statusFilterOptions,
},
{
type: 'field_value_selection',
@ -321,13 +356,9 @@ export const EsDeprecationsTable: React.FunctionComponent<Props> = ({
</EuiTableBody>
) : (
<EuiTableBody>
{visibleDeprecations.map((deprecation, index) => {
return (
<EuiTableRow data-test-subj="deprecationTableRow" key={`deprecation-row-${index}`}>
{renderTableRowCells(deprecation, mlUpgradeModeEnabled)}
</EuiTableRow>
);
})}
{visibleDeprecations.map((deprecation, index) =>
renderTableRow(deprecation, mlUpgradeModeEnabled, index)
)}
</EuiTableBody>
)}
</EuiTable>

View file

@ -17,7 +17,6 @@ interface Props {
resolutionTableCell?: React.ReactNode;
fieldName: DeprecationTableColumns;
deprecation: EnrichedDeprecationInfo;
openFlyout: () => void;
}
const i18nTexts = {
@ -39,20 +38,16 @@ export const EsDeprecationsTableCells: React.FunctionComponent<Props> = ({
resolutionTableCell,
fieldName,
deprecation,
openFlyout,
}) => {
// "Status column"
if (fieldName === 'isCritical') {
return <DeprecationBadge isCritical={deprecation.isCritical} />;
if (fieldName === 'level') {
return <DeprecationBadge level={deprecation.level} />;
}
// "Issue" column
if (fieldName === 'message') {
return (
<EuiLink
data-test-subj={`deprecation-${deprecation.correctiveAction?.type ?? 'default'}`}
onClick={openFlyout}
>
<EuiLink data-test-subj={`deprecation-${deprecation.correctiveAction?.type ?? 'default'}`}>
{deprecation.message}
</EuiLink>
);

View file

@ -7,5 +7,4 @@
export { KibanaDeprecations } from './kibana_deprecations';
export { EsDeprecations } from './es_deprecations';
export { EsDeprecationLogs } from './es_deprecation_logs';
export { Overview } from './overview';

View file

@ -1,4 +0,0 @@
// Used to add spacing between the list of manual deprecation steps
.upgResolveStep {
margin-bottom: $euiSizeL;
}

View file

@ -8,6 +8,7 @@
import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react';
import { METRIC_TYPE } from '@kbn/analytics';
import {
@ -25,14 +26,13 @@ import {
EuiMarkdownFormat,
getDefaultEuiMarkdownPlugins,
useEuiFontSize,
useEuiTheme,
} from '@elastic/eui';
import { uiMetricService, UIM_KIBANA_QUICK_RESOLVE_CLICK } from '../../lib/ui_metric';
import { DeprecationFlyoutLearnMoreLink, DeprecationBadge } from '../shared';
import type { DeprecationResolutionState, KibanaDeprecationDetails } from './kibana_deprecations';
import './_deprecation_details_flyout.scss';
export interface DeprecationDetailsFlyoutProps {
deprecation: KibanaDeprecationDetails;
closeFlyout: () => void;
@ -168,11 +168,12 @@ export const DeprecationDetailsFlyout = ({
}, [deprecation, resolveDeprecation]);
const { lineHeight: lineHeightMedium } = useEuiFontSize('m');
const { euiTheme } = useEuiTheme();
return (
<>
<EuiFlyoutHeader hasBorder>
<DeprecationBadge isCritical={deprecation.level === 'critical'} isResolved={isResolved} />
<DeprecationBadge level={deprecation.level} isResolved={isResolved} />
<EuiSpacer size="s" />
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2 id="kibanaDeprecationDetailsFlyoutTitle" className="eui-textBreakWord">
@ -262,7 +263,10 @@ export const DeprecationDetailsFlyout = ({
<li
data-test-subj="manualStepsListItem"
key={`step-${stepIndex}`}
className="upgResolveStep eui-textBreakWord"
className="eui-textBreakWord"
css={css`
margin-bottom: ${euiTheme.size.l};
`}
>
{step}
</li>

View file

@ -74,12 +74,24 @@ const i18nTexts = {
defaultMessage: 'Type',
}
),
statusFilterLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.statusFilterLabel',
{
defaultMessage: 'Status',
}
),
criticalFilterLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.criticalFilterLabel',
{
defaultMessage: 'Critical',
}
),
warningFilterLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.warningFilterLabel',
{
defaultMessage: 'Warning',
}
),
searchPlaceholderLabel: i18n.translate(
'xpack.upgradeAssistant.kibanaDeprecations.table.searchPlaceholderLabel',
{
@ -109,7 +121,7 @@ export const KibanaDeprecationsTable: React.FunctionComponent<Props> = ({
truncateText: true,
sortable: true,
render: (level: KibanaDeprecationDetails['level']) => {
return <DeprecationBadge isCritical={level === 'critical'} />;
return <DeprecationBadge level={level} />;
},
},
{
@ -181,10 +193,20 @@ export const KibanaDeprecationsTable: React.FunctionComponent<Props> = ({
const searchConfig: Search = {
filters: [
{
type: 'field_value_toggle',
name: i18nTexts.criticalFilterLabel,
type: 'field_value_selection',
field: 'level',
value: 'critical',
name: i18nTexts.statusFilterLabel,
multiSelect: false,
options: [
{
value: 'critical',
name: i18nTexts.criticalFilterLabel,
},
{
value: 'warning',
name: i18nTexts.warningFilterLabel,
},
],
},
{
type: 'field_value_selection',
@ -235,8 +257,11 @@ export const KibanaDeprecationsTable: React.FunctionComponent<Props> = ({
search={searchConfig}
sorting={sorting}
pagination={PAGINATION_CONFIG}
rowProps={() => ({
rowProps={(deprecation) => ({
'data-test-subj': 'row',
onClick: () => {
toggleFlyout(deprecation);
},
})}
cellProps={(deprecation, field) => ({
'data-test-subj': `${((field?.name as string) || 'table').toLowerCase()}Cell`,

View file

@ -1,24 +0,0 @@
/**
* Push <NoDeprecationIssues isPartial={false} /> success state to the bottom
* of the card, so it aligns with <NoDeprecationIssues isPartial={true} />,
* which is inside EuiStat.
*/
.upgDeprecationIssuesPanel .euiCard__content {
display: flex;
flex-direction: column;
justify-content: space-between;
}
/**
* Ensure the stat is a consistent height, even when it contains
* <NoDeprecationIssues isPartial={true} />, which is shorter than the
* standard number value. We also push it to the bottom of the its
* container, to base-align it with the number value.
*/
.upgDeprecationIssuesPanel__stat {
height: 60px; // Derived from font measurements, not sizing vars
justify-content: space-between;
flex-grow: 1;
flex-direction: column;
display: flex;
}

View file

@ -0,0 +1,35 @@
/*
* 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 from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon } from '@elastic/eui';
interface Props {
type: string;
color: string;
iconType: string;
message: React.ReactNode;
}
export const DeprecationIssue = (props: Props) => {
const { type, color, iconType, message } = props;
return (
<EuiFlexItem data-test-subj={`${type}Deprecations`}>
<EuiText color={color}>
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type={iconType} />
</EuiFlexItem>
<EuiFlexItem grow={false} alignItems="center">
<EuiFlexGroup gutterSize="s" alignItems="center">
{message}
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>
</EuiFlexItem>
);
};

View file

@ -7,31 +7,15 @@
import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { EuiCard, EuiStat, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EuiCard, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { reactRouterNavigate } from '../../../../../shared_imports';
import { DeprecationSource } from '../../../../../../common/types';
import { getDeprecationsUpperLimit } from '../../../../lib/utils';
import { LoadingIssuesError } from './loading_issues_error';
import { NoDeprecationIssues } from './no_deprecation_issues';
import './_deprecation_issues_panel.scss';
const i18nTexts = {
warningDeprecationsTitle: i18n.translate(
'xpack.upgradeAssistant.deprecationStats.warningDeprecationsTitle',
{
defaultMessage: 'Warning',
}
),
criticalDeprecationsTitle: i18n.translate(
'xpack.upgradeAssistant.deprecationStats.criticalDeprecationsTitle',
{
defaultMessage: 'Critical',
}
),
};
import { DeprecationIssue } from './deprecation_issues';
interface Props {
'data-test-subj': string;
@ -70,8 +54,9 @@ export const DeprecationIssuesPanel = (props: Props) => {
return (
<EuiCard
data-test-subj={props['data-test-subj']}
className="upgDeprecationIssuesPanel"
layout="horizontal"
display="plain"
hasBorder
title={deprecationSource}
titleSize="xs"
{...(!hasNoIssues && reactRouterNavigate(history, linkUrl))}
@ -84,50 +69,49 @@ export const DeprecationIssuesPanel = (props: Props) => {
<NoDeprecationIssues data-test-subj="noDeprecationIssues" />
) : (
<EuiFlexGroup>
<EuiFlexItem>
<EuiStat
data-test-subj="criticalDeprecations"
className="upgDeprecationIssuesPanel__stat"
title={
hasError ? (
'--'
) : hasCriticalIssues ? (
getDeprecationsUpperLimit(criticalDeprecationsCount)
) : (
<NoDeprecationIssues
isPartial={true}
data-test-subj="noCriticalDeprecationIssues"
/>
)
{isLoading && (
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="m" />
</EuiFlexItem>
)}
{hasCriticalIssues && (
<DeprecationIssue
type="critical"
color="danger"
iconType="errorFilled"
message={
<FormattedMessage
id="xpack.upgradeAssistant.deprecationStats.criticalDeprecationsTitle"
defaultMessage="{errorCountValue} {criticalDeprecationsCount, plural, one {Error} other {Errors}}"
values={{
criticalDeprecationsCount,
errorCountValue: (
<strong>{getDeprecationsUpperLimit(criticalDeprecationsCount)}</strong>
),
}}
/>
}
titleElement="span"
description={i18nTexts.criticalDeprecationsTitle}
titleColor="danger"
isLoading={isLoading}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
data-test-subj="warningDeprecations"
className="upgDeprecationIssuesPanel__stat"
title={
hasError ? (
'--'
) : hasWarningIssues ? (
getDeprecationsUpperLimit(warningDeprecationsCount)
) : (
<NoDeprecationIssues
isPartial={true}
data-test-subj="noWarningDeprecationIssues"
/>
)
)}
{hasWarningIssues && (
<DeprecationIssue
type="warning"
color="warning"
iconType="warningFilled"
message={
<FormattedMessage
id="xpack.upgradeAssistant.deprecationStats.warningDeprecationsTitle"
defaultMessage="{warningCountValue} {warningDeprecationsCount, plural, one {Warning} other {Warnings}}"
values={{
warningDeprecationsCount,
warningCountValue: (
<strong>{getDeprecationsUpperLimit(warningDeprecationsCount)}</strong>
),
}}
/>
}
titleElement="span"
description={i18nTexts.warningDeprecationsTitle}
isLoading={isLoading}
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
)}
</EuiCard>

View file

@ -23,12 +23,13 @@ export const EsDeprecationIssuesPanel: FunctionComponent<Props> = ({ setIsFixed
const { data: esDeprecations, isLoading, error } = api.useLoadEsDeprecations();
const criticalDeprecationsCount =
esDeprecations?.migrationsDeprecations?.filter((deprecation) => deprecation.isCritical)
?.length ?? 0;
esDeprecations?.migrationsDeprecations?.filter(
(deprecation) => deprecation.level === 'critical'
)?.length ?? 0;
const warningDeprecationsCount =
esDeprecations?.migrationsDeprecations?.filter(
(deprecation) => deprecation.isCritical === false
(deprecation) => deprecation.level !== 'critical'
)?.length ?? 0;
const errorMessage = error && getEsDeprecationError(error).message;

View file

@ -10,34 +10,25 @@ import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
const i18nTexts = {
noPartialDeprecationIssuesText: i18n.translate(
'xpack.upgradeAssistant.noPartialDeprecationsMessage',
{
defaultMessage: 'None',
}
),
noDeprecationIssuesText: i18n.translate('xpack.upgradeAssistant.noDeprecationsMessage', {
defaultMessage: 'No issues',
}),
};
interface Props {
isPartial?: boolean;
'data-test-subj'?: string;
}
export const NoDeprecationIssues: FunctionComponent<Props> = (props) => {
const { isPartial = false } = props;
return (
<EuiText color="success">
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon type="check" />
<EuiIcon type="checkInCircleFilled" />
</EuiFlexItem>
<EuiFlexItem grow={false} data-test-subj={props['data-test-subj']}>
{isPartial ? i18nTexts.noPartialDeprecationIssuesText : i18nTexts.noDeprecationIssuesText}
{i18nTexts.noDeprecationIssuesText}
</EuiFlexItem>
</EuiFlexGroup>
</EuiText>

View file

@ -7,7 +7,7 @@
import React, { FunctionComponent, useState, useEffect } from 'react';
import { EuiText, EuiFlexItem, EuiFlexGroup, EuiSpacer } from '@elastic/eui';
import { EuiText, EuiFlexGroup, EuiSpacer, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';
@ -38,11 +38,10 @@ const FixIssuesStep: FunctionComponent<Props> = ({ setIsComplete }) => {
return (
<EuiFlexGroup>
<EuiFlexItem>
<EuiFlexItem grow={false} style={{ width: 350 }}>
<EsDeprecationIssuesPanel setIsFixed={setIsEsFixed} />
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexItem grow={false} style={{ width: 350 }}>
<KibanaDeprecationIssuesPanel setIsFixed={setIsKibanaFixed} />
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -5,9 +5,17 @@
* 2.0.
*/
import React, { useEffect } from 'react';
import React, { useEffect, useState, useCallback } from 'react';
import { EuiText, EuiSpacer, EuiButton, EuiCallOut, EuiSkeletonText, EuiCode } from '@elastic/eui';
import {
EuiText,
EuiSpacer,
EuiButton,
EuiCallOut,
EuiSkeletonText,
EuiCode,
EuiFlexGroup,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n-react';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';
@ -17,11 +25,16 @@ import {
APP_LOGS_COUNT_CLUSTER_PRIVILEGES,
APP_LOGS_COUNT_INDEX_PRIVILEGES,
} from '../../../../../common/constants';
import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports';
import { WithPrivileges, MissingPrivileges, GlobalFlyout } from '../../../../shared_imports';
import { useAppContext } from '../../../app_context';
import { loadLogsCheckpoint } from '../../../lib/logs_checkpoint';
import type { OverviewStepProps } from '../../types';
import { useDeprecationLogging } from '../../es_deprecation_logs';
import { DiscoverExternalLinks } from '../../es_deprecation_logs/fix_deprecation_logs/external_links';
import {
EsDeprecationLogsFlyout,
EsDeprecationLogsFlyoutProps,
} from '../../es_deprecation_logs/fix_deprecation_logs/es_deprecation_logs_flyout';
const i18nTexts = {
logsStepTitle: i18n.translate('xpack.upgradeAssistant.overview.logsStep.title', {
@ -30,10 +43,10 @@ const i18nTexts = {
logsStepDescription: i18n.translate('xpack.upgradeAssistant.overview.logsStep.description', {
defaultMessage: `Review the Elasticsearch deprecation logs to ensure you're not using deprecated APIs.`,
}),
viewLogsButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel',
viewDetailsButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.logsStep.viewDetailsButtonLabel',
{
defaultMessage: 'View logs',
defaultMessage: 'View details',
}
),
enableLogsButtonLabel: i18n.translate(
@ -101,11 +114,13 @@ const i18nTexts = {
}),
};
const FLYOUT_ID = 'deprecationLogsFlyout';
const { useGlobalFlyout } = GlobalFlyout;
interface LogStepProps {
setIsComplete: (isComplete: boolean) => void;
hasPrivileges: boolean;
privilegesMissing: MissingPrivileges;
navigateToEsDeprecationLogs: () => void;
}
const LogStepDescription = () => (
@ -114,17 +129,13 @@ const LogStepDescription = () => (
</EuiText>
);
const LogsStep = ({
setIsComplete,
hasPrivileges,
privilegesMissing,
navigateToEsDeprecationLogs,
}: LogStepProps) => {
const LogsStep = ({ setIsComplete, hasPrivileges, privilegesMissing }: LogStepProps) => {
const {
services: { api },
} = useAppContext();
const { isDeprecationLogIndexingEnabled } = useDeprecationLogging();
const { isDeprecationLogIndexingEnabled, resendRequest: refreshDeprecationLogging } =
useDeprecationLogging();
const checkpoint = loadLogsCheckpoint();
@ -147,6 +158,38 @@ const LogsStep = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDeprecationLogIndexingEnabled, logsCount]);
const [showFlyout, setShowFlyout] = useState(false);
const { addContent: addContentToGlobalFlyout, removeContent: removeContentFromGlobalFlyout } =
useGlobalFlyout();
const closeFlyout = useCallback(() => {
setShowFlyout(false);
removeContentFromGlobalFlyout(FLYOUT_ID);
}, [removeContentFromGlobalFlyout]);
const handleToggleChange = useCallback(() => {
refreshDeprecationLogging();
}, [refreshDeprecationLogging]);
useEffect(() => {
if (showFlyout) {
addContentToGlobalFlyout<EsDeprecationLogsFlyoutProps>({
id: FLYOUT_ID,
Component: EsDeprecationLogsFlyout,
props: {
closeFlyout,
handleToggleChange,
},
flyoutProps: {
onClose: closeFlyout,
'data-test-subj': 'esDeprecationLogsFlyout',
'aria-labelledby': 'esDeprecationLogsFlyoutTitle',
},
});
}
}, [addContentToGlobalFlyout, closeFlyout, handleToggleChange, showFlyout]);
if (hasPrivileges === false && isDeprecationLogIndexingEnabled) {
return (
<>
@ -223,16 +266,22 @@ const LogsStep = ({
</EuiText>
<EuiSpacer />
<EuiButton onClick={navigateToEsDeprecationLogs} data-test-subj="viewLogsLink">
{i18nTexts.viewLogsButtonLabel}
</EuiButton>
<EuiFlexGroup responsive={false} wrap gutterSize="s" alignItems="center">
<DiscoverExternalLinks
checkpoint={checkpoint}
showInfoParagraph={false}
isButtonFormat={true}
/>
<EuiButton onClick={() => setShowFlyout(true)} data-test-subj="viewDetailsLink">
{i18nTexts.viewDetailsButtonLabel}
</EuiButton>
</EuiFlexGroup>
</>
) : (
<>
<EuiSpacer />
<EuiButton onClick={navigateToEsDeprecationLogs} data-test-subj="enableLogsLink">
<EuiButton onClick={() => setShowFlyout(true)} data-test-subj="enableLogsLink">
{i18nTexts.enableLogsButtonLabel}
</EuiButton>
</>
@ -242,15 +291,7 @@ const LogsStep = ({
);
};
interface CustomProps {
navigateToEsDeprecationLogs: () => void;
}
export const getLogsStep = ({
isComplete,
setIsComplete,
navigateToEsDeprecationLogs,
}: OverviewStepProps & CustomProps): EuiStepProps => {
export const getLogsStep = ({ isComplete, setIsComplete }: OverviewStepProps): EuiStepProps => {
const status = isComplete ? 'complete' : 'incomplete';
const requiredPrivileges = [
@ -268,7 +309,6 @@ export const getLogsStep = ({
<LogsStep
setIsComplete={setIsComplete}
hasPrivileges={!isLoading && hasPrivileges}
navigateToEsDeprecationLogs={navigateToEsDeprecationLogs}
privilegesMissing={privilegesMissing}
/>
)}

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import React from 'react';
import React, { useState, ReactNode } from 'react';
import { startCase } from 'lodash';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import {
EuiButtonEmpty,
EuiFlexGroup,
@ -22,6 +22,11 @@ import {
EuiIcon,
EuiSpacer,
EuiInMemoryTable,
EuiButtonIcon,
EuiDescriptionList,
EuiScreenReaderOnly,
EuiBasicTableColumn,
EuiCallOut,
} from '@elastic/eui';
import {
@ -29,10 +34,15 @@ import {
SystemIndicesMigrationFeature,
MIGRATION_STATUS,
} from '../../../../../common/types';
import { MigrateSystemIndicesButton } from './migrate_button';
export interface SystemIndicesFlyoutProps {
closeFlyout: () => void;
data: SystemIndicesMigrationStatus;
beginSystemIndicesMigration: () => void;
isInitialRequest: boolean;
isLoading: boolean;
migrationStatus?: MIGRATION_STATUS;
}
const i18nTexts = {
@ -82,6 +92,33 @@ const i18nTexts = {
defaultMessage: 'Status',
}
),
errorTooltipLabel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.errorTooltipLabel',
{
defaultMessage: 'Migration failed for the following indices: ',
}
),
unknownErrorLabel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.unknownErrorLabel',
{
defaultMessage: 'Unknown error',
}
),
migrationNotNeeded: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.migrationNotNeeded',
{
defaultMessage: 'Systems indices migration not needed',
}
),
};
const getFailedIndices = (feature: SystemIndicesMigrationFeature) => {
return feature.indices
.filter((index) => index.failure_cause && index.failure_cause.error)
.map((index) => ({
index: index.index,
reason: index?.failure_cause?.error.type,
}));
};
const renderMigrationStatus = (status: MIGRATION_STATUS) => {
@ -138,46 +175,111 @@ const renderMigrationStatus = (status: MIGRATION_STATUS) => {
);
}
return '';
return null;
};
const columns = [
{
field: 'feature_name',
name: i18nTexts.featureNameTableColumn,
sortable: true,
truncateText: true,
render: (name: string) => startCase(name),
},
{
field: 'migration_status',
name: i18nTexts.statusTableColumn,
sortable: true,
render: renderMigrationStatus,
},
];
export const SystemIndicesFlyout = ({
closeFlyout,
data,
beginSystemIndicesMigration,
isInitialRequest,
isLoading,
migrationStatus,
}: SystemIndicesFlyoutProps) => {
const [expandedRows, setExpandedRows] = useState<Record<string, ReactNode>>({});
const toggleRow = (feature: SystemIndicesMigrationFeature) => {
setExpandedRows((prev) => {
const newRows = { ...prev };
if (newRows[feature.feature_name]) {
delete newRows[feature.feature_name];
} else {
const failedIndices = getFailedIndices(feature);
const errorDetails = failedIndices.map(({ index, reason }) => ({
title: index,
description: reason || i18nTexts.unknownErrorLabel,
}));
newRows[feature.feature_name] = <EuiDescriptionList listItems={errorDetails} />;
}
return newRows;
});
};
const columns = [
{
field: 'feature_name',
name: i18nTexts.featureNameTableColumn,
sortable: true,
truncateText: true,
render: (name: string) => startCase(name),
},
{
field: 'migration_status',
name: i18nTexts.statusTableColumn,
sortable: true,
render: renderMigrationStatus,
},
{
align: 'right',
width: '40px',
isExpander: true,
name: (
<EuiScreenReaderOnly>
<span>
<FormattedMessage
id="xpack.upgradeAssistant.overview.systemIndices.expandRow"
defaultMessage="Expand row"
/>
</span>
</EuiScreenReaderOnly>
),
render: (feature: SystemIndicesMigrationFeature) => {
return feature.migration_status === 'ERROR' ? (
<EuiButtonIcon
onClick={() => toggleRow(feature)}
aria-label={expandedRows[feature.feature_name] ? 'Collapse' : 'Expand'}
iconType={expandedRows[feature.feature_name] ? 'arrowDown' : 'arrowRight'}
/>
) : null;
},
},
] as Array<EuiBasicTableColumn<SystemIndicesMigrationFeature>>;
export const SystemIndicesFlyout = ({ closeFlyout, data }: SystemIndicesFlyoutProps) => {
return (
<>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="s" data-test-subj="flyoutTitle">
<h2>{i18nTexts.flyoutTitle}</h2>
<h2 id="migrateSystemIndicesFlyoutTitle">{i18nTexts.flyoutTitle}</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody data-test-subj="flyoutDetails">
<EuiText>
<p>{i18nTexts.flyoutDescription}</p>
</EuiText>
<EuiSpacer size="l" />
<EuiInMemoryTable<SystemIndicesMigrationFeature>
data-test-subj="featuresTable"
itemId="feature_name"
items={data.features}
columns={columns}
pagination={true}
sorting={true}
/>
{migrationStatus === 'NO_MIGRATION_NEEDED' && (
<EuiCallOut
title={i18nTexts.migrationNotNeeded}
iconType="cheer"
color="success"
data-test-subj="noMigrationNeededCallout"
/>
)}
{migrationStatus !== 'NO_MIGRATION_NEEDED' && (
<>
<EuiText>
<p>{i18nTexts.flyoutDescription}</p>
</EuiText>
<EuiSpacer size="l" />
<EuiInMemoryTable<SystemIndicesMigrationFeature>
data-test-subj="featuresTable"
itemId="feature_name"
items={data.features}
columns={columns}
itemIdToExpandedRowMap={expandedRows}
pagination={true}
sorting={true}
/>
</>
)}
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
@ -186,6 +288,18 @@ export const SystemIndicesFlyout = ({ closeFlyout, data }: SystemIndicesFlyoutPr
{i18nTexts.closeButtonLabel}
</EuiButtonEmpty>
</EuiFlexItem>
{migrationStatus !== 'NO_MIGRATION_NEEDED' && (
<EuiFlexItem grow={false}>
<MigrateSystemIndicesButton
buttonProps={{ fill: true }}
beginSystemIndicesMigration={beginSystemIndicesMigration}
isInitialRequest={isInitialRequest}
isLoading={isLoading}
isMigrating={migrationStatus === 'IN_PROGRESS'}
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlyoutFooter>
</>

View file

@ -0,0 +1,99 @@
/*
* 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, { useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButton, EuiConfirmModal, EuiButtonProps } from '@elastic/eui';
const i18nTexts = {
inProgressButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.inProgressButtonLabel',
{
defaultMessage: 'Migration in progress',
}
),
startButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.startButtonLabel',
{
defaultMessage: 'Migrate indices',
}
),
modalTitle: i18n.translate('xpack.upgradeAssistant.overview.systemIndices.confirmModal.title', {
defaultMessage: 'Migrate Indices',
}),
modalButtonCancel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.confirmModal.cancelButton.label',
{
defaultMessage: 'Cancel',
}
),
modalButtonConfirm: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.confirmModal.confirmButton.label',
{
defaultMessage: 'Confirm',
}
),
modalButtonDescription: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.confirmModal.description',
{
defaultMessage: 'Migrating system indices may lead to downtime while they are reindexed.',
}
),
};
interface MigrateButtonProps {
buttonProps?: EuiButtonProps;
beginSystemIndicesMigration: () => void;
isInitialRequest: boolean;
isLoading: boolean;
isMigrating: boolean;
}
export const MigrateSystemIndicesButton = ({
buttonProps,
beginSystemIndicesMigration,
isInitialRequest,
isLoading,
isMigrating,
}: MigrateButtonProps) => {
const [isModalVisible, setIsModalVisible] = useState(false);
const isButtonDisabled = isInitialRequest && isLoading;
const handleConfirmMigration = () => {
beginSystemIndicesMigration();
setIsModalVisible(false);
};
return (
<>
<EuiButton
{...buttonProps}
isLoading={isMigrating}
isDisabled={isButtonDisabled}
onClick={() => setIsModalVisible(true)}
data-test-subj="startSystemIndicesMigrationButton"
>
{isMigrating ? i18nTexts.inProgressButtonLabel : i18nTexts.startButtonLabel}
</EuiButton>
{isModalVisible && (
<EuiConfirmModal
title={i18nTexts.modalTitle}
onCancel={() => setIsModalVisible(false)}
onConfirm={handleConfirmMigration}
cancelButtonText={i18nTexts.modalButtonCancel}
confirmButtonText={i18nTexts.modalButtonConfirm}
defaultFocusedButton="confirm"
data-test-subj="migrationConfirmModal"
>
{i18nTexts.modalButtonDescription}
</EuiConfirmModal>
)}
</>
);
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { FunctionComponent, useEffect, useState } from 'react';
import React, { FunctionComponent, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
@ -20,7 +20,6 @@ import {
EuiFlexItem,
EuiCode,
EuiLink,
EuiConfirmModal,
} from '@elastic/eui';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';
@ -28,23 +27,55 @@ import { DocLinksStart } from '@kbn/core/public';
import type { SystemIndicesMigrationFeature } from '../../../../../common/types';
import type { OverviewStepProps } from '../../types';
import { useMigrateSystemIndices } from './use_migrate_system_indices';
import { MigrateSystemIndicesButton } from './migrate_button';
interface Props {
setIsComplete: OverviewStepProps['setIsComplete'];
}
const getFailureCause = (features: SystemIndicesMigrationFeature[]) => {
const featureWithError = features.find((feature) => feature.migration_status === 'ERROR');
const getFailureCauses = (features: SystemIndicesMigrationFeature[]) => {
const errorsByFeature: Record<string, { errors: Set<string>; indices: number }> = {};
if (featureWithError) {
const indexWithError = featureWithError.indices.find((index) => index.failure_cause);
return {
feature: featureWithError?.feature_name,
failureCause: indexWithError?.failure_cause?.error.type,
};
}
features.forEach((feature) => {
if (feature.migration_status === 'ERROR') {
feature.indices.forEach((index) => {
if (index.failure_cause) {
if (!errorsByFeature[feature.feature_name]) {
errorsByFeature[feature.feature_name] = { errors: new Set(), indices: 0 };
}
errorsByFeature[feature.feature_name].errors.add(index.failure_cause.error.type);
errorsByFeature[feature.feature_name].indices += 1;
}
});
}
});
return {};
return (
<ul>
{Object.entries(errorsByFeature).map(([feature, { errors, indices }]) => {
const indicesAffectedText = i18n.translate(
'xpack.upgradeAssistant.systemIndices.migrationFailed.indicesAffected',
{
defaultMessage: '{count, plural, =1 {# index affected} other {# indices affected}}',
values: { count: indices },
}
);
return (
<li key={feature}>
<strong>{feature}</strong>:{' '}
{Array.from(errors).map((error, index) => (
<React.Fragment key={error}>
<EuiCode>{error}</EuiCode>
{index < errors.size - 1 && ', '}
</React.Fragment>
))}{' '}
({indicesAffectedText})
</li>
);
})}
</ul>
);
};
const i18nTexts = {
@ -69,18 +100,6 @@ const i18nTexts = {
/>
);
},
startButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.startButtonLabel',
{
defaultMessage: 'Migrate indices',
}
),
inProgressButtonLabel: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.inProgressButtonLabel',
{
defaultMessage: 'Migration in progress',
}
),
noMigrationNeeded: i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.noMigrationNeeded',
{
@ -109,70 +128,29 @@ const i18nTexts = {
}
),
migrationFailedBody: (features: SystemIndicesMigrationFeature[]) => {
const { feature, failureCause } = getFailureCause(features);
const failureCauses = getFailureCauses(features);
return (
<FormattedMessage
id="xpack.upgradeAssistant.overview.systemIndices.migrationFailedBody"
defaultMessage="An error ocurred while migrating system indices for {feature}: {failureCause}"
values={{
feature,
failureCause: <EuiCode>{failureCause}</EuiCode>,
}}
/>
<EuiText size="s">
<FormattedMessage
id="xpack.upgradeAssistant.overview.systemIndices.migrationFailedBodyFirstParagraph"
defaultMessage="Errors occurred while migrating system indices:"
/>
<EuiSpacer size="s" />
{failureCauses}
<FormattedMessage
id="xpack.upgradeAssistant.overview.systemIndices.migrationFailedBodySecondParagraph"
defaultMessage="Check migration details for more information."
tagName="p"
/>
</EuiText>
);
},
};
const ConfirmModal: React.FC<{
onCancel: () => void;
onConfirm: () => void;
}> = ({ onCancel, onConfirm }) => (
<EuiConfirmModal
title={i18n.translate('xpack.upgradeAssistant.overview.systemIndices.confirmModal.title', {
defaultMessage: 'Migrate Indices',
})}
onCancel={onCancel}
onConfirm={onConfirm}
cancelButtonText={i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.confirmModal.cancelButton.label',
{
defaultMessage: 'Cancel',
}
)}
confirmButtonText={i18n.translate(
'xpack.upgradeAssistant.overview.systemIndices.confirmModal.confirmButton.label',
{
defaultMessage: 'Confirm',
}
)}
defaultFocusedButton="confirm"
data-test-subj="migrationConfirmModal"
>
{i18n.translate('xpack.upgradeAssistant.overview.systemIndices.confirmModal.description', {
defaultMessage: 'Migrating system indices may lead to downtime while they are reindexed.',
})}
</EuiConfirmModal>
);
const MigrateSystemIndicesStep: FunctionComponent<Props> = ({ setIsComplete }) => {
const { beginSystemIndicesMigration, startMigrationStatus, migrationStatus, setShowFlyout } =
useMigrateSystemIndices();
const [isModalVisible, setIsModalVisible] = useState(false);
const openMigrationModal = () => {
setIsModalVisible(true);
};
const onCancel = () => {
setIsModalVisible(false);
};
const confirmMigrationAction = () => {
beginSystemIndicesMigration();
setIsModalVisible(false);
};
useEffect(() => {
setIsComplete(migrationStatus.data?.migration_status === 'NO_MIGRATION_NEEDED');
// Depending upon setIsComplete would create an infinite loop.
@ -246,24 +224,20 @@ const MigrateSystemIndicesStep: FunctionComponent<Props> = ({ setIsComplete }) =
title={i18nTexts.migrationFailedTitle}
data-test-subj="migrationFailedCallout"
>
<p>{i18nTexts.migrationFailedBody(migrationStatus.data?.features)}</p>
{i18nTexts.migrationFailedBody(migrationStatus.data?.features)}
</EuiCallOut>
<EuiSpacer size="m" />
</>
)}
{isModalVisible && <ConfirmModal onCancel={onCancel} onConfirm={confirmMigrationAction} />}
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton
isLoading={isMigrating}
isDisabled={isButtonDisabled}
onClick={openMigrationModal}
data-test-subj="startSystemIndicesMigrationButton"
>
{isMigrating ? i18nTexts.inProgressButtonLabel : i18nTexts.startButtonLabel}
</EuiButton>
<MigrateSystemIndicesButton
beginSystemIndicesMigration={beginSystemIndicesMigration}
isInitialRequest={migrationStatus.isInitialRequest}
isLoading={migrationStatus.isLoading}
isMigrating={isMigrating}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
@ -297,7 +271,7 @@ export const getMigrateSystemIndicesStep = ({
'data-test-subj': `migrateSystemIndicesStep-${status}`,
children: (
<>
<EuiText>
<EuiText data-test-subj="migrateSystemIndicesText">
<p>{i18nTexts.bodyDescription(docLinks.links.elasticsearch.hiddenIndices)}</p>
</EuiText>

View file

@ -18,7 +18,7 @@ const FLYOUT_ID = 'migrateSystemIndicesFlyout';
const { useGlobalFlyout } = GlobalFlyout;
export type StatusType = 'idle' | 'error' | 'started';
interface MigrationStatus {
export interface MigrationStatus {
statusType: StatusType;
error?: ResponseError;
}
@ -49,22 +49,6 @@ export const useMigrateSystemIndices = () => {
removeContentFromGlobalFlyout(FLYOUT_ID);
}, [removeContentFromGlobalFlyout]);
useEffect(() => {
if (showFlyout) {
addContentToGlobalFlyout<SystemIndicesFlyoutProps>({
id: FLYOUT_ID,
Component: SystemIndicesFlyout,
props: {
data: data!,
closeFlyout,
},
flyoutProps: {
onClose: closeFlyout,
},
});
}
}, [addContentToGlobalFlyout, data, showFlyout, closeFlyout]);
const beginSystemIndicesMigration = useCallback(async () => {
const { error: startMigrationError } = await api.migrateSystemIndices();
@ -78,6 +62,36 @@ export const useMigrateSystemIndices = () => {
}
}, [api, resendRequest]);
useEffect(() => {
if (showFlyout) {
addContentToGlobalFlyout<SystemIndicesFlyoutProps>({
id: FLYOUT_ID,
Component: SystemIndicesFlyout,
props: {
data: data!,
closeFlyout,
beginSystemIndicesMigration,
isInitialRequest,
isLoading,
migrationStatus: data?.migration_status,
},
flyoutProps: {
onClose: closeFlyout,
'data-test-subj': 'migrateSystemIndicesFlyout',
'aria-labelledby': 'migrateSystemIndicesFlyoutTitle',
},
});
}
}, [
addContentToGlobalFlyout,
data,
showFlyout,
closeFlyout,
beginSystemIndicesMigration,
isLoading,
isInitialRequest,
]);
return {
setShowFlyout,
startMigrationStatus,

View file

@ -10,12 +10,13 @@ import React, { useEffect, useState } from 'react';
import {
EuiSteps,
EuiPageHeader,
EuiButtonEmpty,
EuiSpacer,
EuiLink,
EuiPageBody,
EuiPageSection,
EuiText,
EuiToolTip,
EuiIcon,
} from '@elastic/eui';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';
@ -24,6 +25,7 @@ import { METRIC_TYPE } from '@kbn/analytics';
import { FormattedMessage } from '@kbn/i18n-react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { LATEST_VERSION, MIN_VERSION_TO_UPGRADE_TO_LATEST } from '../../../../common/constants';
import { useAppContext } from '../../app_context';
import { uiMetricService, UIM_OVERVIEW_PAGE_LOAD } from '../../lib/ui_metric';
import { getBackupStep } from './backup_step';
@ -42,8 +44,11 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => {
core: { docLinks },
},
plugins: { cloud },
kibanaVersionInfo: { currentMajor, currentMinor, currentPatch },
} = useAppContext();
const currentVersion = `${currentMajor}.${currentMinor}.${currentPatch}`;
useEffect(() => {
uiMetricService.trackUiMetric(METRIC_TYPE.LOADED, UIM_OVERVIEW_PAGE_LOAD);
}, []);
@ -67,37 +72,57 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => {
});
};
const versionTooltipContent = () => {
if (currentVersion >= MIN_VERSION_TO_UPGRADE_TO_LATEST) {
return null;
}
return (
<EuiToolTip
position="right"
content={
<FormattedMessage
id="xpack.upgradeAssistant.overview.latestMinVersionTooltip"
defaultMessage="Upgrading to v{latestVersion} requires v{minVersionToUpgradeToLatest}."
values={{
latestVersion: LATEST_VERSION,
minVersionToUpgradeToLatest: MIN_VERSION_TO_UPGRADE_TO_LATEST,
}}
/>
}
>
<EuiIcon type="iInCircle" size="s" />
</EuiToolTip>
);
};
return (
<EuiPageBody restrictWidth={true} data-test-subj="overview">
<EuiPageSection color="transparent" paddingSize="none">
<EuiPageHeader
bottomBorder
data-test-subj="overviewPageHeader"
pageTitle={i18n.translate('xpack.upgradeAssistant.overview.pageTitle', {
defaultMessage: 'Upgrade Assistant',
})}
description={i18n.translate('xpack.upgradeAssistant.overview.pageDescription', {
defaultMessage: 'Get ready for the next version of the Elastic Stack!',
})}
rightSideItems={[
<EuiButtonEmpty
href={docLinks.links.upgradeAssistant.overview}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.documentationLinkText"
defaultMessage="Documentation"
/>
</EuiButtonEmpty>,
]}
description={
<FormattedMessage
id="xpack.upgradeAssistant.overview.versionInfo"
defaultMessage="Current version: {currentVersion} | Latest available version: {latestVersion} {versionTooltip}"
values={{
currentVersion: <strong>{currentVersion}</strong>,
latestVersion: <strong>{LATEST_VERSION}</strong>,
versionTooltip: versionTooltipContent(),
}}
/>
}
>
<EuiText>
<FormattedMessage
id="xpack.upgradeAssistant.overview.upgradeToLatestMinorBeforeMajorMessage"
defaultMessage="Check the {link}. Before upgrading to a new major version, you must first upgrade to the latest minor of this major version."
id="xpack.upgradeAssistant.overview.linkToReleaseNotes"
defaultMessage="{linkToReleaseNotes}"
values={{
link: (
linkToReleaseNotes: (
<EuiLink
data-test-subj="whatsNewLink"
href={docLinks.links.elasticsearch.latestReleaseHighlights}
@ -105,7 +130,10 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => {
>
<FormattedMessage
id="xpack.upgradeAssistant.overview.minorOfLatestMajorReleaseNotes"
defaultMessage="latest release highlights"
defaultMessage="What's new in version v{latestVersion}"
values={{
latestVersion: LATEST_VERSION,
}}
/>
</EuiLink>
),
@ -135,7 +163,6 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => {
getLogsStep({
isComplete: isStepComplete('logs'),
setIsComplete: setCompletedStep.bind(null, 'logs'),
navigateToEsDeprecationLogs: () => history.push('/es_deprecation_logs'),
}),
getUpgradeStep(),
].filter(Boolean) as EuiStepProps[]

View file

@ -20,12 +20,7 @@ export enum CancelLoadingState {
Error,
}
export type DeprecationTableColumns =
| 'type'
| 'index'
| 'message'
| 'correctiveAction'
| 'isCritical';
export type DeprecationTableColumns = 'type' | 'index' | 'message' | 'correctiveAction' | 'level';
export type Status = 'in_progress' | 'complete' | 'idle' | 'error';
export interface DeprecationLoggingPreviewProps {

Some files were not shown because too many files have changed in this diff Show more