From 3248ba28c8803024ba9990e273dbb907adc1a5a4 Mon Sep 17 00:00:00 2001 From: Keith Chong Date: Mon, 2 Nov 2026 17:10:36 -0500 Subject: [PATCH 1/2] feat: Add Needs Attention, Infrastructure cards to Dashboard (#11627) Signed-off-by: Keith Chong --- console-extensions.json | 40 +- locales/en/plugin__gitops-plugin.json | 81 +++- locales/es/plugin__gitops-plugin.json | 81 +++- locales/fr/plugin__gitops-plugin.json | 81 +++- locales/ja/plugin__gitops-plugin.json | 81 +++- locales/ko/plugin__gitops-plugin.json | 81 +++- locales/zh/plugin__gitops-plugin.json | 81 +++- src/gitops/Statuses/HealthStatus.test.tsx | 15 +- src/gitops/Statuses/HealthStatus.tsx | 2 +- src/gitops/Statuses/SyncStatus.test.tsx | 11 +- src/gitops/Statuses/SyncStatus.tsx | 2 +- .../overview/DashboardOverviewPage.scss | 85 ++++ .../overview/DashboardOverviewPage.tsx | 107 ++--- .../components/overview/chartHelpers.tsx | 11 + .../health-status/HealthStatusCard.tsx | 8 +- .../application/ApplicationsCard.tsx | 21 + .../appset/ApplicationSetsCard.tsx | 21 + .../argocd/ArgoCDInstancesCard.tsx | 125 ++++++ .../attention/NeedsAttentionCard.scss | 4 + .../attention/NeedsAttentionCard.tsx | 420 ++++++++++++++++++ .../imageupdater/ImageUpdatersCard.tsx | 21 + .../operator/GitOpsOperatorCard.tsx | 241 ++++++++++ .../project/AppProjectsCard.tsx | 21 + .../resources/ResourcesStatus.tsx | 133 ++++++ .../rollout-manager/RolloutManagersCard.tsx | 21 + .../infrastructure/rollout/RolloutsCard.tsx | 21 + .../shared/CreateResourceLink.tsx | 34 ++ .../infrastructure/shared/ErrorHeader.tsx | 21 + .../shared/InfrastructureCardTitle.tsx | 75 ++++ .../shared/InfrastructureResourceCard.tsx | 114 +++++ .../infrastructure/shared/LoadingHeader.tsx | 17 + .../infrastructure/shared/constants.ts | 6 + .../infrastructure/shared/resourceEntries.tsx | 198 +++++++++ .../OperationalMetricsCard.tsx | 45 +- .../RecentOperationsCard.tsx | 236 ++++++++++ .../reconciliation/ReconciliationCard.tsx | 4 +- .../sync-activity/SyncActivityCard.tsx | 12 +- .../overview/sync-status/SyncStatusCard.tsx | 8 +- .../overview/tabs/ApplicationsOverviewTab.tsx | 110 +++++ .../tabs/InfrastructureOverviewTab.tsx | 74 +++ .../components/rollout/model/RolloutModel.ts | 36 +- src/gitops/models/ArgoCDModel.ts | 81 ++++ src/images/OpenShift_GitOps.png | Bin 0 -> 14108 bytes src/images/OpenShift_GitOps.svg | 1 + 44 files changed, 2724 insertions(+), 164 deletions(-) create mode 100644 src/gitops/components/overview/infrastructure/application/ApplicationsCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/appset/ApplicationSetsCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/argocd/ArgoCDInstancesCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.scss create mode 100644 src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/imageupdater/ImageUpdatersCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/operator/GitOpsOperatorCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/project/AppProjectsCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/resources/ResourcesStatus.tsx create mode 100644 src/gitops/components/overview/infrastructure/rollout-manager/RolloutManagersCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/rollout/RolloutsCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/shared/CreateResourceLink.tsx create mode 100644 src/gitops/components/overview/infrastructure/shared/ErrorHeader.tsx create mode 100644 src/gitops/components/overview/infrastructure/shared/InfrastructureCardTitle.tsx create mode 100644 src/gitops/components/overview/infrastructure/shared/InfrastructureResourceCard.tsx create mode 100644 src/gitops/components/overview/infrastructure/shared/LoadingHeader.tsx create mode 100644 src/gitops/components/overview/infrastructure/shared/constants.ts create mode 100644 src/gitops/components/overview/infrastructure/shared/resourceEntries.tsx create mode 100644 src/gitops/components/overview/recent-operations/RecentOperationsCard.tsx create mode 100644 src/gitops/components/overview/tabs/ApplicationsOverviewTab.tsx create mode 100644 src/gitops/components/overview/tabs/InfrastructureOverviewTab.tsx create mode 100644 src/gitops/models/ArgoCDModel.ts create mode 100644 src/images/OpenShift_GitOps.png create mode 100644 src/images/OpenShift_GitOps.svg diff --git a/console-extensions.json b/console-extensions.json index 6fe673a01..11e3163d4 100644 --- a/console-extensions.json +++ b/console-extensions.json @@ -129,7 +129,6 @@ "version": "v1alpha1", "kind": "Rollout" }, - "badge": "dev", "color": "#E9654B", "label": "Argo Rollout", "labelPlural": "Argo Rollouts", @@ -147,14 +146,13 @@ "version": "v1alpha1", "kind": "RolloutManager" }, - "badge": "dev", "color": "#E9654B", "label": "Argo Rollout Manager", "labelPlural": "Argo Rollout Managers", "abbr": "ARM" }, "flags": { - "required": ["ARGO_ROLLOUT", "GITOPS_ENABLE_TOPOLOGY"] + "required": ["ARGO_ROLLOUT"] } }, { @@ -178,6 +176,23 @@ "name": "GitOps" } }, + { + "type": "console.model-metadata", + "properties": { + "model": { + "group": "argoproj.io", + "version": "v1beta1", + "kind": "ArgoCD" + }, + "color": "#E9654B", + "label": "Argo CD Instance", + "labelPlural": "Argo CD Instances", + "abbr": "ACD" + }, + "flags": { + "required": ["ARGOCD"] + } + }, { "type": "console.model-metadata", "properties": { @@ -186,7 +201,6 @@ "version": "v1alpha1", "kind": "Application" }, - "badge": "dev", "color": "#E9654B", "label": "Argo CD Application", "labelPlural": "Argo CD Applications", @@ -221,7 +235,6 @@ "version": "v1alpha1", "kind": "ApplicationSet" }, - "badge": "dev", "color": "#E9654B", "label": "Argo CD ApplicationSet", "labelPlural": "Argo CD ApplicationSets", @@ -239,7 +252,6 @@ "version": "v1alpha1", "kind": "AnalysisTemplate" }, - "badge": "dev", "color": "#E9654B", "label": "Analysis Template", "labelPlural": "Application Templates", @@ -257,7 +269,6 @@ "version": "v1alpha1", "kind": "ClusterAnalysisTemplate" }, - "badge": "dev", "color": "#E9654B", "label": "Cluster Analysis Template", "labelPlural": "Cluster Application Templates", @@ -284,6 +295,17 @@ "required": ["IMAGEUPDATER"] } }, + { + "type": "console.flag/model", + "properties": { + "flag": "ARGOCD", + "model": { + "group": "argoproj.io", + "version": "v1beta1", + "kind": "ArgoCD" + } + } + }, { "type": "console.flag/model", "properties": { @@ -322,7 +344,7 @@ "properties": { "id": "openshift-gitops-overview", "href": "/gitops/overview", - "name": "Dashboard", + "name": "Overview", "perspective": "admin", "section": "gitops-navigation-section", "namespaced": true @@ -339,7 +361,7 @@ { "type": "console.page/route", "properties": { - "exact": true, + "exact": false, "path": ["/gitops/overview/all-namespaces", "/gitops/overview/ns/:ns"], "component": { "$codeRef": "DashboardOverviewPage" } } diff --git a/locales/en/plugin__gitops-plugin.json b/locales/en/plugin__gitops-plugin.json index 563f7e57f..e22afb3f7 100644 --- a/locales/en/plugin__gitops-plugin.json +++ b/locales/en/plugin__gitops-plugin.json @@ -102,7 +102,6 @@ "Argo CD project that this ApplicationSet belongs to.": "Argo CD project that this ApplicationSet belongs to.", "Git repository URL where the ApplicationSet configuration is stored.": "Git repository URL where the ApplicationSet configuration is stored.", "Progressive Sync Step {{x}}": "Progressive Sync Step {{x}}", - "Application": "Application", "Applications": "Applications", "Show all match expressions": "Show all match expressions", "Edit ApplicationSet": "Edit ApplicationSet", @@ -133,6 +132,7 @@ "Observed Generation": "Observed Generation", "The generation of the resource that was last reconciled.": "The generation of the resource that was last reconciled.", "Conditions": "Conditions", + "ImageUpdater": "ImageUpdater", "No ImageUpdaters match the search filter": "No ImageUpdaters match the search filter", "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Try removing the filter or searching for a different term to see more ImageUpdaters.", "There are no ImageUpdaters in this namespace.": "There are no ImageUpdaters in this namespace.", @@ -162,6 +162,8 @@ "Updated At": "Updated At", "No datapoints found.": "No datapoints found.", "Loading...": "Loading...", + "Application Overview": "Application Overview", + "Infrastructure": "Infrastructure", "GitOps Overview": "GitOps Overview", "Healthy": "Healthy", "Progressing": "Progressing", @@ -171,13 +173,66 @@ "Health status": "Health status", "Unable to retrieve applications": "Unable to retrieve applications", "Error retrieving applications: {{x}}": "Error retrieving applications: {{x}}", + "Error retrieving Applications": "Error retrieving Applications", + "View Applications List Page": "View Applications List Page", + "Create Application": "Create Application", + "ApplicationSets": "ApplicationSets", + "Error retrieving ApplicationSets": "Error retrieving ApplicationSets", + "View ApplicationSets List Page": "View ApplicationSets List Page", + "Create ApplicationSet": "Create ApplicationSet", + "All Namespaces": "All Namespaces", + "Argo CD Instances": "Argo CD Instances", + "Error retrieving Argo CD instances": "Error retrieving Argo CD instances", + "No {{x}} found": "No {{x}} found", + "Create Argo CD instance": "Create Argo CD instance", + "Applications Needing Attention": "Applications Needing Attention", + "Application": "Application", + "No {{x}} needing attention": "No {{x}} needing attention", + "{{x}}": "{{x}}", + "is not on the cluster (Missing).": "is not on the cluster (Missing).", + "is {{x}}.": "is {{x}}.", + " {{x}}.": " {{x}}.", + "The application's resources are all missing. Try syncing the application.": "The application's resources are all missing. Try syncing the application.", + "Operation: Sync": "Operation: Sync", + "Finished At: {{x}}": "Finished At: {{x}}", + "Message: {{x}}": "Message: {{x}}", + "Message: {{x}}.": "Message: {{x}}.", + "...and {{x}} more": "...and {{x}} more", + "Image Updaters": "Image Updaters", + "Error retrieving Image Updaters": "Error retrieving Image Updaters", + "View Image Updaters List Page": "View Image Updaters List Page", + "Create Image Updater": "Create Image Updater", + "GitOps Operator": "GitOps Operator", + "Error retrieving CSV for the GitOps Operator": "Error retrieving CSV for the GitOps Operator", + "Version: {{x}}": "Version: {{x}}", + "Display Name: {{x}}": "Display Name: {{x}}", + "Provider: {{x}}": "Provider: {{x}}", + "Namspace: {{x}}": "Namspace: {{x}}", + "Created At:": "Created At:", + "Not found": "Not found", + "The OpenShift GitOps Operator is not installed or not found for this namespace": "The OpenShift GitOps Operator is not installed or not found for this namespace", + "App Projects": "App Projects", + "Error retrieving App Projects": "Error retrieving App Projects", + "View AppProjects List Page": "View AppProjects List Page", + "Create AppProject": "Create AppProject", + "Updated message(s) for the {{x}}:": "Updated message(s) for the {{x}}:", + "Rollout Managers": "Rollout Managers", + "Error retrieving Rollout Managers": "Error retrieving Rollout Managers", + "View Rollout Managers List Page": "View Rollout Managers List Page", + "Create Rollout Manager": "Create Rollout Manager", + "Rollouts": "Rollouts", + "Error retrieving Rollouts": "Error retrieving Rollouts", + "View Rollouts List Page": "View Rollouts List Page", + "Create Rollout": "Create Rollout", + "Total:": "Total:", + "ns={{x}}": "ns={{x}}", "Error fetching metric data. Click to view metrics dashboard.": "Error fetching metric data. Click to view metrics dashboard.", "Operational metrics": "Operational metrics", - "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", + "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", "Successful syncs": "Successful syncs", "Number of successful syncs": "Number of successful syncs", "Failed syncs": "Failed syncs", - "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.": "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.", + "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.": "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.", "Orphaned resources": "Orphaned resources", "Number of orphaned resources": "Number of orphaned resources", "Apps with Autosync enabled": "Apps with Autosync enabled", @@ -188,15 +243,24 @@ "Number of repos in the queue": "Number of repos in the queue", "Git fetch failures": "Git fetch failures", "Number of git fetch failures": "Number of git fetch failures", + "Recent Operations": "Recent Operations", + "(Last {{x}} operations)": "(Last {{x}} operations)", + "No recent operations": "No recent operations", "Application Reconciliation Performance (24 hours)": "Application Reconciliation Performance (24 hours)", "Unable to retrieve metrics data": "Unable to retrieve metrics data", + "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.", "Application reconciliation performance over time": "Application reconciliation performance over time", "View in Observe/Metrics": "View in Observe/Metrics", "Syncs (24h sliding window)": "Syncs (24h sliding window)", "Synced": "Synced", "Out of Sync": "Out of Sync", "Application Sync Activity (24 hours)": "Application Sync Activity (24 hours)", + "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.", "Application sync activity over time": "Application sync activity over time", + "Application model does not exist": "Application model does not exist", + "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.": "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.", "Server": "Server", "Deny": "Deny", "Allow": "Allow", @@ -247,6 +311,7 @@ "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.", "Enabled": "Enabled", "Disabled": "Disabled", + "AppProject": "AppProject", "No Argo CD App Projects match the search filter": "No Argo CD App Projects match the search filter", "Try removing the filter or searching for a different term to see more App Projects.": "Try removing the filter or searching for a different term to see more App Projects.", "There are no Argo CD App Projects in this project.": "There are no Argo CD App Projects in this project.", @@ -255,7 +320,6 @@ "No Argo CD App Projects": "No Argo CD App Projects", "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", "AppProjects": "AppProjects", - "Create AppProject": "Create AppProject", "Last Updated": "Last Updated", "Has Description": "Has Description", "No Description": "No Description", @@ -326,12 +390,11 @@ "There is no rollout status. Check that the Rollout Manager is created and is available.": "There is no rollout status. Check that the Rollout Manager is created and is available.", "Strategy": "Strategy", "Whether the rollout is using a blue-green or canary strategy": "Whether the rollout is using a blue-green or canary strategy", + "Rollout": "Rollout", "No Argo Rollouts": "No Argo Rollouts", "There are no Argo Rollouts in this project.": "There are no Argo Rollouts in this project.", "There are no Argo Rollouts in all projects.": "There are no Argo Rollouts in all projects.", "There was an error retrieving rollouts. Check your connection and reload the page.": "There was an error retrieving rollouts. Check your connection and reload the page.", - "Rollouts": "Rollouts", - "Create Rollout": "Create Rollout", "Pods": "Pods", "Selector": "Selector", "Rollout Status": "Rollout Status", @@ -362,6 +425,7 @@ "ApplicationSet Applications": "ApplicationSet Applications", "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.", "Revision": "Revision", + "ApplicationSet": "ApplicationSet", "No Argo CD ApplicationSets match the filter": "No Argo CD ApplicationSets match the filter", "Adjust the filter to see more ApplicationSets.": "Adjust the filter to see more ApplicationSets.", "There are no Argo CD ApplicationSets in this project.": "There are no Argo CD ApplicationSets in this project.", @@ -369,8 +433,6 @@ "No matching Argo CD ApplicationSets": "No matching Argo CD ApplicationSets", "No Argo CD ApplicationSets": "No Argo CD ApplicationSets", "There was an error retrieving applicationsets. Check your connection and reload the page.": "There was an error retrieving applicationsets. Check your connection and reload the page.", - "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "Create ApplicationSet", "No labels": "No labels", "Namespace defines the space within which each name must be unique.": "Namespace defines the space within which each name must be unique.", "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Map of string keys and values that can be used to organize and categorize (scope and select) objects.", @@ -380,14 +442,15 @@ "Created at": "Created at", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", + "Extra": "Extra", "Manage columns": "Manage columns", "Selected columns will appear in the table.": "Selected columns will appear in the table.", "The namespace column is only shown when in \"All projects\"": "The namespace column is only shown when in \"All projects\"", "Default {{resourceKind}} columns": "Default {{resourceKind}} columns", "Additional columns": "Additional columns", - "Restore default columns": "Restore default columns", "Save": "Save", "Cancel": "Cancel", + "Restore default columns": "Restore default columns", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", diff --git a/locales/es/plugin__gitops-plugin.json b/locales/es/plugin__gitops-plugin.json index 82d1fd59c..6887848f3 100644 --- a/locales/es/plugin__gitops-plugin.json +++ b/locales/es/plugin__gitops-plugin.json @@ -102,7 +102,6 @@ "Argo CD project that this ApplicationSet belongs to.": "Proyecto Argo CD al que pertenece este ApplicationSet.", "Git repository URL where the ApplicationSet configuration is stored.": "URL del repositorio Git en el que se almacena la configuración de ApplicationSet.", "Progressive Sync Step {{x}}": "Paso de sincronización progresiva {{x}}", - "Application": "Aplicación", "Applications": "Aplicaciones", "Show all match expressions": "Mostrar todas las expresiones de coincidencia", "Edit ApplicationSet": "Editar ApplicationSet", @@ -133,6 +132,7 @@ "Observed Generation": "Generación observada", "The generation of the resource that was last reconciled.": "La generación del recurso que se concilió por última vez.", "Conditions": "Condiciones", + "ImageUpdater": "ImageUpdater", "No ImageUpdaters match the search filter": "No se encontraron ImageUpdaters que coincidan con el filtro de búsqueda.", "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Quite el filtro o busque un término diferente para ver más ImageUpdaters.", "There are no ImageUpdaters in this namespace.": "No hay ImageUpdaters en este espacio de nombres.", @@ -162,6 +162,8 @@ "Updated At": "Actualizado a las", "No datapoints found.": "No datapoints found.", "Loading...": "Loading...", + "Application Overview": "Application Overview", + "Infrastructure": "Infrastructure", "GitOps Overview": "GitOps Overview", "Healthy": "Healthy", "Progressing": "Progressing", @@ -171,13 +173,66 @@ "Health status": "Health status", "Unable to retrieve applications": "Unable to retrieve applications", "Error retrieving applications: {{x}}": "Error retrieving applications: {{x}}", + "Error retrieving Applications": "Error retrieving Applications", + "View Applications List Page": "View Applications List Page", + "Create Application": "Create Application", + "ApplicationSets": "ApplicationSets", + "Error retrieving ApplicationSets": "Error retrieving ApplicationSets", + "View ApplicationSets List Page": "View ApplicationSets List Page", + "Create ApplicationSet": "Crear ApplicationSet", + "All Namespaces": "All Namespaces", + "Argo CD Instances": "Argo CD Instances", + "Error retrieving Argo CD instances": "Error retrieving Argo CD instances", + "No {{x}} found": "No {{x}} found", + "Create Argo CD instance": "Create Argo CD instance", + "Applications Needing Attention": "Applications Needing Attention", + "Application": "Aplicación", + "No {{x}} needing attention": "No {{x}} needing attention", + "{{x}}": "{{x}}", + "is not on the cluster (Missing).": "is not on the cluster (Missing).", + "is {{x}}.": "is {{x}}.", + " {{x}}.": " {{x}}.", + "The application's resources are all missing. Try syncing the application.": "The application's resources are all missing. Try syncing the application.", + "Operation: Sync": "Operation: Sync", + "Finished At: {{x}}": "Finished At: {{x}}", + "Message: {{x}}": "Message: {{x}}", + "Message: {{x}}.": "Message: {{x}}.", + "...and {{x}} more": "...and {{x}} more", + "Image Updaters": "Image Updaters", + "Error retrieving Image Updaters": "Error retrieving Image Updaters", + "View Image Updaters List Page": "View Image Updaters List Page", + "Create Image Updater": "Create Image Updater", + "GitOps Operator": "GitOps Operator", + "Error retrieving CSV for the GitOps Operator": "Error retrieving CSV for the GitOps Operator", + "Version: {{x}}": "Version: {{x}}", + "Display Name: {{x}}": "Display Name: {{x}}", + "Provider: {{x}}": "Provider: {{x}}", + "Namspace: {{x}}": "Namspace: {{x}}", + "Created At:": "Created At:", + "Not found": "Not found", + "The OpenShift GitOps Operator is not installed or not found for this namespace": "The OpenShift GitOps Operator is not installed or not found for this namespace", + "App Projects": "App Projects", + "Error retrieving App Projects": "Error retrieving App Projects", + "View AppProjects List Page": "View AppProjects List Page", + "Create AppProject": "Crear AppProject", + "Updated message(s) for the {{x}}:": "Updated message(s) for the {{x}}:", + "Rollout Managers": "Rollout Managers", + "Error retrieving Rollout Managers": "Error retrieving Rollout Managers", + "View Rollout Managers List Page": "View Rollout Managers List Page", + "Create Rollout Manager": "Create Rollout Manager", + "Rollouts": "Implementaciones", + "Error retrieving Rollouts": "Error retrieving Rollouts", + "View Rollouts List Page": "View Rollouts List Page", + "Create Rollout": "Crear implementación", + "Total:": "Total:", + "ns={{x}}": "ns={{x}}", "Error fetching metric data. Click to view metrics dashboard.": "Error fetching metric data. Click to view metrics dashboard.", "Operational metrics": "Operational metrics", - "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", + "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", "Successful syncs": "Successful syncs", "Number of successful syncs": "Number of successful syncs", "Failed syncs": "Failed syncs", - "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.": "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.", + "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.": "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.", "Orphaned resources": "Orphaned resources", "Number of orphaned resources": "Number of orphaned resources", "Apps with Autosync enabled": "Apps with Autosync enabled", @@ -188,15 +243,24 @@ "Number of repos in the queue": "Number of repos in the queue", "Git fetch failures": "Git fetch failures", "Number of git fetch failures": "Number of git fetch failures", + "Recent Operations": "Recent Operations", + "(Last {{x}} operations)": "(Last {{x}} operations)", + "No recent operations": "No recent operations", "Application Reconciliation Performance (24 hours)": "Application Reconciliation Performance (24 hours)", "Unable to retrieve metrics data": "Unable to retrieve metrics data", + "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.", "Application reconciliation performance over time": "Application reconciliation performance over time", "View in Observe/Metrics": "View in Observe/Metrics", "Syncs (24h sliding window)": "Syncs (24h sliding window)", "Synced": "Synced", "Out of Sync": "Out of Sync", "Application Sync Activity (24 hours)": "Application Sync Activity (24 hours)", + "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.", "Application sync activity over time": "Application sync activity over time", + "Application model does not exist": "Application model does not exist", + "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.": "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.", "Server": "Servidor", "Deny": "Denegar", "Allow": "Permitir", @@ -247,6 +311,7 @@ "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "Cuando está habilitada, las aplicaciones solo se pueden implementar en clústeres con alcance a este proyecto. Esto impide la implementación en clústeres que no forman parte del proyecto.", "Enabled": "Activado", "Disabled": "Desactivado", + "AppProject": "AppProject", "No Argo CD App Projects match the search filter": "No hay proyectos de aplicaciones de Argo CD que coincidan con el filtro de búsqueda", "Try removing the filter or searching for a different term to see more App Projects.": "Quite el filtro o busque un término diferente para ver más proyectos de aplicaciones.", "There are no Argo CD App Projects in this project.": "Non hay proyectos de aplicaciones de Argo CD en este proyecto.", @@ -255,7 +320,6 @@ "No Argo CD App Projects": "No hay proyectos de aplicaciones de Argo CD", "There was an error retrieving App Projects. Check your connection and reload the page.": "Se produjo un error al recuperar los proyectos de aplicaciones. Compruebe su conexión y vuelva a cargar la página.", "AppProjects": "AppProjects", - "Create AppProject": "Crear AppProject", "Last Updated": "Última actualización", "Has Description": "Tiene descripción", "No Description": "Sin descripción", @@ -326,12 +390,11 @@ "There is no rollout status. Check that the Rollout Manager is created and is available.": "No hay estado de la implementación. Verifique que se haya creado el administrador de implementación y esté disponible.", "Strategy": "Estrategia", "Whether the rollout is using a blue-green or canary strategy": "Indica si la implementación utiliza una estrategia blue-green o canary", + "Rollout": "Rollout", "No Argo Rollouts": "Sin implementaciones de Argo", "There are no Argo Rollouts in this project.": "No hay implementaciones de Argo en este proyecto.", "There are no Argo Rollouts in all projects.": "No hay implementaciones de Argo en todos los proyectos.", "There was an error retrieving rollouts. Check your connection and reload the page.": "Se produjo un error al recuperar las implementaciones. Compruebe su conexión y vuelva a cargar la página.", - "Rollouts": "Implementaciones", - "Create Rollout": "Crear implementación", "Pods": "Pods", "Selector": "Selector", "Rollout Status": "Estado de implementación", @@ -362,6 +425,7 @@ "ApplicationSet Applications": "Aplicaciones del ApplicationSet", "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "Las vistas de gráfico y tabla muestran las aplicaciones del ApplicationSet. Utilice el filtro para filtrar las aplicaciones según su estado general y de sincronización.", "Revision": "Revisión", + "ApplicationSet": "ApplicationSet", "No Argo CD ApplicationSets match the filter": "Ningún ApplicationSet de Argo CD coincide con el filtro", "Adjust the filter to see more ApplicationSets.": "Ajuste el filtro para ver más ApplicationSets.", "There are no Argo CD ApplicationSets in this project.": "Non hay ApplicationSets de Argo CD en este proyecto.", @@ -369,8 +433,6 @@ "No matching Argo CD ApplicationSets": "No hay ApplicationSets de Argo CD que coincidan", "No Argo CD ApplicationSets": "Sin ApplicationSets de Argo CD", "There was an error retrieving applicationsets. Check your connection and reload the page.": "Se produjo un error al recuperar los applicationsets. Compruebe su conexión y vuelva a cargar la página.", - "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "Crear ApplicationSet", "No labels": "Sin etiquetas", "Namespace defines the space within which each name must be unique.": "El espacio de nombre define el espacio dentro del cual cada nombre debe ser único.", "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Mapa de claves y valores de cadena que se pueden usar para organizar y categorizar (delimitar el alcance y seleccionar) objetos.", @@ -380,14 +442,15 @@ "Created at": "Creado en", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time es una envoltura de time. Tiempo que admite la serialización correcta a YAML y JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Las referencias del propietario vinculan este recurso con su objeto principal. Por ejemplo, las aplicaciones generadas por un ApplicationSet tendrán a ese ApplicationSet como propietario. Esta relación permite una gestión adecuada del ciclo de vida de los recursos y la recolección de basura.", + "Extra": "Extra", "Manage columns": "Administrar columnas", "Selected columns will appear in the table.": "Las columnas seleccionadas aparecerán en la tabla.", "The namespace column is only shown when in \"All projects\"": "La columna de espacio de nombres solo se muestra en \"Todos los proyectos\"", "Default {{resourceKind}} columns": "Columnas {{resourceKind}} predeterminadas", "Additional columns": "Columnas adicionales", - "Restore default columns": "Restaurar columnas predeterminadas", "Save": "Guardar", "Cancel": "Cancelar", + "Restore default columns": "Restaurar columnas predeterminadas", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", diff --git a/locales/fr/plugin__gitops-plugin.json b/locales/fr/plugin__gitops-plugin.json index 88fd5e83e..7fea1c85d 100644 --- a/locales/fr/plugin__gitops-plugin.json +++ b/locales/fr/plugin__gitops-plugin.json @@ -102,7 +102,6 @@ "Argo CD project that this ApplicationSet belongs to.": "Projet Argo CD auquel appartient cet ApplicationSet.", "Git repository URL where the ApplicationSet configuration is stored.": "URL du dépôt Git où est stockée la configuration ApplicationSet.", "Progressive Sync Step {{x}}": "Étape de synchronisation progressive {{x}}", - "Application": "Application", "Applications": "Applications", "Show all match expressions": "Afficher toutes les expressions de correspondance", "Edit ApplicationSet": "Modifier l'ensemble d'applications", @@ -133,6 +132,7 @@ "Observed Generation": "Génération observée", "The generation of the resource that was last reconciled.": "La génération de la ressource qui a été réconciliée en dernier lieu.", "Conditions": "Conditions", + "ImageUpdater": "ImageUpdater", "No ImageUpdaters match the search filter": "Aucun ImageUpdater ne correspond au filtre de recherche", "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Essayez de supprimer le filtre ou de rechercher un terme différent pour voir plus d'ImageUpdaters.", "There are no ImageUpdaters in this namespace.": "Il n'y a pas d'ImageUpdaters dans cet espace de noms.", @@ -162,6 +162,8 @@ "Updated At": "Mise à jour le", "No datapoints found.": "No datapoints found.", "Loading...": "Loading...", + "Application Overview": "Application Overview", + "Infrastructure": "Infrastructure", "GitOps Overview": "GitOps Overview", "Healthy": "Healthy", "Progressing": "Progressing", @@ -171,13 +173,66 @@ "Health status": "Health status", "Unable to retrieve applications": "Unable to retrieve applications", "Error retrieving applications: {{x}}": "Error retrieving applications: {{x}}", + "Error retrieving Applications": "Error retrieving Applications", + "View Applications List Page": "View Applications List Page", + "Create Application": "Create Application", + "ApplicationSets": "Ensembles d'applications", + "Error retrieving ApplicationSets": "Error retrieving ApplicationSets", + "View ApplicationSets List Page": "View ApplicationSets List Page", + "Create ApplicationSet": "Créer une application", + "All Namespaces": "All Namespaces", + "Argo CD Instances": "Argo CD Instances", + "Error retrieving Argo CD instances": "Error retrieving Argo CD instances", + "No {{x}} found": "No {{x}} found", + "Create Argo CD instance": "Create Argo CD instance", + "Applications Needing Attention": "Applications Needing Attention", + "Application": "Application", + "No {{x}} needing attention": "No {{x}} needing attention", + "{{x}}": "{{x}}", + "is not on the cluster (Missing).": "is not on the cluster (Missing).", + "is {{x}}.": "is {{x}}.", + " {{x}}.": " {{x}}.", + "The application's resources are all missing. Try syncing the application.": "The application's resources are all missing. Try syncing the application.", + "Operation: Sync": "Operation: Sync", + "Finished At: {{x}}": "Finished At: {{x}}", + "Message: {{x}}": "Message: {{x}}", + "Message: {{x}}.": "Message: {{x}}.", + "...and {{x}} more": "...and {{x}} more", + "Image Updaters": "Image Updaters", + "Error retrieving Image Updaters": "Error retrieving Image Updaters", + "View Image Updaters List Page": "View Image Updaters List Page", + "Create Image Updater": "Create Image Updater", + "GitOps Operator": "GitOps Operator", + "Error retrieving CSV for the GitOps Operator": "Error retrieving CSV for the GitOps Operator", + "Version: {{x}}": "Version: {{x}}", + "Display Name: {{x}}": "Display Name: {{x}}", + "Provider: {{x}}": "Provider: {{x}}", + "Namspace: {{x}}": "Namspace: {{x}}", + "Created At:": "Created At:", + "Not found": "Not found", + "The OpenShift GitOps Operator is not installed or not found for this namespace": "The OpenShift GitOps Operator is not installed or not found for this namespace", + "App Projects": "App Projects", + "Error retrieving App Projects": "Error retrieving App Projects", + "View AppProjects List Page": "View AppProjects List Page", + "Create AppProject": "Créer un projet d'application", + "Updated message(s) for the {{x}}:": "Updated message(s) for the {{x}}:", + "Rollout Managers": "Rollout Managers", + "Error retrieving Rollout Managers": "Error retrieving Rollout Managers", + "View Rollout Managers List Page": "View Rollout Managers List Page", + "Create Rollout Manager": "Create Rollout Manager", + "Rollouts": "Déploiements", + "Error retrieving Rollouts": "Error retrieving Rollouts", + "View Rollouts List Page": "View Rollouts List Page", + "Create Rollout": "Créer un déploiement", + "Total:": "Total:", + "ns={{x}}": "ns={{x}}", "Error fetching metric data. Click to view metrics dashboard.": "Error fetching metric data. Click to view metrics dashboard.", "Operational metrics": "Operational metrics", - "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", + "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", "Successful syncs": "Successful syncs", "Number of successful syncs": "Number of successful syncs", "Failed syncs": "Failed syncs", - "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.": "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.", + "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.": "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.", "Orphaned resources": "Orphaned resources", "Number of orphaned resources": "Number of orphaned resources", "Apps with Autosync enabled": "Apps with Autosync enabled", @@ -188,15 +243,24 @@ "Number of repos in the queue": "Number of repos in the queue", "Git fetch failures": "Git fetch failures", "Number of git fetch failures": "Number of git fetch failures", + "Recent Operations": "Recent Operations", + "(Last {{x}} operations)": "(Last {{x}} operations)", + "No recent operations": "No recent operations", "Application Reconciliation Performance (24 hours)": "Application Reconciliation Performance (24 hours)", "Unable to retrieve metrics data": "Unable to retrieve metrics data", + "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.", "Application reconciliation performance over time": "Application reconciliation performance over time", "View in Observe/Metrics": "View in Observe/Metrics", "Syncs (24h sliding window)": "Syncs (24h sliding window)", "Synced": "Synced", "Out of Sync": "Out of Sync", "Application Sync Activity (24 hours)": "Application Sync Activity (24 hours)", + "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.", "Application sync activity over time": "Application sync activity over time", + "Application model does not exist": "Application model does not exist", + "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.": "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.", "Server": "Serveur", "Deny": "Refuser", "Allow": "Autoriser", @@ -247,6 +311,7 @@ "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "Lorsqu'elle est activée, cette option permet uniquement de déployer des applications sur des clusters associés à ce projet. Cela empêche le déploiement sur des clusters qui ne font pas partie du projet.", "Enabled": "Activé", "Disabled": "Désactivé", + "AppProject": "AppProject", "No Argo CD App Projects match the search filter": "Aucun projet d'application Argo CD ne correspond au filtre de recherche", "Try removing the filter or searching for a different term to see more App Projects.": "Essayez de supprimer le filtre ou de rechercher un terme différent pour voir plus de projets d'applications.", "There are no Argo CD App Projects in this project.": "Ce projet ne contient aucun projet d'application Argo CD.", @@ -255,7 +320,6 @@ "No Argo CD App Projects": "Aucun projet d'application Argo CD", "There was an error retrieving App Projects. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des projets d'application. Vérifiez votre connexion et rechargez la page.", "AppProjects": "Projets d'application", - "Create AppProject": "Créer un projet d'application", "Last Updated": "Dernière mise à jour", "Has Description": "Contient une description", "No Description": "Aucune description", @@ -326,12 +390,11 @@ "There is no rollout status. Check that the Rollout Manager is created and is available.": "Aucun statut de déploiement n'est disponible. Vérifiez que le gestionnaire de déploiement est créé et disponible.", "Strategy": "Stratégie", "Whether the rollout is using a blue-green or canary strategy": "Que le déploiement utilise une stratégie bleu-vert ou canary", + "Rollout": "Rollout", "No Argo Rollouts": "Aucun déploiement d'Argo", "There are no Argo Rollouts in this project.": "Aucun déploiement Argo n'est prévu dans ce projet.", "There are no Argo Rollouts in all projects.": "Il n'y a pas de déploiement Argo dans tous les projets.", "There was an error retrieving rollouts. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des déploiements. Vérifiez votre connexion et rechargez la page.", - "Rollouts": "Déploiements", - "Create Rollout": "Créer un déploiement", "Pods": "Pods", "Selector": "Sélecteur", "Rollout Status": "État du déploiement", @@ -362,6 +425,7 @@ "ApplicationSet Applications": "Applications ApplicationSet", "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "Les vues graphique et tabulaire affichent les applications de l'ensemble d'applications. Utilisez le filtre pour trier les applications en fonction de leur état et de leur statut de synchronisation.", "Revision": "Révision", + "ApplicationSet": "ApplicationSet", "No Argo CD ApplicationSets match the filter": "Aucun ensemble d'applications Argo CD ne correspond au filtre", "Adjust the filter to see more ApplicationSets.": "Ajustez le filtre pour afficher plus d'ensembles d'applications.", "There are no Argo CD ApplicationSets in this project.": "Ce projet ne contient aucun ensemble d'applications Argo CD.", @@ -369,8 +433,6 @@ "No matching Argo CD ApplicationSets": "Aucun ensemble d'applications Argo CD correspondant", "No Argo CD ApplicationSets": "Aucun ensemble d'applications Argo CD", "There was an error retrieving applicationsets. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des ensembles d'applications. Vérifiez votre connexion et rechargez la page.", - "ApplicationSets": "Ensembles d'applications", - "Create ApplicationSet": "Créer une application", "No labels": "Aucune étiquette", "Namespace defines the space within which each name must be unique.": "L'espace de noms définit l'espace dans lequel chaque nom doit être unique.", "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Carte des clés et des valeurs de chaîne qui peuvent être utilisées pour organiser et catégoriser (portée et sélection) des objets.", @@ -380,14 +442,15 @@ "Created at": "Heure de création", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Le temps est un emballage autour du temps. Temps permettant une sérialisation correcte en YAML et JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Les références de propriétaire relient cette ressource à son objet parent. Par exemple, les applications générées par un ApplicationSet auront cet ApplicationSet comme propriétaire. Cette relation permet une gestion adéquate du cycle de vie des ressources et une collecte efficace des déchets.", + "Extra": "Extra", "Manage columns": "Gérer les colonnes", "Selected columns will appear in the table.": "Les colonnes sélectionnées apparaîtront dans le tableau.", "The namespace column is only shown when in \"All projects\"": "La colonne d’espace de noms n’est affichée que dans « Tous les projets ».", "Default {{resourceKind}} columns": "Colonnes {{resourceKind}} par défaut", "Additional columns": "Colonnes supplémentaires", - "Restore default columns": "Restaurer les colonnes par défaut", "Save": "Enregistrer", "Cancel": "Annuler", + "Restore default columns": "Restaurer les colonnes par défaut", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", diff --git a/locales/ja/plugin__gitops-plugin.json b/locales/ja/plugin__gitops-plugin.json index 00de8add6..8404b0ef5 100644 --- a/locales/ja/plugin__gitops-plugin.json +++ b/locales/ja/plugin__gitops-plugin.json @@ -102,7 +102,6 @@ "Argo CD project that this ApplicationSet belongs to.": "この ApplicationSet が属する Argo CD プロジェクト。", "Git repository URL where the ApplicationSet configuration is stored.": "ApplicationSet の設定が保存されている Git リポジトリーの URL。", "Progressive Sync Step {{x}}": "Progressive Sync ステップ {{x}}", - "Application": "アプリケーション", "Applications": "アプリケーション", "Show all match expressions": "すべてのマッチ式の表示", "Edit ApplicationSet": "ApplicationSet の編集", @@ -133,6 +132,7 @@ "Observed Generation": "確認済みの世代", "The generation of the resource that was last reconciled.": "最後にリコンサイルされたリソースの世代。", "Conditions": "状態", + "ImageUpdater": "ImageUpdater", "No ImageUpdaters match the search filter": "検索フィルターに一致する ImageUpdater はありません", "Try removing the filter or searching for a different term to see more ImageUpdaters.": "フィルターを解除するか、別の用語で検索して、より多くの ImageUpdater を表示します。", "There are no ImageUpdaters in this namespace.": "この namespace には ImageUpdater がありません。", @@ -162,6 +162,8 @@ "Updated At": "更新日時", "No datapoints found.": "No datapoints found.", "Loading...": "Loading...", + "Application Overview": "Application Overview", + "Infrastructure": "Infrastructure", "GitOps Overview": "GitOps Overview", "Healthy": "Healthy", "Progressing": "Progressing", @@ -171,13 +173,66 @@ "Health status": "Health status", "Unable to retrieve applications": "Unable to retrieve applications", "Error retrieving applications: {{x}}": "Error retrieving applications: {{x}}", + "Error retrieving Applications": "Error retrieving Applications", + "View Applications List Page": "View Applications List Page", + "Create Application": "Create Application", + "ApplicationSets": "ApplicationSets", + "Error retrieving ApplicationSets": "Error retrieving ApplicationSets", + "View ApplicationSets List Page": "View ApplicationSets List Page", + "Create ApplicationSet": "ApplicationSet の作成", + "All Namespaces": "All Namespaces", + "Argo CD Instances": "Argo CD Instances", + "Error retrieving Argo CD instances": "Error retrieving Argo CD instances", + "No {{x}} found": "No {{x}} found", + "Create Argo CD instance": "Create Argo CD instance", + "Applications Needing Attention": "Applications Needing Attention", + "Application": "アプリケーション", + "No {{x}} needing attention": "No {{x}} needing attention", + "{{x}}": "{{x}}", + "is not on the cluster (Missing).": "is not on the cluster (Missing).", + "is {{x}}.": "is {{x}}.", + " {{x}}.": " {{x}}.", + "The application's resources are all missing. Try syncing the application.": "The application's resources are all missing. Try syncing the application.", + "Operation: Sync": "Operation: Sync", + "Finished At: {{x}}": "Finished At: {{x}}", + "Message: {{x}}": "Message: {{x}}", + "Message: {{x}}.": "Message: {{x}}.", + "...and {{x}} more": "...and {{x}} more", + "Image Updaters": "Image Updaters", + "Error retrieving Image Updaters": "Error retrieving Image Updaters", + "View Image Updaters List Page": "View Image Updaters List Page", + "Create Image Updater": "Create Image Updater", + "GitOps Operator": "GitOps Operator", + "Error retrieving CSV for the GitOps Operator": "Error retrieving CSV for the GitOps Operator", + "Version: {{x}}": "Version: {{x}}", + "Display Name: {{x}}": "Display Name: {{x}}", + "Provider: {{x}}": "Provider: {{x}}", + "Namspace: {{x}}": "Namspace: {{x}}", + "Created At:": "Created At:", + "Not found": "Not found", + "The OpenShift GitOps Operator is not installed or not found for this namespace": "The OpenShift GitOps Operator is not installed or not found for this namespace", + "App Projects": "App Projects", + "Error retrieving App Projects": "Error retrieving App Projects", + "View AppProjects List Page": "View AppProjects List Page", + "Create AppProject": "AppProject の作成", + "Updated message(s) for the {{x}}:": "Updated message(s) for the {{x}}:", + "Rollout Managers": "Rollout Managers", + "Error retrieving Rollout Managers": "Error retrieving Rollout Managers", + "View Rollout Managers List Page": "View Rollout Managers List Page", + "Create Rollout Manager": "Create Rollout Manager", + "Rollouts": "ロールアウト", + "Error retrieving Rollouts": "Error retrieving Rollouts", + "View Rollouts List Page": "View Rollouts List Page", + "Create Rollout": "ロールアウトの作成", + "Total:": "Total:", + "ns={{x}}": "ns={{x}}", "Error fetching metric data. Click to view metrics dashboard.": "Error fetching metric data. Click to view metrics dashboard.", "Operational metrics": "Operational metrics", - "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", + "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", "Successful syncs": "Successful syncs", "Number of successful syncs": "Number of successful syncs", "Failed syncs": "Failed syncs", - "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.": "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.", + "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.": "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.", "Orphaned resources": "Orphaned resources", "Number of orphaned resources": "Number of orphaned resources", "Apps with Autosync enabled": "Apps with Autosync enabled", @@ -188,15 +243,24 @@ "Number of repos in the queue": "Number of repos in the queue", "Git fetch failures": "Git fetch failures", "Number of git fetch failures": "Number of git fetch failures", + "Recent Operations": "Recent Operations", + "(Last {{x}} operations)": "(Last {{x}} operations)", + "No recent operations": "No recent operations", "Application Reconciliation Performance (24 hours)": "Application Reconciliation Performance (24 hours)", "Unable to retrieve metrics data": "Unable to retrieve metrics data", + "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.", "Application reconciliation performance over time": "Application reconciliation performance over time", "View in Observe/Metrics": "View in Observe/Metrics", "Syncs (24h sliding window)": "Syncs (24h sliding window)", "Synced": "Synced", "Out of Sync": "Out of Sync", "Application Sync Activity (24 hours)": "Application Sync Activity (24 hours)", + "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.", "Application sync activity over time": "Application sync activity over time", + "Application model does not exist": "Application model does not exist", + "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.": "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.", "Server": "サーバー", "Deny": "拒否", "Allow": "許可", @@ -247,6 +311,7 @@ "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "有効にすると、アプリケーションはこのプロジェクト範囲のクラスターにのみデプロイできます。これにより、プロジェクトに含まれていないクラスターへのデプロイが防止されます。", "Enabled": "有効", "Disabled": "無効", + "AppProject": "AppProject", "No Argo CD App Projects match the search filter": "検索フィルターに一致する Argo CD App Projects はありません。", "Try removing the filter or searching for a different term to see more App Projects.": "フィルターを解除するか、別のキーワードで検索して、より多くの App Projects を表示します。", "There are no Argo CD App Projects in this project.": "このプロジェクトには、Argo CD App Projects は含まれていません。", @@ -255,7 +320,6 @@ "No Argo CD App Projects": "Argo CD App Projects はありません", "There was an error retrieving App Projects. Check your connection and reload the page.": "App Projects の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", "AppProjects": "AppProjects", - "Create AppProject": "AppProject の作成", "Last Updated": "最終更新", "Has Description": "説明あり", "No Description": "説明なし", @@ -326,12 +390,11 @@ "There is no rollout status. Check that the Rollout Manager is created and is available.": "ロールアウトのステータスは不明です。Rollout Manager が作成され、利用可能であることを確認します。", "Strategy": "ストラテジー", "Whether the rollout is using a blue-green or canary strategy": "ロールアウトにブルーグリーン戦略またはカナリアストラテジーが使用されているかどうか", + "Rollout": "Rollout", "No Argo Rollouts": "Argo Rollouts はありません", "There are no Argo Rollouts in this project.": "このプロジェクトには Argo Rollouts はありません。", "There are no Argo Rollouts in all projects.": "すべてのプロジェクトに Argo Rollouts があるわけではありません。", "There was an error retrieving rollouts. Check your connection and reload the page.": "ロールアウトの取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", - "Rollouts": "ロールアウト", - "Create Rollout": "ロールアウトの作成", "Pods": "Pod", "Selector": "セレクター", "Rollout Status": "ロールアウトのステータス", @@ -362,6 +425,7 @@ "ApplicationSet Applications": "ApplicationSet アプリケーション", "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "グラフビューと表ビューには、ApplicationSet に含まれるアプリケーションが表示されます。フィルターを使用して、アプリケーションをその健全性や同期ステータスに基づいて絞り込むことができます。", "Revision": "リビジョン", + "ApplicationSet": "ApplicationSet", "No Argo CD ApplicationSets match the filter": "フィルターに一致する Argo CD ApplicationSets はありません", "Adjust the filter to see more ApplicationSets.": "フィルターを調整して、より多くの ApplicationSets を表示します。", "There are no Argo CD ApplicationSets in this project.": "このプロジェクトには Argo CD ApplicationSets は存在しません。", @@ -369,8 +433,6 @@ "No matching Argo CD ApplicationSets": "一致する Argo CD ApplicationSets はありません", "No Argo CD ApplicationSets": "Argo CD ApplicationSets なし", "There was an error retrieving applicationsets. Check your connection and reload the page.": "applicationsets の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", - "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "ApplicationSet の作成", "No labels": "ラベルがありません", "Namespace defines the space within which each name must be unique.": "namespace は、各名前が一意である必要がある空間を定義します。", "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "オブジェクトを整理および分類 (スコープ指定および選択) するために使用できる文字列のキー値のマップ", @@ -380,14 +442,15 @@ "Created at": "作成日時", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time は time のラッパーです。YAML と JSON への正しいマーシャリングをサポートする時間。", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "オーナーリファレンスは、このリソースをその親オブジェクトにリンクします。たとえば、ApplicationSet によって生成されたアプリケーションは、その ApplicationSet を所有者として持つことになります。この関係により、適切なリソースライフサイクル管理とガベージコレクションが可能になります。", + "Extra": "Extra", "Manage columns": "列の管理", "Selected columns will appear in the table.": "選択した列がテーブルに表示されます。", "The namespace column is only shown when in \"All projects\"": "namespace 列は \"すべてのプロジェクト\" の場合にのみ表示されます", "Default {{resourceKind}} columns": "デフォルトの {{resourceKind}} 列", "Additional columns": "追加の列", - "Restore default columns": "デフォルト列の復元", "Save": "保存", "Cancel": "キャンセル", + "Restore default columns": "デフォルト列の復元", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", diff --git a/locales/ko/plugin__gitops-plugin.json b/locales/ko/plugin__gitops-plugin.json index 4ff93779b..600fb2ba2 100644 --- a/locales/ko/plugin__gitops-plugin.json +++ b/locales/ko/plugin__gitops-plugin.json @@ -102,7 +102,6 @@ "Argo CD project that this ApplicationSet belongs to.": "이 ApplicationSet이 속한 Argo CD 프로젝트입니다.", "Git repository URL where the ApplicationSet configuration is stored.": "ApplicationSet 구성이 저장되는 Git 리포지토리 URL입니다.", "Progressive Sync Step {{x}}": "점진적 동기화 단계 {{x}}", - "Application": "애플리케이션", "Applications": "애플리케이션", "Show all match expressions": "모든 일치 표현식 표시", "Edit ApplicationSet": "ApplicationSet 편집", @@ -133,6 +132,7 @@ "Observed Generation": "관찰된 생성 버전", "The generation of the resource that was last reconciled.": "마지막으로 조정된 리소스의 생성 버전입니다.", "Conditions": "조건", + "ImageUpdater": "ImageUpdater", "No ImageUpdaters match the search filter": "검색 필터와 일치하는 ImageUpdater가 없음", "Try removing the filter or searching for a different term to see more ImageUpdaters.": "더 많은 ImageUpdaters를 보려면 필터를 제거하거나 다른 용어를 검색하십시오.", "There are no ImageUpdaters in this namespace.": "이 네임스페이스에는 ImageUpdaters가 없습니다.", @@ -162,6 +162,8 @@ "Updated At": "업데이트 시간", "No datapoints found.": "No datapoints found.", "Loading...": "Loading...", + "Application Overview": "Application Overview", + "Infrastructure": "Infrastructure", "GitOps Overview": "GitOps Overview", "Healthy": "Healthy", "Progressing": "Progressing", @@ -171,13 +173,66 @@ "Health status": "Health status", "Unable to retrieve applications": "Unable to retrieve applications", "Error retrieving applications: {{x}}": "Error retrieving applications: {{x}}", + "Error retrieving Applications": "Error retrieving Applications", + "View Applications List Page": "View Applications List Page", + "Create Application": "Create Application", + "ApplicationSets": "ApplicationSets", + "Error retrieving ApplicationSets": "Error retrieving ApplicationSets", + "View ApplicationSets List Page": "View ApplicationSets List Page", + "Create ApplicationSet": "ApplicationSet 만들기", + "All Namespaces": "All Namespaces", + "Argo CD Instances": "Argo CD Instances", + "Error retrieving Argo CD instances": "Error retrieving Argo CD instances", + "No {{x}} found": "No {{x}} found", + "Create Argo CD instance": "Create Argo CD instance", + "Applications Needing Attention": "Applications Needing Attention", + "Application": "애플리케이션", + "No {{x}} needing attention": "No {{x}} needing attention", + "{{x}}": "{{x}}", + "is not on the cluster (Missing).": "is not on the cluster (Missing).", + "is {{x}}.": "is {{x}}.", + " {{x}}.": " {{x}}.", + "The application's resources are all missing. Try syncing the application.": "The application's resources are all missing. Try syncing the application.", + "Operation: Sync": "Operation: Sync", + "Finished At: {{x}}": "Finished At: {{x}}", + "Message: {{x}}": "Message: {{x}}", + "Message: {{x}}.": "Message: {{x}}.", + "...and {{x}} more": "...and {{x}} more", + "Image Updaters": "Image Updaters", + "Error retrieving Image Updaters": "Error retrieving Image Updaters", + "View Image Updaters List Page": "View Image Updaters List Page", + "Create Image Updater": "Create Image Updater", + "GitOps Operator": "GitOps Operator", + "Error retrieving CSV for the GitOps Operator": "Error retrieving CSV for the GitOps Operator", + "Version: {{x}}": "Version: {{x}}", + "Display Name: {{x}}": "Display Name: {{x}}", + "Provider: {{x}}": "Provider: {{x}}", + "Namspace: {{x}}": "Namspace: {{x}}", + "Created At:": "Created At:", + "Not found": "Not found", + "The OpenShift GitOps Operator is not installed or not found for this namespace": "The OpenShift GitOps Operator is not installed or not found for this namespace", + "App Projects": "App Projects", + "Error retrieving App Projects": "Error retrieving App Projects", + "View AppProjects List Page": "View AppProjects List Page", + "Create AppProject": "AppProject 생성", + "Updated message(s) for the {{x}}:": "Updated message(s) for the {{x}}:", + "Rollout Managers": "Rollout Managers", + "Error retrieving Rollout Managers": "Error retrieving Rollout Managers", + "View Rollout Managers List Page": "View Rollout Managers List Page", + "Create Rollout Manager": "Create Rollout Manager", + "Rollouts": "롤아웃", + "Error retrieving Rollouts": "Error retrieving Rollouts", + "View Rollouts List Page": "View Rollouts List Page", + "Create Rollout": "롤아웃 생성", + "Total:": "Total:", + "ns={{x}}": "ns={{x}}", "Error fetching metric data. Click to view metrics dashboard.": "Error fetching metric data. Click to view metrics dashboard.", "Operational metrics": "Operational metrics", - "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", + "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", "Successful syncs": "Successful syncs", "Number of successful syncs": "Number of successful syncs", "Failed syncs": "Failed syncs", - "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.": "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.", + "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.": "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.", "Orphaned resources": "Orphaned resources", "Number of orphaned resources": "Number of orphaned resources", "Apps with Autosync enabled": "Apps with Autosync enabled", @@ -188,15 +243,24 @@ "Number of repos in the queue": "Number of repos in the queue", "Git fetch failures": "Git fetch failures", "Number of git fetch failures": "Number of git fetch failures", + "Recent Operations": "Recent Operations", + "(Last {{x}} operations)": "(Last {{x}} operations)", + "No recent operations": "No recent operations", "Application Reconciliation Performance (24 hours)": "Application Reconciliation Performance (24 hours)", "Unable to retrieve metrics data": "Unable to retrieve metrics data", + "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.", "Application reconciliation performance over time": "Application reconciliation performance over time", "View in Observe/Metrics": "View in Observe/Metrics", "Syncs (24h sliding window)": "Syncs (24h sliding window)", "Synced": "Synced", "Out of Sync": "Out of Sync", "Application Sync Activity (24 hours)": "Application Sync Activity (24 hours)", + "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.", "Application sync activity over time": "Application sync activity over time", + "Application model does not exist": "Application model does not exist", + "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.": "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.", "Server": "서버", "Deny": "거부", "Allow": "허용", @@ -247,6 +311,7 @@ "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "이 옵션을 활성화하면 애플리케이션을 이 프로젝트로 범위가 지정된 클러스터에만 배포할 수 있습니다. 이렇게 하면 프로젝트에 포함되지 않은 클러스터에 배포하는 것을 방지합니다.", "Enabled": "활성화됨", "Disabled": "비활성화됨", + "AppProject": "AppProject", "No Argo CD App Projects match the search filter": "검색 필터와 일치하는 Argo CD AppProject가 없음", "Try removing the filter or searching for a different term to see more App Projects.": "더 많은 AppProject를 확인하려면 필터를 제거하거나 다른 용어로 검색해 보십시오.", "There are no Argo CD App Projects in this project.": "이 프로젝트에 Argo CD AppProject가 없습니다.", @@ -255,7 +320,6 @@ "No Argo CD App Projects": "Argo CD AppProject가 없음", "There was an error retrieving App Projects. Check your connection and reload the page.": "AppProject를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", "AppProjects": "AppProjects", - "Create AppProject": "AppProject 생성", "Last Updated": "마지막 업데이트 시간", "Has Description": "설명 있음", "No Description": "설명 없음", @@ -326,12 +390,11 @@ "There is no rollout status. Check that the Rollout Manager is created and is available.": "롤아웃 상태가 없습니다. Rollout Manager가 생성되고 사용 가능한 상태인지 확인합니다.", "Strategy": "전략", "Whether the rollout is using a blue-green or canary strategy": "롤아웃이 Blue-Green 또는 Canary 전략을 사용하고 있는지 여부", + "Rollout": "Rollout", "No Argo Rollouts": "Argo Rollouts 없음", "There are no Argo Rollouts in this project.": "이 프로젝트에는 Argo Rollouts이 없습니다.", "There are no Argo Rollouts in all projects.": "모든 프로젝트에 Argo Rollouts이 없습니다.", "There was an error retrieving rollouts. Check your connection and reload the page.": "롤아웃을 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", - "Rollouts": "롤아웃", - "Create Rollout": "롤아웃 생성", "Pods": "Pod", "Selector": "선택기", "Rollout Status": "롤아웃 상태", @@ -362,6 +425,7 @@ "ApplicationSet Applications": "ApplicationSet 애플리케이션", "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "그래프 및 테이블 보기에는 ApplicationSet의 애플리케이션이 표시됩니다. 필터를 사용하여 상태 및 동기화 상태에 따라 애플리케이션을 필터링합니다.", "Revision": "개정 버전", + "ApplicationSet": "ApplicationSet", "No Argo CD ApplicationSets match the filter": "필터와 일치하는 Argo CD ApplicationSet이 없음", "Adjust the filter to see more ApplicationSets.": "더 많은 ApplicationSet을 확인하려면 필터를 조정합니다.", "There are no Argo CD ApplicationSets in this project.": "이 프로젝트에 Argo CD ApplicationSets가 없습니다.", @@ -369,8 +433,6 @@ "No matching Argo CD ApplicationSets": "일치하는 Argo CD ApplicationSets 없음", "No Argo CD ApplicationSets": "Argo CD ApplicationSets 없음", "There was an error retrieving applicationsets. Check your connection and reload the page.": "applicationsets를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", - "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "ApplicationSet 만들기", "No labels": "레이블 없음", "Namespace defines the space within which each name must be unique.": "네임 스페이스는 각 이름을 고유해야 하는 공간을 정의합니다.", "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "객체를 구성하고 분류(범위 지정 및 선택)하는 데 사용할 수 있는 문자열 키와 값의 맵입니다.", @@ -380,14 +442,15 @@ "Created at": "생성 시간", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time은 시간을 나타내는 래퍼입니다. Time 타입은 올바른 YAML 및 JSON 마샬링을 지원합니다.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "소유자 참조는 이 리소스를 상위 객체에 연결합니다. 예를 들어 ApplicationSet에서 생성된 애플리케이션은 해당 ApplicationSet이 소유자로 지정됩니다. 이 관계를 통해 적절한 리소스 라이프사이클 관리 및 가비지 컬렉션이 가능합니다.", + "Extra": "Extra", "Manage columns": "열 관리", "Selected columns will appear in the table.": "선택한 열이 테이블에 표시됩니다.", "The namespace column is only shown when in \"All projects\"": "네임 스페이스 열은 \"All projects\"에 있을 때만 표시됩니다.", "Default {{resourceKind}} columns": "기본 {{resourceKind}} 열", "Additional columns": "추가 열", - "Restore default columns": "기본 열 복원", "Save": "저장", "Cancel": "취소", + "Restore default columns": "기본 열 복원", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", diff --git a/locales/zh/plugin__gitops-plugin.json b/locales/zh/plugin__gitops-plugin.json index 0c853a4ef..1ff386563 100644 --- a/locales/zh/plugin__gitops-plugin.json +++ b/locales/zh/plugin__gitops-plugin.json @@ -102,7 +102,6 @@ "Argo CD project that this ApplicationSet belongs to.": "此 ApplicationSet 所属的 Argo CD 项目。", "Git repository URL where the ApplicationSet configuration is stored.": "存储 ApplicationSet 配置的 Git 存储库 URL。", "Progressive Sync Step {{x}}": "渐进式同步步骤 {{x}}", - "Application": "应用程序", "Applications": "应用程序", "Show all match expressions": "显示所有匹配表达式", "Edit ApplicationSet": "编辑 ApplicationSet", @@ -133,6 +132,7 @@ "Observed Generation": "已观测的版本号", "The generation of the resource that was last reconciled.": "上次协调的资源版本号。", "Conditions": "条件", + "ImageUpdater": "ImageUpdater", "No ImageUpdaters match the search filter": "没有与搜索过滤器匹配的 ImageUpdaters", "Try removing the filter or searching for a different term to see more ImageUpdaters.": "移除筛选条件或搜索其他关键词,以查看更多 ImageUpdaters。", "There are no ImageUpdaters in this namespace.": "这个命名空间中没有 ImageUpdaters。", @@ -162,6 +162,8 @@ "Updated At": "更新时间", "No datapoints found.": "No datapoints found.", "Loading...": "Loading...", + "Application Overview": "Application Overview", + "Infrastructure": "Infrastructure", "GitOps Overview": "GitOps Overview", "Healthy": "Healthy", "Progressing": "Progressing", @@ -171,13 +173,66 @@ "Health status": "Health status", "Unable to retrieve applications": "Unable to retrieve applications", "Error retrieving applications: {{x}}": "Error retrieving applications: {{x}}", + "Error retrieving Applications": "Error retrieving Applications", + "View Applications List Page": "View Applications List Page", + "Create Application": "Create Application", + "ApplicationSets": "ApplicationSets", + "Error retrieving ApplicationSets": "Error retrieving ApplicationSets", + "View ApplicationSets List Page": "View ApplicationSets List Page", + "Create ApplicationSet": "创建 ApplicationSet", + "All Namespaces": "All Namespaces", + "Argo CD Instances": "Argo CD Instances", + "Error retrieving Argo CD instances": "Error retrieving Argo CD instances", + "No {{x}} found": "No {{x}} found", + "Create Argo CD instance": "Create Argo CD instance", + "Applications Needing Attention": "Applications Needing Attention", + "Application": "应用程序", + "No {{x}} needing attention": "No {{x}} needing attention", + "{{x}}": "{{x}}", + "is not on the cluster (Missing).": "is not on the cluster (Missing).", + "is {{x}}.": "is {{x}}.", + " {{x}}.": " {{x}}.", + "The application's resources are all missing. Try syncing the application.": "The application's resources are all missing. Try syncing the application.", + "Operation: Sync": "Operation: Sync", + "Finished At: {{x}}": "Finished At: {{x}}", + "Message: {{x}}": "Message: {{x}}", + "Message: {{x}}.": "Message: {{x}}.", + "...and {{x}} more": "...and {{x}} more", + "Image Updaters": "Image Updaters", + "Error retrieving Image Updaters": "Error retrieving Image Updaters", + "View Image Updaters List Page": "View Image Updaters List Page", + "Create Image Updater": "Create Image Updater", + "GitOps Operator": "GitOps Operator", + "Error retrieving CSV for the GitOps Operator": "Error retrieving CSV for the GitOps Operator", + "Version: {{x}}": "Version: {{x}}", + "Display Name: {{x}}": "Display Name: {{x}}", + "Provider: {{x}}": "Provider: {{x}}", + "Namspace: {{x}}": "Namspace: {{x}}", + "Created At:": "Created At:", + "Not found": "Not found", + "The OpenShift GitOps Operator is not installed or not found for this namespace": "The OpenShift GitOps Operator is not installed or not found for this namespace", + "App Projects": "App Projects", + "Error retrieving App Projects": "Error retrieving App Projects", + "View AppProjects List Page": "View AppProjects List Page", + "Create AppProject": "创建 AppProject", + "Updated message(s) for the {{x}}:": "Updated message(s) for the {{x}}:", + "Rollout Managers": "Rollout Managers", + "Error retrieving Rollout Managers": "Error retrieving Rollout Managers", + "View Rollout Managers List Page": "View Rollout Managers List Page", + "Create Rollout Manager": "Create Rollout Manager", + "Rollouts": "Rollouts", + "Error retrieving Rollouts": "Error retrieving Rollouts", + "View Rollouts List Page": "View Rollouts List Page", + "Create Rollout": "创建 Rollout", + "Total:": "Total:", + "ns={{x}}": "ns={{x}}", "Error fetching metric data. Click to view metrics dashboard.": "Error fetching metric data. Click to view metrics dashboard.", "Operational metrics": "Operational metrics", - "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", + "Last update time. Updated every 10 seconds.": "Last update time. Updated every 10 seconds.", "Successful syncs": "Successful syncs", "Number of successful syncs": "Number of successful syncs", "Failed syncs": "Failed syncs", - "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.": "Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.", + "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.": "Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.", "Orphaned resources": "Orphaned resources", "Number of orphaned resources": "Number of orphaned resources", "Apps with Autosync enabled": "Apps with Autosync enabled", @@ -188,15 +243,24 @@ "Number of repos in the queue": "Number of repos in the queue", "Git fetch failures": "Git fetch failures", "Number of git fetch failures": "Number of git fetch failures", + "Recent Operations": "Recent Operations", + "(Last {{x}} operations)": "(Last {{x}} operations)", + "No recent operations": "No recent operations", "Application Reconciliation Performance (24 hours)": "Application Reconciliation Performance (24 hours)", "Unable to retrieve metrics data": "Unable to retrieve metrics data", + "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the Argo CD reconciliation performance. Check that the cluster metrics monitoring is enabled.", "Application reconciliation performance over time": "Application reconciliation performance over time", "View in Observe/Metrics": "View in Observe/Metrics", "Syncs (24h sliding window)": "Syncs (24h sliding window)", "Synced": "Synced", "Out of Sync": "Out of Sync", "Application Sync Activity (24 hours)": "Application Sync Activity (24 hours)", + "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Syncs performed. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of Synced apps. Check that the cluster metrics monitoring is enabled.", + "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.": "Cannot retrieve data for the number of OutOfSync apps. Check that the cluster metrics monitoring is enabled.", "Application sync activity over time": "Application sync activity over time", + "Application model does not exist": "Application model does not exist", + "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.": "The Argo CD Application CRD does not exist. Check that the GitOps Operator is installed.", "Server": "服务器", "Deny": "拒绝", "Allow": "允许", @@ -247,6 +311,7 @@ "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "启用后,应用程序只能部署到此项目范围内的集群。这可以防止部署到不属于此项目的集群。", "Enabled": "已启用", "Disabled": "禁用", + "AppProject": "AppProject", "No Argo CD App Projects match the search filter": "没有符合搜索筛选条件的 Argo CD 项目", "Try removing the filter or searching for a different term to see more App Projects.": "尝试移除筛选条件或搜索其他词,以查看更多 App 项目。", "There are no Argo CD App Projects in this project.": "此项目中没有 Argo CD App 项目。", @@ -255,7 +320,6 @@ "No Argo CD App Projects": "没有 Argo CD 应用程序项目", "There was an error retrieving App Projects. Check your connection and reload the page.": "获取 App 项目时出错。检查您的连接并重新载入页面。", "AppProjects": "AppProjects", - "Create AppProject": "创建 AppProject", "Last Updated": "最后更新", "Has Description": "具有描述", "No Description": "没有描述", @@ -326,12 +390,11 @@ "There is no rollout status. Check that the Rollout Manager is created and is available.": "没有 rollout 状态。检查 Rollout Manager 是否已创建并可用。", "Strategy": "策略", "Whether the rollout is using a blue-green or canary strategy": "Rollout 是否使用 Blue-Green 还是 Canary 策略", + "Rollout": "Rollout", "No Argo Rollouts": "没有 Argo Rollouts", "There are no Argo Rollouts in this project.": "此项目中没有 Argo Rollouts。", "There are no Argo Rollouts in all projects.": "所有项目中都没有 Argo Rollouts。", "There was an error retrieving rollouts. Check your connection and reload the page.": "获取 Rollout 时出错。检查您的连接并重新载入页面。", - "Rollouts": "Rollouts", - "Create Rollout": "创建 Rollout", "Pods": "Pod", "Selector": "选择器", "Rollout Status": "Rollout 状态", @@ -362,6 +425,7 @@ "ApplicationSet Applications": "ApplicationSet 应用程序", "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "图形和表视图显示 ApplicationSet 的应用程序。使用筛选条件,根据应用的健康状态和同步状态进行筛选。", "Revision": "版本", + "ApplicationSet": "ApplicationSet", "No Argo CD ApplicationSets match the filter": "没有符合筛选条件的 Argo CD ApplicationSet", "Adjust the filter to see more ApplicationSets.": "调整筛选条件以查看更多 ApplicationSet。", "There are no Argo CD ApplicationSets in this project.": "此项目中没有 Argo CD ApplicationSets。", @@ -369,8 +433,6 @@ "No matching Argo CD ApplicationSets": "没有匹配的 Argo CD ApplicationSet", "No Argo CD ApplicationSets": "没有 Argo CD ApplicationSets", "There was an error retrieving applicationsets. Check your connection and reload the page.": "获取应用程序时出错。检查您的连接并重新载入页面。", - "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "创建 ApplicationSet", "No labels": "没有标签", "Namespace defines the space within which each name must be unique.": "命名空间定义了一个空间,其中的每个名称必须是唯一的。", "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "用于组织和分类(范围和选择)对象的字符串键和值映射。", @@ -380,14 +442,15 @@ "Created at": "创建于", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time 是对 time 的封装。支持正确进行 YAML 和 JSON 编组的 Time 类型。", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "所有者引用将此资源关联到其父对象。例如,一个 ApplicationSet 生成的应用程序会将 ApplicationSet 作为所有者。这种关联关系可实现正确的资源生命周期管理和垃圾回收。", + "Extra": "Extra", "Manage columns": "管理列", "Selected columns will appear in the table.": "选定的列将出现在表中。", "The namespace column is only shown when in \"All projects\"": "仅在“所有项目”中显示名称空间列", "Default {{resourceKind}} columns": "默认 {{resourceKind}} 列", "Additional columns": "额外列", - "Restore default columns": "恢复默认列", "Save": "保存", "Cancel": "取消", + "Restore default columns": "恢复默认列", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", diff --git a/src/gitops/Statuses/HealthStatus.test.tsx b/src/gitops/Statuses/HealthStatus.test.tsx index 506276763..0f8358e02 100644 --- a/src/gitops/Statuses/HealthStatus.test.tsx +++ b/src/gitops/Statuses/HealthStatus.test.tsx @@ -1,46 +1,47 @@ import { renderToStaticMarkup } from 'react-dom/server'; + import HealthStatus, { HealthStatusIcon } from './HealthStatus'; describe('HealthStatus', () => { it('renders Healthy', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
Healthy
"`, + `"
Healthy
"`, ); }); it('renders Degraded', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
Degraded
"`, + `"
Degraded
"`, ); }); it('renders Progressing', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
Progressing
"`, + `"
Progressing
"`, ); }); it('renders Suspended', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
Suspended
"`, + `"
Suspended
"`, ); }); it('renders Missing', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
Missing
"`, + `"
Missing
"`, ); }); it('renders Unknown for unrecognized status', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
SomethingElse
"`, + `"
SomethingElse
"`, ); }); it('renders Unknown for undefined status', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
"`, + `"
"`, ); }); diff --git a/src/gitops/Statuses/HealthStatus.tsx b/src/gitops/Statuses/HealthStatus.tsx index 4ed713b87..0bb88ccdd 100644 --- a/src/gitops/Statuses/HealthStatus.tsx +++ b/src/gitops/Statuses/HealthStatus.tsx @@ -57,7 +57,7 @@ const HealthStatus: React.FC = ({ status, message }) => { ); } else { showStatus = ( -
+
{targetIcon} {status}
); diff --git a/src/gitops/Statuses/SyncStatus.test.tsx b/src/gitops/Statuses/SyncStatus.test.tsx index d26f65b46..64d33caf2 100644 --- a/src/gitops/Statuses/SyncStatus.test.tsx +++ b/src/gitops/Statuses/SyncStatus.test.tsx @@ -1,34 +1,35 @@ import { renderToStaticMarkup } from 'react-dom/server'; + import SyncStatus from './SyncStatus'; describe('SyncStatus', () => { it('renders Synced', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `" Synced"`, + `" Synced"`, ); }); it('renders OutOfSync', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `" OutOfSync"`, + `" OutOfSync"`, ); }); it('renders Unknown', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `" Unknown"`, + `" Unknown"`, ); }); it('renders empty status', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `" "`, + `" "`, ); }); it('renders Unknown icon for undefined status', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `" "`, + `" "`, ); }); }); diff --git a/src/gitops/Statuses/SyncStatus.tsx b/src/gitops/Statuses/SyncStatus.tsx index 8e5901cb3..298c969b9 100644 --- a/src/gitops/Statuses/SyncStatus.tsx +++ b/src/gitops/Statuses/SyncStatus.tsx @@ -18,7 +18,7 @@ const SyncStatus: React.FC = ({ status }) => { targetIcon = ; } return ( - + {status ? targetIcon : ''} {status} ); diff --git a/src/gitops/components/overview/DashboardOverviewPage.scss b/src/gitops/components/overview/DashboardOverviewPage.scss index a6dd1f014..938e06107 100644 --- a/src/gitops/components/overview/DashboardOverviewPage.scss +++ b/src/gitops/components/overview/DashboardOverviewPage.scss @@ -15,6 +15,8 @@ width: 270px; overflow: hidden; flex-shrink: 0; + margin-top: 0px; + padding-top: 0px; } .gitops-dashboard__donut-card-body { @@ -22,6 +24,28 @@ align-items: center; justify-content: center; height: 100%; + overflow-y: hidden; +} + +.gitops-dashboard__fixed-height-application-firstrow-card { + @media (min-width: 768px) { + height: 300px; + } +} + +.gitops-dashboard__operational-metrics-card-body { + // height: 100%; + min-height: 0; + overflow-y: auto; +} + +.gitops-dashboard__operational-metrics-card { + @media (min-width: 768px) { + height: 300px; + } + overflow: visible; + min-height: 0; + overflow-y: auto; } .gitops-dashboard__fixed-height-row-card { @@ -29,6 +53,67 @@ height: 350px; } } + +.gitops-dashboard-overview-page { + display: flex; + flex-direction: column; + height: 100%; + max-height: 100%; + + // overflow: visible; + &__content { + display: flex; + // flex: 1; + flex-direction: column; + position: relative; + overflow: auto; + } +} + +// PatternFly's `.pf-v6-c-card` sets `overflow: auto` unconditionally on the whole card (title + +// body together). Once we give the card a fixed height below, that turns the *entire* card into +// one scrollable box, so scrolling the body also drags the title/border along with it. Override +// `overflow` back to `visible` here and make only the body scrollable via +// `.gitops-dashboard__infrastructure-card-body`, so the title/border stay fixed in place while +// just the body's content scrolls internally. +.gitops-dashboard__infrastructure-card { + .pf-v6-c-card__title { + margin-bottom: 1px; + padding-bottom: 1px; + } + @media (min-width: 768px) { + height: 200px; + } + overflow: visible; + + &__loading-condition { + height: 80%; + } + + &__error-condition { + height: 60%; + } +} + +.gitops-dashboard__infrastructure-card-applications-needing-attention { + .pf-v6-c-card__title { + margin-bottom: 1px; + padding-bottom: 1px; + } + + @media (min-width: 768px) { + height: 300px; + } + overflow: visible; +} + +.gitops-dashboard__infrastructure-card-body { + // Allow the body to shrink within the card's fixed height instead of growing to fit its + // content (flex items default to `min-height: auto`, which otherwise prevents shrinking). + min-height: 0; + overflow-y: auto; +} + .gitops-dashboard__chart-container { @media (min-width: 768px) { width: 100%; diff --git a/src/gitops/components/overview/DashboardOverviewPage.tsx b/src/gitops/components/overview/DashboardOverviewPage.tsx index e8efedca6..81e388dfc 100644 --- a/src/gitops/components/overview/DashboardOverviewPage.tsx +++ b/src/gitops/components/overview/DashboardOverviewPage.tsx @@ -1,31 +1,42 @@ import * as React from 'react'; -import { Navigate, useNavigate, useParams } from 'react-router-dom-v5-compat'; +import { Navigate, useLocation, useNavigate, useParams } from 'react-router-dom-v5-compat'; -import { ApplicationKind } from '@gitops/models/ApplicationModel'; import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; import { - ListPageBody, + HorizontalNav, ListPageHeader, NamespaceBar, useActiveNamespace, - useK8sWatchResource, } from '@openshift-console/dynamic-plugin-sdk'; -import { Grid, GridItem } from '@patternfly/react-core'; -import HealthStatusCard from './health-status/HealthStatusCard'; -import OperationalMetricsCard from './operational-metrics/OperationalMetricsCard'; -import ReconciliationCard from './reconciliation/ReconciliationCard'; -import SyncActivityCard from './sync-activity/SyncActivityCard'; -import SyncStatusCard from './sync-status/SyncStatusCard'; +import ApplicationsOverviewTab from './tabs/ApplicationsOverviewTab'; +import InfrastructureOverviewTab from './tabs/InfrastructureOverviewTab'; import './DashboardOverviewPage.scss'; const ALL_NAMESPACES_KEY = '#ALL_NS#'; +const ALL_NAMESPACES_PATH = '/gitops/overview/all-namespaces'; +const NS_PATH_PREFIX = '/gitops/overview/ns/'; -const buildOverviewPath = (namespace: string): string => - !namespace || namespace === ALL_NAMESPACES_KEY - ? '/gitops/overview/all-namespaces' - : `/gitops/overview/ns/${namespace}`; +const buildOverviewPath = (namespace: string, tabSuffix = ''): string => { + const base = + !namespace || namespace === ALL_NAMESPACES_KEY + ? ALL_NAMESPACES_PATH + : `${NS_PATH_PREFIX}${namespace}`; + return tabSuffix ? `${base}/${tabSuffix}` : base; +}; + +/** Tab path after the overview base (e.g. '' or 'infrastructure'). */ +const getOverviewTabSuffix = (pathname: string): string => { + if (pathname.startsWith(`${ALL_NAMESPACES_PATH}/`)) { + return pathname.slice(ALL_NAMESPACES_PATH.length + 1); + } + if (pathname === ALL_NAMESPACES_PATH) { + return ''; + } + const nsMatch = pathname.match(/^\/gitops\/overview\/ns\/[^/]+(?:\/(.*))?$/); + return nsMatch?.[1] ?? ''; +}; // Registered at the `/gitops/overview` path - see console-extensions.json export const GitOpsOverviewRedirect: React.FC = () => { @@ -42,6 +53,7 @@ const DashboardOverviewPage: React.FC = ({ }) => { const { ns } = useParams<{ ns?: string }>(); const navigate = useNavigate(); + const { pathname } = useLocation(); const [, setActiveNamespace] = useActiveNamespace(); const namespace = ns || namespaceProp; @@ -50,55 +62,34 @@ const DashboardOverviewPage: React.FC = ({ }, [namespace, setActiveNamespace]); const handleNamespaceChange = (newNamespace: string) => { - navigate(buildOverviewPath(newNamespace)); + navigate(buildOverviewPath(newNamespace, getOverviewTabSuffix(pathname))); }; - const [applications, isAppsLoaded, appsLoadedError] = useK8sWatchResource({ - isList: true, - groupVersionKind: { - group: 'argoproj.io', - kind: 'Application', - version: 'v1alpha1', - }, - namespaced: !!namespace, - namespace, - }); + // HorizontalNav appends each page.href to the current path and renders that page's component. + // Pass shared data (like namespace) via customData — tab components receive it as a prop. + const pages = React.useMemo( + () => [ + { + href: '', + name: t('Application Overview'), + component: ApplicationsOverviewTab, + }, + { + href: 'infrastructure', + name: t('Infrastructure'), + component: InfrastructureOverviewTab, + }, + ], + [], + ); return ( -
+
- - - - - - - - - - - - - - - - - - - - - - +
+ + +
); }; diff --git a/src/gitops/components/overview/chartHelpers.tsx b/src/gitops/components/overview/chartHelpers.tsx index e4aeead8d..f8727bf90 100644 --- a/src/gitops/components/overview/chartHelpers.tsx +++ b/src/gitops/components/overview/chartHelpers.tsx @@ -285,6 +285,17 @@ export const errorState = (errorTitle: string, errorMessage: string) => { ); }; +export const warningState = (title: string, message: string) => { + return ( + } // Hide the button + bodyText={message} + /> + ); +}; + export const StatusChartLegendLabel = ({ datum, ...props }: any) => { return ( = ({ ]; return ( - + {t('Health status')} {/* eslint-disable-next-line no-nested-ternary */} @@ -169,7 +169,7 @@ const HealthStatusCard: React.FC = ({ width={270} labels={({ datum }) => `${datum.x}: ${datum.y}`} legendData={healthStatusLegendData} - legendPosition="bottom" + legendPosition="right" legendOrientation="vertical" colorScale={[ 'var(--pf-t--global--color--status--success--default)', @@ -181,9 +181,9 @@ const HealthStatusCard: React.FC = ({ ]} name="HealthStatus" padding={{ - bottom: 150, + bottom: 20, left: 10, - right: 10, + right: 150, top: 20, }} labelComponent={ diff --git a/src/gitops/components/overview/infrastructure/application/ApplicationsCard.tsx b/src/gitops/components/overview/infrastructure/application/ApplicationsCard.tsx new file mode 100644 index 000000000..3ea1e1d50 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/application/ApplicationsCard.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { ApplicationModel } from '@gitops/models/ApplicationModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; + +import { OverviewCardProps } from '../../chartHelpers'; +import InfrastructureResourceCard from '../shared/InfrastructureResourceCard'; + +const ApplicationsCard: React.FC = ({ namespace }) => ( + +); + +export default ApplicationsCard; diff --git a/src/gitops/components/overview/infrastructure/appset/ApplicationSetsCard.tsx b/src/gitops/components/overview/infrastructure/appset/ApplicationSetsCard.tsx new file mode 100644 index 000000000..83b8373e7 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/appset/ApplicationSetsCard.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { ApplicationSetModel } from '@gitops/models/ApplicationSetModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; + +import { OverviewCardProps } from '../../chartHelpers'; +import InfrastructureResourceCard from '../shared/InfrastructureResourceCard'; + +const ApplicationSetsCard: React.FC = ({ namespace }) => ( + +); + +export default ApplicationSetsCard; diff --git a/src/gitops/components/overview/infrastructure/argocd/ArgoCDInstancesCard.tsx b/src/gitops/components/overview/infrastructure/argocd/ArgoCDInstancesCard.tsx new file mode 100644 index 000000000..374a6f0c5 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/argocd/ArgoCDInstancesCard.tsx @@ -0,0 +1,125 @@ +import * as React from 'react'; + +import { ArgoCDGroupVersionKind, ArgoCDKind, ArgoCDModel } from '@gitops/models/ArgoCDModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { ALL_NAMESPACES_SESSION_KEY } from '@gitops/utils/utils'; +import { useAccessReview, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import { Card, CardBody, Flex } from '@patternfly/react-core'; + +import { DEFAULT_GITOPS_OPERATOR_NAMESPACE, OverviewCardProps } from '../../chartHelpers'; +import { CSVKind } from '../operator/GitOpsOperatorCard'; +import { FLEX_SPACE_SM } from '../shared/constants'; +import CreateResourceLink from '../shared/CreateResourceLink'; +import ErrorHeader from '../shared/ErrorHeader'; +import InfrastructureCardTitle from '../shared/InfrastructureCardTitle'; +import LoadingHeader from '../shared/LoadingHeader'; +import { createK8sResourceEntries } from '../shared/resourceEntries'; + +const ArgoCDInstancesCard: React.FC = ({ namespace }) => { + // TODO NEED TO COMBINE THIS WITH GitOpsOperatorCard + const [csvs, csvsLoaded, csvsError] = useK8sWatchResource({ + isList: true, + groupVersionKind: { + group: 'operators.coreos.com', + version: 'v1alpha1', + kind: 'ClusterServiceVersion', + }, + namespaced: !!namespace, + ...(namespace && namespace !== ALL_NAMESPACES_SESSION_KEY ? { namespace: namespace } : {}), + }); + + const gitopsOperator = React.useMemo(() => { + const csv = (csvs ?? []).find((c) => { + const name = (c.metadata as Record)?.name ?? ''; + return ( + name.startsWith(DEFAULT_GITOPS_OPERATOR_NAMESPACE) || name.startsWith('gitops-operator') + ); + }); + if (!csv) return null; + const meta = csv.metadata; + const spec = csv.spec; + const status = csv.status; + return { + name: meta.name, + message: status?.message ?? '', + phase: status?.phase ?? 'Unknown', + displayName: spec?.displayName ?? '', + provider: spec?.provider?.name ?? '', + version: spec?.version ?? '', + operatorNamespace: meta.namespace ?? '', + createdAt: meta.creationTimestamp || undefined, + currentNamespace: namespace || t('All Namespaces'), + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [csvs]); + + // END OF TODO - Update references below too + + const [argoCDInstances, argoCDInstancesLoaded, argoCDInstancesError] = useK8sWatchResource< + ArgoCDKind[] + >({ + groupVersionKind: { + group: ArgoCDGroupVersionKind.group, + version: ArgoCDGroupVersionKind.version, + kind: ArgoCDGroupVersionKind.kind, + }, + isList: true, + namespaced: !!namespace, + ...(namespace ? { namespace: namespace } : {}), + }); + + const canCreateArgoCDAccess = useAccessReview({ + group: ArgoCDGroupVersionKind.group, + resource: ArgoCDModel.plural, + verb: 'create', + namespace: namespace, + }); + + return ( + + + {/* eslint-disable-next-line no-nested-ternary */} + {!argoCDInstancesLoaded && !argoCDInstancesError ? ( + + ) : argoCDInstancesError ? ( + + ) : ( + + {argoCDInstances && argoCDInstances.length > 0 ? ( + + {createK8sResourceEntries( + argoCDInstances, + 'id-argocd-instance', + ArgoCDModel, + namespace, + )} + + ) : ( + + {t('No {{x}} found', { x: ArgoCDModel.labelPlural })} + + )} + {canCreateArgoCDAccess[0] && + !canCreateArgoCDAccess[1] && + csvsLoaded && + !csvsError && + gitopsOperator && + argoCDInstances?.length === 0 && + namespace && ( + + )} + + )} + + ); +}; + +export default ArgoCDInstancesCard; diff --git a/src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.scss b/src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.scss new file mode 100644 index 000000000..02001741c --- /dev/null +++ b/src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.scss @@ -0,0 +1,4 @@ +.gitops-dashboard-resource-link { + margin: 0 5px 0 0; + display: inline-flex; +} diff --git a/src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.tsx b/src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.tsx new file mode 100644 index 000000000..b561cf160 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/attention/NeedsAttentionCard.tsx @@ -0,0 +1,420 @@ +import React from 'react'; +import { Link } from 'react-router-dom-v5-compat'; +import { HealthStatus as HS, SyncStatus as SS } from 'src/gitops/utils/constants'; + +import { + ApplicationCondition, + ApplicationKind, + ApplicationModel, + ApplicationResourceStatus, +} from '@gitops/models/ApplicationModel'; +import HealthStatus from '@gitops/Statuses/HealthStatus'; +import SyncStatus from '@gitops/Statuses/SyncStatus'; +import { dangerColor } from '@gitops/utils/components/Icons/Icons'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { modelToGroupVersionKind, modelToRef } from '@gitops/utils/utils'; +import { K8sModel, ResourceLink, useAccessReview } from '@openshift-console/dynamic-plugin-sdk'; +import { + Card, + CardBody, + CardHeader, + Divider, + Flex, + FlexItem, + Label, + Tooltip, +} from '@patternfly/react-core'; +import { ExclamationCircleIcon } from '@patternfly/react-icons'; + +import { OverviewCardForApplicationsProps } from '../../chartHelpers'; +import ResourcesStatus from '../resources/ResourcesStatus'; +import { + FLEX_ALIGN_CENTER, + FLEX_SPACE_SM, + LINK_MARGIN, + LINK_MARGIN_FOR_EMPTY_LIST, +} from '../shared/constants'; +import InfrastructureCardTitle from '../shared/InfrastructureCardTitle'; +import LoadingHeader from '../shared/LoadingHeader'; + +import './NeedsAttentionCard.scss'; + +const NeedsAttentionCard: React.FC = ({ + namespace, + applications, + isAppsLoaded, + appsLoadedError, +}) => { + const applicationsNeedingAttention = applications.filter( + (instance) => + instance.status?.health?.status !== HS.HEALTHY || instance.status?.sync?.status !== SS.SYNCED, + ); + + const modelRef = modelToRef(ApplicationModel); + const linkToResourceList = namespace + ? `/k8s/ns/${namespace}/${modelRef}` + : `/k8s/all-namespaces/${modelRef}`; + + const canListAccess = useAccessReview({ + group: ApplicationModel.apiGroup, + resource: ApplicationModel.plural, + verb: 'list', + namespace: namespace ? namespace : undefined, + }); + const isEmpty = !applicationsNeedingAttention || applicationsNeedingAttention.length === 0; + + return ( + + + {/* eslint-disable-next-line no-nested-ternary */} + {!isAppsLoaded && !appsLoadedError ? ( + + ) : appsLoadedError ? ( + + + + + + {t('Error retrieving Applications')} + + + {appsLoadedError} + + + ) : ( + <> + + + + + {t('Application')} + + + + + {t('Details')} + + + + + {t('Status')} + + + + + + + {applicationsNeedingAttention && applicationsNeedingAttention.length > 0 ? ( +
+ {createApplicationResourceEntries( + applicationsNeedingAttention, + 'application', + ApplicationModel, + namespace, + )} +
+ ) : ( + + {t('No {{x}} needing attention', { x: ApplicationModel.labelPlural })} + + )} + {canListAccess[0] && !canListAccess[1] && ( + <> + + + {t('View Applications List Page')} + + + )} +
+ + )} +
+ ); +}; + +const createApplicationResourceEntry = ( + isLast: boolean, + instance: ApplicationKind, + model: K8sModel, + projectNamespace: string, + healthStatus?: string, + syncStatus?: string, +) => { + const unhealthyResources = instance.status?.resources?.filter( + (resource: ApplicationResourceStatus) => + resource.health && resource.health.status !== HS.HEALTHY, + ); + const missingResources = instance.status?.resources?.filter( + (resource: ApplicationResourceStatus) => + resource.health && resource.health.status === HS.MISSING, + ); + const operationStateMessage = instance.status?.operationState?.message; + + return ( +
+ + + + + + + + {projectNamespace === undefined && ( + + {t(`{{x}}`, { x: instance.metadata?.namespace })} + + )} + + + + + + {unhealthyResources && unhealthyResources.length > 0 && ( +
+ + {missingResources && + unhealthyResources && + missingResources.length !== unhealthyResources.length ? ( + unhealthyResources.map((resource: ApplicationResourceStatus) => ( +
+ + { + + + {/* eslint-disable-next-line no-nested-ternary */} + {resource.health?.status === HS.MISSING + ? t('is not on the cluster (Missing).') + : resource.health?.status + ? t('is {{x}}.', { x: resource.health?.status?.toLowerCase() }) + : ''} + {resource.health?.message && + t(' {{x}}.', { + x: resource.health.message, + })} + + } + +
+ +
+ +
+ )) + ) : ( + + {t( + `The application's resources are all missing. Try syncing the application.`, + )} + + )} +
+ {instance.status?.operationState?.phase && ( + + {instance.status?.operationState?.operation?.sync && ( + + + + {t('Operation: Sync')} {instance.status?.operationState?.phase} + {' - '} + {t('Finished At: {{x}}', { + x: instance.status?.operationState?.finishedAt + ? new Date( + instance.status?.operationState?.finishedAt ?? '', + ).toLocaleString(undefined, { + dateStyle: 'medium', + timeStyle: 'medium', + hour12: false, + }) + : '-', + })} + + + + )} + {operationStateMessage && ( + + {operationStateMessage.length > 200 ? ( + + {t('Message: {{x}}', { x: operationStateMessage.slice(0, 200) })} + + + + + ) : ( + t('Message: {{x}}.', { x: operationStateMessage }) + )} + + )} + + {instance.status?.conditions && instance.status.conditions.length > 0 && ( + + {instance.status?.conditions.map((condition: ApplicationCondition) => ( + + {condition.type && condition.type.toLowerCase() + '.'} + {condition.message && condition.message.length > 200 ? ( + + {condition.message.slice(0, 200)} + + + + + ) : ( + condition.message.toLowerCase() + '.' + )} + + ))} + + )} + + )} +
+ )} +
+
+ + + + {healthStatus && } + {syncStatus && } + + + +
+ {!isLast && ( + + )} +
+ ); +}; + +const createApplicationResourceEntries = ( + resources: ApplicationKind[], + uniqueKey: string, + k8sModel: K8sModel, + projectNamespace: string, + listLimit?: number, +) => { + const LIST_LIMIT = listLimit || 10; + const onlyNeedsAttention = resources.filter( + (instance) => + instance.status?.health?.status !== HS.HEALTHY || instance.status?.sync?.status !== SS.SYNCED, + ); + + if (onlyNeedsAttention.length <= LIST_LIMIT) { + const entries = onlyNeedsAttention.map((instance, index) => + createApplicationResourceEntry( + index == onlyNeedsAttention.length - 1, + instance, + k8sModel, + projectNamespace, + instance.status?.health?.status, + instance.status?.sync?.status, + ), + ); + return entries; + } + const entries = onlyNeedsAttention + .slice(0, LIST_LIMIT) + .map((instance, index) => + createApplicationResourceEntry( + index == LIST_LIMIT - 1, + instance, + k8sModel, + projectNamespace, + instance.status?.health?.status, + instance.status?.sync?.status, + ), + ); + + entries.push( + + + {t('...and {{x}} more', { x: onlyNeedsAttention.length - LIST_LIMIT })} + + , + ); + return entries; +}; + +export default NeedsAttentionCard; diff --git a/src/gitops/components/overview/infrastructure/imageupdater/ImageUpdatersCard.tsx b/src/gitops/components/overview/infrastructure/imageupdater/ImageUpdatersCard.tsx new file mode 100644 index 000000000..be9f63456 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/imageupdater/ImageUpdatersCard.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { ImageUpdaterModel } from '@gitops/models/ImageUpdaterModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; + +import { OverviewCardProps } from '../../chartHelpers'; +import InfrastructureResourceCard from '../shared/InfrastructureResourceCard'; + +const ImageUpdatersCard: React.FC = ({ namespace }) => ( + +); + +export default ImageUpdatersCard; diff --git a/src/gitops/components/overview/infrastructure/operator/GitOpsOperatorCard.tsx b/src/gitops/components/overview/infrastructure/operator/GitOpsOperatorCard.tsx new file mode 100644 index 000000000..4db0fe792 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/operator/GitOpsOperatorCard.tsx @@ -0,0 +1,241 @@ +import * as React from 'react'; +import { useMemo } from 'react'; +import { Link } from 'react-router-dom-v5-compat'; + +import { dangerColor, successColor, warningColor } from '@gitops/utils/components/Icons/Icons'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { ALL_NAMESPACES_SESSION_KEY } from '@gitops/utils/utils'; +import OpenshiftGitOpsIcon from '@images/OpenShift_GitOps.svg'; +import { K8sResourceCommon, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import { + Card, + CardBody, + CardHeader, + CardTitle, + Divider, + Flex, + FlexItem, + Label, + Spinner, + Timestamp, + TimestampFormat, +} from '@patternfly/react-core'; +import { CheckCircleIcon, ExclamationCircleIcon, GlobeAmericasIcon } from '@patternfly/react-icons'; + +import { + DEFAULT_GITOPS_OPERATOR_NAMESPACE, + loadingState, + OverviewCardProps, +} from '../../chartHelpers'; +import { FLEX_ALIGN_CENTER, FLEX_SPACE_SM } from '../shared/constants'; + +export type CSVKind = K8sResourceCommon & { + spec?: { + version?: string; + displayName?: string; + provider?: { + name?: string; + }; + }; + status?: { + phase?: string; + message?: string; + lastUpdateTime?: string; + }; +}; + +const GitOpsOperatorCard: React.FC = ({ namespace }) => { + const [csvs, csvsLoaded, csvsError] = useK8sWatchResource({ + isList: true, + groupVersionKind: { + group: 'operators.coreos.com', + version: 'v1alpha1', + kind: 'ClusterServiceVersion', + }, + namespaced: !!namespace, + ...(namespace && namespace !== ALL_NAMESPACES_SESSION_KEY ? { namespace: namespace } : {}), + }); + + const gitopsOperator = useMemo(() => { + const csv = (csvs ?? []).find((c) => { + const name = (c.metadata as Record)?.name ?? ''; + return ( + name.startsWith(DEFAULT_GITOPS_OPERATOR_NAMESPACE) || name.startsWith('gitops-operator') + ); + }); + if (!csv) return null; + const meta = csv.metadata; + const spec = csv.spec; + const status = csv.status; + return { + name: meta.name, + message: status?.message ?? '', + phase: status?.phase ?? 'Unknown', + displayName: spec?.displayName ?? '', + provider: spec?.provider?.name ?? '', + version: spec?.version ?? '', + operatorNamespace: meta.namespace ?? '', + createdAt: meta.creationTimestamp || undefined, + currentNamespace: namespace || t('All Namespaces'), + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [csvs]); + + return ( + + {t('GitOps Operator')} + {/* eslint-disable no-nested-ternary */} + {!csvsLoaded && !csvsError ? ( + + + +
{loadingState()}
+
+
+
+ ) : csvsError ? ( + + + + + + {t('Error retrieving CSV for the GitOps Operator')} + + + {csvsError} + + + ) : gitopsOperator ? ( + + + + + + + + + + {gitopsOperator.name} + + + + + + + + {/* eslint-disable no-nested-ternary */} + {gitopsOperator.phase === 'Succeeded' || + gitopsOperator.phase === 'Available' ? ( + + ) : gitopsOperator.phase === 'Failure' || + gitopsOperator.phase === 'Failed' || + gitopsOperator.phase === 'Unknown' ? ( + + ) : gitopsOperator.phase === 'Pending' ? ( + + ) : ( + <> + )} + + {/* eslint-enable no-nested-ternary */} + + + + + + + + + {t('Version: {{x}}', { x: gitopsOperator.version })} + + + + + {t('Display Name: {{x}}', { x: gitopsOperator.displayName })} + + + + + {t('Provider: {{x}}', { x: gitopsOperator.provider })} + + + + + {t('Namspace: {{x}}', { x: gitopsOperator.currentNamespace })} + + + + + {t('Message: {{x}}', { x: gitopsOperator.message })} + + + + + {t('Created At:')} + {gitopsOperator.createdAt ? ( + + ) : ( + 'N/A' + )} + + + + + + ) : ( + + + + + + {t('Not found')} + + + + {t('The OpenShift GitOps Operator is not installed or not found for this namespace')} + + + + )} + {/* eslint-enable no-nested-ternary */} +
+ ); +}; + +export default GitOpsOperatorCard; diff --git a/src/gitops/components/overview/infrastructure/project/AppProjectsCard.tsx b/src/gitops/components/overview/infrastructure/project/AppProjectsCard.tsx new file mode 100644 index 000000000..eab3f1255 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/project/AppProjectsCard.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { AppProjectModel } from '@gitops/models/AppProjectModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; + +import { OverviewCardProps } from '../../chartHelpers'; +import InfrastructureResourceCard from '../shared/InfrastructureResourceCard'; + +const AppProjectsCard: React.FC = ({ namespace }) => ( + +); + +export default AppProjectsCard; diff --git a/src/gitops/components/overview/infrastructure/resources/ResourcesStatus.tsx b/src/gitops/components/overview/infrastructure/resources/ResourcesStatus.tsx new file mode 100644 index 000000000..be65f7bbf --- /dev/null +++ b/src/gitops/components/overview/infrastructure/resources/ResourcesStatus.tsx @@ -0,0 +1,133 @@ +import { Fragment, useMemo } from 'react'; + +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { + K8sGroupVersionKind, + K8sResourceCommon, + K8sResourceCondition, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; +import { Divider, Flex, FlexItem, Label, Tooltip } from '@patternfly/react-core'; + +// All of our cards will accept a namespace since the project can be specific or All Projects. +export interface ResourcesStatusProps { + namespace: string; + name: string; + resourceKind: K8sGroupVersionKind; +} + +type GitOpsK8sResourceKind = K8sResourceCommon & { + spec?: { + version?: string; + displayName?: string; + provider?: { + name?: string; + }; + }; + status?: { + phase?: string; + message?: string; + lastUpdateTime?: string; + conditions?: K8sResourceCondition[]; + }; +}; + +const ResourcesStatus: React.FC = ({ namespace, name, resourceKind }) => { + const [resources] = useK8sWatchResource({ + groupVersionKind: { + group: resourceKind.group, + version: resourceKind.version, + kind: resourceKind.kind, + }, + isList: true, + namespaced: !!namespace, + ...(namespace ? { namespace: namespace } : {}), + }); + + const theResource = useMemo(() => { + const res = (resources ?? []).find((c) => { + const resName = (c.metadata as Record)?.name ?? ''; + return resName === name; + }); + if (!res) return null; + const meta = res.metadata; + const spec = res.spec; + const status = res.status; + return { + name: meta.name, + conditions: status?.conditions ?? [], + message: status?.message ?? '', + phase: status?.phase ?? 'Unknown', + displayName: spec?.displayName ?? '', + provider: spec?.provider?.name ?? '', + version: spec?.version ?? '', + operatorNamespace: meta.namespace ?? '', + createdAt: meta.creationTimestamp || undefined, + currentNamespace: namespace || t('All Namespaces'), + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [resources]); + + return ( +
+ + + + + + {theResource?.conditions?.length > 0 && ( + <> + {t('Updated message(s) for the {{x}}:', { x: resourceKind.kind })} + + + + + +
+ {theResource?.conditions?.map((condition, index) => ( + + + {condition.lastTransitionTime + ? new Date(condition.lastTransitionTime).toLocaleString(undefined, { + dateStyle: 'medium', + timeStyle: 'medium', + hour12: false, + }) + : ''} + + {condition.message.length > 200 ? ( + + {condition.message.slice(0, 200)} + + + + + ) : ( + {condition.message} + )} + + ))} +
+ + )} +
+ ); +}; + +export default ResourcesStatus; diff --git a/src/gitops/components/overview/infrastructure/rollout-manager/RolloutManagersCard.tsx b/src/gitops/components/overview/infrastructure/rollout-manager/RolloutManagersCard.tsx new file mode 100644 index 000000000..4ce864da2 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/rollout-manager/RolloutManagersCard.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { RolloutManagerModel } from '@gitops/components/rollout/model/RolloutModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; + +import { OverviewCardProps } from '../../chartHelpers'; +import InfrastructureResourceCard from '../shared/InfrastructureResourceCard'; + +const RolloutManagersCard: React.FC = ({ namespace }) => ( + +); + +export default RolloutManagersCard; diff --git a/src/gitops/components/overview/infrastructure/rollout/RolloutsCard.tsx b/src/gitops/components/overview/infrastructure/rollout/RolloutsCard.tsx new file mode 100644 index 000000000..d151e3a18 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/rollout/RolloutsCard.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { RolloutModel } from '@gitops/components/rollout/model/RolloutModel'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; + +import { OverviewCardProps } from '../../chartHelpers'; +import InfrastructureResourceCard from '../shared/InfrastructureResourceCard'; + +const RolloutsCard: React.FC = ({ namespace }) => ( + +); + +export default RolloutsCard; diff --git a/src/gitops/components/overview/infrastructure/shared/CreateResourceLink.tsx b/src/gitops/components/overview/infrastructure/shared/CreateResourceLink.tsx new file mode 100644 index 000000000..faf903c2f --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/CreateResourceLink.tsx @@ -0,0 +1,34 @@ +import { Link } from 'react-router-dom-v5-compat'; + +import { Flex, FlexItem } from '@patternfly/react-core'; +import { PlusCircleIcon } from '@patternfly/react-icons'; + +import { LINK_MARGIN, LINK_MARGIN_FOR_EMPTY_LIST } from './constants'; + +export interface CreateResourcePanelProps { + isEmptyList: boolean; + createLinkUrlString: string; + createLinkText: string; +} + +const CreateResourceLink: React.FC = ({ + isEmptyList, + createLinkUrlString, + createLinkText, +}) => { + return ( + + +
+ + + + {createLinkText} + + +
+
+ ); +}; + +export default CreateResourceLink; diff --git a/src/gitops/components/overview/infrastructure/shared/ErrorHeader.tsx b/src/gitops/components/overview/infrastructure/shared/ErrorHeader.tsx new file mode 100644 index 000000000..3bad2eb3b --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/ErrorHeader.tsx @@ -0,0 +1,21 @@ +import { dangerColor } from '@gitops/utils/components/Icons/Icons'; +import { CardHeader, Flex, FlexItem } from '@patternfly/react-core'; +import { ExclamationCircleIcon } from '@patternfly/react-icons'; + +const ErrorHeader: React.FC<{ title: string; error: string }> = ({ title, error }) => { + return ( + + + + + + {title} + + + {error} + + + ); +}; + +export default ErrorHeader; diff --git a/src/gitops/components/overview/infrastructure/shared/InfrastructureCardTitle.tsx b/src/gitops/components/overview/infrastructure/shared/InfrastructureCardTitle.tsx new file mode 100644 index 000000000..03a1f47af --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/InfrastructureCardTitle.tsx @@ -0,0 +1,75 @@ +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { CardTitle, Divider, Flex, FlexItem, Label } from '@patternfly/react-core'; + +interface InfrastructureCardTitleProps { + title: string; + total: number; + titleDescription?: string; + showDivider?: boolean; + alignTotal?: 'left' | 'center' | 'right'; + showTotal?: boolean; +} + +const InfrastructureCardTitle: React.FC = ({ + title, + total, + titleDescription, + showDivider = true, + alignTotal = 'right', + showTotal = true, +}) => { + const flexValue = + alignTotal === 'right' ? ({ default: 'flex_1' } as const) : ({ default: 'flexNone' } as const); + return ( + + + + {title} + {titleDescription && ( + + {titleDescription} + + )} + + {showTotal && ( + + + + + {t('Total:')} + + + + + + + + )} + + {showDivider && ( + + )} + + ); +}; + +export default InfrastructureCardTitle; diff --git a/src/gitops/components/overview/infrastructure/shared/InfrastructureResourceCard.tsx b/src/gitops/components/overview/infrastructure/shared/InfrastructureResourceCard.tsx new file mode 100644 index 000000000..929565a1e --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/InfrastructureResourceCard.tsx @@ -0,0 +1,114 @@ +import * as React from 'react'; +import { Link } from 'react-router-dom-v5-compat'; + +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { modelToRef } from '@gitops/utils/utils'; +import { + K8sModel, + useAccessReview, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; +import { Card, CardBody, Divider, Flex } from '@patternfly/react-core'; + +import { OverviewCardProps } from '../../chartHelpers'; + +import { FLEX_SPACE_SM, LINK_MARGIN, LINK_MARGIN_FOR_EMPTY_LIST } from './constants'; +import CreateResourceLink from './CreateResourceLink'; +import ErrorHeader from './ErrorHeader'; +import InfrastructureCardTitle from './InfrastructureCardTitle'; +import LoadingHeader from './LoadingHeader'; +import { createK8sResourceEntries, ResourceWithStatus } from './resourceEntries'; + +export type InfrastructureResourceCardProps = OverviewCardProps & { + model: K8sModel; + title: string; + entryKeyPrefix: string; + errorTitle: string; + viewListLinkText: string; + createLinkText: string; + className?: string; +}; + +const InfrastructureResourceCard: React.FC = ({ + namespace, + model, + title, + entryKeyPrefix, + errorTitle, + viewListLinkText, + createLinkText, + className, +}) => { + const [resources, loaded, error] = useK8sWatchResource({ + groupVersionKind: { + group: model.apiGroup, + version: model.apiVersion, + kind: model.kind, + }, + isList: true, + namespaced: !!namespace, + ...(namespace ? { namespace } : {}), + }); + + // K8sVerb from Dynamic Pluging SDK - we need to move up + const canCreateAccess = useAccessReview({ + group: model.apiGroup, + resource: model.plural, + verb: 'create', + namespace, + }); + + const canListAccess = useAccessReview({ + group: model.apiGroup, + resource: model.plural, + verb: 'list', + namespace: namespace ? namespace : undefined, + }); + + const modelRef = modelToRef(model); + const linkToResourceList = namespace + ? `/k8s/ns/${namespace}/${modelRef}` + : `/k8s/all-namespaces/${modelRef}`; + const isEmpty = !resources || resources.length === 0; + + return ( + + + {/* eslint-disable-next-line no-nested-ternary */} + {!loaded && !error ? ( + + ) : error ? ( + + ) : ( + + {!isEmpty ? ( + + {createK8sResourceEntries(resources, entryKeyPrefix, model, namespace)} + + ) : ( + + {t('No {{x}} found', { x: model.labelPlural })} + + )} + {canListAccess[0] && !canListAccess[1] && ( + <> + + + {viewListLinkText} + + + )} + {canCreateAccess[0] && !canCreateAccess[1] && namespace && ( + + )} + + )} + + ); +}; + +export default InfrastructureResourceCard; diff --git a/src/gitops/components/overview/infrastructure/shared/LoadingHeader.tsx b/src/gitops/components/overview/infrastructure/shared/LoadingHeader.tsx new file mode 100644 index 000000000..3d0d952e7 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/LoadingHeader.tsx @@ -0,0 +1,17 @@ +import { CardHeader, Flex, FlexItem } from '@patternfly/react-core'; + +import { loadingState } from '../../chartHelpers'; + +const LoadingHeader: React.FC = () => { + return ( + + + +
{loadingState()}
+
+
+
+ ); +}; + +export default LoadingHeader; diff --git a/src/gitops/components/overview/infrastructure/shared/constants.ts b/src/gitops/components/overview/infrastructure/shared/constants.ts new file mode 100644 index 000000000..d12754293 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/constants.ts @@ -0,0 +1,6 @@ +export const FLEX_SPACE_SM = { default: 'spaceItemsSm' } as const; +export const FLEX_SPACE_MD = { default: 'spaceItemsMd' } as const; +export const FLEX_SPACE_XL = { default: 'spaceItemsXl' } as const; +export const FLEX_ALIGN_CENTER = { default: 'alignItemsCenter' } as const; +export const LINK_MARGIN = { margin: '10px 0px 5px 0px' } as const; +export const LINK_MARGIN_FOR_EMPTY_LIST = { margin: '5px 0px 5px 0px' } as const; diff --git a/src/gitops/components/overview/infrastructure/shared/resourceEntries.tsx b/src/gitops/components/overview/infrastructure/shared/resourceEntries.tsx new file mode 100644 index 000000000..2ad8c1649 --- /dev/null +++ b/src/gitops/components/overview/infrastructure/shared/resourceEntries.tsx @@ -0,0 +1,198 @@ +import { RolloutModel } from '@gitops/components/rollout/model/RolloutModel'; +import { RolloutStatusFragment } from '@gitops/components/rollout/RolloutStatus'; +import { RolloutStatus } from '@gitops/components/rollout/utils/rollout-utils'; +import { ApplicationModel } from '@gitops/models/ApplicationModel'; +import { AppProjectModel } from '@gitops/models/AppProjectModel'; +import HealthStatus from '@gitops/Statuses/HealthStatus'; +import SyncStatus from '@gitops/Statuses/SyncStatus'; +import { dangerColor, successColor } from '@gitops/utils/components/Icons/Icons'; +import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; +import { modelToGroupVersionKind } from '@gitops/utils/utils'; +import { + K8sModel, + K8sResourceCommon, + K8sResourceCondition, + K8sResourceKind, + ResourceLink, +} from '@openshift-console/dynamic-plugin-sdk'; +import { Flex, FlexItem, Label, Spinner, Tooltip } from '@patternfly/react-core'; +import { CheckCircleIcon, ExclamationCircleIcon } from '@patternfly/react-icons'; + +import { FLEX_ALIGN_CENTER, FLEX_SPACE_SM } from './constants'; + +/** + * Currently all our model kinds (eg. ArgoCDKind, RolloutManagerKind, etc.) are specialized types, OR-ed with K8sResourceCommon, + * but for this common helper function, we need a general one to accomodate status.phase, health (for apps) and sync fields, etc. + */ +export type ResourceWithStatus = K8sResourceCommon & { + status?: { + phase?: string; + health?: { status?: string }; + sync?: { status?: string }; + conditions?: K8sResourceCondition[]; + }; +}; + +/** + * Shared/Common function intended to be called from createK8sResourceEntries only. + * + * @param instance - This is typed to K8sResourceCommon, since we only need the metadata + * @param model + * @param phase + * @returns + */ +export const createK8sResourceEntry = ( + instance: ResourceWithStatus, + model: K8sModel, + phase: string | undefined, + projectNamespace: string, + healthStatus?: string, + syncStatus?: string, +) => { + return ( + + + + + + {model.kind === AppProjectModel.kind && projectNamespace === undefined && ( + + {t(`ns={{x}}`, { x: instance.metadata?.namespace })} + + )} + + + + + + {/* eslint-disable no-nested-ternary */} + {model.kind === ApplicationModel.kind ? ( + + {healthStatus && } + {syncStatus && } + + ) : model.kind === RolloutModel.kind ? ( + + 0 && + instance.status?.conditions[instance.status?.conditions?.length - 1].message + } + > + + + + ) : ( + + 0 && instance.status?.conditions[0]?.message + } + > + {phase === 'Available' ? ( + + ) : phase === 'Failure' ? ( + + ) : phase === 'Pending' ? ( + + ) : ( + <> + )} + + {phase && ( + 0 && + instance.status?.conditions[instance.status?.conditions?.length - 1].message + } + > + + + )} + {healthStatus && } + + )} + {/* eslint-enable no-nested-ternary */} + + + + ); +}; + +/** + * Shared/Common function to create a list of resource entries for the resource list in a dashboard card + * + * @param resources - List of Argo Resource Kind specialized type of K8sResourceCommon + * @param uniqueKey - unique key prefix for repeatable elements in the list. Must be unique for each list or call to this function for this dashboard + * @param linkToResourceList - link to the console's resource list page for the resource type + * @param linkText - the link's text to display + * @returns + */ +export const createK8sResourceEntries = ( + resources: ResourceWithStatus[] | K8sResourceKind[], + uniqueKey: string, + k8sModel: K8sModel, + projectNamespace: string, + listLimit?: number, +) => { + const LIST_LIMIT = listLimit || 5; + const entries = + resources.length > LIST_LIMIT + ? resources + .slice(0, LIST_LIMIT) + .map((instance) => + createK8sResourceEntry( + instance, + k8sModel, + instance.status?.phase, + projectNamespace, + instance.status?.health?.status, + instance.status?.sync?.status, + ), + ) + : resources.map((instance) => + createK8sResourceEntry( + instance, + k8sModel, + instance.status?.phase, + projectNamespace, + instance.status?.health?.status, + instance.status?.sync?.status, + ), + ); + if (resources.length > LIST_LIMIT) { + entries.push( + + + {t('...and {{x}} more', { x: resources.length - LIST_LIMIT })} + + , + ); + } + return entries; +}; diff --git a/src/gitops/components/overview/operational-metrics/OperationalMetricsCard.tsx b/src/gitops/components/overview/operational-metrics/OperationalMetricsCard.tsx index 80f79cab4..ce0ae17e1 100644 --- a/src/gitops/components/overview/operational-metrics/OperationalMetricsCard.tsx +++ b/src/gitops/components/overview/operational-metrics/OperationalMetricsCard.tsx @@ -97,18 +97,12 @@ const OperationalMetricsCard: React.FC = ({ namespace }) => { query: successfulSyncsPQ, }); const noOfSuccessfulSyncs = resultSuccessfulSyncsPQ?.data?.result[0]?.value[1]; - // Use first metric to determine last update time. For the other metrics, it will be the same delay - const timeOfSuccessfulSyncs = resultSuccessfulSyncsPQ?.data?.result[0]?.value[0] - ? new Date( - Number(resultSuccessfulSyncsPQ?.data?.result[0]?.value[0]) * 1000, - ).toLocaleTimeString() - : undefined; // Failed Syncs const failedSyncsPQ = - `sum(argocd_app_sync_total{phase!='Succeeded'` + + `sum(increase(argocd_app_sync_total{phase!='Succeeded'` + (namespace ? `,namespace='` + namespace + `'` : ``) + - `})`; + `}[24h]))`; const [resultFailedSyncsPQ, loadedFailedSyncsPQ, errorFailedSyncsPQ] = usePrometheusPoll({ endpoint: PrometheusEndpoint.QUERY, delay: lastUpdateTime * 1000, @@ -144,6 +138,15 @@ const OperationalMetricsCard: React.FC = ({ namespace }) => { query: autosyncEnabledPQ, }); const noOfAutosyncEnabled = resultAutosyncEnabledPQ?.data?.result[0]?.value[1]; + // Last update time can be undefined for 0 apps. If last successful sync is used, then the last update time + // can be undefined for > 0 apps that haven't synced yet. Therefore, use the following two metrics to determine the + // last update time. For any x number of apps, the there should be at least one with either autosync enabled or disabled. + // The same delay update time will be used for all metrics. + let timeOfLastUpdate = resultAutosyncEnabledPQ?.data?.result[0]?.value[0] + ? new Date( + Number(resultAutosyncEnabledPQ?.data?.result[0]?.value[0]) * 1000, + ).toLocaleTimeString() + : undefined; // Apps with Autosync disabled const autosyncDisabledPQ = @@ -157,7 +160,14 @@ const OperationalMetricsCard: React.FC = ({ namespace }) => { query: autosyncDisabledPQ, }); const noOfAutosyncDisabled = resultAutosyncDisabledPQ?.data?.result[0]?.value[1]; - + // If there are no apps with autosync enabled, then there should be at least one with autosync disabled. + if (!timeOfLastUpdate) { + timeOfLastUpdate = resultAutosyncDisabledPQ?.data?.result[0]?.value[0] + ? new Date( + Number(resultAutosyncDisabledPQ?.data?.result[0]?.value[0]) * 1000, + ).toLocaleTimeString() + : undefined; + } // Repo Queue const repoQueuePQ = `sum(argocd_repo_pending_request_total` + @@ -181,20 +191,23 @@ const OperationalMetricsCard: React.FC = ({ namespace }) => { const noOfGitFetchFailedTotal = resultGitFetchFailedTotalPQ?.data?.result[0]?.value[1]; return ( - + {t('Operational metrics')} - {timeOfSuccessfulSyncs && ( - + {timeOfLastUpdate && ( + )} - + {rowMetric( t('Successful syncs'), successfulSyncsPQ, @@ -216,7 +229,7 @@ const OperationalMetricsCard: React.FC = ({ namespace }) => { loadedFailedSyncsPQ, errorFailedSyncsPQ, t( - 'Number of failed syncs. Apps successfully synced from a failed sync will not decrease this count.', + 'Number of failed syncs over a 24 hour moving window. If a failed sync happens, this counter increases by one. 24 hours later, this number will then decrease by one.', ), noOfFailedSyncs ? ( ) : (