diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ac2e375cb7789..428e4e9b6a164 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1305,7 +1305,6 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql ## Logs UI code exceptions -> @elastic/obs-ux-logs-team /x-pack/test/api_integration/deployment_agnostic/apis/observability/data_quality/ @elastic/obs-ux-logs-team -/x-pack/test/upgrade/apps/logs @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/page_objects/svl_oblt_onboarding_stream_log_file.ts @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/page_objects/svl_oblt_onboarding_page.ts @elastic/obs-ux-logs-team /x-pack/solutions/observability/plugins/infra/common/http_api/log_alerts @elastic/obs-ux-logs-team @@ -1420,7 +1419,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/test/functional/page_objects/dataset_quality.ts @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/test_suites/observability/index* @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/test_suites/observability/cypress @elastic/obs-ux-logs-team -/x-pack/test/functional/services/infra_source_configuration_form.ts @elastic/obs-ux-logs-team +/x-pack/test/functional/services/infra_source_configuration_form.ts @elastic/obs-ux-infra_services-team /x-pack/test/functional/services/logs_ui @elastic/obs-ux-logs-team /x-pack/test/functional/page_objects/observability_logs_explorer.ts @elastic/obs-ux-logs-team /test/functional/services/selectable.ts @elastic/obs-ux-logs-team diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index e75c7d5da2d8b..e72f25f0c0a02 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -23699,7 +23699,6 @@ "xpack.infra.analysisSetup.steps.setupProcess.viewResultsButton": "Afficher les résultats", "xpack.infra.analysisSetup.timeRangeDescription": "Par défaut, le Machine Learning analyse les messages de logs dans vos index de logs n'excédant pas quatre semaines et continue indéfiniment. Vous pouvez spécifier une date de début, de fin ou les deux différente.", "xpack.infra.analysisSetup.timeRangeTitle": "Choisir une plage temporelle", - "xpack.infra.appName": "Logs Infra", "xpack.infra.assetDetails.alerts.tooltip.alertsLabel": "Affichage des alertes pour cet hôte. Vous pouvez créer et gérer les alertes dans {alerts}", "xpack.infra.assetDetails.alerts.tooltip.documentationLabel": "Pour en savoir plus, consultez la {documentation}", "xpack.infra.assetDetails.alerts.tooltip.documentationLink": "documentation", @@ -24109,7 +24108,6 @@ "xpack.infra.logs.analysis.logEntryCategoriesModuleName": "Catégorisation", "xpack.infra.logs.analysis.logEntryExamplesViewAnomalyInMlLabel": "Afficher l'anomalie dans le Machine Learning", "xpack.infra.logs.analysis.logEntryExamplesViewDetailsLabel": "Afficher les détails", - "xpack.infra.logs.analysis.logEntryExamplesViewInStreamLabel": "Afficher dans le flux", "xpack.infra.logs.analysis.logEntryRateModuleDescription": "Utilisez le Machine Learning pour détecter automatiquement les taux d'entrées de logs anormaux.", "xpack.infra.logs.analysis.logEntryRateModuleName": "Taux du log", "xpack.infra.logs.analysis.manageMlJobsButtonLabel": "Gérer les tâches ML", @@ -24133,23 +24131,9 @@ "xpack.infra.logs.analysisPage.unavailable.mlAppLink": "Application de Machine Learning", "xpack.infra.logs.anomaliesPageTitle": "Anomalies", "xpack.infra.logs.categoryExample.viewInContextText": "Afficher en contexte", - "xpack.infra.logs.categoryExample.viewInStreamText": "Afficher dans le flux", - "xpack.infra.logs.common.invalidStateCalloutTitle": "État non valide rencontré", - "xpack.infra.logs.common.invalidStateMessage": "Impossible de traiter l'état {stateValue}.", - "xpack.infra.logs.customizeLogs.customizeButtonLabel": "Personnaliser", - "xpack.infra.logs.customizeLogs.lineWrappingFormRowLabel": "Retour automatique à la ligne", - "xpack.infra.logs.customizeLogs.textSizeFormRowLabel": "Taille du texte", - "xpack.infra.logs.customizeLogs.textSizeRadioGroup": "{textScale, select, small {Petit} medium {Moyen} large {Grand} other {{textScale}} }", - "xpack.infra.logs.customizeLogs.wrapLongLinesSwitchLabel": "Formater les longues lignes", - "xpack.infra.logs.highlights.clearHighlightTermsButtonLabel": "Effacer les termes à mettre en surbrillance", - "xpack.infra.logs.highlights.goToNextHighlightButtonLabel": "Passer au surlignage suivant", - "xpack.infra.logs.highlights.goToPreviousHighlightButtonLabel": "Passer au surlignage précédent", - "xpack.infra.logs.highlights.highlightsPopoverButtonLabel": "Surlignages", - "xpack.infra.logs.highlights.highlightTermsFieldLabel": "Termes à mettre en surbrillance", "xpack.infra.logs.index.anomaliesTabTitle": "Anomalies des logs", "xpack.infra.logs.index.logCategoriesBetaBadgeTitle": "Catégories de logs", "xpack.infra.logs.index.settingsTabTitle": "Paramètres", - "xpack.infra.logs.index.streamTabTitle": "Flux", "xpack.infra.logs.logCategoriesTitle": "Catégories", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlButtonLabel": "Analyse dans ML", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlTooltipDescription": "Analysez cette catégorie dans l'application ML.", @@ -24185,42 +24169,10 @@ "xpack.infra.logs.noDataConfig.beatsCard.title": "Ajouter une intégration au logging", "xpack.infra.logs.noDataConfig.solutionName": "Observabilité", "xpack.infra.logs.pluginTitle": "Logs", - "xpack.infra.logs.search.nextButtonLabel": "Suivant", - "xpack.infra.logs.search.previousButtonLabel": "Précédent", - "xpack.infra.logs.search.searchInLogsAriaLabel": "rechercher", - "xpack.infra.logs.search.searchInLogsPlaceholder": "Recherche", - "xpack.infra.logs.searchResultTooltip": "{bucketCount, plural, one {# entrée mise en surbrillance} other {# entrées mises en surbrillance}}", - "xpack.infra.logs.settings.inlineLogViewCalloutButtonText": "Revenir à la vue par défaut du flux de logs", - "xpack.infra.logs.settings.inlineLogViewCalloutWidgetDescription": "Les modifications seront synchronisées avec l'URL, mais elles ne seront pas conservées dans la vue par défaut du flux de logs.", - "xpack.infra.logs.settings.inlineLogViewCalloutWidgetTitle": "Vous configurez un widget intégré", - "xpack.infra.logs.startStreamingButtonLabel": "Diffuser en direct", - "xpack.infra.logs.stopStreamingButtonLabel": "Arrêter la diffusion", - "xpack.infra.logs.streamPageTitle": "Flux", "xpack.infra.logs.viewInContext.logsFromContainerTitle": "Les logs affichés proviennent du conteneur {container}", "xpack.infra.logs.viewInContext.logsFromFileTitle": "Les logs affichés proviennent du fichier {file} et de l'hôte {host}", "xpack.infra.logsDeprecationCallout.euiCallOut.discoverANewLogLabel": "Il existe une nouvelle (et meilleure) façon d'explorer vos logs !", "xpack.infra.logsHeaderAddDataButtonLabel": "Ajouter des données", - "xpack.infra.logSourceConfiguration.childFormElementErrorMessage": "L'état d'au moins un champ du formulaire est non valide.", - "xpack.infra.logSourceConfiguration.dataViewDescription": "Vue de données contenant les données de log", - "xpack.infra.logSourceConfiguration.dataViewLabel": "Vue de données de log", - "xpack.infra.logSourceConfiguration.dataViewSectionTitle": "Vue de données (déclassée)", - "xpack.infra.logSourceConfiguration.dataViewSelectorPlaceholder": "Choisir une vue de données", - "xpack.infra.logSourceConfiguration.dataViewsManagementLinkText": "écran de gestion des vues de données", - "xpack.infra.logSourceConfiguration.dataViewTitle": "Vue de données de log", - "xpack.infra.logSourceConfiguration.emptyColumnListErrorMessage": "La liste de colonnes ne doit pas être vide.", - "xpack.infra.logSourceConfiguration.emptyFieldErrorMessage": "Le champ \"{fieldName}\" ne doit pas être vide.", - "xpack.infra.logSourceConfiguration.includesSpacesErrorMessage": "Le champ \"{fieldName}\" ne doit pas contenir d’espaces.", - "xpack.infra.logSourceConfiguration.invalidMessageFieldTypeErrorMessage": "Le champ {messageField} doit être un champ textuel.", - "xpack.infra.logSourceConfiguration.kibanaAdvancedSettingSectionTitle": "Paramètres avancés des sources de logs Kibana", - "xpack.infra.logSourceConfiguration.logDataViewHelpText": "Les vues de données sont partagées entre les applications dans l'espace Kibana et peuvent être gérées via l’{dataViewsManagementLink}. Une vue de données peut cibler plusieurs index.", - "xpack.infra.logSourceConfiguration.logSourceConfigurationFormErrorsCalloutTitle": "Configuration de la source incohérente", - "xpack.infra.logSourceConfiguration.logSourcesTitle": "Sources de log", - "xpack.infra.logSourceConfiguration.missingDataViewErrorMessage": "La vue de données {dataViewId} doit exister.", - "xpack.infra.logSourceConfiguration.missingDataViewsLabel": "Vue de données {indexPatternId} manquante", - "xpack.infra.logSourceConfiguration.missingMessageFieldErrorMessage": "La vue de données doit contenir un champ {messageField}.", - "xpack.infra.logSourceConfiguration.missingTimestampFieldErrorMessage": "La vue de données doit être basée sur le temps.", - "xpack.infra.logSourceConfiguration.rollupIndexPatternErrorMessage": "La vue de données ne doit pas être un modèle d'indexation de cumul.", - "xpack.infra.logSourceConfiguration.unsavedFormPromptMessage": "Voulez-vous vraiment quitter ? Les modifications seront perdues", "xpack.infra.logSourceErrorPage.failedToLoadSourceMessage": "Des erreurs se sont produites lors du chargement de la configuration. Réessayez ou modifiez la configuration pour résoudre le problème.", "xpack.infra.logSourceErrorPage.failedToLoadSourceTitle": "Impossible de charger la configuration", "xpack.infra.logSourceErrorPage.fetchLogSourceConfigurationErrorTitle": "Impossible de charger la configuration de la source de logs", @@ -24229,13 +24181,7 @@ "xpack.infra.logSourceErrorPage.resolveLogSourceConfigurationErrorTitle": "Impossible de résoudre la configuration de la source de logs", "xpack.infra.logSourceErrorPage.savedObjectNotFoundErrorMessage": "Impossible de localiser ce {savedObjectType} : {savedObjectId}", "xpack.infra.logSourceErrorPage.tryAgainButtonLabel": "Réessayer", - "xpack.infra.logsPage.toolbar.kqlSearchFieldPlaceholder": "Recherche d'entrées de log… (par ex. host.name:host-1)", - "xpack.infra.logsPage.toolbar.logFilterErrorToastTitle": "Erreur de filtrage du log", - "xpack.infra.logsSettingsPage.loadingButtonLabel": "Chargement", "xpack.infra.logsStreamEmbeddable.deprecationWarningDescription": "La maintenance des panneaux de flux de logs n'est plus assurée. Essayez d'utiliser {savedSearchDocsLink} pour une visualisation similaire.", - "xpack.infra.logStreamPageTemplate.backtoLogsStream": "Retour au flux de logs", - "xpack.infra.logStreamPageTemplate.widgetBadge": "Widget", - "xpack.infra.logStreamPageTemplate.widgetDescription": "Vous visionnez un widget intégré. Les modifications seront synchronisées avec l'URL, mais elles ne seront pas conservées dans la vue par défaut du flux de logs.", "xpack.infra.metadata.pinAriaLabel": "Champ épinglé", "xpack.infra.metadataEmbeddable.AddFilterAriaLabel": "Ajouter un filtre", "xpack.infra.metadataEmbeddable.errorAction": "récupérer de nouveau les métadonnées", @@ -24590,9 +24536,6 @@ "xpack.infra.ml.aomalyFlyout.jobSetup.flyoutHeader": "Activer le Machine Learning pour {nodeType}", "xpack.infra.ml.metricsHostModuleDescription": "Utilisez le Machine Learning pour détecter automatiquement les taux d'entrées de logs anormaux.", "xpack.infra.ml.metricsModuleName": "Détection des anomalies d'indicateurs", - "xpack.infra.ml.splash.inlineLogView.buttonText": "Revenir à la vue de log (persistante) par défaut", - "xpack.infra.ml.splash.inlineLogView.description": "Cette fonctionnalité ne prend pas en charge les vues de journal en ligne.", - "xpack.infra.ml.splash.inlineLogView.title": "Basculer vers la vue de log persistante", "xpack.infra.ml.splash.loadingMessage": "Vérification de la licence...", "xpack.infra.ml.splash.startTrialCta": "Démarrer l'essai", "xpack.infra.ml.splash.startTrialDescription": "Notre essai gratuit inclut les fonctionnalités de Machine Learning, qui vous permettent de détecter les anomalies dans vos logs.", @@ -24683,28 +24626,14 @@ "xpack.infra.savedView.updateView": "Mettre à jour la vue", "xpack.infra.showHistory": "Afficher l'historique", "xpack.infra.snapshot.missingSnapshotMetricError": "L'agrégation de {metric} pour {nodeType} n'est pas disponible.", - "xpack.infra.sourceConfiguration.addLogColumnButtonLabel": "Ajouter une colonne", "xpack.infra.sourceConfiguration.anomalyThresholdDescription": "Définit le score de sévérité minimal requis pour afficher les anomalies dans l'application Metrics.", "xpack.infra.sourceConfiguration.anomalyThresholdLabel": "Score de sévérité minimal", "xpack.infra.sourceConfiguration.anomalyThresholdTitle": "Seuil de sévérité d'anomalie", - "xpack.infra.sourceConfiguration.applySettingsButtonLabel": "Appliquer", - "xpack.infra.sourceConfiguration.discardSettingsButtonLabel": "Abandonner", "xpack.infra.sourceConfiguration.featuresSectionTitle": "Fonctionnalités", "xpack.infra.sourceConfiguration.fieldContainEmptyEntryErrorMessage": "Le champ ne doit pas inclure de valeurs vides séparées par des virgules.", "xpack.infra.sourceConfiguration.fieldContainSpacesErrorMessage": "Le champ ne doit pas contenir d'espaces.", "xpack.infra.sourceConfiguration.fieldEmptyErrorMessage": "Le champ ne doit pas être vide.", - "xpack.infra.sourceConfiguration.fieldLogColumnTitle": "Champ", "xpack.infra.sourceConfiguration.indicesSectionTitle": "Index", - "xpack.infra.sourceConfiguration.logColumnsSectionTitle": "Colonnes de log", - "xpack.infra.sourceConfiguration.logIndices.viewAffectedRulesLink": "Afficher les règles affectées", - "xpack.infra.sourceConfiguration.logIndicesDescription": "Modèle d'indexation pour la correspondance d'index contenant des données de log", - "xpack.infra.sourceConfiguration.logIndicesLabel": "Index de log", - "xpack.infra.sourceConfiguration.logIndicesRecommendedValue": "La valeur recommandée est {defaultValue}", - "xpack.infra.sourceConfiguration.logIndicesTitle": "Index de log", - "xpack.infra.sourceConfiguration.logsIndicesSectionTitle": "Index (déclassés)", - "xpack.infra.sourceConfiguration.logsIndicesUsedByRulesMessage": "Une ou plusieurs règles d’alerte reposent sur ce paramètre de source de données. La modification de ce paramètre modifiera les données utilisées pour générer des alertes.", - "xpack.infra.sourceConfiguration.logsIndicesUsedByRulesTitle": "Les règles d'alerte utilisent ce paramètre de source de données", - "xpack.infra.sourceConfiguration.messageLogColumnDescription": "Ce champ système affiche le message d'entrée de log dérivé des champs de document.", "xpack.infra.sourceConfiguration.metricIndices.viewAffectedRulesLink": "Afficher les règles affectées", "xpack.infra.sourceConfiguration.metricIndicesDescription": "Modèle d'indexation pour la correspondance d'index contenant des données d'indicateurs", "xpack.infra.sourceConfiguration.metricIndicesDoNotExist": "Impossible de trouver des données d’indicateurs car le modèle saisi ne correspond à aucun index.", @@ -24719,16 +24648,11 @@ "xpack.infra.sourceConfiguration.nameDescription": "Nom descriptif pour la configuration de la source", "xpack.infra.sourceConfiguration.nameLabel": "Nom", "xpack.infra.sourceConfiguration.nameSectionTitle": "Nom", - "xpack.infra.sourceConfiguration.noLogColumnsDescription": "Ajoutez une colonne à cette liste à l'aide du bouton ci-dessus.", - "xpack.infra.sourceConfiguration.noLogColumnsTitle": "Aucune colonne", "xpack.infra.sourceConfiguration.noRemoteClusterMessage": "Nous ne parvenons pas à nous connecter au cluster distant, ce qui nous empêche de récupérer les indicateurs et les données dont vous avez besoin. Pour résoudre ce problème, vérifiez la configuration de vos index et assurez-vous qu'elle est correctement effectuée.", "xpack.infra.sourceConfiguration.noRemoteClusterTitle": "Impossible de se connecter au serveur distant", "xpack.infra.sourceConfiguration.remoteClusterConnectionDoNotExist": "Vérifiez que le cluster distant est disponible ou que les paramètres de connexion à distance sont corrects.", "xpack.infra.sourceConfiguration.remoteClusterConnectionDoNotExistTitle": "Impossible de se connecter au cluster distant", - "xpack.infra.sourceConfiguration.removeLogColumnButtonLabel": "Retirer la colonne {columnDescription}", "xpack.infra.sourceConfiguration.saveButton": "Enregistrer les modifications", - "xpack.infra.sourceConfiguration.systemColumnBadgeLabel": "Système", - "xpack.infra.sourceConfiguration.timestampLogColumnDescription": "Ce champ système affiche l'heure de l'entrée de log telle que déterminée par le paramètre du champ {timestampSetting}.", "xpack.infra.sourceConfiguration.unsavedFormPrompt": "Voulez-vous vraiment quitter ? Les modifications seront perdues", "xpack.infra.sourceConfiguration.updateFailureBody": "Nous n'avons pas pu appliquer les modifications à la configuration des indicateurs. Réessayez plus tard.", "xpack.infra.sourceConfiguration.updateFailureTitle": "La mise à jour de la configuration a échoué", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index eaecad312844b..2a319b541fd1b 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -23559,7 +23559,6 @@ "xpack.infra.analysisSetup.steps.setupProcess.viewResultsButton": "結果を表示", "xpack.infra.analysisSetup.timeRangeDescription": "デフォルトで、機械学習は 4 週間以内のログインデックスのログメッセージを分析し、永久に継続します。別の開始日、終了日、または両方を指定できます。", "xpack.infra.analysisSetup.timeRangeTitle": "時間範囲の選択", - "xpack.infra.appName": "インフラログ", "xpack.infra.assetDetails.alerts.tooltip.alertsLabel": "このホストのアラートを表示しています。{alerts}でアラートを作成および管理できます", "xpack.infra.assetDetails.alerts.tooltip.documentationLabel": "詳細については、{documentation}を参照してください", "xpack.infra.assetDetails.alerts.tooltip.documentationLink": "ドキュメンテーション", @@ -23971,7 +23970,6 @@ "xpack.infra.logs.analysis.logEntryCategoriesModuleName": "カテゴリー分け", "xpack.infra.logs.analysis.logEntryExamplesViewAnomalyInMlLabel": "機械学習で異常を表示", "xpack.infra.logs.analysis.logEntryExamplesViewDetailsLabel": "詳細を表示", - "xpack.infra.logs.analysis.logEntryExamplesViewInStreamLabel": "ストリームで表示", "xpack.infra.logs.analysis.logEntryRateModuleDescription": "機械学習を使用して自動的に異常ログエントリ率を検出します。", "xpack.infra.logs.analysis.logEntryRateModuleName": "ログレート", "xpack.infra.logs.analysis.manageMlJobsButtonLabel": "MLジョブの管理", @@ -23995,23 +23993,9 @@ "xpack.infra.logs.analysisPage.unavailable.mlAppLink": "機械学習アプリ", "xpack.infra.logs.anomaliesPageTitle": "異常", "xpack.infra.logs.categoryExample.viewInContextText": "コンテキストで表示", - "xpack.infra.logs.categoryExample.viewInStreamText": "ストリームで表示", - "xpack.infra.logs.common.invalidStateCalloutTitle": "無効な状態が発生しました", - "xpack.infra.logs.common.invalidStateMessage": "状態{stateValue}を処理できません。", - "xpack.infra.logs.customizeLogs.customizeButtonLabel": "カスタマイズ", - "xpack.infra.logs.customizeLogs.lineWrappingFormRowLabel": "改行", - "xpack.infra.logs.customizeLogs.textSizeFormRowLabel": "テキストサイズ", - "xpack.infra.logs.customizeLogs.textSizeRadioGroup": "{textScale, select, small {小} Medium {中} Large {大} other {{textScale}} }", - "xpack.infra.logs.customizeLogs.wrapLongLinesSwitchLabel": "長い行を改行", - "xpack.infra.logs.highlights.clearHighlightTermsButtonLabel": "ハイライトする用語をクリア", - "xpack.infra.logs.highlights.goToNextHighlightButtonLabel": "次のハイライトにスキップ", - "xpack.infra.logs.highlights.goToPreviousHighlightButtonLabel": "前のハイライトにスキップ", - "xpack.infra.logs.highlights.highlightsPopoverButtonLabel": "ハイライト", - "xpack.infra.logs.highlights.highlightTermsFieldLabel": "ハイライトする用語", "xpack.infra.logs.index.anomaliesTabTitle": "Logs異常", "xpack.infra.logs.index.logCategoriesBetaBadgeTitle": "Logsカテゴリ", "xpack.infra.logs.index.settingsTabTitle": "設定", - "xpack.infra.logs.index.streamTabTitle": "ストリーム", "xpack.infra.logs.logCategoriesTitle": "カテゴリー", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlButtonLabel": "ML で分析", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlTooltipDescription": "ML アプリでこのカテゴリーを分析します。", @@ -24047,41 +24031,10 @@ "xpack.infra.logs.noDataConfig.beatsCard.title": "ロギング統合を追加", "xpack.infra.logs.noDataConfig.solutionName": "Observability", "xpack.infra.logs.pluginTitle": "ログ", - "xpack.infra.logs.search.nextButtonLabel": "次へ", - "xpack.infra.logs.search.previousButtonLabel": "前へ", - "xpack.infra.logs.search.searchInLogsAriaLabel": "検索", - "xpack.infra.logs.search.searchInLogsPlaceholder": "検索", - "xpack.infra.logs.searchResultTooltip": "{bucketCount, plural, other {# 件のハイライトされたエントリー}}", - "xpack.infra.logs.settings.inlineLogViewCalloutButtonText": "デフォルトログストリームビューに戻す", - "xpack.infra.logs.settings.inlineLogViewCalloutWidgetDescription": "変更はURLと同期されますが、デフォルトログストリームビューには永続しません。", - "xpack.infra.logs.settings.inlineLogViewCalloutWidgetTitle": "埋め込まれたウィジェットを構成しています", - "xpack.infra.logs.startStreamingButtonLabel": "ライブストリーム", - "xpack.infra.logs.stopStreamingButtonLabel": "ストリーム停止", - "xpack.infra.logs.streamPageTitle": "ストリーム", "xpack.infra.logs.viewInContext.logsFromContainerTitle": "表示されたログはコンテナー{container}から取得されました", "xpack.infra.logs.viewInContext.logsFromFileTitle": "表示されたログは、ファイル{file}およびホスト{host}から取得されました", "xpack.infra.logsDeprecationCallout.euiCallOut.discoverANewLogLabel": "ログの探索には、新しく、もっと効果的な方法があります。", "xpack.infra.logsHeaderAddDataButtonLabel": "データの追加", - "xpack.infra.logSourceConfiguration.childFormElementErrorMessage": "1つ以上のフォームフィールドが無効な状態です。", - "xpack.infra.logSourceConfiguration.dataViewDescription": "ログデータを含むデータビュー", - "xpack.infra.logSourceConfiguration.dataViewLabel": "ログデータビュー", - "xpack.infra.logSourceConfiguration.dataViewSectionTitle": "データビュー(廃止予定)", - "xpack.infra.logSourceConfiguration.dataViewSelectorPlaceholder": "データビューを選択", - "xpack.infra.logSourceConfiguration.dataViewsManagementLinkText": "データビュー管理画面", - "xpack.infra.logSourceConfiguration.dataViewTitle": "ログデータビュー", - "xpack.infra.logSourceConfiguration.emptyColumnListErrorMessage": "列リストは未入力のままにできません。", - "xpack.infra.logSourceConfiguration.emptyFieldErrorMessage": "フィールド''{fieldName}''は未入力のままにできません。", - "xpack.infra.logSourceConfiguration.includesSpacesErrorMessage": "フィールド''{fieldName}''にはスペースを入力できません。", - "xpack.infra.logSourceConfiguration.invalidMessageFieldTypeErrorMessage": "{messageField}フィールドはテキストフィールドでなければなりません。", - "xpack.infra.logSourceConfiguration.kibanaAdvancedSettingSectionTitle": "Kibanaログソース詳細設定", - "xpack.infra.logSourceConfiguration.logSourceConfigurationFormErrorsCalloutTitle": "一貫しないソース構成", - "xpack.infra.logSourceConfiguration.logSourcesTitle": "ログソース", - "xpack.infra.logSourceConfiguration.missingDataViewErrorMessage": "データビュー{dataViewId}が存在する必要があります。", - "xpack.infra.logSourceConfiguration.missingDataViewsLabel": "データビュー{indexPatternId}が見つかりません", - "xpack.infra.logSourceConfiguration.missingMessageFieldErrorMessage": "データビューには{messageField}フィールドが必要です。", - "xpack.infra.logSourceConfiguration.missingTimestampFieldErrorMessage": "データビューは時間に基づく必要があります。", - "xpack.infra.logSourceConfiguration.rollupIndexPatternErrorMessage": "データビューがロールアップインデックスパターンであってはなりません。", - "xpack.infra.logSourceConfiguration.unsavedFormPromptMessage": "終了してよろしいですか?変更内容は失われます", "xpack.infra.logSourceErrorPage.failedToLoadSourceMessage": "構成の読み込み試行中にエラーが発生しました。再試行するか、構成を変更して問題を修正してください。", "xpack.infra.logSourceErrorPage.failedToLoadSourceTitle": "構成を読み込めませんでした", "xpack.infra.logSourceErrorPage.fetchLogSourceConfigurationErrorTitle": "ログソース構成を読み込めませんでした", @@ -24090,13 +24043,7 @@ "xpack.infra.logSourceErrorPage.resolveLogSourceConfigurationErrorTitle": "ログソース構成を解決できませんでした", "xpack.infra.logSourceErrorPage.savedObjectNotFoundErrorMessage": "{savedObjectType}:{savedObjectId}が見つかりませんでした", "xpack.infra.logSourceErrorPage.tryAgainButtonLabel": "再試行", - "xpack.infra.logsPage.toolbar.kqlSearchFieldPlaceholder": "ログエントリーを検索中…(例:host.name:host-1)", - "xpack.infra.logsPage.toolbar.logFilterErrorToastTitle": "ログフィルターエラー", - "xpack.infra.logsSettingsPage.loadingButtonLabel": "読み込み中", "xpack.infra.logsStreamEmbeddable.deprecationWarningDescription": "ログストリームパネルは管理されていません。{savedSearchDocsLink}を同様の視覚化に活用してください。", - "xpack.infra.logStreamPageTemplate.backtoLogsStream": "ログストリームに戻る", - "xpack.infra.logStreamPageTemplate.widgetBadge": "ウィジェット", - "xpack.infra.logStreamPageTemplate.widgetDescription": "埋め込まれたウィジェットを表示しています。変更はURLと同期されますが、デフォルトログストリームビューには永続しません。", "xpack.infra.metadata.pinAriaLabel": "固定されたフィールド", "xpack.infra.metadataEmbeddable.AddFilterAriaLabel": "フィルターを追加", "xpack.infra.metadataEmbeddable.errorAction": "メタデータを再取得", @@ -24450,9 +24397,6 @@ "xpack.infra.ml.aomalyFlyout.jobSetup.flyoutHeader": "{nodeType}の機械学習を有効にする", "xpack.infra.ml.metricsHostModuleDescription": "機械学習を使用して自動的に異常ログエントリ率を検出します。", "xpack.infra.ml.metricsModuleName": "メトリック異常検知", - "xpack.infra.ml.splash.inlineLogView.buttonText": "デフォルト(永続)ログビューに戻す", - "xpack.infra.ml.splash.inlineLogView.description": "この機能はインラインログビューをサポートしていません", - "xpack.infra.ml.splash.inlineLogView.title": "永続ログビューに切り替える", "xpack.infra.ml.splash.loadingMessage": "ライセンスを確認しています...", "xpack.infra.ml.splash.startTrialCta": "トライアルを開始", "xpack.infra.ml.splash.startTrialDescription": "無料の試用版には、機械学習機能が含まれており、ログで異常を検出することができます。", @@ -24542,28 +24486,14 @@ "xpack.infra.savedView.updateView": "ビューの更新", "xpack.infra.showHistory": "履歴を表示", "xpack.infra.snapshot.missingSnapshotMetricError": "{nodeType}の{metric}の集約を使用できません。", - "xpack.infra.sourceConfiguration.addLogColumnButtonLabel": "列を追加", "xpack.infra.sourceConfiguration.anomalyThresholdDescription": "メトリックアプリケーションで異常値を表示するために必要な最低重要度スコアを設定します。", "xpack.infra.sourceConfiguration.anomalyThresholdLabel": "最低重要度スコア", "xpack.infra.sourceConfiguration.anomalyThresholdTitle": "異常重要度しきい値", - "xpack.infra.sourceConfiguration.applySettingsButtonLabel": "適用", - "xpack.infra.sourceConfiguration.discardSettingsButtonLabel": "破棄", "xpack.infra.sourceConfiguration.featuresSectionTitle": "機能", "xpack.infra.sourceConfiguration.fieldContainEmptyEntryErrorMessage": "フィールドには空のカンマ区切り値を含めることはできません。", "xpack.infra.sourceConfiguration.fieldContainSpacesErrorMessage": "フィールドにはスペースを入力できません。", "xpack.infra.sourceConfiguration.fieldEmptyErrorMessage": "このフィールドは未入力のままにできません。", - "xpack.infra.sourceConfiguration.fieldLogColumnTitle": "フィールド", "xpack.infra.sourceConfiguration.indicesSectionTitle": "インデックス", - "xpack.infra.sourceConfiguration.logColumnsSectionTitle": "ログ列", - "xpack.infra.sourceConfiguration.logIndices.viewAffectedRulesLink": "影響を受けるルールを表示", - "xpack.infra.sourceConfiguration.logIndicesDescription": "ログデータを含む一致するインデックスのインデックスパターンです", - "xpack.infra.sourceConfiguration.logIndicesLabel": "ログインデックス", - "xpack.infra.sourceConfiguration.logIndicesRecommendedValue": "推奨値は {defaultValue} です", - "xpack.infra.sourceConfiguration.logIndicesTitle": "ログインデックス", - "xpack.infra.sourceConfiguration.logsIndicesSectionTitle": "インデックス(廃止予定)", - "xpack.infra.sourceConfiguration.logsIndicesUsedByRulesMessage": "1つ以上のアラートルールがこのデータソース設定に依存しています。この設定を変更すると、アラートを生成するために使用されるデータが変更されます。", - "xpack.infra.sourceConfiguration.logsIndicesUsedByRulesTitle": "アラートルールはこのデータソース設定を使用します。", - "xpack.infra.sourceConfiguration.messageLogColumnDescription": "このシステムフィールドは、ドキュメントフィールドから取得されたログエントリーメッセージを表示します。", "xpack.infra.sourceConfiguration.metricIndices.viewAffectedRulesLink": "影響を受けるルールを表示", "xpack.infra.sourceConfiguration.metricIndicesDescription": "メトリックデータを含む一致するインデックスのインデックスパターンです", "xpack.infra.sourceConfiguration.metricIndicesDoNotExist": "入力されたパターンがインデックスと一致しないため、メトリックデータを検索できませんでした。", @@ -24578,16 +24508,11 @@ "xpack.infra.sourceConfiguration.nameDescription": "ソース構成を説明する名前です", "xpack.infra.sourceConfiguration.nameLabel": "名前", "xpack.infra.sourceConfiguration.nameSectionTitle": "名前", - "xpack.infra.sourceConfiguration.noLogColumnsDescription": "上のボタンでこのリストに列を追加します。", - "xpack.infra.sourceConfiguration.noLogColumnsTitle": "列がありません", "xpack.infra.sourceConfiguration.noRemoteClusterMessage": "リモートクラスターに接続できません。このため、必要なメトリックとデータを取得できません。この問題を解決するには、インデックス構成を確認し、構成が正しいことを確かめてください。", "xpack.infra.sourceConfiguration.noRemoteClusterTitle": "リモートクラスターに接続できませんでした", "xpack.infra.sourceConfiguration.remoteClusterConnectionDoNotExist": "リモートクラスターが利用可能であるか、リモート接続の設定が正しいことを確認します。", "xpack.infra.sourceConfiguration.remoteClusterConnectionDoNotExistTitle": "リモートクラスターに接続できませんでした", - "xpack.infra.sourceConfiguration.removeLogColumnButtonLabel": "{columnDescription} 列を削除", "xpack.infra.sourceConfiguration.saveButton": "変更を保存", - "xpack.infra.sourceConfiguration.systemColumnBadgeLabel": "システム", - "xpack.infra.sourceConfiguration.timestampLogColumnDescription": "このシステムフィールドは、{timestampSetting} フィールド設定から判断されたログエントリーの時刻を表示します。", "xpack.infra.sourceConfiguration.unsavedFormPrompt": "終了してよろしいですか?変更内容は失われます", "xpack.infra.sourceConfiguration.updateFailureBody": "変更をメトリック構成に適用できませんでした。しばらくたってから再試行してください。", "xpack.infra.sourceConfiguration.updateFailureTitle": "構成の更新が失敗しました", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 6cda136de7b0a..cc9d9fb709ea8 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -23186,7 +23186,6 @@ "xpack.infra.analysisSetup.steps.setupProcess.viewResultsButton": "查看结果", "xpack.infra.analysisSetup.timeRangeDescription": "默认情况下,Machine Learning 分析日志索引中不超过 4 周的日志消息,并无限持续下去。您可以指定不同的开始日期或/和结束日期。", "xpack.infra.analysisSetup.timeRangeTitle": "选择时间范围", - "xpack.infra.appName": "基础架构日志", "xpack.infra.assetDetails.alerts.tooltip.alertsLabel": "正在显示此主机的告警。可以在 {alerts} 中创建和管理告警", "xpack.infra.assetDetails.alerts.tooltip.documentationLabel": "请参阅{documentation}了解更多信息", "xpack.infra.assetDetails.alerts.tooltip.documentationLink": "文档", @@ -23590,7 +23589,6 @@ "xpack.infra.logs.analysis.logEntryCategoriesModuleName": "归类", "xpack.infra.logs.analysis.logEntryExamplesViewAnomalyInMlLabel": "在 Machine Learning 中查看异常", "xpack.infra.logs.analysis.logEntryExamplesViewDetailsLabel": "查看详情", - "xpack.infra.logs.analysis.logEntryExamplesViewInStreamLabel": "在流中查看", "xpack.infra.logs.analysis.logEntryRateModuleDescription": "使用 Machine Learning 自动检测异常日志条目速率。", "xpack.infra.logs.analysis.logEntryRateModuleName": "日志速率", "xpack.infra.logs.analysis.manageMlJobsButtonLabel": "管理 ML 作业", @@ -23614,23 +23612,9 @@ "xpack.infra.logs.analysisPage.unavailable.mlAppLink": "Machine Learning 应用", "xpack.infra.logs.anomaliesPageTitle": "异常", "xpack.infra.logs.categoryExample.viewInContextText": "在上下文中查看", - "xpack.infra.logs.categoryExample.viewInStreamText": "在流中查看", - "xpack.infra.logs.common.invalidStateCalloutTitle": "遇到无效状态", - "xpack.infra.logs.common.invalidStateMessage": "无法处理状态 {stateValue}。", - "xpack.infra.logs.customizeLogs.customizeButtonLabel": "定制", - "xpack.infra.logs.customizeLogs.lineWrappingFormRowLabel": "换行", - "xpack.infra.logs.customizeLogs.textSizeFormRowLabel": "文本大小", - "xpack.infra.logs.customizeLogs.textSizeRadioGroup": "{textScale, select, small {小} medium {Medium} large {Large} other {{textScale}} }", - "xpack.infra.logs.customizeLogs.wrapLongLinesSwitchLabel": "长行换行", - "xpack.infra.logs.highlights.clearHighlightTermsButtonLabel": "清除要突出显示的词", - "xpack.infra.logs.highlights.goToNextHighlightButtonLabel": "跳转到下一高亮条目", - "xpack.infra.logs.highlights.goToPreviousHighlightButtonLabel": "跳转到上一高亮条目", - "xpack.infra.logs.highlights.highlightsPopoverButtonLabel": "突出显示", - "xpack.infra.logs.highlights.highlightTermsFieldLabel": "要突出显示的词", "xpack.infra.logs.index.anomaliesTabTitle": "日志异常", "xpack.infra.logs.index.logCategoriesBetaBadgeTitle": "日志类别", "xpack.infra.logs.index.settingsTabTitle": "设置", - "xpack.infra.logs.index.streamTabTitle": "流式传输", "xpack.infra.logs.logCategoriesTitle": "类别", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlButtonLabel": "在 ML 中分析", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlTooltipDescription": "在 ML 应用中分析此类别。", @@ -23666,40 +23650,10 @@ "xpack.infra.logs.noDataConfig.beatsCard.title": "添加日志记录集成", "xpack.infra.logs.noDataConfig.solutionName": "Observability", "xpack.infra.logs.pluginTitle": "日志", - "xpack.infra.logs.search.nextButtonLabel": "下一步", - "xpack.infra.logs.search.previousButtonLabel": "上一页", - "xpack.infra.logs.search.searchInLogsAriaLabel": "搜索", - "xpack.infra.logs.search.searchInLogsPlaceholder": "搜索", - "xpack.infra.logs.searchResultTooltip": "{bucketCount, plural, other {# 个高亮条目}}", - "xpack.infra.logs.settings.inlineLogViewCalloutButtonText": "恢复为默认日志流视图", - "xpack.infra.logs.settings.inlineLogViewCalloutWidgetDescription": "更改将同步到 URL,但不会持续存在于默认日志流视图。", - "xpack.infra.logs.settings.inlineLogViewCalloutWidgetTitle": "您正在配置嵌入式小组件", - "xpack.infra.logs.startStreamingButtonLabel": "实时流式传输", - "xpack.infra.logs.stopStreamingButtonLabel": "停止流式传输", - "xpack.infra.logs.streamPageTitle": "流式传输", "xpack.infra.logs.viewInContext.logsFromContainerTitle": "显示的日志来自容器 {container}", "xpack.infra.logs.viewInContext.logsFromFileTitle": "显示的日志来自文件 {file} 和主机 {host}", "xpack.infra.logsDeprecationCallout.euiCallOut.discoverANewLogLabel": "这是浏览日志的更有效的新方法!", "xpack.infra.logsHeaderAddDataButtonLabel": "添加数据", - "xpack.infra.logSourceConfiguration.childFormElementErrorMessage": "至少一个表单字段处于无效状态。", - "xpack.infra.logSourceConfiguration.dataViewDescription": "包含日志数据的数据视图", - "xpack.infra.logSourceConfiguration.dataViewLabel": "日志数据视图", - "xpack.infra.logSourceConfiguration.dataViewSectionTitle": "数据视图(已过时)", - "xpack.infra.logSourceConfiguration.dataViewSelectorPlaceholder": "选择数据视图", - "xpack.infra.logSourceConfiguration.dataViewsManagementLinkText": "数据视图管理屏幕", - "xpack.infra.logSourceConfiguration.dataViewTitle": "日志数据视图", - "xpack.infra.logSourceConfiguration.emptyColumnListErrorMessage": "列列表不得为空。", - "xpack.infra.logSourceConfiguration.invalidMessageFieldTypeErrorMessage": "{messageField} 字段必须是文本字段。", - "xpack.infra.logSourceConfiguration.kibanaAdvancedSettingSectionTitle": "Kibana 日志源高级设置", - "xpack.infra.logSourceConfiguration.logDataViewHelpText": "数据视图在 Kibana 工作区中的应用间共享,并可以通过 {dataViewsManagementLink} 进行管理。单一数据视图可以针对多个索引。", - "xpack.infra.logSourceConfiguration.logSourceConfigurationFormErrorsCalloutTitle": "内容配置不一致", - "xpack.infra.logSourceConfiguration.logSourcesTitle": "日志源", - "xpack.infra.logSourceConfiguration.missingDataViewErrorMessage": "数据视图 {dataViewId} 必须存在。", - "xpack.infra.logSourceConfiguration.missingDataViewsLabel": "缺少数据视图 {indexPatternId}", - "xpack.infra.logSourceConfiguration.missingMessageFieldErrorMessage": "数据视图必须包含 {messageField} 字段。", - "xpack.infra.logSourceConfiguration.missingTimestampFieldErrorMessage": "数据视图必须基于时间。", - "xpack.infra.logSourceConfiguration.rollupIndexPatternErrorMessage": "数据视图不得为汇总/打包索引模式。", - "xpack.infra.logSourceConfiguration.unsavedFormPromptMessage": "是否确定要离开?更改将丢失", "xpack.infra.logSourceErrorPage.failedToLoadSourceMessage": "尝试加载配置时出错。请重试或更改配置以解决问题。", "xpack.infra.logSourceErrorPage.failedToLoadSourceTitle": "无法加载配置", "xpack.infra.logSourceErrorPage.fetchLogSourceConfigurationErrorTitle": "无法加载日志源配置", @@ -23708,13 +23662,7 @@ "xpack.infra.logSourceErrorPage.resolveLogSourceConfigurationErrorTitle": "无法解决日志源配置", "xpack.infra.logSourceErrorPage.savedObjectNotFoundErrorMessage": "无法找到该{savedObjectType}:{savedObjectId}", "xpack.infra.logSourceErrorPage.tryAgainButtonLabel": "重试", - "xpack.infra.logsPage.toolbar.kqlSearchFieldPlaceholder": "搜索日志条目……(例如 host.name:host-1)", - "xpack.infra.logsPage.toolbar.logFilterErrorToastTitle": "日志筛选错误", - "xpack.infra.logsSettingsPage.loadingButtonLabel": "正在加载", "xpack.infra.logsStreamEmbeddable.deprecationWarningDescription": "将不再维护日志流面板。尝试将 {savedSearchDocsLink} 用于类似可视化。", - "xpack.infra.logStreamPageTemplate.backtoLogsStream": "返回到日志流", - "xpack.infra.logStreamPageTemplate.widgetBadge": "小组件", - "xpack.infra.logStreamPageTemplate.widgetDescription": "您正在查看嵌入式小组件。更改将同步到 URL,但不会持续存在于默认日志流视图。", "xpack.infra.metadata.pinAriaLabel": "已固定字段", "xpack.infra.metadataEmbeddable.AddFilterAriaLabel": "添加筛选", "xpack.infra.metadataEmbeddable.errorAction": "重新提取元数据", @@ -24066,9 +24014,6 @@ "xpack.infra.ml.aomalyFlyout.jobSetup.flyoutHeader": "为 {nodeType} 启用 Machine Learning", "xpack.infra.ml.metricsHostModuleDescription": "使用 Machine Learning 自动检测异常日志条目速率。", "xpack.infra.ml.metricsModuleName": "指标异常检测", - "xpack.infra.ml.splash.inlineLogView.buttonText": "恢复到默认(持久化)日志视图", - "xpack.infra.ml.splash.inlineLogView.description": "此功能不支持内联日志视图", - "xpack.infra.ml.splash.inlineLogView.title": "切换到持久化日志视图", "xpack.infra.ml.splash.loadingMessage": "正在检查许可证......", "xpack.infra.ml.splash.startTrialCta": "开始试用", "xpack.infra.ml.splash.startTrialDescription": "我们的免费试用版包含 Machine Learning 功能,可用于检测日志中的异常。", @@ -24159,28 +24104,14 @@ "xpack.infra.savedView.updateView": "更新视图", "xpack.infra.showHistory": "显示历史记录", "xpack.infra.snapshot.missingSnapshotMetricError": "{nodeType} 的 {metric} 聚合不可用。", - "xpack.infra.sourceConfiguration.addLogColumnButtonLabel": "添加列", "xpack.infra.sourceConfiguration.anomalyThresholdDescription": "设置在 Metrics 应用程序中显示异常所需的最低严重性分数。", "xpack.infra.sourceConfiguration.anomalyThresholdLabel": "最低严重性分数", "xpack.infra.sourceConfiguration.anomalyThresholdTitle": "异常严重性阈值", - "xpack.infra.sourceConfiguration.applySettingsButtonLabel": "应用", - "xpack.infra.sourceConfiguration.discardSettingsButtonLabel": "丢弃", "xpack.infra.sourceConfiguration.featuresSectionTitle": "功能", "xpack.infra.sourceConfiguration.fieldContainEmptyEntryErrorMessage": "字段不得包含逗号分隔的空值。", "xpack.infra.sourceConfiguration.fieldContainSpacesErrorMessage": "字段不得包括空格。", "xpack.infra.sourceConfiguration.fieldEmptyErrorMessage": "字段不得为空。", - "xpack.infra.sourceConfiguration.fieldLogColumnTitle": "字段", "xpack.infra.sourceConfiguration.indicesSectionTitle": "索引", - "xpack.infra.sourceConfiguration.logColumnsSectionTitle": "日志列", - "xpack.infra.sourceConfiguration.logIndices.viewAffectedRulesLink": "查看受影响的规则", - "xpack.infra.sourceConfiguration.logIndicesDescription": "用于匹配包含日志数据的索引的索引模式", - "xpack.infra.sourceConfiguration.logIndicesLabel": "日志索引", - "xpack.infra.sourceConfiguration.logIndicesRecommendedValue": "推荐值为 {defaultValue}", - "xpack.infra.sourceConfiguration.logIndicesTitle": "日志索引", - "xpack.infra.sourceConfiguration.logsIndicesSectionTitle": "索引(已过时)", - "xpack.infra.sourceConfiguration.logsIndicesUsedByRulesMessage": "一个或多个告警规则依赖于此数据源设置。更改此设置会更改用于生成告警的数据。", - "xpack.infra.sourceConfiguration.logsIndicesUsedByRulesTitle": "告警规则使用此数据源设置", - "xpack.infra.sourceConfiguration.messageLogColumnDescription": "此系统字段显示派生自文档字段的日志条目消息。", "xpack.infra.sourceConfiguration.metricIndices.viewAffectedRulesLink": "查看受影响的规则", "xpack.infra.sourceConfiguration.metricIndicesDescription": "用于匹配包含指标数据的索引的索引模式", "xpack.infra.sourceConfiguration.metricIndicesDoNotExist": "找不到任何指标数据,因为输入的模式不匹配任何索引。", @@ -24195,15 +24126,11 @@ "xpack.infra.sourceConfiguration.nameDescription": "源配置的描述性名称", "xpack.infra.sourceConfiguration.nameLabel": "名称", "xpack.infra.sourceConfiguration.nameSectionTitle": "名称", - "xpack.infra.sourceConfiguration.noLogColumnsDescription": "使用上面的按钮将列添加到此列表。", - "xpack.infra.sourceConfiguration.noLogColumnsTitle": "无列", "xpack.infra.sourceConfiguration.noRemoteClusterMessage": "无法连接到远程集群,这导致我们无法检索您所需的指标和数据。要解决此问题,请检查您的索引配置,并确保进行了正确配置。", "xpack.infra.sourceConfiguration.noRemoteClusterTitle": "无法连接到远程集群", "xpack.infra.sourceConfiguration.remoteClusterConnectionDoNotExist": "检查远程集群是否可用,或远程连接设置是否正确。", "xpack.infra.sourceConfiguration.remoteClusterConnectionDoNotExistTitle": "无法连接到远程集群", "xpack.infra.sourceConfiguration.saveButton": "保存更改", - "xpack.infra.sourceConfiguration.systemColumnBadgeLabel": "系统", - "xpack.infra.sourceConfiguration.timestampLogColumnDescription": "此系统字段显示 {timestampSetting} 字段设置所确定的日志条目时间。", "xpack.infra.sourceConfiguration.unsavedFormPrompt": "是否确定要离开?更改将丢失", "xpack.infra.sourceConfiguration.updateFailureBody": "无法对指标配置应用更改。请稍后重试。", "xpack.infra.sourceConfiguration.updateFailureTitle": "配置更新失败", diff --git a/x-pack/platform/plugins/shared/logs_shared/common/http_api/index.ts b/x-pack/platform/plugins/shared/logs_shared/common/http_api/index.ts index 939f72786183b..25de1a66b6de6 100644 --- a/x-pack/platform/plugins/shared/logs_shared/common/http_api/index.ts +++ b/x-pack/platform/plugins/shared/logs_shared/common/http_api/index.ts @@ -9,5 +9,4 @@ * Exporting versioned APIs types */ export * from './latest'; -export * as logEntriesV1 from './log_entries/v1'; export * as logViewsV1 from './log_views/v1'; diff --git a/x-pack/platform/plugins/shared/logs_shared/common/http_api/latest.ts b/x-pack/platform/plugins/shared/logs_shared/common/http_api/latest.ts index 63f58bf4f92c0..84ece561371f6 100644 --- a/x-pack/platform/plugins/shared/logs_shared/common/http_api/latest.ts +++ b/x-pack/platform/plugins/shared/logs_shared/common/http_api/latest.ts @@ -5,5 +5,4 @@ * 2.0. */ -export * from './log_entries/v1'; export * from './log_views/v1'; diff --git a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/highlights.ts b/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/highlights.ts deleted file mode 100644 index f879ca3f87961..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/highlights.ts +++ /dev/null @@ -1,70 +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 * as rt from 'io-ts'; -import { logEntryCursorRT, logEntryRT } from '../../../log_entry'; -import { logViewColumnConfigurationRT } from '../../../log_views'; -import { logViewReferenceRT } from '../../../log_views'; - -export const LOG_ENTRIES_HIGHLIGHTS_PATH = '/api/log_entries/highlights'; - -export const logEntriesHighlightsBaseRequestRT = rt.intersection([ - rt.type({ - logView: logViewReferenceRT, - startTimestamp: rt.number, - endTimestamp: rt.number, - highlightTerms: rt.array(rt.string), - }), - rt.partial({ - query: rt.union([rt.string, rt.null]), - size: rt.number, - columns: rt.array(logViewColumnConfigurationRT), - }), -]); - -export const logEntriesHighlightsBeforeRequestRT = rt.intersection([ - logEntriesHighlightsBaseRequestRT, - rt.type({ before: rt.union([logEntryCursorRT, rt.literal('last')]) }), -]); - -export const logEntriesHighlightsAfterRequestRT = rt.intersection([ - logEntriesHighlightsBaseRequestRT, - rt.type({ after: rt.union([logEntryCursorRT, rt.literal('first')]) }), -]); - -export const logEntriesHighlightsCenteredRequestRT = rt.intersection([ - logEntriesHighlightsBaseRequestRT, - rt.type({ center: logEntryCursorRT }), -]); - -export const logEntriesHighlightsRequestRT = rt.union([ - logEntriesHighlightsBaseRequestRT, - logEntriesHighlightsBeforeRequestRT, - logEntriesHighlightsAfterRequestRT, - logEntriesHighlightsCenteredRequestRT, -]); - -export type LogEntriesHighlightsRequest = rt.TypeOf; - -export const logEntriesHighlightsResponseRT = rt.type({ - data: rt.array( - rt.union([ - rt.type({ - topCursor: rt.null, - bottomCursor: rt.null, - entries: rt.array(logEntryRT), - }), - rt.type({ - topCursor: logEntryCursorRT, - bottomCursor: logEntryCursorRT, - entries: rt.array(logEntryRT), - }), - ]) - ), -}); - -export type LogEntriesHighlightsResponse = rt.TypeOf; diff --git a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/index.ts b/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/index.ts deleted file mode 100644 index 83d240ca8f273..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/index.ts +++ /dev/null @@ -1,10 +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. - */ - -export * from './highlights'; -export * from './summary'; -export * from './summary_highlights'; diff --git a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/summary.ts b/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/summary.ts deleted file mode 100644 index 318ff44b296c0..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/summary.ts +++ /dev/null @@ -1,39 +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 * as rt from 'io-ts'; -import { logViewReferenceRT } from '../../../log_views'; - -export const LOG_ENTRIES_SUMMARY_PATH = '/api/log_entries/summary'; - -export const logEntriesSummaryRequestRT = rt.type({ - logView: logViewReferenceRT, - startTimestamp: rt.number, - endTimestamp: rt.number, - bucketSize: rt.number, - query: rt.union([rt.string, rt.undefined, rt.null]), -}); - -export type LogEntriesSummaryRequest = rt.TypeOf; - -export const logEntriesSummaryBucketRT = rt.type({ - start: rt.number, - end: rt.number, - entriesCount: rt.number, -}); - -export type LogEntriesSummaryBucket = rt.TypeOf; - -export const logEntriesSummaryResponseRT = rt.type({ - data: rt.type({ - start: rt.number, - end: rt.number, - buckets: rt.array(logEntriesSummaryBucketRT), - }), -}); - -export type LogEntriesSummaryResponse = rt.TypeOf; diff --git a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/summary_highlights.ts b/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/summary_highlights.ts deleted file mode 100644 index f12bc72fc12f5..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/common/http_api/log_entries/v1/summary_highlights.ts +++ /dev/null @@ -1,47 +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 * as rt from 'io-ts'; -import { logEntryCursorRT } from '../../../log_entry'; -import { logEntriesSummaryRequestRT, logEntriesSummaryBucketRT } from './summary'; - -export const LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH = '/api/log_entries/summary_highlights'; - -export const logEntriesSummaryHighlightsRequestRT = rt.intersection([ - logEntriesSummaryRequestRT, - rt.type({ - highlightTerms: rt.array(rt.string), - }), -]); - -export type LogEntriesSummaryHighlightsRequest = rt.TypeOf< - typeof logEntriesSummaryHighlightsRequestRT ->; - -export const logEntriesSummaryHighlightsBucketRT = rt.intersection([ - logEntriesSummaryBucketRT, - rt.type({ - representativeKey: logEntryCursorRT, - }), -]); - -export type LogEntriesSummaryHighlightsBucket = rt.TypeOf< - typeof logEntriesSummaryHighlightsBucketRT ->; - -export const logEntriesSummaryHighlightsResponseRT = rt.type({ - data: rt.array( - rt.type({ - start: rt.number, - end: rt.number, - buckets: rt.array(logEntriesSummaryHighlightsBucketRT), - }) - ), -}); -export type LogEntriesSummaryHighlightsResponse = rt.TypeOf< - typeof logEntriesSummaryHighlightsResponseRT ->; diff --git a/x-pack/platform/plugins/shared/logs_shared/common/index.ts b/x-pack/platform/plugins/shared/logs_shared/common/index.ts index d5287460b5de8..fab9fa213790d 100644 --- a/x-pack/platform/plugins/shared/logs_shared/common/index.ts +++ b/x-pack/platform/plugins/shared/logs_shared/common/index.ts @@ -47,19 +47,6 @@ export * from './log_entry'; export { convertISODateToNanoPrecision } from './utils'; -// Http types -export type { LogEntriesSummaryBucket, LogEntriesSummaryHighlightsBucket } from './http_api'; - -// Http runtime -export { - LOG_ENTRIES_HIGHLIGHTS_PATH, - LOG_ENTRIES_SUMMARY_PATH, - logEntriesHighlightsRequestRT, - logEntriesHighlightsResponseRT, - logEntriesSummaryRequestRT, - logEntriesSummaryResponseRT, -} from './http_api'; - // Locators export { type LogsLocatorParams, diff --git a/x-pack/platform/plugins/shared/logs_shared/common/time/time_key.ts b/x-pack/platform/plugins/shared/logs_shared/common/time/time_key.ts index 1ff661af69d0a..fa56f74590828 100644 --- a/x-pack/platform/plugins/shared/logs_shared/common/time/time_key.ts +++ b/x-pack/platform/plugins/shared/logs_shared/common/time/time_key.ts @@ -6,7 +6,7 @@ */ import type { TimeKey } from '@kbn/io-ts-utils'; -import { ascending, bisector } from 'd3-array'; +import { ascending } from 'd3-array'; export type Comparator = (firstValue: any, secondValue: any) => number; @@ -38,25 +38,3 @@ export const compareToTimeKey = (keyAccessor: (value: Value) => TimeKey, compareValues?: Comparator) => (value: Value, key: TimeKey) => compareTimeKeys(keyAccessor(value), key, compareValues); - -export const getIndexAtTimeKey = ( - keyAccessor: (value: Value) => TimeKey, - compareValues?: Comparator -) => { - const comparator = compareToTimeKey(keyAccessor, compareValues); - const collectionBisector = bisector(comparator); - - return (collection: Value[], key: TimeKey): number | null => { - const index = collectionBisector.left(collection, key); - - if (index >= collection.length) { - return null; - } - - if (comparator(collection[index], key) !== 0) { - return null; - } - - return index; - }; -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts deleted file mode 100644 index 91f418f943247..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/api/fetch_log_entries_highlights.ts +++ /dev/null @@ -1,30 +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 type { HttpHandler } from '@kbn/core/public'; - -import { decodeOrThrow } from '../../../../../common/runtime_types'; - -import { - LOG_ENTRIES_HIGHLIGHTS_PATH, - LogEntriesHighlightsRequest, - logEntriesHighlightsRequestRT, - logEntriesHighlightsResponseRT, -} from '../../../../../common/http_api'; - -export const fetchLogEntriesHighlights = async ( - requestArgs: LogEntriesHighlightsRequest, - fetch: HttpHandler -) => { - const response = await fetch(LOG_ENTRIES_HIGHLIGHTS_PATH, { - method: 'POST', - body: JSON.stringify(logEntriesHighlightsRequestRT.encode(requestArgs)), - version: '1', - }); - - return decodeOrThrow(logEntriesHighlightsResponseRT)(response); -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts deleted file mode 100644 index 8753926fceb8d..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/api/fetch_log_summary_highlights.ts +++ /dev/null @@ -1,29 +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 type { HttpHandler } from '@kbn/core/public'; -import { decodeOrThrow } from '../../../../../common/runtime_types'; - -import { - LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, - LogEntriesSummaryHighlightsRequest, - logEntriesSummaryHighlightsRequestRT, - logEntriesSummaryHighlightsResponseRT, -} from '../../../../../common/http_api'; - -export const fetchLogSummaryHighlights = async ( - requestArgs: LogEntriesSummaryHighlightsRequest, - fetch: HttpHandler -) => { - const response = await fetch(LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, { - method: 'POST', - body: JSON.stringify(logEntriesSummaryHighlightsRequestRT.encode(requestArgs)), - version: '1', - }); - - return decodeOrThrow(logEntriesSummaryHighlightsResponseRT)(response); -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/index.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/index.ts deleted file mode 100644 index e448689aa281f..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export * from './log_highlights'; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_entry_highlights.tsx b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_entry_highlights.tsx deleted file mode 100644 index 117a78d619596..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_entry_highlights.tsx +++ /dev/null @@ -1,104 +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 { TimeKey } from '@kbn/io-ts-utils'; -import { useEffect, useMemo, useState } from 'react'; -import { LogViewReference } from '../../../../common'; -import { LogEntriesHighlightsResponse } from '../../../../common/http_api'; -import { LogEntry } from '../../../../common/log_entry'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { useTrackedPromise } from '../../../utils/use_tracked_promise'; -import { fetchLogEntriesHighlights } from './api/fetch_log_entries_highlights'; - -export const useLogEntryHighlights = ( - logViewReference: LogViewReference, - sourceVersion: string | undefined, - startTimestamp: number | null, - endTimestamp: number | null, - centerPoint: TimeKey | null, - size: number, - filterQuery: string | null, - highlightTerms: string[] -) => { - const { services } = useKibanaContextForPlugin(); - const [logEntryHighlights, setLogEntryHighlights] = useState< - LogEntriesHighlightsResponse['data'] - >([]); - const [loadLogEntryHighlightsRequest, loadLogEntryHighlights] = useTrackedPromise( - { - cancelPreviousOn: 'resolution', - createPromise: async () => { - if (!startTimestamp || !endTimestamp || !centerPoint || !highlightTerms.length) { - throw new Error('Skipping request: Insufficient parameters'); - } - - return await fetchLogEntriesHighlights( - { - logView: logViewReference, - startTimestamp, - endTimestamp, - center: centerPoint, - size, - query: filterQuery || undefined, - highlightTerms, - }, - services.http.fetch - ); - }, - onResolve: (response) => { - setLogEntryHighlights(response.data); - }, - }, - [logViewReference, startTimestamp, endTimestamp, centerPoint, size, filterQuery, highlightTerms] - ); - - useEffect(() => { - setLogEntryHighlights([]); - }, [highlightTerms]); - - useEffect(() => { - if ( - highlightTerms.filter((highlightTerm) => highlightTerm.length > 0).length && - startTimestamp && - endTimestamp - ) { - loadLogEntryHighlights(); - } else { - setLogEntryHighlights([]); - } - }, [ - endTimestamp, - filterQuery, - highlightTerms, - loadLogEntryHighlights, - sourceVersion, - startTimestamp, - ]); - - const logEntryHighlightsById = useMemo( - () => - logEntryHighlights.reduce>( - (accumulatedLogEntryHighlightsById, highlightData) => { - return highlightData.entries.reduce((singleHighlightLogEntriesById, entry) => { - const highlightsForId = singleHighlightLogEntriesById[entry.id] || []; - return { - ...singleHighlightLogEntriesById, - [entry.id]: [...highlightsForId, entry], - }; - }, accumulatedLogEntryHighlightsById); - }, - {} - ), - [logEntryHighlights] - ); - - return { - logEntryHighlights, - logEntryHighlightsById, - loadLogEntryHighlightsRequest, - }; -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_highlights.tsx b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_highlights.tsx deleted file mode 100644 index 3317f02d034d3..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_highlights.tsx +++ /dev/null @@ -1,93 +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 createContainer from 'constate'; -import { useState } from 'react'; -import useThrottle from 'react-use/lib/useThrottle'; -import { TimeKey } from '@kbn/io-ts-utils'; -import { LogViewReference } from '../../../../common'; -import { useLogEntryHighlights } from './log_entry_highlights'; -import { useLogSummaryHighlights } from './log_summary_highlights'; -import { useNextAndPrevious } from './next_and_previous'; -import { useLogPositionStateContext } from '../log_position'; - -const FETCH_THROTTLE_INTERVAL = 3000; - -interface UseLogHighlightsStateProps { - logViewReference: LogViewReference; - sourceVersion: string | undefined; - centerCursor: TimeKey | null; - size: number; - filterQuery: string | null; -} - -const useLogHighlightsState = ({ - logViewReference, - sourceVersion, - centerCursor, - size, - filterQuery, -}: UseLogHighlightsStateProps) => { - const [highlightTerms, setHighlightTerms] = useState([]); - const { visibleMidpoint, jumpToTargetPosition, startTimestamp, endTimestamp } = - useLogPositionStateContext(); - - const throttledStartTimestamp = useThrottle(startTimestamp, FETCH_THROTTLE_INTERVAL); - const throttledEndTimestamp = useThrottle(endTimestamp, FETCH_THROTTLE_INTERVAL); - - const { logEntryHighlights, logEntryHighlightsById, loadLogEntryHighlightsRequest } = - useLogEntryHighlights( - logViewReference, - sourceVersion, - throttledStartTimestamp, - throttledEndTimestamp, - centerCursor, - size, - filterQuery, - highlightTerms - ); - - const { logSummaryHighlights, loadLogSummaryHighlightsRequest } = useLogSummaryHighlights( - logViewReference, - sourceVersion, - throttledStartTimestamp, - throttledEndTimestamp, - filterQuery, - highlightTerms - ); - - const { - currentHighlightKey, - hasPreviousHighlight, - hasNextHighlight, - goToPreviousHighlight, - goToNextHighlight, - } = useNextAndPrevious({ - visibleMidpoint, - logEntryHighlights, - highlightTerms, - jumpToTargetPosition, - }); - - return { - highlightTerms, - setHighlightTerms, - logEntryHighlights, - logEntryHighlightsById, - logSummaryHighlights, - loadLogEntryHighlightsRequest, - loadLogSummaryHighlightsRequest, - currentHighlightKey, - hasPreviousHighlight, - hasNextHighlight, - goToPreviousHighlight, - goToNextHighlight, - }; -}; - -export const [LogHighlightsStateProvider, useLogHighlightsStateContext] = - createContainer(useLogHighlightsState); diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_summary_highlights.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_summary_highlights.ts deleted file mode 100644 index 61a1a02618e7a..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/log_summary_highlights.ts +++ /dev/null @@ -1,93 +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 { useEffect, useMemo, useState } from 'react'; -import { debounce } from 'lodash'; - -import { LogViewReference } from '../../../../common'; -import { useTrackedPromise } from '../../../utils/use_tracked_promise'; -import { fetchLogSummaryHighlights } from './api/fetch_log_summary_highlights'; -import { LogEntriesSummaryHighlightsResponse } from '../../../../common/http_api'; -import { useBucketSize } from '../log_summary/bucket_size'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; - -export const useLogSummaryHighlights = ( - logViewReference: LogViewReference, - sourceVersion: string | undefined, - startTimestamp: number | null, - endTimestamp: number | null, - filterQuery: string | null, - highlightTerms: string[] -) => { - const { services } = useKibanaContextForPlugin(); - const [logSummaryHighlights, setLogSummaryHighlights] = useState< - LogEntriesSummaryHighlightsResponse['data'] - >([]); - - const bucketSize = useBucketSize(startTimestamp, endTimestamp); - - const [loadLogSummaryHighlightsRequest, loadLogSummaryHighlights] = useTrackedPromise( - { - cancelPreviousOn: 'resolution', - createPromise: async () => { - if (!startTimestamp || !endTimestamp || !bucketSize || !highlightTerms.length) { - throw new Error('Skipping request: Insufficient parameters'); - } - - return await fetchLogSummaryHighlights( - { - logView: logViewReference, - startTimestamp, - endTimestamp, - bucketSize, - query: filterQuery, - highlightTerms, - }, - services.http.fetch - ); - }, - onResolve: (response) => { - setLogSummaryHighlights(response.data); - }, - }, - [logViewReference, startTimestamp, endTimestamp, bucketSize, filterQuery, highlightTerms] - ); - - const debouncedLoadSummaryHighlights = useMemo( - () => debounce(loadLogSummaryHighlights, 275), - [loadLogSummaryHighlights] - ); - - useEffect(() => { - setLogSummaryHighlights([]); - }, [highlightTerms]); - - useEffect(() => { - if ( - highlightTerms.filter((highlightTerm) => highlightTerm.length > 0).length && - startTimestamp && - endTimestamp - ) { - debouncedLoadSummaryHighlights(); - } else { - setLogSummaryHighlights([]); - } - }, [ - bucketSize, - debouncedLoadSummaryHighlights, - filterQuery, - highlightTerms, - sourceVersion, - startTimestamp, - endTimestamp, - ]); - - return { - logSummaryHighlights, - loadLogSummaryHighlightsRequest, - }; -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/next_and_previous.tsx b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/next_and_previous.tsx deleted file mode 100644 index c76d66711b928..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_highlights/next_and_previous.tsx +++ /dev/null @@ -1,105 +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 { isNumber } from 'lodash'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { TimeKey, UniqueTimeKey } from '@kbn/io-ts-utils'; -import { - getLogEntryIndexAtTime, - getLogEntryIndexBeforeTime, - getUniqueLogEntryKey, -} from '../../../utils/log_entry'; -import { LogEntriesHighlightsResponse } from '../../../../common/http_api'; - -export const useNextAndPrevious = ({ - highlightTerms, - jumpToTargetPosition, - logEntryHighlights, - visibleMidpoint, -}: { - highlightTerms: string[]; - jumpToTargetPosition: (target: TimeKey) => void; - logEntryHighlights: LogEntriesHighlightsResponse['data'] | undefined; - visibleMidpoint: TimeKey | null; -}) => { - const [currentTimeKey, setCurrentTimeKey] = useState(null); - - const entries = useMemo( - // simplification, because we only support one highlight phrase for now - () => - logEntryHighlights && logEntryHighlights.length > 0 ? logEntryHighlights[0].entries : [], - [logEntryHighlights] - ); - - useEffect(() => { - setCurrentTimeKey(null); - }, [highlightTerms]); - - useEffect(() => { - if (currentTimeKey) { - jumpToTargetPosition(currentTimeKey); - } - }, [currentTimeKey, jumpToTargetPosition]); - - useEffect(() => { - if (currentTimeKey === null && entries.length > 0) { - const initialIndex = visibleMidpoint - ? clampValue(getLogEntryIndexBeforeTime(entries, visibleMidpoint), 0, entries.length - 1) - : 0; - const initialTimeKey = getUniqueLogEntryKey(entries[initialIndex]); - setCurrentTimeKey(initialTimeKey); - } - }, [currentTimeKey, entries, setCurrentTimeKey, visibleMidpoint]); - - const indexOfCurrentTimeKey = useMemo(() => { - if (currentTimeKey && entries.length > 0) { - return getLogEntryIndexAtTime(entries, currentTimeKey); - } else { - return null; - } - }, [currentTimeKey, entries]); - - const hasPreviousHighlight = useMemo( - () => isNumber(indexOfCurrentTimeKey) && indexOfCurrentTimeKey > 0, - [indexOfCurrentTimeKey] - ); - - const hasNextHighlight = useMemo( - () => - entries.length > 0 && - isNumber(indexOfCurrentTimeKey) && - indexOfCurrentTimeKey < entries.length - 1, - [indexOfCurrentTimeKey, entries] - ); - - const goToPreviousHighlight = useCallback(() => { - if (entries.length && isNumber(indexOfCurrentTimeKey)) { - const previousIndex = indexOfCurrentTimeKey - 1; - const entryTimeKey = getUniqueLogEntryKey(entries[previousIndex]); - setCurrentTimeKey(entryTimeKey); - } - }, [indexOfCurrentTimeKey, entries]); - - const goToNextHighlight = useCallback(() => { - if (entries.length > 0 && isNumber(indexOfCurrentTimeKey)) { - const nextIndex = indexOfCurrentTimeKey + 1; - const entryTimeKey = getUniqueLogEntryKey(entries[nextIndex]); - setCurrentTimeKey(entryTimeKey); - } - }, [indexOfCurrentTimeKey, entries]); - - return { - currentHighlightKey: currentTimeKey, - hasPreviousHighlight, - hasNextHighlight, - goToPreviousHighlight, - goToNextHighlight, - }; -}; - -const clampValue = (value: number, minValue: number, maxValue: number) => - Math.min(Math.max(value, minValue), maxValue); diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/api/fetch_log_summary.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/api/fetch_log_summary.ts deleted file mode 100644 index 5d89b50e6eaae..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/api/fetch_log_summary.ts +++ /dev/null @@ -1,29 +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 type { HttpHandler } from '@kbn/core/public'; -import { decodeOrThrow } from '../../../../../common/runtime_types'; - -import { - LOG_ENTRIES_SUMMARY_PATH, - LogEntriesSummaryRequest, - logEntriesSummaryRequestRT, - logEntriesSummaryResponseRT, -} from '../../../../../common/http_api'; - -export const fetchLogSummary = async ( - requestArgs: LogEntriesSummaryRequest, - fetch: HttpHandler -) => { - const response = await fetch(LOG_ENTRIES_SUMMARY_PATH, { - method: 'POST', - body: JSON.stringify(logEntriesSummaryRequestRT.encode(requestArgs)), - version: '1', - }); - - return decodeOrThrow(logEntriesSummaryResponseRT)(response); -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/bucket_size.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/bucket_size.ts deleted file mode 100644 index ad048d2f8082e..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/bucket_size.ts +++ /dev/null @@ -1,24 +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 { useMemo } from 'react'; - -const SUMMARY_BUCKET_COUNT = 100; - -export function useBucketSize( - startTimestamp: number | null, - endTimestamp: number | null -): number | null { - const bucketSize = useMemo(() => { - if (!startTimestamp || !endTimestamp) { - return null; - } - return (endTimestamp - startTimestamp) / SUMMARY_BUCKET_COUNT; - }, [startTimestamp, endTimestamp]); - - return bucketSize; -} diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/index.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/index.ts deleted file mode 100644 index 935bda868e23b..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/index.ts +++ /dev/null @@ -1,9 +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. - */ - -export * from './log_summary'; -export * from './with_summary'; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx deleted file mode 100644 index 8635df14731a5..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx +++ /dev/null @@ -1,215 +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 { waitFor, renderHook } from '@testing-library/react'; -// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock` -import { coreMock as mockCoreMock } from '@kbn/core/public/mocks'; - -import { useLogSummary } from './log_summary'; - -import { fetchLogSummary } from './api/fetch_log_summary'; -import { datemathToEpochMillis } from '../../../utils/datemath'; - -const LOG_VIEW_REFERENCE = { type: 'log-view-reference' as const, logViewId: 'LOG_VIEW_ID' }; -const CHANGED_LOG_VIEW_REFERENCE = { - type: 'log-view-reference' as const, - logViewId: 'CHANGED_LOG_VIEW_ID', -}; - -// Typescript doesn't know that `fetchLogSummary` is a jest mock. -// We use a second variable with a type cast to help the compiler further down the line. -jest.mock('./api/fetch_log_summary', () => ({ fetchLogSummary: jest.fn() })); -const fetchLogSummaryMock = fetchLogSummary as jest.MockedFunction; - -jest.mock('../../../hooks/use_kibana', () => { - const services = mockCoreMock.createStart(); - return { - useKibanaContextForPlugin: () => ({ services }), - }; -}); - -describe('useLogSummary hook', () => { - beforeEach(() => { - fetchLogSummaryMock.mockClear(); - }); - - it('provides an empty list of buckets by default', () => { - const { result } = renderHook(() => useLogSummary(LOG_VIEW_REFERENCE, null, null, null)); - expect(result.current.buckets).toEqual([]); - }); - - it('queries for new summary buckets when the source id changes', async () => { - const { startTimestamp, endTimestamp } = createMockDateRange(); - - const firstMockResponse = createMockResponse([ - { start: startTimestamp, end: endTimestamp, entriesCount: 1 }, - ]); - const secondMockResponse = createMockResponse([ - { start: startTimestamp, end: endTimestamp, entriesCount: 2 }, - ]); - - fetchLogSummaryMock - .mockResolvedValueOnce(firstMockResponse) - .mockResolvedValueOnce(secondMockResponse); - - const { result, rerender } = renderHook( - ({ logViewReference }) => useLogSummary(logViewReference, startTimestamp, endTimestamp, null), - { - initialProps: { logViewReference: LOG_VIEW_REFERENCE }, - } - ); - - await waitFor(() => new Promise((resolve) => resolve(null))); - - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - logView: LOG_VIEW_REFERENCE, - }), - expect.anything() - ); - expect(result.current.buckets).toEqual(firstMockResponse.data.buckets); - - rerender({ logViewReference: CHANGED_LOG_VIEW_REFERENCE }); - await waitFor(() => new Promise((resolve) => resolve(null))); - - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(2); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - logView: CHANGED_LOG_VIEW_REFERENCE, - }), - expect.anything() - ); - expect(result.current.buckets).toEqual(secondMockResponse.data.buckets); - }); - - it('queries for new summary buckets when the filter query changes', async () => { - const { startTimestamp, endTimestamp } = createMockDateRange(); - - const firstMockResponse = createMockResponse([ - { start: startTimestamp, end: endTimestamp, entriesCount: 1 }, - ]); - const secondMockResponse = createMockResponse([ - { start: startTimestamp, end: endTimestamp, entriesCount: 2 }, - ]); - - fetchLogSummaryMock - .mockResolvedValueOnce(firstMockResponse) - .mockResolvedValueOnce(secondMockResponse); - - const { result, rerender } = renderHook( - ({ filterQuery }) => - useLogSummary(LOG_VIEW_REFERENCE, startTimestamp, endTimestamp, filterQuery), - { - initialProps: { filterQuery: 'INITIAL_FILTER_QUERY' }, - } - ); - - await waitFor(() => new Promise((resolve) => resolve(null))); - - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - query: 'INITIAL_FILTER_QUERY', - }), - expect.anything() - ); - expect(result.current.buckets).toEqual(firstMockResponse.data.buckets); - - rerender({ filterQuery: 'CHANGED_FILTER_QUERY' }); - await waitFor(() => new Promise((resolve) => resolve(null))); - - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(2); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - query: 'CHANGED_FILTER_QUERY', - }), - expect.anything() - ); - expect(result.current.buckets).toEqual(secondMockResponse.data.buckets); - }); - - it('queries for new summary buckets when the start and end date changes', async () => { - fetchLogSummaryMock - .mockResolvedValueOnce(createMockResponse([])) - .mockResolvedValueOnce(createMockResponse([])); - - const firstRange = createMockDateRange(); - const { rerender } = renderHook( - ({ startTimestamp, endTimestamp }) => - useLogSummary(LOG_VIEW_REFERENCE, startTimestamp, endTimestamp, null), - { - initialProps: firstRange, - } - ); - - await waitFor(() => new Promise((resolve) => resolve(null))); - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - startTimestamp: firstRange.startTimestamp, - endTimestamp: firstRange.endTimestamp, - }), - expect.anything() - ); - - const secondRange = createMockDateRange('now-20s', 'now'); - - rerender(secondRange); - await waitFor(() => new Promise((resolve) => resolve(null))); - - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(2); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - startTimestamp: secondRange.startTimestamp, - endTimestamp: secondRange.endTimestamp, - }), - expect.anything() - ); - }); - - it("doesn't query for new summary buckets when the previous request is still in flight", async () => { - fetchLogSummaryMock.mockResolvedValueOnce(createMockResponse([])); - - const firstRange = createMockDateRange(); - const { rerender } = renderHook( - ({ startTimestamp, endTimestamp }) => - useLogSummary(LOG_VIEW_REFERENCE, startTimestamp, endTimestamp, null), - { - initialProps: firstRange, - } - ); - - const secondRange = createMockDateRange('now-20s', 'now'); - - // intentionally don't wait for an update to test the throttling - rerender(secondRange); - await waitFor(() => new Promise((resolve) => resolve(null))); - - expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); - expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( - expect.objectContaining({ - startTimestamp: firstRange.startTimestamp, - endTimestamp: firstRange.endTimestamp, - }), - expect.anything() - ); - }); -}); - -const createMockResponse = ( - buckets: Array<{ start: number; end: number; entriesCount: number }> -) => ({ data: { buckets, start: Number.NEGATIVE_INFINITY, end: Number.POSITIVE_INFINITY } }); - -const createMockDateRange = (startDate = 'now-10s', endDate = 'now') => { - return { - startDate, - endDate, - startTimestamp: datemathToEpochMillis(startDate)!, - endTimestamp: datemathToEpochMillis(endDate, 'up')!, - }; -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/log_summary.tsx b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/log_summary.tsx deleted file mode 100644 index 0360d6d381ada..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/log_summary.tsx +++ /dev/null @@ -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 { useEffect } from 'react'; -import { exhaustMap, map, Observable } from 'rxjs'; -import { HttpHandler } from '@kbn/core-http-browser'; -import { LogViewReference } from '../../../../common'; -import { useObservableState, useReplaySubject } from '../../../utils/use_observable'; -import { fetchLogSummary } from './api/fetch_log_summary'; -import { LogEntriesSummaryRequest, LogEntriesSummaryResponse } from '../../../../common/http_api'; -import { useBucketSize } from './bucket_size'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; - -export type LogSummaryBuckets = LogEntriesSummaryResponse['data']['buckets']; - -export const useLogSummary = ( - logViewReference: LogViewReference, - startTimestamp: number | null, - endTimestamp: number | null, - filterQuery: string | null -) => { - const { services } = useKibanaContextForPlugin(); - const bucketSize = useBucketSize(startTimestamp, endTimestamp); - - const [logSummaryBuckets$, pushLogSummaryBucketsArgs] = useReplaySubject(fetchLogSummary$); - const { latestValue: logSummaryBuckets } = useObservableState(logSummaryBuckets$, NO_BUCKETS); - - useEffect(() => { - if (startTimestamp === null || endTimestamp === null || bucketSize === null) { - return; - } - - pushLogSummaryBucketsArgs([ - { - logView: logViewReference, - startTimestamp, - endTimestamp, - bucketSize, - query: filterQuery, - }, - services.http.fetch, - ]); - }, [ - bucketSize, - endTimestamp, - filterQuery, - pushLogSummaryBucketsArgs, - services.http.fetch, - logViewReference, - startTimestamp, - ]); - - return { - buckets: logSummaryBuckets, - start: startTimestamp, - end: endTimestamp, - }; -}; - -const NO_BUCKETS: LogSummaryBuckets = []; - -type FetchLogSummaryArgs = [args: LogEntriesSummaryRequest, fetch: HttpHandler]; - -const fetchLogSummary$ = ( - fetchArguments$: Observable -): Observable => - fetchArguments$.pipe( - exhaustMap(([args, fetch]) => fetchLogSummary(args, fetch)), - map(({ data: { buckets } }) => buckets) - ); diff --git a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/with_summary.ts b/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/with_summary.ts deleted file mode 100644 index bb8fe69d4356e..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/containers/logs/log_summary/with_summary.ts +++ /dev/null @@ -1,43 +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 useThrottle from 'react-use/lib/useThrottle'; -import { useLogPositionStateContext, useLogViewContext } from '../../..'; -import { RendererFunction } from '../../../utils/typed_react'; -import { LogSummaryBuckets, useLogSummary } from './log_summary'; - -const FETCH_THROTTLE_INTERVAL = 3000; - -export interface WithSummaryProps { - serializedParsedQuery: string | null; - children: RendererFunction<{ - buckets: LogSummaryBuckets; - start: number | null; - end: number | null; - }>; -} - -export const WithSummary = ({ serializedParsedQuery, children }: WithSummaryProps) => { - const { logViewReference } = useLogViewContext(); - const { startTimestamp, endTimestamp } = useLogPositionStateContext(); - - // Keep it reasonably updated for the `now` case, but don't reload all the time when the user scrolls - const throttledStartTimestamp = useThrottle(startTimestamp, FETCH_THROTTLE_INTERVAL); - const throttledEndTimestamp = useThrottle(endTimestamp, FETCH_THROTTLE_INTERVAL); - - const { buckets, start, end } = useLogSummary( - logViewReference, - throttledStartTimestamp, - throttledEndTimestamp, - serializedParsedQuery - ); - - return children({ buckets, start, end }); -}; - -// eslint-disable-next-line import/no-default-export -export default WithSummary; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/index.ts b/x-pack/platform/plugins/shared/logs_shared/public/index.ts index 3d601c9936f2d..be05abd06a69e 100644 --- a/x-pack/platform/plugins/shared/logs_shared/public/index.ts +++ b/x-pack/platform/plugins/shared/logs_shared/public/index.ts @@ -28,11 +28,6 @@ export { LogPositionStateProvider, useLogPositionStateContext, } from './containers/logs/log_position'; -export { - LogHighlightsStateProvider, - useLogHighlightsStateContext, -} from './containers/logs/log_highlights'; -export type { LogSummaryBuckets, WithSummaryProps } from './containers/logs/log_summary'; // Shared components export type { LogAIAssistantDocument } from './components/log_ai_assistant/log_ai_assistant'; @@ -52,7 +47,6 @@ export type { } from './components/logging/log_text_stream/scrollable_log_text_stream_view'; export type { LogsOverviewProps } from './components/logs_overview'; -export const WithSummary = dynamic(() => import('./containers/logs/log_summary/with_summary')); export const LogEntryFlyout = dynamic( () => import('./components/logging/log_entry_flyout/log_entry_flyout') ); diff --git a/x-pack/platform/plugins/shared/logs_shared/public/utils/log_entry/log_entry.ts b/x-pack/platform/plugins/shared/logs_shared/public/utils/log_entry/log_entry.ts index e1027aeeb5799..fa49d3ba27a6b 100644 --- a/x-pack/platform/plugins/shared/logs_shared/public/utils/log_entry/log_entry.ts +++ b/x-pack/platform/plugins/shared/logs_shared/public/utils/log_entry/log_entry.ts @@ -5,11 +5,7 @@ * 2.0. */ -import type { TimeKey, UniqueTimeKey } from '@kbn/io-ts-utils'; -import { bisector } from 'd3-array'; -import { compareToTimeKey, getIndexAtTimeKey } from '../../../common/time'; import { - LogEntry, LogColumn, LogTimestampColumn, LogFieldColumn, @@ -19,25 +15,6 @@ import { LogMessageConstantPart, } from '../../../common/log_entry'; -export const getLogEntryKey = (entry: { cursor: TimeKey }) => entry.cursor; - -export const getUniqueLogEntryKey = (entry: { id: string; cursor: TimeKey }): UniqueTimeKey => ({ - ...entry.cursor, - gid: entry.id, -}); - -const logEntryTimeBisector = bisector(compareToTimeKey(getLogEntryKey)); - -export const getLogEntryIndexBeforeTime = logEntryTimeBisector.left; -export const getLogEntryIndexAfterTime = logEntryTimeBisector.right; -export const getLogEntryIndexAtTime = getIndexAtTimeKey(getLogEntryKey); - -export const getLogEntryAtTime = (entries: LogEntry[], time: TimeKey) => { - const entryIndex = getLogEntryIndexAtTime(entries, time); - - return entryIndex !== null ? entries[entryIndex] : null; -}; - export const isTimestampColumn = (column: LogColumn): column is LogTimestampColumn => column != null && 'time' in column; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/utils/typed_react.tsx b/x-pack/platform/plugins/shared/logs_shared/public/utils/typed_react.tsx deleted file mode 100644 index 664894e1bf05c..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/public/utils/typed_react.tsx +++ /dev/null @@ -1,11 +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 from 'react'; - -export type RendererResult = React.ReactElement | null; -export type RendererFunction = (args: RenderArgs) => Result; diff --git a/x-pack/platform/plugins/shared/logs_shared/public/utils/use_observable.ts b/x-pack/platform/plugins/shared/logs_shared/public/utils/use_observable.ts index 2634a156be986..2899d9f50b764 100644 --- a/x-pack/platform/plugins/shared/logs_shared/public/utils/use_observable.ts +++ b/x-pack/platform/plugins/shared/logs_shared/public/utils/use_observable.ts @@ -6,14 +6,7 @@ */ import { useEffect, useRef, useState } from 'react'; -import { - BehaviorSubject, - Observable, - OperatorFunction, - PartialObserver, - ReplaySubject, - Subscription, -} from 'rxjs'; +import { BehaviorSubject, Observable, OperatorFunction, PartialObserver, Subscription } from 'rxjs'; import { switchMap } from 'rxjs'; export const useLatest = (value: Value) => { @@ -58,22 +51,6 @@ export const useBehaviorSubject = < return [output$, next] as const; }; -export const useReplaySubject = < - InputValue, - OutputValue, - OutputObservable extends Observable ->( - deriveObservableOnce: (input$: Observable) => OutputObservable -) => { - const [[subject$, next], _] = useState(() => { - const newSubject$ = new ReplaySubject(); - const newNext = newSubject$.next.bind(newSubject$); - return [newSubject$, newNext] as const; - }); - const [output$] = useState(() => deriveObservableOnce(subject$)); - return [output$, next] as const; -}; - export const useObservableState = ( state$: Observable, initialState: InitialState | (() => InitialState) diff --git a/x-pack/platform/plugins/shared/logs_shared/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts b/x-pack/platform/plugins/shared/logs_shared/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts index f8102e8f0dffa..9760eab9687b9 100644 --- a/x-pack/platform/plugins/shared/logs_shared/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts +++ b/x-pack/platform/plugins/shared/logs_shared/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts @@ -5,11 +5,6 @@ * 2.0. */ -import { timeMilliseconds } from 'd3-time'; -import { fold, map } from 'fp-ts/lib/Either'; -import { constant, identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; -import * as runtimeTypes from 'io-ts'; import { JsonArray } from '@kbn/utility-types'; import { compact } from 'lodash'; import type { LogsSharedPluginRequestHandlerContext } from '../../../types'; @@ -18,7 +13,6 @@ import { LogEntriesParams, LogEntryDocument, LogEntryQuery, - LogSummaryBucket, LOG_ENTRIES_PAGE_SIZE, } from '../../domains/log_entries_domain'; import { SortedSearchHit } from '../framework'; @@ -28,21 +22,6 @@ import { TIMESTAMP_FIELD, TIEBREAKER_FIELD } from '../../../../common/constants' const TIMESTAMP_FORMAT = 'epoch_millis'; -const MAX_BUCKETS = 1000; - -function getBucketIntervalStarts( - startTimestamp: number, - endTimestamp: number, - bucketSize: number -): Date[] { - // estimated number of buckets - const bucketCount = Math.ceil((endTimestamp - startTimestamp) / bucketSize); - if (bucketCount > MAX_BUCKETS) { - throw new Error(`Requested too many buckets: ${bucketCount} > ${MAX_BUCKETS}`); - } - return timeMilliseconds(new Date(startTimestamp), new Date(endTimestamp), bucketSize); -} - export class LogsSharedKibanaLogEntriesAdapter implements LogEntriesAdapter { constructor(private readonly framework: KibanaFramework) {} @@ -140,86 +119,6 @@ export class LogsSharedKibanaLogEntriesAdapter implements LogEntriesAdapter { hasMoreAfter: sortDirection === 'asc' ? hasMore : undefined, }; } - - public async getContainedLogSummaryBuckets( - requestContext: LogsSharedPluginRequestHandlerContext, - resolvedLogView: ResolvedLogView, - startTimestamp: number, - endTimestamp: number, - bucketSize: number, - filterQuery?: LogEntryQuery - ): Promise { - const bucketIntervalStarts = getBucketIntervalStarts(startTimestamp, endTimestamp, bucketSize); - - const query = { - allow_no_indices: true, - index: resolvedLogView.indices, - ignore_unavailable: true, - body: { - aggregations: { - count_by_date: { - date_range: { - field: TIMESTAMP_FIELD, - format: TIMESTAMP_FORMAT, - ranges: bucketIntervalStarts.map((bucketIntervalStart) => ({ - from: bucketIntervalStart.getTime(), - to: bucketIntervalStart.getTime() + bucketSize, - })), - }, - aggregations: { - top_hits_by_key: { - top_hits: { - size: 1, - sort: [ - { - [TIMESTAMP_FIELD]: { - order: 'asc', - format: 'strict_date_optional_time_nanos', - numeric_type: 'date_nanos', - }, - }, - { [TIEBREAKER_FIELD]: 'asc' }, - ], - _source: false, - }, - }, - }, - }, - }, - query: { - bool: { - filter: [ - ...createQueryFilterClauses(filterQuery), - { - range: { - [TIMESTAMP_FIELD]: { - gte: startTimestamp, - lte: endTimestamp, - format: TIMESTAMP_FORMAT, - }, - }, - }, - ], - }, - }, - runtime_mappings: resolvedLogView.runtimeMappings, - size: 0, - track_total_hits: false, - }, - }; - - const response = await this.framework.callWithRequest(requestContext, 'search', query); - - return pipe( - LogSummaryResponseRuntimeType.decode(response), - map((logSummaryResponse) => - logSummaryResponse.aggregations.count_by_date.buckets.map( - convertDateRangeBucketToSummaryBucket - ) - ), - fold(constant([]), identity) - ); - } } function mapHitsToLogEntryDocuments(hits: SortedSearchHit[], fields: string[]): LogEntryDocument[] { @@ -245,18 +144,6 @@ function mapHitsToLogEntryDocuments(hits: SortedSearchHit[], fields: string[]): }); } -const convertDateRangeBucketToSummaryBucket = ( - bucket: LogSummaryDateRangeBucket -): LogSummaryBucket => ({ - entriesCount: bucket.doc_count, - start: bucket.from || 0, - end: bucket.to || 0, - topEntryKeys: bucket.top_hits_by_key.hits.hits.map((hit) => ({ - tiebreaker: hit.sort[1], - time: hit.sort[0], - })), -}); - const createHighlightQuery = ( highlightTerm: string | undefined, fields: string[] @@ -284,9 +171,6 @@ const createFilterClauses = ( return compact([filterQuery, highlightQuery]) as LogEntryQuery[]; }; -const createQueryFilterClauses = (filterQuery: LogEntryQuery | undefined) => - filterQuery ? [filterQuery] : []; - function processCursor(cursor: LogEntriesParams['cursor']): { sortDirection: 'asc' | 'desc'; searchAfterClause: { search_after?: readonly [string, number] }; @@ -310,35 +194,3 @@ function processCursor(cursor: LogEntriesParams['cursor']): { return { sortDirection: 'asc', searchAfterClause: {} }; } - -const LogSummaryDateRangeBucketRuntimeType = runtimeTypes.intersection([ - runtimeTypes.type({ - doc_count: runtimeTypes.number, - key: runtimeTypes.string, - top_hits_by_key: runtimeTypes.type({ - hits: runtimeTypes.type({ - hits: runtimeTypes.array( - runtimeTypes.type({ - sort: runtimeTypes.tuple([runtimeTypes.string, runtimeTypes.number]), - }) - ), - }), - }), - }), - runtimeTypes.partial({ - from: runtimeTypes.number, - to: runtimeTypes.number, - }), -]); - -export type LogSummaryDateRangeBucket = runtimeTypes.TypeOf< - typeof LogSummaryDateRangeBucketRuntimeType ->; - -const LogSummaryResponseRuntimeType = runtimeTypes.type({ - aggregations: runtimeTypes.type({ - count_by_date: runtimeTypes.type({ - buckets: runtimeTypes.array(LogSummaryDateRangeBucketRuntimeType), - }), - }), -}); diff --git a/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.mock.ts b/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.mock.ts index 74509f11ae4a7..dd739de03f4a9 100644 --- a/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.mock.ts +++ b/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.mock.ts @@ -10,10 +10,7 @@ import { ILogsSharedLogEntriesDomain } from './log_entries_domain'; export const createLogsSharedLogEntriesDomainMock = (): jest.Mocked => { return { - getLogEntriesAround: jest.fn(), getLogEntries: jest.fn(), - getLogSummaryBucketsBetween: jest.fn(), - getLogSummaryHighlightBucketsBetween: jest.fn(), getLogEntryDatasets: jest.fn(), }; }; diff --git a/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.ts index f3cbfb57b09c4..e10d7d87fd0bf 100644 --- a/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/platform/plugins/shared/logs_shared/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -7,11 +7,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { JsonObject } from '@kbn/utility-types'; -import { subtractMillisecondsFromDate } from '../../../../common/utils'; -import { - LogEntriesSummaryBucket, - LogEntriesSummaryHighlightsBucket, -} from '../../../../common/http_api'; import { LogColumn, LogEntry, LogEntryCursor } from '../../../../common/log_entry'; import { LogViewColumnConfiguration, @@ -45,15 +40,6 @@ export interface LogEntriesParams { highlightTerm?: string; } -export interface LogEntriesAroundParams { - startTimestamp: number; - endTimestamp: number; - size?: number; - center: LogEntryCursor; - query?: JsonObject; - highlightTerm?: string; -} - export const LOG_ENTRIES_PAGE_SIZE = 200; const FIELDS_FROM_CONTEXT = ['log.file.path', 'host.name', 'container.id'] as const; @@ -61,35 +47,12 @@ const FIELDS_FROM_CONTEXT = ['log.file.path', 'host.name', 'container.id'] as co const COMPOSITE_AGGREGATION_BATCH_SIZE = 1000; export interface ILogsSharedLogEntriesDomain { - getLogEntriesAround( - requestContext: LogsSharedPluginRequestHandlerContext, - logView: LogViewReference, - params: LogEntriesAroundParams, - columnOverrides?: LogViewColumnConfiguration[] - ): Promise<{ entries: LogEntry[]; hasMoreBefore?: boolean; hasMoreAfter?: boolean }>; getLogEntries( requestContext: LogsSharedPluginRequestHandlerContext, logView: LogViewReference, params: LogEntriesParams, columnOverrides?: LogViewColumnConfiguration[] ): Promise<{ entries: LogEntry[]; hasMoreBefore?: boolean; hasMoreAfter?: boolean }>; - getLogSummaryBucketsBetween( - requestContext: LogsSharedPluginRequestHandlerContext, - logView: LogViewReference, - start: number, - end: number, - bucketSize: number, - filterQuery?: LogEntryQuery - ): Promise; - getLogSummaryHighlightBucketsBetween( - requestContext: LogsSharedPluginRequestHandlerContext, - logView: LogViewReference, - startTimestamp: number, - endTimestamp: number, - bucketSize: number, - highlightQueries: string[], - filterQuery?: LogEntryQuery - ): Promise; getLogEntryDatasets( requestContext: LogsSharedPluginRequestHandlerContext, timestampField: string, @@ -106,66 +69,6 @@ export class LogsSharedLogEntriesDomain implements ILogsSharedLogEntriesDomain { private readonly libs: Pick ) {} - public async getLogEntriesAround( - requestContext: LogsSharedPluginRequestHandlerContext, - logView: LogViewReference, - params: LogEntriesAroundParams, - columnOverrides?: LogViewColumnConfiguration[] - ): Promise<{ entries: LogEntry[]; hasMoreBefore?: boolean; hasMoreAfter?: boolean }> { - const { startTimestamp, endTimestamp, center, query, size, highlightTerm } = params; - - /* - * For odd sizes we will round this value down for the first half, and up - * for the second. This keeps the center cursor right in the center. - * - * For even sizes the half before is one entry bigger than the half after. - * [1, 2, 3, 4, 5, *6*, 7, 8, 9, 10] - * | 5 entries | |4 entries| - */ - const halfSize = (size || LOG_ENTRIES_PAGE_SIZE) / 2; - - const { entries: entriesBefore, hasMoreBefore } = await this.getLogEntries( - requestContext, - logView, - { - startTimestamp, - endTimestamp, - query, - cursor: { before: center }, - size: Math.floor(halfSize), - highlightTerm, - }, - columnOverrides - ); - - /* - * Elasticsearch's `search_after` returns documents after the specified cursor. - * - If we have documents before the center, we search after the last of - * those. The first document of the new group is the center. - * - If there were no documents, we search one milisecond before the - * center. It then becomes the first document. - */ - const cursorAfter = - entriesBefore.length > 0 - ? entriesBefore[entriesBefore.length - 1].cursor - : { time: subtractMillisecondsFromDate(center.time, 1), tiebreaker: 0 }; - - const { entries: entriesAfter, hasMoreAfter } = await this.getLogEntries( - requestContext, - logView, - { - startTimestamp, - endTimestamp, - query, - cursor: { after: cursorAfter }, - size: Math.ceil(halfSize), - highlightTerm, - } - ); - - return { entries: [...entriesBefore, ...entriesAfter], hasMoreBefore, hasMoreAfter }; - } - public async getLogEntries( requestContext: LogsSharedPluginRequestHandlerContext, logView: LogViewReference, @@ -227,86 +130,6 @@ export class LogsSharedLogEntriesDomain implements ILogsSharedLogEntriesDomain { return { entries, hasMoreBefore, hasMoreAfter }; } - public async getLogSummaryBucketsBetween( - requestContext: LogsSharedPluginRequestHandlerContext, - logView: LogViewReference, - start: number, - end: number, - bucketSize: number, - filterQuery?: LogEntryQuery - ): Promise { - const [, { logsDataAccess }, { logViews }] = await this.libs.getStartServices(); - const { savedObjects, elasticsearch } = await requestContext.core; - const logSourcesService = logsDataAccess.services.logSourcesServiceFactory.getLogSourcesService( - savedObjects.client - ); - const resolvedLogView = await logViews - .getClient(savedObjects.client, elasticsearch.client.asCurrentUser, logSourcesService) - .getResolvedLogView(logView); - - const dateRangeBuckets = await this.adapter.getContainedLogSummaryBuckets( - requestContext, - resolvedLogView, - start, - end, - bucketSize, - filterQuery - ); - return dateRangeBuckets; - } - - public async getLogSummaryHighlightBucketsBetween( - requestContext: LogsSharedPluginRequestHandlerContext, - logView: LogViewReference, - startTimestamp: number, - endTimestamp: number, - bucketSize: number, - highlightQueries: string[], - filterQuery?: LogEntryQuery - ): Promise { - const [, { logsDataAccess }, { logViews }] = await this.libs.getStartServices(); - const { savedObjects, elasticsearch } = await requestContext.core; - const logSourcesService = logsDataAccess.services.logSourcesServiceFactory.getLogSourcesService( - savedObjects.client - ); - - const resolvedLogView = await logViews - .getClient(savedObjects.client, elasticsearch.client.asCurrentUser, logSourcesService) - .getResolvedLogView(logView); - - const messageFormattingRules = compileFormattingRules( - getBuiltinRules(resolvedLogView.messageField) - ); - const requiredFields = getRequiredFields(resolvedLogView, messageFormattingRules); - - const summaries = await Promise.all( - highlightQueries.map(async (highlightQueryPhrase) => { - const highlightQuery = createHighlightQueryDsl(highlightQueryPhrase, requiredFields); - const query = filterQuery - ? { - bool: { - must: [filterQuery, highlightQuery], - }, - } - : highlightQuery; - const summaryBuckets = await this.adapter.getContainedLogSummaryBuckets( - requestContext, - resolvedLogView, - startTimestamp, - endTimestamp, - bucketSize, - query - ); - const summaryHighlightBuckets = summaryBuckets - .filter(logSummaryBucketHasEntries) - .map(convertLogSummaryBucketToSummaryHighlightBucket); - return summaryHighlightBuckets; - }) - ); - - return summaries; - } - public async getLogEntryDatasets( requestContext: LogsSharedPluginRequestHandlerContext, timestampField: string, @@ -356,15 +179,6 @@ export interface LogEntriesAdapter { fields: string[], params: LogEntriesParams ): Promise<{ documents: LogEntryDocument[]; hasMoreBefore?: boolean; hasMoreAfter?: boolean }>; - - getContainedLogSummaryBuckets( - requestContext: LogsSharedPluginRequestHandlerContext, - resolvedLogView: ResolvedLogView, - startTimestamp: number, - endTimestamp: number, - bucketSize: number, - filterQuery?: LogEntryQuery - ): Promise; } export type LogEntryQuery = JsonObject; @@ -377,25 +191,6 @@ export interface LogEntryDocument { cursor: LogEntryCursor; } -export interface LogSummaryBucket { - entriesCount: number; - start: number; - end: number; - topEntryKeys: LogEntryCursor[]; -} - -const logSummaryBucketHasEntries = (bucket: LogSummaryBucket) => - bucket.entriesCount > 0 && bucket.topEntryKeys.length > 0; - -const convertLogSummaryBucketToSummaryHighlightBucket = ( - bucket: LogSummaryBucket -): LogEntriesSummaryHighlightsBucket => ({ - entriesCount: bucket.entriesCount, - start: bucket.start, - end: bucket.end, - representativeKey: bucket.topEntryKeys[0], -}); - const getRequiredFields = ( configuration: ResolvedLogView, messageFormattingRules: CompiledLogMessageFormattingRule @@ -416,15 +211,6 @@ const getRequiredFields = ( ); }; -const createHighlightQueryDsl = (phrase: string, fields: string[]) => ({ - multi_match: { - fields, - lenient: true, - query: phrase, - type: 'phrase', - }, -}); - const getContextFromDoc = (doc: LogEntryDocument): LogEntry['context'] => { // Get all context fields, then test for the presence and type of the ones that go together const containerId = doc.fields['container.id']?.[0]; diff --git a/x-pack/platform/plugins/shared/logs_shared/server/logs_shared_server.ts b/x-pack/platform/plugins/shared/logs_shared/server/logs_shared_server.ts index 9bb643c8dd617..d49904866a489 100644 --- a/x-pack/platform/plugins/shared/logs_shared/server/logs_shared_server.ts +++ b/x-pack/platform/plugins/shared/logs_shared/server/logs_shared_server.ts @@ -6,18 +6,11 @@ */ import { LogsSharedBackendLibs } from './lib/logs_shared_types'; -import { - initLogEntriesHighlightsRoute, - initLogEntriesSummaryHighlightsRoute, - initLogEntriesSummaryRoute, -} from './routes/log_entries'; + import { initLogViewRoutes } from './routes/log_views'; import { initMigrateLogViewSettingsRoute } from './routes/deprecations'; export const initLogsSharedServer = (libs: LogsSharedBackendLibs) => { - initLogEntriesHighlightsRoute(libs); - initLogEntriesSummaryRoute(libs); - initLogEntriesSummaryHighlightsRoute(libs); initLogViewRoutes(libs); initMigrateLogViewSettingsRoute(libs); }; diff --git a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/highlights.ts b/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/highlights.ts deleted file mode 100644 index dedf3ced27f28..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/highlights.ts +++ /dev/null @@ -1,118 +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 Boom from '@hapi/boom'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { schema } from '@kbn/config-schema'; - -import { i18n } from '@kbn/i18n'; -import { logEntriesV1 } from '../../../common/http_api'; -import { throwErrors } from '../../../common/runtime_types'; - -import { LogsSharedBackendLibs } from '../../lib/logs_shared_types'; - -import { parseFilterQuery } from '../../utils/serialized_query'; -import { LogEntriesParams } from '../../lib/domains/log_entries_domain'; - -const escapeHatch = schema.object({}, { unknowns: 'allow' }); - -export const initLogEntriesHighlightsRoute = ({ framework, logEntries }: LogsSharedBackendLibs) => { - framework - .registerVersionedRoute({ - access: 'internal', - method: 'post', - path: logEntriesV1.LOG_ENTRIES_HIGHLIGHTS_PATH, - }) - .addVersion( - { - version: '1', - validate: { request: { body: escapeHatch } }, - options: { - deprecated: { - documentationUrl: '', - severity: 'warning', - message: i18n.translate( - 'xpack.logsShared.deprecations.postLogEntriesHighlightsRoute.message', - { - defaultMessage: - 'Given the deprecation of the LogStream feature, this API will not return reliable data in upcoming versions of Kibana.', - } - ), - reason: { type: 'deprecate' }, - }, - }, - }, - async (requestContext, request, response) => { - const payload = pipe( - logEntriesV1.logEntriesHighlightsRequestRT.decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - - const { startTimestamp, endTimestamp, logView, query, size, highlightTerms } = payload; - - let entriesPerHighlightTerm; - - if ('center' in payload) { - entriesPerHighlightTerm = await Promise.all( - highlightTerms.map((highlightTerm) => - logEntries.getLogEntriesAround(requestContext, logView, { - startTimestamp, - endTimestamp, - query: parseFilterQuery(query), - center: payload.center, - size, - highlightTerm, - }) - ) - ); - } else { - let cursor: LogEntriesParams['cursor']; - if ('before' in payload) { - cursor = { before: payload.before }; - } else if ('after' in payload) { - cursor = { after: payload.after }; - } - - entriesPerHighlightTerm = await Promise.all( - highlightTerms.map((highlightTerm) => - logEntries.getLogEntries(requestContext, logView, { - startTimestamp, - endTimestamp, - query: parseFilterQuery(query), - cursor, - size, - highlightTerm, - }) - ) - ); - } - - return response.ok({ - body: logEntriesV1.logEntriesHighlightsResponseRT.encode({ - data: entriesPerHighlightTerm.map(({ entries }) => { - if (entries.length > 0) { - return { - entries, - topCursor: entries[0].cursor, - bottomCursor: entries[entries.length - 1].cursor, - }; - } else { - return { - entries, - topCursor: null, - bottomCursor: null, - }; - } - }), - }), - }); - } - ); -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/index.ts b/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/index.ts deleted file mode 100644 index 83d240ca8f273..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/index.ts +++ /dev/null @@ -1,10 +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. - */ - -export * from './highlights'; -export * from './summary'; -export * from './summary_highlights'; diff --git a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/summary.ts b/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/summary.ts deleted file mode 100644 index 68c9d5ea0e166..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/summary.ts +++ /dev/null @@ -1,88 +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 Boom from '@hapi/boom'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { schema } from '@kbn/config-schema'; - -import { i18n } from '@kbn/i18n'; -import { logEntriesV1 } from '../../../common/http_api'; -import { throwErrors } from '../../../common/runtime_types'; - -import { LogsSharedBackendLibs } from '../../lib/logs_shared_types'; - -import { parseFilterQuery } from '../../utils/serialized_query'; - -const escapeHatch = schema.object({}, { unknowns: 'allow' }); - -export const initLogEntriesSummaryRoute = ({ - framework, - logEntries, - getUsageCollector, -}: LogsSharedBackendLibs) => { - framework - .registerVersionedRoute({ - access: 'internal', - method: 'post', - path: logEntriesV1.LOG_ENTRIES_SUMMARY_PATH, - }) - .addVersion( - { - version: '1', - validate: { request: { body: escapeHatch } }, - options: { - deprecated: { - documentationUrl: '', - severity: 'warning', - message: i18n.translate( - 'xpack.logsShared.deprecations.postLogEntriesSummaryRoute.message', - { - defaultMessage: - 'Given the deprecation of the LogStream feature, this API will not return reliable data in upcoming versions of Kibana.', - } - ), - reason: { type: 'deprecate' }, - }, - }, - }, - async (requestContext, request, response) => { - const payload = pipe( - logEntriesV1.logEntriesSummaryRequestRT.decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - const { logView, startTimestamp, endTimestamp, bucketSize, query } = payload; - - const usageCollector = getUsageCollector(); - - const buckets = await logEntries.getLogSummaryBucketsBetween( - requestContext, - logView, - startTimestamp, - endTimestamp, - bucketSize, - parseFilterQuery(query) - ); - - if (typeof usageCollector.countLogs === 'function') { - usageCollector.countLogs(); - } - - return response.ok({ - body: logEntriesV1.logEntriesSummaryResponseRT.encode({ - data: { - start: startTimestamp, - end: endTimestamp, - buckets, - }, - }), - }); - } - ); -}; diff --git a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/summary_highlights.ts b/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/summary_highlights.ts deleted file mode 100644 index b8f030b91b715..0000000000000 --- a/x-pack/platform/plugins/shared/logs_shared/server/routes/log_entries/summary_highlights.ts +++ /dev/null @@ -1,83 +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 Boom from '@hapi/boom'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { schema } from '@kbn/config-schema'; - -import { i18n } from '@kbn/i18n'; -import { logEntriesV1 } from '../../../common/http_api'; -import { throwErrors } from '../../../common/runtime_types'; - -import { LogsSharedBackendLibs } from '../../lib/logs_shared_types'; - -import { parseFilterQuery } from '../../utils/serialized_query'; - -const escapeHatch = schema.object({}, { unknowns: 'allow' }); - -export const initLogEntriesSummaryHighlightsRoute = ({ - framework, - logEntries, -}: LogsSharedBackendLibs) => { - framework - .registerVersionedRoute({ - access: 'internal', - method: 'post', - path: logEntriesV1.LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, - }) - .addVersion( - { - version: '1', - validate: { request: { body: escapeHatch } }, - options: { - deprecated: { - documentationUrl: '', - severity: 'warning', - message: i18n.translate( - 'xpack.logsShared.deprecations.postLogEntriesSummaryHighlightsRoute.message', - { - defaultMessage: - 'Given the deprecation of the LogStream feature, this API will not return reliable data in upcoming versions of Kibana.', - } - ), - reason: { type: 'deprecate' }, - }, - }, - }, - async (requestContext, request, response) => { - const payload = pipe( - logEntriesV1.logEntriesSummaryHighlightsRequestRT.decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - const { logView, startTimestamp, endTimestamp, bucketSize, query, highlightTerms } = - payload; - - const bucketsPerHighlightTerm = await logEntries.getLogSummaryHighlightBucketsBetween( - requestContext, - logView, - startTimestamp, - endTimestamp, - bucketSize, - highlightTerms, - parseFilterQuery(query) - ); - - return response.ok({ - body: logEntriesV1.logEntriesSummaryHighlightsResponseRT.encode({ - data: bucketsPerHighlightTerm.map((buckets) => ({ - start: startTimestamp, - end: endTimestamp, - buckets, - })), - }), - }); - } - ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/common/log_search_result/index.ts b/x-pack/solutions/observability/plugins/infra/common/log_search_result/index.ts deleted file mode 100644 index 592b23dfc70ad..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/common/log_search_result/index.ts +++ /dev/null @@ -1,13 +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. - */ - -export type { SearchResult } from './log_search_result'; -export { - getSearchResultIndexBeforeTime, - getSearchResultIndexAfterTime, - getSearchResultKey, -} from './log_search_result'; diff --git a/x-pack/solutions/observability/plugins/infra/common/log_search_result/log_search_result.ts b/x-pack/solutions/observability/plugins/infra/common/log_search_result/log_search_result.ts deleted file mode 100644 index 18d0990a80be5..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/common/log_search_result/log_search_result.ts +++ /dev/null @@ -1,32 +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 { bisector } from 'd3-array'; - -import type { TimeKey } from '../time'; -import { compareToTimeKey } from '../time'; - -export interface SearchResult { - gid: string; - fields: TimeKey; - matches: SearchResultFieldMatches; -} - -export interface SearchResultFieldMatches { - [field: string]: string[]; -} - -export const getSearchResultKey = (result: SearchResult) => - ({ - gid: result.gid, - tiebreaker: result.fields.tiebreaker, - time: result.fields.time, - } as TimeKey); - -const searchResultTimeBisector = bisector(compareToTimeKey(getSearchResultKey)); -export const getSearchResultIndexBeforeTime = searchResultTimeBisector.left; -export const getSearchResultIndexAfterTime = searchResultTimeBisector.right; diff --git a/x-pack/solutions/observability/plugins/infra/common/log_search_summary/index.ts b/x-pack/solutions/observability/plugins/infra/common/log_search_summary/index.ts deleted file mode 100644 index 32652753f7799..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/common/log_search_summary/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export type { SearchSummaryBucket } from './log_search_summary'; diff --git a/x-pack/solutions/observability/plugins/infra/common/log_search_summary/log_search_summary.ts b/x-pack/solutions/observability/plugins/infra/common/log_search_summary/log_search_summary.ts deleted file mode 100644 index 09132029261a2..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/common/log_search_summary/log_search_summary.ts +++ /dev/null @@ -1,15 +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 type { SearchResult } from '../log_search_result'; - -export interface SearchSummaryBucket { - start: number; - end: number; - count: number; - representative: SearchResult; -} diff --git a/x-pack/solutions/observability/plugins/infra/common/log_text_scale/index.ts b/x-pack/solutions/observability/plugins/infra/common/log_text_scale/index.ts deleted file mode 100644 index 11ae6d0adc7ff..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/common/log_text_scale/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export * from './log_text_scale'; diff --git a/x-pack/solutions/observability/plugins/infra/common/log_text_scale/log_text_scale.ts b/x-pack/solutions/observability/plugins/infra/common/log_text_scale/log_text_scale.ts deleted file mode 100644 index 7fc774c4b59e0..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/common/log_text_scale/log_text_scale.ts +++ /dev/null @@ -1,12 +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. - */ - -export type TextScale = 'small' | 'medium' | 'large'; - -export function isTextScale(maybeTextScale: string): maybeTextScale is TextScale { - return ['small', 'medium', 'large'].includes(maybeTextScale); -} diff --git a/x-pack/solutions/observability/plugins/infra/common/time/time_key.ts b/x-pack/solutions/observability/plugins/infra/common/time/time_key.ts index 7acbef8b25025..9cfa14357255c 100644 --- a/x-pack/solutions/observability/plugins/infra/common/time/time_key.ts +++ b/x-pack/solutions/observability/plugins/infra/common/time/time_key.ts @@ -6,7 +6,7 @@ */ import { DateFromStringOrNumber } from '@kbn/io-ts-utils'; -import { ascending, bisector } from 'd3-array'; +import { ascending } from 'd3-array'; import * as rt from 'io-ts'; import { pick } from 'lodash'; @@ -69,28 +69,6 @@ export const compareToTimeKey = (value: Value, key: TimeKey) => compareTimeKeys(keyAccessor(value), key, compareValues); -export const getIndexAtTimeKey = ( - keyAccessor: (value: Value) => TimeKey, - compareValues?: Comparator -) => { - const comparator = compareToTimeKey(keyAccessor, compareValues); - const collectionBisector = bisector(comparator); - - return (collection: Value[], key: TimeKey): number | null => { - const index = collectionBisector.left(collection, key); - - if (index >= collection.length) { - return null; - } - - if (comparator(collection[index], key) !== 0) { - return null; - } - - return index; - }; -}; - export const timeKeyIsBetween = (min: TimeKey, max: TimeKey, operand: TimeKey) => compareTimeKeys(min, operand) <= 0 && compareTimeKeys(max, operand) >= 0; diff --git a/x-pack/solutions/observability/plugins/infra/common/url_state_storage_service.ts b/x-pack/solutions/observability/plugins/infra/common/url_state_storage_service.ts index 9eeaa86b9aebf..de065e25026d0 100644 --- a/x-pack/solutions/observability/plugins/infra/common/url_state_storage_service.ts +++ b/x-pack/solutions/observability/plugins/infra/common/url_state_storage_service.ts @@ -7,39 +7,12 @@ import { url } from '@kbn/kibana-utils-plugin/common'; import { encode } from '@kbn/rison'; -import type { Query } from '@kbn/es-query'; import { parse, stringify } from 'query-string'; -import type { DurationInputObject } from 'moment'; -import moment from 'moment'; -import type { LogViewReference } from '@kbn/logs-shared-plugin/common'; -import { - defaultFilterStateKey, - defaultPositionStateKey, - DEFAULT_REFRESH_INTERVAL, -} from '@kbn/logs-shared-plugin/common'; -import type { FilterStateInUrl } from '../public/observability_logs/log_stream_query_state'; -import type { PositionStateInUrl } from '../public/observability_logs/log_stream_position_state/src/url_state_storage_service'; -import type { TimeRange } from './time'; export const defaultLogViewKey = 'logView'; const encodeRisonUrlState = (state: any) => encode(state); -// Used by Locator components -export const replaceLogPositionInQueryString = (time?: number) => - Number.isNaN(time) || time == null - ? (value: string) => value - : replaceStateKeyInQueryString(defaultPositionStateKey, { - position: { - time: moment(time).toISOString(), - tiebreaker: 0, - }, - }); - -// NOTE: Used by Locator components -export const replaceLogViewInQueryString = (logViewReference: LogViewReference) => - replaceStateKeyInQueryString(defaultLogViewKey, logViewReference); - export const replaceStateKeyInQueryString = (stateKey: string, urlState: UrlState | undefined) => (queryString: string) => { @@ -53,38 +26,3 @@ export const replaceStateKeyInQueryString = }; return stringify(url.encodeQuery(newValue), { sort: false, encode: false }); }; - -export const replaceLogFilterInQueryString = (query: Query, time?: number, timeRange?: TimeRange) => - replaceStateKeyInQueryString(defaultFilterStateKey, { - query, - ...getTimeRange(time, timeRange), - refreshInterval: DEFAULT_REFRESH_INTERVAL, - }); - -const getTimeRange = (time?: number, timeRange?: TimeRange) => { - if (timeRange) { - return { - timeRange: { - from: new Date(timeRange.startTime).toISOString(), - to: new Date(timeRange.endTime).toISOString(), - }, - }; - } else if (time) { - return { - timeRange: { - from: getTimeRangeStartFromTime(time), - to: getTimeRangeEndFromTime(time), - }, - }; - } else { - return {}; - } -}; - -const defaultTimeRangeFromPositionOffset: DurationInputObject = { hours: 1 }; - -export const getTimeRangeStartFromTime = (time: number): string => - moment(time).subtract(defaultTimeRangeFromPositionOffset).toISOString(); - -export const getTimeRangeEndFromTime = (time: number): string => - moment(time).add(defaultTimeRangeFromPositionOffset).toISOString(); diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/inline_log_view_splash_page.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/inline_log_view_splash_page.tsx deleted file mode 100644 index 579290f45051c..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/inline_log_view_splash_page.tsx +++ /dev/null @@ -1,72 +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 from 'react'; -import { EuiButton } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; -import { EuiEmptyPrompt } from '@elastic/eui'; -import { EuiText } from '@elastic/eui'; -import { PageTemplate } from '../page_template'; - -type InlineLogViewSplashPageProps = { - revertToDefaultLogView: () => void; -} & LazyObservabilityPageTemplateProps; - -export const InlineLogViewSplashPage: React.FC = (props) => { - const { revertToDefaultLogView, ...templateProps } = props; - return ( - - - - ); -}; - -export const InlineLogViewSplashPrompt: React.FC<{ - revertToDefaultLogView: InlineLogViewSplashPageProps['revertToDefaultLogView']; -}> = ({ revertToDefaultLogView }) => { - const title = ( - - ); - - const ctaButton = ( - - - - ); - - const description = ( - - ); - - return ( - {title}} - body={ - -

{description}

-
- } - actions={ctaButton} - /> - ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_customization_menu.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_customization_menu.tsx deleted file mode 100644 index e39053a489a49..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_customization_menu.tsx +++ /dev/null @@ -1,79 +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 { EuiButtonEmpty, EuiPopover } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import * as React from 'react'; -import styled from '@emotion/styled'; - -interface LogCustomizationMenuState { - isShown: boolean; -} - -export class LogCustomizationMenu extends React.Component< - React.PropsWithChildren<{}>, - LogCustomizationMenuState -> { - public readonly state = { - isShown: false, - }; - - public show = () => { - this.setState({ - isShown: true, - }); - }; - - public hide = () => { - this.setState({ - isShown: false, - }); - }; - - public toggleVisibility = () => { - this.setState((state) => ({ - isShown: !state.isShown, - })); - }; - - public render() { - const { children } = this.props; - const { isShown } = this.state; - - const menuButton = ( - - - - ); - - return ( - - {children} - - ); - } -} - -const CustomizationMenuContent = styled.div` - min-width: 200px; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_datepicker.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_datepicker.tsx deleted file mode 100644 index 214085dc6c6ce..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_datepicker.tsx +++ /dev/null @@ -1,82 +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, { useCallback } from 'react'; -import type { OnTimeChangeProps } from '@elastic/eui'; -import { EuiFlexGroup, EuiFlexItem, EuiSuperDatePicker, EuiButton } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -interface LogDatepickerProps { - startDateExpression: string; - endDateExpression: string; - isStreaming: boolean; - onUpdateDateRange?: (range: { startDateExpression: string; endDateExpression: string }) => void; - onStartStreaming?: () => void; - onStopStreaming?: () => void; -} - -export const LogDatepicker: React.FC = ({ - startDateExpression, - endDateExpression, - isStreaming, - onUpdateDateRange, - onStartStreaming, - onStopStreaming, -}) => { - const handleTimeChange = useCallback( - ({ start, end, isInvalid }: OnTimeChangeProps) => { - if (onUpdateDateRange && !isInvalid) { - onUpdateDateRange({ startDateExpression: start, endDateExpression: end }); - } - }, - [onUpdateDateRange] - ); - - return ( - - - - - - {isStreaming ? ( - - - - ) : ( - - - - )} - - - ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_highlights_menu.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_highlights_menu.tsx deleted file mode 100644 index 1657fdc51450d..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_highlights_menu.tsx +++ /dev/null @@ -1,190 +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 { - EuiButtonEmpty, - EuiButtonIcon, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiPopover, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { debounce } from 'lodash'; -import React, { useCallback, useMemo, useState } from 'react'; -import styled from '@emotion/styled'; -import { useVisibilityState } from '../../hooks/use_visibility_state'; -import { withAttrs } from '../../utils/theme_utils/with_attrs'; - -interface LogHighlightsMenuProps { - onChange: (highlightTerms: string[]) => void; - isLoading: boolean; - activeHighlights: boolean; - hasPreviousHighlight: boolean; - hasNextHighlight: boolean; - goToPreviousHighlight: () => void; - goToNextHighlight: () => void; -} - -export const LogHighlightsMenu: React.FC = ({ - onChange, - isLoading, - activeHighlights, - hasPreviousHighlight, - goToPreviousHighlight, - hasNextHighlight, - goToNextHighlight, -}) => { - const { - isVisible: isPopoverOpen, - hide: closePopover, - toggle: togglePopover, - } = useVisibilityState(false); - - // Input field state - const [highlightTerm, _setHighlightTerm] = useState(''); - - const debouncedOnChange = useMemo(() => debounce(onChange, 275), [onChange]); - const setHighlightTerm = useCallback( - (valueOrUpdater) => - _setHighlightTerm((previousHighlightTerm) => { - const newHighlightTerm = - typeof valueOrUpdater === 'function' - ? valueOrUpdater(previousHighlightTerm) - : valueOrUpdater; - - if (newHighlightTerm !== previousHighlightTerm) { - debouncedOnChange([newHighlightTerm]); - } - - return newHighlightTerm; - }), - [debouncedOnChange] - ); - const changeHighlightTerm = useCallback( - (e: React.ChangeEvent) => { - const value = e.target.value; - setHighlightTerm(value); - }, - [setHighlightTerm] - ); - const clearHighlightTerm = useCallback(() => setHighlightTerm(''), [setHighlightTerm]); - - const button = ( - - - {activeHighlights ? : null} - - ); - return ( - - - - - - - - - - - - - - - - - - - ); -}; - -const termsFieldLabel = i18n.translate('xpack.infra.logs.highlights.highlightTermsFieldLabel', { - defaultMessage: 'Terms to highlight', -}); - -const clearTermsButtonLabel = i18n.translate( - 'xpack.infra.logs.highlights.clearHighlightTermsButtonLabel', - { - defaultMessage: 'Clear terms to highlight', - } -); - -const goToPreviousHighlightLabel = i18n.translate( - 'xpack.infra.logs.highlights.goToPreviousHighlightButtonLabel', - { - defaultMessage: 'Jump to previous highlight', - } -); - -const goToNextHighlightLabel = i18n.translate( - 'xpack.infra.logs.highlights.goToNextHighlightButtonLabel', - { - defaultMessage: 'Jump to next highlight', - } -); - -const ActiveHighlightsIndicator = withAttrs( - styled(EuiIcon)` - padding-left: ${(props) => props.theme.euiTheme.size.xs}; - `, - ({ theme }) => ({ - type: 'checkInCircleFilled', - size: 'm', - color: theme?.euiTheme.colors.accent, - }) -); - -const LogHighlightsMenuContent = styled.div` - width: 300px; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/density_chart.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/density_chart.tsx deleted file mode 100644 index bcf9b4338b1c4..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/density_chart.tsx +++ /dev/null @@ -1,80 +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 { scaleLinear, scaleTime } from 'd3-scale'; -import { area, curveMonotoneY } from 'd3-shape'; -import { max } from 'lodash'; -import * as React from 'react'; -import styled from '@emotion/styled'; -import type { LogEntriesSummaryBucket } from '@kbn/logs-shared-plugin/common'; -import { COLOR_MODES_STANDARD } from '@elastic/eui'; - -interface DensityChartProps { - buckets: LogEntriesSummaryBucket[]; - end: number; - start: number; - width: number; - height: number; -} - -export const DensityChart: React.FC = ({ - buckets, - start, - end, - width, - height, -}) => { - if (start >= end || height <= 0 || width <= 0 || buckets.length <= 0) { - return null; - } - - const yScale = scaleTime().domain([start, end]).range([0, height]); - - const xMax = max(buckets.map((bucket) => bucket.entriesCount)) || 0; - const xScale = scaleLinear().domain([0, xMax]).range([0, width]); - - const path = area() - .x0(xScale(0) ?? 0) - .x1((bucket) => xScale(bucket.entriesCount) ?? 0) - .y0((bucket) => yScale(bucket.start) ?? 0) - .y1((bucket) => yScale(bucket.end) ?? 0) - .curve(curveMonotoneY); - - const firstBucket = buckets[0]; - const lastBucket = buckets[buckets.length - 1]; - const pathBuckets = [ - // Make sure the graph starts at the count of the first point - { start, end: start, entriesCount: firstBucket.entriesCount }, - ...buckets, - // Make sure the line ends at the height of the last point - { start: lastBucket.end, end: lastBucket.end, entriesCount: lastBucket.entriesCount }, - // If the last point is not at the end of the minimap, make sure it doesn't extend indefinitely and goes to 0 - { start: end, end, entriesCount: 0 }, - ]; - const pathData = path(pathBuckets); - - return ( - - - - - ); -}; - -const DensityChartPositiveBackground = styled.rect` - fill: ${(props) => - props.theme.colorMode === COLOR_MODES_STANDARD.dark - ? props.theme.euiTheme.colors.lightShade - : props.theme.euiTheme.colors.lightestShade}; -`; - -const PositiveAreaPath = styled.path` - fill: ${(props) => - props.theme.colorMode === COLOR_MODES_STANDARD.dark - ? props.theme.euiTheme.colors.mediumShade - : props.theme.euiTheme.colors.lightShade}; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/highlighted_interval.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/highlighted_interval.tsx deleted file mode 100644 index a672488cc2c5e..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/highlighted_interval.tsx +++ /dev/null @@ -1,65 +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 * as React from 'react'; -import styled from '@emotion/styled'; - -interface HighlightedIntervalProps { - className?: string; - getPositionOfTime: (time: number) => number; - start: number; - end: number; - targetWidth: number; - width: number; - target: number | null; -} - -export const HighlightedInterval: React.FC = ({ - className, - end, - getPositionOfTime, - start, - targetWidth, - width, - target, -}) => { - const yStart = getPositionOfTime(start); - const yEnd = getPositionOfTime(end); - const yTarget = target && getPositionOfTime(target); - - return ( - <> - {yTarget && ( - - )} - - - ); -}; - -HighlightedInterval.displayName = 'HighlightedInterval'; - -const HighlightTargetMarker = styled.line` - stroke: ${(props) => props.theme.euiTheme.colors.primary}; - stroke-width: 1; -`; - -const HighlightPolygon = styled.polygon` - fill: ${(props) => props.theme.euiTheme.colors.primary}; - fill-opacity: 0.3; - stroke: ${(props) => props.theme.euiTheme.colors.primary}; - stroke-width: 1; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/index.ts b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/index.ts deleted file mode 100644 index e6b9c59414aa7..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export { LogMinimap } from './log_minimap'; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/log_minimap.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/log_minimap.tsx deleted file mode 100644 index bc9c61db300da..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/log_minimap.tsx +++ /dev/null @@ -1,184 +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 styled from '@emotion/styled'; -import type { - LogEntriesSummaryBucket, - LogEntriesSummaryHighlightsBucket, - LogEntryTime, -} from '@kbn/logs-shared-plugin/common'; -import { scaleLinear } from 'd3-scale'; -import moment from 'moment'; -import * as React from 'react'; -import { COLOR_MODES_STANDARD } from '@elastic/eui'; -import { DensityChart } from './density_chart'; -import { HighlightedInterval } from './highlighted_interval'; -import { SearchMarkers } from './search_markers'; -import { TimeRuler } from './time_ruler'; - -interface Interval { - end: number; - start: number; -} - -interface LogMinimapProps { - className?: string; - height: number; - highlightedInterval: Interval | null; - jumpToTarget: (params: LogEntryTime) => any; - summaryBuckets: LogEntriesSummaryBucket[]; - summaryHighlightBuckets?: LogEntriesSummaryHighlightsBucket[]; - target: number | null; - start: number | null; - end: number | null; - width: number; -} - -interface LogMinimapState { - target: number | null; - timeCursorY: number; -} - -// Wide enough to fit "September" -const TIMERULER_WIDTH = 50; - -function calculateYScale(start: number | null, end: number | null, height: number) { - return scaleLinear() - .domain([start || 0, end || 0]) - .range([0, height]); -} - -export class LogMinimap extends React.Component { - constructor(props: LogMinimapProps) { - super(props); - this.state = { - timeCursorY: 0, - target: props.target, - }; - } - - public handleClick: React.MouseEventHandler = (event) => { - const minimapTop = event.currentTarget.getBoundingClientRect().top; - const clickedYPosition = event.clientY - minimapTop; - - const clickedTime = Math.floor(this.getYScale().invert(clickedYPosition)); - - this.props.jumpToTarget({ - tiebreaker: 0, - time: moment(clickedTime).toISOString(), - }); - }; - - public getYScale = () => { - const { start, end, height } = this.props; - return calculateYScale(start, end, height); - }; - - public getPositionOfTime = (time: number) => { - return this.getYScale()(time) ?? 0; - }; - - private updateTimeCursor: React.MouseEventHandler = (event) => { - const svgPosition = event.currentTarget.getBoundingClientRect(); - const timeCursorY = event.clientY - svgPosition.top; - - this.setState({ timeCursorY }); - }; - - public render() { - const { - start, - end, - className, - height, - highlightedInterval, - jumpToTarget, - summaryBuckets, - summaryHighlightBuckets, - width, - } = this.props; - const { timeCursorY, target } = this.state; - const [minTime, maxTime] = calculateYScale(start, end, height).domain(); - const tickCount = height ? Math.floor(height / 50) : 12; - - return ( - - - - - - - - - - {highlightedInterval ? ( - - ) : null} - - - ); - } -} - -const MinimapBorder = styled.line` - stroke: ${(props) => props.theme.euiTheme.colors.mediumShade}; - stroke-width: 1px; -`; - -const TimeCursor = styled.line` - pointer-events: none; - stroke-width: 1px; - stroke: ${(props) => - props.theme.colorMode === COLOR_MODES_STANDARD.dark - ? props.theme.euiTheme.colors.darkestShade - : props.theme.euiTheme.colors.darkShade}; -`; - -const MinimapWrapper = styled.svg` - cursor: pointer; - fill: ${(props) => props.theme.euiTheme.colors.emptyShade}; - & ${TimeCursor} { - visibility: hidden; - } - &:hover ${TimeCursor} { - visibility: visible; - } -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_marker.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_marker.tsx deleted file mode 100644 index 12ec50da28eaa..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_marker.tsx +++ /dev/null @@ -1,125 +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 { FormattedMessage } from '@kbn/i18n-react'; -import styled from '@emotion/styled'; -import { keyframes } from '@emotion/react'; -import type { - LogEntriesSummaryHighlightsBucket, - LogEntryTime, -} from '@kbn/logs-shared-plugin/common'; -import * as React from 'react'; -import { SearchMarkerTooltip } from './search_marker_tooltip'; - -interface SearchMarkerProps { - bucket: LogEntriesSummaryHighlightsBucket; - height: number; - width: number; - jumpToTarget: (target: LogEntryTime) => void; -} - -interface SearchMarkerState { - hoveredPosition: ClientRect | null; -} - -export class SearchMarker extends React.PureComponent { - public readonly state: SearchMarkerState = { - hoveredPosition: null, - }; - - public handleClick: React.MouseEventHandler = (evt) => { - evt.stopPropagation(); - - this.props.jumpToTarget(this.props.bucket.representativeKey); - }; - - public handleMouseEnter: React.MouseEventHandler = (evt) => { - this.setState({ - hoveredPosition: evt.currentTarget.getBoundingClientRect(), - }); - }; - - public handleMouseLeave: React.MouseEventHandler = () => { - this.setState({ - hoveredPosition: null, - }); - }; - - public render() { - const { bucket, height, width } = this.props; - const { hoveredPosition } = this.state; - - const bulge = - bucket.entriesCount > 1 ? ( - - ) : ( - <> - - - - ); - - return ( - <> - {hoveredPosition ? ( - - - - ) : null} - - - {bulge} - - - ); - } -} - -const fadeInAnimation = keyframes` - from { - opacity: 0; - } - to { - opacity: 1; - } -`; - -const SearchMarkerGroup = styled.g` - animation: ${fadeInAnimation} ${(props) => props.theme.euiTheme.animation.extraSlow} ease-in both; -`; - -const SearchMarkerBackgroundRect = styled.rect` - fill: ${(props) => props.theme.euiTheme.colors.accent}; - opacity: 0; - transition: opacity ${(props) => props.theme.euiTheme.animation.normal} ease-in; - cursor: pointer; - - ${SearchMarkerGroup}:hover & { - opacity: 0.3; - } -`; - -const SearchMarkerForegroundRect = styled.rect` - fill: ${(props) => props.theme.euiTheme.colors.accent}; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_marker_tooltip.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_marker_tooltip.tsx deleted file mode 100644 index 64561a528051d..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_marker_tooltip.tsx +++ /dev/null @@ -1,70 +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 type { WithEuiThemeProps } from '@elastic/eui'; -import { calculatePopoverPosition, EuiPortal, withEuiTheme } from '@elastic/eui'; -// @ts-expect-error style types not defined -import { euiToolTipStyles } from '@elastic/eui/lib/components/tool_tip/tool_tip.styles'; -import { css } from '@emotion/react'; -import * as React from 'react'; - -import { AutoSizer } from '../../auto_sizer'; - -const POPOVER_ARROW_SIZE = 12; // px, to position it later - -interface SearchMarkerTooltipProps { - markerPosition: ClientRect; - children: React.ReactNode; -} - -export class _SearchMarkerTooltip extends React.PureComponent< - SearchMarkerTooltipProps & WithEuiThemeProps -> { - public render() { - const { children, markerPosition, theme } = this.props; - const styles = euiToolTipStyles(theme); - - return ( - -
- - {({ measureRef, bounds: { width, height } }) => { - const { top, left } = - width && height - ? calculatePopoverPosition(markerPosition, { width, height }, 'left', 16, [ - 'left', - ]) - : { - left: -9999, // render off-screen before the first measurement - top: 0, - }; - - return ( -
-
-
{children}
-
- ); - }} - -
- - ); - } -} - -export const SearchMarkerTooltip = withEuiTheme(_SearchMarkerTooltip); diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_markers.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_markers.tsx deleted file mode 100644 index 3fc7da615492e..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/search_markers.tsx +++ /dev/null @@ -1,56 +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 type { - LogEntriesSummaryHighlightsBucket, - LogEntryTime, -} from '@kbn/logs-shared-plugin/common'; -import classNames from 'classnames'; -import { scaleTime } from 'd3-scale'; -import * as React from 'react'; -import { SearchMarker } from './search_marker'; - -interface SearchMarkersProps { - buckets: LogEntriesSummaryHighlightsBucket[]; - className?: string; - end: number; - start: number; - width: number; - height: number; - jumpToTarget: (target: LogEntryTime) => void; -} - -export class SearchMarkers extends React.PureComponent { - public render() { - const { buckets, start, end, width, height, jumpToTarget, className } = this.props; - const classes = classNames('minimapSearchMarkers', className); - - if (start >= end || height <= 0 || Object.keys(buckets).length <= 0) { - return null; - } - - const yScale = scaleTime().domain([start, end]).range([0, height]); - - return ( - - {buckets.map((bucket) => ( - - - - ))} - - ); - } -} diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/time_label_formatter.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/time_label_formatter.tsx deleted file mode 100644 index 0fd3cd131da21..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/time_label_formatter.tsx +++ /dev/null @@ -1,24 +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. - */ - -// The default d3-time-format is a bit strange for small ranges, so we will specify our own -export function getTimeLabelFormat(start: number, end: number): string | undefined { - const diff = Math.abs(end - start); - - // 15 seconds - if (diff < 15 * 1000) { - return ':%S.%L'; - } - - // 16 minutes - if (diff < 16 * 60 * 1000) { - return '%I:%M:%S'; - } - - // Use D3's default - return; -} diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/time_ruler.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/time_ruler.tsx deleted file mode 100644 index 93df67958144a..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_minimap/time_ruler.tsx +++ /dev/null @@ -1,77 +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 { scaleTime } from 'd3-scale'; -import * as React from 'react'; -import styled from '@emotion/styled'; -import { COLOR_MODES_STANDARD, useEuiFontSize } from '@elastic/eui'; -import { useKibanaTimeZoneSetting } from '../../../hooks/use_kibana_time_zone_setting'; -import { getTimeLabelFormat } from './time_label_formatter'; - -interface TimeRulerProps { - end: number; - height: number; - start: number; - tickCount: number; - width: number; -} - -const useZonedDate = (timestamp: number) => { - const timeZone = useKibanaTimeZoneSetting(); - - const options = timeZone !== 'local' ? { timeZone } : undefined; - return new Date(new Date(timestamp).toLocaleString('en-US', options)); -}; - -export const TimeRuler: React.FC = ({ end, height, start, tickCount, width }) => { - const startWithOffset = useZonedDate(start); - const endWithOffset = useZonedDate(end); - - const yScale = scaleTime().domain([startWithOffset, endWithOffset]).range([0, height]); - - const ticks = yScale.ticks(tickCount); - const formatTick = yScale.tickFormat( - tickCount, - getTimeLabelFormat(startWithOffset.getTime(), endWithOffset.getTime()) - ); - - return ( - - {ticks.map((tick, tickIndex) => { - const y = yScale(tick) ?? 0; - - return ( - - - {formatTick(tick)} - - - - ); - })} - - ); -}; - -TimeRuler.displayName = 'TimeRuler'; - -const TimeRulerTickLabel = styled.text` - font-size: ${() => useEuiFontSize('xxxs').fontSize}; - line-height: ${() => useEuiFontSize('s').lineHeight}; - fill: ${(props) => props.theme.euiTheme.colors.textSubdued}; - user-select: none; - pointer-events: none; -`; - -const TimeRulerGridLine = styled.line` - stroke: ${(props) => - props.theme.colorMode === COLOR_MODES_STANDARD.dark - ? props.theme.euiTheme.colors.darkestShade - : props.theme.euiTheme.colors.darkShade}; - stroke-opacity: 0.5; - stroke-width: 1px; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/index.ts b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/index.ts deleted file mode 100644 index 5122c14e6f108..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export { LogSearchControls } from './log_search_controls'; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_buttons.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_buttons.tsx deleted file mode 100644 index dacbbb78eb93f..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_buttons.tsx +++ /dev/null @@ -1,77 +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 { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { LogEntryTime } from '@kbn/logs-shared-plugin/common'; -import classNames from 'classnames'; -import * as React from 'react'; - -interface LogSearchButtonsProps { - className?: string; - jumpToTarget: (target: LogEntryTime) => void; - previousSearchResult: LogEntryTime | null; - nextSearchResult: LogEntryTime | null; -} - -export class LogSearchButtons extends React.PureComponent { - public handleJumpToPreviousSearchResult: React.MouseEventHandler = () => { - const { jumpToTarget, previousSearchResult } = this.props; - - if (previousSearchResult) { - jumpToTarget(previousSearchResult); - } - }; - - public handleJumpToNextSearchResult: React.MouseEventHandler = () => { - const { jumpToTarget, nextSearchResult } = this.props; - - if (nextSearchResult) { - jumpToTarget(nextSearchResult); - } - }; - - public render() { - const { className, previousSearchResult, nextSearchResult } = this.props; - - const classes = classNames('searchButtons', className); - const hasPreviousSearchResult = !!previousSearchResult; - const hasNextSearchResult = !!nextSearchResult; - - return ( - - - - - - - - - - - - - ); - } -} diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_controls.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_controls.tsx deleted file mode 100644 index a834408037d93..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_controls.tsx +++ /dev/null @@ -1,64 +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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import classNames from 'classnames'; -import * as React from 'react'; - -import type { LogEntryTime } from '@kbn/logs-shared-plugin/common'; -import { LogSearchButtons } from './log_search_buttons'; -import { LogSearchInput } from './log_search_input'; - -interface LogSearchControlsProps { - className?: string; - clearSearch: () => any; - isLoadingSearchResults: boolean; - previousSearchResult: LogEntryTime | null; - nextSearchResult: LogEntryTime | null; - jumpToTarget: (target: LogEntryTime) => any; - search: (query: string) => any; -} - -export class LogSearchControls extends React.PureComponent { - public render() { - const { - className, - clearSearch, - isLoadingSearchResults, - previousSearchResult, - nextSearchResult, - jumpToTarget, - search, - } = this.props; - - const classes = classNames('searchControls', className); - - return ( - - - - - - - - - ); - } -} diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_input.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_input.tsx deleted file mode 100644 index 25aa19d556cbe..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_search_controls/log_search_input.tsx +++ /dev/null @@ -1,85 +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 { EuiFieldSearch } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import styled from '@emotion/styled'; -import classNames from 'classnames'; -import * as React from 'react'; - -interface LogSearchInputProps { - className?: string; - isLoading: boolean; - onSearch: (query: string) => void; - onClear: () => void; -} - -interface LogSearchInputState { - query: string; -} - -export const LogSearchInput = class extends React.PureComponent< - LogSearchInputProps, - LogSearchInputState -> { - public static displayName = 'LogSearchInput'; - public readonly state = { - query: '', - }; - - public handleSubmit: React.FormEventHandler = (evt) => { - evt.preventDefault(); - - const { query } = this.state; - - if (query === '') { - this.props.onClear(); - } else { - this.props.onSearch(this.state.query); - } - }; - - public handleChangeQuery: React.ChangeEventHandler = (evt) => { - this.setState({ - query: evt.target.value, - }); - }; - - public render() { - const { className, isLoading } = this.props; - const { query } = this.state; - - const classes = classNames('loggingSearchInput', className); - - return ( -
- - - ); - } -}; - -const PlainSearchField = styled(EuiFieldSearch)` - background: transparent; - box-shadow: none; - - &:focus { - box-shadow: inset 0 -2px 0 0 ${(props) => props.theme.euiTheme.colors.primary}; - } -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_statusbar.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_statusbar.tsx deleted file mode 100644 index 4aa8508f3285f..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_statusbar.tsx +++ /dev/null @@ -1,33 +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 { EuiFlexGroup, type EuiFlexGroupProps, EuiFlexItem, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/css'; -import React from 'react'; - -export const LogStatusbar = (props: EuiFlexGroupProps) => { - const { euiTheme } = useEuiTheme(); - - return ( - - ); -}; - -export const LogStatusbarItem = EuiFlexItem; diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_text_scale_controls.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_text_scale_controls.tsx deleted file mode 100644 index eb00a998cf42a..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_text_scale_controls.tsx +++ /dev/null @@ -1,65 +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 { EuiFormRow, EuiRadioGroup } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import * as React from 'react'; - -import type { TextScale } from '../../../common/log_text_scale'; -import { isTextScale } from '../../../common/log_text_scale'; - -interface LogTextScaleControlsProps { - availableTextScales: TextScale[]; - textScale: TextScale; - setTextScale: (scale: TextScale) => any; -} - -export class LogTextScaleControls extends React.PureComponent { - public setTextScale = (textScale: string) => { - if (isTextScale(textScale)) { - this.props.setTextScale(textScale); - } - }; - - public render() { - const { availableTextScales, textScale } = this.props; - - return ( - - } - > - ({ - id: availableTextScale.toString(), - label: ( - - ), - }))} - idSelected={textScale} - onChange={this.setTextScale} - /> - - ); - } -} diff --git a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_text_wrap_controls.tsx b/x-pack/solutions/observability/plugins/infra/public/components/logging/log_text_wrap_controls.tsx deleted file mode 100644 index c84643a6f394a..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/components/logging/log_text_wrap_controls.tsx +++ /dev/null @@ -1,47 +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 { EuiFormRow, EuiSwitch } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import * as React from 'react'; - -interface LogTextWrapControlsProps { - wrap: boolean; - setTextWrap: (scale: boolean) => any; -} - -export class LogTextWrapControls extends React.PureComponent { - public toggleWrap = () => { - this.props.setTextWrap(!this.props.wrap); - }; - - public render() { - const { wrap } = this.props; - - return ( - - } - > - - } - checked={wrap} - onChange={this.toggleWrap} - /> - - ); - } -} diff --git a/x-pack/solutions/observability/plugins/infra/public/containers/logs/log_view_configuration.test.tsx b/x-pack/solutions/observability/plugins/infra/public/containers/logs/log_view_configuration.test.tsx deleted file mode 100644 index 1fe14d9b2965b..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/containers/logs/log_view_configuration.test.tsx +++ /dev/null @@ -1,55 +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 { mountHook } from '@kbn/test-jest-helpers'; - -import { useLogViewConfiguration } from './log_view_configuration'; - -describe('useLogViewConfiguration hook', () => { - describe('textScale state', () => { - it('has a default value', () => { - const { getLastHookValue } = mountHook(() => useLogViewConfiguration().textScale); - - expect(getLastHookValue()).toEqual('medium'); - }); - - it('can be updated', () => { - const { act, getLastHookValue } = mountHook(() => useLogViewConfiguration()); - - act(({ setTextScale }) => { - setTextScale('small'); - }); - - expect(getLastHookValue().textScale).toEqual('small'); - }); - }); - - describe('textWrap state', () => { - it('has a default value', () => { - const { getLastHookValue } = mountHook(() => useLogViewConfiguration().textWrap); - - expect(getLastHookValue()).toEqual(true); - }); - - it('can be updated', () => { - const { act, getLastHookValue } = mountHook(() => useLogViewConfiguration()); - - act(({ setTextWrap }) => { - setTextWrap(false); - }); - - expect(getLastHookValue().textWrap).toEqual(false); - }); - }); - - it('provides the available text scales', () => { - const { getLastHookValue } = mountHook(() => useLogViewConfiguration().availableTextScales); - - expect(getLastHookValue()).toEqual(expect.any(Array)); - expect(getLastHookValue().length).toBeGreaterThan(0); - }); -}); diff --git a/x-pack/solutions/observability/plugins/infra/public/containers/logs/log_view_configuration.tsx b/x-pack/solutions/observability/plugins/infra/public/containers/logs/log_view_configuration.tsx deleted file mode 100644 index 543cc61d78977..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/containers/logs/log_view_configuration.tsx +++ /dev/null @@ -1,36 +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 createContainer from 'constate'; -import { useState } from 'react'; - -export type TextScale = 'small' | 'medium' | 'large'; - -export const useLogViewConfiguration = () => { - // text scale - const [textScale, setTextScale] = useState('medium'); - - // text wrap - const [textWrap, setTextWrap] = useState(true); - - return { - availableTextScales, - setTextScale, - setTextWrap, - textScale, - textWrap, - }; -}; - -export const [LogViewConfigurationProvider, useLogViewConfigurationContext] = - createContainer(useLogViewConfiguration); - -/** - * constants - */ - -export const availableTextScales: TextScale[] = ['large', 'medium', 'small']; diff --git a/x-pack/solutions/observability/plugins/infra/public/containers/logs/with_log_textview.tsx b/x-pack/solutions/observability/plugins/infra/public/containers/logs/with_log_textview.tsx deleted file mode 100644 index 7a394cd94fc13..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/containers/logs/with_log_textview.tsx +++ /dev/null @@ -1,60 +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, { useMemo } from 'react'; - -import { UrlStateContainer } from '../../utils/url_state'; -import type { TextScale } from './log_view_configuration'; -import { availableTextScales, useLogViewConfigurationContext } from './log_view_configuration'; - -interface LogTextviewUrlState { - textScale?: TextScale; - wrap?: boolean; -} - -export const WithLogTextviewUrlState = () => { - const { textScale, textWrap, setTextScale, setTextWrap } = useLogViewConfigurationContext(); - - const urlState = useMemo(() => ({ textScale, wrap: textWrap }), [textScale, textWrap]); - - return ( - { - if (newUrlState && newUrlState.textScale) { - setTextScale(newUrlState.textScale); - } - if (newUrlState && typeof newUrlState.wrap !== 'undefined') { - setTextWrap(newUrlState.wrap); - } - }} - onInitialize={(newUrlState) => { - if (newUrlState && newUrlState.textScale) { - setTextScale(newUrlState.textScale); - } - if (newUrlState && typeof newUrlState.wrap !== 'undefined') { - setTextWrap(newUrlState.wrap); - } - }} - /> - ); -}; - -const mapToUrlState = (value: any): LogTextviewUrlState | undefined => - value - ? { - textScale: mapToTextScaleUrlState(value.textScale), - wrap: mapToWrapUrlState(value.wrap), - } - : undefined; - -const mapToTextScaleUrlState = (value: any) => - availableTextScales.includes(value) ? (value as TextScale) : undefined; - -const mapToWrapUrlState = (value: any) => (typeof value === 'boolean' ? value : undefined); diff --git a/x-pack/solutions/observability/plugins/infra/public/hooks/use_observable.ts b/x-pack/solutions/observability/plugins/infra/public/hooks/use_observable.ts index 167f55dfea546..d75acb84160a0 100644 --- a/x-pack/solutions/observability/plugins/infra/public/hooks/use_observable.ts +++ b/x-pack/solutions/observability/plugins/infra/public/hooks/use_observable.ts @@ -7,7 +7,7 @@ import { useEffect, useRef, useState } from 'react'; import type { OperatorFunction, PartialObserver, Subscription } from 'rxjs'; -import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; +import { BehaviorSubject, Observable } from 'rxjs'; import { switchMap } from 'rxjs'; export const useLatest = (value: Value) => { @@ -52,22 +52,6 @@ export const useBehaviorSubject = < return [output$, next] as const; }; -export const useReplaySubject = < - InputValue, - OutputValue, - OutputObservable extends Observable ->( - deriveObservableOnce: (input$: Observable) => OutputObservable -) => { - const [[subject$, next], _] = useState(() => { - const newSubject$ = new ReplaySubject(); - const newNext = newSubject$.next.bind(newSubject$); - return [newSubject$, newNext] as const; - }); - const [output$] = useState(() => deriveObservableOnce(subject$)); - return [output$, next] as const; -}; - export const useObservableState = ( state$: Observable, initialState: InitialState | (() => InitialState) diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/README.md b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/README.md deleted file mode 100644 index c2f9154a08638..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @kbn/observability-logs-log-stream-page-state - -The state machine of the Observability Logs UI stream page. diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/index.ts deleted file mode 100644 index 3b2a320ae181f..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export * from './src'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/index.ts deleted file mode 100644 index 22f33aa56174c..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/index.ts +++ /dev/null @@ -1,11 +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. - */ - -export * from './provider'; -export * from './selectors'; -export * from './state_machine'; -export * from './types'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts deleted file mode 100644 index 4f307e3a3152e..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts +++ /dev/null @@ -1,89 +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 type { RefreshInterval } from '@kbn/data-plugin/public'; -import type { InvokeCreator, Receiver } from 'xstate'; -import type { TimeKey } from '../../../../../common/time'; -import type { VisiblePositions } from '../../../log_stream_position_state'; -import type { ExtendedTimeRange, ParsedQuery, Timestamps } from '../../../log_stream_query_state'; -import type { LogStreamPageContext, LogStreamPageEvent } from './types'; - -export const waitForInitialQueryParameters = - (): InvokeCreator => - (_context, _event) => - (send, onEvent: Receiver) => { - // constituents of the set of initial parameters - let latestValidQuery: ParsedQuery | undefined; - let latestTimeRange: ExtendedTimeRange | undefined; - let latestRefreshInterval: RefreshInterval | undefined; - let latestTimestamps: Timestamps | undefined; - - onEvent((event) => { - switch (event.type) { - // event types that deliver the parameters - case 'VALID_QUERY_CHANGED': - case 'INVALID_QUERY_CHANGED': - latestValidQuery = event.parsedQuery; - break; - case 'TIME_CHANGED': - latestTimeRange = event.timeRange; - latestRefreshInterval = event.refreshInterval; - latestTimestamps = event.timestamps; - break; - } - - // if all constituents of the parameters have been delivered - if ( - latestValidQuery !== undefined && - latestTimeRange !== undefined && - latestRefreshInterval !== undefined && - latestTimestamps !== undefined - ) { - send({ - type: 'RECEIVED_INITIAL_QUERY_PARAMETERS', - validatedQuery: latestValidQuery, - timeRange: latestTimeRange, - refreshInterval: latestRefreshInterval, - timestamps: latestTimestamps, - }); - } - }); - }; - -export const waitForInitialPositionParameters = - (): InvokeCreator => - (_context, _event) => - (send, onEvent: Receiver) => { - // constituents of the set of initial parameters - let latestTargetPosition: TimeKey | null; - let latestLatestPosition: TimeKey | null; - let latestVisiblePositions: VisiblePositions; - - onEvent((event) => { - switch (event.type) { - case 'POSITIONS_CHANGED': - latestTargetPosition = event.targetPosition; - latestLatestPosition = event.latestPosition; - latestVisiblePositions = event.visiblePositions; - break; - } - - // if all constituents of the parameters have been delivered - if ( - latestTargetPosition !== undefined && - latestLatestPosition !== undefined && - latestVisiblePositions !== undefined - ) { - send({ - type: 'RECEIVED_INITIAL_POSITION_PARAMETERS', - targetPosition: latestTargetPosition, - latestPosition: latestLatestPosition, - visiblePositions: latestVisiblePositions, - }); - } - }); - }; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx deleted file mode 100644 index 0da26759b6a04..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx +++ /dev/null @@ -1,54 +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 { useInterpret } from '@xstate/react'; -import createContainer from 'constate'; -import useMount from 'react-use/lib/useMount'; -import { isDevMode } from '../../../../utils/dev_mode'; -import { - createLogStreamPageStateMachine, - type LogStreamPageStateMachineDependencies, -} from './state_machine'; - -export const useLogStreamPageState = ({ - kibanaQuerySettings, - logViewStateNotifications, - queryStringService, - toastsService, - filterManagerService, - urlStateStorage, - useDevTools = isDevMode(), - timeFilterService, -}: { - useDevTools?: boolean; -} & LogStreamPageStateMachineDependencies) => { - useMount(() => { - // eslint-disable-next-line no-console - console.log( - "A warning in console stating: 'The result of getSnapshot should be cached to avoid an infinite loop' is expected. This will be fixed once we can upgrade versions." - ); - }); - - const logStreamPageStateService = useInterpret( - () => - createLogStreamPageStateMachine({ - kibanaQuerySettings, - logViewStateNotifications, - queryStringService, - toastsService, - filterManagerService, - urlStateStorage, - timeFilterService, - }), - { devTools: useDevTools } - ); - - return logStreamPageStateService; -}; - -export const [LogStreamPageStateProvider, useLogStreamPageStateContext] = - createContainer(useLogStreamPageState); diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/selectors.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/selectors.ts deleted file mode 100644 index b173620892478..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/selectors.ts +++ /dev/null @@ -1,19 +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 type { MatchedStateFromActor } from '@kbn/xstate-utils'; -import type { LogStreamQueryActorRef } from '../../../log_stream_query_state'; -import type { LogStreamPageActorRef } from './state_machine'; - -type LogStreamPageStateWithLogViewIndices = - | MatchedStateFromActor - | MatchedStateFromActor - | MatchedStateFromActor; - -export const selectLogStreamQueryChildService = ( - state: LogStreamPageStateWithLogViewIndices -): LogStreamQueryActorRef => state.children.logStreamQuery; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts deleted file mode 100644 index 0797d629885f6..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts +++ /dev/null @@ -1,355 +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 type { RefreshInterval } from '@kbn/data-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; -import type { ActorRefFrom, EmittedFrom } from 'xstate'; -import { actions, createMachine } from 'xstate'; -import { DEFAULT_REFRESH_INTERVAL } from '@kbn/logs-shared-plugin/common'; -import type { LogViewNotificationChannel } from '@kbn/logs-shared-plugin/public'; -import type { OmitDeprecatedState } from '@kbn/xstate-utils'; -import { datemathToEpochMillis } from '../../../../utils/datemath'; -import { createLogStreamPositionStateMachine } from '../../../log_stream_position_state/src/state_machine'; -import type { LogStreamQueryStateMachineDependencies } from '../../../log_stream_query_state'; -import { - createLogStreamQueryStateMachine, - DEFAULT_TIMERANGE, -} from '../../../log_stream_query_state'; -import { - waitForInitialQueryParameters, - waitForInitialPositionParameters, -} from './initial_parameters_service'; -import type { - LogStreamPageContext, - LogStreamPageContextWithLogView, - LogStreamPageContextWithLogViewError, - LogStreamPageContextWithPositions, - LogStreamPageContextWithQuery, - LogStreamPageContextWithTime, - LogStreamPageEvent, - LogStreamPageTypestate, -} from './types'; - -export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPageContext = {}) => - /** @xstate-layout N4IgpgJg5mDOIC5QBsD2UDKAXATmAhgLYAK+M2+WYAdAK4B2Alk1o-sowF6QDEAMgHkAggBEAkgDkA4gH1BsgGpiAogHUZGACpCASpuUiA2gAYAuolAAHVLEatU9CyAAeiALQAmAJzUPHgGwArIEALAAcHmHhXsEhADQgAJ6IAQDM1IHGYQDs2ZnZxl5e-l6pAL5lCWiYuAQkZGAUVHRMLGwc3BD8wuLScgKKKuoAYkJifAYm5kgg1rb2jjOuCJ4hAIzUqZklHgX+xqlrkQnJCKlB1P4loYH+qV7hHoEVVejYeESk5FiUNAzMdnaXF4glEklk8hkSjUGgAqgBheHKAyTMxOOaAhxOZbZNbZajGXLBVIkrJrYInRBHYzUEIeVIhVJhNZZLws7IhF4garvOpfRo-Zr-NrsYFdUG9CEDKFDOGI5EiSZraZWGyYxagHEhEIEwkeI7Zc7GO6UhCZHzZML7MKBDwhQp0zmVblvWqfBpNGhofAQZhQPjoBSMMAAd26YL6kOhIzGEyMaJmGIW2JS4VpJTCWXp5K82Q8pvN1Et1tt9oedq5PLd9W+v2o3t99H9geDYYl4P6gxhGARSJR8ZVszVyaWiEZPnt-m8Ry8xjta38pqN1FK+uy+w8xhCgS8lddHxrArrDb9AagQdD4clnZl3d7CqVg6TjCxo4QISumy2MWNMWiAVNO58WMFkImMOc50CMI9xqA9+U9etUB9U8W1DYZ8EYZAQR6Dso1lLRdH0Ad0WHF8NRcdxvF8AJYgiKIwhiUIC1SDwMgNcC8g5O1nmdKs4I9QUaAAC3wWAzwvEMxHoX0AGM4GoAFWFFTg-QARVoMAcESHgdGUJExAUAwZEkMRNDEIQ+BkVTYWUHQAE0ZGIXQhAAWWUfQdAwKYSPmMinFOKcNgKXYwnOPMbRYhJlhCYoYN5d1a2aESxNQyTpMYOTYAUkUOjUjStJ4BQLLEEQrJs+yZHhAAJIRpFRJ9SNfTUx2KAtDSLOdLTCyJAhYuLq3gwTqGS8TWyk2T5MUoEVKbdTNO0yQir4EqytshzqtqqR6p89UU3fVqkkQS1WNKXEoP8cLeo8fr+MS4TRNG0Nxoyyacq4PL5p4My3Mqmq6uIxNGvI6KDtOW1Ag6kLuoi67eP3PkBLrEbUuezLssBZS-WIIHYB0vTlAMoyTLMizHIEDBTLEAQJEc5y3I8ryE1VXymoo-bF0OhAGI2EDbVCi6er6uHYIRu7hoelH0rRqbMabbGWfoXHiHJynqYwX7Nu2wGFb2mKOdOIofEKBksgFmGbtFo8kol88xql16MY6XglpW6y1o1-7vO13a3wXPJaTWCJbSne0SQLOcV3XJ5t0yXq1jWC2Eqt+6Uttp77aymWna6b7lA9raAeZn3moQBdCV8b99hiQ0rnzTntx1XMpxuWPDgT4X4sPBDkbTtKJszt7Oh4ZWKbMtX861ouRxLsv8XpHcq8CGup0A+OCVCVJskY4w49h14RaT7ubYk1GHaU7OeAAKVhFziBkTQBHv3Qts0MnR6piQvanvzff2OfK8KEvc4K967Gkjs3GOO826Jy7kNHuJ8M7o3PmKPGys9AygpgAIQmG-VWEhGYNR1r-cu89iiAOXnXU4WwwjgOjsEKB8cYGDSRsfO2-ckHTV4LCYgIghD6HvmIH6OhNZfyHEQmef8K4L3IcAyhR01g+DWCxTIkDd5MMRtbVOCD2FZxQdw3h-DdLDF0hgKqxkJAeSWqI58rNlizykWQ6usilwsloS3Bh7d96d2YZox6fcXoD0digpyW0ZDKAkKVTBsJhjDFsjIXSQhqqTzEcXNm9jSGLwoaaAIJ0o7uLju3Z09BUAQDgE4PiltPQ7WnmzTwDFNjbC8LsY0BwlGmjcCxAk9IOSZgXDuUotx1Fi2FEEzo1Sf4lzpKaNYdJqDknAlkG0bIghbiGcnRCyEmx+PGbYlI+JYhXCtDaXIP54icyZDQ+4-gjgCy2H4HiXiBoaK9EhRszZe7oUwpAHZwNEAQ2ZHaJpdwLpsiWYBHcRZN72njlubw0EO5PLFvAthASfl7TcOEaZEcQhR3WDaGKXVPEugPrAlhWiUXS0Hh9LSaK3zGEAvqSGXUzZXTWUfcl6cdFUrljjWlJd6WcwiKxTcUMWVC0ebddZyLOUBI4cpb53sal2KZDqPI5IllANrgWJ4TL+aXXFcS7xzzqCEEYLAWwWzJb9z5Wkw4-hfCFD8NvG0F1wUWk3pvXEXqDjlAqGUIAA */ - createMachine( - { - context: initialContext, - predictableActionArguments: true, - invoke: { - src: 'logViewNotifications', - }, - id: 'logStreamPageState', - initial: 'uninitialized', - states: { - uninitialized: { - on: { - LOADING_LOG_VIEW_STARTED: { - target: 'loadingLogView', - }, - LOADING_LOG_VIEW_FAILED: { - target: 'loadingLogViewFailed', - actions: 'storeLogViewError', - }, - LOADING_LOG_VIEW_SUCCEEDED: [ - { - target: 'hasLogViewIndices', - cond: 'hasLogViewIndices', - actions: 'storeResolvedLogView', - }, - { - target: 'missingLogViewIndices', - actions: 'storeResolvedLogView', - }, - ], - }, - }, - loadingLogView: { - on: { - LOADING_LOG_VIEW_FAILED: { - target: 'loadingLogViewFailed', - actions: 'storeLogViewError', - }, - LOADING_LOG_VIEW_SUCCEEDED: [ - { - target: 'hasLogViewIndices', - cond: 'hasLogViewIndices', - actions: 'storeResolvedLogView', - }, - { - target: 'missingLogViewIndices', - actions: 'storeResolvedLogView', - }, - ], - }, - }, - loadingLogViewFailed: { - on: { - LOADING_LOG_VIEW_STARTED: { - target: 'loadingLogView', - }, - }, - }, - hasLogViewIndices: { - initial: 'initializingQuery', - - states: { - initializingQuery: { - meta: { - _DX_warning_: - "The Query machine must be invoked and complete initialisation before the Position machine is invoked. This is due to legacy URL dependencies on the 'logPosition' key, we need to read the key before it is reset by the Position machine.", - }, - - invoke: { - src: 'waitForInitialQueryParameters', - id: 'waitForInitialQueryParameters', - }, - - on: { - RECEIVED_INITIAL_QUERY_PARAMETERS: { - target: 'initializingPositions', - actions: ['storeQuery', 'storeTime', 'forwardToLogPosition'], - }, - - VALID_QUERY_CHANGED: { - target: 'initializingQuery', - internal: true, - actions: 'forwardToInitialQueryParameters', - }, - - INVALID_QUERY_CHANGED: { - target: 'initializingQuery', - internal: true, - actions: 'forwardToInitialQueryParameters', - }, - TIME_CHANGED: { - target: 'initializingQuery', - internal: true, - actions: 'forwardToInitialQueryParameters', - }, - }, - }, - initializingPositions: { - meta: { - _DX_warning_: - "The Position machine must be invoked after the Query machine has been invoked and completed initialisation. This is due to the Query machine having some legacy URL dependencies on the 'logPosition' key, we don't want the Position machine to reset the URL parameters before the Query machine has had a chance to read them.", - }, - invoke: [ - { - src: 'waitForInitialPositionParameters', - id: 'waitForInitialPositionParameters', - }, - ], - on: { - RECEIVED_INITIAL_POSITION_PARAMETERS: { - target: 'initialized', - actions: ['storePositions'], - }, - - POSITIONS_CHANGED: { - target: 'initializingPositions', - internal: true, - actions: 'forwardToInitialPositionParameters', - }, - }, - }, - initialized: { - on: { - VALID_QUERY_CHANGED: { - target: 'initialized', - internal: true, - actions: 'storeQuery', - }, - TIME_CHANGED: { - target: 'initialized', - internal: true, - actions: ['storeTime', 'forwardToLogPosition'], - }, - POSITIONS_CHANGED: { - target: 'initialized', - internal: true, - actions: ['storePositions'], - }, - JUMP_TO_TARGET_POSITION: { - target: 'initialized', - internal: true, - actions: ['forwardToLogPosition'], - }, - REPORT_VISIBLE_POSITIONS: { - target: 'initialized', - internal: true, - actions: ['forwardToLogPosition'], - }, - UPDATE_TIME_RANGE: { - target: 'initialized', - internal: true, - actions: ['forwardToLogStreamQuery'], - }, - UPDATE_REFRESH_INTERVAL: { - target: 'initialized', - internal: true, - actions: ['forwardToLogStreamQuery'], - }, - PAGE_END_BUFFER_REACHED: { - target: 'initialized', - internal: true, - actions: ['forwardToLogStreamQuery'], - }, - }, - }, - }, - - invoke: [ - { - src: 'logStreamQuery', - id: 'logStreamQuery', - }, - { - src: 'logStreamPosition', - id: 'logStreamPosition', - }, - ], - }, - missingLogViewIndices: {}, - }, - }, - { - actions: { - forwardToInitialQueryParameters: actions.forwardTo('waitForInitialQueryParameters'), - forwardToInitialPositionParameters: actions.forwardTo('waitForInitialPositionParameters'), - forwardToLogPosition: actions.forwardTo('logStreamPosition'), - forwardToLogStreamQuery: actions.forwardTo('logStreamQuery'), - storeLogViewError: actions.assign((_context, event) => - event.type === 'LOADING_LOG_VIEW_FAILED' - ? ({ logViewError: event.error } as LogStreamPageContextWithLogViewError) - : {} - ), - storeResolvedLogView: actions.assign((_context, event) => - event.type === 'LOADING_LOG_VIEW_SUCCEEDED' - ? ({ - logViewStatus: event.status, - resolvedLogView: event.resolvedLogView, - } as LogStreamPageContextWithLogView) - : {} - ), - storeQuery: actions.assign((_context, event) => - event.type === 'RECEIVED_INITIAL_QUERY_PARAMETERS' - ? ({ - parsedQuery: event.validatedQuery, - } as LogStreamPageContextWithQuery) - : event.type === 'VALID_QUERY_CHANGED' - ? ({ - parsedQuery: event.parsedQuery, - } as LogStreamPageContextWithQuery) - : {} - ), - storeTime: actions.assign((_context, event) => { - return 'timeRange' in event && 'refreshInterval' in event && 'timestamps' in event - ? ({ - timeRange: event.timeRange, - refreshInterval: event.refreshInterval, - timestamps: event.timestamps, - } as LogStreamPageContextWithTime) - : {}; - }), - storePositions: actions.assign((_context, event) => { - return 'targetPosition' in event && - 'visiblePositions' in event && - 'latestPosition' in event - ? ({ - targetPosition: event.targetPosition, - visiblePositions: event.visiblePositions, - latestPosition: event.latestPosition, - } as LogStreamPageContextWithPositions) - : {}; - }), - }, - guards: { - hasLogViewIndices: (_context, event) => - event.type === 'LOADING_LOG_VIEW_SUCCEEDED' && - ['empty', 'available'].includes(event.status.index), - }, - } - ); - -export type LogStreamPageStateMachine = ReturnType; -export type LogStreamPageActorRef = OmitDeprecatedState>; -export type LogStreamPageState = EmittedFrom; -export type LogStreamPageSend = LogStreamPageActorRef['send']; - -export type LogStreamPageStateMachineDependencies = { - logViewStateNotifications: LogViewNotificationChannel; -} & LogStreamQueryStateMachineDependencies; - -export const createLogStreamPageStateMachine = ({ - kibanaQuerySettings, - logViewStateNotifications, - queryStringService, - toastsService, - filterManagerService, - urlStateStorage, - timeFilterService, -}: LogStreamPageStateMachineDependencies) => - createPureLogStreamPageStateMachine().withConfig({ - services: { - logViewNotifications: () => logViewStateNotifications.createService(), - logStreamQuery: (context) => { - if (!('resolvedLogView' in context)) { - throw new Error('Failed to spawn log stream query service: no LogView in context'); - } - - const nowTimestamp = Date.now(); - const initialTimeRangeExpression: TimeRange = DEFAULT_TIMERANGE; - const initialRefreshInterval: RefreshInterval = DEFAULT_REFRESH_INTERVAL; - - return createLogStreamQueryStateMachine( - { - dataViews: [context.resolvedLogView.dataViewReference], - timeRange: { - ...initialTimeRangeExpression, - lastChangedCompletely: nowTimestamp, - }, - timestamps: { - startTimestamp: datemathToEpochMillis(initialTimeRangeExpression.from, 'down') ?? 0, - endTimestamp: datemathToEpochMillis(initialTimeRangeExpression.to, 'up') ?? 0, - lastChangedTimestamp: nowTimestamp, - }, - refreshInterval: initialRefreshInterval, - }, - { - kibanaQuerySettings, - queryStringService, - toastsService, - filterManagerService, - urlStateStorage, - timeFilterService, - } - ); - }, - logStreamPosition: (context) => { - return createLogStreamPositionStateMachine( - { - targetPosition: null, - latestPosition: null, - visiblePositions: { - endKey: null, - middleKey: null, - startKey: null, - pagesBeforeStart: Infinity, - pagesAfterEnd: Infinity, - }, - }, - { - urlStateStorage, - toastsService, - } - ); - }, - waitForInitialQueryParameters: waitForInitialQueryParameters(), - waitForInitialPositionParameters: waitForInitialPositionParameters(), - }, - }); diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts deleted file mode 100644 index 1a705bcc5c380..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts +++ /dev/null @@ -1,116 +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 type { TimeRange } from '@kbn/es-query'; -import type { LogViewStatus } from '@kbn/logs-shared-plugin/common'; -import type { - LogViewContextWithError, - LogViewContextWithResolvedLogView, - LogViewNotificationEvent, -} from '@kbn/logs-shared-plugin/public'; -import type { TimeKey } from '../../../../../common/time'; -import type { - JumpToTargetPositionEvent, - LogStreamPositionContext, - ReportVisiblePositionsEvent, - VisiblePositions, -} from '../../../log_stream_position_state'; -import type { LogStreamPositionNotificationEvent } from '../../../log_stream_position_state/src/notifications'; -import type { - LogStreamQueryContextWithTime, - ParsedQuery, - UpdateRefreshIntervalEvent, - UpdateTimeRangeEvent, -} from '../../../log_stream_query_state'; -import type { LogStreamQueryNotificationEvent } from '../../../log_stream_query_state/src/notifications'; - -export interface ReceivedInitialQueryParametersEvent { - type: 'RECEIVED_INITIAL_QUERY_PARAMETERS'; - validatedQuery: ParsedQuery; - timeRange: LogStreamPageContextWithTime['timeRange']; - refreshInterval: LogStreamPageContextWithTime['refreshInterval']; - timestamps: LogStreamPageContextWithTime['timestamps']; -} - -export interface ReceivedInitialPositionParametersEvent { - type: 'RECEIVED_INITIAL_POSITION_PARAMETERS'; - targetPosition: LogStreamPageContextWithPositions['targetPosition']; - latestPosition: LogStreamPageContextWithPositions['latestPosition']; - visiblePositions: LogStreamPageContextWithPositions['visiblePositions']; -} - -export type LogStreamPageEvent = - | LogViewNotificationEvent - | LogStreamQueryNotificationEvent - | LogStreamPositionNotificationEvent - | ReceivedInitialQueryParametersEvent - | ReceivedInitialPositionParametersEvent - | JumpToTargetPositionEvent - | ReportVisiblePositionsEvent - | UpdateTimeRangeEvent - | UpdateRefreshIntervalEvent; - -export interface LogStreamPageContextWithLogView { - logViewStatus: LogViewStatus; - resolvedLogView: LogViewContextWithResolvedLogView['resolvedLogView']; -} - -export interface LogStreamPageContextWithLogViewError { - logViewError: LogViewContextWithError['error']; -} - -export interface LogStreamPageContextWithQuery { - parsedQuery: ParsedQuery; -} - -export type LogStreamPageContextWithTime = LogStreamQueryContextWithTime; -export type LogStreamPageContextWithPositions = LogStreamPositionContext; - -export type LogStreamPageTypestate = - | { - value: 'uninitialized'; - context: {}; - } - | { - value: 'loadingLogView'; - context: {}; - } - | { - value: 'loadingLogViewFailed'; - context: LogStreamPageContextWithLogViewError; - } - | { - value: 'hasLogViewIndices'; - context: LogStreamPageContextWithLogView; - } - | { - value: { hasLogViewIndices: 'uninitialized' }; - context: LogStreamPageContextWithLogView; - } - | { - value: { hasLogViewIndices: 'initialized' }; - context: LogStreamPageContextWithLogView & - LogStreamPageContextWithQuery & - LogStreamPageContextWithTime & - LogStreamPageContextWithPositions; - } - | { - value: 'missingLogViewIndices'; - context: LogStreamPageContextWithLogView; - }; - -export type LogStreamPageStateValue = LogStreamPageTypestate['value']; -export type LogStreamPageContext = LogStreamPageTypestate['context']; - -export interface LogStreamPageCallbacks { - updateTimeRange: (timeRange: Partial) => void; - jumpToTargetPosition: (targetPosition: TimeKey | null) => void; - jumpToTargetPositionTime: (time: string) => void; - reportVisiblePositions: (visiblePositions: VisiblePositions) => void; - startLiveStreaming: () => void; - stopLiveStreaming: () => void; -} diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/index.ts deleted file mode 100644 index ddc7e818615b6..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/index.ts +++ /dev/null @@ -1,9 +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. - */ - -export * from './src/types'; -export * from './src/defaults'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/defaults.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/defaults.ts deleted file mode 100644 index 15556d8f2b4d7..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/defaults.ts +++ /dev/null @@ -1,9 +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. - */ - -export const DESIRED_BUFFER_PAGES = 2; -export const RELATIVE_END_UPDATE_DELAY = 1000; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/notifications.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/notifications.ts deleted file mode 100644 index f036bec8cb512..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/notifications.ts +++ /dev/null @@ -1,44 +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 type { - LogStreamPositionContext, - LogStreamPositionContextWithLatestPosition, - LogStreamPositionContextWithTargetPosition, - LogStreamPositionContextWithVisiblePositions, -} from './types'; - -export type PositionsChangedEvent = { - type: 'POSITIONS_CHANGED'; -} & LogStreamPositionContextWithTargetPosition & - LogStreamPositionContextWithLatestPosition & - LogStreamPositionContextWithVisiblePositions; - -export interface PageEndBufferReachedEvent { - type: 'PAGE_END_BUFFER_REACHED'; -} - -export type LogStreamPositionNotificationEvent = PositionsChangedEvent | PageEndBufferReachedEvent; - -export const LogStreamPositionNotificationEventSelectors = { - positionsChanged: (context: LogStreamPositionContext) => { - return 'targetPosition' in context && - 'latestPosition' in context && - 'visiblePositions' in context - ? ({ - type: 'POSITIONS_CHANGED', - targetPosition: context.targetPosition, - latestPosition: context.latestPosition, - visiblePositions: context.visiblePositions, - } as LogStreamPositionNotificationEvent) - : undefined; - }, - pageEndBufferReached: (context: LogStreamPositionContext) => - ({ - type: 'PAGE_END_BUFFER_REACHED', - } as LogStreamPositionNotificationEvent), -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts deleted file mode 100644 index 87d0cb8e4ec69..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts +++ /dev/null @@ -1,241 +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 type { IToasts } from '@kbn/core-notifications-browser'; -import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { convertISODateToNanoPrecision } from '@kbn/logs-shared-plugin/common'; -import moment from 'moment'; -import type { ActorRefFrom, EmittedFrom } from 'xstate'; -import { actions, createMachine, SpecialTargets } from 'xstate'; -import type { OmitDeprecatedState } from '@kbn/xstate-utils'; -import { sendIfDefined } from '@kbn/xstate-utils'; -import { isSameTimeKey } from '../../../../common/time'; -import { DESIRED_BUFFER_PAGES, RELATIVE_END_UPDATE_DELAY } from './defaults'; -import { LogStreamPositionNotificationEventSelectors } from './notifications'; -import type { - LogStreamPositionContext, - LogStreamPositionContextWithLatestPosition, - LogStreamPositionContextWithTargetPosition, - LogStreamPositionContextWithVisiblePositions, - LogStreamPositionEvent, - LogStreamPositionTypestate, -} from './types'; -import { initializeFromUrl, updateContextInUrl } from './url_state_storage_service'; - -export const createPureLogStreamPositionStateMachine = (initialContext: LogStreamPositionContext) => - /** @xstate-layout N4IgpgJg5mDOIC5QBsD2UDKAXATmAhgLYAKqsAlluagHbb5ZgB0Arjee1fsuQF6QBiAEoBRAMIiAkgDURAEQD6kgHKSAKpICCAGQUBFAKoihATQXFNQzQFkRa4xgDaABgC6iUAAcylajQ8gAB6IALQAbACsTAAcAEzRzgCcACzJccmxAIzR0QA0IACeiNkAzExhJSUA7FURsSXRYYklEVUAvm35aJi4BCQ+VLT0jEwcvtx8HFAAYjiohAY4yAIq6lrakgBa8grTQgDy1goGQtou7kgg3hSD-pfBCCGxTBHREYnOTelZ0bX5RQg0okmD8miVMhEwmEqmFGh0uuhsHgiKQbn5hswxlwePwIExrr5aLBRpxyBNcQIAFIGazEBRqfb0ywAcTs5n2GDW+2U5wCBNuAQeVUSz2SULCmQ+zlScQi-0QyWcVSYVU+QIhzlejQi8JA3SRfVRhLoWAYmNJ5Mg+IGfmJWLJOMEomI+yEagU0kknIAQtoROzORpuU43HybbRBYg6mEmGloskqrEqjkwrFYvLAdEyhkItLMlVqtVc+1OnrEb0UeGTWaSeNHXj+bba9i+IINLYFGIABKaZSsuS8y6NiP3RDC57ChOpZzStKxOWFRBZMqpqr5xIpT6xEXRXX6iv9NFDU0je2WvFYAAWcywWB4NCgxHwMBENAgylQVAAZuQAMYMJtyAgZAwGEEQXTdD0vUkX1-RdQNJGDQcvCrSMEHeTJygSWJkg+X5FQhDN4xjNNIk1V4xRKWIwj3ctkUPY0MWbB1Wwva9PzvKYnxfN8P2-P8AKJJgrxvTiHzAiD3U9H0-QDLllBDC4UKPO5QAeTJJTKVVITTRpt3iDMaiiCINUSDTMlw-Nklonp6KNW4mLPethPY2970fZ8wFfd9P3IH9-1uYkRI49yBECWAT2YfAv0YHAAApRG0TQNFkBQRGURQDGIORkv9OQRCSkwAEoBH3Oyq0ci1nOCtyuM87y+L8gTApc0T3OQq5UNHBAzOiFVohFEo5xKZx6mSDNeqYDTakyVMlWiTIhpsg1KxUyq61Y1qQrqnifP4gKmxqsSoDCiKa2i2KEoK5KZH9dLMuy3KFHywqSrKw0Ksi5jzy22qH24rzeN8-zBJoILXOOxxMiUzqVLQ2plTqEoRWnGcUgmpopvjRUYWSbJWhKZaD3s9EvqczajvcgGGuB5qmxoYGCimAQOuHVSggVGpymhMJnAhVUEjqDNMiVKJaiG+dfgG6prN1BmIDgAJ3tWxjIrDOHupCDSyjiBIUjnDJsjyRdHjSGJEwWjd8zeNGifKtavrYcncXV400IyIjMI3b36lVXmIgTO2PodmtnamWZ5kWZBXYFTXnmlWE-hNka+uoxIA6zRJZUJ0tlYYhyyaq1iY78NCSkiFULLnSFkYlaEMwacok2yGcRZF1pMiDlWC9DovcWtFT4CHLq1IVRaYnjapEmTRNnHBYXqKm5vhWaBIJTqLv89J3uNv7tm7T7yAS5HUfAQlCfkinmfYjnzIM23KI04z5Hs83knjx3lt+8pnbAb2pqDpEmPuzB4eMtJV1lBURIdcqgZlhH1PmJkcJDTqItEsCJbLB1Vp-Fi38IZU3qkDfaoM7TATAMA92581wynnFAmBRExQgmormCIFEKjUTfp9HBP0f7-UIf-EGLVeFQAod1cyzx4isKqHOfMkIGEkWYeRYiVEaK5zolgnup5D5sTar-GmxCWoM2-EzB8ojT5t2BK8HClFFqREIibduzgVQRCGiNJUyRWEig6B0IAA */ - createMachine( - { - context: initialContext, - predictableActionArguments: true, - id: 'logStreamPositionState', - initial: 'uninitialized', - states: { - uninitialized: { - meta: { - _DX_warning_: - "The Position machine cannot initializeFromUrl until after the Query machine has initialized, this is due to a dual dependency on the 'logPosition' URL parameter for legacy reasons.", - }, - on: { - RECEIVED_INITIAL_QUERY_PARAMETERS: { - target: 'initializingFromUrl', - }, - }, - }, - initializingFromUrl: { - on: { - INITIALIZED_FROM_URL: [ - { - target: 'initialized', - actions: ['storeTargetPosition', 'storeLatestPosition'], - }, - ], - }, - invoke: { - src: 'initializeFromUrl', - }, - }, - initialized: { - type: 'parallel', - states: { - positions: { - initial: 'initialized', - states: { - initialized: { - entry: ['updateContextInUrl', 'notifyPositionsChanged'], - on: { - JUMP_TO_TARGET_POSITION: { - target: 'initialized', - actions: ['updateTargetPosition'], - }, - REPORT_VISIBLE_POSITIONS: { - target: 'initialized', - actions: ['updateVisiblePositions'], - }, - TIME_CHANGED: { - target: 'initialized', - actions: ['updatePositionsFromTimeChange'], - }, - }, - }, - }, - }, - throttlingPageEndNotifications: { - initial: 'idle', - states: { - idle: { - on: { - REPORT_VISIBLE_POSITIONS: { - target: 'throttling', - }, - }, - }, - throttling: { - after: { - RELATIVE_END_UPDATE_DELAY: [ - { - target: 'notifying', - cond: 'hasReachedPageEndBuffer', - }, - { - target: 'idle', - }, - ], - }, - on: { - REPORT_VISIBLE_POSITIONS: { - target: 'throttling', - }, - }, - }, - notifying: { - entry: ['notifyPageEndBufferReached'], - always: 'idle', - }, - }, - }, - }, - }, - }, - }, - { - actions: { - notifyPositionsChanged: actions.pure(() => undefined), - notifyPageEndBufferReached: actions.pure(() => undefined), - storeTargetPosition: actions.assign((_context, event) => - 'targetPosition' in event - ? ({ - targetPosition: event.targetPosition, - } as LogStreamPositionContextWithTargetPosition) - : {} - ), - storeLatestPosition: actions.assign((_context, event) => - 'latestPosition' in event - ? ({ - latestPosition: event.latestPosition, - } as LogStreamPositionContextWithLatestPosition) - : {} - ), - updateTargetPosition: actions.assign((_context, event) => { - if (!('targetPosition' in event)) return {}; - - const nextTargetPosition = event.targetPosition?.time - ? { - time: event.targetPosition.time, - tiebreaker: event.targetPosition.tiebreaker ?? 0, - } - : null; - - const nextLatestPosition = !isSameTimeKey(_context.targetPosition, nextTargetPosition) - ? nextTargetPosition - : _context.latestPosition; - - return { - targetPosition: nextTargetPosition, - latestPosition: nextLatestPosition, - } as LogStreamPositionContextWithLatestPosition & - LogStreamPositionContextWithTargetPosition; - }), - updatePositionsFromTimeChange: actions.assign((_context, event) => { - if (!('timeRange' in event)) return {}; - - const { - timestamps: { startTimestamp, endTimestamp }, - } = event; - - // Reset the target position if it doesn't fall within the new range. - const targetPositionNanoTime = - _context.targetPosition && convertISODateToNanoPrecision(_context.targetPosition.time); - const startNanoDate = convertISODateToNanoPrecision(moment(startTimestamp).toISOString()); - const endNanoDate = convertISODateToNanoPrecision(moment(endTimestamp).toISOString()); - - const targetPositionShouldReset = - targetPositionNanoTime && - (startNanoDate > targetPositionNanoTime || endNanoDate < targetPositionNanoTime); - - return { - targetPosition: targetPositionShouldReset ? null : _context.targetPosition, - latestPosition: targetPositionShouldReset ? null : _context.latestPosition, - } as LogStreamPositionContextWithLatestPosition & - LogStreamPositionContextWithTargetPosition; - }), - updateVisiblePositions: actions.assign((_context, event) => - 'visiblePositions' in event - ? ({ - visiblePositions: event.visiblePositions, - latestPosition: !isSameTimeKey( - _context.visiblePositions.middleKey, - event.visiblePositions.middleKey - ) - ? event.visiblePositions.middleKey - : _context.visiblePositions.middleKey, - } as LogStreamPositionContextWithVisiblePositions) - : {} - ), - }, - delays: { - RELATIVE_END_UPDATE_DELAY, - }, - guards: { - // User is close to the bottom of the page. - hasReachedPageEndBuffer: (context, event) => - context.visiblePositions.pagesAfterEnd < DESIRED_BUFFER_PAGES, - }, - } - ); - -export type LogStreamPositionStateMachine = ReturnType< - typeof createPureLogStreamPositionStateMachine ->; -export type LogStreamPositionActorRef = OmitDeprecatedState< - ActorRefFrom ->; -export type LogStreamPositionState = EmittedFrom; - -export interface LogStreamPositionStateMachineDependencies { - urlStateStorage: IKbnUrlStateStorage; - toastsService: IToasts; -} - -export const createLogStreamPositionStateMachine = ( - initialContext: LogStreamPositionContext, - { urlStateStorage, toastsService }: LogStreamPositionStateMachineDependencies -) => - createPureLogStreamPositionStateMachine(initialContext).withConfig({ - actions: { - updateContextInUrl: updateContextInUrl({ toastsService, urlStateStorage }), - notifyPositionsChanged: sendIfDefined(SpecialTargets.Parent)( - LogStreamPositionNotificationEventSelectors.positionsChanged - ), - notifyPageEndBufferReached: sendIfDefined(SpecialTargets.Parent)( - LogStreamPositionNotificationEventSelectors.pageEndBufferReached - ), - }, - services: { - initializeFromUrl: initializeFromUrl({ toastsService, urlStateStorage }), - }, - }); diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/types.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/types.ts deleted file mode 100644 index 398d7e8addbf5..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/types.ts +++ /dev/null @@ -1,65 +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 type { TimeKey } from '../../../../common/time'; -import type { ReceivedInitialQueryParametersEvent } from '../../log_stream_page/state'; -import type { TimeChangedEvent } from '../../log_stream_query_state/src/notifications'; - -export interface VisiblePositions { - startKey: TimeKey | null; - middleKey: TimeKey | null; - endKey: TimeKey | null; - pagesAfterEnd: number; - pagesBeforeStart: number; -} - -export interface LogStreamPositionContextWithTargetPosition { - targetPosition: TimeKey | null; -} - -export interface LogStreamPositionContextWithLatestPosition { - latestPosition: TimeKey | null; -} -export interface LogStreamPositionContextWithVisiblePositions { - visiblePositions: VisiblePositions; -} -export type LogStreamPositionState = LogStreamPositionContextWithTargetPosition & - LogStreamPositionContextWithLatestPosition & - LogStreamPositionContextWithVisiblePositions; - -export type LogStreamPositionTypestate = - | { - value: 'uninitialized'; - context: LogStreamPositionState; - } - | { - value: 'initialized'; - context: LogStreamPositionState; - }; -export type LogStreamPositionContext = LogStreamPositionTypestate['context']; -export type LogStreamPositionStateValue = LogStreamPositionTypestate['value']; - -export interface JumpToTargetPositionEvent { - type: 'JUMP_TO_TARGET_POSITION'; - targetPosition: Partial | null; -} - -export interface ReportVisiblePositionsEvent { - type: 'REPORT_VISIBLE_POSITIONS'; - visiblePositions: VisiblePositions; -} - -export type LogStreamPositionEvent = - | { - type: 'INITIALIZED_FROM_URL'; - latestPosition: TimeKey | null; - targetPosition: TimeKey | null; - } - | ReceivedInitialQueryParametersEvent - | JumpToTargetPositionEvent - | ReportVisiblePositionsEvent - | TimeChangedEvent; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/url_state_storage_service.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/url_state_storage_service.ts deleted file mode 100644 index d23d708e84877..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_position_state/src/url_state_storage_service.ts +++ /dev/null @@ -1,100 +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 * as rt from 'io-ts'; -import type { IToasts } from '@kbn/core-notifications-browser'; -import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public'; -import * as Either from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/function'; -import type { InvokeCreator } from 'xstate'; -import { createPlainError, formatErrors } from '@kbn/io-ts-utils'; -import { minimalTimeKeyRT, pickTimeKey } from '../../../../common/time'; -import type { LogStreamPositionContext, LogStreamPositionEvent } from './types'; -interface LogStreamPositionUrlStateDependencies { - positionStateKey?: string; - toastsService: IToasts; - urlStateStorage: IKbnUrlStateStorage; -} - -export const defaultPositionStateKey = 'logPosition'; - -export const updateContextInUrl = - ({ - urlStateStorage, - positionStateKey = defaultPositionStateKey, - }: LogStreamPositionUrlStateDependencies) => - (context: LogStreamPositionContext, _event: LogStreamPositionEvent) => { - if (!('latestPosition' in context)) { - throw new Error('Missing keys from context needed to sync to the URL'); - } - - urlStateStorage.set( - positionStateKey, - positionStateInUrlRT.encode({ - position: context.latestPosition ? pickTimeKey(context.latestPosition) : null, - }), - { replace: true } - ); - }; - -export const initializeFromUrl = - ({ - positionStateKey = defaultPositionStateKey, - urlStateStorage, - toastsService, - }: LogStreamPositionUrlStateDependencies): InvokeCreator< - LogStreamPositionContext, - LogStreamPositionEvent - > => - (_context, _event) => - (send) => { - const positionQueryValueFromUrl = urlStateStorage.get(positionStateKey) ?? {}; - - const initialUrlValues = pipe( - decodePositionQueryValueFromUrl(positionQueryValueFromUrl), - Either.map(({ position }) => ({ - targetPosition: position?.time - ? { - time: position.time, - tiebreaker: position.tiebreaker ?? 0, - } - : null, - })), - Either.map(({ targetPosition }) => ({ - targetPosition, - latestPosition: targetPosition, - })) - ); - - if (Either.isLeft(initialUrlValues)) { - withNotifyOnErrors(toastsService).onGetError( - createPlainError(formatErrors(initialUrlValues.left)) - ); - - send({ - type: 'INITIALIZED_FROM_URL', - targetPosition: null, - latestPosition: null, - }); - } else { - send({ - type: 'INITIALIZED_FROM_URL', - targetPosition: initialUrlValues.right.targetPosition ?? null, - latestPosition: initialUrlValues.right.latestPosition ?? null, - }); - } - }; - -export const positionStateInUrlRT = rt.partial({ - position: rt.union([rt.partial(minimalTimeKeyRT.props), rt.null]), -}); - -export type PositionStateInUrl = rt.TypeOf; - -const decodePositionQueryValueFromUrl = (queryValueFromUrl: unknown) => { - return positionStateInUrlRT.decode(queryValueFromUrl); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/index.ts deleted file mode 100644 index 3b2a320ae181f..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export * from './src'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/defaults.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/defaults.ts deleted file mode 100644 index b9f4eb4f5f2a5..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/defaults.ts +++ /dev/null @@ -1,20 +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. - */ - -export const DEFAULT_QUERY = { - language: 'kuery', - query: '', -}; - -export const DEFAULT_FILTERS = []; - -export const DEFAULT_TIMERANGE = { - from: 'now-1d', - to: 'now', -}; - -export const DEFAULT_REFRESH_TIME_RANGE = DEFAULT_TIMERANGE; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/errors.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/errors.ts deleted file mode 100644 index 09e3af3e241a4..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/errors.ts +++ /dev/null @@ -1,21 +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. - */ - -/* eslint-disable max-classes-per-file */ -export class UnsupportedLanguageError extends Error { - constructor(message?: string) { - super(message); - Object.setPrototypeOf(this, new.target.prototype); - } -} - -export class QueryParsingError extends Error { - constructor(message?: string) { - super(message); - Object.setPrototypeOf(this, new.target.prototype); - } -} diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts deleted file mode 100644 index b9f6065f99092..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts +++ /dev/null @@ -1,13 +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. - */ - -export * from './errors'; -export * from './state_machine'; -export * from './types'; -export * from './url_state_storage_service'; -export * from './time_filter_state_service'; -export * from './defaults'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts deleted file mode 100644 index 928671d4d67ca..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts +++ /dev/null @@ -1,56 +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 type { RefreshInterval } from '@kbn/data-plugin/public'; -import type { ExtendedTimeRange, LogStreamQueryContext, ParsedQuery, Timestamps } from './types'; - -export interface TimeChangedEvent { - type: 'TIME_CHANGED'; - timeRange: ExtendedTimeRange; - refreshInterval: RefreshInterval; - timestamps: Timestamps; -} - -export type LogStreamQueryNotificationEvent = - | { - type: 'VALID_QUERY_CHANGED'; - parsedQuery: ParsedQuery; - } - | { - type: 'INVALID_QUERY_CHANGED'; - parsedQuery: ParsedQuery; - error: Error; - } - | TimeChangedEvent; - -export const logStreamQueryNotificationEventSelectors = { - validQueryChanged: (context: LogStreamQueryContext) => - 'parsedQuery' in context - ? ({ - type: 'VALID_QUERY_CHANGED', - parsedQuery: context.parsedQuery, - } as LogStreamQueryNotificationEvent) - : undefined, - invalidQueryChanged: (context: LogStreamQueryContext) => - 'validationError' in context - ? ({ - type: 'INVALID_QUERY_CHANGED', - parsedQuery: context.parsedQuery, - error: context.validationError, - } as LogStreamQueryNotificationEvent) - : undefined, - timeChanged: (context: LogStreamQueryContext) => { - return 'timeRange' in context && 'refreshInterval' in context && 'timestamps' in context - ? ({ - type: 'TIME_CHANGED', - timeRange: context.timeRange, - refreshInterval: context.refreshInterval, - timestamps: context.timestamps, - } as LogStreamQueryNotificationEvent) - : undefined; - }, -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/search_bar_state_service.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/search_bar_state_service.ts deleted file mode 100644 index d7bb762a63b6b..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/search_bar_state_service.ts +++ /dev/null @@ -1,61 +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 type { FilterManager, QueryStringContract } from '@kbn/data-plugin/public'; -import { map } from 'rxjs'; -import type { InvokeCreator } from 'xstate'; -import type { LogStreamQueryContext, LogStreamQueryEvent } from './types'; - -export const subscribeToQuerySearchBarChanges = - ({ - queryStringService, - }: { - queryStringService: QueryStringContract; - }): InvokeCreator => - (context) => - queryStringService.getUpdates$().pipe( - map(() => queryStringService.getQuery()), - map((query): LogStreamQueryEvent => { - return { - type: 'QUERY_FROM_SEARCH_BAR_CHANGED', - query, - }; - }) - ); - -export const updateQueryInSearchBar = - ({ queryStringService }: { queryStringService: QueryStringContract }) => - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if ('query' in context) { - queryStringService.setQuery(context.query); - } - }; - -export const subscribeToFilterSearchBarChanges = - ({ - filterManagerService, - }: { - filterManagerService: FilterManager; - }): InvokeCreator => - (context) => - filterManagerService.getUpdates$().pipe( - map(() => filterManagerService.getFilters()), - map((filters): LogStreamQueryEvent => { - return { - type: 'FILTERS_FROM_SEARCH_BAR_CHANGED', - filters, - }; - }) - ); - -export const updateFiltersInSearchBar = - ({ filterManagerService }: { filterManagerService: FilterManager }) => - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if ('filters' in context) { - filterManagerService.setFilters(context.filters); - } - }; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts deleted file mode 100644 index 6ad01bd1e8598..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts +++ /dev/null @@ -1,362 +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 type { IToasts } from '@kbn/core-notifications-browser'; -import type { - FilterManager, - QueryStringContract, - TimefilterContract, -} from '@kbn/data-plugin/public'; -import type { EsQueryConfig } from '@kbn/es-query'; -import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import type { ActorRefFrom } from 'xstate'; -import { actions, createMachine, SpecialTargets, send } from 'xstate'; -import { DEFAULT_REFRESH_INTERVAL } from '@kbn/logs-shared-plugin/common'; -import type { OmitDeprecatedState } from '@kbn/xstate-utils'; -import { sendIfDefined } from '@kbn/xstate-utils'; -import { logStreamQueryNotificationEventSelectors } from './notifications'; -import { - subscribeToFilterSearchBarChanges, - subscribeToQuerySearchBarChanges, - updateFiltersInSearchBar, - updateQueryInSearchBar, -} from './search_bar_state_service'; -import type { - LogStreamQueryContext, - LogStreamQueryContextWithDataViews, - LogStreamQueryContextWithFilters, - LogStreamQueryContextWithParsedQuery, - LogStreamQueryContextWithQuery, - LogStreamQueryContextWithRefreshInterval, - LogStreamQueryContextWithTime, - LogStreamQueryContextWithTimeRange, - LogStreamQueryContextWithValidationError, - LogStreamQueryEvent, - LogStreamQueryTypestate, -} from './types'; -import { - initializeFromUrl, - safeDefaultParsedQuery, - updateContextInUrl, -} from './url_state_storage_service'; -import { - initializeFromTimeFilterService, - subscribeToTimeFilterServiceChanges, - updateTimeContextFromTimeFilterService, - updateTimeContextFromTimeRangeUpdate, - updateTimeContextFromRefreshIntervalUpdate, - updateTimeInTimeFilterService, - updateTimeContextFromUrl, -} from './time_filter_state_service'; -import { showValidationErrorToast, validateQuery } from './validate_query_service'; -import { DEFAULT_REFRESH_TIME_RANGE } from './defaults'; - -export const createPureLogStreamQueryStateMachine = ( - initialContext: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime -) => - /** @xstate-layout N4IgpgJg5mDOIC5QEUCuYBOBPAdKgdgJZEAuhAhgDaEBekAxANoAMAuoqAA4D2shZ3fBxAAPRAEYAHAGYck8QCYArAoAsC8QHZNygJySANCCwTpszc2njpANnH2FN1UtUBfV0bSZcxfhWo0xFAAYhjcALYAqhiU9ACSAHJxACpxAIIAMnEAWgCiACIA+sEASgDyALKFkSUZLOxIIDx8AkKNYghKzJJyCvJOurqqA4bGiPI4XczTdjbM2kq64u6e6Ng4vmRUtEGhEcmE4WDBhJQkmADKmABuhADGYPFJqZk5BcXlVakVucVxGclciVChcgQA1OIAYVy9WEzT8gmEHWkkhsOGmmnkqnUumkzBsmmkRhMCF0mjRunxCjM9nx0iUkhWIC8602-lokBwAEc1lh6MhIkCAJofSog3JpEqQgAShQAQpLCjK0gkAOIFWGNeGtJHjcRKHA2aR9BT45hKOxKIljBDiZiqcRyAmmySqV2aJSYpksnykdl0CDc3n0YL-QElC6iqqgyUy+WK5VqjVsOG8BFtUAdeQGo0ms0W-XWklLHrDZi6K3SbQ2SSe728jZ+7YBoPeej5NLJNKFCG5ADqkcT6vymq4aZ17T1OeNklNcwLVuJ4wUCnR83kgzd7vr3kbfmbnJ5u+u2wg5DI+Cg9DBrw7qTKCRBkUh0IKyYaY5ahERk9tDtUODSJSdj6uW4i6EupKqMwgGKEoijMCaZKMh4zINmyB6Bke6wntQZ4XleN5ZHecQPsUaT-O+qZfj+mYSP+gHAfYXRLBBNr2HMOBaOBfQbto5o7qyTYBIeDYYGAuGEPhQTXrenakY+wQURkVFauO34ZqI9HiABQH4sxYFsSSdq2Dg5IWoSmiKDY+jSIJvr7iJWFiRJp7njJRFxCRZEXM+r75Kpn7prqf46Yx+mgaxkH9DgwHKDZGgrha9l7lsTk4GQRz0N8vylGKOV-ACQLiiUELQkq0oqsOo5NOptFaQg2aGjOc7mpaRYSO6hoWho5YKBYHooasu4YelmWPJEAAKd6-AVJRVTCKZqTRmlZvqzV5vO7WQeIBIwdIqhVjWZLDHMNgpaNHKBuN9BTTNhQlLkpS5BcsqJOGRE1dqGkhU1uazvm23saouLolYxoWCuahKEoF3CVdGWHGAqX+gwX11atpgOpM1KnYdmIVqoO06LokwyGYh2SJo2KqJocOOQj40o5hTDiB+tUrSF1jYyoB02E4VaSITxOSD03Q0tTQFujo9NpYzSM4LAJDuXc9CTWk6qFLkCRFHKkTBMExWPWkMqBRzwW-rtFjosMQv0rSpqaDtVMAXauKYrO8HMDpsuo9dCtK+J5DhDJIhK+eyPkAAZucGAABTiVH4mwAAFgAlPy6Hwy2TOB2AwdBOjnOW4SpNC+6qICxuxMooBZgQ+aB2WO4qH4NwEBwMIPrURbdEIAAtDYkH9wagxj97tjDCuVZuKhPp4EQ2eQD3E59+oO3GmZli7dYnoMn0dNz1nDOBJeexRDEK8-b+-U9OXwyWVoLFE+x5Y4KaVjUkaihC7TvvNrsMI4QDhHBOGcS4Nx7hgCvvVDoBJIKDH2osKsVYKzgUGP-JyMDMYICsqTf6rUFwdQQCDGCcUpC6BNPIOyR8RpL2ct4bBIVySaA2gDLahZIKelLFSU0iE5hkkwQjbCuBJLSUvEwy2UhWF9EUMoLQbpJ4IJcJMICdpdrQ12kNNCdCT6iWPKeSRfddr80NBWPEQE5jYhsAoaKzgcDYkcKLZx28aHDSEnohhQkxFGIaiYtENkrSWF0FYqeO18QGjxBoQ69J6Solnu4hycsWwiJwOJMR7kJHLV7n46R795BJQUTIJwdiAICKAsaA+kh7RCJzkjXxHQWFsMIUDYyeI0RWmsALBCNZYa0I8ckzkTNLoBgaRIDQrCyQ2AZPpPhSga4ATUIMV0CgyT4nOv0pJftEZHEVsrMgdwxm2ngq7cxVp+aU3AiLNE9cG5Wmgm4nRAztm5xIEHEOWSgqrz8ScriZzbBVyuexHQrDyZWE9M4TQ+hD7uCAA */ - createMachine( - { - context: initialContext, - preserveActionOrder: true, - predictableActionArguments: true, - id: 'Query', - initial: 'uninitialized', - states: { - uninitialized: { - always: { - target: 'initializingFromTimeFilterService', - }, - }, - - initializingFromUrl: { - on: { - INITIALIZED_FROM_URL: { - target: 'initialized', - actions: ['storeQuery', 'storeFilters', 'updateTimeContextFromUrl'], - }, - }, - invoke: { - src: 'initializeFromUrl', - }, - }, - initializingFromTimeFilterService: { - on: { - INITIALIZED_FROM_TIME_FILTER_SERVICE: { - target: 'initializingFromUrl', - actions: ['updateTimeContextFromTimeFilterService'], - }, - }, - invoke: { - src: 'initializeFromTimeFilterService', - }, - }, - initialized: { - type: 'parallel', - states: { - query: { - entry: ['updateContextInUrl', 'updateQueryInSearchBar', 'updateFiltersInSearchBar'], - invoke: [ - { - src: 'subscribeToQuerySearchBarChanges', - }, - { - src: 'subscribeToFilterSearchBarChanges', - }, - ], - initial: 'validating', - states: { - validating: { - invoke: { - src: 'validateQuery', - }, - on: { - VALIDATION_SUCCEEDED: { - target: 'valid', - actions: 'storeParsedQuery', - }, - - VALIDATION_FAILED: { - target: 'invalid', - actions: [ - 'storeValidationError', - 'storeDefaultParsedQuery', - 'showValidationErrorToast', - ], - }, - }, - }, - valid: { - entry: 'notifyValidQueryChanged', - }, - invalid: { - entry: 'notifyInvalidQueryChanged', - }, - revalidating: { - invoke: { - src: 'validateQuery', - }, - on: { - VALIDATION_FAILED: { - target: 'invalid', - actions: ['storeValidationError', 'showValidationErrorToast'], - }, - VALIDATION_SUCCEEDED: { - target: 'valid', - actions: ['clearValidationError', 'storeParsedQuery'], - }, - }, - }, - }, - on: { - QUERY_FROM_SEARCH_BAR_CHANGED: { - target: '.revalidating', - actions: ['storeQuery', 'updateContextInUrl'], - }, - - FILTERS_FROM_SEARCH_BAR_CHANGED: { - target: '.revalidating', - actions: ['storeFilters', 'updateContextInUrl'], - }, - - DATA_VIEWS_CHANGED: { - target: '.revalidating', - actions: 'storeDataViews', - }, - }, - }, - time: { - initial: 'initialized', - entry: ['notifyTimeChanged', 'updateTimeInTimeFilterService'], - invoke: [ - { - src: 'subscribeToTimeFilterServiceChanges', - }, - ], - states: { - initialized: { - always: [{ target: 'streaming', cond: 'isStreaming' }, { target: 'static' }], - }, - static: { - on: { - PAGE_END_BUFFER_REACHED: { - actions: ['expandPageEnd'], - }, - }, - }, - streaming: { - after: { - refresh: { target: 'streaming', actions: ['refreshTime'] }, - }, - }, - }, - on: { - TIME_FROM_TIME_FILTER_SERVICE_CHANGED: { - target: '.initialized', - actions: [ - 'updateTimeContextFromTimeFilterService', - 'notifyTimeChanged', - 'updateContextInUrl', - ], - }, - - UPDATE_TIME_RANGE: { - target: '.initialized', - actions: [ - 'updateTimeContextFromTimeRangeUpdate', - 'notifyTimeChanged', - 'updateTimeInTimeFilterService', - 'updateContextInUrl', - ], - }, - - UPDATE_REFRESH_INTERVAL: { - target: '.initialized', - actions: [ - 'updateTimeContextFromRefreshIntervalUpdate', - 'notifyTimeChanged', - 'updateTimeInTimeFilterService', - 'updateContextInUrl', - ], - }, - }, - }, - }, - }, - }, - }, - { - actions: { - notifyInvalidQueryChanged: actions.pure(() => undefined), - notifyValidQueryChanged: actions.pure(() => undefined), - notifyTimeChanged: actions.pure(() => undefined), - storeQuery: actions.assign((_context, event) => { - return 'query' in event ? ({ query: event.query } as LogStreamQueryContextWithQuery) : {}; - }), - storeFilters: actions.assign((_context, event) => - 'filters' in event ? ({ filters: event.filters } as LogStreamQueryContextWithFilters) : {} - ), - storeTimeRange: actions.assign((_context, event) => - 'timeRange' in event - ? ({ timeRange: event.timeRange } as LogStreamQueryContextWithTimeRange) - : {} - ), - storeRefreshInterval: actions.assign((_context, event) => - 'refreshInterval' in event - ? ({ - refreshInterval: event.refreshInterval, - } as LogStreamQueryContextWithRefreshInterval) - : {} - ), - storeDataViews: actions.assign((_context, event) => - 'dataViews' in event - ? ({ dataViews: event.dataViews } as LogStreamQueryContextWithDataViews) - : {} - ), - storeValidationError: actions.assign((_context, event) => - 'error' in event - ? ({ - validationError: event.error, - } as LogStreamQueryContextWithQuery & LogStreamQueryContextWithValidationError) - : {} - ), - storeDefaultParsedQuery: actions.assign( - (_context, _event) => - ({ parsedQuery: safeDefaultParsedQuery } as LogStreamQueryContextWithParsedQuery) - ), - storeParsedQuery: actions.assign((_context, event) => - 'parsedQuery' in event - ? ({ parsedQuery: event.parsedQuery } as LogStreamQueryContextWithParsedQuery) - : {} - ), - clearValidationError: actions.assign( - (_context, _event) => - ({ validationError: undefined } as Omit< - LogStreamQueryContextWithValidationError, - 'validationError' - >) - ), - updateTimeContextFromTimeFilterService, - updateTimeContextFromTimeRangeUpdate, - updateTimeContextFromRefreshIntervalUpdate, - refreshTime: send({ type: 'UPDATE_TIME_RANGE', timeRange: DEFAULT_REFRESH_TIME_RANGE }), - expandPageEnd: send((context) => ({ - type: 'UPDATE_TIME_RANGE', - timeRange: { to: context.timeRange.to }, - })), - updateTimeContextFromUrl, - }, - guards: { - isStreaming: (context, event) => - 'refreshInterval' in context ? !context.refreshInterval.pause : false, - }, - delays: { - refresh: (context, event) => - 'refreshInterval' in context - ? context.refreshInterval.value - : DEFAULT_REFRESH_INTERVAL.value, - }, - } - ); - -export interface LogStreamQueryStateMachineDependencies { - kibanaQuerySettings: EsQueryConfig; - queryStringService: QueryStringContract; - filterManagerService: FilterManager; - urlStateStorage: IKbnUrlStateStorage; - toastsService: IToasts; - timeFilterService: TimefilterContract; -} - -export const createLogStreamQueryStateMachine = ( - initialContext: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime, - { - kibanaQuerySettings, - queryStringService, - toastsService, - filterManagerService, - urlStateStorage, - timeFilterService, - }: LogStreamQueryStateMachineDependencies -) => - createPureLogStreamQueryStateMachine(initialContext).withConfig({ - actions: { - updateContextInUrl: updateContextInUrl({ toastsService, urlStateStorage }), - // Query - notifyInvalidQueryChanged: sendIfDefined(SpecialTargets.Parent)( - logStreamQueryNotificationEventSelectors.invalidQueryChanged - ), - notifyValidQueryChanged: sendIfDefined(SpecialTargets.Parent)( - logStreamQueryNotificationEventSelectors.validQueryChanged - ), - showValidationErrorToast: showValidationErrorToast({ toastsService }), - updateQueryInSearchBar: updateQueryInSearchBar({ queryStringService }), - updateFiltersInSearchBar: updateFiltersInSearchBar({ filterManagerService }), - // Time - updateTimeInTimeFilterService: updateTimeInTimeFilterService({ timeFilterService }), - notifyTimeChanged: sendIfDefined(SpecialTargets.Parent)( - logStreamQueryNotificationEventSelectors.timeChanged - ), - }, - services: { - initializeFromUrl: initializeFromUrl({ toastsService, urlStateStorage }), - initializeFromTimeFilterService: initializeFromTimeFilterService({ timeFilterService }), - validateQuery: validateQuery({ kibanaQuerySettings }), - subscribeToQuerySearchBarChanges: subscribeToQuerySearchBarChanges({ - queryStringService, - }), - subscribeToFilterSearchBarChanges: subscribeToFilterSearchBarChanges({ - filterManagerService, - }), - subscribeToTimeFilterServiceChanges: subscribeToTimeFilterServiceChanges({ - timeFilterService, - }), - }, - }); - -export type LogStreamQueryStateMachine = ReturnType; -export type LogStreamQueryActorRef = OmitDeprecatedState>; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/time_filter_state_service.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/time_filter_state_service.ts deleted file mode 100644 index 96a2aa6bbc4e6..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/time_filter_state_service.ts +++ /dev/null @@ -1,192 +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 type { RefreshInterval, TimefilterContract } from '@kbn/data-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; -import { map, merge } from 'rxjs'; -import type { InvokeCreator } from 'xstate'; -import { actions } from 'xstate'; -import { datemathToEpochMillis } from '../../../utils/datemath'; -import { DEFAULT_REFRESH_TIME_RANGE } from './defaults'; -import type { LogStreamQueryContext, LogStreamQueryEvent } from './types'; - -export interface TimefilterState { - timeRange: TimeRange; - refreshInterval: RefreshInterval; -} - -export const initializeFromTimeFilterService = - ({ - timeFilterService, - }: { - timeFilterService: TimefilterContract; - }): InvokeCreator => - (_context, _event) => - (send) => { - const timeRange = timeFilterService.getTime(); - const refreshInterval = timeFilterService.getRefreshInterval(); - - send({ - type: 'INITIALIZED_FROM_TIME_FILTER_SERVICE', - timeRange, - refreshInterval, - }); - }; - -export const updateTimeInTimeFilterService = - ({ timeFilterService }: { timeFilterService: TimefilterContract }) => - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if ('timeRange' in context) { - timeFilterService.setTime(context.timeRange); - } - - if ('refreshInterval' in context) { - timeFilterService.setRefreshInterval(context.refreshInterval); - } - }; - -export const subscribeToTimeFilterServiceChanges = - ({ - timeFilterService, - }: { - timeFilterService: TimefilterContract; - }): InvokeCreator => - (context) => - merge(timeFilterService.getTimeUpdate$(), timeFilterService.getRefreshIntervalUpdate$()).pipe( - map(() => getTimefilterState(timeFilterService)), - map((timeState): LogStreamQueryEvent => { - return { - type: 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED', - ...timeState, - }; - }) - ); - -const getTimefilterState = (timeFilterService: TimefilterContract): TimefilterState => ({ - timeRange: timeFilterService.getTime(), - refreshInterval: timeFilterService.getRefreshInterval(), -}); - -export const updateTimeContextFromTimeFilterService = actions.assign( - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if ( - event.type === 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED' || - event.type === 'INITIALIZED_FROM_TIME_FILTER_SERVICE' - ) { - return { - ...getTimeFromEvent(context, event), - refreshInterval: - event.type === 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED' - ? event.refreshInterval - : { ...context.refreshInterval, pause: event.refreshInterval.pause }, - }; - } else { - return {}; - } - } -); - -export const updateTimeContextFromUrl = actions.assign( - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if (event.type === 'INITIALIZED_FROM_URL') { - return { - ...('timeRange' in event && event.timeRange ? { ...getTimeFromEvent(context, event) } : {}), - ...('refreshInterval' in event && event.refreshInterval - ? { refreshInterval: event.refreshInterval } - : {}), - }; - } else { - return {}; - } - } -); - -export const updateTimeContextFromTimeRangeUpdate = actions.assign( - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if ('timeRange' in event && event.type === 'UPDATE_TIME_RANGE') { - return getTimeFromEvent(context, event); - } else { - return {}; - } - } -); - -export const updateTimeContextFromRefreshIntervalUpdate = actions.assign( - (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if ( - 'refreshInterval' in event && - 'refreshInterval' in context && - event.type === 'UPDATE_REFRESH_INTERVAL' - ) { - const pause = event.refreshInterval.pause ?? context.refreshInterval.pause; - const value = event.refreshInterval.value ?? context.refreshInterval.value; - - const nowTimestamp = Date.now(); - - const draftContext = { - refreshInterval: { - pause, - value, - }, - ...(!pause - ? { - timeRange: { - ...DEFAULT_REFRESH_TIME_RANGE, - lastChangedCompletely: nowTimestamp, - }, - } - : {}), - ...(!pause - ? { - timestamps: { - startTimestamp: datemathToEpochMillis(DEFAULT_REFRESH_TIME_RANGE.from, 'down') ?? 0, - endTimestamp: datemathToEpochMillis(DEFAULT_REFRESH_TIME_RANGE.to, 'up') ?? 0, - lastChangedTimestamp: nowTimestamp, - }, - } - : {}), - }; - - return draftContext; - } else { - return {}; - } - } -); - -const getTimeFromEvent = (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if (!('timeRange' in event) || !('timeRange' in context) || !('timestamps' in context)) { - throw new Error('Missing keys to get time from event'); - } - - const nowTimestamp = Date.now(); - const from = event.timeRange?.from ?? context.timeRange.from; - const to = event.timeRange?.to ?? context.timeRange.to; - - const fromTimestamp = event.timeRange?.from - ? datemathToEpochMillis(from, 'down') - : context.timestamps.startTimestamp; - const toTimestamp = event.timeRange?.to - ? datemathToEpochMillis(to, 'up') - : context.timestamps.endTimestamp; - - return { - timeRange: { - from, - to, - lastChangedCompletely: - event.timeRange?.from && event.timeRange?.to - ? nowTimestamp - : context.timeRange.lastChangedCompletely, - }, - timestamps: { - startTimestamp: fromTimestamp ?? 0, - endTimestamp: toTimestamp ?? 0, - lastChangedTimestamp: nowTimestamp, - }, - }; -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts deleted file mode 100644 index 5e058626de9d1..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts +++ /dev/null @@ -1,160 +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 type { RefreshInterval } from '@kbn/data-plugin/public'; -import type { - AggregateQuery, - BoolQuery, - DataViewBase, - Query, - Filter, - TimeRange, -} from '@kbn/es-query'; -import type { PageEndBufferReachedEvent } from '../../log_stream_position_state/src/notifications'; - -export type AnyQuery = Query | AggregateQuery; - -export interface ParsedQuery { - bool: BoolQuery; -} - -export interface LogStreamQueryContextWithDataViews { - dataViews: DataViewBase[]; -} - -export interface LogStreamQueryContextWithSavedQueryId { - savedQueryId: string; -} -export interface LogStreamQueryContextWithQuery { - query: AnyQuery; -} - -export interface LogStreamQueryContextWithParsedQuery { - parsedQuery: ParsedQuery; -} - -export interface LogStreamQueryContextWithFilters { - filters: Filter[]; -} - -export interface LogStreamQueryContextWithValidationError { - validationError: Error; -} - -export type ExtendedTimeRange = TimeRange & { lastChangedCompletely: number }; -export interface LogStreamQueryContextWithTimeRange { - timeRange: ExtendedTimeRange; -} - -export interface LogStreamQueryContextWithRefreshInterval { - refreshInterval: RefreshInterval; -} - -export interface Timestamps { - startTimestamp: number; - endTimestamp: number; - lastChangedTimestamp: number; -} - -export interface LogStreamQueryContextWithTimestamps { - timestamps: Timestamps; -} - -export type LogStreamQueryContextWithTime = LogStreamQueryContextWithTimeRange & - LogStreamQueryContextWithRefreshInterval & - LogStreamQueryContextWithTimestamps; - -export type LogStreamQueryTypestate = - | { - value: 'uninitialized'; - context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime; - } - | { - value: 'query' | { query: 'validating' }; - context: LogStreamQueryContextWithDataViews & - LogStreamQueryContextWithParsedQuery & - LogStreamQueryContextWithQuery & - LogStreamQueryContextWithFilters & - LogStreamQueryContextWithTime; - } - | { - value: { query: 'valid' }; - context: LogStreamQueryContextWithDataViews & - LogStreamQueryContextWithParsedQuery & - LogStreamQueryContextWithQuery & - LogStreamQueryContextWithFilters & - LogStreamQueryContextWithTime; - } - | { - value: { query: 'invalid' }; - context: LogStreamQueryContextWithDataViews & - LogStreamQueryContextWithParsedQuery & - LogStreamQueryContextWithQuery & - LogStreamQueryContextWithFilters & - LogStreamQueryContextWithTime & - LogStreamQueryContextWithValidationError; - } - | { - value: 'time' | { time: 'initialized' } | { time: 'streaming' } | { time: 'static' }; - context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime; - }; - -export type LogStreamQueryContext = LogStreamQueryTypestate['context']; - -export type LogStreamQueryStateValue = LogStreamQueryTypestate['value']; - -export interface UpdateTimeRangeEvent { - type: 'UPDATE_TIME_RANGE'; - timeRange: Partial; -} - -export interface UpdateRefreshIntervalEvent { - type: 'UPDATE_REFRESH_INTERVAL'; - refreshInterval: Partial; -} - -export type LogStreamQueryEvent = - | { - type: 'QUERY_FROM_SEARCH_BAR_CHANGED'; - query: AnyQuery; - } - | { - type: 'FILTERS_FROM_SEARCH_BAR_CHANGED'; - filters: Filter[]; - } - | { - type: 'DATA_VIEWS_CHANGED'; - dataViews: DataViewBase[]; - } - | { - type: 'VALIDATION_SUCCEEDED'; - parsedQuery: ParsedQuery; - } - | { - type: 'VALIDATION_FAILED'; - error: Error; - } - | { - type: 'INITIALIZED_FROM_URL'; - query: AnyQuery; - filters: Filter[]; - timeRange: TimeRange | null; - refreshInterval: RefreshInterval | null; - } - | { - type: 'INITIALIZED_FROM_TIME_FILTER_SERVICE'; - timeRange: TimeRange; - refreshInterval: RefreshInterval; - } - | { - type: 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED'; - timeRange: TimeRange; - refreshInterval: RefreshInterval; - } - | UpdateTimeRangeEvent - | UpdateRefreshIntervalEvent - | PageEndBufferReachedEvent; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts deleted file mode 100644 index bfa7625a2beb1..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts +++ /dev/null @@ -1,284 +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 type { IToasts } from '@kbn/core-notifications-browser'; -import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public'; -import * as Array from 'fp-ts/lib/Array'; -import * as Either from 'fp-ts/lib/Either'; -import { identity, pipe } from 'fp-ts/lib/function'; -import * as rt from 'io-ts'; -import type { InvokeCreator } from 'xstate'; -import { - defaultFilterStateKey, - defaultPositionStateKey, - DEFAULT_REFRESH_INTERVAL, -} from '@kbn/logs-shared-plugin/common'; -import moment from 'moment'; -import { createPlainError, formatErrors } from '@kbn/io-ts-utils'; -import { - getTimeRangeEndFromTime, - getTimeRangeStartFromTime, -} from '../../../../common/url_state_storage_service'; -import { minimalTimeKeyRT } from '../../../../common/time'; -import { datemathStringRT } from '../../../utils/datemath'; -import type { LogStreamQueryContext, LogStreamQueryEvent, ParsedQuery } from './types'; -import { DEFAULT_FILTERS, DEFAULT_QUERY, DEFAULT_TIMERANGE } from './defaults'; - -interface LogStreamQueryUrlStateDependencies { - filterStateKey?: string; - positionStateKey?: string; - savedQueryIdKey?: string; - toastsService: IToasts; - urlStateStorage: IKbnUrlStateStorage; -} - -type RequiredDefaults = Required>; -type OptionalDefaults = Pick; -type FullDefaults = Required; - -const requiredDefaultFilterStateValue: RequiredDefaults = { - query: DEFAULT_QUERY, - filters: DEFAULT_FILTERS, -}; - -const optionalDefaultFilterStateValue = { - timeRange: DEFAULT_TIMERANGE, - refreshInterval: DEFAULT_REFRESH_INTERVAL, -}; - -const defaultFilterStateValue: FullDefaults = { - ...requiredDefaultFilterStateValue, - ...optionalDefaultFilterStateValue, -}; - -export const safeDefaultParsedQuery: ParsedQuery = { - bool: { - must: [], - must_not: [], - should: [], - filter: [{ match_none: {} }], - }, -}; - -export const updateContextInUrl = - ({ - urlStateStorage, - filterStateKey = defaultFilterStateKey, - }: LogStreamQueryUrlStateDependencies) => - (context: LogStreamQueryContext, _event: LogStreamQueryEvent) => { - if ( - !('query' in context) || - !('filters' in context) || - !('timeRange' in context) || - !('refreshInterval' in context) - ) { - throw new Error('Missing keys from context needed to sync to the URL'); - } - - urlStateStorage.set( - filterStateKey, - filterStateInUrlRT.encode({ - query: context.query, - filters: context.filters, - timeRange: context.timeRange, - refreshInterval: context.refreshInterval, - }), - { replace: true } - ); - }; - -export const initializeFromUrl = - ({ - filterStateKey = defaultFilterStateKey, - positionStateKey = defaultPositionStateKey, - toastsService, - urlStateStorage, - }: LogStreamQueryUrlStateDependencies): InvokeCreator< - LogStreamQueryContext, - LogStreamQueryEvent - > => - (_context, _event) => - (send) => { - const filterQueryValueFromUrl = - urlStateStorage.get(filterStateKey) ?? requiredDefaultFilterStateValue; - const filterQueryE = decodeFilterQueryValueFromUrl(filterQueryValueFromUrl); - - // NOTE: Access logPosition for backwards compatibility with values previously stored under that key. - const positionQueryValueFromUrl = urlStateStorage.get(positionStateKey) ?? {}; - const positionQueryE = decodePositionQueryValueFromUrl(positionQueryValueFromUrl); - - if (Either.isLeft(filterQueryE) || Either.isLeft(positionQueryE)) { - withNotifyOnErrors(toastsService).onGetError( - createPlainError( - formatErrors([ - ...(Either.isLeft(filterQueryE) ? filterQueryE.left : []), - ...(Either.isLeft(positionQueryE) ? positionQueryE.left : []), - ]) - ) - ); - - send({ - type: 'INITIALIZED_FROM_URL', - query: defaultFilterStateValue.query, - filters: defaultFilterStateValue.filters, - timeRange: null, - refreshInterval: null, - }); - } else { - send({ - type: 'INITIALIZED_FROM_URL', - query: filterQueryE.right.query ?? defaultFilterStateValue.query, - filters: filterQueryE.right.filters ?? defaultFilterStateValue.filters, - timeRange: pipe( - // Via the logFilter key - pipe( - filterQueryE.right.timeRange, - Either.fromNullable(null), - Either.chain(({ from, to }) => - from && to ? Either.right({ from, to }) : Either.left(null) - ) - ), - // Via the legacy logPosition key, and start / end timeRange parameters - Either.alt(() => - pipe( - positionQueryE.right, - Either.fromNullable(null), - Either.chain(({ start, end }) => - start && end ? Either.right({ from: start, to: end }) : Either.left(null) - ) - ) - ), - // Via the legacy logPosition key, and deriving from / to from position.time - Either.alt(() => - pipe( - positionQueryE.right, - Either.fromNullable(null), - Either.chain(({ position }) => - position && position.time - ? Either.right({ - from: getTimeRangeStartFromTime(moment(position.time).valueOf()), - to: getTimeRangeEndFromTime(moment(position.time).valueOf()), - }) - : Either.left(null) - ) - ) - ), - Either.fold(identity, identity) - ), - refreshInterval: pipe( - // Via the logFilter key - pipe(filterQueryE.right.refreshInterval, Either.fromNullable(null)), - // Via the legacy logPosition key, and the boolean streamLive parameter - Either.alt(() => - pipe( - positionQueryE.right, - Either.fromNullable(null), - Either.chain(({ streamLive }) => - typeof streamLive === 'boolean' - ? Either.right({ - pause: !streamLive, - value: defaultFilterStateValue.refreshInterval.value, // NOTE: Was not previously synced to the URL, so falls straight to the default. - }) - : Either.left(null) - ) - ) - ), - Either.fold(identity, identity) - ), - }); - } - }; - -const legacyLegacyFilterStateWithExpressionInUrlRT = rt.type({ - kind: rt.literal('kuery'), - expression: rt.string, -}); - -export const legacyPositionStateInUrlRT = rt.partial({ - streamLive: rt.boolean, - start: datemathStringRT, - end: datemathStringRT, - position: rt.union([rt.partial(minimalTimeKeyRT.props), rt.null]), -}); - -const decodeFilterQueryValueFromUrl = (queryValueFromUrl: unknown) => - Either.getAltValidation(Array.getMonoid()).alt( - pipe( - pipe( - legacyLegacyFilterStateWithExpressionInUrlRT.decode(queryValueFromUrl), - Either.map(({ expression, kind }) => ({ query: { language: kind, query: expression } })) - ), - Either.alt(() => - pipe( - legacyFilterStateInUrlRT.decode(queryValueFromUrl), - Either.map((legacyQuery) => ({ query: legacyQuery })) - ) - ) - ), - () => filterStateInUrlRT.decode(queryValueFromUrl) - ); - -const decodePositionQueryValueFromUrl = (queryValueFromUrl: unknown) => { - return legacyPositionStateInUrlRT.decode(queryValueFromUrl); -}; - -export type FilterStateInUrl = rt.TypeOf; - -export const filterMeta = rt.partial({ - alias: rt.union([rt.string, rt.null]), - disabled: rt.boolean, - negate: rt.boolean, - controlledBy: rt.string, - group: rt.string, - index: rt.string, - isMultiIndex: rt.boolean, - type: rt.string, - key: rt.string, - params: rt.any, - value: rt.any, -}); - -export const filter = rt.intersection([ - rt.type({ - meta: filterMeta, - }), - rt.partial({ - query: rt.UnknownRecord, - }), -]); - -export const filterStateInUrlRT = rt.partial({ - query: rt.union([ - rt.strict({ - language: rt.string, - query: rt.union([rt.string, rt.record(rt.string, rt.unknown)]), - }), - rt.strict({ - esql: rt.string, - }), - ]), - filters: rt.array(filter), - timeRange: rt.strict({ - from: rt.string, - to: rt.string, - }), - refreshInterval: rt.strict({ - pause: rt.boolean, - value: rt.number, - }), -}); - -export const legacyFilterStateInUrlRT = rt.union([ - rt.strict({ - language: rt.string, - query: rt.union([rt.string, rt.record(rt.string, rt.unknown)]), - }), - rt.strict({ - esql: rt.string, - }), -]); diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/validate_query_service.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/validate_query_service.ts deleted file mode 100644 index 5834b40f838c7..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/log_stream_query_state/src/validate_query_service.ts +++ /dev/null @@ -1,71 +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 type { IToasts } from '@kbn/core-notifications-browser'; -import type { EsQueryConfig } from '@kbn/es-query'; -import { buildEsQuery, isOfQueryType } from '@kbn/es-query'; -import { i18n } from '@kbn/i18n'; -import type { InvokeCreator } from 'xstate'; -import { QueryParsingError, UnsupportedLanguageError } from './errors'; -import type { LogStreamQueryContext, LogStreamQueryEvent } from './types'; - -export const validateQuery = - ({ - kibanaQuerySettings, - }: { - kibanaQuerySettings: EsQueryConfig; - }): InvokeCreator => - (context) => - (send) => { - if (!('query' in context)) { - throw new Error('Failed to validate query: no query in context'); - } - - const { dataViews, query, filters } = context; - - if (!isOfQueryType(query)) { - send({ - type: 'VALIDATION_FAILED', - error: new UnsupportedLanguageError('Failed to validate query: unsupported language'), - }); - - return; - } - - try { - const parsedQuery = buildEsQuery(dataViews, query, filters, kibanaQuerySettings); - - send({ - type: 'VALIDATION_SUCCEEDED', - parsedQuery, - }); - } catch (error) { - send({ - type: 'VALIDATION_FAILED', - error: new QueryParsingError(`${error}`), - }); - } - }; - -export const showValidationErrorToast = - ({ toastsService }: { toastsService: IToasts }) => - (_context: LogStreamQueryContext, event: LogStreamQueryEvent) => { - if (event.type !== 'VALIDATION_FAILED') { - return; - } - - toastsService.addError(event.error, { - title: validationErrorToastTitle, - }); - }; - -const validationErrorToastTitle = i18n.translate( - 'xpack.infra.logsPage.toolbar.logFilterErrorToastTitle', - { - defaultMessage: 'Log filter error', - } -); diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/README.md b/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/README.md deleted file mode 100644 index 337f65add4226..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @kbn/observability-logs-xstate-helpers - -Helpers to design well-typed state machines with XState diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/index.ts deleted file mode 100644 index 3b2a320ae181f..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export * from './src'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/index.ts b/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/index.ts deleted file mode 100644 index 67b23e66b78e8..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/index.ts +++ /dev/null @@ -1,9 +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. - */ - -export * from './invalid_state_callout'; -export * from './state_machine_playground'; diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/invalid_state_callout.tsx b/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/invalid_state_callout.tsx deleted file mode 100644 index d6827fba2f343..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/invalid_state_callout.tsx +++ /dev/null @@ -1,33 +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 { EuiCallOut } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import stringify from 'json-stable-stringify'; -import React from 'react'; -import type { State } from 'xstate'; - -export const InvalidStateCallout: React.FC<{ state: State }> = ({ - state, -}) => ( - - - -); - -const invalidStateCalloutTitle = i18n.translate( - 'xpack.infra.logs.common.invalidStateCalloutTitle', - { defaultMessage: 'Invalid state encountered' } -); diff --git a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/state_machine_playground.tsx b/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/state_machine_playground.tsx deleted file mode 100644 index 5a40bd5d32292..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/observability_logs/xstate_helpers/src/state_machine_playground.tsx +++ /dev/null @@ -1,81 +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 { EuiButton } from '@elastic/eui'; -import React, { useCallback } from 'react'; -import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; - -export const StateMachinePlayground = () => { - const { changeLogViewReference, revertToDefaultLogView, update, isLoading, logViewStateService } = - useLogViewContext(); - - const switchToInlineLogView = useCallback(() => { - changeLogViewReference({ - type: 'log-view-inline', - id: 'playground-log-view', - attributes: { - name: 'playground-log-view-name', - description: 'from the state machine playground', - logIndices: { type: 'index_name', indexName: 'logs-*' }, - logColumns: [ - { - fieldColumn: { - id: 'playground-field-column', - field: 'event.dataset', - }, - }, - ], - }, - }); - }, [changeLogViewReference]); - - const updateLogView = useCallback(() => { - update({ - name: 'Updated playground name', - }); - }, [update]); - - const persistInlineLogView = useCallback(() => { - logViewStateService.send({ - type: 'PERSIST_INLINE_LOG_VIEW', - }); - }, [logViewStateService]); - - return ( - <> - {isLoading && 'Is loading'} - switchToInlineLogView()} - > - {'Switch to inline Log View'} - - persistInlineLogView()} - > - {'Persist inline Log View'} - - revertToDefaultLogView()} - > - {'Revert to default (persisted) Log View'} - - updateLogView()} - > - {'Update log view'} - - - ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx index 59885c7ce3b1b..4fa36fc450a0c 100644 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx +++ b/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_categories/sections/top_categories/category_example_message.tsx @@ -115,8 +115,8 @@ export const CategoryExampleMessage: React.FunctionComponent<{ onClose={closeMenu} items={[ { - label: i18n.translate('xpack.infra.logs.categoryExample.viewInStreamText', { - defaultMessage: 'View in stream', + label: i18n.translate('xpack.infra.logs.categoryExample.viewInDiscoverText', { + defaultMessage: 'View in Discover', }), onClick: viewInStreamLinkProps.onClick!, href: viewInStreamLinkProps.href, diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/log_entry_example.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/log_entry_example.tsx index 61b1685cf36e7..1152b7c96ac17 100644 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/log_entry_example.tsx +++ b/x-pack/solutions/observability/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/log_entry_example.tsx @@ -54,10 +54,10 @@ const VIEW_DETAILS_LABEL = i18n.translate( } ); -const VIEW_IN_STREAM_LABEL = i18n.translate( - 'xpack.infra.logs.analysis.logEntryExamplesViewInStreamLabel', +const VIEW_IN_DISCOVER_LABEL = i18n.translate( + 'xpack.infra.logs.analysis.logEntryExamplesViewInDiscoverLabel', { - defaultMessage: 'View in stream', + defaultMessage: 'View in Discover', } ); @@ -160,7 +160,7 @@ export const LogEntryExampleMessage: React.FunctionComponent = ({ }, }, { - label: VIEW_IN_STREAM_LABEL, + label: VIEW_IN_DISCOVER_LABEL, onClick: viewInStreamLinkProps.onClick, href: viewInStreamLinkProps.href, }, diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/page_content.tsx index 3eb3c9fae53de..774eef04e6274 100644 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/page_content.tsx +++ b/x-pack/solutions/observability/plugins/infra/public/pages/logs/page_content.tsx @@ -10,14 +10,13 @@ import { i18n } from '@kbn/i18n'; import React, { useContext } from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public'; +import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public'; import type { SharePublicStart } from '@kbn/share-plugin/public/plugin'; import { type ObservabilityOnboardingLocatorParams, OBSERVABILITY_ONBOARDING_LOCATOR, } from '@kbn/deeplinks-observability'; import { dynamic } from '@kbn/shared-ux-utility'; -import { isDevMode } from '@kbn/xstate-utils'; import { type LogsLocatorParams, LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common'; import { LazyAlertDropdownWrapper } from '../../alerting/log_threshold'; import { HelpCenterContent } from '../../components/help_center_content'; @@ -34,12 +33,6 @@ const LogEntryRatePage = dynamic(() => import('./log_entry_rate').then((mod) => ({ default: mod.LogEntryRatePage })) ); -const StateMachinePlayground = dynamic(() => - import('../../observability_logs/xstate_helpers').then((mod) => ({ - default: mod.StateMachinePlayground, - })) -); - export const LogsPageContent: React.FunctionComponent = () => { const { application, share } = useKibana<{ share: SharePublicStart }>().services; @@ -49,17 +42,10 @@ export const LogsPageContent: React.FunctionComponent = () => { ); const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext); - const enableDeveloperRoutes = isDevMode(); - useReadOnlyBadge(!uiCapabilities?.logs?.save); const routes = getLogsAppRoutes(); - const settingsLinkProps = useLinkProps({ - app: 'logs', - pathname: 'settings', - }); - return ( <> @@ -69,9 +55,6 @@ export const LogsPageContent: React.FunctionComponent = () => { - - {settingsTabTitle} - { /> - {enableDeveloperRoutes && ( - - )} @@ -115,10 +95,6 @@ const pageTitle = i18n.translate('xpack.infra.header.logsTitle', { defaultMessage: 'Logs', }); -const settingsTabTitle = i18n.translate('xpack.infra.logs.index.settingsTabTitle', { - defaultMessage: 'Settings', -}); - const feedbackLinkUrl = 'https://discuss.elastic.co/c/logs'; const ADD_DATA_LABEL = i18n.translate('xpack.infra.logsHeaderAddDataButtonLabel', { diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/add_log_column_popover.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/add_log_column_popover.tsx deleted file mode 100644 index 1b0fe39429609..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/add_log_column_popover.tsx +++ /dev/null @@ -1,161 +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 type { EuiSelectableOption } from '@elastic/eui'; -import { EuiBadge, EuiButton, EuiPopover, EuiPopoverTitle, EuiSelectable } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useMemo } from 'react'; -import { v4 as uuidv4 } from 'uuid'; -import styled from '@emotion/styled'; -import type { LogColumnConfiguration } from '../../../utils/source_configuration'; -import { useVisibilityState } from '../../../hooks/use_visibility_state'; - -interface SelectableColumnOption { - optionProps: EuiSelectableOption; - columnConfiguration: LogColumnConfiguration; -} - -export const AddLogColumnButtonAndPopover: React.FunctionComponent<{ - addLogColumn: (logColumnConfiguration: LogColumnConfiguration) => void; - availableFields: string[]; - isDisabled?: boolean; -}> = ({ addLogColumn, availableFields, isDisabled }) => { - const { isVisible: isOpen, show: openPopover, hide: closePopover } = useVisibilityState(false); - - const availableColumnOptions = useMemo( - () => [ - { - optionProps: { - append: , - 'data-test-subj': 'addTimestampLogColumn', - // this key works around EuiSelectable using a lowercased label as - // key, which leads to conflicts with field names - key: 'timestamp', - label: 'Timestamp', - }, - columnConfiguration: { - timestampColumn: { - id: uuidv4(), - }, - }, - }, - { - optionProps: { - 'data-test-subj': 'addMessageLogColumn', - append: , - // this key works around EuiSelectable using a lowercased label as - // key, which leads to conflicts with field names - key: 'message', - label: 'Message', - }, - columnConfiguration: { - messageColumn: { - id: uuidv4(), - }, - }, - }, - ...availableFields.map((field) => ({ - optionProps: { - 'data-test-subj': `addFieldLogColumn addFieldLogColumn:${field}`, - // this key works around EuiSelectable using a lowercased label as - // key, which leads to conflicts with fields that only differ in the - // case (e.g. the metricbeat mongodb module) - key: `field-${field}`, - label: field, - }, - columnConfiguration: { - fieldColumn: { - id: uuidv4(), - field, - }, - }, - })), - ], - [availableFields] - ); - - const availableOptions = useMemo( - () => availableColumnOptions.map((availableColumnOption) => availableColumnOption.optionProps), - [availableColumnOptions] - ); - - const handleColumnSelection = useCallback( - (selectedOptions: EuiSelectableOption[]) => { - closePopover(); - - const selectedOptionIndex = selectedOptions.findIndex( - (selectedOption) => selectedOption.checked === 'on' - ); - const selectedOption = availableColumnOptions[selectedOptionIndex]; - - addLogColumn(selectedOption.columnConfiguration); - }, - [addLogColumn, availableColumnOptions, closePopover] - ); - - return ( - - - - } - closePopover={closePopover} - id="addLogColumn" - isOpen={isOpen} - ownFocus - panelPaddingSize="none" - > - - {(list, search) => ( - - {search} - {list} - - )} - - - ); -}; - -const searchProps = { - 'data-test-subj': 'fieldSearchInput', -}; - -const selectableListProps = { - showIcons: false, -}; - -const SystemColumnBadge: React.FunctionComponent = () => ( - - - -); - -const SelectableContent = styled.div` - width: 400px; -`; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/form_elements.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/form_elements.tsx deleted file mode 100644 index 151a070a328b0..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/form_elements.tsx +++ /dev/null @@ -1,244 +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 equal from 'fast-deep-equal'; -import { useCallback, useMemo, useState } from 'react'; -import useAsync from 'react-use/lib/useAsync'; -import type { ObjectEntries } from '../../../../common/utility_types'; -import type { ChildFormValidationError, GenericValidationError } from './validation_errors'; - -const unsetValue = Symbol('unset form value'); - -type ValueUpdater = (updater: (previousValue: Value) => Value) => void; - -export interface FormElement { - initialValue: Value; - isDirty: boolean; - resetValue: () => void; - updateValue: ValueUpdater; - validity: FormElementValidity; - value: Value; -} - -type FormElementMap = { - [formElementName in keyof FormValues]: FormElement; -}; - -export interface CompositeFormElement - extends FormElement { - childFormElements: FormElementMap; -} - -export type FormElementValidity = - | { validity: 'valid' } - | { validity: 'invalid'; reasons: InvalidReason[] } - | { validity: 'pending' }; - -export const useFormElement = ({ - initialValue, - validate, -}: { - initialValue: Value; - validate?: (value: Value) => Promise; -}): FormElement => { - const [changedValue, setChangedValue] = useState(unsetValue); - - const value = changedValue !== unsetValue ? changedValue : initialValue; - - const updateValue = useCallback>( - (updater) => - setChangedValue((previousValue) => - previousValue === unsetValue ? updater(initialValue) : updater(previousValue) - ), - [initialValue] - ); - - const resetValue = useCallback(() => setChangedValue(unsetValue), []); - - const isDirty = useMemo(() => !equal(value, initialValue), [value, initialValue]); - - const validity = useValidity(value, validate); - - return useMemo( - () => ({ - initialValue, - isDirty, - resetValue, - updateValue, - validity, - value, - }), - [initialValue, isDirty, resetValue, updateValue, validity, value] - ); -}; - -export const useCompositeFormElement = ({ - childFormElements, - validate, -}: { - childFormElements: FormElementMap; - validate?: (values: FormValues) => Promise; -}): CompositeFormElement => { - const childFormElementEntries = useMemo( - () => Object.entries(childFormElements) as ObjectEntries, - // eslint-disable-next-line react-hooks/exhaustive-deps - Object.entries(childFormElements).flat() - ); - - const value = useMemo( - () => - childFormElementEntries.reduce( - (accumulatedFormValues, [formElementName, formElement]) => ({ - ...accumulatedFormValues, - [formElementName]: formElement.value, - }), - {} as FormValues - ), - [childFormElementEntries] - ); - - const updateValue = useCallback( - (updater: (previousValues: FormValues) => FormValues) => { - const newValues = updater(value); - - childFormElementEntries.forEach(([formElementName, formElement]) => - formElement.updateValue(() => newValues[formElementName]) - ); - }, - [childFormElementEntries, value] - ); - - const isDirty = useMemo( - () => childFormElementEntries.some(([, formElement]) => formElement.isDirty), - [childFormElementEntries] - ); - - const formValidity = useValidity(value, validate); - const childFormElementsValidity = useMemo< - FormElementValidity - >(() => { - if ( - childFormElementEntries.some(([, formElement]) => formElement.validity.validity === 'invalid') - ) { - return { - validity: 'invalid', - reasons: [{ type: 'child' }], - }; - } else if ( - childFormElementEntries.some(([, formElement]) => formElement.validity.validity === 'pending') - ) { - return { - validity: 'pending', - }; - } else { - return { - validity: 'valid', - }; - } - }, [childFormElementEntries]); - - const validity = useMemo( - () => getCombinedValidity(formValidity, childFormElementsValidity), - [formValidity, childFormElementsValidity] - ); - - const resetValue = useCallback(() => { - childFormElementEntries.forEach(([, formElement]) => formElement.resetValue()); - }, [childFormElementEntries]); - - const initialValue = useMemo( - () => - childFormElementEntries.reduce( - (accumulatedFormValues, [formElementName, formElement]) => ({ - ...accumulatedFormValues, - [formElementName]: formElement.initialValue, - }), - {} as FormValues - ), - [childFormElementEntries] - ); - - return useMemo( - () => ({ - childFormElements, - initialValue, - isDirty, - resetValue, - updateValue, - validity, - value, - }), - [childFormElements, initialValue, isDirty, resetValue, updateValue, validity, value] - ); -}; - -const useValidity = ( - value: Value, - validate?: (value: Value) => Promise -) => { - const validationState = useAsync( - () => validate?.(value) ?? Promise.resolve([]), - [validate, value] - ); - - const validity = useMemo>(() => { - if (validationState.loading) { - return { validity: 'pending' as const }; - } else if (validationState.error != null) { - return { - validity: 'invalid' as const, - reasons: [ - { - type: 'generic' as const, - message: `${validationState.error}`, - }, - ], - }; - } else if (validationState.value && validationState.value.length > 0) { - return { - validity: 'invalid' as const, - reasons: validationState.value, - }; - } else { - return { - validity: 'valid' as const, - }; - } - }, [validationState.error, validationState.loading, validationState.value]); - - return validity; -}; - -export const getCombinedValidity = ( - first: FormElementValidity, - second: FormElementValidity -): FormElementValidity => { - if (first.validity === 'invalid' || second.validity === 'invalid') { - return { - validity: 'invalid', - reasons: [ - ...(first.validity === 'invalid' ? first.reasons : []), - ...(second.validity === 'invalid' ? second.reasons : []), - ], - }; - } else if (first.validity === 'pending' || second.validity === 'pending') { - return { - validity: 'pending', - }; - } else { - return { - validity: 'valid', - }; - } -}; - -export const isFormElementForType = - (isValue: (value: any) => value is Value) => - ( - formElement: FormElement - ): formElement is FormElement => - isValue(formElement.value); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/form_field_props.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/form_field_props.tsx deleted file mode 100644 index 27f8c50db74f9..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/form_field_props.tsx +++ /dev/null @@ -1,39 +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 from 'react'; -import type { FormElement } from './form_elements'; -import { LogSourceConfigurationFormError } from './source_configuration_form_errors'; -import type { FormValidationError } from './validation_errors'; - -export const getFormRowProps = (formElement: FormElement) => ({ - error: - formElement.validity.validity === 'invalid' - ? formElement.validity.reasons.map((error) => ( - - )) - : [], - isInvalid: formElement.validity.validity === 'invalid', -}); - -export const getInputFieldProps = - ( - decodeInputValue: (value: string) => Value, - encodeInputValue: (value: Value) => string - ) => - (formElement: FormElement) => ({ - isInvalid: formElement.validity.validity === 'invalid', - onChange: (evt: React.ChangeEvent) => { - const newValue = evt.currentTarget.value; - formElement.updateValue(() => decodeInputValue(newValue)); - }, - value: encodeInputValue(formElement.value), - }); - -export const getStringInputFieldProps = getInputFieldProps( - (value) => `${value}`, - (value) => value -); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index.ts b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index.ts deleted file mode 100644 index fd8dc9a06753b..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export * from './source_configuration_settings'; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_names_configuration_panel.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_names_configuration_panel.tsx deleted file mode 100644 index cf6629df42215..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_names_configuration_panel.tsx +++ /dev/null @@ -1,86 +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 { EuiCode, EuiDescribedFormGroup, EuiFieldText, EuiFormRow } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React from 'react'; -import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; -import type { LogIndexNameReference } from '@kbn/logs-shared-plugin/common'; -import type { FormElement } from './form_elements'; -import { getFormRowProps, getInputFieldProps } from './form_field_props'; -import type { FormValidationError } from './validation_errors'; - -export const IndexNamesConfigurationPanel: React.FC<{ - isLoading: boolean; - isReadOnly: boolean; - indexNamesFormElement: FormElement; -}> = ({ isLoading, isReadOnly, indexNamesFormElement }) => { - useTrackPageview({ app: 'infra_logs', path: 'log_source_configuration_index_name' }); - useTrackPageview({ - app: 'infra_logs', - path: 'log_source_configuration_index_name', - delay: 15000, - }); - - return ( - <> - - - - } - description={ - - } - > - logs-*,filebeat-*, - }} - /> - } - label={ - - } - {...getFormRowProps(indexNamesFormElement)} - > - - - - - ); -}; - -const getIndexNamesInputFieldProps = getInputFieldProps( - (value) => ({ - type: 'index_name', - indexName: value, - }), - ({ indexName }) => indexName -); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_pattern_configuration_panel.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_pattern_configuration_panel.tsx deleted file mode 100644 index caca8bcf72594..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_pattern_configuration_panel.tsx +++ /dev/null @@ -1,115 +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 { EuiDescribedFormGroup, EuiFormRow, EuiLink, EuiSpacer } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useMemo } from 'react'; -import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; -import { useLinkProps } from '@kbn/observability-shared-plugin/public'; -import type { LogDataViewReference } from '@kbn/logs-shared-plugin/common'; -import type { FormElement } from './form_elements'; -import { getFormRowProps } from './form_field_props'; -import { IndexPatternSelector } from './index_pattern_selector'; -import type { FormValidationError } from './validation_errors'; - -export const IndexPatternConfigurationPanel: React.FC<{ - isLoading: boolean; - isReadOnly: boolean; - indexPatternFormElement: FormElement; -}> = ({ isLoading, isReadOnly, indexPatternFormElement }) => { - useTrackPageview({ app: 'infra_logs', path: 'log_source_configuration_index_pattern' }); - useTrackPageview({ - app: 'infra_logs', - path: 'log_source_configuration_index_pattern', - delay: 15000, - }); - - const changeIndexPatternId = useCallback( - (dataViewId: string | undefined) => { - if (dataViewId != null) { - indexPatternFormElement.updateValue(() => ({ - type: 'data_view', - dataViewId, - })); - } else { - indexPatternFormElement.updateValue(() => undefined); - } - }, - [indexPatternFormElement] - ); - - return ( - <> - - - - - - } - description={ - - } - > - - } - {...useMemo( - () => (isLoading ? {} : getFormRowProps(indexPatternFormElement)), - [isLoading, indexPatternFormElement] - )} - > - - - - - ); -}; - -const DataViewsInlineHelpMessage = React.memo(() => { - const dataViewsManagementLinkProps = useLinkProps({ - app: 'management', - pathname: '/kibana/dataViews', - }); - - return ( - - - - ), - }} - /> - ); -}); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_pattern_selector.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_pattern_selector.tsx deleted file mode 100644 index 7283cbeea47bb..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/index_pattern_selector.tsx +++ /dev/null @@ -1,89 +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 type { EuiComboBoxOptionOption } from '@elastic/eui'; -import { EuiComboBox } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React, { useCallback, useEffect, useMemo } from 'react'; -import { useKibanaIndexPatternTitles } from '../../../hooks/use_kibana_index_patterns'; - -type IndexPatternOption = EuiComboBoxOptionOption; - -export const IndexPatternSelector: React.FC<{ - indexPatternId: string | undefined; - isLoading: boolean; - isReadOnly: boolean; - onChangeIndexPatternId: (indexPatternId: string | undefined) => void; -}> = ({ indexPatternId, isLoading, isReadOnly, onChangeIndexPatternId }) => { - const { - indexPatternTitles: availableIndexPatterns, - latestIndexPatternTitlesRequest, - fetchIndexPatternTitles, - } = useKibanaIndexPatternTitles(); - - useEffect(() => { - fetchIndexPatternTitles(); - }, [fetchIndexPatternTitles]); - - const availableOptions = useMemo(() => { - const options = [ - ...availableIndexPatterns.map(({ id, title }) => ({ - key: id, - label: title, - value: id, - })), - ...(indexPatternId == null || availableIndexPatterns.some(({ id }) => id === indexPatternId) - ? [] - : [ - { - key: indexPatternId, - label: i18n.translate('xpack.infra.logSourceConfiguration.missingDataViewsLabel', { - defaultMessage: `Missing data view {indexPatternId}`, - values: { - indexPatternId, - }, - }), - value: indexPatternId, - }, - ]), - ]; - return options; - }, [availableIndexPatterns, indexPatternId]); - - const selectedOptions = useMemo( - () => availableOptions.filter(({ key }) => key === indexPatternId), - [availableOptions, indexPatternId] - ); - - const changeSelectedIndexPatterns = useCallback( - ([newlySelectedOption]: IndexPatternOption[]) => { - if (typeof newlySelectedOption?.key === 'string') { - return onChangeIndexPatternId(newlySelectedOption.key); - } - - return onChangeIndexPatternId(undefined); - }, - [onChangeIndexPatternId] - ); - - return ( - - isLoading={isLoading || latestIndexPatternTitlesRequest.state === 'pending'} - isDisabled={isReadOnly} - options={availableOptions} - placeholder={indexPatternSelectorPlaceholder} - selectedOptions={selectedOptions} - singleSelection={{ asPlainText: true }} - onChange={changeSelectedIndexPatterns} - /> - ); -}; - -const indexPatternSelectorPlaceholder = i18n.translate( - 'xpack.infra.logSourceConfiguration.dataViewSelectorPlaceholder', - { defaultMessage: 'Choose a data view' } -); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_form_state.ts b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_form_state.ts deleted file mode 100644 index 46f3980c95323..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_form_state.ts +++ /dev/null @@ -1,93 +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 { useMemo } from 'react'; -import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; -import { useUiTracker } from '@kbn/observability-shared-plugin/public'; -import type { - LogDataViewReference, - LogIndexNameReference, - LogSourcesKibanaAdvancedSettingReference, -} from '@kbn/logs-shared-plugin/common'; -import { - logIndexNameReferenceRT, - logSourcesKibanaAdvancedSettingRT, -} from '@kbn/logs-shared-plugin/common'; -import { useKibanaIndexPatternService } from '../../../hooks/use_kibana_index_patterns'; -import { useFormElement } from './form_elements'; -import type { FormValidationError } from './validation_errors'; -import { - validateIndexPattern, - validateStringNotEmpty, - validateStringNoSpaces, -} from './validation_errors'; - -export type LogIndicesFormState = - | LogIndexNameReference - | LogDataViewReference - | LogSourcesKibanaAdvancedSettingReference - | undefined; - -export const useLogIndicesFormElement = (initialValue: LogIndicesFormState) => { - const indexPatternService = useKibanaIndexPatternService(); - - const trackIndexPatternValidationError = useUiTracker({ app: 'infra_logs' }); - - const logIndicesFormElement = useFormElement({ - initialValue, - validate: useMemo( - () => async (logIndices) => { - if (logIndices == null) { - return validateStringNotEmpty('log data view', ''); - } else if (logSourcesKibanaAdvancedSettingRT.is(logIndices)) { - return []; - } else if (logIndexNameReferenceRT.is(logIndices)) { - return [ - ...validateStringNotEmpty('log indices', logIndices.indexName), - ...validateStringNoSpaces('log indices', logIndices.indexName), - ]; - } else { - const emptyStringErrors = validateStringNotEmpty('log data view', logIndices.dataViewId); - - if (emptyStringErrors.length > 0) { - return emptyStringErrors; - } - - const indexPatternErrors = await indexPatternService - .get(logIndices.dataViewId) - .then(validateIndexPattern, (error): FormValidationError[] => { - if (error instanceof SavedObjectNotFound) { - return [ - { - type: 'missing_index_pattern' as const, - indexPatternId: logIndices.dataViewId, - }, - ]; - } else { - throw error; - } - }); - - if (indexPatternErrors.length > 0) { - trackIndexPatternValidationError({ - metric: 'configuration_index_pattern_validation_failed', - }); - } else { - trackIndexPatternValidationError({ - metric: 'configuration_index_pattern_validation_succeeded', - }); - } - - return indexPatternErrors; - } - }, - [indexPatternService, trackIndexPatternValidationError] - ), - }); - - return logIndicesFormElement; -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx deleted file mode 100644 index 864797635312e..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_panel.stories.tsx +++ /dev/null @@ -1,148 +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 type { PropsOf } from '@elastic/eui'; -import { EuiCodeBlock, EuiPage, EuiPageBody, EuiPanel } from '@elastic/eui'; -import { I18nProvider } from '@kbn/i18n-react'; -import type { Meta, Story } from '@storybook/react/types-6-0'; -import React from 'react'; -import { KBN_FIELD_TYPES } from '@kbn/data-plugin/public'; -import type { MockIndexPatternSpec } from '../../../hooks/use_kibana_index_patterns.mock'; -import { MockIndexPatternsKibanaContextProvider } from '../../../hooks/use_kibana_index_patterns.mock'; -import { decorateWithGlobalStorybookThemeProviders } from '../../../test_utils/use_global_storybook_theme'; -import type { LogIndicesFormState } from './indices_configuration_form_state'; -import { useLogIndicesFormElement } from './indices_configuration_form_state'; -import { IndicesConfigurationPanel } from './indices_configuration_panel'; - -export default { - title: 'infra/logsSettings/indicesConfiguration', - decorators: [ - (WrappedStory, { args }) => { - return ( - - - - - - - - - - - - ); - }, - decorateWithGlobalStorybookThemeProviders, - ], - argTypes: { - logIndices: { - control: { - type: 'object', - }, - }, - availableIndexPatterns: { - control: { - type: 'object', - }, - }, - }, -} as Meta; - -type IndicesConfigurationPanelProps = PropsOf; - -type IndicesConfigurationPanelStoryArgs = Pick< - IndicesConfigurationPanelProps, - 'isLoading' | 'isReadOnly' -> & { - availableIndexPatterns: MockIndexPatternSpec[]; - logIndices: LogIndicesFormState; -}; - -const IndicesConfigurationPanelTemplate: Story = ({ - isLoading, - isReadOnly, - logIndices, -}) => { - const logIndicesFormElement = useLogIndicesFormElement(logIndices); - - return ( - <> - - - // field states{'\n'} - {JSON.stringify( - { - logIndices: { - value: logIndicesFormElement.value, - validity: logIndicesFormElement.validity, - }, - }, - null, - 2 - )} - - - ); -}; - -const defaultArgs: IndicesConfigurationPanelStoryArgs = { - isLoading: false, - isReadOnly: false, - logIndices: { - type: 'index_name' as const, - indexName: 'logs-*', - }, - availableIndexPatterns: [ - { - id: 'INDEX_PATTERN_A', - title: 'pattern-a-*', - timeFieldName: '@timestamp', - type: undefined, - fields: [ - { - name: '@timestamp', - type: KBN_FIELD_TYPES.DATE, - searchable: true, - aggregatable: true, - }, - { - name: 'message', - type: KBN_FIELD_TYPES.STRING, - searchable: true, - aggregatable: true, - }, - ], - }, - { - id: 'INDEX_PATTERN_B', - title: 'pattern-b-*', - timeFieldName: '@timestamp', - type: undefined, - fields: [], - }, - ], -}; - -export const IndexNameWithDefaultFields = IndicesConfigurationPanelTemplate.bind({}); - -IndexNameWithDefaultFields.args = { - ...defaultArgs, -}; - -export const IndexPattern = IndicesConfigurationPanelTemplate.bind({}); - -IndexPattern.args = { - ...defaultArgs, - logIndices: undefined, -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx deleted file mode 100644 index 70c59259a2c52..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/indices_configuration_panel.tsx +++ /dev/null @@ -1,246 +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 { EuiCheckableCard, EuiFormFieldset, EuiSpacer, EuiTitle } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useEffect, useState } from 'react'; -import { useUiTracker } from '@kbn/observability-shared-plugin/public'; -import type { LogDataViewReference, LogIndexReference } from '@kbn/logs-shared-plugin/common'; -import { - logIndexNameReferenceRT, - logDataViewReferenceRT, - logSourcesKibanaAdvancedSettingRT, -} from '@kbn/logs-shared-plugin/common'; -import { EuiCallOut } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { loadRuleAggregations } from '@kbn/triggers-actions-ui-plugin/public'; -import { AlertConsumers, LOG_THRESHOLD_ALERT_TYPE_ID } from '@kbn/rule-data-utils'; - -import type { RulesParams } from '@kbn/observability-plugin/public'; -import { rulesLocatorID } from '@kbn/observability-plugin/public'; -import { EuiLink } from '@elastic/eui'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import type { FormElement } from './form_elements'; -import { isFormElementForType } from './form_elements'; -import { IndexNamesConfigurationPanel } from './index_names_configuration_panel'; -import { IndexPatternConfigurationPanel } from './index_pattern_configuration_panel'; -import type { FormValidationError } from './validation_errors'; -import { KibanaAdvancedSettingConfigurationPanel } from './kibana_advanced_setting_configuration_panel'; - -export const IndicesConfigurationPanel = React.memo<{ - isLoading: boolean; - isReadOnly: boolean; - indicesFormElement: FormElement; -}>(({ isLoading, isReadOnly, indicesFormElement }) => { - const { - services: { - http, - share: { - url: { locators }, - }, - }, - } = useKibanaContextForPlugin(); - const [numberOfLogsRules, setNumberOfLogsRules] = useState(0); - - const rulesLocator = locators.get(rulesLocatorID); - const viewAffectedRulesLink = rulesLocator?.useUrl({ type: [LOG_THRESHOLD_ALERT_TYPE_ID] }); - - const trackChangeIndexSourceType = useUiTracker({ app: 'infra_logs' }); - - const changeToIndexPatternType = useCallback(() => { - if (logDataViewReferenceRT.is(indicesFormElement.initialValue)) { - indicesFormElement.updateValue(() => indicesFormElement.initialValue); - } else { - indicesFormElement.updateValue(() => undefined); - } - - trackChangeIndexSourceType({ - metric: 'configuration_switch_to_index_pattern_reference', - }); - }, [indicesFormElement, trackChangeIndexSourceType]); - - const changeToIndexNameType = useCallback(() => { - if (indicesFormElement.initialValue?.type === 'index_name') { - indicesFormElement.updateValue(() => indicesFormElement.initialValue); - } else { - indicesFormElement.updateValue(() => ({ - type: 'index_name', - indexName: '', - })); - } - - trackChangeIndexSourceType({ - metric: 'configuration_switch_to_index_names_reference', - }); - }, [indicesFormElement, trackChangeIndexSourceType]); - - const changeToKibanaAdvancedSettingType = useCallback(() => { - // This is always a readonly value, synced with the setting, we just reset back to the correct type. - indicesFormElement.updateValue(() => ({ - type: 'kibana_advanced_setting', - })); - - trackChangeIndexSourceType({ - metric: 'configuration_switch_to_kibana_advanced_setting_reference', - }); - }, [indicesFormElement, trackChangeIndexSourceType]); - - useEffect(() => { - const getNumberOfInfraRules = async () => { - if (http) { - const { ruleExecutionStatus } = await loadRuleAggregations({ - http, - ruleTypeIds: [LOG_THRESHOLD_ALERT_TYPE_ID], - consumers: [AlertConsumers.LOGS, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], - }); - const numberOfRules = Object.values(ruleExecutionStatus).reduce( - (acc, value) => acc + value, - 0 - ); - setNumberOfLogsRules(numberOfRules); - } - }; - getNumberOfInfraRules(); - }, [http]); - - return ( - -

- -

- - ), - }} - > - {' '} - -

- -

- - } - name="kibanaAdvancedSetting" - value="kibanaAdvancedSetting" - checked={isKibanaAdvancedSettingFormElement(indicesFormElement)} - onChange={changeToKibanaAdvancedSettingType} - disabled={isReadOnly} - > - {isKibanaAdvancedSettingFormElement(indicesFormElement) && ( - - )} -
- - -

- -

- - } - name="dataView" - value="dataView" - checked={isDataViewFormElement(indicesFormElement)} - onChange={changeToIndexPatternType} - disabled={isReadOnly} - > - {isDataViewFormElement(indicesFormElement) && ( - - )} -
- - -

- -

- - } - name="indexNames" - value="indexNames" - checked={isIndexNamesFormElement(indicesFormElement)} - onChange={changeToIndexNameType} - disabled={isReadOnly} - data-test-subj="logIndicesCheckableCard" - > - {isIndexNamesFormElement(indicesFormElement) && ( - - )} -
- {numberOfLogsRules > 0 && indicesFormElement.isDirty && ( - <> - - - - - - - - - - )} -
- ); -}); - -const isDataViewFormElement = isFormElementForType( - (value): value is LogDataViewReference | undefined => - value == null || logDataViewReferenceRT.is(value) -); - -const isIndexNamesFormElement = isFormElementForType(logIndexNameReferenceRT.is); - -const isKibanaAdvancedSettingFormElement = isFormElementForType( - logSourcesKibanaAdvancedSettingRT.is -); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/inline_log_view_callout.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/inline_log_view_callout.tsx deleted file mode 100644 index d3db574528490..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/inline_log_view_callout.tsx +++ /dev/null @@ -1,49 +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 { EuiButton } from '@elastic/eui'; -import { EuiCallOut } from '@elastic/eui'; -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; - -export const InlineLogViewCallout = ({ - revertToDefaultLogView, -}: { - revertToDefaultLogView: () => void; -}) => { - return ( - - } - > - <> -

- -

- - - - -
- ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/kibana_advanced_setting_configuration_panel.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/kibana_advanced_setting_configuration_panel.tsx deleted file mode 100644 index a095b2825cd3e..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/kibana_advanced_setting_configuration_panel.tsx +++ /dev/null @@ -1,37 +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 from 'react'; -import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; -import { - LogSourcesSettingSynchronisationInfo, - useLogSourcesContext, -} from '@kbn/logs-data-access-plugin/public'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; - -export const KibanaAdvancedSettingConfigurationPanel: React.FC = () => { - const { - services: { application }, - } = useKibanaContextForPlugin(); - - useTrackPageview({ app: 'infra_logs', path: 'log_source_configuration_kibana_advanced_setting' }); - useTrackPageview({ - app: 'infra_logs', - path: 'log_source_configuration_kibana_advanced_setting', - delay: 15000, - }); - - const { isLoadingLogSources, combinedIndices } = useLogSourcesContext(); - - return ( - - ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/log_columns_configuration_form_state.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/log_columns_configuration_form_state.tsx deleted file mode 100644 index 79526ec853055..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/log_columns_configuration_form_state.tsx +++ /dev/null @@ -1,21 +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 { useMemo } from 'react'; -import type { LogColumnConfiguration } from '../../../utils/source_configuration'; -import { useFormElement } from './form_elements'; -import type { FormValidationError } from './validation_errors'; -import { validateColumnListNotEmpty } from './validation_errors'; - -export const useLogColumnsFormElement = (initialValue: LogColumnConfiguration[]) => { - const logColumnsFormElement = useFormElement({ - initialValue, - validate: useMemo(() => async (logColumns) => validateColumnListNotEmpty(logColumns), []), - }); - - return logColumnsFormElement; -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/log_columns_configuration_panel.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/log_columns_configuration_panel.tsx deleted file mode 100644 index 4e0139c9d78c7..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/log_columns_configuration_panel.tsx +++ /dev/null @@ -1,336 +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 { - EuiButtonIcon, - EuiDragDropContext, - EuiDraggable, - EuiDroppable, - EuiEmptyPrompt, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiPanel, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback } from 'react'; -import type { DropResult, DragHandleProps } from '../../../types'; -import type { - FieldLogColumnConfiguration, - LogColumnConfiguration, - MessageLogColumnConfiguration, - TimestampLogColumnConfiguration, -} from '../../../utils/source_configuration'; -import { - getLogColumnConfigurationId, - isMessageLogColumnConfiguration, - isTimestampLogColumnConfiguration, -} from '../../../utils/source_configuration'; -import { AddLogColumnButtonAndPopover } from './add_log_column_popover'; -import type { FormElement } from './form_elements'; -import { LogSourceConfigurationFormError } from './source_configuration_form_errors'; -import type { FormValidationError } from './validation_errors'; - -export const LogColumnsConfigurationPanel = React.memo<{ - availableFields: string[]; - isLoading: boolean; - logColumnsFormElement: FormElement; -}>(({ availableFields, isLoading, logColumnsFormElement }) => { - const addLogColumn = useCallback( - (logColumnConfiguration: LogColumnConfiguration) => - logColumnsFormElement.updateValue((logColumns) => [...logColumns, logColumnConfiguration]), - [logColumnsFormElement] - ); - - const removeLogColumn = useCallback( - (logColumn: LogColumnConfiguration) => - logColumnsFormElement.updateValue((logColumns) => - logColumns.filter((item) => item !== logColumn) - ), - [logColumnsFormElement] - ); - - const moveLogColumn = useCallback( - (sourceIndex: number, destinationIndex: number) => { - logColumnsFormElement.updateValue((logColumns) => { - if (destinationIndex >= 0 && sourceIndex <= logColumnsFormElement.value.length - 1) { - const newLogColumns = [...logColumnsFormElement.value]; - newLogColumns.splice(destinationIndex, 0, newLogColumns.splice(sourceIndex, 1)[0]); - return newLogColumns; - } else { - return logColumns; - } - }); - }, - [logColumnsFormElement] - ); - - const onDragEnd = useCallback( - ({ source, destination }: DropResult) => - destination && moveLogColumn(source.index, destination.index), - [moveLogColumn] - ); - - return ( - <> - - - -

- -

-
-
- - - -
- {logColumnsFormElement.value.length > 0 ? ( - - - {logColumnsFormElement.value.map((logColumnConfiguration, index) => { - const columnId = getLogColumnConfigurationId(logColumnConfiguration); - return ( - - {(provided) => ( - - )} - - ); - })} - - - ) : ( - - )} - {logColumnsFormElement.validity.validity === 'invalid' - ? logColumnsFormElement.validity.reasons.map((error) => ( - - - - )) - : null} - - ); -}); - -const LogColumnConfigurationPanel: React.FunctionComponent<{ - logColumnConfiguration: LogColumnConfiguration; - dragHandleProps: DragHandleProps; - onRemove: (logColumnConfiguration: LogColumnConfiguration) => void; -}> = ({ logColumnConfiguration, dragHandleProps, onRemove }) => { - const removeColumn = useCallback( - () => onRemove(logColumnConfiguration), - [logColumnConfiguration, onRemove] - ); - - return ( - <> - - {isTimestampLogColumnConfiguration(logColumnConfiguration) ? ( - - ) : isMessageLogColumnConfiguration(logColumnConfiguration) ? ( - - ) : ( - - )} - - ); -}; - -interface LogColumnConfigurationPanelProps { - logColumnConfiguration: LogColumnConfigurationType; - dragHandleProps: DragHandleProps; - onRemove: () => void; -} - -const TimestampLogColumnConfigurationPanel: React.FunctionComponent< - LogColumnConfigurationPanelProps -> = ({ dragHandleProps, onRemove }) => ( - timestamp, - }} - /> - } - onRemove={onRemove} - dragHandleProps={dragHandleProps} - /> -); - -const MessageLogColumnConfigurationPanel: React.FunctionComponent< - LogColumnConfigurationPanelProps -> = ({ dragHandleProps, onRemove }) => ( - - } - onRemove={onRemove} - dragHandleProps={dragHandleProps} - /> -); - -const FieldLogColumnConfigurationPanel: React.FunctionComponent< - LogColumnConfigurationPanelProps -> = ({ - dragHandleProps, - logColumnConfiguration: { - fieldColumn: { field }, - }, - onRemove, -}) => { - return ( - - - -
- -
-
- {fieldLogColumnTitle} - - {field} - - - - -
-
- ); -}; - -const ExplainedLogColumnConfigurationPanel: React.FunctionComponent<{ - fieldName: React.ReactNode; - helpText: React.ReactNode; - onRemove: () => void; - dragHandleProps: DragHandleProps; -}> = ({ fieldName, helpText, onRemove, dragHandleProps }) => ( - - - -
- -
-
- {fieldName} - - - {helpText} - - - - - -
-
-); - -const RemoveLogColumnButton: React.FunctionComponent<{ - onClick?: () => void; - columnDescription: string; -}> = ({ onClick, columnDescription }) => { - const removeColumnLabel = i18n.translate( - 'xpack.infra.sourceConfiguration.removeLogColumnButtonLabel', - { - defaultMessage: 'Remove {columnDescription} column', - values: { columnDescription }, - } - ); - - return ( - - ); -}; - -const LogColumnConfigurationEmptyPrompt: React.FunctionComponent = () => ( - - - - } - body={ -

- -

- } - /> -); - -const fieldLogColumnTitle = i18n.translate('xpack.infra.sourceConfiguration.fieldLogColumnTitle', { - defaultMessage: 'Field', -}); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/name_configuration_form_state.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/name_configuration_form_state.tsx deleted file mode 100644 index ae653f8d06f6a..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/name_configuration_form_state.tsx +++ /dev/null @@ -1,20 +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 { useMemo } from 'react'; -import { useFormElement } from './form_elements'; -import type { FormValidationError } from './validation_errors'; -import { validateStringNotEmpty } from './validation_errors'; - -export const useNameFormElement = (initialValue: string) => { - const nameFormElement = useFormElement({ - initialValue, - validate: useMemo(() => async (name) => validateStringNotEmpty('name', name), []), - }); - - return nameFormElement; -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/name_configuration_panel.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/name_configuration_panel.tsx deleted file mode 100644 index d319753d49f49..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/name_configuration_panel.tsx +++ /dev/null @@ -1,69 +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 { - EuiDescribedFormGroup, - EuiFieldText, - EuiForm, - EuiFormRow, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useMemo } from 'react'; -import type { FormElement } from './form_elements'; -import { getFormRowProps, getStringInputFieldProps } from './form_field_props'; -import type { FormValidationError } from './validation_errors'; - -export const NameConfigurationPanel = React.memo<{ - isLoading: boolean; - isReadOnly: boolean; - nameFormElement: FormElement; -}>(({ isLoading, isReadOnly, nameFormElement }) => ( - - -

- -

-
- - - - - } - description={ - - } - > - - } - {...useMemo(() => getFormRowProps(nameFormElement), [nameFormElement])} - > - getStringInputFieldProps(nameFormElement), [nameFormElement])} - /> - - -
-)); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_form_errors.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_form_errors.tsx deleted file mode 100644 index 2ed1237ca786a..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_form_errors.tsx +++ /dev/null @@ -1,125 +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 { EuiCallOut, EuiCode } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React from 'react'; -import type { FormValidationError } from './validation_errors'; - -export const LogSourceConfigurationFormErrors: React.FC<{ errors: FormValidationError[] }> = ({ - errors, -}) => ( - -
    - {errors.map((error, errorIndex) => ( -
  • - -
  • - ))} -
-
-); - -export const LogSourceConfigurationFormError: React.FC<{ error: FormValidationError }> = ({ - error, -}) => { - if (error.type === 'generic') { - return <>{error.message}; - } else if (error.type === 'empty_field') { - return ( - - ); - } else if (error.type === 'includes_spaces') { - return ( - - ); - } else if (error.type === 'empty_column_list') { - return ( - - ); - } else if (error.type === 'child') { - return ( - - ); - } else if (error.type === 'missing_timestamp_field') { - return ( - - ); - } else if (error.type === 'missing_message_field') { - return ( - message, - }} - /> - ); - } else if (error.type === 'invalid_message_field_type') { - return ( - message, - }} - /> - ); - } else if (error.type === 'rollup_index_pattern') { - return ( - - ); - } else if (error.type === 'missing_index_pattern') { - return ( - {error.indexPatternId}, - }} - /> - ); - } else { - return null; - } -}; - -const logSourceConfigurationFormErrorsCalloutTitle = i18n.translate( - 'xpack.infra.logSourceConfiguration.logSourceConfigurationFormErrorsCalloutTitle', - { - defaultMessage: 'Inconsistent source configuration', - } -); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_form_state.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_form_state.tsx deleted file mode 100644 index eee7dd8f516e7..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_form_state.tsx +++ /dev/null @@ -1,53 +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 { useMemo } from 'react'; -import type { LogViewAttributes } from '@kbn/logs-shared-plugin/common'; -import { useCompositeFormElement } from './form_elements'; -import { useLogIndicesFormElement } from './indices_configuration_form_state'; -import { useLogColumnsFormElement } from './log_columns_configuration_form_state'; -import { useNameFormElement } from './name_configuration_form_state'; - -export const useLogSourceConfigurationFormState = (logViewAttributes?: LogViewAttributes) => { - const nameFormElement = useNameFormElement(logViewAttributes?.name ?? ''); - - const logIndicesFormElement = useLogIndicesFormElement( - useMemo( - () => - logViewAttributes?.logIndices ?? { - type: 'kibana_advanced_setting', - }, - [logViewAttributes] - ) - ); - - const logColumnsFormElement = useLogColumnsFormElement( - useMemo(() => logViewAttributes?.logColumns ?? [], [logViewAttributes]) - ); - - const sourceConfigurationFormElement = useCompositeFormElement( - useMemo( - () => ({ - childFormElements: { - name: nameFormElement, - logIndices: logIndicesFormElement, - logColumns: logColumnsFormElement, - }, - validate: async () => [], - }), - [nameFormElement, logIndicesFormElement, logColumnsFormElement] - ) - ); - - return { - formState: sourceConfigurationFormElement.value, - logIndicesFormElement, - logColumnsFormElement, - nameFormElement, - sourceConfigurationFormElement, - }; -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_settings.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_settings.tsx deleted file mode 100644 index d1df2a5820dd3..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/source_configuration_settings.tsx +++ /dev/null @@ -1,214 +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 { - EuiButton, - EuiErrorBoundary, - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiSpacer, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useMemo } from 'react'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { Prompt } from '@kbn/observability-shared-plugin/public'; -import { useTrackPageview } from '@kbn/observability-shared-plugin/public'; -import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; -import { LogsDeprecationCallout } from '../../../components/logs_deprecation_callout'; -import { SourceLoadingPage } from '../../../components/source_loading_page'; -import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs'; -import { settingsTitle } from '../../../translations'; -import { LogsPageTemplate } from '../shared/page_template'; -import { IndicesConfigurationPanel } from './indices_configuration_panel'; -import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel'; -import { NameConfigurationPanel } from './name_configuration_panel'; -import { LogSourceConfigurationFormErrors } from './source_configuration_form_errors'; -import { useLogSourceConfigurationFormState } from './source_configuration_form_state'; -import { InlineLogViewCallout } from './inline_log_view_callout'; - -export const LogsSettingsPage = () => { - const uiCapabilities = useKibana().services.application?.capabilities; - const shouldAllowEdit = uiCapabilities?.logs?.configureSource === true; - - useTrackPageview({ app: 'infra_logs', path: 'log_source_configuration' }); - useTrackPageview({ - app: 'infra_logs', - path: 'log_source_configuration', - delay: 15000, - }); - - useLogsBreadcrumbs([ - { - text: settingsTitle, - }, - ]); - - const { - logView, - hasFailedLoadingLogView, - isLoading, - isUninitialized, - update, - resolvedLogView, - isInlineLogView, - revertToDefaultLogView, - } = useLogViewContext(); - - const availableFields = useMemo( - () => resolvedLogView?.fields.map((field) => field.name) ?? [], - [resolvedLogView] - ); - - const { - sourceConfigurationFormElement, - formState, - logIndicesFormElement, - logColumnsFormElement, - nameFormElement, - } = useLogSourceConfigurationFormState(logView?.attributes); - - const persistUpdates = useCallback(async () => { - await update(formState); - sourceConfigurationFormElement.resetValue(); - }, [update, sourceConfigurationFormElement, formState]); - - const isWriteable = useMemo( - () => shouldAllowEdit && logView && logView.origin !== 'internal', - [shouldAllowEdit, logView] - ); - - if ((isLoading || isUninitialized) && !resolvedLogView) { - return ; - } - if (hasFailedLoadingLogView) { - return null; - } - - return ( - - - - - {isInlineLogView && ( - - - - - - - )} - - - - - - - - - - - - - {sourceConfigurationFormElement.validity.validity === 'invalid' ? ( - <> - - - - ) : null} - - {isWriteable && ( - - {isLoading ? ( - - - - {i18n.translate('xpack.infra.logsSettingsPage.loadingButtonLabel', { - defaultMessage: 'Loading', - })} - - - - ) : ( - - - { - sourceConfigurationFormElement.resetValue(); - }} - > - - - - - - - - - - )} - - )} - - - - ); -}; - -const unsavedFormPromptMessage = i18n.translate( - 'xpack.infra.logSourceConfiguration.unsavedFormPromptMessage', - { - defaultMessage: 'Are you sure you want to leave? Changes will be lost', - } -); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/validation_errors.ts b/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/validation_errors.ts deleted file mode 100644 index b2671601bde45..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/settings/validation_errors.ts +++ /dev/null @@ -1,130 +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 type { DataView } from '@kbn/data-views-plugin/public'; -import { KBN_FIELD_TYPES } from '@kbn/data-plugin/public'; - -export interface GenericValidationError { - type: 'generic'; - message: string; -} - -export interface ChildFormValidationError { - type: 'child'; -} - -export interface EmptyFieldValidationError { - type: 'empty_field'; - fieldName: string; -} - -export interface IncludesSpacesValidationError { - type: 'includes_spaces'; - fieldName: string; -} - -export interface EmptyColumnListValidationError { - type: 'empty_column_list'; -} - -export interface MissingTimestampFieldValidationError { - type: 'missing_timestamp_field'; - indexPatternTitle: string; -} - -export interface MissingMessageFieldValidationError { - type: 'missing_message_field'; - indexPatternTitle: string; -} - -export interface InvalidMessageFieldTypeValidationError { - type: 'invalid_message_field_type'; - indexPatternTitle: string; -} - -export interface RollupIndexPatternValidationError { - type: 'rollup_index_pattern'; - indexPatternTitle: string; -} - -export interface MissingIndexPatternValidationError { - type: 'missing_index_pattern'; - indexPatternId: string; -} - -export type FormValidationError = - | GenericValidationError - | ChildFormValidationError - | EmptyFieldValidationError - | IncludesSpacesValidationError - | EmptyColumnListValidationError - | MissingTimestampFieldValidationError - | MissingMessageFieldValidationError - | InvalidMessageFieldTypeValidationError - | RollupIndexPatternValidationError - | MissingIndexPatternValidationError; - -export const validateStringNotEmpty = (fieldName: string, value: string): FormValidationError[] => - value === '' ? [{ type: 'empty_field', fieldName }] : []; - -export const validateStringNoSpaces = (fieldName: string, value: string): FormValidationError[] => - value.includes(' ') ? [{ type: 'includes_spaces', fieldName }] : []; - -export const validateColumnListNotEmpty = (columns: unknown[]): FormValidationError[] => - columns.length <= 0 ? [{ type: 'empty_column_list' }] : []; - -export const validateIndexPattern = (indexPattern: DataView): FormValidationError[] => { - return [ - ...validateIndexPatternIsTimeBased(indexPattern), - ...validateIndexPatternHasStringMessageField(indexPattern), - ...validateIndexPatternIsntRollup(indexPattern), - ]; -}; - -export const validateIndexPatternIsTimeBased = (indexPattern: DataView): FormValidationError[] => - indexPattern.isTimeBased() - ? [] - : [ - { - type: 'missing_timestamp_field' as const, - indexPatternTitle: indexPattern.getIndexPattern(), - }, - ]; - -export const validateIndexPatternHasStringMessageField = ( - indexPattern: DataView -): FormValidationError[] => { - const messageField = indexPattern.getFieldByName('message'); - - if (messageField == null) { - return [ - { - type: 'missing_message_field' as const, - indexPatternTitle: indexPattern.getIndexPattern(), - }, - ]; - } else if (messageField.type !== KBN_FIELD_TYPES.STRING) { - return [ - { - type: 'invalid_message_field_type' as const, - indexPatternTitle: indexPattern.getIndexPattern(), - }, - ]; - } else { - return []; - } -}; - -export const validateIndexPatternIsntRollup = (indexPattern: DataView): FormValidationError[] => - indexPattern.type != null - ? [ - { - type: 'rollup_index_pattern' as const, - indexPatternTitle: indexPattern.getIndexPattern(), - }, - ] - : []; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/shared/page_log_view_error.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/shared/page_log_view_error.tsx index 8914eb36f8c20..d4086e810b700 100644 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/shared/page_log_view_error.tsx +++ b/x-pack/solutions/observability/plugins/infra/public/pages/logs/shared/page_log_view_error.tsx @@ -8,11 +8,9 @@ import { EuiButton, EuiButtonEmpty, EuiCallOut, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { FC, PropsWithChildren } from 'react'; -import React, { useCallback } from 'react'; +import React from 'react'; import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; import { useLinkProps } from '@kbn/observability-shared-plugin/public'; -import { useSelector } from '@xstate/react'; -import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; import { FetchLogViewStatusError, FetchLogViewError, @@ -89,26 +87,6 @@ export const LogViewErrorPage: React.FC<{ export const LogSourceErrorPage = LogViewErrorPage; -export const ConnectedLogViewErrorPage: React.FC = () => { - const { logViewStateService } = useLogViewContext(); - - const errors = useSelector(logViewStateService, (state) => { - return state.matches('loadingFailed') || - state.matches('resolutionFailed') || - state.matches('checkingStatusFailed') - ? [state.context.error] - : []; - }); - - const retry = useCallback(() => { - logViewStateService.send({ - type: 'RETRY', - }); - }, [logViewStateService]); - - return ; -}; - const LogSourceErrorMessage: React.FC<{ error: Error }> = ({ error }) => { if (error instanceof ResolveLogViewError) { return ( diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/components/stream_live_button.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/components/stream_live_button.tsx deleted file mode 100644 index 756849d185c4d..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/components/stream_live_button.tsx +++ /dev/null @@ -1,43 +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 from 'react'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -export const StreamLiveButton: React.FC<{ - isStreaming: boolean; - onStartStreaming: () => void; - onStopStreaming: () => void; -}> = ({ isStreaming, onStartStreaming, onStopStreaming }) => - isStreaming ? ( - - - - ) : ( - - - - ); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/components/stream_page_template.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/components/stream_page_template.tsx deleted file mode 100644 index fbe7a34837031..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/components/stream_page_template.tsx +++ /dev/null @@ -1,87 +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 { APP_WRAPPER_CLASS } from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiBadge, EuiToolTip } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { fullHeightContentStyles } from '../../../../page_template.styles'; -import type { LogsPageTemplateProps } from '../../shared/page_template'; -import { LogsPageTemplate } from '../../shared/page_template'; - -export const LogStreamPageTemplate: React.FC = (props) => { - const { logView, isInlineLogView, revertToDefaultLogView } = useLogViewContext(); - return ( -
- - {logView.attributes.name} - - - } - > - - - - - - - ) : ( - streamTitle - ), - breadcrumbs: isInlineLogView - ? [ - { - text: ( - - - - - - - - - ), - color: 'primary', - 'aria-current': false, - 'data-test-subj': 'infraAssetDetailsReturnButton', - href: '#', - onClick: revertToDefaultLogView, - }, - ] - : undefined, - }} - pageSectionProps={{ - contentProps: { - css: fullHeightContentStyles, - }, - }} - {...props} - /> -
- ); -}; - -const streamTitle = i18n.translate('xpack.infra.logs.streamPageTitle', { - defaultMessage: 'Stream', -}); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/index.ts b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/index.ts deleted file mode 100644 index 56fb7e79e7717..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/index.ts +++ /dev/null @@ -1,8 +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. - */ - -export { StreamPage } from './page'; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page.tsx deleted file mode 100644 index 706fb7811fa78..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page.tsx +++ /dev/null @@ -1,63 +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 { EuiErrorBoundary } from '@elastic/eui'; -import { useKibanaQuerySettings, useTrackPageview } from '@kbn/observability-shared-plugin/public'; -import React from 'react'; -import { useLogViewContext } from '@kbn/logs-shared-plugin/public'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { useLogsBreadcrumbs } from '../../../hooks/use_logs_breadcrumbs'; -import { LogStreamPageStateProvider } from '../../../observability_logs/log_stream_page/state'; -import { streamTitle } from '../../../translations'; -import { useKbnUrlStateStorageFromRouterContext } from '../../../containers/kbn_url_state_context'; -import { ConnectedStreamPageContent } from './page_content'; - -export const StreamPage = () => { - useTrackPageview({ app: 'infra_logs', path: 'stream' }); - useTrackPageview({ app: 'infra_logs', path: 'stream', delay: 15000 }); - - useLogsBreadcrumbs([ - { - text: streamTitle, - }, - ]); - - const { logViewStateNotifications } = useLogViewContext(); - const { - services: { - data: { - query: { - queryString: queryStringService, - filterManager: filterManagerService, - timefilter: { timefilter: timeFilterService }, - }, - }, - notifications: { toasts: toastsService }, - }, - } = useKibanaContextForPlugin(); - - const kibanaQuerySettings = useKibanaQuerySettings(); - const urlStateStorage = useKbnUrlStateStorageFromRouterContext(); - - return ( - - - - - - ); -}; - -const ConnectedStreamPageContentMemo = React.memo(ConnectedStreamPageContent); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_content.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_content.tsx deleted file mode 100644 index 8ec0031f535c1..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_content.tsx +++ /dev/null @@ -1,98 +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 type { TimeRange } from '@kbn/es-query'; -import { useActor } from '@xstate/react'; -import React, { useMemo } from 'react'; -import type { VisiblePositions } from '../../../observability_logs/log_stream_position_state'; -import type { TimeKey } from '../../../../common/time'; -import { SourceLoadingPage } from '../../../components/source_loading_page'; -import type { - LogStreamPageCallbacks, - LogStreamPageState, -} from '../../../observability_logs/log_stream_page/state'; -import { useLogStreamPageStateContext } from '../../../observability_logs/log_stream_page/state'; -import { InvalidStateCallout } from '../../../observability_logs/xstate_helpers'; -import { ConnectedLogViewErrorPage } from '../shared/page_log_view_error'; -import { LogStreamPageTemplate } from './components/stream_page_template'; -import { StreamPageLogsContentForState } from './page_logs_content'; -import { StreamPageMissingIndicesContent } from './page_missing_indices_content'; -import { LogStreamPageContentProviders } from './page_providers'; - -export const ConnectedStreamPageContent: React.FC = () => { - const logStreamPageStateService = useLogStreamPageStateContext(); - const [logStreamPageState, logStreamPageSend] = useActor(logStreamPageStateService); - - const pageStateCallbacks = useMemo(() => { - return { - updateTimeRange: (timeRange: Partial) => { - logStreamPageSend({ - type: 'UPDATE_TIME_RANGE', - timeRange, - }); - }, - jumpToTargetPosition: (targetPosition: TimeKey | null) => { - logStreamPageSend({ type: 'JUMP_TO_TARGET_POSITION', targetPosition }); - }, - jumpToTargetPositionTime: (time: string) => { - logStreamPageSend({ type: 'JUMP_TO_TARGET_POSITION', targetPosition: { time } }); - }, - reportVisiblePositions: (visiblePositions: VisiblePositions) => { - logStreamPageSend({ - type: 'REPORT_VISIBLE_POSITIONS', - visiblePositions, - }); - }, - startLiveStreaming: () => { - logStreamPageSend({ type: 'UPDATE_REFRESH_INTERVAL', refreshInterval: { pause: false } }); - }, - stopLiveStreaming: () => { - logStreamPageSend({ type: 'UPDATE_REFRESH_INTERVAL', refreshInterval: { pause: true } }); - }, - }; - }, [logStreamPageSend]); - - return ( - - ); -}; - -export const StreamPageContentForState: React.FC<{ - logStreamPageState: LogStreamPageState; - logStreamPageCallbacks: LogStreamPageCallbacks; -}> = ({ logStreamPageState, logStreamPageCallbacks }) => { - if ( - logStreamPageState.matches('uninitialized') || - logStreamPageState.matches({ hasLogViewIndices: 'uninitialized' }) || - logStreamPageState.matches('loadingLogView') - ) { - return ; - } else if (logStreamPageState.matches('loadingLogViewFailed')) { - return ; - } else if (logStreamPageState.matches('missingLogViewIndices')) { - return ; - } else if (logStreamPageState.matches({ hasLogViewIndices: 'initialized' })) { - return ( - - - - - - ); - } else { - return ; - } -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_logs_content.tsx deleted file mode 100644 index ad12c1f719a21..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ /dev/null @@ -1,363 +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 { EuiSpacer } from '@elastic/eui'; -import type { Query } from '@kbn/es-query'; -import styled from '@emotion/styled'; -import type { LogEntry } from '@kbn/logs-shared-plugin/common'; -import { convertISODateToNanoPrecision } from '@kbn/logs-shared-plugin/common'; -import type { - LogEntryStreamItem, - UpdatedDateRange, - VisibleInterval, - WithSummaryProps, -} from '@kbn/logs-shared-plugin/public'; -import { - LogEntryFlyout, - ScrollableLogTextStreamView, - useLogHighlightsStateContext, - useLogPositionStateContext, - useLogStreamContext, - useLogViewContext, - WithSummary, -} from '@kbn/logs-shared-plugin/public'; -import { useSelector } from '@xstate/react'; -import stringify from 'json-stable-stringify'; -import React, { useCallback, useEffect, useMemo } from 'react'; -import usePrevious from 'react-use/lib/usePrevious'; -import type { MatchedStateFromActor } from '@kbn/xstate-utils'; -import { LogsDeprecationCallout } from '../../../components/logs_deprecation_callout'; -import type { TimeKey } from '../../../../common/time'; -import { AutoSizer } from '../../../components/auto_sizer'; -import { LogMinimap } from '../../../components/logging/log_minimap'; -import { PageContent } from '../../../components/page'; -import { - useLogEntryFlyoutContext, - WithFlyoutOptionsUrlState, -} from '../../../containers/logs/log_flyout'; -import { useLogViewConfigurationContext } from '../../../containers/logs/log_view_configuration'; -import { useViewLogInProviderContext } from '../../../containers/logs/view_log_in_context'; -import { WithLogTextviewUrlState } from '../../../containers/logs/with_log_textview'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import type { - LogStreamPageActorRef, - LogStreamPageCallbacks, -} from '../../../observability_logs/log_stream_page/state'; -import { useLogStreamPageStateContext } from '../../../observability_logs/log_stream_page/state'; -import { type ParsedQuery } from '../../../observability_logs/log_stream_query_state'; -import { datemathToEpochMillis, isValidDatemath } from '../../../utils/datemath'; -import { LogsToolbar } from './page_toolbar'; -import { PageViewLogInContext } from './page_view_log_in_context'; - -const PAGE_THRESHOLD = 2; - -export const StreamPageLogsContent = React.memo<{ - filterQuery: ParsedQuery; - logStreamPageCallbacks: LogStreamPageCallbacks; -}>(({ filterQuery, logStreamPageCallbacks }) => { - const { - data: { - query: { queryString }, - }, - } = useKibanaContextForPlugin().services; - const { resolvedLogView, logView, logViewReference } = useLogViewContext(); - const { textScale, textWrap } = useLogViewConfigurationContext(); - const { - surroundingLogsId, - setSurroundingLogsId, - closeFlyout: closeLogEntryFlyout, - openFlyout: openLogEntryFlyout, - isFlyoutOpen, - logEntryId: flyoutLogEntryId, - } = useLogEntryFlyoutContext(); - - const { - startTimestamp, - endTimestamp, - isStreaming, - targetPosition, - visibleMidpointTime, - visibleTimeInterval, - reportVisiblePositions, - jumpToTargetPosition, - startLiveStreaming, - stopLiveStreaming, - startDateExpression, - endDateExpression, - updateDateRange, - lastCompleteDateRangeExpressionUpdate, - } = useLogPositionStateContext(); - - const { - isReloading, - entries, - topCursor, - bottomCursor, - hasMoreAfter: hasMoreAfterEnd, - hasMoreBefore: hasMoreBeforeStart, - isLoadingMore, - lastLoadedTime, - fetchEntries, - fetchPreviousEntries, - fetchNextEntries, - fetchNewestEntries, - } = useLogStreamContext(); - - const prevStartTimestamp = usePrevious(startTimestamp); - const prevEndTimestamp = usePrevious(endTimestamp); - const prevFilterQuery = usePrevious(filterQuery); - const prevLastCompleteDateRangeExpressionUpdate = usePrevious( - lastCompleteDateRangeExpressionUpdate - ); - - // Refetch entries if... - useEffect(() => { - const isFirstLoad = !prevStartTimestamp || !prevEndTimestamp; - - const completeDateRangeExpressionHasChanged = - lastCompleteDateRangeExpressionUpdate !== prevLastCompleteDateRangeExpressionUpdate; - - const isCenterPointOutsideLoadedRange = - targetPosition != null && - ((topCursor != null && - convertISODateToNanoPrecision(targetPosition.time) < - convertISODateToNanoPrecision(topCursor.time)) || - (bottomCursor != null && - convertISODateToNanoPrecision(targetPosition.time) > - convertISODateToNanoPrecision(bottomCursor.time))); - - const hasQueryChanged = filterQuery !== prevFilterQuery; - - if ( - isFirstLoad || - completeDateRangeExpressionHasChanged || - isCenterPointOutsideLoadedRange || - hasQueryChanged - ) { - if (isStreaming) { - fetchNewestEntries(); - } else { - fetchEntries(); - } - } - }, [ - fetchEntries, - fetchNewestEntries, - isStreaming, - prevStartTimestamp, - prevEndTimestamp, - startTimestamp, - endTimestamp, - targetPosition, - topCursor, - bottomCursor, - filterQuery, - prevFilterQuery, - lastCompleteDateRangeExpressionUpdate, - prevLastCompleteDateRangeExpressionUpdate, - ]); - - const { logSummaryHighlights, currentHighlightKey, logEntryHighlightsById } = - useLogHighlightsStateContext(); - - const items = useMemo( - () => - isReloading - ? [] - : entries.map((logEntry) => - createLogEntryStreamItem(logEntry, logEntryHighlightsById[logEntry.id] || []) - ), - - [entries, isReloading, logEntryHighlightsById] - ); - - const [, { setContextEntry }] = useViewLogInProviderContext(); - - const handleDateRangeExtension = useCallback( - (newDateRange: UpdatedDateRange) => { - updateDateRange(newDateRange); - - if ( - newDateRange.startDateExpression != null && - isValidDatemath(newDateRange.startDateExpression) - ) { - fetchPreviousEntries({ - force: true, - extendTo: datemathToEpochMillis(newDateRange.startDateExpression)!, - }); - } - if ( - newDateRange.endDateExpression != null && - isValidDatemath(newDateRange.endDateExpression) - ) { - fetchNextEntries({ - force: true, - extendTo: datemathToEpochMillis(newDateRange.endDateExpression)!, - }); - } - }, - [updateDateRange, fetchPreviousEntries, fetchNextEntries] - ); - - const handlePagination = useCallback( - (params: VisibleInterval) => { - reportVisiblePositions(params); - if (!params.fromScroll) { - return; - } - - if (isLoadingMore) { - return; - } - - if (params.pagesBeforeStart < PAGE_THRESHOLD) { - fetchPreviousEntries(); - } else if (params.pagesAfterEnd < PAGE_THRESHOLD) { - fetchNextEntries(); - } - }, - [reportVisiblePositions, isLoadingMore, fetchPreviousEntries, fetchNextEntries] - ); - - const setFilter = useCallback( - (filter: Query, flyoutItemId: string, timeKey: TimeKey | undefined | null) => { - queryString.setQuery(filter); - if (timeKey) { - jumpToTargetPosition(timeKey); - } - setSurroundingLogsId(flyoutItemId); - stopLiveStreaming(); - }, - [jumpToTargetPosition, queryString, setSurroundingLogsId, stopLiveStreaming] - ); - - return ( - <> - - - - - - - {isFlyoutOpen ? ( - - ) : null} - - - - - {({ measureRef, bounds: { height = 0 }, content: { width = 0 } }) => { - return ( - - - {({ buckets, start, end }) => ( - 0 ? logSummaryHighlights[0].buckets : [] - } - target={visibleMidpointTime} - /> - )} - - - ); - }} - - - - ); -}); - -const WithSummaryAndQuery = (props: Omit) => { - const serializedParsedQuery = useSelector(useLogStreamPageStateContext(), (logStreamPageState) => - logStreamPageState.matches({ hasLogViewIndices: 'initialized' }) - ? stringify(logStreamPageState.context.parsedQuery) - : null - ); - - return ; -}; - -type InitializedLogStreamPageState = MatchedStateFromActor< - LogStreamPageActorRef, - { hasLogViewIndices: 'initialized' } ->; - -export const StreamPageLogsContentForState = React.memo<{ - logStreamPageState: InitializedLogStreamPageState; - logStreamPageCallbacks: LogStreamPageCallbacks; -}>(({ logStreamPageState, logStreamPageCallbacks }) => { - const { - context: { parsedQuery }, - } = logStreamPageState; - - return ( - - ); -}); - -const LogPageMinimapColumn = styled.div` - flex: 1 0 0%; - overflow: hidden; - min-width: 100px; - max-width: 100px; - display: flex; - flex-direction: column; -`; - -const createLogEntryStreamItem = ( - logEntry: LogEntry, - highlights: LogEntry[] -): LogEntryStreamItem => ({ - kind: 'logEntry' as 'logEntry', - logEntry, - highlights, -}); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_missing_indices_content.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_missing_indices_content.tsx deleted file mode 100644 index 6d5ecf8ffd26c..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_missing_indices_content.tsx +++ /dev/null @@ -1,13 +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 from 'react'; -import { LogStreamPageTemplate } from './components/stream_page_template'; - -export const StreamPageMissingIndicesContent = React.memo(() => ( - -)); diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_providers.tsx deleted file mode 100644 index cbeb08e3c4f38..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ /dev/null @@ -1,129 +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 stringify from 'json-stable-stringify'; -import type { FC, PropsWithChildren } from 'react'; -import React, { useMemo } from 'react'; -import { - LogHighlightsStateProvider, - LogPositionStateProvider, - LogStreamProvider, - useLogPositionStateContext, - useLogStreamContext, - useLogViewContext, -} from '@kbn/logs-shared-plugin/public'; -import type { MatchedStateFromActor } from '@kbn/xstate-utils'; -import type { - LogStreamPageActorRef, - LogStreamPageCallbacks, -} from '../../../observability_logs/log_stream_page/state'; -import { LogEntryFlyoutProvider } from '../../../containers/logs/log_flyout'; -import { LogViewConfigurationProvider } from '../../../containers/logs/log_view_configuration'; -import { ViewLogInContextProvider } from '../../../containers/logs/view_log_in_context'; - -const ViewLogInContext: FC> = ({ children }) => { - const { startTimestamp, endTimestamp } = useLogPositionStateContext(); - const { logViewReference } = useLogViewContext(); - - if (!startTimestamp || !endTimestamp) { - return null; - } - - return ( - - {children} - - ); -}; - -const LogEntriesStateProvider: FC< - PropsWithChildren<{ - logStreamPageState: InitializedLogStreamPageState; - }> -> = ({ children, logStreamPageState }) => { - const { logViewReference } = useLogViewContext(); - const { startTimestamp, endTimestamp, targetPosition } = useLogPositionStateContext(); - const { - context: { parsedQuery }, - } = logStreamPageState; - - // Don't render anything if the date range is incorrect. - if (!startTimestamp || !endTimestamp) { - return null; - } - - return ( - - {children} - - ); -}; - -const LogHighlightsState: FC< - PropsWithChildren<{ - logStreamPageState: InitializedLogStreamPageState; - }> -> = ({ children, logStreamPageState }) => { - const { logViewReference, logView } = useLogViewContext(); - const { topCursor, bottomCursor, entries } = useLogStreamContext(); - const serializedParsedQuery = useMemo( - () => stringify(logStreamPageState.context.parsedQuery), - [logStreamPageState.context.parsedQuery] - ); - - const highlightsProps = { - logViewReference, - sourceVersion: logView?.version, - entriesStart: topCursor, - entriesEnd: bottomCursor, - centerCursor: entries.length > 0 ? entries[Math.floor(entries.length / 2)].cursor : null, - size: entries.length, - filterQuery: serializedParsedQuery, - }; - return {children}; -}; - -export const LogStreamPageContentProviders: FC< - PropsWithChildren<{ - logStreamPageState: InitializedLogStreamPageState; - logStreamPageCallbacks: LogStreamPageCallbacks; - }> -> = ({ children, logStreamPageState, logStreamPageCallbacks }) => { - return ( - - - - - - - {children} - - - - - - - ); -}; - -type InitializedLogStreamPageState = MatchedStateFromActor< - LogStreamPageActorRef, - { hasLogViewIndices: 'initialized' } ->; diff --git a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_toolbar.tsx b/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_toolbar.tsx deleted file mode 100644 index 9ea8e60eef0b9..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/pages/logs/stream/page_toolbar.tsx +++ /dev/null @@ -1,111 +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 { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import { - useLogHighlightsStateContext, - useLogPositionStateContext, - useLogViewContext, -} from '@kbn/logs-shared-plugin/public'; -import { LogCustomizationMenu } from '../../../components/logging/log_customization_menu'; -import { LogHighlightsMenu } from '../../../components/logging/log_highlights_menu'; -import { LogTextScaleControls } from '../../../components/logging/log_text_scale_controls'; -import { LogTextWrapControls } from '../../../components/logging/log_text_wrap_controls'; -import { useLogViewConfigurationContext } from '../../../containers/logs/log_view_configuration'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { StreamLiveButton } from './components/stream_live_button'; - -export const LogsToolbar = () => { - const { derivedDataView } = useLogViewContext(); - const { availableTextScales, setTextScale, setTextWrap, textScale, textWrap } = - useLogViewConfigurationContext(); - const { - unifiedSearch: { - ui: { SearchBar }, - }, - } = useKibanaContextForPlugin().services; - - const { - setHighlightTerms, - loadLogEntryHighlightsRequest, - highlightTerms, - hasPreviousHighlight, - hasNextHighlight, - goToPreviousHighlight, - goToNextHighlight, - } = useLogHighlightsStateContext(); - const { isStreaming, startLiveStreaming, stopLiveStreaming } = useLogPositionStateContext(); - - const dataViews = useMemo( - () => (derivedDataView != null ? [derivedDataView] : undefined), - [derivedDataView] - ); - - return ( - <> - - -
- - - - - - - - - highlightTerm.length > 0).length > 0 - } - goToPreviousHighlight={goToPreviousHighlight} - goToNextHighlight={goToNextHighlight} - hasPreviousHighlight={hasPreviousHighlight} - hasNextHighlight={hasNextHighlight} - /> - - - - - - -
- - ); -}; diff --git a/x-pack/solutions/observability/plugins/infra/public/translations.ts b/x-pack/solutions/observability/plugins/infra/public/translations.ts index 3377ae1dd1fa1..cb7bd53fe034a 100644 --- a/x-pack/solutions/observability/plugins/infra/public/translations.ts +++ b/x-pack/solutions/observability/plugins/infra/public/translations.ts @@ -15,10 +15,6 @@ export const logsTitle = i18n.translate('xpack.infra.header.logsTitle', { defaultMessage: 'Logs', }); -export const streamTitle = i18n.translate('xpack.infra.logs.index.streamTabTitle', { - defaultMessage: 'Stream', -}); - export const logsAnomaliesTitle = i18n.translate('xpack.infra.logs.index.anomaliesTabTitle', { defaultMessage: 'Logs Anomalies', }); diff --git a/x-pack/solutions/observability/plugins/infra/public/utils/theme_utils/with_attrs.tsx b/x-pack/solutions/observability/plugins/infra/public/utils/theme_utils/with_attrs.tsx deleted file mode 100644 index b56f4e52dc91a..0000000000000 --- a/x-pack/solutions/observability/plugins/infra/public/utils/theme_utils/with_attrs.tsx +++ /dev/null @@ -1,19 +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 { type Theme, useTheme } from '@emotion/react'; -import React from 'react'; - -import type { ComponentType } from 'react'; - -export const withAttrs = - (Component: ComponentType, fn: (args: { theme: Theme; props: any }) => any) => - (props: any) => { - const theme = useTheme(); - const attrs = fn({ theme, props }); - - return ; - }; diff --git a/x-pack/solutions/observability/plugins/infra/tsconfig.json b/x-pack/solutions/observability/plugins/infra/tsconfig.json index 38788900217b7..87aef0b63aa10 100644 --- a/x-pack/solutions/observability/plugins/infra/tsconfig.json +++ b/x-pack/solutions/observability/plugins/infra/tsconfig.json @@ -108,7 +108,6 @@ "@kbn/observability-alerting-rule-utils", "@kbn/core-application-browser", "@kbn/shared-ux-page-no-data-types", - "@kbn/xstate-utils", "@kbn/entityManager-plugin", "@kbn/entities-schema", "@kbn/zod", diff --git a/x-pack/test/api_integration/apis/logs_ui/index.ts b/x-pack/test/api_integration/apis/logs_ui/index.ts index 694698d41f3b6..cc386ce0bff0f 100644 --- a/x-pack/test/api_integration/apis/logs_ui/index.ts +++ b/x-pack/test/api_integration/apis/logs_ui/index.ts @@ -11,8 +11,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('Logs UI routes', () => { loadTestFile(require.resolve('./log_views')); loadTestFile(require.resolve('./log_threshold_alert')); - loadTestFile(require.resolve('./log_entry_highlights')); - loadTestFile(require.resolve('./log_summary')); loadTestFile(require.resolve('./log_analysis_validation_log_entry_datasets')); }); } diff --git a/x-pack/test/api_integration/apis/logs_ui/log_entry_highlights.ts b/x-pack/test/api_integration/apis/logs_ui/log_entry_highlights.ts deleted file mode 100644 index aa0796c584c77..0000000000000 --- a/x-pack/test/api_integration/apis/logs_ui/log_entry_highlights.ts +++ /dev/null @@ -1,213 +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 expect from '@kbn/expect'; - -import semver from 'semver'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { fold } from 'fp-ts/lib/Either'; - -import { createPlainError, throwErrors } from '@kbn/io-ts-utils'; - -import { - LOG_ENTRIES_HIGHLIGHTS_PATH, - logEntriesHighlightsRequestRT, - logEntriesHighlightsResponseRT, -} from '@kbn/logs-shared-plugin/common'; - -import moment from 'moment'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -const KEY_BEFORE_START = { - time: new Date('2000-01-01T00:00:00.000Z').valueOf(), - tiebreaker: -1, -}; -const KEY_AFTER_END = { - time: new Date('2000-01-01T00:00:09.001Z').valueOf(), - tiebreaker: 0, -}; - -const COMMON_HEADERS = { - 'kbn-xsrf': 'some-xsrf-token', - 'Elastic-Api-Version': '1', -}; - -export default function ({ getService }: FtrProviderContext) { - const es = getService('es'); - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); - - describe('log highlight apis', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/simple_logs')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/simple_logs')); - - describe('/log_entries/highlights', () => { - describe('with the default source', () => { - before(() => kibanaServer.savedObjects.cleanStandardList()); - after(() => kibanaServer.savedObjects.cleanStandardList()); - - it('Handles empty responses', async () => { - const { body } = await supertest - .post(LOG_ENTRIES_HIGHLIGHTS_PATH) - .set(COMMON_HEADERS) - .send( - logEntriesHighlightsRequestRT.encode({ - logView: { type: 'log-view-reference', logViewId: 'default' }, - startTimestamp: KEY_BEFORE_START.time, - endTimestamp: KEY_AFTER_END.time, - highlightTerms: ['some string that does not exist'], - }) - ) - .expect(200); - - const logEntriesHighlightsResponse = pipe( - logEntriesHighlightsResponseRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - - expect(logEntriesHighlightsResponse.data).to.have.length(1); - - const data = logEntriesHighlightsResponse.data[0]; - - expect(data.entries).to.have.length(0); - expect(data.topCursor).to.be(null); - expect(data.bottomCursor).to.be(null); - }); - - it('highlights built-in message column', async () => { - const esInfo = await es.info(); - const highlightTerms = 'message of document 0'; - const { body } = await supertest - .post(LOG_ENTRIES_HIGHLIGHTS_PATH) - .set(COMMON_HEADERS) - .send( - logEntriesHighlightsRequestRT.encode({ - logView: { type: 'log-view-reference', logViewId: 'default' }, - startTimestamp: KEY_BEFORE_START.time, - endTimestamp: KEY_AFTER_END.time, - highlightTerms: [highlightTerms], - }) - ) - .expect(200); - - const logEntriesHighlightsResponse = pipe( - logEntriesHighlightsResponseRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - - expect(logEntriesHighlightsResponse.data).to.have.length(1); - - const data = logEntriesHighlightsResponse.data[0]; - const entries = data.entries; - const firstEntry = entries[0]; - const lastEntry = entries[entries.length - 1]; - - // Finds expected entries - expect(entries).to.have.length(10); - - // Cursors are set correctly - expect(firstEntry.cursor).to.eql(data.topCursor); - expect(lastEntry.cursor).to.eql(data.bottomCursor); - - // Entries fall within range - // @kbn/expect doesn't have a `lessOrEqualThan` or `moreOrEqualThan` comparators - expect(firstEntry.cursor.time >= moment(KEY_BEFORE_START.time).toISOString()).to.be(true); - expect(lastEntry.cursor.time <= moment(KEY_AFTER_END.time).toISOString()).to.be(true); - - // All entries contain the highlights - entries.forEach((entry) => { - entry.columns.forEach((column) => { - if ('message' in column && 'highlights' in column.message[0]) { - const expectation = semver.gte(esInfo.version.number, '8.10.0') - ? [highlightTerms] - : highlightTerms.split(' '); - expect(column.message[0].highlights).to.eql(expectation); - } - }); - }); - }); - - it('highlights field columns', async () => { - const { body } = await supertest - .post(LOG_ENTRIES_HIGHLIGHTS_PATH) - .set(COMMON_HEADERS) - .send( - logEntriesHighlightsRequestRT.encode({ - logView: { type: 'log-view-reference', logViewId: 'default' }, - startTimestamp: KEY_BEFORE_START.time, - endTimestamp: KEY_AFTER_END.time, - highlightTerms: ['generate_test_data/simple_logs'], - }) - ) - .expect(200); - - const logEntriesHighlightsResponse = pipe( - logEntriesHighlightsResponseRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - - expect(logEntriesHighlightsResponse.data).to.have.length(1); - - const entries = logEntriesHighlightsResponse.data[0].entries; - - // Finds expected entries - expect(entries).to.have.length(50); - - // All entries contain the highlights - entries.forEach((entry) => { - entry.columns.forEach((column) => { - if ('field' in column && 'highlights' in column && column.highlights.length > 0) { - expect(column.highlights).to.eql(['generate_test_data/simple_logs']); - } - }); - }); - }); - - it('applies the query as well as the highlight', async () => { - const { body } = await supertest - .post(LOG_ENTRIES_HIGHLIGHTS_PATH) - .set(COMMON_HEADERS) - .send( - logEntriesHighlightsRequestRT.encode({ - logView: { type: 'log-view-reference', logViewId: 'default' }, - startTimestamp: KEY_BEFORE_START.time, - endTimestamp: KEY_AFTER_END.time, - query: JSON.stringify({ - multi_match: { query: 'host-a', type: 'phrase', lenient: true }, - }), - highlightTerms: ['message'], - }) - ) - .expect(200); - - const logEntriesHighlightsResponse = pipe( - logEntriesHighlightsResponseRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - - expect(logEntriesHighlightsResponse.data).to.have.length(1); - - const entries = logEntriesHighlightsResponse.data[0].entries; - - // Finds expected entries - expect(entries).to.have.length(25); - - // All entries contain the highlights - entries.forEach((entry) => { - entry.columns.forEach((column) => { - if ('message' in column && 'highlights' in column.message[0]) { - expect(column.message[0].highlights).to.eql(['message', 'message']); - } - }); - }); - }); - }); - }); - }); -} diff --git a/x-pack/test/api_integration/apis/logs_ui/log_summary.ts b/x-pack/test/api_integration/apis/logs_ui/log_summary.ts deleted file mode 100644 index 8a02dad1f1c5b..0000000000000 --- a/x-pack/test/api_integration/apis/logs_ui/log_summary.ts +++ /dev/null @@ -1,79 +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 expect from '@kbn/expect'; - -import { pairs } from 'd3-array'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { fold } from 'fp-ts/lib/Either'; - -import { createPlainError, throwErrors } from '@kbn/io-ts-utils'; - -import { - LOG_ENTRIES_SUMMARY_PATH, - logEntriesSummaryRequestRT, - logEntriesSummaryResponseRT, -} from '@kbn/logs-shared-plugin/common'; - -import { FtrProviderContext } from '../../ftr_provider_context'; - -const EARLIEST_TIME_WITH_DATA = new Date('2018-10-17T19:42:22.000Z').valueOf(); -const LATEST_TIME_WITH_DATA = new Date('2018-10-17T19:57:21.611Z').valueOf(); - -const COMMON_HEADERS = { - 'kbn-xsrf': 'some-xsrf-token', - 'Elastic-Api-Version': '1', -}; - -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - - describe('logSummaryBetween', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); - - it('should return empty and non-empty consecutive buckets', async () => { - const startTimestamp = EARLIEST_TIME_WITH_DATA; - const endTimestamp = - LATEST_TIME_WITH_DATA + (LATEST_TIME_WITH_DATA - EARLIEST_TIME_WITH_DATA); - const bucketSize = Math.ceil((endTimestamp - startTimestamp) / 10); - - const { body } = await supertest - .post(LOG_ENTRIES_SUMMARY_PATH) - .set(COMMON_HEADERS) - .send( - logEntriesSummaryRequestRT.encode({ - logView: { type: 'log-view-reference', logViewId: 'default' }, - startTimestamp, - endTimestamp, - bucketSize, - query: null, - }) - ) - .expect(200); - - const logSummaryResponse = pipe( - logEntriesSummaryResponseRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - - expect(logSummaryResponse.data.buckets).to.have.length(10); - expect( - logSummaryResponse.data.buckets.filter((bucket: any) => bucket.entriesCount > 0) - ).to.have.length(5); - expect( - pairs( - logSummaryResponse.data.buckets, - (first: any, second: any) => first.end === second.start - ).every((pair) => pair) - ).to.equal(true); - }); - }); -} diff --git a/x-pack/test/functional/apps/infra/index.ts b/x-pack/test/functional/apps/infra/index.ts index 999d7342f4639..89f4a40a74d45 100644 --- a/x-pack/test/functional/apps/infra/index.ts +++ b/x-pack/test/functional/apps/infra/index.ts @@ -26,10 +26,7 @@ export default ({ loadTestFile }: FtrProviderContext) => { describe('Logs UI', function () { loadTestFile(require.resolve('./logs/log_entry_categories_tab')); loadTestFile(require.resolve('./logs/log_entry_rate_tab')); - loadTestFile(require.resolve('./logs/logs_source_configuration')); - loadTestFile(require.resolve('./logs/log_stream_date_nano')); loadTestFile(require.resolve('./logs/link_to')); - loadTestFile(require.resolve('./logs/log_stream')); loadTestFile(require.resolve('./logs/ml_job_id_formats/tests')); }); }); diff --git a/x-pack/test/functional/apps/infra/logs/log_stream.ts b/x-pack/test/functional/apps/infra/logs/log_stream.ts deleted file mode 100644 index b8f926380e632..0000000000000 --- a/x-pack/test/functional/apps/infra/logs/log_stream.ts +++ /dev/null @@ -1,88 +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 expect from '@kbn/expect'; -import { URL } from 'url'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const SERVICE_ID = '49a18510598271e924253ed2581d7ada'; - -export default ({ getPageObjects, getService }: FtrProviderContext) => { - const pageObjects = getPageObjects(['common']); - const retry = getService('retry'); - const browser = getService('browser'); - const esArchiver = getService('esArchiver'); - - describe.skip('Log stream', function () { - describe('Legacy URL handling', () => { - describe('Correctly handles legacy versions of logFilter', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/logs_and_metrics'); - }); - after(async () => { - await esArchiver.unload( - 'x-pack/test/functional/es_archives/infra/8.0.0/logs_and_metrics' - ); - }); - it('Expression and kind', async () => { - const location = { - hash: '', - pathname: '/stream', - search: `logFilter=(expression:'service.id:"${SERVICE_ID}"',kind:kuery)`, - state: undefined, - }; - - await pageObjects.common.navigateToUrlWithBrowserHistory( - 'infraLogs', - location.pathname, - location.search, - { - ensureCurrentUrl: false, - } - ); - - await retry.tryForTime(5000, async () => { - const currentUrl = await browser.getCurrentUrl(); - const parsedUrl = new URL(currentUrl); - - expect(parsedUrl.pathname).to.be('/app/logs/stream'); - expect(parsedUrl.searchParams.get('logFilter')).to.contain( - `(filters:!(),query:(language:kuery,query:\'service.id:"${SERVICE_ID}"\')` - ); - }); - }); - it('Top-level query and language', async () => { - const location = { - hash: '', - pathname: '/stream', - search: `logFilter=(query:'service.id:"${SERVICE_ID}"',language:kuery)`, - state: undefined, - }; - - await pageObjects.common.navigateToUrlWithBrowserHistory( - 'infraLogs', - location.pathname, - location.search, - { - ensureCurrentUrl: false, - } - ); - - await retry.tryForTime(5000, async () => { - const currentUrl = await browser.getCurrentUrl(); - const parsedUrl = new URL(currentUrl); - - expect(parsedUrl.pathname).to.be('/app/logs/stream'); - expect(parsedUrl.searchParams.get('logFilter')).to.contain( - `(filters:!(),query:(language:kuery,query:\'service.id:"${SERVICE_ID}"\')` - ); - }); - }); - }); - }); - }); -}; diff --git a/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts b/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts deleted file mode 100644 index eb0e23083ad6b..0000000000000 --- a/x-pack/test/functional/apps/infra/logs/log_stream_date_nano.ts +++ /dev/null @@ -1,87 +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 expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; -import { DATES } from '../constants'; - -export default ({ getPageObjects, getService }: FtrProviderContext) => { - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const logsUi = getService('logsUi'); - const find = getService('find'); - const logFilter = { - timeRange: { - from: DATES.metricsAndLogs.stream.startWithData, - to: DATES.metricsAndLogs.stream.endWithData, - }, - }; - - describe.skip('Log stream supports nano precision', function () { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/logs_with_nano_date'); - }); - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/infra/logs_with_nano_date'); - }); - - it('should display logs entries containing date_nano timestamps properly ', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); - - expect(logStreamEntries.length).to.be(4); - }); - - it('should render timestamp column properly', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - await retry.try(async () => { - const columnHeaderLabels = await logsUi.logStreamPage.getColumnHeaderLabels(); - expect(columnHeaderLabels[0]).to.eql('Oct 17, 2018'); - }); - }); - - it('should render timestamp column values properly', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); - - const firstLogStreamEntry = logStreamEntries[0]; - - const entryTimestamp = await logsUi.logStreamPage.getLogEntryColumnValueByName( - firstLogStreamEntry, - 'timestampLogColumn' - ); - - expect(entryTimestamp).to.be('19:43:22.111'); - }); - - it('should properly render timestamp in flyout with nano precision', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); - const firstLogStreamEntry = logStreamEntries[0]; - - await logsUi.logStreamPage.openLogEntryDetailsFlyout(firstLogStreamEntry); - - const cells = await find.allByCssSelector('.euiTableCellContent'); - - let isFound = false; - - for (const cell of cells) { - const cellText = await cell.getVisibleText(); - if (cellText === '2018-10-17T19:43:22.111111111Z') { - isFound = true; - return; - } - } - - expect(isFound).to.be(true); - }); - }); -}; diff --git a/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts deleted file mode 100644 index 27fa95ca16696..0000000000000 --- a/x-pack/test/functional/apps/infra/logs/logs_source_configuration.ts +++ /dev/null @@ -1,195 +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 expect from '@kbn/expect'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; -import { DATES } from '../constants'; - -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const COMMON_REQUEST_HEADERS = { - 'kbn-xsrf': 'some-xsrf-token', -}; - -export default ({ getPageObjects, getService }: FtrProviderContext) => { - const esArchiver = getService('esArchiver'); - const browser = getService('browser'); - const logsUi = getService('logsUi'); - const infraSourceConfigurationForm = getService('infraSourceConfigurationForm'); - const pageObjects = getPageObjects(['common', 'header', 'infraLogs']); - const retry = getService('retry'); - const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); - - describe.skip('Logs Source Configuration', function () { - before(async () => { - await kibanaServer.savedObjects.cleanStandardList(); - }); - after(async () => { - await kibanaServer.savedObjects.cleanStandardList(); - }); - - describe('Allows indices configuration', () => { - const logFilter = { - timeRange: { - from: DATES.metricsAndLogs.stream.startWithData, - to: DATES.metricsAndLogs.stream.endWithData, - }, - }; - const formattedLocalStart = new Date(logFilter.timeRange.from).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric', - }); - - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - }); - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - }); - - it('renders the correct page title', async () => { - await pageObjects.infraLogs.navigateToTab('settings'); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async () => { - const documentTitle = await browser.getTitle(); - expect(documentTitle).to.contain('Settings - Logs - Observability - Elastic'); - }); - }); - - it('can change the log indices to a pattern that matches nothing', async () => { - await pageObjects.infraLogs.navigateToTab('settings'); - - await retry.try(async () => { - await infraSourceConfigurationForm.getForm(); - }); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - await infraSourceConfigurationForm.selectIndicesPanel(); - - const nameInput = await infraSourceConfigurationForm.getNameInput(); - await nameInput.clearValueWithKeyboard({ charByChar: true }); - await nameInput.type('Modified Source'); - - const logIndicesInput = await infraSourceConfigurationForm.getLogIndicesInput(); - await logIndicesInput.clearValueWithKeyboard({ charByChar: true }); - await logIndicesInput.type('does-not-exist-*'); - - await infraSourceConfigurationForm.saveConfiguration(); - }); - - it('renders the no indices screen when no indices match the pattern', async () => { - await logsUi.logStreamPage.navigateTo(); - - await retry.try(async () => { - await logsUi.logStreamPage.getNoDataPage(); - }); - }); - - it('can change the log indices back to a pattern that matches something', async () => { - await pageObjects.infraLogs.navigateToTab('settings'); - - await retry.try(async () => { - await infraSourceConfigurationForm.getForm(); - }); - - await pageObjects.header.waitUntilLoadingHasFinished(); - - const logIndicesInput = await infraSourceConfigurationForm.getLogIndicesInput(); - await logIndicesInput.clearValueWithKeyboard({ charByChar: true }); - await logIndicesInput.type('filebeat-*'); - - await infraSourceConfigurationForm.saveConfiguration(); - }); - - it('renders the default log columns with their headers', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - await retry.try(async () => { - const columnHeaderLabels = await logsUi.logStreamPage.getColumnHeaderLabels(); - - expect(columnHeaderLabels).to.eql([formattedLocalStart, 'event.dataset', 'Message']); - }); - - const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); - expect(logStreamEntries.length).to.be.greaterThan(0); - - const firstLogStreamEntry = logStreamEntries[0]; - const logStreamEntryColumns = await logsUi.logStreamPage.getLogColumnsOfStreamEntry( - firstLogStreamEntry - ); - - expect(logStreamEntryColumns).to.have.length(3); - }); - - it('records telemetry for logs', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - await logsUi.logStreamPage.getStreamEntries(); - - const [{ stats }] = await supertest - .post(`/internal/telemetry/clusters/_stats`) - .set(COMMON_REQUEST_HEADERS) - .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .set('Accept', 'application/json') - .send({ - unencrypted: true, - refreshCache: true, - }) - .expect(200) - .then((res: any) => res.body); - - expect(stats.stack_stats.kibana.plugins.infraops.last_24_hours.hits.logs).to.be.greaterThan( - 0 - ); - }); - - it('can change the log columns', async () => { - await pageObjects.infraLogs.navigateToTab('settings'); - - await retry.try(async () => { - await infraSourceConfigurationForm.getForm(); - }); - - await infraSourceConfigurationForm.removeAllLogColumns(); - await infraSourceConfigurationForm.addTimestampLogColumn(); - await infraSourceConfigurationForm.addFieldLogColumn('host.name'); - - await infraSourceConfigurationForm.saveConfiguration(); - }); - - it('renders the changed log columns with their headers', async () => { - await logsUi.logStreamPage.navigateTo({ logFilter }); - - await retry.try(async () => { - const columnHeaderLabels = await logsUi.logStreamPage.getColumnHeaderLabels(); - - expect(columnHeaderLabels).to.eql([formattedLocalStart, 'host.name']); - }); - - const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); - - expect(logStreamEntries.length).to.be.greaterThan(0); - - const firstLogStreamEntry = logStreamEntries[0]; - const logStreamEntryColumns = await logsUi.logStreamPage.getLogColumnsOfStreamEntry( - firstLogStreamEntry - ); - - expect(logStreamEntryColumns).to.have.length(2); - }); - }); - }); -}; diff --git a/x-pack/test/functional/page_objects/infra_logs_page.ts b/x-pack/test/functional/page_objects/infra_logs_page.ts index 778acfc5fe480..21d54b844a050 100644 --- a/x-pack/test/functional/page_objects/infra_logs_page.ts +++ b/x-pack/test/functional/page_objects/infra_logs_page.ts @@ -5,24 +5,8 @@ * 2.0. */ -import { FlyoutOptionsUrlState } from '@kbn/infra-plugin/public/containers/logs/log_flyout'; -import querystring from 'querystring'; -import { encode } from '@kbn/rison'; -import type { PositionStateInUrl } from '@kbn/infra-plugin/public/observability_logs/log_stream_position_state/src/url_state_storage_service'; -import { FilterStateInUrl } from '@kbn/infra-plugin/public/observability_logs/log_stream_query_state'; import { FtrProviderContext } from '../ftr_provider_context'; -export interface TabsParams { - stream: { - logPosition?: Partial; - logFilter?: Partial; - flyoutOptions?: Partial; - }; - settings: never; - 'log-categories': any; - 'log-rate': any; -} - export function InfraLogsPageProvider({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common']); @@ -32,24 +16,11 @@ export function InfraLogsPageProvider({ getPageObjects, getService }: FtrProvide await pageObjects.common.navigateToApp('infraLogs'); }, - async navigateToTab(logsUiTab: T, params?: TabsParams[T]) { - let qs = ''; - if (params) { - const parsedParams: Record = {}; - - for (const key in params) { - if (Object.hasOwn(params, key)) { - const value = params[key]; - parsedParams[key] = encode(value); - } - } - qs = '?' + querystring.stringify(parsedParams); - } - + async navigateToTab(logsUiTab: T) { await pageObjects.common.navigateToUrlWithBrowserHistory( 'infraLogs', `/${logsUiTab}`, - qs, + '', { ensureCurrentUrl: false } // Test runner struggles with `rison-node` escaped values ); }, @@ -60,4 +31,4 @@ export function InfraLogsPageProvider({ getPageObjects, getService }: FtrProvide }; } -type LogsUiTab = 'log-categories' | 'log-rate' | 'settings' | 'stream'; +type LogsUiTab = 'log-categories' | 'log-rate'; diff --git a/x-pack/test/functional/services/infra_source_configuration_form.ts b/x-pack/test/functional/services/infra_source_configuration_form.ts index c8d28e0e3656b..9589debf5d289 100644 --- a/x-pack/test/functional/services/infra_source_configuration_form.ts +++ b/x-pack/test/functional/services/infra_source_configuration_form.ts @@ -14,8 +14,6 @@ export function InfraSourceConfigurationFormProvider({ }: FtrProviderContext) { const retry = getService('retry'); const testSubjects = getService('testSubjects'); - const browser = getService('browser'); - const common = getPageObject('common'); return { /** @@ -24,92 +22,12 @@ export function InfraSourceConfigurationFormProvider({ async getNameInput(): Promise { return await testSubjects.findDescendant('~nameInput', await this.getForm()); }, - async getLogIndicesInput(): Promise { - return await testSubjects.findDescendant('~logIndicesInput', await this.getForm()); - }, async getMetricIndicesInput(): Promise { return await testSubjects.findDescendant('~metricIndicesInput', await this.getForm()); }, async selectIndicesPanel(): Promise { return await testSubjects.click('logIndicesCheckableCard'); }, - /** - * Logs - */ - async getAddLogColumnButton(): Promise { - return await testSubjects.findDescendant('~addLogColumnButton', await this.getForm()); - }, - async getAddLogColumnPopover(): Promise { - return await testSubjects.find('~addLogColumnPopover'); - }, - async addTimestampLogColumn() { - // try to open the popover - const popover = await retry.try(async () => { - await (await this.getAddLogColumnButton()).click(); - return this.getAddLogColumnPopover(); - }); - - // try to select the timestamp field - await retry.try(async () => { - await (await testSubjects.findDescendant('~addTimestampLogColumn', popover)).click(); - }); - - // wait for timestamp panel to show up - await testSubjects.findDescendant('~systemLogColumnPanel:Timestamp', await this.getForm()); - }, - async addFieldLogColumn(fieldName: string) { - // try to open the popover - const popover = await retry.try(async () => { - await (await this.getAddLogColumnButton()).click(); - return this.getAddLogColumnPopover(); - }); - - // try to select the given field - await retry.try(async () => { - await (await testSubjects.findDescendant('~fieldSearchInput', popover)).type(fieldName); - await ( - await testSubjects.findDescendant(`~addFieldLogColumn:${fieldName}`, popover) - ).click(); - }); - - // wait for field panel to show up - await testSubjects.findDescendant(`~fieldLogColumnPanel:${fieldName}`, await this.getForm()); - }, - async getLogColumnPanels(): Promise { - return await testSubjects.findAllDescendant('~logColumnPanel', await this.getForm()); - }, - async removeLogColumn(columnIndex: number) { - const logColumnPanel = (await this.getLogColumnPanels())[columnIndex]; - await (await testSubjects.findDescendant('~removeLogColumnButton', logColumnPanel)).click(); - await testSubjects.waitForDeleted(logColumnPanel); - }, - async removeAllLogColumns() { - for (const _ of await this.getLogColumnPanels()) { - await this.removeLogColumn(0); - } - }, - async moveLogColumn(sourceIndex: number, destinationIndex: number) { - const KEY_PRESS_DELAY_MS = 500; // This may need to be high for Jenkins; 100 works on desktop - - const logColumnPanel = (await this.getLogColumnPanels())[sourceIndex]; - const moveLogColumnHandle = await testSubjects.findDescendant( - '~moveLogColumnHandle', - logColumnPanel - ); - await moveLogColumnHandle.focus(); - const movementDifference = destinationIndex - sourceIndex; - await moveLogColumnHandle.pressKeys(browser.keys.SPACE); - for (let i = 0; i < Math.abs(movementDifference); i++) { - await common.sleep(KEY_PRESS_DELAY_MS); - if (movementDifference > 0) { - await moveLogColumnHandle.pressKeys(browser.keys.ARROW_DOWN); - } else { - await moveLogColumnHandle.pressKeys(browser.keys.ARROW_UP); - } - } - await moveLogColumnHandle.pressKeys(browser.keys.SPACE); - await common.sleep(KEY_PRESS_DELAY_MS); - }, /** * Infra Metrics bottom actions bar diff --git a/x-pack/test/functional/services/logs_ui/index.ts b/x-pack/test/functional/services/logs_ui/index.ts index c0690957c4148..7a7bf8050dbf7 100644 --- a/x-pack/test/functional/services/logs_ui/index.ts +++ b/x-pack/test/functional/services/logs_ui/index.ts @@ -8,13 +8,11 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { LogEntryCategoriesPageProvider } from './log_entry_categories'; import { LogEntryRatePageProvider } from './log_entry_rate'; -import { LogStreamPageProvider } from './log_stream'; export function LogsUiProvider(context: FtrProviderContext) { return { logEntryCategoriesPage: LogEntryCategoriesPageProvider(context), logEntryRatePage: LogEntryRatePageProvider(context), - logStreamPage: LogStreamPageProvider(context), cleanIndices: createCleanIndicesHandler(context), }; } diff --git a/x-pack/test/functional/services/logs_ui/log_stream.ts b/x-pack/test/functional/services/logs_ui/log_stream.ts deleted file mode 100644 index 160e949c84de4..0000000000000 --- a/x-pack/test/functional/services/logs_ui/log_stream.ts +++ /dev/null @@ -1,80 +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 { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; -import { FtrProviderContext } from '../../ftr_provider_context'; -import { TabsParams } from '../../page_objects/infra_logs_page'; - -export function LogStreamPageProvider({ getPageObjects, getService }: FtrProviderContext) { - const pageObjects = getPageObjects(['infraLogs']); - const retry = getService('retry'); - const find = getService('find'); - const testSubjects = getService('testSubjects'); - - return { - async navigateTo(params?: TabsParams['stream']) { - await pageObjects.infraLogs.navigateToTab('stream', params); - }, - - async getColumnHeaderLabels(): Promise { - const columnHeaderElements: WebElementWrapper[] = await testSubjects.findAll( - '~logColumnHeader' - ); - return await Promise.all(columnHeaderElements.map((element) => element.getVisibleText())); - }, - - async getStreamEntries(minimumItems = 1): Promise { - await retry.try(async () => { - const elements = await testSubjects.findAll('~streamEntry'); - if (!elements || elements.length < minimumItems) { - throw new Error(); - } - }); - - return await testSubjects.findAll('~streamEntry'); - }, - - async getLogColumnsOfStreamEntry( - entryElement: WebElementWrapper - ): Promise { - return await testSubjects.findAllDescendant('~logColumn', entryElement); - }, - - async getLogEntryColumnValueByName( - entryElement: WebElementWrapper, - column: string - ): Promise { - const columnElement = await testSubjects.findDescendant(`~${column}`, entryElement); - - const contentElement = await columnElement.findByCssSelector( - `[data-test-subj='LogEntryColumnContent']` - ); - - return await contentElement.getVisibleText(); - }, - - async openLogEntryDetailsFlyout(entryElement: WebElementWrapper) { - await entryElement.click(); - - const menuButton = await testSubjects.findDescendant( - `~infraLogEntryContextMenuButton`, - entryElement - ); - await menuButton.click(); - - await find.clickByButtonText('View details'); - }, - - async getNoLogsIndicesPrompt() { - return await testSubjects.find('noLogsIndicesPrompt'); - }, - - async getNoDataPage() { - return await testSubjects.find('noDataPage'); - }, - }; -} diff --git a/x-pack/test/upgrade/apps/logs/index.ts b/x-pack/test/upgrade/apps/logs/index.ts deleted file mode 100644 index ed4181f75d76d..0000000000000 --- a/x-pack/test/upgrade/apps/logs/index.ts +++ /dev/null @@ -1,14 +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 { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('upgrade', function () { - loadTestFile(require.resolve('./logs_smoke_tests')); - }); -} diff --git a/x-pack/test/upgrade/apps/logs/logs_smoke_tests.ts b/x-pack/test/upgrade/apps/logs/logs_smoke_tests.ts deleted file mode 100644 index 2cde8de43b62a..0000000000000 --- a/x-pack/test/upgrade/apps/logs/logs_smoke_tests.ts +++ /dev/null @@ -1,40 +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 expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getPageObjects, getService }: FtrProviderContext) { - const PageObjects = getPageObjects(['common', 'header', 'home', 'timePicker']); - const logsUi = getService('logsUi'); - - describe('upgrade logs smoke tests', function describeIndexTests() { - const spaces = [ - { space: 'default', basePath: '' }, - { space: 'automation', basePath: 's/automation' }, - ]; - - spaces.forEach(({ space, basePath }) => { - describe('space: ' + space, () => { - before(async () => { - await PageObjects.common.navigateToActualUrl('home', '/tutorial_directory/sampleData', { - basePath, - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.home.launchSampleLogs('logs'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.timePicker.setCommonlyUsedTime('Last_1 year'); - }); - - it('should show log streams', async () => { - const logStreamEntries = await logsUi.logStreamPage.getStreamEntries(); - expect(logStreamEntries.length).to.be.greaterThan(100); - }); - }); - }); - }); -} diff --git a/x-pack/test/upgrade/config.ts b/x-pack/test/upgrade/config.ts index d6458f087e393..732b9004e2abd 100644 --- a/x-pack/test/upgrade/config.ts +++ b/x-pack/test/upgrade/config.ts @@ -24,7 +24,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('./apps/dashboard'), require.resolve('./apps/discover'), require.resolve('./apps/graph'), - require.resolve('./apps/logs'), require.resolve('./apps/maps'), require.resolve('./apps/reporting'), require.resolve('./apps/rules'),